grub2: bring back build of aros-side grub2 tools
[AROS.git] / workbench / devs / USB / drivers / UHCI / hardware.c
blob66343d4ce44cb43c33b4148526b175aa1c45c6dc
1 /*
2 Copyright (C) 2006 by Michal Schulz
3 $Id$
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with this program; if not, write to the
17 Free Software Foundation, Inc.,
18 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 #define DEBUG 0
23 #include <inttypes.h>
25 #include <aros/symbolsets.h>
27 #include <aros/debug.h>
29 #include <exec/types.h>
30 #include <oop/oop.h>
32 #include <devices/timer.h>
34 #include <hidd/hidd.h>
35 #include <hidd/pci.h>
37 #include <usb/usb.h>
39 #include <asm/io.h>
41 #include <proto/oop.h>
42 #include <proto/utility.h>
44 #include "uhci.h"
46 //#define ENABLE_RECLAIM_BANDWIDTH 1
48 void uhci_sleep(OOP_Class *cl, OOP_Object *o, uint32_t msec)
50 UHCIData *uhci = OOP_INST_DATA(cl, o);
52 uhci->tr->tr_node.io_Command = TR_ADDREQUEST;
53 uhci->tr->tr_time.tv_secs = msec / 1000;
54 uhci->tr->tr_time.tv_micro = 1000 * (msec % 1000);
56 uhci->tr->tr_node.io_Message.mn_ReplyPort->mp_SigTask = FindTask(NULL);
58 DoIO((struct IORequest *)uhci->tr);
62 * This function allocates a new 16-byte Transfer Descriptor from the
63 * pool of 4K-aligned PCI-accessible memory regions. Within each 4K page,
64 * a bitmap is used to determine, which of the TD elements are available
65 * for use.
67 * This function returns NULL if no free TD's are found and no more memory
68 * is available.
70 UHCI_TransferDesc *uhci_AllocTD(OOP_Class *cl, OOP_Object *o)
72 UHCIData *uhci = OOP_INST_DATA(cl, o);
73 struct TDNode *n;
74 uint32_t node_num = 32;
75 uint32_t bmp_pos = 8;
77 Disable();
79 /* Walk through the list of already available 4K pages */
80 ForeachNode(&SD(cl)->td_list, n)
83 * For each 4K page, search the first free node (cleared bit) and alloc it.
85 for (bmp_pos=0; bmp_pos < 8; bmp_pos++)
87 if (n->td_Bitmap[bmp_pos] != 0xffffffff)
89 for (node_num = 0; node_num < 32; node_num++)
91 if (!(n->td_Bitmap[bmp_pos] & (1 << node_num)))
93 UHCI_TransferDesc * td = (UHCI_TransferDesc *)&n->td_Page[(bmp_pos*32 + node_num) * 16];
94 /* Mark the TD as used and return a pointer to it */
95 n->td_Bitmap[bmp_pos] |= 1 << node_num;
97 Enable();
99 return td;
107 * No free TDs have been found on the list of 4K pages. Create new Page node
108 * and alloc 4K PCI accessible memory region for it
110 if ((n = AllocPooled(SD(cl)->MemPool, sizeof(struct TDNode))))
112 if ((n->td_Page = HIDD_PCIDriver_AllocPCIMem(uhci->pciDriver, 4096)))
114 /* Make 4K node available for future allocations */
115 AddHead(&SD(cl)->td_list, (struct Node*)n);
116 UHCI_TransferDesc * td = (UHCI_TransferDesc *)(UHCI_TransferDesc *)&n->td_Page[0];
118 /* Mark first TD as used and return a pointer to it */
119 n->td_Bitmap[0] |= 1;
121 Enable();
123 return td;
125 FreePooled(SD(cl)->MemPool, n, sizeof(struct TDNode));
128 Enable();
130 /* Everything failed? Out of memory, most likely */
131 return NULL;
135 * This function allocates a new 8-bit Queue Header aligned at the 16-byte boundary.
136 * See uhci_AllocTD for more details.
138 UHCI_QueueHeader *uhci_AllocQH(OOP_Class *cl, OOP_Object *o)
141 * Since the Queue Headers have to be aligned at the 16-byte boundary, they may
142 * be allocated from the same pool TD's do
144 return (UHCI_QueueHeader *)uhci_AllocTD(cl, o);
148 * Mark the Transfer Descriptor free, so that it may be allocated by another one.
149 * A quick version which may be called from interrupts.
151 void uhci_FreeTDQuick(UHCIData *uhci, UHCI_TransferDesc *td)
153 struct TDNode *t;
154 /* We're inside interrupt probably. Don't ObtainSemaphore. Just lock interrupts instead */
155 Disable();
157 /* traverse through the list of 4K pages */
158 ForeachNode(&uhci->sd->td_list, t)
160 /* Address match? */
161 if ((IPTR)t->td_Page == ((IPTR)td & ~0xfff))
163 /* extract the correct location of the TD within the bitmap */
164 int bmp = (((IPTR)td & 0xe00) >> 9);
165 int node = (((IPTR)td & 0x1f0) >> 4);
167 /* Free the node */
168 t->td_Bitmap[bmp] &= ~(1 << node);
170 break;
174 Enable();
177 void uhci_FreeQHQuick(UHCIData *uhci, UHCI_QueueHeader *qh)
179 uhci_FreeTDQuick(uhci, (UHCI_TransferDesc *)qh);
183 * Mark the Transfer Descriptor free, so that it may be allocated by another one.
184 * If the 4K page contains no used descriptors, the page will be freed
186 void uhci_FreeTD(OOP_Class *cl, OOP_Object *o, UHCI_TransferDesc *td)
188 struct TDNode *t, *next;
189 UHCIData *uhci = OOP_INST_DATA(cl, o);
191 Disable();
193 /* traverse through the list of 4K pages */
194 ForeachNodeSafe(&SD(cl)->td_list, t, next)
196 /* Address match? */
197 if ((IPTR)t->td_Page == ((IPTR)td & ~0xfff))
199 /* extract the correct location of the TD within the bitmap */
200 int bmp = (((IPTR)td & 0xe00) >> 9);
201 int node = (((IPTR)td & 0x1f0) >> 4);
203 /* Free the node */
204 t->td_Bitmap[bmp] &= ~(1 << node);
206 /* Check if all TD nodes are free within the 4K page */
207 int i;
208 for (i=0; i < 8; i++)
209 if (t->td_Bitmap[i] != 0)
210 break;
212 /* So it is. Free the 4K page */
213 if (i==8)
215 Remove((struct Node*)t);
216 HIDD_PCIDriver_FreePCIMem(uhci->pciDriver, t->td_Page);
217 FreePooled(SD(cl)->MemPool, t, sizeof(struct TDNode));
220 break;
223 Enable();
226 void uhci_FreeQH(OOP_Class *cl, OOP_Object *o, UHCI_QueueHeader *qh)
228 uhci_FreeTD(cl, o, (UHCI_TransferDesc *)qh);
231 void uhci_globalreset(OOP_Class *cl, OOP_Object *o)
233 UHCIData *uhci = OOP_INST_DATA(cl, o);
235 outw(UHCI_CMD_GRESET, uhci->iobase + UHCI_CMD);
236 uhci_sleep(cl, o, USB_BUS_RESET_DELAY);
237 outw(0, uhci->iobase + UHCI_CMD);
240 void uhci_reset(OOP_Class *cl, OOP_Object *o)
242 UHCIData *uhci = OOP_INST_DATA(cl, o);
243 int n;
245 outw(UHCI_CMD_HCRESET, uhci->iobase + UHCI_CMD);
246 for (n=0; n < UHCI_RESET_TIMEOUT && (inw(uhci->iobase + UHCI_CMD) & UHCI_CMD_HCRESET); n++)
247 uhci_sleep(cl, o, 10);
249 if (n >= UHCI_RESET_TIMEOUT)
250 D(bug("[UHCI] Device did not reset properly\n"));
253 BOOL uhci_run(OOP_Class *cl, OOP_Object *o, BOOL run)
255 UHCIData *uhci = OOP_INST_DATA(cl, o);
256 BOOL running;
257 uint16_t cmd;
258 int n;
260 cmd = inw(uhci->iobase + UHCI_CMD);
261 if (run)
262 cmd |= UHCI_CMD_RS;
263 else
264 cmd &= ~UHCI_CMD_RS;
266 outw(cmd, uhci->iobase + UHCI_CMD);
268 for (n=0; n < 10; n++)
270 running = !(inw(uhci->iobase + UHCI_STS) & UHCI_STS_HCH);
272 if (run == running)
274 D(bug("[UHCI] %s done. cmd=%04x, sts=%04x\n",
275 run ? "start":"stop", inw(uhci->iobase + UHCI_CMD),
276 inw(uhci->iobase + UHCI_STS)));
278 return TRUE;
281 uhci_sleep(cl, o, 10);
284 D(bug("[UHCI] Failed to change the running state\n"));
285 return FALSE;
288 void uhci_RebuildList(OOP_Class *cl, OOP_Object *o)
290 UHCIData *uhci = OOP_INST_DATA(cl, o);
291 UHCI_Pipe *p;
292 UHCI_QueueHeader *qh, *first_fast = NULL;
294 qh = uhci->qh01;
297 * If low speed control list is not empty, iterate through all its elements
298 * and link them linear using the qh pointer
300 if (!IsListEmpty(&uhci->ControlLS))
302 ForeachNode(&uhci->ControlLS, p)
305 /* The successor QH's horizontal link should point to end of the list
306 * as long as the node is not linked properly. This way we guarantee,
307 * that the list of QH's may be always executed */
309 p->p_Queue->qh_HLink = UHCI_PTR_T;
311 qh->qh_HLink = (uint32_t)p->p_Queue | UHCI_PTR_QH;
312 qh = (UHCI_QueueHeader *)p->p_Queue;
316 if (!IsListEmpty(&uhci->ControlFS))
318 first_fast = (UHCI_QueueHeader *)((UHCI_Pipe *)(GetHead(&uhci->ControlFS)))->p_Queue;
320 ForeachNode(&uhci->ControlFS, p)
322 p->p_Queue->qh_HLink = UHCI_PTR_T;
323 qh->qh_HLink = (uint32_t)p->p_Queue | UHCI_PTR_QH;
324 qh = (UHCI_QueueHeader *)p->p_Queue;
328 if (!IsListEmpty(&uhci->Bulk))
330 if (!first_fast)
331 first_fast = (UHCI_QueueHeader *)((UHCI_Pipe *)(GetHead(&uhci->Bulk)))->p_Queue;
333 ForeachNode(&uhci->Bulk, p)
335 p->p_Queue->qh_HLink = UHCI_PTR_T;
336 qh->qh_HLink = (uint32_t)p->p_Queue | UHCI_PTR_QH;
337 qh = (UHCI_QueueHeader *)p->p_Queue;
342 * If the first fast node exists, make a loop of FullSpeed control and bulk queue
343 * headers, in order to reclaim the bandwidth (since all bulk QH's are executed by
344 * bredth first).
346 #ifdef ENABLE_RECLAIM_BANDWIDTH
347 if (first_fast)
349 qh->qh_HLink = (uint32_t)first_fast | UHCI_PTR_QH;
351 else
353 qh->qh_HLink = UHCI_PTR_T;
355 #else
356 qh->qh_HLink = UHCI_PTR_T;
357 #endif
360 void uhci_DeletePipe(OOP_Class *cl, OOP_Object *o, UHCI_Pipe *pipe)
362 D(bug("[UHCI] DeletePipe(%p)\n", pipe));
364 if (pipe)
366 UHCI_TransferDesc *td = (UHCI_TransferDesc *)pipe->p_FirstTD;
368 /* Lock interrupts */
369 Disable();
370 /* Remove the pipe from transfer list and rebuild the lists */
371 Remove((struct Node*)pipe);
372 uhci_RebuildList(cl, o);
373 Enable();
375 /* FIXME: Don't delay. Just wait for the incomplete TD's */
376 //Delay(1);
378 /* At this stage the transfer nodes may be safely deleted from the queue */
379 while ((uint32_t)td != UHCI_PTR_T)
381 UHCI_TransferDesc *tnext = (UHCI_TransferDesc *)(td->td_LinkPtr & 0xfffffff1);
382 uhci_FreeTD(cl, o, td);
383 td = tnext;
386 pipe->p_Timeout->tr_node.io_Message.mn_ReplyPort->mp_SigBit = AllocSignal(-1);
387 CloseDevice((struct IORequest *)pipe->p_Timeout);
388 DeleteMsgPort(pipe->p_Timeout->tr_node.io_Message.mn_ReplyPort);
389 DeleteIORequest((struct IORequest *)pipe->p_Timeout);
391 FreePooled(SD(cl)->MemPool, pipe, sizeof(UHCI_Pipe));
395 void uhci_InsertIntr(UHCIData *uhci, UHCI_Pipe *pipe)
397 UHCI_QueueHeader **q;
398 uint8_t count, i, minimum, bestat;
400 (bug("[UHCI] Inserting Interrupt queue %p with period %d\n", pipe, pipe->p_Interval));
402 if (pipe->p_Interval < 2)
404 q = &uhci->qh01;
405 count = 1;
407 else if (pipe->p_Interval < 4)
409 q = uhci->qh02;
410 count = 2;
412 else if (pipe->p_Interval < 8)
414 q = uhci->qh04;
415 count = 4;
417 else if (pipe->p_Interval < 16)
419 q = uhci->qh08;
420 count = 8;
422 else if (pipe->p_Interval < 32)
424 q = uhci->qh16;
425 count = 16;
427 else
429 q = uhci->qh32;
430 count = 32;
433 i=0;
434 minimum = q[0]->qh_Data2;
435 bestat = 0;
436 do {
437 if (minimum > q[i]->qh_Data2)
439 minimum = q[i]->qh_Data2;
440 bestat = i;
442 } while (++i < count);
444 (bug("[UHCI] Best node (%d uses) %d from %d\n", minimum, bestat, count));
446 pipe->p_QHNode = bestat;
447 pipe->p_QHLocation = count;
449 q[bestat]->qh_Data2++;
451 pipe->p_Queue->qh_VLink = q[bestat]->qh_VLink;
452 pipe->p_Queue->qh_HLink = q[bestat]->qh_HLink;
453 q[bestat]->qh_VLink = ((uint32_t)pipe->p_Queue) | UHCI_PTR_QH;
456 UHCI_Pipe *uhci_CreatePipe(OOP_Class *cl, OOP_Object *o, enum USB_PipeType type, BOOL fullspeed,
457 uint8_t addr, uint8_t endp, uint8_t period, uint32_t maxp, uint32_t timeout)
459 UHCIData *uhci = OOP_INST_DATA(cl, o);
460 UHCI_Pipe *pipe;
462 pipe = AllocPooled(SD(cl)->MemPool, sizeof(UHCI_Pipe));
464 (bug("[UHCI] CreatePipe(%d, %d, %d, %d, %d)\n",
465 type, fullspeed, addr, endp, maxp));
467 if (pipe)
469 pipe->p_Queue = uhci_AllocQH(cl, o);
471 pipe->p_Type = type;
472 pipe->p_FullSpeed = fullspeed;
473 pipe->p_NextToggle = 0;
474 pipe->p_DevAddr = addr;
475 pipe->p_EndPoint = endp;
476 pipe->p_MaxTransfer = maxp;
477 pipe->p_Interval = period;
478 pipe->p_FirstTD = (APTR)UHCI_PTR_T;
479 pipe->p_LastTD = (APTR)UHCI_PTR_T;
480 pipe->p_Queue->qh_VLink = UHCI_PTR_T;
481 pipe->p_Queue->qh_Data1 = (IPTR)pipe;
482 pipe->p_Queue->qh_Data2 = 0;
484 NEWLIST(&pipe->p_Intr);
486 pipe->p_TimeoutVal = timeout;
487 pipe->p_Timeout = (struct timerequest *)CreateIORequest(
488 CreateMsgPort(), sizeof(struct timerequest));
490 FreeSignal(pipe->p_Timeout->tr_node.io_Message.mn_ReplyPort->mp_SigBit);
491 OpenDevice((STRPTR)"timer.device", UNIT_MICROHZ, (struct IORequest *)pipe->p_Timeout, 0);
493 /* According to the pipe's type, add it to proper list */
494 switch (type)
496 case PIPE_Bulk:
497 AddTail((struct List*)&uhci->Bulk, (struct Node*)pipe);
498 break;
500 case PIPE_Control:
501 if (fullspeed)
502 AddTail((struct List*)&uhci->ControlFS, (struct Node*)pipe);
503 else
504 AddTail((struct List*)&uhci->ControlLS, (struct Node*)pipe);
505 break;
507 case PIPE_Isochronous:
508 AddTail((struct List*)&uhci->Isochronous, (struct Node*)pipe);
509 break;
511 case PIPE_Interrupt:
512 uhci_InsertIntr(uhci, pipe);
513 AddTail((struct List*)&uhci->Interrupts, (struct Node*)pipe);
514 break;
517 uhci_RebuildList(cl, o);
520 return pipe;
523 void uhci_QueuedTransfer(OOP_Class *cl, OOP_Object *o, UHCI_Pipe *pipe, VOID *buffer, uint32_t length, BOOL in)
525 uint8_t *ptr = (uint8_t*)buffer;
526 UHCI_TransferDesc *td=NULL, *t=NULL;
528 uint8_t dt = pipe->p_NextToggle;
529 uint32_t ntd = (length + pipe->p_MaxTransfer - 1) / pipe->p_MaxTransfer;
531 if (ntd % 2 == 0)
532 dt ^= 1;
534 pipe->p_NextToggle = dt ^ 1;
536 while (ntd--)
538 uint32_t len = (length > pipe->p_MaxTransfer) ? pipe->p_MaxTransfer : length;
540 if (td)
542 UHCI_TransferDesc *tmp = uhci_AllocTD(cl, o);
543 td->td_LinkPtr = (uint32_t)tmp | UHCI_PTR_TD;
544 td = tmp;
546 else
548 td = t = uhci_AllocTD(cl, o);
551 td->td_Buffer = (uint32_t)ptr;
552 td->td_LinkPtr = UHCI_PTR_T;
553 td->td_Status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(3) | UHCI_TD_ACTIVE);
554 if (in)
555 td->td_Token = UHCI_TD_IN(len, pipe->p_EndPoint, pipe->p_DevAddr, dt);
556 else
557 td->td_Token = UHCI_TD_OUT(len, pipe->p_EndPoint, pipe->p_DevAddr, dt);
559 if (pipe->p_FullSpeed)
560 td->td_Status |= UHCI_TD_SPD;
561 else
562 td->td_Status |= UHCI_TD_LS | UHCI_TD_SPD;
564 dt ^= 1;
565 ptr += len;
567 D(bug("[UHCI] TD=%p (%08x %08x %08x %08x)\n", td,
568 td->td_LinkPtr, td->td_Status, td->td_Token, td->td_Buffer));
571 td->td_Status |= UHCI_TD_IOC;
573 Disable();
574 if (pipe->p_FirstTD == (APTR)UHCI_PTR_T)
576 pipe->p_FirstTD = t;
577 pipe->p_LastTD = td;
579 else
581 pipe->p_LastTD->td_LinkPtr = (uint32_t)t | UHCI_PTR_TD;
582 pipe->p_LastTD = td;
585 if (pipe->p_Queue->qh_VLink == UHCI_PTR_T)
587 pipe->p_Queue->qh_VLink = (uint32_t)t | UHCI_PTR_TD;
589 Enable();
592 void uhci_QueuedWrite(OOP_Class *cl, OOP_Object *o, UHCI_Pipe *pipe, VOID *buffer, uint32_t length)
594 uhci_QueuedTransfer(cl, o, pipe, buffer, length, FALSE);
597 void uhci_QueuedRead(OOP_Class *cl, OOP_Object *o, UHCI_Pipe *pipe, VOID *buffer, uint32_t length)
599 uhci_QueuedTransfer(cl, o, pipe, buffer, length, TRUE);
602 void uhci_ControlTransfer(OOP_Class *cl, OOP_Object *o, UHCI_Pipe *pipe,
603 USBDevice_Request *request, VOID *buffer, uint32_t length)
605 UHCI_TransferDesc *req, *td=NULL, *stat;
606 BOOL isread = request->bmRequestType & UT_READ;
607 uint32_t len = request->wLength;
609 D(bug("[UHCI] ControlTransfer %08x(%02x %02x %04x %04x %04x) %08x %d\n",
610 request, request->bmRequestType, request->bRequest, request->wValue, request->wIndex,
611 request->wLength, buffer, length));
613 if (length <= 1023)
615 req = uhci_AllocTD(cl, o);
616 req->td_Token = UHCI_TD_SETUP(sizeof(USBDevice_Request), pipe->p_EndPoint, pipe->p_DevAddr);
617 req->td_Buffer = (uint32_t)request;
618 req->td_Status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(3) | UHCI_TD_ACTIVE);
620 if (!pipe->p_FullSpeed)
621 req->td_Status |= UHCI_TD_LS;
623 stat = uhci_AllocTD(cl, o);
624 stat->td_LinkPtr = UHCI_PTR_T;
625 stat->td_Status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(3) | UHCI_TD_ACTIVE | UHCI_TD_IOC);
626 stat->td_Buffer = 0;
627 stat->td_Token = isread ? UHCI_TD_OUT(0, pipe->p_EndPoint, pipe->p_DevAddr, 1)
628 : UHCI_TD_IN (0, pipe->p_EndPoint, pipe->p_DevAddr, 1);
630 if (!pipe->p_FullSpeed)
631 stat->td_Status |= UHCI_TD_LS;
633 if (buffer)
635 uint8_t d = 1;
636 UHCI_TransferDesc *prev = req;
637 uint8_t *buff = buffer;
638 length = len;
640 while (length > 0)
642 len = (length > pipe->p_MaxTransfer) ? pipe->p_MaxTransfer : length;
644 td = uhci_AllocTD(cl, o);
646 td->td_Token = isread ? UHCI_TD_IN (len, pipe->p_EndPoint, pipe->p_DevAddr, d)
647 : UHCI_TD_OUT(len, pipe->p_EndPoint, pipe->p_DevAddr, d);
648 td->td_Status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(3) | UHCI_TD_ACTIVE | UHCI_TD_SPD);
649 td->td_Buffer = (uint32_t)buff;
651 if (!pipe->p_FullSpeed)
652 td->td_Status |= UHCI_TD_LS;
654 td->td_Status |= UHCI_TD_SPD;
655 prev->td_LinkPtr = (uint32_t)td | UHCI_PTR_TD | UHCI_PTR_VF;
657 d ^= 1;
658 prev = td;
659 buff += len;
660 length -= len;
663 td->td_LinkPtr = (uint32_t)stat | UHCI_PTR_TD | UHCI_PTR_VF;
665 else
667 req->td_LinkPtr = (uint32_t)stat | UHCI_PTR_TD | UHCI_PTR_VF;
671 UHCI_TransferDesc *t = req;
673 while ((uint32_t)t != UHCI_PTR_T)
675 bug("[UHCI] TD=%p (%08x %08x %08x %08x)\n", t,
676 t->td_LinkPtr, t->td_Status, t->td_Token, t->td_Buffer);
677 t = (UHCI_TransferDesc *)(t->td_LinkPtr & 0xfffffff1);
681 Disable();
682 if (pipe->p_FirstTD == (APTR)UHCI_PTR_T)
684 pipe->p_FirstTD = req;
685 pipe->p_LastTD = stat;
687 else
689 pipe->p_LastTD->td_LinkPtr = (uint32_t)req | UHCI_PTR_TD;
690 pipe->p_LastTD = stat;
693 if (pipe->p_Queue->qh_VLink == UHCI_PTR_T)
695 pipe->p_Queue->qh_VLink = (uint32_t)req | UHCI_PTR_TD;
697 Enable();
701 BOOL uhci_PortReset(OOP_Class *cl, OOP_Object *o, uint8_t p)
703 UHCIData *uhci = OOP_INST_DATA(cl, o);
704 int lim, port, x;
706 if (p == 1)
707 port = UHCI_PORTSC1;
708 else if (p == 2)
709 port = UHCI_PORTSC2;
710 else
711 return FALSE;
713 x = URWMASK(inw(uhci->iobase + port));
714 outw(x | UHCI_PORTSC_PR, uhci->iobase + port);
716 uhci_sleep(cl, o, 100);
718 x = URWMASK(inw(uhci->iobase + port));
719 outw(x & ~UHCI_PORTSC_PR, uhci->iobase + port);
721 uhci_sleep(cl, o, 100);
723 x = URWMASK(inw(uhci->iobase + port));
724 outw(x | UHCI_PORTSC_PE, uhci->iobase + port);
726 for (lim = 10; --lim > 0;)
728 uhci_sleep(cl, o, 10);
730 x = inw(uhci->iobase + port);
732 if (!(x & UHCI_PORTSC_CCS))
733 break;
735 if (x & (UHCI_PORTSC_POEDC | UHCI_PORTSC_CSC))
737 outw(URWMASK(x) | (x & (UHCI_PORTSC_POEDC | UHCI_PORTSC_CSC)), uhci->iobase + port);
738 continue;
741 if (x & UHCI_PORTSC_PE)
742 break;
744 outw(URWMASK(x) | UHCI_PORTSC_PE, uhci->iobase + port);
748 if (lim <= 0)
750 D(bug("[UHCI] Port reset timeout\n"));
751 return FALSE;
754 uhci->reset |= 1 << (p-1);
756 return TRUE;