po: Update Russian translation
[gnupg.git] / scd / apdu.c
index 41790c6..c50afbd 100644 (file)
@@ -15,7 +15,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 /* NOTE: This module is also used by other software, thus the use of
 /* This is used with GnuPG version < 1.9.  The code has been source
    copied from the current GnuPG >= 1.9  and is maintained over
    there. */
-#include "options.h"
+#include "../common/options.h"
 #include "errors.h"
 #include "memory.h"
-#include "util.h"
-#include "i18n.h"
+#include "../common/util.h"
+#include "../common/i18n.h"
 #include "dynload.h"
 #include "cardglue.h"
 #else /* GNUPG_MAJOR_VERSION != 1 */
 #include "scdaemon.h"
-#include "exechelp.h"
+#include "../common/exechelp.h"
 #endif /* GNUPG_MAJOR_VERSION != 1 */
-#include "host2net.h"
+#include "../common/host2net.h"
 
 #include "iso7816.h"
 #include "apdu.h"
 #define CCID_DRIVER_INCLUDE_USB_IDS 1
 #include "ccid-driver.h"
 
-/* Due to conflicting use of threading libraries we usually can't link
-   against libpcsclite if we are using Pth.  Instead we use a wrapper
-   program.  Note that with nPth there is no need for a wrapper. */
-#ifdef USE_PTH  /* Right, plain old Pth.  */
-#if !defined(HAVE_W32_SYSTEM) && !defined(__CYGWIN__)
-#define NEED_PCSC_WRAPPER 1
-#endif
-#endif
-
+struct dev_list {
+  struct ccid_dev_table *ccid_table;
+  const char *portstr;
+  int idx;
+  int idx_max;
+};
 
 #define MAX_READER 4 /* Number of readers we support concurrently. */
 
@@ -97,13 +94,12 @@ struct reader_table_s {
   int used;            /* True if slot is used. */
   unsigned short port; /* Port number:  0 = unused, 1 - dev/tty */
 
-  /* Function pointers intialized to the various backends.  */
+  /* Function pointers initialized to the various backends.  */
   int (*connect_card)(int);
   int (*disconnect_card)(int);
   int (*close_reader)(int);
-  int (*shutdown_reader)(int);
   int (*reset_reader)(int);
-  int (*get_status_reader)(int, unsigned int *);
+  int (*get_status_reader)(int, unsigned int *, int);
   int (*send_apdu_reader)(int,unsigned char *,size_t,
                           unsigned char *, size_t *, pininfo_t *);
   int (*check_pinpad)(int, int, pininfo_t *);
@@ -123,11 +119,6 @@ struct reader_table_s {
     pcsc_dword_t modify_ioctl;
     int pinmin;
     int pinmax;
-#ifdef NEED_PCSC_WRAPPER
-    int req_fd;
-    int rsp_fd;
-    pid_t pid;
-#endif /*NEED_PCSC_WRAPPER*/
   } pcsc;
 #ifdef USE_G10CODE_RAPDU
   struct {
@@ -135,21 +126,17 @@ struct reader_table_s {
   } rapdu;
 #endif /*USE_G10CODE_RAPDU*/
   char *rdrname;     /* Name of the connected reader or NULL if unknown. */
-  int any_status;    /* True if we have seen any status.  */
-  int last_status;
-  int status;
-  int is_t0;         /* True if we know that we are running T=0. */
-  int is_spr532;     /* True if we know that the reader is a SPR532.  */
-  int pinpad_varlen_supported;  /* True if we know that the reader
-                                   supports variable length pinpad
-                                   input.  */
+  unsigned int is_t0:1;     /* True if we know that we are running T=0. */
+  unsigned int is_spr532:1; /* True if we know that the reader is a SPR532.  */
+  unsigned int pinpad_varlen_supported:1;  /* True if we know that the reader
+                                              supports variable length pinpad
+                                              input.  */
+  unsigned int require_get_status:1;
   unsigned char atr[33];
   size_t atrlen;           /* A zero length indicates that the ATR has
                               not yet been read; i.e. the card is not
                               ready for use. */
-  unsigned int change_counter;
 #ifdef USE_NPTH
-  int lock_initialized;
   npth_mutex_t lock;
 #endif
 };
@@ -158,14 +145,10 @@ typedef struct reader_table_s *reader_table_t;
 /* A global table to keep track of active readers. */
 static struct reader_table_s reader_table[MAX_READER];
 
+#ifdef USE_NPTH
+static npth_mutex_t reader_table_lock;
+#endif
 
-/* ct API function pointer. */
-static char (* DLSTDCALL CT_init) (unsigned short ctn, unsigned short Pn);
-static char (* DLSTDCALL CT_data) (unsigned short ctn, unsigned char *dad,
-                                   unsigned char *sad, unsigned short lc,
-                                   unsigned char *cmd, unsigned short *lr,
-                                   unsigned char *rsp);
-static char (* DLSTDCALL CT_close) (unsigned short ctn);
 
 /* PC/SC constants and function pointer. */
 #define PCSC_SCOPE_USER      0
@@ -218,7 +201,7 @@ static char (* DLSTDCALL CT_close) (unsigned short ctn);
 #define PCSC_STATE_ATRMATCH    0x0040  /* ATR matches card. */
 #define PCSC_STATE_EXCLUSIVE   0x0080  /* Exclusive Mode.  */
 #define PCSC_STATE_INUSE       0x0100  /* Shared mode.  */
-#define PCSC_STATE_MUTE               0x0200  /* Unresponsive card.  */
+#define PCSC_STATE_MUTE        0x0200  /* Unresponsive card.  */
 #ifdef HAVE_W32_SYSTEM
 # define PCSC_STATE_UNPOWERED  0x0400  /* Card not powerred up.  */
 #endif
@@ -244,14 +227,15 @@ static char (* DLSTDCALL CT_close) (unsigned short ctn);
 #define PCSC_E_NOT_TRANSACTED          0x80100016
 #define PCSC_E_READER_UNAVAILABLE      0x80100017
 #define PCSC_E_NO_SERVICE              0x8010001D
+#define PCSC_E_SERVICE_STOPPED         0x8010001E
 #define PCSC_W_REMOVED_CARD            0x80100069
 
-/* Fix pcsc-lite ABI incompatibilty.  */
+/* Fix pcsc-lite ABI incompatibility.  */
 #ifndef SCARD_CTL_CODE
 #ifdef _WIN32
 #include <winioctl.h>
 #define SCARD_CTL_CODE(code) CTL_CODE(FILE_DEVICE_SMARTCARD, (code), \
-                                     METHOD_BUFFERED, FILE_ANY_ACCESS)
+                                      METHOD_BUFFERED, FILE_ANY_ACCESS)
 #else
 #define SCARD_CTL_CODE(code) (0x42000000 + (code))
 #endif
