* trustdb.h, keyedit.c (keyedit_menu, menu_select_uid_namehash): Allow
[gnupg.git] / g10 / ccid-driver.c
index 0a876f0..9fd983f 100644 (file)
@@ -1,5 +1,5 @@
 /* ccid-driver.c - USB ChipCardInterfaceDevices driver
- *     Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+ *     Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
  *      Written by Werner Koch.
  *
  * This file is part of GnuPG.
@@ -52,7 +52,7 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  * OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $Id$
+ * $Date$
  */
 
 
@@ -198,6 +198,10 @@ struct ccid_driver_s
   unsigned short id_vendor;
   unsigned short id_product;
   unsigned short bcd_device;
+  int ifc_no;
+  int ep_bulk_out;
+  int ep_bulk_in;
+  int ep_intr;
   int seqno;
   unsigned char t1_ns;
   unsigned char t1_nr;
@@ -207,6 +211,7 @@ struct ccid_driver_s
   int ifsd;
   int powered_off;
   int has_pinpad;
+  int apdu_level;     /* Reader supports short APDU level exchange.  */
 };
 
 
@@ -218,7 +223,7 @@ static unsigned int compute_edc (const unsigned char *data, size_t datalen,
                                  int use_crc);
 static int bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen);
 static int bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
-                    size_t *nread, int expected_type, int seqno);
+                    size_t *nread, int expected_type, int seqno, int timeout);
 
 /* Convert a little endian stored 4 byte value into an unsigned
    integer. */
