← index #6953Issue #1123
Off-topic · high · value 0.308
QUERY · ISSUE

stm32 HID class USB crash explained

openby doc-hexopened 2021-02-23updated 2024-09-13

Problem: If you call pyb.USB_HID().recv(...) before the USB device is enumerated by the host, a null pointer is dereferenced and hard fault results immediately.

This happens because the HID interface object is not initialized: usb_device.usbd_cdc_msc_hid_state.hid and in particular usb_device.usbd_cdc_msc_hid_state.hid.usbd are zeros.

The init should happen:

  • when the device is enumerated (SetConfig chapter 9 code) in USBD_SetClassConfig
  • calls USBD_CDC_MSC_HID_Init which calls usbd_cdc_state_init
  • I could not find any other paths that might initialize the usbd field in particular; the other fields are also wrong, such as defaulting to dev_speed == USBD_SPEED_HIGH even on my board which can't do high speed, because USBD_SPEED_HIGH is zero.

The null de-ref happens inside USBD_HID_ReceivePacket(&hid->base...) when called by usbd_hid_rx() and it only gets that far (thinking that zero bytes have been received already) because it looks at the un-initialized usbd_hid_itf_t *hid and sees zero for hid->report_in_len rather than USBD_HID_REPORT_INVALID which would be more appropriate in this state.

My workaround, on ports/stm32/usbd_hid_interface.c:

