move the defines to the resource header and include that where necessary.
[AROS.git] / rom / usb / pciusb / uhwcmd.c
blobb8718522f3dad67ee962f045f26dee407788ac9b
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 memset( &unit->hu_NakTimeoutMsgPort, 0, sizeof( 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 unit->hu_NakTimeoutReq.tr_node.io_Message.mn_ReplyPort = &unit->hu_NakTimeoutMsgPort;
183 Cause(&unit->hu_NakTimeoutInt);
184 return(&unit->hu_Unit);
185 } else {
186 ioreq->iouh_Req.io_Error = IOERR_SELFTEST;
187 KPRINTF(20, ("Hardware allocation failure!\n"));
189 uhwCloseTimer(unit, base);
191 return(NULL);
193 /* \\\ */
195 /* /// "Close_Unit()" */
196 void Close_Unit(struct PCIDevice *base,
197 struct PCIUnit *unit,
198 struct IOUsbHWReq *ioreq)
200 /* Disable all interrupts */
201 unit->hu_NakTimeoutMsgPort.mp_Flags = PA_IGNORE;
202 unit->hu_NakTimeoutInt.is_Node.ln_Type = NT_SOFTINT;
203 AbortIO((APTR) &unit->hu_NakTimeoutReq);
205 pciFreeUnit(unit);
207 uhwCloseTimer(unit, base);
208 unit->hu_UnitAllocated = FALSE;
210 /* \\\ */
212 /* /// "uhwGetUsbState()" */
213 UWORD uhwGetUsbState(struct IOUsbHWReq *ioreq,
214 struct PCIUnit *unit,
215 struct PCIDevice *base)
217 return(ioreq->iouh_State = UHSF_OPERATIONAL);
219 /* \\\ */
221 /* /// "cmdReset()" */
223 *======================================================================
224 * cmdReset(ioreq, unit, base)
225 *======================================================================
227 * This is the device CMD_RESET routine.
229 * Resets the whole USB hardware. Goes into USBOperational mode right
230 * after. Must NOT be called from an interrupt.
234 WORD cmdReset(struct IOUsbHWReq *ioreq,
235 struct PCIUnit *unit,
236 struct PCIDevice *base)
238 KPRINTF(10, ("CMD_RESET ioreq: 0x%p\n", ioreq));
240 uhwDelayMS(1, unit);
241 uhwGetUsbState(ioreq, unit, base);
243 if(ioreq->iouh_State & UHSF_OPERATIONAL)
245 return RC_OK;
247 return UHIOERR_USBOFFLINE;
249 /* \\\ */
251 /* /// "cmdUsbReset()" */
253 *======================================================================
254 * cmdUsbReset(ioreq, unit, base)
255 *======================================================================
257 * This is the device UHCMD_USBRESET routine.
259 * Resets the USB bus. Goes into USBOperational mode right after. Must
260 * NOT be called from an interrupt.
264 WORD cmdUsbReset(struct IOUsbHWReq *ioreq,
265 struct PCIUnit *unit,
266 struct PCIDevice *base)
268 KPRINTF(10, ("UHCMD_USBRESET ioreq: 0x%p\n", ioreq));
270 /* FIXME */
271 uhwGetUsbState(ioreq, unit, base);
273 unit->hu_FrameCounter = 1;
274 unit->hu_RootHubAddr = 0;
276 if(ioreq->iouh_State & UHSF_OPERATIONAL)
278 return RC_OK;
280 return UHIOERR_USBOFFLINE;
282 /* \\\ */
284 /* /// "cmdUsbResume()" */
286 *======================================================================
287 * cmdUsbResume(ioreq, unit, base)
288 *======================================================================
290 * This is the device UHCMD_USBRESUME routine.
292 * Tries to resume from USBSuspend mode into USBOperational.
293 * Must NOT be called from an interrupt.
297 WORD cmdUsbResume(struct IOUsbHWReq *ioreq,
298 struct PCIUnit *unit,
299 struct PCIDevice *base)
301 KPRINTF(10, ("UHCMD_USBRESUME ioreq: 0x%p\n", ioreq));
303 /* FIXME */
304 uhwGetUsbState(ioreq, unit, base);
305 if(ioreq->iouh_State & UHSF_OPERATIONAL)
307 return RC_OK;
309 return UHIOERR_USBOFFLINE;
311 /* \\\ */
313 /* /// "cmdUsbSuspend()" */
315 *======================================================================
316 * cmdUsbSuspend(ioreq, unit, base)
317 *======================================================================
319 * This is the device UHCMD_USBSUSPEND routine.
321 * Sets the USB into USBSuspend mode.
322 * Must NOT be called from an interrupt.
326 WORD cmdUsbSuspend(struct IOUsbHWReq *ioreq,
327 struct PCIUnit *unit,
328 struct PCIDevice *base)
330 KPRINTF(10, ("UHCMD_USBSUSPEND ioreq: 0x%p\n", ioreq));
332 /* FIXME */
333 uhwGetUsbState(ioreq, unit, base);
334 if(ioreq->iouh_State & UHSF_SUSPENDED)
336 return RC_OK;
338 return UHIOERR_USBOFFLINE;
340 /* \\\ */
342 /* /// "cmdUsbOper()" */
344 *======================================================================
345 * cmdUsbOper(ioreq, unit, base)
346 *======================================================================
348 * This is the device UHCMD_USBOPER routine.
350 * Sets the USB into USBOperational mode.
351 * Must NOT be called from an interrupt.
355 WORD cmdUsbOper(struct IOUsbHWReq *ioreq,
356 struct PCIUnit *unit,
357 struct PCIDevice *base)
359 KPRINTF(10, ("UHCMD_USBOPER ioreq: 0x%p\n", ioreq));
361 /* FIXME */
362 uhwGetUsbState(ioreq, unit, base);
363 if(ioreq->iouh_State & UHSF_OPERATIONAL)
365 return RC_OK;
367 return UHIOERR_USBOFFLINE;
369 /* \\\ */
371 /* /// "cmdQueryDevice()" */
373 *======================================================================
374 * cmdQueryDevice(ioreq, unit, base)
375 *======================================================================
377 * This is the device UHCMD_QUERYDEVICE routine.
379 * Returns information about the hardware.
383 WORD cmdQueryDevice(struct IOUsbHWReq *ioreq,
384 struct PCIUnit *unit,
385 struct PCIDevice *base)
387 struct TagItem *taglist = (struct TagItem *) ioreq->iouh_Data;
388 struct TagItem *tag;
389 ULONG count = 0;
391 KPRINTF(10, ("UHCMD_QUERYDEVICE ioreq: 0x%p, taglist: 0x%p\n", ioreq, taglist));
393 if((tag = FindTagItem(UHA_State, taglist)))
395 *((ULONG *) tag->ti_Data) = (ULONG) uhwGetUsbState(ioreq, unit, base);
396 count++;
398 if((tag = FindTagItem(UHA_Manufacturer, taglist)))
400 *((STRPTR *) tag->ti_Data) = "Chris Hodges";
401 count++;
403 if((tag = FindTagItem(UHA_ProductName, taglist)))
405 *((STRPTR *) tag->ti_Data) = unit->hu_ProductName;
406 count++;
408 if((tag = FindTagItem(UHA_Description, taglist)))
410 *((STRPTR *) tag->ti_Data) = "Generic adaptive host controller driver for PCI cards";
411 count++;
413 if((tag = FindTagItem(UHA_Copyright, taglist)))
415 *((STRPTR *) tag->ti_Data) ="©2007-2009 Chris Hodges";
416 count++;
418 if((tag = FindTagItem(UHA_Version, taglist)))
420 *((ULONG *) tag->ti_Data) = VERSION_NUMBER;
421 count++;
423 if((tag = FindTagItem(UHA_Revision, taglist)))
425 *((ULONG *) tag->ti_Data) = REVISION_NUMBER;
426 count++;
428 if((tag = FindTagItem(UHA_DriverVersion, taglist)))
430 *((ULONG *) tag->ti_Data) = 0x220;
431 count++;
433 if((tag = FindTagItem(UHA_Capabilities, taglist)))
435 *((ULONG *) tag->ti_Data) = UHCF_USB20;
436 count++;
438 ioreq->iouh_Actual = count;
439 return RC_OK;
441 /* \\\ */
443 /* /// "cmdControlXFerRootHub()" */
444 WORD cmdControlXFerRootHub(struct IOUsbHWReq *ioreq,
445 struct PCIUnit *unit,
446 struct PCIDevice *base)
448 struct PCIController *hc;
449 struct PCIController *chc;
450 UWORD rt = ioreq->iouh_SetupData.bmRequestType;
451 UWORD req = ioreq->iouh_SetupData.bRequest;
452 UWORD idx = AROS_WORD2LE(ioreq->iouh_SetupData.wIndex);
453 UWORD val = AROS_WORD2LE(ioreq->iouh_SetupData.wValue);
454 UWORD len = AROS_WORD2LE(ioreq->iouh_SetupData.wLength);
455 UWORD hciport;
456 ULONG numports = unit->hu_RootHubPorts;
457 BOOL cmdgood;
458 ULONG cnt;
460 if(ioreq->iouh_Endpoint)
462 return(UHIOERR_STALL);
465 if(len != ioreq->iouh_Length)
467 KPRINTF(20, ("RH: Len (%ld != %ld) mismatch!\n", len != ioreq->iouh_Length));
468 return(UHIOERR_STALL);
470 switch(rt)
472 case (URTF_STANDARD|URTF_DEVICE):
473 switch(req)
475 case USR_SET_ADDRESS:
476 KPRINTF(1, ("RH: SetAddress = %ld\n", val));
477 unit->hu_RootHubAddr = val;
478 ioreq->iouh_Actual = len;
479 return(0);
481 case USR_SET_CONFIGURATION:
482 KPRINTF(1, ("RH: SetConfiguration=%ld\n", val));
483 ioreq->iouh_Actual = len;
484 return(0);
486 break;
488 case (URTF_IN|URTF_STANDARD|URTF_DEVICE):
489 switch(req)
491 case USR_GET_DESCRIPTOR:
492 switch(val>>8)
494 case UDT_DEVICE:
495 KPRINTF(1, ("RH: GetDeviceDescriptor (%ld)\n", len));
496 ioreq->iouh_Actual = (len > sizeof(struct UsbStdDevDesc)) ? sizeof(struct UsbStdDevDesc) : len;
497 CopyMem((APTR) &RHDevDesc, ioreq->iouh_Data, ioreq->iouh_Actual);
498 if(ioreq->iouh_Length >= sizeof(struct UsbStdDevDesc))
500 if(unit->hu_RootHub20Ports)
502 struct UsbStdDevDesc *usdd = (struct UsbStdDevDesc *) ioreq->iouh_Data;
503 usdd->bcdUSB = AROS_WORD2LE(0x0200); // signal a highspeed root hub
504 usdd->bDeviceProtocol = 1; // single TT
508 return(0);
510 case UDT_CONFIGURATION:
512 UBYTE tmpbuf[9+9+7];
513 KPRINTF(1, ("RH: GetConfigDescriptor (%ld)\n", len));
514 CopyMem((APTR) &RHCfgDesc, tmpbuf, 9);
515 CopyMem((APTR) &RHIfDesc, &tmpbuf[9], 9);
516 CopyMem((APTR) &RHEPDesc, &tmpbuf[9+9], 7);
517 if(unit->hu_RootHub20Ports)
519 struct UsbStdEPDesc *usepd = (struct UsbStdEPDesc *) &tmpbuf[9+9];
520 usepd->bInterval = 12; // 2048 µFrames
522 ioreq->iouh_Actual = (len > 9+9+7) ? 9+9+7 : len;
523 CopyMem(tmpbuf, ioreq->iouh_Data, ioreq->iouh_Actual);
524 return(0);
527 case UDT_STRING:
528 if(val & 0xff) /* get lang array */
530 CONST_STRPTR source = NULL;
531 UWORD *mptr = ioreq->iouh_Data;
532 UWORD slen = 1;
533 KPRINTF(1, ("RH: GetString %04lx (%ld)\n", val, len));
534 if((val & 0xff) > 4) /* index too high? */
536 return(UHIOERR_STALL);
538 source = RHStrings[(val & 0xff)-1];
539 if(len > 1)
541 ioreq->iouh_Actual = 2;
542 while(*source++)
544 slen++;
546 source = RHStrings[(val & 0xff)-1];
547 *mptr++ = AROS_WORD2BE((slen<<9)|UDT_STRING);
548 while(ioreq->iouh_Actual+1 < len)
550 // special hack for unit number in root hub string
551 if(((val & 0xff) == 2) && (source[1] == 0))
553 *mptr++ = AROS_WORD2LE('0' + unit->hu_UnitNo);
554 } else {
555 *mptr++ = AROS_WORD2LE(*source);
557 source++;
558 ioreq->iouh_Actual += 2;
559 if(!(*source))
561 break;
565 } else {
566 UWORD *mptr = ioreq->iouh_Data;
567 KPRINTF(1, ("RH: GetLangArray %04lx (%ld)\n", val, len));
568 if(len > 1)
570 ioreq->iouh_Actual = 2;
571 mptr[0] = AROS_WORD2BE((4<<8)|UDT_STRING);
572 if(len > 3)
574 ioreq->iouh_Actual += 2;
575 mptr[1] = AROS_WORD2LE(0x0409);
579 return(0);
581 default:
582 KPRINTF(1, ("RH: Unsupported Descriptor %04lx\n", idx));
584 break;
586 case USR_GET_CONFIGURATION:
587 if(len == 1)
589 KPRINTF(1, ("RH: GetConfiguration\n"));
590 ((UBYTE *) ioreq->iouh_Data)[0] = 1;
591 ioreq->iouh_Actual = len;
592 return(0);
594 break;
596 break;
598 case (URTF_CLASS|URTF_OTHER):
599 switch(req)
601 case USR_SET_FEATURE:
602 if((!idx) || (idx > numports))
604 KPRINTF(20, ("Port %ld out of range\n", idx));
605 return(UHIOERR_STALL);
607 chc = unit->hu_PortMap11[idx - 1];
608 if(unit->hu_EhciOwned[idx - 1])
610 hc = unit->hu_PortMap20[idx - 1];
611 hciport = idx - 1;
612 } else {
613 hc = chc;
614 hciport = unit->hu_PortNum11[idx - 1];
616 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"));
617 cmdgood = FALSE;
618 switch(hc->hc_HCIType)
620 case HCITYPE_UHCI:
622 UWORD portreg = hciport ? UHCI_PORT2STSCTRL : UHCI_PORT1STSCTRL;
623 ULONG oldval = READIO16_LE(hc->hc_RegBase, portreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE); // these are clear-on-write!
624 ULONG newval = oldval;
625 switch(val)
627 /* case UFS_PORT_CONNECTION: not possible */
628 case UFS_PORT_ENABLE:
629 KPRINTF(10, ("UHCI: Enabling Port (%s)\n", newval & UHPF_PORTENABLE ? "already" : "ok"));
630 newval |= UHPF_PORTENABLE;
631 cmdgood = TRUE;
632 break;
634 case UFS_PORT_SUSPEND:
635 newval |= UHPF_PORTSUSPEND;
636 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_SUSPEND; // manually fake suspend change
637 cmdgood = TRUE;
638 break;
640 /* case UFS_PORT_OVER_CURRENT: not possible */
641 case UFS_PORT_RESET:
642 KPRINTF(10, ("UHCI: Resetting Port (%s)\n", newval & UHPF_PORTRESET ? "already" : "ok"));
644 // this is an ugly blocking workaround to the inability of UHCI to clear reset automatically
645 newval &= ~(UHPF_PORTSUSPEND|UHPF_PORTENABLE);
646 newval |= UHPF_PORTRESET;
647 WRITEIO16_LE(hc->hc_RegBase, portreg, newval);
648 uhwDelayMS(25, unit);
649 newval = READIO16_LE(hc->hc_RegBase, portreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE|UHPF_PORTSUSPEND|UHPF_PORTENABLE);
650 KPRINTF(10, ("UHCI: Reset=%s\n", newval & UHPF_PORTRESET ? "GOOD" : "BAD!"));
651 // like windows does it
652 newval &= ~UHPF_PORTRESET;
653 WRITEIO16_LE(hc->hc_RegBase, portreg, newval);
654 uhwDelayMicro(50, unit);
655 newval = READIO16_LE(hc->hc_RegBase, portreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE|UHPF_PORTSUSPEND);
656 KPRINTF(10, ("UHCI: Reset=%s\n", newval & UHPF_PORTRESET ? "BAD!" : "GOOD"));
657 newval &= ~(UHPF_PORTSUSPEND|UHPF_PORTRESET);
658 newval |= UHPF_PORTENABLE;
659 WRITEIO16_LE(hc->hc_RegBase, portreg, newval);
660 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_RESET|UPSF_PORT_ENABLE; // manually fake reset change
662 cnt = 100;
665 uhwDelayMS(1, unit);
666 newval = READIO16_LE(hc->hc_RegBase, portreg);
667 } while(--cnt && (!(newval & UHPF_PORTENABLE)));
668 if(cnt)
670 KPRINTF(10, ("UHCI: Enabled after %ld ticks\n", 100-cnt));
671 } else {
672 KPRINTF(20, ("UHCI: Port refuses to be enabled!\n"));
673 return(UHIOERR_HOSTERROR);
675 // make enumeration possible
676 unit->hu_DevControllers[0] = hc;
677 cmdgood = TRUE;
678 break;
680 case UFS_PORT_POWER:
681 KPRINTF(10, ("UHCI: Powering Port\n"));
682 // ignore for UHCI, is always powered
683 cmdgood = TRUE;
684 break;
686 /* case UFS_PORT_LOW_SPEED: not possible */
687 /* case UFS_C_PORT_CONNECTION:
688 case UFS_C_PORT_ENABLE:
689 case UFS_C_PORT_SUSPEND:
690 case UFS_C_PORT_OVER_CURRENT:
691 case UFS_C_PORT_RESET: */
693 if(cmdgood)
695 KPRINTF(5, ("UHCI: Port %ld SET_FEATURE %04lx->%04lx\n", idx, oldval, newval));
696 WRITEIO16_LE(hc->hc_RegBase, portreg, newval);
697 return(0);
699 break;
702 case HCITYPE_OHCI:
704 UWORD portreg = OHCI_PORTSTATUS + (hciport<<2);
705 ULONG oldval = READREG32_LE(hc->hc_RegBase, portreg);
707 switch(val)
709 /* case UFS_PORT_CONNECTION: not possible */
710 case UFS_PORT_ENABLE:
711 KPRINTF(10, ("OHCI: Enabling Port (%s)\n", oldval & OHPF_PORTENABLE ? "already" : "ok"));
712 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTENABLE);
713 cmdgood = TRUE;
714 break;
716 case UFS_PORT_SUSPEND:
717 KPRINTF(10, ("OHCI: Suspending Port (%s)\n", oldval & OHPF_PORTSUSPEND ? "already" : "ok"));
718 //hc->hc_PortChangeMap[hciport] |= UPSF_PORT_SUSPEND; // manually fake suspend change
719 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTSUSPEND);
720 cmdgood = TRUE;
721 break;
723 /* case UFS_PORT_OVER_CURRENT: not possible */
724 case UFS_PORT_RESET:
725 KPRINTF(10, ("OHCI: Resetting Port (%s)\n", oldval & OHPF_PORTRESET ? "already" : "ok"));
726 // make sure we have at least 50ms of reset time here, as required for a root hub port
727 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTRESET);
728 uhwDelayMS(10, unit);
729 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTRESET);
730 uhwDelayMS(10, unit);
731 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTRESET);
732 uhwDelayMS(10, unit);
733 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTRESET);
734 uhwDelayMS(10, unit);
735 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTRESET);
736 uhwDelayMS(15, unit);
737 oldval = READREG32_LE(hc->hc_RegBase, portreg);
738 KPRINTF(10, ("OHCI: Reset release (%s %s)\n", oldval & OHPF_PORTRESET ? "didn't turn off" : "okay",
739 oldval & OHPF_PORTENABLE ? "enabled" : "not enabled"));
740 if(oldval & OHPF_PORTRESET)
742 uhwDelayMS(40, unit);
743 oldval = READREG32_LE(hc->hc_RegBase, portreg);
744 KPRINTF(10, ("OHCI: Reset 2nd release (%s %s)\n", oldval & OHPF_PORTRESET ? "didn't turn off" : "okay",
745 oldval & OHPF_PORTENABLE ? "enabled" : "still not enabled"));
747 // make enumeration possible
748 unit->hu_DevControllers[0] = hc;
749 cmdgood = TRUE;
750 break;
752 case UFS_PORT_POWER:
753 KPRINTF(10, ("OHCI: Powering Port (%s)\n", oldval & OHPF_PORTPOWER ? "already" : "ok"));
754 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTPOWER);
755 cmdgood = TRUE;
756 break;
758 /* case UFS_PORT_LOW_SPEED: not possible */
759 /* case UFS_C_PORT_CONNECTION:
760 case UFS_C_PORT_ENABLE:
761 case UFS_C_PORT_SUSPEND:
762 case UFS_C_PORT_OVER_CURRENT:
763 case UFS_C_PORT_RESET: */
765 if(cmdgood)
767 return(0);
769 break;
772 case HCITYPE_EHCI:
774 UWORD portreg = EHCI_PORTSC1 + (hciport<<2);
775 ULONG oldval = READREG32_LE(hc->hc_RegBase, portreg) & ~(EHPF_OVERCURRENTCHG|EHPF_ENABLECHANGE|EHPF_CONNECTCHANGE); // these are clear-on-write!
776 ULONG newval = oldval;
777 switch(val)
779 /* case UFS_PORT_CONNECTION: not possible */
780 case UFS_PORT_ENABLE:
781 KPRINTF(10, ("EHCI: Enabling Port (%s)\n", newval & EHPF_PORTENABLE ? "already" : "ok"));
782 newval |= EHPF_PORTENABLE;
783 cmdgood = TRUE;
784 break;
786 case UFS_PORT_SUSPEND:
787 newval |= EHPF_PORTSUSPEND;
788 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_SUSPEND; // manually fake suspend change
789 cmdgood = TRUE;
790 break;
792 /* case UFS_PORT_OVER_CURRENT: not possible */
793 case UFS_PORT_RESET:
794 KPRINTF(10, ("EHCI: Resetting Port (%s)\n", newval & EHPF_PORTRESET ? "already" : "ok"));
796 // this is an ugly blocking workaround to the inability of EHCI to clear reset automatically
797 newval &= ~(EHPF_PORTSUSPEND|EHPF_PORTENABLE);
798 newval |= EHPF_PORTRESET;
799 WRITEREG32_LE(hc->hc_RegBase, portreg, newval);
800 uhwDelayMS(50, unit);
801 newval = READREG32_LE(hc->hc_RegBase, portreg) & ~(EHPF_OVERCURRENTCHG|EHPF_ENABLECHANGE|EHPF_CONNECTCHANGE|EHPF_PORTSUSPEND|EHPF_PORTENABLE);
802 KPRINTF(10, ("EHCI: Reset=%s\n", newval & EHPF_PORTRESET ? "GOOD" : "BAD!"));
803 newval &= ~EHPF_PORTRESET;
804 WRITEREG32_LE(hc->hc_RegBase, portreg, newval);
805 uhwDelayMS(10, unit);
806 newval = READREG32_LE(hc->hc_RegBase, portreg) & ~(EHPF_OVERCURRENTCHG|EHPF_ENABLECHANGE|EHPF_CONNECTCHANGE|EHPF_PORTSUSPEND);
807 KPRINTF(10, ("EHCI: Reset=%s\n", newval & EHPF_PORTRESET ? "BAD!" : "GOOD"));
808 KPRINTF(10, ("EHCI: Highspeed=%s\n", newval & EHPF_PORTENABLE ? "YES!" : "NO"));
809 KPRINTF(10, ("EHCI: Port status=%08lx\n", newval));
810 if(!(newval & EHPF_PORTENABLE) && unit->hu_PortMap11[idx - 1] != NULL)
812 // if not highspeed, release ownership
813 KPRINTF(20, ("EHCI: Transferring ownership to UHCI/OHCI port %ld\n", unit->hu_PortNum11[idx - 1]));
814 KPRINTF(10, ("EHCI: Device is %s\n", newval & EHPF_LINESTATUS_DM ? "LOWSPEED" : "FULLSPEED"));
815 newval |= EHPF_NOTPORTOWNER;
816 if(!chc)
818 KPRINTF(20, ("EHCI has no companion controller, can't transfer ownership!\n"));
819 WRITEREG32_LE(hc->hc_RegBase, portreg, newval);
820 return(UHIOERR_HOSTERROR);
822 switch(chc->hc_HCIType)
824 case HCITYPE_UHCI:
826 UWORD uhcihciport = unit->hu_PortNum11[idx - 1];
827 UWORD uhciportreg = uhcihciport ? UHCI_PORT2STSCTRL : UHCI_PORT1STSCTRL;
828 ULONG __unused uhcinewval = READREG16_LE(chc->hc_RegBase, uhciportreg);
830 KPRINTF(10, ("UHCI Port status before handover=%04lx\n", uhcinewval));
831 break;
834 case HCITYPE_OHCI:
836 UWORD ohcihciport = unit->hu_PortNum11[idx - 1];
837 UWORD ohciportreg = OHCI_PORTSTATUS + (ohcihciport<<2);
838 ULONG __unused ohcioldval = READREG32_LE(chc->hc_RegBase, ohciportreg);
840 KPRINTF(10, ("OHCI: Port status before handover=%08lx\n", ohcioldval));
841 KPRINTF(10, ("OHCI: Powering Port (%s)\n", ohcioldval & OHPF_PORTPOWER ? "already" : "ok"));
842 WRITEREG32_LE(chc->hc_RegBase, ohciportreg, OHPF_PORTPOWER);
843 uhwDelayMS(10, unit);
844 KPRINTF(10, ("OHCI: Port status after handover=%08lx\n", READREG32_LE(chc->hc_RegBase, ohciportreg)));
845 break;
848 newval = READREG32_LE(hc->hc_RegBase, portreg) & ~(EHPF_OVERCURRENTCHG|EHPF_ENABLECHANGE|EHPF_CONNECTCHANGE|EHPF_PORTSUSPEND);
849 KPRINTF(10, ("EHCI: Port status (reread)=%08lx\n", newval));
850 newval |= EHPF_NOTPORTOWNER;
851 unit->hu_EhciOwned[idx - 1] = FALSE;
852 WRITEREG32_LE(hc->hc_RegBase, portreg, newval);
853 uhwDelayMS(90, unit);
854 KPRINTF(10, ("EHCI: Port status (after handover)=%08lx\n", READREG32_LE(hc->hc_RegBase, portreg) & ~(EHPF_OVERCURRENTCHG|EHPF_ENABLECHANGE|EHPF_CONNECTCHANGE|EHPF_PORTSUSPEND)));
855 // enable companion controller port
856 switch(chc->hc_HCIType)
858 case HCITYPE_UHCI:
860 UWORD uhcihciport = unit->hu_PortNum11[idx - 1];
861 UWORD uhciportreg = uhcihciport ? UHCI_PORT2STSCTRL : UHCI_PORT1STSCTRL;
862 ULONG uhcinewval;
864 uhcinewval = READIO16_LE(chc->hc_RegBase, uhciportreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE|UHPF_PORTSUSPEND);
865 KPRINTF(10, ("UHCI: Reset=%s\n", uhcinewval & UHPF_PORTRESET ? "BAD!" : "GOOD"));
866 if((uhcinewval & UHPF_PORTRESET))//|| (newval & EHPF_LINESTATUS_DM))
868 // this is an ugly blocking workaround to the inability of UHCI to clear reset automatically
869 KPRINTF(20, ("UHCI: Uhm, reset was bad!\n"));
870 uhcinewval &= ~(UHPF_PORTSUSPEND|UHPF_PORTENABLE);
871 uhcinewval |= UHPF_PORTRESET;
872 WRITEIO16_LE(chc->hc_RegBase, uhciportreg, uhcinewval);
873 uhwDelayMS(50, unit);
874 uhcinewval = READIO16_LE(chc->hc_RegBase, uhciportreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE|UHPF_PORTSUSPEND|UHPF_PORTENABLE);
875 KPRINTF(10, ("UHCI: ReReset=%s\n", uhcinewval & UHPF_PORTRESET ? "GOOD" : "BAD!"));
876 uhcinewval &= ~UHPF_PORTRESET;
877 WRITEIO16_LE(chc->hc_RegBase, uhciportreg, uhcinewval);
878 uhwDelayMicro(50, unit);
879 uhcinewval = READIO16_LE(chc->hc_RegBase, uhciportreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE|UHPF_PORTSUSPEND);
880 KPRINTF(10, ("UHCI: ReReset=%s\n", uhcinewval & UHPF_PORTRESET ? "STILL BAD!" : "GOOD"));
882 uhcinewval &= ~UHPF_PORTRESET;
883 uhcinewval |= UHPF_PORTENABLE;
884 WRITEIO16_LE(chc->hc_RegBase, uhciportreg, uhcinewval);
885 chc->hc_PortChangeMap[uhcihciport] |= UPSF_PORT_RESET|UPSF_PORT_ENABLE; // manually fake reset change
886 uhwDelayMS(5, unit);
887 cnt = 100;
890 uhwDelayMS(1, unit);
891 uhcinewval = READIO16_LE(chc->hc_RegBase, uhciportreg);
892 } while(--cnt && (!(uhcinewval & UHPF_PORTENABLE)));
893 if(cnt)
895 KPRINTF(10, ("UHCI: Enabled after %ld ticks\n", 100-cnt));
896 } else {
897 KPRINTF(20, ("UHCI: Port refuses to be enabled!\n"));
898 return(UHIOERR_HOSTERROR);
900 break;
903 case HCITYPE_OHCI:
905 UWORD ohcihciport = unit->hu_PortNum11[idx - 1];
906 UWORD ohciportreg = OHCI_PORTSTATUS + (ohcihciport<<2);
907 ULONG ohcioldval = READREG32_LE(chc->hc_RegBase, ohciportreg);
908 KPRINTF(10, ("OHCI: Resetting Port (%s)\n", ohcioldval & OHPF_PORTRESET ? "already" : "ok"));
909 // make sure we have at least 50ms of reset time here, as required for a root hub port
910 WRITEREG32_LE(chc->hc_RegBase, ohciportreg, OHPF_PORTRESET);
911 uhwDelayMS(10, unit);
912 WRITEREG32_LE(chc->hc_RegBase, ohciportreg, OHPF_PORTRESET);
913 uhwDelayMS(10, unit);
914 WRITEREG32_LE(chc->hc_RegBase, ohciportreg, OHPF_PORTRESET);
915 uhwDelayMS(10, unit);
916 WRITEREG32_LE(chc->hc_RegBase, ohciportreg, OHPF_PORTRESET);
917 uhwDelayMS(10, unit);
918 WRITEREG32_LE(chc->hc_RegBase, ohciportreg, OHPF_PORTRESET);
919 uhwDelayMS(15, unit);
920 ohcioldval = READREG32_LE(chc->hc_RegBase, ohciportreg);
921 KPRINTF(10, ("OHCI: Reset release (%s %s)\n", ohcioldval & OHPF_PORTRESET ? "didn't turn off" : "okay",
922 ohcioldval & OHPF_PORTENABLE ? "enabled" : "not enabled"));
923 if(ohcioldval & OHPF_PORTRESET)
925 uhwDelayMS(40, unit);
926 ohcioldval = READREG32_LE(chc->hc_RegBase, ohciportreg);
927 KPRINTF(10, ("OHCI: Reset 2nd release (%s %s)\n", ohcioldval & OHPF_PORTRESET ? "didn't turn off" : "okay",
928 ohcioldval & OHPF_PORTENABLE ? "enabled" : "still not enabled"));
930 break;
934 // make enumeration possible
935 unit->hu_DevControllers[0] = chc;
936 return(0);
937 } else {
938 newval &= ~EHPF_PORTRESET;
939 WRITEREG32_LE(hc->hc_RegBase, portreg, newval);
940 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_RESET; // manually fake reset change
941 uhwDelayMS(10, unit);
942 cnt = 100;
945 uhwDelayMS(1, unit);
946 newval = READREG32_LE(hc->hc_RegBase, portreg);
947 } while(--cnt && (!(newval & EHPF_PORTENABLE)));
948 if(cnt)
950 KPRINTF(10, ("EHCI: Enabled after %ld ticks\n", 100-cnt));
951 } else {
952 KPRINTF(20, ("EHCI: Port refuses to be enabled!\n"));
953 return(UHIOERR_HOSTERROR);
955 // make enumeration possible
956 unit->hu_DevControllers[0] = hc;
958 cmdgood = TRUE;
959 break;
961 case UFS_PORT_POWER:
962 KPRINTF(10, ("EHCI: Powering Port\n"));
963 newval |= EHPF_PORTPOWER;
964 cmdgood = TRUE;
965 break;
967 /* case UFS_PORT_LOW_SPEED: not possible */
968 /* case UFS_C_PORT_CONNECTION:
969 case UFS_C_PORT_ENABLE:
970 case UFS_C_PORT_SUSPEND:
971 case UFS_C_PORT_OVER_CURRENT:
972 case UFS_C_PORT_RESET: */
974 if(cmdgood)
976 KPRINTF(5, ("EHCI: Port %ld SET_FEATURE %04lx->%04lx\n", idx, oldval, newval));
977 WRITEREG32_LE(hc->hc_RegBase, portreg, newval);
978 return(0);
980 break;
984 break;
986 case USR_CLEAR_FEATURE:
987 if((!idx) || (idx > numports))
989 KPRINTF(20, ("Port %ld out of range\n", idx));
990 return(UHIOERR_STALL);
992 if(unit->hu_EhciOwned[idx - 1])
994 hc = unit->hu_PortMap20[idx - 1];
995 hciport = idx - 1;
996 } else {
997 hc = unit->hu_PortMap11[idx - 1];
998 hciport = unit->hu_PortNum11[idx - 1];
1000 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"));
1001 cmdgood = FALSE;
1002 switch(hc->hc_HCIType)
1004 case HCITYPE_UHCI:
1006 UWORD portreg = hciport ? UHCI_PORT2STSCTRL : UHCI_PORT1STSCTRL;
1007 ULONG oldval = READIO16_LE(hc->hc_RegBase, portreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE); // these are clear-on-write!
1008 ULONG newval = oldval;
1009 switch(val)
1011 case UFS_PORT_ENABLE:
1012 KPRINTF(10, ("Disabling Port (%s)\n", newval & UHPF_PORTENABLE ? "ok" : "already"));
1013 newval &= ~UHPF_PORTENABLE;
1014 cmdgood = TRUE;
1015 // disable enumeration
1016 unit->hu_DevControllers[0] = NULL;
1017 break;
1019 case UFS_PORT_SUSPEND:
1020 newval &= ~UHPF_PORTSUSPEND;
1021 cmdgood = TRUE;
1022 break;
1024 case UFS_PORT_POWER: // ignore for UHCI, there's no power control here
1025 KPRINTF(10, ("Disabling Power\n"));
1026 KPRINTF(10, ("Disabling Port (%s)\n", newval & UHPF_PORTENABLE ? "ok" : "already"));
1027 newval &= ~UHPF_PORTENABLE;
1028 cmdgood = TRUE;
1029 break;
1031 case UFS_C_PORT_CONNECTION:
1032 newval |= UHPF_CONNECTCHANGE; // clear-on-write!
1033 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_CONNECTION;
1034 cmdgood = TRUE;
1035 break;
1037 case UFS_C_PORT_ENABLE:
1038 newval |= UHPF_ENABLECHANGE; // clear-on-write!
1039 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_ENABLE;
1040 cmdgood = TRUE;
1041 break;
1043 case UFS_C_PORT_SUSPEND: // ignore for UHCI, there's no bit indicating this
1044 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_SUSPEND; // manually fake suspend change clearing
1045 cmdgood = TRUE;
1046 break;
1048 case UFS_C_PORT_OVER_CURRENT: // ignore for UHCI, there's no bit indicating this
1049 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_OVER_CURRENT; // manually fake over current clearing
1050 cmdgood = TRUE;
1051 break;
1053 case UFS_C_PORT_RESET: // ignore for UHCI, there's no bit indicating this
1054 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_RESET; // manually fake reset change clearing
1055 cmdgood = TRUE;
1056 break;
1058 if(cmdgood)
1060 KPRINTF(5, ("Port %ld CLEAR_FEATURE %04lx->%04lx\n", idx, oldval, newval));
1061 WRITEIO16_LE(hc->hc_RegBase, portreg, newval);
1062 if(hc->hc_PortChangeMap[hciport])
1064 unit->hu_RootPortChanges |= 1UL<<idx;
1065 } else {
1066 unit->hu_RootPortChanges &= ~(1UL<<idx);
1068 return(0);
1070 break;
1073 case HCITYPE_OHCI:
1075 UWORD portreg = OHCI_PORTSTATUS + (hciport<<2);
1076 ULONG __unused oldval = READREG32_LE(hc->hc_RegBase, portreg);
1078 switch(val)
1080 case UFS_PORT_ENABLE:
1081 KPRINTF(10, ("Disabling Port (%s)\n", oldval & OHPF_PORTENABLE ? "ok" : "already"));
1082 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTDISABLE);
1083 cmdgood = TRUE;
1084 break;
1086 case UFS_PORT_SUSPEND:
1087 KPRINTF(10, ("Resuming Port (%s)\n", oldval & OHPF_PORTSUSPEND ? "ok" : "already"));
1088 //hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_SUSPEND; // manually fake suspend change
1089 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_RESUME);
1090 cmdgood = TRUE;
1091 break;
1093 case UFS_PORT_POWER:
1094 KPRINTF(10, ("Unpowering Port (%s)\n", oldval & OHPF_PORTPOWER ? "ok" : "already"));
1095 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_PORTUNPOWER);
1096 cmdgood = TRUE;
1097 break;
1099 case UFS_C_PORT_CONNECTION:
1100 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_CONNECTCHANGE);
1101 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_CONNECTION;
1102 cmdgood = TRUE;
1103 break;
1105 case UFS_C_PORT_ENABLE:
1106 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_ENABLECHANGE);
1107 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_ENABLE;
1108 cmdgood = TRUE;
1109 break;
1111 case UFS_C_PORT_SUSPEND:
1112 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_RESUMEDTX);
1113 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_SUSPEND;
1114 cmdgood = TRUE;
1115 break;
1117 case UFS_C_PORT_OVER_CURRENT:
1118 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_OVERCURRENTCHG);
1119 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_OVER_CURRENT;
1120 cmdgood = TRUE;
1121 break;
1123 case UFS_C_PORT_RESET:
1124 WRITEREG32_LE(hc->hc_RegBase, portreg, OHPF_RESETCHANGE);
1125 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_RESET;
1126 cmdgood = TRUE;
1127 break;
1129 if(cmdgood)
1131 return(0);
1133 break;
1136 case HCITYPE_EHCI:
1138 UWORD portreg = EHCI_PORTSC1 + (hciport<<2);
1139 ULONG oldval = READREG32_LE(hc->hc_RegBase, portreg) & ~(EHPF_OVERCURRENTCHG|EHPF_ENABLECHANGE|EHPF_CONNECTCHANGE); // these are clear-on-write!
1140 ULONG newval = oldval;
1141 switch(val)
1143 case UFS_PORT_ENABLE:
1144 KPRINTF(10, ("Disabling Port (%s)\n", newval & EHPF_PORTENABLE ? "ok" : "already"));
1145 newval &= ~EHPF_PORTENABLE;
1146 cmdgood = TRUE;
1147 // disable enumeration
1148 unit->hu_DevControllers[0] = NULL;
1149 break;
1151 case UFS_PORT_SUSPEND:
1152 newval &= ~EHPF_PORTSUSPEND;
1153 cmdgood = TRUE;
1154 break;
1156 case UFS_PORT_POWER: // ignore for UHCI, there's no power control here
1157 KPRINTF(10, ("Disabling Power (%s)\n", newval & EHPF_PORTPOWER ? "ok" : "already"));
1158 KPRINTF(10, ("Disabling Port (%s)\n", newval & EHPF_PORTENABLE ? "ok" : "already"));
1159 newval &= ~(EHPF_PORTENABLE|EHPF_PORTPOWER);
1160 cmdgood = TRUE;
1161 break;
1163 case UFS_C_PORT_CONNECTION:
1164 newval |= EHPF_CONNECTCHANGE; // clear-on-write!
1165 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_CONNECTION;
1166 cmdgood = TRUE;
1167 break;
1169 case UFS_C_PORT_ENABLE:
1170 newval |= EHPF_ENABLECHANGE; // clear-on-write!
1171 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_ENABLE;
1172 cmdgood = TRUE;
1173 break;
1175 case UFS_C_PORT_SUSPEND: // ignore for EHCI, there's no bit indicating this
1176 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_SUSPEND; // manually fake suspend change clearing
1177 cmdgood = TRUE;
1178 break;
1180 case UFS_C_PORT_OVER_CURRENT:
1181 newval |= EHPF_OVERCURRENTCHG; // clear-on-write!
1182 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_OVER_CURRENT; // manually fake over current clearing
1183 cmdgood = TRUE;
1184 break;
1186 case UFS_C_PORT_RESET: // ignore for EHCI, there's no bit indicating this
1187 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_RESET; // manually fake reset change clearing
1188 cmdgood = TRUE;
1189 break;
1191 if(cmdgood)
1193 KPRINTF(5, ("Port %ld CLEAR_FEATURE %08lx->%08lx\n", idx, oldval, newval));
1194 WRITEREG32_LE(hc->hc_RegBase, portreg, newval);
1195 if(hc->hc_PortChangeMap[hciport])
1197 unit->hu_RootPortChanges |= 1UL<<idx;
1198 } else {
1199 unit->hu_RootPortChanges &= ~(1UL<<idx);
1201 return(0);
1203 break;
1207 break;
1209 break;
1211 case (URTF_IN|URTF_CLASS|URTF_OTHER):
1212 switch(req)
1214 case USR_GET_STATUS:
1216 UWORD *mptr = ioreq->iouh_Data;
1217 if(len != sizeof(struct UsbPortStatus))
1219 return(UHIOERR_STALL);
1221 if((!idx) || (idx > numports))
1223 KPRINTF(20, ("Port %ld out of range\n", idx));
1224 return(UHIOERR_STALL);
1226 if(unit->hu_EhciOwned[idx - 1])
1228 hc = unit->hu_PortMap20[idx - 1];
1229 hciport = idx - 1;
1230 } else {
1231 hc = unit->hu_PortMap11[idx - 1];
1232 hciport = unit->hu_PortNum11[idx - 1];
1234 switch(hc->hc_HCIType)
1236 case HCITYPE_UHCI:
1238 UWORD portreg = hciport ? UHCI_PORT2STSCTRL : UHCI_PORT1STSCTRL;
1239 UWORD oldval = READIO16_LE(hc->hc_RegBase, portreg);
1240 *mptr = AROS_WORD2LE(UPSF_PORT_POWER);
1241 if(oldval & UHPF_PORTCONNECTED) *mptr |= AROS_WORD2LE(UPSF_PORT_CONNECTION);
1242 if(oldval & UHPF_PORTENABLE) *mptr |= AROS_WORD2LE(UPSF_PORT_ENABLE);
1243 if(oldval & UHPF_LOWSPEED) *mptr |= AROS_WORD2LE(UPSF_PORT_LOW_SPEED);
1244 if(oldval & UHPF_PORTRESET) *mptr |= AROS_WORD2LE(UPSF_PORT_RESET);
1245 if(oldval & UHPF_PORTSUSPEND) *mptr |= AROS_WORD2LE(UPSF_PORT_SUSPEND);
1247 KPRINTF(5, ("UHCI Port %ld is %s\n", idx, oldval & UHPF_LOWSPEED ? "LOWSPEED" : "FULLSPEED"));
1248 KPRINTF(5, ("UHCI Port %ld Status %08lx\n", idx, *mptr));
1250 mptr++;
1251 if(oldval & UHPF_ENABLECHANGE)
1253 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_ENABLE;
1255 if(oldval & UHPF_CONNECTCHANGE)
1257 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_CONNECTION;
1259 if(oldval & UHPF_RESUMEDTX)
1261 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_SUSPEND|UPSF_PORT_ENABLE;
1263 *mptr = AROS_WORD2LE(hc->hc_PortChangeMap[hciport]);
1264 WRITEIO16_LE(hc->hc_RegBase, portreg, oldval);
1265 KPRINTF(5, ("UHCI Port %ld Change %08lx\n", idx, *mptr));
1266 return(0);
1269 case HCITYPE_OHCI:
1271 UWORD portreg = OHCI_PORTSTATUS + (hciport<<2);
1272 ULONG oldval = READREG32_LE(hc->hc_RegBase, portreg);
1274 *mptr = 0;
1275 if(oldval & OHPF_PORTPOWER) *mptr |= AROS_WORD2LE(UPSF_PORT_POWER);
1276 if(oldval & OHPF_OVERCURRENT) *mptr |= AROS_WORD2LE(UPSF_PORT_OVER_CURRENT);
1277 if(oldval & OHPF_PORTCONNECTED) *mptr |= AROS_WORD2LE(UPSF_PORT_CONNECTION);
1278 if(oldval & OHPF_PORTENABLE) *mptr |= AROS_WORD2LE(UPSF_PORT_ENABLE);
1279 if(oldval & OHPF_LOWSPEED) *mptr |= AROS_WORD2LE(UPSF_PORT_LOW_SPEED);
1280 if(oldval & OHPF_PORTRESET) *mptr |= AROS_WORD2LE(UPSF_PORT_RESET);
1281 if(oldval & OHPF_PORTSUSPEND) *mptr |= AROS_WORD2LE(UPSF_PORT_SUSPEND);
1283 KPRINTF(5, ("OHCI Port %ld (glob. %ld) is %s\n", hciport, idx, oldval & OHPF_LOWSPEED ? "LOWSPEED" : "FULLSPEED"));
1284 KPRINTF(5, ("OHCI Port %ld Status %08lx (%08lx)\n", idx, *mptr, oldval));
1286 mptr++;
1287 if(oldval & OHPF_OVERCURRENTCHG)
1289 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_OVER_CURRENT;
1291 if(oldval & OHPF_RESETCHANGE)
1293 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_RESET;
1295 if(oldval & OHPF_ENABLECHANGE)
1297 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_ENABLE;
1299 if(oldval & OHPF_CONNECTCHANGE)
1301 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_CONNECTION;
1303 if(oldval & OHPF_RESUMEDTX)
1305 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_SUSPEND;
1307 *mptr = AROS_WORD2LE(hc->hc_PortChangeMap[hciport]);
1308 KPRINTF(5, ("OHCI Port %ld Change %08lx\n", idx, *mptr));
1309 return(0);
1312 case HCITYPE_EHCI:
1314 UWORD portreg = EHCI_PORTSC1 + (hciport<<2);
1315 ULONG oldval = READREG32_LE(hc->hc_RegBase, portreg);
1317 *mptr = 0;
1318 if(oldval & EHPF_PORTCONNECTED) *mptr |= AROS_WORD2LE(UPSF_PORT_CONNECTION);
1319 if(oldval & EHPF_PORTENABLE) *mptr |= AROS_WORD2LE(UPSF_PORT_ENABLE|UPSF_PORT_HIGH_SPEED);
1320 if((oldval & (EHPF_LINESTATUS_DM|EHPF_PORTCONNECTED|EHPF_PORTENABLE)) ==
1321 (EHPF_LINESTATUS_DM|EHPF_PORTCONNECTED))
1323 KPRINTF(10, ("EHCI Port %ld is LOWSPEED\n", idx));
1324 // we need to detect low speed devices prior to reset
1325 *mptr |= AROS_WORD2LE(UPSF_PORT_LOW_SPEED);
1328 if(oldval & EHPF_PORTRESET) *mptr |= AROS_WORD2LE(UPSF_PORT_RESET);
1329 if(oldval & EHPF_PORTSUSPEND) *mptr |= AROS_WORD2LE(UPSF_PORT_SUSPEND);
1330 if(oldval & EHPF_PORTPOWER) *mptr |= AROS_WORD2LE(UPSF_PORT_POWER);
1331 if(oldval & EHPM_PORTINDICATOR) *mptr |= AROS_WORD2LE(UPSF_PORT_INDICATOR);
1333 KPRINTF(5, ("EHCI Port %ld Status %08lx\n", idx, *mptr));
1335 mptr++;
1336 if(oldval & EHPF_ENABLECHANGE)
1338 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_ENABLE;
1340 if(oldval & EHPF_CONNECTCHANGE)
1342 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_CONNECTION;
1344 if(oldval & EHPF_RESUMEDTX)
1346 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_SUSPEND|UPSF_PORT_ENABLE;
1348 if(oldval & EHPF_OVERCURRENTCHG)
1350 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_OVER_CURRENT;
1352 *mptr = AROS_WORD2LE(hc->hc_PortChangeMap[hciport]);
1353 WRITEREG32_LE(hc->hc_RegBase, portreg, oldval);
1354 KPRINTF(5, ("EHCI Port %ld Change %08lx\n", idx, *mptr));
1355 return(0);
1359 return(0);
1363 break;
1365 case (URTF_IN|URTF_CLASS|URTF_DEVICE):
1366 switch(req)
1368 case USR_GET_STATUS:
1370 UWORD *mptr = ioreq->iouh_Data;
1371 if(len < sizeof(struct UsbHubStatus))
1373 return(UHIOERR_STALL);
1375 *mptr++ = 0;
1376 *mptr++ = 0;
1377 ioreq->iouh_Actual = 4;
1378 return(0);
1381 case USR_GET_DESCRIPTOR:
1382 switch(val>>8)
1384 case UDT_HUB:
1386 ULONG hubdesclen = 9;
1387 ULONG powergood = 1;
1389 struct UsbHubDesc *uhd = (struct UsbHubDesc *) ioreq->iouh_Data;
1390 KPRINTF(1, ("RH: GetHubDescriptor (%ld)\n", len));
1392 if(unit->hu_RootHubPorts > 7) // needs two bytes for port masks
1394 hubdesclen += 2;
1397 ioreq->iouh_Actual = (len > hubdesclen) ? hubdesclen : len;
1398 CopyMem((APTR) &RHHubDesc, ioreq->iouh_Data, ioreq->iouh_Actual);
1400 if(ioreq->iouh_Length)
1402 uhd->bLength = hubdesclen;
1405 if(ioreq->iouh_Length >= 6)
1407 hc = (struct PCIController *) unit->hu_Controllers.lh_Head;
1408 while(hc->hc_Node.ln_Succ)
1410 if(hc->hc_HCIType == HCITYPE_OHCI)
1412 ULONG localpwgood = (READREG32_LE(hc->hc_RegBase, OHCI_HUBDESCA) & OHAM_POWERGOOD) >> OHAS_POWERGOOD;
1413 if(localpwgood > powergood)
1415 powergood = localpwgood;
1416 KPRINTF(10, ("Increasing power good time to %ld\n", powergood));
1419 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
1422 uhd->bPwrOn2PwrGood = powergood;
1424 if(ioreq->iouh_Length >= hubdesclen)
1426 uhd->bNbrPorts = unit->hu_RootHubPorts;
1427 if(hubdesclen == 9)
1429 uhd->DeviceRemovable = 0;
1430 uhd->PortPwrCtrlMask = (1<<(unit->hu_RootHubPorts+2))-2;
1431 } else {
1432 // each field is now 16 bits wide
1433 uhd->DeviceRemovable = 0;
1434 uhd->PortPwrCtrlMask = 0;
1435 ((UBYTE *) ioreq->iouh_Data)[9] = (1<<(unit->hu_RootHubPorts+2))-2;
1436 ((UBYTE *) ioreq->iouh_Data)[10] = ((1<<(unit->hu_RootHubPorts+2))-2)>>8;
1439 return(0);
1442 default:
1443 KPRINTF(20, ("RH: Unsupported Descriptor %04lx\n", idx));
1445 break;
1449 KPRINTF(20, ("RH: Unsupported command %02lx %02lx %04lx %04lx %04lx!\n", rt, req, idx, val, len));
1450 return(UHIOERR_STALL);
1452 /* \\\ */
1454 /* /// "cmdIntXFerRootHub()" */
1455 WORD cmdIntXFerRootHub(struct IOUsbHWReq *ioreq,
1456 struct PCIUnit *unit,
1457 struct PCIDevice *base)
1459 if((ioreq->iouh_Endpoint != 1) || (!ioreq->iouh_Length))
1461 return(UHIOERR_STALL);
1464 if(unit->hu_RootPortChanges)
1466 KPRINTF(1, ("Immediate Portchange map %04lx\n", unit->hu_RootPortChanges));
1467 if((unit->hu_RootHubPorts < 8) || (ioreq->iouh_Length == 1))
1469 *((UBYTE *) ioreq->iouh_Data) = unit->hu_RootPortChanges;
1470 ioreq->iouh_Actual = 1;
1471 } else {
1472 ((UBYTE *) ioreq->iouh_Data)[0] = unit->hu_RootPortChanges;
1473 ((UBYTE *) ioreq->iouh_Data)[1] = unit->hu_RootPortChanges>>8;
1474 ioreq->iouh_Actual = 2;
1476 unit->hu_RootPortChanges = 0;
1477 return(0);
1479 ioreq->iouh_Req.io_Flags &= ~IOF_QUICK;
1480 Disable();
1481 AddTail(&unit->hu_RHIOQueue, (struct Node *) ioreq);
1482 Enable();
1483 return(RC_DONTREPLY);
1485 /* \\\ */
1487 /* /// "cmdControlXFer()" */
1489 *======================================================================
1490 * cmdControlXFer(ioreq, unit, base)
1491 *======================================================================
1493 * This is the device UHCMD_CONTROLXFER routine.
1495 * First it check if the usb is in proper state and if user passed arguments
1496 * are valid. If everything is ok, the request is linked to queue of
1497 * pending transfer requests.
1501 WORD cmdControlXFer(struct IOUsbHWReq *ioreq,
1502 struct PCIUnit *unit,
1503 struct PCIDevice *base)
1505 struct PCIController *hc;
1507 KPRINTF(10, ("UHCMD_CONTROLXFER ioreq: 0x%p\n", ioreq));
1508 uhwGetUsbState(ioreq, unit, base);
1509 if(!(ioreq->iouh_State & UHSF_OPERATIONAL))
1511 return(UHIOERR_USBOFFLINE);
1513 /* Root hub emulation */
1514 if(ioreq->iouh_DevAddr == unit->hu_RootHubAddr)
1516 return(cmdControlXFerRootHub(ioreq, unit, base));
1519 hc = unit->hu_DevControllers[ioreq->iouh_DevAddr];
1520 if(!hc)
1522 KPRINTF(20, ("No Host controller assigned to device address %ld\n", ioreq->iouh_DevAddr));
1523 return(UHIOERR_HOSTERROR);
1526 ioreq->iouh_Req.io_Flags &= ~IOF_QUICK;
1527 ioreq->iouh_Actual = 0;
1529 Disable();
1530 AddTail(&hc->hc_CtrlXFerQueue, (struct Node *) ioreq);
1531 Enable();
1532 SureCause(base, &hc->hc_CompleteInt);
1534 KPRINTF(10, ("UHCMD_CONTROLXFER processed ioreq: 0x%p\n", ioreq));
1535 return(RC_DONTREPLY);
1537 /* \\\ */
1539 /* /// "cmdBulkXFer()" */
1541 *======================================================================
1542 * cmdBulkXFer(ioreq, unit, base)
1543 *======================================================================
1545 * This is the device UHCMD_BULKXFER routine.
1547 * First it check if the usb is in proper state and if user passed arguments
1548 * are valid. If everything is ok, the request is linked to queue of
1549 * pending transfer requests.
1553 WORD cmdBulkXFer(struct IOUsbHWReq *ioreq,
1554 struct PCIUnit *unit,
1555 struct PCIDevice *base)
1557 struct PCIController *hc;
1559 KPRINTF(10, ("UHCMD_BULKXFER ioreq: 0x%p\n", ioreq));
1560 uhwGetUsbState(ioreq, unit, base);
1561 if(!(ioreq->iouh_State & UHSF_OPERATIONAL))
1563 return(UHIOERR_USBOFFLINE);
1566 if(ioreq->iouh_Flags & UHFF_LOWSPEED)
1568 return(UHIOERR_BADPARAMS);
1571 hc = unit->hu_DevControllers[ioreq->iouh_DevAddr];
1572 if(!hc)
1574 return(UHIOERR_HOSTERROR);
1577 ioreq->iouh_Req.io_Flags &= ~IOF_QUICK;
1578 ioreq->iouh_Actual = 0;
1580 Disable();
1581 AddTail(&hc->hc_BulkXFerQueue, (struct Node *) ioreq);
1582 Enable();
1583 SureCause(base, &hc->hc_CompleteInt);
1585 KPRINTF(10, ("UHCMD_BULKXFER processed ioreq: 0x%p\n", ioreq));
1586 return(RC_DONTREPLY);
1588 /* \\\ */
1590 /* /// "cmdIsoXFer()" */
1592 *======================================================================
1593 * cmdIsoXFer(ioreq, unit, base)
1594 *======================================================================
1596 * This is the device UHCMD_ISOXFER routine.
1598 * First it check if the usb is in proper state and if user passed arguments
1599 * are valid. If everything is ok, the request is linked to queue of
1600 * pending transfer requests.
1604 WORD cmdIsoXFer(struct IOUsbHWReq *ioreq,
1605 struct PCIUnit *unit,
1606 struct PCIDevice *base)
1608 struct PCIController *hc;
1610 KPRINTF(10, ("UHCMD_ISOXFER ioreq: 0x%p\n", ioreq));
1611 uhwGetUsbState(ioreq, unit, base);
1612 if(!(ioreq->iouh_State & UHSF_OPERATIONAL))
1614 return(UHIOERR_USBOFFLINE);
1617 if(ioreq->iouh_Flags & UHFF_LOWSPEED)
1619 return(UHIOERR_BADPARAMS);
1622 hc = unit->hu_DevControllers[ioreq->iouh_DevAddr];
1623 if(!hc)
1625 return(UHIOERR_HOSTERROR);
1628 ioreq->iouh_Req.io_Flags &= ~IOF_QUICK;
1629 ioreq->iouh_Actual = 0;
1631 Disable();
1632 AddTail(&hc->hc_IsoXFerQueue, (struct Node *) ioreq);
1633 Enable();
1634 SureCause(base, &hc->hc_CompleteInt);
1636 KPRINTF(10, ("UHCMD_ISOXFER processed ioreq: 0x%p\n", ioreq));
1637 return(RC_DONTREPLY);
1639 /* \\\ */
1641 /* /// "cmdIntXFer()" */
1643 *======================================================================
1644 * cmdIntXFer(ioreq, unit, base)
1645 *======================================================================
1647 * This is the device UHCMD_INTXFER routine.
1649 * First it check if the usb is in proper state and if user passed arguments
1650 * are valid. If everything is ok, the request is linked to queue of
1651 * pending transfer requests.
1655 WORD cmdIntXFer(struct IOUsbHWReq *ioreq,
1656 struct PCIUnit *unit,
1657 struct PCIDevice *base)
1659 struct PCIController *hc;
1661 KPRINTF(10, ("UHCMD_INTXFER ioreq: 0x%p\n", ioreq));
1662 //uhwDelayMS(1000, unit); /* Wait 200 ms */
1663 uhwGetUsbState(ioreq, unit, base);
1664 if(!(ioreq->iouh_State & UHSF_OPERATIONAL))
1666 return(UHIOERR_USBOFFLINE);
1669 /* Root Hub Emulation */
1670 if(ioreq->iouh_DevAddr == unit->hu_RootHubAddr)
1672 return(cmdIntXFerRootHub(ioreq, unit, base));
1675 hc = unit->hu_DevControllers[ioreq->iouh_DevAddr];
1676 if(!hc)
1678 return(UHIOERR_HOSTERROR);
1681 ioreq->iouh_Req.io_Flags &= ~IOF_QUICK;
1682 ioreq->iouh_Actual = 0;
1684 Disable();
1685 AddTail(&hc->hc_IntXFerQueue, (struct Node *) ioreq);
1686 Enable();
1687 SureCause(base, &hc->hc_CompleteInt);
1689 KPRINTF(10, ("UHCMD_INTXFER processed ioreq: 0x%p\n", ioreq));
1690 return(RC_DONTREPLY);
1692 /* \\\ */
1694 /* /// "cmdFlush()" */
1696 *======================================================================
1697 * cmdFlush(ioreq, base)
1698 *======================================================================
1700 * This is the device CMD_FLUSH routine.
1702 * This routine abort all pending transfer requests.
1706 WORD cmdFlush(struct IOUsbHWReq *ioreq,
1707 struct PCIUnit *unit,
1708 struct PCIDevice *base)
1710 struct IOUsbHWReq *cmpioreq;
1711 struct PCIController *hc;
1712 UWORD devadrep;
1714 KPRINTF(10, ("CMD_FLUSH ioreq: 0x%p\n", ioreq));
1716 Disable();
1717 cmpioreq = (struct IOUsbHWReq *) unit->hu_RHIOQueue.lh_Head;
1718 while(((struct Node *) cmpioreq)->ln_Succ)
1720 Remove(&cmpioreq->iouh_Req.io_Message.mn_Node);
1721 cmpioreq->iouh_Req.io_Error = IOERR_ABORTED;
1722 ReplyMsg(&cmpioreq->iouh_Req.io_Message);
1723 cmpioreq = (struct IOUsbHWReq *) unit->hu_RHIOQueue.lh_Head;
1725 hc = (struct PCIController *) unit->hu_Controllers.lh_Head;
1726 while(hc->hc_Node.ln_Succ)
1728 cmpioreq = (struct IOUsbHWReq *) hc->hc_CtrlXFerQueue.lh_Head;
1729 while(((struct Node *) cmpioreq)->ln_Succ)
1731 Remove(&cmpioreq->iouh_Req.io_Message.mn_Node);
1732 cmpioreq->iouh_Req.io_Error = IOERR_ABORTED;
1733 ReplyMsg(&cmpioreq->iouh_Req.io_Message);
1734 cmpioreq = (struct IOUsbHWReq *) hc->hc_CtrlXFerQueue.lh_Head;
1736 cmpioreq = (struct IOUsbHWReq *) hc->hc_IntXFerQueue.lh_Head;
1737 while(((struct Node *) cmpioreq)->ln_Succ)
1739 Remove(&cmpioreq->iouh_Req.io_Message.mn_Node);
1740 cmpioreq->iouh_Req.io_Error = IOERR_ABORTED;
1741 ReplyMsg(&cmpioreq->iouh_Req.io_Message);
1742 cmpioreq = (struct IOUsbHWReq *) hc->hc_IntXFerQueue.lh_Head;
1744 cmpioreq = (struct IOUsbHWReq *) hc->hc_IsoXFerQueue.lh_Head;
1745 while(((struct Node *) cmpioreq)->ln_Succ)
1747 Remove(&cmpioreq->iouh_Req.io_Message.mn_Node);
1748 cmpioreq->iouh_Req.io_Error = IOERR_ABORTED;
1749 ReplyMsg(&cmpioreq->iouh_Req.io_Message);
1750 cmpioreq = (struct IOUsbHWReq *) hc->hc_IsoXFerQueue.lh_Head;
1752 cmpioreq = (struct IOUsbHWReq *) hc->hc_BulkXFerQueue.lh_Head;
1753 while(((struct Node *) cmpioreq)->ln_Succ)
1755 Remove(&cmpioreq->iouh_Req.io_Message.mn_Node);
1756 cmpioreq->iouh_Req.io_Error = IOERR_ABORTED;
1757 ReplyMsg(&cmpioreq->iouh_Req.io_Message);
1758 cmpioreq = (struct IOUsbHWReq *) hc->hc_BulkXFerQueue.lh_Head;
1760 switch(hc->hc_HCIType)
1762 case HCITYPE_UHCI:
1763 cmpioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head;
1764 while(((struct Node *) cmpioreq)->ln_Succ)
1766 Remove(&cmpioreq->iouh_Req.io_Message.mn_Node);
1767 devadrep = (cmpioreq->iouh_DevAddr<<5) + cmpioreq->iouh_Endpoint + ((cmpioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0);
1768 unit->hu_DevBusyReq[devadrep] = NULL;
1769 uhciFreeQContext(hc, (struct UhciQH *) cmpioreq->iouh_DriverPrivate1);
1770 cmpioreq->iouh_Req.io_Error = IOERR_ABORTED;
1771 ReplyMsg(&cmpioreq->iouh_Req.io_Message);
1772 cmpioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head;
1774 break;
1776 case HCITYPE_EHCI:
1777 cmpioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head;
1778 while(((struct Node *) cmpioreq)->ln_Succ)
1780 ehciFreeAsyncContext(hc, cmpioreq);
1781 cmpioreq->iouh_Req.io_Error = IOERR_ABORTED;
1782 ReplyMsg(&cmpioreq->iouh_Req.io_Message);
1783 cmpioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head;
1785 cmpioreq = (struct IOUsbHWReq *) hc->hc_PeriodicTDQueue.lh_Head;
1786 while(((struct Node *) cmpioreq)->ln_Succ)
1788 ehciFreePeriodicContext(hc, cmpioreq);
1789 cmpioreq->iouh_Req.io_Error = IOERR_ABORTED;
1790 ReplyMsg(&cmpioreq->iouh_Req.io_Message);
1791 cmpioreq = (struct IOUsbHWReq *) hc->hc_PeriodicTDQueue.lh_Head;
1793 break;
1795 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
1797 Enable();
1798 /* Return success
1800 return RC_OK;
1802 /* \\\ */
1804 /* /// "NSD stuff" */
1806 static
1807 const UWORD NSDSupported[] =
1809 CMD_FLUSH, CMD_RESET,
1810 UHCMD_QUERYDEVICE, UHCMD_USBRESET,
1811 UHCMD_USBRESUME, UHCMD_USBSUSPEND,
1812 UHCMD_USBOPER, UHCMD_CONTROLXFER ,
1813 UHCMD_ISOXFER, UHCMD_INTXFER,
1814 UHCMD_BULKXFER,
1815 NSCMD_DEVICEQUERY, 0
1818 WORD cmdNSDeviceQuery(struct IOStdReq *ioreq,
1819 struct PCIUnit *unit,
1820 struct PCIDevice *base)
1822 struct my_NSDeviceQueryResult *query;
1824 query = (struct my_NSDeviceQueryResult *) ioreq->io_Data;
1826 KPRINTF(10, ("NSCMD_DEVICEQUERY ioreq: 0x%p query: 0x%p\n", ioreq, query));
1828 /* NULL ptr?
1829 Enough data?
1830 Valid request?
1832 if((!query) ||
1833 (ioreq->io_Length < sizeof(struct my_NSDeviceQueryResult)) ||
1834 (query->DevQueryFormat != 0) ||
1835 (query->SizeAvailable != 0))
1837 /* Return error. This is special handling, since iorequest is only
1838 guaranteed to be sizeof(struct IOStdReq). If we'd let our
1839 devBeginIO dispatcher return the error, it would trash some
1840 memory past end of the iorequest (ios2_WireError field).
1842 ioreq->io_Error = IOERR_NOCMD;
1843 TermIO((struct IOUsbHWReq *) ioreq, base);
1845 /* Don't reply, we already did.
1847 return RC_DONTREPLY;
1850 ioreq->io_Actual = query->SizeAvailable
1851 = sizeof(struct my_NSDeviceQueryResult);
1852 query->DeviceType = NSDEVTYPE_USBHARDWARE;
1853 query->DeviceSubType = 0;
1854 query->SupportedCommands = NSDSupported;
1856 /* Return success (note that this will NOT poke ios2_WireError).
1858 return RC_OK;
1860 /* \\\ */
1862 /* /// "TermIO()" */
1864 *===========================================================
1865 * TermIO(ioreq, base)
1866 *===========================================================
1868 * Return completed ioreq to sender.
1872 void TermIO(struct IOUsbHWReq *ioreq,
1873 struct PCIDevice *base)
1875 ioreq->iouh_Req.io_Message.mn_Node.ln_Type = NT_FREEMSG;
1877 /* If not quick I/O, reply the message
1879 if(!(ioreq->iouh_Req.io_Flags & IOF_QUICK))
1881 ReplyMsg(&ioreq->iouh_Req.io_Message);
1884 /* \\\ */
1886 /* /// "cmdAbortIO()" */
1887 BOOL cmdAbortIO(struct IOUsbHWReq *ioreq, struct PCIDevice *base)
1889 struct PCIUnit *unit = (struct PCIUnit *) ioreq->iouh_Req.io_Unit;
1890 struct IOUsbHWReq *cmpioreq;
1891 struct PCIController *hc;
1892 UWORD devadrep;
1893 BOOL foundit = FALSE;
1895 KPRINTF(10, ("cmdAbort(%p)\n", ioreq));
1897 Disable();
1898 cmpioreq = (struct IOUsbHWReq *) unit->hu_RHIOQueue.lh_Head;
1899 while(((struct Node *) cmpioreq)->ln_Succ)
1901 if(ioreq == cmpioreq)
1903 Remove(&ioreq->iouh_Req.io_Message.mn_Node);
1904 Enable();
1905 return TRUE;
1907 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
1910 hc = (struct PCIController *) unit->hu_Controllers.lh_Head;
1911 while(hc->hc_Node.ln_Succ)
1913 cmpioreq = (struct IOUsbHWReq *) hc->hc_CtrlXFerQueue.lh_Head;
1914 while(((struct Node *) cmpioreq)->ln_Succ)
1916 if(ioreq == cmpioreq)
1918 foundit = TRUE;
1919 break;
1921 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
1923 if(!foundit)
1925 cmpioreq = (struct IOUsbHWReq *) hc->hc_IntXFerQueue.lh_Head;
1926 while(((struct Node *) cmpioreq)->ln_Succ)
1928 if(ioreq == cmpioreq)
1930 foundit = TRUE;
1931 break;
1933 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
1936 if(!foundit)
1938 cmpioreq = (struct IOUsbHWReq *) hc->hc_IsoXFerQueue.lh_Head;
1939 while(((struct Node *) cmpioreq)->ln_Succ)
1941 if(ioreq == cmpioreq)
1943 foundit = TRUE;
1944 break;
1946 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
1949 if(!foundit)
1951 cmpioreq = (struct IOUsbHWReq *) hc->hc_BulkXFerQueue.lh_Head;
1952 while(((struct Node *) cmpioreq)->ln_Succ)
1954 if(ioreq == cmpioreq)
1956 foundit = TRUE;
1957 break;
1959 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
1962 if(!foundit)
1964 // IOReq is probably pending in some transfer structure
1965 devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint + ((ioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0);
1966 switch(hc->hc_HCIType)
1968 case HCITYPE_UHCI:
1969 cmpioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head;
1970 while(((struct Node *) cmpioreq)->ln_Succ)
1972 if(ioreq == cmpioreq)
1974 foundit = TRUE;
1975 unit->hu_DevBusyReq[devadrep] = NULL;
1976 uhciFreeQContext(hc, (struct UhciQH *) ioreq->iouh_DriverPrivate1);
1977 break;
1979 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
1981 break;
1983 case HCITYPE_OHCI:
1984 cmpioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head;
1985 while(((struct Node *) cmpioreq)->ln_Succ)
1987 if(ioreq == cmpioreq)
1990 * Request's ED is in use by the HC, as well as its TDs and
1991 * data buffers.
1992 * Schedule abort on the HC driver and reply the request
1993 * only when done. However return success.
1995 ioreq->iouh_Req.io_Error = IOERR_ABORTED;
1996 ohciAbortRequest(hc, ioreq);
1997 Enable();
1998 return TRUE;
2000 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
2002 break;
2004 case HCITYPE_EHCI:
2005 cmpioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head;
2006 while(((struct Node *) cmpioreq)->ln_Succ)
2008 if(ioreq == cmpioreq)
2011 * CHECKME: Perhaps immediate freeing can cause issues similar to OHCI.
2012 * Should synchronized abort routine be implemented here too ?
2014 ehciFreeAsyncContext(hc, ioreq);
2015 Enable();
2016 ioreq->iouh_Req.io_Error = IOERR_ABORTED;
2017 TermIO(ioreq, base);
2018 return TRUE;
2020 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
2022 cmpioreq = (struct IOUsbHWReq *) hc->hc_PeriodicTDQueue.lh_Head;
2023 while(((struct Node *) cmpioreq)->ln_Succ)
2025 if(ioreq == cmpioreq)
2027 ehciFreePeriodicContext(hc, ioreq);
2028 Enable();
2029 ioreq->iouh_Req.io_Error = IOERR_ABORTED;
2030 TermIO(ioreq, base);
2031 return TRUE;
2033 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
2035 break;
2039 if(foundit)
2041 Remove(&ioreq->iouh_Req.io_Message.mn_Node);
2042 break;
2044 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
2046 Enable();
2048 if (foundit)
2050 ioreq->iouh_Req.io_Error = IOERR_ABORTED;
2051 TermIO(ioreq, base);
2053 else
2055 KPRINTF(20, ("WARNING, could not abort unknown IOReq %p\n", ioreq));
2057 return(foundit);
2059 /* \\\ */
2061 /* /// "uhwCheckRootHubChanges()" */
2062 void uhwCheckRootHubChanges(struct PCIUnit *unit)
2064 struct IOUsbHWReq *ioreq;
2066 if(unit->hu_RootPortChanges && unit->hu_RHIOQueue.lh_Head->ln_Succ)
2068 KPRINTF(1, ("Portchange map %04lx\n", unit->hu_RootPortChanges));
2069 Disable();
2070 ioreq = (struct IOUsbHWReq *) unit->hu_RHIOQueue.lh_Head;
2071 while(((struct Node *) ioreq)->ln_Succ)
2073 Remove(&ioreq->iouh_Req.io_Message.mn_Node);
2074 if((unit->hu_RootHubPorts < 8) || (ioreq->iouh_Length == 1))
2076 *((UBYTE *) ioreq->iouh_Data) = unit->hu_RootPortChanges;
2077 ioreq->iouh_Actual = 1;
2078 } else {
2079 ((UBYTE *) ioreq->iouh_Data)[0] = unit->hu_RootPortChanges;
2080 ((UBYTE *) ioreq->iouh_Data)[1] = unit->hu_RootPortChanges>>8;
2081 ioreq->iouh_Actual = 2;
2083 ReplyMsg(&ioreq->iouh_Req.io_Message);
2084 ioreq = (struct IOUsbHWReq *) unit->hu_RHIOQueue.lh_Head;
2086 unit->hu_RootPortChanges = 0;
2087 Enable();
2090 /* \\\ */
2092 /* /// "uhwCheckSpecialCtrlTransfers()" */
2093 void uhwCheckSpecialCtrlTransfers(struct PCIController *hc, struct IOUsbHWReq *ioreq)
2095 struct PCIUnit *unit = hc->hc_Unit;
2097 /* Clear Feature(Endpoint halt) */
2098 if((ioreq->iouh_SetupData.bmRequestType == (URTF_STANDARD|URTF_ENDPOINT)) &&
2099 (ioreq->iouh_SetupData.bRequest == USR_CLEAR_FEATURE) &&
2100 (ioreq->iouh_SetupData.wValue == AROS_WORD2LE(UFS_ENDPOINT_HALT)))
2102 KPRINTF(10, ("Resetting toggle bit for endpoint %ld\n", AROS_WORD2LE(ioreq->iouh_SetupData.wIndex) & 0xf));
2103 unit->hu_DevDataToggle[(ioreq->iouh_DevAddr<<5)|(AROS_WORD2LE(ioreq->iouh_SetupData.wIndex) & 0xf)|((AROS_WORD2LE(ioreq->iouh_SetupData.wIndex) & 0x80)>>3)] = 0;
2105 else if((ioreq->iouh_SetupData.bmRequestType == (URTF_STANDARD|URTF_DEVICE)) &&
2106 (ioreq->iouh_SetupData.bRequest == USR_SET_ADDRESS))
2108 /* Set Address -> clear all endpoints */
2109 ULONG epnum;
2110 ULONG adr = AROS_WORD2BE(ioreq->iouh_SetupData.wValue)>>3;
2111 KPRINTF(10, ("Resetting toggle bits for device address %ld\n", adr>>5));
2112 for(epnum = 0; epnum < 31; epnum++)
2114 unit->hu_DevDataToggle[adr+epnum] = 0;
2116 // transfer host controller ownership
2117 unit->hu_DevControllers[ioreq->iouh_DevAddr] = NULL;
2118 unit->hu_DevControllers[adr>>5] = hc;
2120 else if((ioreq->iouh_SetupData.bmRequestType == (URTF_CLASS|URTF_OTHER)) &&
2121 (ioreq->iouh_SetupData.bRequest == USR_SET_FEATURE) &&
2122 (ioreq->iouh_SetupData.wValue == AROS_WORD2LE(UFS_PORT_RESET)))
2124 // a hub will be enumerating a device on this host controller soon!
2125 KPRINTF(10, ("Hub RESET caught, assigning Dev0 to %p!\n", hc));
2126 unit->hu_DevControllers[0] = hc;
2129 /* \\\ */
2131 /* /// "uhwNakTimeoutInt()" */
2132 AROS_INTH1(uhwNakTimeoutInt, struct PCIUnit *, unit)
2134 AROS_INTFUNC_INIT
2136 struct PCIDevice *base = unit->hu_Device;
2137 struct PCIController *hc;
2138 struct IOUsbHWReq *ioreq;
2139 struct UhciQH *uqh;
2140 struct UhciTD *utd;
2141 struct EhciQH *eqh;
2142 UWORD devadrep;
2143 UWORD cnt;
2144 ULONG linkelem;
2145 ULONG ctrlstatus;
2146 BOOL causeint;
2148 KPRINTF(1, ("Enter NakTimeoutInt(0x%p)\n", unit));
2150 // check for port status change for UHCI and frame rollovers and NAK Timeouts
2151 hc = (struct PCIController *) unit->hu_Controllers.lh_Head;
2152 while(hc->hc_Node.ln_Succ)
2154 if (!(hc->hc_Flags & HCF_ONLINE))
2156 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
2157 continue;
2159 causeint = FALSE;
2160 switch(hc->hc_HCIType)
2162 case HCITYPE_UHCI:
2164 ULONG framecnt;
2165 uhciUpdateFrameCounter(hc);
2166 framecnt = hc->hc_FrameCounter;
2168 // NakTimeout
2169 ioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head;
2170 while(((struct Node *) ioreq)->ln_Succ)
2172 if(ioreq->iouh_Flags & UHFF_NAKTIMEOUT)
2174 uqh = (struct UhciQH *) ioreq->iouh_DriverPrivate1;
2175 if(uqh)
2177 KPRINTF(1, ("Examining IOReq=%p with UQH=%p\n", ioreq, uqh));
2178 devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint + ((ioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0);
2179 linkelem = READMEM32_LE(&uqh->uqh_Element);
2180 if(linkelem & UHCI_TERMINATE)
2182 KPRINTF(1, ("UQH terminated %08lx\n", linkelem));
2183 if(framecnt > unit->hu_NakTimeoutFrame[devadrep])
2185 // give the thing the chance to exit gracefully
2186 KPRINTF(20, ("Terminated? NAK timeout %ld > %ld, IOReq=%p\n", framecnt, unit->hu_NakTimeoutFrame[devadrep], ioreq));
2187 causeint = TRUE;
2189 } else {
2190 utd = (struct UhciTD *) (((IPTR)linkelem & UHCI_PTRMASK) - hc->hc_PCIVirtualAdjust - 16); // struct UhciTD starts 16 before physical TD
2191 ctrlstatus = READMEM32_LE(&utd->utd_CtrlStatus);
2192 if(ctrlstatus & UTCF_ACTIVE)
2194 if(framecnt > unit->hu_NakTimeoutFrame[devadrep])
2196 // give the thing the chance to exit gracefully
2197 KPRINTF(20, ("NAK timeout %ld > %ld, IOReq=%p\n", framecnt, unit->hu_NakTimeoutFrame[devadrep], ioreq));
2198 ctrlstatus &= ~UTCF_ACTIVE;
2199 WRITEMEM32_LE(&utd->utd_CtrlStatus, ctrlstatus);
2200 causeint = TRUE;
2202 } else {
2203 if(framecnt > unit->hu_NakTimeoutFrame[devadrep])
2205 // give the thing the chance to exit gracefully
2206 KPRINTF(20, ("Terminated? NAK timeout %ld > %ld, IOReq=%p\n", framecnt, unit->hu_NakTimeoutFrame[devadrep], ioreq));
2207 causeint = TRUE;
2213 ioreq = (struct IOUsbHWReq *) ((struct Node *) ioreq)->ln_Succ;
2216 uhciCheckPortStatusChange(hc);
2217 break;
2220 case HCITYPE_OHCI:
2222 ULONG framecnt;
2223 ohciUpdateFrameCounter(hc);
2224 framecnt = hc->hc_FrameCounter;
2225 // NakTimeout
2226 ioreq = (struct IOUsbHWReq *) hc->hc_TDQueue.lh_Head;
2227 while(((struct Node *) ioreq)->ln_Succ)
2229 // Remember the successor because ohciAbortRequest() will move the request to another list
2230 struct IOUsbHWReq *succ = (struct IOUsbHWReq *)ioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
2232 if(ioreq->iouh_Flags & UHFF_NAKTIMEOUT)
2234 KPRINTF(1, ("Examining IOReq=%p with OED=%p\n", ioreq, ioreq->iouh_DriverPrivate1));
2235 if (ioreq->iouh_DriverPrivate1)
2237 KPRINTF(1, ("CTRL=%04lx, CMD=%01lx, F=%ld, hccaDH=%08lx, hcDH=%08lx, CH=%08lx, CCH=%08lx, IntEn=%08lx\n",
2238 READREG32_LE(hc->hc_RegBase, OHCI_CONTROL),
2239 READREG32_LE(hc->hc_RegBase, OHCI_CMDSTATUS),
2240 READREG32_LE(hc->hc_RegBase, OHCI_FRAMECOUNT),
2241 READMEM32_LE(&hc->hc_OhciHCCA->oha_DoneHead),
2242 READREG32_LE(hc->hc_RegBase, OHCI_DONEHEAD),
2243 READREG32_LE(hc->hc_RegBase, OHCI_CTRL_HEAD_ED),
2244 READREG32_LE(hc->hc_RegBase, OHCI_CTRL_ED),
2245 READREG32_LE(hc->hc_RegBase, OHCI_INTEN)));
2247 devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint + ((ioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0);
2248 if(framecnt > unit->hu_NakTimeoutFrame[devadrep])
2250 // give the thing the chance to exit gracefully
2251 KPRINTF(200, ("HC 0x%p NAK timeout %ld > %ld, IOReq=%p\n", hc, framecnt, unit->hu_NakTimeoutFrame[devadrep], ioreq));
2252 ioreq->iouh_Req.io_Error = UHIOERR_NAKTIMEOUT;
2253 ohciAbortRequest(hc, ioreq);
2257 ioreq = succ;
2259 break;
2262 case HCITYPE_EHCI:
2264 ULONG framecnt;
2265 ehciUpdateFrameCounter(hc);
2266 framecnt = hc->hc_FrameCounter;
2267 // NakTimeout
2268 for(cnt = 0; cnt < 1; cnt++)
2270 ioreq = (struct IOUsbHWReq *) (cnt ? hc->hc_PeriodicTDQueue.lh_Head : hc->hc_TDQueue.lh_Head);
2271 while(((struct Node *) ioreq)->ln_Succ)
2273 if(ioreq->iouh_Flags & UHFF_NAKTIMEOUT)
2275 eqh = (struct EhciQH *) ioreq->iouh_DriverPrivate1;
2276 if(eqh)
2278 KPRINTF(1, ("Examining IOReq=%p with EQH=%p\n", ioreq, eqh));
2279 devadrep = (ioreq->iouh_DevAddr<<5) + ioreq->iouh_Endpoint + ((ioreq->iouh_Dir == UHDIR_IN) ? 0x10 : 0);
2280 ctrlstatus = READMEM32_LE(&eqh->eqh_CtrlStatus);
2281 if(ctrlstatus & ETCF_ACTIVE)
2283 if(framecnt > unit->hu_NakTimeoutFrame[devadrep])
2285 // give the thing the chance to exit gracefully
2286 KPRINTF(20, ("NAK timeout %ld > %ld, IOReq=%p\n", framecnt, unit->hu_NakTimeoutFrame[devadrep], ioreq));
2287 ctrlstatus &= ~ETCF_ACTIVE;
2288 ctrlstatus |= ETSF_HALTED;
2289 WRITEMEM32_LE(&eqh->eqh_CtrlStatus, ctrlstatus);
2290 causeint = TRUE;
2292 } else {
2293 if(ctrlstatus & ETCF_READYINTEN)
2295 KPRINTF(10, ("INT missed?!? Manually causing it! %08lx, IOReq=%p\n",
2296 ctrlstatus, ioreq));
2297 causeint = TRUE;
2302 ioreq = (struct IOUsbHWReq *) ((struct Node *) ioreq)->ln_Succ;
2305 break;
2309 if(causeint)
2311 SureCause(base, &hc->hc_CompleteInt);
2314 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
2317 uhwCheckRootHubChanges(unit);
2319 unit->hu_NakTimeoutReq.tr_time.tv_micro = 150*1000;
2320 SendIO((APTR) &unit->hu_NakTimeoutReq);
2322 KPRINTF(1, ("Exit NakTimeoutInt(0x%p)\n", unit));
2324 return FALSE;
2326 AROS_INTFUNC_EXIT
2328 /* \\\ */