hidpp20: check supported report types

Fixes #854

Signed-off-by: Filipe Laíns <lains@archlinux.org>
This commit is contained in:
Filipe Laíns
2019-12-14 21:13:22 +00:00
committed by Filipe Laíns
parent 904c7988bb
commit 26c534cc74
7 changed files with 65 additions and 5 deletions

View File

@@ -1575,7 +1575,7 @@ hidpp20drv_probe(struct ratbag_device *device)
* If there is a special need like for G900, we can add this in the
* device data file.
*/
dev = hidpp20_device_new(&base, device_idx);
dev = hidpp20_device_new(&base, device_idx, (struct hidpp_hid_report*) device->hidraw[0].reports, device->hidraw[0].num_reports);
if (!dev) {
rc = -ENODEV;
goto err;

View File

@@ -306,6 +306,33 @@ hidpp_read_response(struct hidpp_device *dev, uint8_t *buf, size_t size)
return rc >= 0 ? rc : -errno;
}
void
hidpp_get_supported_report_types(struct hidpp_device *dev, struct hidpp_hid_report *reports, unsigned int num_reports)
{
if (!reports) {
hidpp_log_debug(dev, "hidpp: we don't have information about the hid reports, ignoring checks\n");
dev->supported_report_types = 0xffff;
return;
}
/* reset the bits we are gonna check */
dev->supported_report_types &= (0xff & ~HIDPP_REPORT_SHORT);
dev->supported_report_types &= (0xff & ~HIDPP_REPORT_LONG);
for (unsigned i = 0; i < num_reports; i++)
if ((reports[i].usage_page & 0xff00) == 0xff00) /* vendor defined usage page (0xff00-0xffff) */
switch (reports[i].report_id) {
case REPORT_ID_SHORT:
hidpp_log_debug(dev, "hidpp: device supports short reports\n");
dev->supported_report_types |= HIDPP_REPORT_SHORT;
break;
case REPORT_ID_LONG:
hidpp_log_debug(dev, "hidpp: device supports long reports\n");
dev->supported_report_types |= HIDPP_REPORT_LONG;
break;
}
}
void
hidpp_log(struct hidpp_device *dev,
enum hidpp_log_priority priority,
@@ -363,6 +390,7 @@ hidpp_device_init(struct hidpp_device *dev, int fd)
{
dev->hidraw_fd = fd;
hidpp_device_set_log_handler(dev, simple_log, HIDPP_LOG_PRIORITY_INFO, NULL);
dev->supported_report_types = 0;
}
void

View File

@@ -95,13 +95,23 @@ typedef void (*hidpp_log_handler)(void *userdata,
const char *format, va_list args)
__attribute__ ((format (printf, 3, 0)));
struct hidpp_hid_report {
unsigned int report_id;
unsigned int usage_page;
unsigned int usage;
};
struct hidpp_device {
int hidraw_fd;
void *userdata;
hidpp_log_handler log_handler;
enum hidpp_log_priority log_priority;
uint8_t supported_report_types;
};
#define HIDPP_REPORT_SHORT (1 << 0)
#define HIDPP_REPORT_LONG (1 << 1)
void
hidpp_device_init(struct hidpp_device *dev, int fd);
void
@@ -140,6 +150,11 @@ hidpp_write_command(struct hidpp_device *dev, uint8_t *cmd, int size);
int
hidpp_read_response(struct hidpp_device *dev, uint8_t *buf, size_t size);
void
hidpp_get_supported_report_types(struct hidpp_device *dev,
struct hidpp_hid_report *reports,
unsigned int num_reports);
void
hidpp_log(struct hidpp_device *dev,
enum hidpp_log_priority priority,

View File

@@ -133,6 +133,16 @@ hidpp20_request_command_allow_error(struct hidpp20_device *device, union hidpp20
}
msg->msg.address |= DEVICE_SW_ID;
/* some mice don't support short reports */
if (msg->msg.report_id == REPORT_ID_SHORT && !(device->base.supported_report_types & HIDPP_REPORT_SHORT))
msg->msg.report_id = REPORT_ID_LONG;
/* sanity check */
if (msg->msg.report_id == REPORT_ID_LONG && !(device->base.supported_report_types & HIDPP_REPORT_LONG)) {
hidpp_log_error(&device->base, "hidpp20: trying to use unsupported report type\n");
return -EINVAL;
}
msg_len = msg->msg.report_id == REPORT_ID_SHORT ? SHORT_MESSAGE_LENGTH : LONG_MESSAGE_LENGTH;
/* Send the message to the Device */
@@ -2871,7 +2881,7 @@ hidpp20_onboard_profiles_get_code_from_special(enum ratbag_button_action_special
/* -------------------------------------------------------------------------- */
struct hidpp20_device *
hidpp20_device_new(const struct hidpp_device *base, unsigned int idx)
hidpp20_device_new(const struct hidpp_device *base, unsigned int idx, struct hidpp_hid_report *reports, unsigned int num_reports)
{
struct hidpp20_device *dev;
int rc;
@@ -2884,6 +2894,12 @@ hidpp20_device_new(const struct hidpp_device *base, unsigned int idx)
dev->proto_major = 1;
dev->proto_minor = 0;
hidpp_get_supported_report_types(&(dev->base), reports, num_reports);
if (!(dev->base.supported_report_types & HIDPP_REPORT_SHORT) &&
!(dev->base.supported_report_types & HIDPP_REPORT_LONG))
goto err;
rc = hidpp20_root_get_protocol_version(dev, &dev->proto_major, &dev->proto_minor);
if (rc) {
/* communication error, best to ignore the device */

View File

@@ -80,7 +80,8 @@ const char *hidpp20_get_quirk_string(enum hidpp20_quirk quirk);
/* -------------------------------------------------------------------------- */
struct hidpp20_device *
hidpp20_device_new(const struct hidpp_device *base, unsigned int idx);
hidpp20_device_new(const struct hidpp_device *base, unsigned int idx,
struct hidpp_hid_report *reports, unsigned int num_reports);
void
hidpp20_device_destroy(struct hidpp20_device *device);

View File

@@ -115,7 +115,7 @@ main(int argc, char **argv)
error(1, errno, "Failed to open path %s", path);
hidpp_device_init(&base, fd);
dev = hidpp20_device_new(&base, 0xff);
dev = hidpp20_device_new(&base, 0xff, NULL, 0);
if (!dev)
error(1, 0, "Failed to open %s as a HID++ 2.0 device", path);

View File

@@ -91,7 +91,7 @@ main(int argc, char **argv)
error(1, errno, "Failed to open path %s", path);
hidpp_device_init(&base, fd);
dev = hidpp20_device_new(&base, 0xff);
dev = hidpp20_device_new(&base, 0xff, NULL, 0);
if (!dev)
error(1, 0, "Failed to open %s as a HID++ 2.0 device", path);