Add support for udev based device discovery
This is primarily useful for SPI devices. These devices sometimes needs a combination of an SPI and HID device, so discovery is a bit more complicated.
This commit is contained in:
parent
e95056aa86
commit
b0d9d00762
9 changed files with 242 additions and 9 deletions
|
@ -132,7 +132,9 @@ FpDeviceClass
|
|||
FpTimeoutFunc
|
||||
FpiDeviceAction
|
||||
FpIdEntry
|
||||
FpiDeviceUdevSubtypeFlags
|
||||
fpi_device_get_usb_device
|
||||
fpi_device_get_udev_data
|
||||
fpi_device_get_virtual_env
|
||||
fpi_device_get_current_action
|
||||
fpi_device_retry_new
|
||||
|
|
|
@ -24,6 +24,18 @@
|
|||
#include "fpi-device.h"
|
||||
#include <gusb.h>
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ifdef HAVE_UDEV
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <linux/hidraw.h>
|
||||
#include <gudev/gudev.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* SECTION: fp-context
|
||||
* @title: FpContext
|
||||
|
@ -434,6 +446,103 @@ fp_context_enumerate (FpContext *context)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_UDEV
|
||||
{
|
||||
g_autoptr(GUdevClient) udev_client = g_udev_client_new (NULL);
|
||||
|
||||
/* This uses a very simple algorithm to allocate devices to drivers and assumes that no two drivers will want the same device. Future improvements
|
||||
* could add a usb_discover style udev_discover that returns a score, however for internal devices the potential overlap should be very low between
|
||||
* separate drivers.
|
||||
*/
|
||||
|
||||
g_autoptr(GList) spidev_devices = g_udev_client_query_by_subsystem (udev_client, "spidev");
|
||||
g_autoptr(GList) hidraw_devices = g_udev_client_query_by_subsystem (udev_client, "hidraw");
|
||||
|
||||
/* for each potential driver, try to match all requested resources. */
|
||||
for (i = 0; i < priv->drivers->len; i++)
|
||||
{
|
||||
GType driver = g_array_index (priv->drivers, GType, i);
|
||||
g_autoptr(FpDeviceClass) cls = g_type_class_ref (driver);
|
||||
const FpIdEntry *entry;
|
||||
|
||||
if (cls->type != FP_DEVICE_TYPE_UDEV)
|
||||
continue;
|
||||
|
||||
for (entry = cls->id_table; entry->udev_types; entry++)
|
||||
{
|
||||
GList *matched_spidev = NULL, *matched_hidraw = NULL;
|
||||
|
||||
if (entry->udev_types & FPI_DEVICE_UDEV_SUBTYPE_SPIDEV)
|
||||
{
|
||||
for (matched_spidev = spidev_devices; matched_spidev; matched_spidev = matched_spidev->next)
|
||||
{
|
||||
const gchar * sysfs = g_udev_device_get_sysfs_path (matched_spidev->data);
|
||||
if (!sysfs)
|
||||
continue;
|
||||
if (strstr (sysfs, entry->spi_acpi_id))
|
||||
break;
|
||||
}
|
||||
/* If match was not found exit */
|
||||
if (matched_spidev == NULL)
|
||||
continue;
|
||||
}
|
||||
if (entry->udev_types & FPI_DEVICE_UDEV_SUBTYPE_HIDRAW)
|
||||
{
|
||||
for (matched_hidraw = hidraw_devices; matched_hidraw; matched_hidraw = matched_hidraw->next)
|
||||
{
|
||||
const gchar * devnode = g_udev_device_get_device_file (matched_hidraw->data);
|
||||
int temp_hid = -1, res;
|
||||
struct hidraw_devinfo info;
|
||||
|
||||
if (!devnode)
|
||||
continue;
|
||||
|
||||
temp_hid = open (devnode, O_RDWR);
|
||||
if (temp_hid < 0)
|
||||
continue;
|
||||
|
||||
res = ioctl (temp_hid, HIDIOCGRAWINFO, &info);
|
||||
close (temp_hid);
|
||||
if (res < 0)
|
||||
continue;
|
||||
if (info.vendor == entry->hid_id.vid && info.product == entry->hid_id.pid)
|
||||
break;
|
||||
}
|
||||
/* If match was not found exit */
|
||||
if (matched_hidraw == NULL)
|
||||
continue;
|
||||
}
|
||||
priv->pending_devices++;
|
||||
g_async_initable_new_async (driver,
|
||||
G_PRIORITY_LOW,
|
||||
priv->cancellable,
|
||||
async_device_init_done_cb,
|
||||
context,
|
||||
"fpi-driver-data", entry->driver_data,
|
||||
"fpi-udev-data-spidev", (matched_spidev ? g_udev_device_get_device_file (matched_spidev->data) : NULL),
|
||||
"fpi-udev-data-hidraw", (matched_hidraw ? g_udev_device_get_device_file (matched_hidraw->data) : NULL),
|
||||
NULL);
|
||||
/* remove entries from list to avoid conflicts */
|
||||
if (matched_spidev)
|
||||
{
|
||||
g_object_unref (matched_spidev->data);
|
||||
spidev_devices = g_list_delete_link (spidev_devices, matched_spidev);
|
||||
}
|
||||
if (matched_hidraw)
|
||||
{
|
||||
g_object_unref (matched_hidraw->data);
|
||||
hidraw_devices = g_list_delete_link (hidraw_devices, matched_hidraw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* free all unused elemnts in both lists */
|
||||
g_list_foreach (spidev_devices, (GFunc) g_object_unref, NULL);
|
||||
g_list_foreach (hidraw_devices, (GFunc) g_object_unref, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (priv->pending_devices)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
}
|
||||
|
|
|
@ -28,18 +28,23 @@ typedef struct
|
|||
|
||||
GUsbDevice *usb_device;
|
||||
const gchar *virtual_env;
|
||||
struct
|
||||
{
|
||||
gchar *spidev_path;
|
||||
gchar *hidraw_path;
|
||||
} udev_data;
|
||||
|
||||
gboolean is_removed;
|
||||
gboolean is_open;
|
||||
gboolean is_removed;
|
||||
gboolean is_open;
|
||||
|
||||
gchar *device_id;
|
||||
gchar *device_name;
|
||||
FpScanType scan_type;
|
||||
gchar *device_id;
|
||||
gchar *device_name;
|
||||
FpScanType scan_type;
|
||||
|
||||
guint64 driver_data;
|
||||
guint64 driver_data;
|
||||
|
||||
gint nr_enroll_stages;
|
||||
GSList *sources;
|
||||
gint nr_enroll_stages;
|
||||
GSList *sources;
|
||||
|
||||
/* We always make sure that only one task is run at a time. */
|
||||
FpiDeviceAction current_action;
|
||||
|
|
|
@ -50,6 +50,8 @@ enum {
|
|||
PROP_FINGER_STATUS,
|
||||
PROP_FPI_ENVIRON,
|
||||
PROP_FPI_USB_DEVICE,
|
||||
PROP_FPI_UDEV_DATA_SPIDEV,
|
||||
PROP_FPI_UDEV_DATA_HIDRAW,
|
||||
PROP_FPI_DRIVER_DATA,
|
||||
N_PROPS
|
||||
};
|
||||
|
@ -169,6 +171,8 @@ fp_device_finalize (GObject *object)
|
|||
|
||||
g_clear_object (&priv->usb_device);
|
||||
g_clear_pointer (&priv->virtual_env, g_free);
|
||||
g_clear_pointer (&priv->udev_data.spidev_path, g_free);
|
||||
g_clear_pointer (&priv->udev_data.hidraw_path, g_free);
|
||||
|
||||
G_OBJECT_CLASS (fp_device_parent_class)->finalize (object);
|
||||
}
|
||||
|
@ -248,6 +252,20 @@ fp_device_set_property (GObject *object,
|
|||
g_assert (g_value_get_object (value) == NULL);
|
||||
break;
|
||||
|
||||
case PROP_FPI_UDEV_DATA_SPIDEV:
|
||||
if (cls->type == FP_DEVICE_TYPE_UDEV)
|
||||
priv->udev_data.spidev_path = g_value_dup_string (value);
|
||||
else
|
||||
g_assert (g_value_get_string (value) == NULL);
|
||||
break;
|
||||
|
||||
case PROP_FPI_UDEV_DATA_HIDRAW:
|
||||
if (cls->type == FP_DEVICE_TYPE_UDEV)
|
||||
priv->udev_data.hidraw_path = g_value_dup_string (value);
|
||||
else
|
||||
g_assert (g_value_get_string (value) == NULL);
|
||||
break;
|
||||
|
||||
case PROP_FPI_DRIVER_DATA:
|
||||
priv->driver_data = g_value_get_uint64 (value);
|
||||
break;
|
||||
|
@ -425,6 +443,32 @@ fp_device_class_init (FpDeviceClass *klass)
|
|||
"Private: The USB device for the device",
|
||||
G_USB_TYPE_DEVICE,
|
||||
G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
|
||||
/**
|
||||
* FpDevice::fpi-udev-data-spidev: (skip)
|
||||
*
|
||||
* This property is only for internal purposes.
|
||||
*
|
||||
* Stability: private
|
||||
*/
|
||||
properties[PROP_FPI_UDEV_DATA_SPIDEV] =
|
||||
g_param_spec_string ("fpi-udev-data-spidev",
|
||||
"Udev data: spidev path",
|
||||
"Private: The path to /dev/spidevN.M",
|
||||
NULL,
|
||||
G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
|
||||
/**
|
||||
* FpDevice::fpi-udev-data-hidraw: (skip)
|
||||
*
|
||||
* This property is only for internal purposes.
|
||||
*
|
||||
* Stability: private
|
||||
*/
|
||||
properties[PROP_FPI_UDEV_DATA_HIDRAW] =
|
||||
g_param_spec_string ("fpi-udev-data-hidraw",
|
||||
"Udev data: hidraw path",
|
||||
"Private: The path to /dev/hidrawN",
|
||||
NULL,
|
||||
G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
/**
|
||||
* FpDevice::fpi-driver-data: (skip)
|
||||
|
@ -673,6 +717,7 @@ fp_device_open (FpDevice *device,
|
|||
break;
|
||||
|
||||
case FP_DEVICE_TYPE_VIRTUAL:
|
||||
case FP_DEVICE_TYPE_UDEV:
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -38,10 +38,12 @@ G_DECLARE_DERIVABLE_TYPE (FpDevice, fp_device, FP, DEVICE, GObject)
|
|||
/**
|
||||
* FpDeviceType:
|
||||
* @FP_DEVICE_TYPE_VIRTUAL: The device is a virtual device
|
||||
* @FP_DEVICE_TYPE_UDEV: The device is a udev device
|
||||
* @FP_DEVICE_TYPE_USB: The device is a USB device
|
||||
*/
|
||||
typedef enum {
|
||||
FP_DEVICE_TYPE_VIRTUAL,
|
||||
FP_DEVICE_TYPE_UDEV,
|
||||
FP_DEVICE_TYPE_USB,
|
||||
} FpDeviceType;
|
||||
|
||||
|
|
|
@ -335,6 +335,38 @@ fpi_device_get_usb_device (FpDevice *device)
|
|||
return priv->usb_device;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_device_get_udev_data:
|
||||
* @device: The #FpDevice
|
||||
* @subtype: Which subtype to get information about
|
||||
*
|
||||
* Get a subtype-specific hardware resource for this #FpDevice. Only permissible to call if the
|
||||
* #FpDevice is of type %FP_DEVICE_TYPE_UDEV.
|
||||
*
|
||||
* Returns: Depends on @subtype; for SPIDEV/HIDRAW returns a path to the relevant device.
|
||||
*/
|
||||
gpointer
|
||||
fpi_device_get_udev_data (FpDevice *device, FpiDeviceUdevSubtypeFlags subtype)
|
||||
{
|
||||
FpDevicePrivate *priv = fp_device_get_instance_private (device);
|
||||
|
||||
g_return_val_if_fail (FP_IS_DEVICE (device), NULL);
|
||||
g_return_val_if_fail (priv->type == FP_DEVICE_TYPE_UDEV, NULL);
|
||||
|
||||
switch (subtype)
|
||||
{
|
||||
case FPI_DEVICE_UDEV_SUBTYPE_HIDRAW:
|
||||
return priv->udev_data.hidraw_path;
|
||||
|
||||
case FPI_DEVICE_UDEV_SUBTYPE_SPIDEV:
|
||||
return priv->udev_data.spidev_path;
|
||||
|
||||
default:
|
||||
g_return_val_if_reached (NULL);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_device_get_virtual_env:
|
||||
* @device: The #FpDevice
|
||||
|
@ -977,6 +1009,7 @@ fpi_device_close_complete (FpDevice *device, GError *error)
|
|||
break;
|
||||
|
||||
case FP_DEVICE_TYPE_VIRTUAL:
|
||||
case FP_DEVICE_TYPE_UDEV:
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -24,6 +24,18 @@
|
|||
#include "fp-image.h"
|
||||
#include "fpi-print.h"
|
||||
|
||||
#include <config.h>
|
||||
|
||||
/**
|
||||
* FpiDeviceUdevSubtype:
|
||||
* @FPI_DEVICE_UDEV_SUBTYPE_SPIDEV: The device requires an spidev node
|
||||
* @FPI_DEVICE_UDEV_SUBTYPE_HIDRAW: The device requires a hidraw node
|
||||
*/
|
||||
typedef enum {
|
||||
FPI_DEVICE_UDEV_SUBTYPE_SPIDEV = 1 << 0,
|
||||
FPI_DEVICE_UDEV_SUBTYPE_HIDRAW = 1 << 1,
|
||||
} FpiDeviceUdevSubtypeFlags;
|
||||
|
||||
/**
|
||||
* FpIdEntry:
|
||||
*
|
||||
|
@ -43,6 +55,16 @@ struct _FpIdEntry
|
|||
guint vid;
|
||||
};
|
||||
const gchar *virtual_envvar;
|
||||
struct
|
||||
{
|
||||
FpiDeviceUdevSubtypeFlags udev_types;
|
||||
const gchar *spi_acpi_id;
|
||||
struct
|
||||
{
|
||||
guint pid;
|
||||
guint vid;
|
||||
} hid_id;
|
||||
};
|
||||
};
|
||||
guint64 driver_data;
|
||||
};
|
||||
|
@ -171,6 +193,8 @@ typedef enum {
|
|||
|
||||
GUsbDevice *fpi_device_get_usb_device (FpDevice *device);
|
||||
const gchar *fpi_device_get_virtual_env (FpDevice *device);
|
||||
gpointer fpi_device_get_udev_data (FpDevice *device,
|
||||
FpiDeviceUdevSubtypeFlags subtype);
|
||||
//const gchar *fpi_device_get_spi_dev (FpDevice *device);
|
||||
|
||||
|
||||
|
|
|
@ -224,6 +224,7 @@ deps = [
|
|||
glib_dep,
|
||||
gobject_dep,
|
||||
gusb_dep,
|
||||
gudev_dep,
|
||||
imaging_dep,
|
||||
mathlib_dep,
|
||||
nss_dep,
|
||||
|
|
14
meson.build
14
meson.build
|
@ -94,6 +94,9 @@ virtual_drivers = [
|
|||
'virtual_device_storage',
|
||||
]
|
||||
|
||||
udev_drivers = [
|
||||
]
|
||||
|
||||
default_drivers = [
|
||||
'upektc_img',
|
||||
'vfs5011',
|
||||
|
@ -126,7 +129,7 @@ endian_independent_drivers = virtual_drivers + [
|
|||
'synaptics',
|
||||
]
|
||||
|
||||
all_drivers = default_drivers + virtual_drivers
|
||||
all_drivers = default_drivers + virtual_drivers + udev_drivers
|
||||
|
||||
if drivers == [ 'all' ]
|
||||
drivers = all_drivers
|
||||
|
@ -154,6 +157,7 @@ endif
|
|||
|
||||
nss_dep = dependency('', required: false)
|
||||
imaging_dep = dependency('', required: false)
|
||||
gudev_dep = dependency('', required: false)
|
||||
libfprint_conf.set10('HAVE_PIXMAN', false)
|
||||
foreach driver: drivers
|
||||
if driver == 'uru4000'
|
||||
|
@ -170,6 +174,14 @@ foreach driver: drivers
|
|||
|
||||
libfprint_conf.set10('HAVE_PIXMAN', true)
|
||||
endif
|
||||
if udev_drivers.contains(driver)
|
||||
gudev_dep = dependency('gudev-1.0', required: false)
|
||||
if not gudev_dep.found()
|
||||
error('udev is required for SPI support')
|
||||
endif
|
||||
|
||||
libfprint_conf.set10('HAVE_UDEV', true)
|
||||
endif
|
||||
if not all_drivers.contains(driver)
|
||||
error('Invalid driver \'' + driver + '\'')
|
||||
endif
|
||||
|
|
Loading…
Reference in a new issue