mirror of
https://github.com/libratbag/libratbag.git
synced 2026-11-07 23:23:52 +01:00
Add first hid++ 2.0 protocol support
The Logitech devices talk HID++, and we need a lib to handle that. The first implemented command is the get protocol version which allows to know if the device is using hid++ 1.0 or 2.0. Signed-off-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
This commit is contained in:
@@ -8,6 +8,8 @@ libratbag_la_SOURCES = \
|
||||
driver-logitech-unifying.c \
|
||||
hidpp10.c \
|
||||
hidpp10.h \
|
||||
hidpp20.c \
|
||||
hidpp20.h \
|
||||
libratbag.c \
|
||||
libratbag.h \
|
||||
libratbag-hidraw.c \
|
||||
|
||||
@@ -29,6 +29,12 @@
|
||||
* https://drive.google.com/folderview?id=0BxbRzx7vEV7eWmgwazJ3NUFfQ28&usp=sharing
|
||||
*/
|
||||
|
||||
/*
|
||||
* for this driver to work, you need a kernel >= v3.19 or one which contains
|
||||
* 925f0f3ed24f98b40c28627e74ff3e7f9d1e28bc ("HID: logitech-dj: allow transfer
|
||||
* of HID++ reports from/to the correct dj device")
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <linux/types.h>
|
||||
@@ -37,6 +43,7 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "hidpp20.h"
|
||||
|
||||
#include "libratbag-private.h"
|
||||
#include "libratbag-hidraw.h"
|
||||
@@ -108,6 +115,15 @@ unifying_probe(struct ratbag_device *device, const struct ratbag_id id)
|
||||
drv_data->proto_major = 1;
|
||||
drv_data->proto_minor = 0;
|
||||
|
||||
rc = hidpp20_root_get_protocol_version(device, &drv_data->proto_major, &drv_data->proto_minor);
|
||||
if (rc) {
|
||||
/* communication error, best to ignore the device */
|
||||
rc = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
log_info(device->ratbag, "'%s' is using protocol v%d.%d\n", ratbag_device_get_name(device), drv_data->proto_major, drv_data->proto_minor);
|
||||
|
||||
ratbag_set_drv_data(device, drv_data);
|
||||
|
||||
device->num_profiles = 1;
|
||||
|
||||
160
src/hidpp20.c
Normal file
160
src/hidpp20.c
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* HID++ 2.0 library.
|
||||
*
|
||||
* Copyright 2015 Benjamin Tissoires <benjamin.tissoires@gmail.com>
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on the HID++ 2.0 documentation provided by Nestor Lopez Casado at:
|
||||
* https://drive.google.com/folderview?id=0BxbRzx7vEV7eWmgwazJ3NUFfQ28&usp=sharing
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hidpp20.h"
|
||||
#include "libratbag.h"
|
||||
#include "libratbag-hidraw.h"
|
||||
#include "libratbag-util.h"
|
||||
#include "libratbag-private.h"
|
||||
|
||||
static int
|
||||
hidpp20_write_command(struct ratbag_device *device, uint8_t *cmd, int size)
|
||||
{
|
||||
int res = ratbag_hidraw_output_report(device, cmd, size);
|
||||
|
||||
if (res == 0)
|
||||
return 0;
|
||||
|
||||
if (res < 0)
|
||||
log_error(device->ratbag, "Error: %d\n", errno);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
hidpp20_request_command(struct ratbag_device *device, union hidpp20_message *msg)
|
||||
{
|
||||
struct ratbag *ratbag = device->ratbag;
|
||||
union hidpp20_message read_buffer;
|
||||
int ret;
|
||||
uint8_t hidpp_err = 0;
|
||||
size_t msg_len;
|
||||
|
||||
msg_len = msg->msg.report_id == REPORT_ID_SHORT ? SHORT_MESSAGE_LENGTH : LONG_MESSAGE_LENGTH;
|
||||
|
||||
log_buf_debug(ratbag, "sending: ", msg->data, msg_len);
|
||||
|
||||
/* Send the message to the Device */
|
||||
ret = hidpp20_write_command(device, msg->data, msg_len);
|
||||
if (ret)
|
||||
goto out_err;
|
||||
|
||||
/*
|
||||
* Now read the answers from the device:
|
||||
* 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);
|
||||
log_buf_debug(ratbag, " *** received: ", read_buffer.data, ret);
|
||||
|
||||
if (read_buffer.msg.report_id != REPORT_ID_SHORT &&
|
||||
read_buffer.msg.report_id != REPORT_ID_LONG)
|
||||
continue;
|
||||
|
||||
/* actual answer */
|
||||
if (read_buffer.msg.sub_id == msg->msg.sub_id &&
|
||||
read_buffer.msg.address == msg->msg.address)
|
||||
break;
|
||||
|
||||
/* error */
|
||||
if (read_buffer.msg.sub_id == __ERROR_MSG &&
|
||||
(read_buffer.msg.parameters[0] & 0x0f) == (read_buffer.msg.address & 0x0f)) {
|
||||
hidpp_err = read_buffer.msg.parameters[1];
|
||||
log_error(ratbag,
|
||||
" HID++ error from the device (%d): %s (%02x)\n",
|
||||
read_buffer.msg.device_idx,
|
||||
hidpp_errors[hidpp_err] ? hidpp_errors[hidpp_err] : "Undocumented error code",
|
||||
hidpp_err);
|
||||
break;
|
||||
}
|
||||
} while (ret > 0);
|
||||
|
||||
if (ret < 0) {
|
||||
log_error(ratbag, " USB error: %d\n", errno);
|
||||
perror("write");
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
if (!hidpp_err) {
|
||||
log_buf_debug(ratbag, " received: ", read_buffer.data, ret);
|
||||
/* copy the answer for the caller */
|
||||
*msg = read_buffer;
|
||||
}
|
||||
|
||||
ret = hidpp_err;
|
||||
|
||||
out_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* 0x0000: Root */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#define HIDPP_PAGE_ROOT 0x0000
|
||||
#define HIDPP_PAGE_ROOT_IDX 0x00
|
||||
|
||||
#define CMD_ROOT_GET_FEATURE 0x08
|
||||
#define CMD_ROOT_GET_PROTOCOL_VERSION 0x18
|
||||
|
||||
int
|
||||
hidpp20_root_get_protocol_version(struct ratbag_device *device,
|
||||
unsigned *major,
|
||||
unsigned *minor)
|
||||
{
|
||||
int rc;
|
||||
union hidpp20_message msg = {
|
||||
.msg.report_id = REPORT_ID_SHORT,
|
||||
.msg.device_idx = 0xff,
|
||||
.msg.sub_id = HIDPP_PAGE_ROOT_IDX,
|
||||
.msg.address = CMD_ROOT_GET_PROTOCOL_VERSION,
|
||||
};
|
||||
|
||||
rc = hidpp20_request_command(device, &msg);
|
||||
|
||||
if (rc == ERR_INVALID_SUBID) {
|
||||
*major = 1;
|
||||
*minor = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
*major = msg.msg.parameters[0];
|
||||
*minor = msg.msg.parameters[1];
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
60
src/hidpp20.h
Normal file
60
src/hidpp20.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* HID++ 2.0 library - headers file.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Based on the HID++ 2.0 documentation provided by Nestor Lopez Casado at:
|
||||
* https://drive.google.com/folderview?id=0BxbRzx7vEV7eWmgwazJ3NUFfQ28&usp=sharing
|
||||
*/
|
||||
|
||||
#ifndef HIDPP_20_H
|
||||
#define HIDPP_20_H
|
||||
|
||||
#include "hidpp10.h"
|
||||
|
||||
extern const char *hidpp_errors[0xFF];
|
||||
|
||||
struct _hidpp20_message {
|
||||
uint8_t report_id;
|
||||
uint8_t device_idx;
|
||||
uint8_t sub_id;
|
||||
uint8_t address;
|
||||
uint8_t parameters[LONG_MESSAGE_LENGTH - 4U];
|
||||
} __attribute__((packed));
|
||||
|
||||
union hidpp20_message {
|
||||
struct _hidpp20_message msg;
|
||||
uint8_t data[LONG_MESSAGE_LENGTH];
|
||||
};
|
||||
|
||||
int hidpp20_request_command(struct ratbag_device *device, union hidpp20_message *msg);
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* 0x0000: Root */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
int hidpp20_root_get_protocol_version(struct ratbag_device *device,
|
||||
unsigned *major,
|
||||
unsigned *minor);
|
||||
|
||||
|
||||
#endif /* HIDPP_20_H */
|
||||
Reference in New Issue
Block a user