mirror of
https://github.com/libratbag/libratbag.git
synced 2026-11-07 23:23:52 +01:00
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:
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user