po: Update Russian translation
[gnupg.git] / scd / apdu.c
index 68d4e99..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 "../common/host2net.h"
 
+#include "iso7816.h"
 #include "apdu.h"
+#define CCID_DRIVER_INCLUDE_USB_IDS 1
 #include "ccid-driver.h"
-#include "iso7816.h"
-
-
-/* Due to conflicting use of threading libraries we usually can't link
-   against libpcsclite.   Instead we use a wrapper program.  */
-#ifdef USE_NPTH
-#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. */
 
 #define DLSTDCALL
 #endif
 
-
-/* Helper to pass parameters related to keypad based operations. */
-struct pininfo_s
-{
-  int mode;
-  int minlen;
-  int maxlen;
-  int padlen;
-};
+#if defined(__APPLE__) || defined(_WIN32) || defined(__CYGWIN__)
+typedef unsigned int pcsc_dword_t;
+#else
+typedef unsigned long pcsc_dword_t;
+#endif
 
 /* A structure to collect information pertaining to one reader
    slot. */
@@ -99,35 +94,31 @@ 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 *, struct pininfo_s *);
-  int (*check_keypad)(int, int, int, int, int, int);
+                          unsigned char *, size_t *, pininfo_t *);
+  int (*check_pinpad)(int, int, pininfo_t *);
   void (*dump_status_reader)(int);
   int (*set_progress_cb)(int, gcry_handler_progress_t, void*);
-  int (*keypad_verify)(int, int, int, int, int, struct pininfo_s *);
-  int (*keypad_modify)(int, int, int, int, int, struct pininfo_s *);
+  int (*pinpad_verify)(int, int, int, int, int, pininfo_t *);
+  int (*pinpad_modify)(int, int, int, int, int, pininfo_t *);
 
   struct {
     ccid_driver_t handle;
   } ccid;
   struct {
-    unsigned long context;
-    unsigned long card;
-    unsigned long protocol;
-    unsigned long verify_ioctl;
-    unsigned long modify_ioctl;
-#ifdef NEED_PCSC_WRAPPER
-    int req_fd;
-    int rsp_fd;
-    pid_t pid;
-#endif /*NEED_PCSC_WRAPPER*/
+    long context;
+    long card;
+    pcsc_dword_t protocol;
+    pcsc_dword_t verify_ioctl;
+    pcsc_dword_t modify_ioctl;
+    int pinmin;
+    int pinmax;
   } pcsc;
 #ifdef USE_G10CODE_RAPDU
   struct {
@@ -135,17 +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. */
+  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
 };
@@ -154,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
@@ -214,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
@@ -240,11 +227,32 @@ 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
 
-#define CM_IOCTL_GET_FEATURE_REQUEST (0x42000000 + 3400)
+/* 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)
+#else
+#define SCARD_CTL_CODE(code) (0x42000000 + (code))
+#endif
+#endif
+
+#define CM_IOCTL_GET_FEATURE_REQUEST     SCARD_CTL_CODE(3400)
+#define CM_IOCTL_VENDOR_IFD_EXCHANGE     SCARD_CTL_CODE(1)
 #define FEATURE_VERIFY_PIN_DIRECT        0x06
 #define FEATURE_MODIFY_PIN_DIRECT        0x07
+#define FEATURE_GET_TLV_PROPERTIES       0x12
+
+#define PCSCv2_PART10_PROPERTY_bEntryValidationCondition 2
+#define PCSCv2_PART10_PROPERTY_bTimeOut2                 3
+#define PCSCv2_PART10_PROPERTY_bMinPINSize               6
+#define PCSCv2_PART10_PROPERTY_bMaxPINSize               7
+#define PCSCv2_PART10_PROPERTY_wIdVendor                11
+#define PCSCv2_PART10_PROPERTY_wIdProduct               12
 
 
 /* The PC/SC error is defined as a long as per specs.  Due to left
@@ -261,81 +269,88 @@ struct pcsc_io_request_s
 
 typedef struct pcsc_io_request_s *pcsc_io_request_t;
 
+#ifdef __APPLE__
+#pragma pack(1)
+#endif
+
 struct pcsc_readerstate_s
 {
   const char *reader;
   void *user_data;
-  unsigned long current_state;
-  unsigned long event_state;
-  unsigned long atrlen;
+  pcsc_dword_t current_state;
+  pcsc_dword_t event_state;
+  pcsc_dword_t atrlen;
   unsigned char atr[33];
 };
 
+#ifdef __APPLE__
+#pragma pack()
+#endif
+
 typedef struct pcsc_readerstate_s *pcsc_readerstate_t;
 
-long (* DLSTDCALL pcsc_establish_context) (unsigned long scope,
+long (* DLSTDCALL pcsc_establish_context) (pcsc_dword_t scope,
                                            const void *reserved1,
                                            const void *reserved2,
-                                           unsigned long *r_context);
-long (* DLSTDCALL pcsc_release_context) (unsigned long context);
-long (* DLSTDCALL pcsc_list_readers) (unsigned long context,
+                                           long *r_context);
+long (* DLSTDCALL pcsc_release_context) (long context);
+long (* DLSTDCALL pcsc_list_readers) (long context,
                                       const char *groups,
-                                      char *readers, unsigned long*readerslen);
-long (* DLSTDCALL pcsc_get_status_change) (unsigned long context,
-                                           unsigned long timeout,
+                                      char *readers, pcsc_dword_t*readerslen);
+long (* DLSTDCALL pcsc_get_status_change) (long context,
+                                           pcsc_dword_t timeout,
                                            pcsc_readerstate_t readerstates,
-                                           unsigned long nreaderstates);
-long (* DLSTDCALL pcsc_connect) (unsigned long context,
+                                           pcsc_dword_t nreaderstates);
+long (* DLSTDCALL pcsc_connect) (long context,
                                  const char *reader,
-                                 unsigned long share_mode,
-                                 unsigned long preferred_protocols,
-                                 unsigned long *r_card,
-                                 unsigned long *r_active_protocol);
-long (* DLSTDCALL pcsc_reconnect) (unsigned long card,
-                                   unsigned long share_mode,
-                                   unsigned long preferred_protocols,
-                                   unsigned long initialization,
-                                   unsigned long *r_active_protocol);
-long (* DLSTDCALL pcsc_disconnect) (unsigned long card,
-                                    unsigned long disposition);
-long (* DLSTDCALL pcsc_status) (unsigned long card,
-                                char *reader, unsigned long *readerlen,
-                                unsigned long *r_state,
-                                unsigned long *r_protocol,
-                                unsigned char *atr, unsigned long *atrlen);
-long (* DLSTDCALL pcsc_begin_transaction) (unsigned long card);
-long (* DLSTDCALL pcsc_end_transaction) (unsigned long card,
-                                         unsigned long disposition);
-long (* DLSTDCALL pcsc_transmit) (unsigned long card,
+                                 pcsc_dword_t share_mode,
+                                 pcsc_dword_t preferred_protocols,
+                                 long *r_card,
+                                 pcsc_dword_t *r_active_protocol);
+long (* DLSTDCALL pcsc_reconnect) (long 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,
+                                    pcsc_dword_t disposition);
+long (* DLSTDCALL pcsc_status) (long 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,
+                                         pcsc_dword_t disposition);
+long (* DLSTDCALL pcsc_transmit) (long card,
                                   const pcsc_io_request_t send_pci,
                                   const unsigned char *send_buffer,
-                                  unsigned long send_len,
+                                  pcsc_dword_t send_len,
                                   pcsc_io_request_t recv_pci,
                                   unsigned char *recv_buffer,
-                                  unsigned long *recv_len);
-long (* DLSTDCALL pcsc_set_timeout) (unsigned long context,
-                                     unsigned long timeout);
-long (* DLSTDCALL pcsc_control) (unsigned long card,
-                                 unsigned long control_code,
+                                  pcsc_dword_t *recv_len);
+long (* DLSTDCALL pcsc_set_timeout) (long context,
+                                     pcsc_dword_t timeout);
+long (* DLSTDCALL pcsc_control) (long card,
+                                 pcsc_dword_t control_code,
                                  const void *send_buffer,
-                                 unsigned long send_len,
+                                 pcsc_dword_t send_len,
                                  void *recv_buffer,
-                                 unsigned long recv_len,
-                                 unsigned long *bytes_returned);
+                                 pcsc_dword_t recv_len,
+                                 pcsc_dword_t *bytes_returned);
 
 
 /*  Prototypes.  */
