воскресенье, 30 января 2022 г.

USB HID device debug in linux

Unfortunately there is no simple solution who gives you the full trace of data stream. But there are some tools who can help you when you try to write your own keyboard driver for example.

lsusb

Initially identify your devices using lsusb command. Simply run lsusb. Here you can take vid:pid identificator pair for further tests. Also lsusb command can help you to see all descriptors except report with command:

lsusb -v -d 0x046d:0xc221

My lsusb output:
dltech@dltech-IC780M-A2:~/src/usb_device3$ lsusb
Bus 007 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 006 Device 002: ID 1c4f:0034 SiGma Micro XM102K Optical Wheel Mouse
Bus 006 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 005 Device 004: ID 1a2c:2d23 China Resource Semico Co., Ltd Keyboard
Bus 005 Device 024: ID 046d:c221 Logitech, Inc. G11/G15 Keyboard / Keyboard
Bus 005 Device 023: ID 0483:3748 STMicroelectronics ST-LINK/V2
Bus 005 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
dltech@dltech-IC780M-A2:~/src/usb_device3$ sudo lsusb -v -d 0x046d:0xc221

Bus 005 Device 024: ID 046d:c221 Logitech, Inc. G11/G15 Keyboard / Keyboard
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0        64
  idVendor           0x046d Logitech, Inc.
  idProduct          0xc221 G11/G15 Keyboard / Keyboard
  bcdDevice            1.00
  iManufacturer           1 dltech
  iProduct                2 tv remote
  iSerial                 0 
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength       0x0022
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0xa0
      (Bus Powered)
      Remote Wakeup
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      1 Boot Interface Subclass
      bInterfaceProtocol      1 Keyboard
      iInterface              0 
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.10
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength      63
         Report Descriptors: 
           ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval              32
Device Qualifier (for other device speed):
  bLength                10
  bDescriptorType         6
  bcdUSB               2.00
  bDeviceClass            0 
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0        64
  bNumConfigurations      0
can't get debug descriptor: Resource temporarily unavailable
Device Status:     0x0000
  (Bus Powered)

usbhid-dump

It utility work with device at low level, using libusb. In my case I test my USB STM32 keyboard firmware. It's command:

sudo usbhid-dump -m 0x046d:0xc221 -e "all" -t 5000

Where -m 0x046d:0xc221 are VID:PID and -t 5000 is timeout of test.

Here you can see it's data dump:
dltech@dltech-IC780M-A2:~/src/usb_device3$ sudo usbhid-dump -m 0x046d:0xc221 -e"all" -t 5000
005:029:000:DESCRIPTOR         1643490384.570737
 05 01 09 06 A1 01 05 07 19 E0 29 E7 15 00 25 01
 75 01 95 08 81 02 95 01 75 08 81 01 95 01 75 01
 05 08 19 01 29 01 91 02 95 01 75 07 91 01 95 06
 75 08 15 00 25 65 05 07 19 00 29 81 81 00 C0

Starting dumping interrupt transfer stream
with 5 seconds timeout.

005:029:000:STREAM             1643490386.252786
 00 00 04 00 00 00 00 00

005:029:000:STREAM             1643490386.540785
 00 00 00 00 00 00 00 00

005:029:000:STREAM             1643490389.548860
 00 00 04 00 00 00 00 00

005:029:000:STREAM             1643490389.836863
 00 00 00 00 00 00 00 00

005:029:000:Interrupt transfer timed out
No more interfaces to dump

Firstly here is a report descriptor, then it shows obtained reports, which signalings a button push. In order to check my fw properly, I compare descriptor and report data with similar ones from keyboard of my PC. After a few edits of the code, I got similar results for my keyboard as factory one. It is important not to modify too much standard report format, cause typical one, suggested as example in standard is BIOS compatible. Also you can add extra custom configurations who can be chosen by OS driver.

evtest

That utility work with the kernel. So it shows device data already translated by kernel driver. In order to use it, run it as root and find your device in the list. Secondly run test for your keyboard using command:

sudo su -c 'sleep 1; timeout -k5 10 evtest --grab /dev/input/event2'

And if in previous case we seen a standard keyboard report package with 0x04='a' key keyboard code. In evtest dump at the same moment we can see an event with 'a' key push.

