2 Copyright © 2002-2009, Chris Hodges. All rights reserved.
3 Copyright © 2009-2017, The AROS Development Team. All rights reserved.
7 #include <devices/usb_hub.h>
9 #include <proto/utility.h>
10 #include <proto/exec.h>
11 #include <proto/timer.h>
12 #include <clib/alib_protos.h>
16 #include "cmd_protos.h"
17 #include "roothub_protos.h"
18 #include "chip_protos.h"
19 #include "pci_protos.h"
24 struct my_NSDeviceQueryResult
26 ULONG DevQueryFormat
; /* this is type 0 */
27 ULONG SizeAvailable
; /* bytes available */
28 UWORD DeviceType
; /* what the device does */
29 UWORD DeviceSubType
; /* depends on the main type */
30 const UWORD
*SupportedCommands
; /* 0 terminated list of cmd's */
33 static BOOL
OpenTimer(struct PCIUnit
*unit
, struct PCIDevice
*base
);
34 static void CloseTimer(struct PCIUnit
*unit
, struct PCIDevice
*base
);
35 static UWORD
GetUsbState(struct IOUsbHWReq
*ioreq
,
36 struct PCIUnit
*unit
, struct PCIDevice
*base
);
38 static const struct TagItem query_tags
[] = {
39 {UHA_Manufacturer
, (IPTR
) "Chris Hodges, AROS Development Team"},
40 {UHA_Description
, (IPTR
) "Open Host Controller Interface driver"},
42 (IPTR
) "©2007-2012 Chris Hodges,\n AROS Development Team"},
43 {UHA_Version
, VERSION_NUMBER
},
44 {UHA_Revision
, REVISION_NUMBER
},
45 {UHA_DriverVersion
, 0x220},
49 /* /// "OpenTimer()" */
50 static BOOL
OpenTimer(struct PCIUnit
*unit
, struct PCIDevice
*base
)
52 if ((unit
->hu_MsgPort
= CreateMsgPort()))
54 if ((unit
->hu_TimerReq
=
55 (struct timerequest
*)CreateIORequest(unit
->hu_MsgPort
,
56 sizeof(struct timerequest
))))
58 if (!OpenDevice("timer.device", UNIT_MICROHZ
,
59 (struct IORequest
*)unit
->hu_TimerReq
, 0))
61 unit
->hu_TimerReq
->tr_node
.io_Message
.mn_Node
.ln_Name
=
63 unit
->hu_TimerReq
->tr_node
.io_Command
= TR_ADDREQUEST
;
64 KPRINTF(1, ("opened timer device\n"));
67 DeleteIORequest((struct IORequest
*)unit
->hu_TimerReq
);
68 unit
->hu_TimerReq
= NULL
;
70 DeleteMsgPort(unit
->hu_MsgPort
);
71 unit
->hu_MsgPort
= NULL
;
73 KPRINTF(5, ("failed to open timer.device\n"));
79 void DelayMS(ULONG milli
, struct PCIUnit
*unit
)
81 unit
->hu_TimerReq
->tr_time
.tv_secs
= 0;
82 unit
->hu_TimerReq
->tr_time
.tv_micro
= milli
* 1000;
83 DoIO((struct IORequest
*)unit
->hu_TimerReq
);
87 /* /// "CloseTimer()" */
88 static void CloseTimer(struct PCIUnit
*unit
, struct PCIDevice
*base
)
92 if (unit
->hu_TimerReq
)
94 KPRINTF(1, ("closing timer.device\n"));
95 CloseDevice((APTR
) unit
->hu_TimerReq
);
96 DeleteIORequest((struct IORequest
*)unit
->hu_TimerReq
);
97 unit
->hu_TimerReq
= NULL
;
99 DeleteMsgPort(unit
->hu_MsgPort
);
100 unit
->hu_MsgPort
= NULL
;
105 /* /// "Open_Unit()" */
106 struct Unit
*Open_Unit(struct IOUsbHWReq
*ioreq
,
107 LONG unitnr
, struct PCIDevice
*base
)
109 struct PCIUnit
*unit
= NULL
;
111 if (!base
->hd_ScanDone
)
113 base
->hd_ScanDone
= TRUE
;
119 unit
= (struct PCIUnit
*)base
->hd_Units
.lh_Head
;
120 while (((struct Node
*)unit
)->ln_Succ
)
122 if (unit
->hu_UnitNo
== unitnr
)
126 unit
= (struct PCIUnit
*)((struct Node
*)unit
)->ln_Succ
;
128 if (!((struct Node
*)unit
)->ln_Succ
)
130 KPRINTF(20, ("Unit %ld does not exist!\n", unitnr
));
133 if (unit
->hu_UnitAllocated
)
135 ioreq
->iouh_Req
.io_Error
= IOERR_UNITBUSY
;
136 KPRINTF(5, ("Unit %ld already open!\n", unitnr
));
140 if (OpenTimer(unit
, base
))
143 if (pciAllocUnit(unit
)) // hardware self test
145 unit
->hu_UnitAllocated
= TRUE
;
146 unit
->hu_NakTimeoutInt
.is_Node
.ln_Type
= NT_INTERRUPT
;
147 unit
->hu_NakTimeoutInt
.is_Node
.ln_Name
= "PCI NakTimeout";
148 unit
->hu_NakTimeoutInt
.is_Node
.ln_Pri
= -16;
149 unit
->hu_NakTimeoutInt
.is_Data
= unit
;
150 unit
->hu_NakTimeoutInt
.is_Code
= (VOID_FUNC
) NakTimeoutInt
;
152 CopyMem(unit
->hu_TimerReq
, &unit
->hu_NakTimeoutReq
,
153 sizeof(struct timerequest
));
154 memset( &unit
->hu_NakTimeoutMsgPort
, 0, sizeof( unit
->hu_NakTimeoutMsgPort
) );
155 unit
->hu_NakTimeoutMsgPort
.mp_Node
.ln_Type
= NT_MSGPORT
;
156 unit
->hu_NakTimeoutMsgPort
.mp_Flags
= PA_SOFTINT
;
157 unit
->hu_NakTimeoutMsgPort
.mp_SigTask
= &unit
->hu_NakTimeoutInt
;
158 NewList(&unit
->hu_NakTimeoutMsgPort
.mp_MsgList
);
159 unit
->hu_NakTimeoutReq
.tr_node
.io_Message
.mn_ReplyPort
=
160 &unit
->hu_NakTimeoutMsgPort
;
161 Cause(&unit
->hu_NakTimeoutInt
);
162 return &unit
->hu_Unit
;
166 ioreq
->iouh_Req
.io_Error
= IOERR_SELFTEST
;
167 KPRINTF(20, ("Hardware allocation failure!\n"));
169 CloseTimer(unit
, base
);
175 /* /// "Close_Unit()" */
176 void Close_Unit(struct PCIDevice
*base
,
177 struct PCIUnit
*unit
, struct IOUsbHWReq
*ioreq
)
179 /* Disable all interrupts */
180 unit
->hu_NakTimeoutMsgPort
.mp_Flags
= PA_IGNORE
;
181 unit
->hu_NakTimeoutInt
.is_Node
.ln_Type
= NT_SOFTINT
;
182 AbortIO((APTR
) & unit
->hu_NakTimeoutReq
);
186 CloseTimer(unit
, base
);
187 unit
->hu_UnitAllocated
= FALSE
;
191 /* /// "GetUsbState()" */
192 static UWORD
GetUsbState(struct IOUsbHWReq
*ioreq
,
193 struct PCIUnit
*unit
, struct PCIDevice
*base
)
195 return ioreq
->iouh_State
= UHSF_OPERATIONAL
;
199 /* /// "cmdReset()" */
201 *======================================================================
202 * cmdReset(ioreq, unit, base)
203 *======================================================================
205 * This is the device CMD_RESET routine.
207 * Resets the whole USB hardware. Goes into USBOperational mode right
208 * after. Must NOT be called from an interrupt.
212 WORD
cmdReset(struct IOUsbHWReq
* ioreq
,
213 struct PCIUnit
* unit
, struct PCIDevice
* base
)
215 KPRINTF(10, ("CMD_RESET ioreq: 0x%p\n", ioreq
));
218 GetUsbState(ioreq
, unit
, base
);
220 if (ioreq
->iouh_State
& UHSF_OPERATIONAL
)
224 return UHIOERR_USBOFFLINE
;
228 /* /// "cmdUsbReset()" */
230 *======================================================================
231 * cmdUsbReset(ioreq, unit, base)
232 *======================================================================
234 * This is the device UHCMD_USBRESET routine.
236 * Resets the USB bus. Goes into USBOperational mode right after. Must
237 * NOT be called from an interrupt.
241 WORD
cmdUsbReset(struct IOUsbHWReq
* ioreq
,
242 struct PCIUnit
* unit
, struct PCIDevice
* base
)
244 KPRINTF(10, ("UHCMD_USBRESET ioreq: 0x%p\n", ioreq
));
247 GetUsbState(ioreq
, unit
, base
);
249 unit
->hu_FrameCounter
= 1;
250 unit
->hu_RootHubAddr
= 0;
252 if (ioreq
->iouh_State
& UHSF_OPERATIONAL
)
256 return UHIOERR_USBOFFLINE
;
260 /* /// "cmdUsbResume()" */
262 *======================================================================
263 * cmdUsbResume(ioreq, unit, base)
264 *======================================================================
266 * This is the device UHCMD_USBRESUME routine.
268 * Tries to resume from USBSuspend mode into USBOperational.
269 * Must NOT be called from an interrupt.
273 WORD
cmdUsbResume(struct IOUsbHWReq
* ioreq
,
274 struct PCIUnit
* unit
, struct PCIDevice
* base
)
276 KPRINTF(10, ("UHCMD_USBRESUME ioreq: 0x%p\n", ioreq
));
279 GetUsbState(ioreq
, unit
, base
);
280 if (ioreq
->iouh_State
& UHSF_OPERATIONAL
)
284 return UHIOERR_USBOFFLINE
;
288 /* /// "cmdUsbSuspend()" */
290 *======================================================================
291 * cmdUsbSuspend(ioreq, unit, base)
292 *======================================================================
294 * This is the device UHCMD_USBSUSPEND routine.
296 * Sets the USB into USBSuspend mode.
297 * Must NOT be called from an interrupt.
301 WORD
cmdUsbSuspend(struct IOUsbHWReq
* ioreq
,
302 struct PCIUnit
* unit
, struct PCIDevice
* base
)
304 KPRINTF(10, ("UHCMD_USBSUSPEND ioreq: 0x%p\n", ioreq
));
307 GetUsbState(ioreq
, unit
, base
);
308 if (ioreq
->iouh_State
& UHSF_SUSPENDED
)
312 return UHIOERR_USBOFFLINE
;
316 /* /// "cmdUsbOper()" */
318 *======================================================================
319 * cmdUsbOper(ioreq, unit, base)
320 *======================================================================
322 * This is the device UHCMD_USBOPER routine.
324 * Sets the USB into USBOperational mode.
325 * Must NOT be called from an interrupt.
329 WORD
cmdUsbOper(struct IOUsbHWReq
* ioreq
,
330 struct PCIUnit
* unit
, struct PCIDevice
* base
)
332 KPRINTF(10, ("UHCMD_USBOPER ioreq: 0x%p\n", ioreq
));
335 GetUsbState(ioreq
, unit
, base
);
336 if (ioreq
->iouh_State
& UHSF_OPERATIONAL
)
340 return UHIOERR_USBOFFLINE
;
344 /* /// "cmdQueryDevice()" */
346 *======================================================================
347 * cmdQueryDevice(ioreq, unit, base)
348 *======================================================================
350 * This is the device UHCMD_QUERYDEVICE routine.
352 * Returns information about the hardware.
356 WORD
cmdQueryDevice(struct IOUsbHWReq
* ioreq
,
357 struct PCIUnit
* unit
, struct PCIDevice
* base
)
359 struct TagItem
*taglist
= (struct TagItem
*)ioreq
->iouh_Data
;
363 KPRINTF(10, ("UHCMD_QUERYDEVICE ioreq: 0x%p, taglist: 0x%p\n", ioreq
,
366 while ((tag
= NextTagItem(&taglist
)) != NULL
)
371 *((ULONG
*) tag
->ti_Data
) =
372 (ULONG
) GetUsbState(ioreq
, unit
, base
);
374 case UHA_ProductName
:
375 *((STRPTR
*) tag
->ti_Data
) = unit
->hu_ProductName
;
378 *((IPTR
*) tag
->ti_Data
) =
379 GetTagData(tag
->ti_Tag
, *((IPTR
*) tag
->ti_Data
),
385 ioreq
->iouh_Actual
= count
;
390 WORD
cmdXFer(struct IOUsbHWReq
* ioreq
,
391 struct PCIUnit
* unit
, struct PCIDevice
* base
)
393 struct PCIController
*hc
;
397 switch (ioreq
->iouh_Req
.io_Command
)
399 case UHCMD_CONTROLXFER
:
400 xfer_type
= CTRL_XFER
;
403 xfer_type
= ISO_XFER
;
406 xfer_type
= INT_XFER
;
409 xfer_type
= BULK_XFER
;
413 KPRINTF(10, ("UHCMD_%sXFER ioreq: 0x%p\n", xfer_names
[xfer_type
],
415 GetUsbState(ioreq
, unit
, base
);
416 if (!(ioreq
->iouh_State
& UHSF_OPERATIONAL
))
418 return UHIOERR_USBOFFLINE
;
421 if (xfer_type
== CTRL_XFER
)
423 /* Root Hub Emulation */
424 if (ioreq
->iouh_DevAddr
== unit
->hu_RootHubAddr
)
426 return cmdControlXFerRootHub(ioreq
, unit
, base
);
429 else if (xfer_type
== INT_XFER
)
431 /* Root Hub Emulation */
432 if (ioreq
->iouh_DevAddr
== unit
->hu_RootHubAddr
)
434 return cmdIntXFerRootHub(ioreq
, unit
, base
);
437 else if (xfer_type
== BULK_XFER
|| xfer_type
== ISO_XFER
)
439 if (ioreq
->iouh_Flags
& UHFF_LOWSPEED
)
441 return UHIOERR_BADPARAMS
;
445 hc
= unit
->hu_DevControllers
[ioreq
->iouh_DevAddr
];
448 return UHIOERR_HOSTERROR
;
451 ioreq
->iouh_Req
.io_Flags
&= ~IOF_QUICK
;
452 ioreq
->iouh_Actual
= 0;
453 ioreq
->iouh_DriverPrivate1
= NULL
;
456 AddTail(&hc
->hc_XferQueues
[xfer_type
], (struct Node
*)ioreq
);
458 Cause(&hc
->hc_CompleteInt
);
460 KPRINTF(10, ("UHCMD_%sXFER processed ioreq: 0x%p\n",
461 xfer_names
[xfer_type
], ioreq
));
466 /* /// "cmdFlush()" */
468 *======================================================================
469 * cmdFlush(ioreq, base)
470 *======================================================================
472 * This is the device CMD_FLUSH routine.
474 * This routine abort all pending transfer requests.
478 WORD
cmdFlush(struct IOUsbHWReq
* ioreq
,
479 struct PCIUnit
* unit
, struct PCIDevice
* base
)
481 struct IOUsbHWReq
*cmpioreq
;
482 struct PCIController
*hc
;
486 KPRINTF(10, ("CMD_FLUSH ioreq: 0x%p\n", ioreq
));
489 cmpioreq
= (struct IOUsbHWReq
*)unit
->hu_RHIOQueue
.lh_Head
;
490 while (((struct Node
*)cmpioreq
)->ln_Succ
)
492 Remove(&cmpioreq
->iouh_Req
.io_Message
.mn_Node
);
493 cmpioreq
->iouh_Req
.io_Error
= IOERR_ABORTED
;
494 ReplyMsg(&cmpioreq
->iouh_Req
.io_Message
);
495 cmpioreq
= (struct IOUsbHWReq
*)unit
->hu_RHIOQueue
.lh_Head
;
497 hc
= (struct PCIController
*)unit
->hu_Controllers
.lh_Head
;
498 while (hc
->hc_Node
.ln_Succ
)
500 for (i
= 0; i
< XFER_COUNT
; i
++)
502 list
= (struct List
*)&hc
->hc_XferQueues
[i
];
503 while ((cmpioreq
= (struct IOUsbHWReq
*)RemHead(list
)) != NULL
)
505 cmpioreq
->iouh_Req
.io_Error
= IOERR_ABORTED
;
506 ReplyMsg(&cmpioreq
->iouh_Req
.io_Message
);
509 hc
= (struct PCIController
*)hc
->hc_Node
.ln_Succ
;
518 /* /// "NSD stuff" */
520 static const UWORD NSDSupported
[] = {
521 CMD_FLUSH
, CMD_RESET
,
522 UHCMD_QUERYDEVICE
, UHCMD_USBRESET
,
523 UHCMD_USBRESUME
, UHCMD_USBSUSPEND
,
524 UHCMD_USBOPER
, UHCMD_CONTROLXFER
,
525 UHCMD_ISOXFER
, UHCMD_INTXFER
,
530 WORD
cmdNSDeviceQuery(struct IOStdReq
*ioreq
,
531 struct PCIUnit
*unit
, struct PCIDevice
*base
)
533 struct my_NSDeviceQueryResult
*query
;
535 query
= (struct my_NSDeviceQueryResult
*)ioreq
->io_Data
;
537 KPRINTF(10, ("NSCMD_DEVICEQUERY ioreq: 0x%p query: 0x%p\n", ioreq
,
545 (ioreq
->io_Length
< sizeof(struct my_NSDeviceQueryResult
)) ||
546 (query
->DevQueryFormat
!= 0) || (query
->SizeAvailable
!= 0))
548 /* Return error. This is special handling, since iorequest is only
549 guaranteed to be sizeof(struct IOStdReq). If we'd let our
550 devBeginIO dispatcher return the error, it would trash some
551 memory past end of the iorequest (ios2_WireError field).
553 ioreq
->io_Error
= IOERR_NOCMD
;
554 TermIO((struct IOUsbHWReq
*)ioreq
, base
);
556 /* Don't reply, we already did.
561 ioreq
->io_Actual
= query
->SizeAvailable
562 = sizeof(struct my_NSDeviceQueryResult
);
563 query
->DeviceType
= NSDEVTYPE_USBHARDWARE
;
564 query
->DeviceSubType
= 0;
565 query
->SupportedCommands
= NSDSupported
;
567 /* Return success (note that this will NOT poke ios2_WireError).
575 *===========================================================
576 * TermIO(ioreq, base)
577 *===========================================================
579 * Return completed ioreq to sender.
583 void TermIO(struct IOUsbHWReq
*ioreq
, struct PCIDevice
*base
)
585 ioreq
->iouh_Req
.io_Message
.mn_Node
.ln_Type
= NT_FREEMSG
;
587 /* If not quick I/O, reply the message
589 if (!(ioreq
->iouh_Req
.io_Flags
& IOF_QUICK
))
591 ReplyMsg(&ioreq
->iouh_Req
.io_Message
);
596 /* /// "cmdAbortIO()" */
597 BOOL
cmdAbortIO(struct IOUsbHWReq
*ioreq
, struct PCIDevice
*base
)
599 struct PCIUnit
*unit
= (struct PCIUnit
*)ioreq
->iouh_Req
.io_Unit
;
600 struct IOUsbHWReq
*cmpioreq
;
601 struct PCIController
*hc
;
602 BOOL foundit
= FALSE
;
605 KPRINTF(10, ("cmdAbort(%p)\n", ioreq
));
608 cmpioreq
= (struct IOUsbHWReq
*)unit
->hu_RHIOQueue
.lh_Head
;
609 while (((struct Node
*)cmpioreq
)->ln_Succ
)
611 if (ioreq
== cmpioreq
)
613 Remove(&ioreq
->iouh_Req
.io_Message
.mn_Node
);
615 ioreq
->iouh_Req
.io_Error
= IOERR_ABORTED
;
620 (struct IOUsbHWReq
*)cmpioreq
->iouh_Req
.io_Message
.
624 hc
= (struct PCIController
*)unit
->hu_Controllers
.lh_Head
;
625 while (hc
->hc_Node
.ln_Succ
)
627 for (i
= 0; i
< XFER_COUNT
&& !foundit
; i
++)
630 (struct IOUsbHWReq
*)hc
->hc_XferQueues
[i
].lh_Head
;
631 ((struct Node
*)cmpioreq
)->ln_Succ
!= NULL
&& !foundit
;
633 (struct IOUsbHWReq
*)cmpioreq
->iouh_Req
.io_Message
.
636 if (ioreq
== cmpioreq
)
642 // IOReq is probably pending in some transfer structure
643 cmpioreq
= (struct IOUsbHWReq
*)hc
->hc_TDQueue
.lh_Head
;
644 while (((struct Node
*)cmpioreq
)->ln_Succ
)
646 if (ioreq
== cmpioreq
)
649 * Request's ED is in use by the HC, as well as its TDs
651 * Schedule abort on the HC driver and reply the request
652 * only when done. However return success.
654 ioreq
->iouh_Req
.io_Error
= IOERR_ABORTED
;
655 AbortRequest(hc
, ioreq
);
660 (struct IOUsbHWReq
*)cmpioreq
->iouh_Req
.
661 io_Message
.mn_Node
.ln_Succ
;
668 Remove(&ioreq
->iouh_Req
.io_Message
.mn_Node
);
671 hc
= (struct PCIController
*)hc
->hc_Node
.ln_Succ
;
677 ioreq
->iouh_Req
.io_Error
= IOERR_ABORTED
;
682 KPRINTF(20, ("WARNING, could not abort unknown IOReq %p\n", ioreq
));
688 /* /// "CheckSpecialCtrlTransfers()" */
689 void CheckSpecialCtrlTransfers(struct PCIController
*hc
,
690 struct IOUsbHWReq
*ioreq
)
692 struct PCIUnit
*unit
= hc
->hc_Unit
;
694 /* Clear Feature(Endpoint halt) */
695 if ((ioreq
->iouh_SetupData
.bmRequestType
==
696 (URTF_STANDARD
| URTF_ENDPOINT
))
697 && (ioreq
->iouh_SetupData
.bRequest
== USR_CLEAR_FEATURE
)
698 && (ioreq
->iouh_SetupData
.wValue
==
699 AROS_WORD2LE(UFS_ENDPOINT_HALT
)))
701 KPRINTF(10, ("Resetting toggle bit for endpoint %ld\n",
702 AROS_WORD2LE(ioreq
->iouh_SetupData
.wIndex
) & 0xf));
704 hu_DevDataToggle
[(ioreq
->iouh_DevAddr
<< 5) |
705 (AROS_WORD2LE(ioreq
->
706 iouh_SetupData
.wIndex
) & 0xf) | ((AROS_WORD2LE(ioreq
->
707 iouh_SetupData
.wIndex
) & 0x80) >> 3)] = 0;
709 else if ((ioreq
->iouh_SetupData
.bmRequestType
==
710 (URTF_STANDARD
| URTF_DEVICE
))
711 && (ioreq
->iouh_SetupData
.bRequest
== USR_SET_ADDRESS
))
713 /* Set Address -> clear all endpoints */
715 ULONG adr
= AROS_WORD2BE(ioreq
->iouh_SetupData
.wValue
) >> 3;
716 KPRINTF(10, ("Resetting toggle bits for device address %ld\n",
718 for (epnum
= 0; epnum
< 31; epnum
++)
720 unit
->hu_DevDataToggle
[adr
+ epnum
] = 0;
722 // transfer host controller ownership
723 unit
->hu_DevControllers
[ioreq
->iouh_DevAddr
] = NULL
;
724 unit
->hu_DevControllers
[adr
>> 5] = hc
;
726 else if ((ioreq
->iouh_SetupData
.bmRequestType
==
727 (URTF_CLASS
| URTF_OTHER
))
728 && (ioreq
->iouh_SetupData
.bRequest
== USR_SET_FEATURE
)
729 && (ioreq
->iouh_SetupData
.wValue
== AROS_WORD2LE(UFS_PORT_RESET
)))
731 // a hub will be enumerating a device on this host controller soon!
732 KPRINTF(10, ("Hub RESET caught, assigning Dev0 to %p!\n", hc
));
733 unit
->hu_DevControllers
[0] = hc
;
738 /* /// "NakTimeoutInt()" */
739 AROS_INTH1(NakTimeoutInt
, struct PCIUnit
*, unit
)
743 struct PCIController
*hc
;
744 struct IOUsbHWReq
*ioreq
;
748 KPRINTF(1, ("Enter NakTimeoutInt(0x%p)\n", unit
));
750 // check for NAK Timeouts
751 hc
= (struct PCIController
*)unit
->hu_Controllers
.lh_Head
;
752 while (hc
->hc_Node
.ln_Succ
)
754 if (!(hc
->hc_Flags
& HCF_ONLINE
))
756 hc
= (struct PCIController
*)hc
->hc_Node
.ln_Succ
;
759 UpdateFrameCounter(hc
);
760 framecnt
= hc
->hc_FrameCounter
;
762 ioreq
= (struct IOUsbHWReq
*)hc
->hc_TDQueue
.lh_Head
;
763 while (((struct Node
*)ioreq
)->ln_Succ
)
765 // Remember the successor because AbortRequest() will move the request to another list
766 struct IOUsbHWReq
*succ
=
767 (struct IOUsbHWReq
*)ioreq
->iouh_Req
.io_Message
.
770 if (ioreq
->iouh_Flags
& UHFF_NAKTIMEOUT
)
772 KPRINTF(1, ("Examining IOReq=%p with OED=%p\n", ioreq
,
773 ioreq
->iouh_DriverPrivate1
));
774 if (ioreq
->iouh_DriverPrivate1
)
777 ("CTRL=%04lx, CMD=%01lx, F=%ld, hccaDH=%08lx, "
778 "hcDH=%08lx, CH=%08lx, CCH=%08lx, "
779 "IntStatus=%08lx, IntEn=%08lx\n",
780 READREG32_LE(hc
->hc_RegBase
, OHCI_CONTROL
),
781 READREG32_LE(hc
->hc_RegBase
, OHCI_CMDSTATUS
),
782 READREG32_LE(hc
->hc_RegBase
, OHCI_FRAMECOUNT
),
783 READMEM32_LE(&hc
->hc_HCCA
->ha_DoneHead
),
784 READREG32_LE(hc
->hc_RegBase
, OHCI_DONEHEAD
),
785 READREG32_LE(hc
->hc_RegBase
, OHCI_CTRL_HEAD_ED
),
786 READREG32_LE(hc
->hc_RegBase
, OHCI_CTRL_ED
),
787 READREG32_LE(hc
->hc_RegBase
, OHCI_INTSTATUS
),
788 READREG32_LE(hc
->hc_RegBase
, OHCI_INTEN
)));
791 (ioreq
->iouh_DevAddr
<< 5) + ioreq
->iouh_Endpoint
+
792 ((ioreq
->iouh_Dir
== UHDIR_IN
) ? 0x10 : 0);
793 if (framecnt
> unit
->hu_NakTimeoutFrame
[target
])
795 // give the thing the chance to exit gracefully
797 ("HC 0x%p NAK timeout %ld > %ld, IOReq=%p\n",
799 unit
->hu_NakTimeoutFrame
[target
], ioreq
));
800 ioreq
->iouh_Req
.io_Error
= UHIOERR_NAKTIMEOUT
;
801 AbortRequest(hc
, ioreq
);
808 hc
= (struct PCIController
*)hc
->hc_Node
.ln_Succ
;
811 CheckRootHubChanges(unit
);
813 unit
->hu_NakTimeoutReq
.tr_time
.tv_micro
= 150 * 1000;
814 SendIO((APTR
) & unit
->hu_NakTimeoutReq
);
816 KPRINTF(1, ("Exit NakTimeoutInt(0x%p)\n", unit
));