From 99bcaad18aad5c41997b94a66862e19c841c2986 Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Mon, 8 Apr 2013 17:00:42 +0200 Subject: Initial commit of RE/debug programs/notes --- .gitignore | 3 + README.txt | 42 ++++++++ hidraw.c | 237 +++++++++++++++++++++++++++++++++++++++++++++ notes.txt | 207 +++++++++++++++++++++++++++++++++++++++ read-dev-usbmon.c | 150 ++++++++++++++++++++++++++++ registers.txt | 284 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ usbmon.awk | 132 +++++++++++++++++++++++++ 7 files changed, 1055 insertions(+) create mode 100644 .gitignore create mode 100644 README.txt create mode 100755 hidraw.c create mode 100644 notes.txt create mode 100644 read-dev-usbmon.c create mode 100644 registers.txt create mode 100755 usbmon.awk diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2a62954 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.*.sw* +read-dev-usbmon +hidraw diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..56f85cf --- /dev/null +++ b/README.txt @@ -0,0 +1,42 @@ +Logitech documents + +2200_mousepointer.pdf, 4301_k750_solarkeyboard_lightandbattery.pdf, +6100_touchpadraw.pdf, 6110_touchmouseraw.pdf, +logitech_hidpp10_specification_for_Unifying_Receivers.pdf have been created +from .doc(x) files using LibreOffice. +logitech_hidpp_2.0_specification_draft_2012-06-04.pdf was already a PDF, so no +conversion was necessary. + +The contents of the aforementioned files are (C) Logitech. +Retrieved from https://drive.google.com/?tab=mo&pli=1&authuser=0#folders/0BxbRzx7vEV7eWmgwazJ3NUFfQ28 +(found at http://code.google.com/p/chromium/issues/detail?id=175572) + +usbmon.awk was a RE attempt before I found the spec, it helped me understand +the packets when the specification was not available. + +You will find the HID++ 1.0 spec the most interesting, I hope to produce a +pairing program soon. + + +Debuggers +usbmon.awk - initial debugging tool used for tapping usbmon from debugfs +hidraw.c - successor of usbmon.awk that can parse packets of usb payload. +read-dev-usbmon.c - Reads data from /dev/usbmonX and show interpreted data in a + more human-readable way. + +Note: as a quick-n-dirty hack, I included hidraw.c at some point into the +read-dev-usbmon program. Otherwise, I had no way to show the difference between +a send or receive packet without adding to the same stdout stream. If I included +it in the stderr pipe, then it would be interleaved with stdout in an +unpredictable manner. This means that hidraw.c is currently unusable, it does +not process data correctly. + +Usage of USB debugger: +1. Use `lsusb -d 046d:c52b` to determine the bus number. If the output is "Bus + 001 ..", your usb monitor device is at /dev/usbmon1. +2. sudo chgrp $USER /dev/usbmon1 +3. sudo chmod g+r /dev/usbmon1 +4. ./read-dev-usbmon /dev/usbmon1 +5. Profit! + +~ Peter Wu diff --git a/hidraw.c b/hidraw.c new file mode 100755 index 0000000..dd35051 --- /dev/null +++ b/hidraw.c @@ -0,0 +1,237 @@ +/* + * Displays a more human-readable interpretation of the USB data payload + * for Logitech Unifying Receiver. + * + * Example usage: read-dev-usbmon /dev/usbmon0 | hidraw + * + * Copyright (C) 2013 Peter Wu + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include + +typedef unsigned char u8; + +#define SHORT_MSG 0x10 +#define SHORT_MSG_LEN 7 +#define LONG_MSG 0x11 +#define LONG_MSG_LEN 20 + +struct payload_short { + u8 address; + u8 value[3]; +}; +struct payload_long { + u8 address; + u8 str[16]; +}; +struct report { + u8 report_id; + u8 device_index; + u8 sub_id; + union { + struct payload_long l; + struct payload_short s; + }; +} __attribute__((__packed__)); + +static const char * report_types[0xFF] = { + // 0x00 - 0x3F HID reports + [0x01] = "KEYBOARD", + [0x02] = "MOUSE", + [0x03] = "CONSUMER_CONTROL", + [0x04] = "SYSTEM_CONTROL", + + [0x08] = "MEDIA_CENTER", + + [0x0E] = "LEDS", + + // 0x40 - 0x7F enumerator notifications + [0x40] = "NOTIF_DEVICE_UNPAIRED", + [0x41] = "NOTIF_DEVICE_PAIRED", + [0x42] = "NOTIF_CONNECTION_STATUS", + [0x4A] = "NOTIF_RECV_LOCK_CHANGED", + [0x4B] = "?NOTIF_PAIR_ACCEPTED", + + [0x7F] = "NOTIF_ERROR", + + // 0x80 - 0xFF enumerator commands; Register Access + [0x80] = "SET_REG", // was CMD_SWITCH + [0x81] = "GET_REG", // was CMD_GET_PAIRED_DEVICES + [0x82] = "SET_LONG_REG", + [0x83] = "GET_LONG_REG", + [0x8F] = "_ERROR_MSG", +}; + +static const char * error_messages[0xFF] = { + // error messages for type=8F (ERROR_MSG) + [0x01] = "SUCCESS", + [0x02] = "INVALID_SUBID", + [0x03] = "INVALID_ADDRESS", + [0x04] = "INVALID_VALUE", + [0x05] = "CONNECT_FAIL", + [0x06] = "TOO_MANY_DEVICES", + [0x07] = "ALREADY_EXISTS", + [0x08] = "BUSY", + [0x09] = "UNKNOWN_DEVICE", + [0x0a] = "RESOURCE_ERROR", + [0x0b] = "REQUEST_UNAVAILABLE", + [0x0c] = "INVALID_PARAM_VALUE", + [0x0d] = "WRONG_PIN_CODE", +}; + +static const char * registers[0xFF] = { + [0x00] = "ENABLED_NOTIFS", + [0x01] = "KBD_HAND_DETECT?", + [0x02] = "CONNECTION_STATE", + [0x03] = "FN_KEY_SWAP?", + [0x17] = "ILLUMINATION_INFO?", + [0xb2] = "DEVICE_PAIRING", + [0xb3] = "DEVICE_ACTIVITY", + [0xb5] = "PAIRING_INFO", + [0xf1] = "VERSION_INFO?", /* guessed */ +}; + +const char * report_type_str(u8 type) { + const char * str = report_types[type]; + return str ? str : ""; +} +const char * device_type_str(u8 type) { + switch (type) { + case 0x01: return "DEV1"; + case 0x02: return "DEV2"; + case 0x03: return "DEV3"; + case 0x04: return "DEV4"; + case 0x05: return "DEV5"; + case 0x06: return "DEV6"; + case 0xFF: return "RECV"; + default: return ""; + } +} +const char *error_str(u8 er) { + const char * str = error_messages[er]; + return str ? str : ""; +} +const char *register_str(u8 reg) { + const char * str = registers[reg]; + return str ? str : ""; +} + +void process_msg_payload(struct report *r, u8 data_len) { + u8 pos, i; + u8 * bytes = (u8 *) &r->s; + + switch (r->sub_id) { + case 0x8F: // error + // TODO: length check + printf("SubID=%02X %s ", bytes[0], report_type_str(bytes[0])); + printf("reg=%02X %s ", bytes[1], register_str(bytes[1])); + printf("err=%02X %s ", bytes[2], error_str(bytes[2])); + pos = 4; // everything is processed + break; + case 0x80: + case 0x81: + case 0x82: /* long */ + case 0x83: /* long */ + printf("reg=%02X %s ", bytes[0], register_str(bytes[0])); + pos = 1; + break; + default: + pos = 0; // nothing has been processed + break; + } + + if (pos < data_len) { + printf("params="); + //printf("params(len=%02X)=", data_len); + } + for (i = 0; pos < data_len; pos++, i++) { + printf("%02X ", bytes[pos]); + if (i % 4 == 3 && pos + 1 < data_len) { + putchar(' '); + } + } +} + +void process_msg(struct report *report, ssize_t size) { + const char * report_type; + + switch (report->report_id) { + case SHORT_MSG: + report_type = "short"; + if (size != SHORT_MSG_LEN) { + fprintf(stderr, "Invalid short msg len %zi\n", size); + return; + } + break; + case LONG_MSG: + report_type = "long"; + if (size != LONG_MSG_LEN) { + fprintf(stderr, "Invalid long msg len %zi\n", size); + return; + } + break; + default: + report_type = "unkn"; + //fprintf(stderr, "Unknown report ID %02x, len=%zi\n", report->report_id, size); + if (size < 3) { + return; + } + break; + } + + printf("report_id=%02X %-5s ", report->report_id, report_type); + printf("device=%02X %-4s ", report->device_index, + device_type_str(report->device_index)); + printf("type=%02X %-23s ", report->sub_id, + report_type_str(report->sub_id)); + + if (size > 3) { + process_msg_payload(report, size - 3); + } + putchar('\n'); +} + +#ifndef NO_MAIN +int main(int argc, char ** argv) { + int fd = STDIN_FILENO; + ssize_t r; + struct report report; + + if (argc >= 2 && (fd = open(argv[1], O_RDONLY)) < 0) { + perror(argv[1]); + return 1; + } + + do { + memset(&report, 0xCC, sizeof report); // for debugging purposes + r = read(fd, &report, sizeof report); + if (r > 0) { + process_msg(&report, r); + } + } while (r >= 0); + + if (r < 0) { + perror("read"); + } + + close(fd); + + return 0; +} +#endif /* ! NO_MAIN */ diff --git a/notes.txt b/notes.txt new file mode 100644 index 0000000..b9e398f --- /dev/null +++ b/notes.txt @@ -0,0 +1,207 @@ +// vim:syntax=c: +// docs at https://drive.google.com/?tab=mo&pli=1&authuser=0#folders/0BxbRzx7vEV7eWmgwazJ3NUFfQ28 (found at http://code.google.com/p/chromium/issues/detail?id=175572) +struct dj_report { + u8 report_id; + u8 device_index; + u8 report_type; + u8 report_params[DJREPORT_SHORT_LENGTH - 3]; +}; + +// char magic_sequence[] = {0x10, 0xFF, 0x80, 0xB2, 0x01, 0x00, 0x00}; + +#define REPORT_TYPE_KEYBOARD 0x01 +#define REPORT_TYPE_MOUSE 0x02 +#define REPORT_TYPE_CONSUMER_CONTROL 0x03 +#define REPORT_TYPE_SYSTEM_CONTROL 0x04 + +#define REPORT_TYPE_MEDIA_CENTER 0x08 + +#define REPORT_TYPE_LEDS 0x0E + +#define REPORT_TYPE_NOTIF_DEVICE_UNPAIRED 0x40 +#define REPORT_TYPE_NOTIF_DEVICE_PAIRED 0x41 +#define REPORT_TYPE_NOTIF_CONNECTION_STATUS 0x42 + +#define REPORT_TYPE_NOTIF_ERROR 0x7F + +#define REPORT_TYPE_CMD_SWITCH 0x80 +#define REPORT_TYPE_CMD_GET_PAIRED_DEVICES 0x81 + + dj_report->report_id = REPORT_ID_DJ_SHORT; + dj_report->device_index = 0xFF; + dj_report->report_type = REPORT_TYPE_CMD_GET_PAIRED_DEVICES; + retval = logi_dj_recv_send_report(djrcv_dev, dj_report); + +report_id = 0x10; +device_index = 0xFF; +report_type = 0x80; // REPORT_TYPE_CMD_SWITCH +report_params = {0xB2, 0x01, 0x00, 0x00}; +// { 0xB2 , Connect Devices, Device Number, Open Lock Timeout } +// = {0xb2, 0x01, 0x50, 0x3c} +// observation: S b203 0100 perform unpair +// S b201 533c when discovery is enabled (with no paired devices) +// R b200 0000 when discovery is enabled (no paired devices, waiting; also recvd when unpaired while in Advanced mode) +// S b202 5394 when discovery is disabled (both with 1 paired kbd and no paired kbd; explicitly issued when closing pair program) +// 0:1 1 address +// 1:3 3 value (0 is returned on succesfully setting register) +// Related to type 0x4A + +// observations + guesses +// issued after 10 ff CMD_SWITCH b2 .. .. .. +report_id = 0x10 +device_index = 0xFF +report_type = 0x4A // receiver status - open for new devices? +// R 0100 0000 discovery enabled +// R 0001 0000 discovery disabled (issued after timeout) +// R 0000 0000 discovery disabled (after CMD_SWITCH b200 0000; succesful pair) + +// 00000000 00000000 is sent when device is turned off, "null report"? + +// No paired devices, just started program: +// output report_id=10 dev_idx=ff RECV type=83 parms=b5030000 +// ep3 report_id=11 dev_idx=ff RECV type=83 parms=b503af4f95 ea150609 00000000 00000000 +// No paired devices (same for unpaired kbd off/on), just started program: +// output report_id=10 dev_idx=ff RECV type=83 ?CMD_DEVICE_INFO parms=b5030000 +// ep3 report_id=11 dev_idx=ff RECV type=83 ?CMD_DEVICE_INFO parms=b503af4f95 ea15060a 00000000 00000000 +// Press "Advanced", unpaired (same for unpaired kbd on/off): +// output report_id=10 dev_idx=ff RECV type=83 ?CMD_DEVICE_INFO parms=b3000000 +// ep3 report_id=11 dev_idx=ff RECV type=83 ?CMD_DEVICE_INFO parms=b308000000 00000000 00000000 00000000 + +/* +report_id=10; dev_id=01 for Sent0+Recv0 and Sent1+Recv1, but ff for Sent1+Recv2 + Sent0 Recv0 + 00120100* +0d000000 810d0200* +07000000 07050000 + + Sent1 Recv1 Recv2 +f1010000 f1012201 f1011201 +f1020000 f1020019 f1020019 +f1030000 f1030007 81f10300* +f1040000 f1040201 f1040214 + +*) type=8f instead of 81 CMD_GET_PAIRED_DEVICES +Order = Sent0+Recv0, Sent1+Recv1, Sent1+Recv2 (+ = interleaved) +*/ + + +// Discover? (click Advanced and get a lot of this spam) +// send: report_id=10 dev_idx=ff type=83 parms=b3000000 # report yourself guys? +// +// recv: report_id=11 dev_idx=ff type=83 parms=b3a1000000 00000000 00000000 00000000 +// ep3 report_id=11 dev_idx=ff type=83 parms=b32a000000 00000000 00000000 00000000 # byte 2 is channel/encrypt key??? +// ep3 report_id=11 dev_idx=ff type=83 parms=b331000000 00000000 00000000 00000000 # No devices turned on +// ep3 report_id=11 dev_idx=ff type=83 parms=b334000000 00000000 00000000 00000000 # Device pair step 1 (after Sent0+Recv0) +// ep3 report_id=11 dev_idx=ff type=83 parms=b336000000 00000000 00000000 00000000 # Device pair step 2 (after Sent1+Recv1) +// ep3 report_id=11 dev_idx=ff type=83 parms=b338000000 00000000 00000000 00000000 # Device just paired (after Sent1+Recv2) + + +// Unpair: +// send: report_id=10 dev_idx=ff type=80 CMD_SWITCH parms=b2030100 # R: Unpair device request +// +// recv: report_id=03 dev_idx=00 type=00 parms=0000 +// recv: report_id=10 dev_idx=01 type=40 NOTIF_DEVICE_UNPAIRED parms=02000000 +// recv: report_id=00 dev_idx=00 type=00 parms=0000000000 +// +// recv: report_id=20 dev_idx=01 type=40 NOTIF_DEVICE_UNPAIRED parms=0000000000 00000000 000000 +// +// recv: report_id=10 dev_idx=ff type=80 CMD_SWITCH parms=b2000000 # K: Ready to accept other receiver? + +// Prepare switch? +// send: report_id=10 dev_idx=ff type=80 CMD_SWITCH parms=b201533c # R: Looking for devices? +// recv: +// recv: report_id=10 dev_idx=ff type=4a parms=01000000 # K: Hi I am a device +// recv: +// recv: report_id=10 dev_idx=ff type=80 CMD_SWITCH parms=b2000000 # K: I want to pair with you +// Switch timeout? (+/- 60 seconds) +// recv: report_id=10 dev_idx=ff type=4a parms=00010000 # K: Nevermind, nobody responded + +// Turn on kbd while pair program is waiting for recv +// recv: report_id=10 dev_idx=01 type=41 NOTIF_DEVICE_PAIRED parms=04611020 # L: I just turned myself on +// +// send: report_id=10 dev_idx=ff type=83 parms=b5400000 # R: Hey, wanna join me? +// recv: report_id=20 dev_idx=01 type=41 NOTIF_DEVICE_PAIRED parms=0010201a40 00000000 000000 +// +// recv: report_id=10 dev_idx=ff type=4a parms=00000000 +// +// recv: report_id=11 dev_idx=ff type=83 parms=b540044b38 30300000 00000000 00000000 +// +// send: report_id=10 dev_idx=ff type=83 parms=b5300000 +// +// recv: report_id=11 dev_idx=ff type=83 parms=b530fb841b 861a4000 00070000 00000000 +// b530 +// fb841b 86 Serial No +// 1a4000 00070000 00000000 ??? +// +// recv: report_id=10 dev_idx=01 type=41 NOTIF_DEVICE_PAIRED parms=04a11020 # I am already paired? (0x6_ -> 0xa_, 0110 -> 1010); Also sent when turning on paired kbd +// type=41 Device Connection +// 04 0000 0100 - Unifying protocol +// a1 1010 0001 - DeviceType=Keyboard; Link is encrypted; Link is established; Packet with payload +// 10 0001 0000 - Wireless PID LSB +// 20 0010 0000 - Wireless PID MSB + +// continued switch. +// send: report_id=10 dev_idx=01 type=00 parms=12283f94 +// : report_id=10 dev_idx=01 type=4b parms=01000000 +// +// : report_id=10 dev_idx=01 type=8f parms=00120100 +// +// send: report_id=10 dev_idx=01 type=81 CMD_GET_PAIRED_DEVICES parms=0d000000 +// +// : report_id=10 dev_idx=01 type=8f parms=810d0200 +// +// send: report_id=10 dev_idx=01 type=81 CMD_GET_PAIRED_DEVICES parms=07000000 +// +// : report_id=10 dev_idx=01 type=81 CMD_GET_PAIRED_DEVICES parms=07050000 +// +// send: report_id=10 dev_idx=01 type=81 CMD_GET_PAIRED_DEVICES parms=f1010000 +// +// : report_id=10 dev_idx=01 type=81 CMD_GET_PAIRED_DEVICES parms=f1012201 +// +// send: report_id=10 dev_idx=01 type=81 CMD_GET_PAIRED_DEVICES parms=f1020000 +// +// : report_id=10 dev_idx=01 type=81 CMD_GET_PAIRED_DEVICES parms=f1020019 +// +// send: report_id=10 dev_idx=01 type=81 CMD_GET_PAIRED_DEVICES parms=f1030000 +// +// : report_id=10 dev_idx=01 type=81 CMD_GET_PAIRED_DEVICES parms=f1030007 +// +// send: report_id=10 dev_idx=01 type=81 CMD_GET_PAIRED_DEVICES parms=f1040000 +// +// : report_id=10 dev_idx=01 type=81 CMD_GET_PAIRED_DEVICES parms=f1040201 +// +// send: report_id=10 dev_idx=ff type=81 CMD_GET_PAIRED_DEVICES parms=f1010000 +// : report_id=10 dev_idx=ff type=81 CMD_GET_PAIRED_DEVICES parms=f1011201 +// +// send: report_id=10 dev_idx=ff type=81 CMD_GET_PAIRED_DEVICES parms=f1020000 +// : report_id=10 dev_idx=ff type=81 CMD_GET_PAIRED_DEVICES parms=f1020019 +// +// send: report_id=10 dev_idx=ff type=81 CMD_GET_PAIRED_DEVICES parms=f1030000 +// : +// : report_id=10 dev_idx=ff type=8f parms=81f10300 +// : +// send: report_id=10 dev_idx=ff type=81 CMD_GET_PAIRED_DEVICES parms=f1040000 +// : report_id=10 dev_idx=ff type=81 CMD_GET_PAIRED_DEVICES parms=f1040214 + + +// http://tequals0.wordpress.com/2011/11/01/reverse-engineering-logitech-unifying-usb-protocol/ +/* +T: Bus=05 Lev=01 Prnt=01 Port=01 Cnt=02 Dev#= 3 Spd=12 MxCh= 0 +D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1 +P: Vendor=046d ProdID=c52b Rev=12.01 +S: Manufacturer=Logitech +S: Product=USB Receiver +C:* #Ifs= 3 Cfg#= 1 Atr=a0 MxPwr= 98mA +I:* If#= 0 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=01 Prot=01 Driver=usbhid +E: Ad=81(I) Atr=03(Int.) MxPS= 8 Ivl=8ms +I:* If#= 1 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=01 Prot=02 Driver=usbhid +E: Ad=82(I) Atr=03(Int.) MxPS= 8 Ivl=2ms +I:* If#= 2 Alt= 0 #EPs= 1 Cls=03(HID ) Sub=00 Prot=00 Driver=usbhid +E: Ad=83(I) Atr=03(Int.) MxPS= 32 Ivl=2ms + +b=$'\e[1;32m';e=$'\e[m';sudo cat /sys/kernel/debug/usb/usbmon/5u | sed -ur "s/= (..)(..)(..)(..) (..)(....)(..)/= report_id=$b\1$e dev_idx=$b\2$e type=$b\3$e parms=$b\4\5 \6 \7$e/" + +see lt/usbmon.awk +awk -vOFS=' ' 'function l(s){return "\033[1;32m" s "\033[m"}{if(match($0,/(.*? = )(..)(..)(..)(..) (.*)/,a)){printf("%-85s",$0);print "report_id=" l(a[2]), "dev_idx=" l(a[3]), "type=" l(a[4]), "parms=" l(a[5] a[6])}else print "\033[1;30m" $0 "\033[m"}' + +*/ diff --git a/read-dev-usbmon.c b/read-dev-usbmon.c new file mode 100644 index 0000000..916bf37 --- /dev/null +++ b/read-dev-usbmon.c @@ -0,0 +1,150 @@ +/* + * Tool for reading usbmon messages and writing non-empty data to stdout. + * Because of limitations of a single output stream, there is currently a hack + * that directly includes hidraw.c. + * + * Copyright (C) 2013 Peter Wu + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include /* getenv */ + +typedef uint16_t u16; +typedef int32_t s32; +typedef uint64_t u64; +typedef int64_t s64; +#define SETUP_LEN 8 + +/* taken from Linux, Documentation/usb/usbmon.txt */ +struct usbmon_packet { + u64 id; /* 0: URB ID - from submission to callback */ + unsigned char type; /* 8: Same as text; extensible. */ + unsigned char xfer_type; /* ISO (0), Intr, Control, Bulk (3) */ + unsigned char epnum; /* Endpoint number and transfer direction */ + unsigned char devnum; /* Device address */ + u16 busnum; /* 12: Bus number */ + char flag_setup; /* 14: Same as text */ + char flag_data; /* 15: Same as text; Binary zero is OK. */ + s64 ts_sec; /* 16: gettimeofday */ + s32 ts_usec; /* 24: gettimeofday */ + int status; /* 28: */ + unsigned int length; /* 32: Length of data (submitted or actual) */ + unsigned int len_cap; /* 36: Delivered length */ + union { /* 40: */ + unsigned char setup[SETUP_LEN]; /* Only for Control S-type */ + struct iso_rec { /* Only for ISO */ + int error_count; + int numdesc; + } iso; + } s; + int interval; /* 48: Only for Interrupt and ISO */ + int start_frame; /* 52: For ISO */ + unsigned int xfer_flags; /* 56: copy of URB's transfer_flags */ + unsigned int ndesc; /* 60: Actual number of ISO descriptors */ +}; + +struct mon_get_arg { + struct usbmon_packet *hdr; + void *data; + size_t alloc; /* Length of data (can be zero) */ +}; + +#define MON_IOC_MAGIC 0x92 +#define MON_IOCQ_URB_LEN _IO(MON_IOC_MAGIC, 1) +#define MON_IOCX_GET _IOW(MON_IOC_MAGIC, 6, struct mon_get_arg) + +#define NO_MAIN +// HACK - otherwise there is no easy wat to tell whether a packet is read or +// written from the usbmon +#include "hidraw.c" +#undef NO_MAIN + +int main(int argc, char ** argv) { + unsigned char data[1024]; + struct usbmon_packet hdr; + struct mon_get_arg event; + int fd, r; + + if (argc < 2) { + fprintf(stderr, "Usage: %s /dev/usbmonX\n", argv[0]); + return 1; + } + + fd = open(argv[1], O_RDONLY); + if (fd < 0) { + perror(argv[1]); + return 1; + } + + memset(&hdr, 0, sizeof hdr); + event.hdr = &hdr; // hopefully it is OK to use stack for this + event.data = &data; + event.alloc = sizeof data; + + //r = ioctl(fd, MON_IOCQ_URB_LEN); + //printf("%i\n", r); + for (;;) { + memset(&data, 0xCC, sizeof data); // for debugging purposes + r = ioctl(fd, MON_IOCX_GET, &event); + if (r < 0) { + perror("ioctl"); + break; + } + + // ignore non-data packets + if (hdr.len_cap) { + if (getenv("HEX")) { + unsigned int i; + printf("Type=%c\n", hdr.type); + for (i=0; i +# Date: 2013-04-04 + +BEGIN { + OFS=" "; +# Taken from Linux source, drivers/hid/hid-logitech-dj.h +# Catgegories are taken from patent description of US8386651 +# 0x00 - 0x3F HID reports +types["01"] = "KEYBOARD"; +types["02"] = "MOUSE"; +types["03"] = "CONSUMER_CONTROL"; +types["04"] = "SYSTEM_CONTROL"; + +types["08"] = "MEDIA_CENTER"; + +types["0E"] = "LEDS"; + +# 0x40 - 0x7F enumerator notifications +types["40"] = "NOTIF_DEVICE_UNPAIRED"; +types["41"] = "NOTIF_DEVICE_PAIRED"; +types["42"] = "NOTIF_CONNECTION_STATUS"; +types["4A"] = "NOTIF_RECV_LOCK_CHANGED"; # 0100 0000 = ready for connections, 0010 0000 = new connections disabled +types["4B"] = "?NOTIF_PAIR_ACCEPTED"; # 0100 0000 + +types["7F"] = "NOTIF_ERROR"; + +# 0x80 - 0xFF enumerator commands; Register Access +types["80"] = "SET_REG"; # CMD_SWITCH +types["81"] = "GET_REG"; # CMD_GET_PAIRED_DEVICES +types["82"] = "SET_LONG_REG"; +types["83"] = "GET_LONG_REG"; +types["8F"] = "_ERROR_MSG"; +# Align type name +maxlen=0; +for (i in types) { + if (maxlen < length(types[i])) { + maxlen = length(types[i]); + } +} + +# error messages for type=8F (ERROR_MSG) +errmsgs["01"] = "SUCCESS"; +errmsgs["02"] = "INVALID_SUBID"; +errmsgs["03"] = "INVALID_ADDRESS"; +errmsgs["04"] = "INVALID_VALUE"; +errmsgs["05"] = "CONNECT_FAIL"; +errmsgs["06"] = "TOO_MANY_DEVICES"; +errmsgs["07"] = "ALREADY_EXISTS"; +errmsgs["08"] = "BUSY"; +errmsgs["09"] = "UNKNOWN_DEVICE"; +errmsgs["0a"] = "RESOURCE_ERROR"; +errmsgs["0b"] = "REQUEST_UNAVAILABLE"; +errmsgs["0c"] = "INVALID_PARAM_VALUE"; +errmsgs["0d"] = "WRONG_PIN_CODE"; + +regs["00"] = "ENABLED_NOTIFS"; +regs["02"] = "CONNECTION_STATE"; +regs["b2"] = "DEVICE_PAIRING"; +regs["b3"] = "DEVICE_ACTIVITY"; +regs["b5"] = "PAIRING_INFO"; +} # end of BEGIN +function colorize(col, s) { + return "\033[" col "m" s "\033[m"; +} +# global color +function c(s) { + return colorize(color, s); +} +function endPoint(ep) { + if (ep == "0") return "output"; + if (ep == "1") return " input"; + if (ep == "2") return colorize("1;33", "enumIf"); + # if (ep == "3") return " ???"; # seen in the output of usbmon + return sprintf("%6s", "ep" ep); +} +function dev(hex) { + if (hex == "ff") { + return "RECV"; + } + if (int(hex) >= 1 && int(hex) <= 6) { + return "DEV" int(hex) + } + return " "; +} +function typeStr(hex) { + return sprintf("%-" maxlen "s", types[toupper(hex)]); +} +function payload(type, p) { + v1 = substr(p, 1, 2); + if (type == "8f") { # error + er=substr(p, 5, 2); + reg=substr(p, 3, 2); + parms = "SubID=" v1 + parms = parms ", Reg=" c(reg) " " regs[reg]; + parms = parms ", er=" c(er); + parms = parms " " errmsgs[er]; + } else if (type == "80" || type == "81" || type == "82" || type == "83") { + parms = "reg=" c(v1) " " regs[v1]; + parms = parms " parms=" c(substr(p, 3)); + } else { + parms = "parms=" c(p); + } + return parms; +} + +{ + if (match($0, /.*?:[0-9]+:[0-9]{3,}:([0-9]+) .*? = (..)(..)(..)(..) (.*)/, a)) { + # length 85 is ok for most, but not when starting logitech program + if (length($0) > 100) { + print $0; + $0 = ""; + } + printf("%-100s", $0); + color = "1;32"; + # sending data instead of receiving data + if ($0 ~ " s ") color = "1;31"; + + print " " endPoint(a[1]), + "report_id=" c(a[2]), + "dev_idx=" c(a[3]) " " dev(a[3]), + "type=" c(a[4]) " " typeStr(a[4]), + payload(a[4], a[5] a[6]); + } else { + print colorize("1;30", $0); + } + fflush(); +} -- cgit v1.2.1