mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-03 12:11:33 +01:00
Support for CardMan 4040
This commit is contained in:
parent
dfaee3d480
commit
a5465705fb
@ -1,3 +1,18 @@
|
|||||||
|
2006-02-02 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
|
* ccid-driver.c (special_transport): New
|
||||||
|
(ccid_open_reader, do_close_reader, ccid_shutdown_reader)
|
||||||
|
(bulk_out, bulk_in): Add support for CardMan 4040 reader.
|
||||||
|
|
||||||
|
* ccid-driver.c (scan_or_find_devices): Factored most code out to
|
||||||
|
(scan_or_find_usb_device): .. new.
|
||||||
|
(make_reader_id): Fixed vendor mask.
|
||||||
|
|
||||||
|
2006-01-01 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
|
* app-openpgp.c (do_sign): Give user error if hash algorithm is
|
||||||
|
not supported by the card.
|
||||||
|
|
||||||
2005-12-06 Werner Koch <wk@g10code.com>
|
2005-12-06 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
* apdu.c (open_pcsc_reader): Check that pcsc-wrapper is actually
|
* apdu.c (open_pcsc_reader): Check that pcsc-wrapper is actually
|
||||||
|
@ -484,7 +484,7 @@ count_bits (const unsigned char *a, size_t len)
|
|||||||
Everything up to a LF is considered a mailbox or account name. If
|
Everything up to a LF is considered a mailbox or account name. If
|
||||||
the first LF is followed by DC4 (0x14) control sequence are
|
the first LF is followed by DC4 (0x14) control sequence are
|
||||||
expected up to the next LF. Control sequences are separated by FS
|
expected up to the next LF. Control sequences are separated by FS
|
||||||
(0x28) and consist of key=value pairs. There is one key defined:
|
(0x18) and consist of key=value pairs. There is one key defined:
|
||||||
|
|
||||||
F=<flags>
|
F=<flags>
|
||||||
|
|
||||||
@ -2084,7 +2084,7 @@ check_against_given_fingerprint (app_t app, const char *fpr, int keyno)
|
|||||||
raw message digest. For this application the KEYIDSTR consists of
|
raw message digest. For this application the KEYIDSTR consists of
|
||||||
the serialnumber and the fingerprint delimited by a slash.
|
the serialnumber and the fingerprint delimited by a slash.
|
||||||
|
|
||||||
Note that this fucntion may return the error code
|
Note that this function may return the error code
|
||||||
GPG_ERR_WRONG_CARD to indicate that the card currently present does
|
GPG_ERR_WRONG_CARD to indicate that the card currently present does
|
||||||
not match the one required for the requested action (e.g. the
|
not match the one required for the requested action (e.g. the
|
||||||
serial number does not match). */
|
serial number does not match). */
|
||||||
@ -2120,7 +2120,11 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
|
|||||||
&& !memcmp (indata, rmd160_prefix, 15))
|
&& !memcmp (indata, rmd160_prefix, 15))
|
||||||
;
|
;
|
||||||
else
|
else
|
||||||
return gpg_error (GPG_ERR_INV_VALUE);
|
{
|
||||||
|
log_error (_("card does not support digest algorithm %s\n"),
|
||||||
|
gcry_md_algo_name (hashalgo));
|
||||||
|
return gpg_error (GPG_ERR_INV_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
/* Check whether an OpenPGP card of any version has been requested. */
|
/* Check whether an OpenPGP card of any version has been requested. */
|
||||||
if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12))
|
if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12))
|
||||||
|
@ -67,8 +67,8 @@
|
|||||||
portable access to USB.
|
portable access to USB.
|
||||||
|
|
||||||
This driver has been tested with the SCM SCR335 and SPR532
|
This driver has been tested with the SCM SCR335 and SPR532
|
||||||
smartcard readers and requires that a reader implements the TPDU
|
smartcard readers and requires that a reader implements APDU or
|
||||||
level exchange and does fully automatic initialization.
|
TPDU level exchange and does fully automatic initialization.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
@ -82,6 +82,9 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
#include <usb.h>
|
#include <usb.h>
|
||||||
|
|
||||||
@ -194,11 +197,29 @@ enum {
|
|||||||
|
|
||||||
/* 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_CHERRY = 0x046a,
|
VENDOR_CHERRY = 0x046a,
|
||||||
|
VENDOR_SCM = 0x04e6,
|
||||||
|
VENDOR_OMNIKEY= 0x076b,
|
||||||
VENDOR_GEMPC = 0x08e6
|
VENDOR_GEMPC = 0x08e6
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* A list and a table with special transport descriptions. */
|
||||||
|
enum {
|
||||||
|
TRANSPORT_USB = 0, /* Standard USB transport. */
|
||||||
|
TRANSPORT_CM4040 = 1 /* As used by the Cardman 4040. */
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
char *name; /* Device name. */
|
||||||
|
int type;
|
||||||
|
|
||||||
|
} transports[] = {
|
||||||
|
{ "/dev/cmx0", TRANSPORT_CM4040 },
|
||||||
|
{ "/dev/cmx1", TRANSPORT_CM4040 },
|
||||||
|
{ NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Store information on the driver's state. A pointer to such a
|
/* Store information on the driver's state. A pointer to such a
|
||||||
structure is used as handle for most functions. */
|
structure is used as handle for most functions. */
|
||||||
@ -206,6 +227,8 @@ struct ccid_driver_s
|
|||||||
{
|
{
|
||||||
usb_dev_handle *idev;
|
usb_dev_handle *idev;
|
||||||
char *rid;
|
char *rid;
|
||||||
|
int dev_fd; /* -1 for USB transport or file descriptor of the
|
||||||
|
transport device. */
|
||||||
unsigned short id_vendor;
|
unsigned short id_vendor;
|
||||||
unsigned short id_product;
|
unsigned short id_product;
|
||||||
unsigned short bcd_device;
|
unsigned short bcd_device;
|
||||||
@ -306,7 +329,34 @@ print_command_failed (const unsigned char *msg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Given a handle used for special transport prepare it for use. In
|
||||||
|
particular setup all information in way that resembles what
|
||||||
|
parse_cccid_descriptor does. */
|
||||||
|
static void
|
||||||
|
prepare_special_transport (ccid_driver_t handle)
|
||||||
|
{
|
||||||
|
assert (!handle->id_vendor);
|
||||||
|
|
||||||
|
handle->nonnull_nad = 0;
|
||||||
|
handle->auto_ifsd = 0;
|
||||||
|
handle->max_ifsd = 32;
|
||||||
|
handle->ifsd = 0;
|
||||||
|
handle->has_pinpad = 0;
|
||||||
|
handle->apdu_level = 0;
|
||||||
|
switch (handle->id_product)
|
||||||
|
{
|
||||||
|
case TRANSPORT_CM4040:
|
||||||
|
DEBUGOUT ("setting up transport for CardMan 4040\n");
|
||||||
|
/* Most values are guessed. */
|
||||||
|
handle->nonnull_nad = 1;
|
||||||
|
handle->auto_ifsd = 1;
|
||||||
|
handle->max_ifsd = 254;
|
||||||
|
handle->apdu_level = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: assert (!"transport not defined");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Parse a CCID descriptor, optionally print all available features
|
/* Parse a CCID descriptor, optionally print all available features
|
||||||
and test whether this reader is usable by this driver. Returns 0
|
and test whether this reader is usable by this driver. Returns 0
|
||||||
@ -615,7 +665,7 @@ make_reader_id (usb_dev_handle *idev,
|
|||||||
char *rid;
|
char *rid;
|
||||||
char prefix[20];
|
char prefix[20];
|
||||||
|
|
||||||
sprintf (prefix, "%04X:%04X:", (vendor & 0xfff), (product & 0xffff));
|
sprintf (prefix, "%04X:%04X:", (vendor & 0xffff), (product & 0xffff));
|
||||||
rid = get_escaped_usb_string (idev, serialno_index, prefix, ":0");
|
rid = get_escaped_usb_string (idev, serialno_index, prefix, ":0");
|
||||||
if (!rid)
|
if (!rid)
|
||||||
{
|
{
|
||||||
@ -658,10 +708,177 @@ find_endpoint (struct usb_interface_descriptor *ifcdesc, int mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Helper for scan_or_find_devices. This function returns true if a
|
||||||
|
requested device has been found or the caller should stop scanning
|
||||||
|
for other reasons. */
|
||||||
|
static int
|
||||||
|
scan_or_find_usb_device (int scan_mode,
|
||||||
|
int *readerno, int *count, char **rid_list,
|
||||||
|
const char *readerid,
|
||||||
|
struct usb_device *dev,
|
||||||
|
char **r_rid,
|
||||||
|
struct usb_device **r_dev,
|
||||||
|
usb_dev_handle **r_idev,
|
||||||
|
unsigned char **ifcdesc_extra,
|
||||||
|
size_t *ifcdesc_extra_len,
|
||||||
|
int *interface_number,
|
||||||
|
int *ep_bulk_out, int *ep_bulk_in, int *ep_intr)
|
||||||
|
{
|
||||||
|
int cfg_no;
|
||||||
|
int ifc_no;
|
||||||
|
int set_no;
|
||||||
|
struct usb_config_descriptor *config;
|
||||||
|
struct usb_interface *interface;
|
||||||
|
struct usb_interface_descriptor *ifcdesc;
|
||||||
|
char *rid;
|
||||||
|
usb_dev_handle *idev;
|
||||||
|
|
||||||
|
*r_idev = NULL;
|
||||||
|
|
||||||
|
for (cfg_no=0; cfg_no < dev->descriptor.bNumConfigurations; cfg_no++)
|
||||||
|
{
|
||||||
|
config = dev->config + cfg_no;
|
||||||
|
if(!config)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (ifc_no=0; ifc_no < config->bNumInterfaces; ifc_no++)
|
||||||
|
{
|
||||||
|
interface = config->interface + ifc_no;
|
||||||
|
if (!interface)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (set_no=0; set_no < interface->num_altsetting; set_no++)
|
||||||
|
{
|
||||||
|
ifcdesc = (interface->altsetting + set_no);
|
||||||
|
/* The second condition is for older SCM SPR 532 who did
|
||||||
|
not know about the assigned CCID class. Instead of
|
||||||
|
trying to interpret the strings we simply check the
|
||||||
|
product ID. */
|
||||||
|
if (ifcdesc && ifcdesc->extra
|
||||||
|
&& ((ifcdesc->bInterfaceClass == 11
|
||||||
|
&& ifcdesc->bInterfaceSubClass == 0
|
||||||
|
&& ifcdesc->bInterfaceProtocol == 0)
|
||||||
|
|| (ifcdesc->bInterfaceClass == 255
|
||||||
|
&& dev->descriptor.idVendor == VENDOR_SCM
|
||||||
|
&& dev->descriptor.idProduct == 0xe003)))
|
||||||
|
{
|
||||||
|
idev = usb_open (dev);
|
||||||
|
if (!idev)
|
||||||
|
{
|
||||||
|
DEBUGOUT_1 ("usb_open failed: %s\n",
|
||||||
|
strerror (errno));
|
||||||
|
continue; /* with next setting. */
|
||||||
|
}
|
||||||
|
|
||||||
|
rid = make_reader_id (idev,
|
||||||
|
dev->descriptor.idVendor,
|
||||||
|
dev->descriptor.idProduct,
|
||||||
|
dev->descriptor.iSerialNumber);
|
||||||
|
if (rid)
|
||||||
|
{
|
||||||
|
if (scan_mode)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
/* We are collecting infos about all
|
||||||
|
available CCID readers. Store them and
|
||||||
|
continue. */
|
||||||
|
DEBUGOUT_2 ("found CCID reader %d (ID=%s)\n",
|
||||||
|
*count, rid );
|
||||||
|
p = malloc ((*rid_list? strlen (*rid_list):0) + 1
|
||||||
|
+ strlen (rid) + 1);
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
*p = 0;
|
||||||
|
if (*rid_list)
|
||||||
|
{
|
||||||
|
strcat (p, *rid_list);
|
||||||
|
free (*rid_list);
|
||||||
|
}
|
||||||
|
strcat (p, rid);
|
||||||
|
strcat (p, "\n");
|
||||||
|
*rid_list = p;
|
||||||
|
}
|
||||||
|
else /* Out of memory. */
|
||||||
|
free (rid);
|
||||||
|
|
||||||
|
rid = NULL;
|
||||||
|
++*count;
|
||||||
|
}
|
||||||
|
else if (!*readerno
|
||||||
|
|| (*readerno < 0
|
||||||
|
&& readerid
|
||||||
|
&& !strcmp (readerid, rid)))
|
||||||
|
{
|
||||||
|
/* We found the requested reader. */
|
||||||
|
if (ifcdesc_extra && ifcdesc_extra_len)
|
||||||
|
{
|
||||||
|
*ifcdesc_extra = malloc (ifcdesc
|
||||||
|
->extralen);
|
||||||
|
if (!*ifcdesc_extra)
|
||||||
|
{
|
||||||
|
usb_close (idev);
|
||||||
|
free (rid);
|
||||||
|
return 1; /* Out of core. */
|
||||||
|
}
|
||||||
|
memcpy (*ifcdesc_extra, ifcdesc->extra,
|
||||||
|
ifcdesc->extralen);
|
||||||
|
*ifcdesc_extra_len = ifcdesc->extralen;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (interface_number)
|
||||||
|
*interface_number = (ifcdesc->bInterfaceNumber);
|
||||||
|
|
||||||
|
if (ep_bulk_out)
|
||||||
|
*ep_bulk_out = find_endpoint (ifcdesc, 0);
|
||||||
|
if (ep_bulk_in)
|
||||||
|
*ep_bulk_in = find_endpoint (ifcdesc, 1);
|
||||||
|
if (ep_intr)
|
||||||
|
*ep_intr = find_endpoint (ifcdesc, 2);
|
||||||
|
|
||||||
|
if (r_dev)
|
||||||
|
*r_dev = dev;
|
||||||
|
if (r_rid)
|
||||||
|
{
|
||||||
|
*r_rid = rid;
|
||||||
|
rid = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
free (rid);
|
||||||
|
|
||||||
|
*r_idev = idev;
|
||||||
|
return 1; /* Found requested device. */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* This is not yet the reader we want.
|
||||||
|
fixme: We should avoid the extra usb_open
|
||||||
|
in this case. */
|
||||||
|
if (*readerno >= 0)
|
||||||
|
--*readerno;
|
||||||
|
}
|
||||||
|
free (rid);
|
||||||
|
}
|
||||||
|
|
||||||
|
usb_close (idev);
|
||||||
|
idev = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Combination function to either scan all CCID devices or to find and
|
/* Combination function to either scan all CCID devices or to find and
|
||||||
open one specific device.
|
open one specific device.
|
||||||
|
|
||||||
|
The function returns 0 if a reader has been found or when a scan
|
||||||
|
returned without error.
|
||||||
|
|
||||||
|
FIXME!!
|
||||||
|
|
||||||
With READERNO = -1 and READERID is NULL, scan mode is used and
|
With READERNO = -1 and READERID is NULL, scan mode is used and
|
||||||
R_RID should be the address where to store the list of reader_ids
|
R_RID should be the address where to store the list of reader_ids
|
||||||
we found. If on return this list is empty, no CCID device has been
|
we found. If on return this list is empty, no CCID device has been
|
||||||
@ -671,11 +888,11 @@ find_endpoint (struct usb_interface_descriptor *ifcdesc, int mode)
|
|||||||
With READERNO >= 0 or READERID is not NULL find mode is used. This
|
With READERNO >= 0 or READERID is not NULL find mode is used. This
|
||||||
uses the same algorithm as the scan mode but stops and returns at
|
uses the same algorithm as the scan mode but stops and returns at
|
||||||
the entry number READERNO and return the handle for the the opened
|
the entry number READERNO and return the handle for the the opened
|
||||||
USB device. If R_ID is not NULL it will receive the reader ID of
|
USB device. If R_RID is not NULL it will receive the reader ID of
|
||||||
that device. If R_DEV is not NULL it will the device pointer of
|
that device. If R_DEV is not NULL it will the device pointer of
|
||||||
that device. If IFCDESC_EXTRA is NOT NULL it will receive a
|
that device. If IFCDESC_EXTRA is NOT NULL it will receive a
|
||||||
malloced copy of the interfaces "extra: data filed;
|
malloced copy of the interfaces "extra: data filed;
|
||||||
IFCDESC_EXTRA_LEN receive the lengtyh of this field. If there is
|
IFCDESC_EXTRA_LEN receive the length of this field. If there is
|
||||||
no reader with number READERNO or that reader is not usable by our
|
no reader with number READERNO or that reader is not usable by our
|
||||||
implementation NULL will be returned. The caller must close a
|
implementation NULL will be returned. The caller must close a
|
||||||
returned USB device handle and free (if not passed as NULL) the
|
returned USB device handle and free (if not passed as NULL) the
|
||||||
@ -684,17 +901,25 @@ find_endpoint (struct usb_interface_descriptor *ifcdesc, int mode)
|
|||||||
IFCDESC_EXTRA_LEN. With READERID being -1 the function stops if
|
IFCDESC_EXTRA_LEN. With READERID being -1 the function stops if
|
||||||
the READERID was found.
|
the READERID was found.
|
||||||
|
|
||||||
|
If R_FD is not -1 on return the device is not using USB for
|
||||||
|
transport but the device associated with that file descriptor. In
|
||||||
|
this case INTERFACE will receive the transport type and the other
|
||||||
|
USB specific return values are not used; the return value is
|
||||||
|
(void*)(1).
|
||||||
|
|
||||||
Note that the first entry of the returned reader ID list in scan mode
|
Note that the first entry of the returned reader ID list in scan mode
|
||||||
corresponds with a READERNO of 0 in find mode.
|
corresponds with a READERNO of 0 in find mode.
|
||||||
*/
|
*/
|
||||||
static usb_dev_handle *
|
static int
|
||||||
scan_or_find_devices (int readerno, const char *readerid,
|
scan_or_find_devices (int readerno, const char *readerid,
|
||||||
char **r_rid,
|
char **r_rid,
|
||||||
struct usb_device **r_dev,
|
struct usb_device **r_dev,
|
||||||
unsigned char **ifcdesc_extra,
|
unsigned char **ifcdesc_extra,
|
||||||
size_t *ifcdesc_extra_len,
|
size_t *ifcdesc_extra_len,
|
||||||
int *interface_number,
|
int *interface_number,
|
||||||
int *ep_bulk_out, int *ep_bulk_in, int *ep_intr)
|
int *ep_bulk_out, int *ep_bulk_in, int *ep_intr,
|
||||||
|
usb_dev_handle **r_idev,
|
||||||
|
int *r_fd)
|
||||||
{
|
{
|
||||||
char *rid_list = NULL;
|
char *rid_list = NULL;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
@ -702,8 +927,9 @@ scan_or_find_devices (int readerno, const char *readerid,
|
|||||||
struct usb_device *dev = NULL;
|
struct usb_device *dev = NULL;
|
||||||
usb_dev_handle *idev = NULL;
|
usb_dev_handle *idev = NULL;
|
||||||
int scan_mode = (readerno == -1 && !readerid);
|
int scan_mode = (readerno == -1 && !readerid);
|
||||||
|
int i;
|
||||||
|
|
||||||
/* Set return values to a default. */
|
/* Set return values to a default. */
|
||||||
if (r_rid)
|
if (r_rid)
|
||||||
*r_rid = NULL;
|
*r_rid = NULL;
|
||||||
if (r_dev)
|
if (r_dev)
|
||||||
@ -714,6 +940,10 @@ scan_or_find_devices (int readerno, const char *readerid,
|
|||||||
*ifcdesc_extra_len = 0;
|
*ifcdesc_extra_len = 0;
|
||||||
if (interface_number)
|
if (interface_number)
|
||||||
*interface_number = 0;
|
*interface_number = 0;
|
||||||
|
if (r_idev)
|
||||||
|
*r_idev = NULL;
|
||||||
|
if (r_fd)
|
||||||
|
*r_fd = -1;
|
||||||
|
|
||||||
/* See whether we want scan or find mode. */
|
/* See whether we want scan or find mode. */
|
||||||
if (scan_mode)
|
if (scan_mode)
|
||||||
@ -734,161 +964,102 @@ scan_or_find_devices (int readerno, const char *readerid,
|
|||||||
{
|
{
|
||||||
for (dev = bus->devices; dev; dev = dev->next)
|
for (dev = bus->devices; dev; dev = dev->next)
|
||||||
{
|
{
|
||||||
int cfg_no;
|
if (scan_or_find_usb_device (scan_mode, &readerno, &count, &rid_list,
|
||||||
|
readerid,
|
||||||
for (cfg_no=0; cfg_no < dev->descriptor.bNumConfigurations; cfg_no++)
|
dev,
|
||||||
|
r_rid,
|
||||||
|
r_dev,
|
||||||
|
&idev,
|
||||||
|
ifcdesc_extra,
|
||||||
|
ifcdesc_extra_len,
|
||||||
|
interface_number,
|
||||||
|
ep_bulk_out, ep_bulk_in, ep_intr))
|
||||||
{
|
{
|
||||||
struct usb_config_descriptor *config = dev->config + cfg_no;
|
/* Found requested device or out of core. */
|
||||||
int ifc_no;
|
if (!idev)
|
||||||
|
|
||||||
if(!config)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (ifc_no=0; ifc_no < config->bNumInterfaces; ifc_no++)
|
|
||||||
{
|
{
|
||||||
struct usb_interface *interface
|
free (rid_list);
|
||||||
= config->interface + ifc_no;
|
return -1; /* error */
|
||||||
int set_no;
|
|
||||||
|
|
||||||
if (!interface)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
for (set_no=0; set_no < interface->num_altsetting; set_no++)
|
|
||||||
{
|
|
||||||
struct usb_interface_descriptor *ifcdesc
|
|
||||||
= interface->altsetting + set_no;
|
|
||||||
char *rid;
|
|
||||||
|
|
||||||
/* The second condition is for some SCM Micro
|
|
||||||
SPR 532 which does not know about the
|
|
||||||
assigned CCID class. Instead of trying to
|
|
||||||
interpret the strings we simply look at the
|
|
||||||
product ID. */
|
|
||||||
if (ifcdesc && ifcdesc->extra
|
|
||||||
&& ( (ifcdesc->bInterfaceClass == 11
|
|
||||||
&& ifcdesc->bInterfaceSubClass == 0
|
|
||||||
&& ifcdesc->bInterfaceProtocol == 0)
|
|
||||||
|| (ifcdesc->bInterfaceClass == 255
|
|
||||||
&& dev->descriptor.idVendor == 0x04e6
|
|
||||||
&& dev->descriptor.idProduct == 0xe003)))
|
|
||||||
{
|
|
||||||
idev = usb_open (dev);
|
|
||||||
if (!idev)
|
|
||||||
{
|
|
||||||
DEBUGOUT_1 ("usb_open failed: %s\n",
|
|
||||||
strerror (errno));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
rid = make_reader_id (idev,
|
|
||||||
dev->descriptor.idVendor,
|
|
||||||
dev->descriptor.idProduct,
|
|
||||||
dev->descriptor.iSerialNumber);
|
|
||||||
if (rid)
|
|
||||||
{
|
|
||||||
if (scan_mode)
|
|
||||||
{
|
|
||||||
char *p;
|
|
||||||
|
|
||||||
/* We are collecting infos about all
|
|
||||||
available CCID readers. Store
|
|
||||||
them and continue. */
|
|
||||||
DEBUGOUT_2 ("found CCID reader %d "
|
|
||||||
"(ID=%s)\n",
|
|
||||||
count, rid );
|
|
||||||
if ((p = malloc ((rid_list?
|
|
||||||
strlen (rid_list):0)
|
|
||||||
+ 1 + strlen (rid)
|
|
||||||
+ 1)))
|
|
||||||
{
|
|
||||||
*p = 0;
|
|
||||||
if (rid_list)
|
|
||||||
{
|
|
||||||
strcat (p, rid_list);
|
|
||||||
free (rid_list);
|
|
||||||
}
|
|
||||||
strcat (p, rid);
|
|
||||||
strcat (p, "\n");
|
|
||||||
rid_list = p;
|
|
||||||
}
|
|
||||||
else /* Out of memory. */
|
|
||||||
free (rid);
|
|
||||||
rid = NULL;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
else if (!readerno
|
|
||||||
|| (readerno < 0
|
|
||||||
&& readerid
|
|
||||||
&& !strcmp (readerid, rid)))
|
|
||||||
{
|
|
||||||
/* We found the requested reader. */
|
|
||||||
if (ifcdesc_extra && ifcdesc_extra_len)
|
|
||||||
{
|
|
||||||
*ifcdesc_extra = malloc (ifcdesc
|
|
||||||
->extralen);
|
|
||||||
if (!*ifcdesc_extra)
|
|
||||||
{
|
|
||||||
usb_close (idev);
|
|
||||||
free (rid);
|
|
||||||
return NULL; /* Out of core. */
|
|
||||||
}
|
|
||||||
memcpy (*ifcdesc_extra, ifcdesc->extra,
|
|
||||||
ifcdesc->extralen);
|
|
||||||
*ifcdesc_extra_len = ifcdesc->extralen;
|
|
||||||
}
|
|
||||||
if (interface_number)
|
|
||||||
*interface_number = (ifcdesc->
|
|
||||||
bInterfaceNumber);
|
|
||||||
if (ep_bulk_out)
|
|
||||||
*ep_bulk_out = find_endpoint (ifcdesc, 0);
|
|
||||||
if (ep_bulk_in)
|
|
||||||
*ep_bulk_in = find_endpoint (ifcdesc, 1);
|
|
||||||
if (ep_intr)
|
|
||||||
*ep_intr = find_endpoint (ifcdesc, 2);
|
|
||||||
|
|
||||||
|
|
||||||
if (r_dev)
|
|
||||||
*r_dev = dev;
|
|
||||||
if (r_rid)
|
|
||||||
{
|
|
||||||
*r_rid = rid;
|
|
||||||
rid = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
free (rid);
|
|
||||||
return idev; /* READY. */
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* This is not yet the reader we
|
|
||||||
want. fixme: We could avoid the
|
|
||||||
extra usb_open in this case. */
|
|
||||||
if (readerno >= 0)
|
|
||||||
readerno--;
|
|
||||||
}
|
|
||||||
free (rid);
|
|
||||||
}
|
|
||||||
|
|
||||||
usb_close (idev);
|
|
||||||
idev = NULL;
|
|
||||||
goto next_device;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
*r_idev = idev;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
next_device:
|
|
||||||
;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scan_mode)
|
/* Now check whether there are any devices with special transport types. */
|
||||||
*r_rid = rid_list;
|
for (i=0; transports[i].name; i++)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
char *rid, *p;
|
||||||
|
|
||||||
return NULL;
|
fd = open (transports[i].name, O_RDWR);
|
||||||
|
if (fd == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
rid = malloc (strlen (transports[i].name) + 30 + 10);
|
||||||
|
if (!rid)
|
||||||
|
{
|
||||||
|
close (fd);
|
||||||
|
free (rid_list);
|
||||||
|
return -1; /* Error. */
|
||||||
|
}
|
||||||
|
sprintf (rid, "0000:%04X:%s:0", transports[i].type, transports[i].name);
|
||||||
|
if (scan_mode)
|
||||||
|
{
|
||||||
|
DEBUGOUT_2 ("found CCID reader %d (ID=%s)\n", count, rid);
|
||||||
|
p = malloc ((rid_list? strlen (rid_list):0) + 1 + strlen (rid) + 1);
|
||||||
|
if (!p)
|
||||||
|
{
|
||||||
|
close (fd);
|
||||||
|
free (rid_list);
|
||||||
|
free (rid);
|
||||||
|
return -1; /* Error. */
|
||||||
|
}
|
||||||
|
*p = 0;
|
||||||
|
if (rid_list)
|
||||||
|
{
|
||||||
|
strcat (p, rid_list);
|
||||||
|
free (rid_list);
|
||||||
|
}
|
||||||
|
strcat (p, rid);
|
||||||
|
strcat (p, "\n");
|
||||||
|
rid_list = p;
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
else if (!readerno ||
|
||||||
|
(readerno < 0 && readerid && !strcmp (readerid, rid)))
|
||||||
|
{
|
||||||
|
/* Found requested device. */
|
||||||
|
if (interface_number)
|
||||||
|
*interface_number = transports[i].type;
|
||||||
|
if (r_rid)
|
||||||
|
*r_rid = rid;
|
||||||
|
else
|
||||||
|
free (rid);
|
||||||
|
*r_fd = fd;
|
||||||
|
return 0; /* Okay, found device */
|
||||||
|
}
|
||||||
|
else /* This is not yet the reader we want. */
|
||||||
|
{
|
||||||
|
if (readerno >= 0)
|
||||||
|
--readerno;
|
||||||
|
}
|
||||||
|
free (rid);
|
||||||
|
close (fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scan_mode)
|
||||||
|
{
|
||||||
|
*r_rid = rid_list;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Set the level of debugging to to usea dn return the old level. -1
|
/* Set the level of debugging to LEVEL and return the old level. -1
|
||||||
just returns the old level. A level of 0 disables debugging, 1
|
just returns the old level. A level of 0 disables debugging, 1
|
||||||
enables debugging, 2 enables additional tracing of the T=1
|
enables debugging, 2 enables additional tracing of the T=1
|
||||||
protocol, other values are not yet defined. */
|
protocol, other values are not yet defined. */
|
||||||
@ -913,8 +1084,9 @@ ccid_get_reader_list (void)
|
|||||||
initialized_usb = 1;
|
initialized_usb = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
scan_or_find_devices (-1, NULL, &reader_list, NULL, NULL, NULL, NULL,
|
if (scan_or_find_devices (-1, NULL, &reader_list, NULL, NULL, NULL, NULL,
|
||||||
NULL, NULL, NULL);
|
NULL, NULL, NULL, NULL, NULL))
|
||||||
|
return NULL; /* Error. */
|
||||||
return reader_list;
|
return reader_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -927,6 +1099,7 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
|
|||||||
int rc = 0;
|
int rc = 0;
|
||||||
struct usb_device *dev = NULL;
|
struct usb_device *dev = NULL;
|
||||||
usb_dev_handle *idev = NULL;
|
usb_dev_handle *idev = NULL;
|
||||||
|
int dev_fd = -1;
|
||||||
char *rid = NULL;
|
char *rid = NULL;
|
||||||
unsigned char *ifcdesc_extra = NULL;
|
unsigned char *ifcdesc_extra = NULL;
|
||||||
size_t ifcdesc_extra_len;
|
size_t ifcdesc_extra_len;
|
||||||
@ -959,10 +1132,10 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
|
|||||||
else
|
else
|
||||||
readerno = 0; /* Default. */
|
readerno = 0; /* Default. */
|
||||||
|
|
||||||
idev = scan_or_find_devices (readerno, readerid, &rid, &dev,
|
if (scan_or_find_devices (readerno, readerid, &rid, &dev,
|
||||||
&ifcdesc_extra, &ifcdesc_extra_len,
|
&ifcdesc_extra, &ifcdesc_extra_len,
|
||||||
&ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr);
|
&ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr,
|
||||||
if (!idev)
|
&idev, &dev_fd) )
|
||||||
{
|
{
|
||||||
if (readerno == -1)
|
if (readerno == -1)
|
||||||
DEBUGOUT_1 ("no CCID reader with ID %s\n", readerid );
|
DEBUGOUT_1 ("no CCID reader with ID %s\n", readerid );
|
||||||
@ -980,34 +1153,52 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
|
|||||||
rc = CCID_DRIVER_ERR_OUT_OF_CORE;
|
rc = CCID_DRIVER_ERR_OUT_OF_CORE;
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
(*handle)->idev = idev;
|
|
||||||
(*handle)->rid = rid;
|
(*handle)->rid = rid;
|
||||||
(*handle)->id_vendor = dev->descriptor.idVendor;
|
if (idev) /* Regular USB transport. */
|
||||||
(*handle)->id_product = dev->descriptor.idProduct;
|
{
|
||||||
(*handle)->bcd_device = dev->descriptor.bcdDevice;
|
(*handle)->idev = idev;
|
||||||
(*handle)->ifc_no = ifc_no;
|
(*handle)->dev_fd = -1;
|
||||||
(*handle)->ep_bulk_out = ep_bulk_out;
|
(*handle)->id_vendor = dev->descriptor.idVendor;
|
||||||
(*handle)->ep_bulk_in = ep_bulk_in;
|
(*handle)->id_product = dev->descriptor.idProduct;
|
||||||
(*handle)->ep_intr = ep_intr;
|
(*handle)->bcd_device = dev->descriptor.bcdDevice;
|
||||||
|
(*handle)->ifc_no = ifc_no;
|
||||||
|
(*handle)->ep_bulk_out = ep_bulk_out;
|
||||||
|
(*handle)->ep_bulk_in = ep_bulk_in;
|
||||||
|
(*handle)->ep_intr = ep_intr;
|
||||||
|
}
|
||||||
|
else if (dev_fd != -1) /* Device transport. */
|
||||||
|
{
|
||||||
|
(*handle)->idev = NULL;
|
||||||
|
(*handle)->dev_fd = dev_fd;
|
||||||
|
(*handle)->id_vendor = 0; /* Magic vendor for special transport. */
|
||||||
|
(*handle)->id_product = ifc_no; /* Transport type */
|
||||||
|
prepare_special_transport (*handle);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert (!"no transport"); /* Bug. */
|
||||||
|
}
|
||||||
|
|
||||||
DEBUGOUT_2 ("using CCID reader %d (ID=%s)\n", readerno, rid );
|
DEBUGOUT_2 ("using CCID reader %d (ID=%s)\n", readerno, rid );
|
||||||
|
|
||||||
|
if (idev)
|
||||||
|
{
|
||||||
|
if (parse_ccid_descriptor (*handle, ifcdesc_extra, ifcdesc_extra_len))
|
||||||
|
{
|
||||||
|
DEBUGOUT ("device not supported\n");
|
||||||
|
rc = CCID_DRIVER_ERR_NO_READER;
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = usb_claim_interface (idev, ifc_no);
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc);
|
||||||
|
rc = CCID_DRIVER_ERR_CARD_IO_ERROR;
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (parse_ccid_descriptor (*handle, ifcdesc_extra, ifcdesc_extra_len))
|
|
||||||
{
|
|
||||||
DEBUGOUT ("device not supported\n");
|
|
||||||
rc = CCID_DRIVER_ERR_NO_READER;
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = usb_claim_interface (idev, ifc_no);
|
|
||||||
if (rc)
|
|
||||||
{
|
|
||||||
DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc);
|
|
||||||
rc = CCID_DRIVER_ERR_CARD_IO_ERROR;
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
free (ifcdesc_extra);
|
free (ifcdesc_extra);
|
||||||
if (rc)
|
if (rc)
|
||||||
@ -1015,6 +1206,8 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
|
|||||||
free (rid);
|
free (rid);
|
||||||
if (idev)
|
if (idev)
|
||||||
usb_close (idev);
|
usb_close (idev);
|
||||||
|
if (dev_fd != -1)
|
||||||
|
close (dev_fd);
|
||||||
free (*handle);
|
free (*handle);
|
||||||
*handle = NULL;
|
*handle = NULL;
|
||||||
}
|
}
|
||||||
@ -1054,6 +1247,11 @@ do_close_reader (ccid_driver_t handle)
|
|||||||
usb_close (handle->idev);
|
usb_close (handle->idev);
|
||||||
handle->idev = NULL;
|
handle->idev = NULL;
|
||||||
}
|
}
|
||||||
|
if (handle->dev_fd != -1)
|
||||||
|
{
|
||||||
|
close (handle->dev_fd);
|
||||||
|
handle->dev_fd = -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1080,43 +1278,49 @@ ccid_shutdown_reader (ccid_driver_t handle)
|
|||||||
|
|
||||||
do_close_reader (handle);
|
do_close_reader (handle);
|
||||||
|
|
||||||
idev = scan_or_find_devices (-1, handle->rid, NULL, &dev,
|
if (scan_or_find_devices (-1, handle->rid, NULL, &dev,
|
||||||
&ifcdesc_extra, &ifcdesc_extra_len,
|
&ifcdesc_extra, &ifcdesc_extra_len,
|
||||||
&ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr);
|
&ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr,
|
||||||
if (!idev)
|
&idev, NULL) || !idev)
|
||||||
{
|
{
|
||||||
DEBUGOUT_1 ("no CCID reader with ID %s\n", handle->rid);
|
DEBUGOUT_1 ("no CCID reader with ID %s\n", handle->rid);
|
||||||
return CCID_DRIVER_ERR_NO_READER;
|
return CCID_DRIVER_ERR_NO_READER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (idev)
|
||||||
handle->idev = idev;
|
|
||||||
handle->ifc_no = ifc_no;
|
|
||||||
handle->ep_bulk_out = ep_bulk_out;
|
|
||||||
handle->ep_bulk_in = ep_bulk_in;
|
|
||||||
handle->ep_intr = ep_intr;
|
|
||||||
|
|
||||||
if (parse_ccid_descriptor (handle, ifcdesc_extra, ifcdesc_extra_len))
|
|
||||||
{
|
{
|
||||||
DEBUGOUT ("device not supported\n");
|
handle->idev = idev;
|
||||||
rc = CCID_DRIVER_ERR_NO_READER;
|
handle->ifc_no = ifc_no;
|
||||||
goto leave;
|
handle->ep_bulk_out = ep_bulk_out;
|
||||||
|
handle->ep_bulk_in = ep_bulk_in;
|
||||||
|
handle->ep_intr = ep_intr;
|
||||||
|
|
||||||
|
if (parse_ccid_descriptor (handle, ifcdesc_extra, ifcdesc_extra_len))
|
||||||
|
{
|
||||||
|
DEBUGOUT ("device not supported\n");
|
||||||
|
rc = CCID_DRIVER_ERR_NO_READER;
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = usb_claim_interface (idev, ifc_no);
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc);
|
||||||
|
rc = CCID_DRIVER_ERR_CARD_IO_ERROR;
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = usb_claim_interface (idev, ifc_no);
|
|
||||||
if (rc)
|
|
||||||
{
|
|
||||||
DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc);
|
|
||||||
rc = CCID_DRIVER_ERR_CARD_IO_ERROR;
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
free (ifcdesc_extra);
|
free (ifcdesc_extra);
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
usb_close (handle->idev);
|
if (handle->idev)
|
||||||
|
usb_close (handle->idev);
|
||||||
handle->idev = NULL;
|
handle->idev = NULL;
|
||||||
|
if (handle->dev_fd != -1)
|
||||||
|
close (handle->dev_fd);
|
||||||
|
handle->dev_fd = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
@ -1147,6 +1351,31 @@ ccid_check_card_presence (ccid_driver_t handle)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Write NBYTES of BUF to file descriptor FD. */
|
||||||
|
static int
|
||||||
|
writen (int fd, const void *buf, size_t nbytes)
|
||||||
|
{
|
||||||
|
size_t nleft = nbytes;
|
||||||
|
int nwritten;
|
||||||
|
|
||||||
|
while (nleft > 0)
|
||||||
|
{
|
||||||
|
nwritten = write (fd, buf, nleft);
|
||||||
|
if (nwritten < 0)
|
||||||
|
{
|
||||||
|
if (errno == EINTR)
|
||||||
|
nwritten = 0;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
nleft -= nwritten;
|
||||||
|
buf = (const char*)buf + nwritten;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Write a MSG of length MSGLEN to the designated bulk out endpoint.
|
/* Write a MSG of length MSGLEN to the designated bulk out endpoint.
|
||||||
Returns 0 on success. */
|
Returns 0 on success. */
|
||||||
static int
|
static int
|
||||||
@ -1154,17 +1383,28 @@ bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen)
|
|||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = usb_bulk_write (handle->idev,
|
if (handle->idev)
|
||||||
handle->ep_bulk_out,
|
{
|
||||||
(char*)msg, msglen,
|
rc = usb_bulk_write (handle->idev,
|
||||||
1000 /* ms timeout */);
|
handle->ep_bulk_out,
|
||||||
if (rc == msglen)
|
(char*)msg, msglen,
|
||||||
return 0;
|
1000 /* ms timeout */);
|
||||||
|
if (rc == msglen)
|
||||||
if (rc == -1)
|
return 0;
|
||||||
DEBUGOUT_1 ("usb_bulk_write error: %s\n", strerror (errno));
|
if (rc == -1)
|
||||||
|
DEBUGOUT_1 ("usb_bulk_write error: %s\n", strerror (errno));
|
||||||
|
else
|
||||||
|
DEBUGOUT_1 ("usb_bulk_write failed: %d\n", rc);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
DEBUGOUT_1 ("usb_bulk_write failed: %d\n", rc);
|
{
|
||||||
|
rc = writen (handle->dev_fd, msg, msglen);
|
||||||
|
if (!rc)
|
||||||
|
return 0;
|
||||||
|
DEBUGOUT_2 ("writen to %d failed: %s\n",
|
||||||
|
handle->dev_fd, strerror (errno));
|
||||||
|
|
||||||
|
}
|
||||||
return CCID_DRIVER_ERR_CARD_IO_ERROR;
|
return CCID_DRIVER_ERR_CARD_IO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1187,17 +1427,31 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
|
|||||||
for USB IOCTLs. */
|
for USB IOCTLs. */
|
||||||
memset (buffer, 0, length);
|
memset (buffer, 0, length);
|
||||||
retry:
|
retry:
|
||||||
rc = usb_bulk_read (handle->idev,
|
if (handle->idev)
|
||||||
handle->ep_bulk_in,
|
|
||||||
(char*)buffer, length,
|
|
||||||
timeout);
|
|
||||||
if (rc < 0)
|
|
||||||
{
|
{
|
||||||
DEBUGOUT_1 ("usb_bulk_read error: %s\n", strerror (errno));
|
rc = usb_bulk_read (handle->idev,
|
||||||
return CCID_DRIVER_ERR_CARD_IO_ERROR;
|
handle->ep_bulk_in,
|
||||||
|
(char*)buffer, length,
|
||||||
|
timeout);
|
||||||
|
if (rc < 0)
|
||||||
|
{
|
||||||
|
DEBUGOUT_1 ("usb_bulk_read error: %s\n", strerror (errno));
|
||||||
|
return CCID_DRIVER_ERR_CARD_IO_ERROR;
|
||||||
|
}
|
||||||
|
*nread = msglen = rc;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rc = read (handle->dev_fd, buffer, length);
|
||||||
|
if (rc < 0)
|
||||||
|
{
|
||||||
|
DEBUGOUT_2 ("read from %d failed: %s\n",
|
||||||
|
handle->dev_fd, strerror (errno));
|
||||||
|
return CCID_DRIVER_ERR_CARD_IO_ERROR;
|
||||||
|
}
|
||||||
|
*nread = msglen = rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
*nread = msglen = rc;
|
|
||||||
|
|
||||||
if (msglen < 10)
|
if (msglen < 10)
|
||||||
{
|
{
|
||||||
@ -1339,11 +1593,16 @@ ccid_poll (ccid_driver_t handle)
|
|||||||
size_t msglen;
|
size_t msglen;
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
rc = usb_bulk_read (handle->idev,
|
if (handle->idev)
|
||||||
handle->ep_intr,
|
{
|
||||||
(char*)msg, sizeof msg,
|
rc = usb_bulk_read (handle->idev,
|
||||||
0 /* ms timeout */ );
|
handle->ep_intr,
|
||||||
if (rc < 0 && errno == ETIMEDOUT)
|
(char*)msg, sizeof msg,
|
||||||
|
0 /* ms timeout */ );
|
||||||
|
if (rc < 0 && errno == ETIMEDOUT)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user