wks: Take name of sendmail from configure.
[gnupg.git] / scd / ccid-driver.c
index fbbd157..f33a36c 100644 (file)
@@ -1228,7 +1228,12 @@ ccid_get_reader_list (void)
 
   if (!initialized_usb)
     {
-      libusb_init (NULL);
+      int rc;
+      if ((rc = libusb_init (NULL)))
+        {
+          DEBUGOUT_1 ("usb_init failed: %s.\n", libusb_error_name (rc));
+          return NULL;
+        }
       initialized_usb = 1;
     }
 
@@ -1292,9 +1297,17 @@ ccid_dev_scan (int *idx_max_p, struct ccid_dev_table **t_p)
   int idx = 0;
   int err = 0;
 
+  *idx_max_p = 0;
+  *t_p = NULL;
+
   if (!initialized_usb)
     {
-      libusb_init (NULL);
+      int rc;
+      if ((rc = libusb_init (NULL)))
+        {
+          DEBUGOUT_1 ("usb_init failed: %s.\n", libusb_error_name (rc));
+          return gpg_error (GPG_ERR_ENODEV);
+        }
       initialized_usb = 1;
     }
 
@@ -1373,8 +1386,6 @@ ccid_dev_scan (int *idx_max_p, struct ccid_dev_table **t_p)
 
   if (err)
     {
-      *idx_max_p = 0;
-      *t_p = NULL;
       for (i = 0; i < idx; i++)
         {
           free (ccid_dev_table[idx].ifcdesc_extra);
@@ -1456,7 +1467,8 @@ intr_cb (struct libusb_transfer *transfer)
 
   DEBUGOUT_1 ("CCID: interrupt callback %d\n", transfer->status);
 
-  if (transfer->status == LIBUSB_TRANSFER_TIMED_OUT)
+  if (transfer->status == LIBUSB_TRANSFER_TIMED_OUT
+      || transfer->status == LIBUSB_TRANSFER_NO_DEVICE)
     {
       int err;
 
@@ -1476,6 +1488,7 @@ intr_cb (struct libusb_transfer *transfer)
         {
           DEBUGOUT ("CCID: card removed\n");
           handle->powered_off = 1;
+          scd_kick_the_loop ();
         }
       else
         {
@@ -1490,9 +1503,8 @@ intr_cb (struct libusb_transfer *transfer)
     device_removed:
       DEBUGOUT ("CCID: device removed\n");
       handle->powered_off = 1;
+      scd_kick_the_loop ();
     }
-
-  scd_kick_the_loop ();
 }
 
 static void
@@ -1650,9 +1662,6 @@ ccid_open_usb_reader (const char *spec_reader_name,
         }
     }
 
-  if ((*handle)->ep_intr >= 0)
-    ccid_setup_intr (*handle);
-
   rc = ccid_vendor_specific_init (*handle);
 
  leave:
@@ -1770,6 +1779,7 @@ do_close_reader (ccid_driver_t handle)
         }
 
       libusb_free_transfer (handle->transfer);
+      handle->transfer = NULL;
     }
   libusb_release_interface (handle->idev, handle->ifc_no);
   --ccid_usb_thread_is_alive;
@@ -2030,10 +2040,17 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
       /*
        * Communication failure by device side.
        * Possibly, it was forcibly suspended and resumed.
+       *
+       * Only detect this kind of failure when interrupt transfer is
+       * not supported.  For card reader with interrupt transfer
+       * support removal is detected by intr_cb.
        */
-      DEBUGOUT ("CCID: card inactive/removed\n");
-      handle->powered_off = 1;
-      scd_kick_the_loop ();
+      if (handle->ep_intr < 0)
+        {
+          DEBUGOUT ("CCID: card inactive/removed\n");
+          handle->powered_off = 1;
+          scd_kick_the_loop ();
+        }
     }
 
   return rc;
@@ -2297,6 +2314,11 @@ ccid_slot_status (ccid_driver_t handle, int *statusbits, int on_wire)
      no need to send on wire.  */
   if (!on_wire && !ccid_require_get_status (handle))
     {
+      /* Setup interrupt transfer at the initial call of slot_status
+         with ON_WIRE == 0 */
+      if (handle->transfer == NULL && handle->ep_intr >= 0)
+        ccid_setup_intr (handle);
+
       *statusbits = 0;
       return 0;
     }
@@ -2523,6 +2545,14 @@ ccid_get_atr (ccid_driver_t handle,
   if (statusbits == 2)
     return CCID_DRIVER_ERR_NO_CARD;
 
+  /*
+   * In the first invocation of ccid_slot_status, card reader may
+   * return CCID_DRIVER_ERR_CARD_INACTIVE and handle->powered_off may
+   * become 1.  Because inactive card is no problem (we are turning it
+   * ON here), clear the flag.
+   */
+  handle->powered_off = 0;
+
   /* For an inactive and also for an active card, issue the PowerOn
      command to get the ATR.  */
  again:
@@ -3734,7 +3764,7 @@ main (int argc, char **argv)
   if (!no_poll)
     ccid_poll (ccid);
   fputs ("getting slot status ...\n", stderr);
-  rc = ccid_slot_status (ccid, &slotstat);
+  rc = ccid_slot_status (ccid, &slotstat, 1);
   if (rc)
     {
       print_error (rc);