@@ -260,6 +265,7 @@ parse_ccid_descriptor (ccid_driver_t handle,
   handle->max_ifsd = 32;
   handle->ifsd = 0;
   handle->has_pinpad = 0;
+  handle->apdu_level = 0;
   DEBUGOUT_3 ("idVendor: %04X  idProduct: %04X  bcdDevice: %04X\n",
               handle->id_vendor, handle->id_product, handle->bcd_device);
   if (buflen < 54 || buf[0] < 54)
@@ -372,9 +378,15 @@ parse_ccid_descriptor (ccid_driver_t handle,
       have_tpdu = 1;
     } 
   else if ((us & 0x00020000))
-    DEBUGOUT ("    Short APDU level exchange\n");
+    {
+      DEBUGOUT ("    Short APDU level exchange\n");
+      handle->apdu_level = 1;
+    }
   else if ((us & 0x00040000))
-    DEBUGOUT ("    Short and extended APDU level exchange\n");
+    {
+      DEBUGOUT ("    Short and extended APDU level exchange\n");
+      handle->apdu_level = 1;
+    }
   else if ((us & 0x00070000))
     DEBUGOUT ("    WARNING: conflicting exchange levels\n");
 
@@ -391,7 +403,7 @@ parse_ccid_descriptor (ccid_driver_t handle,
   if (buf[49] == 0xff)
     DEBUGOUT_CONT ("echo\n");
   else
-    DEBUGOUT_1 ("  %02X\n", buf[48]);
+    DEBUGOUT_CONT_1 ("  %02X\n", buf[48]);
 
   DEBUGOUT (  "  wlcdLayout           ");
   if (!buf[50] && !buf[51])
@@ -421,10 +433,10 @@ parse_ccid_descriptor (ccid_driver_t handle,
     DEBUGOUT_LF ();
   }
 
-  if (!have_t1 || !have_tpdu || !have_auto_conf)
+  if (!have_t1 || !(have_tpdu  || handle->apdu_level) || !have_auto_conf)
     {
       DEBUGOUT ("this drivers requires that the reader supports T=1, "
-                "TPDU level exchange and auto configuration - "
+                "TPDU or APDU level exchange and auto configuration - "
                 "this is not available\n");
       return -1;
     }
@@ -434,12 +446,20 @@ parse_ccid_descriptor (ccid_driver_t handle,
      send a frame of n*wMaxPacketSize back to us.  Given that
      wMaxPacketSize is 64 for these readers we set the IFSD to a value
      lower than that:
-        64 - 10 CCID header -  4 T1frame - 2 reserved = 48 */
+        64 - 10 CCID header -  4 T1frame - 2 reserved = 48
+     Product Ids:
+        0xe001 - SCR 331 
+        0x5111 - SCR 331-DI 
+        0x5115 - SCR 335 
+        0xe003 - SPR 532 
+  */
   if (handle->id_vendor == VENDOR_SCM
-      /* FIXME: check whether it is the same
-                firmware version for all drivers.  */
-      && handle->bcd_device < 0x0513
-      && handle->max_ifsd > 48)
+      && 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 < 0x0519)
+          ||(handle->id_product == 0xe003 && handle->bcd_device < 0x0504)
+          ))
     {
       DEBUGOUT ("enabling workaround for buggy SCM readers\n");
       handle->max_ifsd = 48;
@@ -546,6 +566,36 @@ make_reader_id (usb_dev_handle *idev,
 }
 
 
+/* Helper to find the endpoint from an interface descriptor.  */
+static int
+find_endpoint (struct usb_interface_descriptor *ifcdesc, int mode)
+{
+  int no;
+  int want_bulk_in = 0;
+
+  if (mode == 1)
+    want_bulk_in = 0x80;
+  for (no=0; no < ifcdesc->bNumEndpoints; no++)
+    {
+      struct usb_endpoint_descriptor *ep = ifcdesc->endpoint + no;
+      if (ep->bDescriptorType != USB_DT_ENDPOINT)
+        ;
+      else if (mode == 2
+          && ((ep->bmAttributes & USB_ENDPOINT_TYPE_MASK)
+              == USB_ENDPOINT_TYPE_INTERRUPT)
+          && (ep->bEndpointAddress & 0x80))
+        return (ep->bEndpointAddress & 0x0f);
+      else if (((ep->bmAttributes & USB_ENDPOINT_TYPE_MASK)
+                == USB_ENDPOINT_TYPE_BULK)
+               && (ep->bEndpointAddress & 0x80) == want_bulk_in)
+        return (ep->bEndpointAddress & 0x0f);
+    }
+  /* Should never happen.  */
+  return mode == 2? 0x83 : mode == 1? 0x82 :1;
+}
+
+
+
 /* Combination function to either scan all CCID devices or to find and
    open one specific device. 
 
@@ -579,7 +629,9 @@ scan_or_find_devices (int readerno, const char *readerid,
                       char **r_rid,
                       struct usb_device **r_dev,
                       unsigned char **ifcdesc_extra,
-                      size_t *ifcdesc_extra_len)
+                      size_t *ifcdesc_extra_len,
+                      int *interface_number,
+                      int *ep_bulk_out, int *ep_bulk_in, int *ep_intr)
 {
   char *rid_list = NULL;
   int count = 0;
@@ -597,6 +649,8 @@ scan_or_find_devices (int readerno, const char *readerid,
     *ifcdesc_extra = NULL;
   if (ifcdesc_extra_len)
     *ifcdesc_extra_len = 0;
+  if (interface_number)
+    *interface_number = 0;
 
   /* See whether we want scan or find mode. */
   if (scan_mode) 
@@ -653,9 +707,7 @@ scan_or_find_devices (int readerno, const char *readerid,
                                   && ifcdesc->bInterfaceProtocol == 0)
                               || (ifcdesc->bInterfaceClass == 255
                                   && dev->descriptor.idVendor == 0x04e6
-                                  && dev->descriptor.idProduct == 0xe003
-                                  && ifcdesc->bInterfaceSubClass == 1
-                                  && ifcdesc->bInterfaceProtocol == 1)))
+                                  && dev->descriptor.idProduct == 0xe003)))
                         {
                           idev = usb_open (dev);
                           if (!idev)
@@ -721,6 +773,16 @@ scan_or_find_devices (int readerno, const char *readerid,
                                               ifcdesc->extralen);
                                       *ifcdesc_extra_len = ifcdesc->extralen;
                                     }
+                                  if (interface_number)
+                                    *interface_number = (ifcdesc->
+                                                         bInterfaceNumber);
+                                  if (ep_bulk_out)
+                                    *ep_bulk_out = find_endpoint (ifcdesc, 0);
+                                  if (ep_bulk_in)
+                                    *ep_bulk_in = find_endpoint (ifcdesc, 1);
+                                  if (ep_intr)
+                                    *ep_intr = find_endpoint (ifcdesc, 2);
+
 
                                   if (r_dev)
                                     *r_dev = dev;
