scan_or_find_usb_device (int scan_mode,
                         int *readerno, int *count, char **rid_list,
                         const char *readerid,
                         struct usb_device *dev,
                         char **r_rid,
                         struct usb_device **r_dev,
                         usb_dev_handle **r_idev,
                         unsigned char **ifcdesc_extra,
                         size_t *ifcdesc_extra_len,
                         int *interface_number,
                         int *ep_bulk_out, int *ep_bulk_in, int *ep_intr)
{
  int cfg_no;
  int ifc_no;
  int set_no;
  struct usb_config_descriptor *config;
  struct usb_interface *interface;
  struct usb_interface_descriptor *ifcdesc;
  char *rid;
  usb_dev_handle *idev;

  *r_idev = NULL;

  for (cfg_no=0; cfg_no < dev->descriptor.bNumConfigurations; cfg_no++)
    {
      config = dev->config + cfg_no;
      if(!config)
        continue;

      for (ifc_no=0; ifc_no < config->bNumInterfaces; ifc_no++)
        {
          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.  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 == SCM_SPR532)
                      || (ifcdesc->bInterfaceClass == 255
                          && dev->descriptor.idVendor == VENDOR_CHERRY
                          && dev->descriptor.idProduct == CHERRY_ST2000)))
                {
                  idev = usb_open (dev);
                  if (!idev)
                    {
                      DEBUGOUT_1 ("usb_open failed: %s\n",
                                  strerror (errno));
                      continue; /* with next setting. */
                    }

                  rid = make_reader_id (idev,
                                        dev->descriptor.idVendor,
                                        dev->descriptor.idProduct,
                                        dev->descriptor.iSerialNumber);
                  if (rid)
                    {
                      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. */
                            free (rid);

                          rid = NULL;
                          ++*count;
                        }
                      else if (!*readerno
                               || (*readerno < 0
                                   && readerid
                                   && !strcmp (readerid, rid)))
                        {
                          /* We found the requested reader. */
                          if (ifcdesc_extra && ifcdesc_extra_len)
                            {
                              *ifcdesc_extra = malloc (ifcdesc
                                                       ->extralen);
                              if (!*ifcdesc_extra)
                                {
                                  usb_close (idev);
                                  free (rid);
                                  return 1; /* Out of core. */
                                }
                              memcpy (*ifcdesc_extra, ifcdesc->extra,
                                      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;
                          if (r_rid)
                            {
                              *r_rid = rid;
                              rid = NULL;
                            }
                          else
                            free (rid);

                          *r_idev = idev;
                          return 1; /* Found requested device. */
                        }
                      else
                        {
                          /* This is not yet the reader we want.
                             fixme: We should avoid the extra usb_open
                             in this case. */
                          if (*readerno >= 0)
                            --*readerno;
                        }
                      free (rid);
                    }

                  usb_close (idev);
                  idev = NULL;
                  return 0;
                }
            }
        }
    }

  return 0;
}