-static int pcsc_get_status (int slot, unsigned int *status);
+static int pcsc_vendor_specific_init (int slot);
+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 check_pcsc_keypad (int slot, int command, int pin_mode,
-                              int pinlen_min, int pinlen_max, int pin_padlen);
-static int pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1,
-                               struct pininfo_s *pininfo);
-static int pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1,
-                               struct pininfo_s *pininfo);
+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);
+static int pcsc_pinpad_modify (int slot, int class, int ins, int p0, int p1,
+                               pininfo_t *pininfo);
 
 
 \f
@@ -343,61 +358,101 @@ static int pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1,
       Helper
  */
 
+static int
+lock_slot (int slot)
+{
+#ifdef USE_NPTH
+  int err;
+
+  err = npth_mutex_lock (&reader_table[slot].lock);
+  if (err)
+    {
+      log_error ("failed to acquire apdu lock: %s\n", strerror (err));
+      return SW_HOST_LOCKING_FAILED;
+    }
+#endif /*USE_NPTH*/
+  return 0;
+}
+
+static int
+trylock_slot (int slot)
+{
+#ifdef USE_NPTH
+  int err;
+
+  err = npth_mutex_trylock (&reader_table[slot].lock);
+  if (err == EBUSY)
+    return SW_HOST_BUSY;
+  else if (err)
+    {
+      log_error ("failed to acquire apdu lock: %s\n", strerror (err));
+      return SW_HOST_LOCKING_FAILED;
+    }
+#endif /*USE_NPTH*/
+  return 0;
+}
+
+static void
+unlock_slot (int slot)
+{
+#ifdef USE_NPTH
+  int err;
+
+  err = npth_mutex_unlock (&reader_table[slot].lock);
+  if (err)
+    log_error ("failed to release apdu lock: %s\n", strerror (errno));
+#endif /*USE_NPTH*/
+}
+
 
 /* Find an unused reader slot for PORTSTR and put it into the reader
-   table.  Return -1 on error or the index into the reader table. */
+   table.  Return -1 on error or the index into the reader table.
+   Acquire slot's lock on successful return.  Caller needs to unlock it.  */
 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)
+
+  if (lock_slot (reader))
     {
-      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;
+      reader_table[reader].used = 0;
+      return -1;
     }
-#endif /*USE_NPTH*/
+
   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;
-  reader_table[reader].check_keypad = check_pcsc_keypad;
+  reader_table[reader].check_pinpad = check_pcsc_pinpad;
   reader_table[reader].dump_status_reader = NULL;
   reader_table[reader].set_progress_cb = NULL;
-  reader_table[reader].keypad_verify = pcsc_keypad_verify;
-  reader_table[reader].keypad_modify = pcsc_keypad_modify;
+  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;
-#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].is_spr532 = 0;
+  reader_table[reader].pinpad_varlen_supported = 0;
+  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;
+  reader_table[reader].pcsc.pinmax = -1;
 
   return reader;
 }
@@ -412,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);
@@ -440,7 +494,7 @@ host_sw_string (long err)
     case SW_HOST_GENERAL_ERROR: return "general error";
     case SW_HOST_NO_READER: return "no reader";
     case SW_HOST_ABORTED: return "aborted";
-    case SW_HOST_NO_KEYPAD: return "no keypad";
+    case SW_HOST_NO_PINPAD: return "no pinpad";
     case SW_HOST_ALREADY_CONNECTED: return "already connected";
     default: return "unknown host status error";
     }
@@ -457,6 +511,7 @@ apdu_strerror (int rc)
     case SW_WRONG_LENGTH   : return "wrong length";
     case SW_CHV_WRONG      : return "CHV wrong";
     case SW_CHV_BLOCKED    : return "CHV blocked";
+    case SW_REF_DATA_INV   : return "referenced data invalidated";
     case SW_USE_CONDITIONS : return "use conditions not satisfied";
     case SW_BAD_PARAMETER  : return "bad parameter";
     case SW_NOT_SUPPORTED  : return "not supported";
@@ -479,277 +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, struct pininfo_s *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;
-      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_keypad = NULL;
-  reader_table[reader].dump_status_reader = ct_dump_reader_status;
-  reader_table[reader].keypad_verify = NULL;
-  reader_table[reader].keypad_modify = NULL;
-
-  dump_reader_status (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)
 {
@@ -816,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;
@@ -852,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;
@@ -889,9 +680,11 @@ pcsc_get_status_direct (int slot, unsigned int *status)
 
   *status = 0;
   if ( (rdrstates[0].event_state & PCSC_STATE_PRESENT) )
-    *status |= APDU_CARD_PRESENT;
-  if ( !(rdrstates[0].event_state & PCSC_STATE_MUTE) )
-    *status |= APDU_CARD_ACTIVE;
+    {
+      *status |= APDU_CARD_PRESENT;
+      if ( !(rdrstates[0].event_state & PCSC_STATE_MUTE) )
+        *status |= APDU_CARD_ACTIVE;
+    }
 #ifndef HAVE_W32_SYSTEM
   /* We indicate a useful card if it is not in use by another
      application.  This is because we only use exclusive access
@@ -910,426 +703,45 @@ pcsc_get_status_direct (int slot, unsigned int *status)
 
   return 0;
 }
-#endif /*!NEED_PCSC_WRAPPER*/
 
 
-#ifdef 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_get_status_wrapped (int slot, unsigned int *status)
+pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
+                unsigned char *buffer, size_t *buflen,
+                pininfo_t *pininfo)
 {
   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;
+  struct pcsc_io_request_s send_pci;
+  pcsc_dword_t recv_len;
 
-  slotp = reader_table + slot;
+  (void)pininfo;
 
-  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;
-    }
+  if (!reader_table[slot].atrlen
+      && (err = reset_pcsc_reader (slot)))
+    return err;
 
-  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;
-    }
+  if (DBG_CARD_IO)
+    log_printhex ("  PCSC_data:", apdu, apdulen);
 
