xref: /minix3/minix/drivers/usb/usbd/hcd/hcd_common.c (revision 663180310555bd327d139fb2cd11318607a7f247)
1433d6423SLionel Sambuc /*
2433d6423SLionel Sambuc  * Implementation of commonly used procedures for HCD handling/initialization
3433d6423SLionel Sambuc  * If possible, everything OS specific should be here
4433d6423SLionel Sambuc  */
5433d6423SLionel Sambuc 
6433d6423SLionel Sambuc #include <string.h>			/* memset... */
7433d6423SLionel Sambuc #include <time.h>			/* nanosleep */
8433d6423SLionel Sambuc 
9433d6423SLionel Sambuc #include <sys/mman.h>			/* Physical to virtual memory mapping */
10433d6423SLionel Sambuc 
11433d6423SLionel Sambuc #include <ddekit/interrupt.h>		/* DDEKit based interrupt handling */
12433d6423SLionel Sambuc 
13433d6423SLionel Sambuc #include <minix/clkconf.h>		/* clkconf_* */
14433d6423SLionel Sambuc #include <minix/syslib.h>		/* sys_privctl */
15433d6423SLionel Sambuc 
162d64210cSWojciech Zajac #include <usbd/hcd_common.h>
172d64210cSWojciech Zajac #include <usbd/hcd_interface.h>
182d64210cSWojciech Zajac #include <usbd/usbd_common.h>
19433d6423SLionel Sambuc 
20433d6423SLionel Sambuc 
21433d6423SLionel Sambuc /*===========================================================================*
22433d6423SLionel Sambuc  *    Local prototypes                                                       *
23433d6423SLionel Sambuc  *===========================================================================*/
242d64210cSWojciech Zajac /* Descriptor related operations */
25433d6423SLionel Sambuc static int hcd_fill_configuration(hcd_reg1 *, int, hcd_configuration *, int);
26433d6423SLionel Sambuc static int hcd_fill_interface(hcd_reg1 *, int, hcd_interface *, int);
27433d6423SLionel Sambuc static int hcd_fill_endpoint(hcd_reg1 *, int, hcd_endpoint *);
28433d6423SLionel Sambuc 
292d64210cSWojciech Zajac /* Handling free USB device addresses */
302d64210cSWojciech Zajac static hcd_reg1 hcd_reserve_addr(hcd_driver_state *);
312d64210cSWojciech Zajac static void hcd_release_addr(hcd_driver_state *, hcd_reg1);
322d64210cSWojciech Zajac 
332d64210cSWojciech Zajac 
342d64210cSWojciech Zajac /*===========================================================================*
352d64210cSWojciech Zajac  *    Local definitions                                                      *
362d64210cSWojciech Zajac  *===========================================================================*/
372d64210cSWojciech Zajac /* List of all allocated devices */
382d64210cSWojciech Zajac static hcd_device_state * dev_list = NULL;
392d64210cSWojciech Zajac 
40433d6423SLionel Sambuc 
41433d6423SLionel Sambuc /*===========================================================================*
42433d6423SLionel Sambuc  *    hcd_os_interrupt_attach                                                *
43433d6423SLionel Sambuc  *===========================================================================*/
44433d6423SLionel Sambuc int
hcd_os_interrupt_attach(int irq,void (* init)(void *),void (* isr)(void *),void * priv)45433d6423SLionel Sambuc hcd_os_interrupt_attach(int irq, void (*init)(void *),
46433d6423SLionel Sambuc 			void (*isr)(void *), void *priv)
47433d6423SLionel Sambuc {
48433d6423SLionel Sambuc 	DEBUG_DUMP;
49433d6423SLionel Sambuc 
50433d6423SLionel Sambuc 	if (NULL == ddekit_interrupt_attach(irq, 0, init, isr, priv)) {
51433d6423SLionel Sambuc 		USB_MSG("Attaching interrupt %d failed", irq);
52433d6423SLionel Sambuc 		return EXIT_FAILURE;
53433d6423SLionel Sambuc 	}
54433d6423SLionel Sambuc 
55433d6423SLionel Sambuc 	return EXIT_SUCCESS;
56433d6423SLionel Sambuc }
57433d6423SLionel Sambuc 
58433d6423SLionel Sambuc 
59433d6423SLionel Sambuc /*===========================================================================*
60433d6423SLionel Sambuc  *    hcd_os_interrupt_detach                                                *
61433d6423SLionel Sambuc  *===========================================================================*/
62433d6423SLionel Sambuc void
hcd_os_interrupt_detach(int irq)63433d6423SLionel Sambuc hcd_os_interrupt_detach(int irq)
64433d6423SLionel Sambuc {
65433d6423SLionel Sambuc 	DEBUG_DUMP;
66433d6423SLionel Sambuc 	ddekit_interrupt_detach(irq);
67433d6423SLionel Sambuc }
68433d6423SLionel Sambuc 
69433d6423SLionel Sambuc 
70433d6423SLionel Sambuc /*===========================================================================*
71433d6423SLionel Sambuc  *    hcd_os_interrupt_enable                                                *
72433d6423SLionel Sambuc  *===========================================================================*/
73433d6423SLionel Sambuc void
hcd_os_interrupt_enable(int irq)74433d6423SLionel Sambuc hcd_os_interrupt_enable(int irq)
75433d6423SLionel Sambuc {
76433d6423SLionel Sambuc 	DEBUG_DUMP;
77433d6423SLionel Sambuc 	ddekit_interrupt_enable(irq);
78433d6423SLionel Sambuc }
79433d6423SLionel Sambuc 
80433d6423SLionel Sambuc 
81433d6423SLionel Sambuc /*===========================================================================*
82433d6423SLionel Sambuc  *    hcd_os_interrupt_disable                                               *
83433d6423SLionel Sambuc  *===========================================================================*/
84433d6423SLionel Sambuc void
hcd_os_interrupt_disable(int irq)85433d6423SLionel Sambuc hcd_os_interrupt_disable(int irq)
86433d6423SLionel Sambuc {
87433d6423SLionel Sambuc 	DEBUG_DUMP;
88433d6423SLionel Sambuc 	ddekit_interrupt_disable(irq);
89433d6423SLionel Sambuc }
90433d6423SLionel Sambuc 
91433d6423SLionel Sambuc 
92433d6423SLionel Sambuc /*===========================================================================*
93433d6423SLionel Sambuc  *    hcd_os_regs_init                                                       *
94433d6423SLionel Sambuc  *===========================================================================*/
95433d6423SLionel Sambuc void *
hcd_os_regs_init(hcd_addr phys_addr,unsigned long addr_len)96433d6423SLionel Sambuc hcd_os_regs_init(hcd_addr phys_addr, unsigned long addr_len)
97433d6423SLionel Sambuc {
98433d6423SLionel Sambuc 	/* Memory range where we need privileged access */
99433d6423SLionel Sambuc 	struct minix_mem_range mr;
100433d6423SLionel Sambuc 
101433d6423SLionel Sambuc 	/* NULL unless initialization was fully completed */
102433d6423SLionel Sambuc 	void * virt_reg_base;
103433d6423SLionel Sambuc 
104433d6423SLionel Sambuc 	DEBUG_DUMP;
105433d6423SLionel Sambuc 
106433d6423SLionel Sambuc 	virt_reg_base = NULL;
107433d6423SLionel Sambuc 
108433d6423SLionel Sambuc 	/* Must have been set before */
109433d6423SLionel Sambuc 	USB_ASSERT(0 != phys_addr, "Invalid base address!");
110433d6423SLionel Sambuc 	USB_ASSERT(0 != addr_len, "Invalid base length!");
111433d6423SLionel Sambuc 
112433d6423SLionel Sambuc 	/* Set memory range for peripheral */
113433d6423SLionel Sambuc 	mr.mr_base = phys_addr;
114433d6423SLionel Sambuc 	mr.mr_limit = phys_addr + addr_len;
115433d6423SLionel Sambuc 
116433d6423SLionel Sambuc 	/* Try getting access to memory range */
117433d6423SLionel Sambuc 	if (EXIT_SUCCESS == sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr)) {
118433d6423SLionel Sambuc 
119433d6423SLionel Sambuc 		/* And map it where we want it */
120433d6423SLionel Sambuc 		virt_reg_base = vm_map_phys(SELF, (void *)phys_addr, addr_len);
121433d6423SLionel Sambuc 
122433d6423SLionel Sambuc 		/* Check for mapping errors to allow us returning NULL */
123433d6423SLionel Sambuc 		if (MAP_FAILED == virt_reg_base) {
124433d6423SLionel Sambuc 			USB_MSG("Mapping memory with vm_map_phys() failed");
125433d6423SLionel Sambuc 			virt_reg_base = NULL;
126433d6423SLionel Sambuc 		}
127433d6423SLionel Sambuc 
128433d6423SLionel Sambuc 	} else
129433d6423SLionel Sambuc 		USB_MSG("Acquiring memory with sys_privctl() failed");
130433d6423SLionel Sambuc 
131433d6423SLionel Sambuc 	return virt_reg_base;
132433d6423SLionel Sambuc }
133433d6423SLionel Sambuc 
134433d6423SLionel Sambuc 
135433d6423SLionel Sambuc /*===========================================================================*
136433d6423SLionel Sambuc  *    hcd_os_regs_deinit                                                     *
137433d6423SLionel Sambuc  *===========================================================================*/
138433d6423SLionel Sambuc int
hcd_os_regs_deinit(hcd_addr virt_addr,unsigned long addr_len)139433d6423SLionel Sambuc hcd_os_regs_deinit(hcd_addr virt_addr, unsigned long addr_len)
140433d6423SLionel Sambuc {
141433d6423SLionel Sambuc 	DEBUG_DUMP;
142433d6423SLionel Sambuc 
143433d6423SLionel Sambuc 	/* To keep USBD return value convention */
144433d6423SLionel Sambuc 	return (0 == vm_unmap_phys(SELF, (void*)virt_addr, addr_len)) ?
145433d6423SLionel Sambuc 		EXIT_SUCCESS : EXIT_FAILURE;
146433d6423SLionel Sambuc }
147433d6423SLionel Sambuc 
148433d6423SLionel Sambuc 
149433d6423SLionel Sambuc /*===========================================================================*
150433d6423SLionel Sambuc  *    hcd_os_clkconf                                                         *
151433d6423SLionel Sambuc  *===========================================================================*/
152433d6423SLionel Sambuc int
hcd_os_clkconf(unsigned long clk,unsigned long mask,unsigned long value)153433d6423SLionel Sambuc hcd_os_clkconf(unsigned long clk, unsigned long mask, unsigned long value)
154433d6423SLionel Sambuc {
155433d6423SLionel Sambuc 	DEBUG_DUMP;
156433d6423SLionel Sambuc 
157433d6423SLionel Sambuc 	/* Apparently clkconf_init may be called more than once anyway */
158433d6423SLionel Sambuc 	if ((0 == clkconf_init()) && (0 == clkconf_set(clk, mask, value)))
159433d6423SLionel Sambuc 		return EXIT_SUCCESS;
160433d6423SLionel Sambuc 	else
161433d6423SLionel Sambuc 		return EXIT_FAILURE;
162433d6423SLionel Sambuc }
163433d6423SLionel Sambuc 
164433d6423SLionel Sambuc 
165433d6423SLionel Sambuc /*===========================================================================*
166433d6423SLionel Sambuc  *    hcd_os_clkconf_release                                                 *
167433d6423SLionel Sambuc  *===========================================================================*/
168433d6423SLionel Sambuc int
hcd_os_clkconf_release(void)169433d6423SLionel Sambuc hcd_os_clkconf_release(void)
170433d6423SLionel Sambuc {
171433d6423SLionel Sambuc 	DEBUG_DUMP;
172433d6423SLionel Sambuc 	return clkconf_release();
173433d6423SLionel Sambuc }
174433d6423SLionel Sambuc 
175433d6423SLionel Sambuc 
176433d6423SLionel Sambuc /*===========================================================================*
177433d6423SLionel Sambuc  *    hcd_os_nanosleep                                                       *
178433d6423SLionel Sambuc  *===========================================================================*/
179433d6423SLionel Sambuc void
hcd_os_nanosleep(int nanosec)180433d6423SLionel Sambuc hcd_os_nanosleep(int nanosec)
181433d6423SLionel Sambuc {
182433d6423SLionel Sambuc 	struct timespec nanotm;
183*66318031SLionel Sambuc 	int r;
184433d6423SLionel Sambuc 
185433d6423SLionel Sambuc 	DEBUG_DUMP;
186433d6423SLionel Sambuc 
187433d6423SLionel Sambuc 	if (nanosec >= HCD_NANO) {
188433d6423SLionel Sambuc 		nanotm.tv_sec = nanosec / HCD_NANO;
189433d6423SLionel Sambuc 		nanotm.tv_nsec = nanosec % HCD_NANO;
190433d6423SLionel Sambuc 	} else {
191433d6423SLionel Sambuc 		nanotm.tv_sec = 0;
192433d6423SLionel Sambuc 		nanotm.tv_nsec = nanosec;
193433d6423SLionel Sambuc 	}
194433d6423SLionel Sambuc 
195433d6423SLionel Sambuc 	/* TODO: Since it is not likely to be ever interrupted, we do not try
196433d6423SLionel Sambuc 	 * to sleep for a remaining time in case of signal handling */
197433d6423SLionel Sambuc 	/* Signal handling will most likely end up with termination anyway */
198*66318031SLionel Sambuc 	r = nanosleep(&nanotm, NULL);
199*66318031SLionel Sambuc 	USB_ASSERT(EXIT_SUCCESS == r, "Calling nanosleep() failed");
200433d6423SLionel Sambuc }
201433d6423SLionel Sambuc 
202433d6423SLionel Sambuc 
203433d6423SLionel Sambuc /*===========================================================================*
2042d64210cSWojciech Zajac  *    hcd_connect_device                                                     *
205433d6423SLionel Sambuc  *===========================================================================*/
206433d6423SLionel Sambuc int
hcd_connect_device(hcd_device_state * this_device,hcd_thread_function funct)207433d6423SLionel Sambuc hcd_connect_device(hcd_device_state * this_device, hcd_thread_function funct)
208433d6423SLionel Sambuc {
209433d6423SLionel Sambuc 	DEBUG_DUMP;
210433d6423SLionel Sambuc 
2112d64210cSWojciech Zajac 	/* This is meant to allow thread name distinction
2122d64210cSWojciech Zajac 	 * and should not be used for anything else */
2132d64210cSWojciech Zajac 	static unsigned int devnum = 0;
2142d64210cSWojciech Zajac 
2152d64210cSWojciech Zajac 	/* Should be able to hold device prefix and some number */
2162d64210cSWojciech Zajac 	char devname[] = "dev..........";
2172d64210cSWojciech Zajac 
2182d64210cSWojciech Zajac 	USB_ASSERT((NULL == this_device->lock) &&
2192d64210cSWojciech Zajac 		(NULL == this_device->thread) &&
2202d64210cSWojciech Zajac 		(HCD_DEFAULT_ADDR == this_device->reserved_address) &&
2212d64210cSWojciech Zajac 		(HCD_STATE_DISCONNECTED == this_device->state),
2222d64210cSWojciech Zajac 		"Device structure not clean");
2232d64210cSWojciech Zajac 
2242d64210cSWojciech Zajac 	/* Mark as 'plugged in' to avoid treating device
2252d64210cSWojciech Zajac 	 * as 'disconnected' in case of errors below */
2262d64210cSWojciech Zajac 	this_device->state = HCD_STATE_CONNECTION_PENDING;
2272d64210cSWojciech Zajac 
2282d64210cSWojciech Zajac 	/* Reserve device address for further use if available */
2292d64210cSWojciech Zajac 	if (HCD_DEFAULT_ADDR == (this_device->reserved_address =
2302d64210cSWojciech Zajac 				hcd_reserve_addr(this_device->driver))) {
2312d64210cSWojciech Zajac 		USB_MSG("No free device addresses");
232433d6423SLionel Sambuc 		return EXIT_FAILURE;
233433d6423SLionel Sambuc 	}
234433d6423SLionel Sambuc 
2352d64210cSWojciech Zajac 	/* Get 'lock' that makes device thread wait for events to occur */
2362d64210cSWojciech Zajac 	if (NULL == (this_device->lock = ddekit_sem_init(0))) {
2372d64210cSWojciech Zajac 		USB_MSG("Failed to initialize thread lock");
238433d6423SLionel Sambuc 		return EXIT_FAILURE;
2392d64210cSWojciech Zajac 	}
240433d6423SLionel Sambuc 
2412d64210cSWojciech Zajac 	/* Prepare name */
2422d64210cSWojciech Zajac 	snprintf(devname, sizeof(devname), "dev%u", devnum++);
2432d64210cSWojciech Zajac 
2442d64210cSWojciech Zajac 	/* Get thread itself */
245433d6423SLionel Sambuc 	if (NULL == (this_device->thread = ddekit_thread_create(funct,
246433d6423SLionel Sambuc 						this_device,
2472d64210cSWojciech Zajac 						(const char *)devname))) {
2482d64210cSWojciech Zajac 		USB_MSG("Failed to initialize USB device thread");
249433d6423SLionel Sambuc 		return EXIT_FAILURE;
250433d6423SLionel Sambuc 	}
251433d6423SLionel Sambuc 
252433d6423SLionel Sambuc 	return EXIT_SUCCESS;
253433d6423SLionel Sambuc }
254433d6423SLionel Sambuc 
2552d64210cSWojciech Zajac 
256433d6423SLionel Sambuc /*===========================================================================*
2572d64210cSWojciech Zajac  *    hcd_disconnect_device                                                  *
258433d6423SLionel Sambuc  *===========================================================================*/
259433d6423SLionel Sambuc void
hcd_disconnect_device(hcd_device_state * this_device)260433d6423SLionel Sambuc hcd_disconnect_device(hcd_device_state * this_device)
261433d6423SLionel Sambuc {
262433d6423SLionel Sambuc 	DEBUG_DUMP;
263433d6423SLionel Sambuc 
2642d64210cSWojciech Zajac 	/* TODO: This should disconnect all the children if they exist */
2652d64210cSWojciech Zajac 
2662d64210cSWojciech Zajac 	/* Clean configuration tree in case it was acquired */
267433d6423SLionel Sambuc 	hcd_tree_cleanup(&(this_device->config_tree));
268433d6423SLionel Sambuc 
2692d64210cSWojciech Zajac 	/* Release allocated resources */
2702d64210cSWojciech Zajac 	if (NULL != this_device->thread)
271433d6423SLionel Sambuc 		ddekit_thread_terminate(this_device->thread);
2722d64210cSWojciech Zajac 	if (NULL != this_device->lock)
273433d6423SLionel Sambuc 		ddekit_sem_deinit(this_device->lock);
274433d6423SLionel Sambuc 
2752d64210cSWojciech Zajac 	/* Release reserved address */
2762d64210cSWojciech Zajac 	if (HCD_DEFAULT_ADDR != this_device->reserved_address)
2772d64210cSWojciech Zajac 		hcd_release_addr(this_device->driver,
2782d64210cSWojciech Zajac 				this_device->reserved_address);
2792d64210cSWojciech Zajac 
2802d64210cSWojciech Zajac 	/* Mark as disconnected */
2812d64210cSWojciech Zajac 	this_device->state = HCD_STATE_DISCONNECTED;
282433d6423SLionel Sambuc }
283433d6423SLionel Sambuc 
284433d6423SLionel Sambuc 
285433d6423SLionel Sambuc /*===========================================================================*
286433d6423SLionel Sambuc  *    hcd_device_wait                                                        *
287433d6423SLionel Sambuc  *===========================================================================*/
288433d6423SLionel Sambuc void
hcd_device_wait(hcd_device_state * device,hcd_event event,hcd_reg1 ep)2892d64210cSWojciech Zajac hcd_device_wait(hcd_device_state * device, hcd_event event, hcd_reg1 ep)
290433d6423SLionel Sambuc {
291433d6423SLionel Sambuc 	DEBUG_DUMP;
292433d6423SLionel Sambuc 
2932d64210cSWojciech Zajac 	USB_DBG("0x%08X wait (0x%02X, 0x%02X)", device, event, ep);
294433d6423SLionel Sambuc 
2952d64210cSWojciech Zajac 	device->wait_event = event;
2962d64210cSWojciech Zajac 	device->wait_ep = ep;
297433d6423SLionel Sambuc 
2982d64210cSWojciech Zajac 	ddekit_sem_down(device->lock);
299433d6423SLionel Sambuc }
300433d6423SLionel Sambuc 
301433d6423SLionel Sambuc 
302433d6423SLionel Sambuc /*===========================================================================*
303433d6423SLionel Sambuc  *    hcd_device_continue                                                    *
304433d6423SLionel Sambuc  *===========================================================================*/
305433d6423SLionel Sambuc void
hcd_device_continue(hcd_device_state * device,hcd_event event,hcd_reg1 ep)3062d64210cSWojciech Zajac hcd_device_continue(hcd_device_state * device, hcd_event event, hcd_reg1 ep)
307433d6423SLionel Sambuc {
3082d64210cSWojciech Zajac 	DEBUG_DUMP;
3092d64210cSWojciech Zajac 
3102d64210cSWojciech Zajac 	USB_DBG("0x%08X continue (0x%02X, 0x%02X)", device, event, ep);
3112d64210cSWojciech Zajac 
3122d64210cSWojciech Zajac 	USB_ASSERT(device->wait_event == event, "Unexpected event");
3132d64210cSWojciech Zajac 	USB_ASSERT(device->wait_ep == ep, "Unexpected endpoint");
3142d64210cSWojciech Zajac 
3152d64210cSWojciech Zajac 	ddekit_sem_up(device->lock);
3162d64210cSWojciech Zajac }
3172d64210cSWojciech Zajac 
3182d64210cSWojciech Zajac 
3192d64210cSWojciech Zajac /*===========================================================================*
3202d64210cSWojciech Zajac  *    hcd_new_device                                                         *
3212d64210cSWojciech Zajac  *===========================================================================*/
3222d64210cSWojciech Zajac hcd_device_state *
hcd_new_device(void)3232d64210cSWojciech Zajac hcd_new_device(void)
3242d64210cSWojciech Zajac {
3252d64210cSWojciech Zajac 	hcd_device_state * d;
326433d6423SLionel Sambuc 
327433d6423SLionel Sambuc 	DEBUG_DUMP;
328433d6423SLionel Sambuc 
3292d64210cSWojciech Zajac 	/* One new blank device */
3302d64210cSWojciech Zajac 	d = calloc(1, sizeof(*d));
331433d6423SLionel Sambuc 
3322d64210cSWojciech Zajac 	USB_ASSERT(NULL != d, "Failed to allocate device");
333433d6423SLionel Sambuc 
3342d64210cSWojciech Zajac 	if (NULL == dev_list) {
3352d64210cSWojciech Zajac 		dev_list = d;
3362d64210cSWojciech Zajac 	} else {
3372d64210cSWojciech Zajac 		d->_next = dev_list;
3382d64210cSWojciech Zajac 		dev_list = d;
339433d6423SLionel Sambuc 	}
340433d6423SLionel Sambuc 
3412d64210cSWojciech Zajac #ifdef HCD_DUMP_DEVICE_LIST
3422d64210cSWojciech Zajac 	/* Dump updated state of device list */
3432d64210cSWojciech Zajac 	hcd_dump_devices();
3442d64210cSWojciech Zajac #endif
3452d64210cSWojciech Zajac 
3462d64210cSWojciech Zajac 	return d;
3472d64210cSWojciech Zajac }
3482d64210cSWojciech Zajac 
3492d64210cSWojciech Zajac 
3502d64210cSWojciech Zajac /*===========================================================================*
3512d64210cSWojciech Zajac  *    hcd_delete_device                                                      *
3522d64210cSWojciech Zajac  *===========================================================================*/
3532d64210cSWojciech Zajac void
hcd_delete_device(hcd_device_state * d)3542d64210cSWojciech Zajac hcd_delete_device(hcd_device_state * d)
3552d64210cSWojciech Zajac {
3562d64210cSWojciech Zajac 	hcd_device_state * temp;
3572d64210cSWojciech Zajac 
3582d64210cSWojciech Zajac 	DEBUG_DUMP;
3592d64210cSWojciech Zajac 
3602d64210cSWojciech Zajac 	if (d == dev_list) {
3612d64210cSWojciech Zajac 		dev_list = dev_list->_next;
3622d64210cSWojciech Zajac 	} else {
3632d64210cSWojciech Zajac 		temp = dev_list;
3642d64210cSWojciech Zajac 
3652d64210cSWojciech Zajac 		/* Find the device and ... */
3662d64210cSWojciech Zajac 		while (temp->_next != d) {
3672d64210cSWojciech Zajac 			USB_ASSERT(NULL != temp->_next,
3682d64210cSWojciech Zajac 				"Invalid state of device list");
3692d64210cSWojciech Zajac 			temp = temp->_next;
3702d64210cSWojciech Zajac 		}
3712d64210cSWojciech Zajac 
3722d64210cSWojciech Zajac 		/* ...make device list forget about it */
3732d64210cSWojciech Zajac 		temp->_next = temp->_next->_next;
3742d64210cSWojciech Zajac 	}
3752d64210cSWojciech Zajac 
3762d64210cSWojciech Zajac 	free(d);
3772d64210cSWojciech Zajac 
3782d64210cSWojciech Zajac #ifdef HCD_DUMP_DEVICE_LIST
3792d64210cSWojciech Zajac 	/* Dump updated state of device list */
3802d64210cSWojciech Zajac 	hcd_dump_devices();
3812d64210cSWojciech Zajac #endif
3822d64210cSWojciech Zajac }
3832d64210cSWojciech Zajac 
3842d64210cSWojciech Zajac 
3852d64210cSWojciech Zajac /*===========================================================================*
3862d64210cSWojciech Zajac  *    hcd_dump_devices                                                       *
3872d64210cSWojciech Zajac  *===========================================================================*/
3882d64210cSWojciech Zajac void
hcd_dump_devices(void)3892d64210cSWojciech Zajac hcd_dump_devices(void)
3902d64210cSWojciech Zajac {
3912d64210cSWojciech Zajac 	hcd_device_state * temp;
3922d64210cSWojciech Zajac 
3932d64210cSWojciech Zajac 	DEBUG_DUMP;
3942d64210cSWojciech Zajac 
3952d64210cSWojciech Zajac 	temp = dev_list;
3962d64210cSWojciech Zajac 
3972d64210cSWojciech Zajac 	USB_MSG("Allocated devices:");
3982d64210cSWojciech Zajac 
3992d64210cSWojciech Zajac 	while (NULL != temp) {
4002d64210cSWojciech Zajac 		USB_MSG("0x%08X", (int)temp);
4012d64210cSWojciech Zajac 		temp = temp->_next;
4022d64210cSWojciech Zajac 	}
4032d64210cSWojciech Zajac }
4042d64210cSWojciech Zajac 
4052d64210cSWojciech Zajac 
4062d64210cSWojciech Zajac /*===========================================================================*
4072d64210cSWojciech Zajac  *    hcd_check_device                                                       *
4082d64210cSWojciech Zajac  *===========================================================================*/
4092d64210cSWojciech Zajac int
hcd_check_device(hcd_device_state * d)4102d64210cSWojciech Zajac hcd_check_device(hcd_device_state * d)
4112d64210cSWojciech Zajac {
4122d64210cSWojciech Zajac 	hcd_device_state * temp;
4132d64210cSWojciech Zajac 
4142d64210cSWojciech Zajac 	DEBUG_DUMP;
4152d64210cSWojciech Zajac 
4162d64210cSWojciech Zajac 	temp = dev_list;
4172d64210cSWojciech Zajac 
4182d64210cSWojciech Zajac 	/* Traverse the list of allocated devices
4192d64210cSWojciech Zajac 	 * to determine validity of this one */
4202d64210cSWojciech Zajac 	while (NULL != temp) {
4212d64210cSWojciech Zajac 		if (temp == d)
4222d64210cSWojciech Zajac 			return EXIT_SUCCESS; /* Device found within the list */
4232d64210cSWojciech Zajac 		temp = temp->_next;
4242d64210cSWojciech Zajac 	}
4252d64210cSWojciech Zajac 
4262d64210cSWojciech Zajac 	/* Device was not found, may have been removed earlier */
4272d64210cSWojciech Zajac 	return EXIT_FAILURE;
428433d6423SLionel Sambuc }
429433d6423SLionel Sambuc 
430433d6423SLionel Sambuc 
431433d6423SLionel Sambuc /*===========================================================================*
432433d6423SLionel Sambuc  *    hcd_buffer_to_tree                                                     *
433433d6423SLionel Sambuc  *===========================================================================*/
434433d6423SLionel Sambuc int
hcd_buffer_to_tree(hcd_reg1 * buf,int len,hcd_configuration * c)435433d6423SLionel Sambuc hcd_buffer_to_tree(hcd_reg1 * buf, int len, hcd_configuration * c)
436433d6423SLionel Sambuc {
437433d6423SLionel Sambuc 	hcd_interface * i;
438433d6423SLionel Sambuc 	hcd_endpoint * e;
439433d6423SLionel Sambuc 	hcd_descriptor * desc;
440433d6423SLionel Sambuc 	int cfg_num;
441433d6423SLionel Sambuc 	int if_num;
442433d6423SLionel Sambuc 	int ep_num;
443433d6423SLionel Sambuc 
444433d6423SLionel Sambuc 	DEBUG_DUMP;
445433d6423SLionel Sambuc 
446433d6423SLionel Sambuc 	cfg_num = 0;
447433d6423SLionel Sambuc 	if_num = 0;
448433d6423SLionel Sambuc 	ep_num = 0;
449433d6423SLionel Sambuc 
450433d6423SLionel Sambuc 	i = NULL;
451433d6423SLionel Sambuc 	e = NULL;
452433d6423SLionel Sambuc 
453433d6423SLionel Sambuc 	/* Cleanup initially to NULL pointers before any allocation */
454433d6423SLionel Sambuc 	memset(c, 0, sizeof(*c));
455433d6423SLionel Sambuc 
456433d6423SLionel Sambuc 	while (len > (int)sizeof(*desc)) {
457433d6423SLionel Sambuc 		/* Check descriptor type */
458433d6423SLionel Sambuc 		desc = (hcd_descriptor *)buf;
459433d6423SLionel Sambuc 
460433d6423SLionel Sambuc 		if (0 == desc->bLength) {
461433d6423SLionel Sambuc 			USB_MSG("Zero length descriptor");
462433d6423SLionel Sambuc 			goto PARSE_ERROR;
463433d6423SLionel Sambuc 		}
464433d6423SLionel Sambuc 
465433d6423SLionel Sambuc 		if (UDESC_CONFIG == desc->bDescriptorType) {
466433d6423SLionel Sambuc 			if (EXIT_SUCCESS != hcd_fill_configuration(buf, len,
467433d6423SLionel Sambuc 								c, cfg_num++))
468433d6423SLionel Sambuc 				goto PARSE_ERROR;
469433d6423SLionel Sambuc 
470433d6423SLionel Sambuc 			if_num = 0;
471433d6423SLionel Sambuc 		}
472433d6423SLionel Sambuc 		else if (UDESC_INTERFACE == desc->bDescriptorType) {
473433d6423SLionel Sambuc 			if (NULL == c->interface)
474433d6423SLionel Sambuc 				goto PARSE_ERROR;
475433d6423SLionel Sambuc 
476433d6423SLionel Sambuc 			i = &(c->interface[if_num]);
477433d6423SLionel Sambuc 
478433d6423SLionel Sambuc 			if (EXIT_SUCCESS != hcd_fill_interface(buf, len,
479433d6423SLionel Sambuc 								i, if_num++))
480433d6423SLionel Sambuc 				goto PARSE_ERROR;
481433d6423SLionel Sambuc 
482433d6423SLionel Sambuc 			ep_num = 0;
483433d6423SLionel Sambuc 		}
484433d6423SLionel Sambuc 		else if (UDESC_ENDPOINT == desc->bDescriptorType) {
485433d6423SLionel Sambuc 			if (NULL == c->interface)
486433d6423SLionel Sambuc 				goto PARSE_ERROR;
487433d6423SLionel Sambuc 
488433d6423SLionel Sambuc 			if (NULL == i)
489433d6423SLionel Sambuc 				goto PARSE_ERROR;
490433d6423SLionel Sambuc 
491433d6423SLionel Sambuc 			e = &(i->endpoint[ep_num++]);
492433d6423SLionel Sambuc 
493433d6423SLionel Sambuc 			if (EXIT_SUCCESS != hcd_fill_endpoint(buf, len, e))
494433d6423SLionel Sambuc 				goto PARSE_ERROR;
495433d6423SLionel Sambuc 		} else
496433d6423SLionel Sambuc 			USB_DBG("Unhandled descriptor type 0x%02X",
497433d6423SLionel Sambuc 				desc->bDescriptorType);
498433d6423SLionel Sambuc 
499433d6423SLionel Sambuc 		len -= desc->bLength;
500433d6423SLionel Sambuc 		buf += desc->bLength;
501433d6423SLionel Sambuc 	}
502433d6423SLionel Sambuc 
503433d6423SLionel Sambuc 	if (0 != len) {
504433d6423SLionel Sambuc 		USB_MSG("After parsing, some descriptor data remains");
505433d6423SLionel Sambuc 		goto PARSE_ERROR;
506433d6423SLionel Sambuc 	}
507433d6423SLionel Sambuc 
508433d6423SLionel Sambuc 	return EXIT_SUCCESS;
509433d6423SLionel Sambuc 
510433d6423SLionel Sambuc 	PARSE_ERROR:
511433d6423SLionel Sambuc 	hcd_tree_cleanup(c);
512433d6423SLionel Sambuc 	return EXIT_FAILURE;
513433d6423SLionel Sambuc }
514433d6423SLionel Sambuc 
515433d6423SLionel Sambuc 
516433d6423SLionel Sambuc /*===========================================================================*
517433d6423SLionel Sambuc  *    hcd_tree_cleanup                                                       *
518433d6423SLionel Sambuc  *===========================================================================*/
519433d6423SLionel Sambuc void
hcd_tree_cleanup(hcd_configuration * c)520433d6423SLionel Sambuc hcd_tree_cleanup(hcd_configuration * c)
521433d6423SLionel Sambuc {
522433d6423SLionel Sambuc 	int if_idx;
523433d6423SLionel Sambuc 
524433d6423SLionel Sambuc 	DEBUG_DUMP;
525433d6423SLionel Sambuc 
526433d6423SLionel Sambuc 	/* Free if anything was allocated */
527433d6423SLionel Sambuc 	if (NULL != c->interface) {
528433d6423SLionel Sambuc 
529433d6423SLionel Sambuc 		USB_ASSERT(c->num_interfaces > 0, "Interface number error");
530433d6423SLionel Sambuc 
531433d6423SLionel Sambuc 		for (if_idx = 0; if_idx < c->num_interfaces; if_idx++) {
532433d6423SLionel Sambuc 			if (NULL != c->interface[if_idx].endpoint) {
533433d6423SLionel Sambuc 				USB_DBG("Freeing ep for interface #%d", if_idx);
534433d6423SLionel Sambuc 				free(c->interface[if_idx].endpoint);
535433d6423SLionel Sambuc 			}
536433d6423SLionel Sambuc 		}
537433d6423SLionel Sambuc 
538433d6423SLionel Sambuc 		USB_DBG("Freeing interfaces");
539433d6423SLionel Sambuc 		free(c->interface);
540433d6423SLionel Sambuc 		c->interface = NULL;
541433d6423SLionel Sambuc 	}
542433d6423SLionel Sambuc }
543433d6423SLionel Sambuc 
544433d6423SLionel Sambuc 
545433d6423SLionel Sambuc /*===========================================================================*
546433d6423SLionel Sambuc  *    hcd_tree_find_ep                                                       *
547433d6423SLionel Sambuc  *===========================================================================*/
548433d6423SLionel Sambuc hcd_endpoint *
hcd_tree_find_ep(hcd_configuration * c,hcd_reg1 ep)549433d6423SLionel Sambuc hcd_tree_find_ep(hcd_configuration * c, hcd_reg1 ep)
550433d6423SLionel Sambuc {
551433d6423SLionel Sambuc 	hcd_interface * i;
552433d6423SLionel Sambuc 	hcd_endpoint * e;
553433d6423SLionel Sambuc 	int if_idx;
554433d6423SLionel Sambuc 	int ep_idx;
555433d6423SLionel Sambuc 
556433d6423SLionel Sambuc 	DEBUG_DUMP;
557433d6423SLionel Sambuc 
558433d6423SLionel Sambuc 	/* Free if anything was allocated */
559433d6423SLionel Sambuc 	USB_ASSERT(NULL != c->interface, "No interfaces available");
560433d6423SLionel Sambuc 	USB_ASSERT(c->num_interfaces > 0, "Interface number error");
561433d6423SLionel Sambuc 
562433d6423SLionel Sambuc 	for (if_idx = 0; if_idx < c->num_interfaces; if_idx++) {
563433d6423SLionel Sambuc 		i = &(c->interface[if_idx]);
564433d6423SLionel Sambuc 		for (ep_idx = 0; ep_idx < i->num_endpoints; ep_idx++) {
565433d6423SLionel Sambuc 			e = &(i->endpoint[ep_idx]);
566433d6423SLionel Sambuc 			if (UE_GET_ADDR(e->descriptor.bEndpointAddress) == ep)
567433d6423SLionel Sambuc 				return e;
568433d6423SLionel Sambuc 		}
569433d6423SLionel Sambuc 	}
570433d6423SLionel Sambuc 
571433d6423SLionel Sambuc 	return NULL;
572433d6423SLionel Sambuc }
573433d6423SLionel Sambuc 
574433d6423SLionel Sambuc 
575433d6423SLionel Sambuc /*===========================================================================*
576433d6423SLionel Sambuc  *    hcd_fill_configuration                                                 *
577433d6423SLionel Sambuc  *===========================================================================*/
578433d6423SLionel Sambuc static int
hcd_fill_configuration(hcd_reg1 * buf,int len,hcd_configuration * c,int num)579433d6423SLionel Sambuc hcd_fill_configuration(hcd_reg1 * buf, int len, hcd_configuration * c, int num)
580433d6423SLionel Sambuc {
581433d6423SLionel Sambuc 	hcd_config_descriptor * desc;
582433d6423SLionel Sambuc 	int interfaces_size;
583433d6423SLionel Sambuc 
584433d6423SLionel Sambuc 	DEBUG_DUMP;
585433d6423SLionel Sambuc 
586433d6423SLionel Sambuc 	desc = (hcd_config_descriptor *)buf;
587433d6423SLionel Sambuc 
588433d6423SLionel Sambuc 	USB_DBG("Configuration #%d", num);
589433d6423SLionel Sambuc 
590433d6423SLionel Sambuc 	if (num > 0) {
591433d6423SLionel Sambuc 		USB_DBG("Only one configuration possible");
592433d6423SLionel Sambuc 		return EXIT_SUCCESS;
593433d6423SLionel Sambuc 	}
594433d6423SLionel Sambuc 
595433d6423SLionel Sambuc 	if (UDESC_CONFIG != desc->bDescriptorType)
596433d6423SLionel Sambuc 		return EXIT_FAILURE;
597433d6423SLionel Sambuc 
598433d6423SLionel Sambuc 	if (desc->bLength > len)
599433d6423SLionel Sambuc 		return EXIT_FAILURE;
600433d6423SLionel Sambuc 
601433d6423SLionel Sambuc 	if (sizeof(*desc) != desc->bLength)
602433d6423SLionel Sambuc 		return EXIT_FAILURE;
603433d6423SLionel Sambuc 
604433d6423SLionel Sambuc 	memcpy(&(c->descriptor), buf, sizeof(c->descriptor));
605433d6423SLionel Sambuc 
606433d6423SLionel Sambuc 	c->num_interfaces = c->descriptor.bNumInterface;
607433d6423SLionel Sambuc 
608433d6423SLionel Sambuc 	interfaces_size = c->num_interfaces * sizeof(*(c->interface));
609433d6423SLionel Sambuc 
610433d6423SLionel Sambuc 	USB_DBG("Allocating interfaces, %dB", interfaces_size);
611433d6423SLionel Sambuc 	c->interface = malloc(interfaces_size);
612433d6423SLionel Sambuc 
613433d6423SLionel Sambuc 	memset(c->interface, 0, interfaces_size);
614433d6423SLionel Sambuc 
615433d6423SLionel Sambuc 	/* Dump configuration in debug mode */
616433d6423SLionel Sambuc 	USB_DBG("<<CONFIGURATION>>");
617433d6423SLionel Sambuc 	USB_DBG("bLength %02X",			desc->bLength);
618433d6423SLionel Sambuc 	USB_DBG("bDescriptorType %02X",		desc->bDescriptorType);
619433d6423SLionel Sambuc 	USB_DBG("wTotalLength %04X",		UGETW(desc->wTotalLength));
620433d6423SLionel Sambuc 	USB_DBG("bNumInterface %02X",		desc->bNumInterface);
621433d6423SLionel Sambuc 	USB_DBG("bConfigurationValue %02X",	desc->bConfigurationValue);
622433d6423SLionel Sambuc 	USB_DBG("iConfiguration %02X",		desc->iConfiguration);
623433d6423SLionel Sambuc 	USB_DBG("bmAttributes %02X",		desc->bmAttributes);
624433d6423SLionel Sambuc 	USB_DBG("bMaxPower %02X",		desc->bMaxPower);
625433d6423SLionel Sambuc 
626433d6423SLionel Sambuc 	return EXIT_SUCCESS;
627433d6423SLionel Sambuc }
628433d6423SLionel Sambuc 
629433d6423SLionel Sambuc 
630433d6423SLionel Sambuc /*===========================================================================*
631433d6423SLionel Sambuc  *    hcd_fill_interface                                                     *
632433d6423SLionel Sambuc  *===========================================================================*/
633433d6423SLionel Sambuc static int
hcd_fill_interface(hcd_reg1 * buf,int len,hcd_interface * i,int num)634433d6423SLionel Sambuc hcd_fill_interface(hcd_reg1 * buf, int len, hcd_interface * i, int num)
635433d6423SLionel Sambuc {
636433d6423SLionel Sambuc 	hcd_interface_descriptor * desc;
637433d6423SLionel Sambuc 	int endpoints_size;
638433d6423SLionel Sambuc 
639433d6423SLionel Sambuc 	DEBUG_DUMP;
640433d6423SLionel Sambuc 
641433d6423SLionel Sambuc 	desc = (hcd_interface_descriptor *)buf;
642433d6423SLionel Sambuc 
643433d6423SLionel Sambuc 	USB_DBG("Interface #%d", num);
644433d6423SLionel Sambuc 
645433d6423SLionel Sambuc 	if (UDESC_INTERFACE != desc->bDescriptorType)
646433d6423SLionel Sambuc 		return EXIT_FAILURE;
647433d6423SLionel Sambuc 
648433d6423SLionel Sambuc 	if (desc->bLength > len)
649433d6423SLionel Sambuc 		return EXIT_FAILURE;
650433d6423SLionel Sambuc 
651433d6423SLionel Sambuc 	if (sizeof(*desc) != desc->bLength)
652433d6423SLionel Sambuc 		return EXIT_FAILURE;
653433d6423SLionel Sambuc 
654433d6423SLionel Sambuc 	/* It is mandatory to supply interfaces in correct order */
655433d6423SLionel Sambuc 	if (desc->bInterfaceNumber != num)
656433d6423SLionel Sambuc 		return EXIT_FAILURE;
657433d6423SLionel Sambuc 
658433d6423SLionel Sambuc 	memcpy(&(i->descriptor), buf, sizeof(i->descriptor));
659433d6423SLionel Sambuc 
660433d6423SLionel Sambuc 	i->num_endpoints = i->descriptor.bNumEndpoints;
661433d6423SLionel Sambuc 
662433d6423SLionel Sambuc 	endpoints_size = i->num_endpoints * sizeof(*(i->endpoint));
663433d6423SLionel Sambuc 
664433d6423SLionel Sambuc 	USB_DBG("Allocating endpoints, %dB", endpoints_size);
665433d6423SLionel Sambuc 	i->endpoint = malloc(endpoints_size);
666433d6423SLionel Sambuc 
667433d6423SLionel Sambuc 	memset(i->endpoint, 0, endpoints_size);
668433d6423SLionel Sambuc 
669433d6423SLionel Sambuc 	/* Dump interface in debug mode */
670433d6423SLionel Sambuc 	USB_DBG("<<INTERFACE>>");
671433d6423SLionel Sambuc 	USB_DBG("bLength %02X",			desc->bLength);
672433d6423SLionel Sambuc 	USB_DBG("bDescriptorType %02X",		desc->bDescriptorType);
673433d6423SLionel Sambuc 	USB_DBG("bInterfaceNumber %02X",	desc->bInterfaceNumber);
674433d6423SLionel Sambuc 	USB_DBG("bAlternateSetting %02X",	desc->bAlternateSetting);
675433d6423SLionel Sambuc 	USB_DBG("bNumEndpoints %02X",		desc->bNumEndpoints);
676433d6423SLionel Sambuc 	USB_DBG("bInterfaceClass %02X",		desc->bInterfaceClass);
677433d6423SLionel Sambuc 	USB_DBG("bInterfaceSubClass %02X",	desc->bInterfaceSubClass);
678433d6423SLionel Sambuc 	USB_DBG("bInterfaceProtocol %02X",	desc->bInterfaceProtocol);
679433d6423SLionel Sambuc 	USB_DBG("iInterface %02X",		desc->iInterface);
680433d6423SLionel Sambuc 
681433d6423SLionel Sambuc 	return EXIT_SUCCESS;
682433d6423SLionel Sambuc }
683433d6423SLionel Sambuc 
684433d6423SLionel Sambuc 
685433d6423SLionel Sambuc /*===========================================================================*
686433d6423SLionel Sambuc  *    hcd_fill_endpoint                                                      *
687433d6423SLionel Sambuc  *===========================================================================*/
688433d6423SLionel Sambuc static int
hcd_fill_endpoint(hcd_reg1 * buf,int len,hcd_endpoint * e)689433d6423SLionel Sambuc hcd_fill_endpoint(hcd_reg1 * buf, int len, hcd_endpoint * e)
690433d6423SLionel Sambuc {
691433d6423SLionel Sambuc 	hcd_endpoint_descriptor * desc;
692433d6423SLionel Sambuc 
693433d6423SLionel Sambuc 	DEBUG_DUMP;
694433d6423SLionel Sambuc 
695433d6423SLionel Sambuc 	desc = (hcd_endpoint_descriptor *)buf;
696433d6423SLionel Sambuc 
697433d6423SLionel Sambuc 	USB_DBG("Endpoint #%d", UE_GET_ADDR(desc->bEndpointAddress));
698433d6423SLionel Sambuc 
699433d6423SLionel Sambuc 	if (UDESC_ENDPOINT != desc->bDescriptorType)
700433d6423SLionel Sambuc 		return EXIT_FAILURE;
701433d6423SLionel Sambuc 
702433d6423SLionel Sambuc 	if (desc->bLength > len)
703433d6423SLionel Sambuc 		return EXIT_FAILURE;
704433d6423SLionel Sambuc 
705433d6423SLionel Sambuc 	if (sizeof(*desc) != desc->bLength)
706433d6423SLionel Sambuc 		return EXIT_FAILURE;
707433d6423SLionel Sambuc 
708433d6423SLionel Sambuc 	memcpy(&(e->descriptor), buf, sizeof(e->descriptor));
709433d6423SLionel Sambuc 
710433d6423SLionel Sambuc 	/* Dump endpoint in debug mode */
711433d6423SLionel Sambuc 	USB_DBG("<<ENDPOINT>>");
712433d6423SLionel Sambuc 	USB_DBG("bLength %02X",			desc->bLength);
713433d6423SLionel Sambuc 	USB_DBG("bDescriptorType %02X",		desc->bDescriptorType);
714433d6423SLionel Sambuc 	USB_DBG("bEndpointAddress %02X",	desc->bEndpointAddress);
715433d6423SLionel Sambuc 	USB_DBG("bmAttributes %02X",		desc->bmAttributes);
716433d6423SLionel Sambuc 	USB_DBG("wMaxPacketSize %04X",		UGETW(desc->wMaxPacketSize));
717433d6423SLionel Sambuc 	USB_DBG("bInterval %02X",		desc->bInterval);
718433d6423SLionel Sambuc 
719433d6423SLionel Sambuc 	return EXIT_SUCCESS;
720433d6423SLionel Sambuc }
7212d64210cSWojciech Zajac 
7222d64210cSWojciech Zajac 
7232d64210cSWojciech Zajac /*===========================================================================*
7242d64210cSWojciech Zajac  *    hcd_reserve_addr                                                       *
7252d64210cSWojciech Zajac  *===========================================================================*/
7262d64210cSWojciech Zajac static hcd_reg1
hcd_reserve_addr(hcd_driver_state * driver)7272d64210cSWojciech Zajac hcd_reserve_addr(hcd_driver_state * driver)
7282d64210cSWojciech Zajac {
7292d64210cSWojciech Zajac 	hcd_reg1 addr;
7302d64210cSWojciech Zajac 
7312d64210cSWojciech Zajac 	DEBUG_DUMP;
7322d64210cSWojciech Zajac 
7332d64210cSWojciech Zajac 	for (addr = HCD_FIRST_ADDR; addr <= HCD_LAST_ADDR; addr++) {
7342d64210cSWojciech Zajac 		if (HCD_ADDR_AVAILABLE == driver->dev_addr[addr]) {
7352d64210cSWojciech Zajac 			USB_DBG("Reserved address: %u", addr);
7362d64210cSWojciech Zajac 			driver->dev_addr[addr] = HCD_ADDR_USED;
7372d64210cSWojciech Zajac 			return addr;
7382d64210cSWojciech Zajac 		}
7392d64210cSWojciech Zajac 	}
7402d64210cSWojciech Zajac 
7412d64210cSWojciech Zajac 	/* This means error */
7422d64210cSWojciech Zajac 	return HCD_DEFAULT_ADDR;
7432d64210cSWojciech Zajac }
7442d64210cSWojciech Zajac 
7452d64210cSWojciech Zajac 
7462d64210cSWojciech Zajac /*===========================================================================*
7472d64210cSWojciech Zajac  *    hcd_release_addr                                                       *
7482d64210cSWojciech Zajac  *===========================================================================*/
7492d64210cSWojciech Zajac static void
hcd_release_addr(hcd_driver_state * driver,hcd_reg1 addr)7502d64210cSWojciech Zajac hcd_release_addr(hcd_driver_state * driver, hcd_reg1 addr)
7512d64210cSWojciech Zajac {
7522d64210cSWojciech Zajac 	DEBUG_DUMP;
7532d64210cSWojciech Zajac 
7542d64210cSWojciech Zajac 	USB_ASSERT((addr > HCD_DEFAULT_ADDR) && (addr <= HCD_LAST_ADDR),
7552d64210cSWojciech Zajac 		"Invalid device address to be released");
7562d64210cSWojciech Zajac 	USB_ASSERT(HCD_ADDR_USED == driver->dev_addr[addr],
7572d64210cSWojciech Zajac 		"Attempted to release unused address");
7582d64210cSWojciech Zajac 
7592d64210cSWojciech Zajac 	USB_DBG("Released address: %u", addr);
7602d64210cSWojciech Zajac 	driver->dev_addr[addr] = HCD_ADDR_AVAILABLE;
7612d64210cSWojciech Zajac }
762