aboutsummaryrefslogtreecommitdiffstats
path: root/scd/apdu.c
diff options
context:
space:
mode:
Diffstat (limited to 'scd/apdu.c')
-rw-r--r--scd/apdu.c560
1 files changed, 309 insertions, 251 deletions
diff --git a/scd/apdu.c b/scd/apdu.c
index 2df113c5e..f86a63897 100644
--- a/scd/apdu.c
+++ b/scd/apdu.c
@@ -55,7 +55,7 @@
#include "ccid-driver.h"
struct dev_list {
- struct ccid_dev_table *ccid_table;
+ void *table;
const char *portstr;
int idx;
int idx_max;
@@ -76,6 +76,19 @@ typedef unsigned int pcsc_dword_t;
typedef unsigned long pcsc_dword_t;
#endif
+#ifdef HAVE_W32_SYSTEM
+#define HANDLE uintptr_t
+#else
+#define HANDLE long
+#endif
+
+/* PC/SC context to access readers. Shared among all readers. */
+static struct pcsc_global_data {
+ HANDLE context;
+ int count;
+ const char *rdrname[MAX_READER];
+} pcsc;
+
/* A structure to collect information pertaining to one reader
slot. */
struct reader_table_s {
@@ -101,8 +114,7 @@ struct reader_table_s {
ccid_driver_t handle;
} ccid;
struct {
- long context;
- long card;
+ HANDLE card;
pcsc_dword_t protocol;
pcsc_dword_t verify_ioctl;
pcsc_dword_t modify_ioctl;
@@ -288,35 +300,35 @@ typedef struct pcsc_readerstate_s *pcsc_readerstate_t;
long (* DLSTDCALL pcsc_establish_context) (pcsc_dword_t scope,
const void *reserved1,
const void *reserved2,
- long *r_context);
-long (* DLSTDCALL pcsc_release_context) (long context);
-long (* DLSTDCALL pcsc_list_readers) (long context,
+ HANDLE *r_context);
+long (* DLSTDCALL pcsc_release_context) (HANDLE context);
+long (* DLSTDCALL pcsc_list_readers) (HANDLE context,
const char *groups,
char *readers, pcsc_dword_t*readerslen);
-long (* DLSTDCALL pcsc_get_status_change) (long context,
+long (* DLSTDCALL pcsc_get_status_change) (HANDLE context,
pcsc_dword_t timeout,
pcsc_readerstate_t readerstates,
pcsc_dword_t nreaderstates);
-long (* DLSTDCALL pcsc_connect) (long context,
+long (* DLSTDCALL pcsc_connect) (HANDLE context,
const char *reader,
pcsc_dword_t share_mode,
pcsc_dword_t preferred_protocols,
- long *r_card,
+ HANDLE *r_card,
pcsc_dword_t *r_active_protocol);
-long (* DLSTDCALL pcsc_reconnect) (long card,
+long (* DLSTDCALL pcsc_reconnect) (HANDLE card,
pcsc_dword_t share_mode,
pcsc_dword_t preferred_protocols,
pcsc_dword_t initialization,
pcsc_dword_t *r_active_protocol);
-long (* DLSTDCALL pcsc_disconnect) (long card,
+long (* DLSTDCALL pcsc_disconnect) (HANDLE card,
pcsc_dword_t disposition);
-long (* DLSTDCALL pcsc_status) (long card,
+long (* DLSTDCALL pcsc_status) (HANDLE card,
char *reader, pcsc_dword_t *readerlen,
pcsc_dword_t *r_state,
pcsc_dword_t *r_protocol,
unsigned char *atr, pcsc_dword_t *atrlen);
long (* DLSTDCALL pcsc_begin_transaction) (long card);
-long (* DLSTDCALL pcsc_end_transaction) (long card,
+long (* DLSTDCALL pcsc_end_transaction) (HANDLE card,
pcsc_dword_t disposition);
long (* DLSTDCALL pcsc_transmit) (long card,
const pcsc_io_request_t send_pci,
@@ -325,9 +337,9 @@ long (* DLSTDCALL pcsc_transmit) (long card,
pcsc_io_request_t recv_pci,
unsigned char *recv_buffer,
pcsc_dword_t *recv_len);
-long (* DLSTDCALL pcsc_set_timeout) (long context,
+long (* DLSTDCALL pcsc_set_timeout) (HANDLE context,
pcsc_dword_t timeout);
-long (* DLSTDCALL pcsc_control) (long card,
+long (* DLSTDCALL pcsc_control) (HANDLE card,
pcsc_dword_t control_code,
const void *send_buffer,
pcsc_dword_t send_len,
@@ -652,9 +664,7 @@ pcsc_get_status (int slot, unsigned int *status, int on_wire)
memset (rdrstates, 0, sizeof *rdrstates);
rdrstates[0].reader = reader_table[slot].rdrname;
rdrstates[0].current_state = reader_table[slot].pcsc.current_state;
- err = pcsc_get_status_change (reader_table[slot].pcsc.context,
- 0,
- rdrstates, 1);
+ err = pcsc_get_status_change (pcsc.context, 0, rdrstates, 1);
if (err == PCSC_E_TIMEOUT)
err = 0; /* Timeout is no error here. */
if (err)
@@ -788,7 +798,16 @@ control_pcsc (int slot, pcsc_dword_t ioctl_code,
static int
close_pcsc_reader (int slot)
{
- pcsc_release_context (reader_table[slot].pcsc.context);
+ (void)slot;
+ if (--pcsc.count == 0)
+ {
+ int i;
+
+ pcsc_release_context (pcsc.context);
+ pcsc.context = 0;
+ for (i = 0; i < MAX_READER; i++)
+ pcsc.rdrname[i] = NULL;
+ }
return 0;
}
@@ -807,7 +826,7 @@ connect_pcsc_card (int slot)
reader_table[slot].atrlen = 0;
reader_table[slot].is_t0 = 0;
- err = pcsc_connect (reader_table[slot].pcsc.context,
+ err = pcsc_connect (pcsc.context,
reader_table[slot].rdrname,
PCSC_SHARE_EXCLUSIVE,
PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
@@ -829,7 +848,7 @@ connect_pcsc_card (int slot)
pcsc_vendor_specific_init (slot);
atrlen = DIM (reader_table[0].atr);
- readerlen = sizeof reader -1 ;
+ readerlen = sizeof reader - 1;
err = pcsc_status (reader_table[slot].pcsc.card,
reader, &readerlen,
&card_state, &card_protocol,
@@ -1042,94 +1061,128 @@ pcsc_vendor_specific_init (int slot)
return 0;
}
-
-/* Open the PC/SC reader without using the wrapper. Returns -1 on
- error or a slot number for the reader. */
static int
-open_pcsc_reader (const char *portstr)
+pcsc_init (void)
{
+ static int pcsc_api_loaded;
long err;
- int slot;
- char *list = NULL;
- char *rdrname = NULL;
- pcsc_dword_t nreader;
- char *p;
-
- slot = new_reader_slot ();
- if (slot == -1)
- return -1;
- /* Fixme: Allocating a context for each slot is not required. One
- global context should be sufficient. */
- err = pcsc_establish_context (PCSC_SCOPE_SYSTEM, NULL, NULL,
- &reader_table[slot].pcsc.context);
- if (err)
+ /* Lets try the PC/SC API */
+ if (!pcsc_api_loaded)
{
- log_error ("pcsc_establish_context failed: %s (0x%lx)\n",
- pcsc_error_string (err), err);
- reader_table[slot].used = 0;
- unlock_slot (slot);
- return -1;
- }
+ void *handle;
- err = pcsc_list_readers (reader_table[slot].pcsc.context,
- NULL, NULL, &nreader);
- if (!err)
- {
- list = xtrymalloc (nreader+1); /* Better add 1 for safety reasons. */
- if (!list)
+ handle = dlopen (opt.pcsc_driver, RTLD_LAZY);
+ if (!handle)
{
- log_error ("error allocating memory for reader list\n");
- pcsc_release_context (reader_table[slot].pcsc.context);
- reader_table[slot].used = 0;
- unlock_slot (slot);
- return -1 /*SW_HOST_OUT_OF_CORE*/;
+ log_error ("apdu_open_reader: failed to open driver '%s': %s\n",
+ opt.pcsc_driver, dlerror ());
+ return -1;
+ }
+
+ pcsc_establish_context = dlsym (handle, "SCardEstablishContext");
+ pcsc_release_context = dlsym (handle, "SCardReleaseContext");
+ pcsc_list_readers = dlsym (handle, "SCardListReaders");
+#if defined(_WIN32) || defined(__CYGWIN__)
+ if (!pcsc_list_readers)
+ pcsc_list_readers = dlsym (handle, "SCardListReadersA");
+#endif
+ pcsc_get_status_change = dlsym (handle, "SCardGetStatusChange");
+#if defined(_WIN32) || defined(__CYGWIN__)
+ if (!pcsc_get_status_change)
+ pcsc_get_status_change = dlsym (handle, "SCardGetStatusChangeA");
+#endif
+ pcsc_connect = dlsym (handle, "SCardConnect");
+#if defined(_WIN32) || defined(__CYGWIN__)
+ if (!pcsc_connect)
+ pcsc_connect = dlsym (handle, "SCardConnectA");
+#endif
+ pcsc_reconnect = dlsym (handle, "SCardReconnect");
+#if defined(_WIN32) || defined(__CYGWIN__)
+ if (!pcsc_reconnect)
+ pcsc_reconnect = dlsym (handle, "SCardReconnectA");
+#endif
+ pcsc_disconnect = dlsym (handle, "SCardDisconnect");
+ pcsc_status = dlsym (handle, "SCardStatus");
+#if defined(_WIN32) || defined(__CYGWIN__)
+ if (!pcsc_status)
+ pcsc_status = dlsym (handle, "SCardStatusA");
+#endif
+ pcsc_begin_transaction = dlsym (handle, "SCardBeginTransaction");
+ pcsc_end_transaction = dlsym (handle, "SCardEndTransaction");
+ pcsc_transmit = dlsym (handle, "SCardTransmit");
+ pcsc_set_timeout = dlsym (handle, "SCardSetTimeout");
+ pcsc_control = dlsym (handle, "SCardControl");
+
+ if (!pcsc_establish_context
+ || !pcsc_release_context
+ || !pcsc_list_readers
+ || !pcsc_get_status_change
+ || !pcsc_connect
+ || !pcsc_reconnect
+ || !pcsc_disconnect
+ || !pcsc_status
+ || !pcsc_begin_transaction
+ || !pcsc_end_transaction
+ || !pcsc_transmit
+ || !pcsc_control
+ /* || !pcsc_set_timeout */)
+ {
+ /* Note that set_timeout is currently not used and also not
+ available under Windows. */
+ log_error ("apdu_open_reader: invalid PC/SC driver "
+ "(%d%d%d%d%d%d%d%d%d%d%d%d%d)\n",
+ !!pcsc_establish_context,
+ !!pcsc_release_context,
+ !!pcsc_list_readers,
+ !!pcsc_get_status_change,
+ !!pcsc_connect,
+ !!pcsc_reconnect,
+ !!pcsc_disconnect,
+ !!pcsc_status,
+ !!pcsc_begin_transaction,
+ !!pcsc_end_transaction,
+ !!pcsc_transmit,
+ !!pcsc_set_timeout,
+ !!pcsc_control );
+ dlclose (handle);
+ return -1;
}
- err = pcsc_list_readers (reader_table[slot].pcsc.context,
- NULL, list, &nreader);
+ pcsc_api_loaded = 1;
}
+
+ err = pcsc_establish_context (PCSC_SCOPE_SYSTEM, NULL, NULL,
+ &pcsc.context);
if (err)
{
- log_error ("pcsc_list_readers failed: %s (0x%lx)\n",
+ log_error ("pcsc_establish_context failed: %s (0x%lx)\n",
pcsc_error_string (err), err);
- pcsc_release_context (reader_table[slot].pcsc.context);
- reader_table[slot].used = 0;
- xfree (list);
- unlock_slot (slot);
return -1;
}
- p = list;
- while (nreader)
- {
- if (!*p && !p[1])
- break;
- log_info ("detected reader '%s'\n", p);
- if (nreader < (strlen (p)+1))
- {
- log_error ("invalid response from pcsc_list_readers\n");
- break;
- }
- if (!rdrname && portstr && !strncmp (p, portstr, strlen (portstr)))
- rdrname = p;
- nreader -= strlen (p)+1;
- p += strlen (p) + 1;
- }
+ return 0;
+}
- if (!rdrname)
- rdrname = list;
+/* Open the PC/SC reader. Returns -1 on error or a slot number for
+ the reader. */
+static int
+open_pcsc_reader (const char *rdrname)
+{
+ int slot;
+
+ slot = new_reader_slot ();
+ if (slot == -1)
+ return -1;
reader_table[slot].rdrname = xtrystrdup (rdrname);
if (!reader_table[slot].rdrname)
{
log_error ("error allocating memory for reader name\n");
- pcsc_release_context (reader_table[slot].pcsc.context);
+ close_pcsc_reader (0);
reader_table[slot].used = 0;
unlock_slot (slot);
return -1;
}
- xfree (list);
- list = NULL;
reader_table[slot].pcsc.card = 0;
reader_table[slot].atrlen = 0;
@@ -1142,6 +1195,7 @@ open_pcsc_reader (const char *portstr)
reader_table[slot].send_apdu_reader = pcsc_send_apdu;
reader_table[slot].dump_status_reader = dump_pcsc_reader_status;
+ pcsc.count++;
dump_reader_status (slot);
unlock_slot (slot);
return slot;
@@ -1520,7 +1574,7 @@ open_ccid_reader (struct dev_list *dl)
return -1;
slotp = reader_table + slot;
- err = ccid_open_reader (dl->portstr, dl->idx, dl->ccid_table,
+ err = ccid_open_reader (dl->portstr, dl->idx, dl->table,
&slotp->ccid.handle, &slotp->rdrname);
if (!err)
{
@@ -1866,51 +1920,111 @@ gpg_error_t
apdu_dev_list_start (const char *portstr, struct dev_list **l_p)
{
struct dev_list *dl = xtrymalloc (sizeof (struct dev_list));
+ gpg_error_t err;
*l_p = NULL;
if (!dl)
return gpg_error_from_syserror ();
+ dl->table = NULL;
dl->portstr = portstr;
dl->idx = 0;
+ dl->idx_max = 0;
npth_mutex_lock (&reader_table_lock);
#ifdef HAVE_LIBUSB
- if (opt.disable_ccid)
+ if (!opt.disable_ccid)
{
- dl->ccid_table = NULL;
- dl->idx_max = 1;
+ err = ccid_dev_scan (&dl->idx_max, &dl->table);
+ if (err)
+ {
+ npth_mutex_unlock (&reader_table_lock);
+ return err;
+ }
+
+ if (dl->idx_max == 0)
+ {
+ if (DBG_READER)
+ log_debug ("leave: apdu_open_reader => slot=-1 (no ccid)\n");
+
+ xfree (dl);
+ npth_mutex_unlock (&reader_table_lock);
+ return gpg_error (GPG_ERR_ENODEV);
+ }
}
else
- {
- gpg_error_t err;
+#endif
+ { /* PC/SC readers. */
+ long r;
+ pcsc_dword_t nreader;
+ char *p = NULL;
- err = ccid_dev_scan (&dl->idx_max, &dl->ccid_table);
- if (err)
- return err;
+ if (!pcsc.context)
+ if (pcsc_init () < 0)
+ {
+ npth_mutex_unlock (&reader_table_lock);
+ return gpg_error (GPG_ERR_NO_SERVICE);
+ }
- if (dl->idx_max == 0)
+ r = pcsc_list_readers (pcsc.context, NULL, NULL, &nreader);
+ if (!r)
{
- /* If a CCID reader specification has been given, the user does
- not want a fallback to other drivers. */
- if (portstr && strlen (portstr) > 5 && portstr[4] == ':')
+ p = xtrymalloc (nreader);
+ if (!p)
{
- if (DBG_READER)
- log_debug ("leave: apdu_open_reader => slot=-1 (no ccid)\n");
+ err = gpg_error_from_syserror ();
- xfree (dl);
+ log_error ("error allocating memory for reader list\n");
+ close_pcsc_reader (0);
npth_mutex_unlock (&reader_table_lock);
- return gpg_error (GPG_ERR_ENODEV);
+ return err;
+ }
+ r = pcsc_list_readers (pcsc.context, NULL, p, &nreader);
+ }
+ if (r)
+ {
+ log_error ("pcsc_list_readers failed: %s (0x%lx)\n",
+ pcsc_error_string (r), r);
+ xfree (p);
+ close_pcsc_reader (0);
+ npth_mutex_unlock (&reader_table_lock);
+ return gpg_error (GPG_ERR_NO_SERVICE);
+ }
+
+ dl->table = p;
+ dl->idx_max = 0;
+
+ while (nreader > 0)
+ {
+ size_t n;
+
+ if (!*p)
+ break;
+
+ for (n = 0; n < nreader; n++)
+ if (!p[n])
+ break;
+
+ if (n >= nreader)
+ {
+ log_error ("invalid response from pcsc_list_readers\n");
+ break;
+ }
+
+ log_info ("detected reader '%s'\n", p);
+ pcsc.rdrname[dl->idx_max] = p;
+ nreader -= n + 1;
+ p += n + 1;
+ dl->idx_max++;
+ if (dl->idx_max > MAX_READER)
+ {
+ log_error ("too many readers from pcsc_list_readers\n");
+ dl->idx_max--;
+ break;
}
- else
- dl->idx_max = 1;
}
}
-#else
- dl->ccid_table = NULL;
- dl->idx_max = 1;
-#endif /* HAVE_LIBUSB */
*l_p = dl;
return 0;
@@ -1920,161 +2034,65 @@ void
apdu_dev_list_finish (struct dev_list *dl)
{
#ifdef HAVE_LIBUSB
- if (dl->ccid_table)
- ccid_dev_scan_finish (dl->ccid_table, dl->idx_max);
+ if (!opt.disable_ccid)
+ {
+ if (dl->table)
+ ccid_dev_scan_finish (dl->table, dl->idx_max);
+ }
+ else
#endif
+ { /* PC/SC readers. */
+ int i;
+
+ xfree (dl->table);
+ for (i = 0; i < MAX_READER; i++)
+ pcsc.rdrname[i] = NULL;
+ }
xfree (dl);
npth_mutex_unlock (&reader_table_lock);
}
-/* Open the reader and return an internal slot number or -1 on
- error. If PORTSTR is NULL we default to a suitable port (for ctAPI:
- the first USB reader. For PC/SC the first listed reader). */
-static int
-apdu_open_one_reader (const char *portstr)
+int
+apdu_open_reader (struct dev_list *dl)
{
- static int pcsc_api_loaded;
int slot;
+ int readerno;
- if (DBG_READER)
- log_debug ("enter: apdu_open_reader: portstr=%s\n", portstr);
+ if (!dl->table)
+ return -1;
- /* Lets try the PC/SC API */
- if (!pcsc_api_loaded)
+ /* See whether we want to use the reader ID string or a reader
+ number. A readerno of -1 indicates that the reader ID string is
+ to be used. */
+ if (dl->portstr && strchr (dl->portstr, ':'))
+ readerno = -1; /* We want to use the readerid. */
+ else if (dl->portstr)
{
- void *handle;
-
- handle = dlopen (opt.pcsc_driver, RTLD_LAZY);
- if (!handle)
- {
- log_error ("apdu_open_reader: failed to open driver '%s': %s\n",
- opt.pcsc_driver, dlerror ());
- return -1;
- }
+ readerno = atoi (dl->portstr);
+ if (readerno < 0 || readerno >= dl->idx_max)
+ return -1;
- pcsc_establish_context = dlsym (handle, "SCardEstablishContext");
- pcsc_release_context = dlsym (handle, "SCardReleaseContext");
- pcsc_list_readers = dlsym (handle, "SCardListReaders");
-#if defined(_WIN32) || defined(__CYGWIN__)
- if (!pcsc_list_readers)
- pcsc_list_readers = dlsym (handle, "SCardListReadersA");
-#endif
- pcsc_get_status_change = dlsym (handle, "SCardGetStatusChange");
-#if defined(_WIN32) || defined(__CYGWIN__)
- if (!pcsc_get_status_change)
- pcsc_get_status_change = dlsym (handle, "SCardGetStatusChangeA");
-#endif
- pcsc_connect = dlsym (handle, "SCardConnect");
-#if defined(_WIN32) || defined(__CYGWIN__)
- if (!pcsc_connect)
- pcsc_connect = dlsym (handle, "SCardConnectA");
-#endif
- pcsc_reconnect = dlsym (handle, "SCardReconnect");
-#if defined(_WIN32) || defined(__CYGWIN__)
- if (!pcsc_reconnect)
- pcsc_reconnect = dlsym (handle, "SCardReconnectA");
-#endif
- pcsc_disconnect = dlsym (handle, "SCardDisconnect");
- pcsc_status = dlsym (handle, "SCardStatus");
-#if defined(_WIN32) || defined(__CYGWIN__)
- if (!pcsc_status)
- pcsc_status = dlsym (handle, "SCardStatusA");
-#endif
- pcsc_begin_transaction = dlsym (handle, "SCardBeginTransaction");
- pcsc_end_transaction = dlsym (handle, "SCardEndTransaction");
- pcsc_transmit = dlsym (handle, "SCardTransmit");
- pcsc_set_timeout = dlsym (handle, "SCardSetTimeout");
- pcsc_control = dlsym (handle, "SCardControl");
-
- if (!pcsc_establish_context
- || !pcsc_release_context
- || !pcsc_list_readers
- || !pcsc_get_status_change
- || !pcsc_connect
- || !pcsc_reconnect
- || !pcsc_disconnect
- || !pcsc_status
- || !pcsc_begin_transaction
- || !pcsc_end_transaction
- || !pcsc_transmit
- || !pcsc_control
- /* || !pcsc_set_timeout */)
- {
- /* Note that set_timeout is currently not used and also not
- available under Windows. */
- log_error ("apdu_open_reader: invalid PC/SC driver "
- "(%d%d%d%d%d%d%d%d%d%d%d%d%d)\n",
- !!pcsc_establish_context,
- !!pcsc_release_context,
- !!pcsc_list_readers,
- !!pcsc_get_status_change,
- !!pcsc_connect,
- !!pcsc_reconnect,
- !!pcsc_disconnect,
- !!pcsc_status,
- !!pcsc_begin_transaction,
- !!pcsc_end_transaction,
- !!pcsc_transmit,
- !!pcsc_set_timeout,
- !!pcsc_control );
- dlclose (handle);
- return -1;
- }
- pcsc_api_loaded = 1;
+ dl->idx = readerno;
+ dl->portstr = NULL;
}
-
- slot = open_pcsc_reader (portstr);
-
- if (DBG_READER)
- log_debug ("leave: apdu_open_reader => slot=%d [pc/sc]\n", slot);
- return slot;
-}
-
-int
-apdu_open_reader (struct dev_list *dl, int app_empty)
-{
- int slot;
+ else
+ readerno = 0; /* Default. */
#ifdef HAVE_LIBUSB
- if (dl->ccid_table)
+ if (!opt.disable_ccid)
{ /* CCID readers. */
- int readerno;
-
- /* See whether we want to use the reader ID string or a reader
- number. A readerno of -1 indicates that the reader ID string is
- to be used. */
- if (dl->portstr && strchr (dl->portstr, ':'))
- readerno = -1; /* We want to use the readerid. */
- else if (dl->portstr)
- {
- readerno = atoi (dl->portstr);
- if (readerno < 0)
- {
- return -1;
- }
- }
- else
- readerno = 0; /* Default. */
-
if (readerno > 0)
{ /* Use single, the specific reader. */
- if (readerno >= dl->idx_max)
- return -1;
-
- dl->idx = readerno;
- dl->portstr = NULL;
slot = open_ccid_reader (dl);
+ /* And stick the reader and no scan. */
dl->idx = dl->idx_max;
- if (slot >= 0)
- return slot;
- else
- return -1;
+ return slot;
}
while (dl->idx < dl->idx_max)
{
- unsigned int bai = ccid_get_BAI (dl->idx, dl->ccid_table);
+ unsigned int bai = ccid_get_BAI (dl->idx, dl->table);
if (DBG_READER)
log_debug ("apdu_open_reader: BAI=%x\n", bai);
@@ -2107,25 +2125,60 @@ apdu_open_reader (struct dev_list *dl, int app_empty)
dl->idx++;
}
- /* Not found. Try one for PC/SC, only when it's the initial scan. */
- if (app_empty && dl->idx == dl->idx_max)
- {
- dl->idx++;
- slot = apdu_open_one_reader (dl->portstr);
- }
- else
- slot = -1;
+ /* Not found. */
+ slot = -1;
}
else
#endif
{ /* PC/SC readers. */
- if (app_empty && dl->idx == 0)
+ if (readerno > 0)
+ { /* Use single, the specific reader. */
+ slot = open_pcsc_reader (pcsc.rdrname[readerno]);
+ /* And stick the reader and no scan. */
+ dl->idx = dl->idx_max;
+ return slot;
+ }
+
+ while (dl->idx < dl->idx_max)
{
- dl->idx++;
- slot = apdu_open_one_reader (dl->portstr);
+ const char *rdrname = pcsc.rdrname[dl->idx];
+
+ if (DBG_READER)
+ log_debug ("apdu_open_reader: %s\n", rdrname);
+
+ /* Check the identity of reader against already opened one. */
+ for (slot = 0; slot < MAX_READER; slot++)
+ if (reader_table[slot].used
+ && !strcmp (reader_table[slot].rdrname, rdrname))
+ break;
+
+ if (slot == MAX_READER)
+ { /* Found a new device. */
+ if (DBG_READER)
+ log_debug ("apdu_open_reader: new device=%s\n", rdrname);
+
+ /* When reader string is specified, check if it is the one. */
+ if (readerno < 0 && strcmp (rdrname, dl->portstr) != 0)
+ continue;
+
+ slot = open_pcsc_reader (rdrname);
+
+ dl->idx++;
+ if (slot >= 0)
+ return slot;
+ else
+ {
+ /* Skip this reader. */
+ log_error ("pcsc open error: skip\n");
+ continue;
+ }
+ }
+ else
+ dl->idx++;
}
- else
- slot = -1;
+
+ /* Not found. */
+ slot = -1;
}
return slot;
@@ -3305,6 +3358,11 @@ apdu_init (void)
gpg_error_t err;
int i;
+ pcsc.count = 0;
+ pcsc.context = 0;
+ for (i = 0; i < MAX_READER; i++)
+ pcsc.rdrname[i] = NULL;
+
if (npth_mutex_init (&reader_table_lock, NULL))
goto leave;