revert between 56095 -> 55830 in arch
[AROS.git] / rom / usb / pciusbhc / uhci / uhwcmd.c
blobae729266702e1bc9615e18e012cb6615d0b79537
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>
8 #include <strings.h>
10 #include "uhwcmd.h"
12 /* we cannot use AROS_WORD2LE in struct initializer */
13 #if AROS_BIG_ENDIAN
14 #define WORD2LE(w) (UWORD)(((w) >> 8) & 0x00FF) | (((w) << 8) & 0xFF00)
15 #else
16 #define WORD2LE(w) (w)
17 #endif
19 /* Root hub data */
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 */
41 Disable();
43 if((interrupt->is_Node.ln_Type == NT_SOFTINT) || (interrupt->is_Node.ln_Type == NT_USER))
45 // signal tailed call
46 interrupt->is_Node.ln_Type = NT_USER;
47 } else {
50 interrupt->is_Node.ln_Type = NT_SOFTINT;
51 Forbid(); // make sure code is not interrupted by other tasks
52 Enable();
53 AROS_INTC1(interrupt->is_Code, interrupt->is_Data);
54 Disable();
55 Permit();
56 } while(interrupt->is_Node.ln_Type != NT_SOFTINT);
57 interrupt->is_Node.ln_Type = NT_INTERRUPT;
59 Enable();
61 /* \\\ */
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"));
75 return(TRUE);
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"));
84 return(FALSE);
86 /* \\\ */
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);
95 /* \\\ */
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);
104 /* \\\ */
106 /* /// "uhwCloseTimer()" */
107 void uhwCloseTimer(struct PCIUnit *unit, struct PCIDevice *base)
109 if(unit->hu_MsgPort)
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;
122 /* \\\ */
124 /* /// "Open_Unit()" */
125 struct Unit * Open_Unit(struct IOUsbHWReq *ioreq,
126 LONG unitnr,
127 struct PCIDevice *base)
129 struct PCIUnit *unit = NULL;
131 if(!base->hd_ScanDone)
133 base->hd_ScanDone = TRUE;
134 if(!pciInit(base))
136 return NULL;
139 unit = (struct PCIUnit *) base->hd_Units.lh_Head;
140 while(((struct Node *) unit)->ln_Succ)
142 if(unit->hu_UnitNo == unitnr)
144 break;
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));
151 return NULL;
153 if(unit->hu_UnitAllocated)
155 ioreq->iouh_Req.io_Error = IOERR_UNITBUSY;
156 KPRINTF(5, ("Unit %ld already open!\n", unitnr));
157 return NULL;
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);
181 } else {
182 ioreq->iouh_Req.io_Error = IOERR_SELFTEST;
183 KPRINTF(20, ("Hardware allocation failure!\n"));
185 uhwCloseTimer(unit, base);
187 return(NULL);
189 /* \\\ */
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);
201 pciFreeUnit(unit);
203 uhwCloseTimer(unit, base);
204 unit->hu_UnitAllocated = FALSE;
206 /* \\\ */
208 /* /// "uhwGetUsbState()" */
209 UWORD uhwGetUsbState(struct IOUsbHWReq *ioreq,
210 struct PCIUnit *unit,
211 struct PCIDevice *base)
213 return(ioreq->iouh_State = UHSF_OPERATIONAL);
215 /* \\\ */
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));
236 uhwDelayMS(1, unit);
237 uhwGetUsbState(ioreq, unit, base);
239 if(ioreq->iouh_State & UHSF_OPERATIONAL)
241 return RC_OK;
243 return UHIOERR_USBOFFLINE;
245 /* \\\ */
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));
266 /* FIXME */
267 uhwGetUsbState(ioreq, unit, base);
269 unit->hu_RootHubAddr = 0;
271 if(ioreq->iouh_State & UHSF_OPERATIONAL)
273 return RC_OK;
275 return UHIOERR_USBOFFLINE;
277 /* \\\ */
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));
298 /* FIXME */
299 uhwGetUsbState(ioreq, unit, base);
300 if(ioreq->iouh_State & UHSF_OPERATIONAL)
302 return RC_OK;
304 return UHIOERR_USBOFFLINE;
306 /* \\\ */
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));
327 /* FIXME */
328 uhwGetUsbState(ioreq, unit, base);
329 if(ioreq->iouh_State & UHSF_SUSPENDED)
331 return RC_OK;
333 return UHIOERR_USBOFFLINE;
335 /* \\\ */
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));
356 /* FIXME */
357 uhwGetUsbState(ioreq, unit, base);
358 if(ioreq->iouh_State & UHSF_OPERATIONAL)
360 return RC_OK;
362 return UHIOERR_USBOFFLINE;
364 /* \\\ */
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;
383 struct TagItem *tag;
384 ULONG count = 0;
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);
391 count++;
393 if((tag = FindTagItem(UHA_Manufacturer, taglist)))
395 *((STRPTR *) tag->ti_Data) = "Chris Hodges";
396 count++;
398 if((tag = FindTagItem(UHA_ProductName, taglist)))
400 *((STRPTR *) tag->ti_Data) = "PCI UHCI USB 1.1 Host Controller";
401 count++;
403 if((tag = FindTagItem(UHA_Description, taglist)))
405 *((STRPTR *) tag->ti_Data) = "Generic adaptive host controller driver for PCI cards";
406 count++;
408 if((tag = FindTagItem(UHA_Copyright, taglist)))
410 *((STRPTR *) tag->ti_Data) ="©2007-2009 Chris Hodges";
411 count++;
413 if((tag = FindTagItem(UHA_Version, taglist)))
415 *((ULONG *) tag->ti_Data) = VERSION_NUMBER;
416 count++;
418 if((tag = FindTagItem(UHA_Revision, taglist)))
420 *((ULONG *) tag->ti_Data) = REVISION_NUMBER;
421 count++;
423 if((tag = FindTagItem(UHA_DriverVersion, taglist)))
425 *((ULONG *) tag->ti_Data) = 0x220;
426 count++;
428 if((tag = FindTagItem(UHA_Capabilities, taglist)))
430 *((ULONG *) tag->ti_Data) = UHCF_USB20;
431 count++;
433 ioreq->iouh_Actual = count;
434 return RC_OK;
436 /* \\\ */
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);
450 UWORD hciport;
451 ULONG numports = unit->hu_RootHubPorts;
452 BOOL cmdgood;
453 ULONG cnt;
455 UWORD portreg;
456 ULONG oldval;
457 ULONG newval;
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);
468 switch(rt) {
469 case (URTF_STANDARD|URTF_DEVICE):
470 switch(req) {
471 case USR_SET_ADDRESS:
472 KPRINTF(1, ("RH: SetAddress = %ld\n", val));
473 unit->hu_RootHubAddr = val;
474 ioreq->iouh_Actual = len;
475 return(0);
477 case USR_SET_CONFIGURATION:
478 KPRINTF(1, ("RH: SetConfiguration=%ld\n", val));
479 ioreq->iouh_Actual = len;
480 return(0);
482 break;
484 case (URTF_IN|URTF_STANDARD|URTF_DEVICE):
485 switch(req) {
486 case USR_GET_DESCRIPTOR:
487 switch(val>>8) {
488 case UDT_DEVICE:
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);
492 return(0);
494 case UDT_CONFIGURATION: {
495 UBYTE tmpbuf[9+9+7];
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);
502 return(0);
505 case UDT_STRING:
506 if(val & 0xff) /* get lang array */
508 CONST_STRPTR source = NULL;
509 UWORD *mptr = ioreq->iouh_Data;
510 UWORD slen = 1;
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];
517 if(len > 1)
519 ioreq->iouh_Actual = 2;
520 while(*source++)
522 slen++;
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);
531 } else {
532 *mptr++ = AROS_WORD2LE(*source);
534 source++;
535 ioreq->iouh_Actual += 2;
536 if(!(*source)) {
537 break;
541 } else {
542 UWORD *mptr = ioreq->iouh_Data;
543 KPRINTF(1, ("RH: GetLangArray %04lx (%ld)\n", val, len));
544 if(len > 1) {
545 ioreq->iouh_Actual = 2;
546 mptr[0] = AROS_WORD2BE((4<<8)|UDT_STRING);
547 if(len > 3)
549 ioreq->iouh_Actual += 2;
550 mptr[1] = AROS_WORD2LE(0x0409);
554 return(0);
556 default:
557 KPRINTF(1, ("RH: Unsupported Descriptor %04lx\n", idx));
559 break;
561 case USR_GET_CONFIGURATION:
562 if(len == 1) {
563 KPRINTF(1, ("RH: GetConfiguration\n"));
564 ((UBYTE *) ioreq->iouh_Data)[0] = 1;
565 ioreq->iouh_Actual = len;
566 return(0);
568 break;
570 break;
572 case (URTF_CLASS|URTF_OTHER):
573 switch(req) {
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])
582 // {
583 // hc = unit->hu_PortMap20[idx - 1];
584 // hciport = idx - 1;
585 // } else {
586 hc = chc;
587 hciport = unit->hu_PortNum11[idx - 1];
588 // }
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"));
590 cmdgood = FALSE;
592 portreg = hciport ? UHCI_PORT2STSCTRL : UHCI_PORT1STSCTRL;
593 oldval = READIO16_LE(hc->hc_RegBase, portreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE); // these are clear-on-write!
594 newval = oldval;
596 switch(val) {
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;
601 cmdgood = TRUE;
602 break;
604 case UFS_PORT_SUSPEND:
605 newval |= UHPF_PORTSUSPEND;
606 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_SUSPEND; // manually fake suspend change
607 cmdgood = TRUE;
608 break;
610 /* case UFS_PORT_OVER_CURRENT: not possible */
611 case UFS_PORT_RESET:
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
635 cnt = 100;
636 do {
637 uhwDelayMS(1, unit);
638 newval = READIO16_LE(hc->hc_RegBase, portreg);
639 } while(--cnt && (!(newval & UHPF_PORTENABLE)));
641 if(cnt) {
642 KPRINTF(10, ("Enabled after %ld ticks\n", 100-cnt));
643 } else {
644 KPRINTF(20, ("Port refuses to be enabled!\n"));
645 return(UHIOERR_HOSTERROR);
648 // make enumeration possible
649 unit->hu_DevControllers[0] = hc;
650 cmdgood = TRUE;
651 break;
653 case UFS_PORT_POWER:
654 KPRINTF(10, ("Powering Port\n"));
655 // ignore for UHCI, is always powered
656 cmdgood = TRUE;
657 break;
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: */
667 if(cmdgood) {
668 KPRINTF(5, ("Port %ld SET_FEATURE %04lx->%04lx\n", idx, oldval, newval));
669 WRITEIO16_LE(hc->hc_RegBase, portreg, newval);
670 return(0);
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])
680 // {
681 // hc = unit->hu_PortMap20[idx - 1];
682 // hciport = idx - 1;
683 // } else {
684 hc = unit->hu_PortMap11[idx - 1];
685 hciport = unit->hu_PortNum11[idx - 1];
686 // }
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"));
688 cmdgood = FALSE;
690 portreg = hciport ? UHCI_PORT2STSCTRL : UHCI_PORT1STSCTRL;
691 oldval = READIO16_LE(hc->hc_RegBase, portreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE); // these are clear-on-write!
692 newval = oldval;
693 switch(val) {
694 case UFS_PORT_ENABLE:
695 KPRINTF(10, ("Disabling Port (%s)\n", newval & UHPF_PORTENABLE ? "ok" : "already"));
696 newval &= ~UHPF_PORTENABLE;
697 cmdgood = TRUE;
698 // disable enumeration
699 unit->hu_DevControllers[0] = NULL;
700 break;
702 case UFS_PORT_SUSPEND:
703 newval &= ~UHPF_PORTSUSPEND;
704 cmdgood = TRUE;
705 break;
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;
711 cmdgood = TRUE;
712 break;
714 case UFS_C_PORT_CONNECTION:
715 newval |= UHPF_CONNECTCHANGE; // clear-on-write!
716 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_CONNECTION;
717 cmdgood = TRUE;
718 break;
720 case UFS_C_PORT_ENABLE:
721 newval |= UHPF_ENABLECHANGE; // clear-on-write!
722 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_ENABLE;
723 cmdgood = TRUE;
724 break;
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
728 cmdgood = TRUE;
729 break;
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
733 cmdgood = TRUE;
734 break;
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
738 cmdgood = TRUE;
739 break;
742 if(cmdgood) {
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;
747 } else {
748 unit->hu_RootPortChanges &= ~(1UL<<idx);
750 return(0);
753 break;
755 break;
757 case (URTF_IN|URTF_CLASS|URTF_OTHER):
758 switch(req) {
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])
771 // {
772 // hc = unit->hu_PortMap20[idx - 1];
773 // hciport = idx - 1;
774 // } else {
775 hc = unit->hu_PortMap11[idx - 1];
776 hciport = unit->hu_PortNum11[idx - 1];
777 // }
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));
792 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));
805 return(0);
809 break;
811 case (URTF_IN|URTF_CLASS|URTF_DEVICE):
812 switch(req)
814 case USR_GET_STATUS:
816 UWORD *mptr = ioreq->iouh_Data;
817 if(len < sizeof(struct UsbHubStatus))
819 return(UHIOERR_STALL);
821 *mptr++ = 0;
822 *mptr++ = 0;
823 ioreq->iouh_Actual = 4;
824 return(0);
827 case USR_GET_DESCRIPTOR:
828 switch(val>>8)
830 case UDT_HUB:
832 ULONG hubdesclen = 9;
833 ULONG powergood = 1;
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
840 hubdesclen += 2;
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;
859 if(hubdesclen == 9)
861 uhd->DeviceRemovable = 0;
862 uhd->PortPwrCtrlMask = (1<<(unit->hu_RootHubPorts+2))-2;
863 } else {
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;
871 return(0);
874 default:
875 KPRINTF(20, ("RH: Unsupported Descriptor %04lx\n", idx));
877 break;
881 KPRINTF(20, ("RH: Unsupported command %02lx %02lx %04lx %04lx %04lx!\n", rt, req, idx, val, len));
882 return(UHIOERR_STALL);
884 /* \\\ */
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;
903 } else {
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;
909 return(0);
911 ioreq->iouh_Req.io_Flags &= ~IOF_QUICK;
912 Disable();
913 AddTail(&unit->hu_RHIOQueue, (struct Node *) ioreq);
914 Enable();
915 return(RC_DONTREPLY);
917 /* \\\ */
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];
952 if(!hc)
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;
961 Disable();
962 AddTail(&hc->hc_CtrlXFerQueue, (struct Node *) ioreq);
963 Enable();
964 SureCause(base, &hc->hc_CompleteInt);
966 KPRINTF(10, ("UHCMD_CONTROLXFER processed ioreq: 0x%p\n", ioreq));
967 return(RC_DONTREPLY);
969 /* \\\ */
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];
1004 if(!hc)
1006 return(UHIOERR_HOSTERROR);
1009 ioreq->iouh_Req.io_Flags &= ~IOF_QUICK;
1010 ioreq->iouh_Actual = 0;
1012 Disable();
1013 AddTail(&hc->hc_BulkXFerQueue, (struct Node *) ioreq);
1014 Enable();
1015 SureCause(base, &hc->hc_CompleteInt);
1017 KPRINTF(10, ("UHCMD_BULKXFER processed ioreq: 0x%p\n", ioreq));
1018 return(RC_DONTREPLY);
1020 /* \\\ */
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];
1055 if(!hc)
1057 return(UHIOERR_HOSTERROR);
1060 ioreq->iouh_Req.io_Flags &= ~IOF_QUICK;
1061 ioreq->iouh_Actual = 0;
1063 Disable();
1064 AddTail(&hc->hc_IsoXFerQueue, (struct Node *) ioreq);
1065 Enable();
1066 SureCause(base, &hc->hc_CompleteInt);
1068 KPRINTF(10, ("UHCMD_ISOXFER processed ioreq: 0x%p\n", ioreq));
1069 return(RC_DONTREPLY);
1071 /* \\\ */
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];
1108 if(!hc)
1110 return(UHIOERR_HOSTERROR);
1113 ioreq->iouh_Req.io_Flags &= ~IOF_QUICK;
1114 ioreq->iouh_Actual = 0;
1116 Disable();
1117 AddTail(&hc->hc_IntXFerQueue, (struct Node *) ioreq);
1118 Enable();
1119 SureCause(base, &hc->hc_CompleteInt);
1121 KPRINTF(10, ("UHCMD_INTXFER processed ioreq: 0x%p\n", ioreq));
1122 return(RC_DONTREPLY);
1124 /* \\\ */
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;
1144 UWORD devadrep;
1146 KPRINTF(10, ("CMD_FLUSH ioreq: 0x%p\n", ioreq));
1148 Disable();
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;
1205 Enable();
1206 /* Return success
1208 return RC_OK;
1210 /* \\\ */
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;
1218 UWORD devadrep;
1219 BOOL foundit = FALSE;
1221 KPRINTF(10, ("cmdAbort(%p)\n", ioreq));
1223 Disable();
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);
1230 Enable();
1231 return TRUE;
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)
1244 foundit = TRUE;
1245 break;
1247 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
1249 if(!foundit)
1251 cmpioreq = (struct IOUsbHWReq *) hc->hc_IntXFerQueue.lh_Head;
1252 while(((struct Node *) cmpioreq)->ln_Succ)
1254 if(ioreq == cmpioreq)
1256 foundit = TRUE;
1257 break;
1259 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
1262 if(!foundit)
1264 cmpioreq = (struct IOUsbHWReq *) hc->hc_IsoXFerQueue.lh_Head;
1265 while(((struct Node *) cmpioreq)->ln_Succ)
1267 if(ioreq == cmpioreq)
1269 foundit = TRUE;
1270 break;
1272 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
1276 if(!foundit) {
1277 cmpioreq = (struct IOUsbHWReq *) hc->hc_BulkXFerQueue.lh_Head;
1278 while(((struct Node *) cmpioreq)->ln_Succ)
1280 if(ioreq == cmpioreq)
1282 foundit = TRUE;
1283 break;
1285 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
1289 if(!foundit) {
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) {
1296 foundit = TRUE;
1297 unit->hu_DevBusyReq[devadrep] = NULL;
1298 uhciFreeQContext(hc, (struct UhciQH *) ioreq->iouh_DriverPrivate1);
1299 break;
1301 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
1305 if(foundit) {
1306 Remove(&ioreq->iouh_Req.io_Message.mn_Node);
1307 break;
1309 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
1311 Enable();
1313 if (foundit) {
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);
1322 }else{
1323 KPRINTF(20, ("WARNING, could not abort unknown IOReq %p\n", ioreq));
1325 return(foundit);
1327 /* \\\ */
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));
1337 Disable();
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;
1346 } else {
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;
1355 Enable();
1358 /* \\\ */
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 */
1377 ULONG epnum;
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;
1397 /* \\\ */
1399 /* /// "uhwNakTimeoutInt()" */
1400 AROS_INTH1(uhwNakTimeoutInt, struct PCIUnit *, unit)
1402 AROS_INTFUNC_INIT
1404 struct PCIDevice *base = unit->hu_Device;
1405 struct PCIController *hc;
1406 struct IOUsbHWReq *ioreq;
1407 struct UhciQH *uqh;
1408 struct UhciTD *utd;
1409 UWORD devadrep;
1410 ULONG linkelem;
1411 ULONG ctrlstatus;
1412 BOOL causeint;
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;
1421 continue;
1423 causeint = FALSE;
1424 ULONG framecnt;
1425 uhciUpdateFrameCounter(hc);
1426 framecnt = hc->hc_FrameCounter;
1428 // NakTimeout
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;
1433 if(uqh) {
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));
1442 causeint = TRUE;
1444 } else {
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);
1453 causeint = TRUE;
1455 } else {
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));
1459 causeint = TRUE;
1465 ioreq = (struct IOUsbHWReq *) ((struct Node *) ioreq)->ln_Succ;
1468 uhciCheckPortStatusChange(hc);
1470 if(causeint) {
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));
1484 return FALSE;
1486 AROS_INTFUNC_EXIT
1488 /* \\\ */