Initial import of work-in-progress of Poseidon port.
[cake.git] / rom / usb / classes / hub / hub.class.c
blob2a8aec03eaffc4d7dcab20a8aba7b39db78f2388
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 libInit(LIBBASETYPEPTR nh)
17 KPRINTF(10, ("libInit nh: 0x%08lx SysBase: 0x%08lx\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 libExpunge(LIBBASETYPEPTR nh)
38 KPRINTF(10, ("libExpunge nh: 0x%08lx SysBase: 0x%08lx\n", nh, SysBase));
40 CloseLibrary(UtilityBase);
41 nh->nh_UtilityBase = NULL;
43 return TRUE;
46 ADD2INITLIB(libInit, 0)
47 ADD2EXPUNGELIB(libExpunge, 0)
48 /* \\\ */
51 * ***********************************************************************
52 * * Library functions *
53 * ***********************************************************************
56 /* /// "usbAttemptDeviceBinding()" */
57 struct NepClassHub * usbAttemptDeviceBinding(struct NepHubBase *nh, struct PsdDevice *pd)
59 struct Library *ps;
60 IPTR devclass;
62 KPRINTF(1, ("nepHubAttemptDeviceBinding(%08lx)\n", pd));
64 if((ps = OpenLibrary("poseidon.library", 4)))
66 psdGetAttrs(PGA_DEVICE, pd,
67 DA_Class, &devclass,
68 TAG_DONE);
69 CloseLibrary(ps);
70 if(devclass == HUB_CLASSCODE)
72 return(usbForceDeviceBinding(nh, pd));
75 return(NULL);
77 /* \\\ */
79 /* /// "usbForceDeviceBinding()" */
80 struct NepClassHub * usbForceDeviceBinding(struct NepHubBase * nh, struct PsdDevice *pd)
82 struct Library *ps;
83 struct NepClassHub *nch;
84 STRPTR devname;
85 char buf[64];
86 struct Task *tmptask;
88 KPRINTF(1, ("nepHubAttemptDeviceBinding(%08lx)\n", pd));
90 if((ps = OpenLibrary("poseidon.library", 4)))
92 psdGetAttrs(PGA_DEVICE, pd,
93 DA_ProductName, &devname,
94 TAG_DONE);
95 if((nch = psdAllocVec(sizeof(struct NepClassHub))))
97 nch->nch_HubBase = nh;
98 nch->nch_SysBase = SysBase;
99 nch->nch_Device = pd;
100 psdSafeRawDoFmt(buf, 64, "hub.class<%08lx>", nch);
101 nch->nch_ReadySignal = SIGB_SINGLE;
102 nch->nch_ReadySigTask = FindTask(NULL);
103 SetSignal(0, SIGF_SINGLE);
104 if((tmptask = psdSpawnSubTask(buf, nHubTask, nch)))
106 psdBorrowLocksWait(tmptask, 1UL<<nch->nch_ReadySignal);
107 if(nch->nch_Task)
109 nch->nch_ReadySigTask = NULL;
110 //FreeSignal(nch->nch_ReadySignal);
111 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
112 "I'm in love with hub '%s'.",
113 devname);
115 Forbid();
116 AddTail(&nh->nh_Bindings, nch);
117 Permit();
118 CloseLibrary(ps);
119 return(nch);
122 nch->nch_ReadySigTask = NULL;
123 //FreeSignal(nch->nch_ReadySignal);
124 psdFreeVec(nch);
126 CloseLibrary(ps);
128 return(NULL);
130 /* \\\ */
132 /* /// "usbReleaseDeviceBinding()" */
133 void usbReleaseDeviceBinding(struct NepHubBase *nh, struct NepClassHub *nch)
135 struct Library *ps;
136 STRPTR devname;
138 KPRINTF(1, ("nepHubReleaseDeviceBinding(%08lx)\n", nch));
139 if((ps = OpenLibrary("poseidon.library", 4)))
141 Forbid();
142 nch->nch_ReadySignal = SIGB_SINGLE;
143 nch->nch_ReadySigTask = FindTask(NULL);
144 if(nch->nch_Task)
146 KPRINTF(1, ("Sending Break\n"));
147 Signal(nch->nch_Task, SIGBREAKF_CTRL_C);
149 Permit();
150 while(nch->nch_Task)
152 psdBorrowLocksWait(nch->nch_Task, 1UL<<nch->nch_ReadySignal);
154 KPRINTF(1, ("Task gone\n"));
155 //FreeSignal(nch->nch_ReadySignal);
156 psdGetAttrs(PGA_DEVICE, nch->nch_Device, DA_ProductName, &devname, TAG_END);
157 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
158 "Time to get rid of '%s'!",
159 devname);
160 Forbid();
161 Remove(nch);
162 Permit();
164 psdFreeVec(nch);
165 CloseLibrary(ps);
168 /* \\\ */
170 /* /// "usbGetAttrsA()" */
171 AROS_LH3(LONG, usbGetAttrsA,
172 AROS_LHA(ULONG, type, D0),
173 AROS_LHA(APTR, usbstruct, A0),
174 AROS_LHA(struct TagItem *, tags, A1),
175 LIBBASETYPEPTR, nh, 5, nep)
177 AROS_LIBFUNC_INIT
179 struct TagItem *ti;
180 LONG count = 0;
182 KPRINTF(1, ("nepHubGetAttrsA(%ld, %08lx, %08lx)\n", type, usbstruct, tags));
183 switch(type)
185 case UGA_CLASS:
186 if((ti = FindTagItem(UCCA_Priority, tags)))
188 *((IPTR *) ti->ti_Data) = 0;
189 count++;
191 if((ti = FindTagItem(UCCA_Description, tags)))
193 *((STRPTR *) ti->ti_Data) = "Root/external hub base class";
194 count++;
196 if((ti = FindTagItem(UCCA_HasClassCfgGUI, tags)))
198 *((IPTR *) ti->ti_Data) = FALSE;
199 count++;
201 if((ti = FindTagItem(UCCA_HasBindingCfgGUI, tags)))
203 *((IPTR *) ti->ti_Data) = FALSE;
204 count++;
206 if((ti = FindTagItem(UCCA_AfterDOSRestart, tags)))
208 *((IPTR *) ti->ti_Data) = FALSE;
209 count++;
211 if((ti = FindTagItem(UCCA_UsingDefaultCfg, tags)))
213 *((IPTR *) ti->ti_Data) = TRUE;
214 count++;
216 if((ti = FindTagItem(UCCA_SupportsSuspend, tags)))
218 *((IPTR *) ti->ti_Data) = TRUE;
219 count++;
221 break;
223 case UGA_BINDING:
224 if((ti = FindTagItem(UCBA_UsingDefaultCfg, tags)))
226 *((IPTR *) ti->ti_Data) = TRUE;
227 count++;
229 break;
231 return(count);
232 AROS_LIBFUNC_EXIT
234 /* \\\ */
236 /* /// "usbSetAttrsA()" */
237 AROS_LH3(LONG, usbSetAttrsA,
238 AROS_LHA(ULONG, type, D0),
239 AROS_LHA(APTR, usbstruct, A0),
240 AROS_LHA(struct TagItem *, tags, A1),
241 LIBBASETYPEPTR, nh, 6, nep)
243 AROS_LIBFUNC_INIT
244 return(0);
245 AROS_LIBFUNC_EXIT
247 /* \\\ */
249 /* /// "usbDoMethodA()" */
250 AROS_LH2(IPTR, usbDoMethodA,
251 AROS_LHA(ULONG, methodid, D0),
252 AROS_LHA(IPTR *, methoddata, A1),
253 LIBBASETYPEPTR, nh, 7, nep)
255 AROS_LIBFUNC_INIT
257 struct NepClassHub *nch;
259 KPRINTF(10, ("Do Method %ld\n", methodid));
260 switch(methodid)
262 case UCM_AttemptDeviceBinding:
263 return(usbAttemptDeviceBinding(nh, (struct PsdDevice *) methoddata[0]));
265 case UCM_ForceDeviceBinding:
266 return(usbForceDeviceBinding(nh, (struct PsdDevice *) methoddata[0]));
268 case UCM_ReleaseDeviceBinding:
269 usbReleaseDeviceBinding(nh, (struct NepClassHub *) methoddata[0]);
270 return(TRUE);
272 case UCM_HubPowerCyclePort:
273 case UCM_HubDisablePort:
275 struct PsdDevice *pd = (struct PsdDevice *) methoddata[0];
276 ULONG port = (ULONG) methoddata[1];
277 if(!(pd && port))
279 KPRINTF(20, ("HubPowerCycle/DisablePort Params Null!\n"));
280 return(FALSE);
282 Forbid();
283 nch = (struct NepClassHub *) nh->nh_Bindings.lh_Head;
284 while(nch->nch_Node.ln_Succ)
286 if(nch->nch_Device == pd)
288 KPRINTF(20, ("HubPowerCycle/DisablePort Dev found (port %ld)!\n", port));
289 if(port <= nch->nch_NumPorts)
291 nch->nch_DisablePort |= 1UL<<port;
292 if(methodid == UCM_HubPowerCyclePort)
294 nch->nch_PowerCycle |= 1UL<<port;
296 if(nch->nch_Task)
298 Signal(nch->nch_Task, (1L<<nch->nch_TaskMsgPort->mp_SigBit));
300 Permit();
301 return(TRUE);
303 break;
305 nch = (struct NepClassHub *) nch->nch_Node.ln_Succ;
307 Permit();
308 return(FALSE);
311 case UCM_HubClassScan:
313 nch = (struct NepClassHub *) methoddata[0];
314 Forbid();
315 nch->nch_ClassScan = TRUE;
316 if(nch->nch_Task)
318 Signal(nch->nch_Task, (1L<<nch->nch_TaskMsgPort->mp_SigBit));
320 Permit();
321 return(TRUE);
324 case UCM_AttemptSuspendDevice:
325 case UCM_AttemptResumeDevice:
326 case UCM_HubClaimAppBinding:
327 case UCM_HubReleaseIfBinding:
328 case UCM_HubReleaseDevBinding:
329 case UCM_HubSuspendDevice:
330 case UCM_HubResumeDevice:
332 struct NepHubMsg nhm;
333 struct Library *ps;
334 nch = (struct NepClassHub *) methoddata[0];
335 nhm.nhm_Result = NULL;
336 nhm.nhm_MethodID = methodid;
337 nhm.nhm_Params = methoddata;
338 if((ps = OpenLibrary("poseidon.library", 4)))
340 if(nch->nch_Task == FindTask(NULL))
342 // if we would send the message to ourself, we would deadlock, so handle this directly
343 nHandleHubMethod(nch, &nhm);
344 } else {
345 nhm.nhm_Msg.mn_ReplyPort = CreateMsgPort();
346 nhm.nhm_Msg.mn_Length = sizeof(struct NepHubMsg);
347 Forbid();
348 if(nch->nch_Task && nhm.nhm_Msg.mn_ReplyPort)
350 PutMsg(nch->nch_CtrlMsgPort, &nhm.nhm_Msg);
351 Permit();
352 while(!GetMsg(nhm.nhm_Msg.mn_ReplyPort))
354 psdBorrowLocksWait(nch->nch_Task, 1UL<<nhm.nhm_Msg.mn_ReplyPort->mp_SigBit);
356 } else {
357 Permit();
359 DeleteMsgPort(nhm.nhm_Msg.mn_ReplyPort);
361 CloseLibrary(ps);
363 return(nhm.nhm_Result);
366 default:
367 break;
369 return(0);
370 AROS_LIBFUNC_EXIT
372 /* \\\ */
374 #undef ps
375 #define ps nch->nch_Base
377 /* /// "nHubTask()" */
378 AROS_UFH0(void, nHubTask)
380 AROS_USERFUNC_INIT
382 struct NepClassHub *nch;
383 struct PsdPipe *pp;
384 ULONG sigmask;
385 ULONG sigs;
386 UWORD num;
387 LONG ioerr;
388 struct UsbPortStatus uhps;
389 struct UsbHubStatus uhhs;
390 ULONG count;
391 struct PsdDevice *pd;
392 STRPTR devname;
393 struct NepHubMsg *nhm;
395 if((nch = nAllocHub()))
397 Forbid();
398 if(nch->nch_ReadySigTask)
400 Signal(nch->nch_ReadySigTask, 1L<<nch->nch_ReadySignal);
402 Permit();
403 count = 0;
404 for(num = 1; num <= nch->nch_NumPorts; num++)
406 if(((nch->nch_Downstream)[num-1] = pd = nConfigurePort(nch, num)))
408 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
409 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
410 "Detected device '%s' at port %ld. I like it.",
411 devname, num);
412 count++;
415 if(count)
417 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
418 "Hub has added %ld device(s). That'll be fun!",
419 count);
421 // do a class scan
422 for(num = 1; num <= nch->nch_NumPorts; num++)
424 if((pd = (nch->nch_Downstream)[num-1]))
426 psdHubClassScan(pd);
429 sigmask = (1L<<nch->nch_TaskMsgPort->mp_SigBit)|(1L<<nch->nch_CtrlMsgPort->mp_SigBit)|SIGBREAKF_CTRL_C;
430 nch->nch_Running = TRUE;
431 nch->nch_IOStarted = FALSE;
434 if(nch->nch_Running && (!nch->nch_IOStarted))
436 psdSendPipe(nch->nch_EP1Pipe, nch->nch_PortChanges, 1);
437 nch->nch_IOStarted = TRUE;
439 sigs = Wait(sigmask);
440 while((nhm = (struct NepHubMsg *) GetMsg(nch->nch_CtrlMsgPort)))
442 nHandleHubMethod(nch, nhm);
444 ReplyMsg(nhm);
446 if(nch->nch_DisablePort)
448 for(num = 1; num <= nch->nch_NumPorts; num++)
450 if((nch->nch_DisablePort) & (1L<<num))
452 nch->nch_DisablePort &= ~(1L<<num);
453 /* Remove device */
454 if((pd = (nch->nch_Downstream)[num-1]))
456 psdSetAttrs(PGA_DEVICE, pd, DA_IsConnected, FALSE, TAG_END);
457 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
458 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
459 "Zapping device '%s' at port %ld!",
460 devname, num);
461 psdFreeDevice(pd);
462 psdSendEvent(EHMB_REMDEVICE, pd, NULL);
463 (nch->nch_Downstream)[num-1] = NULL;
464 pd = NULL;
465 /* disable port */
466 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
467 USR_CLEAR_FEATURE, UFS_PORT_ENABLE, (ULONG) num);
468 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
469 if(ioerr)
471 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
472 "CLEAR_PORT_ENABLE failed: %s (%ld)",
473 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
474 KPRINTF(1, ("CLEAR_PORT_ENABLE failed %ld.\n", ioerr));
477 if(nch->nch_PowerCycle & (1<<num))
479 nch->nch_PowerCycle &= ~(1L<<num);
481 /* Wait for device to settle */
482 psdDelayMS(250);
483 if(((nch->nch_Downstream)[num-1] = pd = nConfigurePort(nch, num)))
485 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
486 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
487 "Device '%s' returned. Happy happy joy joy.",
488 devname);
489 psdHubClassScan(pd);
495 if(nch->nch_ClassScan)
497 nch->nch_ClassScan = FALSE;
498 for(num = 1; num <= nch->nch_NumPorts; num++)
500 if((pd = (nch->nch_Downstream)[num-1]))
502 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
503 psdHubClassScan(pd);
507 while((pp = (struct PsdPipe *) GetMsg(nch->nch_TaskMsgPort)))
509 if(pp == nch->nch_EP1Pipe)
511 nch->nch_IOStarted = FALSE;
512 ioerr = psdGetPipeError(nch->nch_EP1Pipe);
513 if(ioerr == UHIOERR_TIMEOUT)
515 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
516 "Hub involuntarily gone! Disconnecting...");
517 psdSetAttrs(PGA_DEVICE, nch->nch_Device,
518 DA_IsConnected, FALSE,
519 TAG_END);
520 nch->nch_PortChanges[0] = 0xff;
521 sigs |= SIGBREAKF_CTRL_C;
523 if((!ioerr) || (ioerr == UHIOERR_TIMEOUT))
525 KPRINTF(2, ("Port changed at %08lx, Numports=%ld!\n", nch->nch_PortChanges[0], nch->nch_NumPorts));
527 if(nch->nch_PortChanges[0] & 1)
529 psdPipeSetup(nch->nch_EP0Pipe, URTF_IN|URTF_CLASS|URTF_DEVICE,
530 USR_GET_STATUS, 0, 0);
531 ioerr = psdDoPipe(nch->nch_EP0Pipe, &uhhs, sizeof(struct UsbHubStatus));
532 uhhs.wHubStatus = AROS_WORD2LE(uhhs.wHubStatus);
533 uhhs.wHubChange = AROS_WORD2LE(uhhs.wHubChange);
534 if(!ioerr)
536 if(uhhs.wHubStatus & UHSF_OVER_CURRENT)
538 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
539 "Hub over-current situation detected! Unpowering ALL ports!");
540 for(num = 1; num <= nch->nch_NumPorts; num++)
542 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
543 USR_CLEAR_FEATURE, UFS_PORT_POWER, (ULONG) num);
544 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
545 if(ioerr)
547 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
548 "PORT_POWER for port %ld failed: %s (%ld)",
549 num, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
550 KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", num, ioerr));
553 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
554 USR_CLEAR_FEATURE, UFS_C_PORT_OVER_CURRENT, (ULONG) num);
555 psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
557 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_DEVICE,
558 USR_CLEAR_FEATURE, UFS_C_HUB_OVER_CURRENT, 0);
559 psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
561 if(uhhs.wHubChange & UHSF_LOCAL_POWER_LOST)
563 struct PsdConfig *pc = NULL;
564 struct PsdHardware *phw = NULL;
565 psdGetAttrs(PGA_DEVICE, nch->nch_Device,
566 DA_Config, &pc,
567 DA_Hardware, &phw,
568 TAG_END);
569 if(uhhs.wHubStatus & UHSF_LOCAL_POWER_LOST)
571 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
572 "Hub is no longer self-powered! Low power conditions may occur.");
574 if(pc && phw)
576 psdSetAttrs(PGA_CONFIG, pc, CA_SelfPowered, FALSE, TAG_END);
577 psdCalculatePower(phw);
579 } else {
580 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
581 "Hub is now self-powered! Yay!");
582 if(pc && phw)
584 psdSetAttrs(PGA_CONFIG, pc, CA_SelfPowered, TRUE, TAG_END);
585 psdCalculatePower(phw);
588 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_DEVICE,
589 USR_CLEAR_FEATURE, UFS_C_HUB_LOCAL_POWER, 0);
590 psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
595 for(num = 1; num <= nch->nch_NumPorts; num++)
597 if(nch->nch_PortChanges[0] & (1L<<num))
599 psdPipeSetup(nch->nch_EP0Pipe, URTF_IN|URTF_CLASS|URTF_OTHER,
600 USR_GET_STATUS, 0, (ULONG) num);
601 ioerr = psdDoPipe(nch->nch_EP0Pipe, &uhps, sizeof(struct UsbPortStatus));
602 uhps.wPortStatus = AROS_WORD2LE(uhps.wPortStatus);
603 uhps.wPortChange = AROS_WORD2LE(uhps.wPortChange);
604 if(ioerr == UHIOERR_TIMEOUT)
606 uhps.wPortStatus = 0;
607 uhps.wPortChange = 0xffff;
608 ioerr = 0;
609 } else {
610 nClearPortStatus(nch, num);
612 if(!ioerr)
614 pd = (nch->nch_Downstream)[num-1];
615 if(uhps.wPortStatus & UPSF_PORT_OVER_CURRENT)
617 if(pd)
619 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
620 } else {
621 devname = "a ghost";
623 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
624 "Over-current situation detected with %s at port %ld! Unpowering port!",
625 devname, num);
626 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
627 USR_CLEAR_FEATURE, UFS_PORT_POWER, (ULONG) num);
628 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
629 if(ioerr)
631 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
632 "PORT_POWER for port %ld failed: %s (%ld)",
633 num, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
634 KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", num, ioerr));
637 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
638 USR_CLEAR_FEATURE, UFS_C_PORT_OVER_CURRENT, (ULONG) num);
639 psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
641 if(uhps.wPortChange & UPSF_PORT_SUSPEND)
643 if((!(uhps.wPortStatus & UPSF_PORT_SUSPEND)) && pd)
645 IPTR oldsusp = 0;
646 psdGetAttrs(PGA_DEVICE, pd, DA_IsSuspended, &oldsusp, TAG_END);
647 psdSetAttrs(PGA_DEVICE, pd, DA_IsSuspended, FALSE, TAG_END);
648 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
649 if(oldsusp)
651 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
652 "Device '%s' at port %ld resumed from remote!",
653 devname, num);
654 psdSendEvent(EHMB_DEVRESUMED, pd, NULL);
655 psdResumeBindings(pd);
658 else if((uhps.wPortStatus & UPSF_PORT_SUSPEND) && pd)
660 psdSetAttrs(PGA_DEVICE, pd, DA_IsSuspended, FALSE, TAG_END);
661 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
662 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
663 "Device '%s' at port %ld suspended!",
664 devname, num);
665 } else {
666 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
667 "Bogus suspend/resume change on port %ld.",
668 num);
671 if(uhps.wPortChange & UPSF_PORT_CONNECTION)
673 /* Remove device */
674 if((!(uhps.wPortStatus & UPSF_PORT_CONNECTION)) && pd)
676 psdSetAttrs(PGA_DEVICE, pd, DA_IsConnected, FALSE, TAG_END);
677 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
678 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
679 "Device '%s' at port %ld is gone!",
680 devname, num);
681 psdFreeDevice(pd);
682 psdSendEvent(EHMB_REMDEVICE, pd, NULL);
683 (nch->nch_Downstream)[num-1] = NULL;
684 pd = NULL;
686 /* add new device */
687 if((uhps.wPortStatus & UPSF_PORT_CONNECTION) && (!pd))
689 /* Wait for device to settle */
690 psdDelayMS(100);
691 if(((nch->nch_Downstream)[num-1] = pd = nConfigurePort(nch, num)))
693 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
694 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
695 "New device '%s' at port %ld. Very nice.",
696 devname, num);
697 psdClassScan();
704 /* Bail out on time out. */
705 if(nch->nch_PortChanges[0] == 0xff)
707 break;
709 psdDelayMS(50);
710 } else {
711 if(ioerr != IOERR_ABORTED)
713 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
714 "Something weird happened to the status packet, it failed: %s (%ld)",
715 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
716 psdDelayMS(200);
719 break;
720 } else {
721 KPRINTF(20, ("Bogus message received!\n"));
724 } while(!(sigs & SIGBREAKF_CTRL_C));
725 KPRINTF(20, ("Going down the river!\n"));
726 if(nch->nch_IOStarted)
728 psdAbortPipe(nch->nch_EP1Pipe);
729 psdWaitPipe(nch->nch_EP1Pipe);
731 psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Oh no! I've been shot! Arrggghh...");
732 nFreeHub(nch);
734 AROS_USERFUNC_EXIT
736 /* \\\ */
738 /* /// "nAllocHub()" */
739 struct NepClassHub * nAllocHub(void)
741 struct UsbHubDesc *uhd;
742 struct Task *thistask;
743 struct NepClassHub *nch;
744 struct UsbHubStatus uhhs;
745 LONG ioerr;
746 ULONG len;
747 UWORD num;
748 UBYTE buf;
749 IPTR ishighspeed = 0;
750 IPTR prodid;
751 IPTR vendid;
752 BOOL overcurrent = FALSE;
754 thistask = FindTask(NULL);
755 nch = thistask->tc_UserData;
758 if(!(nch->nch_Base = OpenLibrary("poseidon.library", 4)))
760 Alert(AG_OpenLib);
761 break;
764 psdGetAttrs(PGA_DEVICE, nch->nch_Device,
765 DA_Hardware, &nch->nch_Hardware,
766 DA_IsHighspeed, &ishighspeed,
767 DA_ProductID, &prodid,
768 DA_VendorID, &vendid,
769 TAG_END);
770 nch->nch_IsUSB20 = ishighspeed;
771 // try to select multi TT interface first
772 nch->nch_Interface = psdFindInterface(nch->nch_Device, NULL,
773 IFA_Class, HUB_CLASSCODE,
774 IFA_Protocol, 2,
775 IFA_AlternateNum, 0xffffffff,
776 TAG_END);
777 if(!nch->nch_Interface)
779 // any will do
780 nch->nch_Interface = psdFindInterface(nch->nch_Device, NULL,
781 IFA_Class, HUB_CLASSCODE,
782 TAG_END);
784 if((vendid == 0x05E3) && ishighspeed)
786 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "Genesys Logic hubs are broken and will cause failures with USB 2.0 devices.");
787 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "If you encounter problems, try the device without the hub.");
788 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "If this solves the problem, you need to buy a different USB 2.0 hub.");
791 if(!nch->nch_Interface)
793 KPRINTF(1, ("Ooops!?! No interfaces defined?\n"));
794 break;
796 nch->nch_EP1 = psdFindEndpoint(nch->nch_Interface, NULL,
797 EA_IsIn, TRUE,
798 EA_TransferType, USEAF_INTERRUPT,
799 TAG_END);
801 if(!nch->nch_EP1)
803 psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname, "Ooops!?! No endpoints defined?");
804 KPRINTF(1, ("Ooops!?! No Endpoints defined?\n"));
805 break;
807 if((nch->nch_CtrlMsgPort = CreateMsgPort()))
809 if((nch->nch_TaskMsgPort = CreateMsgPort()))
811 if((nch->nch_EP0Pipe = psdAllocPipe(nch->nch_Device, nch->nch_TaskMsgPort, NULL)))
813 psdSetAttrs(PGA_PIPE, nch->nch_EP0Pipe,
814 PPA_NakTimeout, TRUE,
815 PPA_NakTimeoutTime, 1000,
816 TAG_END);
817 psdSetAltInterface(nch->nch_EP0Pipe, nch->nch_Interface);
818 if((nch->nch_EP1Pipe = psdAllocPipe(nch->nch_Device, nch->nch_TaskMsgPort, nch->nch_EP1)))
820 psdPipeSetup(nch->nch_EP0Pipe, URTF_IN|URTF_CLASS|URTF_DEVICE,
821 USR_GET_DESCRIPTOR, UDT_HUB<<8, 0);
822 ioerr = psdDoPipe(nch->nch_EP0Pipe, &buf, 1);
823 if((!ioerr) || (ioerr == UHIOERR_OVERFLOW))
825 len = buf;
826 if((uhd = psdAllocVec(len)))
828 ioerr = psdDoPipe(nch->nch_EP0Pipe, uhd, len);
829 if(!ioerr)
831 nch->nch_NumPorts = uhd->bNbrPorts;
832 nch->nch_HubAttr = AROS_WORD2LE(uhd->wHubCharacteristics);
833 nch->nch_PwrGoodTime = uhd->bPwrOn2PwrGood<<1;
834 nch->nch_HubCurrent = uhd->bHubContrCurrent;
835 nch->nch_Removable = 0;
836 if(nch->nch_HubAttr & UHCM_THINK_TIME)
838 psdSetAttrs(PGA_DEVICE, nch->nch_Device,
839 DA_HubThinkTime, (nch->nch_HubAttr & UHCM_THINK_TIME)>>UHCS_THINK_TIME,
840 TAG_END);
843 for(num = 0; num < ((nch->nch_NumPorts + 7)>>3); num++)
845 nch->nch_Removable |= ((&uhd->DeviceRemovable)[num])<<(num<<3);
847 KPRINTF(1, ("Hub with %ld ports\n"
848 " PowerGood after %ld ms\n"
849 " Power consumption %ld mA\n",
850 nch->nch_NumPorts,
851 nch->nch_PwrGoodTime, nch->nch_HubCurrent));
852 psdFreeVec(uhd);
854 psdPipeSetup(nch->nch_EP0Pipe, URTF_IN|URTF_CLASS|URTF_DEVICE,
855 USR_GET_STATUS, 0, 0);
856 ioerr = psdDoPipe(nch->nch_EP0Pipe, &uhhs, sizeof(struct UsbHubStatus));
857 uhhs.wHubStatus = AROS_WORD2LE(uhhs.wHubStatus);
858 uhhs.wHubChange = AROS_WORD2LE(uhhs.wHubChange);
859 if(!ioerr)
861 struct PsdConfig *pc = NULL;
862 struct PsdHardware *phw = NULL;
863 if(uhhs.wHubStatus & UHSF_OVER_CURRENT)
865 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
866 "Hub over-current situation detected! Resolve this first!");
867 //overcurrent = TRUE;
870 psdGetAttrs(PGA_DEVICE, nch->nch_Device,
871 DA_Config, &pc,
872 DA_Hardware, &phw,
873 TAG_END);
874 if(uhhs.wHubStatus & UHSF_LOCAL_POWER_LOST)
876 if(pc && phw)
878 psdSetAttrs(PGA_CONFIG, pc, CA_SelfPowered, FALSE, TAG_END);
879 psdCalculatePower(phw);
881 } else {
882 if(pc && phw)
884 psdSetAttrs(PGA_CONFIG, pc, CA_SelfPowered, TRUE, TAG_END);
885 psdCalculatePower(phw);
889 if(!overcurrent)
891 if((nch->nch_Downstream = psdAllocVec((ULONG) nch->nch_NumPorts*sizeof(APTR))))
893 /*for(num = 1; num <= nch->nch_NumPorts; num++)
895 nClearPortStatus(nch, num);
897 psdDelayMS(20);*/
898 for(num = 1; num <= nch->nch_NumPorts; num++)
900 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
901 USR_SET_FEATURE, UFS_PORT_POWER, (ULONG) num);
902 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
903 if(ioerr)
905 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
906 "PORT_POWER for port %ld failed: %s (%ld)",
907 num, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
908 KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", num, ioerr));
911 psdDelayMS((ULONG) nch->nch_PwrGoodTime + 15);
913 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
914 "Hub with %ld ports successfully configured.",
915 nch->nch_NumPorts);
917 KPRINTF(10, ("%s ready!\n", thistask->tc_Node.ln_Name));
918 nch->nch_Task = thistask;
919 return(nch);
920 } else {
921 KPRINTF(1, ("No downstream port array memory!\n"));
924 } else {
925 psdFreeVec(uhd);
926 psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname,
927 "GET_HUB_DESCRIPTOR (%ld) failed: %s (%ld)",
928 len, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
929 KPRINTF(1, ("GET_HUB_DESCRIPTOR (%ld) failed %ld!\n", len, ioerr));
931 } else {
932 KPRINTF(1, ("No Hub Descriptor memory!\n"));
934 } else {
935 psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname,
936 "GET_HUB_DESCRIPTOR (%ld) failed: %s (%ld)",
937 1, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
938 KPRINTF(1, ("GET_HUB_DESCRIPTOR (1) failed %ld!\n", ioerr));
940 psdFreePipe(nch->nch_EP1Pipe);
942 psdFreePipe(nch->nch_EP0Pipe);
944 DeleteMsgPort(nch->nch_TaskMsgPort);
946 DeleteMsgPort(nch->nch_CtrlMsgPort);
948 } while(FALSE);
949 CloseLibrary(nch->nch_Base);
950 Forbid();
951 nch->nch_Task = NULL;
952 if(nch->nch_ReadySigTask)
954 Signal(nch->nch_ReadySigTask, 1L<<nch->nch_ReadySignal);
956 return(NULL);
958 /* \\\ */
960 /* /// "nFreeHub()" */
961 void nFreeHub(struct NepClassHub *nch)
963 UWORD num;
964 LONG ioerr;
965 struct PsdDevice *pd;
966 STRPTR devname;
967 IPTR isconnected;
968 struct Message *msg;
970 KPRINTF(1, ("FreeHub\n"));
971 psdGetAttrs(PGA_DEVICE, nch->nch_Device, DA_IsConnected, &isconnected, TAG_END);
972 for(num = 1; num <= nch->nch_NumPorts; num++)
974 KPRINTF(1, ("Iterating Port %ld\n", num));
975 /* Remove downstream device */
976 pd = (nch->nch_Downstream)[num-1];
977 if(pd)
979 if(!isconnected)
981 psdSetAttrs(PGA_DEVICE, pd, DA_IsConnected, FALSE, TAG_END);
983 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
984 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
985 "My death killed device '%s' at port %ld!",
986 devname, num);
987 KPRINTF(1, ("FreeDevice %08lx\n", pd));
988 psdFreeDevice(pd);
989 psdSendEvent(EHMB_REMDEVICE, pd, NULL);
990 (nch->nch_Downstream)[num-1] = NULL;
992 /* There's no sense trying to send out commands if the hub is already gone! */
993 if(isconnected)
995 /* power down for port */
996 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
997 USR_CLEAR_FEATURE, UFS_PORT_POWER, (ULONG) num);
998 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
999 if(ioerr)
1001 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1002 "PORT_POWER for port %ld failed: %s (%ld)",
1003 num, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1004 KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", num, ioerr));
1008 KPRINTF(1, ("FreePipes\n"));
1009 psdFreePipe(nch->nch_EP1Pipe);
1010 psdFreePipe(nch->nch_EP0Pipe);
1011 psdFreeVec(nch->nch_Downstream);
1012 KPRINTF(1, ("Entering Forbid\n"));
1013 Forbid();
1014 // clear queue
1015 while((msg = GetMsg(nch->nch_CtrlMsgPort)))
1017 ReplyMsg(msg);
1019 DeleteMsgPort(nch->nch_TaskMsgPort);
1020 DeleteMsgPort(nch->nch_CtrlMsgPort);
1021 CloseLibrary(nch->nch_Base);
1022 nch->nch_Task = NULL;
1023 if(nch->nch_ReadySigTask)
1025 Signal(nch->nch_ReadySigTask, 1L<<nch->nch_ReadySignal);
1027 KPRINTF(1, ("Really gone now!\n"));
1029 /* \\\ */
1031 /* *** HUB Class *** */
1033 /* /// "nClearPortStatus()" */
1034 LONG nClearPortStatus(struct NepClassHub *nch, UWORD port)
1036 LONG ioerr;
1037 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1038 USR_CLEAR_FEATURE, UFS_C_PORT_CONNECTION, (ULONG) port);
1039 if((ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0)))
1041 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1042 "CLEAR_PORT_FEATURE (C_PORT_CONNECTION) failed: %s (%ld)",
1043 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1044 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1045 return(ioerr);
1048 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1049 USR_CLEAR_FEATURE, UFS_C_PORT_ENABLE, (ULONG) port);
1050 if((ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0)))
1052 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1053 "CLEAR_PORT_FEATURE (C_PORT_ENABLE) failed: %s (%ld)",
1054 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1055 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1056 return(ioerr);
1059 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1060 USR_CLEAR_FEATURE, UFS_C_PORT_SUSPEND, (ULONG) port);
1061 if((ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0)))
1063 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1064 "CLEAR_PORT_FEATURE (C_PORT_SUSPEND) failed: %s (%ld)",
1065 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1066 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1067 return(ioerr);
1070 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1071 USR_CLEAR_FEATURE, UFS_C_PORT_OVER_CURRENT, (ULONG) port);
1072 if((ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0)))
1074 /*psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1075 "CLEAR_PORT_FEATURE (C_OVER_CURRENT) failed: %s (%ld)",
1076 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);*/
1077 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1080 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1081 USR_CLEAR_FEATURE, UFS_C_PORT_RESET, (ULONG) port);
1082 if((ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0)))
1084 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1085 "CLEAR_PORT_FEATURE (C_PORT_RESET) failed: %s (%ld)",
1086 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1087 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1088 return(ioerr);
1090 return(0);
1092 /* \\\ */
1094 /* /// "nConfigurePort()" */
1095 struct PsdDevice * nConfigurePort(struct NepClassHub *nch, UWORD port)
1097 LONG ioerr;
1098 LONG delayretries;
1099 LONG resetretries;
1100 ULONG delaytime = 10;
1101 struct UsbPortStatus uhps;
1102 struct PsdDevice *pd;
1103 struct PsdPipe *pp;
1104 BOOL washighspeed = FALSE;
1105 BOOL islowspeed = FALSE;
1107 psdPipeSetup(nch->nch_EP0Pipe, URTF_IN|URTF_CLASS|URTF_OTHER,
1108 USR_GET_STATUS, UFS_PORT_CONNECTION, (ULONG) port);
1109 ioerr = psdDoPipe(nch->nch_EP0Pipe, &uhps, sizeof(struct UsbPortStatus));
1110 uhps.wPortStatus = AROS_WORD2LE(uhps.wPortStatus);
1111 uhps.wPortChange = AROS_WORD2LE(uhps.wPortChange);
1112 if(!ioerr)
1114 if(uhps.wPortStatus & UPSF_PORT_ENABLE)
1116 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1117 USR_CLEAR_FEATURE, UFS_PORT_ENABLE, (ULONG) port);
1118 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
1119 if(ioerr)
1121 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1122 "CLEAR_PORT_ENABLE failed: %s (%ld)",
1123 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1124 KPRINTF(1, ("CLEAR_PORT_ENABLE failed %ld.\n", ioerr));
1125 } else {
1126 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1127 "Disabling port %ld.", port);
1130 if(uhps.wPortStatus & UPSF_PORT_CONNECTION)
1132 KPRINTF(1, ("There's something at port %ld!\n", port));
1133 Forbid();
1134 if((pd = psdAllocDevice(nch->nch_Hardware)))
1136 psdLockWriteDevice(pd);
1137 Permit();
1138 /* Hub reference */
1139 psdSetAttrs(PGA_DEVICE, pd,
1140 DA_HubDevice, (ULONG) nch->nch_Device,
1141 DA_IsConnected, TRUE,
1142 DA_AtHubPortNumber, port,
1143 TAG_END);
1144 if(uhps.wPortStatus & UPSF_PORT_LOW_SPEED)
1146 psdSetAttrs(PGA_DEVICE, pd, DA_IsLowspeed, TRUE, TAG_END);
1147 KPRINTF(1, (" It's a lowspeed device!\n"));
1148 islowspeed = TRUE;
1150 ObtainSemaphore(&nch->nch_HubBase->nh_Adr0Sema);
1151 for(resetretries = 0; resetretries < 3; resetretries++)
1153 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1154 USR_SET_FEATURE, UFS_PORT_RESET, (ULONG) port);
1155 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
1156 if(ioerr)
1158 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1159 "PORT_RESET for port %ld failed: %s (%ld)",
1160 port, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1161 KPRINTF(1, ("PORT_RESET failed %ld.\n", ioerr));
1162 break;
1164 for(delayretries = 0; delayretries < 500; delayretries += delaytime)
1166 psdDelayMS(delaytime);
1167 psdPipeSetup(nch->nch_EP0Pipe, URTF_IN|URTF_CLASS|URTF_OTHER,
1168 USR_GET_STATUS, UFS_PORT_CONNECTION, (ULONG) port);
1169 ioerr = psdDoPipe(nch->nch_EP0Pipe, &uhps, sizeof(struct UsbPortStatus));
1170 uhps.wPortStatus = AROS_WORD2LE(uhps.wPortStatus);
1171 uhps.wPortChange = AROS_WORD2LE(uhps.wPortChange);
1172 if(ioerr)
1174 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1175 "GET_PORT_CONNECTION for port %ld failed: %s (%ld)",
1176 port, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1177 KPRINTF(1, ("GET_PORT_CONNECTION failed %ld.\n", ioerr));
1178 break;
1180 if(!(uhps.wPortStatus & UPSF_PORT_CONNECTION))
1182 break;
1184 if((uhps.wPortStatus &
1185 (UPSF_PORT_RESET|UPSF_PORT_CONNECTION|UPSF_PORT_ENABLE|UPSF_PORT_POWER|UPSF_PORT_OVER_CURRENT)) ==
1186 (UPSF_PORT_CONNECTION|UPSF_PORT_ENABLE|UPSF_PORT_POWER))
1188 if((uhps.wPortStatus & UPSF_PORT_HIGH_SPEED) || washighspeed)
1190 psdSetAttrs(PGA_DEVICE, pd, DA_IsHighspeed, TRUE, TAG_END);
1191 washighspeed = TRUE;
1192 KPRINTF(1, (" It's a highspeed device!\n"));
1193 } else {
1194 IPTR needssplit = 0;
1195 // inherit needs split from hub
1196 psdGetAttrs(PGA_DEVICE, nch->nch_Device, DA_NeedsSplitTrans, &needssplit, TAG_END);
1197 if(nch->nch_IsUSB20) /* this is a low/full speed device connected to a 2.0 hub! */
1199 needssplit = TRUE;
1201 psdSetAttrs(PGA_DEVICE, pd, DA_NeedsSplitTrans, needssplit, TAG_END);
1203 nClearPortStatus(nch, port);
1204 psdDelayMS((ULONG) (islowspeed ? 1000 : 100));
1205 if((pp = psdAllocPipe(pd, nch->nch_TaskMsgPort, NULL)))
1207 if(psdEnumerateDevice(pp))
1209 KPRINTF(1, (" Device successfully added!\n"));
1210 psdFreePipe(pp);
1211 psdUnlockDevice(pd);
1212 psdSendEvent(EHMB_ADDDEVICE, pd, NULL);
1213 ReleaseSemaphore(&nch->nch_HubBase->nh_Adr0Sema);
1214 return(pd);
1216 psdFreePipe(pp);
1218 break;
1219 } else {
1220 if(!(uhps.wPortStatus & UPSF_PORT_RESET))
1222 psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname,
1223 "Wrong port status %04lx for port %ld!",
1224 uhps.wPortStatus, port);
1225 KPRINTF(1, ("Wrong port status %04lx for port %ld.\n", uhps.wPortStatus, port));
1228 if(delayretries > 20)
1230 delaytime = 300;
1233 if((uhps.wPortStatus &
1234 (UPSF_PORT_RESET|UPSF_PORT_CONNECTION|UPSF_PORT_ENABLE|UPSF_PORT_POWER|UPSF_PORT_OVER_CURRENT|UPSF_PORT_LOW_SPEED)) ==
1235 (UPSF_PORT_CONNECTION|UPSF_PORT_POWER|UPSF_PORT_LOW_SPEED))
1237 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1238 "Strange port response, power-cycling port %ld",
1239 port);
1240 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1241 USR_CLEAR_FEATURE, UFS_PORT_POWER, (ULONG) port);
1242 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
1243 if(ioerr)
1245 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1246 "PORT_POWER for port %ld failed: %s (%ld)",
1247 port, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1248 KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", port, ioerr));
1250 psdDelayMS(50);
1251 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1252 USR_SET_FEATURE, UFS_PORT_POWER, (ULONG) port);
1253 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
1254 if(ioerr)
1256 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1257 "PORT_POWER for port %ld failed: %s (%ld)",
1258 port, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1259 KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", port, ioerr));
1261 psdDelayMS((ULONG) nch->nch_PwrGoodTime + 15);
1264 delaytime = 200;
1266 psdUnlockDevice(pd);
1267 psdFreeDevice(pd);
1268 /* Disable port! It's too dangerous having a connection with
1269 crazy devices on the bus open */
1270 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1271 USR_CLEAR_FEATURE, UFS_PORT_ENABLE, (ULONG) port);
1272 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
1273 if(ioerr)
1275 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1276 "CLEAR_PORT_ENABLE failed: %s (%ld)",
1277 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1278 KPRINTF(1, ("CLEAR_PORT_ENABLE failed %ld.\n", ioerr));
1280 ReleaseSemaphore(&nch->nch_HubBase->nh_Adr0Sema);
1281 nClearPortStatus(nch, port);
1282 } else {
1283 Permit();
1284 KPRINTF(1, ("AllocDevice() failed.\n"));
1287 } else {
1288 psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname,
1289 "GET_PORT_CONNECTION failed: %s (%ld)",
1290 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1291 KPRINTF(1, ("GET_PORT_CONNECTION failed %ld.\n", ioerr));
1293 return(NULL);
1295 /* \\\ */
1297 /* /// "nHandleHubMethod()" */
1298 void nHandleHubMethod(struct NepClassHub *nch, struct NepHubMsg *nhm)
1300 ULONG num;
1301 struct PsdDevice *pd;
1302 nhm->nhm_Result = 0;
1303 switch(nhm->nhm_MethodID)
1305 case UCM_HubClaimAppBinding:
1306 nhm->nhm_Result = (ULONG) psdHubClaimAppBindingA((struct TagItem *) nhm->nhm_Params[1]);
1307 break;
1309 case UCM_HubReleaseIfBinding:
1311 psdHubReleaseIfBinding((struct PsdInterface *) nhm->nhm_Params[1]);
1312 break;
1314 case UCM_HubReleaseDevBinding:
1315 psdHubReleaseDevBinding((struct PsdDevice *) nhm->nhm_Params[1]);
1316 break;
1318 case UCM_AttemptSuspendDevice:
1320 BOOL res = TRUE;
1321 for(num = 1; num <= nch->nch_NumPorts; num++)
1323 if((pd = (nch->nch_Downstream)[num-1]))
1325 res &= psdSuspendDevice(pd);
1328 if(res)
1330 // suspending of all downstream devices successful, so stop all activity, too.
1331 psdAbortPipe(nch->nch_EP1Pipe);
1332 nch->nch_Running = FALSE;
1333 nhm->nhm_Result = TRUE;
1335 break;
1338 case UCM_AttemptResumeDevice:
1339 if(!nch->nch_Running)
1341 psdWaitPipe(nch->nch_EP1Pipe);
1342 psdSendPipe(nch->nch_EP1Pipe, nch->nch_PortChanges, 1);
1343 nch->nch_Running = TRUE;
1345 nhm->nhm_Result = TRUE;
1346 for(num = 1; num <= nch->nch_NumPorts; num++)
1348 if((pd = (nch->nch_Downstream)[num-1]))
1350 psdResumeDevice(pd);
1353 break;
1355 case UCM_HubSuspendDevice:
1356 nhm->nhm_Result = nHubSuspendDevice(nch, (struct PsdDevice *) nhm->nhm_Params[1]);
1357 break;
1359 case UCM_HubResumeDevice:
1360 nhm->nhm_Result = nHubResumeDevice(nch, (struct PsdDevice *) nhm->nhm_Params[1]);
1361 break;
1365 /* \\\ */
1367 /* /// "nHubSuspendDevice()" */
1368 BOOL nHubSuspendDevice(struct NepClassHub *nch, struct PsdDevice *pd)
1370 APTR binding = NULL;
1371 APTR puc = NULL;
1372 ULONG num;
1373 BOOL result = FALSE;
1374 LONG ioerr;
1376 psdGetAttrs(PGA_DEVICE, pd,
1377 DA_Binding, &binding,
1378 DA_BindingClass, &puc,
1379 TAG_END);
1381 for(num = 1; num <= nch->nch_NumPorts; num++)
1383 if(pd == (nch->nch_Downstream)[num-1])
1385 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1386 USR_SET_FEATURE, UFS_PORT_SUSPEND, num);
1388 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
1389 if(ioerr)
1391 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1392 "SET_PORT_SUSPEND failed: %s (%ld)",
1393 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1394 KPRINTF(1, ("SET_PORT_SUSPEND failed %ld.\n", ioerr));
1395 } else {
1396 result = TRUE;
1397 psdSetAttrs(PGA_DEVICE, pd, DA_IsSuspended, TRUE, TAG_END);
1398 psdSendEvent(EHMB_DEVSUSPENDED, pd, NULL);
1402 return result;
1404 /* \\\ */
1406 /* /// "nHubResumeDevice()" */
1407 BOOL nHubResumeDevice(struct NepClassHub *nch, struct PsdDevice *pd)
1409 ULONG num;
1410 BOOL result = FALSE;
1411 LONG ioerr;
1413 for(num = 1; num <= nch->nch_NumPorts; num++)
1415 if(pd == (nch->nch_Downstream)[num-1])
1417 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1418 USR_CLEAR_FEATURE, UFS_PORT_SUSPEND, (ULONG) num);
1420 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
1421 if(ioerr)
1423 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1424 "CLEAR_PORT_SUSPEND failed: %s (%ld)",
1425 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1426 KPRINTF(1, ("CLEAR_PORT_SUSPEND failed %ld.\n", ioerr));
1427 } else {
1428 psdSetAttrs(PGA_DEVICE, pd, DA_IsSuspended, FALSE, TAG_END);
1429 psdSendEvent(EHMB_DEVRESUMED, pd, NULL);
1430 result = TRUE;
1431 psdDelayMS(30);
1435 return result;
1437 /* \\\ */