2 * Implementation of commonly used procedures for HCD handling/initialization
3 * If possible, everything OS specific should be here
6 #include <string.h> /* memset... */
7 #include <time.h> /* nanosleep */
9 #include <sys/mman.h> /* Physical to virtual memory mapping */
11 #include <ddekit/interrupt.h> /* DDEKit based interrupt handling */
13 #include <minix/clkconf.h> /* clkconf_* */
14 #include <minix/syslib.h> /* sys_privctl */
16 #include <usbd/hcd_common.h>
17 #include <usbd/hcd_interface.h>
18 #include <usbd/usbd_common.h>
21 /*===========================================================================*
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
*);
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
);
34 /*===========================================================================*
36 *===========================================================================*/
37 /* List of all allocated devices */
38 static hcd_device_state
* dev_list
= NULL
;
41 /*===========================================================================*
42 * hcd_os_interrupt_attach *
43 *===========================================================================*/
45 hcd_os_interrupt_attach(int irq
, void (*init
)(void *),
46 void (*isr
)(void *), void *priv
)
50 if (NULL
== ddekit_interrupt_attach(irq
, 0, init
, isr
, priv
)) {
51 USB_MSG("Attaching interrupt %d failed", irq
);
59 /*===========================================================================*
60 * hcd_os_interrupt_detach *
61 *===========================================================================*/
63 hcd_os_interrupt_detach(int irq
)
66 ddekit_interrupt_detach(irq
);
70 /*===========================================================================*
71 * hcd_os_interrupt_enable *
72 *===========================================================================*/
74 hcd_os_interrupt_enable(int irq
)
77 ddekit_interrupt_enable(irq
);
81 /*===========================================================================*
82 * hcd_os_interrupt_disable *
83 *===========================================================================*/
85 hcd_os_interrupt_disable(int irq
)
88 ddekit_interrupt_disable(irq
);
92 /*===========================================================================*
94 *===========================================================================*/
96 hcd_os_regs_init(hcd_addr phys_addr
, unsigned long addr_len
)
98 /* Memory range where we need privileged access */
99 struct minix_mem_range mr
;
101 /* NULL unless initialization was fully completed */
102 void * virt_reg_base
;
106 virt_reg_base
= NULL
;
108 /* Must have been set before */
109 USB_ASSERT(0 != phys_addr
, "Invalid base address!");
110 USB_ASSERT(0 != addr_len
, "Invalid base length!");
112 /* Set memory range for peripheral */
113 mr
.mr_base
= phys_addr
;
114 mr
.mr_limit
= phys_addr
+ addr_len
;
116 /* Try getting access to memory range */
117 if (EXIT_SUCCESS
== sys_privctl(SELF
, SYS_PRIV_ADD_MEM
, &mr
)) {
119 /* And map it where we want it */
120 virt_reg_base
= vm_map_phys(SELF
, (void *)phys_addr
, addr_len
);
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
;
129 USB_MSG("Acquiring memory with sys_privctl() failed");
131 return virt_reg_base
;
135 /*===========================================================================*
136 * hcd_os_regs_deinit *
137 *===========================================================================*/
139 hcd_os_regs_deinit(hcd_addr virt_addr
, unsigned long addr_len
)
143 /* To keep USBD return value convention */
144 return (0 == vm_unmap_phys(SELF
, (void*)virt_addr
, addr_len
)) ?
145 EXIT_SUCCESS
: EXIT_FAILURE
;
149 /*===========================================================================*
151 *===========================================================================*/
153 hcd_os_clkconf(unsigned long clk
, unsigned long mask
, unsigned long value
)
157 /* Apparently clkconf_init may be called more than once anyway */
158 if ((0 == clkconf_init()) && (0 == clkconf_set(clk
, mask
, value
)))
165 /*===========================================================================*
166 * hcd_os_clkconf_release *
167 *===========================================================================*/
169 hcd_os_clkconf_release(void)
172 return clkconf_release();
176 /*===========================================================================*
178 *===========================================================================*/
180 hcd_os_nanosleep(int nanosec
)
182 struct timespec nanotm
;
187 if (nanosec
>= HCD_NANO
) {
188 nanotm
.tv_sec
= nanosec
/ HCD_NANO
;
189 nanotm
.tv_nsec
= nanosec
% HCD_NANO
;
192 nanotm
.tv_nsec
= nanosec
;
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");
203 /*===========================================================================*
204 * hcd_connect_device *
205 *===========================================================================*/
207 hcd_connect_device(hcd_device_state
* this_device
, hcd_thread_function funct
)
211 /* This is meant to allow thread name distinction
212 * and should not be used for anything else */
213 static unsigned int devnum
= 0;
215 /* Should be able to hold device prefix and some number */
216 char devname
[] = "dev..........";
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");
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
;
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");
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");
242 snprintf(devname
, sizeof(devname
), "dev%u", devnum
++);
244 /* Get thread itself */
245 if (NULL
== (this_device
->thread
= ddekit_thread_create(funct
,
247 (const char *)devname
))) {
248 USB_MSG("Failed to initialize USB device thread");
256 /*===========================================================================*
257 * hcd_disconnect_device *
258 *===========================================================================*/
260 hcd_disconnect_device(hcd_device_state
* this_device
)
264 /* TODO: This should disconnect all the children if they exist */
266 /* Clean configuration tree in case it was acquired */
267 hcd_tree_cleanup(&(this_device
->config_tree
));
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
);
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
);
280 /* Mark as disconnected */
281 this_device
->state
= HCD_STATE_DISCONNECTED
;
285 /*===========================================================================*
287 *===========================================================================*/
289 hcd_device_wait(hcd_device_state
* device
, hcd_event event
, hcd_reg1 ep
)
293 USB_DBG("0x%08X wait (0x%02X, 0x%02X)", device
, event
, ep
);
295 device
->wait_event
= event
;
296 device
->wait_ep
= ep
;
298 ddekit_sem_down(device
->lock
);
302 /*===========================================================================*
303 * hcd_device_continue *
304 *===========================================================================*/
306 hcd_device_continue(hcd_device_state
* device
, hcd_event event
, hcd_reg1 ep
)
310 USB_DBG("0x%08X continue (0x%02X, 0x%02X)", device
, event
, ep
);
312 USB_ASSERT(device
->wait_event
== event
, "Unexpected event");
313 USB_ASSERT(device
->wait_ep
== ep
, "Unexpected endpoint");
315 ddekit_sem_up(device
->lock
);
319 /*===========================================================================*
321 *===========================================================================*/
325 hcd_device_state
* d
;
329 /* One new blank device */
330 d
= calloc(1, sizeof(*d
));
332 USB_ASSERT(NULL
!= d
, "Failed to allocate device");
334 if (NULL
== dev_list
) {
341 #ifdef HCD_DUMP_DEVICE_LIST
342 /* Dump updated state of device list */
350 /*===========================================================================*
351 * hcd_delete_device *
352 *===========================================================================*/
354 hcd_delete_device(hcd_device_state
* d
)
356 hcd_device_state
* temp
;
361 dev_list
= dev_list
->_next
;
365 /* Find the device and ... */
366 while (temp
->_next
!= d
) {
367 USB_ASSERT(NULL
!= temp
->_next
,
368 "Invalid state of device list");
372 /* ...make device list forget about it */
373 temp
->_next
= temp
->_next
->_next
;
378 #ifdef HCD_DUMP_DEVICE_LIST
379 /* Dump updated state of device list */
385 /*===========================================================================*
387 *===========================================================================*/
389 hcd_dump_devices(void)
391 hcd_device_state
* temp
;
397 USB_MSG("Allocated devices:");
399 while (NULL
!= temp
) {
400 USB_MSG("0x%08X", (int)temp
);
406 /*===========================================================================*
408 *===========================================================================*/
410 hcd_check_device(hcd_device_state
* d
)
412 hcd_device_state
* temp
;
418 /* Traverse the list of allocated devices
419 * to determine validity of this one */
420 while (NULL
!= temp
) {
422 return EXIT_SUCCESS
; /* Device found within the list */
426 /* Device was not found, may have been removed earlier */
431 /*===========================================================================*
432 * hcd_buffer_to_tree *
433 *===========================================================================*/
435 hcd_buffer_to_tree(hcd_reg1
* buf
, int len
, hcd_configuration
* c
)
439 hcd_descriptor
* desc
;
453 /* Cleanup initially to NULL pointers before any allocation */
454 memset(c
, 0, sizeof(*c
));
456 while (len
> (int)sizeof(*desc
)) {
457 /* Check descriptor type */
458 desc
= (hcd_descriptor
*)buf
;
460 if (0 == desc
->bLength
) {
461 USB_MSG("Zero length descriptor");
465 if (UDESC_CONFIG
== desc
->bDescriptorType
) {
466 if (EXIT_SUCCESS
!= hcd_fill_configuration(buf
, len
,
472 else if (UDESC_INTERFACE
== desc
->bDescriptorType
) {
473 if (NULL
== c
->interface
)
476 i
= &(c
->interface
[if_num
]);
478 if (EXIT_SUCCESS
!= hcd_fill_interface(buf
, len
,
484 else if (UDESC_ENDPOINT
== desc
->bDescriptorType
) {
485 if (NULL
== c
->interface
)
491 e
= &(i
->endpoint
[ep_num
++]);
493 if (EXIT_SUCCESS
!= hcd_fill_endpoint(buf
, len
, e
))
496 USB_DBG("Unhandled descriptor type 0x%02X",
497 desc
->bDescriptorType
);
499 len
-= desc
->bLength
;
500 buf
+= desc
->bLength
;
504 USB_MSG("After parsing, some descriptor data remains");
516 /*===========================================================================*
518 *===========================================================================*/
520 hcd_tree_cleanup(hcd_configuration
* c
)
526 /* Free if anything was allocated */
527 if (NULL
!= c
->interface
) {
529 USB_ASSERT(c
->num_interfaces
> 0, "Interface number error");
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
);
538 USB_DBG("Freeing interfaces");
545 /*===========================================================================*
547 *===========================================================================*/
549 hcd_tree_find_ep(hcd_configuration
* c
, hcd_reg1 ep
)
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");
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
)
575 /*===========================================================================*
576 * hcd_fill_configuration *
577 *===========================================================================*/
579 hcd_fill_configuration(hcd_reg1
* buf
, int len
, hcd_configuration
* c
, int num
)
581 hcd_config_descriptor
* desc
;
586 desc
= (hcd_config_descriptor
*)buf
;
588 USB_DBG("Configuration #%d", num
);
591 USB_DBG("Only one configuration possible");
595 if (UDESC_CONFIG
!= desc
->bDescriptorType
)
598 if (desc
->bLength
> len
)
601 if (sizeof(*desc
) != desc
->bLength
)
604 memcpy(&(c
->descriptor
), buf
, sizeof(c
->descriptor
));
606 c
->num_interfaces
= c
->descriptor
.bNumInterface
;
608 interfaces_size
= c
->num_interfaces
* sizeof(*(c
->interface
));
610 USB_DBG("Allocating interfaces, %dB", interfaces_size
);
611 c
->interface
= malloc(interfaces_size
);
613 memset(c
->interface
, 0, interfaces_size
);
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
);
630 /*===========================================================================*
631 * hcd_fill_interface *
632 *===========================================================================*/
634 hcd_fill_interface(hcd_reg1
* buf
, int len
, hcd_interface
* i
, int num
)
636 hcd_interface_descriptor
* desc
;
641 desc
= (hcd_interface_descriptor
*)buf
;
643 USB_DBG("Interface #%d", num
);
645 if (UDESC_INTERFACE
!= desc
->bDescriptorType
)
648 if (desc
->bLength
> len
)
651 if (sizeof(*desc
) != desc
->bLength
)
654 /* It is mandatory to supply interfaces in correct order */
655 if (desc
->bInterfaceNumber
!= num
)
658 memcpy(&(i
->descriptor
), buf
, sizeof(i
->descriptor
));
660 i
->num_endpoints
= i
->descriptor
.bNumEndpoints
;
662 endpoints_size
= i
->num_endpoints
* sizeof(*(i
->endpoint
));
664 USB_DBG("Allocating endpoints, %dB", endpoints_size
);
665 i
->endpoint
= malloc(endpoints_size
);
667 memset(i
->endpoint
, 0, endpoints_size
);
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
);
685 /*===========================================================================*
686 * hcd_fill_endpoint *
687 *===========================================================================*/
689 hcd_fill_endpoint(hcd_reg1
* buf
, int len
, hcd_endpoint
* e
)
691 hcd_endpoint_descriptor
* desc
;
695 desc
= (hcd_endpoint_descriptor
*)buf
;
697 USB_DBG("Endpoint #%d", UE_GET_ADDR(desc
->bEndpointAddress
));
699 if (UDESC_ENDPOINT
!= desc
->bDescriptorType
)
702 if (desc
->bLength
> len
)
705 if (sizeof(*desc
) != desc
->bLength
)
708 memcpy(&(e
->descriptor
), buf
, sizeof(e
->descriptor
));
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
);
723 /*===========================================================================*
725 *===========================================================================*/
727 hcd_reserve_addr(hcd_driver_state
* driver
)
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
;
741 /* This means error */
742 return HCD_DEFAULT_ADDR
;
746 /*===========================================================================*
748 *===========================================================================*/
750 hcd_release_addr(hcd_driver_state
* driver
, hcd_reg1 addr
)
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");
759 USB_DBG("Released address: %u", addr
);
760 driver
->dev_addr
[addr
] = HCD_ADDR_AVAILABLE
;