[Pcsclite-cvs-commit] r2470 - trunk/Drivers/ccid/src
Ludovic Rousseau
rousseau at alioth.debian.org
Thu Mar 8 13:44:37 CET 2007
Author: rousseau
Date: 2007-03-08 12:44:37 +0000 (Thu, 08 Mar 2007)
New Revision: 2470
Modified:
trunk/Drivers/ccid/src/ccid.c
trunk/Drivers/ccid/src/ccid.h
trunk/Drivers/ccid/src/ccid_usb.c
trunk/Drivers/ccid/src/commands.c
Log:
add support of ICCD version A and B
Modified: trunk/Drivers/ccid/src/ccid.c
===================================================================
--- trunk/Drivers/ccid/src/ccid.c 2007-03-08 10:21:47 UTC (rev 2469)
+++ trunk/Drivers/ccid/src/ccid.c 2007-03-08 12:44:37 UTC (rev 2470)
@@ -252,6 +252,38 @@
break;
}
+ /* ICCD type A */
+ if (ICCD_A == ccid_descriptor->bInterfaceProtocol)
+ {
+ unsigned char tmp[MAX_ATR_SIZE];
+ unsigned int n = sizeof(tmp);
+
+ DEBUG_COMM("ICCD type A");
+ CmdPowerOff(reader_index);
+ CmdPowerOn(reader_index, &n, tmp, CCID_CLASS_AUTO_VOLTAGE);
+ CmdPowerOff(reader_index);
+ }
+
+ /* ICCD type B */
+ if (ICCD_B == ccid_descriptor->bInterfaceProtocol)
+ {
+ unsigned char tmp[MAX_ATR_SIZE];
+ unsigned int n = sizeof(tmp);
+
+ DEBUG_COMM("ICCD type B");
+ if (CCID_CLASS_SHORT_APDU ==
+ (ccid_descriptor->dwFeatures & CCID_CLASS_EXCHANGE_MASK))
+ {
+ /* use the extended APDU comm alogorithm */
+ ccid_descriptor->dwFeatures &= ~CCID_CLASS_EXCHANGE_MASK;
+ ccid_descriptor->dwFeatures |= CCID_CLASS_EXTENDED_APDU;
+ }
+
+ CmdPowerOff(reader_index);
+ CmdPowerOn(reader_index, &n, tmp, CCID_CLASS_AUTO_VOLTAGE);
+ CmdPowerOff(reader_index);
+ }
+
return 0;
} /* ccid_open_hack */
Modified: trunk/Drivers/ccid/src/ccid.h
===================================================================
--- trunk/Drivers/ccid/src/ccid.h 2007-03-08 10:21:47 UTC (rev 2469)
+++ trunk/Drivers/ccid/src/ccid.h 2007-03-08 12:44:37 UTC (rev 2470)
@@ -90,6 +90,11 @@
* Card protocol
*/
int cardProtocol;
+
+ /*
+ * bInterfaceProtocol (CCID, ICCD-A, ICCD-B)
+ */
+ int bInterfaceProtocol;
} _ccid_descriptor;
/* Features from dwFeatures */
@@ -118,6 +123,10 @@
#define CCID_COMMAND_FAILED 0x40 /* 01 0000 00 */
#define CCID_TIME_EXTENSION 0x80 /* 10 0000 00 */
+/* bInterfaceProtocol for ICCD */
+#define ICCD_A 1 /* ICCD Version A */
+#define ICCD_B 2 /* ICCD Version B */
+
/* Product identification for special treatments */
#define GEMPC433 0x08E64433
#define GEMPCKEY 0x08E63438
Modified: trunk/Drivers/ccid/src/ccid_usb.c
===================================================================
--- trunk/Drivers/ccid/src/ccid_usb.c 2007-03-08 10:21:47 UTC (rev 2469)
+++ trunk/Drivers/ccid/src/ccid_usb.c 2007-03-08 12:44:37 UTC (rev 2470)
@@ -428,6 +428,7 @@
usbDevice[reader_index].ccid.bCurrentSlotIndex = 0;
usbDevice[reader_index].ccid.readTimeout = DEFAULT_COM_READ_TIMEOUT;
usbDevice[reader_index].ccid.arrayOfSupportedDataRates = get_data_rates(reader_index, dev);
+ usbDevice[reader_index].ccid.bInterfaceProtocol = usb_interface->altsetting->bInterfaceProtocol;
goto end;
}
}
Modified: trunk/Drivers/ccid/src/commands.c
===================================================================
--- trunk/Drivers/ccid/src/commands.c 2007-03-08 10:21:47 UTC (rev 2469)
+++ trunk/Drivers/ccid/src/commands.c 2007-03-08 12:44:37 UTC (rev 2470)
@@ -23,6 +23,7 @@
#include <string.h>
#include <stdlib.h>
+#include <errno.h>
#include <pcsclite.h>
#include <ifdhandler.h>
#include <reader.h>
@@ -78,6 +79,84 @@
RESPONSECODE return_value = IFD_SUCCESS;
_ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+ if (ICCD_A == ccid_descriptor->bInterfaceProtocol)
+ {
+ int r;
+ unsigned char pcbuffer[SIZE_GET_SLOT_STATUS];
+
+ /* first power off to reset the ICC state machine */
+ r = CmdPowerOff(reader_index);
+ if (r != IFD_SUCCESS)
+ return r;
+
+ /* wait for ready */
+ r = CmdGetSlotStatus(reader_index, pcbuffer);
+ if (r != IFD_SUCCESS)
+ return r;
+
+ /* Power On */
+ r = ControlUSB(reader_index, 0xA1, 0x62, 0, buffer, *nlength);
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Power On failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ *nlength = r;
+
+ return IFD_SUCCESS;
+ }
+
+ if (ICCD_B == ccid_descriptor->bInterfaceProtocol)
+ {
+ int r;
+ unsigned char tmp[MAX_ATR_SIZE+1];
+
+ /* first power off to reset the ICC state machine */
+ r = CmdPowerOff(reader_index);
+ if (r != IFD_SUCCESS)
+ return r;
+
+ /* Power On */
+ r = ControlUSB(reader_index, 0x21, 0x62, 1, NULL, 0);
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Power On failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ /* Data Block */
+ r = ControlUSB(reader_index, 0xA1, 0x6F, 0, tmp, sizeof(tmp));
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Data Block failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ if (tmp[0] != 0x00)
+ {
+ DEBUG_CRITICAL2("bResponseType: 0x%02X", tmp[0]);
+
+ /* Status Information? */
+ if (0x40 == tmp[0])
+ ccid_error(tmp[2], __FILE__, __LINE__, __FUNCTION__);
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ DEBUG_INFO_XXD("Data Block: ", tmp, r);
+ if (*nlength > r-1)
+ *nlength = r-1;
+ memcpy(buffer, tmp+1, *nlength);
+
+ return IFD_SUCCESS;
+ }
+
/* store length of buffer[] */
length = *nlength;
@@ -669,6 +748,51 @@
RESPONSECODE return_value = IFD_SUCCESS;
_ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+ if (ICCD_A == ccid_descriptor->bInterfaceProtocol)
+ {
+ int r;
+
+ /* PowerOff */
+ r = ControlUSB(reader_index, 0x21, 0x63, 0, NULL, 0);
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Power Off failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ return IFD_SUCCESS;
+ }
+
+ if (ICCD_B == ccid_descriptor->bInterfaceProtocol)
+ {
+ int r;
+ unsigned char buffer[3];
+
+ /* PowerOff */
+ r = ControlUSB(reader_index, 0x21, 0x63, 0, NULL, 0);
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Power Off failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ /* SlotStatus */
+ r = ControlUSB(reader_index, 0xA1, 0x81, 0, buffer, sizeof(buffer));
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC SlotStatus failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ return IFD_SUCCESS;
+ }
+
cmd[0] = 0x63; /* IccPowerOff */
cmd[1] = cmd[2] = cmd[3] = cmd[4] = 0; /* dwLength */
cmd[5] = ccid_descriptor->bCurrentSlotIndex; /* slot number */
@@ -713,6 +837,80 @@
RESPONSECODE return_value = IFD_SUCCESS;
_ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
+ if (ICCD_A == ccid_descriptor->bInterfaceProtocol)
+ {
+ int r;
+ unsigned char status[1];
+
+again_status:
+ /* SlotStatus */
+ r = ControlUSB(reader_index, 0xA1, 0xA0, 0, status, sizeof(status));
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Slot Status failed: %s", strerror(errno));
+ if (ENODEV == errno)
+ return IFD_NO_SUCH_DEVICE;
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ /* busy */
+ if (status[0] & 0x40)
+ {
+ DEBUG_INFO2("Busy: 0x%02X", status[0]);
+ usleep(1000 * 10);
+ goto again_status;
+ }
+
+ /* simulate a CCID bStatus */
+ /* present and active by default */
+ buffer[7] = CCID_ICC_PRESENT_ACTIVE;
+
+ /* mute */
+ if (0x80 == status[0])
+ buffer[7] = CCID_ICC_ABSENT;
+
+ /* store the status for CmdXfrBlockCHAR_T0() */
+ buffer[0] = status[0];
+
+ return IFD_SUCCESS;
+ }
+
+ if (ICCD_B == ccid_descriptor->bInterfaceProtocol)
+ {
+ int r;
+ unsigned char buffer_tmp[3];
+
+ /* SlotStatus */
+ r = ControlUSB(reader_index, 0xA1, 0x81, 0, buffer_tmp,
+ sizeof(buffer_tmp));
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Slot Status failed: %s", strerror(errno));
+ if (ENODEV == errno)
+ return IFD_NO_SUCH_DEVICE;
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ /* simulate a CCID bStatus */
+ switch (buffer_tmp[1] & 0x03)
+ {
+ case 0:
+ buffer[7] = CCID_ICC_PRESENT_ACTIVE;
+ break;
+ case 1:
+ buffer[7] = CCID_ICC_PRESENT_INACTIVE;
+ break;
+ case 2:
+ case 3:
+ buffer[7] = CCID_ICC_ABSENT;
+ }
+ return IFD_SUCCESS;
+ }
+
cmd[0] = 0x65; /* GetSlotStatus */
cmd[1] = cmd[2] = cmd[3] = cmd[4] = 0; /* dwLength */
cmd[5] = ccid_descriptor->bCurrentSlotIndex; /* slot number */
@@ -829,6 +1027,46 @@
_ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
status_t ret;
+ if (ICCD_A == ccid_descriptor->bInterfaceProtocol)
+ {
+ int r;
+
+ /* Xfr Block */
+ r = ControlUSB(reader_index, 0x21, 0x65, 0, tx_buffer, tx_length);
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Xfr Block failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ return IFD_SUCCESS;
+ }
+
+ if (ICCD_B == ccid_descriptor->bInterfaceProtocol)
+ {
+ int r;
+
+ /* nul block so we are chaining */
+ if (NULL == tx_buffer)
+ rx_length = 0x10; /* bLevelParameter */
+
+ /* Xfr Block */
+ DEBUG_COMM2("chain parameter: %d", rx_length);
+ r = ControlUSB(reader_index, 0x21, 0x65, rx_length << 8, tx_buffer,
+ tx_length);
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Xfr Block failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ return IFD_SUCCESS;
+ }
+
cmd[0] = 0x6F; /* XfrBlock */
i2dw(tx_length, cmd+1); /* APDU length */
cmd[5] = ccid_descriptor->bCurrentSlotIndex; /* slot number */
@@ -867,8 +1105,98 @@
unsigned char cmd[10+CMD_BUF_SIZE]; /* CCID + APDU buffer */
unsigned int length;
RESPONSECODE return_value = IFD_SUCCESS;
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
status_t ret;
+ if (ICCD_A == ccid_descriptor->bInterfaceProtocol)
+ {
+ int r;
+
+ /* Data Block */
+ r = ControlUSB(reader_index, 0xA1, 0x6F, 0, rx_buffer, *rx_length);
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Data Block failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ return IFD_SUCCESS;
+ }
+
+ if (ICCD_B == ccid_descriptor->bInterfaceProtocol)
+ {
+ int r;
+ unsigned char rx_tmp[4];
+
+ /* read a nul block. buffer need to be at least 4-bytes */
+ if (NULL == rx_buffer)
+ {
+ rx_buffer = rx_tmp;
+ *rx_length = sizeof(rx_tmp);
+ }
+
+time_request_ICCD_B:
+ /* Data Block */
+ r = ControlUSB(reader_index, 0xA1, 0x6F, 0, rx_buffer, *rx_length);
+
+ /* we got an error? */
+ if (r < 0)
+ {
+ DEBUG_INFO2("ICC Data Block failed: %s", strerror(errno));
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ /* bResponseType */
+ switch (rx_buffer[0])
+ {
+ case 0x00:
+ /* the abData field contains the information created by the
+ * preceding request */
+ break;
+
+ case 0x40:
+ /* Status Information */
+ ccid_error(rx_buffer[2], __FILE__, __LINE__, __FUNCTION__);
+ return IFD_COMMUNICATION_ERROR;
+
+ case 0x80:
+ /* Polling */
+ {
+ int delay;
+
+ delay = (rx_buffer[2] << 8) + rx_buffer[1];
+ DEBUG_COMM2("Pooling delay: %d", delay);
+
+ if (0 == delay)
+ /* host select the delay */
+ delay = 1;
+ usleep(delay * 1000 * 10);
+ goto time_request_ICCD_B;
+ }
+
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x10:
+ /* Extended case
+ * Only valid for Data Block frames */
+ if (chain_parameter)
+ *chain_parameter = rx_buffer[0];
+ break;
+
+ default:
+ DEBUG_CRITICAL2("Unknown bResponseType: 0x%02X", rx_buffer[0]);
+ return IFD_COMMUNICATION_ERROR;
+ }
+
+ memmove(rx_buffer, rx_buffer+1, r-1);
+ *rx_length = r-1;
+
+ return IFD_SUCCESS;
+ }
+
time_request:
length = sizeof(cmd);
ret = ReadPort(reader_index, &length, cmd);
@@ -960,6 +1288,15 @@
unsigned int local_rx_length, received_length;
int buffer_overflow = 0;
+ if (ICCD_B == ccid_descriptor->bInterfaceProtocol)
+ {
+ /* length is on 16-bits only
+ * if a size > 0x1000 is used then usb_control_msg() fails with
+ * "Invalid argument" */
+ if (*rx_length > 0x1000)
+ *rx_length = 0x1000;
+ }
+
DEBUG_COMM2("T=0 (extended): %d bytes", tx_length);
/* send the APDU */
@@ -1347,9 +1684,76 @@
unsigned int exp_len, in_len;
unsigned char ins, *in_buf;
RESPONSECODE return_value = IFD_SUCCESS;
+ _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index);
DEBUG_COMM2("T=0: %d bytes", snd_len);
+ if (ICCD_A == ccid_descriptor->bInterfaceProtocol)
+ {
+ unsigned char pcbuffer[SIZE_GET_SLOT_STATUS];
+
+ /* Command to send to the smart card (must be 5 bytes) */
+ memset(cmd, 0, sizeof(cmd));
+ if (snd_len == 4)
+ {
+ memcpy(cmd, snd_buf, 4);
+ snd_buf += 4;
+ snd_len -= 4;
+ }
+ else
+ {
+ memcpy(cmd, snd_buf, 5);
+ snd_buf += 5;
+ snd_len -= 5;
+ }
+
+ /* at most 5 bytes */
+ return_value = CCID_Transmit(reader_index, 5, cmd, 0, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ /* wait for ready */
+ return_value = CmdGetSlotStatus(reader_index, pcbuffer);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ if ((0x20 != pcbuffer[0]) && (snd_len > 0))
+ {
+ /* continue sending the APDU */
+ return_value = CCID_Transmit(reader_index, snd_len, snd_buf, 0, 0);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+ }
+ else
+ {
+ if ((0x20 == pcbuffer[0]) && (*rcv_len > 2))
+ /* we will just read SW1-SW2 */
+ *rcv_len = 2;
+
+ return_value = CCID_Receive(reader_index, rcv_len, rcv_buf, NULL);
+ if (return_value != IFD_SUCCESS)
+ DEBUG_CRITICAL("CCID_Receive failed");
+
+ return return_value;
+ }
+
+ /* wait for ready */
+ return_value = CmdGetSlotStatus(reader_index, pcbuffer);
+ if (return_value != IFD_SUCCESS)
+ return return_value;
+
+ if ((0x20 == pcbuffer[0]) && (*rcv_len > 2))
+ /* we will just read SW1-SW2 */
+ *rcv_len = 2;
+
+ /* read SW1-SW2 */
+ return_value = CCID_Receive(reader_index, rcv_len, rcv_buf, NULL);
+ if (return_value != IFD_SUCCESS)
+ DEBUG_CRITICAL("CCID_Receive failed");
+
+ return return_value;
+ }
+
in_buf = tmp_buf;
in_len = 0;
*rcv_len = 0;
More information about the Pcsclite-cvs-commit
mailing list