From 872bcec5b6613d18cfa9267336429ba13076a200 Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Wed, 19 Mar 2014 19:24:28 +0100 Subject: unifying: handle receiver regs 0 and 2 --- hw/usb/hid-logitech-dj.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++- hw/usb/hid-logitech-dj.h | 9 ++++++--- 2 files changed, 52 insertions(+), 4 deletions(-) (limited to 'hw') diff --git a/hw/usb/hid-logitech-dj.c b/hw/usb/hid-logitech-dj.c index 77e7f20202..dddc5027f4 100644 --- a/hw/usb/hid-logitech-dj.c +++ b/hw/usb/hid-logitech-dj.c @@ -38,6 +38,12 @@ enum { DJ_LONG = 0x21, /* 32 bytes */ }; +/* helpers to handle the HID++ register queries */ +#define SET_REG(reg) (0x108000 | (reg)) +#define GET_REG(reg) (0x108100 | (reg)) +#define SET_LONG_REG(reg) (0x118200 | (reg)) +#define GET_LONG_REG(reg) (0x118300 | (reg)) + /* returns the expected length of the report or 0 if invalid */ static unsigned msg_report_length(HidppMsg *msg) { @@ -149,7 +155,46 @@ static bool hidpp_process_receiver_report(USBLtunifyState *s, HidppMsg *msg) hidpp_queue_error(s, msg, HIDPP_ERR_INVALID_SUBID); } } else if (msg->report_id == HIDPP_SHORT || msg->report_id == HIDPP_LONG) { - /* TODO: handle requests */ + LHidReceiver *rcvr = &s->receiver; + HidppMsgShort *ms = &msg->hidpp_s; + unsigned req = (ms->report_id << 16) | (ms->sub_id << 8) | ms->address; + + switch (req) { + case GET_REG(0x00): /* Enable HID++ notifs */ + ms->value[0] = ms->value[2] = 0; + ms->value[1] = rcvr->reporting_flags; + hidpp_queue_output_report(s, msg); + break; + case SET_REG(0x00): /* Enable HID++ notifs */ + rcvr->reporting_flags = ms->value[1]; + rcvr->reporting_flags &= REPORTING_FLAG_RECV_MASK; + memset(ms->value, 0, 3); + hidpp_queue_output_report(s, msg); + break; + case GET_REG(0x02): /* Connection State */ + memset(ms->value, 0, 3); + for (i = 0; i < MAX_DEVICES; i++) { + if (s->devices[i].info.device_type) { + ms->value[1]++; + } + } + hidpp_queue_output_report(s, msg); + break; + default: + /* unknown request, return error */ + switch (req & ~0xFF) { + case SET_REG(0): + case GET_REG(0): + case SET_LONG_REG(0): + case GET_LONG_REG(0): + /* register request unsatisfied */ + hidpp_queue_error(s, msg, HIDPP_ERR_INVALID_ADDRESS); + break; + default: + /* invalid report ID and command SubID combination */ + hidpp_queue_error(s, msg, HIDPP_ERR_INVALID_SUBID); + } + } } else { /* DJ_LONG is unhandled */ return false; diff --git a/hw/usb/hid-logitech-dj.h b/hw/usb/hid-logitech-dj.h index 5e0ba2efe8..6518c39fba 100644 --- a/hw/usb/hid-logitech-dj.h +++ b/hw/usb/hid-logitech-dj.h @@ -127,8 +127,10 @@ typedef struct { struct firmware_version version; } info; /* static information */ -#define REPORTING_FLAG_WIRELESS_NOTIFS 0 -#define REPORTING_FLAG_SOFTWARE_PRESENT (1 << 3) +#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) */ @@ -170,7 +172,8 @@ typedef struct { } mode; bool powered_on; uint8_t report_interval; -#define REPORTING_FLAG_BATTERY_STATUS (1 << 4) +#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) */ -- cgit v1.2.1