Indentation fix, cleanup.
[AROS.git] / arch / all-pc / boot / grub2-aros / grub-core / bus / usb / uhci.c
blob7c5811fd643383db24273cf3f724ff6d39360219
1 /* uhci.c - UHCI Support. */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2008 Free Software Foundation, Inc.
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.
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.
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/>.
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/io.h>
27 #include <grub/time.h>
28 #include <grub/cpu/pci.h>
29 #include <grub/disk.h>
31 GRUB_MOD_LICENSE ("GPLv3+");
33 #define GRUB_UHCI_IOMASK (0x7FF << 5)
35 #define N_QH 256
36 #define N_TD 640
38 typedef enum
40 GRUB_UHCI_REG_USBCMD = 0x00,
41 GRUB_UHCI_REG_USBINTR = 0x04,
42 GRUB_UHCI_REG_FLBASEADD = 0x08,
43 GRUB_UHCI_REG_PORTSC1 = 0x10,
44 GRUB_UHCI_REG_PORTSC2 = 0x12,
45 GRUB_UHCI_REG_USBLEGSUP = 0xc0
46 } grub_uhci_reg_t;
48 enum
50 GRUB_UHCI_DETECT_CHANGED = (1 << 1),
51 GRUB_UHCI_DETECT_HAVE_DEVICE = 1,
52 GRUB_UHCI_DETECT_LOW_SPEED = (1 << 8)
55 /* R/WC legacy support bits */
56 enum
58 GRUB_UHCI_LEGSUP_END_A20GATE = (1 << 15),
59 GRUB_UHCI_TRAP_BY_64H_WSTAT = (1 << 11),
60 GRUB_UHCI_TRAP_BY_64H_RSTAT = (1 << 10),
61 GRUB_UHCI_TRAP_BY_60H_WSTAT = (1 << 9),
62 GRUB_UHCI_TRAP_BY_60H_RSTAT = (1 << 8)
65 /* Reset all legacy support - clear all R/WC bits and all R/W bits */
66 #define GRUB_UHCI_RESET_LEGSUP_SMI ( GRUB_UHCI_LEGSUP_END_A20GATE \
67 | GRUB_UHCI_TRAP_BY_64H_WSTAT \
68 | GRUB_UHCI_TRAP_BY_64H_RSTAT \
69 | GRUB_UHCI_TRAP_BY_60H_WSTAT \
70 | GRUB_UHCI_TRAP_BY_60H_RSTAT )
72 /* Some UHCI commands */
73 #define GRUB_UHCI_CMD_RUN_STOP (1 << 0)
74 #define GRUB_UHCI_CMD_HCRESET (1 << 1)
75 #define GRUB_UHCI_CMD_MAXP (1 << 7)
77 /* Important bits in structures */
78 #define GRUB_UHCI_LINK_TERMINATE 1
79 #define GRUB_UHCI_LINK_QUEUE_HEAD 2
81 enum
83 GRUB_UHCI_REG_PORTSC_CONNECT_CHANGED = 0x0002,
84 GRUB_UHCI_REG_PORTSC_PORT_ENABLED = 0x0004,
85 GRUB_UHCI_REG_PORTSC_RESUME = 0x0040,
86 GRUB_UHCI_REG_PORTSC_RESET = 0x0200,
87 GRUB_UHCI_REG_PORTSC_SUSPEND = 0x1000,
88 GRUB_UHCI_REG_PORTSC_RW = GRUB_UHCI_REG_PORTSC_PORT_ENABLED
89 | GRUB_UHCI_REG_PORTSC_RESUME | GRUB_UHCI_REG_PORTSC_RESET
90 | GRUB_UHCI_REG_PORTSC_SUSPEND,
91 /* These bits should not be written as 1 unless we really need it */
92 GRUB_UHCI_PORTSC_RWC = ((1 << 1) | (1 << 3) | (1 << 11) | (3 << 13))
95 /* UHCI Queue Head. */
96 struct grub_uhci_qh
98 /* Queue head link pointer which points to the next queue head. */
99 grub_uint32_t linkptr;
101 /* Queue element link pointer which points to the first data object
102 within the queue. */
103 grub_uint32_t elinkptr;
105 /* Queue heads are aligned on 16 bytes, pad so a queue head is 16
106 bytes so we can store many in a 4K page. */
107 grub_uint8_t pad[8];
108 } GRUB_PACKED;
110 /* UHCI Transfer Descriptor. */
111 struct grub_uhci_td
113 /* Pointer to the next TD in the list. */
114 grub_uint32_t linkptr;
116 /* Control and status bits. */
117 grub_uint32_t ctrl_status;
119 /* All information required to transfer the Token packet. */
120 grub_uint32_t token;
122 /* A pointer to the data buffer, UHCI requires this pointer to be 32
123 bits. */
124 grub_uint32_t buffer;
126 /* Another linkptr that is not overwritten by the Host Controller.
127 This is GRUB specific. */
128 grub_uint32_t linkptr2;
130 /* 3 additional 32 bits words reserved for the Host Controller Driver. */
131 grub_uint32_t data[3];
132 } GRUB_PACKED;
134 typedef volatile struct grub_uhci_td *grub_uhci_td_t;
135 typedef volatile struct grub_uhci_qh *grub_uhci_qh_t;
137 struct grub_uhci
139 grub_port_t iobase;
140 volatile grub_uint32_t *framelist_virt;
141 grub_uint32_t framelist_phys;
142 struct grub_pci_dma_chunk *framelist_chunk;
144 /* N_QH Queue Heads. */
145 struct grub_pci_dma_chunk *qh_chunk;
146 volatile grub_uhci_qh_t qh_virt;
147 grub_uint32_t qh_phys;
149 /* N_TD Transfer Descriptors. */
150 struct grub_pci_dma_chunk *td_chunk;
151 volatile grub_uhci_td_t td_virt;
152 grub_uint32_t td_phys;
154 /* Free Transfer Descriptors. */
155 grub_uhci_td_t tdfree;
157 int qh_busy[N_QH];
159 struct grub_uhci *next;
162 static struct grub_uhci *uhci;
164 static grub_uint16_t
165 grub_uhci_readreg16 (struct grub_uhci *u, grub_uhci_reg_t reg)
167 return grub_inw (u->iobase + reg);
170 #if 0
171 static grub_uint32_t
172 grub_uhci_readreg32 (struct grub_uhci *u, grub_uhci_reg_t reg)
174 return grub_inl (u->iobase + reg);
176 #endif
178 static void
179 grub_uhci_writereg16 (struct grub_uhci *u,
180 grub_uhci_reg_t reg, grub_uint16_t val)
182 grub_outw (val, u->iobase + reg);
185 static void
186 grub_uhci_writereg32 (struct grub_uhci *u,
187 grub_uhci_reg_t reg, grub_uint32_t val)
189 grub_outl (val, u->iobase + reg);
192 /* Iterate over all PCI devices. Determine if a device is an UHCI
193 controller. If this is the case, initialize it. */
194 static int
195 grub_uhci_pci_iter (grub_pci_device_t dev,
196 grub_pci_id_t pciid __attribute__((unused)),
197 void *data __attribute__ ((unused)))
199 grub_uint32_t class_code;
200 grub_uint32_t class;
201 grub_uint32_t subclass;
202 grub_uint32_t interf;
203 grub_uint32_t base;
204 grub_uint32_t fp;
205 grub_pci_address_t addr;
206 struct grub_uhci *u;
207 int i;
209 addr = grub_pci_make_address (dev, GRUB_PCI_REG_CLASS);
210 class_code = grub_pci_read (addr) >> 8;
212 interf = class_code & 0xFF;
213 subclass = (class_code >> 8) & 0xFF;
214 class = class_code >> 16;
216 /* If this is not an UHCI controller, just return. */
217 if (class != 0x0c || subclass != 0x03 || interf != 0x00)
218 return 0;
220 /* Determine IO base address. */
221 addr = grub_pci_make_address (dev, GRUB_PCI_REG_ADDRESS_REG4);
222 base = grub_pci_read (addr);
223 /* Stop if there is no IO space base address defined. */
224 if ((base & GRUB_PCI_ADDR_SPACE_MASK) != GRUB_PCI_ADDR_SPACE_IO)
225 return 0;
227 if ((base & GRUB_UHCI_IOMASK) == 0)
228 return 0;
230 /* Set bus master - needed for coreboot or broken BIOSes */
231 addr = grub_pci_make_address (dev, GRUB_PCI_REG_COMMAND);
232 grub_pci_write_word(addr, GRUB_PCI_COMMAND_IO_ENABLED
233 | GRUB_PCI_COMMAND_BUS_MASTER
234 | GRUB_PCI_COMMAND_MEM_ENABLED
235 | grub_pci_read_word (addr));
237 grub_dprintf ("uhci", "base = %x\n", base);
239 /* Allocate memory for the controller and register it. */
240 u = grub_zalloc (sizeof (*u));
241 if (! u)
242 return 1;
244 u->iobase = (base & GRUB_UHCI_IOMASK) + GRUB_MACHINE_PCI_IO_BASE;
246 /* Reset PIRQ and SMI */
247 addr = grub_pci_make_address (dev, GRUB_UHCI_REG_USBLEGSUP);
248 grub_pci_write_word(addr, GRUB_UHCI_RESET_LEGSUP_SMI);
249 /* Reset the HC */
250 grub_uhci_writereg16(u, GRUB_UHCI_REG_USBCMD, GRUB_UHCI_CMD_HCRESET);
251 grub_millisleep(5);
252 /* Disable interrupts and commands (just to be safe) */
253 grub_uhci_writereg16(u, GRUB_UHCI_REG_USBINTR, 0);
254 /* Finish HC reset, HC remains disabled */
255 grub_uhci_writereg16(u, GRUB_UHCI_REG_USBCMD, 0);
256 /* Read back to be sure PCI write is done */
257 grub_uhci_readreg16(u, GRUB_UHCI_REG_USBCMD);
259 /* Reserve a page for the frame list. */
260 u->framelist_chunk = grub_memalign_dma32 (4096, 4096);
261 if (! u->framelist_chunk)
262 goto fail;
263 u->framelist_virt = grub_dma_get_virt (u->framelist_chunk);
264 u->framelist_phys = grub_dma_get_phys (u->framelist_chunk);
266 grub_dprintf ("uhci",
267 "class=0x%02x 0x%02x interface 0x%02x base=0x%x framelist=%p\n",
268 class, subclass, interf, u->iobase, u->framelist_virt);
270 /* The QH pointer of UHCI is only 32 bits, make sure this
271 code works on on 64 bits architectures. */
272 u->qh_chunk = grub_memalign_dma32 (4096, sizeof(struct grub_uhci_qh) * N_QH);
273 if (! u->qh_chunk)
274 goto fail;
275 u->qh_virt = grub_dma_get_virt (u->qh_chunk);
276 u->qh_phys = grub_dma_get_phys (u->qh_chunk);
278 /* The TD pointer of UHCI is only 32 bits, make sure this
279 code works on on 64 bits architectures. */
280 u->td_chunk = grub_memalign_dma32 (4096, sizeof(struct grub_uhci_td) * N_TD);
281 if (! u->td_chunk)
282 goto fail;
283 u->td_virt = grub_dma_get_virt (u->td_chunk);
284 u->td_phys = grub_dma_get_phys (u->td_chunk);
286 grub_dprintf ("uhci", "QH=%p, TD=%p\n",
287 u->qh_virt, u->td_virt);
289 /* Link all Transfer Descriptors in a list of available Transfer
290 Descriptors. */
291 for (i = 0; i < N_TD; i++)
292 u->td_virt[i].linkptr = u->td_phys + (i + 1) * sizeof(struct grub_uhci_td);
293 u->td_virt[N_TD - 2].linkptr = 0;
294 u->tdfree = u->td_virt;
296 /* Setup the frame list pointers. Since no isochronous transfers
297 are and will be supported, they all point to the (same!) queue
298 head. */
299 fp = u->qh_phys & (~15);
300 /* Mark this as a queue head. */
301 fp |= 2;
302 for (i = 0; i < 1024; i++)
303 u->framelist_virt[i] = fp;
304 /* Program the framelist address into the UHCI controller. */
305 grub_uhci_writereg32 (u, GRUB_UHCI_REG_FLBASEADD, u->framelist_phys);
307 /* Make the Queue Heads point to each other. */
308 for (i = 0; i < N_QH; i++)
310 /* Point to the next QH. */
311 u->qh_virt[i].linkptr = ((u->qh_phys
312 + (i + 1) * sizeof(struct grub_uhci_qh))
313 & (~15));
315 /* This is a QH. */
316 u->qh_virt[i].linkptr |= GRUB_UHCI_LINK_QUEUE_HEAD;
318 /* For the moment, do not point to a Transfer Descriptor. These
319 are set at transfer time, so just terminate it. */
320 u->qh_virt[i].elinkptr = 1;
323 /* The last Queue Head should terminate. */
324 u->qh_virt[N_QH - 1].linkptr = 1;
326 /* Enable UHCI again. */
327 grub_uhci_writereg16 (u, GRUB_UHCI_REG_USBCMD,
328 GRUB_UHCI_CMD_RUN_STOP | GRUB_UHCI_CMD_MAXP);
330 /* UHCI is initialized and ready for transfers. */
331 grub_dprintf ("uhci", "UHCI initialized\n");
334 #if 0
336 int i;
337 for (i = 0; i < 10; i++)
339 grub_uint16_t frnum;
341 frnum = grub_uhci_readreg16 (u, 6);
342 grub_dprintf ("uhci", "Framenum=%d\n", frnum);
343 grub_millisleep (100);
346 #endif
348 /* Link to uhci now that initialisation is successful. */
349 u->next = uhci;
350 uhci = u;
352 return 0;
354 fail:
355 if (u)
357 grub_dma_free (u->qh_chunk);
358 grub_dma_free (u->framelist_chunk);
360 grub_free (u);
362 return 1;
365 static void
366 grub_uhci_inithw (void)
368 grub_pci_iterate (grub_uhci_pci_iter, NULL);
371 static grub_uhci_td_t
372 grub_alloc_td (struct grub_uhci *u)
374 grub_uhci_td_t ret;
376 /* Check if there is a Transfer Descriptor available. */
377 if (! u->tdfree)
378 return NULL;
380 ret = u->tdfree;
381 u->tdfree = grub_dma_phys2virt (u->tdfree->linkptr, u->td_chunk);
383 return ret;
386 static void
387 grub_free_td (struct grub_uhci *u, grub_uhci_td_t td)
389 td->linkptr = grub_dma_virt2phys (u->tdfree, u->td_chunk);
390 u->tdfree = td;
393 static void
394 grub_free_queue (struct grub_uhci *u, grub_uhci_qh_t qh, grub_uhci_td_t td,
395 grub_usb_transfer_t transfer, grub_size_t *actual)
397 int i; /* Index of TD in transfer */
399 u->qh_busy[qh - u->qh_virt] = 0;
401 *actual = 0;
403 /* Free the TDs in this queue and set last_trans. */
404 for (i=0; td; i++)
406 grub_uhci_td_t tdprev;
408 grub_dprintf ("uhci", "Freeing %p\n", td);
409 /* Check state of TD and possibly set last_trans */
410 if (transfer && (td->linkptr & 1))
411 transfer->last_trans = i;
413 *actual += (td->ctrl_status + 1) & 0x7ff;
415 /* Unlink the queue. */
416 tdprev = td;
417 if (!td->linkptr2)
418 td = 0;
419 else
420 td = grub_dma_phys2virt (td->linkptr2, u->td_chunk);
422 /* Free the TD. */
423 grub_free_td (u, tdprev);
427 static grub_uhci_qh_t
428 grub_alloc_qh (struct grub_uhci *u,
429 grub_transaction_type_t tr __attribute__((unused)))
431 int i;
432 grub_uhci_qh_t qh;
434 /* Look for a Queue Head for this transfer. Skip the first QH if
435 this is a Interrupt Transfer. */
436 #if 0
437 if (tr == GRUB_USB_TRANSACTION_TYPE_INTERRUPT)
438 i = 0;
439 else
440 #endif
441 i = 1;
443 for (; i < N_QH; i++)
445 if (!u->qh_busy[i])
446 break;
448 qh = &u->qh_virt[i];
449 if (i == N_QH)
451 grub_error (GRUB_ERR_OUT_OF_MEMORY,
452 "no free queue heads available");
453 return NULL;
456 u->qh_busy[qh - u->qh_virt] = 1;
458 return qh;
461 static grub_uhci_td_t
462 grub_uhci_transaction (struct grub_uhci *u, unsigned int endp,
463 grub_transfer_type_t type, unsigned int addr,
464 unsigned int toggle, grub_size_t size,
465 grub_uint32_t data, grub_usb_speed_t speed)
467 grub_uhci_td_t td;
468 static const unsigned int tf[] = { 0x69, 0xE1, 0x2D };
470 /* XXX: Check if data is <4GB. If it isn't, just copy stuff around.
471 This is only relevant for 64 bits architectures. */
473 /* Grab a free Transfer Descriptor and initialize it. */
474 td = grub_alloc_td (u);
475 if (! td)
477 grub_error (GRUB_ERR_OUT_OF_MEMORY,
478 "no transfer descriptors available for UHCI transfer");
479 return 0;
482 grub_dprintf ("uhci",
483 "transaction: endp=%d, type=%d, addr=%d, toggle=%d, size=%lu data=0x%x td=%p\n",
484 endp, type, addr, toggle, (unsigned long) size, data, td);
486 /* Don't point to any TD, just terminate. */
487 td->linkptr = 1;
489 /* Active! Only retry a transfer 3 times. */
490 td->ctrl_status = (1 << 23) | (3 << 27) |
491 ((speed == GRUB_USB_SPEED_LOW) ? (1 << 26) : 0);
493 /* If zero bytes are transmitted, size is 0x7FF. Otherwise size is
494 size-1. */
495 if (size == 0)
496 size = 0x7FF;
497 else
498 size = size - 1;
500 /* Setup whatever is required for the token packet. */
501 td->token = ((size << 21) | (toggle << 19) | (endp << 15)
502 | (addr << 8) | tf[type]);
504 td->buffer = data;
506 return td;
509 struct grub_uhci_transfer_controller_data
511 grub_uhci_qh_t qh;
512 grub_uhci_td_t td_first;
515 static grub_usb_err_t
516 grub_uhci_setup_transfer (grub_usb_controller_t dev,
517 grub_usb_transfer_t transfer)
519 struct grub_uhci *u = (struct grub_uhci *) dev->data;
520 grub_uhci_td_t td;
521 grub_uhci_td_t td_prev = NULL;
522 int i;
523 struct grub_uhci_transfer_controller_data *cdata;
525 cdata = grub_malloc (sizeof (*cdata));
526 if (!cdata)
527 return GRUB_USB_ERR_INTERNAL;
529 cdata->td_first = NULL;
531 /* Allocate a queue head for the transfer queue. */
532 cdata->qh = grub_alloc_qh (u, GRUB_USB_TRANSACTION_TYPE_CONTROL);
533 if (! cdata->qh)
535 grub_free (cdata);
536 return GRUB_USB_ERR_INTERNAL;
539 grub_dprintf ("uhci", "transfer, iobase:%08x\n", u->iobase);
541 for (i = 0; i < transfer->transcnt; i++)
543 grub_usb_transaction_t tr = &transfer->transactions[i];
545 td = grub_uhci_transaction (u, transfer->endpoint & 15, tr->pid,
546 transfer->devaddr, tr->toggle,
547 tr->size, tr->data,
548 transfer->dev->speed);
549 if (! td)
551 grub_size_t actual = 0;
552 /* Terminate and free. */
553 if (td_prev)
555 td_prev->linkptr2 = 0;
556 td_prev->linkptr = 1;
559 if (cdata->td_first)
560 grub_free_queue (u, cdata->qh, cdata->td_first, NULL, &actual);
562 grub_free (cdata);
563 return GRUB_USB_ERR_INTERNAL;
566 if (! cdata->td_first)
567 cdata->td_first = td;
568 else
570 td_prev->linkptr2 = grub_dma_virt2phys (td, u->td_chunk);
571 td_prev->linkptr = grub_dma_virt2phys (td, u->td_chunk);
572 td_prev->linkptr |= 4;
574 td_prev = td;
576 td_prev->linkptr2 = 0;
577 td_prev->linkptr = 1;
579 grub_dprintf ("uhci", "setup transaction %d\n", transfer->type);
581 /* Link it into the queue and terminate. Now the transaction can
582 take place. */
583 cdata->qh->elinkptr = grub_dma_virt2phys (cdata->td_first, u->td_chunk);
585 grub_dprintf ("uhci", "initiate transaction\n");
587 transfer->controller_data = cdata;
589 return GRUB_USB_ERR_NONE;
592 static grub_usb_err_t
593 grub_uhci_check_transfer (grub_usb_controller_t dev,
594 grub_usb_transfer_t transfer,
595 grub_size_t *actual)
597 struct grub_uhci *u = (struct grub_uhci *) dev->data;
598 grub_uhci_td_t errtd;
599 struct grub_uhci_transfer_controller_data *cdata = transfer->controller_data;
601 *actual = 0;
603 if (cdata->qh->elinkptr & ~0x0f)
604 errtd = grub_dma_phys2virt (cdata->qh->elinkptr & ~0x0f, u->qh_chunk);
605 else
606 errtd = 0;
608 if (errtd)
610 grub_dprintf ("uhci", ">t status=0x%02x data=0x%02x td=%p, %x\n",
611 errtd->ctrl_status, errtd->buffer & (~15), errtd,
612 cdata->qh->elinkptr);
615 /* Check if the transaction completed. */
616 if (cdata->qh->elinkptr & 1)
618 grub_dprintf ("uhci", "transaction complete\n");
620 /* Place the QH back in the free list and deallocate the associated
621 TDs. */
622 cdata->qh->elinkptr = 1;
623 grub_free_queue (u, cdata->qh, cdata->td_first, transfer, actual);
624 grub_free (cdata);
625 return GRUB_USB_ERR_NONE;
628 if (errtd && !(errtd->ctrl_status & (1 << 23)))
630 grub_usb_err_t err = GRUB_USB_ERR_NONE;
632 /* Check if the endpoint is stalled. */
633 if (errtd->ctrl_status & (1 << 22))
634 err = GRUB_USB_ERR_STALL;
636 /* Check if an error related to the data buffer occurred. */
637 else if (errtd->ctrl_status & (1 << 21))
638 err = GRUB_USB_ERR_DATA;
640 /* Check if a babble error occurred. */
641 else if (errtd->ctrl_status & (1 << 20))
642 err = GRUB_USB_ERR_BABBLE;
644 /* Check if a NAK occurred. */
645 else if (errtd->ctrl_status & (1 << 19))
646 err = GRUB_USB_ERR_NAK;
648 /* Check if a timeout occurred. */
649 else if (errtd->ctrl_status & (1 << 18))
650 err = GRUB_USB_ERR_TIMEOUT;
652 /* Check if a bitstuff error occurred. */
653 else if (errtd->ctrl_status & (1 << 17))
654 err = GRUB_USB_ERR_BITSTUFF;
656 if (err)
658 grub_dprintf ("uhci", "transaction failed\n");
660 /* Place the QH back in the free list and deallocate the associated
661 TDs. */
662 cdata->qh->elinkptr = 1;
663 grub_free_queue (u, cdata->qh, cdata->td_first, transfer, actual);
664 grub_free (cdata);
666 return err;
670 /* Fall through, no errors occurred, so the QH might be
671 updated. */
672 grub_dprintf ("uhci", "transaction fallthrough\n");
674 return GRUB_USB_ERR_WAIT;
677 static grub_usb_err_t
678 grub_uhci_cancel_transfer (grub_usb_controller_t dev,
679 grub_usb_transfer_t transfer)
681 struct grub_uhci *u = (struct grub_uhci *) dev->data;
682 grub_size_t actual;
683 struct grub_uhci_transfer_controller_data *cdata = transfer->controller_data;
685 grub_dprintf ("uhci", "transaction cancel\n");
687 /* Place the QH back in the free list and deallocate the associated
688 TDs. */
689 cdata->qh->elinkptr = 1;
690 grub_free_queue (u, cdata->qh, cdata->td_first, transfer, &actual);
691 grub_free (cdata);
693 return GRUB_USB_ERR_NONE;
696 static int
697 grub_uhci_iterate (grub_usb_controller_iterate_hook_t hook, void *hook_data)
699 struct grub_uhci *u;
700 struct grub_usb_controller dev;
702 for (u = uhci; u; u = u->next)
704 dev.data = u;
705 if (hook (&dev, hook_data))
706 return 1;
709 return 0;
712 static grub_usb_err_t
713 grub_uhci_portstatus (grub_usb_controller_t dev,
714 unsigned int port, unsigned int enable)
716 struct grub_uhci *u = (struct grub_uhci *) dev->data;
717 int reg;
718 unsigned int status;
719 grub_uint64_t endtime;
721 grub_dprintf ("uhci", "portstatus, iobase:%08x\n", u->iobase);
723 grub_dprintf ("uhci", "enable=%d port=%d\n", enable, port);
725 if (port == 0)
726 reg = GRUB_UHCI_REG_PORTSC1;
727 else if (port == 1)
728 reg = GRUB_UHCI_REG_PORTSC2;
729 else
730 return GRUB_USB_ERR_INTERNAL;
732 status = grub_uhci_readreg16 (u, reg);
733 grub_dprintf ("uhci", "detect=0x%02x\n", status);
735 if (!enable) /* We don't need reset port */
737 /* Disable the port. */
738 grub_uhci_writereg16 (u, reg, 0 << 2);
739 grub_dprintf ("uhci", "waiting for the port to be disabled\n");
740 endtime = grub_get_time_ms () + 1000;
741 while ((grub_uhci_readreg16 (u, reg) & (1 << 2)))
742 if (grub_get_time_ms () > endtime)
743 return GRUB_USB_ERR_TIMEOUT;
745 status = grub_uhci_readreg16 (u, reg);
746 grub_dprintf ("uhci", ">3detect=0x%02x\n", status);
747 return GRUB_USB_ERR_NONE;
750 /* Reset the port. */
751 status = grub_uhci_readreg16 (u, reg) & ~GRUB_UHCI_PORTSC_RWC;
752 grub_uhci_writereg16 (u, reg, status | (1 << 9));
753 grub_uhci_readreg16 (u, reg); /* Ensure it is writen... */
755 /* Wait for the reset to complete. XXX: How long exactly? */
756 grub_millisleep (50); /* For root hub should be nominaly 50ms */
757 status = grub_uhci_readreg16 (u, reg) & ~GRUB_UHCI_PORTSC_RWC;
758 grub_uhci_writereg16 (u, reg, status & ~(1 << 9));
759 grub_uhci_readreg16 (u, reg); /* Ensure it is writen... */
761 /* Note: some debug prints were removed because they affected reset/enable timing. */
763 grub_millisleep (1); /* Probably not needed at all or only few microsecs. */
765 /* Reset bits Connect & Enable Status Change */
766 status = grub_uhci_readreg16 (u, reg) & ~GRUB_UHCI_PORTSC_RWC;
767 grub_uhci_writereg16 (u, reg, status | (1 << 3) | GRUB_UHCI_REG_PORTSC_CONNECT_CHANGED);
768 grub_uhci_readreg16 (u, reg); /* Ensure it is writen... */
770 /* Enable the port. */
771 status = grub_uhci_readreg16 (u, reg) & ~GRUB_UHCI_PORTSC_RWC;
772 grub_uhci_writereg16 (u, reg, status | (1 << 2));
773 grub_uhci_readreg16 (u, reg); /* Ensure it is writen... */
775 endtime = grub_get_time_ms () + 1000;
776 while (! ((status = grub_uhci_readreg16 (u, reg)) & (1 << 2)))
777 if (grub_get_time_ms () > endtime)
778 return GRUB_USB_ERR_TIMEOUT;
780 /* Reset recovery time */
781 grub_millisleep (10);
783 /* Read final port status */
784 status = grub_uhci_readreg16 (u, reg);
785 grub_dprintf ("uhci", ">3detect=0x%02x\n", status);
788 return GRUB_USB_ERR_NONE;
791 static grub_usb_speed_t
792 grub_uhci_detect_dev (grub_usb_controller_t dev, int port, int *changed)
794 struct grub_uhci *u = (struct grub_uhci *) dev->data;
795 int reg;
796 unsigned int status;
798 grub_dprintf ("uhci", "detect_dev, iobase:%08x\n", u->iobase);
800 if (port == 0)
801 reg = GRUB_UHCI_REG_PORTSC1;
802 else if (port == 1)
803 reg = GRUB_UHCI_REG_PORTSC2;
804 else
805 return GRUB_USB_SPEED_NONE;
807 status = grub_uhci_readreg16 (u, reg);
809 grub_dprintf ("uhci", "detect=0x%02x port=%d\n", status, port);
811 /* Connect Status Change bit - it detects change of connection */
812 if (status & GRUB_UHCI_DETECT_CHANGED)
814 *changed = 1;
815 /* Reset bit Connect Status Change */
816 grub_uhci_writereg16 (u, reg, (status & GRUB_UHCI_REG_PORTSC_RW)
817 | GRUB_UHCI_REG_PORTSC_CONNECT_CHANGED);
819 else
820 *changed = 0;
822 if (! (status & GRUB_UHCI_DETECT_HAVE_DEVICE))
823 return GRUB_USB_SPEED_NONE;
824 else if (status & GRUB_UHCI_DETECT_LOW_SPEED)
825 return GRUB_USB_SPEED_LOW;
826 else
827 return GRUB_USB_SPEED_FULL;
830 static int
831 grub_uhci_hubports (grub_usb_controller_t dev __attribute__((unused)))
833 /* The root hub has exactly two ports. */
834 return 2;
838 static struct grub_usb_controller_dev usb_controller =
840 .name = "uhci",
841 .iterate = grub_uhci_iterate,
842 .setup_transfer = grub_uhci_setup_transfer,
843 .check_transfer = grub_uhci_check_transfer,
844 .cancel_transfer = grub_uhci_cancel_transfer,
845 .hubports = grub_uhci_hubports,
846 .portstatus = grub_uhci_portstatus,
847 .detect_dev = grub_uhci_detect_dev,
848 /* estimated max. count of TDs for one bulk transfer */
849 .max_bulk_tds = N_TD * 3 / 4
852 GRUB_MOD_INIT(uhci)
854 grub_stop_disk_firmware ();
856 grub_uhci_inithw ();
857 grub_usb_controller_dev_register (&usb_controller);
858 grub_dprintf ("uhci", "registered\n");
861 GRUB_MOD_FINI(uhci)
863 struct grub_uhci *u;
865 /* Disable all UHCI controllers. */
866 for (u = uhci; u; u = u->next)
867 grub_uhci_writereg16 (u, GRUB_UHCI_REG_USBCMD, 0);
869 /* Unregister the controller. */
870 grub_usb_controller_dev_unregister (&usb_controller);