Check for SYS/GL during library init. Reason is that
[AROS.git] / rom / usb / pciusbhc / uhci / uhwcmd.c
blobfadd9aae3ff5f9188debd54c9af83130514faf30
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 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);
180 } else {
181 ioreq->iouh_Req.io_Error = IOERR_SELFTEST;
182 KPRINTF(20, ("Hardware allocation failure!\n"));
184 uhwCloseTimer(unit, base);
186 return(NULL);
188 /* \\\ */
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);
200 pciFreeUnit(unit);
202 uhwCloseTimer(unit, base);
203 unit->hu_UnitAllocated = FALSE;
205 /* \\\ */
207 /* /// "uhwGetUsbState()" */
208 UWORD uhwGetUsbState(struct IOUsbHWReq *ioreq,
209 struct PCIUnit *unit,
210 struct PCIDevice *base)
212 return(ioreq->iouh_State = UHSF_OPERATIONAL);
214 /* \\\ */
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));
235 uhwDelayMS(1, unit);
236 uhwGetUsbState(ioreq, unit, base);
238 if(ioreq->iouh_State & UHSF_OPERATIONAL)
240 return RC_OK;
242 return UHIOERR_USBOFFLINE;
244 /* \\\ */
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));
265 /* FIXME */
266 uhwGetUsbState(ioreq, unit, base);
268 unit->hu_RootHubAddr = 0;
270 if(ioreq->iouh_State & UHSF_OPERATIONAL)
272 return RC_OK;
274 return UHIOERR_USBOFFLINE;
276 /* \\\ */
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));
297 /* FIXME */
298 uhwGetUsbState(ioreq, unit, base);
299 if(ioreq->iouh_State & UHSF_OPERATIONAL)
301 return RC_OK;
303 return UHIOERR_USBOFFLINE;
305 /* \\\ */
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));
326 /* FIXME */
327 uhwGetUsbState(ioreq, unit, base);
328 if(ioreq->iouh_State & UHSF_SUSPENDED)
330 return RC_OK;
332 return UHIOERR_USBOFFLINE;
334 /* \\\ */
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));
355 /* FIXME */
356 uhwGetUsbState(ioreq, unit, base);
357 if(ioreq->iouh_State & UHSF_OPERATIONAL)
359 return RC_OK;
361 return UHIOERR_USBOFFLINE;
363 /* \\\ */
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;
382 struct TagItem *tag;
383 ULONG count = 0;
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);
390 count++;
392 if((tag = FindTagItem(UHA_Manufacturer, taglist)))
394 *((STRPTR *) tag->ti_Data) = "Chris Hodges";
395 count++;
397 if((tag = FindTagItem(UHA_ProductName, taglist)))
399 *((STRPTR *) tag->ti_Data) = "PCI UHCI USB 1.1 Host Controller";
400 count++;
402 if((tag = FindTagItem(UHA_Description, taglist)))
404 *((STRPTR *) tag->ti_Data) = "Generic adaptive host controller driver for PCI cards";
405 count++;
407 if((tag = FindTagItem(UHA_Copyright, taglist)))
409 *((STRPTR *) tag->ti_Data) ="©2007-2009 Chris Hodges";
410 count++;
412 if((tag = FindTagItem(UHA_Version, taglist)))
414 *((ULONG *) tag->ti_Data) = VERSION_NUMBER;
415 count++;
417 if((tag = FindTagItem(UHA_Revision, taglist)))
419 *((ULONG *) tag->ti_Data) = REVISION_NUMBER;
420 count++;
422 if((tag = FindTagItem(UHA_DriverVersion, taglist)))
424 *((ULONG *) tag->ti_Data) = 0x220;
425 count++;
427 if((tag = FindTagItem(UHA_Capabilities, taglist)))
429 *((ULONG *) tag->ti_Data) = UHCF_USB20;
430 count++;
432 ioreq->iouh_Actual = count;
433 return RC_OK;
435 /* \\\ */
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);
449 UWORD hciport;
450 ULONG numports = unit->hu_RootHubPorts;
451 BOOL cmdgood;
452 ULONG cnt;
454 UWORD portreg;
455 ULONG oldval;
456 ULONG newval;
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);
467 switch(rt) {
468 case (URTF_STANDARD|URTF_DEVICE):
469 switch(req) {
470 case USR_SET_ADDRESS:
471 KPRINTF(1, ("RH: SetAddress = %ld\n", val));
472 unit->hu_RootHubAddr = val;
473 ioreq->iouh_Actual = len;
474 return(0);
476 case USR_SET_CONFIGURATION:
477 KPRINTF(1, ("RH: SetConfiguration=%ld\n", val));
478 ioreq->iouh_Actual = len;
479 return(0);
481 break;
483 case (URTF_IN|URTF_STANDARD|URTF_DEVICE):
484 switch(req) {
485 case USR_GET_DESCRIPTOR:
486 switch(val>>8) {
487 case UDT_DEVICE:
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);
491 return(0);
493 case UDT_CONFIGURATION: {
494 UBYTE tmpbuf[9+9+7];
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);
501 return(0);
504 case UDT_STRING:
505 if(val & 0xff) /* get lang array */
507 CONST_STRPTR source = NULL;
508 UWORD *mptr = ioreq->iouh_Data;
509 UWORD slen = 1;
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];
516 if(len > 1)
518 ioreq->iouh_Actual = 2;
519 while(*source++)
521 slen++;
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);
530 } else {
531 *mptr++ = AROS_WORD2LE(*source);
533 source++;
534 ioreq->iouh_Actual += 2;
535 if(!(*source)) {
536 break;
540 } else {
541 UWORD *mptr = ioreq->iouh_Data;
542 KPRINTF(1, ("RH: GetLangArray %04lx (%ld)\n", val, len));
543 if(len > 1) {
544 ioreq->iouh_Actual = 2;
545 mptr[0] = AROS_WORD2BE((4<<8)|UDT_STRING);
546 if(len > 3)
548 ioreq->iouh_Actual += 2;
549 mptr[1] = AROS_WORD2LE(0x0409);
553 return(0);
555 default:
556 KPRINTF(1, ("RH: Unsupported Descriptor %04lx\n", idx));
558 break;
560 case USR_GET_CONFIGURATION:
561 if(len == 1) {
562 KPRINTF(1, ("RH: GetConfiguration\n"));
563 ((UBYTE *) ioreq->iouh_Data)[0] = 1;
564 ioreq->iouh_Actual = len;
565 return(0);
567 break;
569 break;
571 case (URTF_CLASS|URTF_OTHER):
572 switch(req) {
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])
581 // {
582 // hc = unit->hu_PortMap20[idx - 1];
583 // hciport = idx - 1;
584 // } else {
585 hc = chc;
586 hciport = unit->hu_PortNum11[idx - 1];
587 // }
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"));
589 cmdgood = FALSE;
591 portreg = hciport ? UHCI_PORT2STSCTRL : UHCI_PORT1STSCTRL;
592 oldval = READIO16_LE(hc->hc_RegBase, portreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE); // these are clear-on-write!
593 newval = oldval;
595 switch(val) {
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;
600 cmdgood = TRUE;
601 break;
603 case UFS_PORT_SUSPEND:
604 newval |= UHPF_PORTSUSPEND;
605 hc->hc_PortChangeMap[hciport] |= UPSF_PORT_SUSPEND; // manually fake suspend change
606 cmdgood = TRUE;
607 break;
609 /* case UFS_PORT_OVER_CURRENT: not possible */
610 case UFS_PORT_RESET:
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
634 cnt = 100;
635 do {
636 uhwDelayMS(1, unit);
637 newval = READIO16_LE(hc->hc_RegBase, portreg);
638 } while(--cnt && (!(newval & UHPF_PORTENABLE)));
640 if(cnt) {
641 KPRINTF(10, ("Enabled after %ld ticks\n", 100-cnt));
642 } else {
643 KPRINTF(20, ("Port refuses to be enabled!\n"));
644 return(UHIOERR_HOSTERROR);
647 // make enumeration possible
648 unit->hu_DevControllers[0] = hc;
649 cmdgood = TRUE;
650 break;
652 case UFS_PORT_POWER:
653 KPRINTF(10, ("Powering Port\n"));
654 // ignore for UHCI, is always powered
655 cmdgood = TRUE;
656 break;
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: */
666 if(cmdgood) {
667 KPRINTF(5, ("Port %ld SET_FEATURE %04lx->%04lx\n", idx, oldval, newval));
668 WRITEIO16_LE(hc->hc_RegBase, portreg, newval);
669 return(0);
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])
679 // {
680 // hc = unit->hu_PortMap20[idx - 1];
681 // hciport = idx - 1;
682 // } else {
683 hc = unit->hu_PortMap11[idx - 1];
684 hciport = unit->hu_PortNum11[idx - 1];
685 // }
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"));
687 cmdgood = FALSE;
689 portreg = hciport ? UHCI_PORT2STSCTRL : UHCI_PORT1STSCTRL;
690 oldval = READIO16_LE(hc->hc_RegBase, portreg) & ~(UHPF_ENABLECHANGE|UHPF_CONNECTCHANGE); // these are clear-on-write!
691 newval = oldval;
692 switch(val) {
693 case UFS_PORT_ENABLE:
694 KPRINTF(10, ("Disabling Port (%s)\n", newval & UHPF_PORTENABLE ? "ok" : "already"));
695 newval &= ~UHPF_PORTENABLE;
696 cmdgood = TRUE;
697 // disable enumeration
698 unit->hu_DevControllers[0] = NULL;
699 break;
701 case UFS_PORT_SUSPEND:
702 newval &= ~UHPF_PORTSUSPEND;
703 cmdgood = TRUE;
704 break;
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;
710 cmdgood = TRUE;
711 break;
713 case UFS_C_PORT_CONNECTION:
714 newval |= UHPF_CONNECTCHANGE; // clear-on-write!
715 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_CONNECTION;
716 cmdgood = TRUE;
717 break;
719 case UFS_C_PORT_ENABLE:
720 newval |= UHPF_ENABLECHANGE; // clear-on-write!
721 hc->hc_PortChangeMap[hciport] &= ~UPSF_PORT_ENABLE;
722 cmdgood = TRUE;
723 break;
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
727 cmdgood = TRUE;
728 break;
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
732 cmdgood = TRUE;
733 break;
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
737 cmdgood = TRUE;
738 break;
741 if(cmdgood) {
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;
746 } else {
747 unit->hu_RootPortChanges &= ~(1UL<<idx);
749 return(0);
752 break;
754 break;
756 case (URTF_IN|URTF_CLASS|URTF_OTHER):
757 switch(req) {
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])
770 // {
771 // hc = unit->hu_PortMap20[idx - 1];
772 // hciport = idx - 1;
773 // } else {
774 hc = unit->hu_PortMap11[idx - 1];
775 hciport = unit->hu_PortNum11[idx - 1];
776 // }
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));
791 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));
804 return(0);
808 break;
810 case (URTF_IN|URTF_CLASS|URTF_DEVICE):
811 switch(req)
813 case USR_GET_STATUS:
815 UWORD *mptr = ioreq->iouh_Data;
816 if(len < sizeof(struct UsbHubStatus))
818 return(UHIOERR_STALL);
820 *mptr++ = 0;
821 *mptr++ = 0;
822 ioreq->iouh_Actual = 4;
823 return(0);
826 case USR_GET_DESCRIPTOR:
827 switch(val>>8)
829 case UDT_HUB:
831 ULONG hubdesclen = 9;
832 ULONG powergood = 1;
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
839 hubdesclen += 2;
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;
858 if(hubdesclen == 9)
860 uhd->DeviceRemovable = 0;
861 uhd->PortPwrCtrlMask = (1<<(unit->hu_RootHubPorts+2))-2;
862 } else {
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;
870 return(0);
873 default:
874 KPRINTF(20, ("RH: Unsupported Descriptor %04lx\n", idx));
876 break;
880 KPRINTF(20, ("RH: Unsupported command %02lx %02lx %04lx %04lx %04lx!\n", rt, req, idx, val, len));
881 return(UHIOERR_STALL);
883 /* \\\ */
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;
902 } else {
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;
908 return(0);
910 ioreq->iouh_Req.io_Flags &= ~IOF_QUICK;
911 Disable();
912 AddTail(&unit->hu_RHIOQueue, (struct Node *) ioreq);
913 Enable();
914 return(RC_DONTREPLY);
916 /* \\\ */
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];
951 if(!hc)
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;
960 Disable();
961 AddTail(&hc->hc_CtrlXFerQueue, (struct Node *) ioreq);
962 Enable();
963 SureCause(base, &hc->hc_CompleteInt);
965 KPRINTF(10, ("UHCMD_CONTROLXFER processed ioreq: 0x%p\n", ioreq));
966 return(RC_DONTREPLY);
968 /* \\\ */
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];
1003 if(!hc)
1005 return(UHIOERR_HOSTERROR);
1008 ioreq->iouh_Req.io_Flags &= ~IOF_QUICK;
1009 ioreq->iouh_Actual = 0;
1011 Disable();
1012 AddTail(&hc->hc_BulkXFerQueue, (struct Node *) ioreq);
1013 Enable();
1014 SureCause(base, &hc->hc_CompleteInt);
1016 KPRINTF(10, ("UHCMD_BULKXFER processed ioreq: 0x%p\n", ioreq));
1017 return(RC_DONTREPLY);
1019 /* \\\ */
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];
1054 if(!hc)
1056 return(UHIOERR_HOSTERROR);
1059 ioreq->iouh_Req.io_Flags &= ~IOF_QUICK;
1060 ioreq->iouh_Actual = 0;
1062 Disable();
1063 AddTail(&hc->hc_IsoXFerQueue, (struct Node *) ioreq);
1064 Enable();
1065 SureCause(base, &hc->hc_CompleteInt);
1067 KPRINTF(10, ("UHCMD_ISOXFER processed ioreq: 0x%p\n", ioreq));
1068 return(RC_DONTREPLY);
1070 /* \\\ */
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];
1107 if(!hc)
1109 return(UHIOERR_HOSTERROR);
1112 ioreq->iouh_Req.io_Flags &= ~IOF_QUICK;
1113 ioreq->iouh_Actual = 0;
1115 Disable();
1116 AddTail(&hc->hc_IntXFerQueue, (struct Node *) ioreq);
1117 Enable();
1118 SureCause(base, &hc->hc_CompleteInt);
1120 KPRINTF(10, ("UHCMD_INTXFER processed ioreq: 0x%p\n", ioreq));
1121 return(RC_DONTREPLY);
1123 /* \\\ */
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;
1143 UWORD devadrep;
1145 KPRINTF(10, ("CMD_FLUSH ioreq: 0x%p\n", ioreq));
1147 Disable();
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;
1204 Enable();
1205 /* Return success
1207 return RC_OK;
1209 /* \\\ */
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;
1217 UWORD devadrep;
1218 BOOL foundit = FALSE;
1220 KPRINTF(10, ("cmdAbort(%p)\n", ioreq));
1222 Disable();
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);
1229 Enable();
1230 return TRUE;
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)
1243 foundit = TRUE;
1244 break;
1246 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
1248 if(!foundit)
1250 cmpioreq = (struct IOUsbHWReq *) hc->hc_IntXFerQueue.lh_Head;
1251 while(((struct Node *) cmpioreq)->ln_Succ)
1253 if(ioreq == cmpioreq)
1255 foundit = TRUE;
1256 break;
1258 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
1261 if(!foundit)
1263 cmpioreq = (struct IOUsbHWReq *) hc->hc_IsoXFerQueue.lh_Head;
1264 while(((struct Node *) cmpioreq)->ln_Succ)
1266 if(ioreq == cmpioreq)
1268 foundit = TRUE;
1269 break;
1271 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
1275 if(!foundit) {
1276 cmpioreq = (struct IOUsbHWReq *) hc->hc_BulkXFerQueue.lh_Head;
1277 while(((struct Node *) cmpioreq)->ln_Succ)
1279 if(ioreq == cmpioreq)
1281 foundit = TRUE;
1282 break;
1284 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
1288 if(!foundit) {
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) {
1295 foundit = TRUE;
1296 unit->hu_DevBusyReq[devadrep] = NULL;
1297 uhciFreeQContext(hc, (struct UhciQH *) ioreq->iouh_DriverPrivate1);
1298 break;
1300 cmpioreq = (struct IOUsbHWReq *) cmpioreq->iouh_Req.io_Message.mn_Node.ln_Succ;
1304 if(foundit) {
1305 Remove(&ioreq->iouh_Req.io_Message.mn_Node);
1306 break;
1308 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
1310 Enable();
1312 if (foundit) {
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);
1321 }else{
1322 KPRINTF(20, ("WARNING, could not abort unknown IOReq %p\n", ioreq));
1324 return(foundit);
1326 /* \\\ */
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));
1336 Disable();
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;
1345 } else {
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;
1354 Enable();
1357 /* \\\ */
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 */
1376 ULONG epnum;
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;
1396 /* \\\ */
1398 /* /// "uhwNakTimeoutInt()" */
1399 AROS_INTH1(uhwNakTimeoutInt, struct PCIUnit *, unit)
1401 AROS_INTFUNC_INIT
1403 struct PCIDevice *base = unit->hu_Device;
1404 struct PCIController *hc;
1405 struct IOUsbHWReq *ioreq;
1406 struct UhciQH *uqh;
1407 struct UhciTD *utd;
1408 UWORD devadrep;
1409 ULONG linkelem;
1410 ULONG ctrlstatus;
1411 BOOL causeint;
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;
1420 continue;
1422 causeint = FALSE;
1423 ULONG framecnt;
1424 uhciUpdateFrameCounter(hc);
1425 framecnt = hc->hc_FrameCounter;
1427 // NakTimeout
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;
1432 if(uqh) {
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));
1441 causeint = TRUE;
1443 } else {
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);
1452 causeint = TRUE;
1454 } else {
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));
1458 causeint = TRUE;
1464 ioreq = (struct IOUsbHWReq *) ((struct Node *) ioreq)->ln_Succ;
1467 uhciCheckPortStatusChange(hc);
1469 if(causeint) {
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));
1483 return FALSE;
1485 AROS_INTFUNC_EXIT
1487 /* \\\ */