pciusb.device: Differentiate between different debug messages by hardware type
[AROS.git] / rom / usb / pciusb / uhwcmd.c
blobee0397fcdcb127c2e5d62479fb450abe137c99a5
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)
38 #ifdef AROS_USB30_CODE
39 const struct UsbSSHubDesc RHSSHubDesc = { 12, // 0 Number of bytes in this descriptor, including this byte. (12 bytes)
40 UDT_SSHUB, // 1 Descriptor Type, value: 2AH for SuperSpeed hub descriptor
41 0, // 2 Number of downstream facing ports that this hub supports. The maximum number of ports of ports a hub can support is 15
42 WORD2LE(UHCF_INDIVID_POWER|UHCF_INDIVID_OVP), // 3 wHubCharacteristics
43 0, // 5 bPwrOn2PwrGood
44 10, // 6 bHubContrCurrent
45 0, // 7 bHubHdrDecLat
46 0, // 8 wHubDelay
47 0 // 10 DeviceRemovable
49 #endif
51 const CONST_STRPTR RHStrings[] = { "Chris Hodges", "PCI Root Hub Unit x", "Standard Config", "Hub interface" };
53 /* /// "SureCause()" */
54 void SureCause(struct PCIDevice *base, struct Interrupt *interrupt)
56 /* this is a workaround for the original Cause() function missing tailed calls */
57 Disable();
59 if((interrupt->is_Node.ln_Type == NT_SOFTINT) || (interrupt->is_Node.ln_Type == NT_USER))
61 // signal tailed call
62 interrupt->is_Node.ln_Type = NT_USER;
63 } else {
66 interrupt->is_Node.ln_Type = NT_SOFTINT;
67 Forbid(); // make sure code is not interrupted by other tasks
68 Enable();
69 AROS_INTC1(interrupt->is_Code, interrupt->is_Data);
70 Disable();
71 Permit();
72 } while(interrupt->is_Node.ln_Type != NT_SOFTINT);
73 interrupt->is_Node.ln_Type = NT_INTERRUPT;
75 Enable();
77 /* \\\ */
79 /* /// "uhwOpenTimer()" */
80 BOOL uhwOpenTimer(struct PCIUnit *unit, struct PCIDevice *base)
82 if((unit->hu_MsgPort = CreateMsgPort()))
84 if((unit->hu_TimerReq = (struct timerequest *) CreateIORequest(unit->hu_MsgPort, sizeof(struct timerequest))))
86 if(!OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest *) unit->hu_TimerReq, 0))
88 unit->hu_TimerReq->tr_node.io_Message.mn_Node.ln_Name = "PCI hardware";
89 unit->hu_TimerReq->tr_node.io_Command = TR_ADDREQUEST;
90 KPRINTF(1, ("opened timer device\n"));
91 return(TRUE);
93 DeleteIORequest((struct IORequest *) unit->hu_TimerReq);
94 unit->hu_TimerReq = NULL;
96 DeleteMsgPort(unit->hu_MsgPort);
97 unit->hu_MsgPort = NULL;
99 KPRINTF(5, ("failed to open timer.device\n"));
100 return(FALSE);
102 /* \\\ */
104 /* /// "uhwDelayMS()" */
105 void uhwDelayMS(ULONG milli, struct PCIUnit *unit)
107 unit->hu_TimerReq->tr_time.tv_secs = 0;
108 unit->hu_TimerReq->tr_time.tv_micro = milli * 1000;
109 DoIO((struct IORequest *) unit->hu_TimerReq);
111 /* \\\ */
113 /* /// "uhwDelayMicro()" */
114 void uhwDelayMicro(ULONG micro, struct PCIUnit *unit)
116 unit->hu_TimerReq->tr_time.tv_secs = 0;
117 unit->hu_TimerReq->tr_time.tv_micro = micro;
118 DoIO((struct IORequest *) unit->hu_TimerReq);
120 /* \\\ */
122 /* /// "uhwCloseTimer()" */
123 void uhwCloseTimer(struct PCIUnit *unit, struct PCIDevice *base)
125 if(unit->hu_MsgPort)
127 if(unit->hu_TimerReq)
129 KPRINTF(1, ("closing timer.device\n"));
130 CloseDevice((APTR) unit->hu_TimerReq);
131 DeleteIORequest((struct IORequest *) unit->hu_TimerReq);
132 unit->hu_TimerReq = NULL;
134 DeleteMsgPort(unit->hu_MsgPort);
135 unit->hu_MsgPort = NULL;
138 /* \\\ */
140 /* /// "Open_Unit()" */
141 struct Unit * Open_Unit(struct IOUsbHWReq *ioreq,
142 LONG unitnr,
143 struct PCIDevice *base)
145 struct PCIUnit *unit = NULL;
147 if(!base->hd_ScanDone)
149 base->hd_ScanDone = TRUE;
150 if(!pciInit(base))
152 return NULL;
155 unit = (struct PCIUnit *) base->hd_Units.lh_Head;
156 while(((struct Node *) unit)->ln_Succ)
158 if(unit->hu_UnitNo == unitnr)
160 break;
162 unit = (struct PCIUnit *) ((struct Node *) unit)->ln_Succ;
164 if(!((struct Node *) unit)->ln_Succ)
166 KPRINTF(20, ("Unit %ld does not exist!\n", unitnr));
167 return NULL;
169 if(unit->hu_UnitAllocated)
171 ioreq->iouh_Req.io_Error = IOERR_UNITBUSY;
172 KPRINTF(5, ("Unit %ld already open!\n", unitnr));
173 return NULL;
176 if(uhwOpenTimer(unit, base))
179 if(pciAllocUnit(unit)) // hardware self test
181 unit->hu_UnitAllocated = TRUE;
182 unit->hu_NakTimeoutInt.is_Node.ln_Type = NT_INTERRUPT;
183 unit->hu_NakTimeoutInt.is_Node.ln_Name = "PCI NakTimeout";
184 unit->hu_NakTimeoutInt.is_Node.ln_Pri = -16;
185 unit->hu_NakTimeoutInt.is_Data = unit;
186 unit->hu_NakTimeoutInt.is_Code = (VOID_FUNC)uhwNakTimeoutInt;
188 CopyMem(unit->hu_TimerReq, &unit->hu_NakTimeoutReq, sizeof(struct timerequest));
189 unit->hu_NakTimeoutReq.tr_node.io_Message.mn_ReplyPort = &unit->hu_NakTimeoutMsgPort;
190 unit->hu_NakTimeoutMsgPort.mp_Node.ln_Type = NT_MSGPORT;
191 unit->hu_NakTimeoutMsgPort.mp_Flags = PA_SOFTINT;
192 unit->hu_NakTimeoutMsgPort.mp_SigTask = &unit->hu_NakTimeoutInt;
193 NewList(&unit->hu_NakTimeoutMsgPort.mp_MsgList);
194 Cause(&unit->hu_NakTimeoutInt);
195 return(&unit->hu_Unit);
196 } else {
197 ioreq->iouh_Req.io_Error = IOERR_SELFTEST;
198 KPRINTF(20, ("Hardware allocation failure!\n"));
200 uhwCloseTimer(unit, base);
202 return(NULL);
204 /* \\\ */
206 /* /// "Close_Unit()" */
207 void Close_Unit(struct PCIDevice *base,
208 struct PCIUnit *unit,
209 struct IOUsbHWReq *ioreq)
211 /* Disable all interrupts */
212 unit->hu_NakTimeoutMsgPort.mp_Flags = PA_IGNORE;
213 unit->hu_NakTimeoutInt.is_Node.ln_Type = NT_SOFTINT;
214 AbortIO((APTR) &unit->hu_NakTimeoutReq);
216 pciFreeUnit(unit);
218 uhwCloseTimer(unit, base);
219 unit->hu_UnitAllocated = FALSE;
221 /* \\\ */
223 /* /// "uhwGetUsbState()" */
224 UWORD uhwGetUsbState(struct IOUsbHWReq *ioreq,
225 struct PCIUnit *unit,
226 struct PCIDevice *base)
228 return(ioreq->iouh_State = UHSF_OPERATIONAL);
230 /* \\\ */
232 /* /// "cmdReset()" */
234 *======================================================================
235 * cmdReset(ioreq, unit, base)
236 *======================================================================
238 * This is the device CMD_RESET routine.
240 * Resets the whole USB hardware. Goes into USBOperational mode right
241 * after. Must NOT be called from an interrupt.
245 WORD cmdReset(struct IOUsbHWReq *ioreq,
246 struct PCIUnit *unit,
247 struct PCIDevice *base)
249 KPRINTF(10, ("CMD_RESET ioreq: 0x%p\n", ioreq));
251 uhwDelayMS(1, unit);
252 uhwGetUsbState(ioreq, unit, base);
254 if(ioreq->iouh_State & UHSF_OPERATIONAL)
256 return RC_OK;
258 return UHIOERR_USBOFFLINE;
260 /* \\\ */
262 /* /// "cmdUsbReset()" */
264 *======================================================================
265 * cmdUsbReset(ioreq, unit, base)
266 *======================================================================
268 * This is the device UHCMD_USBRESET routine.
270 * Resets the USB bus. Goes into USBOperational mode right after. Must
271 * NOT be called from an interrupt.
275 WORD cmdUsbReset(struct IOUsbHWReq *ioreq,
276 struct PCIUnit *unit,
277 struct PCIDevice *base)
279 KPRINTF(10, ("UHCMD_USBRESET ioreq: 0x%p\n", ioreq));
281 /* FIXME */
282 uhwGetUsbState(ioreq, unit, base);
284 unit->hu_FrameCounter = 1;
285 unit->hu_RootHubAddr = 0;
287 if(ioreq->iouh_State & UHSF_OPERATIONAL)
289 return RC_OK;
291 return UHIOERR_USBOFFLINE;
293 /* \\\ */
295 /* /// "cmdUsbResume()" */
297 *======================================================================
298 * cmdUsbResume(ioreq, unit, base)
299 *======================================================================
301 * This is the device UHCMD_USBRESUME routine.
303 * Tries to resume from USBSuspend mode into USBOperational.
304 * Must NOT be called from an interrupt.
308 WORD cmdUsbResume(struct IOUsbHWReq *ioreq,
309 struct PCIUnit *unit,
310 struct PCIDevice *base)
312 KPRINTF(10, ("UHCMD_USBRESUME ioreq: 0x%p\n", ioreq));
314 /* FIXME */
315 uhwGetUsbState(ioreq, unit, base);
316 if(ioreq->iouh_State & UHSF_OPERATIONAL)
318 return RC_OK;
320 return UHIOERR_USBOFFLINE;
322 /* \\\ */
324 /* /// "cmdUsbSuspend()" */
326 *======================================================================
327 * cmdUsbSuspend(ioreq, unit, base)
328 *======================================================================
330 * This is the device UHCMD_USBSUSPEND routine.
332 * Sets the USB into USBSuspend mode.
333 * Must NOT be called from an interrupt.
337 WORD cmdUsbSuspend(struct IOUsbHWReq *ioreq,
338 struct PCIUnit *unit,
339 struct PCIDevice *base)
341 KPRINTF(10, ("UHCMD_USBSUSPEND ioreq: 0x%p\n", ioreq));
343 /* FIXME */
344 uhwGetUsbState(ioreq, unit, base);
345 if(ioreq->iouh_State & UHSF_SUSPENDED)
347 return RC_OK;
349 return UHIOERR_USBOFFLINE;
351 /* \\\ */
353 /* /// "cmdUsbOper()" */
355 *======================================================================
356 * cmdUsbOper(ioreq, unit, base)
357 *======================================================================
359 * This is the device UHCMD_USBOPER routine.
361 * Sets the USB into USBOperational mode.
362 * Must NOT be called from an interrupt.
366 WORD cmdUsbOper(struct IOUsbHWReq *ioreq,
367 struct PCIUnit *unit,
368 struct PCIDevice *base)
370 KPRINTF(10, ("UHCMD_USBOPER ioreq: 0x%p\n", ioreq));
372 /* FIXME */
373 uhwGetUsbState(ioreq, unit, base);
374 if(ioreq->iouh_State & UHSF_OPERATIONAL)
376 return RC_OK;
378 return UHIOERR_USBOFFLINE;
380 /* \\\ */
382 /* /// "cmdQueryDevice()" */
384 *======================================================================
385 * cmdQueryDevice(ioreq, unit, base)
386 *======================================================================
388 * This is the device UHCMD_QUERYDEVICE routine.
390 * Returns information about the hardware.
394 WORD cmdQueryDevice(struct IOUsbHWReq *ioreq,
395 struct PCIUnit *unit,
396 struct PCIDevice *base)
398 struct TagItem *taglist = (struct TagItem *) ioreq->iouh_Data;
399 struct TagItem *tag;
400 ULONG count = 0;
402 KPRINTF(10, ("UHCMD_QUERYDEVICE ioreq: 0x%p, taglist: 0x%p\n", ioreq, taglist));
404 if((tag = FindTagItem(UHA_State, taglist)))
406 *((ULONG *) tag->ti_Data) = (ULONG) uhwGetUsbState(ioreq, unit, base);
407 count++;
409 if((tag = FindTagItem(UHA_Manufacturer, taglist)))
411 *((STRPTR *) tag->ti_Data) = "Chris Hodges";
412 count++;
414 if((tag = FindTagItem(UHA_ProductName, taglist)))
416 *((STRPTR *) tag->ti_Data) = unit->hu_ProductName;
417 count++;
419 if((tag = FindTagItem(UHA_Description, taglist)))
421 *((STRPTR *) tag->ti_Data) = "Generic adaptive host controller driver for PCI cards";
422 count++;
424 if((tag = FindTagItem(UHA_Copyright, taglist)))
426 *((STRPTR *) tag->ti_Data) ="©2007-2009 Chris Hodges";
427 count++;
429 if((tag = FindTagItem(UHA_Version, taglist)))
431 *((ULONG *) tag->ti_Data) = VERSION_NUMBER;
432 count++;
434 if((tag = FindTagItem(UHA_Revision, taglist)))
436 *((ULONG *) tag->ti_Data) = REVISION_NUMBER;
437 count++;
439 if((tag = FindTagItem(UHA_DriverVersion, taglist)))
441 *((ULONG *) tag->ti_Data) = 0x220;
442 count++;
444 if((tag = FindTagItem(UHA_Capabilities, taglist)))
446 *((ULONG *) tag->ti_Data) = UHCF_USB20;
447 count++;
449 ioreq->iouh_Actual = count;
450 return RC_OK;
452 /* \\\ */
454 /* /// "cmdControlXFerRootHub()" */
455 WORD cmdControlXFerRootHub(struct IOUsbHWReq *ioreq,
456 struct PCIUnit *unit,
457 struct PCIDevice *base)
459 struct PCIController *hc;
460 struct PCIController *chc;
461 UWORD rt = ioreq->iouh_SetupData.bmRequestType;
462 UWORD req = ioreq->iouh_SetupData.bRequest;
463 UWORD idx = AROS_WORD2LE(ioreq->iouh_SetupData.wIndex);
464 UWORD val = AROS_WORD2LE(ioreq->iouh_SetupData.wValue);
465 UWORD len = AROS_WORD2LE(ioreq->iouh_SetupData.wLength);
466 UWORD hciport;
467 ULONG numports = unit->hu_RootHubPorts;
468 BOOL cmdgood;
469 ULONG cnt;
471 if(ioreq->iouh_Endpoint)
473 return(UHIOERR_STALL);
476 if(len != ioreq->iouh_Length)
478 KPRINTF(20, ("RH: Len (%ld != %ld) mismatch!\n", len != ioreq->iouh_Length));
479 return(UHIOERR_STALL);
481 switch(rt)
483 case (URTF_STANDARD|URTF_DEVICE):
484 switch(req)
486 case USR_SET_ADDRESS:
487 KPRINTF(1, ("RH: SetAddress = %ld\n", val));
488 unit->hu_RootHubAddr = val;
489 ioreq->iouh_Actual = len;
490 return(0);
492 case USR_SET_CONFIGURATION:
493 KPRINTF(1, ("RH: SetConfiguration=%ld\n", val));
494 ioreq->iouh_Actual = len;
495 return(0);
497 break;
499 case (URTF_IN|URTF_STANDARD|URTF_DEVICE):
500 switch(req)
502 case USR_GET_DESCRIPTOR:
503 switch(val>>8)
505 case UDT_DEVICE:
506 KPRINTF(1, ("RH: GetDeviceDescriptor (%ld)\n", len));
507 ioreq->iouh_Actual = (len > sizeof(struct UsbStdDevDesc)) ? sizeof(struct UsbStdDevDesc) : len;
508 CopyMem((APTR) &RHDevDesc, ioreq->iouh_Data, ioreq->iouh_Actual);
509 if(ioreq->iouh_Length >= sizeof(struct UsbStdDevDesc))
511 if(unit->hu_RootHub20Ports)
513 struct UsbStdDevDesc *usdd = (struct UsbStdDevDesc *) ioreq->iouh_Data;
514 usdd->bcdUSB = AROS_WORD2LE(0x0200); // signal a highspeed root hub
515 usdd->bDeviceProtocol = 1; // single TT
517 #ifdef AROS_USB30_CODE
518 if(unit->hu_RootHub30Ports)
520 struct UsbStdDevDesc *usdd = (struct UsbStdDevDesc *) ioreq->iouh_Data;
521 usdd->bcdUSB = AROS_WORD2LE(0x0300); // signal a superspeed root hub
522 usdd->bDeviceProtocol = 3;
524 #endif
526 return(0);
528 case UDT_CONFIGURATION:
530 UBYTE tmpbuf[9+9+7];
531 KPRINTF(1, ("RH: GetConfigDescriptor (%ld)\n", len));
532 CopyMem((APTR) &RHCfgDesc, tmpbuf, 9);
533 CopyMem((APTR) &RHIfDesc, &tmpbuf[9], 9);
534 CopyMem((APTR) &RHEPDesc, &tmpbuf[9+9], 7);
535 if(unit->hu_RootHub20Ports)
537 struct UsbStdEPDesc *usepd = (struct UsbStdEPDesc *) &tmpbuf[9+9];
538 usepd->bInterval = 12; // 2048 µFrames
540 ioreq->iouh_Actual = (len > 9+9+7) ? 9+9+7 : len;
541 CopyMem(tmpbuf, ioreq->iouh_Data, ioreq->iouh_Actual);
542 return(0);
545 case UDT_STRING:
546 if(val & 0xff) /* get lang array */
548 CONST_STRPTR source = NULL;
549 UWORD *mptr = ioreq->iouh_Data;
550 UWORD slen = 1;
551 KPRINTF(1, ("RH: GetString %04lx (%ld)\n", val, len));
552 if((val & 0xff) > 4) /* index too high? */
554 return(UHIOERR_STALL);
556 source = RHStrings[(val & 0xff)-1];
557 if(len > 1)
559 ioreq->iouh_Actual = 2;
560 while(*source++)
562 slen++;
564 source = RHStrings[(val & 0xff)-1];
565 *mptr++ = AROS_WORD2BE((slen<<9)|UDT_STRING);
566 while(ioreq->iouh_Actual+1 < len)
568 // special hack for unit number in root hub string
569 if(((val & 0xff) == 2) && (source[1] == 0))
571 *mptr++ = AROS_WORD2LE('0' + unit->hu_UnitNo);
572 } else {
573 *mptr++ = AROS_WORD2LE(*source);
575 source++;
576 ioreq->iouh_Actual += 2;
577 if(!(*source))
579 break;
583 } else {
584 UWORD *mptr = ioreq->iouh_Data;
585 KPRINTF(1, ("RH: GetLangArray %04lx (%ld)\n", val, len));
586 if(len > 1)
588 ioreq->iouh_Actual = 2;
589 mptr[0] = AROS_WORD2BE((4<<8)|UDT_STRING);
590 if(len > 3)
592 ioreq->iouh_Actual += 2;
593 mptr[1] = AROS_WORD2LE(0x0409);
597 return(0);
599 default:
600 KPRINTF(1, ("RH: Unsupported Descriptor %04lx\n", idx));
602 break;
604 case USR_GET_CONFIGURATION:
605 if(len == 1)
607 KPRINTF(1, ("RH: GetConfiguration\n"));
608 ((UBYTE *) ioreq->iouh_Data)[0] = 1;
609 ioreq->iouh_Actual = len;
610 return(0);
612 break;
614 break;
616 case (URTF_CLASS|URTF_OTHER):
617 switch(req)
619 case USR_SET_FEATURE:
620 if((!idx) && (idx > numports))
622 KPRINTF(20, ("Port %ld out of range\n", idx));
623 return(UHIOERR_STALL);
625 chc = unit->hu_PortMap11[idx - 1];
626 if(unit->hu_EhciOwned[idx - 1])
628 hc = unit->hu_PortMap20[idx - 1];
629 hciport = idx - 1;
630 } else {
631 hc = chc;
632 hciport = unit->hu_PortNum11[idx - 1];
634 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"));
635 cmdgood = FALSE;
636 switch(hc->hc_HCIType)
638 case HCITYPE_UHCI:
640 UWORD portreg = hciport ? UHCI_PORT2STSCTRL : UHCI_PORT1STSCTRL;
641 ULONG oldval = READIO16_LE(hc->hc_RegBase, portreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE); // these are clear-on-write!
642 ULONG newval = oldval;
643 switch(val)
645 /* case UFS_PORT_CONNECTION: not possible */
646 case UFS_PORT_ENABLE:
647 KPRINTF(10, ("UHCI: Enabling Port (%s)\n", newval & UHPF_PORTENABLE ? "already" : "ok"));
648 newval |= UHPF_PORTENABLE;
649 cmdgood = TRUE;
650 break;
652 case UFS_PORT_SUSPEND:
653 newval |= UHPF_PORTSUSPEND;
654 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_SUSPEND; // manually fake suspend change
655 cmdgood = TRUE;
656 break;
658 /* case UFS_PORT_OVER_CURRENT: not possible */
659 case UFS_PORT_RESET:
660 KPRINTF(10, ("UHCI: Resetting Port (%s)\n", newval & UHPF_PORTRESET ? "already" : "ok"));
662 // this is an ugly blocking workaround to the inability of UHCI to clear reset automatically
663 newval &= ~(UHPF_PORTSUSPEND|UHPF_PORTENABLE);
664 newval |= UHPF_PORTRESET;
665 WRITEIO16_LE(hc->hc_RegBase, portreg, newval);
666 uhwDelayMS(25, unit);
667 newval = READIO16_LE(hc->hc_RegBase, portreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE|UHPF_PORTSUSPEND|UHPF_PORTENABLE);
668 KPRINTF(10, ("UHCI: Reset=%s\n", newval & UHPF_PORTRESET ? "GOOD" : "BAD!"));
669 // like windows does it
670 newval &= ~UHPF_PORTRESET;
671 WRITEIO16_LE(hc->hc_RegBase, portreg, newval);
672 uhwDelayMicro(50, unit);
673 newval = READIO16_LE(hc->hc_RegBase, portreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE|UHPF_PORTSUSPEND);
674 KPRINTF(10, ("UHCI: Reset=%s\n", newval & UHPF_PORTRESET ? "BAD!" : "GOOD"));
675 newval &= ~(UHPF_PORTSUSPEND|UHPF_PORTRESET);
676 newval |= UHPF_PORTENABLE;
677 WRITEIO16_LE(hc->hc_RegBase, portreg, newval);
678 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_RESET|UPSF_PORT_ENABLE; // manually fake reset change
680 cnt = 100;
683 uhwDelayMS(1, unit);
684 newval = READIO16_LE(hc->hc_RegBase, portreg);
685 } while(--cnt && (!(newval & UHPF_PORTENABLE)));
686 if(cnt)
688 KPRINTF(10, ("UHCI: Enabled after %ld ticks\n", 100-cnt));
689 } else {
690 KPRINTF(20, ("UHCI: Port refuses to be enabled!\n"));
691 return(UHIOERR_HOSTERROR);
693 // make enumeration possible
694 unit->hu_DevControllers[0] = hc;
695 cmdgood = TRUE;
696 break;
698 case UFS_PORT_POWER:
699 KPRINTF(10, ("UHCI: Powering Port\n"));
700 // ignore for UHCI, is always powered
701 cmdgood = TRUE;
702 break;
704 /* case UFS_PORT_LOW_SPEED: not possible */
705 /* case UFS_C_PORT_CONNECTION:
706 case UFS_C_PORT_ENABLE:
707 case UFS_C_PORT_SUSPEND:
708 case UFS_C_PORT_OVER_CURRENT:
709 case UFS_C_PORT_RESET: */
711 if(cmdgood)
713 KPRINTF(5, ("UHCI: Port %ld SET_FEATURE %04lx->%04lx\n", idx, oldval, newval));
714 WRITEIO16_LE(hc->hc_RegBase, portreg, newval);
715 return(0);
717 break;
720 case HCITYPE_OHCI:
722 UWORD portreg = OHCI_PORTSTATUS + (hciport<<2);
723 ULONG oldval = READREG32_LE(hc->hc_RegBase, portreg);
725 switch(val)
727 /* case UFS_PORT_CONNECTION: not possible */
728 case UFS_PORT_ENABLE:
729 KPRINTF(10, ("OHCI: Enabling Port (%s)\n", oldval & OHPF_PORTENABLE ? "already" : "ok"));
730 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTENABLE);
731 cmdgood = TRUE;
732 break;
734 case UFS_PORT_SUSPEND:
735 KPRINTF(10, ("OHCI: Suspending Port (%s)\n", oldval & OHPF_PORTSUSPEND ? "already" : "ok"));
736 //hc->hc_PortChangeMap[hciport] |= UPSF_PORT_SUSPEND; // manually fake suspend change
737 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTSUSPEND);
738 cmdgood = TRUE;
739 break;
741 /* case UFS_PORT_OVER_CURRENT: not possible */
742 case UFS_PORT_RESET:
743 KPRINTF(10, ("OHCI: Resetting Port (%s)\n", oldval & OHPF_PORTRESET ? "already" : "ok"));
744 // make sure we have at least 50ms of reset time here, as required for a root hub port
745 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTRESET);
746 uhwDelayMS(10, unit);
747 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTRESET);
748 uhwDelayMS(10, unit);
749 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTRESET);
750 uhwDelayMS(10, unit);
751 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTRESET);
752 uhwDelayMS(10, unit);
753 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTRESET);
754 uhwDelayMS(15, unit);
755 oldval = READREG32_LE(hc->hc_RegBase, portreg);
756 KPRINTF(10, ("OHCI: Reset release (%s %s)\n", oldval & OHPF_PORTRESET ? "didn't turn off" : "okay",
757 oldval & OHPF_PORTENABLE ? "enabled" : "not enabled"));
758 if(oldval & OHPF_PORTRESET)
760 uhwDelayMS(40, unit);
761 oldval = READREG32_LE(hc->hc_RegBase, portreg);
762 KPRINTF(10, ("OHCI: Reset 2nd release (%s %s)\n", oldval & OHPF_PORTRESET ? "didn't turn off" : "okay",
763 oldval & OHPF_PORTENABLE ? "enabled" : "still not enabled"));
765 // make enumeration possible
766 unit->hu_DevControllers[0] = hc;
767 cmdgood = TRUE;
768 break;
770 case UFS_PORT_POWER:
771 KPRINTF(10, ("OHCI: Powering Port (%s)\n", oldval & OHPF_PORTPOWER ? "already" : "ok"));
772 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTPOWER);
773 cmdgood = TRUE;
774 break;
776 /* case UFS_PORT_LOW_SPEED: not possible */
777 /* case UFS_C_PORT_CONNECTION:
778 case UFS_C_PORT_ENABLE:
779 case UFS_C_PORT_SUSPEND:
780 case UFS_C_PORT_OVER_CURRENT:
781 case UFS_C_PORT_RESET: */
783 if(cmdgood)
785 return(0);
787 break;
790 case HCITYPE_EHCI:
792 UWORD portreg = EHCI_PORTSC1 + (hciport<<2);
793 ULONG oldval = READREG32_LE(hc->hc_RegBase, portreg) & ~(EHPF_OVERCURRENTCHG|EHPF_ENABLECHANGE|EHPF_CONNECTCHANGE); // these are clear-on-write!
794 ULONG newval = oldval;
795 switch(val)
797 /* case UFS_PORT_CONNECTION: not possible */
798 case UFS_PORT_ENABLE:
799 KPRINTF(10, ("EHCI: Enabling Port (%s)\n", newval & EHPF_PORTENABLE ? "already" : "ok"));
800 newval |= EHPF_PORTENABLE;
801 cmdgood = TRUE;
802 break;
804 case UFS_PORT_SUSPEND:
805 newval |= EHPF_PORTSUSPEND;
806 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_SUSPEND; // manually fake suspend change
807 cmdgood = TRUE;
808 break;
810 /* case UFS_PORT_OVER_CURRENT: not possible */
811 case UFS_PORT_RESET:
812 KPRINTF(10, ("EHCI: Resetting Port (%s)\n", newval & EHPF_PORTRESET ? "already" : "ok"));
814 // this is an ugly blocking workaround to the inability of EHCI to clear reset automatically
815 newval &= ~(EHPF_PORTSUSPEND|EHPF_PORTENABLE);
816 newval |= EHPF_PORTRESET;
817 WRITEREG32_LE(hc->hc_RegBase, portreg, newval);
818 uhwDelayMS(50, unit);
819 newval = READREG32_LE(hc->hc_RegBase, portreg) & ~(EHPF_OVERCURRENTCHG|EHPF_ENABLECHANGE|EHPF_CONNECTCHANGE|EHPF_PORTSUSPEND|EHPF_PORTENABLE);
820 KPRINTF(10, ("EHCI: Reset=%s\n", newval & EHPF_PORTRESET ? "GOOD" : "BAD!"));
821 newval &= ~EHPF_PORTRESET;
822 WRITEREG32_LE(hc->hc_RegBase, portreg, newval);
823 uhwDelayMS(10, unit);
824 newval = READREG32_LE(hc->hc_RegBase, portreg) & ~(EHPF_OVERCURRENTCHG|EHPF_ENABLECHANGE|EHPF_CONNECTCHANGE|EHPF_PORTSUSPEND);
825 KPRINTF(10, ("EHCI: Reset=%s\n", newval & EHPF_PORTRESET ? "BAD!" : "GOOD"));
826 KPRINTF(10, ("EHCI: Highspeed=%s\n", newval & EHPF_PORTENABLE ? "YES!" : "NO"));
827 KPRINTF(10, ("EHCI: Port status=%08lx\n", newval));
828 if(!(newval & EHPF_PORTENABLE))
830 // if not highspeed, release ownership
831 KPRINTF(20, ("EHCI: Transferring ownership to UHCI/OHCI port %ld\n", unit->hu_PortNum11[idx - 1]));
832 KPRINTF(10, ("EHCI: Device is %s\n", newval & EHPF_LINESTATUS_DM ? "LOWSPEED" : "FULLSPEED"));
833 newval |= EHPF_NOTPORTOWNER;
834 if(!chc)
836 KPRINTF(20, ("EHCI has no companion controller, can't transfer ownership!\n"));
837 WRITEREG32_LE(hc->hc_RegBase, portreg, newval);
838 return(UHIOERR_HOSTERROR);
840 switch(chc->hc_HCIType)
842 case HCITYPE_UHCI:
844 UWORD uhcihciport = unit->hu_PortNum11[idx - 1];
845 UWORD uhciportreg = uhcihciport ? UHCI_PORT2STSCTRL : UHCI_PORT1STSCTRL;
846 ULONG __unused uhcinewval = READREG16_LE(chc->hc_RegBase, uhciportreg);
848 KPRINTF(10, ("UHCI Port status before handover=%04lx\n", uhcinewval));
849 break;
852 case HCITYPE_OHCI:
854 UWORD ohcihciport = unit->hu_PortNum11[idx - 1];
855 UWORD ohciportreg = OHCI_PORTSTATUS + (ohcihciport<<2);
856 ULONG __unused ohcioldval = READREG32_LE(chc->hc_RegBase, ohciportreg);
858 KPRINTF(10, ("OHCI: Port status before handover=%08lx\n", ohcioldval));
859 KPRINTF(10, ("OHCI: Powering Port (%s)\n", ohcioldval & OHPF_PORTPOWER ? "already" : "ok"));
860 WRITEREG32_LE(chc->hc_RegBase, ohciportreg, OHPF_PORTPOWER);
861 uhwDelayMS(10, unit);
862 KPRINTF(10, ("OHCI: Port status after handover=%08lx\n", READREG32_LE(chc->hc_RegBase, ohciportreg)));
863 break;
866 newval = READREG32_LE(hc->hc_RegBase, portreg) & ~(EHPF_OVERCURRENTCHG|EHPF_ENABLECHANGE|EHPF_CONNECTCHANGE|EHPF_PORTSUSPEND);
867 KPRINTF(10, ("EHCI: Port status (reread)=%08lx\n", newval));
868 newval |= EHPF_NOTPORTOWNER;
869 unit->hu_EhciOwned[idx - 1] = FALSE;
870 WRITEREG32_LE(hc->hc_RegBase, portreg, newval);
871 uhwDelayMS(90, unit);
872 KPRINTF(10, ("EHCI: Port status (after handover)=%08lx\n", READREG32_LE(hc->hc_RegBase, portreg) & ~(EHPF_OVERCURRENTCHG|EHPF_ENABLECHANGE|EHPF_CONNECTCHANGE|EHPF_PORTSUSPEND)));
873 // enable companion controller port
874 switch(chc->hc_HCIType)
876 case HCITYPE_UHCI:
878 UWORD uhcihciport = unit->hu_PortNum11[idx - 1];
879 UWORD uhciportreg = uhcihciport ? UHCI_PORT2STSCTRL : UHCI_PORT1STSCTRL;
880 ULONG uhcinewval;
882 uhcinewval = READIO16_LE(chc->hc_RegBase, uhciportreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE|UHPF_PORTSUSPEND);
883 KPRINTF(10, ("UHCI: Reset=%s\n", uhcinewval & UHPF_PORTRESET ? "BAD!" : "GOOD"));
884 if((uhcinewval & UHPF_PORTRESET))//|| (newval & EHPF_LINESTATUS_DM))
886 // this is an ugly blocking workaround to the inability of UHCI to clear reset automatically
887 KPRINTF(20, ("UHCI: Uhm, reset was bad!\n"));
888 uhcinewval &= ~(UHPF_PORTSUSPEND|UHPF_PORTENABLE);
889 uhcinewval |= UHPF_PORTRESET;
890 WRITEIO16_LE(chc->hc_RegBase, uhciportreg, uhcinewval);
891 uhwDelayMS(50, unit);
892 uhcinewval = READIO16_LE(chc->hc_RegBase, uhciportreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE|UHPF_PORTSUSPEND|UHPF_PORTENABLE);
893 KPRINTF(10, ("UHCI: ReReset=%s\n", uhcinewval & UHPF_PORTRESET ? "GOOD" : "BAD!"));
894 uhcinewval &= ~UHPF_PORTRESET;
895 WRITEIO16_LE(chc->hc_RegBase, uhciportreg, uhcinewval);
896 uhwDelayMicro(50, unit);
897 uhcinewval = READIO16_LE(chc->hc_RegBase, uhciportreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE|UHPF_PORTSUSPEND);
898 KPRINTF(10, ("UHCI: ReReset=%s\n", uhcinewval & UHPF_PORTRESET ? "STILL BAD!" : "GOOD"));
900 uhcinewval &= ~UHPF_PORTRESET;
901 uhcinewval |= UHPF_PORTENABLE;
902 WRITEIO16_LE(chc->hc_RegBase, uhciportreg, uhcinewval);
903 chc->hc_PortChangeMap[uhcihciport] |= UPSF_PORT_RESET|UPSF_PORT_ENABLE; // manually fake reset change
904 uhwDelayMS(5, unit);
905 cnt = 100;
908 uhwDelayMS(1, unit);
909 uhcinewval = READIO16_LE(chc->hc_RegBase, uhciportreg);
910 } while(--cnt && (!(uhcinewval & UHPF_PORTENABLE)));
911 if(cnt)
913 KPRINTF(10, ("UHCI: Enabled after %ld ticks\n", 100-cnt));
914 } else {
915 KPRINTF(20, ("UHCI: Port refuses to be enabled!\n"));
916 return(UHIOERR_HOSTERROR);
918 break;
921 case HCITYPE_OHCI:
923 UWORD ohcihciport = unit->hu_PortNum11[idx - 1];
924 UWORD ohciportreg = OHCI_PORTSTATUS + (ohcihciport<<2);
925 ULONG ohcioldval = READREG32_LE(chc->hc_RegBase, ohciportreg);
926 KPRINTF(10, ("OHCI: Resetting Port (%s)\n", ohcioldval & OHPF_PORTRESET ? "already" : "ok"));
927 // make sure we have at least 50ms of reset time here, as required for a root hub port
928 WRITEREG32_LE(chc->hc_RegBase, ohciportreg, OHPF_PORTRESET);
929 uhwDelayMS(10, unit);
930 WRITEREG32_LE(chc->hc_RegBase, ohciportreg, OHPF_PORTRESET);
931 uhwDelayMS(10, unit);
932 WRITEREG32_LE(chc->hc_RegBase, ohciportreg, OHPF_PORTRESET);
933 uhwDelayMS(10, unit);
934 WRITEREG32_LE(chc->hc_RegBase, ohciportreg, OHPF_PORTRESET);
935 uhwDelayMS(10, unit);
936 WRITEREG32_LE(chc->hc_RegBase, ohciportreg, OHPF_PORTRESET);
937 uhwDelayMS(15, unit);
938 ohcioldval = READREG32_LE(chc->hc_RegBase, ohciportreg);
939 KPRINTF(10, ("OHCI: Reset release (%s %s)\n", ohcioldval & OHPF_PORTRESET ? "didn't turn off" : "okay",
940 ohcioldval & OHPF_PORTENABLE ? "enabled" : "not enabled"));
941 if(ohcioldval & OHPF_PORTRESET)
943 uhwDelayMS(40, unit);
944 ohcioldval = READREG32_LE(chc->hc_RegBase, ohciportreg);
945 KPRINTF(10, ("OHCI: Reset 2nd release (%s %s)\n", ohcioldval & OHPF_PORTRESET ? "didn't turn off" : "okay",
946 ohcioldval & OHPF_PORTENABLE ? "enabled" : "still not enabled"));
948 break;
952 // make enumeration possible
953 unit->hu_DevControllers[0] = chc;
954 return(0);
955 } else {
956 newval &= ~EHPF_PORTRESET;
957 WRITEREG16_LE(hc->hc_RegBase, portreg, newval);
958 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_RESET; // manually fake reset change
959 uhwDelayMS(10, unit);
960 cnt = 100;
963 uhwDelayMS(1, unit);
964 newval = READREG32_LE(hc->hc_RegBase, portreg);
965 } while(--cnt && (!(newval & EHPF_PORTENABLE)));
966 if(cnt)
968 KPRINTF(10, ("EHCI: Enabled after %ld ticks\n", 100-cnt));
969 } else {
970 KPRINTF(20, ("EHCI: Port refuses to be enabled!\n"));
971 return(UHIOERR_HOSTERROR);
973 // make enumeration possible
974 unit->hu_DevControllers[0] = hc;
976 cmdgood = TRUE;
977 break;
979 case UFS_PORT_POWER:
980 KPRINTF(10, ("EHCI: Powering Port\n"));
981 newval |= EHPF_PORTPOWER;
982 cmdgood = TRUE;
983 break;
985 /* case UFS_PORT_LOW_SPEED: not possible */
986 /* case UFS_C_PORT_CONNECTION:
987 case UFS_C_PORT_ENABLE:
988 case UFS_C_PORT_SUSPEND:
989 case UFS_C_PORT_OVER_CURRENT:
990 case UFS_C_PORT_RESET: */
992 if(cmdgood)
994 KPRINTF(5, ("EHCI: Port %ld SET_FEATURE %04lx->%04lx\n", idx, oldval, newval));
995 WRITEREG32_LE(hc->hc_RegBase, portreg, newval);
996 return(0);
998 break;
1001 #ifdef AROS_USB30_CODE
1002 /* (URTF_CLASS|URTF_OTHER) USR_SET_FEATURE */
1003 case HCITYPE_XHCI:
1005 cmdgood = TRUE;
1006 if(cmdgood)
1008 KPRINTF(1000, ("XHCI (URTF_CLASS|URTF_OTHER) USR_SET_FEATURE\n"));
1009 return(0);
1011 break;
1013 #endif
1016 break;
1018 case USR_CLEAR_FEATURE:
1019 if((!idx) && (idx > numports))
1021 KPRINTF(20, ("Port %ld out of range\n", idx));
1022 return(UHIOERR_STALL);
1024 if(unit->hu_EhciOwned[idx - 1])
1026 hc = unit->hu_PortMap20[idx - 1];
1027 hciport = idx - 1;
1028 } else {
1029 hc = unit->hu_PortMap11[idx - 1];
1030 hciport = unit->hu_PortNum11[idx - 1];
1032 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"));
1033 cmdgood = FALSE;
1034 switch(hc->hc_HCIType)
1036 case HCITYPE_UHCI:
1038 UWORD portreg = hciport ? UHCI_PORT2STSCTRL : UHCI_PORT1STSCTRL;
1039 ULONG oldval = READIO16_LE(hc->hc_RegBase, portreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE); // these are clear-on-write!
1040 ULONG newval = oldval;
1041 switch(val)
1043 case UFS_PORT_ENABLE:
1044 KPRINTF(10, ("Disabling Port (%s)\n", newval & UHPF_PORTENABLE ? "ok" : "already"));
1045 newval &= ~UHPF_PORTENABLE;
1046 cmdgood = TRUE;
1047 // disable enumeration
1048 unit->hu_DevControllers[0] = NULL;
1049 break;
1051 case UFS_PORT_SUSPEND:
1052 newval &= ~UHPF_PORTSUSPEND;
1053 cmdgood = TRUE;
1054 break;
1056 case UFS_PORT_POWER: // ignore for UHCI, there's no power control here
1057 KPRINTF(10, ("Disabling Power\n"));
1058 KPRINTF(10, ("Disabling Port (%s)\n", newval & UHPF_PORTENABLE ? "ok" : "already"));
1059 newval &= ~UHPF_PORTENABLE;
1060 cmdgood = TRUE;
1061 break;
1063 case UFS_C_PORT_CONNECTION:
1064 newval |= UHPF_CONNECTCHANGE; // clear-on-write!
1065 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_CONNECTION;
1066 cmdgood = TRUE;
1067 break;
1069 case UFS_C_PORT_ENABLE:
1070 newval |= UHPF_ENABLECHANGE; // clear-on-write!
1071 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_ENABLE;
1072 cmdgood = TRUE;
1073 break;
1075 case UFS_C_PORT_SUSPEND: // ignore for UHCI, there's no bit indicating this
1076 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_SUSPEND; // manually fake suspend change clearing
1077 cmdgood = TRUE;
1078 break;
1080 case UFS_C_PORT_OVER_CURRENT: // ignore for UHCI, there's no bit indicating this
1081 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_OVER_CURRENT; // manually fake over current clearing
1082 cmdgood = TRUE;
1083 break;
1085 case UFS_C_PORT_RESET: // ignore for UHCI, there's no bit indicating this
1086 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_RESET; // manually fake reset change clearing
1087 cmdgood = TRUE;
1088 break;
1090 if(cmdgood)
1092 KPRINTF(5, ("Port %ld CLEAR_FEATURE %04lx->%04lx\n", idx, oldval, newval));
1093 WRITEIO16_LE(hc->hc_RegBase, portreg, newval);
1094 if(hc->hc_PortChangeMap[hciport])
1096 unit->hu_RootPortChanges |= 1UL<<idx;
1097 } else {
1098 unit->hu_RootPortChanges &= ~(1UL<<idx);
1100 return(0);
1102 break;
1105 case HCITYPE_OHCI:
1107 UWORD portreg = OHCI_PORTSTATUS + (hciport<<2);
1108 ULONG __unused oldval = READREG32_LE(hc->hc_RegBase, portreg);
1110 switch(val)
1112 case UFS_PORT_ENABLE:
1113 KPRINTF(10, ("Disabling Port (%s)\n", oldval & OHPF_PORTENABLE ? "ok" : "already"));
1114 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTDISABLE);
1115 cmdgood = TRUE;
1116 break;
1118 case UFS_PORT_SUSPEND:
1119 KPRINTF(10, ("Resuming Port (%s)\n", oldval & OHPF_PORTSUSPEND ? "ok" : "already"));
1120 //hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_SUSPEND; // manually fake suspend change
1121 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_RESUME);
1122 cmdgood = TRUE;
1123 break;
1125 case UFS_PORT_POWER:
1126 KPRINTF(10, ("Unpowering Port (%s)\n", oldval & OHPF_PORTPOWER ? "ok" : "already"));
1127 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTUNPOWER);
1128 cmdgood = TRUE;
1129 break;
1131 case UFS_C_PORT_CONNECTION:
1132 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_CONNECTCHANGE);
1133 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_CONNECTION;
1134 cmdgood = TRUE;
1135 break;
1137 case UFS_C_PORT_ENABLE:
1138 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_ENABLECHANGE);
1139 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_ENABLE;
1140 cmdgood = TRUE;
1141 break;
1143 case UFS_C_PORT_SUSPEND:
1144 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_RESUMEDTX);
1145 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_SUSPEND;
1146 cmdgood = TRUE;
1147 break;
1149 case UFS_C_PORT_OVER_CURRENT:
1150 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_OVERCURRENTCHG);
1151 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_OVER_CURRENT;
1152 cmdgood = TRUE;
1153 break;
1155 case UFS_C_PORT_RESET:
1156 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_RESETCHANGE);
1157 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_RESET;
1158 cmdgood = TRUE;
1159 break;
1161 if(cmdgood)
1163 return(0);
1165 break;
1168 case HCITYPE_EHCI:
1170 UWORD portreg = EHCI_PORTSC1 + (hciport<<2);
1171 ULONG oldval = READREG32_LE(hc->hc_RegBase, portreg) & ~(EHPF_OVERCURRENTCHG|EHPF_ENABLECHANGE|EHPF_CONNECTCHANGE); // these are clear-on-write!
1172 ULONG newval = oldval;
1173 switch(val)
1175 case UFS_PORT_ENABLE:
1176 KPRINTF(10, ("Disabling Port (%s)\n", newval & EHPF_PORTENABLE ? "ok" : "already"));
1177 newval &= ~EHPF_PORTENABLE;
1178 cmdgood = TRUE;
1179 // disable enumeration
1180 unit->hu_DevControllers[0] = NULL;
1181 break;
1183 case UFS_PORT_SUSPEND:
1184 newval &= ~EHPF_PORTSUSPEND;
1185 cmdgood = TRUE;
1186 break;
1188 case UFS_PORT_POWER: // ignore for UHCI, there's no power control here
1189 KPRINTF(10, ("Disabling Power (%s)\n", newval & EHPF_PORTPOWER ? "ok" : "already"));
1190 KPRINTF(10, ("Disabling Port (%s)\n", newval & EHPF_PORTENABLE ? "ok" : "already"));
1191 newval &= ~(EHPF_PORTENABLE|EHPF_PORTPOWER);
1192 cmdgood = TRUE;
1193 break;
1195 case UFS_C_PORT_CONNECTION:
1196 newval |= EHPF_CONNECTCHANGE; // clear-on-write!
1197 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_CONNECTION;
1198 cmdgood = TRUE;
1199 break;
1201 case UFS_C_PORT_ENABLE:
1202 newval |= EHPF_ENABLECHANGE; // clear-on-write!
1203 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_ENABLE;
1204 cmdgood = TRUE;
1205 break;
1207 case UFS_C_PORT_SUSPEND: // ignore for EHCI, there's no bit indicating this
1208 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_SUSPEND; // manually fake suspend change clearing
1209 cmdgood = TRUE;
1210 break;
1212 case UFS_C_PORT_OVER_CURRENT:
1213 newval |= EHPF_OVERCURRENTCHG; // clear-on-write!
1214 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_OVER_CURRENT; // manually fake over current clearing
1215 cmdgood = TRUE;
1216 break;
1218 case UFS_C_PORT_RESET: // ignore for EHCI, there's no bit indicating this
1219 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_RESET; // manually fake reset change clearing
1220 cmdgood = TRUE;
1221 break;
1223 if(cmdgood)
1225 KPRINTF(5, ("Port %ld CLEAR_FEATURE %08lx->%08lx\n", idx, oldval, newval));
1226 WRITEREG32_LE(hc->hc_RegBase, portreg, newval);
1227 if(hc->hc_PortChangeMap[hciport])
1229 unit->hu_RootPortChanges |= 1UL<<idx;
1230 } else {
1231 unit->hu_RootPortChanges &= ~(1UL<<idx);
1233 return(0);
1235 break;
1238 #ifdef AROS_USB30_CODE
1239 /* (URTF_CLASS|URTF_OTHER) USR_CLEAR_FEATURE */
1240 case HCITYPE_XHCI:
1242 cmdgood = TRUE;
1243 if(cmdgood)
1245 KPRINTF(1000, ("XHCI (URTF_CLASS|URTF_OTHER) USR_CLEAR_FEATURE\n"));
1246 return(0);
1248 break;
1250 #endif
1253 break;
1255 break;
1257 case (URTF_IN|URTF_CLASS|URTF_OTHER):
1258 switch(req)
1260 case USR_GET_STATUS:
1262 UWORD *mptr = ioreq->iouh_Data;
1263 if(len != sizeof(struct UsbPortStatus))
1265 return(UHIOERR_STALL);
1267 if((!idx) && (idx > numports))
1269 KPRINTF(20, ("Port %ld out of range\n", idx));
1270 return(UHIOERR_STALL);
1272 if(unit->hu_EhciOwned[idx - 1])
1274 hc = unit->hu_PortMap20[idx - 1];
1275 hciport = idx - 1;
1276 } else {
1277 hc = unit->hu_PortMap11[idx - 1];
1278 hciport = unit->hu_PortNum11[idx - 1];
1280 switch(hc->hc_HCIType)
1282 case HCITYPE_UHCI:
1284 UWORD portreg = hciport ? UHCI_PORT2STSCTRL : UHCI_PORT1STSCTRL;
1285 UWORD oldval = READIO16_LE(hc->hc_RegBase, portreg);
1286 *mptr = AROS_WORD2LE(UPSF_PORT_POWER);
1287 if(oldval & UHPF_PORTCONNECTED) *mptr |= AROS_WORD2LE(UPSF_PORT_CONNECTION);
1288 if(oldval & UHPF_PORTENABLE) *mptr |= AROS_WORD2LE(UPSF_PORT_ENABLE);
1289 if(oldval & UHPF_LOWSPEED) *mptr |= AROS_WORD2LE(UPSF_PORT_LOW_SPEED);
1290 if(oldval & UHPF_PORTRESET) *mptr |= AROS_WORD2LE(UPSF_PORT_RESET);
1291 if(oldval & UHPF_PORTSUSPEND) *mptr |= AROS_WORD2LE(UPSF_PORT_SUSPEND);
1293 KPRINTF(5, ("UHCI Port %ld is %s\n", idx, oldval & UHPF_LOWSPEED ? "LOWSPEED" : "FULLSPEED"));
1294 KPRINTF(5, ("UHCI Port %ld Status %08lx\n", idx, *mptr));
1296 mptr++;
1297 if(oldval & UHPF_ENABLECHANGE)
1299 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_ENABLE;
1301 if(oldval & UHPF_CONNECTCHANGE)
1303 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_CONNECTION;
1305 if(oldval & UHPF_RESUMEDTX)
1307 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_SUSPEND|UPSF_PORT_ENABLE;
1309 *mptr = AROS_WORD2LE(hc->hc_PortChangeMap[hciport]);
1310 WRITEIO16_LE(hc->hc_RegBase, portreg, oldval);
1311 KPRINTF(5, ("UHCI Port %ld Change %08lx\n", idx, *mptr));
1312 return(0);
1315 case HCITYPE_OHCI:
1317 UWORD portreg = OHCI_PORTSTATUS + (hciport<<2);
1318 ULONG oldval = READREG32_LE(hc->hc_RegBase, portreg);
1320 *mptr = 0;
1321 if(oldval & OHPF_PORTPOWER) *mptr |= AROS_WORD2LE(UPSF_PORT_POWER);
1322 if(oldval & OHPF_OVERCURRENT) *mptr |= AROS_WORD2LE(UPSF_PORT_OVER_CURRENT);
1323 if(oldval & OHPF_PORTCONNECTED) *mptr |= AROS_WORD2LE(UPSF_PORT_CONNECTION);
1324 if(oldval & OHPF_PORTENABLE) *mptr |= AROS_WORD2LE(UPSF_PORT_ENABLE);
1325 if(oldval & OHPF_LOWSPEED) *mptr |= AROS_WORD2LE(UPSF_PORT_LOW_SPEED);
1326 if(oldval & OHPF_PORTRESET) *mptr |= AROS_WORD2LE(UPSF_PORT_RESET);
1327 if(oldval & OHPF_PORTSUSPEND) *mptr |= AROS_WORD2LE(UPSF_PORT_SUSPEND);
1329 KPRINTF(5, ("OHCI Port %ld (glob. %ld) is %s\n", hciport, idx, oldval & OHPF_LOWSPEED ? "LOWSPEED" : "FULLSPEED"));
1330 KPRINTF(5, ("OHCI Port %ld Status %08lx (%08lx)\n", idx, *mptr, oldval));
1332 mptr++;
1333 if(oldval & OHPF_OVERCURRENTCHG)
1335 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_OVER_CURRENT;
1337 if(oldval & OHPF_RESETCHANGE)
1339 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_RESET;
1341 if(oldval & OHPF_ENABLECHANGE)
1343 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_ENABLE;
1345 if(oldval & OHPF_CONNECTCHANGE)
1347 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_CONNECTION;
1349 if(oldval & OHPF_RESUMEDTX)
1351 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_SUSPEND;
1353 *mptr = AROS_WORD2LE(hc->hc_PortChangeMap[hciport]);
1354 KPRINTF(5, ("OHCI Port %ld Change %08lx\n", idx, *mptr));
1355 return(0);
1358 case HCITYPE_EHCI:
1360 UWORD portreg = EHCI_PORTSC1 + (hciport<<2);
1361 ULONG oldval = READREG32_LE(hc->hc_RegBase, portreg);
1363 *mptr = 0;
1364 if(oldval & EHPF_PORTCONNECTED) *mptr |= AROS_WORD2LE(UPSF_PORT_CONNECTION);
1365 if(oldval & EHPF_PORTENABLE) *mptr |= AROS_WORD2LE(UPSF_PORT_ENABLE|UPSF_PORT_HIGH_SPEED);
1366 if((oldval & (EHPF_LINESTATUS_DM|EHPF_PORTCONNECTED|EHPF_PORTENABLE)) ==
1367 (EHPF_LINESTATUS_DM|EHPF_PORTCONNECTED))
1369 KPRINTF(10, ("EHCI Port %ld is LOWSPEED\n", idx));
1370 // we need to detect low speed devices prior to reset
1371 *mptr |= AROS_WORD2LE(UPSF_PORT_LOW_SPEED);
1374 if(oldval & EHPF_PORTRESET) *mptr |= AROS_WORD2LE(UPSF_PORT_RESET);
1375 if(oldval & EHPF_PORTSUSPEND) *mptr |= AROS_WORD2LE(UPSF_PORT_SUSPEND);
1376 if(oldval & EHPF_PORTPOWER) *mptr |= AROS_WORD2LE(UPSF_PORT_POWER);
1377 if(oldval & EHPM_PORTINDICATOR) *mptr |= AROS_WORD2LE(UPSF_PORT_INDICATOR);
1379 KPRINTF(5, ("EHCI Port %ld Status %08lx\n", idx, *mptr));
1381 mptr++;
1382 if(oldval & EHPF_ENABLECHANGE)
1384 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_ENABLE;
1386 if(oldval & EHPF_CONNECTCHANGE)
1388 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_CONNECTION;
1390 if(oldval & EHPF_RESUMEDTX)
1392 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_SUSPEND|UPSF_PORT_ENABLE;
1394 if(oldval & EHPF_OVERCURRENTCHG)
1396 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_OVER_CURRENT;
1398 *mptr = AROS_WORD2LE(hc->hc_PortChangeMap[hciport]);
1399 WRITEREG32_LE(hc->hc_RegBase, portreg, oldval);
1400 KPRINTF(5, ("EHCI Port %ld Change %08lx\n", idx, *mptr));
1401 return(0);
1404 #ifdef AROS_USB30_CODE
1405 /* (URTF_IN|URTF_CLASS|URTF_OTHER) USR_GET_STATUS */
1406 case HCITYPE_XHCI:
1408 KPRINTF(1000, ("XHCI (URTF_IN|URTF_CLASS|URTF_OTHER) USR_GET_STATUS\n"));
1409 return(0);
1411 #endif
1414 return(0);
1418 break;
1420 case (URTF_IN|URTF_CLASS|URTF_DEVICE):
1421 switch(req)
1423 case USR_GET_STATUS:
1425 UWORD *mptr = ioreq->iouh_Data;
1426 if(len < sizeof(struct UsbHubStatus))
1428 return(UHIOERR_STALL);
1430 *mptr++ = 0;
1431 *mptr++ = 0;
1432 ioreq->iouh_Actual = 4;
1433 return(0);
1436 case USR_GET_DESCRIPTOR:
1437 switch(val>>8)
1439 //FIXME: Add USB3.0 hub descriptor support
1440 #ifdef AROS_USB30_CODE
1441 case UDT_SSHUB:
1443 ULONG hubdesclen = 12;
1445 struct UsbSSHubDesc *uhd = (struct UsbSSHubDesc *) ioreq->iouh_Data;
1446 KPRINTF(1, ("RH: Get(SS)HubDescriptor (%ld)\n", len));
1448 ioreq->iouh_Actual = (len > hubdesclen) ? hubdesclen : len;
1449 CopyMem((APTR) &RHSSHubDesc, ioreq->iouh_Data, ioreq->iouh_Actual);
1451 if(ioreq->iouh_Length)
1453 uhd->bLength = hubdesclen;
1456 uhd->bNbrPorts = unit->hu_RootHubPorts;
1458 return(0);
1460 #endif
1461 case UDT_HUB:
1463 ULONG hubdesclen = 9;
1464 ULONG powergood = 1;
1466 struct UsbHubDesc *uhd = (struct UsbHubDesc *) ioreq->iouh_Data;
1467 KPRINTF(1, ("RH: GetHubDescriptor (%ld)\n", len));
1469 if(unit->hu_RootHubPorts > 7) // needs two bytes for port masks
1471 hubdesclen += 2;
1474 ioreq->iouh_Actual = (len > hubdesclen) ? hubdesclen : len;
1475 CopyMem((APTR) &RHHubDesc, ioreq->iouh_Data, ioreq->iouh_Actual);
1477 if(ioreq->iouh_Length)
1479 uhd->bLength = hubdesclen;
1482 if(ioreq->iouh_Length >= 6)
1484 hc = (struct PCIController *) unit->hu_Controllers.lh_Head;
1485 while(hc->hc_Node.ln_Succ)
1487 if(hc->hc_HCIType == HCITYPE_OHCI)
1489 ULONG localpwgood = (READREG32_LE(hc->hc_RegBase, OHCI_HUBDESCA) & OHAM_POWERGOOD) >> OHAS_POWERGOOD;
1490 if(localpwgood > powergood)
1492 powergood = localpwgood;
1493 KPRINTF(10, ("Increasing power good time to %ld\n", powergood));
1496 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
1499 uhd->bPwrOn2PwrGood = powergood;
1501 if(ioreq->iouh_Length >= hubdesclen)
1503 uhd->bNbrPorts = unit->hu_RootHubPorts;
1504 if(hubdesclen == 9)
1506 uhd->DeviceRemovable = 0;
1507 uhd->PortPwrCtrlMask = (1<<(unit->hu_RootHubPorts+2))-2;
1508 } else {
1509 // each field is now 16 bits wide
1510 uhd->DeviceRemovable = 0;
1511 uhd->PortPwrCtrlMask = 0;
1512 ((UBYTE *) ioreq->iouh_Data)[9] = (1<<(unit->hu_RootHubPorts+2))-2;
1513 ((UBYTE *) ioreq->iouh_Data)[10] = ((1<<(unit->hu_RootHubPorts+2))-2)>>8;
1516 return(0);
1519 default:
1520 KPRINTF(20, ("RH: Unsupported Descriptor %04lx\n", idx));
1522 break;
1526 KPRINTF(20, ("RH: Unsupported command %02lx %02lx %04lx %04lx %04lx!\n", rt, req, idx, val, len));
1527 return(UHIOERR_STALL);
1529 /* \\\ */
1531 /* /// "cmdIntXFerRootHub()" */
1532 WORD cmdIntXFerRootHub(struct IOUsbHWReq *ioreq,
1533 struct PCIUnit *unit,
1534 struct PCIDevice *base)
1536 if((ioreq->iouh_Endpoint != 1) || (!ioreq->iouh_Length))
1538 return(UHIOERR_STALL);
1541 if(unit->hu_RootPortChanges)
1543 KPRINTF(1, ("Immediate Portchange map %04lx\n", unit->hu_RootPortChanges));
1544 if((unit->hu_RootHubPorts < 8) || (ioreq->iouh_Length == 1))
1546 *((UBYTE *) ioreq->iouh_Data) = unit->hu_RootPortChanges;
1547 ioreq->iouh_Actual = 1;
1548 } else {
1549 ((UBYTE *) ioreq->iouh_Data)[0] = unit->hu_RootPortChanges;
1550 ((UBYTE *) ioreq->iouh_Data)[1] = unit->hu_RootPortChanges>>8;
1551 ioreq->iouh_Actual = 2;
1553 unit->hu_RootPortChanges = 0;
1554 return(0);
1556 ioreq->iouh_Req.io_Flags &= ~IOF_QUICK;
1557 Disable();
1558 AddTail(&unit->hu_RHIOQueue, (struct Node *) ioreq);
1559 Enable();
1560 return(RC_DONTREPLY);
1562 /* \\\ */
1564 /* /// "cmdControlXFer()" */
1566 *======================================================================
1567 * cmdControlXFer(ioreq, unit, base)
1568 *======================================================================
1570 * This is the device UHCMD_CONTROLXFER routine.
1572 * First it check if the usb is in proper state and if user passed arguments
1573 * are valid. If everything is ok, the request is linked to queue of
1574 * pending transfer requests.
1578 WORD cmdControlXFer(struct IOUsbHWReq *ioreq,
1579 struct PCIUnit *unit,
1580 struct PCIDevice *base)
1582 struct PCIController *hc;
1584 KPRINTF(10, ("UHCMD_CONTROLXFER ioreq: 0x%p\n", ioreq));
1585 uhwGetUsbState(ioreq, unit, base);
1586 if(!(ioreq->iouh_State & UHSF_OPERATIONAL))
1588 return(UHIOERR_USBOFFLINE);
1590 /* Root hub emulation */
1591 if(ioreq->iouh_DevAddr == unit->hu_RootHubAddr)
1593 return(cmdControlXFerRootHub(ioreq, unit, base));
1596 hc = unit->hu_DevControllers[ioreq->iouh_DevAddr];
1597 if(!hc)
1599 KPRINTF(20, ("No Host controller assigned to device address %ld\n", ioreq->iouh_DevAddr));
1600 return(UHIOERR_HOSTERROR);
1603 ioreq->iouh_Req.io_Flags &= ~IOF_QUICK;
1604 ioreq->iouh_Actual = 0;
1606 Disable();
1607 AddTail(&hc->hc_CtrlXFerQueue, (struct Node *) ioreq);
1608 Enable();
1609 SureCause(base, &hc->hc_CompleteInt);
1611 KPRINTF(10, ("UHCMD_CONTROLXFER processed ioreq: 0x%p\n", ioreq));
1612 return(RC_DONTREPLY);
1614 /* \\\ */
1616 /* /// "cmdBulkXFer()" */
1618 *======================================================================
1619 * cmdBulkXFer(ioreq, unit, base)
1620 *======================================================================
1622 * This is the device UHCMD_BULKXFER routine.
1624 * First it check if the usb is in proper state and if user passed arguments
1625 * are valid. If everything is ok, the request is linked to queue of
1626 * pending transfer requests.
1630 WORD cmdBulkXFer(struct IOUsbHWReq *ioreq,
1631 struct PCIUnit *unit,
1632 struct PCIDevice *base)
1634 struct PCIController *hc;
1636 KPRINTF(10, ("UHCMD_BULKXFER ioreq: 0x%p\n", ioreq));
1637 uhwGetUsbState(ioreq, unit, base);
1638 if(!(ioreq->iouh_State & UHSF_OPERATIONAL))
1640 return(UHIOERR_USBOFFLINE);
1643 if(ioreq->iouh_Flags & UHFF_LOWSPEED)
1645 return(UHIOERR_BADPARAMS);
1648 hc = unit->hu_DevControllers[ioreq->iouh_DevAddr];
1649 if(!hc)
1651 return(UHIOERR_HOSTERROR);
1654 ioreq->iouh_Req.io_Flags &= ~IOF_QUICK;
1655 ioreq->iouh_Actual = 0;
1657 Disable();
1658 AddTail(&hc->hc_BulkXFerQueue, (struct Node *) ioreq);
1659 Enable();
1660 SureCause(base, &hc->hc_CompleteInt);
1662 KPRINTF(10, ("UHCMD_BULKXFER processed ioreq: 0x%p\n", ioreq));
1663 return(RC_DONTREPLY);
1665 /* \\\ */
1667 /* /// "cmdIsoXFer()" */
1669 *======================================================================
1670 * cmdIsoXFer(ioreq, unit, base)
1671 *======================================================================
1673 * This is the device UHCMD_ISOXFER routine.
1675 * First it check if the usb is in proper state and if user passed arguments
1676 * are valid. If everything is ok, the request is linked to queue of
1677 * pending transfer requests.
1681 WORD cmdIsoXFer(struct IOUsbHWReq *ioreq,
1682 struct PCIUnit *unit,
1683 struct PCIDevice *base)
1685 struct PCIController *hc;
1687 KPRINTF(10, ("UHCMD_ISOXFER ioreq: 0x%p\n", ioreq));
1688 uhwGetUsbState(ioreq, unit, base);
1689 if(!(ioreq->iouh_State & UHSF_OPERATIONAL))
1691 return(UHIOERR_USBOFFLINE);
1694 if(ioreq->iouh_Flags & UHFF_LOWSPEED)
1696 return(UHIOERR_BADPARAMS);
1699 hc = unit->hu_DevControllers[ioreq->iouh_DevAddr];
1700 if(!hc)
1702 return(UHIOERR_HOSTERROR);
1705 ioreq->iouh_Req.io_Flags &= ~IOF_QUICK;
1706 ioreq->iouh_Actual = 0;
1708 Disable();
1709 AddTail(&hc->hc_IsoXFerQueue, (struct Node *) ioreq);
1710 Enable();
1711 SureCause(base, &hc->hc_CompleteInt);
1713 KPRINTF(10, ("UHCMD_ISOXFER processed ioreq: 0x%p\n", ioreq));
1714 return(RC_DONTREPLY);
1716 /* \\\ */
1718 /* /// "cmdIntXFer()" */
1720 *======================================================================
1721 * cmdIntXFer(ioreq, unit, base)
1722 *======================================================================
1724 * This is the device UHCMD_INTXFER routine.
1726 * First it check if the usb is in proper state and if user passed arguments
1727 * are valid. If everything is ok, the request is linked to queue of
1728 * pending transfer requests.
1732 WORD cmdIntXFer(struct IOUsbHWReq *ioreq,
1733 struct PCIUnit *unit,
1734 struct PCIDevice *base)
1736 struct PCIController *hc;
1738 KPRINTF(10, ("UHCMD_INTXFER ioreq: 0x%p\n", ioreq));
1739 //uhwDelayMS(1000, unit); /* Wait 200 ms */
1740 uhwGetUsbState(ioreq, unit, base);
1741 if(!(ioreq->iouh_State & UHSF_OPERATIONAL))
1743 return(UHIOERR_USBOFFLINE);
1746 /* Root Hub Emulation */
1747 if(ioreq->iouh_DevAddr == unit->hu_RootHubAddr)
1749 return(cmdIntXFerRootHub(ioreq, unit, base));
1752 hc = unit->hu_DevControllers[ioreq->iouh_DevAddr];
1753 if(!hc)
1755 return(UHIOERR_HOSTERROR);
1758 ioreq->iouh_Req.io_Flags &= ~IOF_QUICK;
1759 ioreq->iouh_Actual = 0;
1761 Disable();
1762 AddTail(&hc->hc_IntXFerQueue, (struct Node *) ioreq);
1763 Enable();
1764 SureCause(base, &hc->hc_CompleteInt);
1766 KPRINTF(10, ("UHCMD_INTXFER processed ioreq: 0x%p\n", ioreq));
1767 return(RC_DONTREPLY);
1769 /* \\\ */
1771 /* /// "cmdFlush()" */
1773 *======================================================================
1774 * cmdFlush(ioreq, base)
1775 *======================================================================
1777 * This is the device CMD_FLUSH routine.
1779 * This routine abort all pending transfer requests.
1783 WORD cmdFlush(struct IOUsbHWReq *ioreq,
1784 struct PCIUnit *unit,
1785 struct PCIDevice *base)
1787 struct IOUsbHWReq *cmpioreq;
1788 struct PCIController *hc;
1789 UWORD devadrep;
1791 KPRINTF(10, ("CMD_FLUSH ioreq: 0x%p\n", ioreq));
1793 Disable();
1794 cmpioreq = (struct IOUsbHWReq *) unit->hu_RHIOQueue.lh_Head;
1795 while(((struct Node *) cmpioreq)->ln_Succ)
1797 Remove(&cmpioreq->iouh_Req.io_Message.mn_Node);
1798 cmpioreq->iouh_Req.io_Error = IOERR_ABORTED;
1799 ReplyMsg(&cmpioreq->iouh_Req.io_Message);
1800 cmpioreq = (struct IOUsbHWReq *) unit->hu_RHIOQueue.lh_Head;
1802 hc = (struct PCIController *) unit->hu_Controllers.lh_Head;
1803 while(hc->hc_Node.ln_Succ)
1805 cmpioreq = (struct IOUsbHWReq *) hc->hc_CtrlXFerQueue.lh_Head;
1806 while(((struct Node *) cmpioreq)->ln_Succ)
1808 Remove(&cmpioreq->iouh_Req.io_Message.mn_Node);
1809 cmpioreq->iouh_Req.io_Error = IOERR_ABORTED;
1810 ReplyMsg(&cmpioreq->iouh_Req.io_Message);
1811 cmpioreq = (struct IOUsbHWReq *) hc->hc_CtrlXFerQueue.lh_Head;
1813 cmpioreq = (struct IOUsbHWReq *) hc->hc_IntXFerQueue.lh_Head;
1814 while(((struct Node *) cmpioreq)->ln_Succ)
1816 Remove(&cmpioreq->iouh_Req.io_Message.mn_Node);
1817 cmpioreq->iouh_Req.io_Error = IOERR_ABORTED;
1818 ReplyMsg(&cmpioreq->iouh_Req.io_Message);
1819 cmpioreq = (struct IOUsbHWReq *) hc->hc_IntXFerQueue.lh_Head;
1821 cmpioreq = (struct IOUsbHWReq *) hc->hc_IsoXFerQueue.lh_Head;
1822 while(((struct Node *) cmpioreq)->ln_Succ)
1824 Remove(&cmpioreq->iouh_Req.io_Message.mn_Node);
1825 cmpioreq->iouh_Req.io_Error = IOERR_ABORTED;
1826 ReplyMsg(&cmpioreq->iouh_Req.io_Message);
1827 cmpioreq = (struct IOUsbHWReq *) hc->hc_IsoXFerQueue.lh_Head;
1829 cmpioreq = (struct IOUsbHWReq *) hc->hc_BulkXFerQueue.lh_Head;
1830 while(((struct Node *) cmpioreq)->ln_Succ)
1832 Remove(&cmpioreq->iouh_Req.io_Message.mn_Node);
1833 cmpioreq->iouh_Req.io_Error = IOERR_ABORTED;
1834 ReplyMsg(&cmpioreq->iouh_Req.io_Message);
1835 cmpioreq = (struct IOUsbHWReq *) hc->hc_BulkXFerQueue.lh_Head;
1837 switch(hc->hc_HCIType)
1839 case HCITYPE_UHCI:
1840 cmpioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head;
1841 while(((struct Node *) cmpioreq)->ln_Succ)
1843 Remove(&cmpioreq->iouh_Req.io_Message.mn_Node);
1844 devadrep = (cmpioreq->iouh_DevAddr<<5) + cmpioreq->iouh_Endpoint + ((cmpioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0);
1845 unit->hu_DevBusyReq[devadrep] = NULL;
1846 uhciFreeQContext(hc, (struct UhciQH *) cmpioreq->iouh_DriverPrivate1);
1847 cmpioreq->iouh_Req.io_Error = IOERR_ABORTED;
1848 ReplyMsg(&cmpioreq->iouh_Req.io_Message);
1849 cmpioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head;
1851 break;
1853 case HCITYPE_EHCI:
1854 cmpioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head;
1855 while(((struct Node *) cmpioreq)->ln_Succ)
1857 ehciFreeAsyncContext(hc, cmpioreq);
1858 cmpioreq->iouh_Req.io_Error = IOERR_ABORTED;
1859 ReplyMsg(&cmpioreq->iouh_Req.io_Message);
1860 cmpioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head;
1862 cmpioreq = (struct IOUsbHWReq *) hc->hc_PeriodicTDQueue.lh_Head;
1863 while(((struct Node *) cmpioreq)->ln_Succ)
1865 ehciFreePeriodicContext(hc, cmpioreq);
1866 cmpioreq->iouh_Req.io_Error = IOERR_ABORTED;
1867 ReplyMsg(&cmpioreq->iouh_Req.io_Message);
1868 cmpioreq = (struct IOUsbHWReq *) hc->hc_PeriodicTDQueue.lh_Head;
1870 break;
1871 #ifdef AROS_USB30_CODE
1872 case HCITYPE_XHCI:
1873 KPRINTF(1000, ("XHCI cmdFlush\n"));
1874 break;
1875 #endif
1877 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
1879 Enable();
1880 /* Return success
1882 return RC_OK;
1884 /* \\\ */
1886 /* /// "NSD stuff" */
1888 static
1889 const UWORD NSDSupported[] =
1891 CMD_FLUSH, CMD_RESET,
1892 UHCMD_QUERYDEVICE, UHCMD_USBRESET,
1893 UHCMD_USBRESUME, UHCMD_USBSUSPEND,
1894 UHCMD_USBOPER, UHCMD_CONTROLXFER ,
1895 UHCMD_ISOXFER, UHCMD_INTXFER,
1896 UHCMD_BULKXFER,
1897 NSCMD_DEVICEQUERY, 0
1900 WORD cmdNSDeviceQuery(struct IOStdReq *ioreq,
1901 struct PCIUnit *unit,
1902 struct PCIDevice *base)
1904 struct my_NSDeviceQueryResult *query;
1906 query = (struct my_NSDeviceQueryResult *) ioreq->io_Data;
1908 KPRINTF(10, ("NSCMD_DEVICEQUERY ioreq: 0x%p query: 0x%p\n", ioreq, query));
1910 /* NULL ptr?
1911 Enough data?
1912 Valid request?
1914 if((!query) ||
1915 (ioreq->io_Length < sizeof(struct my_NSDeviceQueryResult)) ||
1916 (query->DevQueryFormat != 0) ||
1917 (query->SizeAvailable != 0))
1919 /* Return error. This is special handling, since iorequest is only
1920 guaranteed to be sizeof(struct IOStdReq). If we'd let our
1921 devBeginIO dispatcher return the error, it would trash some
1922 memory past end of the iorequest (ios2_WireError field).
1924 ioreq->io_Error = IOERR_NOCMD;
1925 TermIO((struct IOUsbHWReq *) ioreq, base);
1927 /* Don't reply, we already did.
1929 return RC_DONTREPLY;
1932 ioreq->io_Actual = query->SizeAvailable
1933 = sizeof(struct my_NSDeviceQueryResult);
1934 query->DeviceType = NSDEVTYPE_USBHARDWARE;
1935 query->DeviceSubType = 0;
1936 query->SupportedCommands = NSDSupported;
1938 /* Return success (note that this will NOT poke ios2_WireError).
1940 return RC_OK;
1942 /* \\\ */
1944 /* /// "TermIO()" */
1946 *===========================================================
1947 * TermIO(ioreq, base)
1948 *===========================================================
1950 * Return completed ioreq to sender.
1954 void TermIO(struct IOUsbHWReq *ioreq,
1955 struct PCIDevice *base)
1957 ioreq->iouh_Req.io_Message.mn_Node.ln_Type = NT_FREEMSG;
1959 /* If not quick I/O, reply the message
1961 if(!(ioreq->iouh_Req.io_Flags & IOF_QUICK))
1963 ReplyMsg(&ioreq->iouh_Req.io_Message);
1966 /* \\\ */
1968 /* /// "cmdAbortIO()" */
1969 BOOL cmdAbortIO(struct IOUsbHWReq *ioreq, struct PCIDevice *base)
1971 struct PCIUnit *unit = (struct PCIUnit *) ioreq->iouh_Req.io_Unit;
1972 struct IOUsbHWReq *cmpioreq;
1973 struct PCIController *hc;
1974 UWORD devadrep;
1975 BOOL foundit = FALSE;
1977 KPRINTF(10, ("cmdAbort(%p)\n", ioreq));
1979 Disable();
1980 cmpioreq = (struct IOUsbHWReq *) unit->hu_RHIOQueue.lh_Head;
1981 while(((struct Node *) cmpioreq)->ln_Succ)
1983 if(ioreq == cmpioreq)
1985 Remove(&ioreq->iouh_Req.io_Message.mn_Node);
1986 Enable();
1987 return TRUE;
1989 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
1992 hc = (struct PCIController *) unit->hu_Controllers.lh_Head;
1993 while(hc->hc_Node.ln_Succ)
1995 cmpioreq = (struct IOUsbHWReq *) hc->hc_CtrlXFerQueue.lh_Head;
1996 while(((struct Node *) cmpioreq)->ln_Succ)
1998 if(ioreq == cmpioreq)
2000 foundit = TRUE;
2001 break;
2003 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
2005 if(!foundit)
2007 cmpioreq = (struct IOUsbHWReq *) hc->hc_IntXFerQueue.lh_Head;
2008 while(((struct Node *) cmpioreq)->ln_Succ)
2010 if(ioreq == cmpioreq)
2012 foundit = TRUE;
2013 break;
2015 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
2018 if(!foundit)
2020 cmpioreq = (struct IOUsbHWReq *) hc->hc_IsoXFerQueue.lh_Head;
2021 while(((struct Node *) cmpioreq)->ln_Succ)
2023 if(ioreq == cmpioreq)
2025 foundit = TRUE;
2026 break;
2028 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
2031 if(!foundit)
2033 cmpioreq = (struct IOUsbHWReq *) hc->hc_BulkXFerQueue.lh_Head;
2034 while(((struct Node *) cmpioreq)->ln_Succ)
2036 if(ioreq == cmpioreq)
2038 foundit = TRUE;
2039 break;
2041 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
2044 if(!foundit)
2046 // IOReq is probably pending in some transfer structure
2047 devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint + ((ioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0);
2048 switch(hc->hc_HCIType)
2050 case HCITYPE_UHCI:
2051 cmpioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head;
2052 while(((struct Node *) cmpioreq)->ln_Succ)
2054 if(ioreq == cmpioreq)
2056 foundit = TRUE;
2057 unit->hu_DevBusyReq[devadrep] = NULL;
2058 uhciFreeQContext(hc, (struct UhciQH *) ioreq->iouh_DriverPrivate1);
2059 break;
2061 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
2063 break;
2065 case HCITYPE_OHCI:
2066 cmpioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head;
2067 while(((struct Node *) cmpioreq)->ln_Succ)
2069 if(ioreq == cmpioreq)
2072 * Request's ED is in use by the HC, as well as its TDs and
2073 * data buffers.
2074 * Schedule abort on the HC driver and reply the request
2075 * only when done. However return success.
2077 ioreq->iouh_Req.io_Error = IOERR_ABORTED;
2078 ohciAbortRequest(hc, ioreq);
2079 Enable();
2080 return TRUE;
2082 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
2084 break;
2086 case HCITYPE_EHCI:
2087 cmpioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head;
2088 while(((struct Node *) cmpioreq)->ln_Succ)
2090 if(ioreq == cmpioreq)
2093 * CHECKME: Perhaps immediate freeing can cause issues similar to OHCI.
2094 * Should synchronized abort routine be implemented here too ?
2096 ehciFreeAsyncContext(hc, ioreq);
2097 Enable();
2098 ioreq->iouh_Req.io_Error = IOERR_ABORTED;
2099 TermIO(ioreq, base);
2100 return TRUE;
2102 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
2104 cmpioreq = (struct IOUsbHWReq *) hc->hc_PeriodicTDQueue.lh_Head;
2105 while(((struct Node *) cmpioreq)->ln_Succ)
2107 if(ioreq == cmpioreq)
2109 ehciFreePeriodicContext(hc, ioreq);
2110 Enable();
2111 ioreq->iouh_Req.io_Error = IOERR_ABORTED;
2112 TermIO(ioreq, base);
2113 return TRUE;
2115 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
2117 break;
2119 #ifdef AROS_USB30_CODE
2120 case HCITYPE_XHCI:
2121 KPRINTF(1000, ("XHCI cmdAbortIO\n"));
2122 break;
2123 #endif
2127 if(foundit)
2129 Remove(&ioreq->iouh_Req.io_Message.mn_Node);
2130 break;
2132 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
2134 Enable();
2136 if (foundit)
2138 ioreq->iouh_Req.io_Error = IOERR_ABORTED;
2139 TermIO(ioreq, base);
2141 else
2143 KPRINTF(20, ("WARNING, could not abort unknown IOReq %p\n", ioreq));
2145 return(foundit);
2147 /* \\\ */
2149 /* /// "uhwCheckRootHubChanges()" */
2150 void uhwCheckRootHubChanges(struct PCIUnit *unit)
2152 struct IOUsbHWReq *ioreq;
2154 if(unit->hu_RootPortChanges && unit->hu_RHIOQueue.lh_Head->ln_Succ)
2156 KPRINTF(1, ("Portchange map %04lx\n", unit->hu_RootPortChanges));
2157 Disable();
2158 ioreq = (struct IOUsbHWReq *) unit->hu_RHIOQueue.lh_Head;
2159 while(((struct Node *) ioreq)->ln_Succ)
2161 Remove(&ioreq->iouh_Req.io_Message.mn_Node);
2162 if((unit->hu_RootHubPorts < 8) || (ioreq->iouh_Length == 1))
2164 *((UBYTE *) ioreq->iouh_Data) = unit->hu_RootPortChanges;
2165 ioreq->iouh_Actual = 1;
2166 } else {
2167 ((UBYTE *) ioreq->iouh_Data)[0] = unit->hu_RootPortChanges;
2168 ((UBYTE *) ioreq->iouh_Data)[1] = unit->hu_RootPortChanges>>8;
2169 ioreq->iouh_Actual = 2;
2171 ReplyMsg(&ioreq->iouh_Req.io_Message);
2172 ioreq = (struct IOUsbHWReq *) unit->hu_RHIOQueue.lh_Head;
2174 unit->hu_RootPortChanges = 0;
2175 Enable();
2178 /* \\\ */
2180 /* /// "uhwCheckSpecialCtrlTransfers()" */
2181 void uhwCheckSpecialCtrlTransfers(struct PCIController *hc, struct IOUsbHWReq *ioreq)
2183 struct PCIUnit *unit = hc->hc_Unit;
2185 /* Clear Feature(Endpoint halt) */
2186 if((ioreq->iouh_SetupData.bmRequestType == (URTF_STANDARD|URTF_ENDPOINT)) &&
2187 (ioreq->iouh_SetupData.bRequest == USR_CLEAR_FEATURE) &&
2188 (ioreq->iouh_SetupData.wValue == AROS_WORD2LE(UFS_ENDPOINT_HALT)))
2190 KPRINTF(10, ("Resetting toggle bit for endpoint %ld\n", AROS_WORD2LE(ioreq->iouh_SetupData.wIndex) & 0xf));
2191 unit->hu_DevDataToggle[(ioreq->iouh_DevAddr<<5)|(AROS_WORD2LE(ioreq->iouh_SetupData.wIndex) & 0xf)|((AROS_WORD2LE(ioreq->iouh_SetupData.wIndex) & 0x80)>>3)] = 0;
2193 else if((ioreq->iouh_SetupData.bmRequestType == (URTF_STANDARD|URTF_DEVICE)) &&
2194 (ioreq->iouh_SetupData.bRequest == USR_SET_ADDRESS))
2196 /* Set Address -> clear all endpoints */
2197 ULONG epnum;
2198 ULONG adr = AROS_WORD2BE(ioreq->iouh_SetupData.wValue)>>3;
2199 KPRINTF(10, ("Resetting toggle bits for device address %ld\n", adr>>5));
2200 for(epnum = 0; epnum < 31; epnum++)
2202 unit->hu_DevDataToggle[adr+epnum] = 0;
2204 // transfer host controller ownership
2205 unit->hu_DevControllers[ioreq->iouh_DevAddr] = NULL;
2206 unit->hu_DevControllers[adr>>5] = hc;
2208 else if((ioreq->iouh_SetupData.bmRequestType == (URTF_CLASS|URTF_OTHER)) &&
2209 (ioreq->iouh_SetupData.bRequest == USR_SET_FEATURE) &&
2210 (ioreq->iouh_SetupData.wValue == AROS_WORD2LE(UFS_PORT_RESET)))
2212 // a hub will be enumerating a device on this host controller soon!
2213 KPRINTF(10, ("Hub RESET caught, assigning Dev0 to %p!\n", hc));
2214 unit->hu_DevControllers[0] = hc;
2217 /* \\\ */
2219 /* /// "uhwNakTimeoutInt()" */
2220 AROS_INTH1(uhwNakTimeoutInt, struct PCIUnit *, unit)
2222 AROS_INTFUNC_INIT
2224 struct PCIDevice *base = unit->hu_Device;
2225 struct PCIController *hc;
2226 struct IOUsbHWReq *ioreq;
2227 struct UhciQH *uqh;
2228 struct UhciTD *utd;
2229 struct EhciQH *eqh;
2230 UWORD devadrep;
2231 UWORD cnt;
2232 ULONG linkelem;
2233 ULONG ctrlstatus;
2234 BOOL causeint;
2236 KPRINTF(1, ("Enter NakTimeoutInt(0x%p)\n", unit));
2238 // check for port status change for UHCI and frame rollovers and NAK Timeouts
2239 hc = (struct PCIController *) unit->hu_Controllers.lh_Head;
2240 while(hc->hc_Node.ln_Succ)
2242 if (!(hc->hc_Flags & HCF_ONLINE))
2244 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
2245 continue;
2247 causeint = FALSE;
2248 switch(hc->hc_HCIType)
2250 case HCITYPE_UHCI:
2252 ULONG framecnt;
2253 uhciUpdateFrameCounter(hc);
2254 framecnt = hc->hc_FrameCounter;
2256 // NakTimeout
2257 ioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head;
2258 while(((struct Node *) ioreq)->ln_Succ)
2260 if(ioreq->iouh_Flags & UHFF_NAKTIMEOUT)
2262 uqh = (struct UhciQH *) ioreq->iouh_DriverPrivate1;
2263 if(uqh)
2265 KPRINTF(1, ("Examining IOReq=%p with UQH=%p\n", ioreq, uqh));
2266 devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint + ((ioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0);
2267 linkelem = READMEM32_LE(&uqh->uqh_Element);
2268 if(linkelem & UHCI_TERMINATE)
2270 KPRINTF(1, ("UQH terminated %08lx\n", linkelem));
2271 if(framecnt > unit->hu_NakTimeoutFrame[devadrep])
2273 // give the thing the chance to exit gracefully
2274 KPRINTF(20, ("Terminated? NAK timeout %ld > %ld, IOReq=%p\n", framecnt, unit->hu_NakTimeoutFrame[devadrep], ioreq));
2275 causeint = TRUE;
2277 } else {
2278 utd = (struct UhciTD *) (((IPTR)linkelem & UHCI_PTRMASK) - hc->hc_PCIVirtualAdjust - 16); // struct UhciTD starts 16 before physical TD
2279 ctrlstatus = READMEM32_LE(&utd->utd_CtrlStatus);
2280 if(ctrlstatus & UTCF_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 &= ~UTCF_ACTIVE;
2287 WRITEMEM32_LE(&utd->utd_CtrlStatus, ctrlstatus);
2288 causeint = TRUE;
2290 } else {
2291 if(framecnt > unit->hu_NakTimeoutFrame[devadrep])
2293 // give the thing the chance to exit gracefully
2294 KPRINTF(20, ("Terminated? NAK timeout %ld > %ld, IOReq=%p\n", framecnt, unit->hu_NakTimeoutFrame[devadrep], ioreq));
2295 causeint = TRUE;
2301 ioreq = (struct IOUsbHWReq *) ((struct Node *) ioreq)->ln_Succ;
2304 uhciCheckPortStatusChange(hc);
2305 break;
2308 case HCITYPE_OHCI:
2310 ULONG framecnt;
2311 ohciUpdateFrameCounter(hc);
2312 framecnt = hc->hc_FrameCounter;
2313 // NakTimeout
2314 ioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head;
2315 while(((struct Node *) ioreq)->ln_Succ)
2317 // Remember the successor because ohciAbortRequest() will move the request to another list
2318 struct IOUsbHWReq *succ = (struct IOUsbHWReq *)ioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
2320 if(ioreq->iouh_Flags & UHFF_NAKTIMEOUT)
2322 KPRINTF(1, ("Examining IOReq=%p with OED=%p\n", ioreq, ioreq->iouh_DriverPrivate1));
2323 if (ioreq->iouh_DriverPrivate1)
2325 KPRINTF(1, ("CTRL=%04lx, CMD=%01lx, F=%ld, hccaDH=%08lx, hcDH=%08lx, CH=%08lx, CCH=%08lx, IntEn=%08lx\n",
2326 READREG32_LE(hc->hc_RegBase, OHCI_CONTROL),
2327 READREG32_LE(hc->hc_RegBase, OHCI_CMDSTATUS),
2328 READREG32_LE(hc->hc_RegBase, OHCI_FRAMECOUNT),
2329 READMEM32_LE(&hc->hc_OhciHCCA->oha_DoneHead),
2330 READREG32_LE(hc->hc_RegBase, OHCI_DONEHEAD),
2331 READREG32_LE(hc->hc_RegBase, OHCI_CTRL_HEAD_ED),
2332 READREG32_LE(hc->hc_RegBase, OHCI_CTRL_ED),
2333 READREG32_LE(hc->hc_RegBase, OHCI_INTEN)));
2335 devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint + ((ioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0);
2336 if(framecnt > unit->hu_NakTimeoutFrame[devadrep])
2338 // give the thing the chance to exit gracefully
2339 KPRINTF(200, ("HC 0x%p NAK timeout %ld > %ld, IOReq=%p\n", hc, framecnt, unit->hu_NakTimeoutFrame[devadrep], ioreq));
2340 ioreq->iouh_Req.io_Error = UHIOERR_NAKTIMEOUT;
2341 ohciAbortRequest(hc, ioreq);
2345 ioreq = succ;
2347 break;
2350 case HCITYPE_EHCI:
2352 ULONG framecnt;
2353 ehciUpdateFrameCounter(hc);
2354 framecnt = hc->hc_FrameCounter;
2355 // NakTimeout
2356 for(cnt = 0; cnt < 1; cnt++)
2358 ioreq = (struct IOUsbHWReq *) (cnt ? hc->hc_PeriodicTDQueue.lh_Head : hc->hc_TDQueue.lh_Head);
2359 while(((struct Node *) ioreq)->ln_Succ)
2361 if(ioreq->iouh_Flags & UHFF_NAKTIMEOUT)
2363 eqh = (struct EhciQH *) ioreq->iouh_DriverPrivate1;
2364 if(eqh)
2366 KPRINTF(1, ("Examining IOReq=%p with EQH=%p\n", ioreq, eqh));
2367 devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint + ((ioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0);
2368 ctrlstatus = READMEM32_LE(&eqh->eqh_CtrlStatus);
2369 if(ctrlstatus & ETCF_ACTIVE)
2371 if(framecnt > unit->hu_NakTimeoutFrame[devadrep])
2373 // give the thing the chance to exit gracefully
2374 KPRINTF(20, ("NAK timeout %ld > %ld, IOReq=%p\n", framecnt, unit->hu_NakTimeoutFrame[devadrep], ioreq));
2375 ctrlstatus &= ~ETCF_ACTIVE;
2376 ctrlstatus |= ETSF_HALTED;
2377 WRITEMEM32_LE(&eqh->eqh_CtrlStatus, ctrlstatus);
2378 causeint = TRUE;
2380 } else {
2381 if(ctrlstatus & ETCF_READYINTEN)
2383 KPRINTF(10, ("INT missed?!? Manually causing it! %08lx, IOReq=%p\n",
2384 ctrlstatus, ioreq));
2385 causeint = TRUE;
2390 ioreq = (struct IOUsbHWReq *) ((struct Node *) ioreq)->ln_Succ;
2393 break;
2395 #ifdef AROS_USB30_CODE
2396 case HCITYPE_XHCI:
2398 //KPRINTF(1000, ("XHCI uhwNakTimeoutInt\n"));
2399 break;
2401 #endif
2403 if(causeint)
2405 SureCause(base, &hc->hc_CompleteInt);
2408 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
2411 uhwCheckRootHubChanges(unit);
2413 unit->hu_NakTimeoutReq.tr_time.tv_micro = 150*1000;
2414 SendIO((APTR) &unit->hu_NakTimeoutReq);
2416 KPRINTF(1, ("Exit NakTimeoutInt(0x%p)\n", unit));
2418 return FALSE;
2420 AROS_INTFUNC_EXIT
2422 /* \\\ */