]> git.proxmox.com Git - grub2.git/blob - bus/usb/uhci.c
2009-02-08 Marco Gerards <marco@gnu.org>
[grub2.git] / bus / usb / uhci.c
1 /* uhci.c - UHCI Support. */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2008 Free Software Foundation, Inc.
5 *
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <grub/dl.h>
21 #include <grub/mm.h>
22 #include <grub/misc.h>
23 #include <grub/usb.h>
24 #include <grub/usbtrans.h>
25 #include <grub/pci.h>
26 #include <grub/cpu/pci.h>
27 #include <grub/i386/io.h>
28 #include <grub/time.h>
29
30 #define GRUB_UHCI_IOMASK (0x7FF << 5)
31
32 typedef enum
33 {
34 GRUB_UHCI_REG_USBCMD = 0x00,
35 GRUB_UHCI_REG_FLBASEADD = 0x08,
36 GRUB_UHCI_REG_PORTSC1 = 0x10,
37 GRUB_UHCI_REG_PORTSC2 = 0x12
38 } grub_uhci_reg_t;
39
40 #define GRUB_UHCI_LINK_TERMINATE 1
41 #define GRUB_UHCI_LINK_QUEUE_HEAD 2
42
43
44 /* UHCI Queue Head. */
45 struct grub_uhci_qh
46 {
47 /* Queue head link pointer which points to the next queue head. */
48 grub_uint32_t linkptr;
49
50 /* Queue element link pointer which points to the first data object
51 within the queue. */
52 grub_uint32_t elinkptr;
53
54 /* Queue heads are aligned on 16 bytes, pad so a queue head is 16
55 bytes so we can store many in a 4K page. */
56 grub_uint8_t pad[8];
57 } __attribute__ ((packed));
58
59 /* UHCI Tranfer Descriptor. */
60 struct grub_uhci_td
61 {
62 /* Pointer to the next TD in the list. */
63 grub_uint32_t linkptr;
64
65 /* Control and status bits. */
66 grub_uint32_t ctrl_status;
67
68 /* All information required to transfer the Token packet. */
69 grub_uint32_t token;
70
71 /* A pointer to the data buffer, UHCI requires this pointer to be 32
72 bits. */
73 grub_uint32_t buffer;
74
75 /* Another linkptr that is not overwritten by the Host Controller.
76 This is GRUB specific. */
77 grub_uint32_t linkptr2;
78
79 /* 3 additional 32 bits words reserved for the Host Controller Driver. */
80 grub_uint32_t data[3];
81 } __attribute__ ((packed));
82
83 typedef volatile struct grub_uhci_td *grub_uhci_td_t;
84 typedef volatile struct grub_uhci_qh *grub_uhci_qh_t;
85
86 struct grub_uhci
87 {
88 int iobase;
89 grub_uint32_t *framelist;
90
91 /* 256 Queue Heads. */
92 grub_uhci_qh_t qh;
93
94 /* 256 Transfer Descriptors. */
95 grub_uhci_td_t td;
96
97 /* Free Transfer Descriptors. */
98 grub_uhci_td_t tdfree;
99
100 struct grub_uhci *next;
101 };
102
103 static struct grub_uhci *uhci;
104
105 static grub_uint16_t
106 grub_uhci_readreg16 (struct grub_uhci *u, grub_uhci_reg_t reg)
107 {
108 return grub_inw (u->iobase + reg);
109 }
110
111 #if 0
112 static grub_uint32_t
113 grub_uhci_readreg32 (struct grub_uhci *u, grub_uhci_reg_t reg)
114 {
115 return grub_inl (u->iobase + reg);
116 }
117 #endif
118
119 static void
120 grub_uhci_writereg16 (struct grub_uhci *u,
121 grub_uhci_reg_t reg, grub_uint16_t val)
122 {
123 grub_outw (val, u->iobase + reg);
124 }
125
126 static void
127 grub_uhci_writereg32 (struct grub_uhci *u,
128 grub_uhci_reg_t reg, grub_uint32_t val)
129 {
130 grub_outl (val, u->iobase + reg);
131 }
132
133 static grub_err_t
134 grub_uhci_portstatus (grub_usb_controller_t dev,
135 unsigned int port, unsigned int enable);
136
137
138 /* Iterate over all PCI devices. Determine if a device is an UHCI
139 controller. If this is the case, initialize it. */
140 static int grub_uhci_pci_iter (int bus, int device, int func,
141 grub_pci_id_t pciid __attribute__((unused)))
142 {
143 grub_uint32_t class;
144 grub_uint32_t subclass;
145 grub_uint32_t base;
146 grub_uint32_t fp;
147 grub_pci_address_t addr;
148 struct grub_uhci *u;
149 int i;
150
151 addr = grub_pci_make_address (bus, device, func, 2);
152 class = grub_pci_read (addr);
153 addr = grub_pci_make_address (bus, device, func, 2);
154 class = grub_pci_read (addr);
155
156 subclass = (class >> 16) & 0xFF;
157 class >>= 24;
158
159 /* If this is not an UHCI controller, just return. */
160 if (class != 0x0c || subclass != 0x03)
161 return 0;
162
163 /* Determine IO base address. */
164 addr = grub_pci_make_address (bus, device, func, 8);
165 base = grub_pci_read (addr);
166 /* Stop if there is no IO space base address defined. */
167 if (! (base & 1))
168 return 0;
169
170 /* Allocate memory for the controller and register it. */
171 u = grub_malloc (sizeof (*u));
172 if (! u)
173 return 1;
174
175 u->next = uhci;
176 uhci = u;
177 u->iobase = base & GRUB_UHCI_IOMASK;
178 u->framelist = 0;
179 u->qh = 0;
180 u->td = 0;
181 grub_dprintf ("uhci", "class=0x%02x 0x%02x base=0x%x\n",
182 class, subclass, u->iobase);
183
184 /* Reserve a page for the frame list. */
185 u->framelist = grub_memalign (4096, 4096);
186 if (! u->framelist)
187 goto fail;
188
189 /* The framelist pointer of UHCI is only 32 bits, make sure this
190 code works on on 64 bits architectures. */
191 #if GRUB_CPU_SIZEOF_VOID_P == 8
192 if ((grub_uint64_t) u->framelist >> 32)
193 {
194 grub_error (GRUB_ERR_OUT_OF_MEMORY,
195 "allocated frame list memory not <4GB");
196 goto fail;
197 }
198 #endif
199
200 /* The QH pointer of UHCI is only 32 bits, make sure this
201 code works on on 64 bits architectures. */
202 u->qh = (grub_uhci_qh_t) grub_memalign (4096, 4096);
203 if (! u->qh)
204 goto fail;
205
206 #if GRUB_CPU_SIZEOF_VOID_P == 8
207 if ((grub_uint64_t) u->qh >> 32)
208 {
209 grub_error (GRUB_ERR_OUT_OF_MEMORY, "allocated QH memory not <4GB");
210 goto fail;
211 }
212 #endif
213
214 /* The TD pointer of UHCI is only 32 bits, make sure this
215 code works on on 64 bits architectures. */
216 u->td = (grub_uhci_td_t) grub_memalign (4096, 4096*2);
217 if (! u->td)
218 goto fail;
219
220 #if GRUB_CPU_SIZEOF_VOID_P == 8
221 if ((grub_uint64_t) u->td >> 32)
222 {
223 grub_error (GRUB_ERR_OUT_OF_MEMORY, "allocated TD memory not <4GB");
224 goto fail;
225 }
226 #endif
227
228 /* Link all Transfer Descriptors in a list of available Transfer
229 Descriptors. */
230 for (i = 0; i < 256; i++)
231 u->td[i].linkptr = (grub_uint32_t) &u->td[i + 1];
232 u->td[255 - 1].linkptr = 0;
233 u->tdfree = u->td;
234
235 /* Make sure UHCI is disabled! */
236 grub_uhci_writereg16 (u, GRUB_UHCI_REG_USBCMD, 0);
237
238 /* Setup the frame list pointers. Since no isochronous transfers
239 are and will be supported, they all point to the (same!) queue
240 head. */
241 fp = (grub_uint32_t) u->qh & (~15);
242 /* Mark this as a queue head. */
243 fp |= 2;
244 for (i = 0; i < 1024; i++)
245 u->framelist[i] = fp;
246 /* Program the framelist address into the UHCI controller. */
247 grub_uhci_writereg32 (u, GRUB_UHCI_REG_FLBASEADD,
248 (grub_uint32_t) u->framelist);
249
250 /* Make the Queue Heads point to eachother. */
251 for (i = 0; i < 256; i++)
252 {
253 /* Point to the next QH. */
254 u->qh[i].linkptr = (grub_uint32_t) (&u->qh[i + 1]) & (~15);
255
256 /* This is a QH. */
257 u->qh[i].linkptr |= GRUB_UHCI_LINK_QUEUE_HEAD;
258
259 /* For the moment, do not point to a Transfer Descriptor. These
260 are set at transfer time, so just terminate it. */
261 u->qh[i].elinkptr = 1;
262 }
263
264 /* The last Queue Head should terminate. 256 are too many QHs so
265 just use 50. */
266 u->qh[50 - 1].linkptr = 1;
267
268 /* Enable UHCI again. */
269 grub_uhci_writereg16 (u, GRUB_UHCI_REG_USBCMD, 1 | (1 << 7));
270
271 /* UHCI is initialized and ready for transfers. */
272 grub_dprintf ("uhci", "UHCI initialized\n");
273
274
275 #if 0
276 {
277 int i;
278 for (i = 0; i < 10; i++)
279 {
280 grub_uint16_t frnum;
281
282 frnum = grub_uhci_readreg16 (u, 6);
283 grub_dprintf ("uhci", "Framenum=%d\n", frnum);
284 grub_millisleep (100);
285 }
286 }
287 #endif
288
289 return 0;
290
291 fail:
292 if (u)
293 {
294 grub_free ((void *) u->qh);
295 grub_free (u->framelist);
296 }
297 grub_free (u);
298
299 return 1;
300 }
301
302 static void
303 grub_uhci_inithw (void)
304 {
305 grub_pci_iterate (grub_uhci_pci_iter);
306 }
307
308 static grub_uhci_td_t
309 grub_alloc_td (struct grub_uhci *u)
310 {
311 grub_uhci_td_t ret;
312
313 /* Check if there is a Transfer Descriptor available. */
314 if (! u->tdfree)
315 return NULL;
316
317 ret = u->tdfree;
318 u->tdfree = (grub_uhci_td_t) u->tdfree->linkptr;
319
320 return ret;
321 }
322
323 static void
324 grub_free_td (struct grub_uhci *u, grub_uhci_td_t td)
325 {
326 td->linkptr = (grub_uint32_t) u->tdfree;
327 u->tdfree = td;
328 }
329
330 static void
331 grub_free_queue (struct grub_uhci *u, grub_uhci_td_t td)
332 {
333 /* Free the TDs in this queue. */
334 while (td)
335 {
336 grub_uhci_td_t tdprev;
337
338 /* Unlink the queue. */
339 tdprev = td;
340 td = (grub_uhci_td_t) td->linkptr2;
341
342 /* Free the TD. */
343 grub_free_td (u, tdprev);
344 }
345 }
346
347 static grub_uhci_qh_t
348 grub_alloc_qh (struct grub_uhci *u,
349 grub_transaction_type_t tr __attribute__((unused)))
350 {
351 int i;
352 grub_uhci_qh_t qh;
353
354 /* Look for a Queue Head for this transfer. Skip the first QH if
355 this is a Interrupt Transfer. */
356 #if 0
357 if (tr == GRUB_USB_TRANSACTION_TYPE_INTERRUPT)
358 i = 0;
359 else
360 #endif
361 i = 1;
362
363 for (; i < 255; i++)
364 {
365 if (u->qh[i].elinkptr & 1)
366 break;
367 }
368 qh = &u->qh[i];
369 if (! (qh->elinkptr & 1))
370 {
371 grub_error (GRUB_ERR_OUT_OF_MEMORY,
372 "no free queue heads available");
373 return NULL;
374 }
375
376 return qh;
377 }
378
379 static grub_uhci_td_t
380 grub_uhci_transaction (struct grub_uhci *u, unsigned int endp,
381 grub_transfer_type_t type, unsigned int addr,
382 unsigned int toggle, grub_size_t size,
383 char *data)
384 {
385 grub_uhci_td_t td;
386 static const unsigned int tf[] = { 0x69, 0xE1, 0x2D };
387
388 /* XXX: Check if data is <4GB. If it isn't, just copy stuff around.
389 This is only relevant for 64 bits architectures. */
390
391 /* Grab a free Transfer Descriptor and initialize it. */
392 td = grub_alloc_td (u);
393 if (! td)
394 {
395 grub_error (GRUB_ERR_OUT_OF_MEMORY,
396 "no transfer descriptors available for UHCI transfer");
397 return 0;
398 }
399
400 grub_dprintf ("uhci",
401 "transaction: endp=%d, type=%d, addr=%d, toggle=%d, size=%d data=%p td=%p\n",
402 endp, type, addr, toggle, size, data, td);
403
404 /* Don't point to any TD, just terminate. */
405 td->linkptr = 1;
406
407 /* Active! Only retry a transfer 3 times. */
408 td->ctrl_status = (1 << 23) | (3 << 27);
409
410 /* If zero bytes are transmitted, size is 0x7FF. Otherwise size is
411 size-1. */
412 if (size == 0)
413 size = 0x7FF;
414 else
415 size = size - 1;
416
417 /* Setup whatever is required for the token packet. */
418 td->token = ((size << 21) | (toggle << 19) | (endp << 15)
419 | (addr << 8) | tf[type]);
420
421 td->buffer = (grub_uint32_t) data;
422
423 return td;
424 }
425
426 static grub_usb_err_t
427 grub_uhci_transfer (grub_usb_controller_t dev,
428 grub_usb_transfer_t transfer)
429 {
430 struct grub_uhci *u = (struct grub_uhci *) dev->data;
431 grub_uhci_qh_t qh;
432 grub_uhci_td_t td;
433 grub_uhci_td_t td_first = NULL;
434 grub_uhci_td_t td_prev = NULL;
435 grub_usb_err_t err = GRUB_USB_ERR_NONE;
436 int i;
437
438 /* Allocate a queue head for the transfer queue. */
439 qh = grub_alloc_qh (u, GRUB_USB_TRANSACTION_TYPE_CONTROL);
440 if (! qh)
441 return grub_errno;
442
443 for (i = 0; i < transfer->transcnt; i++)
444 {
445 grub_usb_transaction_t tr = &transfer->transactions[i];
446
447 td = grub_uhci_transaction (u, transfer->endpoint, tr->pid,
448 transfer->devaddr, tr->toggle,
449 tr->size, tr->data);
450 if (! td)
451 {
452 /* Terminate and free. */
453 td_prev->linkptr2 = 0;
454 td_prev->linkptr = 1;
455
456 if (td_first)
457 grub_free_queue (u, td_first);
458
459 return GRUB_USB_ERR_INTERNAL;
460 }
461
462 if (! td_first)
463 td_first = td;
464 else
465 {
466 td_prev->linkptr2 = (grub_uint32_t) td;
467 td_prev->linkptr = (grub_uint32_t) td;
468 td_prev->linkptr |= 4;
469 }
470 td_prev = td;
471 }
472 td_prev->linkptr2 = 0;
473 td_prev->linkptr = 1;
474
475 grub_dprintf ("uhci", "setup transaction %d\n", transfer->type);
476
477 /* Link it into the queue and terminate. Now the transaction can
478 take place. */
479 qh->elinkptr = (grub_uint32_t) td_first;
480
481 grub_dprintf ("uhci", "initiate transaction\n");
482
483 /* Wait until either the transaction completed or an error
484 occured. */
485 for (;;)
486 {
487 grub_uhci_td_t errtd;
488
489 errtd = (grub_uhci_td_t) (qh->elinkptr & ~0x0f);
490
491 grub_dprintf ("uhci", ">t status=0x%02x data=0x%02x td=%p\n",
492 errtd->ctrl_status, errtd->buffer & (~15), errtd);
493
494 /* Check if the transaction completed. */
495 if (qh->elinkptr & 1)
496 break;
497
498 grub_dprintf ("uhci", "t status=0x%02x\n", errtd->ctrl_status);
499
500 /* Check if the TD is not longer active. */
501 if (! (errtd->ctrl_status & (1 << 23)))
502 {
503 grub_dprintf ("uhci", ">>t status=0x%02x\n", errtd->ctrl_status);
504
505 /* Check if the endpoint is stalled. */
506 if (errtd->ctrl_status & (1 << 22))
507 err = GRUB_USB_ERR_STALL;
508
509 /* Check if an error related to the data buffer occured. */
510 if (errtd->ctrl_status & (1 << 21))
511 err = GRUB_USB_ERR_DATA;
512
513 /* Check if a babble error occured. */
514 if (errtd->ctrl_status & (1 << 20))
515 err = GRUB_USB_ERR_BABBLE;
516
517 /* Check if a NAK occured. */
518 if (errtd->ctrl_status & (1 << 19))
519 err = GRUB_USB_ERR_NAK;
520
521 /* Check if a timeout occured. */
522 if (errtd->ctrl_status & (1 << 18))
523 err = GRUB_USB_ERR_TIMEOUT;
524
525 /* Check if a bitstuff error occured. */
526 if (errtd->ctrl_status & (1 << 17))
527 err = GRUB_USB_ERR_BITSTUFF;
528
529 if (err)
530 goto fail;
531
532 /* Fall through, no errors occured, so the QH might be
533 updated. */
534 grub_dprintf ("uhci", "transaction fallthrough\n");
535 }
536 }
537
538 grub_dprintf ("uhci", "transaction complete\n");
539
540 fail:
541
542 grub_dprintf ("uhci", "transaction failed\n");
543
544 /* Place the QH back in the free list and deallocate the associated
545 TDs. */
546 qh->elinkptr = 1;
547 grub_free_queue (u, td_first);
548
549 return err;
550 }
551
552 static int
553 grub_uhci_iterate (int (*hook) (grub_usb_controller_t dev))
554 {
555 struct grub_uhci *u;
556 struct grub_usb_controller dev;
557
558 for (u = uhci; u; u = u->next)
559 {
560 dev.data = u;
561 if (hook (&dev))
562 return 1;
563 }
564
565 return 0;
566 }
567
568 static grub_err_t
569 grub_uhci_portstatus (grub_usb_controller_t dev,
570 unsigned int port, unsigned int enable)
571 {
572 struct grub_uhci *u = (struct grub_uhci *) dev->data;
573 int reg;
574 unsigned int status;
575
576 grub_dprintf ("uhci", "enable=%d port=%d\n", enable, port);
577
578 if (port == 0)
579 reg = GRUB_UHCI_REG_PORTSC1;
580 else if (port == 1)
581 reg = GRUB_UHCI_REG_PORTSC2;
582 else
583 return grub_error (GRUB_ERR_OUT_OF_RANGE,
584 "UHCI Root Hub port does not exist");
585
586 status = grub_uhci_readreg16 (u, reg);
587 grub_dprintf ("uhci", "detect=0x%02x\n", status);
588
589 /* Reset the port. */
590 grub_uhci_writereg16 (u, reg, enable << 9);
591
592 /* Wait for the reset to complete. XXX: How long exactly? */
593 grub_millisleep (10);
594 status = grub_uhci_readreg16 (u, reg);
595 grub_uhci_writereg16 (u, reg, status & ~(1 << 9));
596 grub_dprintf ("uhci", "reset completed\n");
597
598 /* Enable the port. */
599 grub_uhci_writereg16 (u, reg, enable << 2);
600 grub_millisleep (10);
601
602 grub_dprintf ("uhci", "waiting for the port to be enabled\n");
603
604 while (! (grub_uhci_readreg16 (u, reg) & (1 << 2)));
605
606 status = grub_uhci_readreg16 (u, reg);
607 grub_dprintf ("uhci", ">3detect=0x%02x\n", status);
608
609
610 return GRUB_ERR_NONE;
611 }
612
613 static grub_usb_speed_t
614 grub_uhci_detect_dev (grub_usb_controller_t dev, int port)
615 {
616 struct grub_uhci *u = (struct grub_uhci *) dev->data;
617 int reg;
618 unsigned int status;
619
620 if (port == 0)
621 reg = GRUB_UHCI_REG_PORTSC1;
622 else if (port == 1)
623 reg = GRUB_UHCI_REG_PORTSC2;
624 else
625 return grub_error (GRUB_ERR_OUT_OF_RANGE,
626 "UHCI Root Hub port does not exist");
627
628 status = grub_uhci_readreg16 (u, reg);
629
630 grub_dprintf ("uhci", "detect=0x%02x port=%d\n", status, port);
631
632 if (! (status & 1))
633 return GRUB_USB_SPEED_NONE;
634 else if (status & (1 << 8))
635 return GRUB_USB_SPEED_LOW;
636 else
637 return GRUB_USB_SPEED_FULL;
638 }
639
640 static int
641 grub_uhci_hubports (grub_usb_controller_t dev __attribute__((unused)))
642 {
643 /* The root hub has exactly two ports. */
644 return 2;
645 }
646
647 \f
648 static struct grub_usb_controller_dev usb_controller =
649 {
650 .name = "uhci",
651 .iterate = grub_uhci_iterate,
652 .transfer = grub_uhci_transfer,
653 .hubports = grub_uhci_hubports,
654 .portstatus = grub_uhci_portstatus,
655 .detect_dev = grub_uhci_detect_dev
656 };
657
658 GRUB_MOD_INIT(uhci)
659 {
660 grub_uhci_inithw ();
661 grub_usb_controller_dev_register (&usb_controller);
662 grub_dprintf ("uhci", "registed\n");
663 }
664
665 GRUB_MOD_FINI(uhci)
666 {
667 struct grub_uhci *u;
668
669 /* Disable all UHCI controllers. */
670 for (u = uhci; u; u = u->next)
671 grub_uhci_writereg16 (u, GRUB_UHCI_REG_USBCMD, 0);
672
673 /* Unregister the controller. */
674 grub_usb_controller_dev_unregister (&usb_controller);
675 }