@@ -787,7 +849,8 @@ ccid_get_reader_list (void)
       initialized_usb = 1;
     }
 
-  scan_or_find_devices (-1, NULL, &reader_list, NULL, NULL, NULL);
+  scan_or_find_devices (-1, NULL, &reader_list, NULL, NULL, NULL, NULL,
+                        NULL, NULL, NULL);
   return reader_list;
 }
 
@@ -804,6 +867,7 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
   unsigned char *ifcdesc_extra = NULL;
   size_t ifcdesc_extra_len;
   int readerno;
+  int ifc_no, ep_bulk_out, ep_bulk_in, ep_intr;
 
   *handle = NULL;
 
@@ -832,7 +896,8 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
     readerno = 0;  /* Default. */
 
   idev = scan_or_find_devices (readerno, readerid, &rid, &dev,
-                               &ifcdesc_extra, &ifcdesc_extra_len);
+                               &ifcdesc_extra, &ifcdesc_extra_len,
+                               &ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr);
   if (!idev)
     {
       if (readerno == -1)
@@ -856,6 +921,10 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
   (*handle)->id_vendor = dev->descriptor.idVendor;
   (*handle)->id_product = dev->descriptor.idProduct;
   (*handle)->bcd_device = dev->descriptor.bcdDevice;
+  (*handle)->ifc_no = ifc_no;
+  (*handle)->ep_bulk_out = ep_bulk_out;
+  (*handle)->ep_bulk_in = ep_bulk_in;
+  (*handle)->ep_intr = ep_intr;
 
   DEBUGOUT_2 ("using CCID reader %d (ID=%s)\n",  readerno, rid );
 
@@ -867,9 +936,7 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
       goto leave;
     }
   
-  /* fixme: Do we need to claim and set the interface as
-     determined above? */
-  rc = usb_claim_interface (idev, 0);
+  rc = usb_claim_interface (idev, ifc_no);
   if (rc)
     {
       DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc);
@@ -877,9 +944,6 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid)
       goto leave;
     }
   
-  /* FIXME: Do we need to get the endpoint addresses from the
-     structure and store them with the handle? */
-              
  leave:
   free (ifcdesc_extra);
   if (rc)
@@ -916,12 +980,14 @@ do_close_reader (ccid_driver_t handle)
       
       rc = bulk_out (handle, msg, msglen);
       if (!rc)
-        bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus,seqno);
+        bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus,
+                 seqno, 2000);
       handle->powered_off = 1;
     }
   if (handle->idev)
     {
-      usb_release_interface (handle->idev, 0);
+      usb_reset (handle->idev);
+      usb_release_interface (handle->idev, handle->ifc_no);
       usb_close (handle->idev);
       handle->idev = NULL;
     }
@@ -944,6 +1010,7 @@ ccid_shutdown_reader (ccid_driver_t handle)
   usb_dev_handle *idev = NULL;
   unsigned char *ifcdesc_extra = NULL;
   size_t ifcdesc_extra_len;
+  int ifc_no, ep_bulk_out, ep_bulk_in, ep_intr;
 
   if (!handle || !handle->rid)
     return CCID_DRIVER_ERR_INV_VALUE;
@@ -951,7 +1018,8 @@ ccid_shutdown_reader (ccid_driver_t handle)
   do_close_reader (handle);
 
   idev = scan_or_find_devices (-1, handle->rid, NULL, &dev,
-                               &ifcdesc_extra, &ifcdesc_extra_len);
+                               &ifcdesc_extra, &ifcdesc_extra_len,
+                               &ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr);
   if (!idev)
     {
       DEBUGOUT_1 ("no CCID reader with ID %s\n", handle->rid);
@@ -960,6 +1028,10 @@ ccid_shutdown_reader (ccid_driver_t handle)
 
 
   handle->idev = idev;
+  handle->ifc_no = ifc_no;
+  handle->ep_bulk_out = ep_bulk_out;
+  handle->ep_bulk_in = ep_bulk_in;
+  handle->ep_intr = ep_intr;
 
   if (parse_ccid_descriptor (handle, ifcdesc_extra, ifcdesc_extra_len))
     {
@@ -968,9 +1040,7 @@ ccid_shutdown_reader (ccid_driver_t handle)
       goto leave;
     }
   
-  /* fixme: Do we need to claim and set the interface as
-     determined above? */
-  rc = usb_claim_interface (idev, 0);
+  rc = usb_claim_interface (idev, ifc_no);
   if (rc)
     {
       DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc);
@@ -1022,7 +1092,7 @@ bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen)
   int rc;
 
   rc = usb_bulk_write (handle->idev, 
-                       1, /*endpoint */
+                       handle->ep_bulk_out,
                        msg, msglen,
                        1000 /* ms timeout */);
   if (rc == msglen)
