hidraw: allow opening of sibling devices

Some mice have a separate hid interface for configuring the advanced
features. It occurs that this is a common enough use case to be handled
directly by libratbag-hidraw instead of having a per-device quirk.

The idea is to allow opening the sibling hidraw devices during .probe()
and to give a matching callback. If the callback succeeds, then the
hidraw node will be used.
With this, one device might be opened several times, this has to be fixed
in a separate commit.

Fixes issue #19

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
This commit is contained in:
Benjamin Tissoires
2015-10-07 17:28:10 -04:00
parent ce37417525
commit 975c91ae54
4 changed files with 97 additions and 14 deletions

View File

@@ -191,6 +191,12 @@ hidpp10drv_fill_from_profile(struct ratbag_device *device, struct hidpp10_device
return 0;
}
static int
hidpp10drv_test_hidraw(struct ratbag_device *device)
{
return ratbag_hidraw_has_report(device, REPORT_ID_SHORT);
}
static int
hidpp10drv_probe(struct ratbag_device *device, const struct ratbag_id id)
{
@@ -198,8 +204,10 @@ hidpp10drv_probe(struct ratbag_device *device, const struct ratbag_id id)
struct hidpp10drv_data *drv_data = NULL;
struct hidpp10_device *dev = NULL;
rc = ratbag_open_hidraw(device);
if (rc) {
rc = ratbag_find_hidraw(device, hidpp10drv_test_hidraw);
if (rc == -ENODEV) {
return rc;
} else if (rc) {
log_error(device->ratbag,
"Can't open corresponding hidraw node: '%s' (%d)\n",
strerror(-rc),
@@ -208,11 +216,6 @@ hidpp10drv_probe(struct ratbag_device *device, const struct ratbag_id id)
goto err;
}
if (!ratbag_hidraw_has_report(device, REPORT_ID_SHORT)) {
ratbag_close_hidraw(device);
return -ENODEV;
}
drv_data = zalloc(sizeof(*drv_data));
/* We can treat all devices as wired devices here. If we talk to the

View File

@@ -431,14 +431,22 @@ hidpp20drv_20_probe(struct ratbag_device *device, const struct ratbag_id id)
}
static int
hidpp20drv_test_hidraw(struct ratbag_device *device)
{
return ratbag_hidraw_has_report(device, REPORT_ID_LONG);
}
static int
hidpp20drv_probe(struct ratbag_device *device, const struct ratbag_id id)
{
int rc;
struct hidpp20drv_data *drv_data;
rc = ratbag_open_hidraw(device);
if (rc) {
rc = ratbag_find_hidraw(device, hidpp20drv_test_hidraw);
if (rc == -ENODEV) {
return rc;
} else if (rc) {
log_error(device->ratbag,
"Can't open corresponding hidraw node: '%s' (%d)\n",
strerror(-rc),
@@ -446,11 +454,6 @@ hidpp20drv_probe(struct ratbag_device *device, const struct ratbag_id id)
return -ENODEV;
}
if (!ratbag_hidraw_has_report(device, REPORT_ID_LONG)) {
ratbag_close_hidraw(device);
return -ENODEV;
}
drv_data = zalloc(sizeof(*drv_data));
ratbag_set_drv_data(device, drv_data);

View File

@@ -212,6 +212,70 @@ ratbag_open_hidraw(struct ratbag_device *device)
return rc;
}
int
ratbag_find_hidraw(struct ratbag_device *device, int (*match)(struct ratbag_device *device))
{
struct ratbag *ratbag = device->ratbag;
struct udev_enumerate *e;
struct udev_list_entry *entry;
struct udev_device *udev_device;
const char *path, *sysname;
struct udev_device *hid_udev;
struct udev_device *parent_udev;
struct udev *udev = ratbag->udev;
int rc = -ENODEV;
int matched;
assert(match);
hid_udev = udev_device_get_parent_with_subsystem_devtype(device->udev_device, "hid", NULL);
if (!hid_udev)
return -ENODEV;
if (device->ids.bustype == BUS_USB)
/* using the parent usb_device to match siblings */
parent_udev = udev_device_get_parent_with_subsystem_devtype(hid_udev, "usb", "usb_device");
else
parent_udev = hid_udev;
e = udev_enumerate_new(udev);
udev_enumerate_add_match_subsystem(e, "hidraw");
udev_enumerate_add_match_parent(e, parent_udev);
udev_enumerate_scan_devices(e);
udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
path = udev_list_entry_get_name(entry);
udev_device = udev_device_new_from_syspath(udev, path);
if (!udev_device)
continue;
sysname = udev_device_get_sysname(udev_device);
if (!strneq("hidraw", sysname, 6)) {
udev_device_unref(udev_device);
continue;
}
rc = ratbag_open_hidraw_node(device, udev_device);
if (rc)
ratbag_close_hidraw(device);
matched = match(device);
udev_device_unref(udev_device);
if (matched == 1) {
rc = 0;
goto out;
}
rc = -ENODEV;
}
out:
udev_enumerate_unref(e);
return rc;
}
int
ratbag_hidraw_has_report(struct ratbag_device *device, uint8_t report_id)
{

View File

@@ -49,6 +49,19 @@ struct ratbag_hidraw {
*/
int ratbag_open_hidraw(struct ratbag_device *device);
/**
* Find and open the hidraw device associated with the device by using the
* given matching function.
*
* @param device the ratbag device
* @param match the matching test (return 1 if matched, 0 if not)
*
* @return 0 on success or a negative errno on error
*/
int
ratbag_find_hidraw(struct ratbag_device *device,
int (*match)(struct ratbag_device *device));
/**
* Close the hidraw device associated with the device.
*