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>)
14 #include <aros/debug.h>
16 #include <proto/poseidon.h>
17 #include <proto/arossupport.h>
19 #include <devices/usb.h>
20 #include <devices/usb_hub.h>
21 #include <devices/usbhardware.h>
22 #include <libraries/usbclass.h>
24 #include "hubss_class.h"
26 #include LC_LIBDEFS_FILE
28 struct NepClassHub
* GM_UNIQUENAME(usbAttemptDeviceBinding
)(struct NepHubBase
*nh
, struct PsdDevice
*pd
);
29 struct NepClassHub
* GM_UNIQUENAME(usbForceDeviceBinding
)(struct NepHubBase
* nh
, struct PsdDevice
*pd
);
30 void GM_UNIQUENAME(usbReleaseDeviceBinding
)(struct NepHubBase
*nh
, struct NepClassHub
*nch
);
32 struct NepClassHub
* GM_UNIQUENAME(nAllocHub
)(void);
33 void GM_UNIQUENAME(nFreeHub
)(struct NepClassHub
*nch
);
34 struct PsdDevice
* GM_UNIQUENAME(nConfigurePort
)(struct NepClassHub
*nch
, UWORD port
);
35 LONG
GM_UNIQUENAME(nClearPortStatus
)(struct NepClassHub
*nch
, UWORD port
);
36 BOOL
GM_UNIQUENAME(nHubSuspendDevice
)(struct NepClassHub
*nch
, struct PsdDevice
*pd
);
37 BOOL
GM_UNIQUENAME(nHubResumeDevice
)(struct NepClassHub
*nch
, struct PsdDevice
*pd
);
38 void GM_UNIQUENAME(nHandleHubMethod
)(struct NepClassHub
*nch
, struct NepHubMsg
*nhm
);
39 AROS_UFP0(void, GM_UNIQUENAME(nHubssTask
));
42 static const STRPTR libname
= MOD_NAME_STRING
;
44 static int GM_UNIQUENAME(libInit
)(LIBBASETYPEPTR nh
) {
46 NEWLIST(&nh
->nh_Bindings
);
47 InitSemaphore(&nh
->nh_Adr0Sema
);
52 ADD2INITLIB(GM_UNIQUENAME(libInit
), 0)
57 * ***********************************************************************
58 * * Library functions *
59 * ***********************************************************************
62 /* /// "usbAttemptDeviceBinding()" */
63 struct NepClassHub
* GM_UNIQUENAME(usbAttemptDeviceBinding
)(struct NepHubBase
*nh
, struct PsdDevice
*pd
) {
66 IPTR issuperspeed
= 0;
68 //KPRINTF(0, ("usbAttemptDeviceBinding(%p)\n", pd));
70 if((ps
= OpenLibrary("poseidon.library", 4))) {
71 psdGetAttrs(PGA_DEVICE
, pd
, DA_Class
, &devclass
, DA_IsSuperspeed
, &issuperspeed
, TAG_DONE
);
74 if((devclass
== HUB_CLASSCODE
) && (issuperspeed
)) {
75 return(GM_UNIQUENAME(usbForceDeviceBinding
)(nh
, pd
));
81 /* /// "usbForceDeviceBinding()" */
82 struct NepClassHub
* GM_UNIQUENAME(usbForceDeviceBinding
)(struct NepHubBase
* nh
, struct PsdDevice
*pd
) {
84 struct NepClassHub
*nch
;
89 //KPRINTF(0, ("usbForceDeviceBinding(%p)\n", pd));
91 if((ps
= OpenLibrary("poseidon.library", 4))) {
92 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_DONE
);
94 if((nch
= psdAllocVec(sizeof(struct NepClassHub
)))) {
95 nch
->nch_HubBase
= nh
;
97 psdSafeRawDoFmt(buf
, 64, "hubss.class<%p>", nch
);
98 nch
->nch_ReadySignal
= SIGB_SINGLE
;
99 nch
->nch_ReadySigTask
= FindTask(NULL
);
100 SetSignal(0, SIGF_SINGLE
);
102 if((tmptask
= psdSpawnSubTask(buf
, GM_UNIQUENAME(nHubssTask
), nch
))) {
103 psdBorrowLocksWait(tmptask
, 1UL<<nch
->nch_ReadySignal
);
106 nch
->nch_ReadySigTask
= NULL
;
107 //FreeSignal(nch->nch_ReadySignal);
108 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
, "I'm in love with superspeed hub '%s'.", devname
);
111 AddTail(&nh
->nh_Bindings
, &nch
->nch_Node
);
118 nch
->nch_ReadySigTask
= NULL
;
119 //FreeSignal(nch->nch_ReadySignal);
129 /* /// "usbReleaseDeviceBinding()" */
130 void GM_UNIQUENAME(usbReleaseDeviceBinding
)(struct NepHubBase
*nh
, struct NepClassHub
*nch
) {
134 KPRINTF(1, ("nepHubReleaseDeviceBinding(%p)\n", nch
));
136 if((ps
= OpenLibrary("poseidon.library", 4))) {
139 nch
->nch_ReadySignal
= SIGB_SINGLE
;
140 nch
->nch_ReadySigTask
= FindTask(NULL
);
142 KPRINTF(1, ("Sending Break\n"));
143 Signal(nch
->nch_Task
, SIGBREAKF_CTRL_C
);
147 while(nch
->nch_Task
) {
148 psdBorrowLocksWait(nch
->nch_Task
, 1UL<<nch
->nch_ReadySignal
);
150 KPRINTF(1, ("Task gone\n"));
152 //FreeSignal(nch->nch_ReadySignal);
153 psdGetAttrs(PGA_DEVICE
, nch
->nch_Device
, DA_ProductName
, &devname
, TAG_END
);
154 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
, "Time to get rid of '%s'!", devname
);
157 Remove(&nch
->nch_Node
);
165 /* /// "usbGetAttrsA()" */
166 AROS_LH3(LONG
, usbGetAttrsA
, AROS_LHA(ULONG
, type
, D0
), AROS_LHA(APTR
, usbstruct
, A0
), AROS_LHA(struct TagItem
*, taglist
, A1
), LIBBASETYPEPTR
, nh
, 5, hub
) {
172 KPRINTF(1, ("nepHubGetAttrsA(%ld, %p, %p)\n", type
, usbstruct
, taglist
));
176 while((ti
= LibNextTagItem(&taglist
)) != NULL
) {
177 switch (ti
->ti_Tag
) {
179 *((SIPTR
*) ti
->ti_Data
) = 0;
182 case UCCA_Description
:
183 *((STRPTR
*) ti
->ti_Data
) = "Root/external superspeed hub base class";
186 case UCCA_HasClassCfgGUI
:
187 *((IPTR
*) ti
->ti_Data
) = FALSE
;
190 case UCCA_HasBindingCfgGUI
:
191 *((IPTR
*) ti
->ti_Data
) = FALSE
;
194 case UCCA_AfterDOSRestart
:
195 *((IPTR
*) ti
->ti_Data
) = FALSE
;
198 case UCCA_UsingDefaultCfg
:
199 *((IPTR
*) ti
->ti_Data
) = TRUE
;
202 case UCCA_SupportsSuspend
:
203 *((IPTR
*) ti
->ti_Data
) = TRUE
;
206 } /* switch (ti->ti_Tag) */
207 }; /* while((ti = LibNextTagItem(&taglist)) != NULL) */
211 if((ti
= LibFindTagItem(UCBA_UsingDefaultCfg
, taglist
))) {
212 *((IPTR
*) ti
->ti_Data
) = TRUE
;
222 /* /// "usbSetAttrsA()" */
223 AROS_LH3(LONG
, usbSetAttrsA
, AROS_LHA(ULONG
, type
, D0
), AROS_LHA(APTR
, usbstruct
, A0
), AROS_LHA(struct TagItem
*, tags
, A1
), LIBBASETYPEPTR
, nh
, 6, hub
) {
230 /* /// "usbDoMethodA()" */
231 AROS_LH2(IPTR
, usbDoMethodA
, AROS_LHA(ULONG
, methodid
, D0
), AROS_LHA(IPTR
*, methoddata
, A1
), LIBBASETYPEPTR
, nh
, 7, hub
) {
234 struct NepClassHub
*nch
;
236 KPRINTF(1, ("Do Method %ld\n", methodid
));
238 case UCM_AttemptDeviceBinding
:
239 return((IPTR
) GM_UNIQUENAME(usbAttemptDeviceBinding
)(nh
, (struct PsdDevice
*) methoddata
[0]));
241 case UCM_ForceDeviceBinding
:
242 return((IPTR
) GM_UNIQUENAME(usbForceDeviceBinding
)(nh
, (struct PsdDevice
*) methoddata
[0]));
244 case UCM_ReleaseDeviceBinding
:
245 GM_UNIQUENAME(usbReleaseDeviceBinding
)(nh
, (struct NepClassHub
*) methoddata
[0]);
248 case UCM_HubPowerCyclePort
:
249 case UCM_HubDisablePort
: {
250 struct PsdDevice
*pd
= (struct PsdDevice
*) methoddata
[0];
251 ULONG port
= (ULONG
) methoddata
[1];
254 KPRINTF(20, ("HubPowerCycle/DisablePort Params Null!\n"));
259 nch
= (struct NepClassHub
*) nh
->nh_Bindings
.lh_Head
;
260 while(nch
->nch_Node
.ln_Succ
) {
261 if(nch
->nch_Device
== pd
) {
262 KPRINTF(20, ("HubPowerCycle/DisablePort Dev found (port %ld)!\n", port
));
263 if(port
<= nch
->nch_NumPorts
) {
264 nch
->nch_DisablePort
|= 1UL<<port
;
265 if(methodid
== UCM_HubPowerCyclePort
) {
266 nch
->nch_PowerCycle
|= 1UL<<port
;
269 Signal(nch
->nch_Task
, (1L<<nch
->nch_TaskMsgPort
->mp_SigBit
));
276 nch
= (struct NepClassHub
*) nch
->nch_Node
.ln_Succ
;
281 } /* case UCM_HubDisablePort */
283 case UCM_HubClassScan
: {
284 nch
= (struct NepClassHub
*) methoddata
[0];
287 nch
->nch_ClassScan
= TRUE
;
289 Signal(nch
->nch_Task
, (1L<<nch
->nch_TaskMsgPort
->mp_SigBit
));
294 } /* case UCM_HubClassScan */
296 case UCM_AttemptSuspendDevice
:
297 case UCM_AttemptResumeDevice
:
298 case UCM_HubClaimAppBinding
:
299 case UCM_HubReleaseIfBinding
:
300 case UCM_HubReleaseDevBinding
:
301 case UCM_HubSuspendDevice
:
302 case UCM_HubResumeDevice
: {
303 struct NepHubMsg nhm
;
305 nch
= (struct NepClassHub
*) methoddata
[0];
306 nhm
.nhm_Result
= (IPTR
) NULL
;
307 nhm
.nhm_MethodID
= methodid
;
308 nhm
.nhm_Params
= methoddata
;
310 if((ps
= OpenLibrary("poseidon.library", 4))) {
311 if(nch
->nch_Task
== FindTask(NULL
)) {
312 // if we would send the message to ourself, we would deadlock, so handle this directly
313 GM_UNIQUENAME(nHandleHubMethod
)(nch
, &nhm
);
315 nhm
.nhm_Msg
.mn_ReplyPort
= CreateMsgPort();
316 nhm
.nhm_Msg
.mn_Length
= sizeof(struct NepHubMsg
);
319 if(nch
->nch_Task
&& nhm
.nhm_Msg
.mn_ReplyPort
) {
320 PutMsg(nch
->nch_CtrlMsgPort
, &nhm
.nhm_Msg
);
323 while(!GetMsg(nhm
.nhm_Msg
.mn_ReplyPort
)) {
324 psdBorrowLocksWait(nch
->nch_Task
, 1UL<<nhm
.nhm_Msg
.mn_ReplyPort
->mp_SigBit
);
329 DeleteMsgPort(nhm
.nhm_Msg
.mn_ReplyPort
);
334 return(nhm
.nhm_Result
);
335 }/* case UCM_HubResumeDevice */
346 #define ps nch->nch_Base
348 /* /// "nHubssTask()" */
349 AROS_UFH0(void, GM_UNIQUENAME(nHubssTask
)) {
352 struct NepClassHub
*nch
;
358 struct UsbPortStatus uhps
;
359 struct UsbHubStatus uhhs
;
361 struct PsdDevice
*pd
;
363 struct NepHubMsg
*nhm
;
365 if((nch
= GM_UNIQUENAME(nAllocHub
)())) {
367 if(nch
->nch_ReadySigTask
) {
368 Signal(nch
->nch_ReadySigTask
, 1L<<nch
->nch_ReadySignal
);
372 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++) {
373 if(((nch
->nch_Downstream
)[num
-1] = pd
= GM_UNIQUENAME(nConfigurePort
)(nch
, num
))) {
374 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
375 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
376 "Detected device '%s' at port %ld. I like it.",
382 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
383 "Hub has added %ld device(s). That'll be fun!",
387 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++) {
388 if((pd
= (nch
->nch_Downstream
)[num
-1])) {
392 sigmask
= (1L<<nch
->nch_TaskMsgPort
->mp_SigBit
)|(1L<<nch
->nch_CtrlMsgPort
->mp_SigBit
)|SIGBREAKF_CTRL_C
;
393 nch
->nch_Running
= TRUE
;
394 nch
->nch_IOStarted
= FALSE
;
396 if(nch
->nch_Running
&& (!nch
->nch_IOStarted
)) {
397 psdSendPipe(nch
->nch_EP1Pipe
, nch
->nch_PortChanges
, (nch
->nch_NumPorts
+8)>>3);
398 nch
->nch_IOStarted
= TRUE
;
400 sigs
= Wait(sigmask
);
402 while((nhm
= (struct NepHubMsg
*) GetMsg(nch
->nch_CtrlMsgPort
))) {
403 GM_UNIQUENAME(nHandleHubMethod
)(nch
, nhm
);
404 ReplyMsg((struct Message
*) nhm
);
407 if(nch
->nch_DisablePort
) {
408 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++) {
409 if((nch
->nch_DisablePort
) & (1L<<num
)) {
410 nch
->nch_DisablePort
&= ~(1L<<num
);
412 if((pd
= (nch
->nch_Downstream
)[num
-1])) {
413 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsConnected
, FALSE
, TAG_END
);
414 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
415 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
416 "Zapping device '%s' at port %ld!",
419 psdSendEvent(EHMB_REMDEVICE
, pd
, NULL
);
420 (nch
->nch_Downstream
)[num
-1] = NULL
;
423 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
424 USR_CLEAR_FEATURE
, UFS_PORT_ENABLE
, (ULONG
) num
);
425 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
427 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
428 "CLEAR_PORT_ENABLE failed: %s (%ld)",
429 psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
430 KPRINTF(1, ("CLEAR_PORT_ENABLE failed %ld.\n", ioerr
));
433 if(nch
->nch_PowerCycle
& (1<<num
)) {
434 KPRINTF(2, ("Powercycle request for port %lu\n", num
));
435 nch
->nch_PowerCycle
&= ~(1L<<num
);
437 /* Wait for device to settle */
439 if(((nch
->nch_Downstream
)[num
-1] = pd
= GM_UNIQUENAME(nConfigurePort
)(nch
, num
))) {
440 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
441 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
442 "Device '%s' returned. Happy happy joy joy.",
451 if(nch
->nch_ClassScan
) {
452 nch
->nch_ClassScan
= FALSE
;
453 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++)
455 if((pd
= (nch
->nch_Downstream
)[num
-1]))
457 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
462 while((pp
= (struct PsdPipe
*) GetMsg(nch
->nch_TaskMsgPort
))) {
463 if(pp
== nch
->nch_EP1Pipe
) {
464 nch
->nch_IOStarted
= FALSE
;
465 ioerr
= psdGetPipeError(nch
->nch_EP1Pipe
);
466 if(ioerr
== UHIOERR_TIMEOUT
) {
467 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
468 "Hub involuntarily gone! Disconnecting...");
469 psdSetAttrs(PGA_DEVICE
, nch
->nch_Device
,
470 DA_IsConnected
, FALSE
,
472 nch
->nch_PortChanges
[0] = 0xff;
473 nch
->nch_PortChanges
[1] = 0xff;
474 nch
->nch_PortChanges
[2] = 0xff;
475 nch
->nch_PortChanges
[3] = 0xff;
476 sigs
|= SIGBREAKF_CTRL_C
;
478 if((!ioerr
) || (ioerr
== UHIOERR_TIMEOUT
)) {
479 KPRINTF(2, ("Port changed at %p, Numports=%ld!\n", nch
->nch_PortChanges
[0], nch
->nch_NumPorts
));
481 if(nch
->nch_PortChanges
[0] & 1) {
482 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_IN
|URTF_CLASS
|URTF_DEVICE
,
483 USR_GET_STATUS
, 0, 0);
484 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, &uhhs
, sizeof(struct UsbHubStatus
));
485 uhhs
.wHubStatus
= AROS_WORD2LE(uhhs
.wHubStatus
);
486 uhhs
.wHubChange
= AROS_WORD2LE(uhhs
.wHubChange
);
489 if(uhhs
.wHubStatus
& UHSF_OVER_CURRENT
)
491 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
492 "Hub over-current situation detected! Unpowering ALL ports!");
493 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++)
495 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
496 USR_CLEAR_FEATURE
, UFS_PORT_POWER
, (ULONG
) num
);
497 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
500 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
501 "PORT_POWER for port %ld failed: %s (%ld)",
502 num
, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
503 KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", num
, ioerr
));
506 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
507 USR_CLEAR_FEATURE
, UFS_C_PORT_OVER_CURRENT
, (ULONG
) num
);
508 psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
510 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_DEVICE
,
511 USR_CLEAR_FEATURE
, UFS_C_HUB_OVER_CURRENT
, 0);
512 psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
514 if(uhhs
.wHubChange
& UHSF_LOCAL_POWER_LOST
)
516 struct PsdConfig
*pc
= NULL
;
517 struct PsdHardware
*phw
= NULL
;
518 psdGetAttrs(PGA_DEVICE
, nch
->nch_Device
,
522 if(uhhs
.wHubStatus
& UHSF_LOCAL_POWER_LOST
)
524 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
525 "Hub is no longer self-powered! Low power conditions may occur.");
529 psdSetAttrs(PGA_CONFIG
, pc
, CA_SelfPowered
, FALSE
, TAG_END
);
530 psdCalculatePower(phw
);
533 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
534 "Hub is now self-powered! Yay!");
537 psdSetAttrs(PGA_CONFIG
, pc
, CA_SelfPowered
, TRUE
, TAG_END
);
538 psdCalculatePower(phw
);
541 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_DEVICE
,
542 USR_CLEAR_FEATURE
, UFS_C_HUB_LOCAL_POWER
, 0);
543 psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
548 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++)
550 if(nch
->nch_PortChanges
[num
>>3] & (1L<<(num
& 7)))
552 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_IN
|URTF_CLASS
|URTF_OTHER
,
553 USR_GET_STATUS
, 0, (ULONG
) num
);
554 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, &uhps
, sizeof(struct UsbPortStatus
));
555 uhps
.wPortStatus
= AROS_WORD2LE(uhps
.wPortStatus
);
556 uhps
.wPortChange
= AROS_WORD2LE(uhps
.wPortChange
);
557 if(ioerr
== UHIOERR_TIMEOUT
)
559 uhps
.wPortStatus
= 0;
560 uhps
.wPortChange
= 0xffff;
563 GM_UNIQUENAME(nClearPortStatus
)(nch
, num
);
567 pd
= (nch
->nch_Downstream
)[num
-1];
568 if(uhps
.wPortStatus
& UPSF_PORT_OVER_CURRENT
)
572 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
576 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
577 "Over-current situation detected with %s at port %ld! Unpowering port!",
579 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
580 USR_CLEAR_FEATURE
, UFS_PORT_POWER
, (ULONG
) num
);
581 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
584 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
585 "PORT_POWER for port %ld failed: %s (%ld)",
586 num
, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
587 KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", num
, ioerr
));
590 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
591 USR_CLEAR_FEATURE
, UFS_C_PORT_OVER_CURRENT
, (ULONG
) num
);
592 psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
594 if(uhps
.wPortChange
& UPSF_PORT_SUSPEND
)
596 if((!(uhps
.wPortStatus
& UPSF_PORT_SUSPEND
)) && pd
)
599 psdGetAttrs(PGA_DEVICE
, pd
, DA_IsSuspended
, &oldsusp
, TAG_END
);
600 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsSuspended
, FALSE
, TAG_END
);
601 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
604 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
605 "Device '%s' at port %ld resumed from remote!",
607 psdSendEvent(EHMB_DEVRESUMED
, pd
, NULL
);
608 psdResumeBindings(pd
);
611 else if((uhps
.wPortStatus
& UPSF_PORT_SUSPEND
) && pd
)
613 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsSuspended
, FALSE
, TAG_END
);
614 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
615 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
616 "Device '%s' at port %ld suspended!",
619 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
620 "Bogus suspend/resume change on port %ld.",
624 if(uhps
.wPortChange
& UPSF_PORT_CONNECTION
)
627 if((!(uhps
.wPortStatus
& UPSF_PORT_CONNECTION
)) && pd
)
629 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsConnected
, FALSE
, TAG_END
);
630 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
631 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
632 "Device '%s' at port %ld is gone!",
635 psdSendEvent(EHMB_REMDEVICE
, pd
, NULL
);
636 (nch
->nch_Downstream
)[num
-1] = NULL
;
640 if((uhps
.wPortStatus
& UPSF_PORT_CONNECTION
) && (!pd
))
642 /* Wait for device to settle */
644 if(((nch
->nch_Downstream
)[num
-1] = pd
= GM_UNIQUENAME(nConfigurePort
)(nch
, num
)))
646 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
647 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
648 "New device '%s' at port %ld. Very nice.",
657 /* Bail out on time out. */
658 if(nch
->nch_PortChanges
[0] == 0xff)
664 if(ioerr
!= IOERR_ABORTED
)
666 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
667 "Something weird happened to the status packet, it failed: %s (%ld)",
668 psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
674 KPRINTF(20, ("Bogus message received!\n"));
677 } while(!(sigs
& SIGBREAKF_CTRL_C
));
678 KPRINTF(20, ("Going down the river!\n"));
679 if(nch
->nch_IOStarted
)
681 psdAbortPipe(nch
->nch_EP1Pipe
);
682 psdWaitPipe(nch
->nch_EP1Pipe
);
684 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
, "Oh no! I've been shot! Arrggghh...");
685 GM_UNIQUENAME(nFreeHub
)(nch
);
690 /* /// "nAllocHub()" */
691 struct NepClassHub
* GM_UNIQUENAME(nAllocHub
)(void) {
692 struct UsbSSHubDesc
*usshd
;
693 //struct UsbStdBOSDesc *usbosd;
694 struct Task
*thistask
;
695 struct NepClassHub
*nch
;
696 struct UsbHubStatus uhhs
;
702 IPTR issuperspeed
= 0;
705 BOOL overcurrent
= FALSE
;
707 thistask
= FindTask(NULL
);
708 nch
= thistask
->tc_UserData
;
711 if(!(nch
->nch_Base
= OpenLibrary("poseidon.library", 4))) {
716 psdGetAttrs(PGA_DEVICE
, nch
->nch_Device
,
717 DA_Hardware
, &nch
->nch_Hardware
,
718 DA_IsSuperspeed
, &issuperspeed
,
719 DA_ProductID
, &prodid
,
720 DA_VendorID
, &vendid
,
721 DA_HubDevice
, &parenthub
,
724 nch
->nch_IsRootHub
= (parenthub
? FALSE
: TRUE
);
725 nch
->nch_IsUSB30
= issuperspeed
;
727 if(!nch
->nch_Interface
) {
728 nch
->nch_Interface
= psdFindInterface(nch
->nch_Device
, NULL
, IFA_Class
, HUB_CLASSCODE
, TAG_END
);
731 if(!nch
->nch_Interface
) {
732 KPRINTF(1, ("Ooops!?! No interfaces defined?\n"));
736 nch
->nch_EP1
= psdFindEndpoint(nch
->nch_Interface
, NULL
, EA_IsIn
, TRUE
, EA_TransferType
, USEAF_INTERRUPT
, TAG_END
);
739 psdAddErrorMsg(RETURN_FAIL
, (STRPTR
) libname
, "Ooops!?! No endpoints defined?");
740 KPRINTF(1, ("Ooops!?! No Endpoints defined?\n"));
745 Device descriptor tree:
751 ...SS capability descriptor
752 ......USB2.0 LPM descriptor
754 Endpoint descriptor 0
755 ...Endpoint descriptor 1
756 ......Endpoint descriptor n
761 Get device descriptor
763 Get config descriptor
768 see: http://youtu.be/5ChWxMLKzOs
772 if((nch
->nch_CtrlMsgPort
= CreateMsgPort())) {
773 if((nch
->nch_TaskMsgPort
= CreateMsgPort())) {
774 if((nch
->nch_EP0Pipe
= psdAllocPipe(nch
->nch_Device
, nch
->nch_TaskMsgPort
, NULL
))) {
776 psdSetAttrs(PGA_PIPE
, nch
->nch_EP0Pipe
, PPA_NakTimeout
, TRUE
, PPA_NakTimeoutTime
, 1000, TAG_END
);
777 psdSetAltInterface(nch
->nch_EP0Pipe
, nch
->nch_Interface
);
779 if((nch
->nch_EP1Pipe
= psdAllocPipe(nch
->nch_Device
, nch
->nch_TaskMsgPort
, nch
->nch_EP1
))) {
781 psdSetAttrs(PGA_PIPE
, nch
->nch_EP1Pipe
, PPA_AllowRuntPackets
, TRUE
, TAG_END
);
782 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_IN
|URTF_CLASS
|URTF_DEVICE
, USR_GET_DESCRIPTOR
, UDT_SSHUB
<<8, 0);
784 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, &buf
, 2);
786 if(buf
[1] == UDT_SSHUB
) {
788 if((!ioerr
) || (ioerr
== UHIOERR_OVERFLOW
)) {
791 if((usshd
= psdAllocVec(len
))) {
792 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, usshd
, len
);
795 nch
->nch_NumPorts
= (UWORD
)usshd
->bNbrPorts
;
796 nch
->nch_HubAttr
= (UWORD
)AROS_WORD2LE(usshd
->wHubCharacteristics
);
797 nch
->nch_PwrGoodTime
= (UWORD
)usshd
->bPwrOn2PwrGood
<<1;
798 nch
->nch_HubCurrent
= (UWORD
)usshd
->bHubContrCurrent
;
799 nch
->nch_HubHdrDecLat
= (UWORD
)usshd
->bHubHdrDecLat
;
800 nch
->nch_HubDelay
= (UWORD
)usshd
->wHubDelay
;
801 nch
->nch_Removable
= (UWORD
)usshd
->DeviceRemovable
;
803 if(nch
->nch_HubAttr
& UHCM_THINK_TIME
) {
804 psdSetAttrs(PGA_DEVICE
, nch
->nch_Device
, DA_HubThinkTime
, (nch
->nch_HubAttr
& UHCM_THINK_TIME
)>>UHCS_THINK_TIME
, TAG_END
);
807 KPRINTF(2, ("Parsed SSHub descriptor\n"
808 " nch_NumPorts = %d\n"
809 " nch_HubAttr = 0x%04x\n"
810 " nch_PwrGoodTime = %d\n"
811 " nch_HubCurrent = %d\n"
812 " nch_HubHdrDecLat = %d\n"
813 " nch_HubDelay = %d\n"
814 " nch_Removable = 0x%04x\n\n",
815 (ULONG
)nch
->nch_NumPorts
,
816 (ULONG
)nch
->nch_HubAttr
,
817 (ULONG
)nch
->nch_PwrGoodTime
,
818 (ULONG
)nch
->nch_HubCurrent
,
819 (ULONG
)nch
->nch_HubHdrDecLat
,
820 (ULONG
)nch
->nch_HubDelay
,
821 (ULONG
)nch
->nch_Removable
));
825 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_IN
|URTF_CLASS
|URTF_DEVICE
, USR_GET_STATUS
, 0, 0);
826 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, &uhhs
, sizeof(struct UsbHubStatus
));
828 uhhs
.wHubStatus
= AROS_WORD2LE(uhhs
.wHubStatus
);
829 uhhs
.wHubChange
= AROS_WORD2LE(uhhs
.wHubChange
);
832 struct PsdConfig
*pc
= NULL
;
833 struct PsdHardware
*phw
= NULL
;
834 if(uhhs
.wHubStatus
& UHSF_OVER_CURRENT
)
836 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
837 "Hub over-current situation detected! Resolve this first!");
838 //overcurrent = TRUE;
841 psdGetAttrs(PGA_DEVICE
, nch
->nch_Device
,
845 if(uhhs
.wHubStatus
& UHSF_LOCAL_POWER_LOST
)
849 psdSetAttrs(PGA_CONFIG
, pc
, CA_SelfPowered
, FALSE
, TAG_END
);
850 psdCalculatePower(phw
);
855 psdSetAttrs(PGA_CONFIG
, pc
, CA_SelfPowered
, TRUE
, TAG_END
);
856 psdCalculatePower(phw
);
861 if((nch
->nch_Downstream
= psdAllocVec((ULONG
) nch
->nch_NumPorts
*sizeof(APTR
)))) {
862 /*for(num = 1; num <= nch->nch_NumPorts; num++)
864 GM_UNIQUENAME(nClearPortStatus)(nch, num);
868 KPRINTF(2, ("Powering up ports...\n\n"));
870 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++) {
871 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
, USR_SET_FEATURE
, UFS_PORT_POWER
, (ULONG
) num
);
872 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
875 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
, "PORT_POWER for port %ld failed: %s (%ld)", num
, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
876 KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", num
, ioerr
));
879 psdDelayMS((ULONG
) nch
->nch_PwrGoodTime
+ 15);
881 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
, "Hub with %ld ports successfully configured.", nch
->nch_NumPorts
);
883 KPRINTF(10, ("%s ready!\n", thistask
->tc_Node
.ln_Name
));
884 nch
->nch_Task
= thistask
;
888 KPRINTF(1, ("No downstream port array memory!\n"));
893 psdAddErrorMsg(RETURN_FAIL
, (STRPTR
) libname
, "GET_HUB_DESCRIPTOR (%ld) failed: %s (%ld)", len
, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
894 KPRINTF(1, ("GET_HUB_DESCRIPTOR (%ld) failed %ld!\n", len
, ioerr
));
898 KPRINTF(1, ("No Hub Descriptor memory!\n"));
901 psdAddErrorMsg(RETURN_FAIL
, (STRPTR
) libname
, "GET_HUB_DESCRIPTOR (%ld) failed: %s (%ld)", 1, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
902 KPRINTF(1, ("GET_HUB_DESCRIPTOR (1) failed %ld!\n", ioerr
));
907 psdFreePipe(nch
->nch_EP1Pipe
);
909 psdFreePipe(nch
->nch_EP0Pipe
);
911 DeleteMsgPort(nch
->nch_TaskMsgPort
);
913 DeleteMsgPort(nch
->nch_CtrlMsgPort
);
917 CloseLibrary(nch
->nch_Base
);
920 nch
->nch_Task
= NULL
;
922 if(nch
->nch_ReadySigTask
) {
923 Signal(nch
->nch_ReadySigTask
, 1L<<nch
->nch_ReadySignal
);
929 /* /// "nFreeHub()" */
930 void GM_UNIQUENAME(nFreeHub
)(struct NepClassHub
*nch
) {
933 struct PsdDevice
*pd
;
938 KPRINTF(1, ("FreeHub\n"));
939 psdGetAttrs(PGA_DEVICE
, nch
->nch_Device
, DA_IsConnected
, &isconnected
, TAG_END
);
940 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++) {
941 KPRINTF(1, ("Iterating Port %ld\n", num
));
942 /* Remove downstream device */
943 pd
= (nch
->nch_Downstream
)[num
-1];
946 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsConnected
, FALSE
, TAG_END
);
948 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
949 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
, "My death killed device '%s' at port %ld!", devname
, num
);
950 KPRINTF(1, ("FreeDevice %p\n", pd
));
952 psdSendEvent(EHMB_REMDEVICE
, pd
, NULL
);
953 (nch
->nch_Downstream
)[num
-1] = NULL
;
955 /* There's no sense trying to send out commands if the hub is already gone! */
957 /* power down for port */
958 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
, USR_CLEAR_FEATURE
, UFS_PORT_POWER
, (ULONG
) num
);
959 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
961 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
, "PORT_POWER for port %ld failed: %s (%ld)", num
, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
962 KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", num
, ioerr
));
967 KPRINTF(1, ("FreePipes\n"));
968 psdFreePipe(nch
->nch_EP1Pipe
);
969 psdFreePipe(nch
->nch_EP0Pipe
);
970 psdFreeVec(nch
->nch_Downstream
);
972 KPRINTF(1, ("Entering Forbid\n"));
975 while((msg
= GetMsg(nch
->nch_CtrlMsgPort
))) {
979 DeleteMsgPort(nch
->nch_TaskMsgPort
);
980 DeleteMsgPort(nch
->nch_CtrlMsgPort
);
981 CloseLibrary(nch
->nch_Base
);
982 nch
->nch_Task
= NULL
;
984 if(nch
->nch_ReadySigTask
) {
985 Signal(nch
->nch_ReadySigTask
, 1L<<nch
->nch_ReadySignal
);
988 KPRINTF(1, ("Really gone now!\n"));
992 /* *** HUBSS Class *** */
994 /* /// "nClearPortStatus()" */
995 LONG
GM_UNIQUENAME(nClearPortStatus
)(struct NepClassHub
*nch
, UWORD port
) {
998 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
, USR_CLEAR_FEATURE
, UFS_C_PORT_CONNECTION
, (ULONG
) port
);
999 if((ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0))) {
1000 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
, "CLEAR_PORT_FEATURE (C_PORT_CONNECTION) failed: %s (%ld)", psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1001 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1005 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
, USR_CLEAR_FEATURE
, UFS_C_PORT_ENABLE
, (ULONG
) port
);
1006 if((ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0))) {
1007 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
, "CLEAR_PORT_FEATURE (C_PORT_ENABLE) failed: %s (%ld)", psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1008 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1012 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
, USR_CLEAR_FEATURE
, UFS_C_PORT_SUSPEND
, (ULONG
) port
);
1013 if((ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0))) {
1014 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
, "CLEAR_PORT_FEATURE (C_PORT_SUSPEND) failed: %s (%ld)", psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1015 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1019 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
, USR_CLEAR_FEATURE
, UFS_C_PORT_OVER_CURRENT
, (ULONG
) port
);
1020 if((ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0))) {
1021 //psdAddErrorMsg(RETURN_WARN, (STRPTR) libname, "CLEAR_PORT_FEATURE (C_OVER_CURRENT) failed: %s (%ld)", psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);
1022 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1025 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
, USR_CLEAR_FEATURE
, UFS_C_PORT_RESET
, (ULONG
) port
);
1026 if((ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0))) {
1027 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
, "CLEAR_PORT_FEATURE (C_PORT_RESET) failed: %s (%ld)", psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1028 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1034 /* /// "nConfigurePort()" */
1035 struct PsdDevice
* GM_UNIQUENAME(nConfigurePort
)(struct NepClassHub
*nch
, UWORD port
) {
1039 ULONG delaytime
= 10;
1040 struct UsbPortStatus uhps
;
1041 struct PsdDevice
*pd
;
1043 BOOL washighspeed
= FALSE
;
1044 BOOL islowspeed
= FALSE
;
1046 KPRINTF(2, ("\nConfiguring port %ld of hub 0x%p\n", port
, nch
));
1048 uhps
.wPortStatus
= 0xDEAD;
1049 uhps
.wPortChange
= 0xDA1A;
1051 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_IN
|URTF_CLASS
|URTF_OTHER
, USR_GET_STATUS
, UFS_PORT_CONNECTION
, (ULONG
) port
);
1052 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, &uhps
, sizeof(struct UsbPortStatus
));
1054 uhps
.wPortStatus
= AROS_WORD2LE(uhps
.wPortStatus
);
1055 uhps
.wPortChange
= AROS_WORD2LE(uhps
.wPortChange
);
1058 KPRINTF(2, ("Status 0x%04x, change 0x%04x\n", uhps
.wPortStatus
, uhps
.wPortChange
));
1060 if(uhps
.wPortStatus
& UPSF_PORT_ENABLE
) {
1061 KPRINTF(2, ("Disabling port %u\n", port
));
1063 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
, USR_CLEAR_FEATURE
, UFS_PORT_ENABLE
, (ULONG
) port
);
1064 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
1066 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
, "CLEAR_PORT_ENABLE failed: %s (%ld)", psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1067 KPRINTF(1, ("CLEAR_PORT_ENABLE failed %ld.\n", ioerr
));
1069 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
, "Disabling port %ld.", port
);
1073 if(uhps
.wPortStatus
& UPSF_PORT_CONNECTION
) {
1074 KPRINTF(2, ("There's something at port %ld!\n", port
));
1077 if((pd
= psdAllocDevice(nch
->nch_Hardware
))) {
1078 psdLockWriteDevice(pd
);
1081 psdSetAttrs(PGA_DEVICE
, pd
, DA_HubDevice
, nch
->nch_Device
, DA_IsConnected
, TRUE
, DA_AtHubPortNumber
, port
, TAG_END
);
1082 if(uhps
.wPortStatus
& UPSF_PORT_LOW_SPEED
) {
1083 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsLowspeed
, TRUE
, TAG_END
);
1084 KPRINTF(2, (" It's a lowspeed device!\n"));
1088 ObtainSemaphore(&nch
->nch_HubBase
->nh_Adr0Sema
);
1090 for(resetretries
= 0; resetretries
< 3; resetretries
++) {
1091 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
, USR_SET_FEATURE
, UFS_PORT_RESET
, (ULONG
) port
);
1092 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
1095 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
, "PORT_RESET for port %ld failed: %s (%ld)", port
, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1096 KPRINTF(1, ("PORT_RESET failed %ld.\n", ioerr
));
1100 if(nch
->nch_IsRootHub
) {
1101 // Root hubs need 50ms minimum delay
1105 for(delayretries
= 0; delayretries
< 500; delayretries
+= delaytime
) {
1106 psdDelayMS(delaytime
);
1107 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_IN
|URTF_CLASS
|URTF_OTHER
, USR_GET_STATUS
, UFS_PORT_CONNECTION
, (ULONG
) port
);
1108 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, &uhps
, sizeof(struct UsbPortStatus
));
1110 uhps
.wPortStatus
= AROS_WORD2LE(uhps
.wPortStatus
);
1111 uhps
.wPortChange
= AROS_WORD2LE(uhps
.wPortChange
);
1114 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
, "GET_PORT_CONNECTION for port %ld failed: %s (%ld)", port
, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1115 KPRINTF(1, ("GET_PORT_CONNECTION failed %ld.\n", ioerr
));
1119 KPRINTF(2, ("After reset: status 0x%04x, change 0x%04x\n", uhps
.wPortStatus
, uhps
.wPortChange
));
1120 if(!(uhps
.wPortStatus
& UPSF_PORT_CONNECTION
)) {
1124 if((uhps
.wPortStatus
& (UPSF_PORT_RESET
|UPSF_PORT_CONNECTION
|UPSF_PORT_ENABLE
|UPSF_PORT_POWER
|UPSF_PORT_OVER_CURRENT
)) == (UPSF_PORT_CONNECTION
|UPSF_PORT_ENABLE
|UPSF_PORT_POWER
)) {
1125 if((uhps
.wPortStatus
& UPSF_PORT_HIGH_SPEED
) || washighspeed
) {
1126 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsHighspeed
, TRUE
, TAG_END
);
1127 washighspeed
= TRUE
;
1128 KPRINTF(2, (" It's a highspeed device!\n"));
1130 IPTR needssplit
= 0;
1132 /* Some hubs (Apple Keyboard bultin hub) report speed correctly only after reset */
1133 if (uhps
.wPortStatus
& UPSF_PORT_LOW_SPEED
) {
1134 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsLowspeed
, TRUE
, TAG_END
);
1135 KPRINTF(2, (" It's a lowspeed device!\n"));
1139 // inherit needs split from hub
1140 psdGetAttrs(PGA_DEVICE
, nch
->nch_Device
, DA_NeedsSplitTrans
, &needssplit
, TAG_END
);
1141 KPRINTF(2, (" Needs split transfers: %ld\n", needssplit
));
1143 psdSetAttrs(PGA_DEVICE
, pd
, DA_NeedsSplitTrans
, needssplit
, TAG_END
);
1146 GM_UNIQUENAME(nClearPortStatus
)(nch
, port
);
1147 psdDelayMS((ULONG
) (islowspeed
? 1000 : 100));
1148 if((pp
= psdAllocPipe(pd
, nch
->nch_TaskMsgPort
, NULL
))) {
1149 if(psdEnumerateDevice(pp
)) {
1150 KPRINTF(2, (" Device successfully added!\n"));
1152 psdUnlockDevice(pd
);
1153 psdSendEvent(EHMB_ADDDEVICE
, pd
, NULL
);
1154 ReleaseSemaphore(&nch
->nch_HubBase
->nh_Adr0Sema
);
1161 if(!(uhps
.wPortStatus
& UPSF_PORT_RESET
)) {
1162 psdAddErrorMsg(RETURN_ERROR
, (STRPTR
) libname
, "Wrong port status %04lx for port %ld!", uhps
.wPortStatus
, port
);
1163 KPRINTF(2, ("Wrong port status %04lx for port %ld.\n", uhps
.wPortStatus
, port
));
1167 if(delayretries
> 20) {
1172 if((uhps
.wPortStatus
& \
1173 (UPSF_PORT_RESET
|UPSF_PORT_CONNECTION
|UPSF_PORT_ENABLE
|UPSF_PORT_POWER
|UPSF_PORT_OVER_CURRENT
|UPSF_PORT_LOW_SPEED
)) \
1174 == (UPSF_PORT_CONNECTION
|UPSF_PORT_POWER
|UPSF_PORT_LOW_SPEED
)) {
1176 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
, "Strange port response, power-cycling port %ld", port
);
1177 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
, USR_CLEAR_FEATURE
, UFS_PORT_ENABLE
, (ULONG
) port
);
1178 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
1181 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
, "CLEAR_PORT_ENABLE for port %ld failed: %s (%ld)", port
, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1182 KPRINTF(1, ("CLEAR_PORT_ENABLE for port %ld failed %ld!\n", port
, ioerr
));
1186 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
, USR_CLEAR_FEATURE
, UFS_PORT_POWER
, (ULONG
) port
);
1187 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
1190 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
, "CLEAR_PORT_POWER for port %ld failed: %s (%ld)", port
, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1191 KPRINTF(1, ("CLEAR_PORT_POWER for port %ld failed %ld!\n", port
, ioerr
));
1195 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
, USR_SET_FEATURE
, UFS_PORT_POWER
, (ULONG
) port
);
1196 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
1199 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
, "SET_PORT_POWER for port %ld failed: %s (%ld)", port
, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1200 KPRINTF(1, ("SET_PORT_POWER for port %ld failed %ld!\n", port
, ioerr
));
1202 psdDelayMS((ULONG
) nch
->nch_PwrGoodTime
+ 15);
1209 psdUnlockDevice(pd
);
1211 /* Disable port! It's too dangerous having a connection with crazy devices on the bus open */
1212 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
, USR_CLEAR_FEATURE
, UFS_PORT_ENABLE
, (ULONG
) port
);
1213 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
1216 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
, "CLEAR_PORT_ENABLE failed: %s (%ld)", psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1217 KPRINTF(1, ("CLEAR_PORT_ENABLE failed %ld.\n", ioerr
));
1219 ReleaseSemaphore(&nch
->nch_HubBase
->nh_Adr0Sema
);
1220 GM_UNIQUENAME(nClearPortStatus
)(nch
, port
);
1223 KPRINTF(1, ("AllocDevice() failed.\n"));
1227 psdAddErrorMsg(RETURN_ERROR
, (STRPTR
) libname
, "GET_PORT_CONNECTION failed: %s (%ld)", psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1228 KPRINTF(1, ("GET_PORT_CONNECTION for port %d failed %ld.\n", port
, ioerr
));
1233 /* /// "nHandleHubMethod()" */
1234 void GM_UNIQUENAME(nHandleHubMethod
)(struct NepClassHub
*nch
, struct NepHubMsg
*nhm
) {
1236 struct PsdDevice
*pd
;
1237 nhm
->nhm_Result
= 0;
1239 switch(nhm
->nhm_MethodID
) {
1240 case UCM_HubClaimAppBinding
:
1241 nhm
->nhm_Result
= (IPTR
) psdHubClaimAppBindingA((struct TagItem
*) nhm
->nhm_Params
[1]);
1244 case UCM_HubReleaseIfBinding
: {
1245 psdHubReleaseIfBinding((struct PsdInterface
*) nhm
->nhm_Params
[1]);
1247 } /* case UCM_HubReleaseIfBinding */
1249 case UCM_HubReleaseDevBinding
:
1250 psdHubReleaseDevBinding((struct PsdDevice
*) nhm
->nhm_Params
[1]);
1253 case UCM_AttemptSuspendDevice
:
1257 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++) {
1258 if((pd
= (nch
->nch_Downstream
)[num
-1])) {
1259 res
&= psdSuspendDevice(pd
);
1264 // suspending of all downstream devices successful, so stop all activity, too.
1265 psdAbortPipe(nch
->nch_EP1Pipe
);
1266 nch
->nch_Running
= FALSE
;
1267 nhm
->nhm_Result
= TRUE
;
1270 } /* case UCM_AttemptSuspendDevice */
1273 case UCM_AttemptResumeDevice
:
1275 if(!nch
->nch_Running
) {
1276 psdWaitPipe(nch
->nch_EP1Pipe
);
1277 psdSendPipe(nch
->nch_EP1Pipe
, nch
->nch_PortChanges
, (nch
->nch_NumPorts
+8)>>3);
1278 nch
->nch_Running
= TRUE
;
1281 nhm
->nhm_Result
= TRUE
;
1283 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++) {
1284 if((pd
= (nch
->nch_Downstream
)[num
-1])) {
1285 psdResumeDevice(pd
);
1291 case UCM_HubSuspendDevice
:
1292 nhm
->nhm_Result
= GM_UNIQUENAME(nHubSuspendDevice
)(nch
, (struct PsdDevice
*) nhm
->nhm_Params
[1]);
1295 case UCM_HubResumeDevice
:
1296 nhm
->nhm_Result
= GM_UNIQUENAME(nHubResumeDevice
)(nch
, (struct PsdDevice
*) nhm
->nhm_Params
[1]);
1302 /* /// "nHubSuspendDevice()" */
1303 BOOL
GM_UNIQUENAME(nHubSuspendDevice
)(struct NepClassHub
*nch
, struct PsdDevice
*pd
) {
1304 APTR binding
= NULL
;
1307 BOOL result
= FALSE
;
1310 psdGetAttrs(PGA_DEVICE
, pd
, DA_Binding
, &binding
, DA_BindingClass
, &puc
, TAG_END
);
1312 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++) {
1313 if(pd
== (nch
->nch_Downstream
)[num
-1]) {
1314 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
, USR_SET_FEATURE
, UFS_PORT_SUSPEND
, num
);
1315 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
1318 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
, "SET_PORT_SUSPEND failed: %s (%ld)", psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1319 KPRINTF(1, ("SET_PORT_SUSPEND failed %ld.\n", ioerr
));
1322 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsSuspended
, TRUE
, TAG_END
);
1323 psdSendEvent(EHMB_DEVSUSPENDED
, pd
, NULL
);
1331 /* /// "nHubResumeDevice()" */
1332 BOOL
GM_UNIQUENAME(nHubResumeDevice
)(struct NepClassHub
*nch
, struct PsdDevice
*pd
) {
1334 BOOL result
= FALSE
;
1337 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++) {
1338 if(pd
== (nch
->nch_Downstream
)[num
-1]) {
1339 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
, USR_CLEAR_FEATURE
, UFS_PORT_SUSPEND
, (ULONG
) num
);
1340 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
1343 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
, "CLEAR_PORT_SUSPEND failed: %s (%ld)", psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1344 KPRINTF(1, ("CLEAR_PORT_SUSPEND failed %ld.\n", ioerr
));
1346 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsSuspended
, FALSE
, TAG_END
);
1347 psdSendEvent(EHMB_DEVRESUMED
, pd
, NULL
);