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>
|
||||
|
||||
* 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
|
||||
the first LF is followed by DC4 (0x14) control sequence are
|
||||
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>
|
||||
|
||||
@ -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
|
||||
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
|
||||
not match the one required for the requested action (e.g. the
|
||||
serial number does not match). */
|
||||
@ -2120,7 +2120,11 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
|
||||
&& !memcmp (indata, rmd160_prefix, 15))
|
||||
;
|
||||
else
|
||||
{
|
||||
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. */
|
||||
if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12))
|
||||
|
@ -67,8 +67,8 @@
|
||||
portable access to USB.
|
||||
|
||||
This driver has been tested with the SCM SCR335 and SPR532
|
||||
smartcard readers and requires that a reader implements the TPDU
|
||||
level exchange and does fully automatic initialization.
|
||||
smartcard readers and requires that a reader implements APDU or
|
||||
TPDU level exchange and does fully automatic initialization.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
@ -82,6 +82,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include <usb.h>
|
||||
|
||||
@ -194,11 +197,29 @@ enum {
|
||||
|
||||
/* We need to know the vendor to do some hacks. */
|
||||
enum {
|
||||
VENDOR_SCM = 0x04e6,
|
||||
VENDOR_CHERRY = 0x046a,
|
||||
VENDOR_SCM = 0x04e6,
|
||||
VENDOR_OMNIKEY= 0x076b,
|
||||
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
|
||||
structure is used as handle for most functions. */
|
||||
@ -206,6 +227,8 @@ struct ccid_driver_s
|
||||
{
|
||||
usb_dev_handle *idev;
|
||||
char *rid;
|
||||
int dev_fd; /* -1 for USB transport or file descriptor of the
|
||||
transport device. */
|
||||
unsigned short id_vendor;
|
||||
unsigned short id_product;
|
||||
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
|
||||
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 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");
|
||||
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
|
||||
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
|
||||
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
|
||||
@ -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
|
||||
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
|
||||
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 IFCDESC_EXTRA is NOT NULL it will receive a
|
||||
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
|
||||
implementation NULL will be returned. The caller must close a
|
||||
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
|
||||
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
|
||||
corresponds with a READERNO of 0 in find mode.
|
||||
*/
|
||||
static usb_dev_handle *
|
||||
static int
|
||||
scan_or_find_devices (int readerno, const char *readerid,
|
||||
char **r_rid,
|
||||
struct usb_device **r_dev,
|
||||
unsigned char **ifcdesc_extra,
|
||||
size_t *ifcdesc_extra_len,
|
||||
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;
|
||||
int count = 0;
|
||||
@ -702,6 +927,7 @@ scan_or_find_devices (int readerno, const char *readerid,
|
||||
struct usb_device *dev = NULL;
|
||||
usb_dev_handle *idev = NULL;
|
||||
int scan_mode = (readerno == -1 && !readerid);
|
||||
int i;
|
||||
|
||||
/* Set return values to a default. */
|
||||
if (r_rid)
|
||||
@ -714,6 +940,10 @@ scan_or_find_devices (int readerno, const char *readerid,
|
||||
*ifcdesc_extra_len = 0;
|
||||
if (interface_number)
|
||||
*interface_number = 0;
|
||||
if (r_idev)
|
||||
*r_idev = NULL;
|
||||
if (r_fd)
|
||||
*r_fd = -1;
|
||||
|
||||
/* See whether we want scan or find mode. */
|
||||
if (scan_mode)
|
||||
@ -734,73 +964,58 @@ scan_or_find_devices (int readerno, const char *readerid,
|
||||
{
|
||||
for (dev = bus->devices; dev; dev = dev->next)
|
||||
{
|
||||
int cfg_no;
|
||||
|
||||
for (cfg_no=0; cfg_no < dev->descriptor.bNumConfigurations; cfg_no++)
|
||||
if (scan_or_find_usb_device (scan_mode, &readerno, &count, &rid_list,
|
||||
readerid,
|
||||
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;
|
||||
int ifc_no;
|
||||
|
||||
if(!config)
|
||||
continue;
|
||||
|
||||
for (ifc_no=0; ifc_no < config->bNumInterfaces; ifc_no++)
|
||||
{
|
||||
struct usb_interface *interface
|
||||
= config->interface + ifc_no;
|
||||
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);
|
||||
/* Found requested device or out of core. */
|
||||
if (!idev)
|
||||
{
|
||||
DEBUGOUT_1 ("usb_open failed: %s\n",
|
||||
strerror (errno));
|
||||
continue;
|
||||
free (rid_list);
|
||||
return -1; /* error */
|
||||
}
|
||||
*r_idev = idev;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rid = make_reader_id (idev,
|
||||
dev->descriptor.idVendor,
|
||||
dev->descriptor.idProduct,
|
||||
dev->descriptor.iSerialNumber);
|
||||
if (rid)
|
||||
/* Now check whether there are any devices with special transport types. */
|
||||
for (i=0; transports[i].name; i++)
|
||||
{
|
||||
int fd;
|
||||
char *rid, *p;
|
||||
|
||||
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)
|
||||
{
|
||||
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)))
|
||||
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)
|
||||
{
|
||||
@ -810,85 +1025,41 @@ scan_or_find_devices (int readerno, const char *readerid,
|
||||
strcat (p, rid);
|
||||
strcat (p, "\n");
|
||||
rid_list = p;
|
||||
++count;
|
||||
}
|
||||
else /* Out of memory. */
|
||||
free (rid);
|
||||
rid = NULL;
|
||||
count++;
|
||||
}
|
||||
else if (!readerno
|
||||
|| (readerno < 0
|
||||
&& readerid
|
||||
&& !strcmp (readerid, rid)))
|
||||
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;
|
||||
}
|
||||
/* Found requested device. */
|
||||
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;
|
||||
*interface_number = transports[i].type;
|
||||
if (r_rid)
|
||||
{
|
||||
*r_rid = rid;
|
||||
rid = NULL;
|
||||
}
|
||||
else
|
||||
free (rid);
|
||||
return idev; /* READY. */
|
||||
*r_fd = fd;
|
||||
return 0; /* Okay, found device */
|
||||
}
|
||||
else
|
||||
else /* This is not yet the reader we want. */
|
||||
{
|
||||
/* This is not yet the reader we
|
||||
want. fixme: We could avoid the
|
||||
extra usb_open in this case. */
|
||||
if (readerno >= 0)
|
||||
readerno--;
|
||||
--readerno;
|
||||
}
|
||||
free (rid);
|
||||
}
|
||||
|
||||
usb_close (idev);
|
||||
idev = NULL;
|
||||
goto next_device;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
next_device:
|
||||
;
|
||||
}
|
||||
close (fd);
|
||||
}
|
||||
|
||||
if (scan_mode)
|
||||
{
|
||||
*r_rid = rid_list;
|
||||
|
||||
return NULL;
|
||||
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
|
||||
enables debugging, 2 enables additional tracing of the T=1
|
||||
protocol, other values are not yet defined. */
|
||||
@ -913,8 +1084,9 @@ ccid_get_reader_list (void)
|
||||
initialized_usb = 1;
|
||||
}
|
||||
|
||||
scan_or_find_devices (-1, NULL, &reader_list, NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL);
|
||||
if (scan_or_find_devices (-1, NULL, &reader_list, NULL, NULL, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL, NULL))
|
||||
return NULL; /* Error. */
|
||||
return reader_list;
|
||||
}
|
||||
|
||||
@ -927,6 +1099,7 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
|
||||
int rc = 0;
|
||||
struct usb_device *dev = NULL;
|
||||
usb_dev_handle *idev = NULL;
|
||||
int dev_fd = -1;
|
||||
char *rid = NULL;
|
||||
unsigned char *ifcdesc_extra = NULL;
|
||||
size_t ifcdesc_extra_len;
|
||||
@ -959,10 +1132,10 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
|
||||
else
|
||||
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,
|
||||
&ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr);
|
||||
if (!idev)
|
||||
&ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr,
|
||||
&idev, &dev_fd) )
|
||||
{
|
||||
if (readerno == -1)
|
||||
DEBUGOUT_1 ("no CCID reader with ID %s\n", readerid );
|
||||
@ -980,8 +1153,11 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
|
||||
rc = CCID_DRIVER_ERR_OUT_OF_CORE;
|
||||
goto leave;
|
||||
}
|
||||
(*handle)->idev = idev;
|
||||
(*handle)->rid = rid;
|
||||
if (idev) /* Regular USB transport. */
|
||||
{
|
||||
(*handle)->idev = idev;
|
||||
(*handle)->dev_fd = -1;
|
||||
(*handle)->id_vendor = dev->descriptor.idVendor;
|
||||
(*handle)->id_product = dev->descriptor.idProduct;
|
||||
(*handle)->bcd_device = dev->descriptor.bcdDevice;
|
||||
@ -989,10 +1165,24 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
|
||||
(*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 );
|
||||
|
||||
|
||||
if (idev)
|
||||
{
|
||||
if (parse_ccid_descriptor (*handle, ifcdesc_extra, ifcdesc_extra_len))
|
||||
{
|
||||
DEBUGOUT ("device not supported\n");
|
||||
@ -1007,6 +1197,7 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
|
||||
rc = CCID_DRIVER_ERR_CARD_IO_ERROR;
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
leave:
|
||||
free (ifcdesc_extra);
|
||||
@ -1015,6 +1206,8 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
|
||||
free (rid);
|
||||
if (idev)
|
||||
usb_close (idev);
|
||||
if (dev_fd != -1)
|
||||
close (dev_fd);
|
||||
free (*handle);
|
||||
*handle = NULL;
|
||||
}
|
||||
@ -1054,6 +1247,11 @@ do_close_reader (ccid_driver_t handle)
|
||||
usb_close (handle->idev);
|
||||
handle->idev = NULL;
|
||||
}
|
||||
if (handle->dev_fd != -1)
|
||||
{
|
||||
close (handle->dev_fd);
|
||||
handle->dev_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1080,16 +1278,17 @@ ccid_shutdown_reader (ccid_driver_t 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,
|
||||
&ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr);
|
||||
if (!idev)
|
||||
&ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr,
|
||||
&idev, NULL) || !idev)
|
||||
{
|
||||
DEBUGOUT_1 ("no CCID reader with ID %s\n", handle->rid);
|
||||
return CCID_DRIVER_ERR_NO_READER;
|
||||
}
|
||||
|
||||
|
||||
if (idev)
|
||||
{
|
||||
handle->idev = idev;
|
||||
handle->ifc_no = ifc_no;
|
||||
handle->ep_bulk_out = ep_bulk_out;
|
||||
@ -1110,13 +1309,18 @@ ccid_shutdown_reader (ccid_driver_t handle)
|
||||
rc = CCID_DRIVER_ERR_CARD_IO_ERROR;
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
leave:
|
||||
free (ifcdesc_extra);
|
||||
if (rc)
|
||||
{
|
||||
if (handle->idev)
|
||||
usb_close (handle->idev);
|
||||
handle->idev = NULL;
|
||||
if (handle->dev_fd != -1)
|
||||
close (handle->dev_fd);
|
||||
handle->dev_fd = -1;
|
||||
}
|
||||
|
||||
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.
|
||||
Returns 0 on success. */
|
||||
static int
|
||||
@ -1154,17 +1383,28 @@ bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (handle->idev)
|
||||
{
|
||||
rc = usb_bulk_write (handle->idev,
|
||||
handle->ep_bulk_out,
|
||||
(char*)msg, msglen,
|
||||
1000 /* ms timeout */);
|
||||
if (rc == msglen)
|
||||
return 0;
|
||||
|
||||
if (rc == -1)
|
||||
DEBUGOUT_1 ("usb_bulk_write error: %s\n", strerror (errno));
|
||||
else
|
||||
DEBUGOUT_1 ("usb_bulk_write failed: %d\n", rc);
|
||||
}
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1187,6 +1427,8 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
|
||||
for USB IOCTLs. */
|
||||
memset (buffer, 0, length);
|
||||
retry:
|
||||
if (handle->idev)
|
||||
{
|
||||
rc = usb_bulk_read (handle->idev,
|
||||
handle->ep_bulk_in,
|
||||
(char*)buffer, length,
|
||||
@ -1196,8 +1438,20 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
if (msglen < 10)
|
||||
{
|
||||
@ -1339,12 +1593,17 @@ ccid_poll (ccid_driver_t handle)
|
||||
size_t msglen;
|
||||
int i, j;
|
||||
|
||||
if (handle->idev)
|
||||
{
|
||||
rc = usb_bulk_read (handle->idev,
|
||||
handle->ep_intr,
|
||||
(char*)msg, sizeof msg,
|
||||
0 /* ms timeout */ );
|
||||
if (rc < 0 && errno == ETIMEDOUT)
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
|
||||
if (rc < 0)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user