driver-hidpp10: override the hidraw device for unifying receivers

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
Peter Hutterer
2015-08-24 11:31:21 +10:00
parent 6ab11a0585
commit 0d97c99306
3 changed files with 102 additions and 1 deletions

View File

@@ -35,8 +35,11 @@
#include "config.h"
#define USB_VENDOR_ID_LOGITECH 0x046d
#include <linux/types.h>
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
@@ -96,12 +99,93 @@ hidpp10drv_write_profile(struct ratbag_profile *profile)
return -1;
}
static bool
hidpp10drv_is_unifying_receiver(struct ratbag_device *device)
{
struct udev_device *hidraw;
struct input_id id;
const char *product;
int rc;
hidraw = device->udev_hidraw;
/* Note: PRODUCT on the hid device is missing the bustype! */
product = udev_prop_value(hidraw, "PRODUCT");
rc = sscanf(product, "%hx/%hx/%hx", &id.vendor, &id.product, &id.version);
if (rc != 3)
return false;
if (id.vendor == USB_VENDOR_ID_LOGITECH &&
(id.product == 0xc52b || id.product == 0xc532))
return true;
return false;
}
static int
hidpp10drv_find_unifying_hidraw(struct ratbag_device *device)
{
struct udev_device *receiver, *hid, *hidraw;
struct udev *udev;
struct udev_enumerate *e;
struct udev_list_entry *entry;
hidraw = device->udev_hidraw;
/* the receiver device is two up */
hid = udev_device_get_parent_with_subsystem_devtype(hidraw, "hid", NULL);
receiver = udev_device_get_parent_with_subsystem_devtype(hid, "hid", NULL);
if (!receiver)
return -1; /* should not happen */
udev = udev_device_get_udev(hidraw);
e = udev_enumerate_new(udev);
udev_enumerate_add_match_subsystem(e, "hidraw");
udev_enumerate_add_match_parent(e, receiver);
udev_enumerate_scan_devices(e);
udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
const char *path, *sysname;
path = udev_list_entry_get_name(entry);
hidraw = udev_device_new_from_syspath(udev, path);
if (!hidraw)
continue;
sysname = udev_device_get_sysname(hidraw);
if (!strneq("hidraw", sysname, 6)) {
udev_device_unref(hidraw);
continue;
}
/* The receiver has multiple hidraw devices, we only want
* the one where the direct parent is the receiver */
hid = udev_device_get_parent_with_subsystem_devtype(hidraw, "hid", NULL);
if (!streq(udev_device_get_syspath(hid), udev_device_get_syspath(receiver)))
continue;
ratbag_device_set_hidraw_device(device, hidraw);
udev_device_unref(hidraw);
goto out;
}
out:
udev_enumerate_unref(e);
return 0;
}
static int
hidpp10drv_probe(struct ratbag_device *device, const struct ratbag_id id)
{
int rc;
struct hidpp10drv_data *drv_data;
/* check if the device is a unifying receiver first so we can update
* the hidraw path before we open it */
if (hidpp10drv_is_unifying_receiver(device))
hidpp10drv_find_unifying_hidraw(device);
rc = ratbag_open_hidraw(device);
if (rc) {
log_error(device->ratbag,
@@ -132,7 +216,6 @@ hidpp10drv_remove(struct ratbag_device *device)
free(ratbag_get_drv_data(device));
}
#define USB_VENDOR_ID_LOGITECH 0x046d
#define LOGITECH_DEVICE(_bus, _pid) \
{ .bustype = (_bus), \
.vendor = USB_VENDOR_ID_LOGITECH, \

View File

@@ -234,6 +234,12 @@ ratbag_profile_get_drv_data(struct ratbag_profile *profile)
return profile->drv_data;
}
/**
* Override the auto-picked hidraw device.
*/
void
ratbag_device_set_hidraw_device(struct ratbag_device *device,
struct udev_device *hidraw);
void
log_msg_va(struct ratbag *ratbag,

View File

@@ -140,6 +140,17 @@ ratbag_log_set_handler(struct ratbag *ratbag,
ratbag->log_handler = log_handler;
}
void
ratbag_device_set_hidraw_device(struct ratbag_device *device,
struct udev_device *hidraw)
{
udev_device_unref(device->udev_hidraw);
device->udev_hidraw = udev_device_ref(hidraw);
log_debug(device->ratbag,
"Overriding hidraw device with %s\n",
udev_device_get_syspath(hidraw));
}
static inline struct udev_device *
udev_device_from_devnode(struct ratbag *ratbag, int fd)
@@ -228,6 +239,7 @@ ratbag_device_init_udev(struct ratbag_device *device,
if (!hidraw_udev)
goto out;
/* Note: may be overridden later */
device->udev_hidraw = udev_device_ref(hidraw_udev);
log_debug(device->ratbag,