Revert SCD changes of 2010-05-03.
[gnupg.git] / scd / ccid-driver.c
index b3f2493..3fe932c 100644 (file)
@@ -40,7 +40,7 @@
  *    products derived from this software without specific prior
  *    written permission.
  *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  * OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * $Date$
  */
 
 
 /* CCID (ChipCardInterfaceDevices) is a specification for accessing
-   smartcard via a reader connected to the USB.  
+   smartcard via a reader connected to the USB.
 
    This is a limited driver allowing to use some CCID drivers directly
    without any other specila drivers. This is a fallback driver to be
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
+#include <time.h>
+#ifdef HAVE_NPTH
+# include <npth.h>
+#endif /*HAVE_NPTH*/
 
 #include <usb.h>
 
@@ -205,9 +207,20 @@ enum {
   VENDOR_SCM    = 0x04e6,
   VENDOR_OMNIKEY= 0x076b,
   VENDOR_GEMPC  = 0x08e6,
-  VENDOR_KAAN   = 0x0d46
+  VENDOR_KAAN   = 0x0d46,
+  VENDOR_FSIJ   = 0x234b,
+  VENDOR_VASCO  = 0x1a44
 };
 
+/* Some product ids.  */
+#define SCM_SCR331      0xe001
+#define SCM_SCR331DI    0x5111
+#define SCM_SCR335      0x5115
+#define SCM_SCR3320     0x5117
+#define SCM_SPR532      0xe003
+#define CHERRY_ST2000   0x003e
+#define VASCO_920       0x0920
+
 /* A list and a table with special transport descriptions. */
 enum {
   TRANSPORT_USB    = 0, /* Standard USB transport. */
@@ -215,20 +228,20 @@ enum {
 };
 
 static struct
-{ 
+{
   char *name;  /* Device name. */
   int  type;
 
 } transports[] = {
-  { "/dev/cmx0", TRANSPORT_CM4040 },  
-  { "/dev/cmx1", TRANSPORT_CM4040 },  
+  { "/dev/cmx0", TRANSPORT_CM4040 },
+  { "/dev/cmx1", TRANSPORT_CM4040 },
   { NULL },
 };
 
 
 /* Store information on the driver's state.  A pointer to such a
    structure is used as handle for most functions. */
-struct ccid_driver_s 
+struct ccid_driver_s
 {
   usb_dev_handle *idev;
   char *rid;
@@ -244,21 +257,29 @@ struct ccid_driver_s
   int seqno;
   unsigned char t1_ns;
   unsigned char t1_nr;
-  int nonnull_nad;
-  int auto_ifsd;
+  unsigned char nonnull_nad;
   int max_ifsd;
   int ifsd;
   int ifsc;
-  int powered_off;
-  int has_pinpad;
-  int apdu_level;     /* Reader supports short APDU level exchange.
-                         With a value of 2 short and extended level is
-                         supported.*/
+  unsigned char apdu_level:2;     /* Reader supports short APDU level
+                                     exchange.  With a value of 2 short
+                                     and extended level is supported.*/
+  unsigned int auto_ifsd:1;
+  unsigned int powered_off:1;
+  unsigned int has_pinpad:2;
+  unsigned int enodev_seen:1;
+
+  time_t last_progress; /* Last time we sent progress line.  */
+
+  /* The progress callback and its first arg as supplied to
+     ccid_set_progress_cb.  */
+  void (*progress_cb)(void *, const char *, int, int, int);
+  void *progress_cb_arg;
 };
 
 
 static int initialized_usb; /* Tracks whether USB has been initialized. */
-static int debug_level;     /* Flag to control the debug output. 
+static int debug_level;     /* Flag to control the debug output.
                                0 = No debugging
                                1 = USB I/O info
                                2 = Level 1 + T=1 protocol tracing
@@ -277,19 +298,19 @@ static int abort_cmd (ccid_driver_t handle, int seqno);
 
 /* Convert a little endian stored 4 byte value into an unsigned
    integer. */
-static unsigned int 
+static unsigned int
 convert_le_u32 (const unsigned char *buf)
 {
-  return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24); 
+  return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
 }
 
 
 /* Convert a little endian stored 2 byte value into an unsigned
    integer. */
-static unsigned int 
+static unsigned int
 convert_le_u16 (const unsigned char *buf)
 {
-  return buf[0] | (buf[1] << 8); 
+  return buf[0] | (buf[1] << 8);
 }
 
 static void
@@ -302,6 +323,47 @@ set_msg_len (unsigned char *msg, unsigned int length)
 }
 
 
+static void
+my_sleep (int seconds)
+{
+#ifdef HAVE_NPTH
+  /* With Pth we also call the standard sleep(0) so that the process
+     may give up its timeslot.  */
+  if (!seconds)
+    {
+# ifdef HAVE_W32_SYSTEM
+      Sleep (0);
+# else
+      sleep (0);
+# endif
+    }
+  pth_sleep (seconds);
+#else
+# ifdef HAVE_W32_SYSTEM
+  Sleep (seconds*1000);
+# else
+  sleep (seconds);
+# endif
+#endif
+}
+
+static void
+print_progress (ccid_driver_t handle)
+{
+  time_t ct = time (NULL);
+
+  /* We don't want to print progress lines too often. */
+  if (ct == handle->last_progress)
+    return;
+
+  if (handle->progress_cb)
+    handle->progress_cb (handle->progress_cb_arg, "card_busy", 'w', 0, 0);
+
+  handle->last_progress = ct;
+}
+
+
+
 /* Pint an error message for a failed CCID command including a textual
    error code.  MSG shall be the CCID message at a minimum of 10 bytes. */
 static void
@@ -318,7 +380,7 @@ print_command_failed (const unsigned char *msg)
   switch (ec)
     {
     case 0x00: t = "Command not supported"; break;
-    
+
     case 0xE0: t = "Slot busy"; break;
     case 0xEF: t = "PIN cancelled"; break;
     case 0xF0: t = "PIN timeout"; break;
@@ -360,7 +422,7 @@ print_pr_data (const unsigned char *data, size_t datalen, size_t off)
         {
           if (any)
             DEBUGOUT_LF ();
-          DEBUGOUT_1 ("  [%04d] ", off);
+          DEBUGOUT_1 ("  [%04lu] ", (unsigned long) off);
         }
       DEBUGOUT_CONT_1 (" %02X", data[off]);
       any = 1;
@@ -369,7 +431,7 @@ print_pr_data (const unsigned char *data, size_t datalen, size_t off)
     DEBUGOUT_LF ();
 }
 
+
 static void
 print_p2r_header (const char *name, const unsigned char *msg, size_t msglen)
 {
@@ -593,7 +655,7 @@ print_r2p_slotstatus (const unsigned char *msg, size_t msglen)
               msg[9] == 3? " (stopped)":"");
   print_pr_data (msg, msglen, 10);
 }
