3

After another user related question on this forum I try to get my USB HID Gadget Keyboard running in BIOS. My gadget is the RPi-Z using libcomposite on Raspbian Buster.

When I plug my keyboard into my another RaspberryPi where Raspbian is also installed, I can see the Boot Protocol used when I'm on my desktop and when I open a terminal and type lsusb -v -d VIP:PID.

The lsusb return an """UNAVAILABLE DESCRIPTOR""", so I think it is because the Boot Protocol is used (subclass indicate Boot protocol) and then the Report Descriptor is not used because when Boot Descriptor is used Report Descriptor is not used. But if I use usbhid-dump tool , I can also get the HID keyboard descriptor, so I don't really understand yet.

This is my 'boot' test :

I plug my gadget on another computer and I press F12 for enter in BIOS settings on the PC default keyboard. (The raspberry is correctly power-on when I start the PC.)

My first menu is to select a boot drive or advanced settings. So I don't move from here and I wait for my Raspbian boot and 'mount' the keyboard for sending [down] or [up] keys with Wi-Fi and ssh. (I use an ssh script for that where the script work perfectly)

But when I send a key DOWN or UP (arrows) keys nothing is appended in this BIOS menu. My tool show the 8 Bytes datas send (key & modifier),and send the other 8 Bytes datas (release all keys) and the script is always opened 'same as the hosts not responding'

