1
0
forked from drath/libratbag

Start moving uLogitech files into libratbag proper

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
Peter Hutterer
2015-08-20 11:19:03 +10:00
parent 93ca4e24d4
commit f36f4d22a7
6 changed files with 10 additions and 7 deletions

View File

@@ -1,59 +0,0 @@
/*
* debug definitions.
*
* Copyright 2013 Benjamin Tissoires <benjamin.tissoires@gmail.com>
* Copyright 2013 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.
*/
#ifndef DEBUG_H
#define DEBUG_H
#define DEBUG_LVL 0
#if DEBUG_LVL > 0
static void pr_buffer(__u8 *buffer, int size) {
char *sep = "";
int i;
if (size < 0)
return;
for (i = 0; i < size; ++i) {
printf("%s%02x", sep, buffer[i] & 0xFF);
sep = " ";
}
printf("\n");
}
#else
#define pr_buffer(buffer, size) do {} while (0)
#endif
#if DEBUG_LVL > 0
#define pr_dbg(fmt, arg...) \
printf(fmt, ##arg)
#else /* DEBUG_LVL > 0 */
#define pr_dbg(fmt, arg...) \
do {} while(0);
#endif /* DEBUG_LVL > 0 */
#endif /* DEBUG_H */

View File

@@ -1,167 +0,0 @@
/*
* HID++ 1.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++ 1.0 documentation provided by Nestor Lopez Casado at:
* https://drive.google.com/folderview?id=0BxbRzx7vEV7eWmgwazJ3NUFfQ28&usp=sharing
*/
#include <debug.h>
#include <unifying.h>
#ifndef HIDPP_10_H
#define HIDPP_10_H
#define RECEIVER_IDX 0xFF
#define REPORT_ID_SHORT 0x10
#define REPORT_ID_LONG 0x11
#define SHORT_MESSAGE_LENGTH 7
#define LONG_MESSAGE_LENGTH 20
#define SET_REGISTER_REQ 0x80
#define SET_REGISTER_RSP 0x80
#define GET_REGISTER_REQ 0x81
#define GET_REGISTER_RSP 0x81
#define SET_LONG_REGISTER_REQ 0x82
#define SET_LONG_REGISTER_RSP 0x82
#define GET_LONG_REGISTER_REQ 0x83
#define GET_LONG_REGISTER_RSP 0x83
#define __ERROR_MSG 0x8F
#define __CMD_ENABLE_INDIVIDUAL_FEATURES 0x01
#define FEATURE_BIT_R0_SPECIAL_BUTTON_FUNCTION 1
#define FEATURE_BIT_R0_ENHANCED_KEY_USAGE 2
#define FEATURE_BIT_R0_FAST_FORWARD_REWIND 3
#define FEATURE_BIT_R0_SCROLLING_ACCELERATION 6
#define FEATURE_BIT_R0_BUTTONS_CONTROL_THE_RESOLUTION 7
#define FEATURE_BIT_R2_INHIBIT_LOCK_KEY_SOUND 0
#define FEATURE_BIT_R2_3D_ENGINE 2
#define FEATURE_BIT_R2_HOST_SW_CONTROLS_LEDS 3
#define __CMD_DEVICE_CONNECTION_DISCONNECTION 0xB2
#define CONNECT_DEVICES_OPEN_LOCK 1
#define CONNECT_DEVICES_CLOSE_LOCK 2
#define CONNECT_DEVICES_DISCONNECT 3
#define __CMD_PAIRING_INFORMATION 0xB5
#define DEVICE_PAIRING_INFORMATION 0x20
#define DEVICE_EXTENDED_PAIRING_INFORMATION 0x30
#define DEVICE_NAME 0x40
#define __CMD_DEVICE_FIRMWARE_INFORMATION 0xF1
#define FIRMWARE_INFO_ITEM_FW_NAME_AND_VERSION(MCU) ((MCU - 1) << 4 | 0x01)
#define FIRMWARE_INFO_ITEM_FW_BUILD_NUMBER(MCU) ((MCU - 1) << 4 | 0x02)
#define FIRMWARE_INFO_ITEM_HW_VERSION(MCU) ((MCU - 1) << 4 | 0x03)
#define FIRMWARE_INFO_ITEM_BOOTLOADER_VERSION(MCU) ((MCU - 1) << 4 | 0x04)
#define CMD_PAIRING_INFORMATION(idx, type) { \
.msg = { \
.report_id = REPORT_ID_SHORT, \
.device_idx = RECEIVER_IDX, \
.sub_id = GET_LONG_REGISTER_REQ, \
.address = __CMD_PAIRING_INFORMATION, \
.parameters = {type + idx, 0x00, 0x00 }, \
} \
}
#define CMD_DEVICE_FIRMWARE_INFORMATION(idx, fw_info_item) { \
.msg = { \
.report_id = REPORT_ID_SHORT, \
.device_idx = idx + 1, \
.sub_id = GET_REGISTER_REQ, \
.address = __CMD_DEVICE_FIRMWARE_INFORMATION, \
.parameters = {fw_info_item, 0x00, 0x00 }, \
} \
}
#define CMD_ENABLE_INDIVIDUAL_FEATURES(idx, sub) { \
.msg = { \
.report_id = REPORT_ID_SHORT, \
.device_idx = idx + 1, \
.sub_id = sub, \
.address = __CMD_ENABLE_INDIVIDUAL_FEATURES, \
.parameters = {0x00, 0x00, 0x00 }, \
} \
}
#define CMD_DEVICE_CONNECTION_DISCONNECTION(idx, cmd, timeout) { \
.msg = { \
.report_id = REPORT_ID_SHORT, \
.device_idx = RECEIVER_IDX, \
.sub_id = SET_REGISTER_REQ, \
.address = __CMD_DEVICE_CONNECTION_DISCONNECTION, \
.parameters = {cmd, idx, timeout }, \
} \
}
#define ERR_SUCCESS 0x00
#define ERR_INVALID_SUBID 0x01
#define ERR_INVALID_ADDRESS 0x02
#define ERR_INVALID_VALUE 0x03
#define ERR_CONNECT_FAIL 0x04
#define ERR_TOO_MANY_DEVICES 0x05
#define ERR_ALREADY_EXISTS 0x06
#define ERR_BUSY 0x07
#define ERR_UNKNOWN_DEVICE 0x08
#define ERR_RESOURCE_ERROR 0x09
#define ERR_REQUEST_UNAVAILABLE 0x0A
#define ERR_INVALID_PARAM_VALUE 0x0B
#define ERR_WRONG_PIN_CODE 0x0C
#define ERROR_MSG(__hidpp_msg, idx) { \
.msg = { \
.report_id = REPORT_ID_SHORT, \
.device_idx = idx, \
.sub_id = __ERROR_MSG, \
.address = __hidpp_msg->msg.sub_id, \
.parameters = {__hidpp_msg->msg.address, 0x00, 0x00 }, \
} \
}
struct _hidpp10_message {
__u8 report_id;
__u8 device_idx;
__u8 sub_id;
__u8 address;
union {
__u8 parameters[3];
__u8 string[16];
};
};
union hidpp10_message {
struct _hidpp10_message msg;
__u8 data[LONG_MESSAGE_LENGTH];
};
int hidpp10_request_command(int fd, union hidpp10_message *msg);
int hidpp10_toggle_individual_feature(int fd, struct unifying_device *dev, int feature_bit_r0, int feature_bit_r2);
int hidpp10_open_lock(int fd);
int hidpp10_disconnect(int fd, int idx);
void hidpp10_list_devices(int fd);
int hidpp10_get_device_from_wpid(int fd, __u16 wpid, struct unifying_device *dev);
int hidpp10_get_device_from_idx(int fd, int idx, struct unifying_device *dev);
#endif /* HIDPP_10_H */

