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
|
FpTimeoutFunc
|
||||||
FpiDeviceAction
|
FpiDeviceAction
|
||||||
FpIdEntry
|
FpIdEntry
|
||||||
|
FpiDeviceUdevSubtypeFlags
|
||||||
fpi_device_get_usb_device
|
fpi_device_get_usb_device
|
||||||
|
fpi_device_get_udev_data
|
||||||
fpi_device_get_virtual_env
|
fpi_device_get_virtual_env
|
||||||
fpi_device_get_current_action
|
fpi_device_get_current_action
|
||||||
fpi_device_retry_new
|
fpi_device_retry_new
|
||||||
|
|
|
@ -24,6 +24,18 @@
|
||||||
#include "fpi-device.h"
|
#include "fpi-device.h"
|
||||||
#include <gusb.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
|
* SECTION: fp-context
|
||||||
* @title: FpContext
|
* @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)
|
while (priv->pending_devices)
|
||||||
g_main_context_iteration (NULL, TRUE);
|
g_main_context_iteration (NULL, TRUE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,18 +28,23 @@ typedef struct
|
||||||
|
|
||||||
GUsbDevice *usb_device;
|
GUsbDevice *usb_device;
|
||||||
const gchar *virtual_env;
|
const gchar *virtual_env;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
gchar *spidev_path;
|
||||||
|
gchar *hidraw_path;
|
||||||
|
} udev_data;
|
||||||
|
|
||||||
gboolean is_removed;
|
gboolean is_removed;
|
||||||
gboolean is_open;
|
gboolean is_open;
|
||||||
|
|
||||||
gchar *device_id;
|
gchar *device_id;
|
||||||
gchar *device_name;
|
gchar *device_name;
|
||||||
FpScanType scan_type;
|
FpScanType scan_type;
|
||||||
|
|
||||||
guint64 driver_data;
|
guint64 driver_data;
|
||||||
|
|
||||||
gint nr_enroll_stages;
|
gint nr_enroll_stages;
|
||||||
GSList *sources;
|
GSList *sources;
|
||||||
|
|
||||||
/* We always make sure that only one task is run at a time. */
|
/* We always make sure that only one task is run at a time. */
|
||||||
FpiDeviceAction current_action;
|
FpiDeviceAction current_action;
|
||||||
|
|
|
@ -50,6 +50,8 @@ enum {
|
||||||
PROP_FINGER_STATUS,
|
PROP_FINGER_STATUS,
|
||||||
PROP_FPI_ENVIRON,
|
PROP_FPI_ENVIRON,
|
||||||
PROP_FPI_USB_DEVICE,
|
PROP_FPI_USB_DEVICE,
|
||||||
|
PROP_FPI_UDEV_DATA_SPIDEV,
|
||||||
|
PROP_FPI_UDEV_DATA_HIDRAW,
|
||||||
PROP_FPI_DRIVER_DATA,
|
PROP_FPI_DRIVER_DATA,
|
||||||
N_PROPS
|
N_PROPS
|
||||||
};
|
};
|
||||||
|
@ -169,6 +171,8 @@ fp_device_finalize (GObject *object)
|
||||||
|
|
||||||
g_clear_object (&priv->usb_device);
|
g_clear_object (&priv->usb_device);
|
||||||
g_clear_pointer (&priv->virtual_env, g_free);
|
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);
|
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);
|
g_assert (g_value_get_object (value) == NULL);
|
||||||
break;
|
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:
|
case PROP_FPI_DRIVER_DATA:
|
||||||
priv->driver_data = g_value_get_uint64 (value);
|
priv->driver_data = g_value_get_uint64 (value);
|
||||||
break;
|
break;
|
||||||
|
@ -425,6 +443,32 @@ fp_device_class_init (FpDeviceClass *klass)
|
||||||
"Private: The USB device for the device",
|
"Private: The USB device for the device",
|
||||||
G_USB_TYPE_DEVICE,
|
G_USB_TYPE_DEVICE,
|
||||||
G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
|
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)
|
* FpDevice::fpi-driver-data: (skip)
|
||||||
|
@ -673,6 +717,7 @@ fp_device_open (FpDevice *device,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FP_DEVICE_TYPE_VIRTUAL:
|
case FP_DEVICE_TYPE_VIRTUAL:
|
||||||
|
case FP_DEVICE_TYPE_UDEV:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -38,10 +38,12 @@ G_DECLARE_DERIVABLE_TYPE (FpDevice, fp_device, FP, DEVICE, GObject)
|
||||||
/**
|
/**
|
||||||
* FpDeviceType:
|
* FpDeviceType:
|
||||||
* @FP_DEVICE_TYPE_VIRTUAL: The device is a virtual device
|
* @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
|
* @FP_DEVICE_TYPE_USB: The device is a USB device
|
||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
FP_DEVICE_TYPE_VIRTUAL,
|
FP_DEVICE_TYPE_VIRTUAL,
|
||||||
|
FP_DEVICE_TYPE_UDEV,
|
||||||
FP_DEVICE_TYPE_USB,
|
FP_DEVICE_TYPE_USB,
|
||||||
} FpDeviceType;
|
} FpDeviceType;
|
||||||
|
|
||||||
|
|
|
@ -335,6 +335,38 @@ fpi_device_get_usb_device (FpDevice *device)
|
||||||
return priv->usb_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:
|
* fpi_device_get_virtual_env:
|
||||||
* @device: The #FpDevice
|
* @device: The #FpDevice
|
||||||
|
@ -977,6 +1009,7 @@ fpi_device_close_complete (FpDevice *device, GError *error)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FP_DEVICE_TYPE_VIRTUAL:
|
case FP_DEVICE_TYPE_VIRTUAL:
|
||||||
|
case FP_DEVICE_TYPE_UDEV:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -24,6 +24,18 @@
|
||||||
#include "fp-image.h"
|
#include "fp-image.h"
|
||||||
#include "fpi-print.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:
|
* FpIdEntry:
|
||||||
*
|
*
|
||||||
|
@ -43,6 +55,16 @@ struct _FpIdEntry
|
||||||
guint vid;
|
guint vid;
|
||||||
};
|
};
|
||||||
const gchar *virtual_envvar;
|
const gchar *virtual_envvar;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
FpiDeviceUdevSubtypeFlags udev_types;
|
||||||
|
const gchar *spi_acpi_id;
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
guint pid;
|
||||||
|
guint vid;
|
||||||
|
} hid_id;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
guint64 driver_data;
|
guint64 driver_data;
|
||||||
};
|
};
|
||||||
|
@ -171,6 +193,8 @@ typedef enum {
|
||||||
|
|
||||||
GUsbDevice *fpi_device_get_usb_device (FpDevice *device);
|
GUsbDevice *fpi_device_get_usb_device (FpDevice *device);
|
||||||
const gchar *fpi_device_get_virtual_env (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);
|
//const gchar *fpi_device_get_spi_dev (FpDevice *device);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -224,6 +224,7 @@ deps = [
|
||||||
glib_dep,
|
glib_dep,
|
||||||
gobject_dep,
|
gobject_dep,
|
||||||
gusb_dep,
|
gusb_dep,
|
||||||
|
gudev_dep,
|
||||||
imaging_dep,
|
imaging_dep,
|
||||||
mathlib_dep,
|
mathlib_dep,
|
||||||
nss_dep,
|
nss_dep,
|
||||||
|
|
14
meson.build
14
meson.build
|
@ -94,6 +94,9 @@ virtual_drivers = [
|
||||||
'virtual_device_storage',
|
'virtual_device_storage',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
udev_drivers = [
|
||||||
|
]
|
||||||
|
|
||||||
default_drivers = [
|
default_drivers = [
|
||||||
'upektc_img',
|
'upektc_img',
|
||||||
'vfs5011',
|
'vfs5011',
|
||||||
|
@ -126,7 +129,7 @@ endian_independent_drivers = virtual_drivers + [
|
||||||
'synaptics',
|
'synaptics',
|
||||||
]
|
]
|
||||||
|
|
||||||
all_drivers = default_drivers + virtual_drivers
|
all_drivers = default_drivers + virtual_drivers + udev_drivers
|
||||||
|
|
||||||
if drivers == [ 'all' ]
|
if drivers == [ 'all' ]
|
||||||
drivers = all_drivers
|
drivers = all_drivers
|
||||||
|
@ -154,6 +157,7 @@ endif
|
||||||
|
|
||||||
nss_dep = dependency('', required: false)
|
nss_dep = dependency('', required: false)
|
||||||
imaging_dep = dependency('', required: false)
|
imaging_dep = dependency('', required: false)
|
||||||
|
gudev_dep = dependency('', required: false)
|
||||||
libfprint_conf.set10('HAVE_PIXMAN', false)
|
libfprint_conf.set10('HAVE_PIXMAN', false)
|
||||||
foreach driver: drivers
|
foreach driver: drivers
|
||||||
if driver == 'uru4000'
|
if driver == 'uru4000'
|
||||||
|
@ -170,6 +174,14 @@ foreach driver: drivers
|
||||||
|
|
||||||
libfprint_conf.set10('HAVE_PIXMAN', true)
|
libfprint_conf.set10('HAVE_PIXMAN', true)
|
||||||
endif
|
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)
|
if not all_drivers.contains(driver)
|
||||||
error('Invalid driver \'' + driver + '\'')
|
error('Invalid driver \'' + driver + '\'')
|
||||||
endif
|
endif
|
||||||
|
|
Loading…
Reference in a new issue