If I exit from the BIOS settings, I go to Cryptsetup for entrer disk encryption key and then my script is closed and the keys was sent correctly (I send [enter] key for cypher key validation and it's works).

What can it mean :

  • Does the BIOS not support the USB HID keyboard ?

  • That once in the BIOS the hardware can no longer be detected 'dynamically' ?


EDIT 1:

I use another usb keyboard,try the same test and it's work, so it's a problem with my gadget conf and not the BIOS. And because the first 8 Bytes are successfully sent from my script and my gadget but nothing happens on the menu. I think it's a problem with my keys

LSUSB

  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength          186
    bNumInterfaces          5
    bConfigurationValue     1
    iConfiguration          4 Config 1: RNDIS network
    bmAttributes         0xa0
      (Bus Powered)
      Remote Wakeup
    MaxPower              250mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        2
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      1 Boot Interface Subclass
      bInterfaceProtocol      1 Keyboard
      iInterface              9 
        HID Device Descriptor:
          bLength                 9
          bDescriptorType        33
          bcdHID               1.01
          bCountryCode            0 Not supported
          bNumDescriptors         1
          bDescriptorType        34 Report
          wDescriptorLength      65
         Report Descriptors: 
           ** UNAVAILABLE **
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x83  EP 3 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval               4
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x02  EP 2 OUT
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval               4

REPORT_DESCRIPTOR (copied from my working usb keyboard)

 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 05 75 01
 05 08 19 01 29 05 91 02 95 01 75 03 91 01 95 06
 75 08 15 00 26 A4 00 05 07 19 00 2A A4 00 81 00
 C0

I have also try this descriptor BootKeyboard.cpp but not work.

If I read this document on page 60 I can see the require descriptor for boot keyboard:

Usage Page (Generic Desktop),
Usage (Keyboard),
Collection (Application),
Report Size (1),
Report Count (8),
Usage Page (Key Codes),
...

My descriptor seems to be correct. Always on document on page 60 I can read :

The following table represents the keyboard input report (8 bytes).

I send :

echo -en '\0\0\x52\0\0\0\0\0' > /dev/hidg0

This command seems to be executed succesfully (but nothing is done on the BIOS menu), follow by :

echo -en '\0\0\0\0\0\0\0\0' > /dev/hidg0

The shell is 'blocked'. (wait for usb response ?)

I use this paper page 53 for reference


EDIT 2:

On the gadget I can see some errors on gadget boot :

[...] configfs-gadget gadget: End Point Request ERROR: -108
[...] dwc2 20980000.usb: new device is high-speed
[...] dwc2 20980000.usb: new device is high-speed
[...] dwc2 20980000.usb: new address 2
[...] configfs-gadget gadget: high-speed config #1: c
[...] dwc2 20980000.usb: dwc2_hsotg_ep_sethalt(ep a792ad4a ep0, 0)
[...] dwc2 20980000.usb: dwc2_hsotg_ep_sethalt: can't clear halt on ep0
[...] dwc2 20980000.usb: dwc2_hsotg_ep_sethalt(ep a792ad4a ep0, 0)
[...] dwc2 20980000.usb: dwc2_hsotg_ep_sethalt: can't clear halt on ep0
[...] dwc2 20980000.usb: dwc2_hsotg_ep_sethalt(ep a792ad4a ep0, 0)
[...] dwc2 20980000.usb: dwc2_hsotg_ep_sethalt: can't clear halt on ep0
[...] dwc2 20980000.usb: dwc2_hsotg_ep_sethalt(ep a792ad4a ep0, 0)
[...] dwc2 20980000.usb: dwc2_hsotg_ep_sethalt: can't clear halt on ep0

EDIT 3:

Other test (same result if I plug my gadget into another USB port) :

sudo bash -c "echo > UDC"
sudo bash -c "echo 20980000.usb > UDC"

[...] dwc2 20980000.usb: bound driver configfs-gadget
[...] dwc2 20980000.usb: new device is high-speed
[...] dwc2 20980000.usb: new address 2
[...] configfs-gadget gadget: high-speed config #1: c
[...] dwc2 20980000.usb: dwc2_hsotg_ep_sethalt(ep a792ad4a ep0, 0)
[...] dwc2 20980000.usb: dwc2_hsotg_ep_sethalt: can't clear halt on ep0
[...] dwc2 20980000.usb: dwc2_hsotg_ep_sethalt(ep a792ad4a ep0, 0)
[...] dwc2 20980000.usb: dwc2_hsotg_ep_sethalt: can't clear halt on ep0

EDIT 4:

When the gadget work :

sudo cat /sys/kernel/debug/20980000.usb/ep0
Endpoint index 0, named ep0,  dir out:
    DIEPCTL=0x00008000, DOEPCTL=0x80028000
    DIEPDMA=0x525bd044, DOEPDMA=0x56b35ae0
    DIEPINT=0x000020d0, DOEPINT=0x00002010
    DIEPTSIZ=0x00000000, DOEPTSIZ=0x00080008

mps 64
total_data=0
request list (63f56bc4,63f56bc4):
* req 83dd708b: 8 bytes @bfdef28f, 0 done, res -115

sudo cat /sys/kernel/debug/20980000.usb/ep3in
Endpoint index 3, named ep3in,  dir in:
    DIEPCTL=0x004c8008, DOEPCTL=0x80088200
    DIEPDMA=0xb03e91cc, DOEPDMA=0x519dd800
    DIEPINT=0x00002090, DOEPINT=0x00000000
    DIEPTSIZ=0x00000000, DOEPTSIZ=0x001805fe

mps 8
total_data=0
request list (1ece2335,1ece2335):

sudo cat /sys/kernel/debug/20980000.usb/ep2out
Endpoint index 2, named ep2out,  dir out:
    DIEPCTL=0x818c8008, DOEPCTL=0x000e8008
    DIEPDMA=0x5404ade8, DOEPDMA=0x519352c4
    DIEPINT=0x00000000, DOEPINT=0x00000000
    DIEPTSIZ=0x20080000, DOEPTSIZ=0x00000007

mps 8
total_data=0
request list (3dc15386,3dc15386):

When the gadget not work :

sudo cat /sys/kernel/debug/20980000.usb/ep0
Endpoint index 0, named ep0,  dir out:
    DIEPCTL=0x00008000, DOEPCTL=0x80028000
    DIEPDMA=0x52e440bc, DOEPDMA=0x569bfb60
    DIEPINT=0x000020d0, DOEPINT=0x00002010
    DIEPTSIZ=0x00000000, DOEPTSIZ=0x00080008

mps 64
total_data=0
request list (0d6f4638,0d6f4638):
* req 1378b877: 8 bytes @044102c4, 0 done, res -115

sudo cat /sys/kernel/debug/20980000.usb/ep3in
Endpoint index 3, named ep3in,  dir in:
    DIEPCTL=0x004c8008, DOEPCTL=0x00000400
    DIEPDMA=0xb01e91cc, DOEPDMA=0xb0d3eb0b
    DIEPINT=0x00000080, DOEPINT=0x00000000
    DIEPTSIZ=0x00000000, DOEPTSIZ=0x00000000

mps 8
total_data=0
request list (3f381df3,3f381df3):

sudo cat /sys/kernel/debug/20980000.usb/ep2out
Endpoint index 2, named ep2out,  dir out:
    DIEPCTL=0x018c8008, DOEPCTL=0x800c8008
    DIEPDMA=0x7532451b, DOEPDMA=0x5152c6e0
    DIEPINT=0x00000000, DOEPINT=0x00000000
    DIEPTSIZ=0x00000000, DOEPTSIZ=0x00080008

mps 8
total_data=0
request list (831d3428,abbeefd9):
* req 7372364d: 8 bytes @d0414864, 0 done, res -115
  req a85c223f: 8 bytes @851c7555, 0 done, res -115
  req 21dba8da: 8 bytes @7fc50fee, 0 done, res -115
  req 621b9773: 8 bytes @dd7307ac, 0 done, res -115

The request seems to use EP2 OUT. I think the output must be on the EP 3 IN but the gadget use the OUT endpoint ?


EDIT 5:

From developer.electricimp.com

Halt Conditions

The device has found itself in a state that requires intervention from the host; the host has to perform some form of recovery action before communication to that endpoint can begin again. An example of an event that can trigger a STALL is an attempt to transfer more data to the device than was specified.

On working device : bMaxPacketSize0: 32 (on the gadget : bMaxPacketSize0: 64, unable to change this value, trying hexa value, dec value ...) ?

From docs.microsoft.com

Interrupt IN transfers

Conversely, a USB device can support interrupt IN endpoints as a way to inform the host about hardware interrupts generated by the device. Typically USB Human Interface Devices (HID) such as keyboards and pointing devices support interrupt OUT endpoints. When an interrupt occurs, the endpoint stores interrupt data but that data does not reach the host immediately. The endpoint must wait for the host controller to poll the device. Because there must be minimal delay between the time data is generated and reaches the host, it polls the device at regular intervals.

Interrupt OUT transfers

A USB device can support interrupt OUT endpoints that receive data from the host at regular intervals. Each time the host polls the device, the host sends data.

On working device : bInterval : 10 (on the gadget : bInterval : 4) ?


EDIT 6:

enter image description here

BootKeyboard.h

void setFeatureReport(void* report, int length){
    if(length > 0){
        featureReport = (uint8_t*)report;
        featureLength = length;

        // Disable feature report by default
        disableFeatureReport();
    }
}

BootKeyboard.cpp

        // Feature (set feature report)
        if(setup.wValueH == HID_REPORT_TYPE_FEATURE){
            // No need to check for negative featureLength values,
            // except the host tries to send more then 32k bytes.
            // We dont have that much ram anyways.
            if (length == featureLength) {
                USB_RecvControl(featureReport, featureLength);

                // Block until data is read (make length negative)
                disableFeatureReport();
                return true;
            }
            // TODO fake clear data?
        }

How to do this with libcomposite ? stall parameter doesn't seem to be available same as UMS configuration.


My other working device have only one endpoint :

  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              10

The differences with my working device USB keyboard are :

  • bMaxPacketSize0: 32 (on the gadget this value is 64, unable to change this value)
  • One Interrupt endpoint (on the gadget I have two endpoints)

  • bInterval :10 (on the gadget the value is 4)


If I understand OTG then my raspberry is powered by its USB OTG port.

Does gadget mode need the OTG, is it possible to power the raspberry via its default power input and use libcomposite ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.