blob: def6b45084a9b088378ee5921705fd06d67f0a1f [file] [log] [blame]
Patrick Georgid21f68b2008-09-02 16:06:22 +00001/*
2 * This file is part of the libpayload project.
3 *
4 * Copyright (C) 2008 coresystems GmbH
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
Jordan Crouse29061a52008-09-11 17:29:00 +000030#include <usb/usb.h>
Patrick Georgid21f68b2008-09-02 16:06:22 +000031#include "uhci.h"
32#include <arch/virtual.h>
33
34static void uhci_start (hci_t *controller);
35static void uhci_stop (hci_t *controller);
36static void uhci_reset (hci_t *controller);
37static void uhci_shutdown (hci_t *controller);
38static int uhci_packet (usbdev_t *dev, int endp, int pid, int toggle,
39 int length, u8 *data);
40static int uhci_bulk (endpoint_t *ep, int size, u8 *data, int finalize);
41static int uhci_control (usbdev_t *dev, pid_t dir, int drlen, void *devreq,
42 int dalen, u8 *data);
Patrick Georgi4727c072008-10-16 19:20:51 +000043static void* uhci_create_intr_queue (endpoint_t *ep, int reqsize, int reqcount, int reqtiming);
44static void uhci_destroy_intr_queue (endpoint_t *ep, void *queue);
45static u8* uhci_poll_intr_queue (void *queue);
Patrick Georgid21f68b2008-09-02 16:06:22 +000046
47#if 0
48/* dump uhci */
49static void
50uhci_dump (hci_t *controller)
51{
52 printf ("dump:\nUSBCMD: %x\n", uhci_reg_read16 (controller, USBCMD));
53 printf ("USBSTS: %x\n", uhci_reg_read16 (controller, USBSTS));
54 printf ("USBINTR: %x\n", uhci_reg_read16 (controller, USBINTR));
55 printf ("FRNUM: %x\n", uhci_reg_read16 (controller, FRNUM));
56 printf ("FLBASEADD: %x\n", uhci_reg_read32 (controller, FLBASEADD));
57 printf ("SOFMOD: %x\n", uhci_reg_read8 (controller, SOFMOD));
58 printf ("PORTSC1: %x\n", uhci_reg_read16 (controller, PORTSC1));
59 printf ("PORTSC2: %x\n", uhci_reg_read16 (controller, PORTSC2));
60}
61#endif
62
63static void
64td_dump (td_t *td)
65{
Stefan Reinauerd233f362009-04-30 16:46:12 +000066 char td_value[3];
67 char *td_type;
68 switch (td->pid) {
69 case SETUP:
70 td_type="SETUP";
71 break;
72 case IN:
73 td_type="IN";
74 break;
75 case OUT:
76 td_type="OUT";
77 break;
78 default:
79 sprintf(td_value, "%x", td->pid);
80 td_type=td_value;
81 }
82 printf ("%s packet (at %lx) to %x.%x failed\n", td_type,
Patrick Georgid21f68b2008-09-02 16:06:22 +000083 virt_to_phys (td), td->dev_addr, td->endp);
84 printf ("td (counter at %x) returns: ", td->counter);
85 printf (" bitstuff err: %x, ", td->status_bitstuff_err);
86 printf (" CRC err: %x, ", td->status_crc_err);
87 printf (" NAK rcvd: %x, ", td->status_nakrcvd);
88 printf (" Babble: %x, ", td->status_babble);
89 printf (" Data Buffer err: %x, ", td->status_databuf_err);
90 printf (" Stalled: %x, ", td->status_stalled);
91 printf (" Active: %x\n", td->status_active);
92 if (td->status_babble)
93 printf (" Babble because of %s\n",
94 td->status_bitstuff_err ? "host" : "device");
95 if (td->status_active)
96 printf (" still active - timeout?\n");
97}
98
99static void
100uhci_reset (hci_t *controller)
101{
102 /* reset */
103 uhci_reg_write16 (controller, USBCMD, 4);
104 mdelay (50);
105 uhci_reg_write16 (controller, USBCMD, 0);
106 mdelay (10);
107 uhci_reg_write16 (controller, USBCMD, 2);
108 while ((uhci_reg_read16 (controller, USBCMD) & 2) != 0)
109 mdelay (1);
110
111 uhci_reg_write32 (controller, FLBASEADD,
112 (u32) virt_to_phys (UHCI_INST (controller)->
113 framelistptr));
114 //printf ("framelist at %p\n",UHCI_INST(controller)->framelistptr);
115
116 /* disable irqs */
117 uhci_reg_write16 (controller, USBINTR, 0);
118
119 /* reset framelist index */
120 uhci_reg_write16 (controller, FRNUM, 0);
121
122 uhci_reg_mask16 (controller, USBCMD, ~0, 0xc0); // max packets, configure flag
123
124 uhci_start (controller);
125}
126
127hci_t *
128uhci_init (pcidev_t addr)
129{
130 int i;
131 hci_t *controller = new_controller ();
132
Stefan Reinauer5fe6e232009-07-31 11:39:55 +0000133 if (!controller)
134 usb_fatal("Could not create USB controller instance.\n");
135
Patrick Georgid21f68b2008-09-02 16:06:22 +0000136 controller->instance = malloc (sizeof (uhci_t));
Stefan Reinauer5fe6e232009-07-31 11:39:55 +0000137 if(!controller->instance)
138 usb_fatal("Not enough memory creating USB controller instance.\n");
139
Patrick Georgid21f68b2008-09-02 16:06:22 +0000140 controller->start = uhci_start;
141 controller->stop = uhci_stop;
142 controller->reset = uhci_reset;
143 controller->shutdown = uhci_shutdown;
144 controller->packet = uhci_packet;
145 controller->bulk = uhci_bulk;
146 controller->control = uhci_control;
Patrick Georgi4727c072008-10-16 19:20:51 +0000147 controller->create_intr_queue = uhci_create_intr_queue;
148 controller->destroy_intr_queue = uhci_destroy_intr_queue;
149 controller->poll_intr_queue = uhci_poll_intr_queue;
Stefan Reinauer219cece2009-07-18 15:17:40 +0000150 for (i = 0; i < 128; i++) {
Patrick Georgi4727c072008-10-16 19:20:51 +0000151 controller->devices[i] = 0;
152 }
153 init_device_entry (controller, 0);
154 UHCI_INST (controller)->roothub = controller->devices[0];
Patrick Georgid21f68b2008-09-02 16:06:22 +0000155
156 controller->bus_address = addr;
157 controller->reg_base = pci_read_config32 (controller->bus_address, 0x20) & ~1; /* ~1 clears the register type indicator that is set to 1 for IO space */
158
159 /* kill legacy support handler */
160 uhci_stop (controller);
161 mdelay (1);
162 uhci_reg_write16 (controller, USBSTS, 0x3f);
163 pci_write_config32 (controller->bus_address, 0xc0, 0x8f00);
164
165 UHCI_INST (controller)->framelistptr = memalign (0x1000, 1024 * sizeof (flistp_t *)); /* 4kb aligned to 4kb */
Stefan Reinauer5fe6e232009-07-31 11:39:55 +0000166 if (! UHCI_INST (controller)->framelistptr)
167 usb_fatal("Not enough memory for USB frame list pointer.\n");
168
Patrick Georgid21f68b2008-09-02 16:06:22 +0000169 memset (UHCI_INST (controller)->framelistptr, 0,
170 1024 * sizeof (flistp_t));
171
Patrick Georgi4727c072008-10-16 19:20:51 +0000172 /* According to the *BSD UHCI code, this one is needed on some
173 PIIX chips, because otherwise they misbehave. It must be
174 added to the last chain.
175
176 FIXME: this leaks, if the driver should ever be reinited
177 for some reason. Not a problem now.
178 */
179 td_t *antiberserk = memalign(16, sizeof(td_t));
Stefan Reinauer5fe6e232009-07-31 11:39:55 +0000180 if (!antiberserk)
181 usb_fatal("Not enough memory for chipset workaround.\n");
Patrick Georgi4727c072008-10-16 19:20:51 +0000182 memset(antiberserk, 0, sizeof(td_t));
183
184 UHCI_INST (controller)->qh_prei = memalign (16, sizeof (qh_t));
Patrick Georgid21f68b2008-09-02 16:06:22 +0000185 UHCI_INST (controller)->qh_intr = memalign (16, sizeof (qh_t));
186 UHCI_INST (controller)->qh_data = memalign (16, sizeof (qh_t));
187 UHCI_INST (controller)->qh_last = memalign (16, sizeof (qh_t));
188
Stefan Reinauer5fe6e232009-07-31 11:39:55 +0000189 if (! UHCI_INST (controller)->qh_prei ||
190 ! UHCI_INST (controller)->qh_intr ||
191 ! UHCI_INST (controller)->qh_data ||
192 ! UHCI_INST (controller)->qh_last)
193 usb_fatal ("Not enough memory for USB controller queues.\n");
194
Patrick Georgi4727c072008-10-16 19:20:51 +0000195 UHCI_INST (controller)->qh_prei->headlinkptr.ptr =
196 virt_to_phys (UHCI_INST (controller)->qh_intr);
197 UHCI_INST (controller)->qh_prei->headlinkptr.queue_head = 1;
198 UHCI_INST (controller)->qh_prei->elementlinkptr.ptr = 0;
199 UHCI_INST (controller)->qh_prei->elementlinkptr.terminate = 1;
200
Patrick Georgid21f68b2008-09-02 16:06:22 +0000201 UHCI_INST (controller)->qh_intr->headlinkptr.ptr =
202 virt_to_phys (UHCI_INST (controller)->qh_data);
203 UHCI_INST (controller)->qh_intr->headlinkptr.queue_head = 1;
204 UHCI_INST (controller)->qh_intr->elementlinkptr.ptr = 0;
205 UHCI_INST (controller)->qh_intr->elementlinkptr.terminate = 1;
206
207 UHCI_INST (controller)->qh_data->headlinkptr.ptr =
208 virt_to_phys (UHCI_INST (controller)->qh_last);
209 UHCI_INST (controller)->qh_data->headlinkptr.queue_head = 1;
210 UHCI_INST (controller)->qh_data->elementlinkptr.ptr = 0;
211 UHCI_INST (controller)->qh_data->elementlinkptr.terminate = 1;
212
Patrick Georgi4727c072008-10-16 19:20:51 +0000213 UHCI_INST (controller)->qh_last->headlinkptr.ptr = virt_to_phys (UHCI_INST (controller)->qh_data);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000214 UHCI_INST (controller)->qh_last->headlinkptr.terminate = 1;
Patrick Georgi4727c072008-10-16 19:20:51 +0000215 UHCI_INST (controller)->qh_last->elementlinkptr.ptr = virt_to_phys (antiberserk);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000216 UHCI_INST (controller)->qh_last->elementlinkptr.terminate = 1;
217
218 for (i = 0; i < 1024; i++) {
219 UHCI_INST (controller)->framelistptr[i].ptr =
Patrick Georgi4727c072008-10-16 19:20:51 +0000220 virt_to_phys (UHCI_INST (controller)->qh_prei);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000221 UHCI_INST (controller)->framelistptr[i].terminate = 0;
222 UHCI_INST (controller)->framelistptr[i].queue_head = 1;
223 }
Patrick Georgi4727c072008-10-16 19:20:51 +0000224 controller->devices[0]->controller = controller;
225 controller->devices[0]->init = uhci_rh_init;
226 controller->devices[0]->init (controller->devices[0]);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000227 uhci_reset (controller);
228 return controller;
229}
230
231static void
232uhci_shutdown (hci_t *controller)
233{
234 if (controller == 0)
235 return;
236 detach_controller (controller);
237 UHCI_INST (controller)->roothub->destroy (UHCI_INST (controller)->
238 roothub);
239 uhci_reg_mask16 (controller, USBCMD, 0, 0); // stop work
240 free (UHCI_INST (controller)->framelistptr);
Patrick Georgi4727c072008-10-16 19:20:51 +0000241 free (UHCI_INST (controller)->qh_prei);
Patrick Georgid21f68b2008-09-02 16:06:22 +0000242 free (UHCI_INST (controller)->qh_intr);
243 free (UHCI_INST (controller)->qh_data);
244 free (UHCI_INST (controller)->qh_last);
245 free (UHCI_INST (controller));
246 free (controller);
247}
248
249static void
250uhci_start (hci_t *controller)
251{
252 uhci_reg_mask16 (controller, USBCMD, ~0, 1); // start work on schedule
253}
254
255static void
256uhci_stop (hci_t *controller)
257{
258 uhci_reg_mask16 (controller, USBCMD, ~1, 0); // stop work on schedule
259}
260
261#define GET_TD(x) ((void*)(((unsigned int)(x))&~0xf))
262
263static td_t *
264wait_for_completed_qh (hci_t *controller, qh_t *qh)
265{
Patrick Georgi4727c072008-10-16 19:20:51 +0000266 int timeout = 1000000; /* max 30 ms. */
Patrick Georgid21f68b2008-09-02 16:06:22 +0000267 void *current = GET_TD (qh->elementlinkptr.ptr);
268 while ((qh->elementlinkptr.terminate == 0) && (timeout-- > 0)) {
269 if (current != GET_TD (qh->elementlinkptr.ptr)) {
270 current = GET_TD (qh->elementlinkptr.ptr);
Patrick Georgi4727c072008-10-16 19:20:51 +0000271 timeout = 1000000;
Patrick Georgid21f68b2008-09-02 16:06:22 +0000272 }
273 uhci_reg_mask16 (controller, USBSTS, ~0, 0); // clear resettable registers
274 udelay (30);
275 }
276 return (GET_TD (qh->elementlinkptr.ptr) ==
277 0) ? 0 : GET_TD (phys_to_virt (qh->elementlinkptr.ptr));
278}
279
280static void
281wait_for_completed_td (hci_t *controller, td_t *td)
282{
283 int timeout = 10000;
284 while ((td->status_active == 1)
285 && ((uhci_reg_read16 (controller, USBSTS) & 2) == 0)
286 && (timeout-- > 0)) {
287 uhci_reg_mask16 (controller, USBSTS, ~0, 0); // clear resettable registers
288 udelay (10);
289 }
290}
291
292static int
293maxlen (int size)
294{
295 return (size - 1) & 0x7ff;
296}
297
298static int
299min (int a, int b)
300{
301 if (a < b)
302 return a;
303 else
304 return b;
305}
306
307static int
308uhci_control (usbdev_t *dev, pid_t dir, int drlen, void *devreq, int dalen,
309 unsigned char *data)
310{
311 int endp = 0; /* this is control: always 0 */
312 int mlen = dev->endpoints[0].maxpacketsize;
313 int count = (2 + (dalen + mlen - 1) / mlen);
314 unsigned short req = ((unsigned short *) devreq)[0];
315 int i;
316 td_t *tds = memalign (16, sizeof (td_t) * count);
317 memset (tds, 0, sizeof (td_t) * count);
318 count--; /* to compensate for 0-indexed array */
319 for (i = 0; i < count; i++) {
320 tds[i].ptr = virt_to_phys (&tds[i + 1]);
321 tds[i].depth_first = 1;
322 tds[i].terminate = 0;
323 }
324 tds[count].ptr = 0;
325 tds[count].depth_first = 1;
326 tds[count].terminate = 1;
327
328 tds[0].pid = SETUP;
329 tds[0].dev_addr = dev->address;
330 tds[0].endp = endp;
331 tds[0].maxlen = maxlen (drlen);
332 tds[0].counter = 3;
333 tds[0].data_toggle = 0;
334 tds[0].lowspeed = dev->lowspeed;
335 tds[0].bufptr = virt_to_phys (devreq);
336 tds[0].status_active = 1;
337
338 int toggle = 1;
339 for (i = 1; i < count; i++) {
340 tds[i].pid = dir;
341 tds[i].dev_addr = dev->address;
342 tds[i].endp = endp;
343 tds[i].maxlen = maxlen (min (mlen, dalen));
344 tds[i].counter = 3;
345 tds[i].data_toggle = toggle;
346 tds[i].lowspeed = dev->lowspeed;
347 tds[i].bufptr = virt_to_phys (data);
348 tds[i].status_active = 1;
349 toggle ^= 1;
350 dalen -= mlen;
351 data += mlen;
352 }
353
354 tds[count].pid = (dir == OUT) ? IN : OUT;
355 tds[count].dev_addr = dev->address;
356 tds[count].endp = endp;
357 tds[count].maxlen = maxlen (0);
358 tds[count].counter = 0; /* as per linux 2.4.10 */
359 tds[count].data_toggle = 1;
360 tds[count].lowspeed = dev->lowspeed, tds[count].bufptr = 0;
361 tds[count].status_active = 1;
362 UHCI_INST (dev->controller)->qh_data->elementlinkptr.ptr =
363 virt_to_phys (tds);
364 UHCI_INST (dev->controller)->qh_data->elementlinkptr.queue_head = 0;
365 UHCI_INST (dev->controller)->qh_data->elementlinkptr.terminate = 0;
366 td_t *td = wait_for_completed_qh (dev->controller,
367 UHCI_INST (dev->controller)->
368 qh_data);
369 int result;
370 if (td == 0) {
371 result = 0;
372 } else {
373 printf ("control packet, req %x\n", req);
374 td_dump (td);
375 result = 1;
376 }
377 free (tds);
378 return result;
379}
380
381static int
382uhci_packet (usbdev_t *dev, int endp, int pid, int toggle, int length,
383 unsigned char *data)
384{
385 static td_t *td = 0;
386 if (td == 0)
387 td = memalign (16, sizeof (td_t));
388
389 memset (td, 0, sizeof (td_t));
390 td->ptr = 0;
391 td->terminate = 1;
392 td->queue_head = 0;
393
394 td->pid = pid;
395 td->dev_addr = dev->address;
396 td->endp = endp & 0xf;
397 td->maxlen = maxlen (length);
398 if (pid == SETUP)
399 td->counter = 3;
400 else
401 td->counter = 0;
402 td->data_toggle = toggle & 1;
403 td->lowspeed = dev->lowspeed;
404 td->bufptr = virt_to_phys (data);
405
406 td->status_active = 1;
407
408 UHCI_INST (dev->controller)->qh_data->elementlinkptr.ptr =
409 virt_to_phys (td);
410 UHCI_INST (dev->controller)->qh_data->elementlinkptr.queue_head = 0;
411 UHCI_INST (dev->controller)->qh_data->elementlinkptr.terminate = 0;
412 wait_for_completed_td (dev->controller, td);
413 if ((td->status & 0x7f) == 0) {
414 //printf("successfully sent a %x packet to %x.%x\n",pid, dev->address,endp);
415 // success
416 return 0;
417 } else {
418 td_dump (td);
419 return 1;
420 }
421}
422
423static td_t *
424create_schedule (int numpackets)
425{
426 if (numpackets == 0)
427 return 0;
428 td_t *tds = memalign (16, sizeof (td_t) * numpackets);
429 memset (tds, 0, sizeof (td_t) * numpackets);
430 int i;
431 for (i = 0; i < numpackets; i++) {
432 tds[i].ptr = virt_to_phys (&tds[i + 1]);
433 tds[i].terminate = 0;
434 tds[i].queue_head = 0;
435 tds[i].depth_first = 1;
436 }
437 tds[numpackets - 1].ptr = 0;
438 tds[numpackets - 1].terminate = 1;
439 tds[numpackets - 1].queue_head = 0;
440 tds[numpackets - 1].depth_first = 0;
441 return tds;
442}
443
444static void
445fill_schedule (td_t *td, endpoint_t *ep, int length, unsigned char *data,
446 int *toggle)
447{
448 td->pid = ep->direction;
449 td->dev_addr = ep->dev->address;
450 td->endp = ep->endpoint & 0xf;
451 td->maxlen = maxlen (length);
452 if (ep->direction == SETUP)
453 td->counter = 3;
454 else
455 td->counter = 0;
456 td->data_toggle = *toggle & 1;
457 td->lowspeed = ep->dev->lowspeed;
458 td->bufptr = virt_to_phys (data);
459
460 td->status_active = 1;
461 *toggle ^= 1;
462}
463
464static int
465run_schedule (usbdev_t *dev, td_t *td)
466{
467 UHCI_INST (dev->controller)->qh_data->elementlinkptr.ptr =
468 virt_to_phys (td);
469 UHCI_INST (dev->controller)->qh_data->elementlinkptr.queue_head = 0;
470 UHCI_INST (dev->controller)->qh_data->elementlinkptr.terminate = 0;
471 td = wait_for_completed_qh (dev->controller,
472 UHCI_INST (dev->controller)->qh_data);
473 if (td == 0) {
474 return 0;
475 } else {
476 td_dump (td);
477 return 1;
478 }
479}
480
481/* finalize == 1: if data is of packet aligned size, add a zero length packet */
482static int
483uhci_bulk (endpoint_t *ep, int size, u8 *data, int finalize)
484{
485 int maxpsize = ep->maxpacketsize;
486 if (maxpsize == 0)
487 fatal ("MaxPacketSize == 0!!!");
488 int numpackets = (size + maxpsize - 1 + finalize) / maxpsize;
489 if (numpackets == 0)
490 return 0;
491 td_t *tds = create_schedule (numpackets);
492 int i = 0, toggle = ep->toggle;
493 while ((size > 0) || ((size == 0) && (finalize != 0))) {
494 fill_schedule (&tds[i], ep, min (size, maxpsize), data,
495 &toggle);
496 i++;
497 data += maxpsize;
498 size -= maxpsize;
499 }
500 if (run_schedule (ep->dev, tds) == 1) {
501 clear_stall (ep);
502 free (tds);
503 return 1;
504 }
505 ep->toggle = toggle;
506 free (tds);
507 return 0;
508}
509
Patrick Georgi4727c072008-10-16 19:20:51 +0000510typedef struct {
511 qh_t *qh;
512 td_t *tds;
513 td_t *last_td;
514 u8 *data;
515 int lastread;
516 int total;
517 int reqsize;
518} intr_q;
519
520/* create and hook-up an intr queue into device schedule */
521static void*
522uhci_create_intr_queue (endpoint_t *ep, int reqsize, int reqcount, int reqtiming)
523{
524 u8 *data = malloc(reqsize*reqcount);
525 td_t *tds = memalign(16, sizeof(td_t) * reqcount);
526 qh_t *qh = memalign(16, sizeof(qh_t));
527
Stefan Reinauer5fe6e232009-07-31 11:39:55 +0000528 if (!data || !tds || !qh)
529 usb_fatal ("Not enough memory to create USB intr queue prerequisites.\n");
530
Patrick Georgi4727c072008-10-16 19:20:51 +0000531 qh->elementlinkptr.ptr = virt_to_phys(tds);
Stefan Reinauerd233f362009-04-30 16:46:12 +0000532 qh->elementlinkptr.queue_head = 0;
Patrick Georgi4727c072008-10-16 19:20:51 +0000533 qh->elementlinkptr.terminate = 0;
534
535 intr_q *q = malloc(sizeof(intr_q));
Stefan Reinauer5fe6e232009-07-31 11:39:55 +0000536 if (!q)
537 usb_fatal ("Not enough memory to create USB intr queue.\n");
Patrick Georgi4727c072008-10-16 19:20:51 +0000538 q->qh = qh;
539 q->tds = tds;
540 q->data = data;
541 q->lastread = 0;
542 q->total = reqcount;
543 q->reqsize = reqsize;
544 q->last_td = &tds[reqcount - 1];
545
546 memset (tds, 0, sizeof (td_t) * reqcount);
547 int i;
548 for (i = 0; i < reqcount; i++) {
549 tds[i].ptr = virt_to_phys (&tds[i + 1]);
550 tds[i].terminate = 0;
551 tds[i].queue_head = 0;
552 tds[i].depth_first = 0;
553
554 tds[i].pid = ep->direction;
555 tds[i].dev_addr = ep->dev->address;
556 tds[i].endp = ep->endpoint & 0xf;
557 tds[i].maxlen = maxlen (reqsize);
558 tds[i].counter = 0;
559 tds[i].data_toggle = ep->toggle & 1;
560 tds[i].lowspeed = ep->dev->lowspeed;
561 tds[i].bufptr = virt_to_phys (data);
562 tds[i].status_active = 1;
563 ep->toggle ^= 1;
564 data += reqsize;
565 }
566 tds[reqcount - 1].ptr = 0;
567 tds[reqcount - 1].terminate = 1;
568 tds[reqcount - 1].queue_head = 0;
569 tds[reqcount - 1].depth_first = 0;
570 for (i = reqtiming; i < 1024; i += reqtiming) {
571 /* FIXME: wrap in another qh, one for each occurance of the qh in the framelist */
572 qh->headlinkptr.ptr = UHCI_INST (ep->dev->controller)->framelistptr[i].ptr;
573 qh->headlinkptr.terminate = 0;
574 UHCI_INST (ep->dev->controller)->framelistptr[i].ptr = virt_to_phys(qh);
575 UHCI_INST (ep->dev->controller)->framelistptr[i].terminate = 0;
576 UHCI_INST (ep->dev->controller)->framelistptr[i].queue_head = 1;
577 }
578 return q;
579}
580
581/* remove queue from device schedule, dropping all data that came in */
582static void
583uhci_destroy_intr_queue (endpoint_t *ep, void *q_)
584{
585 intr_q *q = (intr_q*)q_;
586 u32 val = virt_to_phys (q->qh);
587 u32 end = virt_to_phys (UHCI_INST (ep->dev->controller)->qh_intr);
588 int i;
589 for (i=0; i<1024; i++) {
590 u32 oldptr = 0;
591 u32 ptr = UHCI_INST (ep->dev->controller)->framelistptr[i].ptr;
592 while (ptr != end) {
593 if (((qh_t*)phys_to_virt(ptr))->elementlinkptr.ptr == val) {
594 ((qh_t*)phys_to_virt(oldptr))->headlinkptr.ptr = ((qh_t*)phys_to_virt(ptr))->headlinkptr.ptr;
595 free(phys_to_virt(ptr));
596 break;
597 }
598 oldptr = ptr;
599 ptr = ((qh_t*)phys_to_virt(ptr))->headlinkptr.ptr;
600 }
601 }
602 free(q->data);
603 free(q->tds);
604 free(q->qh);
605 free(q);
606}
607
608/* read one intr-packet from queue, if available. extend the queue for new input.
609 return NULL if nothing new available.
610 Recommended use: while (data=poll_intr_queue(q)) process(data);
611 */
612static u8*
613uhci_poll_intr_queue (void *q_)
614{
615 intr_q *q = (intr_q*)q_;
616 if (q->tds[q->lastread].status_active == 0) {
617 /* FIXME: handle errors */
618 int current = q->lastread;
619 int previous;
620 if (q->lastread == 0) {
621 previous = q->total - 1;
622 } else {
623 previous = q->lastread - 1;
624 }
625 q->tds[previous].status = 0;
626 q->tds[previous].ptr = 0;
627 q->tds[previous].terminate = 1;
628 if (q->last_td != &q->tds[previous]) {
629 q->last_td->ptr = virt_to_phys(&q->tds[previous]);
630 q->last_td->terminate = 0;
631 q->last_td = &q->tds[previous];
632 }
633 q->tds[previous].status_active = 1;
634 q->lastread = (q->lastread + 1) % q->total;
635 return &q->data[current*q->reqsize];
636 }
637 return NULL;
638}
639
Patrick Georgid21f68b2008-09-02 16:06:22 +0000640void
641uhci_reg_write32 (hci_t *ctrl, usbreg reg, u32 value)
642{
643 outl (value, ctrl->reg_base + reg);
644}
645
646u32
647uhci_reg_read32 (hci_t *ctrl, usbreg reg)
648{
649 return inl (ctrl->reg_base + reg);
650}
651
652void
653uhci_reg_write16 (hci_t *ctrl, usbreg reg, u16 value)
654{
655 outw (value, ctrl->reg_base + reg);
656}
657
658u16
659uhci_reg_read16 (hci_t *ctrl, usbreg reg)
660{
661 return inw (ctrl->reg_base + reg);
662}
663
664void
665uhci_reg_write8 (hci_t *ctrl, usbreg reg, u8 value)
666{
667 outb (value, ctrl->reg_base + reg);
668}
669
670u8
671uhci_reg_read8 (hci_t *ctrl, usbreg reg)
672{
673 return inb (ctrl->reg_base + reg);
674}
675
676void
677uhci_reg_mask32 (hci_t *ctrl, usbreg reg, u32 andmask, u32 ormask)
678{
679 uhci_reg_write32 (ctrl, reg,
680 (uhci_reg_read32 (ctrl, reg) & andmask) | ormask);
681}
682
683void
684uhci_reg_mask16 (hci_t *ctrl, usbreg reg, u16 andmask, u16 ormask)
685{
686 uhci_reg_write16 (ctrl, reg,
687 (uhci_reg_read16 (ctrl, reg) & andmask) | ormask);
688}
689
690void
691uhci_reg_mask8 (hci_t *ctrl, usbreg reg, u8 andmask, u8 ormask)
692{
693 uhci_reg_write8 (ctrl, reg,
694 (uhci_reg_read8 (ctrl, reg) & andmask) | ormask);
695}