--- a/ports/stm32/usbd_hid_interface.c
+++ b/ports/stm32/usbd_hid_interface.c
@@ -49,7 +49,7 @@ int8_t usbd_hid_receive(usbd_hid_state_t *hid_in, size_t len) {
 int usbd_hid_rx(usbd_hid_itf_t *hid, size_t len, uint8_t *buf, uint32_t timeout_ms) {
     // Wait for an incoming report
     uint32_t t0 = mp_hal_ticks_ms();
-    while (hid->report_in_len == USBD_HID_REPORT_INVALID) {
+    while (hid->report_in_len == USBD_HID_REPORT_INVALID || !hid->base.usbd) {
         if (mp_hal_ticks_ms() - t0 >= timeout_ms || query_irq() == IRQ_STATE_DISABLED) {
             return -MP_ETIMEDOUT;
         }
@@ -62,6 +62,7 @@ int usbd_hid_rx(usbd_hid_itf_t *hid, size_t len, uint8_t *buf, uint32_t timeout_
 
     // Schedule to receive next incoming report
     hid->report_in_len = USBD_HID_REPORT_INVALID;
+    assert(hid->base.usbd);
     USBD_HID_ReceivePacket(&hid->base, &hid->report_in_buf[0]);

I can't explain why this bug isn't seen more often, but I think what was covering it for me was that pyb_usb_dev_init() gets called after the end of boot.py and so was defaulting to VCP+HID+MSC but I've recently changed things so that USB doesn't get enabled until sometime much later in main.py (ie. I called pyb.usb_mode(None) in boot.py) and that initialized the composite USB device as "VCP+HID". I suspect something in the code path for the MSC setup initializes the HID interface state before enumeration, but I can't confirm that.

CANDIDATE · ISSUE

HID messages touchscreen problem

closedby ice3opened 2015-02-17updated 2018-06-20
port-stm32

Hello,

I want to "create" a touch screen (more exactly only the touch part) with micropython.
I use a custom HID descriptor.

Here is my config :
board : stm32f4 discovery

Micro Python v1.3.10-33-gee831ca on 2015-02-16; F4DISC with STM32F407
Type "help()" for more information.

host :

➭ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 14.04.1 LTS
Release:    14.04
Codename:   trusty

Here is boot.py :


import pyb
#pyb.main('main.py') # main script to run after this one
hid_desc = bytes([
    0x05, 0x0D,        # Usage Page (Digitizer)
    0x09, 0x04,        # Usage (Touch Screen)
    0xA1, 0x01,        # Collection (Application)
    0x85, 0x03,        #   Report ID (3)
    0x05, 0x0D,        #   Usage Page (Digitizer)
    0x09, 0x54,        #   Usage (Contact count)
    0x95, 0x01,        #   Report Count (1)
    0x75, 0x08,        #   Report Size (8)
    0x81, 0x02,        #   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x06, 0x00, 0xFF,  #   Usage Page (Vendor Defined 0xFF00)
    0x75, 0x02,        #   Report Size (2)
    0x09, 0x01,        #   Usage (Button 1 ?)
    0x81, 0x01,        #   Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x75, 0x0E,        #   Report Size (14)
    0x09, 0x02,        #   Usage (0x02)
    0x81, 0x02,        #   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x05, 0x0D,        #   Usage Page (Digitizer)
    0x09, 0x22,        #   Usage (Finger)
    0xA1, 0x02,        #   Collection (Logical)
    0x05, 0x01,        #     Usage Page (Generic Desktop Ctrls)
    0x16, 0x00, 0x00,  #     Logical Minimum (0)
    0x26, 0xFF, 0x07,  #     Logical Maximum (2047)
    0x75, 0x0B,        #     Report Size (11)
    0x09, 0x30,        #     Usage (X)
    0x81, 0x02,        #     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x05, 0x0D,        #     Usage Page (Digitizer)
    0x25, 0x1F,        #     Logical Maximum (31)
    0x75, 0x05,        #     Report Size (5)
    0x09, 0x48,        #     Usage (Width)
    0x81, 0x02,        #     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x05, 0x01,        #     Usage Page (Generic Desktop Ctrls)
    0x16, 0x00, 0x00,  #     Logical Minimum (0)
    0x26, 0xFF, 0x07,  #     Logical Maximum (2047)
    0x75, 0x0B,        #     Report Size (11)
    0x09, 0x31,        #     Usage (Y)
    0x81, 0x02,        #     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x05, 0x0D,        #     Usage Page (Digitizer)
    0x25, 0x1F,        #     Logical Maximum (31)
    0x75, 0x05,        #     Report Size (5)
    0x09, 0x49,        #     Usage (Height)
    0x81, 0x02,        #     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x25, 0xFF,        #     Logical Maximum (255)
    0x75, 0x08,        #     Report Size (8)
    0x09, 0x51,        #     Usage (Contact Identifier)
    0x95, 0x01,        #     Report Count (1)
    0x81, 0x02,        #     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x09, 0x30,        #     Usage (Tip Pressure)
    0x75, 0x05,        #     Report Size (5)
    0x81, 0x02,        #     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x09, 0x42,        #     Usage (Tip Switch)
    0x15, 0x00,        #     Logical Minimum (0)
    0x25, 0x01,        #     Logical Maximum (1)
    0x75, 0x01,        #     Report Size (1)
    0x95, 0x01,        #     Report Count (1)
    0x81, 0x02,        #     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x09, 0x47,        #     Usage (Confidence)
    0x81, 0x02,        #     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x09, 0x32,        #     Usage (In Range)
    0x81, 0x02,        #     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0xC0,              #   End Collection
    0xC0,              # End Collection
    ])

report_len = 12  # bytes
pyb.usb_mode("VCP+HID", pid=0x1234, hid=(0, 0, report_len, hid_desc))

It a custom touch HID descriptor, detecting only one finger.
When I send a HID message from the code or the interpretor, the message is sent correctly.

But dmesg starts shouting error messages :


Feb 17 14:10:28 hoofse ModemManager[807]: <info>  (tty/ttyACM0): released by modem /sys/devices/pci0000:00/0000:00:1a.1/usb4/4-2
Feb 17 14:10:35 hoofse kernel: [14864.020056] usb 4-2: new full-speed USB device number 19 using uhci_hcd
Feb 17 14:10:35 hoofse kernel: [14864.206726] usb 4-2: New USB device found, idVendor=f055, idProduct=1234
Feb 17 14:10:35 hoofse kernel: [14864.206730] usb 4-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
Feb 17 14:10:35 hoofse kernel: [14864.206732] usb 4-2: Product: Pyboard Virtual Comm Port in FS Mode
Feb 17 14:10:35 hoofse kernel: [14864.206734] usb 4-2: Manufacturer: Micro Python
Feb 17 14:10:35 hoofse kernel: [14864.206736] usb 4-2: SerialNumber: 000000000011
Feb 17 14:10:35 hoofse mtp-probe: checking bus 4, device 19: "/sys/devices/pci0000:00/0000:00:1a.1/usb4/4-2"
Feb 17 14:10:35 hoofse kernel: [14864.216780] input: Micro Python Pyboard Virtual Comm Port in FS Mode as /devices/pci0000:00/0000:00:1a.1/usb4/4-2/4-2:1.0/input/input31
Feb 17 14:10:35 hoofse kernel: [14864.216981] hid-multitouch 0003:F055:1234.0015: input,hidraw3: USB HID v1.11 Device [Micro Python Pyboard Virtual Comm Port in FS Mode] on usb-0000:00:1a.1-2/input0
Feb 17 14:10:35 hoofse kernel: [14864.217044] cdc_acm 4-2:1.1: This device cannot do calls on its own. It is not a modem.
Feb 17 14:10:35 hoofse kernel: [14864.217063] cdc_acm 4-2:1.1: ttyACM0: USB ACM device
Feb 17 14:10:35 hoofse mtp-probe: bus: 4, device: 19 was not an MTP device
Feb 17 14:10:51 hoofse ModemManager[807]: <info>  Creating modem with plugin 'Generic' and '1' ports
Feb 17 14:10:51 hoofse ModemManager[807]: <warn>  Could not grab port (tty/ttyACM0): 'Cannot add port 'tty/ttyACM0', unhandled serial type'
Feb 17 14:10:51 hoofse ModemManager[807]: <warn>  Couldn\'t create modem for device at '/sys/devices/pci0000:00/0000:00:1a.1/usb4/4-2': Failed to find primary AT port
Feb 17 14:11:11 hoofse kernel: [14899.710730] usb 4-2: input irq status -75 received
Feb 17 14:11:11 hoofse kernel: [14899.718731] usb 4-2: input irq status -75 received
Feb 17 14:11:11 hoofse kernel: [14899.726731] usb 4-2: input irq status -75 received
Feb 17 14:11:11 hoofse kernel: [14899.734729] usb 4-2: input irq status -75 received
Feb 17 14:11:11 hoofse kernel: [14899.742725] usb 4-2: input irq status -75 received
Feb 17 14:11:11 hoofse kernel: [14899.750729] usb 4-2: input irq status -75 received
Feb 17 14:11:11 hoofse kernel: [14899.758725] usb 4-2: input irq status -75 received
Feb 17 14:11:11 hoofse kernel: [14899.766724] usb 4-2: input irq status -75 received
...

From my investigation, the input irq status -75 received comes from this file

I'm not sure if these messages could come from malformed HID messages by the pyboard (ie if my descriptor is wrong or the pyboard doesn't form them correctly).

Keyboard

j / / n
next pair
k / / p
previous pair
1 / / h
show query pane
2 / / l
show candidate pane
c
copy suggested comment
r
toggle reasoning
g i
go to index
?
show this help
esc
close overlays

press ? or esc to close

copied