blob: ff8bb710431c6dc1a5b56b328f9bf3fc03c20e92 [file] [log] [blame]
/***************************************************************************
* Copyright C 2009 by Amlogic, Inc. All Rights Reserved.
*/
/**\file
* \brief
*
* \author Gong Ke <ke.gong@amlogic.com>
* \date 2010-06-30: create the document
***************************************************************************/
#define AM_DEBUG_LEVEL 5
//#include <am_debug.h>
#include "am_time.h"
#include "am_mem.h"
#include "am_smc_internal.h"
#include "am_adp_internal.h"
#include <assert.h>
#include <unistd.h>
#include <stdio.h>
#include "am_util.h"
/****************************************************************************
* Macro definitions
***************************************************************************/
#define SMC_STATUS_SLEEP_TIME (1000)
/****************************************************************************
* Static data
***************************************************************************/
#ifdef EMU_SMC
extern const AM_SMC_Driver_t emu_drv;
#else
extern const AM_SMC_Driver_t aml_smc_drv;
#endif
static AM_SMC_Device_t smc_devices[] =
{
#ifdef EMU_SMC
{
.drv = &emu_drv
}
#else
{
.drv = &aml_smc_drv
}
#endif
};
/**\brief 智能卡设备数*/
#define SMC_DEV_COUNT AM_ARRAY_SIZE(smc_devices)
/****************************************************************************
* Static functions
***************************************************************************/
/**\brief 根据设备号取得设备结构*/
static AM_INLINE AM_ErrorCode_t smc_get_dev(int dev_no, AM_SMC_Device_t **dev)
{
if ((dev_no < 0) || (dev_no >= SMC_DEV_COUNT))
{
printf( "invalid smartcard device number %d, must in(%d~%d)", dev_no, 0, SMC_DEV_COUNT-1);
return AM_SMC_ERR_INVALID_DEV_NO;
}
*dev = &smc_devices[dev_no];
return AM_SUCCESS;
}
/**\brief 根据设备号取得设备结构并检查设备是否已经打开*/
static AM_INLINE AM_ErrorCode_t smc_get_openned_dev(int dev_no, AM_SMC_Device_t **dev)
{
AM_TRY(smc_get_dev(dev_no, dev));
if (!(*dev)->openned)
{
printf( "smartcard device %d has not been openned", dev_no);
return AM_SMC_ERR_NOT_OPENNED;
}
return AM_SUCCESS;
}
/**\brief 从智能卡读取数据*/
static AM_ErrorCode_t smc_read(AM_SMC_Device_t *dev, uint8_t *buf, int len, int *act_len, int timeout)
{
uint8_t *ptr = buf;
int left = len;
int now, end = 0, diff, cnt = 0;
AM_ErrorCode_t ret = AM_SUCCESS;
if (timeout >= 0)
{
AM_TIME_GetClock(&now);
end = now + timeout;
}
while (left)
{
int tlen = left;
int ms;
if (timeout >= 0)
{
ms = end-now;
}
else
{
ms = -1;
}
ret = dev->drv->read(dev, ptr, &tlen, ms);
if (ret < 0)
{
break;
}
ptr += tlen;
left -= tlen;
cnt += tlen;
AM_TIME_GetClock(&now);
diff = now - end;
if (diff >= 0)
{
printf( "read %d bytes timeout", len);
ret = AM_SMC_ERR_TIMEOUT;
break;
}
}
if (act_len)
*act_len = cnt;
return ret;
}
/**\brief 向智能卡发送数据*/
static AM_ErrorCode_t smc_write(AM_SMC_Device_t *dev, const uint8_t *buf, int len, int *act_len, int timeout)
{
const uint8_t *ptr = buf;
int left = len;
int now, end = 0, diff, cnt = 0;
AM_ErrorCode_t ret = AM_SUCCESS;
if (timeout >= 0)
{
AM_TIME_GetClock(&now);
end = now + timeout;
}
while (left)
{
int tlen = left;
int ms;
if (timeout >= 0)
{
ms = end-now;
}
else
{
ms = -1;
}
ret = dev->drv->write(dev, ptr, &tlen, ms);
if (ret < 0)
{
break;
}
ptr += tlen;
left -= tlen;
cnt += tlen;
AM_TIME_GetClock(&now);
diff = now-end;
if (diff >= 0)
{
printf( "write %d bytes timeout", len);
ret = AM_SMC_ERR_TIMEOUT;
break;
}
}
if (act_len)
*act_len = cnt;
return ret;
}
/**\brief status monitor thread*/
static void*
smc_status_thread(void *arg)
{
AM_SMC_Device_t *dev = (AM_SMC_Device_t*)arg;
AM_SMC_CardStatus_t old_status = AM_SMC_CARD_OUT;
while (dev->enable_thread)
{
AM_SMC_CardStatus_t status = AM_SMC_CARD_OUT;
AM_ErrorCode_t ret;
pthread_mutex_lock(&dev->lock);
ret = dev->drv->get_status(dev, &status);
pthread_mutex_unlock(&dev->lock);
if (status != old_status)
{
old_status = status;
pthread_mutex_lock(&dev->lock);
dev->flags |= SMC_FL_RUN_CB;
pthread_mutex_unlock(&dev->lock);
if (dev->cb)
{
dev->cb(dev->dev_no, status, dev->user_data);
}
AM_EVT_Signal(dev->dev_no, (status==AM_SMC_CARD_OUT)?AM_SMC_EVT_CARD_OUT:AM_SMC_EVT_CARD_IN, NULL);
pthread_mutex_lock(&dev->lock);
dev->flags &= ~SMC_FL_RUN_CB;
pthread_mutex_unlock(&dev->lock);
pthread_cond_broadcast(&dev->cond);
}
usleep(SMC_STATUS_SLEEP_TIME*1000);
}
return NULL;
}
/****************************************************************************
* API functions
***************************************************************************/
/**\brief 打开智能卡设备
* \param dev_no 智能卡设备号
* \param[in] para 智能卡设备开启参数
* \return
* - AM_SUCCESS 成功
* - 其他值 错误代码(见am_smc.h)
*/
AM_ErrorCode_t AM_SMC_Open(int dev_no, const AM_SMC_OpenPara_t *para)
{
AM_SMC_Device_t *dev;
AM_ErrorCode_t ret = AM_SUCCESS;
assert(para);
AM_TRY(smc_get_dev(dev_no, &dev));
// pthread_mutex_lock(&am_gAdpLock);
if (dev->openned)
{
printf( "smartcard device %d has already been openned", dev_no);
ret = AM_SMC_ERR_BUSY;
goto final;
}
dev->dev_no = dev_no;
if (dev->drv->open)
{
AM_TRY_FINAL(dev->drv->open(dev, para));
}
pthread_mutex_init(&dev->lock, NULL);
pthread_cond_init(&dev->cond, NULL);
dev->enable_thread = para->enable_thread;
dev->openned = AM_TRUE;
pthread_mutex_lock(&dev->lock);
dev->flags = 0;
pthread_mutex_unlock(&dev->lock);
if (dev->enable_thread)
{
if (pthread_create(&dev->status_thread, NULL, smc_status_thread, dev))
{
printf( "cannot create the status monitor thread");
pthread_mutex_destroy(&dev->lock);
pthread_cond_destroy(&dev->cond);
if (dev->drv->close)
{
dev->drv->close(dev);
}
ret = AM_SMC_ERR_CANNOT_CREATE_THREAD;
goto final;
}
}
else
{
dev->status_thread = (pthread_t)-1;
}
final:
// pthread_mutex_unlock(&am_gAdpLock);
return ret;
}
/**\brief 关闭智能卡设备
* \param dev_no 智能卡设备号
* \return
* - AM_SUCCESS 成功
* - 其他值 错误代码(见am_smc.h)
*/
AM_ErrorCode_t AM_SMC_Close(int dev_no)
{
AM_SMC_Device_t *dev;
AM_TRY(smc_get_openned_dev(dev_no, &dev));
// pthread_mutex_lock(&am_gAdpLock);
if (dev->enable_thread)
{
dev->enable_thread = AM_FALSE;
pthread_join(dev->status_thread, NULL);
}
if (dev->drv->close)
{
dev->drv->close(dev);
}
pthread_mutex_destroy(&dev->lock);
pthread_cond_destroy(&dev->cond);
dev->openned = AM_FALSE;
// pthread_mutex_unlock(&am_gAdpLock);
return AM_SUCCESS;
}
/**\brief 得到当前的智能卡插入状态
* \param dev_no 智能卡设备号
* \param[out] status 返回智能卡插入状态
* \return
* - AM_SUCCESS 成功
* - 其他值 错误代码(见am_smc.h)
*/
AM_ErrorCode_t AM_SMC_GetCardStatus(int dev_no, AM_SMC_CardStatus_t *status)
{
AM_SMC_Device_t *dev;
AM_ErrorCode_t ret = AM_SUCCESS;
assert(status);
AM_TRY(smc_get_openned_dev(dev_no, &dev));
if (!dev->drv->get_status)
{
printf( "driver do not support get_status");
ret = AM_SMC_ERR_NOT_SUPPORTED;
}
if (ret == 0)
{
pthread_mutex_lock(&dev->lock);
ret = dev->drv->get_status(dev, status);
pthread_mutex_unlock(&dev->lock);
}
return ret;
}
/**\brief 复位智能卡
* \param dev_no 智能卡设备号
* \param[out] atr 返回智能卡的ATR数据
* \param[in,out] len 输入ATR缓冲区大小,返回实际的ATR长度
* \return
* - AM_SUCCESS 成功
* - 其他值 错误代码(见am_smc.h)
*/
AM_ErrorCode_t AM_SMC_Reset(int dev_no, uint8_t *atr, int *len)
{
AM_SMC_Device_t *dev;
AM_ErrorCode_t ret = AM_SUCCESS;
uint8_t atr_buf[AM_SMC_MAX_ATR_LEN];
int len_buf;
if (atr && len)
{
if (*len < AM_SMC_MAX_ATR_LEN)
{
printf( "ATR buffer < %d", AM_SMC_MAX_ATR_LEN);
return AM_SMC_ERR_BUF_TOO_SMALL;
}
}
else
{
if (!atr)
atr = atr_buf;
if (!len)
len = &len_buf;
}
AM_TRY(smc_get_openned_dev(dev_no, &dev));
if (!dev->drv->reset)
{
printf( "driver do not support reset");
ret = AM_SMC_ERR_NOT_SUPPORTED;
}
if (ret == 0)
{
pthread_mutex_lock(&dev->lock);
ret = dev->drv->reset(dev, atr, len);
pthread_mutex_unlock(&dev->lock);
}
return ret;
}
/**\brief 从智能卡读取数据
*直接从智能卡读取数据,调用函数的线程会阻塞,直到读取到期望数目的数据,或到达超时时间。
* \param dev_no 智能卡设备号
* \param[out] data 数据缓冲区
* \param[in] len 希望读取的数据长度
* \param timeout 读取超时时间,以毫秒为单位,<0表示永久等待。
* \return
* - AM_SUCCESS 成功
* - 其他值 错误代码(见am_smc.h)
*/
AM_ErrorCode_t AM_SMC_Read(int dev_no, uint8_t *data, int len, int timeout)
{
AM_SMC_Device_t *dev;
AM_ErrorCode_t ret = AM_SUCCESS;
assert(data);
AM_TRY(smc_get_openned_dev(dev_no, &dev));
pthread_mutex_lock(&dev->lock);
ret = smc_read(dev, data, len, NULL, timeout);
pthread_mutex_unlock(&dev->lock);
return ret;
}
/**\brief 向智能卡发送数据
*直接向智能卡发送数据,调用函数的线程会阻塞,直到全部数据被写入,或到达超时时间。
* \param dev_no 智能卡设备号
* \param[in] data 数据缓冲区
* \param[in] len 希望发送的数据长度
* \param timeout 读取超时时间,以毫秒为单位,<0表示永久等待。
* \return
* - AM_SUCCESS 成功
* - 其他值 错误代码(见am_smc.h)
*/
AM_ErrorCode_t AM_SMC_Write(int dev_no, const uint8_t *data, int len, int timeout)
{
AM_SMC_Device_t *dev;
AM_ErrorCode_t ret = AM_SUCCESS;
assert(data);
AM_TRY(smc_get_openned_dev(dev_no, &dev));
pthread_mutex_lock(&dev->lock);
ret = smc_write(dev, data, len, NULL, timeout);
pthread_mutex_unlock(&dev->lock);
return ret;
}
/**\brief 从智能卡读取数据
*直接从智能卡读取数据,调用函数的线程会阻塞,直到读取到期望数目的数据,或到达超时时间。
* \param dev_no 智能卡设备号
* \param[out] data 数据缓冲区
* \param[in] len 希望读取的数据长度
* \param timeout 读取超时时间,以毫秒为单位,<0表示永久等待。
* \return
* - >=0 实际读取的数据长度
* - 其他值 错误代码(见am_smc.h)
*/
AM_ErrorCode_t
AM_SMC_ReadEx(int dev_no, uint8_t *data, int len, int timeout)
{
AM_SMC_Device_t *dev;
AM_ErrorCode_t ret = AM_SUCCESS;
int act_len;
assert(data);
AM_TRY(smc_get_openned_dev(dev_no, &dev));
pthread_mutex_lock(&dev->lock);
ret = smc_read(dev, data, len, &act_len, timeout);
pthread_mutex_unlock(&dev->lock);
if ((ret >= 0) || (ret == AM_SMC_ERR_TIMEOUT))
return act_len;
return ret;
}
/**\brief 向智能卡发送数据
*直接向智能卡发送数据,调用函数的线程会阻塞,直到全部数据被写入,或到达超时时间。
* \param dev_no 智能卡设备号
* \param[in] data 数据缓冲区
* \param[in] len 希望发送的数据长度
* \param timeout 读取超时时间,以毫秒为单位,<0表示永久等待。
* \return
* - >=0 实际写入的数据长度
* - 其他值 错误代码(见am_smc.h)
*/
AM_ErrorCode_t
AM_SMC_WriteEx(int dev_no, const uint8_t *data, int len, int timeout)
{
AM_SMC_Device_t *dev;
AM_ErrorCode_t ret = AM_SUCCESS;
int act_len;
assert(data);
AM_TRY(smc_get_openned_dev(dev_no, &dev));
pthread_mutex_lock(&dev->lock);
ret = smc_write(dev, data, len, &act_len, timeout);
pthread_mutex_unlock(&dev->lock);
if ((ret >= 0) || (ret == AM_SMC_ERR_TIMEOUT))
return act_len;
return ret;
}
/**\brief 按T0协议传输数据
* \param dev_no 智能卡设备号
* \param[in] send 发送数据缓冲区
* \param[in] slen 待发送的数据长度
* \param[out] recv 接收数据缓冲区
* \param[out] rlen 返回接收数据的长度
* \return
* - AM_SUCCESS 成功
* - 其他值 错误代码(见am_smc.h)
*/
AM_ErrorCode_t AM_SMC_TransferT0(int dev_no, const uint8_t *send, int slen, uint8_t *recv, int *rlen)
{
AM_SMC_Device_t *dev = NULL;
AM_ErrorCode_t ret = AM_SUCCESS;
uint8_t byte = 0;
uint8_t *dst = NULL;
int left = 0;
AM_Bool_t sent = AM_FALSE;
assert(send && recv && rlen && (slen >= 5));
dst = recv;
left = *rlen;
AM_TRY(smc_get_openned_dev(dev_no, &dev));
pthread_mutex_lock(&dev->lock);
AM_TRY_FINAL(smc_write(dev, send, 5, NULL, 1000));
while (1)
{
AM_TRY_FINAL(smc_read(dev, &byte, 1, NULL, 1000));
if (byte == 0x60)
{
continue;
}
if (((byte & 0xF0) == 0x60) || ((byte & 0xF0) == 0x90))
{
if (left < 2)
{
printf( "receive buffer must >= %d", 2);
ret = AM_SMC_ERR_BUF_TOO_SMALL;
goto final;
}
dst[0] = byte;
AM_TRY_FINAL(smc_read(dev, &dst[1], 1, NULL, 1000));
dst += 2;
break;
}
else if (byte == send[1])
{
if (!sent)
{
int cnt = slen - 5;
if (cnt)
{
AM_TRY_FINAL(smc_write(dev, send + 5, cnt, NULL, 5000));
}
else
{
cnt = send[4];
if (!cnt) cnt = 256;
if (left < cnt + 2)
{
printf( "receive buffer must >= %d", cnt+2);
ret = AM_SMC_ERR_BUF_TOO_SMALL;
goto final;
}
AM_TRY_FINAL(smc_read(dev, dst, cnt, NULL, 5000));
dst += cnt;
left -= cnt;
}
sent = AM_TRUE;
}
else
{
ret = AM_SMC_ERR_IO;
break;
}
}
else
{
ret = AM_SMC_ERR_IO;
break;
}
}
final:
pthread_mutex_unlock(&dev->lock);
*rlen = dst-recv;
return ret;
}
/**\brief 取得当前的智能卡状态回调函数
* \param dev_no 智能卡设备号
* \param[out] cb 返回回调函数指针
* \param[out] data 返回用户数据
* \return
* - AM_SUCCESS 成功
* - 其他值 错误代码(见am_smc.h)
*/
AM_ErrorCode_t AM_SMC_GetCallback(int dev_no, AM_SMC_StatusCb_t *cb, void **data)
{
AM_SMC_Device_t *dev;
AM_ErrorCode_t ret = AM_SUCCESS;
AM_TRY(smc_get_openned_dev(dev_no, &dev));
pthread_mutex_lock(&dev->lock);
if (cb)
{
*cb = dev->cb;
}
if (data)
{
*data = dev->user_data;
}
pthread_mutex_unlock(&dev->lock);
return ret;
}
/**\brief 设定智能卡状态回调函数
* \param dev_no 智能卡设备号
* \param[in] cb 回调函数指针
* \param[in] data 用户数据
* \return
* - AM_SUCCESS 成功
* - 其他值 错误代码(见am_smc.h)
*/
AM_ErrorCode_t AM_SMC_SetCallback(int dev_no, AM_SMC_StatusCb_t cb, void *data)
{
AM_SMC_Device_t *dev;
AM_ErrorCode_t ret = AM_SUCCESS;
AM_TRY(smc_get_openned_dev(dev_no, &dev));
pthread_mutex_lock(&dev->lock);
while ((dev->flags & SMC_FL_RUN_CB) && (pthread_self() != dev->status_thread))
{
pthread_cond_wait(&dev->cond, &dev->lock);
}
dev->cb = cb;
dev->user_data = data;
pthread_mutex_unlock(&dev->lock);
return ret;
}
/**\brief 激活智能卡设备
* \param dev_no 智能卡设备号
* \return
* - AM_SUCCESS 成功
* - 其他值 错误代码(见am_smc.h)
*/
AM_ErrorCode_t AM_SMC_Active(int dev_no)
{
AM_SMC_Device_t *dev;
AM_ErrorCode_t ret = AM_SUCCESS;
AM_TRY(smc_get_openned_dev(dev_no, &dev));
if (!dev->drv->active)
{
printf( "driver do not support active");
ret = AM_SMC_ERR_NOT_SUPPORTED;
}
if (ret == 0)
{
pthread_mutex_lock(&dev->lock);
ret = dev->drv->active(dev);
pthread_mutex_unlock(&dev->lock);
}
return ret;
}
/**\brief 取消激活智能卡设备
* \param dev_no 智能卡设备号
* \return
* - AM_SUCCESS 成功
* - 其他值 错误代码(见am_smc.h)
*/
AM_ErrorCode_t AM_SMC_Deactive(int dev_no)
{
AM_SMC_Device_t *dev;
AM_ErrorCode_t ret = AM_SUCCESS;
AM_TRY(smc_get_openned_dev(dev_no, &dev));
if (!dev->drv->deactive)
{
printf( "driver do not support deactive");
ret = AM_SMC_ERR_NOT_SUPPORTED;
}
if (ret == 0)
{
pthread_mutex_lock(&dev->lock);
ret = dev->drv->deactive(dev);
pthread_mutex_unlock(&dev->lock);
}
return ret;
}
/**\brief 获取智能卡参数
* \param dev_no 智能卡设备号
* \param[out] para 返回智能卡参数
* \return
* - AM_SUCCESS 成功
* - 其他值 错误代码(见am_smc.h)
*/
AM_ErrorCode_t AM_SMC_GetParam(int dev_no, AM_SMC_Param_t *para)
{
AM_SMC_Device_t *dev;
AM_ErrorCode_t ret = AM_SUCCESS;
assert(para);
AM_TRY(smc_get_openned_dev(dev_no, &dev));
if (!dev->drv->get_param)
{
printf( "driver do not support get_param");
ret = AM_SMC_ERR_NOT_SUPPORTED;
}
if (ret == 0)
{
pthread_mutex_lock(&dev->lock);
ret = dev->drv->get_param(dev, para);
pthread_mutex_unlock(&dev->lock);
}
return ret;
}
/**\brief 设定智能卡参数
* \param dev_no 智能卡设备号
* \param[in] para 智能卡参数
* \return
* - AM_SUCCESS 成功
* - 其他值 错误代码(见am_smc.h)
*/
AM_ErrorCode_t AM_SMC_SetParam(int dev_no, const AM_SMC_Param_t *para)
{
AM_SMC_Device_t *dev;
AM_ErrorCode_t ret = AM_SUCCESS;
assert(para);
AM_TRY(smc_get_openned_dev(dev_no, &dev));
if (!dev->drv->set_param)
{
printf( "driver do not support set_param");
ret = AM_SMC_ERR_NOT_SUPPORTED;
}
if (ret == 0)
{
pthread_mutex_lock(&dev->lock);
ret = dev->drv->set_param(dev, para);
pthread_mutex_unlock(&dev->lock);
}
return ret;
}