-  
+
 
 static void
 print_r2p_parameters (const unsigned char *msg, size_t msglen)
@@ -717,7 +779,7 @@ parse_ccid_descriptor (ccid_driver_t handle,
   DEBUGOUT_1 ("  bLength             %5u\n", buf[0]);
   DEBUGOUT_1 ("  bDescriptorType     %5u\n", buf[1]);
   DEBUGOUT_2 ("  bcdCCID             %2x.%02x", buf[3], buf[2]);
-    if (buf[3] != 1 || buf[2] != 0) 
+    if (buf[3] != 1 || buf[2] != 0)
       DEBUGOUT_CONT("  (Warning: Only accurate for version 1.0)");
   DEBUGOUT_LF ();
 
@@ -749,7 +811,7 @@ parse_ccid_descriptor (ccid_driver_t handle,
   us = convert_le_u32(buf+23);
   DEBUGOUT_1 ("  dwMaxDataRate     %7u bps\n", us);
   DEBUGOUT_1 ("  bNumDataRatesSupp.  %5u\n", buf[27]);
-        
+
   us = convert_le_u32(buf+28);
   DEBUGOUT_1 ("  dwMaxIFSD           %5u\n", us);
   handle->max_ifsd = us;
@@ -792,11 +854,11 @@ parse_ccid_descriptor (ccid_driver_t handle,
   if ((us & 0x0020))
     DEBUGOUT ("    Auto baud rate change\n");
   if ((us & 0x0040))
-    DEBUGOUT ("    Auto parameter negotation made by CCID\n");
+    DEBUGOUT ("    Auto parameter negotiation made by CCID\n");
   else if ((us & 0x0080))
     DEBUGOUT ("    Auto PPS made by CCID\n");
   else if ((us & (0x0040 | 0x0080)))
-    DEBUGOUT ("    WARNING: conflicting negotation features\n");
+    DEBUGOUT ("    WARNING: conflicting negotiation features\n");
 
   if ((us & 0x0100))
     DEBUGOUT ("    CCID can set ICC in clock stop mode\n");
@@ -815,7 +877,7 @@ parse_ccid_descriptor (ccid_driver_t handle,
     {
       DEBUGOUT ("    TPDU level exchange\n");
       have_tpdu = 1;
-    } 
+    }
   else if ((us & 0x00020000))
     {
       DEBUGOUT ("    Short APDU level exchange\n");
@@ -849,7 +911,7 @@ parse_ccid_descriptor (ccid_driver_t handle,
     DEBUGOUT_CONT ("none\n");
   else
     DEBUGOUT_CONT_2 ("%u cols %u lines\n", buf[50], buf[51]);
-        
+
   DEBUGOUT_1 ("  bPINSupport         %5u ", buf[52]);
   if ((buf[52] & 1))
     {
@@ -862,15 +924,16 @@ parse_ccid_descriptor (ccid_driver_t handle,
       handle->has_pinpad |= 2;
     }
   DEBUGOUT_LF ();
-        
+
   DEBUGOUT_1 ("  bMaxCCIDBusySlots   %5u\n", buf[53]);
 
-  if (buf[0] > 54) {
-    DEBUGOUT ("  junk             ");
-    for (i=54; i < buf[0]-54; i++)
-      DEBUGOUT_CONT_1 (" %02X", buf[i]);
-    DEBUGOUT_LF ();
-  }
+  if (buf[0] > 54)
+    {
+      DEBUGOUT ("  junk             ");
+      for (i=54; i < buf[0]-54; i++)
+        DEBUGOUT_CONT_1 (" %02X", buf[i]);
+      DEBUGOUT_LF ();
+    }
 
   if (!have_t1 || !(have_tpdu  || handle->apdu_level) || !have_auto_conf)
     {
@@ -887,17 +950,23 @@ parse_ccid_descriptor (ccid_driver_t handle,
      lower than that:
         64 - 10 CCID header -  4 T1frame - 2 reserved = 48
      Product Ids:
-        0xe001 - SCR 331 
-        0x5111 - SCR 331-DI 
-        0x5115 - SCR 335 
-        0xe003 - SPR 532 
+        0xe001 - SCR 331
+        0x5111 - SCR 331-DI
+        0x5115 - SCR 335
+        0xe003 - SPR 532
+     The
+         0x5117 - SCR 3320 USB ID-000 reader
+     seems to be very slow but enabling this workaround boosts the
+     performance to a a more or less acceptable level (tested by David).
+
   */
   if (handle->id_vendor == VENDOR_SCM
-      && handle->max_ifsd > 48      
-      && (  (handle->id_product == 0xe001 && handle->bcd_device < 0x0516)
-          ||(handle->id_product == 0x5111 && handle->bcd_device < 0x0620)
-          ||(handle->id_product == 0x5115 && handle->bcd_device < 0x0514)
-          ||(handle->id_product == 0xe003 && handle->bcd_device < 0x0504)
+      && handle->max_ifsd > 48
+      && (  (handle->id_product == SCM_SCR331   && handle->bcd_device < 0x0516)
+          ||(handle->id_product == SCM_SCR331DI && handle->bcd_device < 0x0620)
+          ||(handle->id_product == SCM_SCR335   && handle->bcd_device < 0x0514)
+          ||(handle->id_product == SCM_SPR532   && handle->bcd_device < 0x0504)
+          ||(handle->id_product == SCM_SCR3320  && handle->bcd_device < 0x0522)
           ))
     {
       DEBUGOUT ("enabling workaround for buggy SCM readers\n");
@@ -931,7 +1000,7 @@ get_escaped_usb_string (usb_dev_handle *idev, int idx,
      If we do don't find it we try to use English.  Note that this is
      all in a 2 bute Unicode encoding using little endian. */
   rc = usb_control_msg (idev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
-                        (USB_DT_STRING << 8), 0, 
+                        (USB_DT_STRING << 8), 0,
                         (char*)buf, sizeof buf, 1000 /* ms timeout */);
   if (rc < 4)
     langid = 0x0409; /* English.  */
@@ -953,7 +1022,7 @@ get_escaped_usb_string (usb_dev_handle *idev, int idx,
         n++; /* High byte set. */
       else if (*s <= 0x20 || *s >= 0x7f || *s == '%' || *s == ':')
         n += 3 ;
-      else 
+      else
         n++;
     }
 
@@ -972,7 +1041,7 @@ get_escaped_usb_string (usb_dev_handle *idev, int idx,
           sprintf (result+n, "%%%02X", *s);
           n += 3;
         }
-      else 
+      else
         result[n++] = *s;
     }
   strcpy (result+n, suffix);
@@ -1054,7 +1123,7 @@ scan_or_find_usb_device (int scan_mode,
   int ifc_no;
   int set_no;
   struct usb_config_descriptor *config;
-  struct usb_interface *interface;          
+  struct usb_interface *interface;
   struct usb_interface_descriptor *ifcdesc;
   char *rid;
   usb_dev_handle *idev;
@@ -1072,21 +1141,25 @@ scan_or_find_usb_device (int scan_mode,
           interface = config->interface + ifc_no;
           if (!interface)
             continue;
-                  
+
           for (set_no=0; set_no < interface->num_altsetting; set_no++)
             {
               ifcdesc = (interface->altsetting + set_no);
               /* The second condition is for older SCM SPR 532 who did
-                 not know about the assigned CCID class.  Instead of
-                 trying to interpret the strings we simply check the
-                 product ID. */
+                 not know about the assigned CCID class.  The third
+                 condition does the same for a Cherry SmartTerminal
+                 ST-2000.  Instead of trying to interpret the strings
+                 we simply check the product ID. */
               if (ifcdesc && ifcdesc->extra
                   && ((ifcdesc->bInterfaceClass == 11
                        && ifcdesc->bInterfaceSubClass == 0
                        && ifcdesc->bInterfaceProtocol == 0)
                       || (ifcdesc->bInterfaceClass == 255
                           && dev->descriptor.idVendor == VENDOR_SCM
-                          && dev->descriptor.idProduct == 0xe003)))
+                          && dev->descriptor.idProduct == SCM_SPR532)
+                      || (ifcdesc->bInterfaceClass == 255
+                          && dev->descriptor.idVendor == VENDOR_CHERRY
+                          && dev->descriptor.idProduct == CHERRY_ST2000)))
                 {
                   idev = usb_open (dev);
                   if (!idev)
@@ -1095,7 +1168,7 @@ scan_or_find_usb_device (int scan_mode,
                                   strerror (errno));
                       continue; /* with next setting. */
                     }
-                  
+
                   rid = make_reader_id (idev,
                                         dev->descriptor.idVendor,
                                         dev->descriptor.idProduct,
@@ -1105,7 +1178,7 @@ scan_or_find_usb_device (int scan_mode,
                       if (scan_mode)
                         {
                           char *p;
-                          
+
                           /* We are collecting infos about all
                              available CCID readers.  Store them and
                              continue. */
@@ -1127,7 +1200,7 @@ scan_or_find_usb_device (int scan_mode,
                             }
                           else /* Out of memory. */
                             free (rid);
-                          
+
                           rid = NULL;
                           ++*count;
                         }
@@ -1171,7 +1244,7 @@ scan_or_find_usb_device (int scan_mode,
                             }
                           else
                             free (rid);
-                          
+
                           *r_idev = idev;
                           return 1; /* Found requested device. */
                         }
@@ -1185,7 +1258,7 @@ scan_or_find_usb_device (int scan_mode,
                         }
                       free (rid);
                     }
-                  
+
                   usb_close (idev);
                   idev = NULL;
                   return 0;
@@ -1198,7 +1271,7 @@ scan_or_find_usb_device (int scan_mode,
 }
 
 /* Combination function to either scan all CCID devices or to find and
-   open one specific device. 
+   open one specific device.
 
    The function returns 0 if a reader has been found or when a scan
    returned without error.
@@ -1257,7 +1330,7 @@ scan_or_find_devices (int readerno, const char *readerid,
   if (r_rid)
     *r_rid = NULL;
   if (r_dev)
-    *r_dev = NULL; 
+    *r_dev = NULL;
   if (ifcdesc_extra)
     *ifcdesc_extra = NULL;
   if (ifcdesc_extra_len)
@@ -1270,7 +1343,7 @@ scan_or_find_devices (int readerno, const char *readerid,
     *r_fd = -1;
 
   /* See whether we want scan or find mode. */
-  if (scan_mode) 
+  if (scan_mode)
     {
       assert (r_rid);
     }
@@ -1284,7 +1357,7 @@ scan_or_find_devices (int readerno, const char *readerid,
   busses = usb_busses;
 #endif
 
-  for (bus = busses; bus; bus = bus->next) 
+  for (bus = busses; bus; bus = bus->next)
     {
       for (dev = bus->devices; dev; dev = dev->next)
         {
@@ -1306,7 +1379,7 @@ scan_or_find_devices (int readerno, const char *readerid,
                   return -1; /* error */
                 }
               *r_idev = idev;
-              return 0; 
+              return 0;
             }
         }
     }
@@ -1326,7 +1399,7 @@ scan_or_find_devices (int readerno, const char *readerid,
         }
       else if (fd == -1)
         {
-          DEBUGOUT_2 ("failed to open `%s': %s\n",
+          DEBUGOUT_2 ("failed to open '%s': %s\n",
                      transports[i].name, strerror (errno));
           continue;
         }
@@ -1400,7 +1473,7 @@ scan_or_find_devices (int readerno, const char *readerid,
 /* Set the level of debugging to LEVEL and return the old level.  -1
    just returns the old level.  A level of 0 disables debugging, 1
    enables debugging, 2 enables additional tracing of the T=1
-   protocol, 3 additionally enables debuggng for GetSlotStatus, other
+   protocol, 3 additionally enables debugging for GetSlotStatus, other
    values are not yet defined.
 
    Note that libusb may provide its own debugging feature which is
@@ -1433,9 +1506,9 @@ ccid_get_reader_list (void)
 }
 
 
-/* Open the reader with the internal number READERNO and return a 
+/* Open the reader with the internal number READERNO and return a
    pointer to be used as handle in HANDLE.  Returns 0 on success. */
-int 
+int
 ccid_open_reader (ccid_driver_t *handle, const char *readerid)
 {
   int rc = 0;
@@ -1531,7 +1604,7 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
           rc = CCID_DRIVER_ERR_NO_READER;
           goto leave;
         }
-      
+
       rc = usb_claim_interface (idev, ifc_no);
       if (rc)
         {
@@ -1565,7 +1638,7 @@ do_close_reader (ccid_driver_t handle)
   unsigned char msg[100];
   size_t msglen;
   unsigned char seqno;
-  
+
   if (!handle->powered_off)
     {
       msg[0] = PC_to_RDR_IccPowerOff;
@@ -1576,7 +1649,7 @@ do_close_reader (ccid_driver_t handle)
       msg[9] = 0; /* RFU */
       set_msg_len (msg, 0);
       msglen = 10;
-      
+
       rc = bulk_out (handle, msg, msglen, 0);
       if (!rc)
         bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus,
@@ -1600,12 +1673,12 @@ do_close_reader (ccid_driver_t handle)
 /* Reset a reader on HANDLE.  This is useful in case a reader has been
    plugged of and inserted at a different port.  By resetting the
    handle, the same reader will be get used.  Note, that on error the
-   handle won't get released. 
+   handle won't get released.
 
    This does not return an ATR, so ccid_get_atr should be called right
    after this one.
 */
-int 
+int
 ccid_shutdown_reader (ccid_driver_t handle)
 {
   int rc = 0;
@@ -1643,7 +1716,7 @@ ccid_shutdown_reader (ccid_driver_t handle)
           rc = CCID_DRIVER_ERR_NO_READER;
           goto leave;
         }
-      
+
       rc = usb_claim_interface (idev, ifc_no);
       if (rc)
         {
@@ -1670,8 +1743,22 @@ ccid_shutdown_reader (ccid_driver_t handle)
 }
 
 
+int
+ccid_set_progress_cb (ccid_driver_t handle,
+                      void (*cb)(void *, const char *, int, int, int),
+                      void *cb_arg)
+{
+  if (!handle || !handle->rid)
+    return CCID_DRIVER_ERR_INV_VALUE;
+
+  handle->progress_cb = cb;
+  handle->progress_cb_arg = cb_arg;
+  return 0;
+}
+
+
 /* Close the reader HANDLE. */
-int 
+int
 ccid_close_reader (ccid_driver_t handle)
 {
   if (!handle || (!handle->idev && handle->dev_fd == -1))
@@ -1699,7 +1786,7 @@ writen (int fd, const void *buf, size_t nbytes)
 {
   size_t nleft = nbytes;
   int nwritten;
-  
+
   while (nleft > 0)
     {
       nwritten = write (fd, buf, nleft);
@@ -1713,7 +1800,7 @@ writen (int fd, const void *buf, size_t nbytes)
       nleft -= nwritten;
       buf = (const char*)buf + nwritten;
     }
-    
+
   return 0;
 }
 
@@ -1726,6 +1813,11 @@ bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen,
 {
   int rc;
 
+  /* No need to continue and clutter the log with USB write error
+     messages after we got the first ENODEV.  */
+  if (handle->enodev_seen)
+    return CCID_DRIVER_ERR_NO_READER;
+
   if (debug_level && (!no_debug || debug_level >= 3))
     {
       switch (msglen? msg[0]:0)
@@ -1777,17 +1869,36 @@ bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen,
           break;
         }
     }
-  
+
   if (handle->idev)
     {
-      rc = usb_bulk_write (handle->idev, 
+      rc = usb_bulk_write (handle->idev,
                            handle->ep_bulk_out,
                            (char*)msg, msglen,
                            5000 /* ms timeout */);
       if (rc == msglen)
         return 0;
+#ifdef ENODEV
+      if (rc == -(ENODEV))
+        {
+          /* The Linux libusb returns a negative error value.  Catch
+             the most important one.  */
+          errno = ENODEV;
+          rc = -1;
+        }
+#endif /*ENODEV*/
+
       if (rc == -1)
-        DEBUGOUT_1 ("usb_bulk_write error: %s\n", strerror (errno));
+        {
+          DEBUGOUT_1 ("usb_bulk_write error: %s\n", strerror (errno));
+#ifdef ENODEV
+          if (errno == ENODEV)
+            {
+              handle->enodev_seen = 1;
+              return CCID_DRIVER_ERR_NO_READER;
+            }
+#endif /*ENODEV*/
+        }
       else
         DEBUGOUT_1 ("usb_bulk_write failed: %d\n", rc);
     }
@@ -1798,7 +1909,7 @@ bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen,
         return 0;
       DEBUGOUT_2 ("writen to %d failed: %s\n",
                   handle->dev_fd, strerror (errno));
-      
+
     }
   return CCID_DRIVER_ERR_CARD_IO_ERROR;
 }
@@ -1826,7 +1937,7 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
  retry:
   if (handle->idev)
     {
-      rc = usb_bulk_read (handle->idev, 
+      rc = usb_bulk_read (handle->idev,
                           handle->ep_bulk_in,
                           (char*)buffer, length,
                           timeout);
@@ -1836,9 +1947,7 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
           DEBUGOUT_1 ("usb_bulk_read error: %s\n", strerror (rc));
           if (rc == EAGAIN && eagain_retries++ < 3)
             {
-#ifndef TEST
-              gnupg_sleep (1);
-#endif
+              my_sleep (1);
               goto retry;
             }
           return CCID_DRIVER_ERR_CARD_IO_ERROR;
@@ -1855,9 +1964,7 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
                       handle->dev_fd, strerror (rc));
           if (rc == EAGAIN && eagain_retries++ < 5)
             {
-#ifndef TEST
-              gnupg_sleep (1);
-#endif
+              my_sleep (1);
               goto retry;
             }
           return CCID_DRIVER_ERR_CARD_IO_ERROR;
@@ -1872,12 +1979,12 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
       abort_cmd (handle, seqno);
       return CCID_DRIVER_ERR_INV_VALUE;
     }
-  if (buffer[5] != 0)    
+  if (buffer[5] != 0)
     {
       DEBUGOUT_1 ("unexpected bulk-in slot (%d)\n", buffer[5]);
       return CCID_DRIVER_ERR_INV_VALUE;
     }
-  if (buffer[6] != seqno)    
+  if (buffer[6] != seqno)
     {
       DEBUGOUT_2 ("bulk-in seqno does not match (%d/%d)\n",
                   seqno, buffer[6]);
@@ -1890,7 +1997,7 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
      for the Cherry keyboard which sends a time extension request for
      each key hit.  */
   if ( !(buffer[7] & 0x03) && (buffer[7] & 0xC0) == 0x80)
-    { 
+    {
       /* Card present and active, time extension requested. */
       DEBUGOUT_2 ("time extension requested (%02X,%02X)\n",
                   buffer[7], buffer[8]);
@@ -1960,13 +2067,13 @@ abort_cmd (ccid_driver_t handle, int seqno)
       /* I don't know how to send an abort to non-USB devices.  */
       rc = CCID_DRIVER_ERR_NOT_SUPPORTED;
     }
-  
+
   seqno &= 0xff;
   DEBUGOUT_1 ("sending abort sequence for seqno %d\n", seqno);
   /* Send the abort command to the control pipe.  Note that we don't
      need to keep track of sent abort commands because there should
      never be another thread using the same slot concurrently.  */
-  rc = usb_control_msg (handle->idev, 
+  rc = usb_control_msg (handle->idev,
                         0x21,/* bmRequestType: host-to-device,
                                 class specific, to interface.  */
                         1,   /* ABORT */
@@ -1986,7 +2093,7 @@ abort_cmd (ccid_driver_t handle, int seqno)
   seqno--;  /* Adjust for next increment.  */
   do
     {
-      seqno++; 
+      seqno++;
       msg[0] = PC_to_RDR_Abort;
       msg[5] = 0; /* slot */
       msg[6] = seqno;
@@ -1996,24 +2103,24 @@ abort_cmd (ccid_driver_t handle, int seqno)
       msglen = 10;
       set_msg_len (msg, 0);
 
-      rc = usb_bulk_write (handle->idev, 
+      rc = usb_bulk_write (handle->idev,
                            handle->ep_bulk_out,
                            (char*)msg, msglen,
                            5000 /* ms timeout */);
       if (rc == msglen)
         rc = 0;
       else if (rc == -1)
-        DEBUGOUT_1 ("usb_bulk_write error in abort_cmd: %s\n", 
+        DEBUGOUT_1 ("usb_bulk_write error in abort_cmd: %s\n",
                     strerror (errno));
       else
         DEBUGOUT_1 ("usb_bulk_write failed in abort_cmd: %d\n", rc);
 
       if (rc)
         return rc;
-      
-      rc = usb_bulk_read (handle->idev, 
+
+      rc = usb_bulk_read (handle->idev,
                           handle->ep_bulk_in,
-                          (char*)msg, sizeof msg, 
+                          (char*)msg, sizeof msg,
                           5000 /*ms timeout*/);
       if (rc < 0)
         {
@@ -2029,7 +2136,7 @@ abort_cmd (ccid_driver_t handle, int seqno)
                       (unsigned int)msglen);
           return CCID_DRIVER_ERR_INV_VALUE;
         }
-      if (msg[5] != 0)    
+      if (msg[5] != 0)
         {
           DEBUGOUT_1 ("unexpected bulk-in slot (%d) in abort_cmd\n", msg[5]);
           return CCID_DRIVER_ERR_INV_VALUE;
@@ -2054,7 +2161,7 @@ abort_cmd (ccid_driver_t handle, int seqno)
    operation will get returned in RESULT and its length in RESULTLEN.
    If the response is larger than RESULTMAX, an error is returned and
    the required buffer length returned in RESULTLEN.  */
-static int 
+static int
 send_escape_cmd (ccid_driver_t handle,
                  const unsigned char *data, size_t datalen,
                  unsigned char *result, size_t resultmax, size_t *resultlen)
@@ -2106,7 +2213,7 @@ send_escape_cmd (ccid_driver_t handle,
       default:
         break;
       }
-  
+
   return rc;
 }
 
@@ -2132,14 +2239,14 @@ ccid_poll (ccid_driver_t handle)
 
   if (handle->idev)
     {
-      rc = usb_bulk_read (handle->idev, 
+      rc = usb_bulk_read (handle->idev,
                           handle->ep_intr,
                           (char*)msg, sizeof msg,
                           0 /* ms timeout */ );
       if (rc < 0 && errno == ETIMEDOUT)
         return 0;
     }
-  else 
+  else
     return 0;
 
   if (rc < 0)
@@ -2163,12 +2270,12 @@ ccid_poll (ccid_driver_t handle)
       for (i=1; i < msglen; i++)
         for (j=0; j < 4; j++)
           DEBUGOUT_CONT_3 (" %d:%c%c",
-                           (i-1)*4+j, 
+                           (i-1)*4+j,
                            (msg[i] & (1<<(j*2)))? 'p':'-',
                            (msg[i] & (2<<(j*2)))? '*':' ');
       DEBUGOUT_LF ();
     }
-  else if (msg[0] == RDR_to_PC_HardwareError)    
+  else if (msg[0] == RDR_to_PC_HardwareError)
     {
       DEBUGOUT ("hardware error occured\n");
     }
@@ -2183,7 +2290,7 @@ ccid_poll (ccid_driver_t handle)
 
 /* Note that this function won't return the error codes NO_CARD or
    CARD_INACTIVE */
-int 
+int
 ccid_slot_status (ccid_driver_t handle, int *statusbits)
 {
   int rc;
@@ -2233,7 +2340,7 @@ ccid_slot_status (ccid_driver_t handle, int *statusbits)
 
 /* Return the ATR of the card.  This is not a cached value and thus an
    actual reset is done.  */
-int 
+int
 ccid_get_atr (ccid_driver_t handle,
               unsigned char *atr, size_t maxatrlen, size_t *atrlen)
 {
@@ -2292,7 +2399,7 @@ ccid_get_atr (ccid_driver_t handle,
 
 
   handle->powered_off = 0;
-  
+
   if (atr)
     {
       size_t n = msglen - 10;
@@ -2367,7 +2474,7 @@ ccid_get_atr (ccid_driver_t handle,
       tpdu[0] = handle->nonnull_nad? ((1 << 4) | 0): 0;
       tpdu[1] = (0xc0 | 0 | 1); /* S-block request: change IFSD */
       tpdu[2] = 1;
-      tpdu[3] = handle->max_ifsd? handle->max_ifsd : 32; 
+      tpdu[3] = handle->max_ifsd? handle->max_ifsd : 32;
       tpdulen = 4;
       edc = compute_edc (tpdu, tpdulen, use_crc);
       if (use_crc)
@@ -2377,7 +2484,7 @@ ccid_get_atr (ccid_driver_t handle,
       msg[0] = PC_to_RDR_XfrBlock;
       msg[5] = 0; /* slot */
       msg[6] = seqno = handle->seqno++;
-      msg[7] = 0; 
+      msg[7] = 0;
       msg[8] = 0; /* RFU */
       msg[9] = 0; /* RFU */
       set_msg_len (msg, tpdulen);
@@ -2400,12 +2507,12 @@ ccid_get_atr (ccid_driver_t handle,
                     RDR_to_PC_DataBlock, seqno, 5000, 0);
       if (rc)
         return rc;
-      
+
       tpdu = msg + 10;
       tpdulen = msglen - 10;
-      
-      if (tpdulen < 4) 
-        return CCID_DRIVER_ERR_ABORTED; 
+
+      if (tpdulen < 4)
+        return CCID_DRIVER_ERR_ABORTED;
 
       if (debug_level > 1)
         DEBUGOUT_4 ("T=1: got %c-block seq=%d err=%d%s\n",
@@ -2430,7 +2537,7 @@ ccid_get_atr (ccid_driver_t handle,
 
 \f
 
-static unsigned int 
+static unsigned int
 compute_edc (const unsigned char *data, size_t datalen, int use_crc)
 {
   if (use_crc)
@@ -2440,7 +2547,7 @@ compute_edc (const unsigned char *data, size_t datalen, int use_crc)
   else
     {
       unsigned char crc = 0;
-      
+
       for (; datalen; datalen--)
         crc ^= *data++;
       return crc;
@@ -2482,10 +2589,10 @@ ccid_transceive_apdu_level (ccid_driver_t handle,
 
   /* The maximum length for a short APDU T=1 block is 261.  For an
      extended APDU T=1 block the maximum length 65544; however
-     extended APDU exchange level is not yet supported.  */
-  if (apdulen > 261)
+     extended APDU exchange level is not fully supported yet.  */
+  if (apdulen > 289)
     return CCID_DRIVER_ERR_INV_VALUE; /* Invalid length. */
-  
+
   msg[0] = PC_to_RDR_XfrBlock;
   msg[5] = 0; /* slot */
   msg[6] = seqno = handle->seqno++;
@@ -2505,10 +2612,53 @@ ccid_transceive_apdu_level (ccid_driver_t handle,
                 RDR_to_PC_DataBlock, seqno, 5000, 0);
   if (rc)
     return rc;
-      
-  apdu = msg + 10;
-  apdulen = msglen - 10;
-      
+
+  if (msg[9] == 1)
+    {
+      size_t total_msglen = msglen;
+
+      while (1)
+        {
+          unsigned char status;
+
+          msg = recv_buffer + total_msglen;
+
+          msg[0] = PC_to_RDR_XfrBlock;
+          msg[5] = 0; /* slot */
+          msg[6] = seqno = handle->seqno++;
+          msg[7] = bwi; /* bBWI */
+          msg[8] = 0x10;                /* Request next data block */
+          msg[9] = 0;
+          set_msg_len (msg, 0);
+          msglen = 10;
+
+          rc = bulk_out (handle, msg, msglen, 0);
+          if (rc)
+            return rc;
+
+          rc = bulk_in (handle, msg, sizeof recv_buffer - total_msglen, &msglen,
+                        RDR_to_PC_DataBlock, seqno, 5000, 0);
+          if (rc)
+            return rc;
+          status = msg[9];
+          memmove (msg, msg+10, msglen - 10);
+          total_msglen += msglen - 10;
+          if (total_msglen >= sizeof recv_buffer)
+            return CCID_DRIVER_ERR_OUT_OF_CORE;
+
+          if (status == 0x02)
+            break;
+        }
+
+      apdu = recv_buffer + 10;
+      apdulen = total_msglen - 10;
+    }
+  else
+    {
+      apdu = msg + 10;
+      apdulen = msglen - 10;
+    }
+
   if (resp)
     {
       if (apdulen > maxresplen)
@@ -2518,11 +2668,11 @@ ccid_transceive_apdu_level (ccid_driver_t handle,
                       (unsigned int)apdulen, (unsigned int)maxresplen);
           return CCID_DRIVER_ERR_INV_VALUE;
         }
-      
-      memcpy (resp, apdu, apdulen); 
+
+      memcpy (resp, apdu, apdulen);
       *nresp = apdulen;
     }
-          
+
   return 0;
 }
 
@@ -2533,15 +2683,15 @@ ccid_transceive_apdu_level (ccid_driver_t handle,
 
   Block Structure:
            Prologue Field:
-   1 byte     Node Address (NAD) 
+   1 byte     Node Address (NAD)
    1 byte     Protocol Control Byte (PCB)
-   1 byte     Length (LEN) 
+   1 byte     Length (LEN)
            Information Field:
    0-254 byte APDU or Control Information (INF)
            Epilogue Field:
    1 byte     Error Detection Code (EDC)
 
-  NAD:  
+  NAD:
    bit 7     unused
    bit 4..6  Destination Node Address (DAD)
    bit 3     unused
@@ -2556,7 +2706,7 @@ ccid_transceive_apdu_level (ccid_driver_t handle,
    Information Block (I-Block):
       bit 7    0
       bit 6    Sequence number (yep, that is modulo 2)
-      bit 5    Chaining flag 
+      bit 5    Chaining flag
       bit 4..0 reserved
    Received-Ready Block (R-Block):
       bit 7    1
@@ -2615,7 +2765,11 @@ ccid_transceive (ccid_driver_t handle,
       /* We employ a hack for Omnikey readers which are able to send
          TPDUs using an escape sequence.  There is no documentation
          but the Windows driver does it this way.  Tested using a
-         CM6121.  */
+         CM6121.  This method works also for the Cherry XX44
+         keyboards; however there are problems with the
+         ccid_tranceive_secure which leads to a loss of sync on the
+         CCID level.  If Cherry wants to make their keyboard work
+         again, they should hand over some docs. */
       if ((handle->id_vendor == VENDOR_OMNIKEY
            || (!handle->idev && handle->id_product == TRANSPORT_CM4040))
           && handle->apdu_level < 2
@@ -2655,7 +2809,7 @@ ccid_transceive (ccid_driver_t handle,
           if (apdulen > handle->ifsc )
             {
               apdulen = handle->ifsc;
-              apdu_buf += handle->ifsc;  
+              apdu_buf += handle->ifsc;
               apdu_buflen -= handle->ifsc;
               tpdu[1] |= (1 << 5); /* Set more bit. */
             }
@@ -2702,14 +2856,14 @@ ccid_transceive (ccid_driver_t handle,
                      : !!(msg[pcboff] & 0x40)),
                     (!(msg[pcboff] & 0x80) && (msg[pcboff] & 0x20)?
                      " [more]":""));
-      
+
       rc = bulk_out (handle, msg, msglen, 0);
       if (rc)
         return rc;
 
       msg = recv_buffer;
       rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen,
-                    via_escape? RDR_to_PC_Escape : RDR_to_PC_DataBlock, 
+                    via_escape? RDR_to_PC_Escape : RDR_to_PC_DataBlock,
                     seqno, 5000, 0);
       if (rc)
         return rc;
@@ -2717,11 +2871,11 @@ ccid_transceive (ccid_driver_t handle,
       tpdu = msg + hdrlen;
       tpdulen = msglen - hdrlen;
       resyncing = 0;
-            
-      if (tpdulen < 4) 
+
+      if (tpdulen < 4)
         {
           usb_clear_halt (handle->idev, handle->ep_bulk_in);
-          return CCID_DRIVER_ERR_ABORTED; 
+          return CCID_DRIVER_ERR_ABORTED;
         }
 
       if (debug_level > 1)
@@ -2773,16 +2927,16 @@ ccid_transceive (ccid_driver_t handle,
                               (unsigned int)n, (unsigned int)maxresplen);
                   return CCID_DRIVER_ERR_INV_VALUE;
                 }
-              
-              memcpy (resp, p, n); 
+
+              memcpy (resp, p, n);
               resp += n;
               *nresp += n;
               maxresplen -= n;
             }
-          
+
           if (!(tpdu[1] & 0x20))
             return 0; /* No chaining requested - ready. */
-          
+
           msg = send_buffer;
           tpdu = msg + hdrlen;
           tpdu[0] = nad_byte;
@@ -2796,8 +2950,8 @@ ccid_transceive (ccid_driver_t handle,
         }
       else if ((tpdu[1] & 0xc0) == 0x80)
         { /* This is a R-block. */
-          if ( (tpdu[1] & 0x0f)) 
-            { 
+          if ( (tpdu[1] & 0x0f))
+            {
               retries++;
               if (via_escape && retries == 1 && (msg[pcboff] & 0x0f))
                 {
@@ -2847,7 +3001,7 @@ ccid_transceive (ccid_driver_t handle,
               return CCID_DRIVER_ERR_CARD_IO_ERROR;
             }
         }
-      else 
+      else
         { /* This is a S-block. */
           retries = 0;
           DEBUGOUT_2 ("T=1: S-block %s received cmd=%d\n",
@@ -2890,6 +3044,7 @@ ccid_transceive (ccid_driver_t handle,
                 tpdu[tpdulen++] = (edc >> 8);
               tpdu[tpdulen++] = edc;
               DEBUGOUT_1 ("T=1: waittime extension of bwi=%d\n", bwi);
+              print_progress (handle);
             }
           else if ( (tpdu[1] & 0x20) && (tpdu[1] & 0x1f) == 0 && !tpdu[2])
             {
@@ -2910,14 +3065,14 @@ ccid_transceive (ccid_driver_t handle,
 /* Send the CCID Secure command to the reader.  APDU_BUF should
    contain the APDU template.  PIN_MODE defines how the pin gets
    formatted:
-   
+
      1 := The PIN is ASCII encoded and of variable length.  The
           length of the PIN entered will be put into Lc by the reader.
           The APDU should me made up of 4 bytes without Lc.
 
    PINLEN_MIN and PINLEN_MAX define the limits for the pin length. 0
    may be used t enable reasonable defaults.  PIN_PADLEN should be 0.
-   
+
    When called with RESP and NRESP set to NULL, the function will
    merely check whether the reader supports the secure command for the
    given APDU and PIN_MODE. */
@@ -2925,7 +3080,7 @@ int
 ccid_transceive_secure (ccid_driver_t handle,
                         const unsigned char *apdu_buf, size_t apdu_buflen,
                         int pin_mode, int pinlen_min, int pinlen_max,
-                        int pin_padlen, 
+                        int pin_padlen,
                         unsigned char *resp, size_t maxresplen, size_t *nresp)
 {
   int rc;
@@ -2946,10 +3101,10 @@ ccid_transceive_secure (ccid_driver_t handle,
   if (apdu_buflen >= 4 && apdu_buf[1] == 0x20 && (handle->has_pinpad & 1))
     ;
   else if (apdu_buflen >= 4 && apdu_buf[1] == 0x24 && (handle->has_pinpad & 2))
-    return CCID_DRIVER_ERR_NOT_SUPPORTED; /* Not yet by our code. */
+    ;
   else
     return CCID_DRIVER_ERR_NO_KEYPAD;
-    
+
   if (pin_mode != 1)
     return CCID_DRIVER_ERR_NOT_SUPPORTED;
 
@@ -2963,7 +3118,7 @@ ccid_transceive_secure (ccid_driver_t handle,
 
   /* Note that the 25 is the maximum value the SPR532 allows.  */
   if (pinlen_min < 1 || pinlen_min > 25
-      || pinlen_max < 1 || pinlen_max > 25 
+      || pinlen_max < 1 || pinlen_max > 25
       || pinlen_min > pinlen_max)
     return CCID_DRIVER_ERR_INV_VALUE;
 
@@ -2973,6 +3128,10 @@ ccid_transceive_secure (ccid_driver_t handle,
     {
     case VENDOR_SCM:  /* Tested with SPR 532. */
     case VENDOR_KAAN: /* Tested with KAAN Advanced (1.02). */
+    case VENDOR_FSIJ: /* Tested with the gnuk code (2011-01-05).  */
+      break;
+    case VENDOR_VASCO: /* Tested with DIGIPASS 920 */
+      pinlen_max = 15;
       break;
     case VENDOR_CHERRY:
       /* The CHERRY XX44 keyboard echos an asterisk for each entered
@@ -2982,7 +3141,8 @@ ccid_transceive_secure (ccid_driver_t handle,
          Lc byte to the APDU.  It seems that it will be replaced with
          the actual length instead of being appended before the APDU
          is send to the card. */
-      cherry_mode = 1;
+      if (handle->id_product != CHERRY_ST2000)
+        cherry_mode = 1;
       break;
     default:
      return CCID_DRIVER_ERR_NOT_SUPPORTED;
@@ -2990,7 +3150,7 @@ ccid_transceive_secure (ccid_driver_t handle,
 
   if (testmode)
     return 0; /* Success */
-    
+
   msg = send_buffer;
   if (handle->id_vendor == VENDOR_SCM)
     {
@@ -3007,7 +3167,8 @@ ccid_transceive_secure (ccid_driver_t handle,
   msg[7] = 0; /* bBWI */
   msg[8] = 0; /* RFU */
   msg[9] = 0; /* RFU */
-  msg[10] = 0; /* Perform PIN verification. */
+  msg[10] = apdu_buf[1] == 0x20 ? 0 : 1;
+               /* Perform PIN verification or PIN modification. */
   msg[11] = 0; /* Timeout in seconds. */
   msg[12] = 0x82; /* bmFormatString: Byte, pos=0, left, ASCII. */
   if (handle->id_vendor == VENDOR_SCM)
@@ -3020,34 +3181,64 @@ ccid_transceive_secure (ccid_driver_t handle,
   else
     {
       msg[13] = 0x00; /* bmPINBlockString:
-                         0 bits of pin length to insert. 
+                         0 bits of pin length to insert.
                          0 bytes of PIN block size.  */
       msg[14] = 0x00; /* bmPINLengthFormat:
                          Units are bytes, position is 0. */
     }
 
-  /* The following is a little endian word. */
-  msg[15] = pinlen_max;   /* wPINMaxExtraDigit-Maximum.  */
-  msg[16] = pinlen_min;   /* wPINMaxExtraDigit-Minimum.  */
+  msglen = 15;
+  if (apdu_buf[1] == 0x24)
+    {
+      msg[msglen++] = 0;    /* bInsertionOffsetOld */
+      msg[msglen++] = 0;    /* bInsertionOffsetNew */
+    }
 
-  msg[17] = 0x02; /* bEntryValidationCondition:
-                     Validation key pressed */
+  /* The following is a little endian word. */
+  msg[msglen++] = pinlen_max;   /* wPINMaxExtraDigit-Maximum.  */
+  msg[msglen++] = pinlen_min;   /* wPINMaxExtraDigit-Minimum.  */
+
+  if (apdu_buf[1] == 0x24)
+    msg[msglen++] = apdu_buf[2] == 0 ? 0x03 : 0x01;
+              /* bConfirmPIN
+               *    0x00: new PIN once
+               *    0x01: new PIN twice (confirmation)
+               *    0x02: old PIN and new PIN once
+               *    0x03: old PIN and new PIN twice (confirmation)
+               */
+
+  msg[msglen] = 0x02; /* bEntryValidationCondition:
+                         Validation key pressed */
   if (pinlen_min && pinlen_max && pinlen_min == pinlen_max)
-    msg[17] |= 0x01; /* Max size reached.  */
-  msg[18] = 0xff; /* bNumberMessage: Default. */
-  msg[19] = 0x04; /* wLangId-High. */
-  msg[20] = 0x09; /* wLangId-Low:  English FIXME: use the first entry. */
-  msg[21] = 0;    /* bMsgIndex. */
+    msg[msglen] |= 0x01; /* Max size reached.  */
+  msglen++;
+
+  if (apdu_buf[1] == 0x20)
+    msg[msglen++] = 0xff; /* bNumberMessage: Default. */
+  else
+    msg[msglen++] = 0x03; /* bNumberMessage. */
+
+  msg[msglen++] = 0x09; /* wLangId-Low:  English FIXME: use the first entry. */
+  msg[msglen++] = 0x04; /* wLangId-High. */
+
+  if (apdu_buf[1] == 0x20)
+    msg[msglen++] = 0;    /* bMsgIndex. */
+  else
+    {
+      msg[msglen++] = 0;    /* bMsgIndex1. */
+      msg[msglen++] = 1;    /* bMsgIndex2. */
+      msg[msglen++] = 2;    /* bMsgIndex3. */
+    }
+
   /* bTeoProlog follows: */
-  msg[22] = handle->nonnull_nad? ((1 << 4) | 0): 0;
-  msg[23] = ((handle->t1_ns & 1) << 6); /* I-block */
-  msg[24] = 0; /* The apdulen will be filled in by the reader.  */
+  msg[msglen++] = handle->nonnull_nad? ((1 << 4) | 0): 0;
+  msg[msglen++] = ((handle->t1_ns & 1) << 6); /* I-block */
+  msg[msglen++] = 0; /* The apdulen will be filled in by the reader.  */
   /* APDU follows:  */
-  msg[25] = apdu_buf[0]; /* CLA */
-  msg[26] = apdu_buf[1]; /* INS */
-  msg[27] = apdu_buf[2]; /* P1 */
-  msg[28] = apdu_buf[3]; /* P2 */
-  msglen = 29;
+  msg[msglen++] = apdu_buf[0]; /* CLA */
+  msg[msglen++] = apdu_buf[1]; /* INS */
+  msg[msglen++] = apdu_buf[2]; /* P1 */
+  msg[msglen++] = apdu_buf[3]; /* P2 */
   if (cherry_mode)
     msg[msglen++] = 0;
   /* An EDC is not required. */
@@ -3056,13 +3247,13 @@ ccid_transceive_secure (ccid_driver_t handle,
   rc = bulk_out (handle, msg, msglen, 0);
   if (rc)
     return rc;
-  
+
   msg = recv_buffer;
   rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen,
                 RDR_to_PC_DataBlock, seqno, 30000, 0);
   if (rc)
     return rc;
-  
+
   tpdu = msg + 10;
   tpdulen = msglen - 10;
 
@@ -3077,17 +3268,17 @@ ccid_transceive_secure (ccid_driver_t handle,
                           (unsigned int)tpdulen, (unsigned int)maxresplen);
               return CCID_DRIVER_ERR_INV_VALUE;
             }
-          
-          memcpy (resp, tpdu, tpdulen); 
+
+          memcpy (resp, tpdu, tpdulen);
           *nresp = tpdulen;
         }
       return 0;
     }
-  
-  if (tpdulen < 4) 
+
+  if (tpdulen < 4)
     {
       usb_clear_halt (handle->idev, handle->ep_bulk_in);
-      return CCID_DRIVER_ERR_ABORTED; 
+      return CCID_DRIVER_ERR_ABORTED;
     }
   if (debug_level > 1)
     DEBUGOUT_4 ("T=1: got %c-block seq=%d err=%d%s\n",
@@ -3122,22 +3313,22 @@ ccid_transceive_secure (ccid_driver_t handle,
                           (unsigned int)n, (unsigned int)maxresplen);
               return CCID_DRIVER_ERR_INV_VALUE;
             }
-              
-          memcpy (resp, p, n); 
+
+          memcpy (resp, p, n);
           resp += n;
           *nresp += n;
           maxresplen -= n;
         }
-          
+
       if (!(tpdu[1] & 0x20))
         return 0; /* No chaining requested - ready. */
-      
+
       DEBUGOUT ("chaining requested but not supported for Secure operation\n");
       return CCID_DRIVER_ERR_CARD_IO_ERROR;
     }
   else if ((tpdu[1] & 0xc0) == 0x80)
     { /* This is a R-block. */
-      if ( (tpdu[1] & 0x0f)) 
+      if ( (tpdu[1] & 0x0f))
         { /* Error: repeat last block */
           DEBUGOUT ("No retries supported for Secure operation\n");
           return CCID_DRIVER_ERR_CARD_IO_ERROR;
@@ -3153,13 +3344,13 @@ ccid_transceive_secure (ccid_driver_t handle,
           return CCID_DRIVER_ERR_CARD_IO_ERROR;
         }
     }
-  else 
-    { /* This is a S-bl<ock. */
+  else
+    { /* This is a S-block. */
       DEBUGOUT_2 ("T=1: S-block %s received cmd=%d for Secure operation\n",
                   (tpdu[1] & 0x20)? "response": "request",
                   (tpdu[1] & 0x1f));
       return CCID_DRIVER_ERR_CARD_IO_ERROR;
-    } 
+    }
 
   return 0;
 }
@@ -3315,7 +3506,7 @@ main (int argc, char **argv)
                           result, sizeof result, &resultlen);
     print_result (rc, result, resultlen);
   }
-  
+
 
   if (!no_poll)
     ccid_poll (ccid);
@@ -3336,7 +3527,7 @@ main (int argc, char **argv)
     {
       static unsigned char apdu[] = { 0, 0x20, 0, 0x81 };
 
-      
+
       if (ccid_transceive_secure (ccid,
                                   apdu, sizeof apdu,
                                   1, 0, 0, 0,
@@ -3345,7 +3536,7 @@ main (int argc, char **argv)
       else
         {
           fputs ("verifying CHV1 using the PINPad ....\n", stderr);
-          
+
           rc = ccid_transceive_secure (ccid,
                                        apdu, sizeof apdu,
                                        1, 0, 0, 0,
@@ -3354,7 +3545,7 @@ main (int argc, char **argv)
           did_verify = 1;
         }
     }
-  
+
   if (verify_123456 && !did_verify)
     {
       fputs ("verifying that CHV1 is 123456....\n", stderr);