2 Copyright © 2002-2009, Chris Hodges. All rights reserved.
3 Copyright © 2009-2012, 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 unit
->hu_NakTimeoutReq
.tr_node
.io_Message
.mn_ReplyPort
=
155 &unit
->hu_NakTimeoutMsgPort
;
156 unit
->hu_NakTimeoutMsgPort
.mp_Node
.ln_Type
= NT_MSGPORT
;
157 unit
->hu_NakTimeoutMsgPort
.mp_Flags
= PA_SOFTINT
;
158 unit
->hu_NakTimeoutMsgPort
.mp_SigTask
= &unit
->hu_NakTimeoutInt
;
159 NewList(&unit
->hu_NakTimeoutMsgPort
.mp_MsgList
);
160 Cause(&unit
->hu_NakTimeoutInt
);
161 return &unit
->hu_Unit
;
165 ioreq
->iouh_Req
.io_Error
= IOERR_SELFTEST
;
166 KPRINTF(20, ("Hardware allocation failure!\n"));
168 CloseTimer(unit
, base
);
174 /* /// "Close_Unit()" */
175 void Close_Unit(struct PCIDevice
*base
,
176 struct PCIUnit
*unit
, struct IOUsbHWReq
*ioreq
)
178 /* Disable all interrupts */
179 unit
->hu_NakTimeoutMsgPort
.mp_Flags
= PA_IGNORE
;
180 unit
->hu_NakTimeoutInt
.is_Node
.ln_Type
= NT_SOFTINT
;
181 AbortIO((APTR
) & unit
->hu_NakTimeoutReq
);
185 CloseTimer(unit
, base
);
186 unit
->hu_UnitAllocated
= FALSE
;
190 /* /// "GetUsbState()" */
191 static UWORD
GetUsbState(struct IOUsbHWReq
*ioreq
,
192 struct PCIUnit
*unit
, struct PCIDevice
*base
)
194 return ioreq
->iouh_State
= UHSF_OPERATIONAL
;
198 /* /// "cmdReset()" */
200 *======================================================================
201 * cmdReset(ioreq, unit, base)
202 *======================================================================
204 * This is the device CMD_RESET routine.
206 * Resets the whole USB hardware. Goes into USBOperational mode right
207 * after. Must NOT be called from an interrupt.
211 WORD
cmdReset(struct IOUsbHWReq
* ioreq
,
212 struct PCIUnit
* unit
, struct PCIDevice
* base
)
214 KPRINTF(10, ("CMD_RESET ioreq: 0x%p\n", ioreq
));
217 GetUsbState(ioreq
, unit
, base
);
219 if (ioreq
->iouh_State
& UHSF_OPERATIONAL
)
223 return UHIOERR_USBOFFLINE
;
227 /* /// "cmdUsbReset()" */
229 *======================================================================
230 * cmdUsbReset(ioreq, unit, base)
231 *======================================================================
233 * This is the device UHCMD_USBRESET routine.
235 * Resets the USB bus. Goes into USBOperational mode right after. Must
236 * NOT be called from an interrupt.
240 WORD
cmdUsbReset(struct IOUsbHWReq
* ioreq
,
241 struct PCIUnit
* unit
, struct PCIDevice
* base
)
243 KPRINTF(10, ("UHCMD_USBRESET ioreq: 0x%p\n", ioreq
));
246 GetUsbState(ioreq
, unit
, base
);
248 unit
->hu_FrameCounter
= 1;
249 unit
->hu_RootHubAddr
= 0;
251 if (ioreq
->iouh_State
& UHSF_OPERATIONAL
)
255 return UHIOERR_USBOFFLINE
;
259 /* /// "cmdUsbResume()" */
261 *======================================================================
262 * cmdUsbResume(ioreq, unit, base)
263 *======================================================================
265 * This is the device UHCMD_USBRESUME routine.
267 * Tries to resume from USBSuspend mode into USBOperational.
268 * Must NOT be called from an interrupt.
272 WORD
cmdUsbResume(struct IOUsbHWReq
* ioreq
,
273 struct PCIUnit
* unit
, struct PCIDevice
* base
)
275 KPRINTF(10, ("UHCMD_USBRESUME ioreq: 0x%p\n", ioreq
));
278 GetUsbState(ioreq
, unit
, base
);
279 if (ioreq
->iouh_State
& UHSF_OPERATIONAL
)
283 return UHIOERR_USBOFFLINE
;
287 /* /// "cmdUsbSuspend()" */
289 *======================================================================
290 * cmdUsbSuspend(ioreq, unit, base)
291 *======================================================================
293 * This is the device UHCMD_USBSUSPEND routine.
295 * Sets the USB into USBSuspend mode.
296 * Must NOT be called from an interrupt.
300 WORD
cmdUsbSuspend(struct IOUsbHWReq
* ioreq
,
301 struct PCIUnit
* unit
, struct PCIDevice
* base
)
303 KPRINTF(10, ("UHCMD_USBSUSPEND ioreq: 0x%p\n", ioreq
));
306 GetUsbState(ioreq
, unit
, base
);
307 if (ioreq
->iouh_State
& UHSF_SUSPENDED
)
311 return UHIOERR_USBOFFLINE
;
315 /* /// "cmdUsbOper()" */
317 *======================================================================
318 * cmdUsbOper(ioreq, unit, base)
319 *======================================================================
321 * This is the device UHCMD_USBOPER routine.
323 * Sets the USB into USBOperational mode.
324 * Must NOT be called from an interrupt.
328 WORD
cmdUsbOper(struct IOUsbHWReq
* ioreq
,
329 struct PCIUnit
* unit
, struct PCIDevice
* base
)
331 KPRINTF(10, ("UHCMD_USBOPER ioreq: 0x%p\n", ioreq
));
334 GetUsbState(ioreq
, unit
, base
);
335 if (ioreq
->iouh_State
& UHSF_OPERATIONAL
)
339 return UHIOERR_USBOFFLINE
;
343 /* /// "cmdQueryDevice()" */
345 *======================================================================
346 * cmdQueryDevice(ioreq, unit, base)
347 *======================================================================
349 * This is the device UHCMD_QUERYDEVICE routine.
351 * Returns information about the hardware.
355 WORD
cmdQueryDevice(struct IOUsbHWReq
* ioreq
,
356 struct PCIUnit
* unit
, struct PCIDevice
* base
)
358 struct TagItem
*taglist
= (struct TagItem
*)ioreq
->iouh_Data
;
362 KPRINTF(10, ("UHCMD_QUERYDEVICE ioreq: 0x%p, taglist: 0x%p\n", ioreq
,
365 while ((tag
= NextTagItem(&taglist
)) != NULL
)
370 *((ULONG
*) tag
->ti_Data
) =
371 (ULONG
) GetUsbState(ioreq
, unit
, base
);
373 case UHA_ProductName
:
374 *((STRPTR
*) tag
->ti_Data
) = unit
->hu_ProductName
;
377 *((IPTR
*) tag
->ti_Data
) =
378 GetTagData(tag
->ti_Tag
, *((IPTR
*) tag
->ti_Data
),
384 ioreq
->iouh_Actual
= count
;
389 WORD
cmdXFer(struct IOUsbHWReq
* ioreq
,
390 struct PCIUnit
* unit
, struct PCIDevice
* base
)
392 struct PCIController
*hc
;
396 switch (ioreq
->iouh_Req
.io_Command
)
398 case UHCMD_CONTROLXFER
:
399 xfer_type
= CTRL_XFER
;
402 xfer_type
= ISO_XFER
;
405 xfer_type
= INT_XFER
;
408 xfer_type
= BULK_XFER
;
412 KPRINTF(10, ("UHCMD_%sXFER ioreq: 0x%p\n", xfer_names
[xfer_type
],
414 GetUsbState(ioreq
, unit
, base
);
415 if (!(ioreq
->iouh_State
& UHSF_OPERATIONAL
))
417 return UHIOERR_USBOFFLINE
;
420 if (xfer_type
== CTRL_XFER
)
422 /* Root Hub Emulation */
423 if (ioreq
->iouh_DevAddr
== unit
->hu_RootHubAddr
)
425 return cmdControlXFerRootHub(ioreq
, unit
, base
);
428 else if (xfer_type
== INT_XFER
)
430 /* Root Hub Emulation */
431 if (ioreq
->iouh_DevAddr
== unit
->hu_RootHubAddr
)
433 return cmdIntXFerRootHub(ioreq
, unit
, base
);
436 else if (xfer_type
== BULK_XFER
|| xfer_type
== ISO_XFER
)
438 if (ioreq
->iouh_Flags
& UHFF_LOWSPEED
)
440 return UHIOERR_BADPARAMS
;
444 hc
= unit
->hu_DevControllers
[ioreq
->iouh_DevAddr
];
447 return UHIOERR_HOSTERROR
;
450 ioreq
->iouh_Req
.io_Flags
&= ~IOF_QUICK
;
451 ioreq
->iouh_Actual
= 0;
452 ioreq
->iouh_DriverPrivate1
= NULL
;
455 AddTail(&hc
->hc_XferQueues
[xfer_type
], (struct Node
*)ioreq
);
457 Cause(&hc
->hc_CompleteInt
);
459 KPRINTF(10, ("UHCMD_%sXFER processed ioreq: 0x%p\n",
460 xfer_names
[xfer_type
], ioreq
));
465 /* /// "cmdFlush()" */
467 *======================================================================
468 * cmdFlush(ioreq, base)
469 *======================================================================
471 * This is the device CMD_FLUSH routine.
473 * This routine abort all pending transfer requests.
477 WORD
cmdFlush(struct IOUsbHWReq
* ioreq
,
478 struct PCIUnit
* unit
, struct PCIDevice
* base
)
480 struct IOUsbHWReq
*cmpioreq
;
481 struct PCIController
*hc
;
485 KPRINTF(10, ("CMD_FLUSH ioreq: 0x%p\n", ioreq
));
488 cmpioreq
= (struct IOUsbHWReq
*)unit
->hu_RHIOQueue
.lh_Head
;
489 while (((struct Node
*)cmpioreq
)->ln_Succ
)
491 Remove(&cmpioreq
->iouh_Req
.io_Message
.mn_Node
);
492 cmpioreq
->iouh_Req
.io_Error
= IOERR_ABORTED
;
493 ReplyMsg(&cmpioreq
->iouh_Req
.io_Message
);
494 cmpioreq
= (struct IOUsbHWReq
*)unit
->hu_RHIOQueue
.lh_Head
;
496 hc
= (struct PCIController
*)unit
->hu_Controllers
.lh_Head
;
497 while (hc
->hc_Node
.ln_Succ
)
499 for (i
= 0; i
< XFER_COUNT
; i
++)
501 list
= (struct List
*)&hc
->hc_XferQueues
[i
];
502 while ((cmpioreq
= (struct IOUsbHWReq
*)RemHead(list
)) != NULL
)
504 cmpioreq
->iouh_Req
.io_Error
= IOERR_ABORTED
;
505 ReplyMsg(&cmpioreq
->iouh_Req
.io_Message
);
508 hc
= (struct PCIController
*)hc
->hc_Node
.ln_Succ
;
517 /* /// "NSD stuff" */
519 static const UWORD NSDSupported
[] = {
520 CMD_FLUSH
, CMD_RESET
,
521 UHCMD_QUERYDEVICE
, UHCMD_USBRESET
,
522 UHCMD_USBRESUME
, UHCMD_USBSUSPEND
,
523 UHCMD_USBOPER
, UHCMD_CONTROLXFER
,
524 UHCMD_ISOXFER
, UHCMD_INTXFER
,
529 WORD
cmdNSDeviceQuery(struct IOStdReq
*ioreq
,
530 struct PCIUnit
*unit
, struct PCIDevice
*base
)
532 struct my_NSDeviceQueryResult
*query
;
534 query
= (struct my_NSDeviceQueryResult
*)ioreq
->io_Data
;
536 KPRINTF(10, ("NSCMD_DEVICEQUERY ioreq: 0x%p query: 0x%p\n", ioreq
,
544 (ioreq
->io_Length
< sizeof(struct my_NSDeviceQueryResult
)) ||
545 (query
->DevQueryFormat
!= 0) || (query
->SizeAvailable
!= 0))
547 /* Return error. This is special handling, since iorequest is only
548 guaranteed to be sizeof(struct IOStdReq). If we'd let our
549 devBeginIO dispatcher return the error, it would trash some
550 memory past end of the iorequest (ios2_WireError field).
552 ioreq
->io_Error
= IOERR_NOCMD
;
553 TermIO((struct IOUsbHWReq
*)ioreq
, base
);
555 /* Don't reply, we already did.
560 ioreq
->io_Actual
= query
->SizeAvailable
561 = sizeof(struct my_NSDeviceQueryResult
);
562 query
->DeviceType
= NSDEVTYPE_USBHARDWARE
;
563 query
->DeviceSubType
= 0;
564 query
->SupportedCommands
= NSDSupported
;
566 /* Return success (note that this will NOT poke ios2_WireError).
574 *===========================================================
575 * TermIO(ioreq, base)
576 *===========================================================
578 * Return completed ioreq to sender.
582 void TermIO(struct IOUsbHWReq
*ioreq
, struct PCIDevice
*base
)
584 ioreq
->iouh_Req
.io_Message
.mn_Node
.ln_Type
= NT_FREEMSG
;
586 /* If not quick I/O, reply the message
588 if (!(ioreq
->iouh_Req
.io_Flags
& IOF_QUICK
))
590 ReplyMsg(&ioreq
->iouh_Req
.io_Message
);
595 /* /// "cmdAbortIO()" */
596 BOOL
cmdAbortIO(struct IOUsbHWReq
*ioreq
, struct PCIDevice
*base
)
598 struct PCIUnit
*unit
= (struct PCIUnit
*)ioreq
->iouh_Req
.io_Unit
;
599 struct IOUsbHWReq
*cmpioreq
;
600 struct PCIController
*hc
;
601 BOOL foundit
= FALSE
;
604 KPRINTF(10, ("cmdAbort(%p)\n", ioreq
));
607 cmpioreq
= (struct IOUsbHWReq
*)unit
->hu_RHIOQueue
.lh_Head
;
608 while (((struct Node
*)cmpioreq
)->ln_Succ
)
610 if (ioreq
== cmpioreq
)
612 Remove(&ioreq
->iouh_Req
.io_Message
.mn_Node
);
614 ioreq
->iouh_Req
.io_Error
= IOERR_ABORTED
;
619 (struct IOUsbHWReq
*)cmpioreq
->iouh_Req
.io_Message
.
623 hc
= (struct PCIController
*)unit
->hu_Controllers
.lh_Head
;
624 while (hc
->hc_Node
.ln_Succ
)
626 for (i
= 0; i
< XFER_COUNT
&& !foundit
; i
++)
629 (struct IOUsbHWReq
*)hc
->hc_XferQueues
[i
].lh_Head
;
630 ((struct Node
*)cmpioreq
)->ln_Succ
!= NULL
&& !foundit
;
632 (struct IOUsbHWReq
*)cmpioreq
->iouh_Req
.io_Message
.
635 if (ioreq
== cmpioreq
)
641 // IOReq is probably pending in some transfer structure
642 cmpioreq
= (struct IOUsbHWReq
*)hc
->hc_TDQueue
.lh_Head
;
643 while (((struct Node
*)cmpioreq
)->ln_Succ
)
645 if (ioreq
== cmpioreq
)
648 * Request's ED is in use by the HC, as well as its TDs
650 * Schedule abort on the HC driver and reply the request
651 * only when done. However return success.
653 ioreq
->iouh_Req
.io_Error
= IOERR_ABORTED
;
654 AbortRequest(hc
, ioreq
);
659 (struct IOUsbHWReq
*)cmpioreq
->iouh_Req
.
660 io_Message
.mn_Node
.ln_Succ
;
667 Remove(&ioreq
->iouh_Req
.io_Message
.mn_Node
);
670 hc
= (struct PCIController
*)hc
->hc_Node
.ln_Succ
;
676 ioreq
->iouh_Req
.io_Error
= IOERR_ABORTED
;
681 KPRINTF(20, ("WARNING, could not abort unknown IOReq %p\n", ioreq
));
687 /* /// "CheckSpecialCtrlTransfers()" */
688 void CheckSpecialCtrlTransfers(struct PCIController
*hc
,
689 struct IOUsbHWReq
*ioreq
)
691 struct PCIUnit
*unit
= hc
->hc_Unit
;
693 /* Clear Feature(Endpoint halt) */
694 if ((ioreq
->iouh_SetupData
.bmRequestType
==
695 (URTF_STANDARD
| URTF_ENDPOINT
))
696 && (ioreq
->iouh_SetupData
.bRequest
== USR_CLEAR_FEATURE
)
697 && (ioreq
->iouh_SetupData
.wValue
==
698 AROS_WORD2LE(UFS_ENDPOINT_HALT
)))
700 KPRINTF(10, ("Resetting toggle bit for endpoint %ld\n",
701 AROS_WORD2LE(ioreq
->iouh_SetupData
.wIndex
) & 0xf));
703 hu_DevDataToggle
[(ioreq
->iouh_DevAddr
<< 5) |
704 (AROS_WORD2LE(ioreq
->
705 iouh_SetupData
.wIndex
) & 0xf) | ((AROS_WORD2LE(ioreq
->
706 iouh_SetupData
.wIndex
) & 0x80) >> 3)] = 0;
708 else if ((ioreq
->iouh_SetupData
.bmRequestType
==
709 (URTF_STANDARD
| URTF_DEVICE
))
710 && (ioreq
->iouh_SetupData
.bRequest
== USR_SET_ADDRESS
))
712 /* Set Address -> clear all endpoints */
714 ULONG adr
= AROS_WORD2BE(ioreq
->iouh_SetupData
.wValue
) >> 3;
715 KPRINTF(10, ("Resetting toggle bits for device address %ld\n",
717 for (epnum
= 0; epnum
< 31; epnum
++)
719 unit
->hu_DevDataToggle
[adr
+ epnum
] = 0;
721 // transfer host controller ownership
722 unit
->hu_DevControllers
[ioreq
->iouh_DevAddr
] = NULL
;
723 unit
->hu_DevControllers
[adr
>> 5] = hc
;
725 else if ((ioreq
->iouh_SetupData
.bmRequestType
==
726 (URTF_CLASS
| URTF_OTHER
))
727 && (ioreq
->iouh_SetupData
.bRequest
== USR_SET_FEATURE
)
728 && (ioreq
->iouh_SetupData
.wValue
== AROS_WORD2LE(UFS_PORT_RESET
)))
730 // a hub will be enumerating a device on this host controller soon!
731 KPRINTF(10, ("Hub RESET caught, assigning Dev0 to %p!\n", hc
));
732 unit
->hu_DevControllers
[0] = hc
;
737 /* /// "NakTimeoutInt()" */
738 AROS_INTH1(NakTimeoutInt
, struct PCIUnit
*, unit
)
742 struct PCIController
*hc
;
743 struct IOUsbHWReq
*ioreq
;
747 KPRINTF(1, ("Enter NakTimeoutInt(0x%p)\n", unit
));
749 // check for NAK Timeouts
750 hc
= (struct PCIController
*)unit
->hu_Controllers
.lh_Head
;
751 while (hc
->hc_Node
.ln_Succ
)
753 if (!(hc
->hc_Flags
& HCF_ONLINE
))
755 hc
= (struct PCIController
*)hc
->hc_Node
.ln_Succ
;
758 UpdateFrameCounter(hc
);
759 framecnt
= hc
->hc_FrameCounter
;
761 ioreq
= (struct IOUsbHWReq
*)hc
->hc_TDQueue
.lh_Head
;
762 while (((struct Node
*)ioreq
)->ln_Succ
)
764 // Remember the successor because AbortRequest() will move the request to another list
765 struct IOUsbHWReq
*succ
=
766 (struct IOUsbHWReq
*)ioreq
->iouh_Req
.io_Message
.
769 if (ioreq
->iouh_Flags
& UHFF_NAKTIMEOUT
)
771 KPRINTF(1, ("Examining IOReq=%p with OED=%p\n", ioreq
,
772 ioreq
->iouh_DriverPrivate1
));
773 if (ioreq
->iouh_DriverPrivate1
)
776 ("CTRL=%04lx, CMD=%01lx, F=%ld, hccaDH=%08lx, "
777 "hcDH=%08lx, CH=%08lx, CCH=%08lx, "
778 "IntStatus=%08lx, IntEn=%08lx\n",
779 READREG32_LE(hc
->hc_RegBase
, OHCI_CONTROL
),
780 READREG32_LE(hc
->hc_RegBase
, OHCI_CMDSTATUS
),
781 READREG32_LE(hc
->hc_RegBase
, OHCI_FRAMECOUNT
),
782 READMEM32_LE(&hc
->hc_HCCA
->ha_DoneHead
),
783 READREG32_LE(hc
->hc_RegBase
, OHCI_DONEHEAD
),
784 READREG32_LE(hc
->hc_RegBase
, OHCI_CTRL_HEAD_ED
),
785 READREG32_LE(hc
->hc_RegBase
, OHCI_CTRL_ED
),
786 READREG32_LE(hc
->hc_RegBase
, OHCI_INTSTATUS
),
787 READREG32_LE(hc
->hc_RegBase
, OHCI_INTEN
)));
790 (ioreq
->iouh_DevAddr
<< 5) + ioreq
->iouh_Endpoint
+
791 ((ioreq
->iouh_Dir
== UHDIR_IN
) ? 0x10 : 0);
792 if (framecnt
> unit
->hu_NakTimeoutFrame
[target
])
794 // give the thing the chance to exit gracefully
796 ("HC 0x%p NAK timeout %ld > %ld, IOReq=%p\n",
798 unit
->hu_NakTimeoutFrame
[target
], ioreq
));
799 ioreq
->iouh_Req
.io_Error
= UHIOERR_NAKTIMEOUT
;
800 AbortRequest(hc
, ioreq
);
807 hc
= (struct PCIController
*)hc
->hc_Node
.ln_Succ
;
810 CheckRootHubChanges(unit
);
812 unit
->hu_NakTimeoutReq
.tr_time
.tv_micro
= 150 * 1000;
813 SendIO((APTR
) & unit
->hu_NakTimeoutReq
);
815 KPRINTF(1, ("Exit NakTimeoutInt(0x%p)\n", unit
));