Initial commit of RE/debug programs/notes

This commit is contained in:
Peter Wu
2013-04-08 17:00:42 +02:00
commit 99bcaad18a
7 changed files with 1055 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
.*.sw*
read-dev-usbmon
hidraw

42
README.txt Normal file
View File

@@ -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 <lekensteyn@gmail.com>

237
hidraw.c Executable file
View File

@@ -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 <lekensteyn@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
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 */

207
notes.txt Normal file
View File

@@ -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"}'
*/

150
read-dev-usbmon.c Normal file
View File

@@ -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 <lekensteyn@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h> /* 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<hdr.len_cap; i++) {
printf("%02X%c", data[i],
i + 1 == hdr.len_cap ? '\n' : ' ');
}
} else {
struct report *report = (struct report *)&data;
if (hdr.len_cap < 3) {
fprintf(stderr, "Short data len: %i\n", hdr.len_cap);
continue;
}
#define COLOR(c, cstr) "\033[" c "m" cstr "\033[m"
if (hdr.type == 'C') {
printf(COLOR("1;32", "Recv\t"));
} else if (hdr.type == 'S') {
printf(COLOR("1;31", "Send\t"));
} else {
printf(COLOR("1;35", "Type=%c\t") "\n", hdr.type);
}
process_msg(report, hdr.len_cap);
fflush(NULL);
#if 0
if (write(STDOUT_FILENO, &data, hdr.len_cap) < 0) {
perror("write");
break;
}
#endif
}
}
}
close(fd);
return 0;
}

284
registers.txt Normal file
View File

@@ -0,0 +1,284 @@
Overview
USB VID 0x046d
USB PID 0xc52b
Message Sub ID
0x80 SET_REGISTER
0x81 GET_REGISTER
0x82 SET_LONG_REGISTER
0x83 GET_LONG_REGISTER
0x8F ERROR_MSG
Notifications
0x40 Device Disconnection
0x41 Device Connection
0x4A Unifying Receiver Locking Change information
Registers
0x00 Enable HID++ Notifications
0x02 Connection State
0xB2 Device Connection and Disconnection (Pairing)
0xB3 Device Activity
0xB5 Pairing Information
(more undocumented below)
Not documented:
Long register B5 (Pairing Information) - nn=03 "Receiver information?"
Send: 10 FF 83 B5 03 00 00 00 - Long (10) message for receiver (FF) to retrieve
long register (83) PairingInfo (B5) with special param 03 00 00 00.
Recv: 11 FF 83 B5 03 AF 4F 95 EA 05 06 0E 00 00 00 00 00 00 00 00
11 - Long message
FF - Receiver target
83 - LONG_REGISTER_RESPONSE
B5 - Pairing Info
03 - "Receiver information"?
AF 4F 95 EA - Serial Number of receiver
05
06 - Max Device Capability? (not sure, but it is six)
0E 00 00 00 00 00 00 00 00
Remaining information:
- Wireless Status (0x03)
- ModelId (0x46d c52b)
- Handle: 0xff000001 (0xff is device ID, 01 is internal to the software, ordered)
- Dfu Status (0x1)
- Is Dfu Cancellable (yes)
Short register F1 - "Version information" (guessed)
Header: 10 FF 81 (short msg, receiver is target, GET_REGISTER)
Data: F1 nn xx yy (xx yy is empty for request and contains version for response)
nn=01 xx,yy=12 01
nn=02 xx,yy=00 19
nn=03 error 03 (Invalid address) (but returns 00 07 for keyboard)
nn=04 xx,yy=02 14
Displayed firmware version: 012.001.00019 (x1 . y1 . x2 y2)
Displayed bootloader version: BL.002.014 (BL . x4 . y4)
10 ix 17 3C 00 00 0n
received when the keyboard illumination level is changed. (n = 1..5)
10 ix 07 07 00 00 00
received when battery level is requested using keyboard Fn+F7
More undocumented short regs:
17 rw Illumination info
get 00 00 00 - Retrieve illimunation status?
rsp: 3C 00 02 - (illimunation is disabled)
set 3C 00 01 - Activate illumination only when I start typing
set 3C 00 02 - Disable keyboard illumination
01 rw "Keyboard hand detection?"
get 00 00 00 - retrieve keyboard hand detection status?
rsp: 00 00 20 - (hand detection is disabled)
set 00 00 00 - Enable hand detection
set 00 00 20 - Disable hand detection
09 rw "F key functions"
get 00 00 00 - Retrieve F key function state
rsp: 00 00 00 - (F key functions are not swapped)
set 00 01 00 - Swap F key functions
set 00 00 00 - Do not swap F key functions
00 rw ENABLED_NOTIFS, 10 02 00, 10 is Battery info, buy what is 02?
07 r Likely the battery status of the kbd, not observed for M525 mouse
get 00 00 00
rsp: 07 00 00 - (Battery full?)
17 rw ???
Send report_id=10 short device=02 DEV2 type=81 GET_REG reg=17 params=00 00 00
report_id=10 short device=02 DEV2 type=81 GET_REG reg=17 params=3C 00 01
Send report_id=10 short device=02 DEV2 type=80 SET_REG reg=17 params=3C 00 01
report_id=10 short device=02 DEV2 type=80 SET_REG reg=17 params=00 00 00
Send report_id=10 short device=02 DEV2 type=81 GET_REG reg=01 params=00 00 00
report_id=10 short device=02 DEV2 type=81 GET_REG reg=01 params=00 00 00
Send report_id=10 short device=02 DEV2 type=80 SET_REG reg=01 params=00 00 00
report_id=10 short device=02 DEV2 type=80 SET_REG reg=01 params=00 00 00
Send report_id=10 short device=02 DEV2 type=81 GET_REG reg=09 params=00 00 00
report_id=10 short device=02 DEV2 type=81 GET_REG reg=09 params=00 00 00
Send report_id=10 short device=02 DEV2 type=80 SET_REG reg=09 params=00 00 00
report_id=10 short device=02 DEV2 type=80 SET_REG reg=09 params=00 00 00
Send report_id=10 short device=02 DEV2 type=81 GET_REG reg=07 params=00 00 00
report_id=10 short device=02 DEV2 type=81 GET_REG reg=07 params=07 00 00
Send report_id=10 short device=02 DEV2 type=81 GET_REG reg=00 ENABLED_NOTIFS params=00 00 00
report_id=10 short device=02 DEV2 type=81 GET_REG reg=00 ENABLED_NOTIFS params=10 02 00
Send report_id=10 short device=02 DEV2 type=80 SET_REG reg=00 ENABLED_NOTIFS params=10 02 00
report_id=10 short device=02 DEV2 type=80 SET_REG reg=00 ENABLED_NOTIFS params=00 00 00
Send report_id=10 short device=02 DEV2 type=81 GET_REG reg=17 params=00 00 00
report_id=10 short device=02 DEV2 type=81 GET_REG reg=17 params=3C 00 01
Send report_id=10 short device=02 DEV2 type=80 SET_REG reg=17 params=3C 00 01
report_id=10 short device=02 DEV2 type=80 SET_REG reg=17 params=00 00 00
Send report_id=10 short device=02 DEV2 type=81 GET_REG reg=01 params=00 00 00
report_id=10 short device=02 DEV2 type=81 GET_REG reg=01 params=00 00 00
Send report_id=10 short device=02 DEV2 type=80 SET_REG reg=01 params=00 00 00
report_id=10 short device=02 DEV2 type=80 SET_REG reg=01 params=00 00 00
Send report_id=10 short device=02 DEV2 type=81 GET_REG reg=09 params=00 00 00
report_id=10 short device=02 DEV2 type=81 GET_REG reg=09 params=00 00 00
Send report_id=10 short device=02 DEV2 type=80 SET_REG reg=09 params=00 00 00
report_id=10 short device=02 DEV2 type=80 SET_REG reg=09 params=00 00 00
Send report_id=10 short device=02 DEV2 type=81 GET_REG reg=07 params=00 00 00
report_id=10 short device=02 DEV2 type=81 GET_REG reg=07 params=07 00 00
Documented in hidpp10:
Allows for testing protocol version.
Request: 10 DeviceIndex 00 1n 00 00 uu
- n is SwId
- UU is "ping data" defined by SW
Responses:
HID++ 1.0: 10 ix 8F 00 Fn 01 00 (ERR_INVALID_SUBID)
HID++ 2.0: 10 ix 00 1n 02 00 UU
HID++ X.Y: 10 ix 00 1n XX YY UU
Discovery:
1. Get Reg 00
2. Set Reg 00 to value from (1) with bit 0 of the second byte enabled (v1[1] |= 1)
3. Send read CONNECTION_STATE register for total number of devices
4. Write CONNECTION_STATE 02 00 00 register
5. (4) triggers a 0x41 notification (Device Paired notification) for each
device. Note, device index does not have to start at 1 (if device got
unpaired before).
5. Got response for (3).
6. (disable discovery) Get Reg 00
7. Set Reg 00 to value from (6) with bit 0 of the second byte disabled (v1[1] &= ~1)
Startup (all targeted at receiver, notifications come from device 1..6):
1. Get receiver details from pairing info register (serial number, etc)
2. Get firmware version (recv)
3. Get bootloader version (recv)
4. Get enabled notifications
5. Enable wireless notifications (set enabled notifs reg)
6. Read connection state register for number of machines
for each machine from (6):
7. Write params to connection state register (02 00 00 was written) (read
returns after (8)) (possibly a "trigger report all paired devices")
8. (7) immediately triggers a Device Paired notification for a previously paired dev
9. Send/Read request for paired device device name
10. Send/Read request for paired device extended info (serial, .., location of power switch)
11. Read fw+bootloader version information again (this seems useless?)
A1. Pairing starts: write DEVICE_PAIRING register, enable pairing with timeout (read returns after (A2))
A2. (A1) triggers Receiver Lock Changed notification (subid=0x41) (reason: no error)
A3. On timeout, Receiver Lock Changed notification is received (reason: timeout)
A4. (close button) On close, DEVICE_PAIRING register is written to disable pairing discovery
A5. Receiver Lock Changed notification is immediately received (reason: timeout)
Advanced:
B1. Advanced button is pressed. Polling starts, every x time, DEVICE_ACTIVITY register request is sent/read
B2. Unpair device, Device Unpaired notification (subid=0x40) received (reason:
device disconnected) (note, report id 10 and 20 received, ignore 20)
Send report_id=10 short device=FF RECV type=83 GET_LONG_REG reg=B5 PAIRING_INFO params=03 00 00
report_id=11 long device=FF RECV type=83 GET_LONG_REG reg=B5 PAIRING_INFO params=03 AF 4F 95 EA 05 06 0E 00 00 00 00 00 00 00 00
Send report_id=10 short device=FF RECV type=81 GET_REG reg=F1 VERSION_INFO? params=01 00 00
report_id=10 short device=FF RECV type=81 GET_REG reg=F1 VERSION_INFO? params=01 12 01
Send report_id=10 short device=FF RECV type=81 GET_REG reg=F1 VERSION_INFO? params=02 00 00
report_id=10 short device=FF RECV type=81 GET_REG reg=F1 VERSION_INFO? params=02 00 19
Send report_id=10 short device=FF RECV type=81 GET_REG reg=F1 VERSION_INFO? params=03 00 00
report_id=10 short device=FF RECV type=8F _ERROR_MSG SubID=81 GET_REG reg=F1 VERSION_INFO? err=03 INVALID_ADDRESS
Send report_id=10 short device=FF RECV type=81 GET_REG reg=F1 VERSION_INFO? params=04 00 00
report_id=10 short device=FF RECV type=81 GET_REG reg=F1 VERSION_INFO? params=04 02 14
Send report_id=10 short device=FF RECV type=81 GET_REG reg=00 ENABLED_NOTIFS params=00 00 00
report_id=10 short device=FF RECV type=81 GET_REG reg=00 ENABLED_NOTIFS params=00 01 00
Send report_id=10 short device=FF RECV type=80 SET_REG reg=00 ENABLED_NOTIFS params=00 01 00
report_id=10 short device=FF RECV type=80 SET_REG reg=00 ENABLED_NOTIFS params=00 00 00
Send report_id=10 short device=FF RECV type=81 GET_REG reg=02 CONNECTION_STATE params=00 00 00
report_id=10 short device=FF RECV type=81 GET_REG reg=02 CONNECTION_STATE params=00 01 00
Send report_id=10 short device=FF RECV type=80 SET_REG reg=02 CONNECTION_STATE params=02 00 00
report_id=10 short device=01 DEV1 type=41 NOTIF_DEVICE_PAIRED params=04 61 10 20
report_id=10 short device=FF RECV type=80 SET_REG reg=02 CONNECTION_STATE params=00 00 00
Send report_id=10 short device=FF RECV type=83 GET_LONG_REG reg=B5 PAIRING_INFO params=40 00 00
report_id=11 long device=FF RECV type=83 GET_LONG_REG reg=B5 PAIRING_INFO params=40 04 4B 38 30 30 00 00 00 00 00 00 00 00 00 00
Send report_id=10 short device=FF RECV type=83 GET_LONG_REG reg=B5 PAIRING_INFO params=30 00 00
report_id=11 long device=FF RECV type=83 GET_LONG_REG reg=B5 PAIRING_INFO params=30 FB 84 1B 86 1A 40 00 00 07 00 00 00 00 00 00
Send report_id=10 short device=FF RECV type=81 GET_REG reg=F1 VERSION_INFO? params=01 00 00
report_id=10 short device=FF RECV type=81 GET_REG reg=F1 VERSION_INFO? params=01 12 01
Send report_id=10 short device=FF RECV type=81 GET_REG reg=F1 VERSION_INFO? params=02 00 00
report_id=10 short device=FF RECV type=81 GET_REG reg=F1 VERSION_INFO? params=02 00 19
Send report_id=10 short device=FF RECV type=81 GET_REG reg=F1 VERSION_INFO? params=03 00 00
report_id=10 short device=FF RECV type=8F _ERROR_MSG SubID=81 GET_REG reg=F1 VERSION_INFO? err=03 INVALID_ADDRESS
Send report_id=10 short device=FF RECV type=81 GET_REG reg=F1 VERSION_INFO? params=04 00 00
report_id=10 short device=FF RECV type=81 GET_REG reg=F1 VERSION_INFO? params=04 02 14
No paired devices, start pairing:
1. Enable device pairing (response read returns after (2))
2. Got receiver lock notification (locking open)
3. Enable device, got Device Paired notif (kbd, link encrypted, link not established)
4. Send read request for device name (response in (6))
(5. got report_id=20 for device paired notif)
5. Got Receiver Lock changed notification (lock closed)
6. Response for device name (sent in (4)), Send/Read request for paired device
extended info (serial, .., location of power switch)
7. Got Device Paired notif (kbd, link encrypted, link established, link with payload)
8. (??) Send dev1 [header 10 01 00] 12 28 3F 94
9. Got notification ("Pair accepted"?) [header 10 01 4B] 01 00 00 00
10. Dev1 request (8) returned error message (err=01 SUCCESS)
11. Read dev1 register 0D, but it returns an error (err=02 INVALID_SUBID)
12. Request/read dev1 register 07
13. Read dev1 firmware, bootloader version
14. Read recv firmware, bootloader version
15. Write DEVICE_PAIRING register (close lock)
16. Got Receiver Lock changed notification (lock closed) (was already closed in (5) though)
Send report_id=10 short device=FF RECV type=80 SET_REG reg=B2 DEVICE_PAIRING params=01 53 3C
report_id=10 short device=FF RECV type=4A NOTIF_RECV_LOCK_CHANGED params=01 00 00 00
report_id=10 short device=FF RECV type=80 SET_REG reg=B2 DEVICE_PAIRING params=00 00 00
report_id=10 short device=01 DEV1 type=41 NOTIF_DEVICE_PAIRED params=04 61 10 20
Send report_id=10 short device=FF RECV type=83 GET_LONG_REG reg=B5 PAIRING_INFO params=40 00 00
report_id=20 unkn device=01 DEV1 type=41 NOTIF_DEVICE_PAIRED params=00 10 20 1A 40 00 00 00 00 00 00 00
report_id=10 short device=FF RECV type=4A NOTIF_RECV_LOCK_CHANGED params=00 00 00 00
report_id=11 long device=FF RECV type=83 GET_LONG_REG reg=B5 PAIRING_INFO params=40 04 4B 38 30 30 00 00 00 00 00 00 00 00 00 00
Send report_id=10 short device=FF RECV type=83 GET_LONG_REG reg=B5 PAIRING_INFO params=30 00 00
report_id=11 long device=FF RECV type=83 GET_LONG_REG reg=B5 PAIRING_INFO params=30 FB 84 1B 86 1A 40 00 00 07 00 00 00 00 00 00
report_id=10 short device=01 DEV1 type=41 NOTIF_DEVICE_PAIRED params=04 A1 10 20
Send report_id=10 short device=01 DEV1 type=00 params=12 28 3F 94
report_id=10 short device=01 DEV1 type=4B ?NOTIF_PAIR_ACCEPTED params=01 00 00 00
report_id=10 short device=01 DEV1 type=8F _ERROR_MSG SubID=00 reg=12 err=01 SUCCESS
Send report_id=10 short device=01 DEV1 type=81 GET_REG reg=0D params=00 00 00
report_id=10 short device=01 DEV1 type=8F _ERROR_MSG SubID=81 GET_REG reg=0D err=02 INVALID_SUBID
Send report_id=10 short device=01 DEV1 type=81 GET_REG reg=07 params=00 00 00
report_id=10 short device=01 DEV1 type=81 GET_REG reg=07 params=07 00 00
Send report_id=10 short device=01 DEV1 type=81 GET_REG reg=F1 VERSION_INFO? params=01 00 00
report_id=10 short device=01 DEV1 type=81 GET_REG reg=F1 VERSION_INFO? params=01 22 01
Send report_id=10 short device=01 DEV1 type=81 GET_REG reg=F1 VERSION_INFO? params=02 00 00
report_id=10 short device=01 DEV1 type=81 GET_REG reg=F1 VERSION_INFO? params=02 00 19
Send report_id=10 short device=01 DEV1 type=81 GET_REG reg=F1 VERSION_INFO? params=03 00 00
report_id=10 short device=01 DEV1 type=81 GET_REG reg=F1 VERSION_INFO? params=03 00 07
Send report_id=10 short device=01 DEV1 type=81 GET_REG reg=F1 VERSION_INFO? params=04 00 00
report_id=10 short device=01 DEV1 type=81 GET_REG reg=F1 VERSION_INFO? params=04 02 01
Send report_id=10 short device=FF RECV type=81 GET_REG reg=F1 VERSION_INFO? params=01 00 00
report_id=10 short device=FF RECV type=81 GET_REG reg=F1 VERSION_INFO? params=01 12 01
Send report_id=10 short device=FF RECV type=81 GET_REG reg=F1 VERSION_INFO? params=02 00 00
report_id=10 short device=FF RECV type=81 GET_REG reg=F1 VERSION_INFO? params=02 00 19
Send report_id=10 short device=FF RECV type=81 GET_REG reg=F1 VERSION_INFO? params=03 00 00
report_id=10 short device=FF RECV type=8F _ERROR_MSG SubID=81 GET_REG reg=F1 VERSION_INFO? err=03 INVALID_ADDRESS
Send report_id=10 short device=FF RECV type=81 GET_REG reg=F1 VERSION_INFO? params=04 00 00
report_id=10 short device=FF RECV type=81 GET_REG reg=F1 VERSION_INFO? params=04 02 14
Send report_id=10 short device=FF RECV type=80 SET_REG reg=B2 DEVICE_PAIRING params=02 53 94
report_id=10 short device=FF RECV type=80 SET_REG reg=B2 DEVICE_PAIRING params=00 00 00
report_id=10 short device=FF RECV type=4A NOTIF_RECV_LOCK_CHANGED params=00 00 00 00
Somewhere in the below stream is the battery condition of the M525 mouse (good).
Recv report_id=10 short device=01 DEV1 type=41 NOTIF_DEVICE_PAIRED params=04 52 13 40
Recv report_id=10 short device=FF RECV type=80 SET_REG reg=02 CONNECTION_STATE params=00 00 00
Send report_id=10 short device=FF RECV type=83 GET_LONG_REG reg=B5 PAIRING_INFO params=30 00 00
Recv report_id=11 long device=FF RECV type=83 GET_LONG_REG reg=B5 PAIRING_INFO params=30 DA FA 33 5E 04 00 00 00 01 00 00 00 00 00 00
Recv report_id=10 short device=01 DEV1 type=41 NOTIF_DEVICE_PAIRED params=04 92 13 40
Recv report_id=20 unkn device=01 DEV1 type=42 NOTIF_CONNECTION_STATUS params=00 00 00 00 00 00 00 00 00 00 00 00
Send report_id=10 short device=FF RECV type=83 GET_LONG_REG reg=B5 PAIRING_INFO params=30 00 00
Recv report_id=11 long device=01 DEV1 type=05 params=00 01 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00
Recv report_id=11 long device=FF RECV type=83 GET_LONG_REG reg=B5 PAIRING_INFO params=30 DA FA 33 5E 04 00 00 00 01 00 00 00 00 00 00
Send report_id=10 short device=01 DEV1 type=00 params=05 00 03 00
Recv report_id=11 long device=01 DEV1 type=00 params=05 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Send report_id=10 short device=01 DEV1 type=02 MOUSE params=05 00 00 00
Recv report_id=11 long device=01 DEV1 type=02 MOUSE params=05 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Send report_id=10 short device=01 DEV1 type=02 MOUSE params=15 00 00 00
Recv report_id=11 long device=01 DEV1 type=02 MOUSE params=15 00 52 51 4D 27 02 00 28 00 40 13 00 00 00 00 00
Send report_id=10 short device=01 DEV1 type=04 SYSTEM_CONTROL params=05 00 00 00
Recv report_id=11 long device=01 DEV1 type=04 SYSTEM_CONTROL params=05 5A 05 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Send report_id=10 short device=01 DEV1 type=0B params=15 01 00 00
Recv report_id=11 long device=01 DEV1 type=0B params=15 01 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Recv report_id=20 unkn device=01 DEV1 type=02 MOUSE params=00 00 00 00 00 FF 00 00 00 00 00 00
Recv report_id=20 unkn device=01 DEV1 type=02 MOUSE params=00 00 00 00 00 FF 00 00 00 00 00 00

132
usbmon.awk Executable file
View File

@@ -0,0 +1,132 @@
#!/usr/bin/gawk -f
# Formats the output of usbmon, assuming Logitech Unifying Receiver protocol
# Usage: sudo cat /sys/kernel/debug/usb/usbmon/5u | usbmon.awk
# (on older gawk versions, use gawk --re-interval -f usbmon.awk)
#
# Author: Peter Wu <lekensteyn@gmail.com>
# 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();
}