[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