-  /* 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 = (msgbuf[1] << 24) | (msgbuf[2] << 16) | (msgbuf[3] << 8 ) | msgbuf[4];
-  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 ((msgbuf[5] << 24) | (msgbuf[6] << 16)
-                       | (msgbuf[7] << 8 ) | msgbuf[8]);
+  if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_T1))
+      send_pci.protocol = PCSC_PROTOCOL_T1;
+  else
+      send_pci.protocol = PCSC_PROTOCOL_T0;
+  send_pci.pci_len = sizeof send_pci;
+  recv_len = *buflen;
+  err = pcsc_transmit (reader_table[slot].pcsc.card,
+                       &send_pci, apdu, apdulen,
+                       NULL, buffer, &recv_len);
+  *buflen = recv_len;
   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
-static int
-pcsc_send_apdu_direct (int slot, unsigned char *apdu, size_t apdulen,
-                       unsigned char *buffer, size_t *buflen,
-                       struct pininfo_s *pininfo)
-{
-  long err;
-  struct pcsc_io_request_s send_pci;
-  unsigned long recv_len;
-
-  if (!reader_table[slot].atrlen
-      && (err = reset_pcsc_reader (slot)))
-    return err;
-
-  if (DBG_CARD_IO)
-    log_printhex ("  PCSC_data:", apdu, apdulen);
-
-  if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_T1))
-      send_pci.protocol = PCSC_PROTOCOL_T1;
-  else
-      send_pci.protocol = PCSC_PROTOCOL_T0;
-  send_pci.pci_len = sizeof send_pci;
-  recv_len = *buflen;
-  err = pcsc_transmit (reader_table[slot].pcsc.card,
-                       &send_pci, apdu, apdulen,
-                       NULL, buffer, &recv_len);
-  *buflen = recv_len;
-  if (err)
-    log_error ("pcsc_transmit failed: %s (0x%lx)\n",
-               pcsc_error_string (err), err);
-
-  return pcsc_error_to_sw (err);
-}
-#endif /*!NEED_PCSC_WRAPPER*/
-
-
-#ifdef NEED_PCSC_WRAPPER
-static int
-pcsc_send_apdu_wrapped (int slot, unsigned char *apdu, size_t apdulen,
-                        unsigned char *buffer, size_t *buflen,
-                        struct pininfo_s *pininfo)
-{
-  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 = (msgbuf[1] << 24) | (msgbuf[2] << 16) | (msgbuf[3] << 8 ) | msgbuf[4];
-  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 ((msgbuf[5] << 24) | (msgbuf[6] << 16)
-                       | (msgbuf[7] << 8 ) | msgbuf[8]);
-  if (err)
-    {
-      log_error ("pcsc_transmit 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;
-}
-#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,
-                struct pininfo_s *pininfo)
-{
-#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
-}
-
-
-#ifndef NEED_PCSC_WRAPPER
-static int
-control_pcsc_direct (int slot, unsigned long ioctl_code,
-                     const unsigned char *cntlbuf, size_t len,
-                     unsigned char *buffer, size_t *buflen)
-{
-  long err;
-
-  err = pcsc_control (reader_table[slot].pcsc.card, ioctl_code,
-                      cntlbuf, len, buffer, *buflen, 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, unsigned long ioctl_code,
-                      const unsigned char *cntlbuf, size_t len,
-                      unsigned char *buffer, size_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 = (msgbuf[1] << 24) | (msgbuf[2] << 16) | (msgbuf[3] << 8 ) | msgbuf[4];
-  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 ((msgbuf[5] << 24) | (msgbuf[6] << 16)
-                       | (msgbuf[7] << 8 ) | msgbuf[8]);
-  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;
-
-  n = *buflen < len ? *buflen : len;
-  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;
-    }
-  *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*/
+    log_error ("pcsc_transmit failed: %s (0x%lx)\n",
+               pcsc_error_string (err), err);
 
+  return pcsc_error_to_sw (err);
+}
 
 
 /* Do some control with the value of IOCTL_CODE to the card inserted
@@ -1338,114 +750,34 @@ control_pcsc_wrapped (int slot, unsigned long ioctl_code,
    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, unsigned long ioctl_code,
+control_pcsc (int slot, pcsc_dword_t ioctl_code,
               const unsigned char *cntlbuf, size_t len,
-              unsigned char *buffer, size_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)
+              unsigned char *buffer, pcsc_dword_t *buflen)
 {
   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 = (msgbuf[1] << 24) | (msgbuf[2] << 16) | (msgbuf[3] << 8 ) | msgbuf[4];
-  if (msgbuf[0] != 0x81 || len < 4)
+  err = pcsc_control (reader_table[slot].pcsc.card, ioctl_code,
+                      cntlbuf, len, buffer, buflen? *buflen:0, buflen);
+  if (err)
     {
-      log_error ("invalid response header from PC/SC received\n");
-      goto command_failed;
+      log_error ("pcsc_control failed: %s (0x%lx)\n",
+                 pcsc_error_string (err), err);
+      return pcsc_error_to_sw (err);
     }
-  len -= 4; /* Already read the error code. */
-  err = PCSC_ERR_MASK ((msgbuf[5] << 24) | (msgbuf[6] << 16)
-                       | (msgbuf[7] << 8 ) | msgbuf[8]);
-  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
+  pcsc_release_context (reader_table[slot].pcsc.context);
+  return 0;
 }
 
 
 /* Connect a PC/SC card.  */
-#ifndef NEED_PCSC_WRAPPER
 static int
 connect_pcsc_card (int slot)
 {
@@ -1457,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,
@@ -1476,8 +807,10 @@ connect_pcsc_card (int slot)
   else
     {
       char reader[250];
-      unsigned long readerlen, atrlen;
-      unsigned long card_state, card_protocol;
+      pcsc_dword_t readerlen, atrlen;
+      pcsc_dword_t card_state, card_protocol;
+
+      pcsc_vendor_specific_init (slot);
 
       atrlen = DIM (reader_table[0].atr);
       readerlen = sizeof reader -1 ;
@@ -1487,17 +820,12 @@ connect_pcsc_card (int slot)
                          reader_table[slot].atr, &atrlen);
       if (err)
         log_error ("pcsc_status failed: %s (0x%lx) %lu\n",
-                   pcsc_error_string (err), err, readerlen);
+                   pcsc_error_string (err), err, (long unsigned int)readerlen);
       else
         {
           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);
         }
     }
@@ -1505,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)
 {
@@ -1531,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;
 
@@ -1546,135 +870,171 @@ reset_pcsc_reader_direct (int slot)
 
   return sw;
 }
-#endif /*NEED_PCSC_WRAPPER*/
 
 
-#ifdef NEED_PCSC_WRAPPER
+/* Examine reader specific parameters and initialize.  This is mostly
+   for pinpad input.  Called at opening the connection to the reader.  */
 static int
-reset_pcsc_reader_wrapped (int slot)
+pcsc_vendor_specific_init (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;
+  unsigned char buf[256];
+  pcsc_dword_t len;
+  int sw;
+  int vendor = 0;
+  int product = 0;
+  pcsc_dword_t get_tlv_ioctl = (pcsc_dword_t)-1;
+  unsigned char *p;
 
-  if (slotp->pcsc.req_fd == -1
-      || slotp->pcsc.rsp_fd == -1
-      || slotp->pcsc.pid == (pid_t)(-1) )
+  len = sizeof (buf);
+  sw = control_pcsc (slot, CM_IOCTL_GET_FEATURE_REQUEST, NULL, 0, buf, &len);
+  if (sw)
     {
-      log_error ("pcsc_get_status: pcsc-wrapper not running\n");
-      return sw;
+      log_error ("pcsc_vendor_specific_init: GET_FEATURE_REQUEST failed: %d\n",
+                 sw);
+      return SW_NOT_SUPPORTED;
     }
+  else
+    {
+      p = buf;
+      while (p < buf + len)
+        {
+          unsigned char code = *p++;
+          int l = *p++;
+          unsigned int v = 0;
 
-  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) )
+          if (l == 1)
+            v = p[0];
+          else if (l == 2)
+            v = buf16_to_uint (p);
+          else if (l == 4)
+            v = buf32_to_uint (p);
+
+          if (code == FEATURE_VERIFY_PIN_DIRECT)
+            reader_table[slot].pcsc.verify_ioctl = v;
+          else if (code == FEATURE_MODIFY_PIN_DIRECT)
+            reader_table[slot].pcsc.modify_ioctl = v;
+          else if (code == FEATURE_GET_TLV_PROPERTIES)
+            get_tlv_ioctl = v;
+
+          if (DBG_CARD_IO)
+            log_debug ("feature: code=%02X, len=%d, v=%02X\n", code, l, v);
+
+          p += l;
+        }
+    }
+
+  if (get_tlv_ioctl == (pcsc_dword_t)-1)
     {
-      log_error ("error sending PC/SC RESET request: %s\n",
-                 strerror (errno));
-      goto command_failed;
+      /*
+       * For system which doesn't support GET_TLV_PROPERTIES,
+       * we put some heuristics here.
+       */
+      if (reader_table[slot].rdrname)
+        {
+          if (strstr (reader_table[slot].rdrname, "SPRx32"))
+            {
+              reader_table[slot].is_spr532 = 1;
+              reader_table[slot].pinpad_varlen_supported = 1;
+            }
+          else if (strstr (reader_table[slot].rdrname, "ST-2xxx"))
+            {
+              reader_table[slot].pcsc.pinmax = 15;
+              reader_table[slot].pinpad_varlen_supported = 1;
+            }
+          else if (strstr (reader_table[slot].rdrname, "cyberJack")
+                   || strstr (reader_table[slot].rdrname, "DIGIPASS")
+                   || strstr (reader_table[slot].rdrname, "Gnuk")
+                   || strstr (reader_table[slot].rdrname, "KAAN"))
+            reader_table[slot].pinpad_varlen_supported = 1;
+        }
+
+      return 0;
     }
 