@@ -358,11 +342,10 @@ long (* DLSTDCALL pcsc_control) (long card,
 
 /*  Prototypes.  */
 static int pcsc_vendor_specific_init (int slot);
-static int pcsc_get_status (int slot, unsigned int *status);
+static int pcsc_get_status (int slot, unsigned int *status, int on_wire);
 static int reset_pcsc_reader (int slot);
-static int apdu_get_status_internal (int slot, int hang, int no_atr_reset,
-                                     unsigned int *status,
-                                     unsigned int *changed);
+static int apdu_get_status_internal (int slot, int hang, unsigned int *status,
+                                     int on_wire);
 static int check_pcsc_pinpad (int slot, int command, pininfo_t *pininfo);
 static int pcsc_pinpad_verify (int slot, int class, int ins, int p0, int p1,
                                pininfo_t *pininfo);
@@ -429,39 +412,30 @@ static int
 new_reader_slot (void)
 {
   int i, reader = -1;
-  int err;
 
   for (i=0; i < MAX_READER; i++)
-    {
-      if (!reader_table[i].used && reader == -1)
+    if (!reader_table[i].used)
+      {
         reader = i;
-    }
+        reader_table[reader].used = 1;
+        break;
+      }
+
   if (reader == -1)
     {
       log_error ("new_reader_slot: out of slots\n");
       return -1;
     }
-#ifdef USE_NPTH
-  if (!reader_table[reader].lock_initialized)
-    {
-      err = npth_mutex_init (&reader_table[reader].lock, NULL);
-      if (err)
-        {
-          log_error ("error initializing mutex: %s\n", strerror (err));
-          return -1;
-        }
-      reader_table[reader].lock_initialized = 1;
-    }
-#endif /*USE_NPTH*/
+
   if (lock_slot (reader))
     {
-      log_error ("error locking mutex: %s\n", strerror (errno));
+      reader_table[reader].used = 0;
       return -1;
     }
+
   reader_table[reader].connect_card = NULL;
   reader_table[reader].disconnect_card = NULL;
   reader_table[reader].close_reader = NULL;
-  reader_table[reader].shutdown_reader = NULL;
   reader_table[reader].reset_reader = NULL;
   reader_table[reader].get_status_reader = NULL;
   reader_table[reader].send_apdu_reader = NULL;
@@ -471,17 +445,10 @@ new_reader_slot (void)
   reader_table[reader].pinpad_verify = pcsc_pinpad_verify;
   reader_table[reader].pinpad_modify = pcsc_pinpad_modify;
 
-  reader_table[reader].used = 1;
-  reader_table[reader].any_status = 0;
-  reader_table[reader].last_status = 0;
   reader_table[reader].is_t0 = 1;
   reader_table[reader].is_spr532 = 0;
   reader_table[reader].pinpad_varlen_supported = 0;
-#ifdef NEED_PCSC_WRAPPER
-  reader_table[reader].pcsc.req_fd = -1;
-  reader_table[reader].pcsc.rsp_fd = -1;
-  reader_table[reader].pcsc.pid = (pid_t)(-1);
-#endif
+  reader_table[reader].require_get_status = 1;
   reader_table[reader].pcsc.verify_ioctl = 0;
   reader_table[reader].pcsc.modify_ioctl = 0;
   reader_table[reader].pcsc.pinmin = -1;
@@ -500,8 +467,7 @@ dump_reader_status (int slot)
   if (reader_table[slot].dump_status_reader)
     reader_table[slot].dump_status_reader (slot);
 
-  if (reader_table[slot].status != -1
-      && reader_table[slot].atrlen)
+  if (reader_table[slot].atrlen)
     {
       log_info ("slot %d: ATR=", slot);
       log_printhex ("", reader_table[slot].atr, reader_table[slot].atrlen);
@@ -568,279 +534,11 @@ apdu_strerror (int rc)
       return "unknown status error";
     }
 }
-
-
-\f
-/*
-       ct API Interface
- */
-
-static const char *
-ct_error_string (long err)
-{
-  switch (err)
-    {
-    case 0: return "okay";
-    case -1: return "invalid data";
-    case -8: return "ct error";
-    case -10: return "transmission error";
-    case -11: return "memory allocation error";
-    case -128: return "HTSI error";
-    default: return "unknown CT-API error";
-    }
-}
-
-
-static void
-ct_dump_reader_status (int slot)
-{
-  log_info ("reader slot %d: %s\n", slot,
-            reader_table[slot].status == 1? "Processor ICC present" :
-            reader_table[slot].status == 0? "Memory ICC present" :
-            "ICC not present" );
-}
-
-
-/* Wait for the card in SLOT and activate it.  Return a status word
-   error or 0 on success. */
-static int
-ct_activate_card (int slot)
-{
-  int rc;
-  unsigned char dad[1], sad[1], cmd[11], buf[256];
-  unsigned short buflen;
-
-  /* Check whether card has been inserted. */
-  dad[0] = 1;     /* Destination address: CT. */
-  sad[0] = 2;     /* Source address: Host. */
-
-  cmd[0] = 0x20;  /* Class byte. */
-  cmd[1] = 0x13;  /* Request status. */
-  cmd[2] = 0x00;  /* From kernel. */
-  cmd[3] = 0x80;  /* Return card's DO. */
-  cmd[4] = 0x00;
-
-  buflen = DIM(buf);
-
-  rc = CT_data (slot, dad, sad, 5, cmd, &buflen, buf);
-  if (rc || buflen < 2 || buf[buflen-2] != 0x90)
-    {
-      log_error ("ct_activate_card: can't get status of reader %d: %s\n",
-                 slot, ct_error_string (rc));
-      return SW_HOST_CARD_IO_ERROR;
-    }
-
-  /* Connected, now activate the card. */
-  dad[0] = 1;    /* Destination address: CT. */
-  sad[0] = 2;    /* Source address: Host. */
-
-  cmd[0] = 0x20;  /* Class byte. */
-  cmd[1] = 0x12;  /* Request ICC. */
-  cmd[2] = 0x01;  /* From first interface. */
-  cmd[3] = 0x01;  /* Return card's ATR. */
-  cmd[4] = 0x00;
-
-  buflen = DIM(buf);
-
-  rc = CT_data (slot, dad, sad, 5, cmd, &buflen, buf);
-  if (rc || buflen < 2 || buf[buflen-2] != 0x90)
-    {
-      log_error ("ct_activate_card(%d): activation failed: %s\n",
-                 slot, ct_error_string (rc));
-      if (!rc)
-        log_printhex ("  received data:", buf, buflen);
-      return SW_HOST_CARD_IO_ERROR;
-    }
-
-  /* Store the type and the ATR. */
-  if (buflen - 2 > DIM (reader_table[0].atr))
-    {
-      log_error ("ct_activate_card(%d): ATR too long\n", slot);
-      return SW_HOST_CARD_IO_ERROR;
-    }
-
-  reader_table[slot].status = buf[buflen - 1];
-  memcpy (reader_table[slot].atr, buf, buflen - 2);
-  reader_table[slot].atrlen = buflen - 2;
-  return 0;
-}
-
-
-static int
-close_ct_reader (int slot)
-{
-  CT_close (slot);
-  reader_table[slot].used = 0;
-  return 0;
-}
-
-static int
-reset_ct_reader (int slot)
-{
-  /* FIXME: Check is this is sufficient do do a reset. */
-  return ct_activate_card (slot);
-}
-
-
-static int
-ct_get_status (int slot, unsigned int *status)
-{
-  (void)slot;
-  /* The status we returned is wrong but we don't care becuase ctAPI
-     is not anymore required.  */
-  *status = APDU_CARD_USABLE|APDU_CARD_PRESENT|APDU_CARD_ACTIVE;
-  return 0;
-}
-
-/* Actually send the APDU of length APDULEN to SLOT and return a
-   maximum of *BUFLEN data in BUFFER, the actual retruned size will be
-   set to BUFLEN.  Returns: CT API error code. */
-static int
-ct_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
-              unsigned char *buffer, size_t *buflen, pininfo_t *pininfo)
-{
-  int rc;
-  unsigned char dad[1], sad[1];
-  unsigned short ctbuflen;
-
-  (void)pininfo;
-
-  /* If we don't have an ATR, we need to reset the reader first. */
-  if (!reader_table[slot].atrlen
-      && (rc = reset_ct_reader (slot)))
-    return rc;
-
-  dad[0] = 0;     /* Destination address: Card. */
-  sad[0] = 2;     /* Source address: Host. */
-  ctbuflen = *buflen;
-  if (DBG_CARD_IO)
-    log_printhex ("  CT_data:", apdu, apdulen);
-  rc = CT_data (slot, dad, sad, apdulen, apdu, &ctbuflen, buffer);
-  *buflen = ctbuflen;
-
-  return rc? SW_HOST_CARD_IO_ERROR: 0;
-}
-
-
-
-/* Open a reader and return an internal handle for it.  PORT is a
-   non-negative value with the port number of the reader. USB readers
-   do have port numbers starting at 32769. */
-static int
-open_ct_reader (int port)
-{
-  int rc, reader;
-
-  if (port < 0 || port > 0xffff)
-    {
-      log_error ("open_ct_reader: invalid port %d requested\n", port);
-      return -1;
-    }
-  reader = new_reader_slot ();
-  if (reader == -1)
-    return reader;
-  reader_table[reader].port = port;
-
-  rc = CT_init (reader, (unsigned short)port);
-  if (rc)
-    {
-      log_error ("apdu_open_ct_reader failed on port %d: %s\n",
-                 port, ct_error_string (rc));
-      reader_table[reader].used = 0;
-      unlock_slot (reader);
-      return -1;
-    }
-
-  /* Only try to activate the card. */
-  rc = ct_activate_card (reader);
-  if (rc)
-    {
-      reader_table[reader].atrlen = 0;
-      rc = 0;
-    }
-
-  reader_table[reader].close_reader = close_ct_reader;
-  reader_table[reader].reset_reader = reset_ct_reader;
-  reader_table[reader].get_status_reader = ct_get_status;
-  reader_table[reader].send_apdu_reader = ct_send_apdu;
-  reader_table[reader].check_pinpad = NULL;
-  reader_table[reader].dump_status_reader = ct_dump_reader_status;
-  reader_table[reader].pinpad_verify = NULL;
-  reader_table[reader].pinpad_modify = NULL;
-
-  dump_reader_status (reader);
-  unlock_slot (reader);
-  return reader;
-}
-
 \f
 /*
        PC/SC Interface
  */
 
-#ifdef NEED_PCSC_WRAPPER
-static int
-writen (int fd, const void *buf, size_t nbytes)
-{
-  size_t nleft = nbytes;
-  int nwritten;
-
-/*   log_printhex (" writen:", buf, nbytes); */
-
-  while (nleft > 0)
-    {
-#ifdef USE_NPTH
-      nwritten = npth_write (fd, buf, nleft);
-#else
-      nwritten = write (fd, buf, nleft);
-#endif
-      if (nwritten < 0 && errno == EINTR)
-        continue;
-      if (nwritten < 0)
-        return -1;
-      nleft -= nwritten;
-      buf = (const char*)buf + nwritten;
-    }
-  return 0;
-}
-
-/* Read up to BUFLEN bytes from FD and return the number of bytes
-   actually read in NREAD.  Returns -1 on error or 0 on success. */
-static int
-readn (int fd, void *buf, size_t buflen, size_t *nread)
-{
-  size_t nleft = buflen;
-  int n;
-/*   void *orig_buf = buf; */
-
-  while (nleft > 0)
-    {
-#ifdef USE_NPTH
-# ifdef HAVE_W32_SYSTEM
-#  error Cannot use npth_read here because it expects a system HANDLE.
-# endif
-      n = npth_read (fd, buf, nleft);
-#else
-      n = read (fd, buf, nleft);
-#endif
-      if (n < 0 && errno == EINTR)
-        continue;
-      if (n < 0)
-        return -1; /* read error. */
-      if (!n)
-        break; /* EOF */
-      nleft -= n;
-      buf = (char*)buf + n;
-    }
-  if (nread)
-    *nread = buflen - nleft;
-
-/*   log_printhex ("  readn:", orig_buf, *nread); */
-
-  return 0;
-}
-#endif /*NEED_PCSC_WRAPPER*/
-
 static const char *
 pcsc_error_string (long err)
 {
@@ -907,6 +605,8 @@ pcsc_error_to_sw (long ec)
     case PCSC_E_CANCELLED:           rc = SW_HOST_ABORTED; break;
     case PCSC_E_NO_MEMORY:           rc = SW_HOST_OUT_OF_CORE; break;
     case PCSC_E_TIMEOUT:             rc = SW_HOST_CARD_IO_ERROR; break;
+    case PCSC_E_NO_SERVICE:
+    case PCSC_E_SERVICE_STOPPED:
     case PCSC_E_UNKNOWN_READER:      rc = SW_HOST_NO_READER; break;
     case PCSC_E_SHARING_VIOLATION:   rc = SW_HOST_LOCKING_FAILED; break;
     case PCSC_E_NO_SMARTCARD:        rc = SW_HOST_NO_CARD; break;
@@ -943,13 +643,13 @@ dump_pcsc_reader_status (int slot)
 }
 
 
-#ifndef NEED_PCSC_WRAPPER
 static int
