From a4e1e1690d33d82bcfb2d50244e38faf02b9ea1c Mon Sep 17 00:00:00 2001 From: Thomas Hindoe Paaboel Andersen Date: Sun, 26 Aug 2018 17:09:17 +0200 Subject: [PATCH] hidraw: allow opening multiple hidraw For some devices we have to send reports on one endpoint but read the reply on another. This commit allows us to open and store multiple hidraws and adds API to specify which hidraw to use for open, close, and read input report. Signed-off-by: Thomas Hindoe Paaboel Andersen --- src/driver-hidpp10.c | 2 +- src/driver-hidpp20.c | 2 +- src/libratbag-hidraw.c | 107 +++++++++++++++++++++++++--------------- src/libratbag-hidraw.h | 34 +++++++++++++ src/libratbag-private.h | 2 +- 5 files changed, 105 insertions(+), 42 deletions(-) diff --git a/src/driver-hidpp10.c b/src/driver-hidpp10.c index a2fca37f..65c7b1dd 100644 --- a/src/driver-hidpp10.c +++ b/src/driver-hidpp10.c @@ -612,7 +612,7 @@ hidpp10drv_probe(struct ratbag_device *device) goto err; drv_data = zalloc(sizeof(*drv_data)); - hidpp_device_init(&base, device->hidraw.fd); + hidpp_device_init(&base, device->hidraw[0].fd); hidpp_device_set_log_handler(&base, hidpp10_log, HIDPP_LOG_PRIORITY_RAW, device); typestr = ratbag_device_data_hidpp10_get_profile_type(device->data); diff --git a/src/driver-hidpp20.c b/src/driver-hidpp20.c index 146305e8..6f3e713c 100644 --- a/src/driver-hidpp20.c +++ b/src/driver-hidpp20.c @@ -1310,7 +1310,7 @@ hidpp20drv_probe(struct ratbag_device *device) drv_data = zalloc(sizeof(*drv_data)); ratbag_set_drv_data(device, drv_data); - hidpp_device_init(&base, device->hidraw.fd); + hidpp_device_init(&base, device->hidraw[0].fd); hidpp_device_set_log_handler(&base, hidpp20_log, HIDPP_LOG_PRIORITY_RAW, device); device_idx = ratbag_device_data_hidpp20_get_index(device->data); diff --git a/src/libratbag-hidraw.c b/src/libratbag-hidraw.c index 2059d371..f7766d95 100644 --- a/src/libratbag-hidraw.c +++ b/src/libratbag-hidraw.c @@ -1223,7 +1223,7 @@ static int ratbag_hidraw_parse_report_descriptor(struct ratbag_device *device) { int rc, desc_size = 0; - struct ratbag_hidraw *hidraw = &device->hidraw; + struct ratbag_hidraw *hidraw = &device->hidraw[0]; struct hidraw_report_descriptor report_desc = {0}; unsigned int i, j; unsigned int usage_page, usage; @@ -1291,7 +1291,7 @@ ratbag_hidraw_parse_report_descriptor(struct ratbag_device *device) } static int -ratbag_open_hidraw_node(struct ratbag_device *device, struct udev_device *hidraw_udev) +ratbag_open_hidraw_node(struct ratbag_device *device, struct udev_device *hidraw_udev, int idx) { struct hidraw_devinfo info; struct ratbag_device *tmp_device; @@ -1300,15 +1300,17 @@ ratbag_open_hidraw_node(struct ratbag_device *device, struct udev_device *hidraw const char *sysname; size_t reports_size; - device->hidraw.fd = -1; + assert(idx >= 0 && idx < MAX_HIDRAW); + + device->hidraw[idx].fd = -1; sysname = udev_device_get_sysname(hidraw_udev); if (!strneq("hidraw", sysname, 6)) return -ENODEV; list_for_each(tmp_device, &device->ratbag->devices, link) { - if (tmp_device->hidraw.sysname && - streq(tmp_device->hidraw.sysname, sysname)) { + if (tmp_device->hidraw[idx].sysname && + streq(tmp_device->hidraw[idx].sysname, sysname)) { return -ENODEV; } } @@ -1339,7 +1341,7 @@ ratbag_open_hidraw_node(struct ratbag_device *device, struct udev_device *hidraw device->name, udev_device_get_devnode(hidraw_udev)); - device->hidraw.fd = fd; + device->hidraw[idx].fd = fd; /* parse first to count the number of reports */ res = ratbag_hidraw_parse_report_descriptor(device); @@ -1348,19 +1350,19 @@ ratbag_open_hidraw_node(struct ratbag_device *device, struct udev_device *hidraw "Error while parsing the report descriptor: '%s' (%d)\n", strerror(-res), res); - device->hidraw.fd = -1; + device->hidraw[idx].fd = -1; goto err; } - if (device->hidraw.num_reports) - reports_size = device->hidraw.num_reports * sizeof(struct ratbag_hid_report); + if (device->hidraw[idx].num_reports) + reports_size = device->hidraw[idx].num_reports * sizeof(struct ratbag_hid_report); else reports_size = sizeof(struct ratbag_hid_report); - device->hidraw.reports = zalloc(reports_size); + device->hidraw[idx].reports = zalloc(reports_size); ratbag_hidraw_parse_report_descriptor(device); - device->hidraw.sysname = strdup_safe(sysname); + device->hidraw[idx].sysname = strdup_safe(sysname); return 0; err: @@ -1372,7 +1374,8 @@ err: static int ratbag_find_hidraw_node(struct ratbag_device *device, int (*match)(struct ratbag_device *device), - int use_usb_parent) + int use_usb_parent, + int match_index, int hidraw_index) { struct ratbag *ratbag = device->ratbag; _cleanup_(udev_enumerate_unrefp) struct udev_enumerate *e = NULL; @@ -1382,7 +1385,7 @@ ratbag_find_hidraw_node(struct ratbag_device *device, struct udev_device *parent_udev; struct udev *udev = ratbag->udev; int rc = -ENODEV; - int matched; + int matched, endpoint_index = 0; assert(match); @@ -1414,17 +1417,21 @@ ratbag_find_hidraw_node(struct ratbag_device *device, if (!udev_device) continue; - rc = ratbag_open_hidraw_node(device, udev_device); + if (match_index > 0 && match_index != endpoint_index++) + continue; + + rc = ratbag_open_hidraw_node(device, udev_device, hidraw_index); if (rc) goto skip; + matched = match(device); rc = matched ? 0 : -ENODEV; if (matched == 1) return rc; skip: - ratbag_close_hidraw(device); + ratbag_close_hidraw_index(device, hidraw_index); } return rc; @@ -1433,7 +1440,7 @@ skip: int ratbag_find_hidraw(struct ratbag_device *device, int (*match)(struct ratbag_device *device)) { - return ratbag_find_hidraw_node(device, match, true); + return ratbag_find_hidraw_node(device, match, true, -1, 0); } static int @@ -1445,7 +1452,13 @@ hidraw_match_all(struct ratbag_device *device) int ratbag_open_hidraw(struct ratbag_device *device) { - return ratbag_find_hidraw_node(device, hidraw_match_all, false); + return ratbag_find_hidraw_node(device, hidraw_match_all, false, -1, 0); +} + +int +ratbag_open_hidraw_index(struct ratbag_device *device, int endpoint_index, int hidraw_index) +{ + return ratbag_find_hidraw_node(device, hidraw_match_all, true, endpoint_index, hidraw_index); } static struct ratbag_hid_report * @@ -1454,15 +1467,15 @@ ratbag_hidraw_get_report(struct ratbag_device *device, unsigned int report_id) unsigned i; if (report_id == 0) { - if (device->hidraw.reports[0].report_id == report_id) - return &device->hidraw.reports[0]; + if (device->hidraw[0].reports[0].report_id == report_id) + return &device->hidraw[0].reports[0]; else return NULL; } - for (i = 0; i < device->hidraw.num_reports; i++) { - if (device->hidraw.reports[i].report_id == report_id) - return &device->hidraw.reports[i]; + for (i = 0; i < device->hidraw[0].num_reports; i++) { + if (device->hidraw[0].reports[i].report_id == report_id) + return &device->hidraw[0].reports[i]; } return NULL; @@ -1504,20 +1517,28 @@ ratbag_hidraw_get_usage(struct ratbag_device *device, unsigned int report_id) void ratbag_close_hidraw(struct ratbag_device *device) { - if (device->hidraw.fd < 0) + ratbag_close_hidraw_index(device, 0); +} + +void +ratbag_close_hidraw_index(struct ratbag_device *device, int idx) +{ + assert(idx >= 0 && idx < MAX_HIDRAW); + + if (device->hidraw[idx].fd < 0) return; - if (device->hidraw.sysname) { - free(device->hidraw.sysname); - device->hidraw.sysname = NULL; + if (device->hidraw[idx].sysname) { + free(device->hidraw[idx].sysname); + device->hidraw[idx].sysname = NULL; } - ratbag_close_fd(device, device->hidraw.fd); - device->hidraw.fd = -1; + ratbag_close_fd(device, device->hidraw[idx].fd); + device->hidraw[idx].fd = -1; - if (device->hidraw.reports) { - free(device->hidraw.reports); - device->hidraw.reports = NULL; + if (device->hidraw[idx].reports) { + free(device->hidraw[idx].reports); + device->hidraw[idx].reports = NULL; } } @@ -1528,7 +1549,7 @@ ratbag_hidraw_raw_request(struct ratbag_device *device, unsigned char reportnum, uint8_t tmp_buf[HID_MAX_BUFFER_SIZE]; int rc; - if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf || device->hidraw.fd < 0) + if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf || device->hidraw[0].fd < 0) return -EINVAL; if (rtype != HID_FEATURE_REPORT) @@ -1539,7 +1560,7 @@ ratbag_hidraw_raw_request(struct ratbag_device *device, unsigned char reportnum, memset(tmp_buf, 0, len); tmp_buf[0] = reportnum; - rc = ioctl(device->hidraw.fd, HIDIOCGFEATURE(len), tmp_buf); + rc = ioctl(device->hidraw[0].fd, HIDIOCGFEATURE(len), tmp_buf); if (rc < 0) return -errno; @@ -1551,7 +1572,7 @@ ratbag_hidraw_raw_request(struct ratbag_device *device, unsigned char reportnum, buf[0] = reportnum; log_buf_raw(device->ratbag, "feature set: ", buf, len); - rc = ioctl(device->hidraw.fd, HIDIOCSFEATURE(len), buf); + rc = ioctl(device->hidraw[0].fd, HIDIOCSFEATURE(len), buf); if (rc < 0) return -errno; @@ -1566,12 +1587,12 @@ ratbag_hidraw_output_report(struct ratbag_device *device, uint8_t *buf, size_t l { int rc; - if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf || device->hidraw.fd < 0) + if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf || device->hidraw[0].fd < 0) return -EINVAL; log_buf_raw(device->ratbag, "output report: ", buf, len); - rc = write(device->hidraw.fd, buf, len); + rc = write(device->hidraw[0].fd, buf, len); if (rc < 0) return -errno; @@ -1584,14 +1605,22 @@ ratbag_hidraw_output_report(struct ratbag_device *device, uint8_t *buf, size_t l int ratbag_hidraw_read_input_report(struct ratbag_device *device, uint8_t *buf, size_t len) +{ + return ratbag_hidraw_read_input_report_index(device, buf, len, 0); +} + +int +ratbag_hidraw_read_input_report_index(struct ratbag_device *device, uint8_t *buf, size_t len, int hidrawno) { int rc; struct pollfd fds; - if (len < 1 || !buf || device->hidraw.fd < 0) + assert(hidrawno >= 0 && hidrawno < MAX_HIDRAW); + + if (len < 1 || !buf || device->hidraw[hidrawno].fd < 0) return -EINVAL; - fds.fd = device->hidraw.fd; + fds.fd = device->hidraw[hidrawno].fd; fds.events = POLLIN; rc = poll(&fds, 1, 1000); @@ -1601,7 +1630,7 @@ ratbag_hidraw_read_input_report(struct ratbag_device *device, uint8_t *buf, size if (rc == 0) return -ETIMEDOUT; - rc = read(device->hidraw.fd, buf, len); + rc = read(device->hidraw[hidrawno].fd, buf, len); if (rc > 0) log_buf_raw(device->ratbag, "input report: ", buf, rc); diff --git a/src/libratbag-hidraw.h b/src/libratbag-hidraw.h index 16dfed79..2b80f68c 100644 --- a/src/libratbag-hidraw.h +++ b/src/libratbag-hidraw.h @@ -32,6 +32,7 @@ #define HID_INPUT_REPORT 0 #define HID_OUTPUT_REPORT 1 #define HID_FEATURE_REPORT 2 +#define MAX_HIDRAW 2 struct ratbag_hid_report { unsigned int report_id; @@ -55,6 +56,18 @@ struct ratbag_hidraw { */ int ratbag_open_hidraw(struct ratbag_device *device); +/** + * Open a hidraw device associated with the device by its enumeration order to + * a specific internal hidraw index. + * + * @param device the ratbag device + * @param enumeration index of the endpoint + * @param interal index of hidraw array + * + * @return 0 on success or a negative errno on error + */ +int ratbag_open_hidraw_index(struct ratbag_device *device, int endpoint_index, int hidraw_index); + /** * Find and open the hidraw device associated with the device by using the * given matching function. @@ -75,6 +88,14 @@ ratbag_find_hidraw(struct ratbag_device *device, */ void ratbag_close_hidraw(struct ratbag_device *device); +/** + * Close a hidraw device associated with the device by the internal index. + * + * @param device the ratbag device + * @param interal index of hidraw array + */ +void ratbag_close_hidraw_index(struct ratbag_device *device, int idx); + /** * Send report request to device * @@ -115,6 +136,19 @@ int ratbag_hidraw_output_report(struct ratbag_device *device, uint8_t *buf, size */ int ratbag_hidraw_read_input_report(struct ratbag_device *device, uint8_t *buf, size_t len); +/** + * Read an input report from the device from a specific hidraw index + * + * @param device the ratbag device + * @param[out] buf resulting raw data + * @param len length of buf + * @param interal index of hidraw array + * + * @return count of data transfered, or a negative errno on error + */ +int ratbag_hidraw_read_input_report_index(struct ratbag_device *device, uint8_t *buf, size_t len, int hidrawno); + + /** * Tells if a given device has the specified report ID. * diff --git a/src/libratbag-private.h b/src/libratbag-private.h index 26823f9d..7457cb57 100644 --- a/src/libratbag-private.h +++ b/src/libratbag-private.h @@ -129,7 +129,7 @@ struct ratbag_device { void *userdata; struct udev_device *udev_device; - struct ratbag_hidraw hidraw; + struct ratbag_hidraw hidraw[MAX_HIDRAW]; int refcount; struct input_id ids; struct ratbag_driver *driver;