-  /* Read the response. */
-  if ((i=readn (slotp->pcsc.rsp_fd, msgbuf, 9, &len)) || len != 9)
+  len = sizeof (buf);
+  sw = control_pcsc (slot, get_tlv_ioctl, NULL, 0, buf, &len);
+  if (sw)
     {
-      log_error ("error receiving PC/SC RESET response: %s\n",
-                 i? strerror (errno) : "premature EOF");
-      goto command_failed;
+      log_error ("pcsc_vendor_specific_init: GET_TLV_IOCTL failed: %d\n", sw);
+      return SW_NOT_SUPPORTED;
     }
-  len = (msgbuf[1] << 24) | (msgbuf[2] << 16) | (msgbuf[3] << 8 ) | msgbuf[4];
-  if (msgbuf[0] != 0x81 || len < 4)
+
+  p = buf;
+  while (p < buf + len)
     {
-      log_error ("invalid response header from PC/SC received\n");
-      goto command_failed;
+      unsigned char tag = *p++;
+      int l = *p++;
+      unsigned int v = 0;
+
+      /* Umm... here is little endian, while the encoding above is big.  */
+      if (l == 1)
+        v = p[0];
+      else if (l == 2)
+        v = (((unsigned int)p[1] << 8) | p[0]);
+      else if (l == 4)
+        v = (((unsigned int)p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]);
+
+      if (tag == PCSCv2_PART10_PROPERTY_bMinPINSize)
+        reader_table[slot].pcsc.pinmin = v;
+      else if (tag == PCSCv2_PART10_PROPERTY_bMaxPINSize)
+        reader_table[slot].pcsc.pinmax = v;
+      else if (tag == PCSCv2_PART10_PROPERTY_wIdVendor)
+        vendor = v;
+      else if (tag == PCSCv2_PART10_PROPERTY_wIdProduct)
+        product = v;
+
+      if (DBG_CARD_IO)
+        log_debug ("TLV properties: tag=%02X, len=%d, v=%08X\n", tag, l, v);
+
+      p += l;
     }
-  len -= 4; /* Already read the error code. */
-  if (len > DIM (slotp->atr))
+
+  if (vendor == VENDOR_VEGA && product == VEGA_ALPHA)
     {
-      log_error ("PC/SC returned a too large ATR (len=%lx)\n",
-                 (unsigned long)len);
-      sw = SW_HOST_GENERAL_ERROR;
-      goto command_failed;
+      /*
+       * Please read the comment of ccid_vendor_specific_init in
+       * ccid-driver.c.
+       */
+      const unsigned char cmd[] = { '\xb5', '\x01', '\x00', '\x03', '\x00' };
+      sw = control_pcsc (slot, CM_IOCTL_VENDOR_IFD_EXCHANGE,
+                         cmd, sizeof (cmd), NULL, 0);
+      if (sw)
+        return SW_NOT_SUPPORTED;
     }
-  err = PCSC_ERR_MASK ((msgbuf[5] << 24) | (msgbuf[6] << 16)
-                       | (msgbuf[7] << 8 ) | msgbuf[8]);
-  if (err)
+  else if (vendor == VENDOR_SCM && product == SCM_SPR532) /* SCM SPR532 */
     {
-      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;
+      reader_table[slot].is_spr532 = 1;
+      reader_table[slot].pinpad_varlen_supported = 1;
     }