-pcsc_get_status_direct (int slot, unsigned int *status)
+pcsc_get_status (int slot, unsigned int *status, int on_wire)
 {
   long err;
   struct pcsc_readerstate_s rdrstates[1];
 
+  (void)on_wire;
   memset (rdrstates, 0, sizeof *rdrstates);
   rdrstates[0].reader = reader_table[slot].rdrname;
   rdrstates[0].current_state = PCSC_STATE_UNAWARE;
@@ -983,7 +683,7 @@ pcsc_get_status_direct (int slot, unsigned int *status)
     {
       *status |= APDU_CARD_PRESENT;
       if ( !(rdrstates[0].event_state & PCSC_STATE_MUTE) )
-       *status |= APDU_CARD_ACTIVE;
+        *status |= APDU_CARD_ACTIVE;
     }
 #ifndef HAVE_W32_SYSTEM
   /* We indicate a useful card if it is not in use by another
@@ -1003,135 +703,15 @@ pcsc_get_status_direct (int slot, unsigned int *status)
 
   return 0;
 }
-#endif /*!NEED_PCSC_WRAPPER*/
-
-
-#ifdef NEED_PCSC_WRAPPER
-static int
-pcsc_get_status_wrapped (int slot, unsigned int *status)
-{
-  long err;
-  reader_table_t slotp;
-  size_t len, full_len;
-  int i, n;
-  unsigned char msgbuf[9];
-  unsigned char buffer[16];
-  int sw = SW_HOST_CARD_IO_ERROR;
-
-  slotp = reader_table + slot;
-
-  if (slotp->pcsc.req_fd == -1
-      || slotp->pcsc.rsp_fd == -1
-      || slotp->pcsc.pid == (pid_t)(-1) )
-    {
-      log_error ("pcsc_get_status: pcsc-wrapper not running\n");
-      return sw;
-    }
-
-  msgbuf[0] = 0x04; /* STATUS command. */
-  len = 0;
-  msgbuf[1] = (len >> 24);
-  msgbuf[2] = (len >> 16);
-  msgbuf[3] = (len >>  8);
-  msgbuf[4] = (len      );
-  if ( writen (slotp->pcsc.req_fd, msgbuf, 5) )
-    {
-      log_error ("error sending PC/SC STATUS request: %s\n",
-                 strerror (errno));
-      goto command_failed;
-    }
-
-  /* Read the response. */
-  if ((i=readn (slotp->pcsc.rsp_fd, msgbuf, 9, &len)) || len != 9)
-    {
-      log_error ("error receiving PC/SC STATUS response: %s\n",
-                 i? strerror (errno) : "premature EOF");
-      goto command_failed;
-    }
-  len = buf_to_size_t (msgbuf+1);
-  if (msgbuf[0] != 0x81 || len < 4)
-    {
-      log_error ("invalid response header from PC/SC received\n");
-      goto command_failed;
-    }
-  len -= 4; /* Already read the error code. */
-  err = PCSC_ERR_MASK (buf32_to_ulong (msgbuf+5));
-  if (err)
-    {
-      log_error ("pcsc_status failed: %s (0x%lx)\n",
-                 pcsc_error_string (err), err);
-      /* This is a proper error code, so return immediately.  */
-      return pcsc_error_to_sw (err);
-    }
-
-  full_len = len;
-
-  /* The current version returns 3 words but we allow also for old
-     versions returning only 2 words. */
-  n = 12 < len ? 12 : len;
-  if ((i=readn (slotp->pcsc.rsp_fd, buffer, n, &len))
-      || (len != 8 && len != 12))
-    {
-      log_error ("error receiving PC/SC STATUS response: %s\n",
-                 i? strerror (errno) : "premature EOF");
-      goto command_failed;
-    }
-
-  slotp->is_t0 = (len == 12 && !!(buffer[11] & PCSC_PROTOCOL_T0));
-
-
-  full_len -= len;
-  /* Newer versions of the wrapper might send more status bytes.
-     Read them. */
-  while (full_len)
-    {
-      unsigned char dummybuf[128];
-
-      n = full_len < DIM (dummybuf) ? full_len : DIM (dummybuf);
-      if ((i=readn (slotp->pcsc.rsp_fd, dummybuf, n, &len)) || len != n)
-        {
-          log_error ("error receiving PC/SC TRANSMIT response: %s\n",
-                     i? strerror (errno) : "premature EOF");
-          goto command_failed;
-        }
-      full_len -= n;
-    }
-
-  /* We are lucky: The wrapper already returns the data in the
-     required format. */
-  *status = buffer[3];
-  return 0;
-
- command_failed:
-  close (slotp->pcsc.req_fd);
-  close (slotp->pcsc.rsp_fd);
-  slotp->pcsc.req_fd = -1;
-  slotp->pcsc.rsp_fd = -1;
-  if (slotp->pcsc.pid != -1)
-    kill (slotp->pcsc.pid, SIGTERM);
-  slotp->pcsc.pid = (pid_t)(-1);
-  slotp->used = 0;
-  return sw;
-}
-#endif /*NEED_PCSC_WRAPPER*/
-
-
-static int
-pcsc_get_status (int slot, unsigned int *status)
-{
-#ifdef NEED_PCSC_WRAPPER
-  return pcsc_get_status_wrapped (slot, status);
-#else
-  return pcsc_get_status_direct (slot, status);
-#endif
-}
 
 
-#ifndef NEED_PCSC_WRAPPER
+/* Send the APDU of length APDULEN to SLOT and return a maximum of
+   *BUFLEN data in BUFFER, the actual returned size will be stored at
+   BUFLEN.  Returns: A status word. */
 static int
-pcsc_send_apdu_direct (int slot, unsigned char *apdu, size_t apdulen,
-                       unsigned char *buffer, size_t *buflen,
-                       pininfo_t *pininfo)
+pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
+                unsigned char *buffer, size_t *buflen,
+                pininfo_t *pininfo)
 {
   long err;
   struct pcsc_io_request_s send_pci;
@@ -1162,387 +742,44 @@ pcsc_send_apdu_direct (int slot, unsigned char *apdu, size_t apdulen,
 
   return pcsc_error_to_sw (err);
 }
-#endif /*!NEED_PCSC_WRAPPER*/
 
 
-#ifdef NEED_PCSC_WRAPPER
+/* Do some control with the value of IOCTL_CODE to the card inserted
+   to SLOT.  Input buffer is specified by CNTLBUF of length LEN.
+   Output buffer is specified by BUFFER of length *BUFLEN, and the
+   actual output size will be stored at BUFLEN.  Returns: A status word.
+   This routine is used for PIN pad input support.  */
 static int
-pcsc_send_apdu_wrapped (int slot, unsigned char *apdu, size_t apdulen,
-                        unsigned char *buffer, size_t *buflen,
-                        pininfo_t *pininfo)
+control_pcsc (int slot, pcsc_dword_t ioctl_code,
+              const unsigned char *cntlbuf, size_t len,
+              unsigned char *buffer, pcsc_dword_t *buflen)
 {
   long err;
-  reader_table_t slotp;
-  size_t len, full_len;
-  int i, n;
-  unsigned char msgbuf[9];
-  int sw = SW_HOST_CARD_IO_ERROR;
-
-  (void)pininfo;
-
-  if (!reader_table[slot].atrlen
-      && (err = reset_pcsc_reader (slot)))
-    return err;
-
-  if (DBG_CARD_IO)
-    log_printhex ("  PCSC_data:", apdu, apdulen);
-
-  slotp = reader_table + slot;
-
-  if (slotp->pcsc.req_fd == -1
-      || slotp->pcsc.rsp_fd == -1
-      || slotp->pcsc.pid == (pid_t)(-1) )
-    {
-      log_error ("pcsc_send_apdu: pcsc-wrapper not running\n");
-      return sw;
-    }
-
-  msgbuf[0] = 0x03; /* TRANSMIT command. */
-  len = apdulen;
-  msgbuf[1] = (len >> 24);
-  msgbuf[2] = (len >> 16);
-  msgbuf[3] = (len >>  8);
-  msgbuf[4] = (len      );
-  if ( writen (slotp->pcsc.req_fd, msgbuf, 5)
-       || writen (slotp->pcsc.req_fd, apdu, len))
-    {
-      log_error ("error sending PC/SC TRANSMIT request: %s\n",
-                 strerror (errno));
-      goto command_failed;
-    }
 
-  /* Read the response. */
-  if ((i=readn (slotp->pcsc.rsp_fd, msgbuf, 9, &len)) || len != 9)
-    {
-      log_error ("error receiving PC/SC TRANSMIT response: %s\n",
-                 i? strerror (errno) : "premature EOF");
-      goto command_failed;
-    }
-  len = buf_to_size_t (msgbuf+1);
-  if (msgbuf[0] != 0x81 || len < 4)
-    {
-      log_error ("invalid response header from PC/SC received\n");
-      goto command_failed;
-    }
-  len -= 4; /* Already read the error code. */
-  err = PCSC_ERR_MASK (buf32_to_ulong (msgbuf+5));
+  err = pcsc_control (reader_table[slot].pcsc.card, ioctl_code,
+                      cntlbuf, len, buffer, buflen? *buflen:0, buflen);
   if (err)
     {
-      log_error ("pcsc_transmit failed: %s (0x%lx)\n",
+      log_error ("pcsc_control failed: %s (0x%lx)\n",
                  pcsc_error_string (err), err);
       return pcsc_error_to_sw (err);
     }
 
-   full_len = len;
-
-   n = *buflen < len ? *buflen : len;
-   if ((i=readn (slotp->pcsc.rsp_fd, buffer, n, &len)) || len != n)
-     {
-       log_error ("error receiving PC/SC TRANSMIT response: %s\n",
-                  i? strerror (errno) : "premature EOF");
-       goto command_failed;
-     }
-   *buflen = n;
-
-   full_len -= len;
-   if (full_len)
-     {
-       log_error ("pcsc_send_apdu: provided buffer too short - truncated\n");
-       err = SW_HOST_INV_VALUE;
-     }
-   /* We need to read any rest of the response, to keep the
-      protocol running.  */
-   while (full_len)
-     {
-       unsigned char dummybuf[128];
-
-       n = full_len < DIM (dummybuf) ? full_len : DIM (dummybuf);
-       if ((i=readn (slotp->pcsc.rsp_fd, dummybuf, n, &len)) || len != n)
-         {
-           log_error ("error receiving PC/SC TRANSMIT response: %s\n",
-                      i? strerror (errno) : "premature EOF");
-           goto command_failed;
-         }
-       full_len -= n;
-     }
-
-   return err;
-
- command_failed:
-  close (slotp->pcsc.req_fd);
-  close (slotp->pcsc.rsp_fd);
-  slotp->pcsc.req_fd = -1;
-  slotp->pcsc.rsp_fd = -1;
-  if (slotp->pcsc.pid != -1)
-    kill (slotp->pcsc.pid, SIGTERM);
-  slotp->pcsc.pid = (pid_t)(-1);
-  slotp->used = 0;
-  return sw;
+  return 0;
 }
-#endif /*NEED_PCSC_WRAPPER*/
 
 
-/* Send the APDU of length APDULEN to SLOT and return a maximum of
-   *BUFLEN data in BUFFER, the actual returned size will be stored at
-   BUFLEN.  Returns: A status word. */
 static int
-pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
-                unsigned char *buffer, size_t *buflen,
-                pininfo_t *pininfo)
+close_pcsc_reader (int slot)
 {
-#ifdef NEED_PCSC_WRAPPER
-  return pcsc_send_apdu_wrapped (slot, apdu, apdulen, buffer, buflen, pininfo);
-#else
-  return pcsc_send_apdu_direct (slot, apdu, apdulen, buffer, buflen, pininfo);
-#endif
+  pcsc_release_context (reader_table[slot].pcsc.context);
+  return 0;
 }
 
 
-#ifndef NEED_PCSC_WRAPPER
+/* Connect a PC/SC card.  */
 static int
-control_pcsc_direct (int slot, pcsc_dword_t ioctl_code,
-                     const unsigned char *cntlbuf, size_t len,
-                     unsigned char *buffer, pcsc_dword_t *buflen)
-{
-  long err;
-
-  err = pcsc_control (reader_table[slot].pcsc.card, ioctl_code,
-                      cntlbuf, len, buffer, buflen? *buflen:0, buflen);
-  if (err)
-    {
-      log_error ("pcsc_control failed: %s (0x%lx)\n",
-                 pcsc_error_string (err), err);
-      return pcsc_error_to_sw (err);
-    }
-
-  return 0;
-}
-#endif /*!NEED_PCSC_WRAPPER*/
-
-
-#ifdef NEED_PCSC_WRAPPER
-static int
-control_pcsc_wrapped (int slot, pcsc_dword_t ioctl_code,
-                      const unsigned char *cntlbuf, size_t len,
-                      unsigned char *buffer, pcsc_dword_t *buflen)
-{
-  long err = PCSC_E_NOT_TRANSACTED;
-  reader_table_t slotp;
-  unsigned char msgbuf[9];
-  int i, n;
-  size_t full_len;
-
-  slotp = reader_table + slot;
-
-  msgbuf[0] = 0x06; /* CONTROL command. */
-  msgbuf[1] = ((len + 4) >> 24);
-  msgbuf[2] = ((len + 4) >> 16);
-  msgbuf[3] = ((len + 4) >>  8);
-  msgbuf[4] = ((len + 4)      );
-  msgbuf[5] = (ioctl_code >> 24);
-  msgbuf[6] = (ioctl_code >> 16);
-  msgbuf[7] = (ioctl_code >>  8);
-  msgbuf[8] = (ioctl_code      );
-  if ( writen (slotp->pcsc.req_fd, msgbuf, 9)
-       || writen (slotp->pcsc.req_fd, cntlbuf, len))
-    {
-      log_error ("error sending PC/SC CONTROL request: %s\n",
-                 strerror (errno));
-      goto command_failed;
-    }
-
-  /* Read the response. */
-  if ((i=readn (slotp->pcsc.rsp_fd, msgbuf, 9, &len)) || len != 9)
-    {
-      log_error ("error receiving PC/SC CONTROL response: %s\n",
-                 i? strerror (errno) : "premature EOF");
-      goto command_failed;
-    }
-  len = buf32_to_size_t (msgbuf+1);
-  if (msgbuf[0] != 0x81 || len < 4)
-    {
-      log_error ("invalid response header from PC/SC received\n");
-      goto command_failed;
-    }
-  len -= 4; /* Already read the error code. */
-  err = PCSC_ERR_MASK (buf32_to_ulong (msgbuf+5));
-  if (err)
-    {
-      log_error ("pcsc_control failed: %s (0x%lx)\n",
-                 pcsc_error_string (err), err);
-      return pcsc_error_to_sw (err);
-    }
-
-  full_len = len;
-
-  if (buflen)
-    n = *buflen < len ? *buflen : len;
-  else
-    n = 0;
-  if ((i=readn (slotp->pcsc.rsp_fd, buffer, n, &len)) || len != n)
-    {
-      log_error ("error receiving PC/SC CONTROL response: %s\n",
-                 i? strerror (errno) : "premature EOF");
-      goto command_failed;
-    }
-  if (buflen)
-    *buflen = n;
-
-  full_len -= len;
-  if (full_len)
-    {
-      log_error ("pcsc_send_apdu: provided buffer too short - truncated\n");
-      err = PCSC_E_INVALID_VALUE;
-    }
-  /* We need to read any rest of the response, to keep the
-     protocol running.  */
-  while (full_len)
-    {
-      unsigned char dummybuf[128];
-
-      n = full_len < DIM (dummybuf) ? full_len : DIM (dummybuf);
-      if ((i=readn (slotp->pcsc.rsp_fd, dummybuf, n, &len)) || len != n)
-        {
-          log_error ("error receiving PC/SC CONTROL response: %s\n",
-                     i? strerror (errno) : "premature EOF");
-          goto command_failed;
-        }
-      full_len -= n;
-    }
-
-  if (!err)
-    return 0;
-
- command_failed:
-  close (slotp->pcsc.req_fd);
-  close (slotp->pcsc.rsp_fd);
-  slotp->pcsc.req_fd = -1;
-  slotp->pcsc.rsp_fd = -1;
-  if (slotp->pcsc.pid != -1)
-    kill (slotp->pcsc.pid, SIGTERM);
-  slotp->pcsc.pid = (pid_t)(-1);
-  slotp->used = 0;
-  return pcsc_error_to_sw (err);
-}
-#endif /*NEED_PCSC_WRAPPER*/
-
-
-
-/* Do some control with the value of IOCTL_CODE to the card inserted
-   to SLOT.  Input buffer is specified by CNTLBUF of length LEN.
-   Output buffer is specified by BUFFER of length *BUFLEN, and the
-   actual output size will be stored at BUFLEN.  Returns: A status word.
-   This routine is used for PIN pad input support.  */
-static int
-control_pcsc (int slot, pcsc_dword_t ioctl_code,
-              const unsigned char *cntlbuf, size_t len,
-              unsigned char *buffer, pcsc_dword_t *buflen)
-{
-#ifdef NEED_PCSC_WRAPPER
-  return control_pcsc_wrapped (slot, ioctl_code, cntlbuf, len, buffer, buflen);
-#else
-  return control_pcsc_direct (slot, ioctl_code, cntlbuf, len, buffer, buflen);
-#endif
-}
-
-
-#ifndef NEED_PCSC_WRAPPER
-static int
-close_pcsc_reader_direct (int slot)
-{
-  pcsc_release_context (reader_table[slot].pcsc.context);
-  xfree (reader_table[slot].rdrname);
-  reader_table[slot].rdrname = NULL;
-  reader_table[slot].used = 0;
-  return 0;
-}
-#endif /*!NEED_PCSC_WRAPPER*/
-
-
-#ifdef NEED_PCSC_WRAPPER
-static int
-close_pcsc_reader_wrapped (int slot)
-{
-  long err;
-  reader_table_t slotp;
-  size_t len;
-  int i;
-  unsigned char msgbuf[9];
-
-  slotp = reader_table + slot;
-
-  if (slotp->pcsc.req_fd == -1
-      || slotp->pcsc.rsp_fd == -1
-      || slotp->pcsc.pid == (pid_t)(-1) )
-    {
-      log_error ("close_pcsc_reader: pcsc-wrapper not running\n");
-      return 0;
-    }
-
-  msgbuf[0] = 0x02; /* CLOSE command. */
-  len = 0;
-  msgbuf[1] = (len >> 24);
-  msgbuf[2] = (len >> 16);
-  msgbuf[3] = (len >>  8);
-  msgbuf[4] = (len      );
-  if ( writen (slotp->pcsc.req_fd, msgbuf, 5) )
-    {
-      log_error ("error sending PC/SC CLOSE request: %s\n",
-                 strerror (errno));
-      goto command_failed;
-    }
-
-  /* Read the response. */
-  if ((i=readn (slotp->pcsc.rsp_fd, msgbuf, 9, &len)) || len != 9)
-    {
-      log_error ("error receiving PC/SC CLOSE response: %s\n",
-                 i? strerror (errno) : "premature EOF");
-      goto command_failed;
-    }
-  len = buf32_to_size_t (msgbuf+1);
-  if (msgbuf[0] != 0x81 || len < 4)
-    {
-      log_error ("invalid response header from PC/SC received\n");
-      goto command_failed;
-    }
-  len -= 4; /* Already read the error code. */
-  err = PCSC_ERR_MASK (buf32_to_ulong (msgbuf+5));
-  if (err)
-    log_error ("pcsc_close failed: %s (0x%lx)\n",
-               pcsc_error_string (err), err);
-
-  /* We will close the wrapper in any case - errors are merely
-     informational. */
-
- command_failed:
-  close (slotp->pcsc.req_fd);
-  close (slotp->pcsc.rsp_fd);
-  slotp->pcsc.req_fd = -1;
-  slotp->pcsc.rsp_fd = -1;
-  if (slotp->pcsc.pid != -1)
-    kill (slotp->pcsc.pid, SIGTERM);
-  slotp->pcsc.pid = (pid_t)(-1);
-  slotp->used = 0;
-  return 0;
-}
-#endif /*NEED_PCSC_WRAPPER*/
-
-
-static int
-close_pcsc_reader (int slot)
-{
-#ifdef NEED_PCSC_WRAPPER
-  return close_pcsc_reader_wrapped (slot);
-#else
-  return close_pcsc_reader_direct (slot);
-#endif
-}
-
-
-/* Connect a PC/SC card.  */
-#ifndef NEED_PCSC_WRAPPER
-static int
-connect_pcsc_card (int slot)
+connect_pcsc_card (int slot)
 {
   long err;
 
@@ -1552,7 +789,6 @@ connect_pcsc_card (int slot)
     return SW_HOST_ALREADY_CONNECTED;
 
   reader_table[slot].atrlen = 0;
-  reader_table[slot].last_status = 0;
   reader_table[slot].is_t0 = 0;
 
   err = pcsc_connect (reader_table[slot].pcsc.context,
@@ -1590,11 +826,6 @@ connect_pcsc_card (int slot)
           if (atrlen > DIM (reader_table[0].atr))
             log_bug ("ATR returned by pcsc_status is too large\n");
           reader_table[slot].atrlen = atrlen;
-          /* If we got to here we know that a card is present
-             and usable.  Remember this.  */
-          reader_table[slot].last_status = (   APDU_CARD_USABLE
-                                             | APDU_CARD_PRESENT
-                                             | APDU_CARD_ACTIVE);
           reader_table[slot].is_t0 = !!(card_protocol & PCSC_PROTOCOL_T0);
         }
     }
@@ -1602,12 +833,8 @@ connect_pcsc_card (int slot)
   dump_reader_status (slot);
   return pcsc_error_to_sw (err);
 }
