Fixed weird formatting.
[AROS.git] / rom / usb / pciusbhc / ohci / cmd.c
blob911e84d5f6097a923b6f0bf2da4a8f532de86ac0
1 /*
2 Copyright © 2002-2009, Chris Hodges. All rights reserved.
3 Copyright © 2009-2012, The AROS Development Team. All rights reserved.
4 $Id$
5 */
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>
14 #include "debug.h"
16 #include "cmd_protos.h"
17 #include "roothub_protos.h"
18 #include "chip_protos.h"
19 #include "pci_protos.h"
21 #include "pci.h"
22 #include "chip.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"},
41 {UHA_Copyright,
42 (IPTR) "©2007-2012 Chris Hodges,\n AROS Development Team"},
43 {UHA_Version, VERSION_NUMBER},
44 {UHA_Revision, REVISION_NUMBER},
45 {UHA_DriverVersion, 0x220},
46 {TAG_END, 0}
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 =
62 "PCI hardware";
63 unit->hu_TimerReq->tr_node.io_Command = TR_ADDREQUEST;
64 KPRINTF(1, ("opened timer device\n"));
65 return TRUE;
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"));
74 return FALSE;
76 /* \\\ */
78 /* /// "DelayMS()" */
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);
85 /* \\\ */
87 /* /// "CloseTimer()" */
88 static void CloseTimer(struct PCIUnit *unit, struct PCIDevice *base)
90 if (unit->hu_MsgPort)
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;
103 /* \\\ */
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;
114 if (!pciInit(base))
116 return NULL;
119 unit = (struct PCIUnit *)base->hd_Units.lh_Head;
120 while (((struct Node *)unit)->ln_Succ)
122 if (unit->hu_UnitNo == unitnr)
124 break;
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));
131 return NULL;
133 if (unit->hu_UnitAllocated)
135 ioreq->iouh_Req.io_Error = IOERR_UNITBUSY;
136 KPRINTF(5, ("Unit %ld already open!\n", unitnr));
137 return NULL;
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;
163 else
165 ioreq->iouh_Req.io_Error = IOERR_SELFTEST;
166 KPRINTF(20, ("Hardware allocation failure!\n"));
168 CloseTimer(unit, base);
170 return NULL;
172 /* \\\ */
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);
183 pciFreeUnit(unit);
185 CloseTimer(unit, base);
186 unit->hu_UnitAllocated = FALSE;
188 /* \\\ */
190 /* /// "GetUsbState()" */
191 static UWORD GetUsbState(struct IOUsbHWReq *ioreq,
192 struct PCIUnit *unit, struct PCIDevice *base)
194 return ioreq->iouh_State = UHSF_OPERATIONAL;
196 /* \\\ */
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));
216 DelayMS(1, unit);
217 GetUsbState(ioreq, unit, base);
219 if (ioreq->iouh_State & UHSF_OPERATIONAL)
221 return RC_OK;
223 return UHIOERR_USBOFFLINE;
225 /* \\\ */
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));
245 /* FIXME */
246 GetUsbState(ioreq, unit, base);
248 unit->hu_FrameCounter = 1;
249 unit->hu_RootHubAddr = 0;
251 if (ioreq->iouh_State & UHSF_OPERATIONAL)
253 return RC_OK;
255 return UHIOERR_USBOFFLINE;
257 /* \\\ */
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));
277 /* FIXME */
278 GetUsbState(ioreq, unit, base);
279 if (ioreq->iouh_State & UHSF_OPERATIONAL)
281 return RC_OK;
283 return UHIOERR_USBOFFLINE;
285 /* \\\ */
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));
305 /* FIXME */
306 GetUsbState(ioreq, unit, base);
307 if (ioreq->iouh_State & UHSF_SUSPENDED)
309 return RC_OK;
311 return UHIOERR_USBOFFLINE;
313 /* \\\ */
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));
333 /* FIXME */
334 GetUsbState(ioreq, unit, base);
335 if (ioreq->iouh_State & UHSF_OPERATIONAL)
337 return RC_OK;
339 return UHIOERR_USBOFFLINE;
341 /* \\\ */
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;
359 struct TagItem *tag;
360 ULONG count = 0;
362 KPRINTF(10, ("UHCMD_QUERYDEVICE ioreq: 0x%p, taglist: 0x%p\n", ioreq,
363 taglist));
365 while ((tag = NextTagItem(&taglist)) != NULL)
367 switch (tag->ti_Tag)
369 case UHA_State:
370 *((ULONG *) tag->ti_Data) =
371 (ULONG) GetUsbState(ioreq, unit, base);
372 break;
373 case UHA_ProductName:
374 *((STRPTR *) tag->ti_Data) = unit->hu_ProductName;
375 break;
376 default:
377 *((IPTR *) tag->ti_Data) =
378 GetTagData(tag->ti_Tag, *((IPTR *) tag->ti_Data),
379 query_tags);
381 count++;
384 ioreq->iouh_Actual = count;
385 return RC_OK;
387 /* \\\ */
389 WORD cmdXFer(struct IOUsbHWReq * ioreq,
390 struct PCIUnit * unit, struct PCIDevice * base)
392 struct PCIController *hc;
393 UWORD xfer_type = 0;
395 // get transfer type
396 switch (ioreq->iouh_Req.io_Command)
398 case UHCMD_CONTROLXFER:
399 xfer_type = CTRL_XFER;
400 break;
401 case UHCMD_ISOXFER:
402 xfer_type = ISO_XFER;
403 break;
404 case UHCMD_INTXFER:
405 xfer_type = INT_XFER;
406 break;
407 case UHCMD_BULKXFER:
408 xfer_type = BULK_XFER;
409 break;
412 KPRINTF(10, ("UHCMD_%sXFER ioreq: 0x%p\n", xfer_names[xfer_type],
413 ioreq));
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];
445 if (!hc)
447 return UHIOERR_HOSTERROR;
450 ioreq->iouh_Req.io_Flags &= ~IOF_QUICK;
451 ioreq->iouh_Actual = 0;
452 ioreq->iouh_DriverPrivate1 = NULL;
454 Disable();
455 AddTail(&hc->hc_XferQueues[xfer_type], (struct Node *)ioreq);
456 Enable();
457 Cause(&hc->hc_CompleteInt);
459 KPRINTF(10, ("UHCMD_%sXFER processed ioreq: 0x%p\n",
460 xfer_names[xfer_type], ioreq));
461 return RC_DONTREPLY;
463 /* \\\ */
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;
482 UWORD i;
483 struct List *list;
485 KPRINTF(10, ("CMD_FLUSH ioreq: 0x%p\n", ioreq));
487 Disable();
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;
510 Enable();
511 /* Return success
513 return RC_OK;
515 /* \\\ */
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,
525 UHCMD_BULKXFER,
526 NSCMD_DEVICEQUERY, 0
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,
537 query));
539 /* NULL ptr?
540 Enough data?
541 Valid request?
543 if ((!query) ||
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.
557 return RC_DONTREPLY;
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).
568 return RC_OK;
570 /* \\\ */
572 /* /// "TermIO()" */
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);
593 /* \\\ */
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;
602 UWORD i;
604 KPRINTF(10, ("cmdAbort(%p)\n", ioreq));
606 Disable();
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);
613 Enable();
614 ioreq->iouh_Req.io_Error = IOERR_ABORTED;
615 TermIO(ioreq, base);
616 return TRUE;
618 cmpioreq =
619 (struct IOUsbHWReq *)cmpioreq->iouh_Req.io_Message.
620 mn_Node.ln_Succ;
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++)
628 for (cmpioreq =
629 (struct IOUsbHWReq *)hc->hc_XferQueues[i].lh_Head;
630 ((struct Node *)cmpioreq)->ln_Succ != NULL && !foundit;
631 cmpioreq =
632 (struct IOUsbHWReq *)cmpioreq->iouh_Req.io_Message.
633 mn_Node.ln_Succ)
635 if (ioreq == cmpioreq)
636 foundit = TRUE;
639 if (!foundit)
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
649 * and data buffers.
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);
655 Enable();
656 return TRUE;
658 cmpioreq =
659 (struct IOUsbHWReq *)cmpioreq->iouh_Req.
660 io_Message.mn_Node.ln_Succ;
662 break;
665 if (foundit)
667 Remove(&ioreq->iouh_Req.io_Message.mn_Node);
668 break;
670 hc = (struct PCIController *)hc->hc_Node.ln_Succ;
672 Enable();
674 if (foundit)
676 ioreq->iouh_Req.io_Error = IOERR_ABORTED;
677 TermIO(ioreq, base);
679 else
681 KPRINTF(20, ("WARNING, could not abort unknown IOReq %p\n", ioreq));
683 return foundit;
685 /* \\\ */
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));
702 unit->
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 */
713 ULONG epnum;
714 ULONG adr = AROS_WORD2BE(ioreq->iouh_SetupData.wValue) >> 3;
715 KPRINTF(10, ("Resetting toggle bits for device address %ld\n",
716 adr >> 5));
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;
735 /* \\\ */
737 /* /// "NakTimeoutInt()" */
738 AROS_INTH1(NakTimeoutInt, struct PCIUnit *, unit)
740 AROS_INTFUNC_INIT
742 struct PCIController *hc;
743 struct IOUsbHWReq *ioreq;
744 UWORD target;
745 ULONG framecnt;
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;
756 continue;
758 UpdateFrameCounter(hc);
759 framecnt = hc->hc_FrameCounter;
760 // NakTimeout
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.
767 mn_Node.ln_Succ;
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)
775 KPRINTF(1,
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)));
789 target =
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
795 KPRINTF(200,
796 ("HC 0x%p NAK timeout %ld > %ld, IOReq=%p\n",
797 hc, framecnt,
798 unit->hu_NakTimeoutFrame[target], ioreq));
799 ioreq->iouh_Req.io_Error = UHIOERR_NAKTIMEOUT;
800 AbortRequest(hc, ioreq);
804 ioreq = succ;
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));
817 return FALSE;
819 AROS_INTFUNC_EXIT
821 /* \\\ */