-
-  /* The open function may return a zero for the ATR length to
-     indicate that no card is present.  */
-  n = len;
-  if (n)
+  else if (vendor == 0x046a)
     {
-      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;
-        }
+      /* 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;
     }
-  slotp->atrlen = len;
-
-  /* Read the status so that IS_T0 will be set. */
-  pcsc_get_status (slot, &dummy_status);
+  else if (vendor == 0x0c4b /* Tested with Reiner cyberJack GO */
+           || vendor == 0x1a44 /* Tested with Vasco DIGIPASS 920 */
+           || vendor == 0x234b /* Tested with FSIJ Gnuk Token */
+           || vendor == 0x0d46 /* Tested with KAAN Advanced??? */)
+    reader_table[slot].pinpad_varlen_supported = 1;
 
   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
 }
 
 
 /* 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;
   char *list = NULL;
-  unsigned long nreader, listlen;
+  char *rdrname = NULL;
+  pcsc_dword_t nreader;
   char *p;
 
   slot = new_reader_slot ();
@@ -1690,6 +1050,7 @@ open_pcsc_reader_direct (const char *portstr)
       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;
     }
 
@@ -1703,6 +1064,7 @@ open_pcsc_reader_direct (const char *portstr)
           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,
@@ -1715,41 +1077,44 @@ open_pcsc_reader_direct (const char *portstr)
       pcsc_release_context (reader_table[slot].pcsc.context);
       reader_table[slot].used = 0;
       xfree (list);
+      unlock_slot (slot);
       return -1;
     }
 
-  listlen = nreader;
   p = list;
   while (nreader)
     {
       if (!*p && !p[1])
         break;
-      if (*p)
-        log_info ("detected reader '%s'\n", p);
+      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;
     }
 
-  reader_table[slot].rdrname = xtrymalloc (strlen (portstr? portstr : list)+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;
     }
-  strcpy (reader_table[slot].rdrname, portstr? portstr : list);
   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;
@@ -1760,351 +1125,97 @@ open_pcsc_reader_direct (const char *portstr)
   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;
-      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;
-      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;
-      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 = (msgbuf[1] << 24) | (msgbuf[2] << 16) | (msgbuf[3] << 8 ) | msgbuf[4];
-  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);
-      goto command_failed;
-    }
-  err = PCSC_ERR_MASK ((msgbuf[5] << 24) | (msgbuf[6] << 16)
-                       | (msgbuf[7] << 8 ) | msgbuf[8]);
-
-  if (err)
-    {
-      log_error ("PC/SC OPEN failed: %s\n", pcsc_error_string (err));
-      goto command_failed;
-    }
-
-  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)
-    {
-      if ((i=readn (slotp->pcsc.rsp_fd, slotp->atr, n, &len)) || len != n)
-        {
-          log_error ("error receiving PC/SC OPEN response: %s\n",
-                     i? strerror (errno) : "premature EOF");
-          goto command_failed;
-        }
-      /* 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);
-    }
-  slotp->atrlen = len;
-
-  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;
-
-  /* Read the status so that IS_T0 will be set. */
-  pcsc_get_status (slot, &dummy_status);
-
-  dump_reader_status (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;
-  /* 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
-}
 
 
 /* Check whether the reader supports the ISO command code COMMAND
-   on the keypad.  Return 0 on success.  */
+   on the pinpad.  Return 0 on success.  */
 static int
-check_pcsc_keypad (int slot, int command, int pin_mode,
-                   int pinlen_min, int pinlen_max, int pin_padlen)
+check_pcsc_pinpad (int slot, int command, pininfo_t *pininfo)
 {
-  unsigned char buf[256];
-  size_t len = 256;
-  int sw;
+  int r;
 
-  (void)pin_mode;
-  (void)pinlen_min;
-  (void)pinlen_max;
-  (void)pin_padlen;
+  if (reader_table[slot].pcsc.pinmin >= 0)
+    pininfo->minlen = reader_table[slot].pcsc.pinmin;
 
- check_again:
-  if (command == ISO7816_VERIFY)
-    {
-      if (reader_table[slot].pcsc.verify_ioctl == (unsigned long)-1)
-        return SW_NOT_SUPPORTED;
-      else if (reader_table[slot].pcsc.verify_ioctl != 0)
-        return 0;                       /* Success */
-    }
-  else if (command == ISO7816_CHANGE_REFERENCE_DATA)
-    {
-      if (reader_table[slot].pcsc.modify_ioctl == (unsigned long)-1)
-        return SW_NOT_SUPPORTED;
-      else if (reader_table[slot].pcsc.modify_ioctl != 0)
-        return 0;                       /* Success */
-    }
-  else
-    return SW_NOT_SUPPORTED;
+  if (reader_table[slot].pcsc.pinmax >= 0)
+    pininfo->maxlen = reader_table[slot].pcsc.pinmax;
 
-  reader_table[slot].pcsc.verify_ioctl = (unsigned long)-1;
-  reader_table[slot].pcsc.modify_ioctl = (unsigned long)-1;
+  if (!pininfo->minlen)
+    pininfo->minlen = 1;
+  if (!pininfo->maxlen)
+    pininfo->maxlen = 15;
 
-  sw = control_pcsc (slot, CM_IOCTL_GET_FEATURE_REQUEST, NULL, 0, buf, &len);
-  if (sw)
-    return SW_NOT_SUPPORTED;
+  if ((command == ISO7816_VERIFY && reader_table[slot].pcsc.verify_ioctl != 0)
+      || (command == ISO7816_CHANGE_REFERENCE_DATA
+          && reader_table[slot].pcsc.modify_ioctl != 0))
+    r = 0;                       /* Success */
   else
-    {
-      unsigned char *p = buf;
+    r = SW_NOT_SUPPORTED;
 
-      while (p < buf + len)
-        {
-          unsigned char code = *p++;
+  if (DBG_CARD_IO)
+    log_debug ("check_pcsc_pinpad: command=%02X, r=%d\n",
+               (unsigned int)command, r);
 
-          p++;                  /* Skip length */
-          if (code == FEATURE_VERIFY_PIN_DIRECT)
-            reader_table[slot].pcsc.verify_ioctl
-              = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
-          else if (code == FEATURE_MODIFY_PIN_DIRECT)
-            reader_table[slot].pcsc.modify_ioctl
-              = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
-          p += 4;
-        }
-    }
+  if (reader_table[slot].pinpad_varlen_supported)
+    pininfo->fixedlen = 0;
 
-  goto check_again;
+  return r;
 }
 
-
 #define PIN_VERIFY_STRUCTURE_SIZE 24
 static int
-pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1,
-                    struct pininfo_s *pininfo)
+pcsc_pinpad_verify (int slot, int class, int ins, int p0, int p1,
+                    pininfo_t *pininfo)
 {
   int sw;
   unsigned char *pin_verify;
-  int len = PIN_VERIFY_STRUCTURE_SIZE;
-  unsigned char result[2];
-  size_t resultlen = 2;
+  int len = PIN_VERIFY_STRUCTURE_SIZE + pininfo->fixedlen;
+  /*
+   * The result buffer is only expected to have two-byte result on
+   * return.  However, some implementation uses this buffer for lower
+   * layer too and it assumes that there is enough space for lower
+   * layer communication.  Such an implementation fails for TPDU
+   * readers with "insufficient buffer", as it needs header and
+   * trailer.  Six is the number for header + result + trailer (TPDU).
+   */
+  unsigned char result[6];
+  pcsc_dword_t resultlen = 6;
+  int no_lc;
 
   if (!reader_table[slot].atrlen
       && (sw = reset_pcsc_reader (slot)))
     return sw;
 
-  if (pininfo->mode != 1)
-    return SW_NOT_SUPPORTED;
-
-  if (pininfo->padlen != 0)
+  if (pininfo->fixedlen < 0 || pininfo->fixedlen >= 16)
     return SW_NOT_SUPPORTED;
 
-  if (!pininfo->minlen)
-    pininfo->minlen = 1;
-  if (!pininfo->maxlen)
-    pininfo->maxlen = 25;
-
-  /* Note that the 25 is the maximum value the SPR532 allows.  */
-  if (pininfo->minlen < 1 || pininfo->minlen > 25
-      || pininfo->maxlen < 1 || pininfo->maxlen > 25
-      || pininfo->minlen > pininfo->maxlen)
-    return SW_HOST_INV_VALUE;
-
   pin_verify = xtrymalloc (len);
   if (!pin_verify)
     return SW_HOST_OUT_OF_CORE;
 
-  pin_verify[0] = 0x00; /* bTimerOut */
-  pin_verify[1] = 0x00; /* bTimerOut2 */
+  no_lc = (!pininfo->fixedlen && reader_table[slot].is_spr532);
+
+  pin_verify[0] = 0x00; /* bTimeOut */
+  pin_verify[1] = 0x00; /* bTimeOut2 */
   pin_verify[2] = 0x82; /* bmFormatString: Byte, pos=0, left, ASCII. */
-  pin_verify[3] = 0x00; /* bmPINBlockString */
+  pin_verify[3] = pininfo->fixedlen; /* bmPINBlockString */
   pin_verify[4] = 0x00; /* bmPINLengthFormat */
   pin_verify[5] = pininfo->maxlen; /* wPINMaxExtraDigit */
   pin_verify[6] = pininfo->minlen; /* wPINMaxExtraDigit */
   pin_verify[7] = 0x02; /* bEntryValidationCondition: Validation key pressed */
   if (pininfo->minlen && pininfo->maxlen && pininfo->minlen == pininfo->maxlen)
     pin_verify[7] |= 0x01; /* Max size reached.  */
-  pin_verify[8] = 0xff; /* bNumberMessage: Default */
+  pin_verify[8] = 0x01; /* bNumberMessage: One message */
   pin_verify[9] =  0x09; /* wLangId: 0x0409: US English */
   pin_verify[10] = 0x04; /* wLangId: 0x0409: US English */
   pin_verify[11] = 0x00; /* bMsgIndex */
   pin_verify[12] = 0x00; /* bTeoPrologue[0] */
   pin_verify[13] = 0x00; /* bTeoPrologue[1] */
-  pin_verify[14] = 0x00; /* bTeoPrologue[2] */
-  pin_verify[15] = 0x05; /* ulDataLength */
+  pin_verify[14] = pininfo->fixedlen + 0x05 - no_lc; /* bTeoPrologue[2] */
+  pin_verify[15] = pininfo->fixedlen + 0x05 - no_lc; /* ulDataLength */
   pin_verify[16] = 0x00; /* ulDataLength */
   pin_verify[17] = 0x00; /* ulDataLength */
   pin_verify[18] = 0x00; /* ulDataLength */
@@ -2112,18 +1223,20 @@ pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1,
   pin_verify[20] = ins; /* abData[1] */
   pin_verify[21] = p0; /* abData[2] */
   pin_verify[22] = p1; /* abData[3] */
-  pin_verify[23] = 0x00; /* abData[4] */
+  pin_verify[23] = pininfo->fixedlen; /* abData[4] */
+  if (pininfo->fixedlen)
+    memset (&pin_verify[24], 0xff, pininfo->fixedlen);
+  else if (no_lc)
+    len--;
 
   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);
   xfree (pin_verify);
   if (sw || resultlen < 2)
