2 Copyright (C) 2006 by Michal Schulz
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.
25 #include <aros/symbolsets.h>
27 #include <aros/debug.h>
29 #include <exec/types.h>
32 #include <devices/timer.h>
34 #include <hidd/hidd.h>
41 #include <proto/oop.h>
42 #include <proto/utility.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
67 * This function returns NULL if no free TD's are found and no more memory
70 UHCI_TransferDesc
*uhci_AllocTD(OOP_Class
*cl
, OOP_Object
*o
)
72 UHCIData
*uhci
= OOP_INST_DATA(cl
, o
);
74 uint32_t node_num
= 32;
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
;
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;
125 FreePooled(SD(cl
)->MemPool
, n
, sizeof(struct TDNode
));
130 /* Everything failed? Out of memory, most likely */
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
)
154 /* We're inside interrupt probably. Don't ObtainSemaphore. Just lock interrupts instead */
157 /* traverse through the list of 4K pages */
158 ForeachNode(&uhci
->sd
->td_list
, t
)
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);
168 t
->td_Bitmap
[bmp
] &= ~(1 << node
);
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
);
193 /* traverse through the list of 4K pages */
194 ForeachNodeSafe(&SD(cl
)->td_list
, t
, next
)
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);
204 t
->td_Bitmap
[bmp
] &= ~(1 << node
);
206 /* Check if all TD nodes are free within the 4K page */
208 for (i
=0; i
< 8; i
++)
209 if (t
->td_Bitmap
[i
] != 0)
212 /* So it is. Free the 4K page */
215 Remove((struct Node
*)t
);
216 HIDD_PCIDriver_FreePCIMem(uhci
->pciDriver
, t
->td_Page
);
217 FreePooled(SD(cl
)->MemPool
, t
, sizeof(struct TDNode
));
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
);
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
);
260 cmd
= inw(uhci
->iobase
+ UHCI_CMD
);
266 outw(cmd
, uhci
->iobase
+ UHCI_CMD
);
268 for (n
=0; n
< 10; n
++)
270 running
= !(inw(uhci
->iobase
+ UHCI_STS
) & UHCI_STS_HCH
);
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
)));
281 uhci_sleep(cl
, o
, 10);
284 D(bug("[UHCI] Failed to change the running state\n"));
288 void uhci_RebuildList(OOP_Class
*cl
, OOP_Object
*o
)
290 UHCIData
*uhci
= OOP_INST_DATA(cl
, o
);
292 UHCI_QueueHeader
*qh
, *first_fast
= NULL
;
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
))
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
346 #ifdef ENABLE_RECLAIM_BANDWIDTH
349 qh
->qh_HLink
= (uint32_t)first_fast
| UHCI_PTR_QH
;
353 qh
->qh_HLink
= UHCI_PTR_T
;
356 qh
->qh_HLink
= UHCI_PTR_T
;
360 void uhci_DeletePipe(OOP_Class
*cl
, OOP_Object
*o
, UHCI_Pipe
*pipe
)
362 D(bug("[UHCI] DeletePipe(%p)\n", pipe
));
366 UHCI_TransferDesc
*td
= (UHCI_TransferDesc
*)pipe
->p_FirstTD
;
368 /* Lock interrupts */
370 /* Remove the pipe from transfer list and rebuild the lists */
371 Remove((struct Node
*)pipe
);
372 uhci_RebuildList(cl
, o
);
375 /* FIXME: Don't delay. Just wait for the incomplete TD's */
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
);
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)
407 else if (pipe
->p_Interval
< 4)
412 else if (pipe
->p_Interval
< 8)
417 else if (pipe
->p_Interval
< 16)
422 else if (pipe
->p_Interval
< 32)
434 minimum
= q
[0]->qh_Data2
;
437 if (minimum
> q
[i
]->qh_Data2
)
439 minimum
= q
[i
]->qh_Data2
;
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
);
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
));
469 pipe
->p_Queue
= uhci_AllocQH(cl
, o
);
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 */
497 AddTail((struct List
*)&uhci
->Bulk
, (struct Node
*)pipe
);
502 AddTail((struct List
*)&uhci
->ControlFS
, (struct Node
*)pipe
);
504 AddTail((struct List
*)&uhci
->ControlLS
, (struct Node
*)pipe
);
507 case PIPE_Isochronous
:
508 AddTail((struct List
*)&uhci
->Isochronous
, (struct Node
*)pipe
);
512 uhci_InsertIntr(uhci
, pipe
);
513 AddTail((struct List
*)&uhci
->Interrupts
, (struct Node
*)pipe
);
517 uhci_RebuildList(cl
, o
);
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
;
534 pipe
->p_NextToggle
= dt
^ 1;
538 uint32_t len
= (length
> pipe
->p_MaxTransfer
) ? pipe
->p_MaxTransfer
: length
;
542 UHCI_TransferDesc
*tmp
= uhci_AllocTD(cl
, o
);
543 td
->td_LinkPtr
= (uint32_t)tmp
| UHCI_PTR_TD
;
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
);
555 td
->td_Token
= UHCI_TD_IN(len
, pipe
->p_EndPoint
, pipe
->p_DevAddr
, dt
);
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
;
562 td
->td_Status
|= UHCI_TD_LS
| UHCI_TD_SPD
;
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
;
574 if (pipe
->p_FirstTD
== (APTR
)UHCI_PTR_T
)
581 pipe
->p_LastTD
->td_LinkPtr
= (uint32_t)t
| UHCI_PTR_TD
;
585 if (pipe
->p_Queue
->qh_VLink
== UHCI_PTR_T
)
587 pipe
->p_Queue
->qh_VLink
= (uint32_t)t
| UHCI_PTR_TD
;
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
));
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
);
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
;
636 UHCI_TransferDesc
*prev
= req
;
637 uint8_t *buff
= buffer
;
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
;
663 td
->td_LinkPtr
= (uint32_t)stat
| UHCI_PTR_TD
| UHCI_PTR_VF
;
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);
682 if (pipe
->p_FirstTD
== (APTR
)UHCI_PTR_T
)
684 pipe
->p_FirstTD
= req
;
685 pipe
->p_LastTD
= stat
;
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
;
701 BOOL
uhci_PortReset(OOP_Class
*cl
, OOP_Object
*o
, uint8_t p
)
703 UHCIData
*uhci
= OOP_INST_DATA(cl
, o
);
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
))
735 if (x
& (UHCI_PORTSC_POEDC
| UHCI_PORTSC_CSC
))
737 outw(URWMASK(x
) | (x
& (UHCI_PORTSC_POEDC
| UHCI_PORTSC_CSC
)), uhci
->iobase
+ port
);
741 if (x
& UHCI_PORTSC_PE
)
744 outw(URWMASK(x
) | UHCI_PORTSC_PE
, uhci
->iobase
+ port
);
750 D(bug("[UHCI] Port reset timeout\n"));
754 uhci
->reset
|= 1 << (p
-1);