31
31
#include "py/gc.h"
32
32
#include "py/runtime.h"
33
33
#include "shared-bindings/usb_hid/__init__.h"
34
- #include "shared-module /usb_hid/Device.h"
34
+ #include "shared-bindings /usb_hid/Device.h"
35
35
#include "supervisor/memory.h"
36
36
#include "supervisor/usb.h"
37
37
@@ -44,7 +44,9 @@ static const uint8_t usb_hid_descriptor_template[] = {
44
44
0x02 , // 4 bNumEndpoints 2
45
45
0x03 , // 5 bInterfaceClass: HID
46
46
0x00 , // 6 bInterfaceSubClass: NOBOOT
47
+ #define HID_DESCRIPTOR_SUBCLASS_INDEX (6 )
47
48
0x00 , // 7 bInterfaceProtocol: NONE
49
+ #define HID_DESCRIPTOR_INTERFACE_PROTOCOL_INDEX (7 )
48
50
0xFF , // 8 iInterface (String Index) [SET AT RUNTIME]
49
51
#define HID_DESCRIPTOR_INTERFACE_STRING_INDEX (8 )
50
52
@@ -81,6 +83,14 @@ static usb_hid_device_obj_t hid_devices[MAX_HID_DEVICES];
81
83
// If 0, USB HID is disabled.
82
84
static mp_int_t num_hid_devices ;
83
85
86
+ // Which boot device is available? 0: no boot devices, 1: boot keyboard, 2: boot mouse.
87
+ // This value is set by usb_hid.enable(), and used to build the HID interface descriptor.
88
+ // The value is remembered here from boot.py to code.py.
89
+ static uint8_t hid_boot_device ;
90
+
91
+ // Whether a boot device was requested by a SET_PROTOCOL request from the host.
92
+ static bool hid_boot_device_requested ;
93
+
84
94
// This tuple is store in usb_hid.devices.
85
95
static mp_obj_tuple_t * hid_devices_tuple ;
86
96
@@ -96,13 +106,56 @@ static mp_obj_tuple_t default_hid_devices_tuple = {
96
106
},
97
107
};
98
108
109
+ // These describe the standard descriptors used for boot keyboard and mouse, which don't use report IDs.
110
+ // When the host requests a boot device, replace whatever HID devices were enabled with a tuple
111
+ // containing just one of these, since the host is uninterested in other devices.
112
+ // The driver code will then use the proper report length and send_report() will not send a report ID.
113
+ static const usb_hid_device_obj_t boot_keyboard_obj = {
114
+ .base = {
115
+ .type = & usb_hid_device_type ,
116
+ },
117
+ .report_descriptor = NULL ,
118
+ .report_descriptor_length = 0 ,
119
+ .usage_page = 0x01 ,
120
+ .usage = 0x06 ,
121
+ .num_report_ids = 1 ,
122
+ .report_ids = { 0 , },
123
+ .in_report_lengths = { 8 , },
124
+ .out_report_lengths = { 1 , },
125
+ };
126
+
127
+ static const usb_hid_device_obj_t boot_mouse_obj = {
128
+ .base = {
129
+ .type = & usb_hid_device_type ,
130
+ },
131
+ .report_descriptor = NULL ,
132
+ .report_descriptor_length = 0 ,
133
+ .usage_page = 0x01 ,
134
+ .usage = 0x02 ,
135
+ .num_report_ids = 1 ,
136
+ .report_ids = { 0 , },
137
+ .in_report_lengths = { 4 , },
138
+ .out_report_lengths = { 0 , },
139
+ };
140
+
99
141
bool usb_hid_enabled (void ) {
100
142
return num_hid_devices > 0 ;
101
143
}
102
144
145
+ uint8_t usb_hid_boot_device (void ) {
146
+ return hid_boot_device ;
147
+ }
148
+
149
+ // Returns 1 or 2 if host requested a boot device and boot protocol was enabled in the interface descriptor.
150
+ uint8_t common_hal_usb_hid_get_boot_device (void ) {
151
+ return hid_boot_device_requested ? hid_boot_device : 0 ;
152
+ }
153
+
103
154
void usb_hid_set_defaults (void ) {
155
+ hid_boot_device = 0 ;
156
+ hid_boot_device_requested = false;
104
157
common_hal_usb_hid_enable (
105
- CIRCUITPY_USB_HID_ENABLED_DEFAULT ? & default_hid_devices_tuple : mp_const_empty_tuple );
158
+ CIRCUITPY_USB_HID_ENABLED_DEFAULT ? & default_hid_devices_tuple : mp_const_empty_tuple , 0 );
106
159
}
107
160
108
161
// This is the interface descriptor, not the report descriptor.
@@ -113,12 +166,17 @@ size_t usb_hid_descriptor_length(void) {
113
166
static const char usb_hid_interface_name [] = USB_INTERFACE_NAME " HID" ;
114
167
115
168
// This is the interface descriptor, not the report descriptor.
116
- size_t usb_hid_add_descriptor (uint8_t * descriptor_buf , descriptor_counts_t * descriptor_counts , uint8_t * current_interface_string , uint16_t report_descriptor_length ) {
169
+ size_t usb_hid_add_descriptor (uint8_t * descriptor_buf , descriptor_counts_t * descriptor_counts , uint8_t * current_interface_string , uint16_t report_descriptor_length , uint8_t boot_device ) {
117
170
memcpy (descriptor_buf , usb_hid_descriptor_template , sizeof (usb_hid_descriptor_template ));
118
171
119
172
descriptor_buf [HID_DESCRIPTOR_INTERFACE_INDEX ] = descriptor_counts -> current_interface ;
120
173
descriptor_counts -> current_interface ++ ;
121
174
175
+ if (boot_device > 0 ) {
176
+ descriptor_buf [HID_DESCRIPTOR_SUBCLASS_INDEX ] = 1 ; // BOOT protocol (device) available.
177
+ descriptor_buf [HID_DESCRIPTOR_INTERFACE_PROTOCOL_INDEX ] = boot_device ; // 1: keyboard, 2: mouse
178
+ }
179
+
122
180
usb_add_interface_string (* current_interface_string , usb_hid_interface_name );
123
181
descriptor_buf [HID_DESCRIPTOR_INTERFACE_STRING_INDEX ] = * current_interface_string ;
124
182
(* current_interface_string )++ ;
@@ -151,10 +209,10 @@ static void usb_hid_set_devices_from_hid_devices(void) {
151
209
}
152
210
153
211
bool common_hal_usb_hid_disable (void ) {
154
- return common_hal_usb_hid_enable (mp_const_empty_tuple );
212
+ return common_hal_usb_hid_enable (mp_const_empty_tuple , 0 );
155
213
}
156
214
157
- bool common_hal_usb_hid_enable (const mp_obj_t devices ) {
215
+ bool common_hal_usb_hid_enable (const mp_obj_t devices , uint8_t boot_device ) {
158
216
// We can't change the devices once we're connected.
159
217
if (tud_connected ()) {
160
218
return false;
@@ -167,6 +225,8 @@ bool common_hal_usb_hid_enable(const mp_obj_t devices) {
167
225
168
226
num_hid_devices = num_devices ;
169
227
228
+ hid_boot_device = boot_device ;
229
+
170
230
// Remember the devices in static storage so they live across VMs.
171
231
for (mp_int_t i = 0 ; i < num_hid_devices ; i ++ ) {
172
232
// devices has already been validated to contain only usb_hid_device_obj_t objects.
@@ -182,6 +242,17 @@ bool common_hal_usb_hid_enable(const mp_obj_t devices) {
182
242
183
243
// Called when HID devices are ready to be used, when code.py or the REPL starts running.
184
244
void usb_hid_setup_devices (void ) {
245
+
246
+ // If the host requested a boot device, replace the current list of devices
247
+ // with a single-element tuple containing the proper boot device.
248
+ if (hid_boot_device_requested ) {
249
+ memcpy (& hid_devices [0 ],
250
+ // Will be 1 (keyboard) or 2 (mouse).
251
+ hid_boot_device == 1 ? & boot_keyboard_obj : & boot_mouse_obj ,
252
+ sizeof (usb_hid_device_obj_t ));
253
+ num_hid_devices = 1 ;
254
+ }
255
+
185
256
usb_hid_set_devices_from_hid_devices ();
186
257
187
258
// Create report buffers on the heap.
@@ -272,9 +343,15 @@ bool usb_hid_get_device_with_report_id(uint8_t report_id, usb_hid_device_obj_t *
272
343
return false;
273
344
}
274
345
275
- // Invoked when GET HID REPORT DESCRIPTOR is received.
276
- // Application return pointer to descriptor
346
+ // Callback invoked when we receive a GET HID REPORT DESCRIPTOR
347
+ // Application returns pointer to descriptor
277
348
// Descriptor contents must exist long enough for transfer to complete
278
349
uint8_t const * tud_hid_descriptor_report_cb (uint8_t itf ) {
279
350
return (uint8_t * )hid_report_descriptor_allocation -> ptr ;
280
351
}
352
+
353
+ // Callback invoked when we receive a SET_PROTOCOL request.
354
+ // Protocol is either HID_PROTOCOL_BOOT (0) or HID_PROTOCOL_REPORT (1)
355
+ void tud_hid_set_protocol_cb (uint8_t instance , uint8_t protocol ) {
356
+ hid_boot_device_requested = (protocol == HID_PROTOCOL_BOOT );
357
+ }
0 commit comments