-    return sw? sw : SW_HOST_INCOMPLETE_CARD_RESPONSE;
-  sw = (result[resultlen-2] << 8) | result[resultlen-1];
     {
       log_error ("control_pcsc failed: %d\n", sw);
       return sw? sw: SW_HOST_INCOMPLETE_CARD_RESPONSE;
@@ -2137,47 +1250,36 @@ pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1,
 
 #define PIN_MODIFY_STRUCTURE_SIZE 29
 static int
-pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1,
-                    struct pininfo_s *pininfo)
+pcsc_pinpad_modify (int slot, int class, int ins, int p0, int p1,
+                    pininfo_t *pininfo)
 {
   int sw;
   unsigned char *pin_modify;
-  int len = PIN_MODIFY_STRUCTURE_SIZE;
-  unsigned char result[2];
-  size_t resultlen = 2;
+  int len = PIN_MODIFY_STRUCTURE_SIZE + 2 * pininfo->fixedlen;
+  unsigned char result[6];      /* See the comment at pinpad_verify.  */
+  pcsc_dword_t resultlen = 6;
+  int no_lc;
 
   if (!reader_table[slot].atrlen
       && (sw = reset_pcsc_reader (slot)))
     return sw;
 
-  if (pininfo->mode != 1)
+  if (pininfo->fixedlen < 0 || pininfo->fixedlen >= 16)
     return SW_NOT_SUPPORTED;
 
-  if (pininfo->padlen != 0)
-    return SW_NOT_SUPPORTED;
-
-  if (!pininfo->minlen)
-    pininfo->minlen = 1;
-  if (!pininfo->maxlen)
-    pininfo->maxlen = 25;
-
-  /* Note that the 25 is the maximum value the SPR532 allows.  */
-  if (pininfo->minlen < 1 || pininfo->minlen > 25
-      || pininfo->maxlen < 1 || pininfo->maxlen > 25
-      || pininfo->minlen > pininfo->maxlen)
-    return SW_HOST_INV_VALUE;
-
   pin_modify = xtrymalloc (len);
   if (!pin_modify)
     return SW_HOST_OUT_OF_CORE;
 
-  pin_modify[0] = 0x00; /* bTimerOut */
-  pin_modify[1] = 0x00; /* bTimerOut2 */
+  no_lc = (!pininfo->fixedlen && reader_table[slot].is_spr532);
+
+  pin_modify[0] = 0x00; /* bTimeOut */
+  pin_modify[1] = 0x00; /* bTimeOut2 */
   pin_modify[2] = 0x82; /* bmFormatString: Byte, pos=0, left, ASCII. */
-  pin_modify[3] = 0x00; /* bmPINBlockString */
+  pin_modify[3] = pininfo->fixedlen; /* bmPINBlockString */
   pin_modify[4] = 0x00; /* bmPINLengthFormat */
   pin_modify[5] = 0x00; /* bInsertionOffsetOld */
-  pin_modify[6] = 0x00; /* bInsertionOffsetNew */
+  pin_modify[6] = pininfo->fixedlen; /* bInsertionOffsetNew */
   pin_modify[7] = pininfo->maxlen; /* wPINMaxExtraDigit */
   pin_modify[8] = pininfo->minlen; /* wPINMaxExtraDigit */
   pin_modify[9] = (p0 == 0 ? 0x03 : 0x01);
@@ -2190,16 +1292,16 @@ pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1,
   pin_modify[10] = 0x02; /* bEntryValidationCondition: Validation key pressed */
   if (pininfo->minlen && pininfo->maxlen && pininfo->minlen == pininfo->maxlen)
     pin_modify[10] |= 0x01; /* Max size reached.  */
-  pin_modify[11] = 0xff; /* bNumberMessage: Default */
-  pin_modify[12] =  0x09; /* wLangId: 0x0409: US English */
+  pin_modify[11] = 0x03; /* bNumberMessage: Three messages */
+  pin_modify[12] = 0x09; /* wLangId: 0x0409: US English */
   pin_modify[13] = 0x04; /* wLangId: 0x0409: US English */
   pin_modify[14] = 0x00; /* bMsgIndex1 */
-  pin_modify[15] = 0x00; /* bMsgIndex2 */
-  pin_modify[16] = 0x00; /* bMsgIndex3 */
+  pin_modify[15] = 0x01; /* bMsgIndex2 */
+  pin_modify[16] = 0x02; /* bMsgIndex3 */
   pin_modify[17] = 0x00; /* bTeoPrologue[0] */
   pin_modify[18] = 0x00; /* bTeoPrologue[1] */
-  pin_modify[19] = 0x00; /* bTeoPrologue[2] */
-  pin_modify[20] = 0x05; /* ulDataLength */
+  pin_modify[19] = 2 * pininfo->fixedlen + 0x05 - no_lc; /* bTeoPrologue[2] */
+  pin_modify[20] = 2 * pininfo->fixedlen + 0x05 - no_lc; /* ulDataLength */
   pin_modify[21] = 0x00; /* ulDataLength */
   pin_modify[22] = 0x00; /* ulDataLength */
   pin_modify[23] = 0x00; /* ulDataLength */
@@ -2207,11 +1309,15 @@ pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1,
   pin_modify[25] = ins; /* abData[1] */
   pin_modify[26] = p0; /* abData[2] */
   pin_modify[27] = p1; /* abData[3] */
-  pin_modify[28] = 0x00; /* abData[4] */
+  pin_modify[28] = 2 * pininfo->fixedlen; /* abData[4] */
+  if (pininfo->fixedlen)
+    memset (&pin_modify[29], 0xff, 2 * pininfo->fixedlen);
+  else if (no_lc)
+    len--;
 
   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);
@@ -2243,15 +1349,6 @@ static int
 close_ccid_reader (int slot)
 {
   ccid_close_reader (reader_table[slot].ccid.handle);
-  reader_table[slot].used = 0;
-  return 0;
-}
-
-
-static int
-shutdown_ccid_reader (int slot)
-{
-  ccid_shutdown_reader (reader_table[slot].ccid.handle);
   return 0;
 }
 
@@ -2286,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;
 
