Link with arossupport
[AROS.git] / rom / usb / classes / hubss / hubss.class.c
blob80b8e387dd149a54d9848f04ea9af4b4cfff1083
1 /*
2 Copyright © 2014, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: SuperSpeed USB3.0 hub for Poseidon (based upon hub.class.c by Chris Hodges <chrisly@platon42.de>)
6 Lang: english
7 */
9 #include "debug.h"
11 #include <aros/debug.h>
12 #include <proto/arossupport.h>
14 #include "hubss.class.h"
16 /* /// "Lib Stuff" */
17 static const STRPTR libname = MOD_NAME_STRING;
19 static int GM_UNIQUENAME(libInit)(LIBBASETYPEPTR nh) {
20 KPRINTF(10, ("libInit nh: 0x%p SysBase: 0x%p\n", nh, SysBase));
22 NewList(&nh->nh_Bindings);
23 InitSemaphore(&nh->nh_Adr0Sema);
25 KPRINTF(10, ("libInit: Ok\n"));
26 return TRUE;
29 ADD2INITLIB(GM_UNIQUENAME(libInit), 0)
31 /* \\\ */
34 * ***********************************************************************
35 * * Library functions *
36 * ***********************************************************************
39 /* /// "usbAttemptDeviceBinding()" */
40 struct NepClassHub * GM_UNIQUENAME(usbAttemptDeviceBinding)(struct NepHubBase *nh, struct PsdDevice *pd) {
41 struct Library *ps;
42 IPTR devclass;
43 IPTR issuperspeed = 0;
45 KPRINTF(1, ("nepHubAttemptDeviceBinding(%p)\n", pd));
47 if((ps = OpenLibrary("poseidon.library", 4))) {
48 psdGetAttrs(PGA_DEVICE, pd, DA_Class, &devclass, DA_IsSuperspeed, &issuperspeed, TAG_DONE);
49 CloseLibrary(ps);
51 if((devclass == HUB_CLASSCODE) && (issuperspeed)) {
52 return(GM_UNIQUENAME(usbForceDeviceBinding)(nh, pd));
55 return(NULL);
58 /* /// "usbForceDeviceBinding()" */
59 struct NepClassHub * GM_UNIQUENAME(usbForceDeviceBinding)(struct NepHubBase * nh, struct PsdDevice *pd)
61 struct Library *ps;
62 struct NepClassHub *nch;
63 STRPTR devname;
64 char buf[64];
65 struct Task *tmptask;
67 KPRINTF(1, ("nepHubAttemptDeviceBinding(%p)\n", pd));
69 if((ps = OpenLibrary("poseidon.library", 4)))
71 psdGetAttrs(PGA_DEVICE, pd,
72 DA_ProductName, &devname,
73 TAG_DONE);
74 if((nch = psdAllocVec(sizeof(struct NepClassHub))))
76 nch->nch_HubBase = nh;
77 nch->nch_Device = pd;
78 psdSafeRawDoFmt(buf, 64, "hub.class<%p>", nch);
79 nch->nch_ReadySignal = SIGB_SINGLE;
80 nch->nch_ReadySigTask = FindTask(NULL);
81 SetSignal(0, SIGF_SINGLE);
82 if((tmptask = psdSpawnSubTask(buf, GM_UNIQUENAME(nHubTask), nch)))
84 psdBorrowLocksWait(tmptask, 1UL<<nch->nch_ReadySignal);
85 if(nch->nch_Task)
87 nch->nch_ReadySigTask = NULL;
88 //FreeSignal(nch->nch_ReadySignal);
89 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
90 "I'm in love with hub '%s'.",
91 devname);
93 Forbid();
94 AddTail(&nh->nh_Bindings, &nch->nch_Node);
95 Permit();
96 CloseLibrary(ps);
97 return(nch);
100 nch->nch_ReadySigTask = NULL;
101 //FreeSignal(nch->nch_ReadySignal);
102 psdFreeVec(nch);
104 CloseLibrary(ps);
106 return(NULL);
108 /* \\\ */
110 /* /// "usbReleaseDeviceBinding()" */
111 void GM_UNIQUENAME(usbReleaseDeviceBinding)(struct NepHubBase *nh, struct NepClassHub *nch)
113 struct Library *ps;
114 STRPTR devname;
116 KPRINTF(1, ("nepHubReleaseDeviceBinding(%p)\n", nch));
117 if((ps = OpenLibrary("poseidon.library", 4)))
119 Forbid();
120 nch->nch_ReadySignal = SIGB_SINGLE;
121 nch->nch_ReadySigTask = FindTask(NULL);
122 if(nch->nch_Task)
124 KPRINTF(1, ("Sending Break\n"));
125 Signal(nch->nch_Task, SIGBREAKF_CTRL_C);
127 Permit();
128 while(nch->nch_Task)
130 psdBorrowLocksWait(nch->nch_Task, 1UL<<nch->nch_ReadySignal);
132 KPRINTF(1, ("Task gone\n"));
133 //FreeSignal(nch->nch_ReadySignal);
134 psdGetAttrs(PGA_DEVICE, nch->nch_Device, DA_ProductName, &devname, TAG_END);
135 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
136 "Time to get rid of '%s'!",
137 devname);
138 Forbid();
139 Remove(&nch->nch_Node);
140 Permit();
142 psdFreeVec(nch);
143 CloseLibrary(ps);
146 /* \\\ */
148 /* /// "usbGetAttrsA()" */
149 AROS_LH3(LONG, usbGetAttrsA, AROS_LHA(ULONG, type, D0), AROS_LHA(APTR, usbstruct, A0), AROS_LHA(struct TagItem *, taglist, A1), LIBBASETYPEPTR, nh, 5, hub) {
150 AROS_LIBFUNC_INIT
152 struct TagItem *ti;
153 LONG count = 0;
155 KPRINTF(1, ("nepHubGetAttrsA(%ld, %p, %p)\n", type, usbstruct, taglist));
157 switch(type) {
158 case UGA_CLASS:
159 while((ti = LibNextTagItem(&taglist)) != NULL) {
160 switch (ti->ti_Tag) {
161 case UCCA_Priority:
162 *((SIPTR *) ti->ti_Data) = 0;
163 count++;
164 break;
165 case UCCA_Description:
166 *((STRPTR *) ti->ti_Data) = "Root/external SuperSpeed hub base class";
167 count++;
168 break;
169 case UCCA_HasClassCfgGUI:
170 *((IPTR *) ti->ti_Data) = FALSE;
171 count++;
172 break;
173 case UCCA_HasBindingCfgGUI:
174 *((IPTR *) ti->ti_Data) = FALSE;
175 count++;
176 break;
177 case UCCA_AfterDOSRestart:
178 *((IPTR *) ti->ti_Data) = FALSE;
179 count++;
180 break;
181 case UCCA_UsingDefaultCfg:
182 *((IPTR *) ti->ti_Data) = TRUE;
183 count++;
184 break;
185 case UCCA_SupportsSuspend:
186 *((IPTR *) ti->ti_Data) = TRUE;
187 count++;
188 break;
189 } /* switch (ti->ti_Tag) */
190 }; /* while((ti = LibNextTagItem(&taglist)) != NULL) */
191 break;
193 case UGA_BINDING:
194 if((ti = LibFindTagItem(UCBA_UsingDefaultCfg, taglist))) {
195 *((IPTR *) ti->ti_Data) = TRUE;
196 count++;
198 break;
200 return(count);
201 AROS_LIBFUNC_EXIT
203 /* \\\ */
205 /* /// "usbSetAttrsA()" */
206 AROS_LH3(LONG, usbSetAttrsA,
207 AROS_LHA(ULONG, type, D0),
208 AROS_LHA(APTR, usbstruct, A0),
209 AROS_LHA(struct TagItem *, tags, A1),
210 LIBBASETYPEPTR, nh, 6, hub)
212 AROS_LIBFUNC_INIT
213 return(0);
214 AROS_LIBFUNC_EXIT
216 /* \\\ */
218 /* /// "usbDoMethodA()" */
219 AROS_LH2(IPTR, usbDoMethodA,
220 AROS_LHA(ULONG, methodid, D0),
221 AROS_LHA(IPTR *, methoddata, A1),
222 LIBBASETYPEPTR, nh, 7, hub)
224 AROS_LIBFUNC_INIT
226 struct NepClassHub *nch;
228 KPRINTF(1, ("Do Method %ld\n", methodid));
229 switch(methodid)
231 case UCM_AttemptDeviceBinding:
232 return((IPTR) GM_UNIQUENAME(usbAttemptDeviceBinding)(nh, (struct PsdDevice *) methoddata[0]));
234 case UCM_ForceDeviceBinding:
235 return((IPTR) GM_UNIQUENAME(usbForceDeviceBinding)(nh, (struct PsdDevice *) methoddata[0]));
237 case UCM_ReleaseDeviceBinding:
238 GM_UNIQUENAME(usbReleaseDeviceBinding)(nh, (struct NepClassHub *) methoddata[0]);
239 return(TRUE);
241 case UCM_HubPowerCyclePort:
242 case UCM_HubDisablePort:
244 struct PsdDevice *pd = (struct PsdDevice *) methoddata[0];
245 ULONG port = (ULONG) methoddata[1];
246 if(!(pd && port))
248 KPRINTF(20, ("HubPowerCycle/DisablePort Params Null!\n"));
249 return(FALSE);
251 Forbid();
252 nch = (struct NepClassHub *) nh->nh_Bindings.lh_Head;
253 while(nch->nch_Node.ln_Succ)
255 if(nch->nch_Device == pd)
257 KPRINTF(20, ("HubPowerCycle/DisablePort Dev found (port %ld)!\n", port));
258 if(port <= nch->nch_NumPorts)
260 nch->nch_DisablePort |= 1UL<<port;
261 if(methodid == UCM_HubPowerCyclePort)
263 nch->nch_PowerCycle |= 1UL<<port;
265 if(nch->nch_Task)
267 Signal(nch->nch_Task, (1L<<nch->nch_TaskMsgPort->mp_SigBit));
269 Permit();
270 return(TRUE);
272 break;
274 nch = (struct NepClassHub *) nch->nch_Node.ln_Succ;
276 Permit();
277 return(FALSE);
280 case UCM_HubClassScan:
282 nch = (struct NepClassHub *) methoddata[0];
283 Forbid();
284 nch->nch_ClassScan = TRUE;
285 if(nch->nch_Task)
287 Signal(nch->nch_Task, (1L<<nch->nch_TaskMsgPort->mp_SigBit));
289 Permit();
290 return(TRUE);
293 case UCM_AttemptSuspendDevice:
294 case UCM_AttemptResumeDevice:
295 case UCM_HubClaimAppBinding:
296 case UCM_HubReleaseIfBinding:
297 case UCM_HubReleaseDevBinding:
298 case UCM_HubSuspendDevice:
299 case UCM_HubResumeDevice:
301 struct NepHubMsg nhm;
302 struct Library *ps;
303 nch = (struct NepClassHub *) methoddata[0];
304 nhm.nhm_Result = (IPTR) NULL;
305 nhm.nhm_MethodID = methodid;
306 nhm.nhm_Params = methoddata;
307 if((ps = OpenLibrary("poseidon.library", 4)))
309 if(nch->nch_Task == FindTask(NULL))
311 // if we would send the message to ourself, we would deadlock, so handle this directly
312 GM_UNIQUENAME(nHandleHubMethod)(nch, &nhm);
313 } else {
314 nhm.nhm_Msg.mn_ReplyPort = CreateMsgPort();
315 nhm.nhm_Msg.mn_Length = sizeof(struct NepHubMsg);
316 Forbid();
317 if(nch->nch_Task && nhm.nhm_Msg.mn_ReplyPort)
319 PutMsg(nch->nch_CtrlMsgPort, &nhm.nhm_Msg);
320 Permit();
321 while(!GetMsg(nhm.nhm_Msg.mn_ReplyPort))
323 psdBorrowLocksWait(nch->nch_Task, 1UL<<nhm.nhm_Msg.mn_ReplyPort->mp_SigBit);
325 } else {
326 Permit();
328 DeleteMsgPort(nhm.nhm_Msg.mn_ReplyPort);
330 CloseLibrary(ps);
332 return(nhm.nhm_Result);
335 default:
336 break;
338 return(0);
339 AROS_LIBFUNC_EXIT
341 /* \\\ */
343 #undef ps
344 #define ps nch->nch_Base
346 /* /// "nHubTask()" */
347 AROS_UFH0(void, GM_UNIQUENAME(nHubTask))
349 AROS_USERFUNC_INIT
351 struct NepClassHub *nch;
352 struct PsdPipe *pp;
353 ULONG sigmask;
354 ULONG sigs;
355 UWORD num;
356 LONG ioerr;
357 struct UsbPortStatus uhps;
358 struct UsbHubStatus uhhs;
359 ULONG count;
360 struct PsdDevice *pd;
361 STRPTR devname;
362 struct NepHubMsg *nhm;
364 if((nch = GM_UNIQUENAME(nAllocHub)()))
366 Forbid();
367 if(nch->nch_ReadySigTask)
369 Signal(nch->nch_ReadySigTask, 1L<<nch->nch_ReadySignal);
371 Permit();
372 count = 0;
373 for(num = 1; num <= nch->nch_NumPorts; num++)
375 if(((nch->nch_Downstream)[num-1] = pd = GM_UNIQUENAME(nConfigurePort)(nch, num)))
377 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
378 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
379 "Detected device '%s' at port %ld. I like it.",
380 devname, num);
381 count++;
384 if(count)
386 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
387 "Hub has added %ld device(s). That'll be fun!",
388 count);
390 // do a class scan
391 for(num = 1; num <= nch->nch_NumPorts; num++)
393 if((pd = (nch->nch_Downstream)[num-1]))
395 psdHubClassScan(pd);
398 sigmask = (1L<<nch->nch_TaskMsgPort->mp_SigBit)|(1L<<nch->nch_CtrlMsgPort->mp_SigBit)|SIGBREAKF_CTRL_C;
399 nch->nch_Running = TRUE;
400 nch->nch_IOStarted = FALSE;
403 if(nch->nch_Running && (!nch->nch_IOStarted))
405 psdSendPipe(nch->nch_EP1Pipe, nch->nch_PortChanges, (nch->nch_NumPorts+8)>>3);
406 nch->nch_IOStarted = TRUE;
408 sigs = Wait(sigmask);
409 while((nhm = (struct NepHubMsg *) GetMsg(nch->nch_CtrlMsgPort)))
411 GM_UNIQUENAME(nHandleHubMethod)(nch, nhm);
413 ReplyMsg((struct Message *) nhm);
415 if(nch->nch_DisablePort)
417 for(num = 1; num <= nch->nch_NumPorts; num++)
419 if((nch->nch_DisablePort) & (1L<<num))
421 nch->nch_DisablePort &= ~(1L<<num);
422 /* Remove device */
423 if((pd = (nch->nch_Downstream)[num-1]))
425 psdSetAttrs(PGA_DEVICE, pd, DA_IsConnected, FALSE, TAG_END);
426 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
427 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
428 "Zapping device '%s' at port %ld!",
429 devname, num);
430 psdFreeDevice(pd);
431 psdSendEvent(EHMB_REMDEVICE, pd, NULL);
432 (nch->nch_Downstream)[num-1] = NULL;
433 pd = NULL;
434 /* disable port */
435 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
436 USR_CLEAR_FEATURE, UFS_PORT_ENABLE, (ULONG) num);
437 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
438 if(ioerr)
440 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
441 "CLEAR_PORT_ENABLE failed: %s (%ld)",
442 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
443 KPRINTF(1, ("CLEAR_PORT_ENABLE failed %ld.\n", ioerr));
446 if(nch->nch_PowerCycle & (1<<num))
448 KPRINTF(2, ("Powercycle request for port %lu\n", num));
449 nch->nch_PowerCycle &= ~(1L<<num);
451 /* Wait for device to settle */
452 psdDelayMS(250);
453 if(((nch->nch_Downstream)[num-1] = pd = GM_UNIQUENAME(nConfigurePort)(nch, num)))
455 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
456 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
457 "Device '%s' returned. Happy happy joy joy.",
458 devname);
459 psdHubClassScan(pd);
465 if(nch->nch_ClassScan)
467 nch->nch_ClassScan = FALSE;
468 for(num = 1; num <= nch->nch_NumPorts; num++)
470 if((pd = (nch->nch_Downstream)[num-1]))
472 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
473 psdHubClassScan(pd);
477 while((pp = (struct PsdPipe *) GetMsg(nch->nch_TaskMsgPort)))
479 if(pp == nch->nch_EP1Pipe)
481 nch->nch_IOStarted = FALSE;
482 ioerr = psdGetPipeError(nch->nch_EP1Pipe);
483 if(ioerr == UHIOERR_TIMEOUT)
485 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
486 "Hub involuntarily gone! Disconnecting...");
487 psdSetAttrs(PGA_DEVICE, nch->nch_Device,
488 DA_IsConnected, FALSE,
489 TAG_END);
490 nch->nch_PortChanges[0] = 0xff;
491 nch->nch_PortChanges[1] = 0xff;
492 nch->nch_PortChanges[2] = 0xff;
493 nch->nch_PortChanges[3] = 0xff;
494 sigs |= SIGBREAKF_CTRL_C;
496 if((!ioerr) || (ioerr == UHIOERR_TIMEOUT))
498 KPRINTF(2, ("Port changed at %p, Numports=%ld!\n", nch->nch_PortChanges[0], nch->nch_NumPorts));
500 if(nch->nch_PortChanges[0] & 1)
502 psdPipeSetup(nch->nch_EP0Pipe, URTF_IN|URTF_CLASS|URTF_DEVICE,
503 USR_GET_STATUS, 0, 0);
504 ioerr = psdDoPipe(nch->nch_EP0Pipe, &uhhs, sizeof(struct UsbHubStatus));
505 uhhs.wHubStatus = AROS_WORD2LE(uhhs.wHubStatus);
506 uhhs.wHubChange = AROS_WORD2LE(uhhs.wHubChange);
507 if(!ioerr)
509 if(uhhs.wHubStatus & UHSF_OVER_CURRENT)
511 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
512 "Hub over-current situation detected! Unpowering ALL ports!");
513 for(num = 1; num <= nch->nch_NumPorts; num++)
515 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
516 USR_CLEAR_FEATURE, UFS_PORT_POWER, (ULONG) num);
517 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
518 if(ioerr)
520 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
521 "PORT_POWER for port %ld failed: %s (%ld)",
522 num, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
523 KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", num, ioerr));
526 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
527 USR_CLEAR_FEATURE, UFS_C_PORT_OVER_CURRENT, (ULONG) num);
528 psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
530 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_DEVICE,
531 USR_CLEAR_FEATURE, UFS_C_HUB_OVER_CURRENT, 0);
532 psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
534 if(uhhs.wHubChange & UHSF_LOCAL_POWER_LOST)
536 struct PsdConfig *pc = NULL;
537 struct PsdHardware *phw = NULL;
538 psdGetAttrs(PGA_DEVICE, nch->nch_Device,
539 DA_Config, &pc,
540 DA_Hardware, &phw,
541 TAG_END);
542 if(uhhs.wHubStatus & UHSF_LOCAL_POWER_LOST)
544 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
545 "Hub is no longer self-powered! Low power conditions may occur.");
547 if(pc && phw)
549 psdSetAttrs(PGA_CONFIG, pc, CA_SelfPowered, FALSE, TAG_END);
550 psdCalculatePower(phw);
552 } else {
553 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
554 "Hub is now self-powered! Yay!");
555 if(pc && phw)
557 psdSetAttrs(PGA_CONFIG, pc, CA_SelfPowered, TRUE, TAG_END);
558 psdCalculatePower(phw);
561 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_DEVICE,
562 USR_CLEAR_FEATURE, UFS_C_HUB_LOCAL_POWER, 0);
563 psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
568 for(num = 1; num <= nch->nch_NumPorts; num++)
570 if(nch->nch_PortChanges[num>>3] & (1L<<(num & 7)))
572 psdPipeSetup(nch->nch_EP0Pipe, URTF_IN|URTF_CLASS|URTF_OTHER,
573 USR_GET_STATUS, 0, (ULONG) num);
574 ioerr = psdDoPipe(nch->nch_EP0Pipe, &uhps, sizeof(struct UsbPortStatus));
575 uhps.wPortStatus = AROS_WORD2LE(uhps.wPortStatus);
576 uhps.wPortChange = AROS_WORD2LE(uhps.wPortChange);
577 if(ioerr == UHIOERR_TIMEOUT)
579 uhps.wPortStatus = 0;
580 uhps.wPortChange = 0xffff;
581 ioerr = 0;
582 } else {
583 GM_UNIQUENAME(nClearPortStatus)(nch, num);
585 if(!ioerr)
587 pd = (nch->nch_Downstream)[num-1];
588 if(uhps.wPortStatus & UPSF_PORT_OVER_CURRENT)
590 if(pd)
592 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
593 } else {
594 devname = "a ghost";
596 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
597 "Over-current situation detected with %s at port %ld! Unpowering port!",
598 devname, num);
599 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
600 USR_CLEAR_FEATURE, UFS_PORT_POWER, (ULONG) num);
601 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
602 if(ioerr)
604 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
605 "PORT_POWER for port %ld failed: %s (%ld)",
606 num, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
607 KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", num, ioerr));
610 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
611 USR_CLEAR_FEATURE, UFS_C_PORT_OVER_CURRENT, (ULONG) num);
612 psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
614 if(uhps.wPortChange & UPSF_PORT_SUSPEND)
616 if((!(uhps.wPortStatus & UPSF_PORT_SUSPEND)) && pd)
618 IPTR oldsusp = 0;
619 psdGetAttrs(PGA_DEVICE, pd, DA_IsSuspended, &oldsusp, TAG_END);
620 psdSetAttrs(PGA_DEVICE, pd, DA_IsSuspended, FALSE, TAG_END);
621 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
622 if(oldsusp)
624 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
625 "Device '%s' at port %ld resumed from remote!",
626 devname, num);
627 psdSendEvent(EHMB_DEVRESUMED, pd, NULL);
628 psdResumeBindings(pd);
631 else if((uhps.wPortStatus & UPSF_PORT_SUSPEND) && pd)
633 psdSetAttrs(PGA_DEVICE, pd, DA_IsSuspended, FALSE, TAG_END);
634 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
635 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
636 "Device '%s' at port %ld suspended!",
637 devname, num);
638 } else {
639 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
640 "Bogus suspend/resume change on port %ld.",
641 num);
644 if(uhps.wPortChange & UPSF_PORT_CONNECTION)
646 /* Remove device */
647 if((!(uhps.wPortStatus & UPSF_PORT_CONNECTION)) && pd)
649 psdSetAttrs(PGA_DEVICE, pd, DA_IsConnected, FALSE, TAG_END);
650 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
651 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
652 "Device '%s' at port %ld is gone!",
653 devname, num);
654 psdFreeDevice(pd);
655 psdSendEvent(EHMB_REMDEVICE, pd, NULL);
656 (nch->nch_Downstream)[num-1] = NULL;
657 pd = NULL;
659 /* add new device */
660 if((uhps.wPortStatus & UPSF_PORT_CONNECTION) && (!pd))
662 /* Wait for device to settle */
663 psdDelayMS(100);
664 if(((nch->nch_Downstream)[num-1] = pd = GM_UNIQUENAME(nConfigurePort)(nch, num)))
666 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
667 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
668 "New device '%s' at port %ld. Very nice.",
669 devname, num);
670 psdClassScan();
677 /* Bail out on time out. */
678 if(nch->nch_PortChanges[0] == 0xff)
680 break;
682 psdDelayMS(50);
683 } else {
684 if(ioerr != IOERR_ABORTED)
686 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
687 "Something weird happened to the status packet, it failed: %s (%ld)",
688 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
689 psdDelayMS(200);
692 break;
693 } else {
694 KPRINTF(20, ("Bogus message received!\n"));
697 } while(!(sigs & SIGBREAKF_CTRL_C));
698 KPRINTF(20, ("Going down the river!\n"));
699 if(nch->nch_IOStarted)
701 psdAbortPipe(nch->nch_EP1Pipe);
702 psdWaitPipe(nch->nch_EP1Pipe);
704 psdAddErrorMsg(RETURN_OK, (STRPTR) libname, "Oh no! I've been shot! Arrggghh...");
705 GM_UNIQUENAME(nFreeHub)(nch);
707 AROS_USERFUNC_EXIT
709 /* \\\ */
711 /* /// "nAllocHub()" */
712 struct NepClassHub * GM_UNIQUENAME(nAllocHub)(void) {
713 struct UsbSSHubDesc *usshd;
714 struct Task *thistask;
715 struct NepClassHub *nch;
716 struct UsbHubStatus uhhs;
717 APTR parenthub;
718 LONG ioerr;
719 ULONG len;
720 UWORD num;
721 UBYTE buf[2];
722 IPTR issuperspeed = 0;
723 IPTR prodid;
724 IPTR vendid;
725 BOOL overcurrent = FALSE;
727 thistask = FindTask(NULL);
728 nch = thistask->tc_UserData;
730 do {
731 if(!(nch->nch_Base = OpenLibrary("poseidon.library", 4))) {
732 Alert(AG_OpenLib);
733 break;
736 psdGetAttrs(PGA_DEVICE, nch->nch_Device,
737 DA_Hardware, &nch->nch_Hardware,
738 DA_IsSuperspeed, &issuperspeed,
739 DA_ProductID, &prodid,
740 DA_VendorID, &vendid,
741 DA_HubDevice, &parenthub,
742 TAG_END);
744 nch->nch_IsRootHub = (parenthub ? FALSE : TRUE);
745 nch->nch_IsUSB30 = issuperspeed;
747 // try to select multi TT interface first
748 nch->nch_Interface = psdFindInterface(nch->nch_Device, NULL,
749 IFA_Class, HUB_CLASSCODE,
750 IFA_Protocol, 2,
751 IFA_AlternateNum, 0xffffffff,
752 TAG_END);
754 if(!nch->nch_Interface) {
755 // any will do
756 nch->nch_Interface = psdFindInterface(nch->nch_Device, NULL,
757 IFA_Class, HUB_CLASSCODE,
758 TAG_END);
761 if(!nch->nch_Interface) {
762 KPRINTF(1, ("Ooops!?! No interfaces defined?\n"));
763 break;
766 nch->nch_EP1 = psdFindEndpoint(nch->nch_Interface, NULL,
767 EA_IsIn, TRUE,
768 EA_TransferType, USEAF_INTERRUPT,
769 TAG_END);
771 if(!nch->nch_EP1) {
772 psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname, "Ooops!?! No endpoints defined?");
773 KPRINTF(1, ("Ooops!?! No Endpoints defined?\n"));
774 break;
777 if((nch->nch_CtrlMsgPort = CreateMsgPort())) {
778 if((nch->nch_TaskMsgPort = CreateMsgPort())) {
779 if((nch->nch_EP0Pipe = psdAllocPipe(nch->nch_Device, nch->nch_TaskMsgPort, NULL))) {
781 psdSetAttrs(PGA_PIPE, nch->nch_EP0Pipe,
782 PPA_NakTimeout, TRUE,
783 PPA_NakTimeoutTime, 1000,
784 TAG_END);
786 psdSetAltInterface(nch->nch_EP0Pipe, nch->nch_Interface);
788 if((nch->nch_EP1Pipe = psdAllocPipe(nch->nch_Device, nch->nch_TaskMsgPort, nch->nch_EP1))) {
790 psdSetAttrs(PGA_PIPE, nch->nch_EP1Pipe, PPA_AllowRuntPackets, TRUE, TAG_END);
791 psdPipeSetup(nch->nch_EP0Pipe, URTF_IN|URTF_CLASS|URTF_DEVICE, USR_GET_DESCRIPTOR, UDT_SSHUB<<8, 0);
793 ioerr = psdDoPipe(nch->nch_EP0Pipe, &buf, 2);
795 if(buf[1] == UDT_SSHUB) {
797 if((!ioerr) || (ioerr == UHIOERR_OVERFLOW)) {
798 len = buf[0];
800 if((usshd = psdAllocVec(len))) {
801 ioerr = psdDoPipe(nch->nch_EP0Pipe, usshd, len);
803 if(!ioerr) {
804 nch->nch_NumPorts = usshd->bNbrPorts;
805 nch->nch_HubAttr = AROS_WORD2LE(usshd->wHubCharacteristics);
806 nch->nch_PwrGoodTime = usshd->bPwrOn2PwrGood<<1;
807 nch->nch_HubCurrent = usshd->bHubContrCurrent;
808 nch->nch_HubHdrDecLat = usshd->bHubHdrDecLat;
809 nch->nch_HubDelay = usshd->wHubDelay;
810 nch->nch_Removable = 0; //usshd->DeviceRemovable;
812 if(nch->nch_HubAttr & UHCM_THINK_TIME) {
813 psdSetAttrs(PGA_DEVICE, nch->nch_Device, DA_HubThinkTime, (nch->nch_HubAttr & UHCM_THINK_TIME)>>UHCS_THINK_TIME, TAG_END);
816 for(num = 0; num < ((nch->nch_NumPorts + 7)>>3); num++) {
817 nch->nch_Removable |= ((&usshd->DeviceRemovable)[num])<<(num<<3);
819 KPRINTF(2, ("Hub with %ld ports\n"
820 " Characteristics 0x%04lx\n"
821 " PowerGood after %ld ms\n"
822 " Power consumption %ld mA\n",
823 nch->nch_NumPorts,
824 nch->nch_HubAttr,
825 nch->nch_PwrGoodTime, nch->nch_HubCurrent));
827 psdFreeVec(usshd);
829 psdPipeSetup(nch->nch_EP0Pipe, URTF_IN|URTF_CLASS|URTF_DEVICE, USR_GET_STATUS, 0, 0);
830 ioerr = psdDoPipe(nch->nch_EP0Pipe, &uhhs, sizeof(struct UsbHubStatus));
832 uhhs.wHubStatus = AROS_WORD2LE(uhhs.wHubStatus);
833 uhhs.wHubChange = AROS_WORD2LE(uhhs.wHubChange);
834 if(!ioerr)
836 struct PsdConfig *pc = NULL;
837 struct PsdHardware *phw = NULL;
838 if(uhhs.wHubStatus & UHSF_OVER_CURRENT)
840 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
841 "Hub over-current situation detected! Resolve this first!");
842 //overcurrent = TRUE;
845 psdGetAttrs(PGA_DEVICE, nch->nch_Device,
846 DA_Config, &pc,
847 DA_Hardware, &phw,
848 TAG_END);
849 if(uhhs.wHubStatus & UHSF_LOCAL_POWER_LOST)
851 if(pc && phw)
853 psdSetAttrs(PGA_CONFIG, pc, CA_SelfPowered, FALSE, TAG_END);
854 psdCalculatePower(phw);
856 } else {
857 if(pc && phw)
859 psdSetAttrs(PGA_CONFIG, pc, CA_SelfPowered, TRUE, TAG_END);
860 psdCalculatePower(phw);
864 if(!overcurrent)
866 if((nch->nch_Downstream = psdAllocVec((ULONG) nch->nch_NumPorts*sizeof(APTR))))
868 /*for(num = 1; num <= nch->nch_NumPorts; num++)
870 GM_UNIQUENAME(nClearPortStatus)(nch, num);
872 psdDelayMS(20);*/
873 KPRINTF(2, ("Powering up ports...\n"));
874 for(num = 1; num <= nch->nch_NumPorts; num++)
876 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
877 USR_SET_FEATURE, UFS_PORT_POWER, (ULONG) num);
878 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
879 if(ioerr)
881 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
882 "PORT_POWER for port %ld failed: %s (%ld)",
883 num, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
884 KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", num, ioerr));
887 psdDelayMS((ULONG) nch->nch_PwrGoodTime + 15);
889 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
890 "Hub with %ld ports successfully configured.",
891 nch->nch_NumPorts);
893 KPRINTF(10, ("%s ready!\n", thistask->tc_Node.ln_Name));
894 nch->nch_Task = thistask;
895 return(nch);
896 } else {
897 KPRINTF(1, ("No downstream port array memory!\n"));
900 } else {
901 psdFreeVec(usshd);
902 psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname,
903 "GET_HUB_DESCRIPTOR (%ld) failed: %s (%ld)",
904 len, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
905 KPRINTF(1, ("GET_HUB_DESCRIPTOR (%ld) failed %ld!\n", len, ioerr));
908 } else {
909 KPRINTF(1, ("No Hub Descriptor memory!\n"));
911 } else {
912 psdAddErrorMsg(RETURN_FAIL, (STRPTR) libname,
913 "GET_HUB_DESCRIPTOR (%ld) failed: %s (%ld)",
914 1, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
915 KPRINTF(1, ("GET_HUB_DESCRIPTOR (1) failed %ld!\n", ioerr));
920 psdFreePipe(nch->nch_EP1Pipe);
922 psdFreePipe(nch->nch_EP0Pipe);
924 DeleteMsgPort(nch->nch_TaskMsgPort);
926 DeleteMsgPort(nch->nch_CtrlMsgPort);
928 } while(FALSE);
930 CloseLibrary(nch->nch_Base);
932 Forbid();
933 nch->nch_Task = NULL;
935 if(nch->nch_ReadySigTask) {
936 Signal(nch->nch_ReadySigTask, 1L<<nch->nch_ReadySignal);
939 return(NULL);
941 /* \\\ */
943 /* /// "nFreeHub()" */
944 void GM_UNIQUENAME(nFreeHub)(struct NepClassHub *nch)
946 UWORD num;
947 LONG ioerr;
948 struct PsdDevice *pd;
949 STRPTR devname;
950 IPTR isconnected;
951 struct Message *msg;
953 KPRINTF(1, ("FreeHub\n"));
954 psdGetAttrs(PGA_DEVICE, nch->nch_Device, DA_IsConnected, &isconnected, TAG_END);
955 for(num = 1; num <= nch->nch_NumPorts; num++)
957 KPRINTF(1, ("Iterating Port %ld\n", num));
958 /* Remove downstream device */
959 pd = (nch->nch_Downstream)[num-1];
960 if(pd)
962 if(!isconnected)
964 psdSetAttrs(PGA_DEVICE, pd, DA_IsConnected, FALSE, TAG_END);
966 psdGetAttrs(PGA_DEVICE, pd, DA_ProductName, &devname, TAG_END);
967 psdAddErrorMsg(RETURN_OK, (STRPTR) libname,
968 "My death killed device '%s' at port %ld!",
969 devname, num);
970 KPRINTF(1, ("FreeDevice %p\n", pd));
971 psdFreeDevice(pd);
972 psdSendEvent(EHMB_REMDEVICE, pd, NULL);
973 (nch->nch_Downstream)[num-1] = NULL;
975 /* There's no sense trying to send out commands if the hub is already gone! */
976 if(isconnected)
978 /* power down for port */
979 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
980 USR_CLEAR_FEATURE, UFS_PORT_POWER, (ULONG) num);
981 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
982 if(ioerr)
984 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
985 "PORT_POWER for port %ld failed: %s (%ld)",
986 num, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
987 KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", num, ioerr));
991 KPRINTF(1, ("FreePipes\n"));
992 psdFreePipe(nch->nch_EP1Pipe);
993 psdFreePipe(nch->nch_EP0Pipe);
994 psdFreeVec(nch->nch_Downstream);
995 KPRINTF(1, ("Entering Forbid\n"));
996 Forbid();
997 // clear queue
998 while((msg = GetMsg(nch->nch_CtrlMsgPort)))
1000 ReplyMsg(msg);
1002 DeleteMsgPort(nch->nch_TaskMsgPort);
1003 DeleteMsgPort(nch->nch_CtrlMsgPort);
1004 CloseLibrary(nch->nch_Base);
1005 nch->nch_Task = NULL;
1006 if(nch->nch_ReadySigTask)
1008 Signal(nch->nch_ReadySigTask, 1L<<nch->nch_ReadySignal);
1010 KPRINTF(1, ("Really gone now!\n"));
1012 /* \\\ */
1014 /* *** HUB Class *** */
1016 /* /// "nClearPortStatus()" */
1017 LONG GM_UNIQUENAME(nClearPortStatus)(struct NepClassHub *nch, UWORD port)
1019 LONG ioerr;
1020 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1021 USR_CLEAR_FEATURE, UFS_C_PORT_CONNECTION, (ULONG) port);
1022 if((ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0)))
1024 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1025 "CLEAR_PORT_FEATURE (C_PORT_CONNECTION) failed: %s (%ld)",
1026 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1027 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1028 return(ioerr);
1031 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1032 USR_CLEAR_FEATURE, UFS_C_PORT_ENABLE, (ULONG) port);
1033 if((ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0)))
1035 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1036 "CLEAR_PORT_FEATURE (C_PORT_ENABLE) failed: %s (%ld)",
1037 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1038 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1039 return(ioerr);
1042 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1043 USR_CLEAR_FEATURE, UFS_C_PORT_SUSPEND, (ULONG) port);
1044 if((ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0)))
1046 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1047 "CLEAR_PORT_FEATURE (C_PORT_SUSPEND) failed: %s (%ld)",
1048 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1049 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1050 return(ioerr);
1053 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1054 USR_CLEAR_FEATURE, UFS_C_PORT_OVER_CURRENT, (ULONG) port);
1055 if((ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0)))
1057 /*psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1058 "CLEAR_PORT_FEATURE (C_OVER_CURRENT) failed: %s (%ld)",
1059 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);*/
1060 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1063 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1064 USR_CLEAR_FEATURE, UFS_C_PORT_RESET, (ULONG) port);
1065 if((ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0)))
1067 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1068 "CLEAR_PORT_FEATURE (C_PORT_RESET) failed: %s (%ld)",
1069 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1070 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1071 return(ioerr);
1073 return(0);
1075 /* \\\ */
1077 /* /// "nConfigurePort()" */
1078 struct PsdDevice * GM_UNIQUENAME(nConfigurePort)(struct NepClassHub *nch, UWORD port)
1080 LONG ioerr;
1081 LONG delayretries;
1082 LONG resetretries;
1083 ULONG delaytime = 10;
1084 struct UsbPortStatus uhps;
1085 struct PsdDevice *pd;
1086 struct PsdPipe *pp;
1087 BOOL washighspeed = FALSE;
1088 BOOL islowspeed = FALSE;
1090 KPRINTF(2, ("Configuring port %ld of hub 0x%p\n", port, nch));
1092 uhps.wPortStatus = 0xDEAD;
1093 uhps.wPortChange = 0xDA1A;
1095 psdPipeSetup(nch->nch_EP0Pipe, URTF_IN|URTF_CLASS|URTF_OTHER,
1096 USR_GET_STATUS, UFS_PORT_CONNECTION, (ULONG) port);
1097 ioerr = psdDoPipe(nch->nch_EP0Pipe, &uhps, sizeof(struct UsbPortStatus));
1098 uhps.wPortStatus = AROS_WORD2LE(uhps.wPortStatus);
1099 uhps.wPortChange = AROS_WORD2LE(uhps.wPortChange);
1100 if(!ioerr)
1102 KPRINTF(2, ("Status 0x%04x, change 0x%04x\n", uhps.wPortStatus, uhps.wPortChange));
1104 if(uhps.wPortStatus & UPSF_PORT_ENABLE)
1106 KPRINTF(2, ("Disabling port %u\n", port));
1108 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1109 USR_CLEAR_FEATURE, UFS_PORT_ENABLE, (ULONG) port);
1110 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
1111 if(ioerr)
1113 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1114 "CLEAR_PORT_ENABLE failed: %s (%ld)",
1115 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1116 KPRINTF(1, ("CLEAR_PORT_ENABLE failed %ld.\n", ioerr));
1117 } else {
1118 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1119 "Disabling port %ld.", port);
1122 if(uhps.wPortStatus & UPSF_PORT_CONNECTION)
1124 KPRINTF(2, ("There's something at port %ld!\n", port));
1125 Forbid();
1126 if((pd = psdAllocDevice(nch->nch_Hardware)))
1128 psdLockWriteDevice(pd);
1129 Permit();
1130 /* Hub reference */
1131 psdSetAttrs(PGA_DEVICE, pd,
1132 DA_HubDevice, nch->nch_Device,
1133 DA_IsConnected, TRUE,
1134 DA_AtHubPortNumber, port,
1135 TAG_END);
1136 if(uhps.wPortStatus & UPSF_PORT_LOW_SPEED)
1138 psdSetAttrs(PGA_DEVICE, pd, DA_IsLowspeed, TRUE, TAG_END);
1139 KPRINTF(2, (" It's a lowspeed device!\n"));
1140 islowspeed = TRUE;
1142 ObtainSemaphore(&nch->nch_HubBase->nh_Adr0Sema);
1143 for(resetretries = 0; resetretries < 3; resetretries++)
1145 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1146 USR_SET_FEATURE, UFS_PORT_RESET, (ULONG) port);
1147 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
1148 if(ioerr)
1150 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1151 "PORT_RESET for port %ld failed: %s (%ld)",
1152 port, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1153 KPRINTF(1, ("PORT_RESET failed %ld.\n", ioerr));
1154 break;
1156 if(nch->nch_IsRootHub)
1158 // Root hubs need 50ms minimum delay
1159 psdDelayMS(50);
1161 for(delayretries = 0; delayretries < 500; delayretries += delaytime)
1163 psdDelayMS(delaytime);
1164 psdPipeSetup(nch->nch_EP0Pipe, URTF_IN|URTF_CLASS|URTF_OTHER,
1165 USR_GET_STATUS, UFS_PORT_CONNECTION, (ULONG) port);
1166 ioerr = psdDoPipe(nch->nch_EP0Pipe, &uhps, sizeof(struct UsbPortStatus));
1167 uhps.wPortStatus = AROS_WORD2LE(uhps.wPortStatus);
1168 uhps.wPortChange = AROS_WORD2LE(uhps.wPortChange);
1169 if(ioerr)
1171 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1172 "GET_PORT_CONNECTION for port %ld failed: %s (%ld)",
1173 port, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1174 KPRINTF(1, ("GET_PORT_CONNECTION failed %ld.\n", ioerr));
1175 break;
1177 KPRINTF(2, ("After reset: status 0x%04x, change 0x%04x\n", uhps.wPortStatus, uhps.wPortChange));
1178 if(!(uhps.wPortStatus & UPSF_PORT_CONNECTION))
1180 break;
1182 if((uhps.wPortStatus &
1183 (UPSF_PORT_RESET|UPSF_PORT_CONNECTION|UPSF_PORT_ENABLE|UPSF_PORT_POWER|UPSF_PORT_OVER_CURRENT)) ==
1184 (UPSF_PORT_CONNECTION|UPSF_PORT_ENABLE|UPSF_PORT_POWER))
1186 if((uhps.wPortStatus & UPSF_PORT_HIGH_SPEED) || washighspeed)
1188 psdSetAttrs(PGA_DEVICE, pd, DA_IsHighspeed, TRUE, TAG_END);
1189 washighspeed = TRUE;
1190 KPRINTF(2, (" It's a highspeed device!\n"));
1192 else
1194 IPTR needssplit = 0;
1196 /* Some hubs (Apple Keyboard bultin hub) report speed correctly only after reset */
1197 if (uhps.wPortStatus & UPSF_PORT_LOW_SPEED)
1199 psdSetAttrs(PGA_DEVICE, pd, DA_IsLowspeed, TRUE, TAG_END);
1200 KPRINTF(2, (" It's a lowspeed device!\n"));
1201 islowspeed = TRUE;
1204 // inherit needs split from hub
1205 psdGetAttrs(PGA_DEVICE, nch->nch_Device, DA_NeedsSplitTrans, &needssplit, TAG_END);
1206 KPRINTF(2, (" Needs split transfers: %ld\n", needssplit));
1208 psdSetAttrs(PGA_DEVICE, pd, DA_NeedsSplitTrans, needssplit, TAG_END);
1210 GM_UNIQUENAME(nClearPortStatus)(nch, port);
1211 psdDelayMS((ULONG) (islowspeed ? 1000 : 100));
1212 if((pp = psdAllocPipe(pd, nch->nch_TaskMsgPort, NULL)))
1214 if(psdEnumerateDevice(pp))
1216 KPRINTF(2, (" Device successfully added!\n"));
1217 psdFreePipe(pp);
1218 psdUnlockDevice(pd);
1219 psdSendEvent(EHMB_ADDDEVICE, pd, NULL);
1220 ReleaseSemaphore(&nch->nch_HubBase->nh_Adr0Sema);
1221 return(pd);
1223 psdFreePipe(pp);
1225 break;
1226 } else {
1227 if(!(uhps.wPortStatus & UPSF_PORT_RESET))
1229 psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname,
1230 "Wrong port status %04lx for port %ld!",
1231 uhps.wPortStatus, port);
1232 KPRINTF(2, ("Wrong port status %04lx for port %ld.\n", uhps.wPortStatus, port));
1235 if(delayretries > 20)
1237 delaytime = 300;
1240 if((uhps.wPortStatus &
1241 (UPSF_PORT_RESET|UPSF_PORT_CONNECTION|UPSF_PORT_ENABLE|UPSF_PORT_POWER|UPSF_PORT_OVER_CURRENT|UPSF_PORT_LOW_SPEED)) ==
1242 (UPSF_PORT_CONNECTION|UPSF_PORT_POWER|UPSF_PORT_LOW_SPEED))
1244 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1245 "Strange port response, power-cycling port %ld",
1246 port);
1247 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1248 USR_CLEAR_FEATURE, UFS_PORT_ENABLE, (ULONG) port);
1249 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
1250 if(ioerr)
1252 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1253 "CLEAR_PORT_ENABLE for port %ld failed: %s (%ld)",
1254 port, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1255 KPRINTF(1, ("CLEAR_PORT_ENABLE for port %ld failed %ld!\n", port, ioerr));
1257 psdDelayMS(50);
1258 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1259 USR_CLEAR_FEATURE, UFS_PORT_POWER, (ULONG) port);
1260 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
1261 if(ioerr)
1263 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1264 "CLEAR_PORT_POWER for port %ld failed: %s (%ld)",
1265 port, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1266 KPRINTF(1, ("CLEAR_PORT_POWER for port %ld failed %ld!\n", port, ioerr));
1268 psdDelayMS(50);
1269 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1270 USR_SET_FEATURE, UFS_PORT_POWER, (ULONG) port);
1271 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
1272 if(ioerr)
1274 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1275 "SET_PORT_POWER for port %ld failed: %s (%ld)",
1276 port, psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1277 KPRINTF(1, ("SET_PORT_POWER for port %ld failed %ld!\n", port, ioerr));
1279 psdDelayMS((ULONG) nch->nch_PwrGoodTime + 15);
1282 delaytime = 200;
1284 psdUnlockDevice(pd);
1285 psdFreeDevice(pd);
1286 /* Disable port! It's too dangerous having a connection with
1287 crazy devices on the bus open */
1288 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1289 USR_CLEAR_FEATURE, UFS_PORT_ENABLE, (ULONG) port);
1290 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
1291 if(ioerr)
1293 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1294 "CLEAR_PORT_ENABLE failed: %s (%ld)",
1295 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1296 KPRINTF(1, ("CLEAR_PORT_ENABLE failed %ld.\n", ioerr));
1298 ReleaseSemaphore(&nch->nch_HubBase->nh_Adr0Sema);
1299 GM_UNIQUENAME(nClearPortStatus)(nch, port);
1300 } else {
1301 Permit();
1302 KPRINTF(1, ("AllocDevice() failed.\n"));
1305 } else {
1306 psdAddErrorMsg(RETURN_ERROR, (STRPTR) libname,
1307 "GET_PORT_CONNECTION failed: %s (%ld)",
1308 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1309 KPRINTF(1, ("GET_PORT_CONNECTION failed %ld.\n", ioerr));
1311 return(NULL);
1313 /* \\\ */
1315 /* /// "nHandleHubMethod()" */
1316 void GM_UNIQUENAME(nHandleHubMethod)(struct NepClassHub *nch, struct NepHubMsg *nhm)
1318 ULONG num;
1319 struct PsdDevice *pd;
1320 nhm->nhm_Result = 0;
1321 switch(nhm->nhm_MethodID)
1323 case UCM_HubClaimAppBinding:
1324 nhm->nhm_Result = (IPTR) psdHubClaimAppBindingA((struct TagItem *) nhm->nhm_Params[1]);
1325 break;
1327 case UCM_HubReleaseIfBinding:
1329 psdHubReleaseIfBinding((struct PsdInterface *) nhm->nhm_Params[1]);
1330 break;
1332 case UCM_HubReleaseDevBinding:
1333 psdHubReleaseDevBinding((struct PsdDevice *) nhm->nhm_Params[1]);
1334 break;
1336 case UCM_AttemptSuspendDevice:
1338 BOOL res = TRUE;
1339 for(num = 1; num <= nch->nch_NumPorts; num++)
1341 if((pd = (nch->nch_Downstream)[num-1]))
1343 res &= psdSuspendDevice(pd);
1346 if(res)
1348 // suspending of all downstream devices successful, so stop all activity, too.
1349 psdAbortPipe(nch->nch_EP1Pipe);
1350 nch->nch_Running = FALSE;
1351 nhm->nhm_Result = TRUE;
1353 break;
1356 case UCM_AttemptResumeDevice:
1357 if(!nch->nch_Running)
1359 psdWaitPipe(nch->nch_EP1Pipe);
1360 psdSendPipe(nch->nch_EP1Pipe, nch->nch_PortChanges, (nch->nch_NumPorts+8)>>3);
1361 nch->nch_Running = TRUE;
1363 nhm->nhm_Result = TRUE;
1364 for(num = 1; num <= nch->nch_NumPorts; num++)
1366 if((pd = (nch->nch_Downstream)[num-1]))
1368 psdResumeDevice(pd);
1371 break;
1373 case UCM_HubSuspendDevice:
1374 nhm->nhm_Result = GM_UNIQUENAME(nHubSuspendDevice)(nch, (struct PsdDevice *) nhm->nhm_Params[1]);
1375 break;
1377 case UCM_HubResumeDevice:
1378 nhm->nhm_Result = GM_UNIQUENAME(nHubResumeDevice)(nch, (struct PsdDevice *) nhm->nhm_Params[1]);
1379 break;
1383 /* \\\ */
1385 /* /// "nHubSuspendDevice()" */
1386 BOOL GM_UNIQUENAME(nHubSuspendDevice)(struct NepClassHub *nch, struct PsdDevice *pd)
1388 APTR binding = NULL;
1389 APTR puc = NULL;
1390 ULONG num;
1391 BOOL result = FALSE;
1392 LONG ioerr;
1394 psdGetAttrs(PGA_DEVICE, pd,
1395 DA_Binding, &binding,
1396 DA_BindingClass, &puc,
1397 TAG_END);
1399 for(num = 1; num <= nch->nch_NumPorts; num++)
1401 if(pd == (nch->nch_Downstream)[num-1])
1403 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1404 USR_SET_FEATURE, UFS_PORT_SUSPEND, num);
1406 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
1407 if(ioerr)
1409 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1410 "SET_PORT_SUSPEND failed: %s (%ld)",
1411 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1412 KPRINTF(1, ("SET_PORT_SUSPEND failed %ld.\n", ioerr));
1413 } else {
1414 result = TRUE;
1415 psdSetAttrs(PGA_DEVICE, pd, DA_IsSuspended, TRUE, TAG_END);
1416 psdSendEvent(EHMB_DEVSUSPENDED, pd, NULL);
1420 return result;
1422 /* \\\ */
1424 /* /// "nHubResumeDevice()" */
1425 BOOL GM_UNIQUENAME(nHubResumeDevice)(struct NepClassHub *nch, struct PsdDevice *pd)
1427 ULONG num;
1428 BOOL result = FALSE;
1429 LONG ioerr;
1431 for(num = 1; num <= nch->nch_NumPorts; num++)
1433 if(pd == (nch->nch_Downstream)[num-1])
1435 psdPipeSetup(nch->nch_EP0Pipe, URTF_CLASS|URTF_OTHER,
1436 USR_CLEAR_FEATURE, UFS_PORT_SUSPEND, (ULONG) num);
1438 ioerr = psdDoPipe(nch->nch_EP0Pipe, NULL, 0);
1439 if(ioerr)
1441 psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1442 "CLEAR_PORT_SUSPEND failed: %s (%ld)",
1443 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1444 KPRINTF(1, ("CLEAR_PORT_SUSPEND failed %ld.\n", ioerr));
1445 } else {
1446 psdSetAttrs(PGA_DEVICE, pd, DA_IsSuspended, FALSE, TAG_END);
1447 psdSendEvent(EHMB_DEVRESUMED, pd, NULL);
1448 result = TRUE;
1449 psdDelayMS(30);
1453 return result;
1455 /* \\\ */