Merge pull request #38 from whot/wip/hidpp10-as-separate-library

hidpp10 as separate library
This commit is contained in:
bentiss
2015-10-16 16:43:13 -04:00
10 changed files with 416 additions and 161 deletions

1
.gitignore vendored
View File

@@ -47,3 +47,4 @@ test-context
test-device
test-*.log
ratbag-command
hidpp10-dump-page

View File

@@ -1,4 +1,5 @@
lib_LTLIBRARIES = libratbag.la
noinst_LTLIBRARIES = libhidpp10.la
include_HEADERS = \
libratbag.h
@@ -43,3 +44,11 @@ AM_CFLAGS = $(GCC_CFLAGS)
DISTCLEANFILES = libratbag-version.h
EXTRA_DIST = libratbag-version.h.in libratbag.sym
# The hidpp libraries are static libraries only for in-tree tools. No API
# stability is guaranteed here.
libhidpp10_la_SOURCES = \
hidpp-generic.h \
hidpp-generic.c \
hidpp10.h \
hidpp10.c

View File

@@ -197,12 +197,21 @@ hidpp10drv_test_hidraw(struct ratbag_device *device)
return ratbag_hidraw_has_report(device, REPORT_ID_SHORT);
}
static void
hidpp10_log(void *userdata, enum hidpp_log_priority priority, const char *format, va_list args)
{
struct ratbag_device *device = userdata;
log_msg_va(device->ratbag, priority, format, args);
}
static int
hidpp10drv_probe(struct ratbag_device *device)
{
int rc;
struct hidpp10drv_data *drv_data = NULL;
struct hidpp10_device *dev = NULL;
struct hidpp_device base;
rc = ratbag_find_hidraw(device, hidpp10drv_test_hidraw);
if (rc == -ENODEV) {
@@ -217,13 +226,15 @@ hidpp10drv_probe(struct ratbag_device *device)
}
drv_data = zalloc(sizeof(*drv_data));
hidpp_device_init(&base, device->hidraw.fd);
hidpp_device_set_log_handler(&base, hidpp10_log, HIDPP_LOG_PRIORITY_RAW, device);
/* We can treat all devices as wired devices here. If we talk to the
* correct hidraw device the kernel adjusts the device index for us,
* so even for unifying receiver devices we can just 0x00 as device
* index.
*/
dev = hidpp10_device_new_from_idx(device, WIRED_DEVICE_IDX);
dev = hidpp10_device_new_from_idx(&base, WIRED_DEVICE_IDX);
if (!dev) {
log_error(device->ratbag,

View File

@@ -30,6 +30,8 @@
#include "hidpp-generic.h"
#include <errno.h>
#include <poll.h>
#include <stddef.h>
#include "libratbag-private.h"
@@ -201,3 +203,117 @@ hidpp20_1b04_get_physical_mapping_name(uint16_t value)
return "UNKNOWN";
}
int
hidpp_write_command(struct hidpp_device *dev, uint8_t *cmd, int size)
{
int fd = dev->hidraw_fd;
int res;
if (size < 1 || !cmd || fd < 0)
return -EINVAL;
hidpp_log_buf_raw(dev, "hidpp write: ", cmd, size);
res = write(fd, cmd, size);
if (res < 0) {
res = -errno;
hidpp_log_error(dev, "Error: %s (%d)\n", strerror(-res), -res);
}
return res < 0 ? res : 0;
}
int
hidpp_read_response(struct hidpp_device *dev, uint8_t *buf, size_t size)
{
int fd = dev->hidraw_fd;
struct pollfd fds;
int rc;
if (size < 1 || !buf || fd < 0)
return -EINVAL;
fds.fd = fd;
fds.events = POLLIN;
rc = poll(&fds, 1, 1000);
if (rc == -1)
return -errno;
if (rc == 0)
return -ETIMEDOUT;
rc = read(fd, buf, size);
if (rc > 0)
hidpp_log_buf_raw(dev, "hidpp read: ", buf, rc);
return rc >= 0 ? rc : -errno;
}
void
hidpp_log(struct hidpp_device *dev,
enum hidpp_log_priority priority,
const char *format,
...)
{
va_list args;
if (dev->log_priority > priority)
return;
va_start(args, format);
dev->log_handler(dev->userdata, priority, format, args);
va_end(args);
}
void
hidpp_log_buffer(struct hidpp_device *dev,
enum hidpp_log_priority priority,
const char *header,
uint8_t *buf, size_t len)
{
_cleanup_free_ char *output_buf = NULL;
char *sep = "";
unsigned int i, n;
unsigned int buf_len;
buf_len = header ? strlen(header) : 0;
buf_len += len * 3;
buf_len += 1; /* terminating '\0' */
output_buf = zalloc(buf_len);
n = 0;
if (header)
n += snprintf_safe(output_buf, buf_len - n, "%s", header);
for (i = 0; i < len; ++i) {
n += snprintf_safe(&output_buf[n], buf_len - n, "%s%02x", sep, buf[i] & 0xFF);
sep = " ";
}
hidpp_log(dev, priority, "%s\n", output_buf);
}
static void
simple_log(void *userdata, enum hidpp_log_priority priority, const char *format, va_list args)
{
vprintf(format, args);
}
void
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);
}
void
hidpp_device_set_log_handler(struct hidpp_device *dev,
hidpp_log_handler log_handler,
enum hidpp_log_priority priority,
void *userdata)
{
dev->log_handler = log_handler;
dev->log_priority = priority;
dev->userdata = userdata;
}