evtest dump:
dltech@dltech-IC780M-A2:~/src/usb_device3$ sudo su -c 'sleep 1; timeout -k5 10 evtest --grab /dev/input/event11'
aInput driver version is 1.0.1
Input device ID: bus 0x3 vendor 0x46d product 0xc221 version 0x110
Input device name: "dltech tv remote"
Supported events:
  Event type 0 (EV_SYN)
  Event type 1 (EV_KEY)
    Event code 1 (KEY_ESC)
    Event code 2 (KEY_1)
    Event code 3 (KEY_2)
    Event code 4 (KEY_3)
    Event code 5 (KEY_4)
    Event code 6 (KEY_5)
    Event code 7 (KEY_6)
    Event code 8 (KEY_7)
    Event code 9 (KEY_8)
    Event code 10 (KEY_9)
    Event code 11 (KEY_0)
    Event code 12 (KEY_MINUS)
    Event code 13 (KEY_EQUAL)
    Event code 14 (KEY_BACKSPACE)
    Event code 15 (KEY_TAB)
    Event code 16 (KEY_Q)
    Event code 17 (KEY_W)
    Event code 18 (KEY_E)
    Event code 19 (KEY_R)
    Event code 20 (KEY_T)
    Event code 21 (KEY_Y)
    Event code 22 (KEY_U)
    Event code 23 (KEY_I)
    Event code 24 (KEY_O)
    Event code 25 (KEY_P)
    Event code 26 (KEY_LEFTBRACE)
    Event code 27 (KEY_RIGHTBRACE)
    Event code 28 (KEY_ENTER)
    Event code 29 (KEY_LEFTCTRL)
    Event code 30 (KEY_A)
    Event code 31 (KEY_S)
    Event code 32 (KEY_D)
    Event code 33 (KEY_F)
    Event code 34 (KEY_G)
    Event code 35 (KEY_H)
    Event code 36 (KEY_J)
    Event code 37 (KEY_K)
    Event code 38 (KEY_L)
    Event code 39 (KEY_SEMICOLON)
    Event code 40 (KEY_APOSTROPHE)
    Event code 41 (KEY_GRAVE)
    Event code 42 (KEY_LEFTSHIFT)
    Event code 43 (KEY_BACKSLASH)
    Event code 44 (KEY_Z)
    Event code 45 (KEY_X)
    Event code 46 (KEY_C)
    Event code 47 (KEY_V)
    Event code 48 (KEY_B)
    Event code 49 (KEY_N)
    Event code 50 (KEY_M)
    Event code 51 (KEY_COMMA)
    Event code 52 (KEY_DOT)
    Event code 53 (KEY_SLASH)
    Event code 54 (KEY_RIGHTSHIFT)
    Event code 55 (KEY_KPASTERISK)
    Event code 56 (KEY_LEFTALT)
    Event code 57 (KEY_SPACE)
    Event code 58 (KEY_CAPSLOCK)
    Event code 59 (KEY_F1)
    Event code 60 (KEY_F2)
    Event code 61 (KEY_F3)
    Event code 62 (KEY_F4)
    Event code 63 (KEY_F5)
    Event code 64 (KEY_F6)
    Event code 65 (KEY_F7)
    Event code 66 (KEY_F8)
    Event code 67 (KEY_F9)
    Event code 68 (KEY_F10)
    Event code 69 (KEY_NUMLOCK)
    Event code 70 (KEY_SCROLLLOCK)
    Event code 71 (KEY_KP7)
    Event code 72 (KEY_KP8)
    Event code 73 (KEY_KP9)
    Event code 74 (KEY_KPMINUS)
    Event code 75 (KEY_KP4)
    Event code 76 (KEY_KP5)
    Event code 77 (KEY_KP6)
    Event code 78 (KEY_KPPLUS)
    Event code 79 (KEY_KP1)
    Event code 80 (KEY_KP2)
    Event code 81 (KEY_KP3)
    Event code 82 (KEY_KP0)
    Event code 83 (KEY_KPDOT)
    Event code 86 (KEY_102ND)
    Event code 87 (KEY_F11)
    Event code 88 (KEY_F12)
    Event code 96 (KEY_KPENTER)
    Event code 97 (KEY_RIGHTCTRL)
    Event code 98 (KEY_KPSLASH)
    Event code 99 (KEY_SYSRQ)
    Event code 100 (KEY_RIGHTALT)
    Event code 102 (KEY_HOME)
    Event code 103 (KEY_UP)
    Event code 104 (KEY_PAGEUP)
    Event code 105 (KEY_LEFT)
    Event code 106 (KEY_RIGHT)
    Event code 107 (KEY_END)
    Event code 108 (KEY_DOWN)
    Event code 109 (KEY_PAGEDOWN)
    Event code 110 (KEY_INSERT)
    Event code 111 (KEY_DELETE)
    Event code 113 (KEY_MUTE)
    Event code 114 (KEY_VOLUMEDOWN)
    Event code 115 (KEY_VOLUMEUP)
    Event code 116 (KEY_POWER)
    Event code 117 (KEY_KPEQUAL)
    Event code 119 (KEY_PAUSE)
    Event code 125 (KEY_LEFTMETA)
    Event code 126 (KEY_RIGHTMETA)
    Event code 127 (KEY_COMPOSE)
    Event code 128 (KEY_STOP)
    Event code 129 (KEY_AGAIN)
    Event code 130 (KEY_PROPS)
    Event code 131 (KEY_UNDO)
    Event code 132 (KEY_FRONT)
    Event code 133 (KEY_COPY)
    Event code 134 (KEY_OPEN)
    Event code 135 (KEY_PASTE)
    Event code 136 (KEY_FIND)
    Event code 137 (KEY_CUT)
    Event code 138 (KEY_HELP)
    Event code 183 (KEY_F13)
    Event code 184 (KEY_F14)
    Event code 185 (KEY_F15)
    Event code 186 (KEY_F16)
    Event code 187 (KEY_F17)
    Event code 188 (KEY_F18)
    Event code 189 (KEY_F19)
    Event code 190 (KEY_F20)
    Event code 191 (KEY_F21)
    Event code 192 (KEY_F22)
    Event code 193 (KEY_F23)
    Event code 194 (KEY_F24)
  Event type 4 (EV_MSC)
    Event code 4 (MSC_SCAN)
  Event type 17 (EV_LED)
    Event code 0 (LED_NUML) state 1
