forked from drath/libratbag
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 <phomes@gmail.com>
This commit is contained in:
committed by
Peter Hutterer
parent
38dce69838
commit
a4e1e1690d
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user