xref: /aosp_15_r20/external/coreboot/payloads/libpayload/drivers/usb/uhci.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /*
2  *
3  * Copyright (C) 2008-2010 coresystems GmbH
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. The name of the author may not be used to endorse or promote products
14  *    derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 //#define USB_DEBUG
30 
31 #include <arch/virtual.h>
32 #include <inttypes.h>
33 #include <usb/usb.h>
34 #include "uhci.h"
35 #include "uhci_private.h"
36 
37 static void uhci_start(hci_t *controller);
38 static void uhci_stop(hci_t *controller);
39 static void uhci_reset(hci_t *controller);
40 static void uhci_shutdown(hci_t *controller);
41 static int uhci_bulk(endpoint_t *ep, int size, u8 *data, int finalize);
42 static int uhci_control(usbdev_t *dev, direction_t dir, int drlen, void *devreq,
43 			 int dalen, u8 *data);
44 static void* uhci_create_intr_queue(endpoint_t *ep, int reqsize, int reqcount, int reqtiming);
45 static void uhci_destroy_intr_queue(endpoint_t *ep, void *queue);
46 static u8* uhci_poll_intr_queue(void *queue);
47 
48 #if 0
49 /* dump uhci */
50 static void
51 uhci_dump(hci_t *controller)
52 {
53 	usb_debug("dump:\nUSBCMD: %x\n", uhci_reg_read16(controller, USBCMD));
54 	usb_debug("USBSTS: %x\n", uhci_reg_read16(controller, USBSTS));
55 	usb_debug("USBINTR: %x\n", uhci_reg_read16(controller, USBINTR));
56 	usb_debug("FRNUM: %x\n", uhci_reg_read16(controller, FRNUM));
57 	usb_debug("FLBASEADD: %x\n", uhci_reg_read32(controller, FLBASEADD));
58 	usb_debug("SOFMOD: %x\n", uhci_reg_read8(controller, SOFMOD));
59 	usb_debug("PORTSC1: %x\n", uhci_reg_read16(controller, PORTSC1));
60 	usb_debug("PORTSC2: %x\n", uhci_reg_read16(controller, PORTSC2));
61 }
62 #endif
63 
td_dump(td_t * td)64 static void td_dump(td_t *td)
65 {
66 	usb_debug("+---------------------------------------------------+\n");
67 	if ((td->token & TD_PID_MASK) == UHCI_SETUP)
68 		usb_debug("|..[SETUP]..........................................|\n");
69 	else if ((td->token & TD_PID_MASK) == UHCI_IN)
70 		usb_debug("|..[IN].............................................|\n");
71 	else if ((td->token & TD_PID_MASK) == UHCI_OUT)
72 		usb_debug("|..[OUT]............................................|\n");
73 	else
74 		usb_debug("|..[]...............................................|\n");
75 	usb_debug("|:|============ UHCI TD at [0x%08lx] ==========|:|\n", virt_to_phys(td));
76 	usb_debug("|:+-----------------------------------------------+:|\n");
77 	usb_debug("|:| Next  TD/QH     [0x%08lx]                  |:|\n", td->ptr & ~0xFUL);
78 	usb_debug("|:+-----------------------------------------------+:|\n");
79 	usb_debug("|:| Depth/Breath [%lx]  | QH/TD [%lx] | TERMINATE [%lx] |:|\n",
80 	(td->ptr & (1UL << 2)) >> 2, (td->ptr & (1UL << 1)) >> 1, td->ptr & 1UL);
81 	usb_debug("|:+-----------------------------------------------+:|\n");
82 	usb_debug("|:|   T   | Maximum Length               | [%04lx] |:|\n", (td->token & (0x7FFUL << 21)) >> 21);
83 	usb_debug("|:|   O   | PID CODE                     | [%04"PRIx32"] |:|\n", td->token & 0xFF);
84 	usb_debug("|:|   K   | Endpoint                     | [%04"PRIx32"] |:|\n", (td->token & TD_EP_MASK) >> TD_EP_SHIFT);
85 	usb_debug("|:|   E   | Device Address               | [%04lx] |:|\n", (td->token & (0x7FUL << 8)) >> 8);
86 	usb_debug("|:|   N   | Data Toggle                  |    [%lx] |:|\n", (td->token & (1UL << 19)) >> 19);
87 	usb_debug("|:+-----------------------------------------------+:|\n");
88 	usb_debug("|:|   C   | Short Packet Detector        |    [%lx] |:|\n", (td->ctrlsts & (1UL << 29)) >> 29);
89 	usb_debug("|:|   O   | Error Counter                |    [%lx] |:|\n",
90 		  (td->ctrlsts & (3UL << TD_COUNTER_SHIFT)) >> TD_COUNTER_SHIFT);
91 	usb_debug("|:|   N   | Low Speed Device             |    [%lx] |:|\n", (td->ctrlsts & (1UL << 26)) >> 26);
92 	usb_debug("|:|   T   | Isochronous Select           |    [%lx] |:|\n", (td->ctrlsts & (1UL << 25)) >> 25);
93 	usb_debug("|:|   R   | Interrupt on Complete (IOC)  |    [%lx] |:|\n", (td->ctrlsts & (1UL << 24)) >> 24);
94 	usb_debug("|:+   O   ----------------------------------------+:|\n");
95 	usb_debug("|:|   L   | Active                       |    [%lx] |:|\n", (td->ctrlsts & (1UL << 23)) >> 23);
96 	usb_debug("|:|   &   | Stalled                      |    [%lx] |:|\n", (td->ctrlsts & (1UL << 22)) >> 22);
97 	usb_debug("|:|   S   | Data Buffer Error            |    [%lx] |:|\n", (td->ctrlsts & (1UL << 21)) >> 21);
98 	usb_debug("|:|   T   | Bubble Detected              |    [%lx] |:|\n", (td->ctrlsts & (1UL << 20)) >> 20);
99 	usb_debug("|:|   A   | NAK Received                 |    [%lx] |:|\n", (td->ctrlsts & (1UL << 19)) >> 19);
100 	usb_debug("|:|   T   | CRC/Timeout Error            |    [%lx] |:|\n", (td->ctrlsts & (1UL << 18)) >> 18);
101 	usb_debug("|:|   U   | Bitstuff Error               |    [%lx] |:|\n", (td->ctrlsts & (1UL << 17)) >> 17);
102 	usb_debug("|:|   S   ----------------------------------------|:|\n");
103 	usb_debug("|:|       | Actual Length                | [%04lx] |:|\n", td->ctrlsts & 0x7FFUL);
104 	usb_debug("|:+-----------------------------------------------+:|\n");
105 	usb_debug("|:| Buffer pointer  [0x%08"PRIx32"]                  |:|\n", td->bufptr);
106 	usb_debug("|:|-----------------------------------------------|:|\n");
107 	usb_debug("|...................................................|\n");
108 	usb_debug("+---------------------------------------------------+\n");
109 }
110 
111 static void
uhci_reset(hci_t * controller)112 uhci_reset(hci_t *controller)
113 {
114 	/* reset */
115 	uhci_reg_write16(controller, USBCMD, 4); /* Global Reset */
116 	mdelay(50); /* uhci spec 2.1.1: at least 10ms */
117 	uhci_reg_write16(controller, USBCMD, 0);
118 	mdelay(10);
119 	uhci_reg_write16(controller, USBCMD, 2); /* Host Controller Reset */
120 	/* wait for controller to finish reset */
121 	/* TOTEST: how long to wait? 100ms for now */
122 	int timeout = 200; /* time out after 200 * 500us == 100ms */
123 	while (((uhci_reg_read16(controller, USBCMD) & 2) != 0) && timeout--)
124 		udelay(500);
125 	if (timeout < 0)
126 		usb_debug("Warning: uhci: host controller reset timed out.\n");
127 }
128 
129 static void
uhci_reinit(hci_t * controller)130 uhci_reinit(hci_t *controller)
131 {
132 	uhci_reg_write32(controller, FLBASEADD,
133 			  (u32) virt_to_phys(UHCI_INST(controller)->
134 					      framelistptr));
135 	//usb_debug ("framelist at %p\n",UHCI_INST(controller)->framelistptr);
136 
137 	/* disable irqs */
138 	uhci_reg_write16(controller, USBINTR, 0);
139 
140 	/* reset framelist index */
141 	uhci_reg_write16(controller, FRNUM, 0);
142 
143 	uhci_reg_write16(controller, USBCMD,
144 			 uhci_reg_read16(controller, USBCMD) | 0xc0);	// max packets, configure flag
145 
146 	uhci_start(controller);
147 }
148 
149 hci_t *
uhci_pci_init(pcidev_t addr)150 uhci_pci_init(pcidev_t addr)
151 {
152 	int i;
153 	u16 reg16;
154 
155 	hci_t *controller = new_controller();
156 	controller->pcidev = addr;
157 	controller->instance = xzalloc(sizeof(uhci_t));
158 	controller->type = UHCI;
159 	controller->start = uhci_start;
160 	controller->stop = uhci_stop;
161 	controller->reset = uhci_reset;
162 	controller->init = uhci_reinit;
163 	controller->shutdown = uhci_shutdown;
164 	controller->bulk = uhci_bulk;
165 	controller->control = uhci_control;
166 	controller->set_address = generic_set_address;
167 	controller->finish_device_config = NULL;
168 	controller->destroy_device = NULL;
169 	controller->create_intr_queue = uhci_create_intr_queue;
170 	controller->destroy_intr_queue = uhci_destroy_intr_queue;
171 	controller->poll_intr_queue = uhci_poll_intr_queue;
172 	init_device_entry(controller, 0);
173 	UHCI_INST(controller)->roothub = controller->devices[0];
174 
175 	/* ~1 clears the register type indicator that is set to 1
176 	 * for IO space */
177 	controller->reg_base = pci_read_config32(addr, 0x20) & ~1;
178 
179 	/* kill legacy support handler */
180 	uhci_stop(controller);
181 	mdelay(1);
182 	uhci_reg_write16(controller, USBSTS, 0x3f);
183 	reg16 = pci_read_config16(addr, 0xc0);
184 	reg16 &= 0xdf80;
185 	pci_write_config16(addr, 0xc0, reg16);
186 
187 	UHCI_INST(controller)->framelistptr = memalign(0x1000, 1024 * sizeof(flistp_t));	/* 4kb aligned to 4kb */
188 	if (!UHCI_INST (controller)->framelistptr)
189 		fatal("Not enough memory for USB frame list pointer.\n");
190 
191 	memset(UHCI_INST(controller)->framelistptr, 0,
192 		1024 * sizeof(flistp_t));
193 
194 	/* According to the *BSD UHCI code, this one is needed on some
195 	   PIIX chips, because otherwise they misbehave. It must be
196 	   added to the last chain.
197 
198 	   FIXME: this leaks, if the driver should ever be reinited
199 	          for some reason. Not a problem now.
200 	   */
201 	td_t *antiberserk = memalign(16, sizeof(td_t));
202 	if (!antiberserk)
203 		fatal("Not enough memory for chipset workaround.\n");
204 	memset(antiberserk, 0, sizeof(td_t));
205 
206 	UHCI_INST(controller)->qh_prei = memalign(16, sizeof(qh_t));
207 	UHCI_INST(controller)->qh_intr = memalign(16, sizeof(qh_t));
208 	UHCI_INST(controller)->qh_data = memalign(16, sizeof(qh_t));
209 	UHCI_INST(controller)->qh_last = memalign(16, sizeof(qh_t));
210 
211 	if (!UHCI_INST (controller)->qh_prei ||
212 	    !UHCI_INST (controller)->qh_intr ||
213 	    !UHCI_INST (controller)->qh_data ||
214 	    !UHCI_INST (controller)->qh_last)
215 		fatal("Not enough memory for USB controller queues.\n");
216 
217 	UHCI_INST(controller)->qh_prei->headlinkptr =
218 		virt_to_phys(UHCI_INST(controller)->qh_intr) | FLISTP_QH;
219 	UHCI_INST(controller)->qh_prei->elementlinkptr = 0 | FLISTP_TERMINATE;
220 
221 	UHCI_INST(controller)->qh_intr->headlinkptr =
222 		virt_to_phys(UHCI_INST(controller)->qh_data) | FLISTP_QH;
223 	UHCI_INST(controller)->qh_intr->elementlinkptr = 0 | FLISTP_TERMINATE;
224 
225 	UHCI_INST(controller)->qh_data->headlinkptr =
226 		virt_to_phys(UHCI_INST(controller)->qh_last) | FLISTP_QH;
227 	UHCI_INST(controller)->qh_data->elementlinkptr = 0 | FLISTP_TERMINATE;
228 
229 	UHCI_INST(controller)->qh_last->headlinkptr = virt_to_phys(UHCI_INST(controller)->qh_data) | FLISTP_TERMINATE;
230 	UHCI_INST(controller)->qh_last->elementlinkptr = virt_to_phys(antiberserk) | FLISTP_TERMINATE;
231 
232 	for (i = 0; i < 1024; i++) {
233 		UHCI_INST(controller)->framelistptr[i] =
234 			virt_to_phys(UHCI_INST(controller)->qh_prei) | FLISTP_QH;
235 	}
236 	controller->devices[0]->controller = controller;
237 	controller->devices[0]->init = uhci_rh_init;
238 	controller->devices[0]->init(controller->devices[0]);
239 	uhci_reset(controller);
240 	uhci_reinit(controller);
241 	return controller;
242 }
243 
244 static void
uhci_shutdown(hci_t * controller)245 uhci_shutdown(hci_t *controller)
246 {
247 	if (controller == 0)
248 		return;
249 	detach_controller(controller);
250 	uhci_reg_write16(controller, USBCMD,
251 			 uhci_reg_read16(controller, USBCMD) & 0);	// stop work
252 	free(UHCI_INST(controller)->framelistptr);
253 	free(UHCI_INST(controller)->qh_prei);
254 	free(UHCI_INST(controller)->qh_intr);
255 	free(UHCI_INST(controller)->qh_data);
256 	free(UHCI_INST(controller)->qh_last);
257 	free(UHCI_INST(controller));
258 	free(controller);
259 }
260 
261 static void
uhci_start(hci_t * controller)262 uhci_start(hci_t *controller)
263 {
264 	uhci_reg_write16(controller, USBCMD,
265 			 uhci_reg_read16(controller, USBCMD) | 1);	// start work on schedule
266 }
267 
268 static void
uhci_stop(hci_t * controller)269 uhci_stop(hci_t *controller)
270 {
271 	uhci_reg_write16(controller, USBCMD,
272 			 uhci_reg_read16(controller, USBCMD) & ~1);	// stop work on schedule
273 }
274 
275 #define UHCI_SLEEP_TIME_US 30
276 #define UHCI_TIMEOUT (USB_MAX_PROCESSING_TIME_US / UHCI_SLEEP_TIME_US)
277 #define GET_TD(x) ((void *)(((unsigned long)(x))&~0xf))
278 
279 static td_t *
wait_for_completed_qh(hci_t * controller,qh_t * qh)280 wait_for_completed_qh(hci_t *controller, qh_t *qh)
281 {
282 	int timeout = UHCI_TIMEOUT;
283 	void *current = GET_TD(qh->elementlinkptr);
284 	while (((qh->elementlinkptr & FLISTP_TERMINATE) == 0) && (timeout-- > 0)) {
285 		if (current != GET_TD(qh->elementlinkptr)) {
286 			current = GET_TD(qh->elementlinkptr);
287 			timeout = UHCI_TIMEOUT;
288 		}
289 		uhci_reg_write16(controller, USBSTS,
290 				 uhci_reg_read16(controller, USBSTS) | 0);	// clear resettable registers
291 		udelay(UHCI_SLEEP_TIME_US);
292 	}
293 	return (GET_TD(qh->elementlinkptr) ==
294 		0) ? 0 : GET_TD(phys_to_virt(qh->elementlinkptr));
295 }
296 
297 static int
maxlen(int size)298 maxlen(int size)
299 {
300 	return (size - 1) & 0x7ff;
301 }
302 
303 static int
min(int a,int b)304 min(int a, int b)
305 {
306 	if (a < b)
307 		return a;
308 	else
309 		return b;
310 }
311 
312 static int
uhci_control(usbdev_t * dev,direction_t dir,int drlen,void * devreq,const int dalen,unsigned char * data)313 uhci_control(usbdev_t *dev, direction_t dir, int drlen, void *devreq, const int dalen,
314 	      unsigned char *data)
315 {
316 	int endp = 0;		/* this is control: always 0 */
317 	int mlen = dev->endpoints[0].maxpacketsize;
318 	int count = (2 + (dalen + mlen - 1) / mlen);
319 	unsigned short req = ((unsigned short *) devreq)[0];
320 	int i;
321 	td_t *tds = memalign(16, sizeof(td_t) * count);
322 	if (!tds)
323 		fatal("Not enough memory for uhci control.\n");
324 	memset(tds, 0, sizeof(td_t) * count);
325 	count--;		/* to compensate for 0-indexed array */
326 	for (i = 0; i < count; i++) {
327 		tds[i].ptr = virt_to_phys(&tds[i + 1]) | TD_DEPTH_FIRST;
328 	}
329 	tds[count].ptr = 0 | TD_DEPTH_FIRST | TD_TERMINATE;
330 
331 	tds[0].token = UHCI_SETUP |
332 		dev->address << TD_DEVADDR_SHIFT |
333 		endp << TD_EP_SHIFT |
334 		TD_TOGGLE_DATA0 |
335 		maxlen(drlen) << TD_MAXLEN_SHIFT;
336 	tds[0].bufptr = virt_to_phys(devreq);
337 	tds[0].ctrlsts = (3 << TD_COUNTER_SHIFT) |
338 		(dev->speed?TD_LOWSPEED:0) |
339 		TD_STATUS_ACTIVE;
340 
341 	int toggle = 1;
342 	int len_left = dalen;
343 	for (i = 1; i < count; i++) {
344 		switch (dir) {
345 			case SETUP: tds[i].token = UHCI_SETUP; break;
346 			case IN:    tds[i].token = UHCI_IN;    break;
347 			case OUT:   tds[i].token = UHCI_OUT;   break;
348 		}
349 		tds[i].token |= dev->address << TD_DEVADDR_SHIFT |
350 			endp << TD_EP_SHIFT |
351 			maxlen(min(mlen, len_left)) << TD_MAXLEN_SHIFT |
352 			toggle << TD_TOGGLE_SHIFT;
353 		tds[i].bufptr = virt_to_phys(data);
354 		tds[i].ctrlsts = (3 << TD_COUNTER_SHIFT) |
355 			(dev->speed?TD_LOWSPEED:0) |
356 			TD_STATUS_ACTIVE;
357 		toggle ^= 1;
358 		len_left -= mlen;
359 		data += mlen;
360 	}
361 
362 	tds[count].token = ((dir == OUT) ? UHCI_IN : UHCI_OUT) |
363 		dev->address << TD_DEVADDR_SHIFT |
364 		endp << TD_EP_SHIFT |
365 		maxlen(0) << TD_MAXLEN_SHIFT |
366 		TD_TOGGLE_DATA1;
367 	tds[count].bufptr = 0;
368 	tds[count].ctrlsts = (0 << TD_COUNTER_SHIFT) | /* as Linux 2.4.10 does */
369 		(dev->speed?TD_LOWSPEED:0) |
370 		TD_STATUS_ACTIVE;
371 	UHCI_INST(dev->controller)->qh_data->elementlinkptr =
372 		virt_to_phys(tds) & ~(FLISTP_QH | FLISTP_TERMINATE);
373 	td_t *td = wait_for_completed_qh(dev->controller,
374 					  UHCI_INST(dev->controller)->
375 					  qh_data);
376 	int result;
377 	if (td == 0) {
378 		result = dalen; /* TODO: We should return the actually transferred length. */
379 	} else {
380 		usb_debug("control packet, req %x\n", req);
381 		td_dump(td);
382 		result = -1;
383 	}
384 	free(tds);
385 	return result;
386 }
387 
388 static td_t *
create_schedule(int numpackets)389 create_schedule(int numpackets)
390 {
391 	if (numpackets == 0)
392 		return 0;
393 	td_t *tds = memalign(16, sizeof(td_t) * numpackets);
394 	if (!tds)
395 		fatal("Not enough memory for packets scheduling.\n");
396 	memset(tds, 0, sizeof(td_t) * numpackets);
397 	int i;
398 	for (i = 0; i < numpackets; i++) {
399 		tds[i].ptr = virt_to_phys(&tds[i + 1]) | TD_DEPTH_FIRST;
400 	}
401 	tds[numpackets - 1].ptr = 0 | TD_TERMINATE;
402 	return tds;
403 }
404 
405 static void
fill_schedule(td_t * td,endpoint_t * ep,int length,unsigned char * data,int * toggle)406 fill_schedule(td_t *td, endpoint_t *ep, int length, unsigned char *data,
407 	       int *toggle)
408 {
409 	switch (ep->direction) {
410 		case IN: td->token = UHCI_IN; break;
411 		case OUT: td->token = UHCI_OUT; break;
412 		case SETUP: td->token = UHCI_SETUP; break;
413 	}
414 	td->token |= ep->dev->address << TD_DEVADDR_SHIFT |
415 		(ep->endpoint & 0xf) << TD_EP_SHIFT |
416 		maxlen(length) << TD_MAXLEN_SHIFT |
417 		(*toggle & 1) << TD_TOGGLE_SHIFT;
418 	td->bufptr = virt_to_phys(data);
419 	td->ctrlsts = ((ep->direction == SETUP?3:0) << TD_COUNTER_SHIFT) |
420 		(ep->dev->speed?TD_LOWSPEED:0) |
421 		TD_STATUS_ACTIVE;
422 	*toggle ^= 1;
423 }
424 
425 static int
run_schedule(usbdev_t * dev,td_t * td)426 run_schedule(usbdev_t *dev, td_t *td)
427 {
428 	UHCI_INST(dev->controller)->qh_data->elementlinkptr =
429 		virt_to_phys(td) & ~(FLISTP_QH | FLISTP_TERMINATE);
430 	td = wait_for_completed_qh(dev->controller,
431 				    UHCI_INST(dev->controller)->qh_data);
432 	if (td == 0) {
433 		return 0;
434 	} else {
435 		td_dump(td);
436 		return 1;
437 	}
438 }
439 
440 /* finalize == 1: if data is of packet aligned size, add a zero length packet */
441 static int
uhci_bulk(endpoint_t * ep,const int dalen,u8 * data,int finalize)442 uhci_bulk(endpoint_t *ep, const int dalen, u8 *data, int finalize)
443 {
444 	int maxpsize = ep->maxpacketsize;
445 	if (maxpsize == 0)
446 		fatal("MaxPacketSize == 0!!!");
447 	int numpackets = (dalen + maxpsize - 1) / maxpsize;
448 	if (finalize && ((dalen % maxpsize) == 0)) {
449 		numpackets++;
450 	}
451 	if (numpackets == 0)
452 		return 0;
453 	td_t *tds = create_schedule(numpackets);
454 	int i = 0, toggle = ep->toggle;
455 	int len_left = dalen;
456 	while ((len_left > 0) || ((len_left == 0) && (finalize != 0))) {
457 		fill_schedule(&tds[i], ep, min(len_left, maxpsize), data,
458 			       &toggle);
459 		i++;
460 		data += maxpsize;
461 		len_left -= maxpsize;
462 	}
463 	if (run_schedule(ep->dev, tds) == 1) {
464 		free(tds);
465 		return -1;
466 	}
467 	ep->toggle = toggle;
468 	free(tds);
469 	return dalen; /* TODO: We should return the actually transferred length. */
470 }
471 
472 typedef struct {
473 	qh_t *qh;
474 	td_t *tds;
475 	td_t *last_td;
476 	u8 *data;
477 	int lastread;
478 	int total;
479 	int reqsize;
480 } intr_q;
481 
482 /* create and hook-up an intr queue into device schedule */
483 static void*
uhci_create_intr_queue(endpoint_t * ep,int reqsize,int reqcount,int reqtiming)484 uhci_create_intr_queue(endpoint_t *ep, int reqsize, int reqcount, int reqtiming)
485 {
486 	u8 *data = malloc(reqsize*reqcount);
487 	td_t *tds = memalign(16, sizeof(td_t) * reqcount);
488 	qh_t *qh = memalign(16, sizeof(qh_t));
489 
490 	if (!data || !tds || !qh)
491 		fatal("Not enough memory to create USB intr queue prerequisites.\n");
492 
493 	qh->elementlinkptr = virt_to_phys(tds);
494 
495 	intr_q *q = malloc(sizeof(intr_q));
496 	if (!q)
497 		fatal("Not enough memory to create USB intr queue.\n");
498 	q->qh = qh;
499 	q->tds = tds;
500 	q->data = data;
501 	q->lastread = 0;
502 	q->total = reqcount;
503 	q->reqsize = reqsize;
504 	q->last_td = &tds[reqcount - 1];
505 
506 	memset(tds, 0, sizeof(td_t) * reqcount);
507 	int i;
508 	for (i = 0; i < reqcount; i++) {
509 		tds[i].ptr = virt_to_phys(&tds[i + 1]);
510 
511 		switch (ep->direction) {
512 			case IN: tds[i].token = UHCI_IN; break;
513 			case OUT: tds[i].token = UHCI_OUT; break;
514 			case SETUP: tds[i].token = UHCI_SETUP; break;
515 		}
516 		tds[i].token |= ep->dev->address << TD_DEVADDR_SHIFT |
517 			(ep->endpoint & 0xf) << TD_EP_SHIFT |
518 			maxlen(reqsize) << TD_MAXLEN_SHIFT |
519 			(ep->toggle & 1) << TD_TOGGLE_SHIFT;
520 		tds[i].bufptr = virt_to_phys(data);
521 		tds[i].ctrlsts = (0 << TD_COUNTER_SHIFT) |
522 			(ep->dev->speed?TD_LOWSPEED:0) |
523 			TD_STATUS_ACTIVE;
524 		ep->toggle ^= 1;
525 		data += reqsize;
526 	}
527 	tds[reqcount - 1].ptr = 0 | TD_TERMINATE;
528 
529 	/* insert QH into framelist */
530 	uhci_t *const uhcic = UHCI_INST(ep->dev->controller);
531 	const u32 def_ptr = virt_to_phys(uhcic->qh_prei) | FLISTP_QH;
532 	int nothing_placed = 1;
533 	qh->headlinkptr = def_ptr;
534 	for (i = 0; i < 1024; i += reqtiming) {
535 		/* advance to the next free position */
536 		while ((i < 1024) && (uhcic->framelistptr[i] != def_ptr)) ++i;
537 		if (i < 1024) {
538 			uhcic->framelistptr[i] = virt_to_phys(qh) | FLISTP_QH;
539 			nothing_placed = 0;
540 		}
541 	}
542 	if (nothing_placed) {
543 		usb_debug("Error: Failed to place UHCI interrupt queue "
544 			      "head into framelist: no space left\n");
545 		uhci_destroy_intr_queue(ep, q);
546 		return NULL;
547 	}
548 
549 	return q;
550 }
551 
552 /* remove queue from device schedule, dropping all data that came in */
553 static void
uhci_destroy_intr_queue(endpoint_t * ep,void * q_)554 uhci_destroy_intr_queue(endpoint_t *ep, void *q_)
555 {
556 	intr_q *const q = (intr_q*)q_;
557 
558 	/* remove QH from framelist */
559 	uhci_t *const uhcic = UHCI_INST(ep->dev->controller);
560 	const u32 qh_ptr = virt_to_phys(q->qh) | FLISTP_QH;
561 	const u32 def_ptr = virt_to_phys(uhcic->qh_prei) | FLISTP_QH;
562 	int i;
563 	for (i = 0; i < 1024; ++i) {
564 		if (uhcic->framelistptr[i] == qh_ptr)
565 			uhcic->framelistptr[i] = def_ptr;
566 	}
567 
568 	free(q->data);
569 	free(q->tds);
570 	free(q->qh);
571 	free(q);
572 }
573 
574 /* read one intr-packet from queue, if available. extend the queue for new input.
575    return NULL if nothing new available.
576    Recommended use: while (data=poll_intr_queue(q)) process(data);
577  */
578 static u8*
uhci_poll_intr_queue(void * q_)579 uhci_poll_intr_queue(void *q_)
580 {
581 	intr_q *q = (intr_q*)q_;
582 	if ((q->tds[q->lastread].ctrlsts & TD_STATUS_ACTIVE) == 0) {
583 		int current = q->lastread;
584 		int previous;
585 		if (q->lastread == 0) {
586 			previous = q->total - 1;
587 		} else {
588 			previous = q->lastread - 1;
589 		}
590 		q->tds[previous].ctrlsts &= ~TD_STATUS_MASK;
591 		q->tds[previous].ptr = 0 | TD_TERMINATE;
592 		if (q->last_td != &q->tds[previous]) {
593 			q->last_td->ptr = virt_to_phys(&q->tds[previous]) & ~TD_TERMINATE;
594 			q->last_td = &q->tds[previous];
595 		}
596 		q->tds[previous].ctrlsts |= TD_STATUS_ACTIVE;
597 		q->lastread = (q->lastread + 1) % q->total;
598 		if (!(q->tds[current].ctrlsts & TD_STATUS_MASK))
599 			return &q->data[current*q->reqsize];
600 	}
601 	/* reset queue if we fully processed it after underrun */
602 	else if (q->qh->elementlinkptr & FLISTP_TERMINATE) {
603 		usb_debug("resetting underrun uhci interrupt queue.\n");
604 		q->qh->elementlinkptr = virt_to_phys(q->tds + q->lastread);
605 	}
606 	return NULL;
607 }
608 
609 void
uhci_reg_write32(hci_t * ctrl,usbreg reg,u32 value)610 uhci_reg_write32(hci_t *ctrl, usbreg reg, u32 value)
611 {
612 	outl(value, ctrl->reg_base + reg);
613 }
614 
615 u32
uhci_reg_read32(hci_t * ctrl,usbreg reg)616 uhci_reg_read32(hci_t *ctrl, usbreg reg)
617 {
618 	return inl(ctrl->reg_base + reg);
619 }
620 
621 void
uhci_reg_write16(hci_t * ctrl,usbreg reg,u16 value)622 uhci_reg_write16(hci_t *ctrl, usbreg reg, u16 value)
623 {
624 	outw(value, ctrl->reg_base + reg);
625 }
626 
627 u16
uhci_reg_read16(hci_t * ctrl,usbreg reg)628 uhci_reg_read16(hci_t *ctrl, usbreg reg)
629 {
630 	return inw(ctrl->reg_base + reg);
631 }
632 
633 void
uhci_reg_write8(hci_t * ctrl,usbreg reg,u8 value)634 uhci_reg_write8(hci_t *ctrl, usbreg reg, u8 value)
635 {
636 	outb(value, ctrl->reg_base + reg);
637 }
638 
639 u8
uhci_reg_read8(hci_t * ctrl,usbreg reg)640 uhci_reg_read8(hci_t *ctrl, usbreg reg)
641 {
642 	return inb(ctrl->reg_base + reg);
643 }
644