From 3a5922cc11f73269bfcd762997efc2c029a3b585 Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Tue, 18 Mar 2014 21:21:51 +0100 Subject: unifying: WIP for HID++ support Error queue is implemented, possible receiver and device properties are filled in (in the header). Signed-off-by: Peter Wu --- hw/usb/hid-logitech-dj.h | 176 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 174 insertions(+), 2 deletions(-) (limited to 'hw/usb/hid-logitech-dj.h') diff --git a/hw/usb/hid-logitech-dj.h b/hw/usb/hid-logitech-dj.h index 4269457354..36b2c31e2e 100644 --- a/hw/usb/hid-logitech-dj.h +++ b/hw/usb/hid-logitech-dj.h @@ -1,5 +1,5 @@ /* - * Logitech Unifying recever emulation (DJ mode). + * Logitech Unifying receiver emulation (HID++ protocol). * * Copyright (c) 2014 Peter Wu * @@ -24,13 +24,163 @@ #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_DJ, /* DJ mode */ + 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 { + const struct { + uint32_t serial; + struct firmware_version version; + } info; /* static information */ + +#define REPORTING_FLAG_WIRELESS_NOTIFS 0 +#define REPORTING_FLAG_SOFTWARE_PRESENT (1 << 3) + 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 { + const 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; + const char name[15]; + uint8_t usability_info; /* bits 0..3 power switch location */ + /* TODO: feature set */ + /* TODO: special mouse and key button mappings */ + } info; /* static information */ + + bool powered_on; + uint8_t report_interval; +#define REPORTING_FLAG_BATTERY_STATUS (1 << 4) + 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; +} 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) */ @@ -40,6 +190,28 @@ typedef struct USBLtunifyState { LTUNIFY_MODE_DJ = 2 } mode; HIDState hid[2]; /* HID devices (keyboard, mouse) */ + + /* queue for HID++ requests and responses */ + struct { + HidppMsg reports[16]; + unsigned head; + unsigned n; + } 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]; } 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); #endif -- cgit v1.2.1