-#endif /*!NEED_PCSC_WRAPPER*/
 
 
-/* Disconnect a PC/SC card.  Note that this succeeds even if the card
-   is not connected.  */
-#ifndef NEED_PCSC_WRAPPER
 static int
 disconnect_pcsc_card (int slot)
 {
@@ -1628,12 +855,12 @@ disconnect_pcsc_card (int slot)
   reader_table[slot].pcsc.card = 0;
   return 0;
 }
-#endif /*!NEED_PCSC_WRAPPER*/
 
 
-#ifndef NEED_PCSC_WRAPPER
+/* Send an PC/SC reset command and return a status word on error or 0
+   on success. */
 static int
-reset_pcsc_reader_direct (int slot)
+reset_pcsc_reader (int slot)
 {
   int sw;
 
@@ -1643,122 +870,6 @@ reset_pcsc_reader_direct (int slot)
 
   return sw;
 }
-#endif /*NEED_PCSC_WRAPPER*/
-
-
-#ifdef NEED_PCSC_WRAPPER
-static int
-reset_pcsc_reader_wrapped (int slot)
-{
-  long err;
-  reader_table_t slotp;
-  size_t len;
-  int i, n;
-  unsigned char msgbuf[9];
-  unsigned int dummy_status;
-  int sw = SW_HOST_CARD_IO_ERROR;
-
-  slotp = reader_table + slot;
-
-  if (slotp->pcsc.req_fd == -1
-      || slotp->pcsc.rsp_fd == -1
-      || slotp->pcsc.pid == (pid_t)(-1) )
-    {
-      log_error ("pcsc_get_status: pcsc-wrapper not running\n");
-      return sw;
-    }
-
-  msgbuf[0] = 0x05; /* RESET command. */
-  len = 0;
-  msgbuf[1] = (len >> 24);
-  msgbuf[2] = (len >> 16);
-  msgbuf[3] = (len >>  8);
-  msgbuf[4] = (len      );
-  if ( writen (slotp->pcsc.req_fd, msgbuf, 5) )
-    {
-      log_error ("error sending PC/SC RESET request: %s\n",
-                 strerror (errno));
-      goto command_failed;
-    }
-
-  /* Read the response. */
-  if ((i=readn (slotp->pcsc.rsp_fd, msgbuf, 9, &len)) || len != 9)
-    {
-      log_error ("error receiving PC/SC RESET response: %s\n",
-                 i? strerror (errno) : "premature EOF");
-      goto command_failed;
-    }
-  len = buf32_to_size_t (msgbuf+1);
-  if (msgbuf[0] != 0x81 || len < 4)
-    {
-      log_error ("invalid response header from PC/SC received\n");
-      goto command_failed;
-    }
-  len -= 4; /* Already read the error code. */
-  if (len > DIM (slotp->atr))
-    {
-      log_error ("PC/SC returned a too large ATR (len=%lx)\n",
-                 (unsigned long)len);
-      sw = SW_HOST_GENERAL_ERROR;
-      goto command_failed;
-    }
-  err = PCSC_ERR_MASK (buf32_to_ulong (msgbuf+5));
-  if (err)
-    {
-      log_error ("PC/SC RESET failed: %s (0x%lx)\n",
-                 pcsc_error_string (err), err);
-      /* If the error code is no smart card, we should not considere
-         this a major error and close the wrapper.  */
-      sw = pcsc_error_to_sw (err);
-      if (err == PCSC_E_NO_SMARTCARD)
-        return sw;
-      goto command_failed;
-    }
-
-  /* The open function may return a zero for the ATR length to
-     indicate that no card is present.  */
-  n = len;
-  if (n)
-    {
-      if ((i=readn (slotp->pcsc.rsp_fd, slotp->atr, n, &len)) || len != n)
-        {
-          log_error ("error receiving PC/SC RESET response: %s\n",
-                     i? strerror (errno) : "premature EOF");
-          goto command_failed;
-        }
-    }
-  slotp->atrlen = len;
-
-  /* Read the status so that IS_T0 will be set. */
-  pcsc_get_status (slot, &dummy_status);
-
-  return 0;
-
- command_failed:
-  close (slotp->pcsc.req_fd);
-  close (slotp->pcsc.rsp_fd);
-  slotp->pcsc.req_fd = -1;
-  slotp->pcsc.rsp_fd = -1;
-  if (slotp->pcsc.pid != -1)
-    kill (slotp->pcsc.pid, SIGTERM);
-  slotp->pcsc.pid = (pid_t)(-1);
-  slotp->used = 0;
-  return sw;
-}
-#endif /* !NEED_PCSC_WRAPPER */
-
-
-/* Send an PC/SC reset command and return a status word on error or 0
-   on success. */
-static int
-reset_pcsc_reader (int slot)
-{
-#ifdef NEED_PCSC_WRAPPER
-  return reset_pcsc_reader_wrapped (slot);
-#else
-  return reset_pcsc_reader_direct (slot);
-#endif
-}
 
 
 /* Examine reader specific parameters and initialize.  This is mostly
@@ -1895,8 +1006,12 @@ pcsc_vendor_specific_init (int slot)
       reader_table[slot].is_spr532 = 1;
       reader_table[slot].pinpad_varlen_supported = 1;
     }
-  else if (vendor == 0x046a && product == 0x003e) /* Cherry ST-2xxx */
+  else if (vendor == 0x046a)
     {
+      /* Cherry ST-2xxx (product == 0x003e) supports TPDU level
+       * exchange.  Other products which only support short APDU level
+       * exchange only work with shorter keys like RSA 1024.
+       */
       reader_table[slot].pcsc.pinmax = 15;
       reader_table[slot].pinpad_varlen_supported = 1;
     }
