1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-06-09 23:39:51 +02:00

(parse_ccid_descriptor): SCR335 FW version 5.14 is

good.
(do_close_reader): Never do a reset. The caller should instead
make sure that the reader has been closed properly.  The new retry
code in ccid_slot_status will make sure that the readersatrts up
fine even if the last process didn't closed the USB connection
properly.
(ccid_get_atr): For certain readers try switching to ISO mode.
Thanks to Ludovic Rousseau for this hint and the magic numbers.
(print_command_failed): New.
(bulk_in): Use it here. Add new arg NO_DEBUG.
This commit is contained in:
Werner Koch 2005-05-23 14:17:22 +00:00
parent 05e1dc22f0
commit 487e419990
2 changed files with 119 additions and 22 deletions

View File

@ -1,3 +1,17 @@
2005-05-23 Werner Koch <wk@g10code.com>
* ccid-driver.c (parse_ccid_descriptor): SCR335 FW version 5.14 is
good.
(do_close_reader): Never do a reset. The caller should instead
make sure that the reader has been closed properly. The new retry
code in ccid_slot_status will make sure that the readersatrts up
fine even if the last process didn't closed the USB connection
properly.
(ccid_get_atr): For certain readers try switching to ISO mode.
Thanks to Ludovic Rousseau for this hint and the magic numbers.
(print_command_failed): New.
(bulk_in): Use it here. Add new arg NO_DEBUG.
2005-05-21 Werner Koch <wk@g10code.com> 2005-05-21 Werner Koch <wk@g10code.com>
* scdaemon.c (handle_signal): Print thread info on SIGUSR1. * scdaemon.c (handle_signal): Print thread info on SIGUSR1.

View File