Key repeat handling:
  Repeat type 20 (EV_REP)
    Repeat code 0 (REP_DELAY)
      Value    250
    Repeat code 1 (REP_PERIOD)
      Value     33
Properties:
Testing ... (interrupt to exit)
Event: time 1643491343.681559, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70004
Event: time 1643491343.681559, type 1 (EV_KEY), code 30 (KEY_A), value 1
Event: time 1643491343.681559, -------------- SYN_REPORT ------------
Event: time 1643491343.949867, type 1 (EV_KEY), code 30 (KEY_A), value 2
Event: time 1643491343.949867, -------------- SYN_REPORT ------------
Event: time 1643491343.949867, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70004
Event: time 1643491343.949867, type 1 (EV_KEY), code 30 (KEY_A), value 0
Event: time 1643491343.949867, -------------- SYN_REPORT ------------
Event: time 1643491346.977628, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70004
Event: time 1643491346.977628, type 1 (EV_KEY), code 30 (KEY_A), value 1
Event: time 1643491346.977628, -------------- SYN_REPORT ------------
Event: time 1643491347.245867, type 1 (EV_KEY), code 30 (KEY_A), value 2
Event: time 1643491347.245867, -------------- SYN_REPORT ------------
Event: time 1643491347.245867, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70004
Event: time 1643491347.245867, type 1 (EV_KEY), code 30 (KEY_A), value 0
Event: time 1643491347.245867, -------------- SYN_REPORT ------------
Event: time 1643491350.273700, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70004
Event: time 1643491350.273700, type 1 (EV_KEY), code 30 (KEY_A), value 1
Event: time 1643491350.273700, -------------- SYN_REPORT ------------
Event: time 1643491350.541867, type 1 (EV_KEY), code 30 (KEY_A), value 2
Event: time 1643491350.541867, -------------- SYN_REPORT ------------
Event: time 1643491350.541867, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70004
Event: time 1643491350.541867, type 1 (EV_KEY), code 30 (KEY_A), value 0
Event: time 1643491350.541867, -------------- SYN_REPORT ------------

Now, when I proven that my keyboard is recognized by both test programs (usbhid-dump and evtest) I can be sure in my controller firmware variant. Although at first test it passed test of usbhid but was partially working in evtest. The problem was in LEDs, linux driver ignores keyboard without numlock and capslock LEDs. In fine, when I added fake LEDs to my firmware, my custom keyboard work properly.

Of coure, keyboard firmware is a simple extention of gamepad firmware. You can find both in the same repo.

2 комментария :