@@ -2312,7 +1409,7 @@ get_status_ccid (int slot, unsigned int *status)
 static int
 send_apdu_ccid (int slot, unsigned char *apdu, size_t apdulen,
                 unsigned char *buffer, size_t *buflen,
-                struct pininfo_s *pininfo)
+                pininfo_t *pininfo)
 {
   long err;
   size_t maxbuflen;
@@ -2328,11 +1425,7 @@ send_apdu_ccid (int slot, unsigned char *apdu, size_t apdulen,
   maxbuflen = *buflen;
   if (pininfo)
     err = ccid_transceive_secure (reader_table[slot].ccid.handle,
-                                  apdu, apdulen,
-                                  pininfo->mode,
-                                  pininfo->minlen,
-                                  pininfo->maxlen,
-                                  pininfo->padlen,
+                                  apdu, apdulen, pininfo,
                                   buffer, maxbuflen, buflen);
   else
     err = ccid_transceive (reader_table[slot].ccid.handle,
@@ -2347,25 +1440,22 @@ send_apdu_ccid (int slot, unsigned char *apdu, size_t apdulen,
 
 
 /* Check whether the CCID reader supports the ISO command code COMMAND
-   on the keypad.  Return 0 on success.  For a description of the pin
+   on the pinpad.  Return 0 on success.  For a description of the pin
    parameters, see ccid-driver.c */
 static int
-check_ccid_keypad (int slot, int command, int pin_mode,
-                   int pinlen_min, int pinlen_max, int pin_padlen)
+check_ccid_pinpad (int slot, int command, pininfo_t *pininfo)
 {
   unsigned char apdu[] = { 0, 0, 0, 0x81 };
 
   apdu[1] = command;
-  return ccid_transceive_secure (reader_table[slot].ccid.handle,
-                                 apdu, sizeof apdu,
-                                 pin_mode, pinlen_min, pinlen_max, pin_padlen,
-                                 NULL, 0, NULL);
+  return ccid_transceive_secure (reader_table[slot].ccid.handle, apdu,
+                                 sizeof apdu, pininfo, NULL, 0, NULL);
 }
 
 
 static int
-ccid_keypad_operation (int slot, int class, int ins, int p0, int p1,
-                      struct pininfo_s *pininfo)
+ccid_pinpad_operation (int slot, int class, int ins, int p0, int p1,
+                       pininfo_t *pininfo)
 {
   unsigned char apdu[4];
   int err, sw;
@@ -2377,9 +1467,7 @@ ccid_keypad_operation (int slot, int class, int ins, int p0, int p1,
   apdu[2] = p0;
   apdu[3] = p1;
   err = ccid_transceive_secure (reader_table[slot].ccid.handle,
-                                apdu, sizeof apdu,
-                                pininfo->mode, pininfo->minlen, pininfo->maxlen,
-                                pininfo->padlen,
+                                apdu, sizeof apdu, pininfo,
                                 result, 2, &resultlen);
   if (err)
     return err;
@@ -2394,10 +1482,11 @@ ccid_keypad_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 ();
@@ -2405,52 +1494,44 @@ open_ccid_reader (const char *portstr)
     return -1;
   slotp = reader_table + slot;
 
-  err = ccid_open_reader (&slotp->ccid.handle, portstr);
-  if (err)
+  err = ccid_open_reader (dl->portstr, dl->idx, dl->ccid_table,
+                          &slotp->ccid.handle, &slotp->rdrname);
+  if (!err)
     {
-      slotp->used = 0;
-      return -1;
+      err = ccid_get_atr (slotp->ccid.handle,
+                          slotp->atr, sizeof slotp->atr, &slotp->atrlen);
+      if (err)
+        ccid_close_reader (slotp->ccid.handle);
     }
 
-  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);
+      slotp->used = 0;
+      unlock_slot (slot);
+      return -1;
     }
 
+  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;
-  reader_table[slot].check_keypad = check_ccid_keypad;
+  reader_table[slot].check_pinpad = check_ccid_pinpad;
   reader_table[slot].dump_status_reader = dump_ccid_reader_status;
   reader_table[slot].set_progress_cb = set_progress_cb_ccid_reader;
-  reader_table[slot].keypad_verify = ccid_keypad_operation;
-  reader_table[slot].keypad_modify = ccid_keypad_operation;
+  reader_table[slot].pinpad_verify = ccid_pinpad_operation;
+  reader_table[slot].pinpad_modify = ccid_pinpad_operation;
   /* 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
 /*
@@ -2497,7 +1578,6 @@ static int
 close_rapdu_reader (int slot)
 {
   rapdu_release (reader_table[slot].rapdu.handle);
-  reader_table[slot].used = 0;
   return 0;
 }
 
@@ -2550,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);
@@ -2597,7 +1678,7 @@ my_rapdu_get_status (int slot, unsigned int *status)
 static int
 my_rapdu_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
                     unsigned char *buffer, size_t *buflen,
-                    struct pininfo_s *pininfo)
+                    pininfo_t *pininfo)
 {
   int err;
   reader_table_t slotp;
@@ -2681,6 +1762,7 @@ open_rapdu_reader (int portno,
   if (!slotp->rapdu.handle)
     {
       slotp->used = 0;
+      unlock_slot (slot);
       return -1;
     }
 
@@ -2728,19 +1810,21 @@ open_rapdu_reader (int portno,
   reader_table[slot].reset_reader = reset_rapdu_reader;
   reader_table[slot].get_status_reader = my_rapdu_get_status;
   reader_table[slot].send_apdu_reader = my_rapdu_send_apdu;
-  reader_table[slot].check_keypad = NULL;
+  reader_table[slot].check_pinpad = NULL;
   reader_table[slot].dump_status_reader = NULL;
-  reader_table[slot].keypad_verify = NULL;
-  reader_table[slot].keypad_modify = NULL;
+  reader_table[slot].pinpad_verify = NULL;
+  reader_table[slot].pinpad_modify = NULL;
 
   dump_reader_status (slot);
   rapdu_msg_release (msg);
+  unlock_slot (slot);
   return slot;
 
  failure:
   rapdu_msg_release (msg);
   rapdu_release (slotp->rapdu.handle);
   slotp->used = 0;
+  unlock_slot (slot);
   return -1;
 }
 
@@ -2751,144 +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 ();
 
-static int
-lock_slot (int slot)
-{
-#ifdef USE_NPTH
-  int err;
+  dl->portstr = portstr;
+  dl->idx = 0;
 
-  err = npth_mutex_lock (&reader_table[slot].lock);
-  if (err)
+  npth_mutex_lock (&reader_table_lock);
+
+#ifdef HAVE_LIBUSB
+  if (opt.disable_ccid)
     {
-      log_error ("failed to acquire apdu lock: %s\n", strerror (err));
-      return SW_HOST_LOCKING_FAILED;
+      dl->ccid_table = NULL;
+      dl->idx_max = 1;
     }
-#endif /*USE_NPTH*/
-  return 0;
-}
+  else
+    {
+      gpg_error_t err;
 
-static int
-trylock_slot (int slot)
-{
-#ifdef USE_NPTH
-  int err;
+      err = ccid_dev_scan (&dl->idx_max, &dl->ccid_table);
+      if (err)
+        return err;
 
-  err = npth_mutex_trylock (&reader_table[slot].lock);
-  if (err == EBUSY)
-    return SW_HOST_BUSY;
-  else if (err)
-    {
-      log_error ("failed to acquire apdu lock: %s\n", strerror (err));
-      return SW_HOST_LOCKING_FAILED;
+      if (dl->idx_max == 0)
+        {
+          /* 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");
+
+              xfree (dl);
+              npth_mutex_unlock (&reader_table_lock);
+              return gpg_error (GPG_ERR_ENODEV);
+            }
+          else
+            dl->idx_max = 1;
+        }
     }
-#endif /*USE_NPTH*/
+#else
+  dl->ccid_table = NULL;
+  dl->idx_max = 1;
+#endif /* HAVE_LIBUSB */
+
+  *l_p = dl;
   return 0;
 }
 
-static void
-unlock_slot (int slot)
+void
+apdu_dev_list_finish (struct dev_list *dl)
 {
-#ifdef USE_NPTH
-  int err;
-
-  err = npth_mutex_unlock (&reader_table[slot].lock);
-  if (err)
-    log_error ("failed to release apdu lock: %s\n", strerror (errno));
-#endif /*USE_NPTH*/
+#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);
 }
 
 
 /* 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
+apdu_open_one_reader (const char *portstr)
 {
-  static int pcsc_api_loaded, ct_api_loaded;
+  static int pcsc_api_loaded;
   int slot;
 
   if (DBG_READER)
     log_debug ("enter: apdu_open_reader: portstr=%s\n", portstr);
 
-#ifdef HAVE_LIBUSB
-  if (!opt.disable_ccid)
-    {
-      static int once_available;
-      int i;
-      const char *s;
-
-      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 */
-        }
-
-      /* 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 (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 (DBG_READER)
-                log_debug ("leave: apdu_open_reader => slot=-1 (no ccid)\n");
-              return -1;
-            }
-    }
-
-#endif /* HAVE_LIBUSB */
-
-  if (opt.ctapi_driver && *opt.ctapi_driver)
-    {
-      int port = portstr? atoi (portstr) : 32768;
-
-      if (!ct_api_loaded)
-        {
-          void *handle;
-
-          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);
-    }
-
-
-  /* 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);
@@ -2967,7 +1994,6 @@ apdu_open_reader (const char *portstr)
           dlclose (handle);
           return -1;
         }
-#endif /*!NEED_PCSC_WRAPPER*/
       pcsc_api_loaded = 1;
     }
 
@@ -2978,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,
@@ -3041,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;
@@ -3071,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. */
@@ -3136,13 +2236,16 @@ 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)
 {
-  int sw;
-  unsigned int status;
+  int sw = 0;
+  unsigned int status = 0;
 
   if (DBG_READER)
     log_debug ("enter: apdu_connect: slot=%d\n", slot);
@@ -3151,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.
@@ -3166,15 +2269,15 @@ apdu_connect (int slot)
           unlock_slot (slot);
         }
     }
-  else
-    sw = 0;
 
   /* We need to call apdu_get_status_internal, so that the last-status
      machinery gets setup properly even if a card is inserted while
      scdaemon is fired up and apdu_get_status has not yet been called.
      Without that we would force a reset of the card with the next
      call to apdu_get_status.  */
-  apdu_get_status_internal (slot, 1, 1, &status, NULL);
+  if (!sw)
+    sw = apdu_get_status_internal (slot, 1, &status, 1);
+
   if (sw)
     ;
   else if (!(status & APDU_CARD_PRESENT))
@@ -3182,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;
 }
 
 
@@ -3270,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);
@@ -3339,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;
@@ -3359,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);
     }