@@ -1912,9 +1027,8 @@ pcsc_vendor_specific_init (int slot)
 
 /* Open the PC/SC reader without using the wrapper.  Returns -1 on
    error or a slot number for the reader.  */
-#ifndef NEED_PCSC_WRAPPER
 static int
-open_pcsc_reader_direct (const char *portstr)
+open_pcsc_reader (const char *portstr)
 {
   long err;
   int slot;
@@ -1942,308 +1056,77 @@ open_pcsc_reader_direct (const char *portstr)
 
   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)
-        {
-          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*/;
-        }
-      err = pcsc_list_readers (reader_table[slot].pcsc.context,
-                               NULL, list, &nreader);
-    }
-  if (err)
-    {
-      log_error ("pcsc_list_readers 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;
-    }
-
-  if (!rdrname)
-    rdrname = list;
-
-  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);
-      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;
-  reader_table[slot].last_status = 0;
-
-  reader_table[slot].connect_card = connect_pcsc_card;
-  reader_table[slot].disconnect_card = disconnect_pcsc_card;
-  reader_table[slot].close_reader = close_pcsc_reader;
-  reader_table[slot].reset_reader = reset_pcsc_reader;
-  reader_table[slot].get_status_reader = pcsc_get_status;
-  reader_table[slot].send_apdu_reader = pcsc_send_apdu;
-  reader_table[slot].dump_status_reader = dump_pcsc_reader_status;
-
-  dump_reader_status (slot);
-  unlock_slot (slot);
-  return slot;
-}
-#endif /*!NEED_PCSC_WRAPPER */
-
-
-/* Open the PC/SC reader using the pcsc_wrapper program.  This is
-   needed to cope with different thread models and other peculiarities
-   of libpcsclite. */
-#ifdef NEED_PCSC_WRAPPER
-static int
-open_pcsc_reader_wrapped (const char *portstr)
-{
-  int slot;
-  reader_table_t slotp;
-  int fd, rp[2], wp[2];
-  int n, i;
-  pid_t pid;
-  size_t len;
-  unsigned char msgbuf[9];
-  int err;
-  unsigned int dummy_status;
-
-  /* Note that we use the constant and not the fucntion because this
-     code won't be be used under Windows.  */
-  const char *wrapperpgm = GNUPG_LIBEXECDIR "/gnupg-pcsc-wrapper";
-
-  if (access (wrapperpgm, X_OK))
-    {
-      log_error ("can't run PC/SC access module '%s': %s\n",
-                 wrapperpgm, strerror (errno));
-      return -1;
-    }
-
-  slot = new_reader_slot ();
-  if (slot == -1)
-    return -1;
-  slotp = reader_table + slot;
-
-  /* Fire up the PC/SCc wrapper.  We don't use any fork/exec code from
-     the common directy but implement it directly so that this file
-     may still be source copied. */
-
-  if (pipe (rp) == -1)
-    {
-      log_error ("error creating a pipe: %s\n", strerror (errno));
-      slotp->used = 0;
-      unlock_slot (slot);
-      return -1;
-    }
-  if (pipe (wp) == -1)
-    {
-      log_error ("error creating a pipe: %s\n", strerror (errno));
-      close (rp[0]);
-      close (rp[1]);
-      slotp->used = 0;
-      unlock_slot (slot);
-      return -1;
-    }
-
-  pid = fork ();
-  if (pid == -1)
-    {
-      log_error ("error forking process: %s\n", strerror (errno));
-      close (rp[0]);
-      close (rp[1]);
-      close (wp[0]);
-      close (wp[1]);
-      slotp->used = 0;
-      unlock_slot (slot);
-      return -1;
-    }
-  slotp->pcsc.pid = pid;
-
-  if (!pid)
-    { /*
-         === Child ===
-       */
-
-      /* Double fork. */
-      pid = fork ();
-      if (pid == -1)
-        _exit (31);
-      if (pid)
-        _exit (0); /* Immediate exit this parent, so that the child
-                      gets cleaned up by the init process. */
-
-      /* Connect our pipes. */
-      if (wp[0] != 0 && dup2 (wp[0], 0) == -1)
-        log_fatal ("dup2 stdin failed: %s\n", strerror (errno));
-      if (rp[1] != 1 && dup2 (rp[1], 1) == -1)
-        log_fatal ("dup2 stdout failed: %s\n", strerror (errno));
-
-      /* Send stderr to the bit bucket. */
-      fd = open ("/dev/null", O_WRONLY);
-      if (fd == -1)
-        log_fatal ("can't open '/dev/null': %s", strerror (errno));
-      if (fd != 2 && dup2 (fd, 2) == -1)
-        log_fatal ("dup2 stderr failed: %s\n", strerror (errno));
-
-      /* Close all other files. */
-      close_all_fds (3, NULL);
-
-      execl (wrapperpgm,
-             "pcsc-wrapper",
-             "--",
-             "1", /* API version */
-             opt.pcsc_driver, /* Name of the PC/SC library. */
-              NULL);
-      _exit (31);
-    }
-
-  /*
-     === Parent ===
-   */
-  close (wp[0]);
-  close (rp[1]);
-  slotp->pcsc.req_fd = wp[1];
-  slotp->pcsc.rsp_fd = rp[0];
-
-  /* Wait for the intermediate child to terminate. */
-#ifdef USE_NPTH
-#define WAIT npth_waitpid
-#else
-#define WAIT waitpid
-#endif
-  while ( (i=WAIT (pid, NULL, 0)) == -1 && errno == EINTR)
-    ;
-#undef WAIT
-
-  /* Now send the open request. */
-  msgbuf[0] = 0x01; /* OPEN command. */
-  len = portstr? strlen (portstr):0;
-  msgbuf[1] = (len >> 24);
-  msgbuf[2] = (len >> 16);
-  msgbuf[3] = (len >>  8);
-  msgbuf[4] = (len      );
-  if ( writen (slotp->pcsc.req_fd, msgbuf, 5)
-       || (portstr && writen (slotp->pcsc.req_fd, portstr, len)))
-    {
-      log_error ("error sending PC/SC OPEN request: %s\n",
-                 strerror (errno));
-      goto command_failed;
-    }
-  /* Read the response. */
-  if ((i=readn (slotp->pcsc.rsp_fd, msgbuf, 9, &len)) || len != 9)
-    {
-      log_error ("error receiving PC/SC OPEN response: %s\n",
-                 i? strerror (errno) : "premature EOF");
-      goto command_failed;
-    }
-  len = buf32_to_size_t (msgbuf+1);
-  if (msgbuf[0] != 0x81 || len < 4)
-    {
-      log_error ("invalid response header from PC/SC received\n");
-      goto command_failed;
-    }
-  len -= 4; /* Already read the error code. */
-  if (len > DIM (slotp->atr))
+  if (!err)
     {
-      log_error ("PC/SC returned a too large ATR (len=%lx)\n",
-                 (unsigned long)len);
-      goto command_failed;
+      list = xtrymalloc (nreader+1); /* Better add 1 for safety reasons. */
+      if (!list)
+        {
+          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*/;
+        }
+      err = pcsc_list_readers (reader_table[slot].pcsc.context,
+                               NULL, list, &nreader);
     }
-  err = PCSC_ERR_MASK (buf32_to_ulong (msgbuf+5));
   if (err)
     {
-      log_error ("PC/SC OPEN failed: %s\n", pcsc_error_string (err));
-      goto command_failed;
+      log_error ("pcsc_list_readers 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;
     }
 
-  slotp->last_status = 0;
-
-  /* The open request may return a zero for the ATR length to
-     indicate that no card is present.  */
-  n = len;
-  if (n)
+  p = list;
+  while (nreader)
     {
-      if ((i=readn (slotp->pcsc.rsp_fd, slotp->atr, n, &len)) || len != n)
+      if (!*p && !p[1])
+        break;
+      log_info ("detected reader '%s'\n", p);
+      if (nreader < (strlen (p)+1))
         {
-          log_error ("error receiving PC/SC OPEN response: %s\n",
-                     i? strerror (errno) : "premature EOF");
-          goto command_failed;
+          log_error ("invalid response from pcsc_list_readers\n");
+          break;
         }
-      /* If we got to here we know that a card is present
-         and usable.  Thus remember this.  */
-      slotp->last_status = (  APDU_CARD_USABLE
-                            | APDU_CARD_PRESENT
-                            | APDU_CARD_ACTIVE);
+      if (!rdrname && portstr && !strncmp (p, portstr, strlen (portstr)))
+        rdrname = p;
+      nreader -= strlen (p)+1;
+      p += strlen (p) + 1;
     }
-  slotp->atrlen = len;
 
+  if (!rdrname)
+    rdrname = list;
+
+  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);
+      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;
+
+  reader_table[slot].connect_card = connect_pcsc_card;
+  reader_table[slot].disconnect_card = disconnect_pcsc_card;
   reader_table[slot].close_reader = close_pcsc_reader;
   reader_table[slot].reset_reader = reset_pcsc_reader;
   reader_table[slot].get_status_reader = pcsc_get_status;
   reader_table[slot].send_apdu_reader = pcsc_send_apdu;
   reader_table[slot].dump_status_reader = dump_pcsc_reader_status;
 
-  pcsc_vendor_specific_init (slot);
-
-  /* Read the status so that IS_T0 will be set. */
-  pcsc_get_status (slot, &dummy_status);
-
   dump_reader_status (slot);
   unlock_slot (slot);
   return slot;
-
- command_failed:
-  close (slotp->pcsc.req_fd);
-  close (slotp->pcsc.rsp_fd);
-  slotp->pcsc.req_fd = -1;
-  slotp->pcsc.rsp_fd = -1;
-  if (slotp->pcsc.pid != -1)
-    kill (slotp->pcsc.pid, SIGTERM);
-  slotp->pcsc.pid = (pid_t)(-1);
-  slotp->used = 0;
-  unlock_slot (slot);
-  /* There is no way to return SW. */
-  return -1;
-
-}
-#endif /*NEED_PCSC_WRAPPER*/
-
-
-static int
-open_pcsc_reader (const char *portstr)
-{
-#ifdef NEED_PCSC_WRAPPER
-  return open_pcsc_reader_wrapped (portstr);
-#else
-  return open_pcsc_reader_direct (portstr);
-#endif
 }
 
 
