@@ -79,25 +79,59 @@ static uint8_t usbd_desc_str_cnt = 0;
7979static uint8_t usbd_desc_str_alloc = 0 ;
8080
8181// HID report
82+ static unsigned int __hid_interface = (unsigned int ) -1 ;
83+ static uint8_t __hid_endpoint = 0 ;
8284static int __hid_report_len = 0 ;
8385static uint8_t *__hid_report = nullptr ;
8486
8587// Global USB descriptor
8688static uint8_t *usbd_desc_cfg = nullptr ;
89+ static int usbd_desc_cfg_len = 0 ;
90+
8791#ifdef ENABLE_PICOTOOL_USB
8892static uint8_t _picotool_itf_num;
8993#endif
9094int usb_hid_poll_interval __attribute__ ((weak)) = 10;
9195
9296
97+ // Available bitmask for endpoints, can never be EP 0
98+ static uint32_t _endpointIn = 0xfffffffe ;
99+ static uint32_t _endpointOut = 0xfffffffe ;
100+
101+ // GCC doesn't seem to have builtin_ffs here
102+ static int ffs (uint32_t v) {
103+ for (auto i = 0 ; i < 32 ; i++) {
104+ if (v & (1 << i)) {
105+ return i;
106+ }
107+ }
108+ return 0 ;
109+ }
110+
93111uint8_t usbRegisterEndpointIn () {
94- static uint8_t epin = 0x81 ;
95- return epin++;
112+ if (!_endpointIn) {
113+ return 0 ; // ERROR, out of EPs
114+ }
115+ int firstFree = ffs (_endpointIn);
116+ _endpointIn &= ~(1 << firstFree);
117+ return 0x80 + firstFree;
118+ }
119+
120+ void usbUnregisterEndpointIn (int ep) {
121+ _endpointIn |= 1 << ep;
96122}
97123
98124uint8_t usbRegisterEndpointOut () {
99- static uint8_t epout = 0x01 ;
100- return epout++;
125+ if (!_endpointOut) {
126+ return 0 ; // ERROR, out of EPs
127+ }
128+ int firstFree = ffs (_endpointOut);
129+ _endpointOut &= ~(1 << firstFree);
130+ return firstFree;
131+ }
132+
133+ void usbUnregisterEndpointOut (int ep) {
134+ _endpointOut |= (1 << (ep - 0x80 ));
101135}
102136
103137static uint8_t AddEntry (Entry **head, int interfaces, const uint8_t *descriptor, size_t len, int ordering, uint32_t vidMask) {
@@ -132,6 +166,27 @@ static uint8_t AddEntry(Entry **head, int interfaces, const uint8_t *descriptor,
132166 return n->localid ;
133167}
134168
169+ static void RemoveEntry (Entry **head, unsigned int localid) {
170+ Entry *prev = nullptr ;
171+ Entry *cur = *head;
172+ while (cur && cur->localid != localid) {
173+ prev = cur;
174+ cur = cur->next ;
175+ }
176+ if (!cur) {
177+ // Not found, just exit
178+ return ;
179+ }
180+ if (cur == *head) {
181+ auto p = cur->next ;
182+ free (*head);
183+ *head = p;
184+ } else {
185+ prev->next = cur->next ;
186+ free (cur);
187+ }
188+ }
189+
135190// Find the index (HID report ID or USB interface) of a given localid
136191static unsigned int usbFindID (Entry *head, unsigned int localid) {
137192 unsigned int x = 0 ;
@@ -156,11 +211,18 @@ uint8_t usbRegisterHIDDevice(const uint8_t *descriptor, size_t len, int ordering
156211 return AddEntry (&_hids, 0 , descriptor, len, ordering, vidMask);
157212}
158213
214+ void usbUnregisterHIDDevice (unsigned int localid) {
215+ RemoveEntry (&_hids, localid);
216+ }
217+
159218// Called by an object at global init time to add a new interface (non-HID, like CDC or Picotool)
160219uint8_t usbRegisterInterface (int interfaces, const uint8_t *descriptor, size_t len, int ordering, uint32_t vidMask) {
161220 return AddEntry (&_interfaces, interfaces, descriptor, len, ordering, vidMask);
162221}
163222
223+ void usbUnregisterInterface (unsigned int localid) {
224+ RemoveEntry (&_interfaces, localid);
225+ }
164226
165227uint8_t usbRegisterString (const char *str) {
166228 if (usbd_desc_str_alloc <= usbd_desc_str_cnt) {
@@ -182,41 +244,62 @@ uint8_t usbRegisterString(const char *str) {
182244 return usbd_desc_str_cnt++;
183245}
184246
247+ static uint16_t _forceVID = 0 ;
248+ static uint16_t _forcePID = 0 ;
249+ void usbSetVIDPID (uint16_t vid, uint16_t pid) {
250+ _forceVID = vid;
251+ _forcePID = pid;
252+ }
185253
254+ static uint8_t _forceManuf = 0 ;
255+ static uint8_t _forceProd = 0 ;
256+ static uint8_t _forceSerial = 0 ;
257+ void usbSetManufacturer (const char *str) {
258+ _forceManuf = usbRegisterString (str);
259+ }
260+ void usbSetProduct (const char *str) {
261+ _forceProd = usbRegisterString (str);
262+ }
263+ void usbSetSerialNumber (const char *str) {
264+ _forceSerial = usbRegisterString (str);
265+ }
186266
267+ static tusb_desc_device_t usbd_desc_device;
187268const uint8_t *tud_descriptor_device_cb (void ) {
188269 static char idString[PICO_UNIQUE_BOARD_ID_SIZE_BYTES * 3 + 1 ];
189270 if (!idString[0 ]) {
190271 pico_get_unique_board_id_string (idString, sizeof (idString));
191272 }
192273
193- static tusb_desc_device_t usbd_desc_device = {
274+ usbd_desc_device = {
194275 .bLength = sizeof (tusb_desc_device_t ),
195276 .bDescriptorType = TUSB_DESC_DEVICE,
196277 .bcdUSB = 0x0200 ,
197278 .bDeviceClass = 0 ,
198279 .bDeviceSubClass = 0 ,
199280 .bDeviceProtocol = 0 ,
200281 .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
201- .idVendor = USBD_VID,
202- .idProduct = USBD_PID,
282+ .idVendor = _forceVID ? _forceVID : ( uint16_t ) USBD_VID,
283+ .idProduct = _forcePID ? _forcePID : ( uint16_t ) USBD_PID,
203284 .bcdDevice = 0x0100 ,
204- .iManufacturer = usbRegisterString (USB_MANUFACTURER),
205- .iProduct = usbRegisterString (USB_PRODUCT),
206- .iSerialNumber = usbRegisterString (idString),
285+ .iManufacturer = _forceManuf ? _forceManuf : usbRegisterString (USB_MANUFACTURER),
286+ .iProduct = _forceProd ? _forceProd : usbRegisterString (USB_PRODUCT),
287+ .iSerialNumber = _forceSerial ? _forceSerial : usbRegisterString (idString),
207288 .bNumConfigurations = 1
208289 };
209290
210- // Handle any inversions from the sub-devices
211- Entry *h = _hids;
212- while (h) {
213- usbd_desc_device.idProduct ^= h->mask ;
214- h = h->next ;
215- }
216- h = _interfaces;
217- while (h) {
218- usbd_desc_device.idProduct ^= h->mask ;
219- h = h->next ;
291+ // Handle any inversions from the sub-devices, if we're not forcing things
292+ if (!_forcePID) {
293+ Entry *h = _hids;
294+ while (h) {
295+ usbd_desc_device.idProduct ^= h->mask ;
296+ h = h->next ;
297+ }
298+ h = _interfaces;
299+ while (h) {
300+ usbd_desc_device.idProduct ^= h->mask ;
301+ h = h->next ;
302+ }
220303 }
221304
222305 return (const uint8_t *)&usbd_desc_device;
@@ -282,7 +365,6 @@ const uint8_t *tud_descriptor_configuration_cb(uint8_t index) {
282365// needed ever again
283366void __SetupUSBDescriptor () {
284367 uint8_t interface_count = 0 ;
285- int usbd_desc_len;
286368 if (usbd_desc_cfg) {
287369 return ;
288370 }
@@ -291,32 +373,33 @@ void __SetupUSBDescriptor() {
291373 if (GetDescHIDReport (&hid_report_len)) {
292374 uint8_t hid_desc[TUD_HID_DESC_LEN] = {
293375 // Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval
294- TUD_HID_DESCRIPTOR (1 /* placeholder*/ , 0 , HID_ITF_PROTOCOL_NONE, hid_report_len, usbRegisterEndpointIn (), CFG_TUD_HID_EP_BUFSIZE, (uint8_t )usb_hid_poll_interval)
376+ TUD_HID_DESCRIPTOR (1 /* placeholder*/ , 0 , HID_ITF_PROTOCOL_NONE, hid_report_len, __hid_endpoint = usbRegisterEndpointIn (), CFG_TUD_HID_EP_BUFSIZE, (uint8_t )usb_hid_poll_interval)
295377 };
296- usbRegisterInterface (1 , hid_desc, sizeof (hid_desc), 10 , 0 );
378+ __hid_interface = usbRegisterInterface (1 , hid_desc, sizeof (hid_desc), 10 , 0 );
297379 }
298380
299381#ifdef ENABLE_PICOTOOL_USB
300382 uint8_t picotool_desc[] = { TUD_RPI_RESET_DESCRIPTOR (1 , usbRegisterString (" Reset" )) };
301383 usbRegisterInterface (1 , picotool_desc, sizeof (picotool_desc), 100 , 0 );
302384#endif
303385
304- usbd_desc_len = TUD_CONFIG_DESC_LEN; // Always have a config descriptor
386+ usbd_desc_cfg_len = TUD_CONFIG_DESC_LEN; // Always have a config descriptor
305387 Entry *h = _interfaces;
306388 while (h) {
307- usbd_desc_len += h->len ;
389+ usbd_desc_cfg_len += h->len ;
308390 interface_count += h->interfaces ;
309391 h = h->next ;
310392 }
311393
312394 uint8_t tud_cfg_desc[TUD_CONFIG_DESC_LEN] = {
313395 // Config number, interface count, string index, total length, attribute, power in mA
314- TUD_CONFIG_DESCRIPTOR (1 , interface_count, usbRegisterString (" " ), usbd_desc_len , TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, USBD_MAX_POWER_MA)
396+ TUD_CONFIG_DESCRIPTOR (1 , interface_count, usbRegisterString (" " ), usbd_desc_cfg_len , TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, USBD_MAX_POWER_MA)
315397 };
316398
317399 // Allocate the "real" HID report descriptor
318- usbd_desc_cfg = (uint8_t *)malloc (usbd_desc_len );
400+ usbd_desc_cfg = (uint8_t *)malloc (usbd_desc_cfg_len );
319401 assert (usbd_desc_cfg);
402+ bzero (usbd_desc_cfg, usbd_desc_cfg_len);
320403
321404 // Now copy the descriptors
322405 h = _interfaces;
@@ -374,6 +457,48 @@ static int64_t timer_task(__unused alarm_id_t id, __unused void *user_data) {
374457 return USB_TASK_INTERVAL;
375458}
376459
460+ void usbDisconnect () {
461+ #ifdef __FREERTOS
462+ auto m = __get_freertos_mutex_for_ptr (&__usb_mutex);
463+ xSemaphoreTake (m, portMAX_DELAY);
464+ tud_disconnect ();
465+ vTaskDelay (500 / portTICK_PERIOD_MS);
466+ xSemaphoreGive (m);
467+ #else
468+ mutex_enter_blocking (&__usb_mutex);
469+ tud_disconnect ();
470+ sleep_ms (500 );
471+ mutex_exit (&__usb_mutex);
472+ #endif
473+ // Ensure when we reconnect we make the new descriptor
474+ free (usbd_desc_cfg);
475+ usbd_desc_cfg = nullptr ;
476+ usbd_desc_cfg_len = 0 ;
477+ if (__hid_report) {
478+ usbUnregisterInterface (__hid_interface);
479+ usbUnregisterEndpointIn (__hid_endpoint);
480+ }
481+ free (__hid_report);
482+ __hid_report = nullptr ;
483+ __hid_report_len = 0 ;
484+ }
485+
486+ void usbConnect () {
487+ __SetupDescHIDReport ();
488+ __SetupUSBDescriptor ();
489+
490+ #ifdef __FREERTOS
491+ auto m = __get_freertos_mutex_for_ptr (&__usb_mutex);
492+ xSemaphoreTake (m, portMAX_DELAY);
493+ tusb_connect ();
494+ xSemaphoreGive (m);
495+ #else
496+ mutex_enter_blocking (&__usb_mutex);
497+ tud_connect ();
498+ mutex_exit (&__usb_mutex);
499+ #endif
500+ }
501+
377502void __USBStart () __attribute__((weak));
378503
379504void __USBStart () {
0 commit comments