2 Copyright © 2014, The AROS Development Team. All rights reserved.
5 Desc: SuperSpeed USB3.0 hub for Poseidon (based upon hub.class.c by Chris Hodges <chrisly@platon42.de>)
11 #include <aros/debug.h>
12 #include <proto/arossupport.h>
14 #include "hubss.class.h"
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"));
29 ADD2INITLIB(GM_UNIQUENAME(libInit
), 0)
34 * ***********************************************************************
35 * * Library functions *
36 * ***********************************************************************
39 /* /// "usbAttemptDeviceBinding()" */
40 struct NepClassHub
* GM_UNIQUENAME(usbAttemptDeviceBinding
)(struct NepHubBase
*nh
, struct PsdDevice
*pd
) {
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
);
51 if((devclass
== HUB_CLASSCODE
) && (issuperspeed
)) {
52 return(GM_UNIQUENAME(usbForceDeviceBinding
)(nh
, pd
));
58 /* /// "usbForceDeviceBinding()" */
59 struct NepClassHub
* GM_UNIQUENAME(usbForceDeviceBinding
)(struct NepHubBase
* nh
, struct PsdDevice
*pd
)
62 struct NepClassHub
*nch
;
67 KPRINTF(1, ("nepHubAttemptDeviceBinding(%p)\n", pd
));
69 if((ps
= OpenLibrary("poseidon.library", 4)))
71 psdGetAttrs(PGA_DEVICE
, pd
,
72 DA_ProductName
, &devname
,
74 if((nch
= psdAllocVec(sizeof(struct NepClassHub
))))
76 nch
->nch_HubBase
= nh
;
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
);
87 nch
->nch_ReadySigTask
= NULL
;
88 //FreeSignal(nch->nch_ReadySignal);
89 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
90 "I'm in love with hub '%s'.",
94 AddTail(&nh
->nh_Bindings
, &nch
->nch_Node
);
100 nch
->nch_ReadySigTask
= NULL
;
101 //FreeSignal(nch->nch_ReadySignal);
110 /* /// "usbReleaseDeviceBinding()" */
111 void GM_UNIQUENAME(usbReleaseDeviceBinding
)(struct NepHubBase
*nh
, struct NepClassHub
*nch
)
116 KPRINTF(1, ("nepHubReleaseDeviceBinding(%p)\n", nch
));
117 if((ps
= OpenLibrary("poseidon.library", 4)))
120 nch
->nch_ReadySignal
= SIGB_SINGLE
;
121 nch
->nch_ReadySigTask
= FindTask(NULL
);
124 KPRINTF(1, ("Sending Break\n"));
125 Signal(nch
->nch_Task
, SIGBREAKF_CTRL_C
);
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'!",
139 Remove(&nch
->nch_Node
);
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
) {
155 KPRINTF(1, ("nepHubGetAttrsA(%ld, %p, %p)\n", type
, usbstruct
, taglist
));
159 while((ti
= LibNextTagItem(&taglist
)) != NULL
) {
160 switch (ti
->ti_Tag
) {
162 *((SIPTR
*) ti
->ti_Data
) = 0;
165 case UCCA_Description
:
166 *((STRPTR
*) ti
->ti_Data
) = "Root/external SuperSpeed hub base class";
169 case UCCA_HasClassCfgGUI
:
170 *((IPTR
*) ti
->ti_Data
) = FALSE
;
173 case UCCA_HasBindingCfgGUI
:
174 *((IPTR
*) ti
->ti_Data
) = FALSE
;
177 case UCCA_AfterDOSRestart
:
178 *((IPTR
*) ti
->ti_Data
) = FALSE
;
181 case UCCA_UsingDefaultCfg
:
182 *((IPTR
*) ti
->ti_Data
) = TRUE
;
185 case UCCA_SupportsSuspend
:
186 *((IPTR
*) ti
->ti_Data
) = TRUE
;
189 } /* switch (ti->ti_Tag) */
190 }; /* while((ti = LibNextTagItem(&taglist)) != NULL) */
194 if((ti
= LibFindTagItem(UCBA_UsingDefaultCfg
, taglist
))) {
195 *((IPTR
*) ti
->ti_Data
) = TRUE
;
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
)
218 /* /// "usbDoMethodA()" */
219 AROS_LH2(IPTR
, usbDoMethodA
,
220 AROS_LHA(ULONG
, methodid
, D0
),
221 AROS_LHA(IPTR
*, methoddata
, A1
),
222 LIBBASETYPEPTR
, nh
, 7, hub
)
226 struct NepClassHub
*nch
;
228 KPRINTF(1, ("Do Method %ld\n", 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]);
241 case UCM_HubPowerCyclePort
:
242 case UCM_HubDisablePort
:
244 struct PsdDevice
*pd
= (struct PsdDevice
*) methoddata
[0];
245 ULONG port
= (ULONG
) methoddata
[1];
248 KPRINTF(20, ("HubPowerCycle/DisablePort Params Null!\n"));
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
;
267 Signal(nch
->nch_Task
, (1L<<nch
->nch_TaskMsgPort
->mp_SigBit
));
274 nch
= (struct NepClassHub
*) nch
->nch_Node
.ln_Succ
;
280 case UCM_HubClassScan
:
282 nch
= (struct NepClassHub
*) methoddata
[0];
284 nch
->nch_ClassScan
= TRUE
;
287 Signal(nch
->nch_Task
, (1L<<nch
->nch_TaskMsgPort
->mp_SigBit
));
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
;
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
);
314 nhm
.nhm_Msg
.mn_ReplyPort
= CreateMsgPort();
315 nhm
.nhm_Msg
.mn_Length
= sizeof(struct NepHubMsg
);
317 if(nch
->nch_Task
&& nhm
.nhm_Msg
.mn_ReplyPort
)
319 PutMsg(nch
->nch_CtrlMsgPort
, &nhm
.nhm_Msg
);
321 while(!GetMsg(nhm
.nhm_Msg
.mn_ReplyPort
))
323 psdBorrowLocksWait(nch
->nch_Task
, 1UL<<nhm
.nhm_Msg
.mn_ReplyPort
->mp_SigBit
);
328 DeleteMsgPort(nhm
.nhm_Msg
.mn_ReplyPort
);
332 return(nhm
.nhm_Result
);
344 #define ps nch->nch_Base
346 /* /// "nHubTask()" */
347 AROS_UFH0(void, GM_UNIQUENAME(nHubTask
))
351 struct NepClassHub
*nch
;
357 struct UsbPortStatus uhps
;
358 struct UsbHubStatus uhhs
;
360 struct PsdDevice
*pd
;
362 struct NepHubMsg
*nhm
;
364 if((nch
= GM_UNIQUENAME(nAllocHub
)()))
367 if(nch
->nch_ReadySigTask
)
369 Signal(nch
->nch_ReadySigTask
, 1L<<nch
->nch_ReadySignal
);
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.",
386 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
387 "Hub has added %ld device(s). That'll be fun!",
391 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++)
393 if((pd
= (nch
->nch_Downstream
)[num
-1]))
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
);
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!",
431 psdSendEvent(EHMB_REMDEVICE
, pd
, NULL
);
432 (nch
->nch_Downstream
)[num
-1] = NULL
;
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);
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 */
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.",
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
);
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
,
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
);
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);
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
,
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.");
549 psdSetAttrs(PGA_CONFIG
, pc
, CA_SelfPowered
, FALSE
, TAG_END
);
550 psdCalculatePower(phw
);
553 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
554 "Hub is now self-powered! Yay!");
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;
583 GM_UNIQUENAME(nClearPortStatus
)(nch
, num
);
587 pd
= (nch
->nch_Downstream
)[num
-1];
588 if(uhps
.wPortStatus
& UPSF_PORT_OVER_CURRENT
)
592 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
596 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
597 "Over-current situation detected with %s at port %ld! Unpowering port!",
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);
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
)
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
);
624 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
625 "Device '%s' at port %ld resumed from remote!",
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!",
639 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
640 "Bogus suspend/resume change on port %ld.",
644 if(uhps
.wPortChange
& UPSF_PORT_CONNECTION
)
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!",
655 psdSendEvent(EHMB_REMDEVICE
, pd
, NULL
);
656 (nch
->nch_Downstream
)[num
-1] = NULL
;
660 if((uhps
.wPortStatus
& UPSF_PORT_CONNECTION
) && (!pd
))
662 /* Wait for device to settle */
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.",
677 /* Bail out on time out. */
678 if(nch
->nch_PortChanges
[0] == 0xff)
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
);
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
);
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
;
722 IPTR issuperspeed
= 0;
725 BOOL overcurrent
= FALSE
;
727 thistask
= FindTask(NULL
);
728 nch
= thistask
->tc_UserData
;
731 if(!(nch
->nch_Base
= OpenLibrary("poseidon.library", 4))) {
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
,
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
,
751 IFA_AlternateNum
, 0xffffffff,
754 if(!nch
->nch_Interface
) {
756 nch
->nch_Interface
= psdFindInterface(nch
->nch_Device
, NULL
,
757 IFA_Class
, HUB_CLASSCODE
,
761 if(!nch
->nch_Interface
) {
762 KPRINTF(1, ("Ooops!?! No interfaces defined?\n"));
766 nch
->nch_EP1
= psdFindEndpoint(nch
->nch_Interface
, NULL
,
768 EA_TransferType
, USEAF_INTERRUPT
,
772 psdAddErrorMsg(RETURN_FAIL
, (STRPTR
) libname
, "Ooops!?! No endpoints defined?");
773 KPRINTF(1, ("Ooops!?! No Endpoints defined?\n"));
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,
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
)) {
800 if((usshd
= psdAllocVec(len
))) {
801 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, usshd
, len
);
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",
825 nch
->nch_PwrGoodTime
, nch
->nch_HubCurrent
));
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
);
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
,
849 if(uhhs
.wHubStatus
& UHSF_LOCAL_POWER_LOST
)
853 psdSetAttrs(PGA_CONFIG
, pc
, CA_SelfPowered
, FALSE
, TAG_END
);
854 psdCalculatePower(phw
);
859 psdSetAttrs(PGA_CONFIG
, pc
, CA_SelfPowered
, TRUE
, TAG_END
);
860 psdCalculatePower(phw
);
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);
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);
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.",
893 KPRINTF(10, ("%s ready!\n", thistask
->tc_Node
.ln_Name
));
894 nch
->nch_Task
= thistask
;
897 KPRINTF(1, ("No downstream port array memory!\n"));
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
));
909 KPRINTF(1, ("No Hub Descriptor memory!\n"));
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
);
930 CloseLibrary(nch
->nch_Base
);
933 nch
->nch_Task
= NULL
;
935 if(nch
->nch_ReadySigTask
) {
936 Signal(nch
->nch_ReadySigTask
, 1L<<nch
->nch_ReadySignal
);
943 /* /// "nFreeHub()" */
944 void GM_UNIQUENAME(nFreeHub
)(struct NepClassHub
*nch
)
948 struct PsdDevice
*pd
;
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];
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!",
970 KPRINTF(1, ("FreeDevice %p\n", 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! */
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);
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"));
998 while((msg
= GetMsg(nch
->nch_CtrlMsgPort
)))
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"));
1014 /* *** HUB Class *** */
1016 /* /// "nClearPortStatus()" */
1017 LONG
GM_UNIQUENAME(nClearPortStatus
)(struct NepClassHub
*nch
, UWORD port
)
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"));
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"));
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"));
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"));
1077 /* /// "nConfigurePort()" */
1078 struct PsdDevice
* GM_UNIQUENAME(nConfigurePort
)(struct NepClassHub
*nch
, UWORD port
)
1083 ULONG delaytime
= 10;
1084 struct UsbPortStatus uhps
;
1085 struct PsdDevice
*pd
;
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
);
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);
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
));
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
));
1126 if((pd
= psdAllocDevice(nch
->nch_Hardware
)))
1128 psdLockWriteDevice(pd
);
1131 psdSetAttrs(PGA_DEVICE
, pd
,
1132 DA_HubDevice
, nch
->nch_Device
,
1133 DA_IsConnected
, TRUE
,
1134 DA_AtHubPortNumber
, port
,
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"));
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);
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
));
1156 if(nch
->nch_IsRootHub
)
1158 // Root hubs need 50ms minimum delay
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
);
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
));
1177 KPRINTF(2, ("After reset: status 0x%04x, change 0x%04x\n", uhps
.wPortStatus
, uhps
.wPortChange
));
1178 if(!(uhps
.wPortStatus
& UPSF_PORT_CONNECTION
))
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"));
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"));
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"));
1218 psdUnlockDevice(pd
);
1219 psdSendEvent(EHMB_ADDDEVICE
, pd
, NULL
);
1220 ReleaseSemaphore(&nch
->nch_HubBase
->nh_Adr0Sema
);
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)
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",
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);
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
));
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);
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
));
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);
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);
1284 psdUnlockDevice(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);
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
);
1302 KPRINTF(1, ("AllocDevice() failed.\n"));
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
));
1315 /* /// "nHandleHubMethod()" */
1316 void GM_UNIQUENAME(nHandleHubMethod
)(struct NepClassHub
*nch
, struct NepHubMsg
*nhm
)
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]);
1327 case UCM_HubReleaseIfBinding
:
1329 psdHubReleaseIfBinding((struct PsdInterface
*) nhm
->nhm_Params
[1]);
1332 case UCM_HubReleaseDevBinding
:
1333 psdHubReleaseDevBinding((struct PsdDevice
*) nhm
->nhm_Params
[1]);
1336 case UCM_AttemptSuspendDevice
:
1339 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++)
1341 if((pd
= (nch
->nch_Downstream
)[num
-1]))
1343 res
&= psdSuspendDevice(pd
);
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
;
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
);
1373 case UCM_HubSuspendDevice
:
1374 nhm
->nhm_Result
= GM_UNIQUENAME(nHubSuspendDevice
)(nch
, (struct PsdDevice
*) nhm
->nhm_Params
[1]);
1377 case UCM_HubResumeDevice
:
1378 nhm
->nhm_Result
= GM_UNIQUENAME(nHubResumeDevice
)(nch
, (struct PsdDevice
*) nhm
->nhm_Params
[1]);
1385 /* /// "nHubSuspendDevice()" */
1386 BOOL
GM_UNIQUENAME(nHubSuspendDevice
)(struct NepClassHub
*nch
, struct PsdDevice
*pd
)
1388 APTR binding
= NULL
;
1391 BOOL result
= FALSE
;
1394 psdGetAttrs(PGA_DEVICE
, pd
,
1395 DA_Binding
, &binding
,
1396 DA_BindingClass
, &puc
,
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);
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
));
1415 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsSuspended
, TRUE
, TAG_END
);
1416 psdSendEvent(EHMB_DEVSUSPENDED
, pd
, NULL
);
1424 /* /// "nHubResumeDevice()" */
1425 BOOL
GM_UNIQUENAME(nHubResumeDevice
)(struct NepClassHub
*nch
, struct PsdDevice
*pd
)
1428 BOOL result
= FALSE
;
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);
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
));
1446 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsSuspended
, FALSE
, TAG_END
);
1447 psdSendEvent(EHMB_DEVRESUMED
, pd
, NULL
);