@@ -3419,63 +2495,76 @@ apdu_get_status (int slot, int hang,
 
 
 /* Check whether the reader supports the ISO command code COMMAND on
-   the keypad.  Return 0 on success.  For a description of the pin
+   the pinpad.  Return 0 on success.  For a description of the pin
    parameters, see ccid-driver.c */
 int
-apdu_check_keypad (int slot, int command, int pin_mode,
-                   int pinlen_min, int pinlen_max, int pin_padlen)
+apdu_check_pinpad (int slot, int command, pininfo_t *pininfo)
 {
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return SW_HOST_NO_DRIVER;
 
-  if (reader_table[slot].check_keypad)
-    return reader_table[slot].check_keypad (slot, command,
-                                            pin_mode, pinlen_min, pinlen_max,
-                                            pin_padlen);
+  if (opt.enable_pinpad_varlen)
+    pininfo->fixedlen = 0;
+
+  if (reader_table[slot].check_pinpad)
+    {
+      int sw;
+
+      if ((sw = lock_slot (slot)))
+        return sw;
+
+      sw = reader_table[slot].check_pinpad (slot, command, pininfo);
+      unlock_slot (slot);
+      return sw;
+    }
   else
     return SW_HOST_NOT_SUPPORTED;
 }
 
 
 int
-apdu_keypad_verify (int slot, int class, int ins, int p0, int p1, int pin_mode,
-                    int pinlen_min, int pinlen_max, int pin_padlen)
+apdu_pinpad_verify (int slot, int class, int ins, int p0, int p1,
+                    pininfo_t *pininfo)
 {
-  struct pininfo_s pininfo;
-
-  pininfo.mode = pin_mode;
-  pininfo.minlen = pinlen_min;
-  pininfo.maxlen = pinlen_max;
-  pininfo.padlen = pin_padlen;
-
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return SW_HOST_NO_DRIVER;
 
-  if (reader_table[slot].keypad_verify)
-    return reader_table[slot].keypad_verify (slot, class, ins, p0, p1,
-                                             &pininfo);
+  if (reader_table[slot].pinpad_verify)
+    {
+      int sw;
+
+      if ((sw = lock_slot (slot)))
+        return sw;
+
+      sw = reader_table[slot].pinpad_verify (slot, class, ins, p0, p1,
+                                             pininfo);
+      unlock_slot (slot);
+      return sw;
+    }
   else
     return SW_HOST_NOT_SUPPORTED;
 }
 
 
 int
-apdu_keypad_modify (int slot, int class, int ins, int p0, int p1, int pin_mode,
-                    int pinlen_min, int pinlen_max, int pin_padlen)
+apdu_pinpad_modify (int slot, int class, int ins, int p0, int p1,
+                    pininfo_t *pininfo)
 {
-  struct pininfo_s pininfo;
-
-  pininfo.mode = pin_mode;
-  pininfo.minlen = pinlen_min;
-  pininfo.maxlen = pinlen_max;
-  pininfo.padlen = pin_padlen;
-
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return SW_HOST_NO_DRIVER;
 
-  if (reader_table[slot].keypad_modify)
-    return reader_table[slot].keypad_modify (slot, class, ins, p0, p1,
-                                             &pininfo);
+  if (reader_table[slot].pinpad_modify)
+    {
+      int sw;
+
+      if ((sw = lock_slot (slot)))
+        return sw;
+
+      sw = reader_table[slot].pinpad_modify (slot, class, ins, p0, p1,
+                                             pininfo);
+      unlock_slot (slot);
+      return sw;
+    }
   else
     return SW_HOST_NOT_SUPPORTED;
 }
@@ -3485,7 +2574,7 @@ apdu_keypad_modify (int slot, int class, int ins, int p0, int p1, int pin_mode,
    function should be called in locked state. */
 static int
 send_apdu (int slot, unsigned char *apdu, size_t apdulen,
-           unsigned char *buffer, size_t *buflen, struct pininfo_s *pininfo)
+           unsigned char *buffer, size_t *buflen, pininfo_t *pininfo)
 {
   if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
     return SW_HOST_NO_DRIVER;
@@ -3501,7 +2590,7 @@ send_apdu (int slot, unsigned char *apdu, size_t apdulen,
 
 
 /* Core APDU tranceiver function. Parameters are described at
-   apdu_send_le with the exception of PININFO which indicates keypad
+   apdu_send_le with the exception of PININFO which indicates pinpad
    related operations if not NULL.  If EXTENDED_MODE is not 0
    command chaining or extended length will be used according to these
    values:
@@ -3517,7 +2606,7 @@ static int
 send_le (int slot, int class, int ins, int p0, int p1,
          int lc, const char *data, int le,
          unsigned char **retbuf, size_t *retbuflen,
-         struct pininfo_s *pininfo, int extended_mode)
+         pininfo_t *pininfo, int extended_mode)
 {
 #define SHORT_RESULT_BUFFER_SIZE 258
   /* We allocate 8 extra bytes as a safety margin towards a driver bug.  */
@@ -3608,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);
@@ -3641,9 +2731,9 @@ send_le (int slot, int class, int ins, int p0, int p1,
           apdu[apdulen++] = ins;
           apdu[apdulen++] = p0;
           apdu[apdulen++] = p1;
-          apdu[apdulen++] = 0;  /* Z byte: Extended length marker.  */
-          if (lc >= 0)
+          if (lc > 0)
             {
+              apdu[apdulen++] = 0;  /* Z byte: Extended length marker.  */
               apdu[apdulen++] = ((lc >> 8) & 0xff);
               apdu[apdulen++] = (lc & 0xff);
               memcpy (apdu+apdulen, data, lc);
@@ -3652,6 +2742,8 @@ send_le (int slot, int class, int ins, int p0, int p1,
             }
           if (le != -1)
             {
+              if (lc <= 0)
+                apdu[apdulen++] = 0;  /* Z byte: Extended length marker.  */
               apdu[apdulen++] = ((le >> 8) & 0xff);
               apdu[apdulen++] = (le & 0xff);
             }
@@ -3721,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. */
@@ -3863,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,
@@ -3886,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,
@@ -4139,3 +3230,35 @@ apdu_send_direct (int slot, size_t extended_length,
 
   return 0;
 }
+
+
+const char *
+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;
+}