View File

@@ -27,6 +27,8 @@
*/
#include <stdint.h>
#include <stdarg.h>
#include <stddef.h>
#ifndef HIDPP_GENERIC_H
#define HIDPP_GENERIC_H
@@ -64,6 +66,38 @@
#define ERR_INVALID_PARAM_VALUE 0x0B
#define ERR_WRONG_PIN_CODE 0x0C
/* Keep this in sync with ratbag_log_priority */
enum hidpp_log_priority {
/**
* Raw protocol messages. Using this log level results in *a lot* of
* output.
*/
HIDPP_LOG_PRIORITY_RAW = 10,
HIDPP_LOG_PRIORITY_DEBUG = 20,
HIDPP_LOG_PRIORITY_INFO = 30,
HIDPP_LOG_PRIORITY_ERROR = 40,
};
typedef void (*hidpp_log_handler)(void *userdata,
enum hidpp_log_priority priority,
const char *format, va_list args)
__attribute__ ((format (printf, 3, 0)));
struct hidpp_device {
int hidraw_fd;
void *userdata;
hidpp_log_handler log_handler;
enum hidpp_log_priority log_priority;
};
void
hidpp_device_init(struct hidpp_device *dev, int fd);
void
hidpp_device_set_log_handler(struct hidpp_device *dev,
hidpp_log_handler log_handler,
enum hidpp_log_priority priority,
void *userdata);
extern const char *hidpp_errors[0xFF];
const char *
@@ -81,4 +115,33 @@ hidpp20_1b04_get_logical_mapping(uint16_t value);
uint16_t
hidpp20_1b04_get_logical_control_id(const struct ratbag_button_action *action);
int
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_log(struct hidpp_device *dev,
enum hidpp_log_priority priority,
const char *format,
...)
__attribute__ ((format (printf, 3, 4)));
void
hidpp_log_buffer(struct hidpp_device *dev,
enum hidpp_log_priority priority,
const char *header,
uint8_t *buf, size_t len);
#define hidpp_log_raw(li_, ...) hidpp_log((li_), HIDPP_LOG_PRIORITY_RAW, __VA_ARGS__)
#define hidpp_log_debug(li_, ...) hidpp_log((li_), HIDPP_LOG_PRIORITY_DEBUG, __VA_ARGS__)
#define hidpp_log_info(li_, ...) hidpp_log((li_), HIDPP_LOG_PRIORITY_INFO, __VA_ARGS__)
#define hidpp_log_error(li_, ...) hidpp_log((li_), HIDPP_LOG_PRIORITY_ERROR, __VA_ARGS__)
#define hidpp_log_bug_kernel(li_, ...) hidpp((li_), HIDPP_LOG_PRIORITY_ERROR, "kernel bug: " __VA_ARGS__)
#define hidpp_log_buf_raw(li_, h_, buf_, len_) hidpp_log_buffer(li_, HIDPP_LOG_PRIORITY_RAW, h_, buf_, len_)
#define hidpp_log_buf_debug(li_, h_, buf_, len_) hidpp_log_buffer(li_, HIDPP_LOG_PRIORITY_DEBUG, h_, buf_, len_)
#define hidpp_log_buf_info(li_, h_, buf_, len_) hidpp_log_buffer(li_, HIDPP_LOG_PRIORITY_INFO, h_, buf_, len_)
#define hidpp_log_buf_error(li_, h_, buf_, len_) hidpp_log_buffer(li_, HIDPP_LOG_PRIORITY_ERROR, h_, buf_, len_)
#endif /* HIDPP_GENERIC_H */

View File

