mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-09 12:54:23 +01:00
(parse_ccid_descriptor): Make SCM workaround
reader type specific. (scan_or_find_devices): Do not check the interface subclass in the SPR532 kludge, as this depends on the firmware version. (ccid_get_atr): Get the Slot status first. This solves the problem with readers hanging on recent Linux 2.6.x. (bulk_in): Add argument TIMEOUT and changed all callers to pass an appropriate one. Change the standard timeout from 10 to 5 seconds. (ccid_slot_status): Add a retry code with an initial short timeout. (do_close_reader): Do an usb_reset before closing the reader.
This commit is contained in:
parent
a90637513c
commit
8ba895c763
@ -1,3 +1,16 @@
|
|||||||
|
2005-03-16 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
|
* ccid-driver.c (parse_ccid_descriptor): Make SCM workaround
|
||||||
|
reader type specific.
|
||||||
|
(scan_or_find_devices): Do not check the interface subclass in the
|
||||||
|
SPR532 kludge, as this depends on the firmware version.
|
||||||
|
(ccid_get_atr): Get the Slot status first. This solves the
|
||||||
|
problem with readers hanging on recent Linux 2.6.x.
|
||||||
|
(bulk_in): Add argument TIMEOUT and changed all callers to pass an
|
||||||
|
appropriate one. Change the standard timeout from 10 to 5 seconds.
|
||||||
|
(ccid_slot_status): Add a retry code with an initial short timeout.
|
||||||
|
(do_close_reader): Do an usb_reset before closing the reader.
|
||||||
|
|
||||||
2005-03-14 Werner Koch <wk@g10code.com>
|
2005-03-14 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
* card-util.c (card_status): Use isotimestamp and not the
|
* card-util.c (card_status): Use isotimestamp and not the
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* ccid-driver.c - USB ChipCardInterfaceDevices driver
|
/* ccid-driver.c - USB ChipCardInterfaceDevices driver
|
||||||
* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
|
* Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
|
||||||
* Written by Werner Koch.
|
* Written by Werner Koch.
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
@ -52,7 +52,7 @@
|
|||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $Id$
|
* $Date$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@ -223,7 +223,7 @@ 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);
|
size_t *nread, int expected_type, int seqno, int timeout);
|
||||||
|
|
||||||
/* Convert a little endian stored 4 byte value into an unsigned
|
/* Convert a little endian stored 4 byte value into an unsigned
|
||||||
integer. */
|
integer. */
|
||||||
@ -403,7 +403,7 @@ parse_ccid_descriptor (ccid_driver_t handle,
|
|||||||
if (buf[49] == 0xff)
|
if (buf[49] == 0xff)
|
||||||
DEBUGOUT_CONT ("echo\n");
|
DEBUGOUT_CONT ("echo\n");
|
||||||
else
|
else
|
||||||
DEBUGOUT_1 (" %02X\n", buf[48]);
|
DEBUGOUT_CONT_1 (" %02X\n", buf[48]);
|
||||||
|
|
||||||
DEBUGOUT ( " wlcdLayout ");
|
DEBUGOUT ( " wlcdLayout ");
|
||||||
if (!buf[50] && !buf[51])
|
if (!buf[50] && !buf[51])
|
||||||
@ -446,12 +446,20 @@ parse_ccid_descriptor (ccid_driver_t handle,
|
|||||||
send a frame of n*wMaxPacketSize back to us. Given that
|
send a frame of n*wMaxPacketSize back to us. Given that
|
||||||
wMaxPacketSize is 64 for these readers we set the IFSD to a value
|
wMaxPacketSize is 64 for these readers we set the IFSD to a value
|
||||||
lower than that:
|
lower than that:
|
||||||
64 - 10 CCID header - 4 T1frame - 2 reserved = 48 */
|
64 - 10 CCID header - 4 T1frame - 2 reserved = 48
|
||||||
|
Product Ids:
|
||||||
|
0xe001 - SCR 331
|
||||||
|
0x5111 - SCR 331-DI
|
||||||
|
0x5115 - SCR 335
|
||||||
|
0xe003 - SPR 532
|
||||||
|
*/
|
||||||
if (handle->id_vendor == VENDOR_SCM
|
if (handle->id_vendor == VENDOR_SCM
|
||||||
/* FIXME: check whether it is the same
|
&& handle->max_ifsd > 48
|
||||||
firmware version for all drivers. */
|
&& ( (handle->id_product == 0xe001 && handle->bcd_device < 0x0516)
|
||||||
&& handle->bcd_device < 0x0519
|
||(handle->id_product == 0x5111 && handle->bcd_device < 0x0620)
|
||||||
&& handle->max_ifsd > 48)
|
||(handle->id_product == 0x5115 && handle->bcd_device < 0x0519)
|
||||||
|
||(handle->id_product == 0xe003 && handle->bcd_device < 0x0504)
|
||||||
|
))
|
||||||
{
|
{
|
||||||
DEBUGOUT ("enabling workaround for buggy SCM readers\n");
|
DEBUGOUT ("enabling workaround for buggy SCM readers\n");
|
||||||
handle->max_ifsd = 48;
|
handle->max_ifsd = 48;
|
||||||
@ -699,9 +707,7 @@ scan_or_find_devices (int readerno, const char *readerid,
|
|||||||
&& ifcdesc->bInterfaceProtocol == 0)
|
&& ifcdesc->bInterfaceProtocol == 0)
|
||||||
|| (ifcdesc->bInterfaceClass == 255
|
|| (ifcdesc->bInterfaceClass == 255
|
||||||
&& dev->descriptor.idVendor == 0x04e6
|
&& dev->descriptor.idVendor == 0x04e6
|
||||||
&& dev->descriptor.idProduct == 0xe003
|
&& dev->descriptor.idProduct == 0xe003)))
|
||||||
&& ifcdesc->bInterfaceSubClass == 1
|
|
||||||
&& ifcdesc->bInterfaceProtocol == 1)))
|
|
||||||
{
|
{
|
||||||
idev = usb_open (dev);
|
idev = usb_open (dev);
|
||||||
if (!idev)
|
if (!idev)
|
||||||
@ -974,11 +980,13 @@ 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,seqno);
|
bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus,
|
||||||
|
seqno, 2000);
|
||||||
handle->powered_off = 1;
|
handle->powered_off = 1;
|
||||||
}
|
}
|
||||||
if (handle->idev)
|
if (handle->idev)
|
||||||
{
|
{
|
||||||
|
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;
|
||||||
@ -1102,10 +1110,10 @@ 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. Returns 0 on success. */
|
header. TIMEOUT is the timeout value in ms. 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)
|
size_t *nread, int expected_type, int seqno, int timeout)
|
||||||
{
|
{
|
||||||
int i, rc;
|
int i, rc;
|
||||||
size_t msglen;
|
size_t msglen;
|
||||||
@ -1117,9 +1125,7 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
|
|||||||
rc = usb_bulk_read (handle->idev,
|
rc = usb_bulk_read (handle->idev,
|
||||||
handle->ep_bulk_in,
|
handle->ep_bulk_in,
|
||||||
buffer, length,
|
buffer, length,
|
||||||
10000 /* ms timeout */ );
|
timeout);
|
||||||
/* Fixme: instead of using a 10 second timeout we should better
|
|
||||||
handle the timeout here and retry if appropriate. */
|
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
{
|
{
|
||||||
DEBUGOUT_1 ("usb_bulk_read error: %s\n", strerror (errno));
|
DEBUGOUT_1 ("usb_bulk_read error: %s\n", strerror (errno));
|
||||||
@ -1175,7 +1181,7 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Note that this fucntion won't return the error codes NO_CARD or
|
/* Note that this function won't return the error codes NO_CARD or
|
||||||
CARD_INACTIVE */
|
CARD_INACTIVE */
|
||||||
static int
|
static int
|
||||||
send_escape_cmd (ccid_driver_t handle,
|
send_escape_cmd (ccid_driver_t handle,
|
||||||
@ -1206,7 +1212,8 @@ send_escape_cmd (ccid_driver_t handle,
|
|||||||
rc = bulk_out (handle, msg, msglen);
|
rc = bulk_out (handle, msg, msglen);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Escape, seqno);
|
rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Escape,
|
||||||
|
seqno, 5000);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -1276,7 +1283,9 @@ ccid_slot_status (ccid_driver_t handle, int *statusbits)
|
|||||||
unsigned char msg[100];
|
unsigned char msg[100];
|
||||||
size_t msglen;
|
size_t msglen;
|
||||||
unsigned char seqno;
|
unsigned char seqno;
|
||||||
|
int retries = 0;
|
||||||
|
|
||||||
|
retry:
|
||||||
msg[0] = PC_to_RDR_GetSlotStatus;
|
msg[0] = PC_to_RDR_GetSlotStatus;
|
||||||
msg[5] = 0; /* slot */
|
msg[5] = 0; /* slot */
|
||||||
msg[6] = seqno = handle->seqno++;
|
msg[6] = seqno = handle->seqno++;
|
||||||
@ -1288,7 +1297,21 @@ 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;
|
||||||
rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus, seqno);
|
rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus,
|
||||||
|
seqno, retries? 1000 : 200);
|
||||||
|
if (rc == CCID_DRIVER_ERR_CARD_IO_ERROR && retries < 3)
|
||||||
|
{
|
||||||
|
if (!retries)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "CALLING USB_CLEAR_HALT\n");
|
||||||
|
usb_clear_halt (handle->idev, handle->ep_bulk_in);
|
||||||
|
usb_clear_halt (handle->idev, handle->ep_bulk_out);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fprintf (stderr, "RETRYING AGIAN\n");
|
||||||
|
retries++;
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
if (rc && rc != CCID_DRIVER_ERR_NO_CARD
|
if (rc && rc != CCID_DRIVER_ERR_NO_CARD
|
||||||
&& rc != CCID_DRIVER_ERR_CARD_INACTIVE)
|
&& rc != CCID_DRIVER_ERR_CARD_INACTIVE)
|
||||||
return rc;
|
return rc;
|
||||||
@ -1303,6 +1326,7 @@ ccid_get_atr (ccid_driver_t handle,
|
|||||||
unsigned char *atr, size_t maxatrlen, size_t *atrlen)
|
unsigned char *atr, size_t maxatrlen, size_t *atrlen)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
int statusbits;
|
||||||
unsigned char msg[100];
|
unsigned char msg[100];
|
||||||
unsigned char *tpdu;
|
unsigned char *tpdu;
|
||||||
size_t msglen, tpdulen;
|
size_t msglen, tpdulen;
|
||||||
@ -1311,6 +1335,15 @@ ccid_get_atr (ccid_driver_t handle,
|
|||||||
unsigned int edc;
|
unsigned int edc;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
/* First check whether a card is available. */
|
||||||
|
rc = ccid_slot_status (handle, &statusbits);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
if (statusbits == 2)
|
||||||
|
return CCID_DRIVER_ERR_NO_CARD;
|
||||||
|
|
||||||
|
/* For an inactive and also for an active card, issue the PowerOn
|
||||||
|
command to get the ATR. */
|
||||||
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++;
|
||||||
@ -1323,7 +1356,8 @@ ccid_get_atr (ccid_driver_t handle,
|
|||||||
rc = bulk_out (handle, msg, msglen);
|
rc = bulk_out (handle, msg, msglen);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_DataBlock, seqno);
|
rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_DataBlock,
|
||||||
|
seqno, 5000);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
@ -1367,7 +1401,8 @@ ccid_get_atr (ccid_driver_t handle,
|
|||||||
if (rc)
|
if (rc)
|
||||||
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, seqno);
|
bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters,
|
||||||
|
seqno, 5000);
|
||||||
|
|
||||||
handle->t1_ns = 0;
|
handle->t1_ns = 0;
|
||||||
handle->t1_nr = 0;
|
handle->t1_nr = 0;
|
||||||
@ -1414,7 +1449,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);
|
RDR_to_PC_DataBlock, seqno, 5000);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
@ -1510,7 +1545,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);
|
RDR_to_PC_DataBlock, seqno, 5000);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
@ -1683,7 +1718,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);
|
RDR_to_PC_DataBlock, seqno, 5000);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
@ -1692,7 +1727,7 @@ ccid_transceive (ccid_driver_t handle,
|
|||||||
|
|
||||||
if (tpdulen < 4)
|
if (tpdulen < 4)
|
||||||
{
|
{
|
||||||
usb_clear_halt (handle->idev, 0x82);
|
usb_clear_halt (handle->idev, handle->ep_bulk_in);
|
||||||
return CCID_DRIVER_ERR_ABORTED;
|
return CCID_DRIVER_ERR_ABORTED;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_T1
|
#ifdef DEBUG_T1
|
||||||
@ -1960,7 +1995,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);
|
RDR_to_PC_DataBlock, seqno, 5000);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user