@@ -1040,10 +1110,10 @@ bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen)
    BUFFER and return the actual read number if bytes in NREAD. SEQNO
    is the sequence number used to send the request and EXPECTED_TYPE
    the type of message we expect. Does checks on the ccid
-   header. Returns 0 on success. */
+   header. TIMEOUT is the timeout value in ms. Returns 0 on success. */
 static int
 bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
-         size_t *nread, int expected_type, int seqno)
+         size_t *nread, int expected_type, int seqno, int timeout)
 {
   int i, rc;
   size_t msglen;
@@ -1053,11 +1123,9 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
   memset (buffer, 0, length);
  retry:
   rc = usb_bulk_read (handle->idev, 
-                      0x82,
+                      handle->ep_bulk_in,
                       buffer, length,
-                      10000 /* ms timeout */ );
-  /* Fixme: instead of using a 10 second timeout we should better
-     handle the timeout here and retry if appropriate.  */
+                      timeout);
   if (rc < 0)
     {
       DEBUGOUT_1 ("usb_bulk_read error: %s\n", strerror (errno));
@@ -1113,7 +1181,7 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
 }
 
 
-/* Note that this fucntion won't return the error codes NO_CARD or
+/* Note that this function won't return the error codes NO_CARD or
    CARD_INACTIVE */
 static int 
 send_escape_cmd (ccid_driver_t handle,
@@ -1144,7 +1212,8 @@ send_escape_cmd (ccid_driver_t handle,
   rc = bulk_out (handle, msg, msglen);
   if (rc)
     return rc;
-  rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Escape, seqno);
+  rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Escape,
+                seqno, 5000);
 
   return rc;
 }
@@ -1160,7 +1229,7 @@ ccid_poll (ccid_driver_t handle)
   int i, j;
 
   rc = usb_bulk_read (handle->idev, 
-                      0x83,
+                      handle->ep_intr,
                       msg, sizeof msg,
                       0 /* ms timeout */ );
   if (rc < 0 && errno == ETIMEDOUT)
@@ -1214,7 +1283,9 @@ ccid_slot_status (ccid_driver_t handle, int *statusbits)
   unsigned char msg[100];
   size_t msglen;
   unsigned char seqno;
+  int retries = 0;
 
+ retry:
   msg[0] = PC_to_RDR_GetSlotStatus;
   msg[5] = 0; /* slot */
   msg[6] = seqno = handle->seqno++;
@@ -1226,7 +1297,21 @@ ccid_slot_status (ccid_driver_t handle, int *statusbits)
   rc = bulk_out (handle, msg, 10);
   if (rc)
     return rc;
-  rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus, seqno);
+  rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus,
+                seqno, retries? 1000 : 200);
+  if (rc == CCID_DRIVER_ERR_CARD_IO_ERROR && retries < 3)
+    {
+      if (!retries)
+        {
+          DEBUGOUT ("USB: CALLING USB_CLEAR_HALT\n");
+          usb_clear_halt (handle->idev, handle->ep_bulk_in);
+          usb_clear_halt (handle->idev, handle->ep_bulk_out);
+        }
+      else
+          DEBUGOUT ("USB: RETRYING bulk_in AGAIN\n");
+      retries++;
+      goto retry;
+    }
   if (rc && rc != CCID_DRIVER_ERR_NO_CARD
       && rc != CCID_DRIVER_ERR_CARD_INACTIVE)
     return rc;