@@ -35,13 +35,29 @@
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <poll.h>
#include <unistd.h>
#include "hidpp10.h"
#include "libratbag-util.h"
#include "libratbag-hidraw.h"
#include "libratbag-private.h"
struct _hidpp10_message {
uint8_t report_id;
uint8_t device_idx;
uint8_t sub_id;
uint8_t address;
union {
uint8_t parameters[3];
uint8_t string[16];
};
} __attribute__((packed));
union hidpp10_message {
struct _hidpp10_message msg;
uint8_t data[LONG_MESSAGE_LENGTH];
};
#define ERROR_MSG(__hidpp_msg, idx) { \
.msg = { \
@@ -87,25 +103,8 @@ const char *device_types[0xFF] = {
};
static int
hidpp10_write_command(struct hidpp10_device *dev, uint8_t *cmd, int size)
{
struct ratbag_device *device = dev->ratbag_device;
int res = ratbag_hidraw_output_report(device, cmd, size);
if (res == 0)
return 0;
if (res < 0)
log_error(device->ratbag, "Error: %s (%d)\n", strerror(-res), -res);
return res;
}
int
hidpp10_request_command(struct hidpp10_device *dev, union hidpp10_message *msg)
{
struct ratbag_device *device = dev->ratbag_device;
struct ratbag *ratbag = device->ratbag;
union hidpp10_message read_buffer;
union hidpp10_message expected_header;
union hidpp10_message expected_error_dev = ERROR_MSG(msg, msg->msg.device_idx);
@@ -128,11 +127,11 @@ hidpp10_request_command(struct hidpp10_device *dev, union hidpp10_message *msg)
expected_header = *msg;
/* response message length doesn't depend on request length */
log_buf_raw(ratbag, " expected_header: ?? ", &expected_header.data[1], 3);
log_buf_raw(ratbag, " expected_error_dev: ", expected_error_dev.data, SHORT_MESSAGE_LENGTH);
hidpp_log_buf_raw(&dev->base, " expected_header: ?? ", &expected_header.data[1], 3);
hidpp_log_buf_raw(&dev->base, " expected_error_dev: ", expected_error_dev.data, SHORT_MESSAGE_LENGTH);
/* Send the message to the Device */
ret = hidpp10_write_command(dev, msg->data, command_size);
ret = hidpp_write_command(&dev->base, msg->data, command_size);
if (ret)
goto out_err;
@@ -141,12 +140,12 @@ hidpp10_request_command(struct hidpp10_device *dev, union hidpp10_message *msg)
* loop until we get the actual answer or an error code.
*/
do {
ret = ratbag_hidraw_read_input_report(device, read_buffer.data, LONG_MESSAGE_LENGTH);
ret = hidpp_read_response(&dev->base, read_buffer.data, LONG_MESSAGE_LENGTH);
/* Wait and retry if the USB timed out */
if (ret == -ETIMEDOUT) {
msleep(10);
ret = ratbag_hidraw_read_input_report(device, read_buffer.data, LONG_MESSAGE_LENGTH);
ret = hidpp_read_response(&dev->base, read_buffer.data, LONG_MESSAGE_LENGTH);
}
/* Overwrite the return device index with ours. The kernel
@@ -163,7 +162,7 @@ hidpp10_request_command(struct hidpp10_device *dev, union hidpp10_message *msg)
/* error */
if (!memcmp(read_buffer.data, expected_error_dev.data, 5)) {
hidpp_err = read_buffer.msg.parameters[1];
log_raw(ratbag,
hidpp_log_raw(&dev->base,
" HID++ error from the %s (%d): %s (%02x)\n",
read_buffer.msg.device_idx == RECEIVER_IDX ? "receiver" : "device",
read_buffer.msg.device_idx,
@@ -174,13 +173,13 @@ hidpp10_request_command(struct hidpp10_device *dev, union hidpp10_message *msg)
} while (ret > 0);
if (ret < 0) {
log_error(ratbag, " USB error: %s (%d)\n", strerror(-ret), -ret);
hidpp_log_error(&dev->base, " USB error: %s (%d)\n", strerror(-ret), -ret);
perror("write");
goto out_err;
}
if (!hidpp_err) {
log_buf_raw(ratbag, " received: ", read_buffer.data, ret);
hidpp_log_buf_raw(&dev->base, " received: ", read_buffer.data, ret);
/* copy the answer for the caller */
*msg = read_buffer;
}
@@ -194,9 +193,6 @@ out_err:
/* HID++ 1.0 commands 10 */
/* -------------------------------------------------------------------------- */
static inline void
hidpp10_dump_all_pages(struct hidpp10_device *dev);
/* -------------------------------------------------------------------------- */
/* 0x00: Enable HID++ Notifications */
/* -------------------------------------------------------------------------- */
@@ -221,7 +217,7 @@ hidpp10_get_hidpp_notifications(struct hidpp10_device *dev,
union hidpp10_message notifications = CMD_HIDPP_NOTIFICATIONS(idx, GET_REGISTER_REQ);
int res;
log_raw(dev->ratbag_device->ratbag, "Fetching HID++ notifications\n");
hidpp_log_raw(&dev->base, "Fetching HID++ notifications\n");
res = hidpp10_request_command(dev, &notifications);
if (res)
@@ -242,7 +238,7 @@ hidpp10_set_hidpp_notifications(struct hidpp10_device *dev,
union hidpp10_message notifications = CMD_HIDPP_NOTIFICATIONS(idx, SET_REGISTER_REQ);
int res;
log_raw(dev->ratbag_device->ratbag, "Setting HID++ notifications\n");
hidpp_log_raw(&dev->base, "Setting HID++ notifications\n");
notifications.msg.parameters[0] = reporting_flags & 0xFF;
notifications.msg.parameters[1] = (reporting_flags >> 8) & 0x1F;
@@ -277,7 +273,7 @@ hidpp10_get_individual_features(struct hidpp10_device *dev,
union hidpp10_message features = CMD_ENABLE_INDIVIDUAL_FEATURES(idx, GET_REGISTER_REQ);
int res;
log_raw(dev->ratbag_device->ratbag, "Fetching individual features\n");
hidpp_log_raw(&dev->base, "Fetching individual features\n");
res = hidpp10_request_command(dev, &features);
if (res)
@@ -300,7 +296,7 @@ hidpp10_set_individual_features(struct hidpp10_device *dev,
union hidpp10_message mode = CMD_ENABLE_INDIVIDUAL_FEATURES(idx, SET_REGISTER_REQ);
int res;
log_raw(dev->ratbag_device->ratbag, "Setting individual features\n");
hidpp_log_raw(&dev->base, "Setting individual features\n");
mode.msg.device_idx = dev->index;
@@ -510,7 +506,7 @@ hidpp10_get_current_profile(struct hidpp10_device *dev, int8_t *current_profile)
int res;
int8_t page;
log_raw(dev->ratbag_device->ratbag, "Fetching current profile\n");
hidpp_log_raw(&dev->base, "Fetching current profile\n");
res = hidpp10_request_command(dev, &profile);
if (res)
@@ -529,7 +525,6 @@ hidpp10_get_current_profile(struct hidpp10_device *dev, int8_t *current_profile)
int
hidpp10_get_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_profile *profile_return)
{
struct ratbag *ratbag = dev->ratbag_device->ratbag;
union _hidpp10_profile_data data;
struct _hidpp10_profile *p = &data.profile;
size_t i;
@@ -542,7 +537,7 @@ hidpp10_get_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_pr
* -> profiles are stored in the Flash */
number += 2;
log_raw(dev->ratbag_device->ratbag, "Fetching profile %d\n", number);
hidpp_log_raw(&dev->base, "Fetching profile %d\n", number);
for (i = 0; i < sizeof(data); i += 16) {
/* each sector contains 16 bytes of data */
@@ -603,56 +598,56 @@ hidpp10_get_profile(struct hidpp10_device *dev, int8_t number, struct hidpp10_pr
}
log_buf_raw(ratbag,
hidpp_log_buf_raw(&dev->base,
"+++++++++++++++++++ Profile data: +++++++++++++++++ \n",
data.data, 78);
log_raw(ratbag, "Profile %d:\n", number);
hidpp_log_raw(&dev->base, "Profile %d:\n", number);
for (i = 0; i < 5; i++) {
log_raw(ratbag,
hidpp_log_raw(&dev->base,
"DPI mode: %dx%d dpi\n",
profile.dpi_modes[i].xres,
profile.dpi_modes[i].yres);
log_raw(ratbag,
hidpp_log_raw(&dev->base,
"LED status: 1:%s 2:%s 3:%s 4:%s\n",
(p->dpi_modes[i].led1 & 0x2) ? "on" : "off",
(p->dpi_modes[i].led2 & 0x2) ? "on" : "off",
(p->dpi_modes[i].led3 & 0x2) ? "on" : "off",
(p->dpi_modes[i].led4 & 0x2) ? "on" : "off");
}
log_raw(ratbag, "Angle correction: %d\n", profile.angle_correction);
log_raw(ratbag, "Default DPI mode: %d\n", profile.default_dpi_mode);
log_raw(ratbag, "Refresh rate: %d\n", profile.refresh_rate);
hidpp_log_raw(&dev->base, "Angle correction: %d\n", profile.angle_correction);
hidpp_log_raw(&dev->base, "Default DPI mode: %d\n", profile.default_dpi_mode);
hidpp_log_raw(&dev->base, "Refresh rate: %d\n", profile.refresh_rate);
for (i = 0; i < 13; i++) {
union _hidpp10_button_binding *button = &p->buttons[i];
switch (button->any.type) {
case PROFILE_BUTTON_TYPE_BUTTON:
log_raw(ratbag,
hidpp_log_raw(&dev->base,
"Button %zd: button %d\n",
i,
ffs(hidpp10_get_unaligned_u16le(&button->button.button_flags_lsb)));
break;
case PROFILE_BUTTON_TYPE_KEYS:
log_raw(ratbag,
hidpp_log_raw(&dev->base,
"Button %zd: key %d modifier %x\n",
i,
button->keyboard_keys.key,
button->keyboard_keys.modifier_flags);
break;
case PROFILE_BUTTON_TYPE_SPECIAL:
log_raw(ratbag,
hidpp_log_raw(&dev->base,
"Button %zd: special %x\n",
i,
ffs(hidpp10_get_unaligned_u16le(&button->special.flags1)));
break;
case PROFILE_BUTTON_TYPE_CONSUMER_CONTROL:
log_raw(ratbag,
hidpp_log_raw(&dev->base,
"Button %zd: consumer: %x\n",
i,
hidpp10_get_unaligned_u16(&button->consumer_control.consumer_control1));
break;
case PROFILE_BUTTON_TYPE_DISABLED:
log_raw(ratbag, "Button %zd: disabled\n", i);
hidpp_log_raw(&dev->base, "Button %zd: disabled\n", i);
break;
default:
/* FIXME: this is the page number for the macro,
@@ -691,7 +686,7 @@ hidpp10_get_led_status(struct hidpp10_device *dev,
uint8_t *status = led_status.msg.parameters;
int res;
log_raw(dev->ratbag_device->ratbag, "Fetching LED status\n");
hidpp_log_raw(&dev->base, "Fetching LED status\n");
res = hidpp10_request_command(dev, &led_status);
if (res)
@@ -717,7 +712,7 @@ hidpp10_set_led_status(struct hidpp10_device *dev,
int res;
int i;
log_raw(dev->ratbag_device->ratbag, "Setting LED status\n");
hidpp_log_raw(&dev->base, "Setting LED status\n");
for (i = 0; i < 6; i++) {
switch (led[i]) {
@@ -768,7 +763,7 @@ hidpp10_get_led_intensity(struct hidpp10_device *dev,
uint8_t *intensity = led_intensity.msg.parameters;
int res;
log_raw(dev->ratbag_device->ratbag, "Fetching LED intensity\n");
hidpp_log_raw(&dev->base, "Fetching LED intensity\n");
res = hidpp10_request_command(dev, &led_intensity);
if (res)
@@ -793,7 +788,7 @@ hidpp10_set_led_intensity(struct hidpp10_device *dev,
uint8_t *intensity = led_intensity.msg.parameters;
int res;
log_raw(dev->ratbag_device->ratbag, "Setting LED intensity\n");
hidpp_log_raw(&dev->base, "Setting LED intensity\n");
intensity[0] = led_intensity_in_percent[0]/10 & 0xF;
intensity[0] |= (led_intensity_in_percent[1]/10 & 0xF) << 4;
@@ -832,7 +827,7 @@ hidpp10_get_led_color(struct hidpp10_device *dev,
union hidpp10_message led_color = CMD_LED_COLOR(idx, GET_REGISTER_REQ);
int res;
log_raw(dev->ratbag_device->ratbag, "Fetching LED color\n");
hidpp_log_raw(&dev->base, "Fetching LED color\n");
res = hidpp10_request_command(dev, &led_color);
if (res)
@@ -855,7 +850,7 @@ hidpp10_set_led_color(struct hidpp10_device *dev,
union hidpp10_message led_color = CMD_LED_COLOR(idx, SET_REGISTER_REQ);
int res;
log_raw(dev->ratbag_device->ratbag, "Setting LED color\n");
hidpp_log_raw(&dev->base, "Setting LED color\n");
led_color.msg.parameters[0] = red;
led_color.msg.parameters[1] = green;
@@ -888,7 +883,7 @@ hidpp10_get_optical_sensor_settings(struct hidpp10_device *dev,
union hidpp10_message sensor = CMD_OPTICAL_SENSOR_SETTINGS(idx, GET_REGISTER_REQ);
int res;
log_raw(dev->ratbag_device->ratbag, "Fetching optical sensor settings\n");
hidpp_log_raw(&dev->base, "Fetching optical sensor settings\n");
res = hidpp10_request_command(dev, &sensor);
if (res)
@@ -925,7 +920,7 @@ hidpp10_get_current_resolution(struct hidpp10_device *dev,
union hidpp10_message resolution = CMD_CURRENT_RESOLUTION(REPORT_ID_SHORT, idx, GET_LONG_REGISTER_REQ);
int res;
log_raw(dev->ratbag_device->ratbag, "Fetching current resolution\n");
hidpp_log_raw(&dev->base, "Fetching current resolution\n");
res = hidpp10_request_command(dev, &resolution);
if (res)
@@ -975,7 +970,7 @@ hidpp10_get_usb_refresh_rate(struct hidpp10_device *dev,
union hidpp10_message refresh = CMD_USB_REFRESH_RATE(idx, GET_REGISTER_REQ);
int res;
log_raw(dev->ratbag_device->ratbag, "Fetching USB refresh rate\n");
hidpp_log_raw(&dev->base, "Fetching USB refresh rate\n");
res = hidpp10_request_command(dev, &refresh);
if (res)
@@ -993,7 +988,7 @@ hidpp10_set_usb_refresh_rate(struct hidpp10_device *dev,
unsigned idx = dev->index;
union hidpp10_message refresh = CMD_USB_REFRESH_RATE(idx, GET_REGISTER_REQ);
log_raw(dev->ratbag_device->ratbag, "Setting USB refresh rate\n");
hidpp_log_raw(&dev->base, "Setting USB refresh rate\n");
refresh.msg.parameters[0] = 1000/rate;
@@ -1026,9 +1021,7 @@ hidpp10_read_memory(struct hidpp10_device *dev, uint8_t page, uint8_t offset,
if (page > 31)
return -EINVAL;
log_raw(dev->ratbag_device->ratbag,
"Reading memory page %d, offset %#x\n",
page, offset);
hidpp_log_raw(&dev->base, "Reading memory page %d, offset %#x\n", page, offset);
res = hidpp10_request_command(dev, &readmem);
if (res)
@@ -1039,30 +1032,6 @@ hidpp10_read_memory(struct hidpp10_device *dev, uint8_t page, uint8_t offset,
return 0;
}
static inline void
hidpp10_dump_all_pages(struct hidpp10_device *dev)
{
uint16_t page, offset;
uint8_t bytes[16];
int res;
log_info(dev->ratbag_device->ratbag, "::::::: Dumping memory :::::\n");
for (page = 0; page < 512; page++) {
log_info(dev->ratbag_device->ratbag, ":: page %d\n", page);
for (offset = 0; offset < 256; offset += 16) {
res = hidpp10_read_memory(dev, page, offset, bytes);
if (res != 0)
goto out;
log_buffer(dev->ratbag_device->ratbag, RATBAG_LOG_PRIORITY_INFO, " ", bytes, ARRAY_LENGTH(bytes));
}
}
out:
log_info(dev->ratbag_device->ratbag, "::::::: Dumping memory complete :::::\n");
}
/* -------------------------------------------------------------------------- */
/* 0xB2: Device Connection and Disconnection (Pairing) */
/* -------------------------------------------------------------------------- */
@@ -1125,7 +1094,7 @@ hidpp10_get_pairing_information(struct hidpp10_device *dev,
union hidpp10_message pairing_information = CMD_PAIRING_INFORMATION(idx, DEVICE_PAIRING_INFORMATION);
int res;
log_raw(dev->ratbag_device->ratbag, "Fetching pairing information\n");
hidpp_log_raw(&dev->base, "Fetching pairing information\n");
res = hidpp10_request_command(dev, &pairing_information);
if (res)
@@ -1147,7 +1116,7 @@ hidpp10_get_pairing_information_device_name(struct hidpp10_device *dev,
union hidpp10_message device_name = CMD_PAIRING_INFORMATION(idx, DEVICE_NAME);
int res;
log_raw(dev->ratbag_device->ratbag, "Fetching device name\n");
hidpp_log_raw(&dev->base, "Fetching device name\n");
res = hidpp10_request_command(dev, &device_name);
if (res)
@@ -1190,7 +1159,7 @@ hidpp10_get_firmare_information(struct hidpp10_device *dev,
int res;
uint8_t maj, min, build;
log_raw(dev->ratbag_device->ratbag, "Fetching firmware information\n");
hidpp_log_raw(&dev->base, "Fetching firmware information\n");
/*
* This may fail on some devices
@@ -1214,24 +1183,6 @@ hidpp10_get_firmare_information(struct hidpp10_device *dev,
return 0;
}
void hidpp10_list_devices(struct ratbag_device *device) {
struct hidpp10_device *dev;
int i;
for (i = 0; i < 6; ++i) {
dev = hidpp10_device_new_from_idx(device, i);
if (!dev)
continue;
log_info(device->ratbag, "[%d] %s %s (Wireless PID: %04x)\n",
i,
device_types[dev->device_type] ? device_types[dev->device_type] : "",
dev->name, dev->wpid);
hidpp10_device_destroy(dev);
}
}
/* -------------------------------------------------------------------------- */
/* general device handling */
/* -------------------------------------------------------------------------- */
@@ -1241,26 +1192,32 @@ hidpp10_get_device_info(struct hidpp10_device *dev)
uint32_t feature_mask, notifications;
uint8_t reflect;
int i;
uint16_t xres, yres;
uint16_t refresh_rate;
enum hidpp10_led_status led[6];
int8_t current_profile;
struct hidpp10_profile profiles[HIDPP10_NUM_PROFILES];
hidpp10_get_individual_features(dev, &feature_mask);
hidpp10_get_hidpp_notifications(dev, &notifications);
hidpp10_get_current_resolution(dev, &dev->xres, &dev->yres);
hidpp10_get_led_status(dev, dev->led);
hidpp10_get_usb_refresh_rate(dev, &dev->refresh_rate);
hidpp10_get_current_resolution(dev, &xres, &yres);
hidpp10_get_led_status(dev, led);
hidpp10_get_usb_refresh_rate(dev, &refresh_rate);
hidpp10_get_optical_sensor_settings(dev, &reflect);
hidpp10_get_current_profile(dev, &dev->current_profile);
hidpp10_get_current_profile(dev, &current_profile);
for (i = 0; i < HIDPP10_NUM_PROFILES; i++)
hidpp10_get_profile(dev, i, &dev->profiles[i]);
hidpp10_get_profile(dev, i, &profiles[i]);
return 0;
}
static struct hidpp10_device*
hidpp10_device_new(struct ratbag_device *device, int index)
hidpp10_device_new(const struct hidpp_device *base,
int index)
{
struct hidpp10_device *dev;
@@ -1269,19 +1226,19 @@ hidpp10_device_new(struct ratbag_device *device, int index)
return NULL;
dev->index = index;
dev->ratbag_device = device;
dev->base = *base;
return dev;
}
struct hidpp10_device*
hidpp10_device_new_from_wpid(struct ratbag_device* device, uint16_t wpid)
hidpp10_device_new_from_wpid(const struct hidpp_device *base, uint16_t wpid)
{
struct hidpp10_device *dev;
int i;
for (i = 1; i < 7; i++) {
dev = hidpp10_device_new_from_idx(device, i);
dev = hidpp10_device_new_from_idx(base, i);
if (!dev)
continue;
@@ -1295,11 +1252,11 @@ hidpp10_device_new_from_wpid(struct ratbag_device* device, uint16_t wpid)
}
struct hidpp10_device*
hidpp10_device_new_from_idx(struct ratbag_device *device, int idx)
hidpp10_device_new_from_idx(const struct hidpp_device *base, int idx)
{
struct hidpp10_device *dev;
dev = hidpp10_device_new(device, idx);
dev = hidpp10_device_new(base, idx);
if (!dev)
return NULL;

View File

@@ -33,33 +33,26 @@
#include <stdbool.h>
#include "hidpp-generic.h"
#include "libratbag-private.h"
#include "libratbag.h"
struct hidpp10_device;
/* FIXME: that's what my G500s supports, but only pages 3-5 are valid.
* 0 is zeroed, 1 and 2 are garbage, all above 6 is garbage */
#define HIDPP10_NUM_PROFILES 3
struct _hidpp10_message {
uint8_t report_id;
uint8_t device_idx;
uint8_t sub_id;
uint8_t address;
union {
uint8_t parameters[3];
uint8_t string[16];
};
} __attribute__((packed));
union hidpp10_message {
struct _hidpp10_message msg;
uint8_t data[LONG_MESSAGE_LENGTH];
struct hidpp10_device {
struct hidpp_device base;
unsigned index;
uint16_t wpid;
};
void hidpp10_device_destroy(struct hidpp10_device *dev);
struct hidpp10_device*
hidpp10_device_new_from_wpid(const struct hidpp_device *base,
uint16_t wpid);
struct hidpp10_device*
hidpp10_device_new_from_idx(const struct hidpp_device *base,
int idx);
int hidpp10_request_command(struct hidpp10_device *device, union hidpp10_message *msg);
void hidpp10_list_devices(struct ratbag_device *device);
struct hidpp10_device *hidpp10_device_new_from_wpid(struct ratbag_device *device, uint16_t wpid);
struct hidpp10_device *hidpp10_device_new_from_idx(struct ratbag_device *device, int idx);
void
hidpp10_device_destroy(struct hidpp10_device *dev);
/* -------------------------------------------------------------------------- */
/* 0x00: Enable HID++ Notifications */
@@ -503,24 +496,4 @@ hidpp10_get_firmare_information(struct hidpp10_device *dev,
uint8_t *minor,
uint8_t *build_number);
/* FIXME: that's what my G500s supports, but only pages 3-5 are valid.
* 0 is zeroed, 1 and 2 are garbage, all above 6 is garbage */
#define HIDPP10_NUM_PROFILES 3
struct hidpp10_device {
struct ratbag_device *ratbag_device;
unsigned index;
char name[15];
uint16_t wpid;
uint8_t report_interval;
uint8_t device_type;
uint8_t fw_major;
uint8_t fw_minor;
uint8_t build;
uint16_t xres, yres;
uint16_t refresh_rate;
enum hidpp10_led_status led[6];
int8_t current_profile;
struct hidpp10_profile profiles[HIDPP10_NUM_PROFILES];
};
#endif /* HIDPP_10_H */

View File

@@ -85,6 +85,10 @@ cleanup_free(void *p) {
free(*(void**)p);
}
static inline void
cleanup_close(int *p) {
close(*p);
}
static inline void
cleanup_udev_unref(struct udev **udev) {
if (*udev)
@@ -99,6 +103,7 @@ cleanup_udev_device_unref(struct udev_device **udev_device) {
#define _cleanup_(x) __attribute__((cleanup(x)))
#define _cleanup_free_ _cleanup_(cleanup_free)
#define _cleanup_close_ _cleanup_(cleanup_close)
#define _cleanup_udev_unref_ _cleanup_(cleanup_udev_unref)
#define _cleanup_udev_device_unref_ _cleanup_(cleanup_udev_device_unref)

View File

@@ -1,4 +1,4 @@
noinst_PROGRAMS =
noinst_PROGRAMS = hidpp10-dump-page
bin_PROGRAMS = ratbag-command
noinst_LTLIBRARIES = libshared.la
@@ -16,3 +16,8 @@ ratbag_command_SOURCES = ratbag-command.c
ratbag_command_LDADD = ../src/libratbag.la libshared.la $(LIBUDEV_LIBS) $(LIBEVDEV_LIBS)
ratbag_command_LDFLAGS = -no-install
ratbag_command_CFLAGS = $(LIBUDEV_CFLAGS) $(LIBEVDEV_CFLAGS)
hidpp10_dump_page_SOURCES = hidpp10-dump-page.c
hidpp10_dump_page_LDADD = ../src/libhidpp10.la
hidpp10_dump_page_LDFLAGS = -no-install
hidpp10_dump_page_CFLAGS = -I$(top_srcdir)/src

115
tools/hidpp10-dump-page.c Normal file
View File

@@ -0,0 +1,115 @@
/*
* Copyright © 2015 Red Hat, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <config.h>
#include <errno.h>
#include <error.h>
#include <fcntl.h>
#include <hidpp10.h>
#include <libratbag-util.h>
static inline int
dump_page(struct hidpp10_device *dev, size_t page, size_t offset)
{
int rc = 0;
uint8_t bytes[16];
while (offset < 256) {
hidpp_log_info(&dev->base, "page 0x%02zx off 0x%02zx: ", page, offset);
rc = hidpp10_read_memory(dev, page, offset, bytes);
if (rc != 0)
break;
hidpp_log_buffer(&dev->base, HIDPP_LOG_PRIORITY_INFO, " ", bytes, ARRAY_LENGTH(bytes));
offset += 16;
}
return rc;
}
static inline int
dump_all_pages(struct hidpp10_device *dev)
{
uint8_t page;
int rc = 0;
for (page = 0; page < 31; page++) {
rc = dump_page(dev, page, 0);
if (rc != 0)
break;
}
/* We dumped at least one page successfully and get EAGAIN, so we're
* on the last page. Overwrite the last line with a blank one so it
* doesn't look like an error */
if (page > 0 && rc == EAGAIN) {
hidpp_log_info(&dev->base, "\r \n");
rc = 0;
}
return rc;
}
void
usage(void)
{
printf("Usage: %s [page] [offset] /dev/hidraw0\n", program_invocation_short_name);
}
int
main(int argc, char **argv)
{
_cleanup_close_ int fd;
const char *path;
size_t page = 0, offset = 0;
struct hidpp10_device *dev = NULL;
struct hidpp_device base;
int rc;
if (argc < 2 || argc > 4) {
usage();
return 1;
}
path = argv[argc - 1];
fd = open(path, O_RDWR);
if (fd < 0)
error(1, errno, "Failed to open path %s", path);
hidpp_device_init(&base, fd);
dev = hidpp10_device_new_from_idx(&base, WIRED_DEVICE_IDX);
if (argc == 2)
rc = dump_all_pages(dev);
else {
page = atoi(argv[1]);
if (argc > 3)
offset = atoi(argv[2]);
rc = dump_page(dev, page, offset);
}
hidpp10_device_destroy(dev);
return rc;
}