1 /* uhwcmd.c - pciuhci.device based on work by Chris Hodges */
3 #include <devices/usb_hub.h>
4 #include <proto/utility.h>
5 #include <proto/exec.h>
6 #include <proto/timer.h>
12 /* we cannot use AROS_WORD2LE in struct initializer */
14 #define WORD2LE(w) (UWORD)(((w) >> 8) & 0x00FF) | (((w) << 8) & 0xFF00)
16 #define WORD2LE(w) (w)
20 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 };
22 const struct UsbStdCfgDesc RHCfgDesc
= { 9, UDT_CONFIGURATION
, WORD2LE(9+9+7), 1, 1, 3, USCAF_ONE
|USCAF_SELF_POWERED
, 0 };
23 const struct UsbStdIfDesc RHIfDesc
= { 9, UDT_INTERFACE
, 0, 0, 1, HUB_CLASSCODE
, 0, 0, 4 };
24 const struct UsbStdEPDesc RHEPDesc
= { 7, UDT_ENDPOINT
, URTF_IN
|1, USEAF_INTERRUPT
, WORD2LE(8), 255 };
25 const struct UsbHubDesc RHHubDesc
= { 9, // 0 Number of bytes in this descriptor, including this byte
26 UDT_HUB
, // 1 Descriptor Type, value: 29H for hub descriptor
27 0, // 2 Number of downstream facing ports that this hub supports
28 WORD2LE(UHCF_INDIVID_POWER
|UHCF_INDIVID_OVP
), // 3 wHubCharacteristics
29 0, // 5 bPwrOn2PwrGood
30 1, // 6 bHubContrCurrent
31 1, // 7 DeviceRemovable (size is variable)
32 0 // x PortPwrCtrlMask (size is variable)
35 const CONST_STRPTR RHStrings
[] = { "Chris Hodges", "PCI Root Hub Unit x", "Standard Config", "Hub interface" };
37 /* /// "SureCause()" */
38 void SureCause(struct PCIDevice
*base
, struct Interrupt
*interrupt
)
40 /* this is a workaround for the original Cause() function missing tailed calls */
43 if((interrupt
->is_Node
.ln_Type
== NT_SOFTINT
) || (interrupt
->is_Node
.ln_Type
== NT_USER
))
46 interrupt
->is_Node
.ln_Type
= NT_USER
;
50 interrupt
->is_Node
.ln_Type
= NT_SOFTINT
;
51 Forbid(); // make sure code is not interrupted by other tasks
53 AROS_INTC1(interrupt
->is_Code
, interrupt
->is_Data
);
56 } while(interrupt
->is_Node
.ln_Type
!= NT_SOFTINT
);
57 interrupt
->is_Node
.ln_Type
= NT_INTERRUPT
;
63 /* /// "uhwOpenTimer()" */
64 BOOL
uhwOpenTimer(struct PCIUnit
*unit
, struct PCIDevice
*base
)
66 if((unit
->hu_MsgPort
= CreateMsgPort()))
68 if((unit
->hu_TimerReq
= (struct timerequest
*) CreateIORequest(unit
->hu_MsgPort
, sizeof(struct timerequest
))))
70 if(!OpenDevice("timer.device", UNIT_MICROHZ
, (struct IORequest
*) unit
->hu_TimerReq
, 0))
72 unit
->hu_TimerReq
->tr_node
.io_Message
.mn_Node
.ln_Name
= "PCI hardware";
73 unit
->hu_TimerReq
->tr_node
.io_Command
= TR_ADDREQUEST
;
74 KPRINTF(1, ("opened timer device\n"));
77 DeleteIORequest((struct IORequest
*) unit
->hu_TimerReq
);
78 unit
->hu_TimerReq
= NULL
;
80 DeleteMsgPort(unit
->hu_MsgPort
);
81 unit
->hu_MsgPort
= NULL
;
83 KPRINTF(5, ("failed to open timer.device\n"));
88 /* /// "uhwDelayMS()" */
89 void uhwDelayMS(ULONG milli
, struct PCIUnit
*unit
)
91 unit
->hu_TimerReq
->tr_time
.tv_secs
= 0;
92 unit
->hu_TimerReq
->tr_time
.tv_micro
= milli
* 1000;
93 DoIO((struct IORequest
*) unit
->hu_TimerReq
);
97 /* /// "uhwDelayMicro()" */
98 void uhwDelayMicro(ULONG micro
, struct PCIUnit
*unit
)
100 unit
->hu_TimerReq
->tr_time
.tv_secs
= 0;
101 unit
->hu_TimerReq
->tr_time
.tv_micro
= micro
;
102 DoIO((struct IORequest
*) unit
->hu_TimerReq
);
106 /* /// "uhwCloseTimer()" */
107 void uhwCloseTimer(struct PCIUnit
*unit
, struct PCIDevice
*base
)
111 if(unit
->hu_TimerReq
)
113 KPRINTF(1, ("closing timer.device\n"));
114 CloseDevice((APTR
) unit
->hu_TimerReq
);
115 DeleteIORequest((struct IORequest
*) unit
->hu_TimerReq
);
116 unit
->hu_TimerReq
= NULL
;
118 DeleteMsgPort(unit
->hu_MsgPort
);
119 unit
->hu_MsgPort
= NULL
;
124 /* /// "Open_Unit()" */
125 struct Unit
* Open_Unit(struct IOUsbHWReq
*ioreq
,
127 struct PCIDevice
*base
)
129 struct PCIUnit
*unit
= NULL
;
131 if(!base
->hd_ScanDone
)
133 base
->hd_ScanDone
= TRUE
;
139 unit
= (struct PCIUnit
*) base
->hd_Units
.lh_Head
;
140 while(((struct Node
*) unit
)->ln_Succ
)
142 if(unit
->hu_UnitNo
== unitnr
)
146 unit
= (struct PCIUnit
*) ((struct Node
*) unit
)->ln_Succ
;
148 if(!((struct Node
*) unit
)->ln_Succ
)
150 KPRINTF(20, ("Unit %ld does not exist!\n", unitnr
));
153 if(unit
->hu_UnitAllocated
)
155 ioreq
->iouh_Req
.io_Error
= IOERR_UNITBUSY
;
156 KPRINTF(5, ("Unit %ld already open!\n", unitnr
));
160 if(uhwOpenTimer(unit
, base
))
163 if(pciAllocUnit(unit
)) // hardware self test
165 unit
->hu_UnitAllocated
= TRUE
;
166 unit
->hu_NakTimeoutInt
.is_Node
.ln_Type
= NT_INTERRUPT
;
167 unit
->hu_NakTimeoutInt
.is_Node
.ln_Name
= "PCI NakTimeout";
168 unit
->hu_NakTimeoutInt
.is_Node
.ln_Pri
= -16;
169 unit
->hu_NakTimeoutInt
.is_Data
= unit
;
170 unit
->hu_NakTimeoutInt
.is_Code
= (VOID_FUNC
)uhwNakTimeoutInt
;
172 CopyMem(unit
->hu_TimerReq
, &unit
->hu_NakTimeoutReq
, sizeof(struct timerequest
));
173 unit
->hu_NakTimeoutReq
.tr_node
.io_Message
.mn_ReplyPort
= &unit
->hu_NakTimeoutMsgPort
;
174 unit
->hu_NakTimeoutMsgPort
.mp_Node
.ln_Type
= NT_MSGPORT
;
175 unit
->hu_NakTimeoutMsgPort
.mp_Flags
= PA_SOFTINT
;
176 unit
->hu_NakTimeoutMsgPort
.mp_SigTask
= &unit
->hu_NakTimeoutInt
;
177 NEWLIST(&unit
->hu_NakTimeoutMsgPort
.mp_MsgList
);
178 Cause(&unit
->hu_NakTimeoutInt
);
179 return(&unit
->hu_Unit
);
181 ioreq
->iouh_Req
.io_Error
= IOERR_SELFTEST
;
182 KPRINTF(20, ("Hardware allocation failure!\n"));
184 uhwCloseTimer(unit
, base
);
190 /* /// "Close_Unit()" */
191 void Close_Unit(struct PCIDevice
*base
,
192 struct PCIUnit
*unit
,
193 struct IOUsbHWReq
*ioreq
)
195 /* Disable all interrupts */
196 unit
->hu_NakTimeoutMsgPort
.mp_Flags
= PA_IGNORE
;
197 unit
->hu_NakTimeoutInt
.is_Node
.ln_Type
= NT_SOFTINT
;
198 AbortIO((APTR
) &unit
->hu_NakTimeoutReq
);
202 uhwCloseTimer(unit
, base
);
203 unit
->hu_UnitAllocated
= FALSE
;
207 /* /// "uhwGetUsbState()" */
208 UWORD
uhwGetUsbState(struct IOUsbHWReq
*ioreq
,
209 struct PCIUnit
*unit
,
210 struct PCIDevice
*base
)
212 return(ioreq
->iouh_State
= UHSF_OPERATIONAL
);
216 /* /// "cmdReset()" */
218 *======================================================================
219 * cmdReset(ioreq, unit, base)
220 *======================================================================
222 * This is the device CMD_RESET routine.
224 * Resets the whole USB hardware. Goes into USBOperational mode right
225 * after. Must NOT be called from an interrupt.
229 WORD
cmdReset(struct IOUsbHWReq
*ioreq
,
230 struct PCIUnit
*unit
,
231 struct PCIDevice
*base
)
233 KPRINTF(10, ("CMD_RESET ioreq: 0x%p\n", ioreq
));
236 uhwGetUsbState(ioreq
, unit
, base
);
238 if(ioreq
->iouh_State
& UHSF_OPERATIONAL
)
242 return UHIOERR_USBOFFLINE
;
246 /* /// "cmdUsbReset()" */
248 *======================================================================
249 * cmdUsbReset(ioreq, unit, base)
250 *======================================================================
252 * This is the device UHCMD_USBRESET routine.
254 * Resets the USB bus. Goes into USBOperational mode right after. Must
255 * NOT be called from an interrupt.
259 WORD
cmdUsbReset(struct IOUsbHWReq
*ioreq
,
260 struct PCIUnit
*unit
,
261 struct PCIDevice
*base
)
263 KPRINTF(10, ("UHCMD_USBRESET ioreq: 0x%p\n", ioreq
));
266 uhwGetUsbState(ioreq
, unit
, base
);
268 unit
->hu_RootHubAddr
= 0;
270 if(ioreq
->iouh_State
& UHSF_OPERATIONAL
)
274 return UHIOERR_USBOFFLINE
;
278 /* /// "cmdUsbResume()" */
280 *======================================================================
281 * cmdUsbResume(ioreq, unit, base)
282 *======================================================================
284 * This is the device UHCMD_USBRESUME routine.
286 * Tries to resume from USBSuspend mode into USBOperational.
287 * Must NOT be called from an interrupt.
291 WORD
cmdUsbResume(struct IOUsbHWReq
*ioreq
,
292 struct PCIUnit
*unit
,
293 struct PCIDevice
*base
)
295 KPRINTF(10, ("UHCMD_USBRESUME ioreq: 0x%p\n", ioreq
));
298 uhwGetUsbState(ioreq
, unit
, base
);
299 if(ioreq
->iouh_State
& UHSF_OPERATIONAL
)
303 return UHIOERR_USBOFFLINE
;
307 /* /// "cmdUsbSuspend()" */
309 *======================================================================
310 * cmdUsbSuspend(ioreq, unit, base)
311 *======================================================================
313 * This is the device UHCMD_USBSUSPEND routine.
315 * Sets the USB into USBSuspend mode.
316 * Must NOT be called from an interrupt.
320 WORD
cmdUsbSuspend(struct IOUsbHWReq
*ioreq
,
321 struct PCIUnit
*unit
,
322 struct PCIDevice
*base
)
324 KPRINTF(10, ("UHCMD_USBSUSPEND ioreq: 0x%p\n", ioreq
));
327 uhwGetUsbState(ioreq
, unit
, base
);
328 if(ioreq
->iouh_State
& UHSF_SUSPENDED
)
332 return UHIOERR_USBOFFLINE
;
336 /* /// "cmdUsbOper()" */
338 *======================================================================
339 * cmdUsbOper(ioreq, unit, base)
340 *======================================================================
342 * This is the device UHCMD_USBOPER routine.
344 * Sets the USB into USBOperational mode.
345 * Must NOT be called from an interrupt.
349 WORD
cmdUsbOper(struct IOUsbHWReq
*ioreq
,
350 struct PCIUnit
*unit
,
351 struct PCIDevice
*base
)
353 KPRINTF(10, ("UHCMD_USBOPER ioreq: 0x%p\n", ioreq
));
356 uhwGetUsbState(ioreq
, unit
, base
);
357 if(ioreq
->iouh_State
& UHSF_OPERATIONAL
)
361 return UHIOERR_USBOFFLINE
;
365 /* /// "cmdQueryDevice()" */
367 *======================================================================
368 * cmdQueryDevice(ioreq, unit, base)
369 *======================================================================
371 * This is the device UHCMD_QUERYDEVICE routine.
373 * Returns information about the hardware.
377 WORD
cmdQueryDevice(struct IOUsbHWReq
*ioreq
,
378 struct PCIUnit
*unit
,
379 struct PCIDevice
*base
)
381 struct TagItem
*taglist
= (struct TagItem
*) ioreq
->iouh_Data
;
385 KPRINTF(10, ("UHCMD_QUERYDEVICE ioreq: 0x%p, taglist: 0x%p\n", ioreq
, taglist
));
387 if((tag
= FindTagItem(UHA_State
, taglist
)))
389 *((ULONG
*) tag
->ti_Data
) = (ULONG
) uhwGetUsbState(ioreq
, unit
, base
);
392 if((tag
= FindTagItem(UHA_Manufacturer
, taglist
)))
394 *((STRPTR
*) tag
->ti_Data
) = "Chris Hodges";
397 if((tag
= FindTagItem(UHA_ProductName
, taglist
)))
399 *((STRPTR
*) tag
->ti_Data
) = "PCI UHCI USB 1.1 Host Controller";
402 if((tag
= FindTagItem(UHA_Description
, taglist
)))
404 *((STRPTR
*) tag
->ti_Data
) = "Generic adaptive host controller driver for PCI cards";
407 if((tag
= FindTagItem(UHA_Copyright
, taglist
)))
409 *((STRPTR
*) tag
->ti_Data
) ="©2007-2009 Chris Hodges";
412 if((tag
= FindTagItem(UHA_Version
, taglist
)))
414 *((ULONG
*) tag
->ti_Data
) = VERSION_NUMBER
;
417 if((tag
= FindTagItem(UHA_Revision
, taglist
)))
419 *((ULONG
*) tag
->ti_Data
) = REVISION_NUMBER
;
422 if((tag
= FindTagItem(UHA_DriverVersion
, taglist
)))
424 *((ULONG
*) tag
->ti_Data
) = 0x220;
427 if((tag
= FindTagItem(UHA_Capabilities
, taglist
)))
429 *((ULONG
*) tag
->ti_Data
) = UHCF_USB20
;
432 ioreq
->iouh_Actual
= count
;
437 /* /// "cmdControlXFerRootHub()" */
438 WORD
cmdControlXFerRootHub(struct IOUsbHWReq
*ioreq
,
439 struct PCIUnit
*unit
,
440 struct PCIDevice
*base
)
442 struct PCIController
*hc
;
443 struct PCIController
*chc
;
444 UWORD rt
= ioreq
->iouh_SetupData
.bmRequestType
;
445 UWORD req
= ioreq
->iouh_SetupData
.bRequest
;
446 UWORD idx
= AROS_WORD2LE(ioreq
->iouh_SetupData
.wIndex
);
447 UWORD val
= AROS_WORD2LE(ioreq
->iouh_SetupData
.wValue
);
448 UWORD len
= AROS_WORD2LE(ioreq
->iouh_SetupData
.wLength
);
450 ULONG numports
= unit
->hu_RootHubPorts
;
458 if(ioreq
->iouh_Endpoint
) {
459 return(UHIOERR_STALL
);
462 if(len
!= ioreq
->iouh_Length
) {
463 KPRINTF(20, ("RH: Len (%ld != %ld) mismatch!\n", len
!= ioreq
->iouh_Length
));
464 return(UHIOERR_STALL
);
468 case (URTF_STANDARD
|URTF_DEVICE
):
470 case USR_SET_ADDRESS
:
471 KPRINTF(1, ("RH: SetAddress = %ld\n", val
));
472 unit
->hu_RootHubAddr
= val
;
473 ioreq
->iouh_Actual
= len
;
476 case USR_SET_CONFIGURATION
:
477 KPRINTF(1, ("RH: SetConfiguration=%ld\n", val
));
478 ioreq
->iouh_Actual
= len
;
483 case (URTF_IN
|URTF_STANDARD
|URTF_DEVICE
):
485 case USR_GET_DESCRIPTOR
:
488 KPRINTF(1, ("RH: GetDeviceDescriptor (%ld)\n", len
));
489 ioreq
->iouh_Actual
= (len
> sizeof(struct UsbStdDevDesc
)) ? sizeof(struct UsbStdDevDesc
) : len
;
490 CopyMem((APTR
) &RHDevDesc
, ioreq
->iouh_Data
, ioreq
->iouh_Actual
);
493 case UDT_CONFIGURATION
: {
495 KPRINTF(1, ("RH: GetConfigDescriptor (%ld)\n", len
));
496 CopyMem((APTR
) &RHCfgDesc
, tmpbuf
, 9);
497 CopyMem((APTR
) &RHIfDesc
, &tmpbuf
[9], 9);
498 CopyMem((APTR
) &RHEPDesc
, &tmpbuf
[9+9], 7);
499 ioreq
->iouh_Actual
= (len
> 9+9+7) ? 9+9+7 : len
;
500 CopyMem(tmpbuf
, ioreq
->iouh_Data
, ioreq
->iouh_Actual
);
505 if(val
& 0xff) /* get lang array */
507 CONST_STRPTR source
= NULL
;
508 UWORD
*mptr
= ioreq
->iouh_Data
;
510 KPRINTF(1, ("RH: GetString %04lx (%ld)\n", val
, len
));
511 if((val
& 0xff) > 4) /* index too high? */
513 return(UHIOERR_STALL
);
515 source
= RHStrings
[(val
& 0xff)-1];
518 ioreq
->iouh_Actual
= 2;
523 source
= RHStrings
[(val
& 0xff)-1];
524 *mptr
++ = AROS_WORD2BE((slen
<<9)|UDT_STRING
);
525 while(ioreq
->iouh_Actual
+1 < len
)
527 // special hack for unit number in root hub string
528 if(((val
& 0xff) == 2) && (source
[1] == 0)) {
529 *mptr
++ = AROS_WORD2LE('0' + unit
->hu_UnitNo
);
531 *mptr
++ = AROS_WORD2LE(*source
);
534 ioreq
->iouh_Actual
+= 2;
541 UWORD
*mptr
= ioreq
->iouh_Data
;
542 KPRINTF(1, ("RH: GetLangArray %04lx (%ld)\n", val
, len
));
544 ioreq
->iouh_Actual
= 2;
545 mptr
[0] = AROS_WORD2BE((4<<8)|UDT_STRING
);
548 ioreq
->iouh_Actual
+= 2;
549 mptr
[1] = AROS_WORD2LE(0x0409);
556 KPRINTF(1, ("RH: Unsupported Descriptor %04lx\n", idx
));
560 case USR_GET_CONFIGURATION
:
562 KPRINTF(1, ("RH: GetConfiguration\n"));
563 ((UBYTE
*) ioreq
->iouh_Data
)[0] = 1;
564 ioreq
->iouh_Actual
= len
;
571 case (URTF_CLASS
|URTF_OTHER
):
573 case USR_SET_FEATURE
:
574 if((!idx
) && (idx
> numports
)) {
575 KPRINTF(20, ("Port %ld out of range\n", idx
));
576 return(UHIOERR_STALL
);
578 chc
= unit
->hu_PortMap11
[idx
- 1];
580 // if(unit->hu_EhciOwned[idx - 1])
582 // hc = unit->hu_PortMap20[idx - 1];
583 // hciport = idx - 1;
586 hciport
= unit
->hu_PortNum11
[idx
- 1];
588 // 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"));
591 portreg
= hciport
? UHCI_PORT2STSCTRL
: UHCI_PORT1STSCTRL
;
592 oldval
= READIO16_LE(hc
->hc_RegBase
, portreg
) & ~(UHPF_ENABLECHANGE
|UHPF_CONNECTCHANGE
); // these are clear-on-write!
596 /* case UFS_PORT_CONNECTION: not possible */
597 case UFS_PORT_ENABLE
:
598 KPRINTF(200, ("Enabling Port (%s)\n", newval
& UHPF_PORTENABLE
? "already" : "ok"));
599 newval
|= UHPF_PORTENABLE
;
603 case UFS_PORT_SUSPEND
:
604 newval
|= UHPF_PORTSUSPEND
;
605 hc
->hc_PortChangeMap
[hciport
] |= UPSF_PORT_SUSPEND
; // manually fake suspend change
609 /* case UFS_PORT_OVER_CURRENT: not possible */
611 KPRINTF(200, ("Resetting Port (%s)\n", newval
& UHPF_PORTRESET
? "already" : "ok"));
613 // this is an ugly blocking workaround to the inability of UHCI to clear reset automatically
614 newval
&= ~(UHPF_PORTSUSPEND
|UHPF_PORTENABLE
);
615 newval
|= UHPF_PORTRESET
;
616 WRITEIO16_LE(hc
->hc_RegBase
, portreg
, newval
);
617 uhwDelayMS(25, unit
);
619 newval
= READIO16_LE(hc
->hc_RegBase
, portreg
) & ~(UHPF_ENABLECHANGE
|UHPF_CONNECTCHANGE
|UHPF_PORTSUSPEND
|UHPF_PORTENABLE
);
620 KPRINTF(200, ("Reset=%s\n", newval
& UHPF_PORTRESET
? "GOOD" : "BAD!"));
622 // like windows does it
623 newval
&= ~UHPF_PORTRESET
;
624 WRITEIO16_LE(hc
->hc_RegBase
, portreg
, newval
);
625 uhwDelayMicro(50, unit
);
627 newval
= READIO16_LE(hc
->hc_RegBase
, portreg
) & ~(UHPF_ENABLECHANGE
|UHPF_CONNECTCHANGE
|UHPF_PORTSUSPEND
);
628 KPRINTF(200, ("Reset=%s\n", newval
& UHPF_PORTRESET
? "BAD!" : "GOOD"));
629 newval
&= ~(UHPF_PORTSUSPEND
|UHPF_PORTRESET
);
630 newval
|= UHPF_PORTENABLE
;
631 WRITEIO16_LE(hc
->hc_RegBase
, portreg
, newval
);
632 hc
->hc_PortChangeMap
[hciport
] |= UPSF_PORT_RESET
|UPSF_PORT_ENABLE
; // manually fake reset change
637 newval
= READIO16_LE(hc
->hc_RegBase
, portreg
);
638 } while(--cnt
&& (!(newval
& UHPF_PORTENABLE
)));
641 KPRINTF(10, ("Enabled after %ld ticks\n", 100-cnt
));
643 KPRINTF(20, ("Port refuses to be enabled!\n"));
644 return(UHIOERR_HOSTERROR
);
647 // make enumeration possible
648 unit
->hu_DevControllers
[0] = hc
;
653 KPRINTF(10, ("Powering Port\n"));
654 // ignore for UHCI, is always powered
658 /* case UFS_PORT_LOW_SPEED: not possible
659 case UFS_C_PORT_CONNECTION:
660 case UFS_C_PORT_ENABLE:
661 case UFS_C_PORT_SUSPEND:
662 case UFS_C_PORT_OVER_CURRENT:
663 case UFS_C_PORT_RESET: */
667 KPRINTF(5, ("Port %ld SET_FEATURE %04lx->%04lx\n", idx
, oldval
, newval
));
668 WRITEIO16_LE(hc
->hc_RegBase
, portreg
, newval
);
671 break; /* USR_SET_FEATURE */
673 case USR_CLEAR_FEATURE
:
674 if((!idx
) && (idx
> numports
)) {
675 KPRINTF(20, ("Port %ld out of range\n", idx
));
676 return(UHIOERR_STALL
);
678 // if(unit->hu_EhciOwned[idx - 1])
680 // hc = unit->hu_PortMap20[idx - 1];
681 // hciport = idx - 1;
683 hc
= unit
->hu_PortMap11
[idx
- 1];
684 hciport
= unit
->hu_PortNum11
[idx
- 1];
686 // 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"));
689 portreg
= hciport
? UHCI_PORT2STSCTRL
: UHCI_PORT1STSCTRL
;
690 oldval
= READIO16_LE(hc
->hc_RegBase
, portreg
) & ~(UHPF_ENABLECHANGE
|UHPF_CONNECTCHANGE
); // these are clear-on-write!
693 case UFS_PORT_ENABLE
:
694 KPRINTF(10, ("Disabling Port (%s)\n", newval
& UHPF_PORTENABLE
? "ok" : "already"));
695 newval
&= ~UHPF_PORTENABLE
;
697 // disable enumeration
698 unit
->hu_DevControllers
[0] = NULL
;
701 case UFS_PORT_SUSPEND
:
702 newval
&= ~UHPF_PORTSUSPEND
;
706 case UFS_PORT_POWER
: // ignore for UHCI, there's no power control here
707 KPRINTF(10, ("Disabling Power\n"));
708 KPRINTF(10, ("Disabling Port (%s)\n", newval
& UHPF_PORTENABLE
? "ok" : "already"));
709 newval
&= ~UHPF_PORTENABLE
;
713 case UFS_C_PORT_CONNECTION
:
714 newval
|= UHPF_CONNECTCHANGE
; // clear-on-write!
715 hc
->hc_PortChangeMap
[hciport
] &= ~UPSF_PORT_CONNECTION
;
719 case UFS_C_PORT_ENABLE
:
720 newval
|= UHPF_ENABLECHANGE
; // clear-on-write!
721 hc
->hc_PortChangeMap
[hciport
] &= ~UPSF_PORT_ENABLE
;
725 case UFS_C_PORT_SUSPEND
: // ignore for UHCI, there's no bit indicating this
726 hc
->hc_PortChangeMap
[hciport
] &= ~UPSF_PORT_SUSPEND
; // manually fake suspend change clearing
730 case UFS_C_PORT_OVER_CURRENT
: // ignore for UHCI, there's no bit indicating this
731 hc
->hc_PortChangeMap
[hciport
] &= ~UPSF_PORT_OVER_CURRENT
; // manually fake over current clearing
735 case UFS_C_PORT_RESET
: // ignore for UHCI, there's no bit indicating this
736 hc
->hc_PortChangeMap
[hciport
] &= ~UPSF_PORT_RESET
; // manually fake reset change clearing
742 KPRINTF(5, ("Port %ld CLEAR_FEATURE %04lx->%04lx\n", idx
, oldval
, newval
));
743 WRITEIO16_LE(hc
->hc_RegBase
, portreg
, newval
);
744 if(hc
->hc_PortChangeMap
[hciport
]) {
745 unit
->hu_RootPortChanges
|= 1UL<<idx
;
747 unit
->hu_RootPortChanges
&= ~(1UL<<idx
);
756 case (URTF_IN
|URTF_CLASS
|URTF_OTHER
):
758 case USR_GET_STATUS
: {
759 UWORD
*mptr
= ioreq
->iouh_Data
;
760 if(len
!= sizeof(struct UsbPortStatus
))
762 return(UHIOERR_STALL
);
764 if((!idx
) && (idx
> numports
))
766 KPRINTF(20, ("Port %ld out of range\n", idx
));
767 return(UHIOERR_STALL
);
769 // if(unit->hu_EhciOwned[idx - 1])
771 // hc = unit->hu_PortMap20[idx - 1];
772 // hciport = idx - 1;
774 hc
= unit
->hu_PortMap11
[idx
- 1];
775 hciport
= unit
->hu_PortNum11
[idx
- 1];
779 UWORD portreg
= hciport
? UHCI_PORT2STSCTRL
: UHCI_PORT1STSCTRL
;
780 UWORD oldval
= READIO16_LE(hc
->hc_RegBase
, portreg
);
781 *mptr
= AROS_WORD2LE(UPSF_PORT_POWER
);
782 if(oldval
& UHPF_PORTCONNECTED
) *mptr
|= AROS_WORD2LE(UPSF_PORT_CONNECTION
);
783 if(oldval
& UHPF_PORTENABLE
) *mptr
|= AROS_WORD2LE(UPSF_PORT_ENABLE
);
784 if(oldval
& UHPF_LOWSPEED
) *mptr
|= AROS_WORD2LE(UPSF_PORT_LOW_SPEED
);
785 if(oldval
& UHPF_PORTRESET
) *mptr
|= AROS_WORD2LE(UPSF_PORT_RESET
);
786 if(oldval
& UHPF_PORTSUSPEND
) *mptr
|= AROS_WORD2LE(UPSF_PORT_SUSPEND
);
788 KPRINTF(200, ("UHCI Port %ld is %s\n", idx
, oldval
& UHPF_LOWSPEED
? "LOWSPEED" : "FULLSPEED"));
789 KPRINTF(200, ("UHCI Port %ld Status %08lx\n", idx
, *mptr
));
792 if(oldval
& UHPF_ENABLECHANGE
) {
793 hc
->hc_PortChangeMap
[hciport
] |= UPSF_PORT_ENABLE
;
795 if(oldval
& UHPF_CONNECTCHANGE
) {
796 hc
->hc_PortChangeMap
[hciport
] |= UPSF_PORT_CONNECTION
;
798 if(oldval
& UHPF_RESUMEDTX
) {
799 hc
->hc_PortChangeMap
[hciport
] |= UPSF_PORT_SUSPEND
|UPSF_PORT_ENABLE
;
801 *mptr
= AROS_WORD2LE(hc
->hc_PortChangeMap
[hciport
]);
802 WRITEIO16_LE(hc
->hc_RegBase
, portreg
, oldval
);
803 KPRINTF(5, ("UHCI Port %ld Change %08lx\n", idx
, *mptr
));
810 case (URTF_IN
|URTF_CLASS
|URTF_DEVICE
):
815 UWORD
*mptr
= ioreq
->iouh_Data
;
816 if(len
< sizeof(struct UsbHubStatus
))
818 return(UHIOERR_STALL
);
822 ioreq
->iouh_Actual
= 4;
826 case USR_GET_DESCRIPTOR
:
831 ULONG hubdesclen
= 9;
834 struct UsbHubDesc
*uhd
= (struct UsbHubDesc
*) ioreq
->iouh_Data
;
835 KPRINTF(1, ("RH: GetHubDescriptor (%ld)\n", len
));
837 if(unit
->hu_RootHubPorts
> 7) // needs two bytes for port masks
842 ioreq
->iouh_Actual
= (len
> hubdesclen
) ? hubdesclen
: len
;
843 CopyMem((APTR
) &RHHubDesc
, ioreq
->iouh_Data
, ioreq
->iouh_Actual
);
845 if(ioreq
->iouh_Length
)
847 uhd
->bLength
= hubdesclen
;
850 if(ioreq
->iouh_Length
>= 6)
852 uhd
->bPwrOn2PwrGood
= powergood
;
855 if(ioreq
->iouh_Length
>= hubdesclen
)
857 uhd
->bNbrPorts
= unit
->hu_RootHubPorts
;
860 uhd
->DeviceRemovable
= 0;
861 uhd
->PortPwrCtrlMask
= (1<<(unit
->hu_RootHubPorts
+2))-2;
863 // each field is now 16 bits wide
864 uhd
->DeviceRemovable
= 0;
865 uhd
->PortPwrCtrlMask
= 0;
866 ((UBYTE
*) ioreq
->iouh_Data
)[9] = (1<<(unit
->hu_RootHubPorts
+2))-2;
867 ((UBYTE
*) ioreq
->iouh_Data
)[10] = ((1<<(unit
->hu_RootHubPorts
+2))-2)>>8;
874 KPRINTF(20, ("RH: Unsupported Descriptor %04lx\n", idx
));
880 KPRINTF(20, ("RH: Unsupported command %02lx %02lx %04lx %04lx %04lx!\n", rt
, req
, idx
, val
, len
));
881 return(UHIOERR_STALL
);
885 /* /// "cmdIntXFerRootHub()" */
886 WORD
cmdIntXFerRootHub(struct IOUsbHWReq
*ioreq
,
887 struct PCIUnit
*unit
,
888 struct PCIDevice
*base
)
890 if((ioreq
->iouh_Endpoint
!= 1) || (!ioreq
->iouh_Length
))
892 return(UHIOERR_STALL
);
895 if(unit
->hu_RootPortChanges
)
897 KPRINTF(1, ("Immediate Portchange map %04lx\n", unit
->hu_RootPortChanges
));
898 if((unit
->hu_RootHubPorts
< 8) || (ioreq
->iouh_Length
== 1))
900 *((UBYTE
*) ioreq
->iouh_Data
) = unit
->hu_RootPortChanges
;
901 ioreq
->iouh_Actual
= 1;
903 ((UBYTE
*) ioreq
->iouh_Data
)[0] = unit
->hu_RootPortChanges
;
904 ((UBYTE
*) ioreq
->iouh_Data
)[1] = unit
->hu_RootPortChanges
>>8;
905 ioreq
->iouh_Actual
= 2;
907 unit
->hu_RootPortChanges
= 0;
910 ioreq
->iouh_Req
.io_Flags
&= ~IOF_QUICK
;
912 AddTail(&unit
->hu_RHIOQueue
, (struct Node
*) ioreq
);
914 return(RC_DONTREPLY
);
918 /* /// "cmdControlXFer()" */
920 *======================================================================
921 * cmdControlXFer(ioreq, unit, base)
922 *======================================================================
924 * This is the device UHCMD_CONTROLXFER routine.
926 * First it check if the usb is in proper state and if user passed arguments
927 * are valid. If everything is ok, the request is linked to queue of
928 * pending transfer requests.
932 WORD
cmdControlXFer(struct IOUsbHWReq
*ioreq
,
933 struct PCIUnit
*unit
,
934 struct PCIDevice
*base
)
936 struct PCIController
*hc
;
938 KPRINTF(10, ("UHCMD_CONTROLXFER ioreq: 0x%p\n", ioreq
));
939 uhwGetUsbState(ioreq
, unit
, base
);
940 if(!(ioreq
->iouh_State
& UHSF_OPERATIONAL
))
942 return(UHIOERR_USBOFFLINE
);
944 /* Root hub emulation */
945 if(ioreq
->iouh_DevAddr
== unit
->hu_RootHubAddr
)
947 return(cmdControlXFerRootHub(ioreq
, unit
, base
));
950 hc
= unit
->hu_DevControllers
[ioreq
->iouh_DevAddr
];
953 KPRINTF(20, ("No Host controller assigned to device address %ld\n", ioreq
->iouh_DevAddr
));
954 return(UHIOERR_HOSTERROR
);
957 ioreq
->iouh_Req
.io_Flags
&= ~IOF_QUICK
;
958 ioreq
->iouh_Actual
= 0;
961 AddTail(&hc
->hc_CtrlXFerQueue
, (struct Node
*) ioreq
);
963 SureCause(base
, &hc
->hc_CompleteInt
);
965 KPRINTF(10, ("UHCMD_CONTROLXFER processed ioreq: 0x%p\n", ioreq
));
966 return(RC_DONTREPLY
);
970 /* /// "cmdBulkXFer()" */
972 *======================================================================
973 * cmdBulkXFer(ioreq, unit, base)
974 *======================================================================
976 * This is the device UHCMD_BULKXFER routine.
978 * First it check if the usb is in proper state and if user passed arguments
979 * are valid. If everything is ok, the request is linked to queue of
980 * pending transfer requests.
984 WORD
cmdBulkXFer(struct IOUsbHWReq
*ioreq
,
985 struct PCIUnit
*unit
,
986 struct PCIDevice
*base
)
988 struct PCIController
*hc
;
990 KPRINTF(10, ("UHCMD_BULKXFER ioreq: 0x%p\n", ioreq
));
991 uhwGetUsbState(ioreq
, unit
, base
);
992 if(!(ioreq
->iouh_State
& UHSF_OPERATIONAL
))
994 return(UHIOERR_USBOFFLINE
);
997 if(ioreq
->iouh_Flags
& UHFF_LOWSPEED
)
999 return(UHIOERR_BADPARAMS
);
1002 hc
= unit
->hu_DevControllers
[ioreq
->iouh_DevAddr
];
1005 return(UHIOERR_HOSTERROR
);
1008 ioreq
->iouh_Req
.io_Flags
&= ~IOF_QUICK
;
1009 ioreq
->iouh_Actual
= 0;
1012 AddTail(&hc
->hc_BulkXFerQueue
, (struct Node
*) ioreq
);
1014 SureCause(base
, &hc
->hc_CompleteInt
);
1016 KPRINTF(10, ("UHCMD_BULKXFER processed ioreq: 0x%p\n", ioreq
));
1017 return(RC_DONTREPLY
);
1021 /* /// "cmdIsoXFer()" */
1023 *======================================================================
1024 * cmdIsoXFer(ioreq, unit, base)
1025 *======================================================================
1027 * This is the device UHCMD_ISOXFER routine.
1029 * First it check if the usb is in proper state and if user passed arguments
1030 * are valid. If everything is ok, the request is linked to queue of
1031 * pending transfer requests.
1035 WORD
cmdIsoXFer(struct IOUsbHWReq
*ioreq
,
1036 struct PCIUnit
*unit
,
1037 struct PCIDevice
*base
)
1039 struct PCIController
*hc
;
1041 KPRINTF(10, ("UHCMD_ISOXFER ioreq: 0x%p\n", ioreq
));
1042 uhwGetUsbState(ioreq
, unit
, base
);
1043 if(!(ioreq
->iouh_State
& UHSF_OPERATIONAL
))
1045 return(UHIOERR_USBOFFLINE
);
1048 if(ioreq
->iouh_Flags
& UHFF_LOWSPEED
)
1050 return(UHIOERR_BADPARAMS
);
1053 hc
= unit
->hu_DevControllers
[ioreq
->iouh_DevAddr
];
1056 return(UHIOERR_HOSTERROR
);
1059 ioreq
->iouh_Req
.io_Flags
&= ~IOF_QUICK
;
1060 ioreq
->iouh_Actual
= 0;
1063 AddTail(&hc
->hc_IsoXFerQueue
, (struct Node
*) ioreq
);
1065 SureCause(base
, &hc
->hc_CompleteInt
);
1067 KPRINTF(10, ("UHCMD_ISOXFER processed ioreq: 0x%p\n", ioreq
));
1068 return(RC_DONTREPLY
);
1072 /* /// "cmdIntXFer()" */
1074 *======================================================================
1075 * cmdIntXFer(ioreq, unit, base)
1076 *======================================================================
1078 * This is the device UHCMD_INTXFER routine.
1080 * First it check if the usb is in proper state and if user passed arguments
1081 * are valid. If everything is ok, the request is linked to queue of
1082 * pending transfer requests.
1086 WORD
cmdIntXFer(struct IOUsbHWReq
*ioreq
,
1087 struct PCIUnit
*unit
,
1088 struct PCIDevice
*base
)
1090 struct PCIController
*hc
;
1092 KPRINTF(10, ("UHCMD_INTXFER ioreq: 0x%p\n", ioreq
));
1093 //uhwDelayMS(1000, unit); /* Wait 200 ms */
1094 uhwGetUsbState(ioreq
, unit
, base
);
1095 if(!(ioreq
->iouh_State
& UHSF_OPERATIONAL
))
1097 return(UHIOERR_USBOFFLINE
);
1100 /* Root Hub Emulation */
1101 if(ioreq
->iouh_DevAddr
== unit
->hu_RootHubAddr
)
1103 return(cmdIntXFerRootHub(ioreq
, unit
, base
));
1106 hc
= unit
->hu_DevControllers
[ioreq
->iouh_DevAddr
];
1109 return(UHIOERR_HOSTERROR
);
1112 ioreq
->iouh_Req
.io_Flags
&= ~IOF_QUICK
;
1113 ioreq
->iouh_Actual
= 0;
1116 AddTail(&hc
->hc_IntXFerQueue
, (struct Node
*) ioreq
);
1118 SureCause(base
, &hc
->hc_CompleteInt
);
1120 KPRINTF(10, ("UHCMD_INTXFER processed ioreq: 0x%p\n", ioreq
));
1121 return(RC_DONTREPLY
);
1125 /* /// "cmdFlush()" */
1127 *======================================================================
1128 * cmdFlush(ioreq, base)
1129 *======================================================================
1131 * This is the device CMD_FLUSH routine.
1133 * This routine abort all pending transfer requests.
1137 WORD
cmdFlush(struct IOUsbHWReq
*ioreq
,
1138 struct PCIUnit
*unit
,
1139 struct PCIDevice
*base
)
1141 struct IOUsbHWReq
*cmpioreq
;
1142 struct PCIController
*hc
;
1145 KPRINTF(10, ("CMD_FLUSH ioreq: 0x%p\n", ioreq
));
1148 cmpioreq
= (struct IOUsbHWReq
*) unit
->hu_RHIOQueue
.lh_Head
;
1149 while(((struct Node
*) cmpioreq
)->ln_Succ
) {
1150 Remove(&cmpioreq
->iouh_Req
.io_Message
.mn_Node
);
1151 cmpioreq
->iouh_Req
.io_Error
= IOERR_ABORTED
;
1152 ReplyMsg(&cmpioreq
->iouh_Req
.io_Message
);
1153 cmpioreq
= (struct IOUsbHWReq
*) unit
->hu_RHIOQueue
.lh_Head
;
1156 hc
= (struct PCIController
*) unit
->hu_Controllers
.lh_Head
;
1157 while(hc
->hc_Node
.ln_Succ
) {
1158 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_CtrlXFerQueue
.lh_Head
;
1159 while(((struct Node
*) cmpioreq
)->ln_Succ
)
1161 Remove(&cmpioreq
->iouh_Req
.io_Message
.mn_Node
);
1162 cmpioreq
->iouh_Req
.io_Error
= IOERR_ABORTED
;
1163 ReplyMsg(&cmpioreq
->iouh_Req
.io_Message
);
1164 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_CtrlXFerQueue
.lh_Head
;
1166 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_IntXFerQueue
.lh_Head
;
1167 while(((struct Node
*) cmpioreq
)->ln_Succ
)
1169 Remove(&cmpioreq
->iouh_Req
.io_Message
.mn_Node
);
1170 cmpioreq
->iouh_Req
.io_Error
= IOERR_ABORTED
;
1171 ReplyMsg(&cmpioreq
->iouh_Req
.io_Message
);
1172 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_IntXFerQueue
.lh_Head
;
1174 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_IsoXFerQueue
.lh_Head
;
1175 while(((struct Node
*) cmpioreq
)->ln_Succ
)
1177 Remove(&cmpioreq
->iouh_Req
.io_Message
.mn_Node
);
1178 cmpioreq
->iouh_Req
.io_Error
= IOERR_ABORTED
;
1179 ReplyMsg(&cmpioreq
->iouh_Req
.io_Message
);
1180 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_IsoXFerQueue
.lh_Head
;
1182 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_BulkXFerQueue
.lh_Head
;
1183 while(((struct Node
*) cmpioreq
)->ln_Succ
)
1185 Remove(&cmpioreq
->iouh_Req
.io_Message
.mn_Node
);
1186 cmpioreq
->iouh_Req
.io_Error
= IOERR_ABORTED
;
1187 ReplyMsg(&cmpioreq
->iouh_Req
.io_Message
);
1188 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_BulkXFerQueue
.lh_Head
;
1192 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_TDQueue
.lh_Head
;
1193 while(((struct Node
*) cmpioreq
)->ln_Succ
) {
1194 Remove(&cmpioreq
->iouh_Req
.io_Message
.mn_Node
);
1195 devadrep
= (cmpioreq
->iouh_DevAddr
<<5) + cmpioreq
->iouh_Endpoint
+ ((cmpioreq
->iouh_Dir
== UHDIR_IN
) ? 0x10 : 0);
1196 unit
->hu_DevBusyReq
[devadrep
] = NULL
;
1197 uhciFreeQContext(hc
, (struct UhciQH
*) cmpioreq
->iouh_DriverPrivate1
);
1198 cmpioreq
->iouh_Req
.io_Error
= IOERR_ABORTED
;
1199 ReplyMsg(&cmpioreq
->iouh_Req
.io_Message
);
1200 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_TDQueue
.lh_Head
;
1202 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
1211 /* /// "cmdAbortIO()" */
1212 BOOL
cmdAbortIO(struct IOUsbHWReq
*ioreq
, struct PCIDevice
*base
)
1214 struct PCIUnit
*unit
= (struct PCIUnit
*) ioreq
->iouh_Req
.io_Unit
;
1215 struct IOUsbHWReq
*cmpioreq
;
1216 struct PCIController
*hc
;
1218 BOOL foundit
= FALSE
;
1220 KPRINTF(10, ("cmdAbort(%p)\n", ioreq
));
1223 cmpioreq
= (struct IOUsbHWReq
*) unit
->hu_RHIOQueue
.lh_Head
;
1224 while(((struct Node
*) cmpioreq
)->ln_Succ
)
1226 if(ioreq
== cmpioreq
)
1228 Remove(&ioreq
->iouh_Req
.io_Message
.mn_Node
);
1232 cmpioreq
= (struct IOUsbHWReq
*) cmpioreq
->iouh_Req
.io_Message
.mn_Node
.ln_Succ
;
1235 hc
= (struct PCIController
*) unit
->hu_Controllers
.lh_Head
;
1236 while(hc
->hc_Node
.ln_Succ
)
1238 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_CtrlXFerQueue
.lh_Head
;
1239 while(((struct Node
*) cmpioreq
)->ln_Succ
)
1241 if(ioreq
== cmpioreq
)
1246 cmpioreq
= (struct IOUsbHWReq
*) cmpioreq
->iouh_Req
.io_Message
.mn_Node
.ln_Succ
;
1250 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_IntXFerQueue
.lh_Head
;
1251 while(((struct Node
*) cmpioreq
)->ln_Succ
)
1253 if(ioreq
== cmpioreq
)
1258 cmpioreq
= (struct IOUsbHWReq
*) cmpioreq
->iouh_Req
.io_Message
.mn_Node
.ln_Succ
;
1263 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_IsoXFerQueue
.lh_Head
;
1264 while(((struct Node
*) cmpioreq
)->ln_Succ
)
1266 if(ioreq
== cmpioreq
)
1271 cmpioreq
= (struct IOUsbHWReq
*) cmpioreq
->iouh_Req
.io_Message
.mn_Node
.ln_Succ
;
1276 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_BulkXFerQueue
.lh_Head
;
1277 while(((struct Node
*) cmpioreq
)->ln_Succ
)
1279 if(ioreq
== cmpioreq
)
1284 cmpioreq
= (struct IOUsbHWReq
*) cmpioreq
->iouh_Req
.io_Message
.mn_Node
.ln_Succ
;
1289 // IOReq is probably pending in some transfer structure
1290 devadrep
= (ioreq
->iouh_DevAddr
<<5) + ioreq
->iouh_Endpoint
+ ((ioreq
->iouh_Dir
== UHDIR_IN
) ? 0x10 : 0);
1292 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_TDQueue
.lh_Head
;
1293 while(((struct Node
*) cmpioreq
)->ln_Succ
) {
1294 if(ioreq
== cmpioreq
) {
1296 unit
->hu_DevBusyReq
[devadrep
] = NULL
;
1297 uhciFreeQContext(hc
, (struct UhciQH
*) ioreq
->iouh_DriverPrivate1
);
1300 cmpioreq
= (struct IOUsbHWReq
*) cmpioreq
->iouh_Req
.io_Message
.mn_Node
.ln_Succ
;
1305 Remove(&ioreq
->iouh_Req
.io_Message
.mn_Node
);
1308 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
1313 ioreq
->iouh_Req
.io_Error
= IOERR_ABORTED
;
1315 ioreq
->iouh_Req
.io_Message
.mn_Node
.ln_Type
= NT_FREEMSG
;
1317 /* If not quick I/O, reply the message */
1318 if(!(ioreq
->iouh_Req
.io_Flags
& IOF_QUICK
)) {
1319 ReplyMsg(&ioreq
->iouh_Req
.io_Message
);
1322 KPRINTF(20, ("WARNING, could not abort unknown IOReq %p\n", ioreq
));
1328 /* /// "uhwCheckRootHubChanges()" */
1329 void uhwCheckRootHubChanges(struct PCIUnit
*unit
)
1331 struct IOUsbHWReq
*ioreq
;
1333 if(unit
->hu_RootPortChanges
&& unit
->hu_RHIOQueue
.lh_Head
->ln_Succ
)
1335 KPRINTF(1, ("Portchange map %04lx\n", unit
->hu_RootPortChanges
));
1337 ioreq
= (struct IOUsbHWReq
*) unit
->hu_RHIOQueue
.lh_Head
;
1338 while(((struct Node
*) ioreq
)->ln_Succ
)
1340 Remove(&ioreq
->iouh_Req
.io_Message
.mn_Node
);
1341 if((unit
->hu_RootHubPorts
< 8) || (ioreq
->iouh_Length
== 1))
1343 *((UBYTE
*) ioreq
->iouh_Data
) = unit
->hu_RootPortChanges
;
1344 ioreq
->iouh_Actual
= 1;
1346 ((UBYTE
*) ioreq
->iouh_Data
)[0] = unit
->hu_RootPortChanges
;
1347 ((UBYTE
*) ioreq
->iouh_Data
)[1] = unit
->hu_RootPortChanges
>>8;
1348 ioreq
->iouh_Actual
= 2;
1350 ReplyMsg(&ioreq
->iouh_Req
.io_Message
);
1351 ioreq
= (struct IOUsbHWReq
*) unit
->hu_RHIOQueue
.lh_Head
;
1353 unit
->hu_RootPortChanges
= 0;
1359 /* /// "uhwCheckSpecialCtrlTransfers()" */
1360 void uhwCheckSpecialCtrlTransfers(struct PCIController
*hc
, struct IOUsbHWReq
*ioreq
)
1362 struct PCIUnit
*unit
= hc
->hc_Unit
;
1364 /* Clear Feature(Endpoint halt) */
1365 if((ioreq
->iouh_SetupData
.bmRequestType
== (URTF_STANDARD
|URTF_ENDPOINT
)) &&
1366 (ioreq
->iouh_SetupData
.bRequest
== USR_CLEAR_FEATURE
) &&
1367 (ioreq
->iouh_SetupData
.wValue
== AROS_WORD2LE(UFS_ENDPOINT_HALT
)))
1369 KPRINTF(10, ("Resetting toggle bit for endpoint %ld\n", AROS_WORD2LE(ioreq
->iouh_SetupData
.wIndex
) & 0xf));
1370 unit
->hu_DevDataToggle
[(ioreq
->iouh_DevAddr
<<5)|(AROS_WORD2LE(ioreq
->iouh_SetupData
.wIndex
) & 0xf)|((AROS_WORD2LE(ioreq
->iouh_SetupData
.wIndex
) & 0x80)>>3)] = 0;
1372 else if((ioreq
->iouh_SetupData
.bmRequestType
== (URTF_STANDARD
|URTF_DEVICE
)) &&
1373 (ioreq
->iouh_SetupData
.bRequest
== USR_SET_ADDRESS
))
1375 /* Set Address -> clear all endpoints */
1377 ULONG adr
= AROS_WORD2BE(ioreq
->iouh_SetupData
.wValue
)>>3;
1378 KPRINTF(10, ("Resetting toggle bits for device address %ld\n", adr
>>5));
1379 for(epnum
= 0; epnum
< 31; epnum
++)
1381 unit
->hu_DevDataToggle
[adr
+epnum
] = 0;
1383 // transfer host controller ownership
1384 unit
->hu_DevControllers
[ioreq
->iouh_DevAddr
] = NULL
;
1385 unit
->hu_DevControllers
[adr
>>5] = hc
;
1387 else if((ioreq
->iouh_SetupData
.bmRequestType
== (URTF_CLASS
|URTF_OTHER
)) &&
1388 (ioreq
->iouh_SetupData
.bRequest
== USR_SET_FEATURE
) &&
1389 (ioreq
->iouh_SetupData
.wValue
== AROS_WORD2LE(UFS_PORT_RESET
)))
1391 // a hub will be enumerating a device on this host controller soon!
1392 KPRINTF(10, ("Hub RESET caught, assigning Dev0 to %p!\n", hc
));
1393 unit
->hu_DevControllers
[0] = hc
;
1398 /* /// "uhwNakTimeoutInt()" */
1399 AROS_INTH1(uhwNakTimeoutInt
, struct PCIUnit
*, unit
)
1403 struct PCIDevice
*base
= unit
->hu_Device
;
1404 struct PCIController
*hc
;
1405 struct IOUsbHWReq
*ioreq
;
1413 KPRINTF(1, ("Enter NakTimeoutInt(0x%p)\n", unit
));
1415 // check for port status change for UHCI and frame rollovers and NAK Timeouts
1416 hc
= (struct PCIController
*) unit
->hu_Controllers
.lh_Head
;
1417 while(hc
->hc_Node
.ln_Succ
) {
1418 if (!(hc
->hc_Flags
& HCF_ONLINE
)) {
1419 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
1424 uhciUpdateFrameCounter(hc
);
1425 framecnt
= hc
->hc_FrameCounter
;
1428 ioreq
= (struct IOUsbHWReq
*) hc
->hc_TDQueue
.lh_Head
;
1429 while(((struct Node
*) ioreq
)->ln_Succ
) {
1430 if(ioreq
->iouh_Flags
& UHFF_NAKTIMEOUT
) {
1431 uqh
= (struct UhciQH
*) ioreq
->iouh_DriverPrivate1
;
1433 KPRINTF(1, ("Examining IOReq=%p with UQH=%p\n", ioreq
, uqh
));
1434 devadrep
= (ioreq
->iouh_DevAddr
<<5) + ioreq
->iouh_Endpoint
+ ((ioreq
->iouh_Dir
== UHDIR_IN
) ? 0x10 : 0);
1435 linkelem
= READMEM32_LE(&uqh
->uqh_Element
);
1436 if(linkelem
& UHCI_TERMINATE
) {
1437 KPRINTF(1, ("UQH terminated %08lx\n", linkelem
));
1438 if(framecnt
> unit
->hu_NakTimeoutFrame
[devadrep
]) {
1439 // give the thing the chance to exit gracefully
1440 KPRINTF(20, ("Terminated? NAK timeout %ld > %ld, IOReq=%p\n", framecnt
, unit
->hu_NakTimeoutFrame
[devadrep
], ioreq
));
1444 utd
= (struct UhciTD
*) (((IPTR
)linkelem
& UHCI_PTRMASK
) - hc
->hc_PCIVirtualAdjust
- 16); // struct UhciTD starts 16 before physical TD
1445 ctrlstatus
= READMEM32_LE(&utd
->utd_CtrlStatus
);
1446 if(ctrlstatus
& UTCF_ACTIVE
) {
1447 if(framecnt
> unit
->hu_NakTimeoutFrame
[devadrep
]) {
1448 // give the thing the chance to exit gracefully
1449 KPRINTF(20, ("NAK timeout %ld > %ld, IOReq=%p\n", framecnt
, unit
->hu_NakTimeoutFrame
[devadrep
], ioreq
));
1450 ctrlstatus
&= ~UTCF_ACTIVE
;
1451 WRITEMEM32_LE(&utd
->utd_CtrlStatus
, ctrlstatus
);
1455 if(framecnt
> unit
->hu_NakTimeoutFrame
[devadrep
]) {
1456 // give the thing the chance to exit gracefully
1457 KPRINTF(20, ("Terminated? NAK timeout %ld > %ld, IOReq=%p\n", framecnt
, unit
->hu_NakTimeoutFrame
[devadrep
], ioreq
));
1464 ioreq
= (struct IOUsbHWReq
*) ((struct Node
*) ioreq
)->ln_Succ
;
1467 uhciCheckPortStatusChange(hc
);
1470 SureCause(base
, &hc
->hc_CompleteInt
);
1473 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
1476 uhwCheckRootHubChanges(unit
);
1478 unit
->hu_NakTimeoutReq
.tr_time
.tv_micro
= 150*1000;
1479 SendIO((APTR
) &unit
->hu_NakTimeoutReq
);
1481 KPRINTF(1, ("Exit NakTimeoutInt(0x%p)\n", unit
));