scd: Improve internal CCID driver.
authorNIIBE Yutaka <gniibe@fsij.org>
Thu, 29 Dec 2016 02:31:25 +0000 (11:31 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Thu, 29 Dec 2016 02:31:25 +0000 (11:31 +0900)
* scd/ccid-driver.c (scan_or_find_usb_device): Don't scan for
configuration but use active configuration.  Support alt_setting.
(scan_or_find_devices): Support alt_setting.
(ccid_open_reader): Support alt_setting.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
scd/ccid-driver.c

index 7d70819..6d81122 100644 (file)
@@ -1125,163 +1125,150 @@ scan_or_find_usb_device (int scan_mode,
                          libusb_device_handle **r_idev,
                          unsigned char **ifcdesc_extra,
                          size_t *ifcdesc_extra_len,
-                         int *interface_number,
+                         int *interface_number, int *setting_number,
                          int *ep_bulk_out, int *ep_bulk_in, int *ep_intr)
 {
-  int cfg_no;
   int ifc_no;
   int set_no;
   const struct libusb_interface_descriptor *ifcdesc;
   char *rid;
   libusb_device_handle *idev = NULL;
   int err;
+  struct libusb_config_descriptor *config;
 
   err = libusb_get_device_descriptor (dev, desc);
-  if (err < 0)
+  if (err)
     return 0;
 
   *r_idev = NULL;
 
-  for (cfg_no=0; cfg_no < desc->bNumConfigurations; cfg_no++)
-    {
-      struct libusb_config_descriptor *config;
+  err = libusb_get_active_config_descriptor (dev, &config);
+  if (err)
+    return 0;
 
-      err = libusb_get_config_descriptor (dev, cfg_no, &config);
-      if (err < 0)
-        {
-          if (err == LIBUSB_ERROR_NO_MEM)
-            return 0;
-          continue;
-        }
+  for (ifc_no=0; ifc_no < config->bNumInterfaces; ifc_no++)
+    for (set_no=0; set_no < config->interface[ifc_no].num_altsetting; set_no++)
+      {
+        ifcdesc = (config->interface[ifc_no].altsetting + set_no);
+        /* The second condition is for older SCM SPR 532 who did
+           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
+                    && desc->idVendor == VENDOR_SCM
+                    && desc->idProduct == SCM_SPR532)
+                || (ifcdesc->bInterfaceClass == 255
+                    && desc->idVendor == VENDOR_CHERRY
+                    && desc->idProduct == CHERRY_ST2000)))
+          {
+            ++*count;
+            if (!scan_mode && ((readerno > 0 && readerno != *count - 1)))
+              continue;
 
-      for (ifc_no=0; ifc_no < config->bNumInterfaces; ifc_no++)
-        {
-          for (set_no=0; set_no < config->interface[ifc_no].num_altsetting;
-               set_no++)
-            {
-              ifcdesc = (config->interface[ifc_no].altsetting + set_no);
-              /* The second condition is for older SCM SPR 532 who did
-                 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
-                          && desc->idVendor == VENDOR_SCM
-                          && desc->idProduct == SCM_SPR532)
-                      || (ifcdesc->bInterfaceClass == 255
-                          && desc->idVendor == VENDOR_CHERRY
-                          && desc->idProduct == CHERRY_ST2000)))
-                {
-                  ++*count;
-                  if (!scan_mode
-                      && ((readerno > 0 && readerno != *count - 1)))
-                    continue;
-
-                  err = libusb_open (dev, &idev);
-                  if (err < 0)
-                    {
-                      DEBUGOUT_1 ("usb_open failed: %s\n",
-                                  libusb_error_name (err));
-                      continue; /* with next setting. */
-                    }
-
-                  rid = make_reader_id (idev, desc->idVendor, desc->idProduct,
-                                        desc->iSerialNumber);
-                  if (!rid)
-                    {
-                      libusb_free_config_descriptor (config);
-                      return 0;
-                    }
-
-                  if (!scan_mode && readerno == -1 && readerid
-                      && strncmp (rid, readerid, strlen (readerid)))
-                    continue;
-
-                  if (scan_mode)
-                    {
-                      char *p;
-
-                      /* We are collecting infos about all
-                         available CCID readers.  Store them and
-                         continue. */
-                      DEBUGOUT_2 ("found CCID reader %d (ID=%s)\n",
-                                  *count, rid );
-                      p = malloc ((*rid_list? strlen (*rid_list):0) + 1
-                                  + strlen (rid) + 1);
-                      if (p)
-                        {
-                          *p = 0;
-                          if (*rid_list)
-                            {
-                              strcat (p, *rid_list);
-                              free (*rid_list);
-                            }
-                          strcat (p, rid);
-                          strcat (p, "\n");
-                          *rid_list = p;
-                        }
-                      else /* Out of memory. */
-                        {
-                          libusb_free_config_descriptor (config);
-                          free (rid);
-                          return 0;
-                        }
-                    }
-                  else
-                    {
-                      /* We found the requested reader. */
-                      if (ifcdesc_extra && ifcdesc_extra_len)
-                        {
-                          *ifcdesc_extra = malloc (ifcdesc
-                                                   ->extra_length);
-                          if (!*ifcdesc_extra)
-                            {
-                              libusb_close (idev);
-                              free (rid);
-                              libusb_free_config_descriptor (config);
-                              return 1; /* Out of core. */
-                            }
-                          memcpy (*ifcdesc_extra, ifcdesc->extra,
-                                  ifcdesc->extra_length);
-                          *ifcdesc_extra_len = ifcdesc->extra_length;
-                        }
-
-                      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_rid)
-                        {
-                          *r_rid = rid;
-                          rid = NULL;
-                        }
-                      else
+            err = libusb_open (dev, &idev);
+            if (err)
+              {
+                DEBUGOUT_1 ("usb_open failed: %s\n", libusb_error_name (err));
+                continue; /* with next setting. */
+              }
+
+            rid = make_reader_id (idev, desc->idVendor, desc->idProduct,
+                                  desc->iSerialNumber);
+            if (!rid)
+              {
+                libusb_free_config_descriptor (config);
+                return 0;
+              }
+
+            if (!scan_mode && readerno == -1 && readerid
+                && strncmp (rid, readerid, strlen (readerid)))
+              continue;
+
+            if (scan_mode)
+              {
+                char *p;
+
+                /* We are collecting infos about all
+                   available CCID readers.  Store them and
+                   continue. */
+                DEBUGOUT_2 ("found CCID reader %d (ID=%s)\n", *count, rid);
+                p = malloc ((*rid_list? strlen (*rid_list):0) + 1
+                            + strlen (rid) + 1);
+                if (p)
+                  {
+                    *p = 0;
+                    if (*rid_list)
+                      {
+                        strcat (p, *rid_list);
+                        free (*rid_list);
+                      }
+                    strcat (p, rid);
+                    strcat (p, "\n");
+                    *rid_list = p;
+                  }
+                else /* Out of memory. */
+                  {
+                    libusb_free_config_descriptor (config);
+                    free (rid);
+                    return 0;
+                  }
+              }
+            else
+              {
+                /* We found the requested reader. */
+                if (ifcdesc_extra && ifcdesc_extra_len)
+                  {
+                    *ifcdesc_extra = malloc (ifcdesc->extra_length);
+                    if (!*ifcdesc_extra)
+                      {
+                        libusb_close (idev);
                         free (rid);
+                        libusb_free_config_descriptor (config);
+                        return 1; /* Out of core. */
+                      }
+                    memcpy (*ifcdesc_extra, ifcdesc->extra,
+                            ifcdesc->extra_length);
+                    *ifcdesc_extra_len = ifcdesc->extra_length;
+                  }
+
+                if (interface_number)
+                  *interface_number = ifc_no;
+
+                if (setting_number)
+                  *setting_number = set_no;
+
+                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_rid)
+                  {
+                    *r_rid = rid;
+                    rid = NULL;
+                  }
+                else
+                  free (rid);
 
-                      *r_idev = idev;
-                      libusb_free_config_descriptor (config);
-                      return 1; /* Found requested device. */
-                    }
+                *r_idev = idev;
+                libusb_free_config_descriptor (config);
+                return 1; /* Found requested device. */
+              }
 
-                  free (rid);
-                  libusb_close (idev);
-                  idev = NULL;
-                }
-            }
-        }
+            free (rid);
+            libusb_close (idev);
+            idev = NULL;
+          }
+      }
 