@@ -2348,7 +1231,7 @@ pcsc_pinpad_verify (int slot, int class, int ins, int p0, int p1,
 
   if (DBG_CARD_IO)
     log_debug ("send secure: c=%02X i=%02X p1=%02X p2=%02X len=%d pinmax=%d\n",
-              class, ins, p0, p1, len, pininfo->maxlen);
+               class, ins, p0, p1, len, pininfo->maxlen);
 
   sw = control_pcsc (slot, reader_table[slot].pcsc.verify_ioctl,
                      pin_verify, len, result, &resultlen);
@@ -2434,7 +1317,7 @@ pcsc_pinpad_modify (int slot, int class, int ins, int p0, int p1,
 
   if (DBG_CARD_IO)
     log_debug ("send secure: c=%02X i=%02X p1=%02X p2=%02X len=%d pinmax=%d\n",
-              class, ins, p0, p1, len, (int)pininfo->maxlen);
+               class, ins, p0, p1, len, (int)pininfo->maxlen);
 
   sw = control_pcsc (slot, reader_table[slot].pcsc.modify_ioctl,
                      pin_modify, len, result, &resultlen);
@@ -2466,16 +1349,6 @@ static int
 close_ccid_reader (int slot)
 {
   ccid_close_reader (reader_table[slot].ccid.handle);
-  reader_table[slot].rdrname = NULL;
-  reader_table[slot].used = 0;
-  return 0;
-}
-
-
-static int
-shutdown_ccid_reader (int slot)
-{
-  ccid_shutdown_reader (reader_table[slot].ccid.handle);
   return 0;
 }
 
@@ -2510,12 +1383,12 @@ set_progress_cb_ccid_reader (int slot, gcry_handler_progress_t cb, void *cb_arg)
 
 
 static int
