Rework "discover" code for drivers

Check all the drivers for one that'll drive our device in
question, and prefer ones that have a discover() method that runs
successfully to a driver without such a method.

This allow drivers to both reject devices (if 2 drivers handle
the same USB IDs), or a single driver to handle variants of the
same device (through the devtype out value of the discover method).
This commit is contained in:
Bastien Nocera 2010-08-17 23:14:18 +01:00
parent 48af46a2c5
commit df4a6f53d2
3 changed files with 55 additions and 20 deletions

View file

@ -364,7 +364,7 @@ static struct fp_img_driver * const img_drivers[] = {
#ifdef ENABLE_UPEKSONLY
&upeksonly_driver,
#endif
#ifdef ENABLE_AES1610
&aes1610_driver,
#endif
@ -410,51 +410,80 @@ API_EXPORTED struct fp_driver **fprint_get_drivers (void)
}
static struct fp_driver *find_supporting_driver(libusb_device *udev,
const struct usb_id **usb_id)
const struct usb_id **usb_id, uint32_t *devtype)
{
int ret;
GSList *elem = registered_drivers;
struct libusb_device_descriptor dsc;
const struct usb_id *best_usb_id;
struct fp_driver *best_drv;
uint32_t best_devtype;
int drv_score = 0;
ret = libusb_get_device_descriptor(udev, &dsc);
if (ret < 0) {
fp_err("Failed to get device descriptor");
return NULL;
}
best_drv = NULL;
best_devtype = 0;
do {
struct fp_driver *drv = elem->data;
uint32_t type = 0;
const struct usb_id *id;
for (id = drv->id_table; id->vendor; id++)
for (id = drv->id_table; id->vendor; id++) {
if (dsc.idVendor == id->vendor && dsc.idProduct == id->product) {
if (drv->discover) {
int r = drv->discover(&dsc, &type);
if (r < 0)
fp_err("%s discover failed, code %d", drv->name, r);
if (r <= 0)
continue;
/* Has a discover function, and matched our device */
drv_score = 100;
} else {
/* Already got a driver as good */
if (drv_score >= 50)
continue;
drv_score = 50;
}
fp_dbg("driver %s supports USB device %04x:%04x",
drv->name, id->vendor, id->product);
*usb_id = id;
return drv;
best_usb_id = id;
best_drv = drv;
best_devtype = type;
/* We found the best possible driver */
if (drv_score == 100)
break;
}
}
} while ((elem = g_slist_next(elem)));
return NULL;
fp_dbg("selected driver %s supports USB device %04x:%04x",
best_drv->name, dsc.idVendor, dsc.idProduct);
*devtype = best_devtype;
*usb_id = best_usb_id;
return best_drv;
}
static struct fp_dscv_dev *discover_dev(libusb_device *udev)
{
const struct usb_id *usb_id;
struct fp_driver *drv = find_supporting_driver(udev, &usb_id);
struct fp_driver *drv;
struct fp_dscv_dev *ddev;
uint32_t devtype = 0;
uint32_t devtype;
drv = find_supporting_driver(udev, &usb_id, &devtype);
if (!drv)
return NULL;
if (drv->discover) {
int r = drv->discover(usb_id, &devtype);
if (r < 0)
fp_err("%s discover failed, code %d", drv->name, r);
if (r <= 0)
return NULL;
}
ddev = g_malloc0(sizeof(*ddev));
ddev->drv = drv;
ddev->udev = udev;

View file

@ -844,6 +844,12 @@ static struct fpi_ssm *deinitsm_new(struct fp_dev *dev)
return fpi_ssm_new(dev, deinitsm_state_handler, DEINITSM_NUM_STATES);
}
static int discover(struct libusb_device_descriptor *dsc, uint32_t *devtype)
{
/* FIXME: Detect whether dsc represents a device that we can handle */
return 0;
}
static int dev_init(struct fp_dev *dev, unsigned long driver_data)
{
struct upeke2_dev *upekdev = NULL;
@ -1442,8 +1448,7 @@ static int verify_stop(struct fp_dev *dev, gboolean iterating)
}
static const struct usb_id id_table[] = {
/* FIXME: Disabled for now, as this clashes with the upeksonly driver */
/* { .vendor = 0x147e, .product = 0x2016 }, */
{ .vendor = 0x147e, .product = 0x2016 },
{ 0, 0, 0, }, /* terminating entry */
};
@ -1453,6 +1458,7 @@ struct fp_driver upeke2_driver = {
.full_name = "UPEK Eikon 2",
.id_table = id_table,
.scan_type = FP_SCAN_TYPE_SWIPE,
.discover = discover,
.open = dev_init,
.close = dev_exit,
.enroll_start = enroll_start,

View file

@ -204,7 +204,7 @@ struct fp_driver {
void *priv;
/* Device operations */
int (*discover)(const struct usb_id *usb_id, uint32_t *devtype);
int (*discover)(struct libusb_device_descriptor *dsc, uint32_t *devtype);
int (*open)(struct fp_dev *dev, unsigned long driver_data);
void (*close)(struct fp_dev *dev);
int (*enroll_start)(struct fp_dev *dev);