-      libusb_free_config_descriptor (config);
-    }
+  libusb_free_config_descriptor (config);
 
   return 0;
 }
@@ -1329,7 +1316,7 @@ scan_or_find_devices (int readerno, const char *readerid,
                       struct libusb_device_descriptor *r_desc,
                       unsigned char **ifcdesc_extra,
                       size_t *ifcdesc_extra_len,
-                      int *interface_number,
+                      int *interface_number, int *setting_number,
                       int *ep_bulk_out, int *ep_bulk_in, int *ep_intr,
                       libusb_device_handle **r_idev,
                       int *r_fd)
@@ -1353,6 +1340,8 @@ scan_or_find_devices (int readerno, const char *readerid,
     *ifcdesc_extra_len = 0;
   if (interface_number)
     *interface_number = 0;
+  if (setting_number)
+    *setting_number = 0;
   if (r_idev)
     *r_idev = NULL;
   if (r_fd)
@@ -1377,7 +1366,7 @@ scan_or_find_devices (int readerno, const char *readerid,
                                    &idev,
                                    ifcdesc_extra,
                                    ifcdesc_extra_len,
-                                   interface_number,
+                                   interface_number, setting_number,
                                    ep_bulk_out, ep_bulk_in, ep_intr))
         {
           libusb_free_device_list (dev_list, 1);
@@ -1512,7 +1501,7 @@ ccid_get_reader_list (void)
     }
 
   if (scan_or_find_devices (-1, NULL, &reader_list, NULL, NULL, NULL, NULL,
-                            NULL, NULL, NULL, NULL, NULL))
+                            NULL, NULL, NULL, NULL, NULL, NULL))
     return NULL; /* Error. */
   return reader_list;
 }