-get_status_ccid (int slot, unsigned int *status)
+get_status_ccid (int slot, unsigned int *status, int on_wire)
 {
   int rc;
   int bits;
 
-  rc = ccid_slot_status (reader_table[slot].ccid.handle, &bits);
+  rc = ccid_slot_status (reader_table[slot].ccid.handle, &bits, on_wire);
   if (rc)
     return rc;
 
@@ -2576,13 +1449,13 @@ check_ccid_pinpad (int slot, int command, pininfo_t *pininfo)
 
   apdu[1] = command;
   return ccid_transceive_secure (reader_table[slot].ccid.handle, apdu,
-                                sizeof apdu, pininfo, NULL, 0, NULL);
+                                 sizeof apdu, pininfo, NULL, 0, NULL);
 }
 
 
 static int
 ccid_pinpad_operation (int slot, int class, int ins, int p0, int p1,
-                      pininfo_t *pininfo)
+                       pininfo_t *pininfo)
 {
   unsigned char apdu[4];
   int err, sw;
@@ -2609,10 +1482,11 @@ ccid_pinpad_operation (int slot, int class, int ins, int p0, int p1,
 
 /* Open the reader and try to read an ATR.  */
 static int
-open_ccid_reader (const char *portstr)
+open_ccid_reader (struct dev_list *dl)
 {
   int err;
   int slot;
+  int require_get_status;
   reader_table_t slotp;
 
   slot = new_reader_slot ();
@@ -2620,8 +1494,16 @@ open_ccid_reader (const char *portstr)
     return -1;
   slotp = reader_table + slot;
 
-  err = ccid_open_reader (&slotp->ccid.handle, portstr,
-                          (const char **)&slotp->rdrname);
+  err = ccid_open_reader (dl->portstr, dl->idx, dl->ccid_table,
+                          &slotp->ccid.handle, &slotp->rdrname);
+  if (!err)
+    {
+      err = ccid_get_atr (slotp->ccid.handle,
+                          slotp->atr, sizeof slotp->atr, &slotp->atrlen);
+      if (err)
+        ccid_close_reader (slotp->ccid.handle);
+    }
+
   if (err)
     {
       slotp->used = 0;
@@ -2629,24 +1511,9 @@ open_ccid_reader (const char *portstr)
       return -1;
     }
 
-  err = ccid_get_atr (slotp->ccid.handle,
-                      slotp->atr, sizeof slotp->atr, &slotp->atrlen);
-  if (err)
-    {
-      slotp->atrlen = 0;
-      err = 0;
-    }
-  else
-    {
-      /* If we got to here we know that a card is present
-         and usable.  Thus remember this.  */
-      reader_table[slot].last_status = (APDU_CARD_USABLE
-                                        | APDU_CARD_PRESENT
-                                        | APDU_CARD_ACTIVE);
-    }
+  require_get_status = ccid_require_get_status (slotp->ccid.handle);
 
   reader_table[slot].close_reader = close_ccid_reader;
-  reader_table[slot].shutdown_reader = shutdown_ccid_reader;
   reader_table[slot].reset_reader = reset_ccid_reader;
   reader_table[slot].get_status_reader = get_status_ccid;
   reader_table[slot].send_apdu_reader = send_apdu_ccid;
@@ -2658,17 +1525,13 @@ open_ccid_reader (const char *portstr)
   /* Our CCID reader code does not support T=0 at all, thus reset the
      flag.  */
   reader_table[slot].is_t0 = 0;
+  reader_table[slot].require_get_status = require_get_status;
 
   dump_reader_status (slot);
   unlock_slot (slot);
   return slot;
 }
-
-
-
 #endif /* HAVE_LIBUSB */
-
-
 \f
 #ifdef USE_G10CODE_RAPDU
 /*
@@ -2715,7 +1578,6 @@ static int
 close_rapdu_reader (int slot)
 {
   rapdu_release (reader_table[slot].rapdu.handle);
-  reader_table[slot].used = 0;
   return 0;
 }
 
@@ -2768,13 +1630,14 @@ reset_rapdu_reader (int slot)
 
 
 static int
-my_rapdu_get_status (int slot, unsigned int *status)
+my_rapdu_get_status (int slot, unsigned int *status, int on_wire)
 {
   int err;
   reader_table_t slotp;
   rapdu_msg_t msg = NULL;
   int oldslot;
 
+  (void)on_wire;
   slotp = reader_table + slot;
 
   oldslot = rapdu_set_reader (slotp->rapdu.handle, slot);
@@ -2972,97 +1835,87 @@ open_rapdu_reader (int portno,
 /*
        Driver Access
  */
+gpg_error_t
+apdu_dev_list_start (const char *portstr, struct dev_list **l_p)
+{
+  struct dev_list *dl = xtrymalloc (sizeof (struct dev_list));
 
+  *l_p = NULL;
+  if (!dl)
+    return gpg_error_from_syserror ();
 
-/* 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). */
-int
-apdu_open_reader (const char *portstr)
-{
-  static int pcsc_api_loaded, ct_api_loaded;
-  int slot;
+  dl->portstr = portstr;
+  dl->idx = 0;
 
-  if (DBG_READER)
-    log_debug ("enter: apdu_open_reader: portstr=%s\n", portstr);
+  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;
+    }
+  else
     {
-      static int once_available;
-      int i;
-      const char *s;
+      gpg_error_t err;
 
-      slot = open_ccid_reader (portstr);
-      if (slot != -1)
-        {
-          once_available = 1;
-          if (DBG_READER)
-            log_debug ("leave: apdu_open_reader => slot=%d [ccid]\n", slot);
-          return slot; /* got one */
-        }
+      err = ccid_dev_scan (&dl->idx_max, &dl->ccid_table);
+      if (err)
+        return err;
 
-      /* If we ever loaded successfully loaded a CCID reader we never
-         want to fallback to another driver.  This solves a problem
-         where ccid was used, the card unplugged and then scdaemon
-         tries to find a new reader and will eventually try PC/SC over
-         and over again.  To reset this flag "gpgconf --kill scdaemon"
-         can be used.  */
-      if (once_available)
+      if (dl->idx_max == 0)
         {
-          if (DBG_READER)
-            log_debug ("leave: apdu_open_reader => slot=-1 (once_avail)\n");
-          return -1;
-        }
-
-      /* If a CCID reader specification has been given, the user does
-         not want a fallback to other drivers. */
-      if (portstr)
-        for (s=portstr, i=0; *s; s++)
-          if (*s == ':' && (++i == 3))
+          /* 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] == ':')
             {
               if (DBG_READER)
                 log_debug ("leave: apdu_open_reader => slot=-1 (no ccid)\n");
-              return -1;
+
+              xfree (dl);
+              npth_mutex_unlock (&reader_table_lock);
+              return gpg_error (GPG_ERR_ENODEV);
             }
+          else
+            dl->idx_max = 1;
+        }
     }
-
+#else
+  dl->ccid_table = NULL;
+  dl->idx_max = 1;
 #endif /* HAVE_LIBUSB */
 
-  if (opt.ctapi_driver && *opt.ctapi_driver)
-    {
-      int port = portstr? atoi (portstr) : 32768;
+  *l_p = dl;
+  return 0;
+}
 
-      if (!ct_api_loaded)
-        {
-          void *handle;
+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);
+#endif
+  xfree (dl);
+  npth_mutex_unlock (&reader_table_lock);
+}
 
-          handle = dlopen (opt.ctapi_driver, RTLD_LAZY);
-          if (!handle)
-            {
-              log_error ("apdu_open_reader: failed to open driver: %s\n",
-                         dlerror ());
-              return -1;
-            }
-          CT_init = dlsym (handle, "CT_init");
-          CT_data = dlsym (handle, "CT_data");
-          CT_close = dlsym (handle, "CT_close");
-          if (!CT_init || !CT_data || !CT_close)
-            {
-              log_error ("apdu_open_reader: invalid CT-API driver\n");
-              dlclose (handle);
-              return -1;
-            }
-          ct_api_loaded = 1;
-        }
-      return open_ct_reader (port);
-    }
 
+/* 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)
+{
+  static int pcsc_api_loaded;
+  int slot;
+
+  if (DBG_READER)
+    log_debug ("enter: apdu_open_reader: portstr=%s\n", portstr);
 
-  /* No ctAPI configured, so lets try the PC/SC API */
+  /* Lets try the PC/SC API */
   if (!pcsc_api_loaded)
     {
-#ifndef NEED_PCSC_WRAPPER
       void *handle;
 
       handle = dlopen (opt.pcsc_driver, RTLD_LAZY);
@@ -3141,7 +1994,6 @@ apdu_open_reader (const char *portstr)
           dlclose (handle);
           return -1;
         }
-#endif /*!NEED_PCSC_WRAPPER*/
       pcsc_api_loaded = 1;
     }
 
@@ -3152,13 +2004,113 @@ apdu_open_reader (const char *portstr)
   return slot;
 }
 
+int
+apdu_open_reader (struct dev_list *dl, int app_empty)
+{
+  int slot;
+
+#ifdef HAVE_LIBUSB
+  if (dl->ccid_table)
+    { /* 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);
+          dl->idx = dl->idx_max;
+          if (slot >= 0)
+            return slot;
+          else
+            return -1;
+        }
+
+      while (dl->idx < dl->idx_max)
+        {
+          unsigned int bai = ccid_get_BAI (dl->idx, dl->ccid_table);
+
+          if (DBG_READER)
+            log_debug ("apdu_open_reader: BAI=%x\n", bai);
+
+          /* Check identity by BAI against already opened HANDLEs.  */
+          for (slot = 0; slot < MAX_READER; slot++)
+            if (reader_table[slot].used
+                && reader_table[slot].ccid.handle
+                && ccid_compare_BAI (reader_table[slot].ccid.handle, bai))
+              break;
+
+          if (slot == MAX_READER)
+            { /* Found a new device.  */
+              if (DBG_READER)
+                log_debug ("apdu_open_reader: new device=%x\n", bai);
+
+              slot = open_ccid_reader (dl);
+
+              dl->idx++;
+              if (slot >= 0)
+                return slot;
+              else
+                {
+                  /* Skip this reader.  */
+                  log_error ("ccid open error: skip\n");
+                  continue;
+                }
+            }
+          else
+            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;
+    }
+  else
+#endif
+    { /* PC/SC readers.  */
+      if (app_empty && dl->idx == 0)
+        {
+          dl->idx++;
+          slot = apdu_open_one_reader (dl->portstr);
+        }
+      else
+        slot = -1;
+    }
+
+  return slot;
+}
+
 
 /* Open an remote reader and return an internal slot number or -1 on
    error. This function is an alternative to apdu_open_reader and used
    with remote readers only.  Note that the supplied CLOSEFNC will
    only be called once and the slot will not be valid afther this.
 
-   If PORTSTR is NULL we default to the first availabe port.
+   If PORTSTR is NULL we default to the first available port.
 */
 int
 apdu_open_remote_reader (const char *portstr,
@@ -3215,17 +2167,24 @@ apdu_close_reader (int slot)
   sw = apdu_disconnect (slot);
   if (sw)
     {
+      /*
+       * When the reader/token was removed it might come here.
+       * It should go through to call CLOSE_READER even if we got an error.
+       */
       if (DBG_READER)
-        log_debug ("leave: apdu_close_reader => 0x%x (apdu_disconnect)\n", sw);
-      return sw;
+        log_debug ("apdu_close_reader => 0x%x (apdu_disconnect)\n", sw);
     }
   if (reader_table[slot].close_reader)
     {
       sw = reader_table[slot].close_reader (slot);
+      reader_table[slot].used = 0;
       if (DBG_READER)
         log_debug ("leave: apdu_close_reader => 0x%x (close_reader)\n", sw);
       return sw;
     }
+  xfree (reader_table[slot].rdrname);
+  reader_table[slot].rdrname = NULL;
+  reader_table[slot].used = 0;
   if (DBG_READER)
     log_debug ("leave: apdu_close_reader => SW_HOST_NOT_SUPPORTED\n");
   return SW_HOST_NOT_SUPPORTED;
@@ -3245,56 +2204,23 @@ apdu_prepare_exit (void)
   if (!sentinel)
     {
       sentinel = 1;
+      npth_mutex_lock (&reader_table_lock);
       for (slot = 0; slot < MAX_READER; slot++)
         if (reader_table[slot].used)
           {
             apdu_disconnect (slot);
             if (reader_table[slot].close_reader)
               reader_table[slot].close_reader (slot);
+            xfree (reader_table[slot].rdrname);
+            reader_table[slot].rdrname = NULL;
             reader_table[slot].used = 0;
           }
+      npth_mutex_unlock (&reader_table_lock);
       sentinel = 0;
     }
 }
 
 
