grub2: bring back build of aros-side grub2 tools
[AROS.git] / rom / usb / pciusb / uhwcmd.c
blobfa22b4e0ec57e4054e9a6ebaa35c13dae232cb20
1 /* uhwcmd.c - pciusb.device by Chris Hodges
2 */
4 #include <devices/usb_hub.h>
5 #include <proto/utility.h>
6 #include <proto/exec.h>
7 #include <proto/timer.h>
9 #include <strings.h>
11 #include "uhwcmd.h"
12 #include "ohciproto.h"
14 #define NewList NEWLIST
16 /* we cannot use AROS_WORD2LE in struct initializer */
17 #if AROS_BIG_ENDIAN
18 #define WORD2LE(w) (UWORD)(((w) >> 8) & 0x00FF) | (((w) << 8) & 0xFF00)
19 #else
20 #define WORD2LE(w) (w)
21 #endif
23 /* Root hub data */
24 const struct UsbStdDevDesc RHDevDesc = { sizeof(struct UsbStdDevDesc), UDT_DEVICE, WORD2LE(0x0110), HUB_CLASSCODE, 0, 0, 8, WORD2LE(0x0000), WORD2LE(0x0000), WORD2LE(0x0100), 1, 2, 0, 1 };
26 const struct UsbStdCfgDesc RHCfgDesc = { 9, UDT_CONFIGURATION, WORD2LE(9+9+7), 1, 1, 3, USCAF_ONE|USCAF_SELF_POWERED, 0 };
27 const struct UsbStdIfDesc RHIfDesc = { 9, UDT_INTERFACE, 0, 0, 1, HUB_CLASSCODE, 0, 0, 4 };
28 const struct UsbStdEPDesc RHEPDesc = { 7, UDT_ENDPOINT, URTF_IN|1, USEAF_INTERRUPT, WORD2LE(8), 255 };
29 const struct UsbHubDesc RHHubDesc = { 9, // 0 Number of bytes in this descriptor, including this byte
30 UDT_HUB, // 1 Descriptor Type, value: 29H for hub descriptor
31 0, // 2 Number of downstream facing ports that this hub supports
32 WORD2LE(UHCF_INDIVID_POWER|UHCF_INDIVID_OVP), // 3 wHubCharacteristics
33 0, // 5 bPwrOn2PwrGood
34 1, // 6 bHubContrCurrent
35 1, // 7 DeviceRemovable (size is variable)
36 0 // x PortPwrCtrlMask (size is variable)
39 const CONST_STRPTR RHStrings[] = { "Chris Hodges", "PCI Root Hub Unit x", "Standard Config", "Hub interface" };
41 /* /// "SureCause()" */
42 void SureCause(struct PCIDevice *base, struct Interrupt *interrupt)
44 /* this is a workaround for the original Cause() function missing tailed calls */
45 Disable();
47 if((interrupt->is_Node.ln_Type == NT_SOFTINT) || (interrupt->is_Node.ln_Type == NT_USER))
49 // signal tailed call
50 interrupt->is_Node.ln_Type = NT_USER;
51 } else {
54 interrupt->is_Node.ln_Type = NT_SOFTINT;
55 Forbid(); // make sure code is not interrupted by other tasks
56 Enable();
57 AROS_INTC1(interrupt->is_Code, interrupt->is_Data);
58 Disable();
59 Permit();
60 } while(interrupt->is_Node.ln_Type != NT_SOFTINT);
61 interrupt->is_Node.ln_Type = NT_INTERRUPT;
63 Enable();
65 /* \\\ */
67 /* /// "uhwOpenTimer()" */
68 BOOL uhwOpenTimer(struct PCIUnit *unit, struct PCIDevice *base)
70 if((unit->hu_MsgPort = CreateMsgPort()))
72 if((unit->hu_TimerReq = (struct timerequest *) CreateIORequest(unit->hu_MsgPort, sizeof(struct timerequest))))
74 if(!OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest *) unit->hu_TimerReq, 0))
76 unit->hu_TimerReq->tr_node.io_Message.mn_Node.ln_Name = "PCI hardware";
77 unit->hu_TimerReq->tr_node.io_Command = TR_ADDREQUEST;
78 KPRINTF(1, ("opened timer device\n"));
79 return(TRUE);
81 DeleteIORequest((struct IORequest *) unit->hu_TimerReq);
82 unit->hu_TimerReq = NULL;
84 DeleteMsgPort(unit->hu_MsgPort);
85 unit->hu_MsgPort = NULL;
87 KPRINTF(5, ("failed to open timer.device\n"));
88 return(FALSE);
90 /* \\\ */
92 /* /// "uhwDelayMS()" */
93 void uhwDelayMS(ULONG milli, struct PCIUnit *unit)
95 unit->hu_TimerReq->tr_time.tv_secs = 0;
96 unit->hu_TimerReq->tr_time.tv_micro = milli * 1000;
97 DoIO((struct IORequest *) unit->hu_TimerReq);
99 /* \\\ */
101 /* /// "uhwDelayMicro()" */
102 void uhwDelayMicro(ULONG micro, struct PCIUnit *unit)
104 unit->hu_TimerReq->tr_time.tv_secs = 0;
105 unit->hu_TimerReq->tr_time.tv_micro = micro;
106 DoIO((struct IORequest *) unit->hu_TimerReq);
108 /* \\\ */
110 /* /// "uhwCloseTimer()" */
111 void uhwCloseTimer(struct PCIUnit *unit, struct PCIDevice *base)
113 if(unit->hu_MsgPort)
115 if(unit->hu_TimerReq)
117 KPRINTF(1, ("closing timer.device\n"));
118 CloseDevice((APTR) unit->hu_TimerReq);
119 DeleteIORequest((struct IORequest *) unit->hu_TimerReq);
120 unit->hu_TimerReq = NULL;
122 DeleteMsgPort(unit->hu_MsgPort);
123 unit->hu_MsgPort = NULL;
126 /* \\\ */
128 /* /// "Open_Unit()" */
129 struct Unit * Open_Unit(struct IOUsbHWReq *ioreq,
130 LONG unitnr,
131 struct PCIDevice *base)
133 struct PCIUnit *unit = NULL;
135 if(!base->hd_ScanDone)
137 base->hd_ScanDone = TRUE;
138 if(!pciInit(base))
140 return NULL;
143 unit = (struct PCIUnit *) base->hd_Units.lh_Head;
144 while(((struct Node *) unit)->ln_Succ)
146 if(unit->hu_UnitNo == unitnr)
148 break;
150 unit = (struct PCIUnit *) ((struct Node *) unit)->ln_Succ;
152 if(!((struct Node *) unit)->ln_Succ)
154 KPRINTF(20, ("Unit %ld does not exist!\n", unitnr));
155 return NULL;
157 if(unit->hu_UnitAllocated)
159 ioreq->iouh_Req.io_Error = IOERR_UNITBUSY;
160 KPRINTF(5, ("Unit %ld already open!\n", unitnr));
161 return NULL;
164 if(uhwOpenTimer(unit, base))
167 if(pciAllocUnit(unit)) // hardware self test
169 unit->hu_UnitAllocated = TRUE;
170 unit->hu_NakTimeoutInt.is_Node.ln_Type = NT_INTERRUPT;
171 unit->hu_NakTimeoutInt.is_Node.ln_Name = "PCI NakTimeout";
172 unit->hu_NakTimeoutInt.is_Node.ln_Pri = -16;
173 unit->hu_NakTimeoutInt.is_Data = unit;
174 unit->hu_NakTimeoutInt.is_Code = (VOID_FUNC)uhwNakTimeoutInt;
176 CopyMem(unit->hu_TimerReq, &unit->hu_NakTimeoutReq, sizeof(struct timerequest));
177 unit->hu_NakTimeoutReq.tr_node.io_Message.mn_ReplyPort = &unit->hu_NakTimeoutMsgPort;
178 unit->hu_NakTimeoutMsgPort.mp_Node.ln_Type = NT_MSGPORT;
179 unit->hu_NakTimeoutMsgPort.mp_Flags = PA_SOFTINT;
180 unit->hu_NakTimeoutMsgPort.mp_SigTask = &unit->hu_NakTimeoutInt;
181 NewList(&unit->hu_NakTimeoutMsgPort.mp_MsgList);
182 Cause(&unit->hu_NakTimeoutInt);
183 return(&unit->hu_Unit);
184 } else {
185 ioreq->iouh_Req.io_Error = IOERR_SELFTEST;
186 KPRINTF(20, ("Hardware allocation failure!\n"));
188 uhwCloseTimer(unit, base);
190 return(NULL);
192 /* \\\ */
194 /* /// "Close_Unit()" */
195 void Close_Unit(struct PCIDevice *base,
196 struct PCIUnit *unit,
197 struct IOUsbHWReq *ioreq)
199 /* Disable all interrupts */
200 unit->hu_NakTimeoutMsgPort.mp_Flags = PA_IGNORE;
201 unit->hu_NakTimeoutInt.is_Node.ln_Type = NT_SOFTINT;
202 AbortIO((APTR) &unit->hu_NakTimeoutReq);
204 pciFreeUnit(unit);
206 uhwCloseTimer(unit, base);
207 unit->hu_UnitAllocated = FALSE;
209 /* \\\ */
211 /* /// "uhwGetUsbState()" */
212 UWORD uhwGetUsbState(struct IOUsbHWReq *ioreq,
213 struct PCIUnit *unit,
214 struct PCIDevice *base)
216 return(ioreq->iouh_State = UHSF_OPERATIONAL);
218 /* \\\ */
220 /* /// "cmdReset()" */
222 *======================================================================
223 * cmdReset(ioreq, unit, base)
224 *======================================================================
226 * This is the device CMD_RESET routine.
228 * Resets the whole USB hardware. Goes into USBOperational mode right
229 * after. Must NOT be called from an interrupt.
233 WORD cmdReset(struct IOUsbHWReq *ioreq,
234 struct PCIUnit *unit,
235 struct PCIDevice *base)
237 KPRINTF(10, ("CMD_RESET ioreq: 0x%p\n", ioreq));
239 uhwDelayMS(1, unit);
240 uhwGetUsbState(ioreq, unit, base);
242 if(ioreq->iouh_State & UHSF_OPERATIONAL)
244 return RC_OK;
246 return UHIOERR_USBOFFLINE;
248 /* \\\ */
250 /* /// "cmdUsbReset()" */
252 *======================================================================
253 * cmdUsbReset(ioreq, unit, base)
254 *======================================================================
256 * This is the device UHCMD_USBRESET routine.
258 * Resets the USB bus. Goes into USBOperational mode right after. Must
259 * NOT be called from an interrupt.
263 WORD cmdUsbReset(struct IOUsbHWReq *ioreq,
264 struct PCIUnit *unit,
265 struct PCIDevice *base)
267 KPRINTF(10, ("UHCMD_USBRESET ioreq: 0x%p\n", ioreq));
269 /* FIXME */
270 uhwGetUsbState(ioreq, unit, base);
272 unit->hu_FrameCounter = 1;
273 unit->hu_RootHubAddr = 0;
275 if(ioreq->iouh_State & UHSF_OPERATIONAL)
277 return RC_OK;
279 return UHIOERR_USBOFFLINE;
281 /* \\\ */
283 /* /// "cmdUsbResume()" */
285 *======================================================================
286 * cmdUsbResume(ioreq, unit, base)
287 *======================================================================
289 * This is the device UHCMD_USBRESUME routine.
291 * Tries to resume from USBSuspend mode into USBOperational.
292 * Must NOT be called from an interrupt.
296 WORD cmdUsbResume(struct IOUsbHWReq *ioreq,
297 struct PCIUnit *unit,
298 struct PCIDevice *base)
300 KPRINTF(10, ("UHCMD_USBRESUME ioreq: 0x%p\n", ioreq));
302 /* FIXME */
303 uhwGetUsbState(ioreq, unit, base);
304 if(ioreq->iouh_State & UHSF_OPERATIONAL)
306 return RC_OK;
308 return UHIOERR_USBOFFLINE;
310 /* \\\ */
312 /* /// "cmdUsbSuspend()" */
314 *======================================================================
315 * cmdUsbSuspend(ioreq, unit, base)
316 *======================================================================
318 * This is the device UHCMD_USBSUSPEND routine.
320 * Sets the USB into USBSuspend mode.
321 * Must NOT be called from an interrupt.
325 WORD cmdUsbSuspend(struct IOUsbHWReq *ioreq,
326 struct PCIUnit *unit,
327 struct PCIDevice *base)
329 KPRINTF(10, ("UHCMD_USBSUSPEND ioreq: 0x%p\n", ioreq));
331 /* FIXME */
332 uhwGetUsbState(ioreq, unit, base);
333 if(ioreq->iouh_State & UHSF_SUSPENDED)
335 return RC_OK;
337 return UHIOERR_USBOFFLINE;
339 /* \\\ */
341 /* /// "cmdUsbOper()" */
343 *======================================================================
344 * cmdUsbOper(ioreq, unit, base)
345 *======================================================================
347 * This is the device UHCMD_USBOPER routine.
349 * Sets the USB into USBOperational mode.
350 * Must NOT be called from an interrupt.
354 WORD cmdUsbOper(struct IOUsbHWReq *ioreq,
355 struct PCIUnit *unit,
356 struct PCIDevice *base)
358 KPRINTF(10, ("UHCMD_USBOPER ioreq: 0x%p\n", ioreq));
360 /* FIXME */
361 uhwGetUsbState(ioreq, unit, base);
362 if(ioreq->iouh_State & UHSF_OPERATIONAL)
364 return RC_OK;
366 return UHIOERR_USBOFFLINE;
368 /* \\\ */
370 /* /// "cmdQueryDevice()" */
372 *======================================================================
373 * cmdQueryDevice(ioreq, unit, base)
374 *======================================================================
376 * This is the device UHCMD_QUERYDEVICE routine.
378 * Returns information about the hardware.
382 WORD cmdQueryDevice(struct IOUsbHWReq *ioreq,
383 struct PCIUnit *unit,
384 struct PCIDevice *base)
386 struct TagItem *taglist = (struct TagItem *) ioreq->iouh_Data;
387 struct TagItem *tag;
388 ULONG count = 0;
390 KPRINTF(10, ("UHCMD_QUERYDEVICE ioreq: 0x%p, taglist: 0x%p\n", ioreq, taglist));
392 if((tag = FindTagItem(UHA_State, taglist)))
394 *((ULONG *) tag->ti_Data) = (ULONG) uhwGetUsbState(ioreq, unit, base);
395 count++;
397 if((tag = FindTagItem(UHA_Manufacturer, taglist)))
399 *((STRPTR *) tag->ti_Data) = "Chris Hodges";
400 count++;
402 if((tag = FindTagItem(UHA_ProductName, taglist)))
404 *((STRPTR *) tag->ti_Data) = unit->hu_ProductName;
405 count++;
407 if((tag = FindTagItem(UHA_Description, taglist)))
409 *((STRPTR *) tag->ti_Data) = "Generic adaptive host controller driver for PCI cards";
410 count++;
412 if((tag = FindTagItem(UHA_Copyright, taglist)))
414 *((STRPTR *) tag->ti_Data) ="©2007-2009 Chris Hodges";
415 count++;
417 if((tag = FindTagItem(UHA_Version, taglist)))
419 *((ULONG *) tag->ti_Data) = VERSION_NUMBER;
420 count++;
422 if((tag = FindTagItem(UHA_Revision, taglist)))
424 *((ULONG *) tag->ti_Data) = REVISION_NUMBER;
425 count++;
427 if((tag = FindTagItem(UHA_DriverVersion, taglist)))
429 *((ULONG *) tag->ti_Data) = 0x220;
430 count++;
432 if((tag = FindTagItem(UHA_Capabilities, taglist)))
434 *((ULONG *) tag->ti_Data) = UHCF_USB20;
435 count++;
437 ioreq->iouh_Actual = count;
438 return RC_OK;
440 /* \\\ */
442 /* /// "cmdControlXFerRootHub()" */
443 WORD cmdControlXFerRootHub(struct IOUsbHWReq *ioreq,
444 struct PCIUnit *unit,
445 struct PCIDevice *base)
447 struct PCIController *hc;
448 struct PCIController *chc;
449 UWORD rt = ioreq->iouh_SetupData.bmRequestType;
450 UWORD req = ioreq->iouh_SetupData.bRequest;
451 UWORD idx = AROS_WORD2LE(ioreq->iouh_SetupData.wIndex);
452 UWORD val = AROS_WORD2LE(ioreq->iouh_SetupData.wValue);
453 UWORD len = AROS_WORD2LE(ioreq->iouh_SetupData.wLength);
454 UWORD hciport;
455 ULONG numports = unit->hu_RootHubPorts;
456 BOOL cmdgood;
457 ULONG cnt;
459 if(ioreq->iouh_Endpoint)
461 return(UHIOERR_STALL);
464 if(len != ioreq->iouh_Length)
466 KPRINTF(20, ("RH: Len (%ld != %ld) mismatch!\n", len != ioreq->iouh_Length));
467 return(UHIOERR_STALL);
469 switch(rt)
471 case (URTF_STANDARD|URTF_DEVICE):
472 switch(req)
474 case USR_SET_ADDRESS:
475 KPRINTF(1, ("RH: SetAddress = %ld\n", val));
476 unit->hu_RootHubAddr = val;
477 ioreq->iouh_Actual = len;
478 return(0);
480 case USR_SET_CONFIGURATION:
481 KPRINTF(1, ("RH: SetConfiguration=%ld\n", val));
482 ioreq->iouh_Actual = len;
483 return(0);
485 break;
487 case (URTF_IN|URTF_STANDARD|URTF_DEVICE):
488 switch(req)
490 case USR_GET_DESCRIPTOR:
491 switch(val>>8)
493 case UDT_DEVICE:
494 KPRINTF(1, ("RH: GetDeviceDescriptor (%ld)\n", len));
495 ioreq->iouh_Actual = (len > sizeof(struct UsbStdDevDesc)) ? sizeof(struct UsbStdDevDesc) : len;
496 CopyMem((APTR) &RHDevDesc, ioreq->iouh_Data, ioreq->iouh_Actual);
497 if(ioreq->iouh_Length >= sizeof(struct UsbStdDevDesc))
499 if(unit->hu_RootHub20Ports)
501 struct UsbStdDevDesc *usdd = (struct UsbStdDevDesc *) ioreq->iouh_Data;
502 usdd->bcdUSB = AROS_WORD2LE(0x0200); // signal a highspeed root hub
503 usdd->bDeviceProtocol = 1; // single TT
507 return(0);
509 case UDT_CONFIGURATION:
511 UBYTE tmpbuf[9+9+7];
512 KPRINTF(1, ("RH: GetConfigDescriptor (%ld)\n", len));
513 CopyMem((APTR) &RHCfgDesc, tmpbuf, 9);
514 CopyMem((APTR) &RHIfDesc, &tmpbuf[9], 9);
515 CopyMem((APTR) &RHEPDesc, &tmpbuf[9+9], 7);
516 if(unit->hu_RootHub20Ports)
518 struct UsbStdEPDesc *usepd = (struct UsbStdEPDesc *) &tmpbuf[9+9];
519 usepd->bInterval = 12; // 2048 µFrames
521 ioreq->iouh_Actual = (len > 9+9+7) ? 9+9+7 : len;
522 CopyMem(tmpbuf, ioreq->iouh_Data, ioreq->iouh_Actual);
523 return(0);
526 case UDT_STRING:
527 if(val & 0xff) /* get lang array */
529 CONST_STRPTR source = NULL;
530 UWORD *mptr = ioreq->iouh_Data;
531 UWORD slen = 1;
532 KPRINTF(1, ("RH: GetString %04lx (%ld)\n", val, len));
533 if((val & 0xff) > 4) /* index too high? */
535 return(UHIOERR_STALL);
537 source = RHStrings[(val & 0xff)-1];
538 if(len > 1)
540 ioreq->iouh_Actual = 2;
541 while(*source++)
543 slen++;
545 source = RHStrings[(val & 0xff)-1];
546 *mptr++ = AROS_WORD2BE((slen<<9)|UDT_STRING);
547 while(ioreq->iouh_Actual+1 < len)
549 // special hack for unit number in root hub string
550 if(((val & 0xff) == 2) && (source[1] == 0))
552 *mptr++ = AROS_WORD2LE('0' + unit->hu_UnitNo);
553 } else {
554 *mptr++ = AROS_WORD2LE(*source);
556 source++;
557 ioreq->iouh_Actual += 2;
558 if(!(*source))
560 break;
564 } else {
565 UWORD *mptr = ioreq->iouh_Data;
566 KPRINTF(1, ("RH: GetLangArray %04lx (%ld)\n", val, len));
567 if(len > 1)
569 ioreq->iouh_Actual = 2;
570 mptr[0] = AROS_WORD2BE((4<<8)|UDT_STRING);
571 if(len > 3)
573 ioreq->iouh_Actual += 2;
574 mptr[1] = AROS_WORD2LE(0x0409);
578 return(0);
580 default:
581 KPRINTF(1, ("RH: Unsupported Descriptor %04lx\n", idx));
583 break;
585 case USR_GET_CONFIGURATION:
586 if(len == 1)
588 KPRINTF(1, ("RH: GetConfiguration\n"));
589 ((UBYTE *) ioreq->iouh_Data)[0] = 1;
590 ioreq->iouh_Actual = len;
591 return(0);
593 break;
595 break;
597 case (URTF_CLASS|URTF_OTHER):
598 switch(req)
600 case USR_SET_FEATURE:
601 if((!idx) || (idx > numports))
603 KPRINTF(20, ("Port %ld out of range\n", idx));
604 return(UHIOERR_STALL);
606 chc = unit->hu_PortMap11[idx - 1];
607 if(unit->hu_EhciOwned[idx - 1])
609 hc = unit->hu_PortMap20[idx - 1];
610 hciport = idx - 1;
611 } else {
612 hc = chc;
613 hciport = unit->hu_PortNum11[idx - 1];
615 KPRINTF(10, ("Set Feature %ld maps from glob. Port %ld to local Port %ld (%s)\n", val, idx, hciport, unit->hu_EhciOwned[idx - 1] ? "EHCI" : "U/OHCI"));
616 cmdgood = FALSE;
617 switch(hc->hc_HCIType)
619 case HCITYPE_UHCI:
621 UWORD portreg = hciport ? UHCI_PORT2STSCTRL : UHCI_PORT1STSCTRL;
622 ULONG oldval = READIO16_LE(hc->hc_RegBase, portreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE); // these are clear-on-write!
623 ULONG newval = oldval;
624 switch(val)
626 /* case UFS_PORT_CONNECTION: not possible */
627 case UFS_PORT_ENABLE:
628 KPRINTF(10, ("UHCI: Enabling Port (%s)\n", newval & UHPF_PORTENABLE ? "already" : "ok"));
629 newval |= UHPF_PORTENABLE;
630 cmdgood = TRUE;
631 break;
633 case UFS_PORT_SUSPEND:
634 newval |= UHPF_PORTSUSPEND;
635 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_SUSPEND; // manually fake suspend change
636 cmdgood = TRUE;
637 break;
639 /* case UFS_PORT_OVER_CURRENT: not possible */
640 case UFS_PORT_RESET:
641 KPRINTF(10, ("UHCI: Resetting Port (%s)\n", newval & UHPF_PORTRESET ? "already" : "ok"));
643 // this is an ugly blocking workaround to the inability of UHCI to clear reset automatically
644 newval &= ~(UHPF_PORTSUSPEND|UHPF_PORTENABLE);
645 newval |= UHPF_PORTRESET;
646 WRITEIO16_LE(hc->hc_RegBase, portreg, newval);
647 uhwDelayMS(25, unit);
648 newval = READIO16_LE(hc->hc_RegBase, portreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE|UHPF_PORTSUSPEND|UHPF_PORTENABLE);
649 KPRINTF(10, ("UHCI: Reset=%s\n", newval & UHPF_PORTRESET ? "GOOD" : "BAD!"));
650 // like windows does it
651 newval &= ~UHPF_PORTRESET;
652 WRITEIO16_LE(hc->hc_RegBase, portreg, newval);
653 uhwDelayMicro(50, unit);
654 newval = READIO16_LE(hc->hc_RegBase, portreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE|UHPF_PORTSUSPEND);
655 KPRINTF(10, ("UHCI: Reset=%s\n", newval & UHPF_PORTRESET ? "BAD!" : "GOOD"));
656 newval &= ~(UHPF_PORTSUSPEND|UHPF_PORTRESET);
657 newval |= UHPF_PORTENABLE;
658 WRITEIO16_LE(hc->hc_RegBase, portreg, newval);
659 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_RESET|UPSF_PORT_ENABLE; // manually fake reset change
661 cnt = 100;
664 uhwDelayMS(1, unit);
665 newval = READIO16_LE(hc->hc_RegBase, portreg);
666 } while(--cnt && (!(newval & UHPF_PORTENABLE)));
667 if(cnt)
669 KPRINTF(10, ("UHCI: Enabled after %ld ticks\n", 100-cnt));
670 } else {
671 KPRINTF(20, ("UHCI: Port refuses to be enabled!\n"));
672 return(UHIOERR_HOSTERROR);
674 // make enumeration possible
675 unit->hu_DevControllers[0] = hc;
676 cmdgood = TRUE;
677 break;
679 case UFS_PORT_POWER:
680 KPRINTF(10, ("UHCI: Powering Port\n"));
681 // ignore for UHCI, is always powered
682 cmdgood = TRUE;
683 break;
685 /* case UFS_PORT_LOW_SPEED: not possible */
686 /* case UFS_C_PORT_CONNECTION:
687 case UFS_C_PORT_ENABLE:
688 case UFS_C_PORT_SUSPEND:
689 case UFS_C_PORT_OVER_CURRENT:
690 case UFS_C_PORT_RESET: */
692 if(cmdgood)
694 KPRINTF(5, ("UHCI: Port %ld SET_FEATURE %04lx->%04lx\n", idx, oldval, newval));
695 WRITEIO16_LE(hc->hc_RegBase, portreg, newval);
696 return(0);
698 break;
701 case HCITYPE_OHCI:
703 UWORD portreg = OHCI_PORTSTATUS + (hciport<<2);
704 ULONG oldval = READREG32_LE(hc->hc_RegBase, portreg);
706 switch(val)
708 /* case UFS_PORT_CONNECTION: not possible */
709 case UFS_PORT_ENABLE:
710 KPRINTF(10, ("OHCI: Enabling Port (%s)\n", oldval & OHPF_PORTENABLE ? "already" : "ok"));
711 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTENABLE);
712 cmdgood = TRUE;
713 break;
715 case UFS_PORT_SUSPEND:
716 KPRINTF(10, ("OHCI: Suspending Port (%s)\n", oldval & OHPF_PORTSUSPEND ? "already" : "ok"));
717 //hc->hc_PortChangeMap[hciport] |= UPSF_PORT_SUSPEND; // manually fake suspend change
718 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTSUSPEND);
719 cmdgood = TRUE;
720 break;
722 /* case UFS_PORT_OVER_CURRENT: not possible */
723 case UFS_PORT_RESET:
724 KPRINTF(10, ("OHCI: Resetting Port (%s)\n", oldval & OHPF_PORTRESET ? "already" : "ok"));
725 // make sure we have at least 50ms of reset time here, as required for a root hub port
726 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTRESET);
727 uhwDelayMS(10, unit);
728 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTRESET);
729 uhwDelayMS(10, unit);
730 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTRESET);
731 uhwDelayMS(10, unit);
732 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTRESET);
733 uhwDelayMS(10, unit);
734 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTRESET);
735 uhwDelayMS(15, unit);
736 oldval = READREG32_LE(hc->hc_RegBase, portreg);
737 KPRINTF(10, ("OHCI: Reset release (%s %s)\n", oldval & OHPF_PORTRESET ? "didn't turn off" : "okay",
738 oldval & OHPF_PORTENABLE ? "enabled" : "not enabled"));
739 if(oldval & OHPF_PORTRESET)
741 uhwDelayMS(40, unit);
742 oldval = READREG32_LE(hc->hc_RegBase, portreg);
743 KPRINTF(10, ("OHCI: Reset 2nd release (%s %s)\n", oldval & OHPF_PORTRESET ? "didn't turn off" : "okay",
744 oldval & OHPF_PORTENABLE ? "enabled" : "still not enabled"));
746 // make enumeration possible
747 unit->hu_DevControllers[0] = hc;
748 cmdgood = TRUE;
749 break;
751 case UFS_PORT_POWER:
752 KPRINTF(10, ("OHCI: Powering Port (%s)\n", oldval & OHPF_PORTPOWER ? "already" : "ok"));
753 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTPOWER);
754 cmdgood = TRUE;
755 break;
757 /* case UFS_PORT_LOW_SPEED: not possible */
758 /* case UFS_C_PORT_CONNECTION:
759 case UFS_C_PORT_ENABLE:
760 case UFS_C_PORT_SUSPEND:
761 case UFS_C_PORT_OVER_CURRENT:
762 case UFS_C_PORT_RESET: */
764 if(cmdgood)
766 return(0);
768 break;
771 case HCITYPE_EHCI:
773 UWORD portreg = EHCI_PORTSC1 + (hciport<<2);
774 ULONG oldval = READREG32_LE(hc->hc_RegBase, portreg) & ~(EHPF_OVERCURRENTCHG|EHPF_ENABLECHANGE|EHPF_CONNECTCHANGE); // these are clear-on-write!
775 ULONG newval = oldval;
776 switch(val)
778 /* case UFS_PORT_CONNECTION: not possible */
779 case UFS_PORT_ENABLE:
780 KPRINTF(10, ("EHCI: Enabling Port (%s)\n", newval & EHPF_PORTENABLE ? "already" : "ok"));
781 newval |= EHPF_PORTENABLE;
782 cmdgood = TRUE;
783 break;
785 case UFS_PORT_SUSPEND:
786 newval |= EHPF_PORTSUSPEND;
787 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_SUSPEND; // manually fake suspend change
788 cmdgood = TRUE;
789 break;
791 /* case UFS_PORT_OVER_CURRENT: not possible */
792 case UFS_PORT_RESET:
793 KPRINTF(10, ("EHCI: Resetting Port (%s)\n", newval & EHPF_PORTRESET ? "already" : "ok"));
795 // this is an ugly blocking workaround to the inability of EHCI to clear reset automatically
796 newval &= ~(EHPF_PORTSUSPEND|EHPF_PORTENABLE);
797 newval |= EHPF_PORTRESET;
798 WRITEREG32_LE(hc->hc_RegBase, portreg, newval);
799 uhwDelayMS(50, unit);
800 newval = READREG32_LE(hc->hc_RegBase, portreg) & ~(EHPF_OVERCURRENTCHG|EHPF_ENABLECHANGE|EHPF_CONNECTCHANGE|EHPF_PORTSUSPEND|EHPF_PORTENABLE);
801 KPRINTF(10, ("EHCI: Reset=%s\n", newval & EHPF_PORTRESET ? "GOOD" : "BAD!"));
802 newval &= ~EHPF_PORTRESET;
803 WRITEREG32_LE(hc->hc_RegBase, portreg, newval);
804 uhwDelayMS(10, unit);
805 newval = READREG32_LE(hc->hc_RegBase, portreg) & ~(EHPF_OVERCURRENTCHG|EHPF_ENABLECHANGE|EHPF_CONNECTCHANGE|EHPF_PORTSUSPEND);
806 KPRINTF(10, ("EHCI: Reset=%s\n", newval & EHPF_PORTRESET ? "BAD!" : "GOOD"));
807 KPRINTF(10, ("EHCI: Highspeed=%s\n", newval & EHPF_PORTENABLE ? "YES!" : "NO"));
808 KPRINTF(10, ("EHCI: Port status=%08lx\n", newval));
809 if(!(newval & EHPF_PORTENABLE) && unit->hu_PortMap11[idx - 1] != NULL)
811 // if not highspeed, release ownership
812 KPRINTF(20, ("EHCI: Transferring ownership to UHCI/OHCI port %ld\n", unit->hu_PortNum11[idx - 1]));
813 KPRINTF(10, ("EHCI: Device is %s\n", newval & EHPF_LINESTATUS_DM ? "LOWSPEED" : "FULLSPEED"));
814 newval |= EHPF_NOTPORTOWNER;
815 if(!chc)
817 KPRINTF(20, ("EHCI has no companion controller, can't transfer ownership!\n"));
818 WRITEREG32_LE(hc->hc_RegBase, portreg, newval);
819 return(UHIOERR_HOSTERROR);
821 switch(chc->hc_HCIType)
823 case HCITYPE_UHCI:
825 UWORD uhcihciport = unit->hu_PortNum11[idx - 1];
826 UWORD uhciportreg = uhcihciport ? UHCI_PORT2STSCTRL : UHCI_PORT1STSCTRL;
827 ULONG __unused uhcinewval = READREG16_LE(chc->hc_RegBase, uhciportreg);
829 KPRINTF(10, ("UHCI Port status before handover=%04lx\n", uhcinewval));
830 break;
833 case HCITYPE_OHCI:
835 UWORD ohcihciport = unit->hu_PortNum11[idx - 1];
836 UWORD ohciportreg = OHCI_PORTSTATUS + (ohcihciport<<2);
837 ULONG __unused ohcioldval = READREG32_LE(chc->hc_RegBase, ohciportreg);
839 KPRINTF(10, ("OHCI: Port status before handover=%08lx\n", ohcioldval));
840 KPRINTF(10, ("OHCI: Powering Port (%s)\n", ohcioldval & OHPF_PORTPOWER ? "already" : "ok"));
841 WRITEREG32_LE(chc->hc_RegBase, ohciportreg, OHPF_PORTPOWER);
842 uhwDelayMS(10, unit);
843 KPRINTF(10, ("OHCI: Port status after handover=%08lx\n", READREG32_LE(chc->hc_RegBase, ohciportreg)));
844 break;
847 newval = READREG32_LE(hc->hc_RegBase, portreg) & ~(EHPF_OVERCURRENTCHG|EHPF_ENABLECHANGE|EHPF_CONNECTCHANGE|EHPF_PORTSUSPEND);
848 KPRINTF(10, ("EHCI: Port status (reread)=%08lx\n", newval));
849 newval |= EHPF_NOTPORTOWNER;
850 unit->hu_EhciOwned[idx - 1] = FALSE;
851 WRITEREG32_LE(hc->hc_RegBase, portreg, newval);
852 uhwDelayMS(90, unit);
853 KPRINTF(10, ("EHCI: Port status (after handover)=%08lx\n", READREG32_LE(hc->hc_RegBase, portreg) & ~(EHPF_OVERCURRENTCHG|EHPF_ENABLECHANGE|EHPF_CONNECTCHANGE|EHPF_PORTSUSPEND)));
854 // enable companion controller port
855 switch(chc->hc_HCIType)
857 case HCITYPE_UHCI:
859 UWORD uhcihciport = unit->hu_PortNum11[idx - 1];
860 UWORD uhciportreg = uhcihciport ? UHCI_PORT2STSCTRL : UHCI_PORT1STSCTRL;
861 ULONG uhcinewval;
863 uhcinewval = READIO16_LE(chc->hc_RegBase, uhciportreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE|UHPF_PORTSUSPEND);
864 KPRINTF(10, ("UHCI: Reset=%s\n", uhcinewval & UHPF_PORTRESET ? "BAD!" : "GOOD"));
865 if((uhcinewval & UHPF_PORTRESET))//|| (newval & EHPF_LINESTATUS_DM))
867 // this is an ugly blocking workaround to the inability of UHCI to clear reset automatically
868 KPRINTF(20, ("UHCI: Uhm, reset was bad!\n"));
869 uhcinewval &= ~(UHPF_PORTSUSPEND|UHPF_PORTENABLE);
870 uhcinewval |= UHPF_PORTRESET;
871 WRITEIO16_LE(chc->hc_RegBase, uhciportreg, uhcinewval);
872 uhwDelayMS(50, unit);
873 uhcinewval = READIO16_LE(chc->hc_RegBase, uhciportreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE|UHPF_PORTSUSPEND|UHPF_PORTENABLE);
874 KPRINTF(10, ("UHCI: ReReset=%s\n", uhcinewval & UHPF_PORTRESET ? "GOOD" : "BAD!"));
875 uhcinewval &= ~UHPF_PORTRESET;
876 WRITEIO16_LE(chc->hc_RegBase, uhciportreg, uhcinewval);
877 uhwDelayMicro(50, unit);
878 uhcinewval = READIO16_LE(chc->hc_RegBase, uhciportreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE|UHPF_PORTSUSPEND);
879 KPRINTF(10, ("UHCI: ReReset=%s\n", uhcinewval & UHPF_PORTRESET ? "STILL BAD!" : "GOOD"));
881 uhcinewval &= ~UHPF_PORTRESET;
882 uhcinewval |= UHPF_PORTENABLE;
883 WRITEIO16_LE(chc->hc_RegBase, uhciportreg, uhcinewval);
884 chc->hc_PortChangeMap[uhcihciport] |= UPSF_PORT_RESET|UPSF_PORT_ENABLE; // manually fake reset change
885 uhwDelayMS(5, unit);
886 cnt = 100;
889 uhwDelayMS(1, unit);
890 uhcinewval = READIO16_LE(chc->hc_RegBase, uhciportreg);
891 } while(--cnt && (!(uhcinewval & UHPF_PORTENABLE)));
892 if(cnt)
894 KPRINTF(10, ("UHCI: Enabled after %ld ticks\n", 100-cnt));
895 } else {
896 KPRINTF(20, ("UHCI: Port refuses to be enabled!\n"));
897 return(UHIOERR_HOSTERROR);
899 break;
902 case HCITYPE_OHCI:
904 UWORD ohcihciport = unit->hu_PortNum11[idx - 1];
905 UWORD ohciportreg = OHCI_PORTSTATUS + (ohcihciport<<2);
906 ULONG ohcioldval = READREG32_LE(chc->hc_RegBase, ohciportreg);
907 KPRINTF(10, ("OHCI: Resetting Port (%s)\n", ohcioldval & OHPF_PORTRESET ? "already" : "ok"));
908 // make sure we have at least 50ms of reset time here, as required for a root hub port
909 WRITEREG32_LE(chc->hc_RegBase, ohciportreg, OHPF_PORTRESET);
910 uhwDelayMS(10, unit);
911 WRITEREG32_LE(chc->hc_RegBase, ohciportreg, OHPF_PORTRESET);
912 uhwDelayMS(10, unit);
913 WRITEREG32_LE(chc->hc_RegBase, ohciportreg, OHPF_PORTRESET);
914 uhwDelayMS(10, unit);
915 WRITEREG32_LE(chc->hc_RegBase, ohciportreg, OHPF_PORTRESET);
916 uhwDelayMS(10, unit);
917 WRITEREG32_LE(chc->hc_RegBase, ohciportreg, OHPF_PORTRESET);
918 uhwDelayMS(15, unit);
919 ohcioldval = READREG32_LE(chc->hc_RegBase, ohciportreg);
920 KPRINTF(10, ("OHCI: Reset release (%s %s)\n", ohcioldval & OHPF_PORTRESET ? "didn't turn off" : "okay",
921 ohcioldval & OHPF_PORTENABLE ? "enabled" : "not enabled"));
922 if(ohcioldval & OHPF_PORTRESET)
924 uhwDelayMS(40, unit);
925 ohcioldval = READREG32_LE(chc->hc_RegBase, ohciportreg);
926 KPRINTF(10, ("OHCI: Reset 2nd release (%s %s)\n", ohcioldval & OHPF_PORTRESET ? "didn't turn off" : "okay",
927 ohcioldval & OHPF_PORTENABLE ? "enabled" : "still not enabled"));
929 break;
933 // make enumeration possible
934 unit->hu_DevControllers[0] = chc;
935 return(0);
936 } else {
937 newval &= ~EHPF_PORTRESET;
938 WRITEREG32_LE(hc->hc_RegBase, portreg, newval);
939 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_RESET; // manually fake reset change
940 uhwDelayMS(10, unit);
941 cnt = 100;
944 uhwDelayMS(1, unit);
945 newval = READREG32_LE(hc->hc_RegBase, portreg);
946 } while(--cnt && (!(newval & EHPF_PORTENABLE)));
947 if(cnt)
949 KPRINTF(10, ("EHCI: Enabled after %ld ticks\n", 100-cnt));
950 } else {
951 KPRINTF(20, ("EHCI: Port refuses to be enabled!\n"));
952 return(UHIOERR_HOSTERROR);
954 // make enumeration possible
955 unit->hu_DevControllers[0] = hc;
957 cmdgood = TRUE;
958 break;
960 case UFS_PORT_POWER:
961 KPRINTF(10, ("EHCI: Powering Port\n"));
962 newval |= EHPF_PORTPOWER;
963 cmdgood = TRUE;
964 break;
966 /* case UFS_PORT_LOW_SPEED: not possible */
967 /* case UFS_C_PORT_CONNECTION:
968 case UFS_C_PORT_ENABLE:
969 case UFS_C_PORT_SUSPEND:
970 case UFS_C_PORT_OVER_CURRENT:
971 case UFS_C_PORT_RESET: */
973 if(cmdgood)
975 KPRINTF(5, ("EHCI: Port %ld SET_FEATURE %04lx->%04lx\n", idx, oldval, newval));
976 WRITEREG32_LE(hc->hc_RegBase, portreg, newval);
977 return(0);
979 break;
983 break;
985 case USR_CLEAR_FEATURE:
986 if((!idx) || (idx > numports))
988 KPRINTF(20, ("Port %ld out of range\n", idx));
989 return(UHIOERR_STALL);
991 if(unit->hu_EhciOwned[idx - 1])
993 hc = unit->hu_PortMap20[idx - 1];
994 hciport = idx - 1;
995 } else {
996 hc = unit->hu_PortMap11[idx - 1];
997 hciport = unit->hu_PortNum11[idx - 1];
999 KPRINTF(10, ("Clear Feature %ld maps from glob. Port %ld to local Port %ld (%s)\n", val, idx, hciport, unit->hu_EhciOwned[idx - 1] ? "EHCI" : "U/OHCI"));
1000 cmdgood = FALSE;
1001 switch(hc->hc_HCIType)
1003 case HCITYPE_UHCI:
1005 UWORD portreg = hciport ? UHCI_PORT2STSCTRL : UHCI_PORT1STSCTRL;
1006 ULONG oldval = READIO16_LE(hc->hc_RegBase, portreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE); // these are clear-on-write!
1007 ULONG newval = oldval;
1008 switch(val)
1010 case UFS_PORT_ENABLE:
1011 KPRINTF(10, ("Disabling Port (%s)\n", newval & UHPF_PORTENABLE ? "ok" : "already"));
1012 newval &= ~UHPF_PORTENABLE;
1013 cmdgood = TRUE;
1014 // disable enumeration
1015 unit->hu_DevControllers[0] = NULL;
1016 break;
1018 case UFS_PORT_SUSPEND:
1019 newval &= ~UHPF_PORTSUSPEND;
1020 cmdgood = TRUE;
1021 break;
1023 case UFS_PORT_POWER: // ignore for UHCI, there's no power control here
1024 KPRINTF(10, ("Disabling Power\n"));
1025 KPRINTF(10, ("Disabling Port (%s)\n", newval & UHPF_PORTENABLE ? "ok" : "already"));
1026 newval &= ~UHPF_PORTENABLE;
1027 cmdgood = TRUE;
1028 break;
1030 case UFS_C_PORT_CONNECTION:
1031 newval |= UHPF_CONNECTCHANGE; // clear-on-write!
1032 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_CONNECTION;
1033 cmdgood = TRUE;
1034 break;
1036 case UFS_C_PORT_ENABLE:
1037 newval |= UHPF_ENABLECHANGE; // clear-on-write!
1038 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_ENABLE;
1039 cmdgood = TRUE;
1040 break;
1042 case UFS_C_PORT_SUSPEND: // ignore for UHCI, there's no bit indicating this
1043 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_SUSPEND; // manually fake suspend change clearing
1044 cmdgood = TRUE;
1045 break;
1047 case UFS_C_PORT_OVER_CURRENT: // ignore for UHCI, there's no bit indicating this
1048 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_OVER_CURRENT; // manually fake over current clearing
1049 cmdgood = TRUE;
1050 break;
1052 case UFS_C_PORT_RESET: // ignore for UHCI, there's no bit indicating this
1053 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_RESET; // manually fake reset change clearing
1054 cmdgood = TRUE;
1055 break;
1057 if(cmdgood)
1059 KPRINTF(5, ("Port %ld CLEAR_FEATURE %04lx->%04lx\n", idx, oldval, newval));
1060 WRITEIO16_LE(hc->hc_RegBase, portreg, newval);
1061 if(hc->hc_PortChangeMap[hciport])
1063 unit->hu_RootPortChanges |= 1UL<<idx;
1064 } else {
1065 unit->hu_RootPortChanges &= ~(1UL<<idx);
1067 return(0);
1069 break;
1072 case HCITYPE_OHCI:
1074 UWORD portreg = OHCI_PORTSTATUS + (hciport<<2);
1075 ULONG __unused oldval = READREG32_LE(hc->hc_RegBase, portreg);
1077 switch(val)
1079 case UFS_PORT_ENABLE:
1080 KPRINTF(10, ("Disabling Port (%s)\n", oldval & OHPF_PORTENABLE ? "ok" : "already"));
1081 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTDISABLE);
1082 cmdgood = TRUE;
1083 break;
1085 case UFS_PORT_SUSPEND:
1086 KPRINTF(10, ("Resuming Port (%s)\n", oldval & OHPF_PORTSUSPEND ? "ok" : "already"));
1087 //hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_SUSPEND; // manually fake suspend change
1088 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_RESUME);
1089 cmdgood = TRUE;
1090 break;
1092 case UFS_PORT_POWER:
1093 KPRINTF(10, ("Unpowering Port (%s)\n", oldval & OHPF_PORTPOWER ? "ok" : "already"));
1094 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTUNPOWER);
1095 cmdgood = TRUE;
1096 break;
1098 case UFS_C_PORT_CONNECTION:
1099 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_CONNECTCHANGE);
1100 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_CONNECTION;
1101 cmdgood = TRUE;
1102 break;
1104 case UFS_C_PORT_ENABLE:
1105 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_ENABLECHANGE);
1106 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_ENABLE;
1107 cmdgood = TRUE;
1108 break;
1110 case UFS_C_PORT_SUSPEND:
1111 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_RESUMEDTX);
1112 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_SUSPEND;
1113 cmdgood = TRUE;
1114 break;
1116 case UFS_C_PORT_OVER_CURRENT:
1117 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_OVERCURRENTCHG);
1118 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_OVER_CURRENT;
1119 cmdgood = TRUE;
1120 break;
1122 case UFS_C_PORT_RESET:
1123 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_RESETCHANGE);
1124 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_RESET;
1125 cmdgood = TRUE;
1126 break;
1128 if(cmdgood)
1130 return(0);
1132 break;
1135 case HCITYPE_EHCI:
1137 UWORD portreg = EHCI_PORTSC1 + (hciport<<2);
1138 ULONG oldval = READREG32_LE(hc->hc_RegBase, portreg) & ~(EHPF_OVERCURRENTCHG|EHPF_ENABLECHANGE|EHPF_CONNECTCHANGE); // these are clear-on-write!
1139 ULONG newval = oldval;
1140 switch(val)
1142 case UFS_PORT_ENABLE:
1143 KPRINTF(10, ("Disabling Port (%s)\n", newval & EHPF_PORTENABLE ? "ok" : "already"));
1144 newval &= ~EHPF_PORTENABLE;
1145 cmdgood = TRUE;
1146 // disable enumeration
1147 unit->hu_DevControllers[0] = NULL;
1148 break;
1150 case UFS_PORT_SUSPEND:
1151 newval &= ~EHPF_PORTSUSPEND;
1152 cmdgood = TRUE;
1153 break;
1155 case UFS_PORT_POWER: // ignore for UHCI, there's no power control here
1156 KPRINTF(10, ("Disabling Power (%s)\n", newval & EHPF_PORTPOWER ? "ok" : "already"));
1157 KPRINTF(10, ("Disabling Port (%s)\n", newval & EHPF_PORTENABLE ? "ok" : "already"));
1158 newval &= ~(EHPF_PORTENABLE|EHPF_PORTPOWER);
1159 cmdgood = TRUE;
1160 break;
1162 case UFS_C_PORT_CONNECTION:
1163 newval |= EHPF_CONNECTCHANGE; // clear-on-write!
1164 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_CONNECTION;
1165 cmdgood = TRUE;
1166 break;
1168 case UFS_C_PORT_ENABLE:
1169 newval |= EHPF_ENABLECHANGE; // clear-on-write!
1170 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_ENABLE;
1171 cmdgood = TRUE;
1172 break;
1174 case UFS_C_PORT_SUSPEND: // ignore for EHCI, there's no bit indicating this
1175 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_SUSPEND; // manually fake suspend change clearing
1176 cmdgood = TRUE;
1177 break;
1179 case UFS_C_PORT_OVER_CURRENT:
1180 newval |= EHPF_OVERCURRENTCHG; // clear-on-write!
1181 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_OVER_CURRENT; // manually fake over current clearing
1182 cmdgood = TRUE;
1183 break;
1185 case UFS_C_PORT_RESET: // ignore for EHCI, there's no bit indicating this
1186 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_RESET; // manually fake reset change clearing
1187 cmdgood = TRUE;
1188 break;
1190 if(cmdgood)
1192 KPRINTF(5, ("Port %ld CLEAR_FEATURE %08lx->%08lx\n", idx, oldval, newval));
1193 WRITEREG32_LE(hc->hc_RegBase, portreg, newval);
1194 if(hc->hc_PortChangeMap[hciport])
1196 unit->hu_RootPortChanges |= 1UL<<idx;
1197 } else {
1198 unit->hu_RootPortChanges &= ~(1UL<<idx);
1200 return(0);
1202 break;
1206 break;
1208 break;
1210 case (URTF_IN|URTF_CLASS|URTF_OTHER):
1211 switch(req)
1213 case USR_GET_STATUS:
1215 UWORD *mptr = ioreq->iouh_Data;
1216 if(len != sizeof(struct UsbPortStatus))
1218 return(UHIOERR_STALL);
1220 if((!idx) || (idx > numports))
1222 KPRINTF(20, ("Port %ld out of range\n", idx));
1223 return(UHIOERR_STALL);
1225 if(unit->hu_EhciOwned[idx - 1])
1227 hc = unit->hu_PortMap20[idx - 1];
1228 hciport = idx - 1;
1229 } else {
1230 hc = unit->hu_PortMap11[idx - 1];
1231 hciport = unit->hu_PortNum11[idx - 1];
1233 switch(hc->hc_HCIType)
1235 case HCITYPE_UHCI:
1237 UWORD portreg = hciport ? UHCI_PORT2STSCTRL : UHCI_PORT1STSCTRL;
1238 UWORD oldval = READIO16_LE(hc->hc_RegBase, portreg);
1239 *mptr = AROS_WORD2LE(UPSF_PORT_POWER);
1240 if(oldval & UHPF_PORTCONNECTED) *mptr |= AROS_WORD2LE(UPSF_PORT_CONNECTION);
1241 if(oldval & UHPF_PORTENABLE) *mptr |= AROS_WORD2LE(UPSF_PORT_ENABLE);
1242 if(oldval & UHPF_LOWSPEED) *mptr |= AROS_WORD2LE(UPSF_PORT_LOW_SPEED);
1243 if(oldval & UHPF_PORTRESET) *mptr |= AROS_WORD2LE(UPSF_PORT_RESET);
1244 if(oldval & UHPF_PORTSUSPEND) *mptr |= AROS_WORD2LE(UPSF_PORT_SUSPEND);
1246 KPRINTF(5, ("UHCI Port %ld is %s\n", idx, oldval & UHPF_LOWSPEED ? "LOWSPEED" : "FULLSPEED"));
1247 KPRINTF(5, ("UHCI Port %ld Status %08lx\n", idx, *mptr));
1249 mptr++;
1250 if(oldval & UHPF_ENABLECHANGE)
1252 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_ENABLE;
1254 if(oldval & UHPF_CONNECTCHANGE)
1256 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_CONNECTION;
1258 if(oldval & UHPF_RESUMEDTX)
1260 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_SUSPEND|UPSF_PORT_ENABLE;
1262 *mptr = AROS_WORD2LE(hc->hc_PortChangeMap[hciport]);
1263 WRITEIO16_LE(hc->hc_RegBase, portreg, oldval);
1264 KPRINTF(5, ("UHCI Port %ld Change %08lx\n", idx, *mptr));
1265 return(0);
1268 case HCITYPE_OHCI:
1270 UWORD portreg = OHCI_PORTSTATUS + (hciport<<2);
1271 ULONG oldval = READREG32_LE(hc->hc_RegBase, portreg);
1273 *mptr = 0;
1274 if(oldval & OHPF_PORTPOWER) *mptr |= AROS_WORD2LE(UPSF_PORT_POWER);
1275 if(oldval & OHPF_OVERCURRENT) *mptr |= AROS_WORD2LE(UPSF_PORT_OVER_CURRENT);
1276 if(oldval & OHPF_PORTCONNECTED) *mptr |= AROS_WORD2LE(UPSF_PORT_CONNECTION);
1277 if(oldval & OHPF_PORTENABLE) *mptr |= AROS_WORD2LE(UPSF_PORT_ENABLE);
1278 if(oldval & OHPF_LOWSPEED) *mptr |= AROS_WORD2LE(UPSF_PORT_LOW_SPEED);
1279 if(oldval & OHPF_PORTRESET) *mptr |= AROS_WORD2LE(UPSF_PORT_RESET);
1280 if(oldval & OHPF_PORTSUSPEND) *mptr |= AROS_WORD2LE(UPSF_PORT_SUSPEND);
1282 KPRINTF(5, ("OHCI Port %ld (glob. %ld) is %s\n", hciport, idx, oldval & OHPF_LOWSPEED ? "LOWSPEED" : "FULLSPEED"));
1283 KPRINTF(5, ("OHCI Port %ld Status %08lx (%08lx)\n", idx, *mptr, oldval));
1285 mptr++;
1286 if(oldval & OHPF_OVERCURRENTCHG)
1288 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_OVER_CURRENT;
1290 if(oldval & OHPF_RESETCHANGE)
1292 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_RESET;
1294 if(oldval & OHPF_ENABLECHANGE)
1296 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_ENABLE;
1298 if(oldval & OHPF_CONNECTCHANGE)
1300 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_CONNECTION;
1302 if(oldval & OHPF_RESUMEDTX)
1304 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_SUSPEND;
1306 *mptr = AROS_WORD2LE(hc->hc_PortChangeMap[hciport]);
1307 KPRINTF(5, ("OHCI Port %ld Change %08lx\n", idx, *mptr));
1308 return(0);
1311 case HCITYPE_EHCI:
1313 UWORD portreg = EHCI_PORTSC1 + (hciport<<2);
1314 ULONG oldval = READREG32_LE(hc->hc_RegBase, portreg);
1316 *mptr = 0;
1317 if(oldval & EHPF_PORTCONNECTED) *mptr |= AROS_WORD2LE(UPSF_PORT_CONNECTION);
1318 if(oldval & EHPF_PORTENABLE) *mptr |= AROS_WORD2LE(UPSF_PORT_ENABLE|UPSF_PORT_HIGH_SPEED);
1319 if((oldval & (EHPF_LINESTATUS_DM|EHPF_PORTCONNECTED|EHPF_PORTENABLE)) ==
1320 (EHPF_LINESTATUS_DM|EHPF_PORTCONNECTED))
1322 KPRINTF(10, ("EHCI Port %ld is LOWSPEED\n", idx));
1323 // we need to detect low speed devices prior to reset
1324 *mptr |= AROS_WORD2LE(UPSF_PORT_LOW_SPEED);
1327 if(oldval & EHPF_PORTRESET) *mptr |= AROS_WORD2LE(UPSF_PORT_RESET);
1328 if(oldval & EHPF_PORTSUSPEND) *mptr |= AROS_WORD2LE(UPSF_PORT_SUSPEND);
1329 if(oldval & EHPF_PORTPOWER) *mptr |= AROS_WORD2LE(UPSF_PORT_POWER);
1330 if(oldval & EHPM_PORTINDICATOR) *mptr |= AROS_WORD2LE(UPSF_PORT_INDICATOR);
1332 KPRINTF(5, ("EHCI Port %ld Status %08lx\n", idx, *mptr));
1334 mptr++;
1335 if(oldval & EHPF_ENABLECHANGE)
1337 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_ENABLE;
1339 if(oldval & EHPF_CONNECTCHANGE)
1341 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_CONNECTION;
1343 if(oldval & EHPF_RESUMEDTX)
1345 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_SUSPEND|UPSF_PORT_ENABLE;
1347 if(oldval & EHPF_OVERCURRENTCHG)
1349 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_OVER_CURRENT;
1351 *mptr = AROS_WORD2LE(hc->hc_PortChangeMap[hciport]);
1352 WRITEREG32_LE(hc->hc_RegBase, portreg, oldval);
1353 KPRINTF(5, ("EHCI Port %ld Change %08lx\n", idx, *mptr));
1354 return(0);
1358 return(0);
1362 break;
1364 case (URTF_IN|URTF_CLASS|URTF_DEVICE):
1365 switch(req)
1367 case USR_GET_STATUS:
1369 UWORD *mptr = ioreq->iouh_Data;
1370 if(len < sizeof(struct UsbHubStatus))
1372 return(UHIOERR_STALL);
1374 *mptr++ = 0;
1375 *mptr++ = 0;
1376 ioreq->iouh_Actual = 4;
1377 return(0);
1380 case USR_GET_DESCRIPTOR:
1381 switch(val>>8)
1383 case UDT_HUB:
1385 ULONG hubdesclen = 9;
1386 ULONG powergood = 1;
1388 struct UsbHubDesc *uhd = (struct UsbHubDesc *) ioreq->iouh_Data;
1389 KPRINTF(1, ("RH: GetHubDescriptor (%ld)\n", len));
1391 if(unit->hu_RootHubPorts > 7) // needs two bytes for port masks
1393 hubdesclen += 2;
1396 ioreq->iouh_Actual = (len > hubdesclen) ? hubdesclen : len;
1397 CopyMem((APTR) &RHHubDesc, ioreq->iouh_Data, ioreq->iouh_Actual);
1399 if(ioreq->iouh_Length)
1401 uhd->bLength = hubdesclen;
1404 if(ioreq->iouh_Length >= 6)
1406 hc = (struct PCIController *) unit->hu_Controllers.lh_Head;
1407 while(hc->hc_Node.ln_Succ)
1409 if(hc->hc_HCIType == HCITYPE_OHCI)
1411 ULONG localpwgood = (READREG32_LE(hc->hc_RegBase, OHCI_HUBDESCA) & OHAM_POWERGOOD) >> OHAS_POWERGOOD;
1412 if(localpwgood > powergood)
1414 powergood = localpwgood;
1415 KPRINTF(10, ("Increasing power good time to %ld\n", powergood));
1418 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
1421 uhd->bPwrOn2PwrGood = powergood;
1423 if(ioreq->iouh_Length >= hubdesclen)
1425 uhd->bNbrPorts = unit->hu_RootHubPorts;
1426 if(hubdesclen == 9)
1428 uhd->DeviceRemovable = 0;
1429 uhd->PortPwrCtrlMask = (1<<(unit->hu_RootHubPorts+2))-2;
1430 } else {
1431 // each field is now 16 bits wide
1432 uhd->DeviceRemovable = 0;
1433 uhd->PortPwrCtrlMask = 0;
1434 ((UBYTE *) ioreq->iouh_Data)[9] = (1<<(unit->hu_RootHubPorts+2))-2;
1435 ((UBYTE *) ioreq->iouh_Data)[10] = ((1<<(unit->hu_RootHubPorts+2))-2)>>8;
1438 return(0);
1441 default:
1442 KPRINTF(20, ("RH: Unsupported Descriptor %04lx\n", idx));
1444 break;
1448 KPRINTF(20, ("RH: Unsupported command %02lx %02lx %04lx %04lx %04lx!\n", rt, req, idx, val, len));
1449 return(UHIOERR_STALL);
1451 /* \\\ */
1453 /* /// "cmdIntXFerRootHub()" */
1454 WORD cmdIntXFerRootHub(struct IOUsbHWReq *ioreq,
1455 struct PCIUnit *unit,
1456 struct PCIDevice *base)
1458 if((ioreq->iouh_Endpoint != 1) || (!ioreq->iouh_Length))
1460 return(UHIOERR_STALL);
1463 if(unit->hu_RootPortChanges)
1465 KPRINTF(1, ("Immediate Portchange map %04lx\n", unit->hu_RootPortChanges));
1466 if((unit->hu_RootHubPorts < 8) || (ioreq->iouh_Length == 1))
1468 *((UBYTE *) ioreq->iouh_Data) = unit->hu_RootPortChanges;
1469 ioreq->iouh_Actual = 1;
1470 } else {
1471 ((UBYTE *) ioreq->iouh_Data)[0] = unit->hu_RootPortChanges;
1472 ((UBYTE *) ioreq->iouh_Data)[1] = unit->hu_RootPortChanges>>8;
1473 ioreq->iouh_Actual = 2;
1475 unit->hu_RootPortChanges = 0;
1476 return(0);
1478 ioreq->iouh_Req.io_Flags &= ~IOF_QUICK;
1479 Disable();
1480 AddTail(&unit->hu_RHIOQueue, (struct Node *) ioreq);
1481 Enable();
1482 return(RC_DONTREPLY);
1484 /* \\\ */
1486 /* /// "cmdControlXFer()" */
1488 *======================================================================
1489 * cmdControlXFer(ioreq, unit, base)
1490 *======================================================================
1492 * This is the device UHCMD_CONTROLXFER routine.
1494 * First it check if the usb is in proper state and if user passed arguments
1495 * are valid. If everything is ok, the request is linked to queue of
1496 * pending transfer requests.
1500 WORD cmdControlXFer(struct IOUsbHWReq *ioreq,
1501 struct PCIUnit *unit,
1502 struct PCIDevice *base)
1504 struct PCIController *hc;
1506 KPRINTF(10, ("UHCMD_CONTROLXFER ioreq: 0x%p\n", ioreq));
1507 uhwGetUsbState(ioreq, unit, base);
1508 if(!(ioreq->iouh_State & UHSF_OPERATIONAL))
1510 return(UHIOERR_USBOFFLINE);
1512 /* Root hub emulation */
1513 if(ioreq->iouh_DevAddr == unit->hu_RootHubAddr)
1515 return(cmdControlXFerRootHub(ioreq, unit, base));
1518 hc = unit->hu_DevControllers[ioreq->iouh_DevAddr];
1519 if(!hc)
1521 KPRINTF(20, ("No Host controller assigned to device address %ld\n", ioreq->iouh_DevAddr));
1522 return(UHIOERR_HOSTERROR);
1525 ioreq->iouh_Req.io_Flags &= ~IOF_QUICK;
1526 ioreq->iouh_Actual = 0;
1528 Disable();
1529 AddTail(&hc->hc_CtrlXFerQueue, (struct Node *) ioreq);
1530 Enable();
1531 SureCause(base, &hc->hc_CompleteInt);
1533 KPRINTF(10, ("UHCMD_CONTROLXFER processed ioreq: 0x%p\n", ioreq));
1534 return(RC_DONTREPLY);
1536 /* \\\ */
1538 /* /// "cmdBulkXFer()" */
1540 *======================================================================
1541 * cmdBulkXFer(ioreq, unit, base)
1542 *======================================================================
1544 * This is the device UHCMD_BULKXFER routine.
1546 * First it check if the usb is in proper state and if user passed arguments
1547 * are valid. If everything is ok, the request is linked to queue of
1548 * pending transfer requests.
1552 WORD cmdBulkXFer(struct IOUsbHWReq *ioreq,
1553 struct PCIUnit *unit,
1554 struct PCIDevice *base)
1556 struct PCIController *hc;
1558 KPRINTF(10, ("UHCMD_BULKXFER ioreq: 0x%p\n", ioreq));
1559 uhwGetUsbState(ioreq, unit, base);
1560 if(!(ioreq->iouh_State & UHSF_OPERATIONAL))
1562 return(UHIOERR_USBOFFLINE);
1565 if(ioreq->iouh_Flags & UHFF_LOWSPEED)
1567 return(UHIOERR_BADPARAMS);
1570 hc = unit->hu_DevControllers[ioreq->iouh_DevAddr];
1571 if(!hc)
1573 return(UHIOERR_HOSTERROR);
1576 ioreq->iouh_Req.io_Flags &= ~IOF_QUICK;
1577 ioreq->iouh_Actual = 0;
1579 Disable();
1580 AddTail(&hc->hc_BulkXFerQueue, (struct Node *) ioreq);
1581 Enable();
1582 SureCause(base, &hc->hc_CompleteInt);
1584 KPRINTF(10, ("UHCMD_BULKXFER processed ioreq: 0x%p\n", ioreq));
1585 return(RC_DONTREPLY);
1587 /* \\\ */
1589 /* /// "cmdIsoXFer()" */
1591 *======================================================================
1592 * cmdIsoXFer(ioreq, unit, base)
1593 *======================================================================
1595 * This is the device UHCMD_ISOXFER routine.
1597 * First it check if the usb is in proper state and if user passed arguments
1598 * are valid. If everything is ok, the request is linked to queue of
1599 * pending transfer requests.
1603 WORD cmdIsoXFer(struct IOUsbHWReq *ioreq,
1604 struct PCIUnit *unit,
1605 struct PCIDevice *base)
1607 struct PCIController *hc;
1609 KPRINTF(10, ("UHCMD_ISOXFER ioreq: 0x%p\n", ioreq));
1610 uhwGetUsbState(ioreq, unit, base);
1611 if(!(ioreq->iouh_State & UHSF_OPERATIONAL))
1613 return(UHIOERR_USBOFFLINE);
1616 if(ioreq->iouh_Flags & UHFF_LOWSPEED)
1618 return(UHIOERR_BADPARAMS);
1621 hc = unit->hu_DevControllers[ioreq->iouh_DevAddr];
1622 if(!hc)
1624 return(UHIOERR_HOSTERROR);
1627 ioreq->iouh_Req.io_Flags &= ~IOF_QUICK;
1628 ioreq->iouh_Actual = 0;
1630 Disable();
1631 AddTail(&hc->hc_IsoXFerQueue, (struct Node *) ioreq);
1632 Enable();
1633 SureCause(base, &hc->hc_CompleteInt);
1635 KPRINTF(10, ("UHCMD_ISOXFER processed ioreq: 0x%p\n", ioreq));
1636 return(RC_DONTREPLY);
1638 /* \\\ */
1640 /* /// "cmdIntXFer()" */
1642 *======================================================================
1643 * cmdIntXFer(ioreq, unit, base)
1644 *======================================================================
1646 * This is the device UHCMD_INTXFER routine.
1648 * First it check if the usb is in proper state and if user passed arguments
1649 * are valid. If everything is ok, the request is linked to queue of
1650 * pending transfer requests.
1654 WORD cmdIntXFer(struct IOUsbHWReq *ioreq,
1655 struct PCIUnit *unit,
1656 struct PCIDevice *base)
1658 struct PCIController *hc;
1660 KPRINTF(10, ("UHCMD_INTXFER ioreq: 0x%p\n", ioreq));
1661 //uhwDelayMS(1000, unit); /* Wait 200 ms */
1662 uhwGetUsbState(ioreq, unit, base);
1663 if(!(ioreq->iouh_State & UHSF_OPERATIONAL))
1665 return(UHIOERR_USBOFFLINE);
1668 /* Root Hub Emulation */
1669 if(ioreq->iouh_DevAddr == unit->hu_RootHubAddr)
1671 return(cmdIntXFerRootHub(ioreq, unit, base));
1674 hc = unit->hu_DevControllers[ioreq->iouh_DevAddr];
1675 if(!hc)
1677 return(UHIOERR_HOSTERROR);
1680 ioreq->iouh_Req.io_Flags &= ~IOF_QUICK;
1681 ioreq->iouh_Actual = 0;
1683 Disable();
1684 AddTail(&hc->hc_IntXFerQueue, (struct Node *) ioreq);
1685 Enable();
1686 SureCause(base, &hc->hc_CompleteInt);
1688 KPRINTF(10, ("UHCMD_INTXFER processed ioreq: 0x%p\n", ioreq));
1689 return(RC_DONTREPLY);
1691 /* \\\ */
1693 /* /// "cmdFlush()" */
1695 *======================================================================
1696 * cmdFlush(ioreq, base)
1697 *======================================================================
1699 * This is the device CMD_FLUSH routine.
1701 * This routine abort all pending transfer requests.
1705 WORD cmdFlush(struct IOUsbHWReq *ioreq,
1706 struct PCIUnit *unit,
1707 struct PCIDevice *base)
1709 struct IOUsbHWReq *cmpioreq;
1710 struct PCIController *hc;
1711 UWORD devadrep;
1713 KPRINTF(10, ("CMD_FLUSH ioreq: 0x%p\n", ioreq));
1715 Disable();
1716 cmpioreq = (struct IOUsbHWReq *) unit->hu_RHIOQueue.lh_Head;
1717 while(((struct Node *) cmpioreq)->ln_Succ)
1719 Remove(&cmpioreq->iouh_Req.io_Message.mn_Node);
1720 cmpioreq->iouh_Req.io_Error = IOERR_ABORTED;
1721 ReplyMsg(&cmpioreq->iouh_Req.io_Message);
1722 cmpioreq = (struct IOUsbHWReq *) unit->hu_RHIOQueue.lh_Head;
1724 hc = (struct PCIController *) unit->hu_Controllers.lh_Head;
1725 while(hc->hc_Node.ln_Succ)
1727 cmpioreq = (struct IOUsbHWReq *) hc->hc_CtrlXFerQueue.lh_Head;
1728 while(((struct Node *) cmpioreq)->ln_Succ)
1730 Remove(&cmpioreq->iouh_Req.io_Message.mn_Node);
1731 cmpioreq->iouh_Req.io_Error = IOERR_ABORTED;
1732 ReplyMsg(&cmpioreq->iouh_Req.io_Message);
1733 cmpioreq = (struct IOUsbHWReq *) hc->hc_CtrlXFerQueue.lh_Head;
1735 cmpioreq = (struct IOUsbHWReq *) hc->hc_IntXFerQueue.lh_Head;
1736 while(((struct Node *) cmpioreq)->ln_Succ)
1738 Remove(&cmpioreq->iouh_Req.io_Message.mn_Node);
1739 cmpioreq->iouh_Req.io_Error = IOERR_ABORTED;
1740 ReplyMsg(&cmpioreq->iouh_Req.io_Message);
1741 cmpioreq = (struct IOUsbHWReq *) hc->hc_IntXFerQueue.lh_Head;
1743 cmpioreq = (struct IOUsbHWReq *) hc->hc_IsoXFerQueue.lh_Head;
1744 while(((struct Node *) cmpioreq)->ln_Succ)
1746 Remove(&cmpioreq->iouh_Req.io_Message.mn_Node);
1747 cmpioreq->iouh_Req.io_Error = IOERR_ABORTED;
1748 ReplyMsg(&cmpioreq->iouh_Req.io_Message);
1749 cmpioreq = (struct IOUsbHWReq *) hc->hc_IsoXFerQueue.lh_Head;
1751 cmpioreq = (struct IOUsbHWReq *) hc->hc_BulkXFerQueue.lh_Head;
1752 while(((struct Node *) cmpioreq)->ln_Succ)
1754 Remove(&cmpioreq->iouh_Req.io_Message.mn_Node);
1755 cmpioreq->iouh_Req.io_Error = IOERR_ABORTED;
1756 ReplyMsg(&cmpioreq->iouh_Req.io_Message);
1757 cmpioreq = (struct IOUsbHWReq *) hc->hc_BulkXFerQueue.lh_Head;
1759 switch(hc->hc_HCIType)
1761 case HCITYPE_UHCI:
1762 cmpioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head;
1763 while(((struct Node *) cmpioreq)->ln_Succ)
1765 Remove(&cmpioreq->iouh_Req.io_Message.mn_Node);
1766 devadrep = (cmpioreq->iouh_DevAddr<<5) + cmpioreq->iouh_Endpoint + ((cmpioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0);
1767 unit->hu_DevBusyReq[devadrep] = NULL;
1768 uhciFreeQContext(hc, (struct UhciQH *) cmpioreq->iouh_DriverPrivate1);
1769 cmpioreq->iouh_Req.io_Error = IOERR_ABORTED;
1770 ReplyMsg(&cmpioreq->iouh_Req.io_Message);
1771 cmpioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head;
1773 break;
1775 case HCITYPE_EHCI:
1776 cmpioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head;
1777 while(((struct Node *) cmpioreq)->ln_Succ)
1779 ehciFreeAsyncContext(hc, cmpioreq);
1780 cmpioreq->iouh_Req.io_Error = IOERR_ABORTED;
1781 ReplyMsg(&cmpioreq->iouh_Req.io_Message);
1782 cmpioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head;
1784 cmpioreq = (struct IOUsbHWReq *) hc->hc_PeriodicTDQueue.lh_Head;
1785 while(((struct Node *) cmpioreq)->ln_Succ)
1787 ehciFreePeriodicContext(hc, cmpioreq);
1788 cmpioreq->iouh_Req.io_Error = IOERR_ABORTED;
1789 ReplyMsg(&cmpioreq->iouh_Req.io_Message);
1790 cmpioreq = (struct IOUsbHWReq *) hc->hc_PeriodicTDQueue.lh_Head;
1792 break;
1794 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
1796 Enable();
1797 /* Return success
1799 return RC_OK;
1801 /* \\\ */
1803 /* /// "NSD stuff" */
1805 static
1806 const UWORD NSDSupported[] =
1808 CMD_FLUSH, CMD_RESET,
1809 UHCMD_QUERYDEVICE, UHCMD_USBRESET,
1810 UHCMD_USBRESUME, UHCMD_USBSUSPEND,
1811 UHCMD_USBOPER, UHCMD_CONTROLXFER ,
1812 UHCMD_ISOXFER, UHCMD_INTXFER,
1813 UHCMD_BULKXFER,
1814 NSCMD_DEVICEQUERY, 0
1817 WORD cmdNSDeviceQuery(struct IOStdReq *ioreq,
1818 struct PCIUnit *unit,
1819 struct PCIDevice *base)
1821 struct my_NSDeviceQueryResult *query;
1823 query = (struct my_NSDeviceQueryResult *) ioreq->io_Data;
1825 KPRINTF(10, ("NSCMD_DEVICEQUERY ioreq: 0x%p query: 0x%p\n", ioreq, query));
1827 /* NULL ptr?
1828 Enough data?
1829 Valid request?
1831 if((!query) ||
1832 (ioreq->io_Length < sizeof(struct my_NSDeviceQueryResult)) ||
1833 (query->DevQueryFormat != 0) ||
1834 (query->SizeAvailable != 0))
1836 /* Return error. This is special handling, since iorequest is only
1837 guaranteed to be sizeof(struct IOStdReq). If we'd let our
1838 devBeginIO dispatcher return the error, it would trash some
1839 memory past end of the iorequest (ios2_WireError field).
1841 ioreq->io_Error = IOERR_NOCMD;
1842 TermIO((struct IOUsbHWReq *) ioreq, base);
1844 /* Don't reply, we already did.
1846 return RC_DONTREPLY;
1849 ioreq->io_Actual = query->SizeAvailable
1850 = sizeof(struct my_NSDeviceQueryResult);
1851 query->DeviceType = NSDEVTYPE_USBHARDWARE;
1852 query->DeviceSubType = 0;
1853 query->SupportedCommands = NSDSupported;
1855 /* Return success (note that this will NOT poke ios2_WireError).
1857 return RC_OK;
1859 /* \\\ */
1861 /* /// "TermIO()" */
1863 *===========================================================
1864 * TermIO(ioreq, base)
1865 *===========================================================
1867 * Return completed ioreq to sender.
1871 void TermIO(struct IOUsbHWReq *ioreq,
1872 struct PCIDevice *base)
1874 ioreq->iouh_Req.io_Message.mn_Node.ln_Type = NT_FREEMSG;
1876 /* If not quick I/O, reply the message
1878 if(!(ioreq->iouh_Req.io_Flags & IOF_QUICK))
1880 ReplyMsg(&ioreq->iouh_Req.io_Message);
1883 /* \\\ */
1885 /* /// "cmdAbortIO()" */
1886 BOOL cmdAbortIO(struct IOUsbHWReq *ioreq, struct PCIDevice *base)
1888 struct PCIUnit *unit = (struct PCIUnit *) ioreq->iouh_Req.io_Unit;
1889 struct IOUsbHWReq *cmpioreq;
1890 struct PCIController *hc;
1891 UWORD devadrep;
1892 BOOL foundit = FALSE;
1894 KPRINTF(10, ("cmdAbort(%p)\n", ioreq));
1896 Disable();
1897 cmpioreq = (struct IOUsbHWReq *) unit->hu_RHIOQueue.lh_Head;
1898 while(((struct Node *) cmpioreq)->ln_Succ)
1900 if(ioreq == cmpioreq)
1902 Remove(&ioreq->iouh_Req.io_Message.mn_Node);
1903 Enable();
1904 return TRUE;
1906 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
1909 hc = (struct PCIController *) unit->hu_Controllers.lh_Head;
1910 while(hc->hc_Node.ln_Succ)
1912 cmpioreq = (struct IOUsbHWReq *) hc->hc_CtrlXFerQueue.lh_Head;
1913 while(((struct Node *) cmpioreq)->ln_Succ)
1915 if(ioreq == cmpioreq)
1917 foundit = TRUE;
1918 break;
1920 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
1922 if(!foundit)
1924 cmpioreq = (struct IOUsbHWReq *) hc->hc_IntXFerQueue.lh_Head;
1925 while(((struct Node *) cmpioreq)->ln_Succ)
1927 if(ioreq == cmpioreq)
1929 foundit = TRUE;
1930 break;
1932 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
1935 if(!foundit)
1937 cmpioreq = (struct IOUsbHWReq *) hc->hc_IsoXFerQueue.lh_Head;
1938 while(((struct Node *) cmpioreq)->ln_Succ)
1940 if(ioreq == cmpioreq)
1942 foundit = TRUE;
1943 break;
1945 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
1948 if(!foundit)
1950 cmpioreq = (struct IOUsbHWReq *) hc->hc_BulkXFerQueue.lh_Head;
1951 while(((struct Node *) cmpioreq)->ln_Succ)
1953 if(ioreq == cmpioreq)
1955 foundit = TRUE;
1956 break;
1958 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
1961 if(!foundit)
1963 // IOReq is probably pending in some transfer structure
1964 devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint + ((ioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0);
1965 switch(hc->hc_HCIType)
1967 case HCITYPE_UHCI:
1968 cmpioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head;
1969 while(((struct Node *) cmpioreq)->ln_Succ)
1971 if(ioreq == cmpioreq)
1973 foundit = TRUE;
1974 unit->hu_DevBusyReq[devadrep] = NULL;
1975 uhciFreeQContext(hc, (struct UhciQH *) ioreq->iouh_DriverPrivate1);
1976 break;
1978 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
1980 break;
1982 case HCITYPE_OHCI:
1983 cmpioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head;
1984 while(((struct Node *) cmpioreq)->ln_Succ)
1986 if(ioreq == cmpioreq)
1989 * Request's ED is in use by the HC, as well as its TDs and
1990 * data buffers.
1991 * Schedule abort on the HC driver and reply the request
1992 * only when done. However return success.
1994 ioreq->iouh_Req.io_Error = IOERR_ABORTED;
1995 ohciAbortRequest(hc, ioreq);
1996 Enable();
1997 return TRUE;
1999 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
2001 break;
2003 case HCITYPE_EHCI:
2004 cmpioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head;
2005 while(((struct Node *) cmpioreq)->ln_Succ)
2007 if(ioreq == cmpioreq)
2010 * CHECKME: Perhaps immediate freeing can cause issues similar to OHCI.
2011 * Should synchronized abort routine be implemented here too ?
2013 ehciFreeAsyncContext(hc, ioreq);
2014 Enable();
2015 ioreq->iouh_Req.io_Error = IOERR_ABORTED;
2016 TermIO(ioreq, base);
2017 return TRUE;
2019 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
2021 cmpioreq = (struct IOUsbHWReq *) hc->hc_PeriodicTDQueue.lh_Head;
2022 while(((struct Node *) cmpioreq)->ln_Succ)
2024 if(ioreq == cmpioreq)
2026 ehciFreePeriodicContext(hc, ioreq);
2027 Enable();
2028 ioreq->iouh_Req.io_Error = IOERR_ABORTED;
2029 TermIO(ioreq, base);
2030 return TRUE;
2032 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
2034 break;
2038 if(foundit)
2040 Remove(&ioreq->iouh_Req.io_Message.mn_Node);
2041 break;
2043 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
2045 Enable();
2047 if (foundit)
2049 ioreq->iouh_Req.io_Error = IOERR_ABORTED;
2050 TermIO(ioreq, base);
2052 else
2054 KPRINTF(20, ("WARNING, could not abort unknown IOReq %p\n", ioreq));
2056 return(foundit);
2058 /* \\\ */
2060 /* /// "uhwCheckRootHubChanges()" */
2061 void uhwCheckRootHubChanges(struct PCIUnit *unit)
2063 struct IOUsbHWReq *ioreq;
2065 if(unit->hu_RootPortChanges && unit->hu_RHIOQueue.lh_Head->ln_Succ)
2067 KPRINTF(1, ("Portchange map %04lx\n", unit->hu_RootPortChanges));
2068 Disable();
2069 ioreq = (struct IOUsbHWReq *) unit->hu_RHIOQueue.lh_Head;
2070 while(((struct Node *) ioreq)->ln_Succ)
2072 Remove(&ioreq->iouh_Req.io_Message.mn_Node);
2073 if((unit->hu_RootHubPorts < 8) || (ioreq->iouh_Length == 1))
2075 *((UBYTE *) ioreq->iouh_Data) = unit->hu_RootPortChanges;
2076 ioreq->iouh_Actual = 1;
2077 } else {
2078 ((UBYTE *) ioreq->iouh_Data)[0] = unit->hu_RootPortChanges;
2079 ((UBYTE *) ioreq->iouh_Data)[1] = unit->hu_RootPortChanges>>8;
2080 ioreq->iouh_Actual = 2;
2082 ReplyMsg(&ioreq->iouh_Req.io_Message);
2083 ioreq = (struct IOUsbHWReq *) unit->hu_RHIOQueue.lh_Head;
2085 unit->hu_RootPortChanges = 0;
2086 Enable();
2089 /* \\\ */
2091 /* /// "uhwCheckSpecialCtrlTransfers()" */
2092 void uhwCheckSpecialCtrlTransfers(struct PCIController *hc, struct IOUsbHWReq *ioreq)
2094 struct PCIUnit *unit = hc->hc_Unit;
2096 /* Clear Feature(Endpoint halt) */
2097 if((ioreq->iouh_SetupData.bmRequestType == (URTF_STANDARD|URTF_ENDPOINT)) &&
2098 (ioreq->iouh_SetupData.bRequest == USR_CLEAR_FEATURE) &&
2099 (ioreq->iouh_SetupData.wValue == AROS_WORD2LE(UFS_ENDPOINT_HALT)))
2101 KPRINTF(10, ("Resetting toggle bit for endpoint %ld\n", AROS_WORD2LE(ioreq->iouh_SetupData.wIndex) & 0xf));
2102 unit->hu_DevDataToggle[(ioreq->iouh_DevAddr<<5)|(AROS_WORD2LE(ioreq->iouh_SetupData.wIndex) & 0xf)|((AROS_WORD2LE(ioreq->iouh_SetupData.wIndex) & 0x80)>>3)] = 0;
2104 else if((ioreq->iouh_SetupData.bmRequestType == (URTF_STANDARD|URTF_DEVICE)) &&
2105 (ioreq->iouh_SetupData.bRequest == USR_SET_ADDRESS))
2107 /* Set Address -> clear all endpoints */
2108 ULONG epnum;
2109 ULONG adr = AROS_WORD2BE(ioreq->iouh_SetupData.wValue)>>3;
2110 KPRINTF(10, ("Resetting toggle bits for device address %ld\n", adr>>5));
2111 for(epnum = 0; epnum < 31; epnum++)
2113 unit->hu_DevDataToggle[adr+epnum] = 0;
2115 // transfer host controller ownership
2116 unit->hu_DevControllers[ioreq->iouh_DevAddr] = NULL;
2117 unit->hu_DevControllers[adr>>5] = hc;
2119 else if((ioreq->iouh_SetupData.bmRequestType == (URTF_CLASS|URTF_OTHER)) &&
2120 (ioreq->iouh_SetupData.bRequest == USR_SET_FEATURE) &&
2121 (ioreq->iouh_SetupData.wValue == AROS_WORD2LE(UFS_PORT_RESET)))
2123 // a hub will be enumerating a device on this host controller soon!
2124 KPRINTF(10, ("Hub RESET caught, assigning Dev0 to %p!\n", hc));
2125 unit->hu_DevControllers[0] = hc;
2128 /* \\\ */
2130 /* /// "uhwNakTimeoutInt()" */
2131 AROS_INTH1(uhwNakTimeoutInt, struct PCIUnit *, unit)
2133 AROS_INTFUNC_INIT
2135 struct PCIDevice *base = unit->hu_Device;
2136 struct PCIController *hc;
2137 struct IOUsbHWReq *ioreq;
2138 struct UhciQH *uqh;
2139 struct UhciTD *utd;
2140 struct EhciQH *eqh;
2141 UWORD devadrep;
2142 UWORD cnt;
2143 ULONG linkelem;
2144 ULONG ctrlstatus;
2145 BOOL causeint;
2147 KPRINTF(1, ("Enter NakTimeoutInt(0x%p)\n", unit));
2149 // check for port status change for UHCI and frame rollovers and NAK Timeouts
2150 hc = (struct PCIController *) unit->hu_Controllers.lh_Head;
2151 while(hc->hc_Node.ln_Succ)
2153 if (!(hc->hc_Flags & HCF_ONLINE))
2155 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
2156 continue;
2158 causeint = FALSE;
2159 switch(hc->hc_HCIType)
2161 case HCITYPE_UHCI:
2163 ULONG framecnt;
2164 uhciUpdateFrameCounter(hc);
2165 framecnt = hc->hc_FrameCounter;
2167 // NakTimeout
2168 ioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head;
2169 while(((struct Node *) ioreq)->ln_Succ)
2171 if(ioreq->iouh_Flags & UHFF_NAKTIMEOUT)
2173 uqh = (struct UhciQH *) ioreq->iouh_DriverPrivate1;
2174 if(uqh)
2176 KPRINTF(1, ("Examining IOReq=%p with UQH=%p\n", ioreq, uqh));
2177 devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint + ((ioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0);
2178 linkelem = READMEM32_LE(&uqh->uqh_Element);
2179 if(linkelem & UHCI_TERMINATE)
2181 KPRINTF(1, ("UQH terminated %08lx\n", linkelem));
2182 if(framecnt > unit->hu_NakTimeoutFrame[devadrep])
2184 // give the thing the chance to exit gracefully
2185 KPRINTF(20, ("Terminated? NAK timeout %ld > %ld, IOReq=%p\n", framecnt, unit->hu_NakTimeoutFrame[devadrep], ioreq));
2186 causeint = TRUE;
2188 } else {
2189 utd = (struct UhciTD *) (((IPTR)linkelem & UHCI_PTRMASK) - hc->hc_PCIVirtualAdjust - 16); // struct UhciTD starts 16 before physical TD
2190 ctrlstatus = READMEM32_LE(&utd->utd_CtrlStatus);
2191 if(ctrlstatus & UTCF_ACTIVE)
2193 if(framecnt > unit->hu_NakTimeoutFrame[devadrep])
2195 // give the thing the chance to exit gracefully
2196 KPRINTF(20, ("NAK timeout %ld > %ld, IOReq=%p\n", framecnt, unit->hu_NakTimeoutFrame[devadrep], ioreq));
2197 ctrlstatus &= ~UTCF_ACTIVE;
2198 WRITEMEM32_LE(&utd->utd_CtrlStatus, ctrlstatus);
2199 causeint = TRUE;
2201 } else {
2202 if(framecnt > unit->hu_NakTimeoutFrame[devadrep])
2204 // give the thing the chance to exit gracefully
2205 KPRINTF(20, ("Terminated? NAK timeout %ld > %ld, IOReq=%p\n", framecnt, unit->hu_NakTimeoutFrame[devadrep], ioreq));
2206 causeint = TRUE;
2212 ioreq = (struct IOUsbHWReq *) ((struct Node *) ioreq)->ln_Succ;
2215 uhciCheckPortStatusChange(hc);
2216 break;
2219 case HCITYPE_OHCI:
2221 ULONG framecnt;
2222 ohciUpdateFrameCounter(hc);
2223 framecnt = hc->hc_FrameCounter;
2224 // NakTimeout
2225 ioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head;
2226 while(((struct Node *) ioreq)->ln_Succ)
2228 // Remember the successor because ohciAbortRequest() will move the request to another list
2229 struct IOUsbHWReq *succ = (struct IOUsbHWReq *)ioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
2231 if(ioreq->iouh_Flags & UHFF_NAKTIMEOUT)
2233 KPRINTF(1, ("Examining IOReq=%p with OED=%p\n", ioreq, ioreq->iouh_DriverPrivate1));
2234 if (ioreq->iouh_DriverPrivate1)
2236 KPRINTF(1, ("CTRL=%04lx, CMD=%01lx, F=%ld, hccaDH=%08lx, hcDH=%08lx, CH=%08lx, CCH=%08lx, IntEn=%08lx\n",
2237 READREG32_LE(hc->hc_RegBase, OHCI_CONTROL),
2238 READREG32_LE(hc->hc_RegBase, OHCI_CMDSTATUS),
2239 READREG32_LE(hc->hc_RegBase, OHCI_FRAMECOUNT),
2240 READMEM32_LE(&hc->hc_OhciHCCA->oha_DoneHead),
2241 READREG32_LE(hc->hc_RegBase, OHCI_DONEHEAD),
2242 READREG32_LE(hc->hc_RegBase, OHCI_CTRL_HEAD_ED),
2243 READREG32_LE(hc->hc_RegBase, OHCI_CTRL_ED),
2244 READREG32_LE(hc->hc_RegBase, OHCI_INTEN)));
2246 devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint + ((ioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0);
2247 if(framecnt > unit->hu_NakTimeoutFrame[devadrep])
2249 // give the thing the chance to exit gracefully
2250 KPRINTF(200, ("HC 0x%p NAK timeout %ld > %ld, IOReq=%p\n", hc, framecnt, unit->hu_NakTimeoutFrame[devadrep], ioreq));
2251 ioreq->iouh_Req.io_Error = UHIOERR_NAKTIMEOUT;
2252 ohciAbortRequest(hc, ioreq);
2256 ioreq = succ;
2258 break;
2261 case HCITYPE_EHCI:
2263 ULONG framecnt;
2264 ehciUpdateFrameCounter(hc);
2265 framecnt = hc->hc_FrameCounter;
2266 // NakTimeout
2267 for(cnt = 0; cnt < 1; cnt++)
2269 ioreq = (struct IOUsbHWReq *) (cnt ? hc->hc_PeriodicTDQueue.lh_Head : hc->hc_TDQueue.lh_Head);
2270 while(((struct Node *) ioreq)->ln_Succ)
2272 if(ioreq->iouh_Flags & UHFF_NAKTIMEOUT)
2274 eqh = (struct EhciQH *) ioreq->iouh_DriverPrivate1;
2275 if(eqh)
2277 KPRINTF(1, ("Examining IOReq=%p with EQH=%p\n", ioreq, eqh));
2278 devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint + ((ioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0);
2279 ctrlstatus = READMEM32_LE(&eqh->eqh_CtrlStatus);
2280 if(ctrlstatus & ETCF_ACTIVE)
2282 if(framecnt > unit->hu_NakTimeoutFrame[devadrep])
2284 // give the thing the chance to exit gracefully
2285 KPRINTF(20, ("NAK timeout %ld > %ld, IOReq=%p\n", framecnt, unit->hu_NakTimeoutFrame[devadrep], ioreq));
2286 ctrlstatus &= ~ETCF_ACTIVE;
2287 ctrlstatus |= ETSF_HALTED;
2288 WRITEMEM32_LE(&eqh->eqh_CtrlStatus, ctrlstatus);
2289 causeint = TRUE;
2291 } else {
2292 if(ctrlstatus & ETCF_READYINTEN)
2294 KPRINTF(10, ("INT missed?!? Manually causing it! %08lx, IOReq=%p\n",
2295 ctrlstatus, ioreq));
2296 causeint = TRUE;
2301 ioreq = (struct IOUsbHWReq *) ((struct Node *) ioreq)->ln_Succ;
2304 break;
2308 if(causeint)
2310 SureCause(base, &hc->hc_CompleteInt);
2313 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
2316 uhwCheckRootHubChanges(unit);
2318 unit->hu_NakTimeoutReq.tr_time.tv_micro = 150*1000;
2319 SendIO((APTR) &unit->hu_NakTimeoutReq);
2321 KPRINTF(1, ("Exit NakTimeoutInt(0x%p)\n", unit));
2323 return FALSE;
2325 AROS_INTFUNC_EXIT
2327 /* \\\ */