@@ -1558,7 +1547,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;
+  int ifc_no, set_no, ep_bulk_out, ep_bulk_in, ep_intr;
   struct libusb_device_descriptor desc;
 
   *handle = NULL;
@@ -1587,10 +1576,9 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid,
   else
     readerno = 0;  /* Default. */
 
-  if (scan_or_find_devices (readerno, readerid, &rid, &desc,
-                            &ifcdesc_extra, &ifcdesc_extra_len,
-                            &ifc_no, &ep_bulk_out, &ep_bulk_in, &ep_intr,
-                            &idev, &dev_fd) )
+  if (scan_or_find_devices (readerno, readerid, &rid, &desc, &ifcdesc_extra,
+                            &ifcdesc_extra_len, &ifc_no, &set_no, &ep_bulk_out,
+                            &ep_bulk_in, &ep_intr, &idev, &dev_fd))
     {
       if (readerno == -1)
         DEBUGOUT_1 ("no CCID reader with ID %s\n", readerid );
@@ -1646,12 +1634,23 @@ ccid_open_reader (ccid_driver_t *handle, const char *readerid,
         }
 
       rc = libusb_claim_interface (idev, ifc_no);
-      if (rc < 0)
+      if (rc)
         {
           DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc);
           rc = CCID_DRIVER_ERR_CARD_IO_ERROR;
           goto leave;
         }
+
+      if (set_no != 0)
+        {
+          rc = libusb_set_interface_alt_setting (idev, ifc_no, set_no);
+          if (rc)
+            {
+              DEBUGOUT_1 ("usb_set_interface_alt_setting failed: %d\n", rc);
+              rc = CCID_DRIVER_ERR_CARD_IO_ERROR;
+              goto leave;
+            }
+        }
     }
 
   rc = ccid_vendor_specific_init (*handle);
@@ -1852,7 +1851,7 @@ bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen,
       if (rc == 0 && transferred == msglen)
         return 0;
 
-      if (rc < 0)
+      if (rc)
         {
           DEBUGOUT_1 ("usb_bulk_write error: %s\n", libusb_error_name (rc));
           if (rc == LIBUSB_ERROR_NO_DEVICE)
@@ -1899,7 +1898,7 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
     {
       rc = libusb_bulk_transfer (handle->idev, handle->ep_bulk_in,
                                  (char*)buffer, length, &msglen, timeout);
-      if (rc < 0)
+      if (rc)
         {
           DEBUGOUT_1 ("usb_bulk_read error: %s\n", libusb_error_name (rc));
           if (rc == LIBUSB_ERROR_NO_DEVICE)
@@ -2041,7 +2040,7 @@ abort_cmd (ccid_driver_t handle, int seqno)
                                 handle->ifc_no,
                                 dummybuf, 0,
                                 1000 /* ms timeout */);
-  if (rc < 0)
+  if (rc)
     {
       DEBUGOUT_1 ("usb_control_msg error: %s\n", libusb_error_name (rc));
       return CCID_DRIVER_ERR_CARD_IO_ERROR;
@@ -2070,7 +2069,7 @@ abort_cmd (ccid_driver_t handle, int seqno)
                                  5000 /* ms timeout */);
       if (rc == 0 && transferred == msglen)
         rc = 0;
-      else if (rc < 0)
+      else if (rc)
         DEBUGOUT_1 ("usb_bulk_write error in abort_cmd: %s\n",
                     libusb_error_name (rc));
 
@@ -2080,7 +2079,7 @@ abort_cmd (ccid_driver_t handle, int seqno)
       rc = libusb_bulk_transfer (handle->idev, handle->ep_bulk_in,
                                  (char*)msg, sizeof msg, &msglen,
                                  5000 /*ms timeout*/);
-      if (rc < 0)
+      if (rc)
         {
           DEBUGOUT_1 ("usb_bulk_read error in abort_cmd: %s\n",
                       libusb_error_name (rc));
@@ -2205,7 +2204,7 @@ ccid_poll (ccid_driver_t handle)
   else
     return 0;
 
-  if (rc < 0)
+  if (rc)
     {
       DEBUGOUT_1 ("usb_intr_read error: %s\n", libusb_error_name (rc));
       return CCID_DRIVER_ERR_CARD_IO_ERROR;