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,
                      int *interface_number,
                      int *ep_bulk_out, int *ep_bulk_in, int *ep_intr,
                      usb_dev_handle **r_idev,
                      int *r_fd)
{
  char *rid_list = NULL;
  int count = 0;
  struct usb_bus *busses, *bus;
  struct usb_device *dev = NULL;
  usb_dev_handle *idev = NULL;
  int scan_mode = (readerno == -1 && !readerid);
  int i;

  /* Set return values to a default. */
  if (r_rid)
    *r_rid = NULL;
  if (r_dev)
    *r_dev = NULL;
  if (ifcdesc_extra)
    *ifcdesc_extra = NULL;
  if (ifcdesc_extra_len)
    *ifcdesc_extra_len = 0;
  if (interface_number)
    *interface_number = 0;
  if (r_idev)
    *r_idev = NULL;
  if (r_fd)
    *r_fd = -1;

  /* See whether we want scan or find mode. */
  if (scan_mode)
    {
      assert (r_rid);
    }

  usb_find_busses();
  usb_find_devices();

#ifdef HAVE_USB_GET_BUSSES
  busses = usb_get_busses();
#else
  busses = usb_busses;
#endif

  for (bus = busses; bus; bus = bus->next)
    {
      for (dev = bus->devices; dev; dev = dev->next)
        {
          if (scan_or_find_usb_device (scan_mode, &readerno, &count, &rid_list,
                                       readerid,
                                       dev,
                                       r_rid,
                                       r_dev,
                                       &idev,
                                       ifcdesc_extra,
                                       ifcdesc_extra_len,
                                       interface_number,
                                       ep_bulk_out, ep_bulk_in, ep_intr))
            {
              /* Found requested device or out of core. */
              if (!idev)
                {
                  free (rid_list);
                  return -1; /* error */
                }
              *r_idev = idev;
              return 0;
            }
        }
    }

  /* Now check whether there are any devices with special transport types. */
  for (i=0; transports[i].name; i++)
    {
      int fd;
      char *rid, *p;

      fd = open (transports[i].name, O_RDWR);
      if (fd == -1 && scan_mode && errno == EBUSY)
        {
          /* Ignore this error in scan mode because it indicates that
             the device exists but is already open (most likely by us)
             and thus in general suitable as a reader.  */
        }
      else if (fd == -1)
        {
          DEBUGOUT_2 ("failed to open '%s': %s\n",
                     transports[i].name, strerror (errno));
          continue;
        }

      rid = malloc (strlen (transports[i].name) + 30 + 10);
      if (!rid)
        {
          if (fd != -1)
            close (fd);
          free (rid_list);
          return -1; /* Error. */
        }
      sprintf (rid, "0000:%04X:%s:0", transports[i].type, transports[i].name);
      if (scan_mode)
        {
          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)
            {
              if (fd != -1)
                close (fd);
              free (rid_list);
              free (rid);
              return -1; /* Error. */
            }
          *p = 0;
          if (rid_list)
            {
              strcat (p, rid_list);
              free (rid_list);
            }
          strcat (p, rid);
          strcat (p, "\n");
          rid_list = p;
          ++count;
        }
      else if (!readerno ||
               (readerno < 0 && readerid && !strcmp (readerid, rid)))
        {
          /* Found requested device. */
          if (interface_number)
            *interface_number = transports[i].type;
          if (r_rid)
            *r_rid = rid;
          else
            free (rid);
          if (r_fd)
            *r_fd = fd;
          return 0; /* Okay, found device */
        }
      else /* This is not yet the reader we want. */
        {
          if (readerno >= 0)
            --readerno;
        }
      free (rid);
      if (fd != -1)
        close (fd);
    }

  if (scan_mode)
    {
      *r_rid = rid_list;
      return 0;
    }
  else
    return -1;
}