summaryrefslogtreecommitdiff
path: root/hw/usb
diff options
context:
space:
mode:
authorPeter Wu <peter@lekensteyn.nl>2014-03-19 19:24:28 +0100
committerPeter Wu <peter@lekensteyn.nl>2014-03-19 19:24:28 +0100
commit872bcec5b6613d18cfa9267336429ba13076a200 (patch)
treec8fad6fc99e810f9f1491f186324b4912ce48f3c /hw/usb
parent5817de3fcf4f70c1d23cfcecd01c854272eb97da (diff)
downloadqemu-872bcec5b6613d18cfa9267336429ba13076a200.tar.gz
unifying: handle receiver regs 0 and 2
Diffstat (limited to 'hw/usb')
-rw-r--r--hw/usb/hid-logitech-dj.c47
-rw-r--r--hw/usb/hid-logitech-dj.h9
2 files changed, 52 insertions, 4 deletions
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) */