Description
In order to implement a proper keyboard, with working LEDs for CapsLock, NumLock and the like, we need to be able to receive and examine the SetReport requests, as they contain the bitmask of which LEDs should be on.
From https://wiki.osdev.org/USB_Human_Interface_Devices#LED_lamps:
To set the LED lamps, the driver sends a SetReport request to the device using a standard USB Setup Transaction, with a one-byte data stage. The setup packet's request type should contain 0x21, the request code for SetReport is 0x09. The value field of the setup packet contains the report ID in the low byte, which should be zero. The high byte contains the report type, which should be 0x02 to indicate an output report, or a report that is being sent from the software to the hardware. The index field should contain the interface number of the USB keyboard, which is the number present in the interface descriptor which indicated this device was a USB keyboard at all. The data stage should be 1 byte, which is a bitfield. This Setup Transaction should be transferred to control endpoint zero, which would work on all hardware. Other hardware may or may not support the optional interrupt OUT endpoint. If the hardware supports the interrupt OUT endpoint, you can just transfer the 1 byte data stage to the interrupt OUT endpoint, without the extra overhead of the SETUP stage and STATUS stage. If the hardware support the interrupt OUT endpoint, you should avoid the control endpoint when possible, as the interrupt OUT endpoint is faster and can be programmed with interrupt transfers instead of setup transfers. The format of the 1-byte data stage (for SETUP transaction) or 1-byte interrupt OUT transfer is shown below. When a bit is set to 1, the corresponding LED is turned on.
It looks like we already have a callback C function that gets called when a request comes:
circuitpython/shared-module/usb_hid/Device.c
Lines 75 to 83 in 7f744a2