1 /*
2 * Implementation of commonly used procedures for HCD handling/initialization
3 * If possible, everything OS specific should be here
4 */
5
6 #include <string.h> /* memset... */
7 #include <time.h> /* nanosleep */
8
9 #include <sys/mman.h> /* Physical to virtual memory mapping */
10
11 #include <ddekit/interrupt.h> /* DDEKit based interrupt handling */
12
13 #include <minix/clkconf.h> /* clkconf_* */
14 #include <minix/syslib.h> /* sys_privctl */
15
16 #include <usbd/hcd_common.h>
17 #include <usbd/hcd_interface.h>
18 #include <usbd/usbd_common.h>
19
20
21 /*===========================================================================*
22 * Local prototypes *
23 *===========================================================================*/
24 /* Descriptor related operations */
25 static int hcd_fill_configuration(hcd_reg1 *, int, hcd_configuration *, int);
26 static int hcd_fill_interface(hcd_reg1 *, int, hcd_interface *, int);
27 static int hcd_fill_endpoint(hcd_reg1 *, int, hcd_endpoint *);
28
29 /* Handling free USB device addresses */
30 static hcd_reg1 hcd_reserve_addr(hcd_driver_state *);
31 static void hcd_release_addr(hcd_driver_state *, hcd_reg1);
32
33
34 /*===========================================================================*
35 * Local definitions *
36 *===========================================================================*/
37 /* List of all allocated devices */
38 static hcd_device_state * dev_list = NULL;
39
40
41 /*===========================================================================*
42 * hcd_os_interrupt_attach *
43 *===========================================================================*/
44 int
hcd_os_interrupt_attach(int irq,void (* init)(void *),void (* isr)(void *),void * priv)45 hcd_os_interrupt_attach(int irq, void (*init)(void *),
46 void (*isr)(void *), void *priv)
47 {
48 DEBUG_DUMP;
49
50 if (NULL == ddekit_interrupt_attach(irq, 0, init, isr, priv)) {
51 USB_MSG("Attaching interrupt %d failed", irq);
52 return EXIT_FAILURE;
53 }
54
55 return EXIT_SUCCESS;
56 }
57
58
59 /*===========================================================================*
60 * hcd_os_interrupt_detach *
61 *===========================================================================*/
62 void
hcd_os_interrupt_detach(int irq)63 hcd_os_interrupt_detach(int irq)
64 {
65 DEBUG_DUMP;
66 ddekit_interrupt_detach(irq);
67 }
68
69
70 /*===========================================================================*
71 * hcd_os_interrupt_enable *
72 *===========================================================================*/
73 void
hcd_os_interrupt_enable(int irq)74 hcd_os_interrupt_enable(int irq)
75 {
76 DEBUG_DUMP;
77 ddekit_interrupt_enable(irq);
78 }
79
80
81 /*===========================================================================*
82 * hcd_os_interrupt_disable *
83 *===========================================================================*/
84 void
hcd_os_interrupt_disable(int irq)85 hcd_os_interrupt_disable(int irq)
86 {
87 DEBUG_DUMP;
88 ddekit_interrupt_disable(irq);
89 }
90
91
92 /*===========================================================================*
93 * hcd_os_regs_init *
94 *===========================================================================*/
95 void *
hcd_os_regs_init(hcd_addr phys_addr,unsigned long addr_len)96 hcd_os_regs_init(hcd_addr phys_addr, unsigned long addr_len)
97 {
98 /* Memory range where we need privileged access */
99 struct minix_mem_range mr;
100
101 /* NULL unless initialization was fully completed */
102 void * virt_reg_base;
103
104 DEBUG_DUMP;
105
106 virt_reg_base = NULL;
107
108 /* Must have been set before */
109 USB_ASSERT(0 != phys_addr, "Invalid base address!");
110 USB_ASSERT(0 != addr_len, "Invalid base length!");
111
112 /* Set memory range for peripheral */
113 mr.mr_base = phys_addr;
114 mr.mr_limit = phys_addr + addr_len;
115
116 /* Try getting access to memory range */
117 if (EXIT_SUCCESS == sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr)) {
118
119 /* And map it where we want it */
120 virt_reg_base = vm_map_phys(SELF, (void *)phys_addr, addr_len);
121
122 /* Check for mapping errors to allow us returning NULL */
123 if (MAP_FAILED == virt_reg_base) {
124 USB_MSG("Mapping memory with vm_map_phys() failed");
125 virt_reg_base = NULL;
126 }
127
128 } else
129 USB_MSG("Acquiring memory with sys_privctl() failed");
130
131 return virt_reg_base;
132 }
133
134
135 /*===========================================================================*
136 * hcd_os_regs_deinit *
137 *===========================================================================*/
138 int
hcd_os_regs_deinit(hcd_addr virt_addr,unsigned long addr_len)139 hcd_os_regs_deinit(hcd_addr virt_addr, unsigned long addr_len)
140 {
141 DEBUG_DUMP;
142
143 /* To keep USBD return value convention */
144 return (0 == vm_unmap_phys(SELF, (void*)virt_addr, addr_len)) ?
145 EXIT_SUCCESS : EXIT_FAILURE;
146 }
147
148
149 /*===========================================================================*
150 * hcd_os_clkconf *
151 *===========================================================================*/
152 int
hcd_os_clkconf(unsigned long clk,unsigned long mask,unsigned long value)153 hcd_os_clkconf(unsigned long clk, unsigned long mask, unsigned long value)
154 {
155 DEBUG_DUMP;
156
157 /* Apparently clkconf_init may be called more than once anyway */
158 if ((0 == clkconf_init()) && (0 == clkconf_set(clk, mask, value)))
159 return EXIT_SUCCESS;
160 else
161 return EXIT_FAILURE;
162 }
163
164
165 /*===========================================================================*
166 * hcd_os_clkconf_release *
167 *===========================================================================*/
168 int
hcd_os_clkconf_release(void)169 hcd_os_clkconf_release(void)
170 {
171 DEBUG_DUMP;
172 return clkconf_release();
173 }
174
175
176 /*===========================================================================*
177 * hcd_os_nanosleep *
178 *===========================================================================*/
179 void
hcd_os_nanosleep(int nanosec)180 hcd_os_nanosleep(int nanosec)
181 {
182 struct timespec nanotm;
183 int r;
184
185 DEBUG_DUMP;
186
187 if (nanosec >= HCD_NANO) {
188 nanotm.tv_sec = nanosec / HCD_NANO;
189 nanotm.tv_nsec = nanosec % HCD_NANO;
190 } else {
191 nanotm.tv_sec = 0;
192 nanotm.tv_nsec = nanosec;
193 }
194
195 /* TODO: Since it is not likely to be ever interrupted, we do not try
196 * to sleep for a remaining time in case of signal handling */
197 /* Signal handling will most likely end up with termination anyway */
198 r = nanosleep(&nanotm, NULL);
199 USB_ASSERT(EXIT_SUCCESS == r, "Calling nanosleep() failed");
200 }
201
202
203 /*===========================================================================*
204 * hcd_connect_device *
205 *===========================================================================*/
206 int
hcd_connect_device(hcd_device_state * this_device,hcd_thread_function funct)207 hcd_connect_device(hcd_device_state * this_device, hcd_thread_function funct)
208 {
209 DEBUG_DUMP;
210
211 /* This is meant to allow thread name distinction
212 * and should not be used for anything else */
213 static unsigned int devnum = 0;
214
215 /* Should be able to hold device prefix and some number */
216 char devname[] = "dev..........";
217
218 USB_ASSERT((NULL == this_device->lock) &&
219 (NULL == this_device->thread) &&
220 (HCD_DEFAULT_ADDR == this_device->reserved_address) &&
221 (HCD_STATE_DISCONNECTED == this_device->state),
222 "Device structure not clean");
223
224 /* Mark as 'plugged in' to avoid treating device
225 * as 'disconnected' in case of errors below */
226 this_device->state = HCD_STATE_CONNECTION_PENDING;
227
228 /* Reserve device address for further use if available */
229 if (HCD_DEFAULT_ADDR == (this_device->reserved_address =
230 hcd_reserve_addr(this_device->driver))) {
231 USB_MSG("No free device addresses");
232 return EXIT_FAILURE;
233 }
234
235 /* Get 'lock' that makes device thread wait for events to occur */
236 if (NULL == (this_device->lock = ddekit_sem_init(0))) {
237 USB_MSG("Failed to initialize thread lock");
238 return EXIT_FAILURE;
239 }
240
241 /* Prepare name */
242 snprintf(devname, sizeof(devname), "dev%u", devnum++);
243
244 /* Get thread itself */
245 if (NULL == (this_device->thread = ddekit_thread_create(funct,
246 this_device,
247 (const char *)devname))) {
248 USB_MSG("Failed to initialize USB device thread");
249 return EXIT_FAILURE;
250 }
251
252 return EXIT_SUCCESS;
253 }
254
255
256 /*===========================================================================*
257 * hcd_disconnect_device *
258 *===========================================================================*/
259 void
hcd_disconnect_device(hcd_device_state * this_device)260 hcd_disconnect_device(hcd_device_state * this_device)
261 {
262 DEBUG_DUMP;
263
264 /* TODO: This should disconnect all the children if they exist */
265
266 /* Clean configuration tree in case it was acquired */
267 hcd_tree_cleanup(&(this_device->config_tree));
268
269 /* Release allocated resources */
270 if (NULL != this_device->thread)
271 ddekit_thread_terminate(this_device->thread);
272 if (NULL != this_device->lock)
273 ddekit_sem_deinit(this_device->lock);
274
275 /* Release reserved address */
276 if (HCD_DEFAULT_ADDR != this_device->reserved_address)
277 hcd_release_addr(this_device->driver,
278 this_device->reserved_address);
279
280 /* Mark as disconnected */
281 this_device->state = HCD_STATE_DISCONNECTED;
282 }
283
284
285 /*===========================================================================*
286 * hcd_device_wait *
287 *===========================================================================*/
288 void
hcd_device_wait(hcd_device_state * device,hcd_event event,hcd_reg1 ep)289 hcd_device_wait(hcd_device_state * device, hcd_event event, hcd_reg1 ep)
290 {
291 DEBUG_DUMP;
292
293 USB_DBG("0x%08X wait (0x%02X, 0x%02X)", device, event, ep);
294
295 device->wait_event = event;
296 device->wait_ep = ep;
297
298 ddekit_sem_down(device->lock);
299 }
300
301
302 /*===========================================================================*
303 * hcd_device_continue *
304 *===========================================================================*/
305 void
hcd_device_continue(hcd_device_state * device,hcd_event event,hcd_reg1 ep)306 hcd_device_continue(hcd_device_state * device, hcd_event event, hcd_reg1 ep)
307 {
308 DEBUG_DUMP;
309
310 USB_DBG("0x%08X continue (0x%02X, 0x%02X)", device, event, ep);
311
312 USB_ASSERT(device->wait_event == event, "Unexpected event");
313 USB_ASSERT(device->wait_ep == ep, "Unexpected endpoint");
314
315 ddekit_sem_up(device->lock);
316 }
317
318
319 /*===========================================================================*
320 * hcd_new_device *
321 *===========================================================================*/
322 hcd_device_state *
hcd_new_device(void)323 hcd_new_device(void)
324 {
325 hcd_device_state * d;
326
327 DEBUG_DUMP;
328
329 /* One new blank device */
330 d = calloc(1, sizeof(*d));
331
332 USB_ASSERT(NULL != d, "Failed to allocate device");
333
334 if (NULL == dev_list) {
335 dev_list = d;
336 } else {
337 d->_next = dev_list;
338 dev_list = d;
339 }
340
341 #ifdef HCD_DUMP_DEVICE_LIST
342 /* Dump updated state of device list */
343 hcd_dump_devices();
344 #endif
345
346 return d;
347 }
348
349
350 /*===========================================================================*
351 * hcd_delete_device *
352 *===========================================================================*/
353 void
hcd_delete_device(hcd_device_state * d)354 hcd_delete_device(hcd_device_state * d)
355 {
356 hcd_device_state * temp;
357
358 DEBUG_DUMP;
359
360 if (d == dev_list) {
361 dev_list = dev_list->_next;
362 } else {
363 temp = dev_list;
364
365 /* Find the device and ... */
366 while (temp->_next != d) {
367 USB_ASSERT(NULL != temp->_next,
368 "Invalid state of device list");
369 temp = temp->_next;
370 }
371
372 /* ...make device list forget about it */
373 temp->_next = temp->_next->_next;
374 }
375
376 free(d);
377
378 #ifdef HCD_DUMP_DEVICE_LIST
379 /* Dump updated state of device list */
380 hcd_dump_devices();
381 #endif
382 }
383
384
385 /*===========================================================================*
386 * hcd_dump_devices *
387 *===========================================================================*/
388 void
hcd_dump_devices(void)389 hcd_dump_devices(void)
390 {
391 hcd_device_state * temp;
392
393 DEBUG_DUMP;
394
395 temp = dev_list;
396
397 USB_MSG("Allocated devices:");
398
399 while (NULL != temp) {
400 USB_MSG("0x%08X", (int)temp);
401 temp = temp->_next;
402 }
403 }
404
405
406 /*===========================================================================*
407 * hcd_check_device *
408 *===========================================================================*/
409 int
hcd_check_device(hcd_device_state * d)410 hcd_check_device(hcd_device_state * d)
411 {
412 hcd_device_state * temp;
413
414 DEBUG_DUMP;
415
416 temp = dev_list;
417
418 /* Traverse the list of allocated devices
419 * to determine validity of this one */
420 while (NULL != temp) {
421 if (temp == d)
422 return EXIT_SUCCESS; /* Device found within the list */
423 temp = temp->_next;
424 }
425
426 /* Device was not found, may have been removed earlier */
427 return EXIT_FAILURE;
428 }
429
430
431 /*===========================================================================*
432 * hcd_buffer_to_tree *
433 *===========================================================================*/
434 int
hcd_buffer_to_tree(hcd_reg1 * buf,int len,hcd_configuration * c)435 hcd_buffer_to_tree(hcd_reg1 * buf, int len, hcd_configuration * c)
436 {
437 hcd_interface * i;
438 hcd_endpoint * e;
439 hcd_descriptor * desc;
440 int cfg_num;
441 int if_num;
442 int ep_num;
443
444 DEBUG_DUMP;
445
446 cfg_num = 0;
447 if_num = 0;
448 ep_num = 0;
449
450 i = NULL;
451 e = NULL;
452
453 /* Cleanup initially to NULL pointers before any allocation */
454 memset(c, 0, sizeof(*c));
455
456 while (len > (int)sizeof(*desc)) {
457 /* Check descriptor type */
458 desc = (hcd_descriptor *)buf;
459
460 if (0 == desc->bLength) {
461 USB_MSG("Zero length descriptor");
462 goto PARSE_ERROR;
463 }
464
465 if (UDESC_CONFIG == desc->bDescriptorType) {
466 if (EXIT_SUCCESS != hcd_fill_configuration(buf, len,
467 c, cfg_num++))
468 goto PARSE_ERROR;
469
470 if_num = 0;
471 }
472 else if (UDESC_INTERFACE == desc->bDescriptorType) {
473 if (NULL == c->interface)
474 goto PARSE_ERROR;
475
476 i = &(c->interface[if_num]);
477
478 if (EXIT_SUCCESS != hcd_fill_interface(buf, len,
479 i, if_num++))
480 goto PARSE_ERROR;
481
482 ep_num = 0;
483 }
484 else if (UDESC_ENDPOINT == desc->bDescriptorType) {
485 if (NULL == c->interface)
486 goto PARSE_ERROR;
487
488 if (NULL == i)
489 goto PARSE_ERROR;
490
491 e = &(i->endpoint[ep_num++]);
492
493 if (EXIT_SUCCESS != hcd_fill_endpoint(buf, len, e))
494 goto PARSE_ERROR;
495 } else
496 USB_DBG("Unhandled descriptor type 0x%02X",
497 desc->bDescriptorType);
498
499 len -= desc->bLength;
500 buf += desc->bLength;
501 }
502
503 if (0 != len) {
504 USB_MSG("After parsing, some descriptor data remains");
505 goto PARSE_ERROR;
506 }
507
508 return EXIT_SUCCESS;
509
510 PARSE_ERROR:
511 hcd_tree_cleanup(c);
512 return EXIT_FAILURE;
513 }
514
515
516 /*===========================================================================*
517 * hcd_tree_cleanup *
518 *===========================================================================*/
519 void
hcd_tree_cleanup(hcd_configuration * c)520 hcd_tree_cleanup(hcd_configuration * c)
521 {
522 int if_idx;
523
524 DEBUG_DUMP;
525
526 /* Free if anything was allocated */
527 if (NULL != c->interface) {
528
529 USB_ASSERT(c->num_interfaces > 0, "Interface number error");
530
531 for (if_idx = 0; if_idx < c->num_interfaces; if_idx++) {
532 if (NULL != c->interface[if_idx].endpoint) {
533 USB_DBG("Freeing ep for interface #%d", if_idx);
534 free(c->interface[if_idx].endpoint);
535 }
536 }
537
538 USB_DBG("Freeing interfaces");
539 free(c->interface);
540 c->interface = NULL;
541 }
542 }
543
544
545 /*===========================================================================*
546 * hcd_tree_find_ep *
547 *===========================================================================*/
548 hcd_endpoint *
hcd_tree_find_ep(hcd_configuration * c,hcd_reg1 ep)549 hcd_tree_find_ep(hcd_configuration * c, hcd_reg1 ep)
550 {
551 hcd_interface * i;
552 hcd_endpoint * e;
553 int if_idx;
554 int ep_idx;
555
556 DEBUG_DUMP;
557
558 /* Free if anything was allocated */
559 USB_ASSERT(NULL != c->interface, "No interfaces available");
560 USB_ASSERT(c->num_interfaces > 0, "Interface number error");
561
562 for (if_idx = 0; if_idx < c->num_interfaces; if_idx++) {
563 i = &(c->interface[if_idx]);
564 for (ep_idx = 0; ep_idx < i->num_endpoints; ep_idx++) {
565 e = &(i->endpoint[ep_idx]);
566 if (UE_GET_ADDR(e->descriptor.bEndpointAddress) == ep)
567 return e;
568 }
569 }
570
571 return NULL;
572 }
573
574
575 /*===========================================================================*
576 * hcd_fill_configuration *
577 *===========================================================================*/
578 static int
hcd_fill_configuration(hcd_reg1 * buf,int len,hcd_configuration * c,int num)579 hcd_fill_configuration(hcd_reg1 * buf, int len, hcd_configuration * c, int num)
580 {
581 hcd_config_descriptor * desc;
582 int interfaces_size;
583
584 DEBUG_DUMP;
585
586 desc = (hcd_config_descriptor *)buf;
587
588 USB_DBG("Configuration #%d", num);
589
590 if (num > 0) {
591 USB_DBG("Only one configuration possible");
592 return EXIT_SUCCESS;
593 }
594
595 if (UDESC_CONFIG != desc->bDescriptorType)
596 return EXIT_FAILURE;
597
598 if (desc->bLength > len)
599 return EXIT_FAILURE;
600
601 if (sizeof(*desc) != desc->bLength)
602 return EXIT_FAILURE;
603
604 memcpy(&(c->descriptor), buf, sizeof(c->descriptor));
605
606 c->num_interfaces = c->descriptor.bNumInterface;
607
608 interfaces_size = c->num_interfaces * sizeof(*(c->interface));
609
610 USB_DBG("Allocating interfaces, %dB", interfaces_size);
611 c->interface = malloc(interfaces_size);
612
613 memset(c->interface, 0, interfaces_size);
614
615 /* Dump configuration in debug mode */
616 USB_DBG("<<CONFIGURATION>>");
617 USB_DBG("bLength %02X", desc->bLength);
618 USB_DBG("bDescriptorType %02X", desc->bDescriptorType);
619 USB_DBG("wTotalLength %04X", UGETW(desc->wTotalLength));
620 USB_DBG("bNumInterface %02X", desc->bNumInterface);
621 USB_DBG("bConfigurationValue %02X", desc->bConfigurationValue);
622 USB_DBG("iConfiguration %02X", desc->iConfiguration);
623 USB_DBG("bmAttributes %02X", desc->bmAttributes);
624 USB_DBG("bMaxPower %02X", desc->bMaxPower);
625
626 return EXIT_SUCCESS;
627 }
628
629
630 /*===========================================================================*
631 * hcd_fill_interface *
632 *===========================================================================*/
633 static int
hcd_fill_interface(hcd_reg1 * buf,int len,hcd_interface * i,int num)634 hcd_fill_interface(hcd_reg1 * buf, int len, hcd_interface * i, int num)
635 {
636 hcd_interface_descriptor * desc;
637 int endpoints_size;
638
639 DEBUG_DUMP;
640
641 desc = (hcd_interface_descriptor *)buf;
642
643 USB_DBG("Interface #%d", num);
644
645 if (UDESC_INTERFACE != desc->bDescriptorType)
646 return EXIT_FAILURE;
647
648 if (desc->bLength > len)
649 return EXIT_FAILURE;
650
651 if (sizeof(*desc) != desc->bLength)
652 return EXIT_FAILURE;
653
654 /* It is mandatory to supply interfaces in correct order */
655 if (desc->bInterfaceNumber != num)
656 return EXIT_FAILURE;
657
658 memcpy(&(i->descriptor), buf, sizeof(i->descriptor));
659
660 i->num_endpoints = i->descriptor.bNumEndpoints;
661
662 endpoints_size = i->num_endpoints * sizeof(*(i->endpoint));
663
664 USB_DBG("Allocating endpoints, %dB", endpoints_size);
665 i->endpoint = malloc(endpoints_size);
666
667 memset(i->endpoint, 0, endpoints_size);
668
669 /* Dump interface in debug mode */
670 USB_DBG("<<INTERFACE>>");
671 USB_DBG("bLength %02X", desc->bLength);
672 USB_DBG("bDescriptorType %02X", desc->bDescriptorType);
673 USB_DBG("bInterfaceNumber %02X", desc->bInterfaceNumber);
674 USB_DBG("bAlternateSetting %02X", desc->bAlternateSetting);
675 USB_DBG("bNumEndpoints %02X", desc->bNumEndpoints);
676 USB_DBG("bInterfaceClass %02X", desc->bInterfaceClass);
677 USB_DBG("bInterfaceSubClass %02X", desc->bInterfaceSubClass);
678 USB_DBG("bInterfaceProtocol %02X", desc->bInterfaceProtocol);
679 USB_DBG("iInterface %02X", desc->iInterface);
680
681 return EXIT_SUCCESS;
682 }
683
684
685 /*===========================================================================*
686 * hcd_fill_endpoint *
687 *===========================================================================*/
688 static int
hcd_fill_endpoint(hcd_reg1 * buf,int len,hcd_endpoint * e)689 hcd_fill_endpoint(hcd_reg1 * buf, int len, hcd_endpoint * e)
690 {
691 hcd_endpoint_descriptor * desc;
692
693 DEBUG_DUMP;
694
695 desc = (hcd_endpoint_descriptor *)buf;
696
697 USB_DBG("Endpoint #%d", UE_GET_ADDR(desc->bEndpointAddress));
698
699 if (UDESC_ENDPOINT != desc->bDescriptorType)
700 return EXIT_FAILURE;
701
702 if (desc->bLength > len)
703 return EXIT_FAILURE;
704
705 if (sizeof(*desc) != desc->bLength)
706 return EXIT_FAILURE;
707
708 memcpy(&(e->descriptor), buf, sizeof(e->descriptor));
709
710 /* Dump endpoint in debug mode */
711 USB_DBG("<<ENDPOINT>>");
712 USB_DBG("bLength %02X", desc->bLength);
713 USB_DBG("bDescriptorType %02X", desc->bDescriptorType);
714 USB_DBG("bEndpointAddress %02X", desc->bEndpointAddress);
715 USB_DBG("bmAttributes %02X", desc->bmAttributes);
716 USB_DBG("wMaxPacketSize %04X", UGETW(desc->wMaxPacketSize));
717 USB_DBG("bInterval %02X", desc->bInterval);
718
719 return EXIT_SUCCESS;
720 }
721
722
723 /*===========================================================================*
724 * hcd_reserve_addr *
725 *===========================================================================*/
726 static hcd_reg1
hcd_reserve_addr(hcd_driver_state * driver)727 hcd_reserve_addr(hcd_driver_state * driver)
728 {
729 hcd_reg1 addr;
730
731 DEBUG_DUMP;
732
733 for (addr = HCD_FIRST_ADDR; addr <= HCD_LAST_ADDR; addr++) {
734 if (HCD_ADDR_AVAILABLE == driver->dev_addr[addr]) {
735 USB_DBG("Reserved address: %u", addr);
736 driver->dev_addr[addr] = HCD_ADDR_USED;
737 return addr;
738 }
739 }
740
741 /* This means error */
742 return HCD_DEFAULT_ADDR;
743 }
744
745
746 /*===========================================================================*
747 * hcd_release_addr *
748 *===========================================================================*/
749 static void
hcd_release_addr(hcd_driver_state * driver,hcd_reg1 addr)750 hcd_release_addr(hcd_driver_state * driver, hcd_reg1 addr)
751 {
752 DEBUG_DUMP;
753
754 USB_ASSERT((addr > HCD_DEFAULT_ADDR) && (addr <= HCD_LAST_ADDR),
755 "Invalid device address to be released");
756 USB_ASSERT(HCD_ADDR_USED == driver->dev_addr[addr],
757 "Attempted to release unused address");
758
759 USB_DBG("Released address: %u", addr);
760 driver->dev_addr[addr] = HCD_ADDR_AVAILABLE;
761 }
762