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 memset( &unit
->hu_NakTimeoutMsgPort
, 0, sizeof( 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 unit
->hu_NakTimeoutReq
.tr_node
.io_Message
.mn_ReplyPort
= &unit
->hu_NakTimeoutMsgPort
;
179 Cause(&unit
->hu_NakTimeoutInt
);
180 return(&unit
->hu_Unit
);
182 ioreq
->iouh_Req
.io_Error
= IOERR_SELFTEST
;
183 KPRINTF(20, ("Hardware allocation failure!\n"));
185 uhwCloseTimer(unit
, base
);
191 /* /// "Close_Unit()" */
192 void Close_Unit(struct PCIDevice
*base
,
193 struct PCIUnit
*unit
,
194 struct IOUsbHWReq
*ioreq
)
196 /* Disable all interrupts */
197 unit
->hu_NakTimeoutMsgPort
.mp_Flags
= PA_IGNORE
;
198 unit
->hu_NakTimeoutInt
.is_Node
.ln_Type
= NT_SOFTINT
;
199 AbortIO((APTR
) &unit
->hu_NakTimeoutReq
);
203 uhwCloseTimer(unit
, base
);
204 unit
->hu_UnitAllocated
= FALSE
;
208 /* /// "uhwGetUsbState()" */
209 UWORD
uhwGetUsbState(struct IOUsbHWReq
*ioreq
,
210 struct PCIUnit
*unit
,
211 struct PCIDevice
*base
)
213 return(ioreq
->iouh_State
= UHSF_OPERATIONAL
);
217 /* /// "cmdReset()" */
219 *======================================================================
220 * cmdReset(ioreq, unit, base)
221 *======================================================================
223 * This is the device CMD_RESET routine.
225 * Resets the whole USB hardware. Goes into USBOperational mode right
226 * after. Must NOT be called from an interrupt.
230 WORD
cmdReset(struct IOUsbHWReq
*ioreq
,
231 struct PCIUnit
*unit
,
232 struct PCIDevice
*base
)
234 KPRINTF(10, ("CMD_RESET ioreq: 0x%p\n", ioreq
));
237 uhwGetUsbState(ioreq
, unit
, base
);
239 if(ioreq
->iouh_State
& UHSF_OPERATIONAL
)
243 return UHIOERR_USBOFFLINE
;
247 /* /// "cmdUsbReset()" */
249 *======================================================================
250 * cmdUsbReset(ioreq, unit, base)
251 *======================================================================
253 * This is the device UHCMD_USBRESET routine.
255 * Resets the USB bus. Goes into USBOperational mode right after. Must
256 * NOT be called from an interrupt.
260 WORD
cmdUsbReset(struct IOUsbHWReq
*ioreq
,
261 struct PCIUnit
*unit
,
262 struct PCIDevice
*base
)
264 KPRINTF(10, ("UHCMD_USBRESET ioreq: 0x%p\n", ioreq
));
267 uhwGetUsbState(ioreq
, unit
, base
);
269 unit
->hu_RootHubAddr
= 0;
271 if(ioreq
->iouh_State
& UHSF_OPERATIONAL
)
275 return UHIOERR_USBOFFLINE
;
279 /* /// "cmdUsbResume()" */
281 *======================================================================
282 * cmdUsbResume(ioreq, unit, base)
283 *======================================================================
285 * This is the device UHCMD_USBRESUME routine.
287 * Tries to resume from USBSuspend mode into USBOperational.
288 * Must NOT be called from an interrupt.
292 WORD
cmdUsbResume(struct IOUsbHWReq
*ioreq
,
293 struct PCIUnit
*unit
,
294 struct PCIDevice
*base
)
296 KPRINTF(10, ("UHCMD_USBRESUME ioreq: 0x%p\n", ioreq
));
299 uhwGetUsbState(ioreq
, unit
, base
);
300 if(ioreq
->iouh_State
& UHSF_OPERATIONAL
)
304 return UHIOERR_USBOFFLINE
;
308 /* /// "cmdUsbSuspend()" */
310 *======================================================================
311 * cmdUsbSuspend(ioreq, unit, base)
312 *======================================================================
314 * This is the device UHCMD_USBSUSPEND routine.
316 * Sets the USB into USBSuspend mode.
317 * Must NOT be called from an interrupt.
321 WORD
cmdUsbSuspend(struct IOUsbHWReq
*ioreq
,
322 struct PCIUnit
*unit
,
323 struct PCIDevice
*base
)
325 KPRINTF(10, ("UHCMD_USBSUSPEND ioreq: 0x%p\n", ioreq
));
328 uhwGetUsbState(ioreq
, unit
, base
);
329 if(ioreq
->iouh_State
& UHSF_SUSPENDED
)
333 return UHIOERR_USBOFFLINE
;
337 /* /// "cmdUsbOper()" */
339 *======================================================================
340 * cmdUsbOper(ioreq, unit, base)
341 *======================================================================
343 * This is the device UHCMD_USBOPER routine.
345 * Sets the USB into USBOperational mode.
346 * Must NOT be called from an interrupt.
350 WORD
cmdUsbOper(struct IOUsbHWReq
*ioreq
,
351 struct PCIUnit
*unit
,
352 struct PCIDevice
*base
)
354 KPRINTF(10, ("UHCMD_USBOPER ioreq: 0x%p\n", ioreq
));
357 uhwGetUsbState(ioreq
, unit
, base
);
358 if(ioreq
->iouh_State
& UHSF_OPERATIONAL
)
362 return UHIOERR_USBOFFLINE
;
366 /* /// "cmdQueryDevice()" */
368 *======================================================================
369 * cmdQueryDevice(ioreq, unit, base)
370 *======================================================================
372 * This is the device UHCMD_QUERYDEVICE routine.
374 * Returns information about the hardware.
378 WORD
cmdQueryDevice(struct IOUsbHWReq
*ioreq
,
379 struct PCIUnit
*unit
,
380 struct PCIDevice
*base
)
382 struct TagItem
*taglist
= (struct TagItem
*) ioreq
->iouh_Data
;
386 KPRINTF(10, ("UHCMD_QUERYDEVICE ioreq: 0x%p, taglist: 0x%p\n", ioreq
, taglist
));
388 if((tag
= FindTagItem(UHA_State
, taglist
)))
390 *((ULONG
*) tag
->ti_Data
) = (ULONG
) uhwGetUsbState(ioreq
, unit
, base
);
393 if((tag
= FindTagItem(UHA_Manufacturer
, taglist
)))
395 *((STRPTR
*) tag
->ti_Data
) = "Chris Hodges";
398 if((tag
= FindTagItem(UHA_ProductName
, taglist
)))
400 *((STRPTR
*) tag
->ti_Data
) = "PCI UHCI USB 1.1 Host Controller";
403 if((tag
= FindTagItem(UHA_Description
, taglist
)))
405 *((STRPTR
*) tag
->ti_Data
) = "Generic adaptive host controller driver for PCI cards";
408 if((tag
= FindTagItem(UHA_Copyright
, taglist
)))
410 *((STRPTR
*) tag
->ti_Data
) ="©2007-2009 Chris Hodges";
413 if((tag
= FindTagItem(UHA_Version
, taglist
)))
415 *((ULONG
*) tag
->ti_Data
) = VERSION_NUMBER
;
418 if((tag
= FindTagItem(UHA_Revision
, taglist
)))
420 *((ULONG
*) tag
->ti_Data
) = REVISION_NUMBER
;
423 if((tag
= FindTagItem(UHA_DriverVersion
, taglist
)))
425 *((ULONG
*) tag
->ti_Data
) = 0x220;
428 if((tag
= FindTagItem(UHA_Capabilities
, taglist
)))
430 *((ULONG
*) tag
->ti_Data
) = UHCF_USB20
;
433 ioreq
->iouh_Actual
= count
;
438 /* /// "cmdControlXFerRootHub()" */
439 WORD
cmdControlXFerRootHub(struct IOUsbHWReq
*ioreq
,
440 struct PCIUnit
*unit
,
441 struct PCIDevice
*base
)
443 struct PCIController
*hc
;
444 struct PCIController
*chc
;
445 UWORD rt
= ioreq
->iouh_SetupData
.bmRequestType
;
446 UWORD req
= ioreq
->iouh_SetupData
.bRequest
;
447 UWORD idx
= AROS_WORD2LE(ioreq
->iouh_SetupData
.wIndex
);
448 UWORD val
= AROS_WORD2LE(ioreq
->iouh_SetupData
.wValue
);
449 UWORD len
= AROS_WORD2LE(ioreq
->iouh_SetupData
.wLength
);
451 ULONG numports
= unit
->hu_RootHubPorts
;
459 if(ioreq
->iouh_Endpoint
) {
460 return(UHIOERR_STALL
);
463 if(len
!= ioreq
->iouh_Length
) {
464 KPRINTF(20, ("RH: Len (%ld != %ld) mismatch!\n", len
!= ioreq
->iouh_Length
));
465 return(UHIOERR_STALL
);
469 case (URTF_STANDARD
|URTF_DEVICE
):
471 case USR_SET_ADDRESS
:
472 KPRINTF(1, ("RH: SetAddress = %ld\n", val
));
473 unit
->hu_RootHubAddr
= val
;
474 ioreq
->iouh_Actual
= len
;
477 case USR_SET_CONFIGURATION
:
478 KPRINTF(1, ("RH: SetConfiguration=%ld\n", val
));
479 ioreq
->iouh_Actual
= len
;
484 case (URTF_IN
|URTF_STANDARD
|URTF_DEVICE
):
486 case USR_GET_DESCRIPTOR
:
489 KPRINTF(1, ("RH: GetDeviceDescriptor (%ld)\n", len
));
490 ioreq
->iouh_Actual
= (len
> sizeof(struct UsbStdDevDesc
)) ? sizeof(struct UsbStdDevDesc
) : len
;
491 CopyMem((APTR
) &RHDevDesc
, ioreq
->iouh_Data
, ioreq
->iouh_Actual
);
494 case UDT_CONFIGURATION
: {
496 KPRINTF(1, ("RH: GetConfigDescriptor (%ld)\n", len
));
497 CopyMem((APTR
) &RHCfgDesc
, tmpbuf
, 9);
498 CopyMem((APTR
) &RHIfDesc
, &tmpbuf
[9], 9);
499 CopyMem((APTR
) &RHEPDesc
, &tmpbuf
[9+9], 7);
500 ioreq
->iouh_Actual
= (len
> 9+9+7) ? 9+9+7 : len
;
501 CopyMem(tmpbuf
, ioreq
->iouh_Data
, ioreq
->iouh_Actual
);
506 if(val
& 0xff) /* get lang array */
508 CONST_STRPTR source
= NULL
;
509 UWORD
*mptr
= ioreq
->iouh_Data
;
511 KPRINTF(1, ("RH: GetString %04lx (%ld)\n", val
, len
));
512 if((val
& 0xff) > 4) /* index too high? */
514 return(UHIOERR_STALL
);
516 source
= RHStrings
[(val
& 0xff)-1];
519 ioreq
->iouh_Actual
= 2;
524 source
= RHStrings
[(val
& 0xff)-1];
525 *mptr
++ = AROS_WORD2BE((slen
<<9)|UDT_STRING
);
526 while(ioreq
->iouh_Actual
+1 < len
)
528 // special hack for unit number in root hub string
529 if(((val
& 0xff) == 2) && (source
[1] == 0)) {
530 *mptr
++ = AROS_WORD2LE('0' + unit
->hu_UnitNo
);
532 *mptr
++ = AROS_WORD2LE(*source
);
535 ioreq
->iouh_Actual
+= 2;
542 UWORD
*mptr
= ioreq
->iouh_Data
;
543 KPRINTF(1, ("RH: GetLangArray %04lx (%ld)\n", val
, len
));
545 ioreq
->iouh_Actual
= 2;
546 mptr
[0] = AROS_WORD2BE((4<<8)|UDT_STRING
);
549 ioreq
->iouh_Actual
+= 2;
550 mptr
[1] = AROS_WORD2LE(0x0409);
557 KPRINTF(1, ("RH: Unsupported Descriptor %04lx\n", idx
));
561 case USR_GET_CONFIGURATION
:
563 KPRINTF(1, ("RH: GetConfiguration\n"));
564 ((UBYTE
*) ioreq
->iouh_Data
)[0] = 1;
565 ioreq
->iouh_Actual
= len
;
572 case (URTF_CLASS
|URTF_OTHER
):
574 case USR_SET_FEATURE
:
575 if((!idx
) && (idx
> numports
)) {
576 KPRINTF(20, ("Port %ld out of range\n", idx
));
577 return(UHIOERR_STALL
);
579 chc
= unit
->hu_PortMap11
[idx
- 1];
581 // if(unit->hu_EhciOwned[idx - 1])
583 // hc = unit->hu_PortMap20[idx - 1];
584 // hciport = idx - 1;
587 hciport
= unit
->hu_PortNum11
[idx
- 1];
589 // 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"));
592 portreg
= hciport
? UHCI_PORT2STSCTRL
: UHCI_PORT1STSCTRL
;
593 oldval
= READIO16_LE(hc
->hc_RegBase
, portreg
) & ~(UHPF_ENABLECHANGE
|UHPF_CONNECTCHANGE
); // these are clear-on-write!
597 /* case UFS_PORT_CONNECTION: not possible */
598 case UFS_PORT_ENABLE
:
599 KPRINTF(200, ("Enabling Port (%s)\n", newval
& UHPF_PORTENABLE
? "already" : "ok"));
600 newval
|= UHPF_PORTENABLE
;
604 case UFS_PORT_SUSPEND
:
605 newval
|= UHPF_PORTSUSPEND
;
606 hc
->hc_PortChangeMap
[hciport
] |= UPSF_PORT_SUSPEND
; // manually fake suspend change
610 /* case UFS_PORT_OVER_CURRENT: not possible */
612 KPRINTF(200, ("Resetting Port (%s)\n", newval
& UHPF_PORTRESET
? "already" : "ok"));
614 // this is an ugly blocking workaround to the inability of UHCI to clear reset automatically
615 newval
&= ~(UHPF_PORTSUSPEND
|UHPF_PORTENABLE
);
616 newval
|= UHPF_PORTRESET
;
617 WRITEIO16_LE(hc
->hc_RegBase
, portreg
, newval
);
618 uhwDelayMS(25, unit
);
620 newval
= READIO16_LE(hc
->hc_RegBase
, portreg
) & ~(UHPF_ENABLECHANGE
|UHPF_CONNECTCHANGE
|UHPF_PORTSUSPEND
|UHPF_PORTENABLE
);
621 KPRINTF(200, ("Reset=%s\n", newval
& UHPF_PORTRESET
? "GOOD" : "BAD!"));
623 // like windows does it
624 newval
&= ~UHPF_PORTRESET
;
625 WRITEIO16_LE(hc
->hc_RegBase
, portreg
, newval
);
626 uhwDelayMicro(50, unit
);
628 newval
= READIO16_LE(hc
->hc_RegBase
, portreg
) & ~(UHPF_ENABLECHANGE
|UHPF_CONNECTCHANGE
|UHPF_PORTSUSPEND
);
629 KPRINTF(200, ("Reset=%s\n", newval
& UHPF_PORTRESET
? "BAD!" : "GOOD"));
630 newval
&= ~(UHPF_PORTSUSPEND
|UHPF_PORTRESET
);
631 newval
|= UHPF_PORTENABLE
;
632 WRITEIO16_LE(hc
->hc_RegBase
, portreg
, newval
);
633 hc
->hc_PortChangeMap
[hciport
] |= UPSF_PORT_RESET
|UPSF_PORT_ENABLE
; // manually fake reset change
638 newval
= READIO16_LE(hc
->hc_RegBase
, portreg
);
639 } while(--cnt
&& (!(newval
& UHPF_PORTENABLE
)));
642 KPRINTF(10, ("Enabled after %ld ticks\n", 100-cnt
));
644 KPRINTF(20, ("Port refuses to be enabled!\n"));
645 return(UHIOERR_HOSTERROR
);
648 // make enumeration possible
649 unit
->hu_DevControllers
[0] = hc
;
654 KPRINTF(10, ("Powering Port\n"));
655 // ignore for UHCI, is always powered
659 /* case UFS_PORT_LOW_SPEED: not possible
660 case UFS_C_PORT_CONNECTION:
661 case UFS_C_PORT_ENABLE:
662 case UFS_C_PORT_SUSPEND:
663 case UFS_C_PORT_OVER_CURRENT:
664 case UFS_C_PORT_RESET: */
668 KPRINTF(5, ("Port %ld SET_FEATURE %04lx->%04lx\n", idx
, oldval
, newval
));
669 WRITEIO16_LE(hc
->hc_RegBase
, portreg
, newval
);
672 break; /* USR_SET_FEATURE */
674 case USR_CLEAR_FEATURE
:
675 if((!idx
) && (idx
> numports
)) {
676 KPRINTF(20, ("Port %ld out of range\n", idx
));
677 return(UHIOERR_STALL
);
679 // if(unit->hu_EhciOwned[idx - 1])
681 // hc = unit->hu_PortMap20[idx - 1];
682 // hciport = idx - 1;
684 hc
= unit
->hu_PortMap11
[idx
- 1];
685 hciport
= unit
->hu_PortNum11
[idx
- 1];
687 // 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"));
690 portreg
= hciport
? UHCI_PORT2STSCTRL
: UHCI_PORT1STSCTRL
;
691 oldval
= READIO16_LE(hc
->hc_RegBase
, portreg
) & ~(UHPF_ENABLECHANGE
|UHPF_CONNECTCHANGE
); // these are clear-on-write!
694 case UFS_PORT_ENABLE
:
695 KPRINTF(10, ("Disabling Port (%s)\n", newval
& UHPF_PORTENABLE
? "ok" : "already"));
696 newval
&= ~UHPF_PORTENABLE
;
698 // disable enumeration
699 unit
->hu_DevControllers
[0] = NULL
;
702 case UFS_PORT_SUSPEND
:
703 newval
&= ~UHPF_PORTSUSPEND
;
707 case UFS_PORT_POWER
: // ignore for UHCI, there's no power control here
708 KPRINTF(10, ("Disabling Power\n"));
709 KPRINTF(10, ("Disabling Port (%s)\n", newval
& UHPF_PORTENABLE
? "ok" : "already"));
710 newval
&= ~UHPF_PORTENABLE
;
714 case UFS_C_PORT_CONNECTION
:
715 newval
|= UHPF_CONNECTCHANGE
; // clear-on-write!
716 hc
->hc_PortChangeMap
[hciport
] &= ~UPSF_PORT_CONNECTION
;
720 case UFS_C_PORT_ENABLE
:
721 newval
|= UHPF_ENABLECHANGE
; // clear-on-write!
722 hc
->hc_PortChangeMap
[hciport
] &= ~UPSF_PORT_ENABLE
;
726 case UFS_C_PORT_SUSPEND
: // ignore for UHCI, there's no bit indicating this
727 hc
->hc_PortChangeMap
[hciport
] &= ~UPSF_PORT_SUSPEND
; // manually fake suspend change clearing
731 case UFS_C_PORT_OVER_CURRENT
: // ignore for UHCI, there's no bit indicating this
732 hc
->hc_PortChangeMap
[hciport
] &= ~UPSF_PORT_OVER_CURRENT
; // manually fake over current clearing
736 case UFS_C_PORT_RESET
: // ignore for UHCI, there's no bit indicating this
737 hc
->hc_PortChangeMap
[hciport
] &= ~UPSF_PORT_RESET
; // manually fake reset change clearing
743 KPRINTF(5, ("Port %ld CLEAR_FEATURE %04lx->%04lx\n", idx
, oldval
, newval
));
744 WRITEIO16_LE(hc
->hc_RegBase
, portreg
, newval
);
745 if(hc
->hc_PortChangeMap
[hciport
]) {
746 unit
->hu_RootPortChanges
|= 1UL<<idx
;
748 unit
->hu_RootPortChanges
&= ~(1UL<<idx
);
757 case (URTF_IN
|URTF_CLASS
|URTF_OTHER
):
759 case USR_GET_STATUS
: {
760 UWORD
*mptr
= ioreq
->iouh_Data
;
761 if(len
!= sizeof(struct UsbPortStatus
))
763 return(UHIOERR_STALL
);
765 if((!idx
) && (idx
> numports
))
767 KPRINTF(20, ("Port %ld out of range\n", idx
));
768 return(UHIOERR_STALL
);
770 // if(unit->hu_EhciOwned[idx - 1])
772 // hc = unit->hu_PortMap20[idx - 1];
773 // hciport = idx - 1;
775 hc
= unit
->hu_PortMap11
[idx
- 1];
776 hciport
= unit
->hu_PortNum11
[idx
- 1];
780 UWORD portreg
= hciport
? UHCI_PORT2STSCTRL
: UHCI_PORT1STSCTRL
;
781 UWORD oldval
= READIO16_LE(hc
->hc_RegBase
, portreg
);
782 *mptr
= AROS_WORD2LE(UPSF_PORT_POWER
);
783 if(oldval
& UHPF_PORTCONNECTED
) *mptr
|= AROS_WORD2LE(UPSF_PORT_CONNECTION
);
784 if(oldval
& UHPF_PORTENABLE
) *mptr
|= AROS_WORD2LE(UPSF_PORT_ENABLE
);
785 if(oldval
& UHPF_LOWSPEED
) *mptr
|= AROS_WORD2LE(UPSF_PORT_LOW_SPEED
);
786 if(oldval
& UHPF_PORTRESET
) *mptr
|= AROS_WORD2LE(UPSF_PORT_RESET
);
787 if(oldval
& UHPF_PORTSUSPEND
) *mptr
|= AROS_WORD2LE(UPSF_PORT_SUSPEND
);
789 KPRINTF(200, ("UHCI Port %ld is %s\n", idx
, oldval
& UHPF_LOWSPEED
? "LOWSPEED" : "FULLSPEED"));
790 KPRINTF(200, ("UHCI Port %ld Status %08lx\n", idx
, *mptr
));
793 if(oldval
& UHPF_ENABLECHANGE
) {
794 hc
->hc_PortChangeMap
[hciport
] |= UPSF_PORT_ENABLE
;
796 if(oldval
& UHPF_CONNECTCHANGE
) {
797 hc
->hc_PortChangeMap
[hciport
] |= UPSF_PORT_CONNECTION
;
799 if(oldval
& UHPF_RESUMEDTX
) {
800 hc
->hc_PortChangeMap
[hciport
] |= UPSF_PORT_SUSPEND
|UPSF_PORT_ENABLE
;
802 *mptr
= AROS_WORD2LE(hc
->hc_PortChangeMap
[hciport
]);
803 WRITEIO16_LE(hc
->hc_RegBase
, portreg
, oldval
);
804 KPRINTF(5, ("UHCI Port %ld Change %08lx\n", idx
, *mptr
));
811 case (URTF_IN
|URTF_CLASS
|URTF_DEVICE
):
816 UWORD
*mptr
= ioreq
->iouh_Data
;
817 if(len
< sizeof(struct UsbHubStatus
))
819 return(UHIOERR_STALL
);
823 ioreq
->iouh_Actual
= 4;
827 case USR_GET_DESCRIPTOR
:
832 ULONG hubdesclen
= 9;
835 struct UsbHubDesc
*uhd
= (struct UsbHubDesc
*) ioreq
->iouh_Data
;
836 KPRINTF(1, ("RH: GetHubDescriptor (%ld)\n", len
));
838 if(unit
->hu_RootHubPorts
> 7) // needs two bytes for port masks
843 ioreq
->iouh_Actual
= (len
> hubdesclen
) ? hubdesclen
: len
;
844 CopyMem((APTR
) &RHHubDesc
, ioreq
->iouh_Data
, ioreq
->iouh_Actual
);
846 if(ioreq
->iouh_Length
)
848 uhd
->bLength
= hubdesclen
;
851 if(ioreq
->iouh_Length
>= 6)
853 uhd
->bPwrOn2PwrGood
= powergood
;
856 if(ioreq
->iouh_Length
>= hubdesclen
)
858 uhd
->bNbrPorts
= unit
->hu_RootHubPorts
;
861 uhd
->DeviceRemovable
= 0;
862 uhd
->PortPwrCtrlMask
= (1<<(unit
->hu_RootHubPorts
+2))-2;
864 // each field is now 16 bits wide
865 uhd
->DeviceRemovable
= 0;
866 uhd
->PortPwrCtrlMask
= 0;
867 ((UBYTE
*) ioreq
->iouh_Data
)[9] = (1<<(unit
->hu_RootHubPorts
+2))-2;
868 ((UBYTE
*) ioreq
->iouh_Data
)[10] = ((1<<(unit
->hu_RootHubPorts
+2))-2)>>8;
875 KPRINTF(20, ("RH: Unsupported Descriptor %04lx\n", idx
));
881 KPRINTF(20, ("RH: Unsupported command %02lx %02lx %04lx %04lx %04lx!\n", rt
, req
, idx
, val
, len
));
882 return(UHIOERR_STALL
);
886 /* /// "cmdIntXFerRootHub()" */
887 WORD
cmdIntXFerRootHub(struct IOUsbHWReq
*ioreq
,
888 struct PCIUnit
*unit
,
889 struct PCIDevice
*base
)
891 if((ioreq
->iouh_Endpoint
!= 1) || (!ioreq
->iouh_Length
))
893 return(UHIOERR_STALL
);
896 if(unit
->hu_RootPortChanges
)
898 KPRINTF(1, ("Immediate Portchange map %04lx\n", unit
->hu_RootPortChanges
));
899 if((unit
->hu_RootHubPorts
< 8) || (ioreq
->iouh_Length
== 1))
901 *((UBYTE
*) ioreq
->iouh_Data
) = unit
->hu_RootPortChanges
;
902 ioreq
->iouh_Actual
= 1;
904 ((UBYTE
*) ioreq
->iouh_Data
)[0] = unit
->hu_RootPortChanges
;
905 ((UBYTE
*) ioreq
->iouh_Data
)[1] = unit
->hu_RootPortChanges
>>8;
906 ioreq
->iouh_Actual
= 2;
908 unit
->hu_RootPortChanges
= 0;
911 ioreq
->iouh_Req
.io_Flags
&= ~IOF_QUICK
;
913 AddTail(&unit
->hu_RHIOQueue
, (struct Node
*) ioreq
);
915 return(RC_DONTREPLY
);
919 /* /// "cmdControlXFer()" */
921 *======================================================================
922 * cmdControlXFer(ioreq, unit, base)
923 *======================================================================
925 * This is the device UHCMD_CONTROLXFER routine.
927 * First it check if the usb is in proper state and if user passed arguments
928 * are valid. If everything is ok, the request is linked to queue of
929 * pending transfer requests.
933 WORD
cmdControlXFer(struct IOUsbHWReq
*ioreq
,
934 struct PCIUnit
*unit
,
935 struct PCIDevice
*base
)
937 struct PCIController
*hc
;
939 KPRINTF(10, ("UHCMD_CONTROLXFER ioreq: 0x%p\n", ioreq
));
940 uhwGetUsbState(ioreq
, unit
, base
);
941 if(!(ioreq
->iouh_State
& UHSF_OPERATIONAL
))
943 return(UHIOERR_USBOFFLINE
);
945 /* Root hub emulation */
946 if(ioreq
->iouh_DevAddr
== unit
->hu_RootHubAddr
)
948 return(cmdControlXFerRootHub(ioreq
, unit
, base
));
951 hc
= unit
->hu_DevControllers
[ioreq
->iouh_DevAddr
];
954 KPRINTF(20, ("No Host controller assigned to device address %ld\n", ioreq
->iouh_DevAddr
));
955 return(UHIOERR_HOSTERROR
);
958 ioreq
->iouh_Req
.io_Flags
&= ~IOF_QUICK
;
959 ioreq
->iouh_Actual
= 0;
962 AddTail(&hc
->hc_CtrlXFerQueue
, (struct Node
*) ioreq
);
964 SureCause(base
, &hc
->hc_CompleteInt
);
966 KPRINTF(10, ("UHCMD_CONTROLXFER processed ioreq: 0x%p\n", ioreq
));
967 return(RC_DONTREPLY
);
971 /* /// "cmdBulkXFer()" */
973 *======================================================================
974 * cmdBulkXFer(ioreq, unit, base)
975 *======================================================================
977 * This is the device UHCMD_BULKXFER routine.
979 * First it check if the usb is in proper state and if user passed arguments
980 * are valid. If everything is ok, the request is linked to queue of
981 * pending transfer requests.
985 WORD
cmdBulkXFer(struct IOUsbHWReq
*ioreq
,
986 struct PCIUnit
*unit
,
987 struct PCIDevice
*base
)
989 struct PCIController
*hc
;
991 KPRINTF(10, ("UHCMD_BULKXFER ioreq: 0x%p\n", ioreq
));
992 uhwGetUsbState(ioreq
, unit
, base
);
993 if(!(ioreq
->iouh_State
& UHSF_OPERATIONAL
))
995 return(UHIOERR_USBOFFLINE
);
998 if(ioreq
->iouh_Flags
& UHFF_LOWSPEED
)
1000 return(UHIOERR_BADPARAMS
);
1003 hc
= unit
->hu_DevControllers
[ioreq
->iouh_DevAddr
];
1006 return(UHIOERR_HOSTERROR
);
1009 ioreq
->iouh_Req
.io_Flags
&= ~IOF_QUICK
;
1010 ioreq
->iouh_Actual
= 0;
1013 AddTail(&hc
->hc_BulkXFerQueue
, (struct Node
*) ioreq
);
1015 SureCause(base
, &hc
->hc_CompleteInt
);
1017 KPRINTF(10, ("UHCMD_BULKXFER processed ioreq: 0x%p\n", ioreq
));
1018 return(RC_DONTREPLY
);
1022 /* /// "cmdIsoXFer()" */
1024 *======================================================================
1025 * cmdIsoXFer(ioreq, unit, base)
1026 *======================================================================
1028 * This is the device UHCMD_ISOXFER routine.
1030 * First it check if the usb is in proper state and if user passed arguments
1031 * are valid. If everything is ok, the request is linked to queue of
1032 * pending transfer requests.
1036 WORD
cmdIsoXFer(struct IOUsbHWReq
*ioreq
,
1037 struct PCIUnit
*unit
,
1038 struct PCIDevice
*base
)
1040 struct PCIController
*hc
;
1042 KPRINTF(10, ("UHCMD_ISOXFER ioreq: 0x%p\n", ioreq
));
1043 uhwGetUsbState(ioreq
, unit
, base
);
1044 if(!(ioreq
->iouh_State
& UHSF_OPERATIONAL
))
1046 return(UHIOERR_USBOFFLINE
);
1049 if(ioreq
->iouh_Flags
& UHFF_LOWSPEED
)
1051 return(UHIOERR_BADPARAMS
);
1054 hc
= unit
->hu_DevControllers
[ioreq
->iouh_DevAddr
];
1057 return(UHIOERR_HOSTERROR
);
1060 ioreq
->iouh_Req
.io_Flags
&= ~IOF_QUICK
;
1061 ioreq
->iouh_Actual
= 0;
1064 AddTail(&hc
->hc_IsoXFerQueue
, (struct Node
*) ioreq
);
1066 SureCause(base
, &hc
->hc_CompleteInt
);
1068 KPRINTF(10, ("UHCMD_ISOXFER processed ioreq: 0x%p\n", ioreq
));
1069 return(RC_DONTREPLY
);
1073 /* /// "cmdIntXFer()" */
1075 *======================================================================
1076 * cmdIntXFer(ioreq, unit, base)
1077 *======================================================================
1079 * This is the device UHCMD_INTXFER routine.
1081 * First it check if the usb is in proper state and if user passed arguments
1082 * are valid. If everything is ok, the request is linked to queue of
1083 * pending transfer requests.
1087 WORD
cmdIntXFer(struct IOUsbHWReq
*ioreq
,
1088 struct PCIUnit
*unit
,
1089 struct PCIDevice
*base
)
1091 struct PCIController
*hc
;
1093 KPRINTF(10, ("UHCMD_INTXFER ioreq: 0x%p\n", ioreq
));
1094 //uhwDelayMS(1000, unit); /* Wait 200 ms */
1095 uhwGetUsbState(ioreq
, unit
, base
);
1096 if(!(ioreq
->iouh_State
& UHSF_OPERATIONAL
))
1098 return(UHIOERR_USBOFFLINE
);
1101 /* Root Hub Emulation */
1102 if(ioreq
->iouh_DevAddr
== unit
->hu_RootHubAddr
)
1104 return(cmdIntXFerRootHub(ioreq
, unit
, base
));
1107 hc
= unit
->hu_DevControllers
[ioreq
->iouh_DevAddr
];
1110 return(UHIOERR_HOSTERROR
);
1113 ioreq
->iouh_Req
.io_Flags
&= ~IOF_QUICK
;
1114 ioreq
->iouh_Actual
= 0;
1117 AddTail(&hc
->hc_IntXFerQueue
, (struct Node
*) ioreq
);
1119 SureCause(base
, &hc
->hc_CompleteInt
);
1121 KPRINTF(10, ("UHCMD_INTXFER processed ioreq: 0x%p\n", ioreq
));
1122 return(RC_DONTREPLY
);
1126 /* /// "cmdFlush()" */
1128 *======================================================================
1129 * cmdFlush(ioreq, base)
1130 *======================================================================
1132 * This is the device CMD_FLUSH routine.
1134 * This routine abort all pending transfer requests.
1138 WORD
cmdFlush(struct IOUsbHWReq
*ioreq
,
1139 struct PCIUnit
*unit
,
1140 struct PCIDevice
*base
)
1142 struct IOUsbHWReq
*cmpioreq
;
1143 struct PCIController
*hc
;
1146 KPRINTF(10, ("CMD_FLUSH ioreq: 0x%p\n", ioreq
));
1149 cmpioreq
= (struct IOUsbHWReq
*) unit
->hu_RHIOQueue
.lh_Head
;
1150 while(((struct Node
*) cmpioreq
)->ln_Succ
) {
1151 Remove(&cmpioreq
->iouh_Req
.io_Message
.mn_Node
);
1152 cmpioreq
->iouh_Req
.io_Error
= IOERR_ABORTED
;
1153 ReplyMsg(&cmpioreq
->iouh_Req
.io_Message
);
1154 cmpioreq
= (struct IOUsbHWReq
*) unit
->hu_RHIOQueue
.lh_Head
;
1157 hc
= (struct PCIController
*) unit
->hu_Controllers
.lh_Head
;
1158 while(hc
->hc_Node
.ln_Succ
) {
1159 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_CtrlXFerQueue
.lh_Head
;
1160 while(((struct Node
*) cmpioreq
)->ln_Succ
)
1162 Remove(&cmpioreq
->iouh_Req
.io_Message
.mn_Node
);
1163 cmpioreq
->iouh_Req
.io_Error
= IOERR_ABORTED
;
1164 ReplyMsg(&cmpioreq
->iouh_Req
.io_Message
);
1165 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_CtrlXFerQueue
.lh_Head
;
1167 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_IntXFerQueue
.lh_Head
;
1168 while(((struct Node
*) cmpioreq
)->ln_Succ
)
1170 Remove(&cmpioreq
->iouh_Req
.io_Message
.mn_Node
);
1171 cmpioreq
->iouh_Req
.io_Error
= IOERR_ABORTED
;
1172 ReplyMsg(&cmpioreq
->iouh_Req
.io_Message
);
1173 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_IntXFerQueue
.lh_Head
;
1175 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_IsoXFerQueue
.lh_Head
;
1176 while(((struct Node
*) cmpioreq
)->ln_Succ
)
1178 Remove(&cmpioreq
->iouh_Req
.io_Message
.mn_Node
);
1179 cmpioreq
->iouh_Req
.io_Error
= IOERR_ABORTED
;
1180 ReplyMsg(&cmpioreq
->iouh_Req
.io_Message
);
1181 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_IsoXFerQueue
.lh_Head
;
1183 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_BulkXFerQueue
.lh_Head
;
1184 while(((struct Node
*) cmpioreq
)->ln_Succ
)
1186 Remove(&cmpioreq
->iouh_Req
.io_Message
.mn_Node
);
1187 cmpioreq
->iouh_Req
.io_Error
= IOERR_ABORTED
;
1188 ReplyMsg(&cmpioreq
->iouh_Req
.io_Message
);
1189 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_BulkXFerQueue
.lh_Head
;
1193 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_TDQueue
.lh_Head
;
1194 while(((struct Node
*) cmpioreq
)->ln_Succ
) {
1195 Remove(&cmpioreq
->iouh_Req
.io_Message
.mn_Node
);
1196 devadrep
= (cmpioreq
->iouh_DevAddr
<<5) + cmpioreq
->iouh_Endpoint
+ ((cmpioreq
->iouh_Dir
== UHDIR_IN
) ? 0x10 : 0);
1197 unit
->hu_DevBusyReq
[devadrep
] = NULL
;
1198 uhciFreeQContext(hc
, (struct UhciQH
*) cmpioreq
->iouh_DriverPrivate1
);
1199 cmpioreq
->iouh_Req
.io_Error
= IOERR_ABORTED
;
1200 ReplyMsg(&cmpioreq
->iouh_Req
.io_Message
);
1201 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_TDQueue
.lh_Head
;
1203 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
1212 /* /// "cmdAbortIO()" */
1213 BOOL
cmdAbortIO(struct IOUsbHWReq
*ioreq
, struct PCIDevice
*base
)
1215 struct PCIUnit
*unit
= (struct PCIUnit
*) ioreq
->iouh_Req
.io_Unit
;
1216 struct IOUsbHWReq
*cmpioreq
;
1217 struct PCIController
*hc
;
1219 BOOL foundit
= FALSE
;
1221 KPRINTF(10, ("cmdAbort(%p)\n", ioreq
));
1224 cmpioreq
= (struct IOUsbHWReq
*) unit
->hu_RHIOQueue
.lh_Head
;
1225 while(((struct Node
*) cmpioreq
)->ln_Succ
)
1227 if(ioreq
== cmpioreq
)
1229 Remove(&ioreq
->iouh_Req
.io_Message
.mn_Node
);
1233 cmpioreq
= (struct IOUsbHWReq
*) cmpioreq
->iouh_Req
.io_Message
.mn_Node
.ln_Succ
;
1236 hc
= (struct PCIController
*) unit
->hu_Controllers
.lh_Head
;
1237 while(hc
->hc_Node
.ln_Succ
)
1239 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_CtrlXFerQueue
.lh_Head
;
1240 while(((struct Node
*) cmpioreq
)->ln_Succ
)
1242 if(ioreq
== cmpioreq
)
1247 cmpioreq
= (struct IOUsbHWReq
*) cmpioreq
->iouh_Req
.io_Message
.mn_Node
.ln_Succ
;
1251 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_IntXFerQueue
.lh_Head
;
1252 while(((struct Node
*) cmpioreq
)->ln_Succ
)
1254 if(ioreq
== cmpioreq
)
1259 cmpioreq
= (struct IOUsbHWReq
*) cmpioreq
->iouh_Req
.io_Message
.mn_Node
.ln_Succ
;
1264 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_IsoXFerQueue
.lh_Head
;
1265 while(((struct Node
*) cmpioreq
)->ln_Succ
)
1267 if(ioreq
== cmpioreq
)
1272 cmpioreq
= (struct IOUsbHWReq
*) cmpioreq
->iouh_Req
.io_Message
.mn_Node
.ln_Succ
;
1277 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_BulkXFerQueue
.lh_Head
;
1278 while(((struct Node
*) cmpioreq
)->ln_Succ
)
1280 if(ioreq
== cmpioreq
)
1285 cmpioreq
= (struct IOUsbHWReq
*) cmpioreq
->iouh_Req
.io_Message
.mn_Node
.ln_Succ
;
1290 // IOReq is probably pending in some transfer structure
1291 devadrep
= (ioreq
->iouh_DevAddr
<<5) + ioreq
->iouh_Endpoint
+ ((ioreq
->iouh_Dir
== UHDIR_IN
) ? 0x10 : 0);
1293 cmpioreq
= (struct IOUsbHWReq
*) hc
->hc_TDQueue
.lh_Head
;
1294 while(((struct Node
*) cmpioreq
)->ln_Succ
) {
1295 if(ioreq
== cmpioreq
) {
1297 unit
->hu_DevBusyReq
[devadrep
] = NULL
;
1298 uhciFreeQContext(hc
, (struct UhciQH
*) ioreq
->iouh_DriverPrivate1
);
1301 cmpioreq
= (struct IOUsbHWReq
*) cmpioreq
->iouh_Req
.io_Message
.mn_Node
.ln_Succ
;
1306 Remove(&ioreq
->iouh_Req
.io_Message
.mn_Node
);
1309 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
1314 ioreq
->iouh_Req
.io_Error
= IOERR_ABORTED
;
1316 ioreq
->iouh_Req
.io_Message
.mn_Node
.ln_Type
= NT_FREEMSG
;
1318 /* If not quick I/O, reply the message */
1319 if(!(ioreq
->iouh_Req
.io_Flags
& IOF_QUICK
)) {
1320 ReplyMsg(&ioreq
->iouh_Req
.io_Message
);
1323 KPRINTF(20, ("WARNING, could not abort unknown IOReq %p\n", ioreq
));
1329 /* /// "uhwCheckRootHubChanges()" */
1330 void uhwCheckRootHubChanges(struct PCIUnit
*unit
)
1332 struct IOUsbHWReq
*ioreq
;
1334 if(unit
->hu_RootPortChanges
&& unit
->hu_RHIOQueue
.lh_Head
->ln_Succ
)
1336 KPRINTF(1, ("Portchange map %04lx\n", unit
->hu_RootPortChanges
));
1338 ioreq
= (struct IOUsbHWReq
*) unit
->hu_RHIOQueue
.lh_Head
;
1339 while(((struct Node
*) ioreq
)->ln_Succ
)
1341 Remove(&ioreq
->iouh_Req
.io_Message
.mn_Node
);
1342 if((unit
->hu_RootHubPorts
< 8) || (ioreq
->iouh_Length
== 1))
1344 *((UBYTE
*) ioreq
->iouh_Data
) = unit
->hu_RootPortChanges
;
1345 ioreq
->iouh_Actual
= 1;
1347 ((UBYTE
*) ioreq
->iouh_Data
)[0] = unit
->hu_RootPortChanges
;
1348 ((UBYTE
*) ioreq
->iouh_Data
)[1] = unit
->hu_RootPortChanges
>>8;
1349 ioreq
->iouh_Actual
= 2;
1351 ReplyMsg(&ioreq
->iouh_Req
.io_Message
);
1352 ioreq
= (struct IOUsbHWReq
*) unit
->hu_RHIOQueue
.lh_Head
;
1354 unit
->hu_RootPortChanges
= 0;
1360 /* /// "uhwCheckSpecialCtrlTransfers()" */
1361 void uhwCheckSpecialCtrlTransfers(struct PCIController
*hc
, struct IOUsbHWReq
*ioreq
)
1363 struct PCIUnit
*unit
= hc
->hc_Unit
;
1365 /* Clear Feature(Endpoint halt) */
1366 if((ioreq
->iouh_SetupData
.bmRequestType
== (URTF_STANDARD
|URTF_ENDPOINT
)) &&
1367 (ioreq
->iouh_SetupData
.bRequest
== USR_CLEAR_FEATURE
) &&
1368 (ioreq
->iouh_SetupData
.wValue
== AROS_WORD2LE(UFS_ENDPOINT_HALT
)))
1370 KPRINTF(10, ("Resetting toggle bit for endpoint %ld\n", AROS_WORD2LE(ioreq
->iouh_SetupData
.wIndex
) & 0xf));
1371 unit
->hu_DevDataToggle
[(ioreq
->iouh_DevAddr
<<5)|(AROS_WORD2LE(ioreq
->iouh_SetupData
.wIndex
) & 0xf)|((AROS_WORD2LE(ioreq
->iouh_SetupData
.wIndex
) & 0x80)>>3)] = 0;
1373 else if((ioreq
->iouh_SetupData
.bmRequestType
== (URTF_STANDARD
|URTF_DEVICE
)) &&
1374 (ioreq
->iouh_SetupData
.bRequest
== USR_SET_ADDRESS
))
1376 /* Set Address -> clear all endpoints */
1378 ULONG adr
= AROS_WORD2BE(ioreq
->iouh_SetupData
.wValue
)>>3;
1379 KPRINTF(10, ("Resetting toggle bits for device address %ld\n", adr
>>5));
1380 for(epnum
= 0; epnum
< 31; epnum
++)
1382 unit
->hu_DevDataToggle
[adr
+epnum
] = 0;
1384 // transfer host controller ownership
1385 unit
->hu_DevControllers
[ioreq
->iouh_DevAddr
] = NULL
;
1386 unit
->hu_DevControllers
[adr
>>5] = hc
;
1388 else if((ioreq
->iouh_SetupData
.bmRequestType
== (URTF_CLASS
|URTF_OTHER
)) &&
1389 (ioreq
->iouh_SetupData
.bRequest
== USR_SET_FEATURE
) &&
1390 (ioreq
->iouh_SetupData
.wValue
== AROS_WORD2LE(UFS_PORT_RESET
)))
1392 // a hub will be enumerating a device on this host controller soon!
1393 KPRINTF(10, ("Hub RESET caught, assigning Dev0 to %p!\n", hc
));
1394 unit
->hu_DevControllers
[0] = hc
;
1399 /* /// "uhwNakTimeoutInt()" */
1400 AROS_INTH1(uhwNakTimeoutInt
, struct PCIUnit
*, unit
)
1404 struct PCIDevice
*base
= unit
->hu_Device
;
1405 struct PCIController
*hc
;
1406 struct IOUsbHWReq
*ioreq
;
1414 KPRINTF(1, ("Enter NakTimeoutInt(0x%p)\n", unit
));
1416 // check for port status change for UHCI and frame rollovers and NAK Timeouts
1417 hc
= (struct PCIController
*) unit
->hu_Controllers
.lh_Head
;
1418 while(hc
->hc_Node
.ln_Succ
) {
1419 if (!(hc
->hc_Flags
& HCF_ONLINE
)) {
1420 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
1425 uhciUpdateFrameCounter(hc
);
1426 framecnt
= hc
->hc_FrameCounter
;
1429 ioreq
= (struct IOUsbHWReq
*) hc
->hc_TDQueue
.lh_Head
;
1430 while(((struct Node
*) ioreq
)->ln_Succ
) {
1431 if(ioreq
->iouh_Flags
& UHFF_NAKTIMEOUT
) {
1432 uqh
= (struct UhciQH
*) ioreq
->iouh_DriverPrivate1
;
1434 KPRINTF(1, ("Examining IOReq=%p with UQH=%p\n", ioreq
, uqh
));
1435 devadrep
= (ioreq
->iouh_DevAddr
<<5) + ioreq
->iouh_Endpoint
+ ((ioreq
->iouh_Dir
== UHDIR_IN
) ? 0x10 : 0);
1436 linkelem
= READMEM32_LE(&uqh
->uqh_Element
);
1437 if(linkelem
& UHCI_TERMINATE
) {
1438 KPRINTF(1, ("UQH terminated %08lx\n", linkelem
));
1439 if(framecnt
> unit
->hu_NakTimeoutFrame
[devadrep
]) {
1440 // give the thing the chance to exit gracefully
1441 KPRINTF(20, ("Terminated? NAK timeout %ld > %ld, IOReq=%p\n", framecnt
, unit
->hu_NakTimeoutFrame
[devadrep
], ioreq
));
1445 utd
= (struct UhciTD
*) (((IPTR
)linkelem
& UHCI_PTRMASK
) - hc
->hc_PCIVirtualAdjust
- 16); // struct UhciTD starts 16 before physical TD
1446 ctrlstatus
= READMEM32_LE(&utd
->utd_CtrlStatus
);
1447 if(ctrlstatus
& UTCF_ACTIVE
) {
1448 if(framecnt
> unit
->hu_NakTimeoutFrame
[devadrep
]) {
1449 // give the thing the chance to exit gracefully
1450 KPRINTF(20, ("NAK timeout %ld > %ld, IOReq=%p\n", framecnt
, unit
->hu_NakTimeoutFrame
[devadrep
], ioreq
));
1451 ctrlstatus
&= ~UTCF_ACTIVE
;
1452 WRITEMEM32_LE(&utd
->utd_CtrlStatus
, ctrlstatus
);
1456 if(framecnt
> unit
->hu_NakTimeoutFrame
[devadrep
]) {
1457 // give the thing the chance to exit gracefully
1458 KPRINTF(20, ("Terminated? NAK timeout %ld > %ld, IOReq=%p\n", framecnt
, unit
->hu_NakTimeoutFrame
[devadrep
], ioreq
));
1465 ioreq
= (struct IOUsbHWReq
*) ((struct Node
*) ioreq
)->ln_Succ
;
1468 uhciCheckPortStatusChange(hc
);
1471 SureCause(base
, &hc
->hc_CompleteInt
);
1474 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
1477 uhwCheckRootHubChanges(unit
);
1479 unit
->hu_NakTimeoutReq
.tr_time
.tv_micro
= 150*1000;
1480 SendIO((APTR
) &unit
->hu_NakTimeoutReq
);
1482 KPRINTF(1, ("Exit NakTimeoutInt(0x%p)\n", unit
));