/* * Logitech Unifying receiver emulation (HID++ protocol). * * Copyright (c) 2014 Peter Wu * * 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 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 HID_LOGITECH_DJ_H #define HID_LOGITECH_DJ_H /* HID requests ((bmRequestType << 8) | bRequest) */ #define HID_GET_REPORT 0xa101 #define HID_GET_IDLE 0xa102 #define HID_GET_PROTOCOL 0xa103 /* 0x04-0x08 Reserved */ #define HID_SET_REPORT 0x2109 #define HID_SET_IDLE 0x210a #define HID_SET_PROTOCOL 0x210b /* interface numbers (also used for array indices) */ enum { IFACE_KBD, /* keyboard */ IFACE_MSE, /* mouse; multimedia, power, media center buttons */ IFACE_HIDPP, /* HID++, DJ */ }; #define MAX_DEVICES 6 /* report formats */ typedef struct { uint8_t report_id; uint8_t device_index; uint8_t sub_id; uint8_t address; uint8_t value[3]; } HidppMsgShort; typedef struct { uint8_t report_id; uint8_t device_index; uint8_t sub_id; uint8_t address; uint8_t value[16]; } HidppMsgLong; typedef struct { uint8_t report_id; uint8_t device_index; uint8_t report_type; uint8_t payload[12]; } DjMsgShort; typedef struct { uint8_t report_id; uint8_t device_index; uint8_t report_type; uint8_t payload[29]; } DjMsgLong; /* generic HID++ or DJ report */ typedef struct { union { struct { uint8_t report_id; uint8_t device_index; }; HidppMsgShort hidpp_s; HidppMsgLong hidpp_l; DjMsgShort dj_s; DjMsgLong dj_l; }; } HidppMsg; /* information to generate an error output report */ typedef struct { uint8_t device_index; uint8_t sub_id; uint8_t address; #define HIDPP_ERR_SUCCESS 0x00 #define HIDPP_ERR_INVALID_SUBID 0x01 #define HIDPP_ERR_INVALID_ADDRESS 0x02 #define HIDPP_ERR_INVALID_VALUE 0x03 #define HIDPP_ERR_CONNECT_FAIL 0x04 #define HIDPP_ERR_TOO_MANY_DEVICES 0x05 #define HIDPP_ERR_ALREADY_EXISTS 0x06 #define HIDPP_ERR_BUSY 0x07 #define HIDPP_ERR_UNKNOWN_DEVICE 0x08 #define HIDPP_ERR_RESOURCE_ERROR 0x09 #define HIDPP_ERR_REQUEST_UNAVAILABLE 0x0A #define HIDPP_ERR_INVALID_PARAM_VALUE 0x0B #define HIDPP_ERR_WRONG_PIN_CODE 0x0C uint8_t error; } HidppError; /* device and receiver info */ struct firmware_version { uint8_t fw_major; uint8_t fw_minor; uint16_t fw_build; /* boot loader */ uint8_t bl_major; uint8_t bl_minor; }; typedef struct { struct { uint32_t serial; struct firmware_version version; } info; /* static information */ #define REPORTING_FLAG_DEV_WIRELESS_NOTIFS 1 #define REPORTING_FLAG_DEV_SOFTWARE_PRESENT (1 << 3) #define REPORTING_FLAG_DEV_MASK (REPORTING_FLAG_WIRELESS_NOTIFS | \ REPORTING_FLAG_SOFTWARE_PRESENT) int reporting_flags; uint8_t activity_counter[MAX_DEVICES]; /* TODO: pairing lock open or closed (+ timeout) */ /* TODO: connected devices */ /* TODO: device firmware upgrade things? */ } LHidReceiver; typedef struct { struct { enum { DEVTYPE_KEYBOARD = 1, DEVTYPE_MOUSE, DEVTYPE_NUMPAD, DEVTYPE_PRESENTER, /* 0x05..0x07 Reserved for future */ DEVTYPE_TRACKBALL = 8, DEVTYPE_TOUCHPAD, /* 0x0A..0x0F Reserved */ } device_type; enum { PROTO_UNIFYING = 4, } protocol_type; struct firmware_version version; uint16_t protocol_version; /* HID++ protocol version */ uint16_t wireless_pid; uint32_t serial; char name[15]; uint8_t usability_info; /* bits 0..3 power switch location */ uint32_t report_types; /* supported report types (e.g. mouse) */ /* TODO: feature set */ /* TODO: special mouse and key button mappings */ } info; /* static information */ HIDState *hid; enum { LTUNIFY_MODE_HID = 1, LTUNIFY_MODE_DJ = 2 } mode; bool powered_on; uint8_t report_interval; #define REPORTING_FLAG_RECV_BATTERY_STATUS (1 << 4) #define REPORTING_FLAG_RECV_MASK REPORTING_FLAG_RECV_BATTERY_STATUS int reporting_flags; /* TODO: status (device seen or not, encrypted link) */ struct { uint8_t level; enum { BAT_STS_CHARGING, /* TODO: charging, discharging, etc. */ } status; } battery; uint8_t activity_counter; } LHidDevice; /* helper macros for handling the report and error queue */ #define LQUEUE_SIZE(q) ARRAY_SIZE((q).reports) #define LQUEUE_WRAP(q, val) ((val) & (LQUEUE_SIZE((q)) - 1u)) #define LQUEUE_INCR(q, var) ((var) = LQUEUE_WRAP((q), (var) + 1)) typedef struct USBLtunifyState { USBDevice dev; USBEndpoint *intr[3]; /* interfaces (keyboard, mouse, DJ) */ UsbDumpState *usb_dump_state; HIDState hid[2]; /* HID devices (keyboard, mouse) */ /* queue for HID++ requests and responses */ struct { HidppMsg reports[16]; unsigned head; unsigned n; } input_queue; struct { HidppMsg reports[16]; unsigned head; unsigned n; } output_queue; /* receiver error queue (to be send): drop if full */ struct { HidppMsgShort reports[2]; unsigned head; unsigned n; } error_queue; LHidReceiver receiver; LHidDevice devices[MAX_DEVICES]; /* paired devices */ } USBLtunifyState; /* handle control packets for interface 3 (HID++ / DJ) */ void usb_ltunify_handle_control_hidpp(USBDevice *dev, USBPacket *p, int request, int value, int index, int length, uint8_t *data); /* handle control packets for interface 3 (HID++ / DJ) */ void usb_ltunify_handle_datain_hidpp(USBDevice *dev, USBPacket *p); void hidpp_reset(USBLtunifyState *s); void hidpp_init(USBLtunifyState *s); #endif