-/* Shutdown a reader; that is basically the same as a close but keeps
-   the handle ready for later use. A apdu_reset_reader or apdu_connect
-   should be used to get it active again. */
-int
-apdu_shutdown_reader (int slot)
-{
-  int sw;
-
-  if (DBG_READER)
-    log_debug ("enter: apdu_shutdown_reader: slot=%d\n", slot);
-
-  if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
-    {
-      if (DBG_READER)
-        log_debug ("leave: apdu_shutdown_reader => SW_HOST_NO_DRIVER\n");
-      return SW_HOST_NO_DRIVER;
-    }
-  sw = apdu_disconnect (slot);
-  if (sw)
-    {
-      if (DBG_READER)
-        log_debug ("leave: apdu_shutdown_reader => 0x%x (apdu_disconnect)\n",
-                   sw);
-      return sw;
-    }
-  if (reader_table[slot].shutdown_reader)
-    {
-      sw = reader_table[slot].shutdown_reader (slot);
-      if (DBG_READER)
-        log_debug ("leave: apdu_shutdown_reader => 0x%x (close_reader)\n", sw);
-      return sw;
-    }
-  if (DBG_READER)
-    log_debug ("leave: apdu_shutdown_reader => SW_HOST_NOT_SUPPORTED\n");
-  return SW_HOST_NOT_SUPPORTED;
-}
-
 /* Enumerate all readers and return information on whether this reader
    is in use.  The caller should start with SLOT set to 0 and
    increment it with each call until an error is returned. */
@@ -3310,8 +2236,11 @@ apdu_enum_reader (int slot, int *used)
 
 /* Connect a card.  This is used to power up the card and make sure
    that an ATR is available.  Depending on the reader backend it may
-   return an error for an inactive card or if no card is
-   available.  */
+   return an error for an inactive card or if no card is available.
+   Return -1 on error.  Return 1 if reader requires get_status to
+   watch card removal.  Return 0 if it's a token (always with a card),
+   or it supports INTERRUPT endpoint to watch card removal.
+  */
 int
 apdu_connect (int slot)
 {
@@ -3325,7 +2254,7 @@ apdu_connect (int slot)
     {
       if (DBG_READER)
         log_debug ("leave: apdu_connect => SW_HOST_NO_DRIVER\n");
-      return SW_HOST_NO_DRIVER;
+      return -1;
     }
 
   /* Only if the access method provides a connect function we use it.
@@ -3347,7 +2276,7 @@ apdu_connect (int slot)
      Without that we would force a reset of the card with the next
      call to apdu_get_status.  */
   if (!sw)
-    sw = apdu_get_status_internal (slot, 1, 1, &status, NULL);
+    sw = apdu_get_status_internal (slot, 1, &status, 1);
 
   if (sw)
     ;
@@ -3356,10 +2285,19 @@ apdu_connect (int slot)
   else if ((status & APDU_CARD_PRESENT) && !(status & APDU_CARD_ACTIVE))
     sw = SW_HOST_CARD_INACTIVE;
 
+  if (sw == SW_HOST_CARD_INACTIVE)
+    {
+      /* Try power it up again.  */
+      sw = apdu_reset (slot);
+    }
+
   if (DBG_READER)
     log_debug ("leave: apdu_connect => sw=0x%x\n", sw);
 
-  return sw;
+  if (sw)
+    return -1;
+
+  return reader_table[slot].require_get_status;
 }
 
 
@@ -3444,19 +2382,9 @@ apdu_reset (int slot)
       return sw;
     }
 
-  reader_table[slot].last_status = 0;
   if (reader_table[slot].reset_reader)
     sw = reader_table[slot].reset_reader (slot);
 
-  if (!sw)
-    {
-      /* If we got to here we know that a card is present
-         and usable.  Thus remember this.  */
-      reader_table[slot].last_status = (APDU_CARD_USABLE
-                                        | APDU_CARD_PRESENT
-                                        | APDU_CARD_ACTIVE);
-    }
-
   unlock_slot (slot);
   if (DBG_READER)
     log_debug ("leave: apdu_reset => sw=0x%x\n", sw);
@@ -3513,18 +2441,13 @@ apdu_get_atr (int slot, size_t *atrlen)
      APDU_CARD_ACTIVE  (bit 2) = card active
                        (bit 3) = card access locked [not yet implemented]
 
-   For must applications, testing bit 0 is sufficient.
-
-   CHANGED will receive the value of the counter tracking the number
-   of card insertions.  This value may be used to detect a card
-   change.
+   For most applications, testing bit 0 is sufficient.
 */
 static int
-apdu_get_status_internal (int slot, int hang, int no_atr_reset,
-                          unsigned int *status, unsigned int *changed)
+apdu_get_status_internal (int slot, int hang, unsigned int *status, int on_wire)
 {
   int sw;
-  unsigned int s;
+  unsigned int s = 0;
 
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return SW_HOST_NO_DRIVER;
@@ -3533,58 +2456,37 @@ apdu_get_status_internal (int slot, int hang, int no_atr_reset,
     return sw;
 
   if (reader_table[slot].get_status_reader)
-    sw = reader_table[slot].get_status_reader (slot, &s);
+    sw = reader_table[slot].get_status_reader (slot, &s, on_wire);
 
   unlock_slot (slot);
 
   if (sw)
     {
-      reader_table[slot].last_status = 0;
-      return sw;
-    }
-
-  /* Keep track of changes.  */
-  if (s != reader_table[slot].last_status
-      || !reader_table[slot].any_status )
-    {
-      reader_table[slot].change_counter++;
-      /* Make sure that the ATR is invalid so that a reset will be
-         triggered by apdu_activate.  */
-      if (!no_atr_reset)
+      if (on_wire)
         reader_table[slot].atrlen = 0;
+      s = 0;
     }
-  reader_table[slot].any_status = 1;
-  reader_table[slot].last_status = s;
 
   if (status)
     *status = s;
-  if (changed)
-    *changed = reader_table[slot].change_counter;
-  return 0;
+  return sw;
 }
 
 
 /* See above for a description.  */
 int
-apdu_get_status (int slot, int hang,
-                 unsigned int *status, unsigned int *changed)
+apdu_get_status (int slot, int hang, unsigned int *status)
 {
   int sw;
 
   if (DBG_READER)
     log_debug ("enter: apdu_get_status: slot=%d hang=%d\n", slot, hang);
-  sw = apdu_get_status_internal (slot, hang, 0, status, changed);
+  sw = apdu_get_status_internal (slot, hang, status, 0);
   if (DBG_READER)
     {
-      if (status && changed)
-        log_debug ("leave: apdu_get_status => sw=0x%x status=%u changecnt=%u\n",
-                   sw, *status, *changed);
-      else if (status)
+      if (status)
         log_debug ("leave: apdu_get_status => sw=0x%x status=%u\n",
                    sw, *status);
-      else if (changed)
-        log_debug ("leave: apdu_get_status => sw=0x%x changed=%u\n",
-                   sw, *changed);
       else
         log_debug ("leave: apdu_get_status => sw=0x%x\n", sw);
     }
@@ -3622,7 +2524,7 @@ apdu_check_pinpad (int slot, int command, pininfo_t *pininfo)
 
 int
 apdu_pinpad_verify (int slot, int class, int ins, int p0, int p1,
-                   pininfo_t *pininfo)
+                    pininfo_t *pininfo)
 {
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return SW_HOST_NO_DRIVER;
@@ -3635,7 +2537,7 @@ apdu_pinpad_verify (int slot, int class, int ins, int p0, int p1,
         return sw;
 
       sw = reader_table[slot].pinpad_verify (slot, class, ins, p0, p1,
-                                            pininfo);
+                                             pininfo);
       unlock_slot (slot);
       return sw;
     }
@@ -3646,7 +2548,7 @@ apdu_pinpad_verify (int slot, int class, int ins, int p0, int p1,
 
 int
 apdu_pinpad_modify (int slot, int class, int ins, int p0, int p1,
-                   pininfo_t *pininfo)
+                    pininfo_t *pininfo)
 {
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return SW_HOST_NO_DRIVER;
@@ -3795,8 +2697,9 @@ send_le (int slot, int class, int ins, int p0, int p1,
 
   if (use_extended_length && (le > 256 || le < 0))
     {
-      result_buffer_size = le < 0? 4096 : le;
-      result_buffer = xtrymalloc (result_buffer_size + 10);
+      /* Two more bytes are needed for status bytes.  */
+      result_buffer_size = le < 0? 4096 : (le + 2);
+      result_buffer = xtrymalloc (result_buffer_size);
       if (!result_buffer)
         {
           xfree (apdu_buffer);
@@ -3910,7 +2813,6 @@ send_le (int slot, int class, int ins, int p0, int p1,
     {
       xfree (apdu_buffer);
       apdu_buffer = NULL;
-      apdu_buffer_size = 0;
     }
 
   /* Store away the returned data but strip the statusword. */
@@ -4052,7 +2954,7 @@ send_le (int slot, int class, int ins, int p0, int p1,
    The return value is the status word or -1 for an invalid SLOT or
    other non card related error.  If RETBUF is not NULL, it will
    receive an allocated buffer with the returned data.  The length of
-   that data will be put into *RETBUFLEN.  The caller is reponsible
+   that data will be put into *RETBUFLEN.  The caller is responsible
    for releasing the buffer even in case of errors.  */
 int
 apdu_send_le(int slot, int extended_mode,
@@ -4075,7 +2977,7 @@ apdu_send_le(int slot, int extended_mode,
    return value is the status word or -1 for an invalid SLOT or other
    non card related error.  If RETBUF is not NULL, it will receive an
    allocated buffer with the returned data.  The length of that data
-   will be put into *RETBUFLEN.  The caller is reponsible for
+   will be put into *RETBUFLEN.  The caller is responsible for
    releasing the buffer even in case of errors.  */
 int
 apdu_send (int slot, int extended_mode,
@@ -4335,3 +3237,28 @@ apdu_get_reader_name (int slot)
 {
   return reader_table[slot].rdrname;
 }
+
+gpg_error_t
+apdu_init (void)
+{
+#ifdef USE_NPTH
+  gpg_error_t err;
+  int i;
+
+  if (npth_mutex_init (&reader_table_lock, NULL))
+    goto leave;
+
+  for (i = 0; i < MAX_READER; i++)
+    if (npth_mutex_init (&reader_table[i].lock, NULL))
+      goto leave;
+
+  /* All done well.  */
+  return 0;
+
+ leave:
+  err = gpg_error_from_syserror ();
+  log_error ("apdu: error initializing mutex: %s\n", gpg_strerror (err));
+  return err;
+#endif /*USE_NPTH*/
+  return 0;
+}