From 99f7936cc47f6fc41540ac870bf6cc5961ab3c09 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 14 Aug 2015 22:54:56 -0400 Subject: [PATCH] Add ratbag_hidraw_raw_request to get/set feature reports Signed-off-by: Benjamin Tissoires --- src/etekcity.c | 35 ++++++++++++++++++++++++++++++++++- src/libratbag-hidraw.c | 41 +++++++++++++++++++++++++++++++++++++++++ src/libratbag-hidraw.h | 24 ++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 1 deletion(-) diff --git a/src/etekcity.c b/src/etekcity.c index 9dc32e7b..9f9d5292 100644 --- a/src/etekcity.c +++ b/src/etekcity.c @@ -30,10 +30,27 @@ #include "libratbag-private.h" #include "libratbag-hidraw.h" +static int +etekcity_current_profile(struct ratbag *ratbag) +{ + __u8 buf[3]; + int ret; + + ret = ratbag_hidraw_raw_request(ratbag, 5, buf, sizeof(buf), + HID_FEATURE_REPORT, HID_REQ_GET_REPORT); + if (ret < 0) + return ret; + + if (ret != 3) + return -EIO; + + return buf[2]; +} + static int etekcity_probe(struct ratbag *ratbag, const struct ratbag_id id) { - int rc; + int rc, current_profile; log_debug(ratbag->libratbag, "data: %d\n", id.data); @@ -46,6 +63,22 @@ etekcity_probe(struct ratbag *ratbag, const struct ratbag_id id) return -ENODEV; } + rc = etekcity_current_profile(ratbag); + if (rc < 0) { + log_error(ratbag->libratbag, + "Can't talk to the mouse: '%s' (%d)\n", + strerror(-rc), + rc); + return -ENODEV; + } + + current_profile = rc; + + log_info(ratbag->libratbag, + "'%s' is in profile %d\n", + ratbag_get_name(ratbag), + current_profile); + return 0; } diff --git a/src/libratbag-hidraw.c b/src/libratbag-hidraw.c index d8c2ebc6..402c44ed 100644 --- a/src/libratbag-hidraw.c +++ b/src/libratbag-hidraw.c @@ -25,10 +25,16 @@ #include #include #include +#include #include "libratbag-hidraw.h" #include "libratbag-private.h" +/* defined in include/linux.hid.h in the kernel, but not exported */ +#ifndef HID_MAX_BUFFER_SIZE +#define HID_MAX_BUFFER_SIZE 4096 /* 4kb */ +#endif + int ratbag_open_hidraw(struct ratbag *ratbag) { @@ -64,3 +70,38 @@ err: close(fd); return -errno; } + +int ratbag_hidraw_raw_request(struct ratbag *ratbag, unsigned char reportnum, + __u8 *buf, size_t len, unsigned char rtype, int reqtype) +{ + char tmp_buf[HID_MAX_BUFFER_SIZE]; + int rc; + + if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf || ratbag->hidraw_fd < 0) + return -EINVAL; + + if (rtype != HID_FEATURE_REPORT) + return -ENOTSUP; + + switch (reqtype) { + case HID_REQ_GET_REPORT: + memset(tmp_buf, 0, len); + tmp_buf[0] = reportnum; + + rc = ioctl(ratbag->hidraw_fd, HIDIOCGFEATURE(len), tmp_buf); + if (rc < 0) + return -errno; + + memcpy(buf, tmp_buf, rc); + return rc; + case HID_REQ_SET_REPORT: + buf[0] = reportnum; + rc = ioctl(ratbag->hidraw_fd, HIDIOCSFEATURE(len), buf); + if (rc < 0) + return -errno; + + return rc; + } + + return -EINVAL; +} diff --git a/src/libratbag-hidraw.h b/src/libratbag-hidraw.h index 358b6a99..53a94d30 100644 --- a/src/libratbag-hidraw.h +++ b/src/libratbag-hidraw.h @@ -24,8 +24,32 @@ #ifndef LIBRATBAG_HIDRAW_H #define LIBRATBAG_HIDRAW_H +#include + #include "libratbag.h" +/* defined in the internal hid API in the kernel */ +#define HID_INPUT_REPORT 0 +#define HID_OUTPUT_REPORT 1 +#define HID_FEATURE_REPORT 2 + int ratbag_open_hidraw(struct ratbag *ratbag); +/** + * ratbag_hidraw_raw_request - send report request to device + * + * @ratbag: ratbag device + * @reportnum: report ID + * @buf: in/out data to transfer + * @len: length of buf + * @rtype: HID report type + * @reqtype: HID_REQ_GET_REPORT or HID_REQ_SET_REPORT + * + * @return: count of data transfered, negative if error + * + * Same behavior as hid_hw_request, but with raw buffers instead. + */ +int ratbag_hidraw_raw_request(struct ratbag *ratbag, unsigned char reportnum, + __u8 *buf, size_t len, unsigned char rtype, int reqtype); + #endif /* LIBRATBAG_HIDRAW_H */