View File

@@ -1,59 +0,0 @@
/*
* Logitech Unifying Receiver library - headers file.
*
* Copyright 2013 Benjamin Tissoires <benjamin.tissoires@gmail.com>
* Copyright 2013 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++ 1.0 documentation provided by Nestor Lopez Casado at:
* https://drive.google.com/folderview?id=0BxbRzx7vEV7eWmgwazJ3NUFfQ28&usp=sharing
*/
#ifndef UNIFYING_H
#define UNIFYING_H
#define USB_VENDOR_ID_LOGITECH (__u32)0x046d
#define USB_DEVICE_ID_UNIFYING_RECEIVER (__s16)0xc52b
#define USB_DEVICE_ID_UNIFYING_RECEIVER_2 (__s16)0xc532
struct unifying_device {
unsigned index;
char name[15];
__u16 wpid;
__u8 report_interval;
__u8 device_type;
__u8 fw_major;
__u8 fw_minor;
__u16 build;
};
int unifying_open_receiver(const char *hidraw);
/**
* Scans all /dev/hidraw*, open the first unifying receiver.
*
* @return The hidraw device file descriptor of the first unifying receiver.
*/
int unifying_find_receiver(void);
#endif /* UNIFYING_H */

View File

@@ -1,296 +0,0 @@
/*
* HID++ 1.0 library.
*
* Copyright 2013 Benjamin Tissoires <benjamin.tissoires@gmail.com>
* Copyright 2013 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++ 1.0 documentation provided by Nestor Lopez Casado at:
* https://drive.google.com/folderview?id=0BxbRzx7vEV7eWmgwazJ3NUFfQ28&usp=sharing
*/
#include <linux/types.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <debug.h>
#include <hidpp10.h>
#define MIN(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a < _b ? _a : _b; \
})
#if DEBUG_LVL > 0
const char *hidpp_errors[0xFF] = {
[0x00] = "ERR_SUCCESS",
[0x01] = "ERR_INVALID_SUBID",
[0x02] = "ERR_INVALID_ADDRESS",
[0x03] = "ERR_INVALID_VALUE",
[0x04] = "ERR_CONNECT_FAIL",
[0x05] = "ERR_TOO_MANY_DEVICES",
[0x06] = "ERR_ALREADY_EXISTS",
[0x07] = "ERR_BUSY",
[0x08] = "ERR_UNKNOWN_DEVICE",
[0x09] = "ERR_RESOURCE_ERROR",
[0x0A] = "ERR_REQUEST_UNAVAILABLE",
[0x0B] = "ERR_INVALID_PARAM_VALUE",
[0x0C] = "ERR_WRONG_PIN_CODE",
[0x0D ... 0xFE] = NULL,
};
#endif
const char *device_types[0xFF] = {
[0x00] = "Unknown",
[0x01] = "Keyboard",
[0x02] = "Mouse",
[0x03] = "Numpad",
[0x04] = "Presenter",
[0x05 ... 0x07] = "Reserved for future",
[0x06] = "ERR_ALREADY_EXISTS",
[0x07] = "ERR_BUSY",
[0x08] = "Trackball",
[0x09] = "Touchpad",
[0x0A ... 0xFE] = NULL,
};
static int hidpp10_write_command(int fd, __u8 *cmd, int size) {
int res = write(fd, cmd, size);
if (res == size)
return 0;
if (res < 0) {
printf("Error: %d\n", errno);
perror("write");
} else {
errno = ENOMEM;
printf("write: %d were written instead of %d.\n", res, size);
perror("write");
}
return res;
}
int hidpp10_request_command(int fd, union hidpp10_message *msg) {
union hidpp10_message read_buffer;
union hidpp10_message expected_header;
union hidpp10_message expected_error_recv = ERROR_MSG(msg, RECEIVER_IDX);
union hidpp10_message expected_error_dev = ERROR_MSG(msg, msg->msg.device_idx);
int ret;
__u8 hidpp_err = 0;
/* create the expected header */
expected_header = *msg;
switch (msg->msg.sub_id) {
case SET_REGISTER_REQ:
expected_header.msg.report_id = REPORT_ID_SHORT;
break;
case GET_REGISTER_REQ:
expected_header.msg.report_id = REPORT_ID_SHORT;
break;
case SET_LONG_REGISTER_REQ:
expected_header.msg.report_id = REPORT_ID_LONG;
break;
case GET_LONG_REGISTER_REQ:
expected_header.msg.report_id = REPORT_ID_LONG;
break;
}
pr_dbg("sending: "); pr_buffer(msg->data, SHORT_MESSAGE_LENGTH);
#if DEBUG_LVL > 1
pr_dbg(" expected_header: "); pr_buffer(expected_header.data, SHORT_MESSAGE_LENGTH);
pr_dbg(" expected_error_recv: "); pr_buffer(expected_error_recv.data, SHORT_MESSAGE_LENGTH);
pr_dbg(" expected_error_dev: "); pr_buffer(expected_error_dev.data, SHORT_MESSAGE_LENGTH);
#endif
/* Send the message to the Device */
ret = hidpp10_write_command(fd, msg->data, SHORT_MESSAGE_LENGTH);
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 = read(fd, read_buffer.data, LONG_MESSAGE_LENGTH);
#if DEBUG_LVL > 2
printf(" *** received: "); pr_buffer(read_buffer.data, ret);
#endif
/* actual answer */
if (!memcmp(read_buffer.data, expected_header.data, 4))
break;
/* error */
if (!memcmp(read_buffer.data, expected_error_recv.data, 5) ||
!memcmp(read_buffer.data, expected_error_dev.data, 5)) {
hidpp_err = read_buffer.msg.parameters[1];
pr_dbg(" HID++ error from the %s (%d): %s (%02x)\n",
read_buffer.msg.device_idx == RECEIVER_IDX ? "receiver" : "device",
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) {
printf(" USB error: %d\n", errno);
perror("write");
goto out_err;
}
if (!hidpp_err) {
pr_dbg(" received: "); pr_buffer(read_buffer.data, ret);
/* copy the answer for the caller */
*msg = read_buffer;
}
ret = hidpp_err;
out_err:
return ret;
}
int hidpp10_toggle_individual_feature(int fd, struct unifying_device *dev, int feature_bit_r0, int feature_bit_r2) {
unsigned idx = dev->index;
union hidpp10_message mode = CMD_ENABLE_INDIVIDUAL_FEATURES(idx, GET_REGISTER_REQ);
int res;
/* first read the current values */
res = hidpp10_request_command(fd, &mode);
if (res)
return -1;
/* toggle bits of r0 */
if (feature_bit_r0 >= 0)
mode.msg.parameters[0] ^= 1U << feature_bit_r0;
/* toggle bits of r2 */
if (feature_bit_r2 >= 0)
mode.msg.parameters[2] ^= 1U << feature_bit_r2;
/* now write back the change */
mode.msg.sub_id = SET_REGISTER_REQ;
res = hidpp10_request_command(fd, &mode);
return res;
}
int hidpp10_open_lock(int fd) {
union hidpp10_message open_lock = CMD_DEVICE_CONNECTION_DISCONNECTION(0x00, CONNECT_DEVICES_OPEN_LOCK, 0x08);
return hidpp10_request_command(fd, &open_lock);
}
int hidpp10_disconnect(int fd, int idx) {
union hidpp10_message disconnect = CMD_DEVICE_CONNECTION_DISCONNECTION(idx + 1, CONNECT_DEVICES_DISCONNECT, 0x00);
return hidpp10_request_command(fd, &disconnect);
}
void hidpp10_list_devices(int fd) {
struct unifying_device dev;
int i, res;
for (i = 0; i < 6; ++i) {
res = hidpp10_get_device_from_idx(fd, i, &dev);
if (res)
continue;
printf("[%d] %s %s (Wireless PID: %04x)\n", i, device_types[dev.device_type] ? device_types[dev.device_type] : "", dev.name, dev.wpid);
}
}
static int hidpp10_get_device_info(int fd, struct unifying_device *dev) {
unsigned idx = dev->index;
union hidpp10_message pairing_information = CMD_PAIRING_INFORMATION(idx, DEVICE_PAIRING_INFORMATION);
union hidpp10_message device_name = CMD_PAIRING_INFORMATION(idx, DEVICE_NAME);
union hidpp10_message firmware_information = CMD_DEVICE_FIRMWARE_INFORMATION(idx, FIRMWARE_INFO_ITEM_FW_NAME_AND_VERSION(1));
union hidpp10_message build_information = CMD_DEVICE_FIRMWARE_INFORMATION(idx, FIRMWARE_INFO_ITEM_FW_BUILD_NUMBER(1));
int name_size;
int res;
res = hidpp10_request_command(fd, &pairing_information);
if (res)
return -1;
dev->report_interval = pairing_information.msg.string[2];
dev->wpid = (pairing_information.msg.string[3] << 8) |
pairing_information.msg.string[4];
dev->device_type = pairing_information.msg.string[7];
res = hidpp10_request_command(fd, &device_name);
if (res)
return -1;
name_size = device_name.msg.string[1];
memcpy(dev->name, &device_name.msg.string[2], sizeof(device_name.msg.string));
dev->name[MIN(name_size, sizeof(dev->name) - 1)] = '\0';
/*
* This may fail on some devices
* => we can not retrieve their FW version through HID++ 1.0.
*/
res = hidpp10_request_command(fd, &firmware_information);
if (res)
return 0;
dev->fw_major = firmware_information.msg.string[1];
dev->fw_minor = firmware_information.msg.string[2];
res = hidpp10_request_command(fd, &build_information);
if (res)
return 0;
dev->build = (build_information.msg.string[1] << 8) |
build_information.msg.string[2];
return 0;
}
int hidpp10_get_device_from_wpid(int fd, __u16 wpid, struct unifying_device *dev) {
int i, res;
for (i = 0; i < 6; i++) {
res = hidpp10_get_device_from_idx(fd, i, dev);
if (res)
continue;
if (dev->wpid == wpid)
break;
res = -1;
}
return res;
}
int hidpp10_get_device_from_idx(int fd, int idx, struct unifying_device *dev) {
dev->index = idx;
return hidpp10_get_device_info(fd, dev);
}

View File

@@ -1,126 +0,0 @@
/*
* Logitech Unifying Receiver library.
*
* Copyright 2013 Benjamin Tissoires <benjamin.tissoires@gmail.com>
* Copyright 2013 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++ 1.0 documentation provided by Nestor Lopez Casado at:
* https://drive.google.com/folderview?id=0BxbRzx7vEV7eWmgwazJ3NUFfQ28&usp=sharing
*/
#include <linux/types.h>
#include <linux/input.h>
#include <linux/hidraw.h>
#include <sys/ioctl.h>
#include <unifying.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#define DEV_DIR "/dev"
#define HIDRAW_DEV_NAME "hidraw"
int unifying_open_receiver(const char *hidraw) {
struct hidraw_devinfo info;
int fd, res;
/* Open the Device with non-blocking reads. */
fd = open(hidraw, O_RDWR);
if (fd < 0) {
perror("Unable to open device");
goto out_err;
}
/* Get Raw Info */
res = ioctl(fd, HIDIOCGRAWINFO, &info);
if (res < 0) {
perror("error while getting info from device");
} else {
/* Check if the device is an Unifying receiver */
if (info.bustype != BUS_USB ||
info.vendor != USB_VENDOR_ID_LOGITECH ||
(info.product != USB_DEVICE_ID_UNIFYING_RECEIVER &&
info.product != USB_DEVICE_ID_UNIFYING_RECEIVER_2))
goto out_err;
}
return fd;
out_err:
if (fd >= 0)
close(fd);
return fd >= 0 ? -1 : fd;
}
/**
* Filter for the AutoDevProbe scandir on /dev.
*
* @param dir The current directory entry provided by scandir.
*
* @return Non-zero if the given directory entry starts with "hidraw", or zero
* otherwise.
*/
static int is_hidraw_device(const struct dirent *dir) {
return strncmp(HIDRAW_DEV_NAME, dir->d_name, 6) == 0;
}
/**
* Scans all /dev/hidraw*, open the first unifying receiver.
*
* @return The hidraw device file descriptor of the first unifying receiver.
*/
int unifying_find_receiver(void) {
struct dirent **namelist;
int fd = -1;
char fname[64];
int i, ndev;
ndev = scandir(DEV_DIR, &namelist, is_hidraw_device, alphasort);
if (ndev <= 0)
return fd;
for (i = 0; i < ndev; i++)
{
if (fd < 0) {
snprintf(fname, sizeof(fname),
"%s/%s", DEV_DIR, namelist[i]->d_name);
fd = unifying_open_receiver(fname);
}
free(namelist[i]);
}
free(namelist);
if (fd >= 0)
printf("Using %s as the Unifying receiver.\n", fname);
else
printf("Unable to find an Unifying receiver.\n");
return fd;
}