revert commit 56204.
[AROS.git] / rom / usb / classes / hub / hub.class.c
blobc47ad78a07e852504273968f2cb69b16decb7f96
1 /*
2 *----------------------------------------------------------------------------
3 * hub class for poseidon
4 *----------------------------------------------------------------------------
5 * By Chris Hodges <chrisly@platon42.de>
6 */
8 #include "debug.h"
10 #include "hub.class.h"
12 /* /// "Lib Stuff" */
13 static const STRPTR libname = MOD_NAME_STRING;
15 static int GM_UNIQUENAME(libInit)(LIBBASETYPEPTR nh)
17 KPRINTF(10, ("libInit nh: 0x%p SysBase: 0x%p\n", nh, SysBase));
19 nh->nh_UtilityBase = OpenLibrary("utility.library", 39);
21 #define UtilityBase nh->nh_UtilityBase
23 if(UtilityBase)
25 NewList(&nh->nh_Bindings);
26 InitSemaphore(&nh->nh_Adr0Sema);
27 } else {
28 KPRINTF(20, ("libInit: OpenLibrary(\"utility.library\", 39) failed!\n"));
29 return FALSE;
32 KPRINTF(10, ("libInit: Ok\n"));
33 return TRUE;
36 static int GM_UNIQUENAME(libExpunge)(LIBBASETYPEPTR nh)
38 KPRINTF(10, ("libExpunge nh: 0x%p SysBase: 0x%p\n", nh, SysBase));
39 CloseLibrary(UtilityBase);
40 nh->nh_UtilityBase = NULL;
41 return TRUE;
44 ADD2INITLIB(GM_UNIQUENAME(libInit), 0)
45 ADD2EXPUNGELIB(GM_UNIQUENAME(libExpunge), 0)
46 /* \\\ */
49 * ***********************************************************************
50 * * Library functions *
51 * ***********************************************************************
54 /* /// "usbAttemptDeviceBinding()" */
55 struct NepClassHub * GM_UNIQUENAME(usbAttemptDeviceBinding)(struct NepHubBase *nh, struct PsdDevice *pd)
57 struct Library *ps;
58 IPTR devclass;
59 #ifdef AROS_USB30_CODE
60 IPTR issuperspeed = 0;
61 #endif
62 KPRINTF(1, ("nepHubAttemptDeviceBinding(%p)\n", pd));
64 if((ps = OpenLibrary("poseidon.library", 4)))
66 psdGetAttrs(PGA_DEVICE, pd,
67 DA_Class, &devclass,
68 #ifdef AROS_USB30_CODE
69 DA_IsSuperspeed, &issuperspeed,
70 #endif
71 TAG_DONE);
72 CloseLibrary(ps);
73 #ifdef AROS_USB30_CODE
74 if((devclass == HUB_CLASSCODE) && (!issuperspeed))
75 #else
76 if(devclass == HUB_CLASSCODE)
77 #endif
79 return(GM_UNIQUENAME(usbForceDeviceBinding)(nh, pd));
82 return(NULL);
84 /* \\\ */
86 /* /// "usbForceDeviceBinding()" */
87 struct NepClassHub * GM_UNIQUENAME(usbForceDeviceBinding)(struct NepHubBase * nh, struct PsdDevice *pd)
89 struct Library *ps;
90 struct NepClassHub *nch;
91 STRPTR devname;
92 char buf[64];
93 struct Task *tmptask;
95 KPRINTF(1, ("nepHubAttemptDeviceBinding(%p)\n", pd));
97 if((ps = OpenLibrary("poseidon.library", 4)))
99 psdGetAttrs(PGA_DEVICE, pd,
100 DA_ProductName, &devname,
101 TAG_DONE);
102 if((nch = psdAllocVec(sizeof(struct NepClassHub))))
104 nch->nch_HubBase = nh;
105 nch->nch_Device = pd;
106 psdSafeRawDoFmt(buf, 64, "hub.class<%p>", nch);
107 nch->nch_ReadySignal = SIGB_SINGLE;
108 nch->nch_ReadySigTask = FindTask(NULL);
109 SetSignal(0, SIGF_SINGLE);
110 if((tmptask = psdSpawnSubTask(buf, GM_UNIQUENAME(nHubTask), nch)))
112 psdBorrowLocksWait(tmptask, 1UL<<nch->nch_ReadySignal);
113 if(nch->nch_Task)
115 nch->nch_ReadySigTask = NULL;
116 //FreeSignal(nch->nch_ReadySignal);
117 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
118 "I'm in love with hub '%s'.",
119 devname);
121 Forbid();
122 AddTail(&nh->nh_Bindings, &nch->nch_Node);
123 Permit();
124 CloseLibrary(ps);
125 return(nch);
128 nch->nch_ReadySigTask = NULL;
129 //FreeSignal(nch->nch_ReadySignal);
130 psdFreeVec(nch);
132 CloseLibrary(ps);
134 return(NULL);
136 /* \\\ */
138 /* /// "usbReleaseDeviceBinding()" */
139 void GM_UNIQUENAME(usbReleaseDeviceBinding)(struct NepHubBase *nh, struct NepClassHub *nch)
141 struct Library *ps;
142 STRPTR devname;
144 KPRINTF(1, ("nepHubReleaseDeviceBinding(%p)\n", nch));
145 if((ps = OpenLibrary("poseidon.library", 4)))
147 Forbid();
148 nch->nch_ReadySignal = SIGB_SINGLE;
149 nch->nch_ReadySigTask = FindTask(NULL);
150 if(nch->nch_Task)
152 KPRINTF(1, ("Sending Break\n"));
153 Signal(nch->nch_Task, SIGBREAKF_CTRL_C);
155 Permit();
156 while(nch->nch_Task)
158 psdBorrowLocksWait(nch->nch_Task, 1UL<<nch->nch_ReadySignal);
160 KPRINTF(1, ("Task gone\n"));
161 //FreeSignal(nch->nch_ReadySignal);
162 psdGetAttrs(PGA_DEVICE, nch->nch_Device, DA_ProductName, &devname, TAG_END);
163 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
164 "Time to get rid of '%s'!",
165 devname);
166 Forbid();
167 Remove(&nch->nch_Node);
168 Permit();
170 psdFreeVec(nch);
171 CloseLibrary(ps);
174 /* \\\ */
176 /* /// "usbGetAttrsA()" */
177 AROS_LH3(LONG, usbGetAttrsA,
178 AROS_LHA(ULONG, type, D0),
179 AROS_LHA(APTR, usbstruct, A0),
180 AROS_LHA(struct TagItem *, tags, A1),
181 LIBBASETYPEPTR, nh, 5, hub)
183 AROS_LIBFUNC_INIT
185 struct TagItem *ti;
186 LONG count = 0;
188 KPRINTF(1, ("nepHubGetAttrsA(%ld, %p, %p)\n", type, usbstruct, tags));
189 switch(type)
191 case UGA_CLASS:
192 if((ti = FindTagItem(UCCA_Priority, tags)))
194 *((SIPTR *) ti->ti_Data) = 0;
195 count++;
197 if((ti = FindTagItem(UCCA_Description, tags)))
199 *((STRPTR *) ti->ti_Data) = "Root/external hub base class";
200 count++;
202 if((ti = FindTagItem(UCCA_HasClassCfgGUI, tags)))
204 *((IPTR *) ti->ti_Data) = FALSE;
205 count++;
207 if((ti = FindTagItem(UCCA_HasBindingCfgGUI, tags)))
209 *((IPTR *) ti->ti_Data) = FALSE;
210 count++;
212 if((ti = FindTagItem(UCCA_AfterDOSRestart, tags)))
214 *((IPTR *) ti->ti_Data) = FALSE;
215 count++;
217 if((ti = FindTagItem(UCCA_UsingDefaultCfg, tags)))
219 *((IPTR *) ti->ti_Data) = TRUE;
220 count++;
222 if((ti = FindTagItem(UCCA_SupportsSuspend, tags)))
224 *((IPTR *) ti->ti_Data) = TRUE;
225 count++;
227 break;
229 case UGA_BINDING:
230 if((ti = FindTagItem(UCBA_UsingDefaultCfg, tags)))
232 *((IPTR *) ti->ti_Data) = TRUE;
233 count++;
235 break;
237 return(count);
238 AROS_LIBFUNC_EXIT
240 /* \\\ */
242 /* /// "usbSetAttrsA()" */
243 AROS_LH3(LONG, usbSetAttrsA,
244 AROS_LHA(ULONG, type, D0),
245 AROS_LHA(APTR, usbstruct, A0),
246 AROS_LHA(struct TagItem *, tags, A1),
247 LIBBASETYPEPTR, nh, 6, hub)
249 AROS_LIBFUNC_INIT
250 return(0);
251 AROS_LIBFUNC_EXIT
253 /* \\\ */
255 /* /// "usbDoMethodA()" */
256 AROS_LH2(IPTR, usbDoMethodA,
257 AROS_LHA(ULONG, methodid, D0),
258 AROS_LHA(IPTR *, methoddata, A1),
259 LIBBASETYPEPTR, nh, 7, hub)
261 AROS_LIBFUNC_INIT
263 struct NepClassHub *nch;
265 KPRINTF(1, ("Do Method %ld\n", methodid));
266 switch(methodid)
268 case UCM_AttemptDeviceBinding:
269 return((IPTR) GM_UNIQUENAME(usbAttemptDeviceBinding)(nh, (struct PsdDevice *) methoddata[0]));
271 case UCM_ForceDeviceBinding:
272 return((IPTR) GM_UNIQUENAME(usbForceDeviceBinding)(nh, (struct PsdDevice *) methoddata[0]));
274 case UCM_ReleaseDeviceBinding:
275 GM_UNIQUENAME(usbReleaseDeviceBinding)(nh, (struct NepClassHub *) methoddata[0]);
276 return(TRUE);
278 case UCM_HubPowerCyclePort:
279 case UCM_HubDisablePort:
281 struct PsdDevice *pd = (struct PsdDevice *) methoddata[0];
282 ULONG port = (ULONG) methoddata[1];
283 if(!(pd && port))
285 KPRINTF(20, ("HubPowerCycle/DisablePort Params Null!\n"));
286 return(FALSE);
288 Forbid();
289 nch = (struct NepClassHub *) nh->nh_Bindings.lh_Head;
290 while(nch->nch_Node.ln_Succ)
292 if(nch->nch_Device == pd)
294 KPRINTF(20, ("HubPowerCycle/DisablePort Dev found (port %ld)!\n", port));
295 if(port <= nch->nch_NumPorts)
297 nch->nch_DisablePort |= 1UL<<port;
298 if(methodid == UCM_HubPowerCyclePort)
300 nch->nch_PowerCycle |= 1UL<<port;
302 if(nch->nch_Task)
304 Signal(nch->nch_Task, (1L<<nch->nch_TaskMsgPort->mp_SigBit));
306 Permit();
307 return(TRUE);
309 break;
311 nch = (struct NepClassHub *) nch->nch_Node.ln_Succ;
313 Permit();
314 return(FALSE);
317 case UCM_HubClassScan:
319 nch = (struct NepClassHub *) methoddata[0];
320 Forbid();
321 nch->nch_ClassScan = TRUE;
322 if(nch->nch_Task)
324 Signal(nch->nch_Task, (1L<<nch->nch_TaskMsgPort->mp_SigBit));
326 Permit();
327 return(TRUE);
330 case UCM_AttemptSuspendDevice:
331 case UCM_AttemptResumeDevice:
332 case UCM_HubClaimAppBinding:
333 case UCM_HubReleaseIfBinding:
334 case UCM_HubReleaseDevBinding:
335 case UCM_HubSuspendDevice:
336 case UCM_HubResumeDevice:
338 struct NepHubMsg nhm;
339 struct Library *ps;
340 nch = (struct NepClassHub *) methoddata[0];
341 nhm.nhm_Result = (IPTR) NULL;
342 nhm.nhm_MethodID = methodid;
343 nhm.nhm_Params = methoddata;
344 if((ps = OpenLibrary("poseidon.library", 4)))
346 if(nch->nch_Task == FindTask(NULL))
348 // if we would send the message to ourself, we would deadlock, so handle this directly
349 GM_UNIQUENAME(nHandleHubMethod)(nch, &nhm);
350 } else {
351 nhm.nhm_Msg.mn_ReplyPort = CreateMsgPort();
352 nhm.nhm_Msg.mn_Length = sizeof(struct NepHubMsg);
353 Forbid();
354 if(nch->nch_Task && nhm.nhm_Msg.mn_ReplyPort)
356 PutMsg(nch->nch_CtrlMsgPort, &nhm.nhm_Msg);
357 Permit();
358 while(!GetMsg(nhm.nhm_Msg.mn_ReplyPort))
360 psdBorrowLocksWait(nch->nch_Task, 1UL<<nhm.nhm_Msg.mn_ReplyPort->mp_SigBit);
362 } else {
363 Permit();
365 DeleteMsgPort(nhm.nhm_Msg.mn_ReplyPort);
367 CloseLibrary(ps);
369 return(nhm.nhm_Result);
372 default:
373 break;
375 return(0);
376 AROS_LIBFUNC_EXIT
378 /* \\\ */
380 #undef ps
381 #define ps nch->nch_Base
383 /* /// "nHubTask()" */
384 AROS_UFH0(void, GM_UNIQUENAME(nHubTask))
386 AROS_USERFUNC_INIT
388 struct NepClassHub *nch;
389 struct PsdPipe *pp;
390 ULONG sigmask;
391 ULONG sigs;
392 UWORD num;
393 LONG ioerr;
394 struct UsbPortStatus uhps;
395 struct UsbHubStatus uhhs;
396 ULONG count;
397 struct PsdDevice *pd;
398 STRPTR devname;
399 struct NepHubMsg *nhm;
401 if((nch = GM_UNIQUENAME(nAllocHub)()))
403 Forbid();
404 if(nch->nch_ReadySigTask)
406 Signal(nch->nch_ReadySigTask, 1L<<nch->nch_ReadySignal);
408 Permit();
409 count = 0;
410 for(num = 1; num <= nch->nch_NumPorts; num++)
412 if(((nch->nch_Downstream)[num-1] = pd = GM_UNIQUENAME(nConfigurePort)(nch, num)))
414 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
415 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
416 "Detected device '%s' at port %ld. I like it.",
417 devname, num);
418 count++;
421 if(count)
423 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
424 "Hub has added %ld device(s). That'll be fun!",
425 count);
427 // do a class scan
428 for(num = 1; num <= nch->nch_NumPorts; num++)
430 if((pd = (nch->nch_Downstream)[num-1]))
432 psdHubClassScan(pd);
435 sigmask = (1L<<nch->nch_TaskMsgPort->mp_SigBit)|(1L<<nch->nch_CtrlMsgPort->mp_SigBit)|SIGBREAKF_CTRL_C;
436 nch->nch_Running = TRUE;
437 nch->nch_IOStarted = FALSE;
440 if(nch->nch_Running && (!nch->nch_IOStarted))
442 psdSendPipe(nch->nch_EP1Pipe, nch->nch_PortChanges, (nch->nch_NumPorts+8)>>3);
443 nch->nch_IOStarted = TRUE;
445 sigs = Wait(sigmask);
446 while((nhm = (struct NepHubMsg *) GetMsg(nch->nch_CtrlMsgPort)))
448 GM_UNIQUENAME(nHandleHubMethod)(nch, nhm);
450 ReplyMsg((struct Message *) nhm);
452 if(nch->nch_DisablePort)
454 for(num = 1; num <= nch->nch_NumPorts; num++)
456 if((nch->nch_DisablePort) & (1L<<num))
458 nch->nch_DisablePort &= ~(1L<<num);
459 /* Remove device */
460 if((pd = (nch->nch_Downstream)[num-1]))
462 psdSetAttrs(PGA_DEVICE, pd, DA_IsConnected, FALSE, TAG_END);
463 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
464 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
465 "Zapping device '%s' at port %ld!",
466 devname, num);
467 psdFreeDevice(pd);
468 psdSendEvent(EHMB_REMDEVICE, pd, NULL);
469 (nch->nch_Downstream)[num-1] = NULL;
470 pd = NULL;
471 /* disable port */
472 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
473 USR_CLEAR_FEATURE, UFS_PORT_ENABLE, (ULONG) num);
474 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
475 if(ioerr)
477 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
478 "CLEAR_PORT_ENABLE failed: %s (%ld)",
479 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
480 KPRINTF(1, ("CLEAR_PORT_ENABLE failed %ld.\n", ioerr));
483 if(nch->nch_PowerCycle & (1<<num))
485 KPRINTF(2, ("Powercycle request for port %lu\n", num));
486 nch->nch_PowerCycle &= ~(1L<<num);
488 /* Wait for device to settle */
489 psdDelayMS(250);
490 if(((nch->nch_Downstream)[num-1] = pd = GM_UNIQUENAME(nConfigurePort)(nch, num)))
492 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
493 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
494 "Device '%s' returned. Happy happy joy joy.",
495 devname);
496 psdHubClassScan(pd);
502 if(nch->nch_ClassScan)
504 nch->nch_ClassScan = FALSE;
505 for(num = 1; num <= nch->nch_NumPorts; num++)
507 if((pd = (nch->nch_Downstream)[num-1]))
509 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
510 psdHubClassScan(pd);
514 while((pp = (struct PsdPipe *) GetMsg(nch->nch_TaskMsgPort)))
516 if(pp == nch->nch_EP1Pipe)
518 nch->nch_IOStarted = FALSE;
519 ioerr = psdGetPipeError(nch->nch_EP1Pipe);
520 if(ioerr == UHIOERR_TIMEOUT)
522 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
523 "Hub involuntarily gone! Disconnecting...");
524 psdSetAttrs(PGA_DEVICE, nch->nch_Device,
525 DA_IsConnected, FALSE,
526 TAG_END);
527 nch->nch_PortChanges[0] = 0xff;
528 nch->nch_PortChanges[1] = 0xff;
529 nch->nch_PortChanges[2] = 0xff;
530 nch->nch_PortChanges[3] = 0xff;
531 sigs |= SIGBREAKF_CTRL_C;
533 if((!ioerr) || (ioerr == UHIOERR_TIMEOUT))
535 KPRINTF(2, ("Port changed at %p, Numports=%ld!\n", nch->nch_PortChanges[0], nch->nch_NumPorts));
537 if(nch->nch_PortChanges[0] & 1)
539 psdPipeSetup(nch->nch_EP0Pipe, URTF_IN|URTF_CLASS|URTF_DEVICE,
540 USR_GET_STATUS, 0, 0);
541 ioerr = psdDoPipe(nch->nch_EP0Pipe, &uhhs, sizeof(struct UsbHubStatus));
542 uhhs.wHubStatus = AROS_WORD2LE(uhhs.wHubStatus);
543 uhhs.wHubChange = AROS_WORD2LE(uhhs.wHubChange);
544 if(!ioerr)
546 if(uhhs.wHubStatus & UHSF_OVER_CURRENT)
548 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
549 "Hub over-current situation detected! Unpowering ALL ports!");
550 for(num = 1; num <= nch->nch_NumPorts; num++)
552 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
553 USR_CLEAR_FEATURE, UFS_PORT_POWER, (ULONG) num);
554 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
555 if(ioerr)
557 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
558 "PORT_POWER for port %ld failed: %s (%ld)",
559 num, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
560 KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", num, ioerr));
563 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
564 USR_CLEAR_FEATURE, UFS_C_PORT_OVER_CURRENT, (ULONG) num);
565 psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
567 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_DEVICE,
568 USR_CLEAR_FEATURE, UFS_C_HUB_OVER_CURRENT, 0);
569 psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
571 if(uhhs.wHubChange & UHSF_LOCAL_POWER_LOST)
573 struct PsdConfig *pc = NULL;
574 struct PsdHardware *phw = NULL;
575 psdGetAttrs(PGA_DEVICE, nch->nch_Device,
576 DA_Config, &pc,
577 DA_Hardware, &phw,
578 TAG_END);
579 if(uhhs.wHubStatus & UHSF_LOCAL_POWER_LOST)
581 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
582 "Hub is no longer self-powered! Low power conditions may occur.");
584 if(pc && phw)
586 psdSetAttrs(PGA_CONFIG, pc, CA_SelfPowered, FALSE, TAG_END);
587 psdCalculatePower(phw);
589 } else {
590 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
591 "Hub is now self-powered! Yay!");
592 if(pc && phw)
594 psdSetAttrs(PGA_CONFIG, pc, CA_SelfPowered, TRUE, TAG_END);
595 psdCalculatePower(phw);
598 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_DEVICE,
599 USR_CLEAR_FEATURE, UFS_C_HUB_LOCAL_POWER, 0);
600 psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
605 for(num = 1; num <= nch->nch_NumPorts; num++)
607 if(nch->nch_PortChanges[num>>3] & (1L<<(num & 7)))
609 psdPipeSetup(nch->nch_EP0Pipe, URTF_IN|URTF_CLASS|URTF_OTHER,
610 USR_GET_STATUS, 0, (ULONG) num);
611 ioerr = psdDoPipe(nch->nch_EP0Pipe, &uhps, sizeof(struct UsbPortStatus));
612 uhps.wPortStatus = AROS_WORD2LE(uhps.wPortStatus);
613 uhps.wPortChange = AROS_WORD2LE(uhps.wPortChange);
614 if(ioerr == UHIOERR_TIMEOUT)
616 uhps.wPortStatus = 0;
617 uhps.wPortChange = 0xffff;
618 ioerr = 0;
619 } else {
620 GM_UNIQUENAME(nClearPortStatus)(nch, num);
622 if(!ioerr)
624 pd = (nch->nch_Downstream)[num-1];
625 if(uhps.wPortStatus & UPSF_PORT_OVER_CURRENT)
627 if(pd)
629 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
630 } else {
631 devname = "a ghost";
633 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
634 "Over-current situation detected with %s at port %ld! Unpowering port!",
635 devname, num);
636 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
637 USR_CLEAR_FEATURE, UFS_PORT_POWER, (ULONG) num);
638 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
639 if(ioerr)
641 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
642 "PORT_POWER for port %ld failed: %s (%ld)",
643 num, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
644 KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", num, ioerr));
647 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
648 USR_CLEAR_FEATURE, UFS_C_PORT_OVER_CURRENT, (ULONG) num);
649 psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
651 if(uhps.wPortChange & UPSF_PORT_SUSPEND)
653 if((!(uhps.wPortStatus & UPSF_PORT_SUSPEND)) && pd)
655 IPTR oldsusp = 0;
656 psdGetAttrs(PGA_DEVICE, pd, DA_IsSuspended, &oldsusp, TAG_END);
657 psdSetAttrs(PGA_DEVICE, pd, DA_IsSuspended, FALSE, TAG_END);
658 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
659 if(oldsusp)
661 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
662 "Device '%s' at port %ld resumed from remote!",
663 devname, num);
664 psdSendEvent(EHMB_DEVRESUMED, pd, NULL);
665 psdResumeBindings(pd);
668 else if((uhps.wPortStatus & UPSF_PORT_SUSPEND) && pd)
670 psdSetAttrs(PGA_DEVICE, pd, DA_IsSuspended, FALSE, TAG_END);
671 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
672 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
673 "Device '%s' at port %ld suspended!",
674 devname, num);
675 } else {
676 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
677 "Bogus suspend/resume change on port %ld.",
678 num);
681 if(uhps.wPortChange & UPSF_PORT_CONNECTION)
683 /* Remove device */
684 if((!(uhps.wPortStatus & UPSF_PORT_CONNECTION)) && pd)
686 psdSetAttrs(PGA_DEVICE, pd, DA_IsConnected, FALSE, TAG_END);
687 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
688 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
689 "Device '%s' at port %ld is gone!",
690 devname, num);
691 psdFreeDevice(pd);
692 psdSendEvent(EHMB_REMDEVICE, pd, NULL);
693 (nch->nch_Downstream)[num-1] = NULL;
694 pd = NULL;
696 /* add new device */
697 if((uhps.wPortStatus & UPSF_PORT_CONNECTION) && (!pd))
699 /* Wait for device to settle */
700 psdDelayMS(100);
701 if(((nch->nch_Downstream)[num-1] = pd = GM_UNIQUENAME(nConfigurePort)(nch, num)))
703 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
704 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
705 "New device '%s' at port %ld. Very nice.",
706 devname, num);
707 psdClassScan();
714 /* Bail out on time out. */
715 if(nch->nch_PortChanges[0] == 0xff)
717 break;
719 psdDelayMS(50);
720 } else {
721 if(ioerr != IOERR_ABORTED)
723 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
724 "Something weird happened to the status packet, it failed: %s (%ld)",
725 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
726 psdDelayMS(200);
729 break;
730 } else {
731 KPRINTF(20, ("Bogus message received!\n"));
734 } while(!(sigs & SIGBREAKF_CTRL_C));
735 KPRINTF(20, ("Going down the river!\n"));
736 if(nch->nch_IOStarted)
738 psdAbortPipe(nch->nch_EP1Pipe);
739 psdWaitPipe(nch->nch_EP1Pipe);
741 psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Oh no! I've been shot! Arrggghh...");
742 GM_UNIQUENAME(nFreeHub)(nch);
744 AROS_USERFUNC_EXIT
746 /* \\\ */
748 /* /// "nAllocHub()" */
749 struct NepClassHub * GM_UNIQUENAME(nAllocHub)(void)
751 struct UsbHubDesc *uhd;
752 struct Task *thistask;
753 struct NepClassHub *nch;
754 struct UsbHubStatus uhhs;
755 APTR parenthub;
756 LONG ioerr;
757 ULONG len;
758 UWORD num;
759 #ifdef AROS_USB30_CODE
760 UBYTE buf[2];
761 #else
762 UBYTE buf;
763 #endif
764 IPTR ishighspeed = 0;
765 IPTR prodid;
766 IPTR vendid;
767 BOOL overcurrent = FALSE;
769 thistask = FindTask(NULL);
770 nch = thistask->tc_UserData;
773 if(!(nch->nch_Base = OpenLibrary("poseidon.library", 4)))
775 Alert(AG_OpenLib);
776 break;
779 psdGetAttrs(PGA_DEVICE, nch->nch_Device,
780 DA_Hardware, &nch->nch_Hardware,
781 DA_IsHighspeed, &ishighspeed,
782 DA_ProductID, &prodid,
783 DA_VendorID, &vendid,
784 DA_HubDevice, &parenthub,
785 TAG_END);
787 nch->nch_IsRootHub = (parenthub ? FALSE : TRUE);
788 nch->nch_IsUSB20 = ishighspeed;
789 // try to select multi TT interface first
790 nch->nch_Interface = psdFindInterface(nch->nch_Device, NULL,
791 IFA_Class, HUB_CLASSCODE,
792 IFA_Protocol, 2,
793 IFA_AlternateNum, 0xffffffff,
794 TAG_END);
795 if(!nch->nch_Interface)
797 // any will do
798 nch->nch_Interface = psdFindInterface(nch->nch_Device, NULL,
799 IFA_Class, HUB_CLASSCODE,
800 TAG_END);
802 if((vendid == 0x05E3) && ishighspeed)
804 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Genesys Logic hubs are broken and will cause failures with USB 2.0 devices.");
805 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "If you encounter problems, try the device without the hub.");
806 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "If this solves the problem, you need to buy a different USB 2.0 hub.");
809 if(!nch->nch_Interface)
811 KPRINTF(1, ("Ooops!?! No interfaces defined?\n"));
812 break;
814 nch->nch_EP1 = psdFindEndpoint(nch->nch_Interface, NULL,
815 EA_IsIn, TRUE,
816 EA_TransferType, USEAF_INTERRUPT,
817 TAG_END);
819 if(!nch->nch_EP1)
821 psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname, "Ooops!?! No endpoints defined?");
822 KPRINTF(1, ("Ooops!?! No Endpoints defined?\n"));
823 break;
825 if((nch->nch_CtrlMsgPort = CreateMsgPort()))
827 if((nch->nch_TaskMsgPort = CreateMsgPort()))
829 if((nch->nch_EP0Pipe = psdAllocPipe(nch->nch_Device, nch->nch_TaskMsgPort, NULL)))
831 psdSetAttrs(PGA_PIPE, nch->nch_EP0Pipe,
832 PPA_NakTimeout, TRUE,
833 PPA_NakTimeoutTime, 1000,
834 TAG_END);
835 psdSetAltInterface(nch->nch_EP0Pipe, nch->nch_Interface);
836 if((nch->nch_EP1Pipe = psdAllocPipe(nch->nch_Device, nch->nch_TaskMsgPort, nch->nch_EP1)))
838 psdSetAttrs(PGA_PIPE, nch->nch_EP1Pipe,
839 PPA_AllowRuntPackets, TRUE,
840 TAG_END);
841 psdPipeSetup(nch->nch_EP0Pipe, URTF_IN|URTF_CLASS|URTF_DEVICE,
842 USR_GET_DESCRIPTOR, UDT_HUB<<8, 0);
843 #ifdef AROS_USB30_CODE
844 ioerr = psdDoPipe(nch->nch_EP0Pipe, &buf, 2);
845 #else
846 ioerr = psdDoPipe(nch->nch_EP0Pipe, &buf, 1);
847 #endif
848 if((!ioerr) || (ioerr == UHIOERR_OVERFLOW))
850 #ifdef AROS_USB30_CODE
851 len = buf[0];
852 #else
853 len = buf;
854 #endif
855 if((uhd = psdAllocVec(len)))
857 ioerr = psdDoPipe(nch->nch_EP0Pipe, uhd, len);
858 #ifdef AROS_USB30_CODE
859 if(buf[1]!=UDT_SSHUB) {
860 #endif
861 if(!ioerr)
863 nch->nch_NumPorts = uhd->bNbrPorts;
864 nch->nch_HubAttr = AROS_WORD2LE(uhd->wHubCharacteristics);
865 nch->nch_PwrGoodTime = uhd->bPwrOn2PwrGood<<1;
866 nch->nch_HubCurrent = uhd->bHubContrCurrent;
867 nch->nch_Removable = 0;
868 if(nch->nch_HubAttr & UHCM_THINK_TIME)
870 psdSetAttrs(PGA_DEVICE, nch->nch_Device,
871 DA_HubThinkTime, (nch->nch_HubAttr & UHCM_THINK_TIME)>>UHCS_THINK_TIME,
872 TAG_END);
875 for(num = 0; num < ((nch->nch_NumPorts + 7)>>3); num++)
877 nch->nch_Removable |= ((&uhd->DeviceRemovable)[num])<<(num<<3);
879 KPRINTF(2, ("Hub with %ld ports\n"
880 " Characteristics 0x%04lx\n"
881 " PowerGood after %ld ms\n"
882 " Power consumption %ld mA\n",
883 nch->nch_NumPorts,
884 nch->nch_HubAttr,
885 nch->nch_PwrGoodTime, nch->nch_HubCurrent));
886 psdFreeVec(uhd);
888 psdPipeSetup(nch->nch_EP0Pipe, URTF_IN|URTF_CLASS|URTF_DEVICE,
889 USR_GET_STATUS, 0, 0);
890 ioerr = psdDoPipe(nch->nch_EP0Pipe, &uhhs, sizeof(struct UsbHubStatus));
891 uhhs.wHubStatus = AROS_WORD2LE(uhhs.wHubStatus);
892 uhhs.wHubChange = AROS_WORD2LE(uhhs.wHubChange);
893 if(!ioerr)
895 struct PsdConfig *pc = NULL;
896 struct PsdHardware *phw = NULL;
897 if(uhhs.wHubStatus & UHSF_OVER_CURRENT)
899 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
900 "Hub over-current situation detected! Resolve this first!");
901 //overcurrent = TRUE;
904 psdGetAttrs(PGA_DEVICE, nch->nch_Device,
905 DA_Config, &pc,
906 DA_Hardware, &phw,
907 TAG_END);
908 if(uhhs.wHubStatus & UHSF_LOCAL_POWER_LOST)
910 if(pc && phw)
912 psdSetAttrs(PGA_CONFIG, pc, CA_SelfPowered, FALSE, TAG_END);
913 psdCalculatePower(phw);
915 } else {
916 if(pc && phw)
918 psdSetAttrs(PGA_CONFIG, pc, CA_SelfPowered, TRUE, TAG_END);
919 psdCalculatePower(phw);
923 if(!overcurrent)
925 if((nch->nch_Downstream = psdAllocVec((ULONG) nch->nch_NumPorts*sizeof(APTR))))
927 /*for(num = 1; num <= nch->nch_NumPorts; num++)
929 GM_UNIQUENAME(nClearPortStatus)(nch, num);
931 psdDelayMS(20);*/
932 KPRINTF(2, ("Powering up ports...\n"));
933 for(num = 1; num <= nch->nch_NumPorts; num++)
935 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
936 USR_SET_FEATURE, UFS_PORT_POWER, (ULONG) num);
937 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
938 if(ioerr)
940 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
941 "PORT_POWER for port %ld failed: %s (%ld)",
942 num, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
943 KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", num, ioerr));
946 psdDelayMS((ULONG) nch->nch_PwrGoodTime + 15);
948 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
949 "Hub with %ld ports successfully configured.",
950 nch->nch_NumPorts);
952 KPRINTF(10, ("%s ready!\n", thistask->tc_Node.ln_Name));
953 nch->nch_Task = thistask;
954 return(nch);
955 } else {
956 KPRINTF(1, ("No downstream port array memory!\n"));
959 } else {
960 psdFreeVec(uhd);
961 psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname,
962 "GET_HUB_DESCRIPTOR (%ld) failed: %s (%ld)",
963 len, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
964 KPRINTF(1, ("GET_HUB_DESCRIPTOR (%ld) failed %ld!\n", len, ioerr));
966 #ifdef AROS_USB30_CODE
967 } else {
968 psdFreeVec(uhd);
969 KPRINTF(1, ("GET_HUB_DESCRIPTOR (%ld) failed! Descriptor is wrong type\n", len));
971 #endif
972 } else {
973 KPRINTF(1, ("No Hub Descriptor memory!\n"));
975 } else {
976 psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname,
977 "GET_HUB_DESCRIPTOR (%ld) failed: %s (%ld)",
978 1, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
979 KPRINTF(1, ("GET_HUB_DESCRIPTOR (1) failed %ld!\n", ioerr));
981 psdFreePipe(nch->nch_EP1Pipe);
983 psdFreePipe(nch->nch_EP0Pipe);
985 DeleteMsgPort(nch->nch_TaskMsgPort);
987 DeleteMsgPort(nch->nch_CtrlMsgPort);
989 } while(FALSE);
990 CloseLibrary(nch->nch_Base);
991 Forbid();
992 nch->nch_Task = NULL;
993 if(nch->nch_ReadySigTask)
995 Signal(nch->nch_ReadySigTask, 1L<<nch->nch_ReadySignal);
997 return(NULL);
999 /* \\\ */
1001 /* /// "nFreeHub()" */
1002 void GM_UNIQUENAME(nFreeHub)(struct NepClassHub *nch)
1004 UWORD num;
1005 LONG ioerr;
1006 struct PsdDevice *pd;
1007 STRPTR devname;
1008 IPTR isconnected;
1009 struct Message *msg;
1011 KPRINTF(1, ("FreeHub\n"));
1012 psdGetAttrs(PGA_DEVICE, nch->nch_Device, DA_IsConnected, &isconnected, TAG_END);
1013 for(num = 1; num <= nch->nch_NumPorts; num++)
1015 KPRINTF(1, ("Iterating Port %ld\n", num));
1016 /* Remove downstream device */
1017 pd = (nch->nch_Downstream)[num-1];
1018 if(pd)
1020 if(!isconnected)
1022 psdSetAttrs(PGA_DEVICE, pd, DA_IsConnected, FALSE, TAG_END);
1024 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
1025 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
1026 "My death killed device '%s' at port %ld!",
1027 devname, num);
1028 KPRINTF(1, ("FreeDevice %p\n", pd));
1029 psdFreeDevice(pd);
1030 psdSendEvent(EHMB_REMDEVICE, pd, NULL);
1031 (nch->nch_Downstream)[num-1] = NULL;
1033 /* There's no sense trying to send out commands if the hub is already gone! */
1034 if(isconnected)
1036 /* power down for port */
1037 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1038 USR_CLEAR_FEATURE, UFS_PORT_POWER, (ULONG) num);
1039 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
1040 if(ioerr)
1042 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1043 "PORT_POWER for port %ld failed: %s (%ld)",
1044 num, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1045 KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", num, ioerr));
1049 KPRINTF(1, ("FreePipes\n"));
1050 psdFreePipe(nch->nch_EP1Pipe);
1051 psdFreePipe(nch->nch_EP0Pipe);
1052 psdFreeVec(nch->nch_Downstream);
1053 KPRINTF(1, ("Entering Forbid\n"));
1054 Forbid();
1055 // clear queue
1056 while((msg = GetMsg(nch->nch_CtrlMsgPort)))
1058 ReplyMsg(msg);
1060 DeleteMsgPort(nch->nch_TaskMsgPort);
1061 DeleteMsgPort(nch->nch_CtrlMsgPort);
1062 CloseLibrary(nch->nch_Base);
1063 nch->nch_Task = NULL;
1064 if(nch->nch_ReadySigTask)
1066 Signal(nch->nch_ReadySigTask, 1L<<nch->nch_ReadySignal);
1068 KPRINTF(1, ("Really gone now!\n"));
1070 /* \\\ */
1072 /* *** HUB Class *** */
1074 /* /// "nClearPortStatus()" */
1075 LONG GM_UNIQUENAME(nClearPortStatus)(struct NepClassHub *nch, UWORD port)
1077 LONG ioerr;
1078 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1079 USR_CLEAR_FEATURE, UFS_C_PORT_CONNECTION, (ULONG) port);
1080 if((ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0)))
1082 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1083 "CLEAR_PORT_FEATURE (C_PORT_CONNECTION) failed: %s (%ld)",
1084 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1085 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1086 return(ioerr);
1089 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1090 USR_CLEAR_FEATURE, UFS_C_PORT_ENABLE, (ULONG) port);
1091 if((ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0)))
1093 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1094 "CLEAR_PORT_FEATURE (C_PORT_ENABLE) failed: %s (%ld)",
1095 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1096 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1097 return(ioerr);
1100 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1101 USR_CLEAR_FEATURE, UFS_C_PORT_SUSPEND, (ULONG) port);
1102 if((ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0)))
1104 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1105 "CLEAR_PORT_FEATURE (C_PORT_SUSPEND) failed: %s (%ld)",
1106 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1107 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1108 return(ioerr);
1111 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1112 USR_CLEAR_FEATURE, UFS_C_PORT_OVER_CURRENT, (ULONG) port);
1113 if((ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0)))
1115 /*psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1116 "CLEAR_PORT_FEATURE (C_OVER_CURRENT) failed: %s (%ld)",
1117 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);*/
1118 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1121 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1122 USR_CLEAR_FEATURE, UFS_C_PORT_RESET, (ULONG) port);
1123 if((ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0)))
1125 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1126 "CLEAR_PORT_FEATURE (C_PORT_RESET) failed: %s (%ld)",
1127 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1128 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1129 return(ioerr);
1131 return(0);
1133 /* \\\ */
1135 /* /// "nConfigurePort()" */
1136 struct PsdDevice * GM_UNIQUENAME(nConfigurePort)(struct NepClassHub *nch, UWORD port)
1138 LONG ioerr;
1139 LONG delayretries;
1140 LONG resetretries;
1141 ULONG delaytime = 10;
1142 struct UsbPortStatus uhps;
1143 struct PsdDevice *pd;
1144 struct PsdPipe *pp;
1145 BOOL washighspeed = FALSE;
1146 BOOL islowspeed = FALSE;
1148 KPRINTF(2, ("Configuring port %ld of hub 0x%p\n", port, nch));
1150 uhps.wPortStatus = 0xDEAD;
1151 uhps.wPortChange = 0xDA1A;
1153 psdPipeSetup(nch->nch_EP0Pipe, URTF_IN|URTF_CLASS|URTF_OTHER,
1154 USR_GET_STATUS, UFS_PORT_CONNECTION, (ULONG) port);
1155 ioerr = psdDoPipe(nch->nch_EP0Pipe, &uhps, sizeof(struct UsbPortStatus));
1156 uhps.wPortStatus = AROS_WORD2LE(uhps.wPortStatus);
1157 uhps.wPortChange = AROS_WORD2LE(uhps.wPortChange);
1158 if(!ioerr)
1160 KPRINTF(2, ("Status 0x%04x, change 0x%04x\n", uhps.wPortStatus, uhps.wPortChange));
1162 if(uhps.wPortStatus & UPSF_PORT_ENABLE)
1164 KPRINTF(2, ("Disabling port %u\n", port));
1166 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1167 USR_CLEAR_FEATURE, UFS_PORT_ENABLE, (ULONG) port);
1168 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
1169 if(ioerr)
1171 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1172 "CLEAR_PORT_ENABLE failed: %s (%ld)",
1173 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1174 KPRINTF(1, ("CLEAR_PORT_ENABLE failed %ld.\n", ioerr));
1175 } else {
1176 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1177 "Disabling port %ld.", port);
1180 if(uhps.wPortStatus & UPSF_PORT_CONNECTION)
1182 KPRINTF(2, ("There's something at port %ld!\n", port));
1183 Forbid();
1184 if((pd = psdAllocDevice(nch->nch_Hardware)))
1186 psdLockWriteDevice(pd);
1187 Permit();
1188 /* Hub reference */
1189 psdSetAttrs(PGA_DEVICE, pd,
1190 DA_HubDevice, nch->nch_Device,
1191 DA_IsConnected, TRUE,
1192 DA_AtHubPortNumber, port,
1193 TAG_END);
1194 if(uhps.wPortStatus & UPSF_PORT_LOW_SPEED)
1196 psdSetAttrs(PGA_DEVICE, pd, DA_IsLowspeed, TRUE, TAG_END);
1197 KPRINTF(2, (" It's a lowspeed device!\n"));
1198 islowspeed = TRUE;
1200 ObtainSemaphore(&nch->nch_HubBase->nh_Adr0Sema);
1201 for(resetretries = 0; resetretries < 3; resetretries++)
1203 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1204 USR_SET_FEATURE, UFS_PORT_RESET, (ULONG) port);
1205 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
1206 if(ioerr)
1208 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1209 "PORT_RESET for port %ld failed: %s (%ld)",
1210 port, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1211 KPRINTF(1, ("PORT_RESET failed %ld.\n", ioerr));
1212 break;
1214 if(nch->nch_IsRootHub)
1216 // Root hubs need 50ms minimum delay
1217 psdDelayMS(50);
1219 for(delayretries = 0; delayretries < 500; delayretries += delaytime)
1221 psdDelayMS(delaytime);
1222 psdPipeSetup(nch->nch_EP0Pipe, URTF_IN|URTF_CLASS|URTF_OTHER,
1223 USR_GET_STATUS, UFS_PORT_CONNECTION, (ULONG) port);
1224 ioerr = psdDoPipe(nch->nch_EP0Pipe, &uhps, sizeof(struct UsbPortStatus));
1225 uhps.wPortStatus = AROS_WORD2LE(uhps.wPortStatus);
1226 uhps.wPortChange = AROS_WORD2LE(uhps.wPortChange);
1227 if(ioerr)
1229 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1230 "GET_PORT_CONNECTION for port %ld failed: %s (%ld)",
1231 port, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1232 KPRINTF(1, ("GET_PORT_CONNECTION failed %ld.\n", ioerr));
1233 break;
1235 KPRINTF(2, ("After reset: status 0x%04x, change 0x%04x\n", uhps.wPortStatus, uhps.wPortChange));
1236 if(!(uhps.wPortStatus & UPSF_PORT_CONNECTION))
1238 break;
1240 if((uhps.wPortStatus &
1241 (UPSF_PORT_RESET|UPSF_PORT_CONNECTION|UPSF_PORT_ENABLE|UPSF_PORT_POWER|UPSF_PORT_OVER_CURRENT)) ==
1242 (UPSF_PORT_CONNECTION|UPSF_PORT_ENABLE|UPSF_PORT_POWER))
1244 if((uhps.wPortStatus & UPSF_PORT_HIGH_SPEED) || washighspeed)
1246 psdSetAttrs(PGA_DEVICE, pd, DA_IsHighspeed, TRUE, TAG_END);
1247 washighspeed = TRUE;
1248 KPRINTF(2, (" It's a highspeed device!\n"));
1250 else
1252 IPTR needssplit = 0;
1254 /* Some hubs (Apple Keyboard bultin hub) report speed correctly only after reset */
1255 if (uhps.wPortStatus & UPSF_PORT_LOW_SPEED)
1257 psdSetAttrs(PGA_DEVICE, pd, DA_IsLowspeed, TRUE, TAG_END);
1258 KPRINTF(2, (" It's a lowspeed device!\n"));
1259 islowspeed = TRUE;
1262 // inherit needs split from hub
1263 psdGetAttrs(PGA_DEVICE, nch->nch_Device, DA_NeedsSplitTrans, &needssplit, TAG_END);
1264 KPRINTF(2, (" Needs split transfers: %ld\n", needssplit));
1265 if(nch->nch_IsUSB20) /* this is a low/full speed device connected to a 2.0 hub! */
1267 KPRINTF(2, (" Enforcing split transfers\n"));
1268 needssplit = TRUE;
1270 psdSetAttrs(PGA_DEVICE, pd, DA_NeedsSplitTrans, needssplit, TAG_END);
1272 GM_UNIQUENAME(nClearPortStatus)(nch, port);
1273 psdDelayMS((ULONG) (islowspeed ? 1000 : 100));
1274 if((pp = psdAllocPipe(pd, nch->nch_TaskMsgPort, NULL)))
1276 if(psdEnumerateDevice(pp))
1278 KPRINTF(2, (" Device successfully added!\n"));
1279 psdFreePipe(pp);
1280 psdUnlockDevice(pd);
1281 psdSendEvent(EHMB_ADDDEVICE, pd, NULL);
1282 ReleaseSemaphore(&nch->nch_HubBase->nh_Adr0Sema);
1283 return(pd);
1285 psdFreePipe(pp);
1287 break;
1288 } else {
1289 if(!(uhps.wPortStatus & UPSF_PORT_RESET))
1291 psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname,
1292 "Wrong port status %04lx for port %ld!",
1293 uhps.wPortStatus, port);
1294 KPRINTF(2, ("Wrong port status %04lx for port %ld.\n", uhps.wPortStatus, port));
1297 if(delayretries > 20)
1299 delaytime = 300;
1302 if((uhps.wPortStatus &
1303 (UPSF_PORT_RESET|UPSF_PORT_CONNECTION|UPSF_PORT_ENABLE|UPSF_PORT_POWER|UPSF_PORT_OVER_CURRENT|UPSF_PORT_LOW_SPEED)) ==
1304 (UPSF_PORT_CONNECTION|UPSF_PORT_POWER|UPSF_PORT_LOW_SPEED))
1306 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1307 "Strange port response, power-cycling port %ld",
1308 port);
1309 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1310 USR_CLEAR_FEATURE, UFS_PORT_ENABLE, (ULONG) port);
1311 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
1312 if(ioerr)
1314 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1315 "CLEAR_PORT_ENABLE for port %ld failed: %s (%ld)",
1316 port, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1317 KPRINTF(1, ("CLEAR_PORT_ENABLE for port %ld failed %ld!\n", port, ioerr));
1319 psdDelayMS(50);
1320 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1321 USR_CLEAR_FEATURE, UFS_PORT_POWER, (ULONG) port);
1322 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
1323 if(ioerr)
1325 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1326 "CLEAR_PORT_POWER for port %ld failed: %s (%ld)",
1327 port, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1328 KPRINTF(1, ("CLEAR_PORT_POWER for port %ld failed %ld!\n", port, ioerr));
1330 psdDelayMS(50);
1331 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1332 USR_SET_FEATURE, UFS_PORT_POWER, (ULONG) port);
1333 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
1334 if(ioerr)
1336 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1337 "SET_PORT_POWER for port %ld failed: %s (%ld)",
1338 port, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1339 KPRINTF(1, ("SET_PORT_POWER for port %ld failed %ld!\n", port, ioerr));
1341 psdDelayMS((ULONG) nch->nch_PwrGoodTime + 15);
1344 delaytime = 200;
1346 psdUnlockDevice(pd);
1347 psdFreeDevice(pd);
1348 /* Disable port! It's too dangerous having a connection with
1349 crazy devices on the bus open */
1350 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1351 USR_CLEAR_FEATURE, UFS_PORT_ENABLE, (ULONG) port);
1352 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
1353 if(ioerr)
1355 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1356 "CLEAR_PORT_ENABLE failed: %s (%ld)",
1357 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1358 KPRINTF(1, ("CLEAR_PORT_ENABLE failed %ld.\n", ioerr));
1360 ReleaseSemaphore(&nch->nch_HubBase->nh_Adr0Sema);
1361 GM_UNIQUENAME(nClearPortStatus)(nch, port);
1362 } else {
1363 Permit();
1364 KPRINTF(1, ("AllocDevice() failed.\n"));
1367 } else {
1368 psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname,
1369 "GET_PORT_CONNECTION failed: %s (%ld)",
1370 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1371 KPRINTF(1, ("GET_PORT_CONNECTION failed %ld.\n", ioerr));
1373 return(NULL);
1375 /* \\\ */
1377 /* /// "nHandleHubMethod()" */
1378 void GM_UNIQUENAME(nHandleHubMethod)(struct NepClassHub *nch, struct NepHubMsg *nhm)
1380 ULONG num;
1381 struct PsdDevice *pd;
1382 nhm->nhm_Result = 0;
1383 switch(nhm->nhm_MethodID)
1385 case UCM_HubClaimAppBinding:
1386 nhm->nhm_Result = (IPTR) psdHubClaimAppBindingA((struct TagItem *) nhm->nhm_Params[1]);
1387 break;
1389 case UCM_HubReleaseIfBinding:
1391 psdHubReleaseIfBinding((struct PsdInterface *) nhm->nhm_Params[1]);
1392 break;
1394 case UCM_HubReleaseDevBinding:
1395 psdHubReleaseDevBinding((struct PsdDevice *) nhm->nhm_Params[1]);
1396 break;
1398 case UCM_AttemptSuspendDevice:
1400 BOOL res = TRUE;
1401 for(num = 1; num <= nch->nch_NumPorts; num++)
1403 if((pd = (nch->nch_Downstream)[num-1]))
1405 res &= psdSuspendDevice(pd);
1408 if(res)
1410 // suspending of all downstream devices successful, so stop all activity, too.
1411 psdAbortPipe(nch->nch_EP1Pipe);
1412 nch->nch_Running = FALSE;
1413 nhm->nhm_Result = TRUE;
1415 break;
1418 case UCM_AttemptResumeDevice:
1419 if(!nch->nch_Running)
1421 psdWaitPipe(nch->nch_EP1Pipe);
1422 psdSendPipe(nch->nch_EP1Pipe, nch->nch_PortChanges, (nch->nch_NumPorts+8)>>3);
1423 nch->nch_Running = TRUE;
1425 nhm->nhm_Result = TRUE;
1426 for(num = 1; num <= nch->nch_NumPorts; num++)
1428 if((pd = (nch->nch_Downstream)[num-1]))
1430 psdResumeDevice(pd);
1433 break;
1435 case UCM_HubSuspendDevice:
1436 nhm->nhm_Result = GM_UNIQUENAME(nHubSuspendDevice)(nch, (struct PsdDevice *) nhm->nhm_Params[1]);
1437 break;
1439 case UCM_HubResumeDevice:
1440 nhm->nhm_Result = GM_UNIQUENAME(nHubResumeDevice)(nch, (struct PsdDevice *) nhm->nhm_Params[1]);
1441 break;
1445 /* \\\ */
1447 /* /// "nHubSuspendDevice()" */
1448 BOOL GM_UNIQUENAME(nHubSuspendDevice)(struct NepClassHub *nch, struct PsdDevice *pd)
1450 APTR binding = NULL;
1451 APTR puc = NULL;
1452 ULONG num;
1453 BOOL result = FALSE;
1454 LONG ioerr;
1456 psdGetAttrs(PGA_DEVICE, pd,
1457 DA_Binding, &binding,
1458 DA_BindingClass, &puc,
1459 TAG_END);
1461 for(num = 1; num <= nch->nch_NumPorts; num++)
1463 if(pd == (nch->nch_Downstream)[num-1])
1465 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1466 USR_SET_FEATURE, UFS_PORT_SUSPEND, num);
1468 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
1469 if(ioerr)
1471 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1472 "SET_PORT_SUSPEND failed: %s (%ld)",
1473 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1474 KPRINTF(1, ("SET_PORT_SUSPEND failed %ld.\n", ioerr));
1475 } else {
1476 result = TRUE;
1477 psdSetAttrs(PGA_DEVICE, pd, DA_IsSuspended, TRUE, TAG_END);
1478 psdSendEvent(EHMB_DEVSUSPENDED, pd, NULL);
1482 return result;
1484 /* \\\ */
1486 /* /// "nHubResumeDevice()" */
1487 BOOL GM_UNIQUENAME(nHubResumeDevice)(struct NepClassHub *nch, struct PsdDevice *pd)
1489 ULONG num;
1490 BOOL result = FALSE;
1491 LONG ioerr;
1493 for(num = 1; num <= nch->nch_NumPorts; num++)
1495 if(pd == (nch->nch_Downstream)[num-1])
1497 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1498 USR_CLEAR_FEATURE, UFS_PORT_SUSPEND, (ULONG) num);
1500 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
1501 if(ioerr)
1503 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1504 "CLEAR_PORT_SUSPEND failed: %s (%ld)",
1505 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1506 KPRINTF(1, ("CLEAR_PORT_SUSPEND failed %ld.\n", ioerr));
1507 } else {
1508 psdSetAttrs(PGA_DEVICE, pd, DA_IsSuspended, FALSE, TAG_END);
1509 psdSendEvent(EHMB_DEVRESUMED, pd, NULL);
1510 result = TRUE;
1511 psdDelayMS(30);
1515 return result;
1517 /* \\\ */