@ -184,9 +184,18 @@ enum {
}; };
/* Two macro to detect whether a CCID command has failed and to get
the error code. These macros assume that we can access the
mandatory first 10 bytes of a CCID message in BUF. */
#define CCID_COMMAND_FAILED(buf) ((buf)[7] & 0x40)
#define CCID_ERROR_CODE(buf) (((unsigned char *)(buf))[8])
/* We need to know the vendor to do some hacks. */ /* We need to know the vendor to do some hacks. */
enum { enum {
VENDOR_SCM = 0x04e6 VENDOR_SCM = 0x04e6,
VENDOR_CHERRY = 0x046a,
VENDOR_GEMPC = 0x08e6
}; };
@ -228,7 +237,8 @@ static unsigned int compute_edc (const unsigned char *data, size_t datalen,
int use_crc); int use_crc);
static int bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen); static int bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen);
static int bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, static int bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
size_t *nread, int expected_type, int seqno, int timeout); size_t *nread, int expected_type, int seqno, int timeout,
int no_debug);
/* Convert a little endian stored 4 byte value into an unsigned /* Convert a little endian stored 4 byte value into an unsigned
integer. */ integer. */
@ -248,6 +258,53 @@ set_msg_len (unsigned char *msg, unsigned int length)
} }
/* Pint an error message for a failed CCID command including a textual
error code. MSG is shall be the CCID message of at least 10 bytes. */
static void
print_command_failed (const unsigned char *msg)
{
const char *t;
char buffer[100];
int ec;
if (!debug_level)
return;
ec = CCID_ERROR_CODE (msg);
switch (ec)
{
case 0x00: t = "Command not supported"; break;
case 0xE0: t = "Slot busy"; break;
case 0xEF: t = "PIN cancelled"; break;
case 0xF0: t = "PIN timeout"; break;
case 0xF2: t = "Automatic sequence ongoing"; break;
case 0xF3: t = "Deactivated Protocol"; break;
case 0xF4: t = "Procedure byte conflict"; break;
case 0xF5: t = "ICC class not supported"; break;
case 0xF6: t = "ICC protocol not supported"; break;
case 0xF7: t = "Bad checksum in ATR"; break;
case 0xF8: t = "Bad TS in ATR"; break;
case 0xFB: t = "An all inclusive hardware error occurred"; break;
case 0xFC: t = "Overrun error while talking to the ICC"; break;
case 0xFD: t = "Parity error while talking to the ICC"; break;
case 0xFE: t = "CCID timed out while talking to the ICC"; break;
case 0xFF: t = "Host aborted the current activity"; break;
default:
if (ec > 0 && ec < 128)
sprintf (buffer, "Parameter error at offset %d", ec);
else
sprintf (buffer, "Error code %02X", ec);
t = buffer;
break;
}
DEBUGOUT_1 ("CCID command failed: %s\n", t);
}
/* Parse a CCID descriptor, optionally print all available features /* Parse a CCID descriptor, optionally print all available features
@ -462,7 +519,7 @@ parse_ccid_descriptor (ccid_driver_t handle,
&& handle->max_ifsd > 48 && handle->max_ifsd > 48
&& ( (handle->id_product == 0xe001 && handle->bcd_device < 0x0516) && ( (handle->id_product == 0xe001 && handle->bcd_device < 0x0516)
||(handle->id_product == 0x5111 && handle->bcd_device < 0x0620) ||(handle->id_product == 0x5111 && handle->bcd_device < 0x0620)
||(handle->id_product == 0x5115 && handle->bcd_device < 0x0518) ||(handle->id_product == 0x5115 && handle->bcd_device < 0x0514)
||(handle->id_product == 0xe003 && handle->bcd_device < 0x0504) ||(handle->id_product == 0xe003 && handle->bcd_device < 0x0504)
)) ))
{ {
@ -987,13 +1044,11 @@ do_close_reader (ccid_driver_t handle)
rc = bulk_out (handle, msg, msglen); rc = bulk_out (handle, msg, msglen);
if (!rc) if (!rc)
bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus, bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus,
seqno, 2000); seqno, 2000, 0);
handle->powered_off = 1; handle->powered_off = 1;
} }
if (handle->idev) if (handle->idev)
{ {
if (getenv ("GNUPG_CCID_DRIVER_RESET_BEFORE_CLOSE"))
usb_reset (handle->idev);
usb_release_interface (handle->idev, handle->ifc_no); usb_release_interface (handle->idev, handle->ifc_no);
usb_close (handle->idev); usb_close (handle->idev);
handle->idev = NULL; handle->idev = NULL;
@ -1117,10 +1172,12 @@ bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen)
BUFFER and return the actual read number if bytes in NREAD. SEQNO BUFFER and return the actual read number if bytes in NREAD. SEQNO
is the sequence number used to send the request and EXPECTED_TYPE is the sequence number used to send the request and EXPECTED_TYPE
the type of message we expect. Does checks on the ccid the type of message we expect. Does checks on the ccid
header. TIMEOUT is the timeout value in ms. Returns 0 on success. */ header. TIMEOUT is the timeout value in ms. NO_DEBUG may be set to
avoid debug messages in case of no error. Returns 0 on success. */
static int static int
bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length, bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
size_t *nread, int expected_type, int seqno, int timeout) size_t *nread, int expected_type, int seqno, int timeout,
int no_debug)
{ {
int i, rc; int i, rc;
size_t msglen; size_t msglen;
@ -1170,13 +1227,19 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
buffer[7], buffer[8]); buffer[7], buffer[8]);
goto retry; goto retry;
} }
DEBUGOUT_3 ("status: %02X error: %02X octet[9]: %02X\n"
" data:", buffer[7], buffer[8], buffer[9] );
for (i=10; i < msglen; i++)
DEBUGOUT_CONT_1 (" %02X", buffer[i]);
DEBUGOUT_LF ();
if (!no_debug)
{
DEBUGOUT_3 ("status: %02X error: %02X octet[9]: %02X\n"
" data:", buffer[7], buffer[8], buffer[9] );
for (i=10; i < msglen; i++)
DEBUGOUT_CONT_1 (" %02X", buffer[i]);
DEBUGOUT_LF ();
}
if (CCID_COMMAND_FAILED (buffer))
print_command_failed (buffer);
/* Check whether a card is at all available. */
switch ((buffer[7] & 0x03)) switch ((buffer[7] & 0x03))
{ {
case 0: /* no error */ break; case 0: /* no error */ break;
@ -1220,7 +1283,7 @@ send_escape_cmd (ccid_driver_t handle,
if (rc) if (rc)
return rc; return rc;
rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Escape, rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Escape,
seqno, 5000); seqno, 5000, 0);
return rc; return rc;
} }
@ -1304,8 +1367,11 @@ ccid_slot_status (ccid_driver_t handle, int *statusbits)
rc = bulk_out (handle, msg, 10); rc = bulk_out (handle, msg, 10);
if (rc) if (rc)
return rc; return rc;
/* Note that we set the NO_DEBUG flag here, so that the logs won't
get cluttered up by a ticker function checking for the slot
status and debugging enabled. */
rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus, rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus,
seqno, retries? 1000 : 200); seqno, retries? 1000 : 200, 1);
if (rc == CCID_DRIVER_ERR_CARD_IO_ERROR && retries < 3) if (rc == CCID_DRIVER_ERR_CARD_IO_ERROR && retries < 3)
{ {
if (!retries) if (!retries)
@ -1341,6 +1407,7 @@ ccid_get_atr (ccid_driver_t handle,
int use_crc = 0; int use_crc = 0;
unsigned int edc; unsigned int edc;
int i; int i;
int tried_iso = 0;
/* First check whether a card is available. */ /* First check whether a card is available. */
rc = ccid_slot_status (handle, &statusbits); rc = ccid_slot_status (handle, &statusbits);
@ -1351,6 +1418,7 @@ ccid_get_atr (ccid_driver_t handle,
/* For an inactive and also for an active card, issue the PowerOn /* For an inactive and also for an active card, issue the PowerOn
command to get the ATR. */ command to get the ATR. */
again:
msg[0] = PC_to_RDR_IccPowerOn; msg[0] = PC_to_RDR_IccPowerOn;
msg[5] = 0; /* slot */ msg[5] = 0; /* slot */
msg[6] = seqno = handle->seqno++; msg[6] = seqno = handle->seqno++;
@ -1364,9 +1432,24 @@ ccid_get_atr (ccid_driver_t handle,
if (rc) if (rc)
return rc; return rc;
rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_DataBlock, rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_DataBlock,
seqno, 5000); seqno, 5000, 0);
if (rc) if (rc)
return rc; return rc;
if (!tried_iso && CCID_COMMAND_FAILED (msg) && CCID_ERROR_CODE (msg) == 0xbb
&& ((handle->id_vendor == VENDOR_CHERRY
&& handle->id_product == 0x0005)
|| (handle->id_vendor == VENDOR_GEMPC
&& handle->id_product == 0x4433)
))
{
tried_iso = 1;
/* Try switching to ISO mode. */
if (!send_escape_cmd (handle, "\xF1\x01", 2))
goto again;
}
else if (CCID_COMMAND_FAILED (msg))
return CCID_DRIVER_ERR_CARD_IO_ERROR;
handle->powered_off = 0; handle->powered_off = 0;
@ -1409,7 +1492,7 @@ ccid_get_atr (ccid_driver_t handle,
return rc; return rc;
/* Note that we ignore the error code on purpose. */ /* Note that we ignore the error code on purpose. */
bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters, bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters,
seqno, 5000); seqno, 5000, 0);
handle->t1_ns = 0; handle->t1_ns = 0;
handle->t1_nr = 0; handle->t1_nr = 0;
@ -1457,7 +1540,7 @@ ccid_get_atr (ccid_driver_t handle,
rc = bulk_in (handle, msg, sizeof msg, &msglen, rc = bulk_in (handle, msg, sizeof msg, &msglen,
RDR_to_PC_DataBlock, seqno, 5000); RDR_to_PC_DataBlock, seqno, 5000, 0);
if (rc) if (rc)
return rc; return rc;
@ -1554,7 +1637,7 @@ ccid_transceive_apdu_level (ccid_driver_t handle,
msg = recv_buffer; msg = recv_buffer;
rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen, rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen,
RDR_to_PC_DataBlock, seqno, 5000); RDR_to_PC_DataBlock, seqno, 5000, 0);
if (rc) if (rc)
return rc; return rc;
@ -1728,7 +1811,7 @@ ccid_transceive (ccid_driver_t handle,
msg = recv_buffer; msg = recv_buffer;
rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen, rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen,
RDR_to_PC_DataBlock, seqno, 5000); RDR_to_PC_DataBlock, seqno, 5000, 0);
if (rc) if (rc)
return rc; return rc;
@ -2005,7 +2088,7 @@ ccid_transceive_secure (ccid_driver_t handle,
msg = recv_buffer; msg = recv_buffer;
rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen, rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen,
RDR_to_PC_DataBlock, seqno, 5000); RDR_to_PC_DataBlock, seqno, 5000, 0);
if (rc) if (rc)
return rc; return rc;