@@ -1241,6 +1326,7 @@ ccid_get_atr (ccid_driver_t handle,
               unsigned char *atr, size_t maxatrlen, size_t *atrlen)
 {
   int rc;
+  int statusbits;
   unsigned char msg[100];
   unsigned char *tpdu;
   size_t msglen, tpdulen;
@@ -1249,6 +1335,15 @@ ccid_get_atr (ccid_driver_t handle,
   unsigned int edc;
   int i;
 
+  /* First check whether a card is available.  */
+  rc = ccid_slot_status (handle, &statusbits);
+  if (rc)
+    return rc;
+  if (statusbits == 2)
+    return CCID_DRIVER_ERR_NO_CARD;
+
+  /* For an inactive and also for an active card, issue the PowerOn
+     command to get the ATR.  */
   msg[0] = PC_to_RDR_IccPowerOn;
   msg[5] = 0; /* slot */
   msg[6] = seqno = handle->seqno++;
@@ -1261,7 +1356,8 @@ ccid_get_atr (ccid_driver_t handle,
   rc = bulk_out (handle, msg, msglen);
   if (rc)
     return rc;
-  rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_DataBlock, seqno);
+  rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_DataBlock,
+                seqno, 5000);
   if (rc)
     return rc;
 
@@ -1305,8 +1401,11 @@ ccid_get_atr (ccid_driver_t handle,
   if (rc)
     return rc;
   /* Note that we ignore the error code on purpose. */
-  bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters, seqno);
+  bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters,
+           seqno, 5000);
 
+  handle->t1_ns = 0;
+  handle->t1_nr = 0;
 
   /* Send an S-Block with our maximun IFSD to the CCID.  */
   if (!handle->auto_ifsd)
@@ -1350,7 +1449,7 @@ ccid_get_atr (ccid_driver_t handle,
 
 
       rc = bulk_in (handle, msg, sizeof msg, &msglen,
-                    RDR_to_PC_DataBlock, seqno);
+                    RDR_to_PC_DataBlock, seqno, 5000);
       if (rc)
         return rc;
       
@@ -1400,6 +1499,78 @@ compute_edc (const unsigned char *data, size_t datalen, int use_crc)
 }
 
 
+/* Helper for ccid_transceive used for APDU level exchanges.  */
+static int
+ccid_transceive_apdu_level (ccid_driver_t handle,
+                            const unsigned char *apdu_buf, size_t apdu_buflen,
+                            unsigned char *resp, size_t maxresplen,
+                            size_t *nresp)
+{
+  int rc;
+  unsigned char send_buffer[10+259], recv_buffer[10+259];
+  const unsigned char *apdu;
+  size_t apdulen;
+  unsigned char *msg;
+  size_t msglen;
+  unsigned char seqno;
+  int i;
+
+  msg = send_buffer;
+
+  apdu = apdu_buf;
+  apdulen = apdu_buflen;
+  assert (apdulen);
+
+  if (apdulen > 254)
+    return CCID_DRIVER_ERR_INV_VALUE; /* Invalid length. */
+
+  msg[0] = PC_to_RDR_XfrBlock;
+  msg[5] = 0; /* slot */
+  msg[6] = seqno = handle->seqno++;
+  msg[7] = 4; /* bBWI */
+  msg[8] = 0; /* RFU */
+  msg[9] = 0; /* RFU */
+  memcpy (msg+10, apdu, apdulen);
+  set_msg_len (msg, apdulen);
+  msglen = 10 + apdulen;
+
+  DEBUGOUT ("sending");
+  for (i=0; i < msglen; i++)
+    DEBUGOUT_CONT_1 (" %02X", msg[i]);
+  DEBUGOUT_LF ();
+  
+  rc = bulk_out (handle, msg, msglen);
+  if (rc)
+    return rc;
+
+  msg = recv_buffer;
+  rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen,
+                RDR_to_PC_DataBlock, seqno, 5000);
+  if (rc)
+    return rc;
+      
+  apdu = msg + 10;
+  apdulen = msglen - 10;
+      
+  if (resp)
+    {
+      if (apdulen > maxresplen)
+        {
+          DEBUGOUT_2 ("provided buffer too short for received data "
+                      "(%u/%u)\n",
+                      (unsigned int)apdulen, (unsigned int)maxresplen);
+          return CCID_DRIVER_ERR_INV_VALUE;
+        }
+      
+      memcpy (resp, apdu, apdulen); 
+      *nresp = apdulen;
+    }
+          
+  return 0;
+}
+
+
+
 /*
   Protocol T=1 overview
 
@@ -1476,6 +1647,13 @@ ccid_transceive (ccid_driver_t handle,
     nresp = &dummy_nresp;
   *nresp = 0;
 
+  /* Smarter readers allow to send APDUs directly; divert here. */
+  if (handle->apdu_level)
+    return ccid_transceive_apdu_level (handle, apdu_buf, apdu_buflen,
+                                       resp, maxresplen, nresp);
+
+  /* The other readers we support require sending TPDUs.  */
+
   tpdulen = 0; /* Avoid compiler warning about no initialization. */
   msg = send_buffer;
   for (;;)
