1
0
forked from drath/libratbag

ibratbag-hidraw: add optional filter to hidraw read

Currently, these functions will read and timeout after 1s if
no packets were received. The issue with this is that a lot of times we
may catch unrelated packets, such as mouse or keyboard changes.
To solve this, this patch adds a new optional filter argument, when a filter
is passed the functions now will keep reading packets until a valid packet is found.
The filter argument is user written function that returns true or false.

Co-authored-by: Filipe Laíns <lains@riseup.net>
Signed-off-by: Rafael Silva <perigoso@riseup.net>
This commit is contained in:
Rafael Silva
2021-11-10 21:08:00 +00:00
committed by Peter Hutterer
parent 6dbaeaf506
commit ae53f6123b
4 changed files with 61 additions and 20 deletions

View File

@@ -159,6 +159,22 @@ openinput_get_report_size(unsigned int report)
}
}
static bool
openinput_report_filter(uint8_t *buf, size_t len)
{
if (len < 1)
return false;
switch(buf[0]) {
case OI_REPORT_SHORT:
return len == OI_REPORT_SHORT_SIZE;
case OI_REPORT_LONG:
return len == OI_REPORT_LONG_SIZE;
default:
return false;
}
}
static int
openinput_send_report(struct ratbag_device *device, struct oi_report_t *report)
{
@@ -175,7 +191,7 @@ openinput_send_report(struct ratbag_device *device, struct oi_report_t *report)
return ret;
}
ret = ratbag_hidraw_read_input_report(device, buffer, OI_REPORT_MAX_SIZE);
ret = ratbag_hidraw_read_input_report(device, buffer, OI_REPORT_MAX_SIZE, openinput_report_filter);
if (ret < 0) {
log_error(device->ratbag, "openinput: failed to read data from device (%s)\n",
strerror(-ret));

View File

@@ -234,7 +234,7 @@ steelseries_get_firmware_version(struct ratbag_device *device)
if (ret < 0)
return ret;
ret = ratbag_hidraw_read_input_report_index(device, buf, sizeof(buf), STEELSERIES_INPUT_HIDRAW);
ret = ratbag_hidraw_read_input_report_index(device, buf, sizeof(buf), STEELSERIES_INPUT_HIDRAW, NULL);
if (ret < 0)
return ret;
@@ -278,7 +278,7 @@ steelseries_read_settings(struct ratbag_device *device)
if (ret < 0)
return ret;
ret = ratbag_hidraw_read_input_report_index(device, buf, STEELSERIES_REPORT_SIZE, STEELSERIES_INPUT_HIDRAW);
ret = ratbag_hidraw_read_input_report_index(device, buf, STEELSERIES_REPORT_SIZE, STEELSERIES_INPUT_HIDRAW, NULL);
if (ret < 0)
return ret;

View File

@@ -1642,16 +1642,19 @@ 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)
ratbag_hidraw_read_input_report(struct ratbag_device *device, uint8_t *buf, size_t len,
ratbagd_hidraw_filter_t filter)
{
return ratbag_hidraw_read_input_report_index(device, buf, len, 0);
return ratbag_hidraw_read_input_report_index(device, buf, len, 0, filter);
}
int
ratbag_hidraw_read_input_report_index(struct ratbag_device *device, uint8_t *buf, size_t len, int hidrawno)
ratbag_hidraw_read_input_report_index(struct ratbag_device *device, uint8_t *buf, size_t len, int hidrawno,
ratbagd_hidraw_filter_t filter)
{
int rc;
int rc, nfds;
struct pollfd fds;
int ts, ts_end;
assert(hidrawno >= 0 && hidrawno < MAX_HIDRAW);
@@ -1661,17 +1664,32 @@ ratbag_hidraw_read_input_report_index(struct ratbag_device *device, uint8_t *buf
fds.fd = device->hidraw[hidrawno].fd;
fds.events = POLLIN;
rc = poll(&fds, 1, 1000);
if (rc == -1)
return -errno;
/* convert to ms */
ts = now(CLOCK_MONOTONIC_RAW) / 1000 / 1000;
ts_end = ts + 1000; /* end in now + 1000ms */
if (rc == 0)
return -ETIMEDOUT;
while (ts < ts_end) {
nfds = poll(&fds, 1, ts_end - ts); /* poll for the remainder of timeout */
rc = read(device->hidraw[hidrawno].fd, buf, len);
if (nfds < 0)
return -errno;
if (rc > 0)
log_buf_raw(device->ratbag, "input report: ", buf, rc);
if (nfds > 0) {
rc = read(device->hidraw[hidrawno].fd, buf, len);
return rc >= 0 ? rc : -errno;
if (rc < 0)
return -errno;
if (rc > 0) {
if(!filter || (filter && filter(buf, rc))) {
log_buf_raw(device->ratbag, "input report: ", buf, rc);
return rc;
}
}
}
ts = now(CLOCK_MONOTONIC_RAW) / 1000 / 1000;
}
return -ETIMEDOUT;
}

View File

@@ -47,6 +47,8 @@ struct ratbag_hidraw {
char *sysname;
};
typedef bool (*ratbagd_hidraw_filter_t)(uint8_t *buf, size_t len);
/**
* Open the hidraw device associated with the device.
*
@@ -162,27 +164,32 @@ int ratbag_hidraw_output_report(struct ratbag_device *device, uint8_t *buf, size
/**
* Read an input report from the device
* Optional filter function can be provided, when the filter returns false the packet is ignored
*
* @param device the ratbag device
* @param[out] buf resulting raw data
* @param len length of buf
* @param filter filter function
*
* @return count of data transfered, or a negative errno on error
*/
int ratbag_hidraw_read_input_report(struct ratbag_device *device, uint8_t *buf, size_t len);
int ratbag_hidraw_read_input_report(struct ratbag_device *device, uint8_t *buf, size_t len,
ratbagd_hidraw_filter_t filter);
/**
* Read an input report from the device from a specific hidraw index
* Optional filter function can be provided, when the filter returns false the packet is ignored
*
* @param device the ratbag device
* @param[out] buf resulting raw data
* @param len length of buf
* @param interal index of hidraw array
* @param hidrawno index of hidraw array
* @param filter filter function
*
* @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);
int ratbag_hidraw_read_input_report_index(struct ratbag_device *device, uint8_t *buf, size_t len, int hidrawno,
ratbagd_hidraw_filter_t filter);
/**
* Tells if a given device has the specified report ID.