2 *----------------------------------------------------------------------------
3 * hub class for poseidon
4 *----------------------------------------------------------------------------
5 * By Chris Hodges <chrisly@platon42.de>
10 #include "hub.class.h"
13 static const STRPTR libname
= MOD_NAME_STRING
;
15 static int libInit(LIBBASETYPEPTR nh
)
17 KPRINTF(10, ("libInit nh: 0x%08lx SysBase: 0x%08lx\n", nh
, SysBase
));
19 nh
->nh_UtilityBase
= OpenLibrary("utility.library", 39);
21 #define UtilityBase nh->nh_UtilityBase
25 NewList(&nh
->nh_Bindings
);
26 InitSemaphore(&nh
->nh_Adr0Sema
);
28 KPRINTF(20, ("libInit: OpenLibrary(\"utility.library\", 39) failed!\n"));
32 KPRINTF(10, ("libInit: Ok\n"));
36 static int libExpunge(LIBBASETYPEPTR nh
)
38 KPRINTF(10, ("libExpunge nh: 0x%08lx SysBase: 0x%08lx\n", nh
, SysBase
));
40 CloseLibrary(UtilityBase
);
41 nh
->nh_UtilityBase
= NULL
;
46 ADD2INITLIB(libInit
, 0)
47 ADD2EXPUNGELIB(libExpunge
, 0)
51 * ***********************************************************************
52 * * Library functions *
53 * ***********************************************************************
56 /* /// "usbAttemptDeviceBinding()" */
57 struct NepClassHub
* usbAttemptDeviceBinding(struct NepHubBase
*nh
, struct PsdDevice
*pd
)
62 KPRINTF(1, ("nepHubAttemptDeviceBinding(%08lx)\n", pd
));
64 if((ps
= OpenLibrary("poseidon.library", 4)))
66 psdGetAttrs(PGA_DEVICE
, pd
,
70 if(devclass
== HUB_CLASSCODE
)
72 return(usbForceDeviceBinding(nh
, pd
));
79 /* /// "usbForceDeviceBinding()" */
80 struct NepClassHub
* usbForceDeviceBinding(struct NepHubBase
* nh
, struct PsdDevice
*pd
)
83 struct NepClassHub
*nch
;
88 KPRINTF(1, ("nepHubAttemptDeviceBinding(%08lx)\n", pd
));
90 if((ps
= OpenLibrary("poseidon.library", 4)))
92 psdGetAttrs(PGA_DEVICE
, pd
,
93 DA_ProductName
, &devname
,
95 if((nch
= psdAllocVec(sizeof(struct NepClassHub
))))
97 nch
->nch_HubBase
= nh
;
98 nch
->nch_SysBase
= SysBase
;
100 psdSafeRawDoFmt(buf
, 64, "hub.class<%08lx>", nch
);
101 nch
->nch_ReadySignal
= SIGB_SINGLE
;
102 nch
->nch_ReadySigTask
= FindTask(NULL
);
103 SetSignal(0, SIGF_SINGLE
);
104 if((tmptask
= psdSpawnSubTask(buf
, nHubTask
, nch
)))
106 psdBorrowLocksWait(tmptask
, 1UL<<nch
->nch_ReadySignal
);
109 nch
->nch_ReadySigTask
= NULL
;
110 //FreeSignal(nch->nch_ReadySignal);
111 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
112 "I'm in love with hub '%s'.",
116 AddTail(&nh
->nh_Bindings
, nch
);
122 nch
->nch_ReadySigTask
= NULL
;
123 //FreeSignal(nch->nch_ReadySignal);
132 /* /// "usbReleaseDeviceBinding()" */
133 void usbReleaseDeviceBinding(struct NepHubBase
*nh
, struct NepClassHub
*nch
)
138 KPRINTF(1, ("nepHubReleaseDeviceBinding(%08lx)\n", nch
));
139 if((ps
= OpenLibrary("poseidon.library", 4)))
142 nch
->nch_ReadySignal
= SIGB_SINGLE
;
143 nch
->nch_ReadySigTask
= FindTask(NULL
);
146 KPRINTF(1, ("Sending Break\n"));
147 Signal(nch
->nch_Task
, SIGBREAKF_CTRL_C
);
152 psdBorrowLocksWait(nch
->nch_Task
, 1UL<<nch
->nch_ReadySignal
);
154 KPRINTF(1, ("Task gone\n"));
155 //FreeSignal(nch->nch_ReadySignal);
156 psdGetAttrs(PGA_DEVICE
, nch
->nch_Device
, DA_ProductName
, &devname
, TAG_END
);
157 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
158 "Time to get rid of '%s'!",
170 /* /// "usbGetAttrsA()" */
171 AROS_LH3(LONG
, usbGetAttrsA
,
172 AROS_LHA(ULONG
, type
, D0
),
173 AROS_LHA(APTR
, usbstruct
, A0
),
174 AROS_LHA(struct TagItem
*, tags
, A1
),
175 LIBBASETYPEPTR
, nh
, 5, nep
)
182 KPRINTF(1, ("nepHubGetAttrsA(%ld, %08lx, %08lx)\n", type
, usbstruct
, tags
));
186 if((ti
= FindTagItem(UCCA_Priority
, tags
)))
188 *((IPTR
*) ti
->ti_Data
) = 0;
191 if((ti
= FindTagItem(UCCA_Description
, tags
)))
193 *((STRPTR
*) ti
->ti_Data
) = "Root/external hub base class";
196 if((ti
= FindTagItem(UCCA_HasClassCfgGUI
, tags
)))
198 *((IPTR
*) ti
->ti_Data
) = FALSE
;
201 if((ti
= FindTagItem(UCCA_HasBindingCfgGUI
, tags
)))
203 *((IPTR
*) ti
->ti_Data
) = FALSE
;
206 if((ti
= FindTagItem(UCCA_AfterDOSRestart
, tags
)))
208 *((IPTR
*) ti
->ti_Data
) = FALSE
;
211 if((ti
= FindTagItem(UCCA_UsingDefaultCfg
, tags
)))
213 *((IPTR
*) ti
->ti_Data
) = TRUE
;
216 if((ti
= FindTagItem(UCCA_SupportsSuspend
, tags
)))
218 *((IPTR
*) ti
->ti_Data
) = TRUE
;
224 if((ti
= FindTagItem(UCBA_UsingDefaultCfg
, tags
)))
226 *((IPTR
*) ti
->ti_Data
) = TRUE
;
236 /* /// "usbSetAttrsA()" */
237 AROS_LH3(LONG
, usbSetAttrsA
,
238 AROS_LHA(ULONG
, type
, D0
),
239 AROS_LHA(APTR
, usbstruct
, A0
),
240 AROS_LHA(struct TagItem
*, tags
, A1
),
241 LIBBASETYPEPTR
, nh
, 6, nep
)
249 /* /// "usbDoMethodA()" */
250 AROS_LH2(IPTR
, usbDoMethodA
,
251 AROS_LHA(ULONG
, methodid
, D0
),
252 AROS_LHA(IPTR
*, methoddata
, A1
),
253 LIBBASETYPEPTR
, nh
, 7, nep
)
257 struct NepClassHub
*nch
;
259 KPRINTF(10, ("Do Method %ld\n", methodid
));
262 case UCM_AttemptDeviceBinding
:
263 return(usbAttemptDeviceBinding(nh
, (struct PsdDevice
*) methoddata
[0]));
265 case UCM_ForceDeviceBinding
:
266 return(usbForceDeviceBinding(nh
, (struct PsdDevice
*) methoddata
[0]));
268 case UCM_ReleaseDeviceBinding
:
269 usbReleaseDeviceBinding(nh
, (struct NepClassHub
*) methoddata
[0]);
272 case UCM_HubPowerCyclePort
:
273 case UCM_HubDisablePort
:
275 struct PsdDevice
*pd
= (struct PsdDevice
*) methoddata
[0];
276 ULONG port
= (ULONG
) methoddata
[1];
279 KPRINTF(20, ("HubPowerCycle/DisablePort Params Null!\n"));
283 nch
= (struct NepClassHub
*) nh
->nh_Bindings
.lh_Head
;
284 while(nch
->nch_Node
.ln_Succ
)
286 if(nch
->nch_Device
== pd
)
288 KPRINTF(20, ("HubPowerCycle/DisablePort Dev found (port %ld)!\n", port
));
289 if(port
<= nch
->nch_NumPorts
)
291 nch
->nch_DisablePort
|= 1UL<<port
;
292 if(methodid
== UCM_HubPowerCyclePort
)
294 nch
->nch_PowerCycle
|= 1UL<<port
;
298 Signal(nch
->nch_Task
, (1L<<nch
->nch_TaskMsgPort
->mp_SigBit
));
305 nch
= (struct NepClassHub
*) nch
->nch_Node
.ln_Succ
;
311 case UCM_HubClassScan
:
313 nch
= (struct NepClassHub
*) methoddata
[0];
315 nch
->nch_ClassScan
= TRUE
;
318 Signal(nch
->nch_Task
, (1L<<nch
->nch_TaskMsgPort
->mp_SigBit
));
324 case UCM_AttemptSuspendDevice
:
325 case UCM_AttemptResumeDevice
:
326 case UCM_HubClaimAppBinding
:
327 case UCM_HubReleaseIfBinding
:
328 case UCM_HubReleaseDevBinding
:
329 case UCM_HubSuspendDevice
:
330 case UCM_HubResumeDevice
:
332 struct NepHubMsg nhm
;
334 nch
= (struct NepClassHub
*) methoddata
[0];
335 nhm
.nhm_Result
= NULL
;
336 nhm
.nhm_MethodID
= methodid
;
337 nhm
.nhm_Params
= methoddata
;
338 if((ps
= OpenLibrary("poseidon.library", 4)))
340 if(nch
->nch_Task
== FindTask(NULL
))
342 // if we would send the message to ourself, we would deadlock, so handle this directly
343 nHandleHubMethod(nch
, &nhm
);
345 nhm
.nhm_Msg
.mn_ReplyPort
= CreateMsgPort();
346 nhm
.nhm_Msg
.mn_Length
= sizeof(struct NepHubMsg
);
348 if(nch
->nch_Task
&& nhm
.nhm_Msg
.mn_ReplyPort
)
350 PutMsg(nch
->nch_CtrlMsgPort
, &nhm
.nhm_Msg
);
352 while(!GetMsg(nhm
.nhm_Msg
.mn_ReplyPort
))
354 psdBorrowLocksWait(nch
->nch_Task
, 1UL<<nhm
.nhm_Msg
.mn_ReplyPort
->mp_SigBit
);
359 DeleteMsgPort(nhm
.nhm_Msg
.mn_ReplyPort
);
363 return(nhm
.nhm_Result
);
375 #define ps nch->nch_Base
377 /* /// "nHubTask()" */
378 AROS_UFH0(void, nHubTask
)
382 struct NepClassHub
*nch
;
388 struct UsbPortStatus uhps
;
389 struct UsbHubStatus uhhs
;
391 struct PsdDevice
*pd
;
393 struct NepHubMsg
*nhm
;
395 if((nch
= nAllocHub()))
398 if(nch
->nch_ReadySigTask
)
400 Signal(nch
->nch_ReadySigTask
, 1L<<nch
->nch_ReadySignal
);
404 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++)
406 if(((nch
->nch_Downstream
)[num
-1] = pd
= nConfigurePort(nch
, num
)))
408 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
409 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
410 "Detected device '%s' at port %ld. I like it.",
417 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
418 "Hub has added %ld device(s). That'll be fun!",
422 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++)
424 if((pd
= (nch
->nch_Downstream
)[num
-1]))
429 sigmask
= (1L<<nch
->nch_TaskMsgPort
->mp_SigBit
)|(1L<<nch
->nch_CtrlMsgPort
->mp_SigBit
)|SIGBREAKF_CTRL_C
;
430 nch
->nch_Running
= TRUE
;
431 nch
->nch_IOStarted
= FALSE
;
434 if(nch
->nch_Running
&& (!nch
->nch_IOStarted
))
436 psdSendPipe(nch
->nch_EP1Pipe
, nch
->nch_PortChanges
, 1);
437 nch
->nch_IOStarted
= TRUE
;
439 sigs
= Wait(sigmask
);
440 while((nhm
= (struct NepHubMsg
*) GetMsg(nch
->nch_CtrlMsgPort
)))
442 nHandleHubMethod(nch
, nhm
);
446 if(nch
->nch_DisablePort
)
448 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++)
450 if((nch
->nch_DisablePort
) & (1L<<num
))
452 nch
->nch_DisablePort
&= ~(1L<<num
);
454 if((pd
= (nch
->nch_Downstream
)[num
-1]))
456 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsConnected
, FALSE
, TAG_END
);
457 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
458 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
459 "Zapping device '%s' at port %ld!",
462 psdSendEvent(EHMB_REMDEVICE
, pd
, NULL
);
463 (nch
->nch_Downstream
)[num
-1] = NULL
;
466 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
467 USR_CLEAR_FEATURE
, UFS_PORT_ENABLE
, (ULONG
) num
);
468 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
471 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
472 "CLEAR_PORT_ENABLE failed: %s (%ld)",
473 psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
474 KPRINTF(1, ("CLEAR_PORT_ENABLE failed %ld.\n", ioerr
));
477 if(nch
->nch_PowerCycle
& (1<<num
))
479 nch
->nch_PowerCycle
&= ~(1L<<num
);
481 /* Wait for device to settle */
483 if(((nch
->nch_Downstream
)[num
-1] = pd
= nConfigurePort(nch
, num
)))
485 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
486 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
487 "Device '%s' returned. Happy happy joy joy.",
495 if(nch
->nch_ClassScan
)
497 nch
->nch_ClassScan
= FALSE
;
498 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++)
500 if((pd
= (nch
->nch_Downstream
)[num
-1]))
502 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
507 while((pp
= (struct PsdPipe
*) GetMsg(nch
->nch_TaskMsgPort
)))
509 if(pp
== nch
->nch_EP1Pipe
)
511 nch
->nch_IOStarted
= FALSE
;
512 ioerr
= psdGetPipeError(nch
->nch_EP1Pipe
);
513 if(ioerr
== UHIOERR_TIMEOUT
)
515 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
516 "Hub involuntarily gone! Disconnecting...");
517 psdSetAttrs(PGA_DEVICE
, nch
->nch_Device
,
518 DA_IsConnected
, FALSE
,
520 nch
->nch_PortChanges
[0] = 0xff;
521 sigs
|= SIGBREAKF_CTRL_C
;
523 if((!ioerr
) || (ioerr
== UHIOERR_TIMEOUT
))
525 KPRINTF(2, ("Port changed at %08lx, Numports=%ld!\n", nch
->nch_PortChanges
[0], nch
->nch_NumPorts
));
527 if(nch
->nch_PortChanges
[0] & 1)
529 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_IN
|URTF_CLASS
|URTF_DEVICE
,
530 USR_GET_STATUS
, 0, 0);
531 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, &uhhs
, sizeof(struct UsbHubStatus
));
532 uhhs
.wHubStatus
= AROS_WORD2LE(uhhs
.wHubStatus
);
533 uhhs
.wHubChange
= AROS_WORD2LE(uhhs
.wHubChange
);
536 if(uhhs
.wHubStatus
& UHSF_OVER_CURRENT
)
538 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
539 "Hub over-current situation detected! Unpowering ALL ports!");
540 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++)
542 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
543 USR_CLEAR_FEATURE
, UFS_PORT_POWER
, (ULONG
) num
);
544 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
547 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
548 "PORT_POWER for port %ld failed: %s (%ld)",
549 num
, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
550 KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", num
, ioerr
));
553 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
554 USR_CLEAR_FEATURE
, UFS_C_PORT_OVER_CURRENT
, (ULONG
) num
);
555 psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
557 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_DEVICE
,
558 USR_CLEAR_FEATURE
, UFS_C_HUB_OVER_CURRENT
, 0);
559 psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
561 if(uhhs
.wHubChange
& UHSF_LOCAL_POWER_LOST
)
563 struct PsdConfig
*pc
= NULL
;
564 struct PsdHardware
*phw
= NULL
;
565 psdGetAttrs(PGA_DEVICE
, nch
->nch_Device
,
569 if(uhhs
.wHubStatus
& UHSF_LOCAL_POWER_LOST
)
571 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
572 "Hub is no longer self-powered! Low power conditions may occur.");
576 psdSetAttrs(PGA_CONFIG
, pc
, CA_SelfPowered
, FALSE
, TAG_END
);
577 psdCalculatePower(phw
);
580 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
581 "Hub is now self-powered! Yay!");
584 psdSetAttrs(PGA_CONFIG
, pc
, CA_SelfPowered
, TRUE
, TAG_END
);
585 psdCalculatePower(phw
);
588 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_DEVICE
,
589 USR_CLEAR_FEATURE
, UFS_C_HUB_LOCAL_POWER
, 0);
590 psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
595 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++)
597 if(nch
->nch_PortChanges
[0] & (1L<<num
))
599 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_IN
|URTF_CLASS
|URTF_OTHER
,
600 USR_GET_STATUS
, 0, (ULONG
) num
);
601 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, &uhps
, sizeof(struct UsbPortStatus
));
602 uhps
.wPortStatus
= AROS_WORD2LE(uhps
.wPortStatus
);
603 uhps
.wPortChange
= AROS_WORD2LE(uhps
.wPortChange
);
604 if(ioerr
== UHIOERR_TIMEOUT
)
606 uhps
.wPortStatus
= 0;
607 uhps
.wPortChange
= 0xffff;
610 nClearPortStatus(nch
, num
);
614 pd
= (nch
->nch_Downstream
)[num
-1];
615 if(uhps
.wPortStatus
& UPSF_PORT_OVER_CURRENT
)
619 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
623 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
624 "Over-current situation detected with %s at port %ld! Unpowering port!",
626 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
627 USR_CLEAR_FEATURE
, UFS_PORT_POWER
, (ULONG
) num
);
628 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
631 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
632 "PORT_POWER for port %ld failed: %s (%ld)",
633 num
, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
634 KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", num
, ioerr
));
637 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
638 USR_CLEAR_FEATURE
, UFS_C_PORT_OVER_CURRENT
, (ULONG
) num
);
639 psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
641 if(uhps
.wPortChange
& UPSF_PORT_SUSPEND
)
643 if((!(uhps
.wPortStatus
& UPSF_PORT_SUSPEND
)) && pd
)
646 psdGetAttrs(PGA_DEVICE
, pd
, DA_IsSuspended
, &oldsusp
, TAG_END
);
647 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsSuspended
, FALSE
, TAG_END
);
648 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
651 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
652 "Device '%s' at port %ld resumed from remote!",
654 psdSendEvent(EHMB_DEVRESUMED
, pd
, NULL
);
655 psdResumeBindings(pd
);
658 else if((uhps
.wPortStatus
& UPSF_PORT_SUSPEND
) && pd
)
660 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsSuspended
, FALSE
, TAG_END
);
661 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
662 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
663 "Device '%s' at port %ld suspended!",
666 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
667 "Bogus suspend/resume change on port %ld.",
671 if(uhps
.wPortChange
& UPSF_PORT_CONNECTION
)
674 if((!(uhps
.wPortStatus
& UPSF_PORT_CONNECTION
)) && pd
)
676 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsConnected
, FALSE
, TAG_END
);
677 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
678 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
679 "Device '%s' at port %ld is gone!",
682 psdSendEvent(EHMB_REMDEVICE
, pd
, NULL
);
683 (nch
->nch_Downstream
)[num
-1] = NULL
;
687 if((uhps
.wPortStatus
& UPSF_PORT_CONNECTION
) && (!pd
))
689 /* Wait for device to settle */
691 if(((nch
->nch_Downstream
)[num
-1] = pd
= nConfigurePort(nch
, num
)))
693 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
694 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
695 "New device '%s' at port %ld. Very nice.",
704 /* Bail out on time out. */
705 if(nch
->nch_PortChanges
[0] == 0xff)
711 if(ioerr
!= IOERR_ABORTED
)
713 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
714 "Something weird happened to the status packet, it failed: %s (%ld)",
715 psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
721 KPRINTF(20, ("Bogus message received!\n"));
724 } while(!(sigs
& SIGBREAKF_CTRL_C
));
725 KPRINTF(20, ("Going down the river!\n"));
726 if(nch
->nch_IOStarted
)
728 psdAbortPipe(nch
->nch_EP1Pipe
);
729 psdWaitPipe(nch
->nch_EP1Pipe
);
731 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
, "Oh no! I've been shot! Arrggghh...");
738 /* /// "nAllocHub()" */
739 struct NepClassHub
* nAllocHub(void)
741 struct UsbHubDesc
*uhd
;
742 struct Task
*thistask
;
743 struct NepClassHub
*nch
;
744 struct UsbHubStatus uhhs
;
749 IPTR ishighspeed
= 0;
752 BOOL overcurrent
= FALSE
;
754 thistask
= FindTask(NULL
);
755 nch
= thistask
->tc_UserData
;
758 if(!(nch
->nch_Base
= OpenLibrary("poseidon.library", 4)))
764 psdGetAttrs(PGA_DEVICE
, nch
->nch_Device
,
765 DA_Hardware
, &nch
->nch_Hardware
,
766 DA_IsHighspeed
, &ishighspeed
,
767 DA_ProductID
, &prodid
,
768 DA_VendorID
, &vendid
,
770 nch
->nch_IsUSB20
= ishighspeed
;
771 // try to select multi TT interface first
772 nch
->nch_Interface
= psdFindInterface(nch
->nch_Device
, NULL
,
773 IFA_Class
, HUB_CLASSCODE
,
775 IFA_AlternateNum
, 0xffffffff,
777 if(!nch
->nch_Interface
)
780 nch
->nch_Interface
= psdFindInterface(nch
->nch_Device
, NULL
,
781 IFA_Class
, HUB_CLASSCODE
,
784 if((vendid
== 0x05E3) && ishighspeed
)
786 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
, "Genesys Logic hubs are broken and will cause failures with USB 2.0 devices.");
787 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
, "If you encounter problems, try the device without the hub.");
788 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
, "If this solves the problem, you need to buy a different USB 2.0 hub.");
791 if(!nch
->nch_Interface
)
793 KPRINTF(1, ("Ooops!?! No interfaces defined?\n"));
796 nch
->nch_EP1
= psdFindEndpoint(nch
->nch_Interface
, NULL
,
798 EA_TransferType
, USEAF_INTERRUPT
,
803 psdAddErrorMsg(RETURN_FAIL
, (STRPTR
) libname
, "Ooops!?! No endpoints defined?");
804 KPRINTF(1, ("Ooops!?! No Endpoints defined?\n"));
807 if((nch
->nch_CtrlMsgPort
= CreateMsgPort()))
809 if((nch
->nch_TaskMsgPort
= CreateMsgPort()))
811 if((nch
->nch_EP0Pipe
= psdAllocPipe(nch
->nch_Device
, nch
->nch_TaskMsgPort
, NULL
)))
813 psdSetAttrs(PGA_PIPE
, nch
->nch_EP0Pipe
,
814 PPA_NakTimeout
, TRUE
,
815 PPA_NakTimeoutTime
, 1000,
817 psdSetAltInterface(nch
->nch_EP0Pipe
, nch
->nch_Interface
);
818 if((nch
->nch_EP1Pipe
= psdAllocPipe(nch
->nch_Device
, nch
->nch_TaskMsgPort
, nch
->nch_EP1
)))
820 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_IN
|URTF_CLASS
|URTF_DEVICE
,
821 USR_GET_DESCRIPTOR
, UDT_HUB
<<8, 0);
822 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, &buf
, 1);
823 if((!ioerr
) || (ioerr
== UHIOERR_OVERFLOW
))
826 if((uhd
= psdAllocVec(len
)))
828 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, uhd
, len
);
831 nch
->nch_NumPorts
= uhd
->bNbrPorts
;
832 nch
->nch_HubAttr
= AROS_WORD2LE(uhd
->wHubCharacteristics
);
833 nch
->nch_PwrGoodTime
= uhd
->bPwrOn2PwrGood
<<1;
834 nch
->nch_HubCurrent
= uhd
->bHubContrCurrent
;
835 nch
->nch_Removable
= 0;
836 if(nch
->nch_HubAttr
& UHCM_THINK_TIME
)
838 psdSetAttrs(PGA_DEVICE
, nch
->nch_Device
,
839 DA_HubThinkTime
, (nch
->nch_HubAttr
& UHCM_THINK_TIME
)>>UHCS_THINK_TIME
,
843 for(num
= 0; num
< ((nch
->nch_NumPorts
+ 7)>>3); num
++)
845 nch
->nch_Removable
|= ((&uhd
->DeviceRemovable
)[num
])<<(num
<<3);
847 KPRINTF(1, ("Hub with %ld ports\n"
848 " PowerGood after %ld ms\n"
849 " Power consumption %ld mA\n",
851 nch
->nch_PwrGoodTime
, nch
->nch_HubCurrent
));
854 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_IN
|URTF_CLASS
|URTF_DEVICE
,
855 USR_GET_STATUS
, 0, 0);
856 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, &uhhs
, sizeof(struct UsbHubStatus
));
857 uhhs
.wHubStatus
= AROS_WORD2LE(uhhs
.wHubStatus
);
858 uhhs
.wHubChange
= AROS_WORD2LE(uhhs
.wHubChange
);
861 struct PsdConfig
*pc
= NULL
;
862 struct PsdHardware
*phw
= NULL
;
863 if(uhhs
.wHubStatus
& UHSF_OVER_CURRENT
)
865 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
866 "Hub over-current situation detected! Resolve this first!");
867 //overcurrent = TRUE;
870 psdGetAttrs(PGA_DEVICE
, nch
->nch_Device
,
874 if(uhhs
.wHubStatus
& UHSF_LOCAL_POWER_LOST
)
878 psdSetAttrs(PGA_CONFIG
, pc
, CA_SelfPowered
, FALSE
, TAG_END
);
879 psdCalculatePower(phw
);
884 psdSetAttrs(PGA_CONFIG
, pc
, CA_SelfPowered
, TRUE
, TAG_END
);
885 psdCalculatePower(phw
);
891 if((nch
->nch_Downstream
= psdAllocVec((ULONG
) nch
->nch_NumPorts
*sizeof(APTR
))))
893 /*for(num = 1; num <= nch->nch_NumPorts; num++)
895 nClearPortStatus(nch, num);
898 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++)
900 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
901 USR_SET_FEATURE
, UFS_PORT_POWER
, (ULONG
) num
);
902 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
905 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
906 "PORT_POWER for port %ld failed: %s (%ld)",
907 num
, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
908 KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", num
, ioerr
));
911 psdDelayMS((ULONG
) nch
->nch_PwrGoodTime
+ 15);
913 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
914 "Hub with %ld ports successfully configured.",
917 KPRINTF(10, ("%s ready!\n", thistask
->tc_Node
.ln_Name
));
918 nch
->nch_Task
= thistask
;
921 KPRINTF(1, ("No downstream port array memory!\n"));
926 psdAddErrorMsg(RETURN_FAIL
, (STRPTR
) libname
,
927 "GET_HUB_DESCRIPTOR (%ld) failed: %s (%ld)",
928 len
, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
929 KPRINTF(1, ("GET_HUB_DESCRIPTOR (%ld) failed %ld!\n", len
, ioerr
));
932 KPRINTF(1, ("No Hub Descriptor memory!\n"));
935 psdAddErrorMsg(RETURN_FAIL
, (STRPTR
) libname
,
936 "GET_HUB_DESCRIPTOR (%ld) failed: %s (%ld)",
937 1, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
938 KPRINTF(1, ("GET_HUB_DESCRIPTOR (1) failed %ld!\n", ioerr
));
940 psdFreePipe(nch
->nch_EP1Pipe
);
942 psdFreePipe(nch
->nch_EP0Pipe
);
944 DeleteMsgPort(nch
->nch_TaskMsgPort
);
946 DeleteMsgPort(nch
->nch_CtrlMsgPort
);
949 CloseLibrary(nch
->nch_Base
);
951 nch
->nch_Task
= NULL
;
952 if(nch
->nch_ReadySigTask
)
954 Signal(nch
->nch_ReadySigTask
, 1L<<nch
->nch_ReadySignal
);
960 /* /// "nFreeHub()" */
961 void nFreeHub(struct NepClassHub
*nch
)
965 struct PsdDevice
*pd
;
970 KPRINTF(1, ("FreeHub\n"));
971 psdGetAttrs(PGA_DEVICE
, nch
->nch_Device
, DA_IsConnected
, &isconnected
, TAG_END
);
972 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++)
974 KPRINTF(1, ("Iterating Port %ld\n", num
));
975 /* Remove downstream device */
976 pd
= (nch
->nch_Downstream
)[num
-1];
981 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsConnected
, FALSE
, TAG_END
);
983 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
984 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
985 "My death killed device '%s' at port %ld!",
987 KPRINTF(1, ("FreeDevice %08lx\n", pd
));
989 psdSendEvent(EHMB_REMDEVICE
, pd
, NULL
);
990 (nch
->nch_Downstream
)[num
-1] = NULL
;
992 /* There's no sense trying to send out commands if the hub is already gone! */
995 /* power down for port */
996 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
997 USR_CLEAR_FEATURE
, UFS_PORT_POWER
, (ULONG
) num
);
998 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
1001 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1002 "PORT_POWER for port %ld failed: %s (%ld)",
1003 num
, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1004 KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", num
, ioerr
));
1008 KPRINTF(1, ("FreePipes\n"));
1009 psdFreePipe(nch
->nch_EP1Pipe
);
1010 psdFreePipe(nch
->nch_EP0Pipe
);
1011 psdFreeVec(nch
->nch_Downstream
);
1012 KPRINTF(1, ("Entering Forbid\n"));
1015 while((msg
= GetMsg(nch
->nch_CtrlMsgPort
)))
1019 DeleteMsgPort(nch
->nch_TaskMsgPort
);
1020 DeleteMsgPort(nch
->nch_CtrlMsgPort
);
1021 CloseLibrary(nch
->nch_Base
);
1022 nch
->nch_Task
= NULL
;
1023 if(nch
->nch_ReadySigTask
)
1025 Signal(nch
->nch_ReadySigTask
, 1L<<nch
->nch_ReadySignal
);
1027 KPRINTF(1, ("Really gone now!\n"));
1031 /* *** HUB Class *** */
1033 /* /// "nClearPortStatus()" */
1034 LONG
nClearPortStatus(struct NepClassHub
*nch
, UWORD port
)
1037 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
1038 USR_CLEAR_FEATURE
, UFS_C_PORT_CONNECTION
, (ULONG
) port
);
1039 if((ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0)))
1041 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1042 "CLEAR_PORT_FEATURE (C_PORT_CONNECTION) failed: %s (%ld)",
1043 psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1044 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1048 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
1049 USR_CLEAR_FEATURE
, UFS_C_PORT_ENABLE
, (ULONG
) port
);
1050 if((ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0)))
1052 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1053 "CLEAR_PORT_FEATURE (C_PORT_ENABLE) failed: %s (%ld)",
1054 psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1055 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1059 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
1060 USR_CLEAR_FEATURE
, UFS_C_PORT_SUSPEND
, (ULONG
) port
);
1061 if((ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0)))
1063 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1064 "CLEAR_PORT_FEATURE (C_PORT_SUSPEND) failed: %s (%ld)",
1065 psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1066 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1070 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
1071 USR_CLEAR_FEATURE
, UFS_C_PORT_OVER_CURRENT
, (ULONG
) port
);
1072 if((ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0)))
1074 /*psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1075 "CLEAR_PORT_FEATURE (C_OVER_CURRENT) failed: %s (%ld)",
1076 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);*/
1077 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1080 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
1081 USR_CLEAR_FEATURE
, UFS_C_PORT_RESET
, (ULONG
) port
);
1082 if((ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0)))
1084 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1085 "CLEAR_PORT_FEATURE (C_PORT_RESET) failed: %s (%ld)",
1086 psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1087 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1094 /* /// "nConfigurePort()" */
1095 struct PsdDevice
* nConfigurePort(struct NepClassHub
*nch
, UWORD port
)
1100 ULONG delaytime
= 10;
1101 struct UsbPortStatus uhps
;
1102 struct PsdDevice
*pd
;
1104 BOOL washighspeed
= FALSE
;
1105 BOOL islowspeed
= FALSE
;
1107 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_IN
|URTF_CLASS
|URTF_OTHER
,
1108 USR_GET_STATUS
, UFS_PORT_CONNECTION
, (ULONG
) port
);
1109 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, &uhps
, sizeof(struct UsbPortStatus
));
1110 uhps
.wPortStatus
= AROS_WORD2LE(uhps
.wPortStatus
);
1111 uhps
.wPortChange
= AROS_WORD2LE(uhps
.wPortChange
);
1114 if(uhps
.wPortStatus
& UPSF_PORT_ENABLE
)
1116 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
1117 USR_CLEAR_FEATURE
, UFS_PORT_ENABLE
, (ULONG
) port
);
1118 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
1121 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1122 "CLEAR_PORT_ENABLE failed: %s (%ld)",
1123 psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1124 KPRINTF(1, ("CLEAR_PORT_ENABLE failed %ld.\n", ioerr
));
1126 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1127 "Disabling port %ld.", port
);
1130 if(uhps
.wPortStatus
& UPSF_PORT_CONNECTION
)
1132 KPRINTF(1, ("There's something at port %ld!\n", port
));
1134 if((pd
= psdAllocDevice(nch
->nch_Hardware
)))
1136 psdLockWriteDevice(pd
);
1139 psdSetAttrs(PGA_DEVICE
, pd
,
1140 DA_HubDevice
, (ULONG
) nch
->nch_Device
,
1141 DA_IsConnected
, TRUE
,
1142 DA_AtHubPortNumber
, port
,
1144 if(uhps
.wPortStatus
& UPSF_PORT_LOW_SPEED
)
1146 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsLowspeed
, TRUE
, TAG_END
);
1147 KPRINTF(1, (" It's a lowspeed device!\n"));
1150 ObtainSemaphore(&nch
->nch_HubBase
->nh_Adr0Sema
);
1151 for(resetretries
= 0; resetretries
< 3; resetretries
++)
1153 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
1154 USR_SET_FEATURE
, UFS_PORT_RESET
, (ULONG
) port
);
1155 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
1158 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1159 "PORT_RESET for port %ld failed: %s (%ld)",
1160 port
, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1161 KPRINTF(1, ("PORT_RESET failed %ld.\n", ioerr
));
1164 for(delayretries
= 0; delayretries
< 500; delayretries
+= delaytime
)
1166 psdDelayMS(delaytime
);
1167 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_IN
|URTF_CLASS
|URTF_OTHER
,
1168 USR_GET_STATUS
, UFS_PORT_CONNECTION
, (ULONG
) port
);
1169 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, &uhps
, sizeof(struct UsbPortStatus
));
1170 uhps
.wPortStatus
= AROS_WORD2LE(uhps
.wPortStatus
);
1171 uhps
.wPortChange
= AROS_WORD2LE(uhps
.wPortChange
);
1174 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1175 "GET_PORT_CONNECTION for port %ld failed: %s (%ld)",
1176 port
, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1177 KPRINTF(1, ("GET_PORT_CONNECTION failed %ld.\n", ioerr
));
1180 if(!(uhps
.wPortStatus
& UPSF_PORT_CONNECTION
))
1184 if((uhps
.wPortStatus
&
1185 (UPSF_PORT_RESET
|UPSF_PORT_CONNECTION
|UPSF_PORT_ENABLE
|UPSF_PORT_POWER
|UPSF_PORT_OVER_CURRENT
)) ==
1186 (UPSF_PORT_CONNECTION
|UPSF_PORT_ENABLE
|UPSF_PORT_POWER
))
1188 if((uhps
.wPortStatus
& UPSF_PORT_HIGH_SPEED
) || washighspeed
)
1190 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsHighspeed
, TRUE
, TAG_END
);
1191 washighspeed
= TRUE
;
1192 KPRINTF(1, (" It's a highspeed device!\n"));
1194 IPTR needssplit
= 0;
1195 // inherit needs split from hub
1196 psdGetAttrs(PGA_DEVICE
, nch
->nch_Device
, DA_NeedsSplitTrans
, &needssplit
, TAG_END
);
1197 if(nch
->nch_IsUSB20
) /* this is a low/full speed device connected to a 2.0 hub! */
1201 psdSetAttrs(PGA_DEVICE
, pd
, DA_NeedsSplitTrans
, needssplit
, TAG_END
);
1203 nClearPortStatus(nch
, port
);
1204 psdDelayMS((ULONG
) (islowspeed
? 1000 : 100));
1205 if((pp
= psdAllocPipe(pd
, nch
->nch_TaskMsgPort
, NULL
)))
1207 if(psdEnumerateDevice(pp
))
1209 KPRINTF(1, (" Device successfully added!\n"));
1211 psdUnlockDevice(pd
);
1212 psdSendEvent(EHMB_ADDDEVICE
, pd
, NULL
);
1213 ReleaseSemaphore(&nch
->nch_HubBase
->nh_Adr0Sema
);
1220 if(!(uhps
.wPortStatus
& UPSF_PORT_RESET
))
1222 psdAddErrorMsg(RETURN_ERROR
, (STRPTR
) libname
,
1223 "Wrong port status %04lx for port %ld!",
1224 uhps
.wPortStatus
, port
);
1225 KPRINTF(1, ("Wrong port status %04lx for port %ld.\n", uhps
.wPortStatus
, port
));
1228 if(delayretries
> 20)
1233 if((uhps
.wPortStatus
&
1234 (UPSF_PORT_RESET
|UPSF_PORT_CONNECTION
|UPSF_PORT_ENABLE
|UPSF_PORT_POWER
|UPSF_PORT_OVER_CURRENT
|UPSF_PORT_LOW_SPEED
)) ==
1235 (UPSF_PORT_CONNECTION
|UPSF_PORT_POWER
|UPSF_PORT_LOW_SPEED
))
1237 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1238 "Strange port response, power-cycling port %ld",
1240 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
1241 USR_CLEAR_FEATURE
, UFS_PORT_POWER
, (ULONG
) port
);
1242 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
1245 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1246 "PORT_POWER for port %ld failed: %s (%ld)",
1247 port
, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1248 KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", port
, ioerr
));
1251 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
1252 USR_SET_FEATURE
, UFS_PORT_POWER
, (ULONG
) port
);
1253 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
1256 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1257 "PORT_POWER for port %ld failed: %s (%ld)",
1258 port
, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1259 KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", port
, ioerr
));
1261 psdDelayMS((ULONG
) nch
->nch_PwrGoodTime
+ 15);
1266 psdUnlockDevice(pd
);
1268 /* Disable port! It's too dangerous having a connection with
1269 crazy devices on the bus open */
1270 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
1271 USR_CLEAR_FEATURE
, UFS_PORT_ENABLE
, (ULONG
) port
);
1272 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
1275 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1276 "CLEAR_PORT_ENABLE failed: %s (%ld)",
1277 psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1278 KPRINTF(1, ("CLEAR_PORT_ENABLE failed %ld.\n", ioerr
));
1280 ReleaseSemaphore(&nch
->nch_HubBase
->nh_Adr0Sema
);
1281 nClearPortStatus(nch
, port
);
1284 KPRINTF(1, ("AllocDevice() failed.\n"));
1288 psdAddErrorMsg(RETURN_ERROR
, (STRPTR
) libname
,
1289 "GET_PORT_CONNECTION failed: %s (%ld)",
1290 psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1291 KPRINTF(1, ("GET_PORT_CONNECTION failed %ld.\n", ioerr
));
1297 /* /// "nHandleHubMethod()" */
1298 void nHandleHubMethod(struct NepClassHub
*nch
, struct NepHubMsg
*nhm
)
1301 struct PsdDevice
*pd
;
1302 nhm
->nhm_Result
= 0;
1303 switch(nhm
->nhm_MethodID
)
1305 case UCM_HubClaimAppBinding
:
1306 nhm
->nhm_Result
= (ULONG
) psdHubClaimAppBindingA((struct TagItem
*) nhm
->nhm_Params
[1]);
1309 case UCM_HubReleaseIfBinding
:
1311 psdHubReleaseIfBinding((struct PsdInterface
*) nhm
->nhm_Params
[1]);
1314 case UCM_HubReleaseDevBinding
:
1315 psdHubReleaseDevBinding((struct PsdDevice
*) nhm
->nhm_Params
[1]);
1318 case UCM_AttemptSuspendDevice
:
1321 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++)
1323 if((pd
= (nch
->nch_Downstream
)[num
-1]))
1325 res
&= psdSuspendDevice(pd
);
1330 // suspending of all downstream devices successful, so stop all activity, too.
1331 psdAbortPipe(nch
->nch_EP1Pipe
);
1332 nch
->nch_Running
= FALSE
;
1333 nhm
->nhm_Result
= TRUE
;
1338 case UCM_AttemptResumeDevice
:
1339 if(!nch
->nch_Running
)
1341 psdWaitPipe(nch
->nch_EP1Pipe
);
1342 psdSendPipe(nch
->nch_EP1Pipe
, nch
->nch_PortChanges
, 1);
1343 nch
->nch_Running
= TRUE
;
1345 nhm
->nhm_Result
= TRUE
;
1346 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++)
1348 if((pd
= (nch
->nch_Downstream
)[num
-1]))
1350 psdResumeDevice(pd
);
1355 case UCM_HubSuspendDevice
:
1356 nhm
->nhm_Result
= nHubSuspendDevice(nch
, (struct PsdDevice
*) nhm
->nhm_Params
[1]);
1359 case UCM_HubResumeDevice
:
1360 nhm
->nhm_Result
= nHubResumeDevice(nch
, (struct PsdDevice
*) nhm
->nhm_Params
[1]);
1367 /* /// "nHubSuspendDevice()" */
1368 BOOL
nHubSuspendDevice(struct NepClassHub
*nch
, struct PsdDevice
*pd
)
1370 APTR binding
= NULL
;
1373 BOOL result
= FALSE
;
1376 psdGetAttrs(PGA_DEVICE
, pd
,
1377 DA_Binding
, &binding
,
1378 DA_BindingClass
, &puc
,
1381 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++)
1383 if(pd
== (nch
->nch_Downstream
)[num
-1])
1385 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
1386 USR_SET_FEATURE
, UFS_PORT_SUSPEND
, num
);
1388 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
1391 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1392 "SET_PORT_SUSPEND failed: %s (%ld)",
1393 psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1394 KPRINTF(1, ("SET_PORT_SUSPEND failed %ld.\n", ioerr
));
1397 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsSuspended
, TRUE
, TAG_END
);
1398 psdSendEvent(EHMB_DEVSUSPENDED
, pd
, NULL
);
1406 /* /// "nHubResumeDevice()" */
1407 BOOL
nHubResumeDevice(struct NepClassHub
*nch
, struct PsdDevice
*pd
)
1410 BOOL result
= FALSE
;
1413 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++)
1415 if(pd
== (nch
->nch_Downstream
)[num
-1])
1417 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
1418 USR_CLEAR_FEATURE
, UFS_PORT_SUSPEND
, (ULONG
) num
);
1420 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
1423 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1424 "CLEAR_PORT_SUSPEND failed: %s (%ld)",
1425 psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1426 KPRINTF(1, ("CLEAR_PORT_SUSPEND failed %ld.\n", ioerr
));
1428 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsSuspended
, FALSE
, TAG_END
);
1429 psdSendEvent(EHMB_DEVRESUMED
, pd
, NULL
);