@@ -1540,7 +1718,7 @@ ccid_transceive (ccid_driver_t handle,
 
       msg = recv_buffer;
       rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen,
-                    RDR_to_PC_DataBlock, seqno);
+                    RDR_to_PC_DataBlock, seqno, 5000);
       if (rc)
         return rc;
       
@@ -1549,7 +1727,7 @@ ccid_transceive (ccid_driver_t handle,
       
       if (tpdulen < 4) 
         {
-          usb_clear_halt (handle->idev, 0x82);
+          usb_clear_halt (handle->idev, handle->ep_bulk_in);
           return CCID_DRIVER_ERR_ABORTED; 
         }
 #ifdef DEBUG_T1
@@ -1817,7 +1995,7 @@ ccid_transceive_secure (ccid_driver_t handle,
   
   msg = recv_buffer;
   rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen,
-                RDR_to_PC_DataBlock, seqno);
+                RDR_to_PC_DataBlock, seqno, 5000);
   if (rc)
     return rc;
   
@@ -1826,7 +2004,7 @@ ccid_transceive_secure (ccid_driver_t handle,
   
   if (tpdulen < 4) 
     {
-      usb_clear_halt (handle->idev, 0x82);
+      usb_clear_halt (handle->idev, handle->ep_bulk_in);
       return CCID_DRIVER_ERR_ABORTED; 
     }
 #ifdef DEBUG_T1
@@ -1975,6 +2153,7 @@ main (int argc, char **argv)
   int no_pinpad = 0;
   int verify_123456 = 0;
   int did_verify = 0;
+  int no_poll = 0;
 
   if (argc)
     {
@@ -1999,6 +2178,11 @@ main (int argc, char **argv)
           ccid_set_debug_level (1);
           argc--; argv++;
         }
+      else if ( !strcmp (*argv, "--no-poll"))
+        {
+          no_poll = 1;
+          argc--; argv++;
+        }
       else if ( !strcmp (*argv, "--no-pinpad"))
         {
           no_pinpad = 1;
@@ -2017,7 +2201,8 @@ main (int argc, char **argv)
   if (rc)
     return 1;
 
-  ccid_poll (ccid);
+  if (!no_poll)
+    ccid_poll (ccid);
   fputs ("getting ATR ...\n", stderr);
   rc = ccid_get_atr (ccid, NULL, 0, NULL);
   if (rc)
@@ -2026,7 +2211,8 @@ main (int argc, char **argv)
       return 1;
     }
 
-  ccid_poll (ccid);
+  if (!no_poll)
+    ccid_poll (ccid);
   fputs ("getting slot status ...\n", stderr);
   rc = ccid_slot_status (ccid, &slotstat);
   if (rc)
@@ -2035,7 +2221,8 @@ main (int argc, char **argv)
       return 1;
     }
 
-  ccid_poll (ccid);
+  if (!no_poll)
+    ccid_poll (ccid);
 
   fputs ("selecting application OpenPGP ....\n", stderr);
   {
@@ -2048,7 +2235,8 @@ main (int argc, char **argv)
   }
   
 
-  ccid_poll (ccid);
+  if (!no_poll)
+    ccid_poll (ccid);
 
   fputs ("getting OpenPGP DO 0x65 ....\n", stderr);
   {