mirror of
https://github.com/Lekensteyn/ltunify.git
synced 2025-12-08 17:53:23 +00:00
Initial commit of RE/debug programs/notes
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
.*.sw*
|
||||
read-dev-usbmon
|
||||
hidraw
|
||||
42
README.txt
Normal file
42
README.txt
Normal 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
237
hidraw.c
Executable 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
207
notes.txt
Normal 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
150
read-dev-usbmon.c
Normal 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
284
registers.txt
Normal 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
132
usbmon.awk
Executable 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();
|
||||
}
|
||||
Reference in New Issue
Block a user