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 GM_UNIQUENAME(libInit
)(LIBBASETYPEPTR nh
)
17 KPRINTF(10, ("libInit nh: 0x%p SysBase: 0x%p\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 GM_UNIQUENAME(libExpunge
)(LIBBASETYPEPTR nh
)
38 KPRINTF(10, ("libExpunge nh: 0x%p SysBase: 0x%p\n", nh
, SysBase
));
39 CloseLibrary(UtilityBase
);
40 nh
->nh_UtilityBase
= NULL
;
44 ADD2INITLIB(GM_UNIQUENAME(libInit
), 0)
45 ADD2EXPUNGELIB(GM_UNIQUENAME(libExpunge
), 0)
49 * ***********************************************************************
50 * * Library functions *
51 * ***********************************************************************
54 /* /// "usbAttemptDeviceBinding()" */
55 struct NepClassHub
* GM_UNIQUENAME(usbAttemptDeviceBinding
)(struct NepHubBase
*nh
, struct PsdDevice
*pd
)
59 #ifdef AROS_USB30_CODE
60 IPTR issuperspeed
= 0;
62 KPRINTF(1, ("nepHubAttemptDeviceBinding(%p)\n", pd
));
64 if((ps
= OpenLibrary("poseidon.library", 4)))
66 psdGetAttrs(PGA_DEVICE
, pd
,
68 #ifdef AROS_USB30_CODE
69 DA_IsSuperspeed
, &issuperspeed
,
73 #ifdef AROS_USB30_CODE
74 if((devclass
== HUB_CLASSCODE
) && (!issuperspeed
))
76 if(devclass
== HUB_CLASSCODE
)
79 return(GM_UNIQUENAME(usbForceDeviceBinding
)(nh
, pd
));
86 /* /// "usbForceDeviceBinding()" */
87 struct NepClassHub
* GM_UNIQUENAME(usbForceDeviceBinding
)(struct NepHubBase
* nh
, struct PsdDevice
*pd
)
90 struct NepClassHub
*nch
;
95 KPRINTF(1, ("nepHubAttemptDeviceBinding(%p)\n", pd
));
97 if((ps
= OpenLibrary("poseidon.library", 4)))
99 psdGetAttrs(PGA_DEVICE
, pd
,
100 DA_ProductName
, &devname
,
102 if((nch
= psdAllocVec(sizeof(struct NepClassHub
))))
104 nch
->nch_HubBase
= nh
;
105 nch
->nch_Device
= pd
;
106 psdSafeRawDoFmt(buf
, 64, "hub.class<%p>", nch
);
107 nch
->nch_ReadySignal
= SIGB_SINGLE
;
108 nch
->nch_ReadySigTask
= FindTask(NULL
);
109 SetSignal(0, SIGF_SINGLE
);
110 if((tmptask
= psdSpawnSubTask(buf
, GM_UNIQUENAME(nHubTask
), nch
)))
112 psdBorrowLocksWait(tmptask
, 1UL<<nch
->nch_ReadySignal
);
115 nch
->nch_ReadySigTask
= NULL
;
116 //FreeSignal(nch->nch_ReadySignal);
117 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
118 "I'm in love with hub '%s'.",
122 AddTail(&nh
->nh_Bindings
, &nch
->nch_Node
);
128 nch
->nch_ReadySigTask
= NULL
;
129 //FreeSignal(nch->nch_ReadySignal);
138 /* /// "usbReleaseDeviceBinding()" */
139 void GM_UNIQUENAME(usbReleaseDeviceBinding
)(struct NepHubBase
*nh
, struct NepClassHub
*nch
)
144 KPRINTF(1, ("nepHubReleaseDeviceBinding(%p)\n", nch
));
145 if((ps
= OpenLibrary("poseidon.library", 4)))
148 nch
->nch_ReadySignal
= SIGB_SINGLE
;
149 nch
->nch_ReadySigTask
= FindTask(NULL
);
152 KPRINTF(1, ("Sending Break\n"));
153 Signal(nch
->nch_Task
, SIGBREAKF_CTRL_C
);
158 psdBorrowLocksWait(nch
->nch_Task
, 1UL<<nch
->nch_ReadySignal
);
160 KPRINTF(1, ("Task gone\n"));
161 //FreeSignal(nch->nch_ReadySignal);
162 psdGetAttrs(PGA_DEVICE
, nch
->nch_Device
, DA_ProductName
, &devname
, TAG_END
);
163 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
164 "Time to get rid of '%s'!",
167 Remove(&nch
->nch_Node
);
176 /* /// "usbGetAttrsA()" */
177 AROS_LH3(LONG
, usbGetAttrsA
,
178 AROS_LHA(ULONG
, type
, D0
),
179 AROS_LHA(APTR
, usbstruct
, A0
),
180 AROS_LHA(struct TagItem
*, tags
, A1
),
181 LIBBASETYPEPTR
, nh
, 5, hub
)
188 KPRINTF(1, ("nepHubGetAttrsA(%ld, %p, %p)\n", type
, usbstruct
, tags
));
192 if((ti
= FindTagItem(UCCA_Priority
, tags
)))
194 *((SIPTR
*) ti
->ti_Data
) = 0;
197 if((ti
= FindTagItem(UCCA_Description
, tags
)))
199 *((STRPTR
*) ti
->ti_Data
) = "Root/external hub base class";
202 if((ti
= FindTagItem(UCCA_HasClassCfgGUI
, tags
)))
204 *((IPTR
*) ti
->ti_Data
) = FALSE
;
207 if((ti
= FindTagItem(UCCA_HasBindingCfgGUI
, tags
)))
209 *((IPTR
*) ti
->ti_Data
) = FALSE
;
212 if((ti
= FindTagItem(UCCA_AfterDOSRestart
, tags
)))
214 *((IPTR
*) ti
->ti_Data
) = FALSE
;
217 if((ti
= FindTagItem(UCCA_UsingDefaultCfg
, tags
)))
219 *((IPTR
*) ti
->ti_Data
) = TRUE
;
222 if((ti
= FindTagItem(UCCA_SupportsSuspend
, tags
)))
224 *((IPTR
*) ti
->ti_Data
) = TRUE
;
230 if((ti
= FindTagItem(UCBA_UsingDefaultCfg
, tags
)))
232 *((IPTR
*) ti
->ti_Data
) = TRUE
;
242 /* /// "usbSetAttrsA()" */
243 AROS_LH3(LONG
, usbSetAttrsA
,
244 AROS_LHA(ULONG
, type
, D0
),
245 AROS_LHA(APTR
, usbstruct
, A0
),
246 AROS_LHA(struct TagItem
*, tags
, A1
),
247 LIBBASETYPEPTR
, nh
, 6, hub
)
255 /* /// "usbDoMethodA()" */
256 AROS_LH2(IPTR
, usbDoMethodA
,
257 AROS_LHA(ULONG
, methodid
, D0
),
258 AROS_LHA(IPTR
*, methoddata
, A1
),
259 LIBBASETYPEPTR
, nh
, 7, hub
)
263 struct NepClassHub
*nch
;
265 KPRINTF(1, ("Do Method %ld\n", methodid
));
268 case UCM_AttemptDeviceBinding
:
269 return((IPTR
) GM_UNIQUENAME(usbAttemptDeviceBinding
)(nh
, (struct PsdDevice
*) methoddata
[0]));
271 case UCM_ForceDeviceBinding
:
272 return((IPTR
) GM_UNIQUENAME(usbForceDeviceBinding
)(nh
, (struct PsdDevice
*) methoddata
[0]));
274 case UCM_ReleaseDeviceBinding
:
275 GM_UNIQUENAME(usbReleaseDeviceBinding
)(nh
, (struct NepClassHub
*) methoddata
[0]);
278 case UCM_HubPowerCyclePort
:
279 case UCM_HubDisablePort
:
281 struct PsdDevice
*pd
= (struct PsdDevice
*) methoddata
[0];
282 ULONG port
= (ULONG
) methoddata
[1];
285 KPRINTF(20, ("HubPowerCycle/DisablePort Params Null!\n"));
289 nch
= (struct NepClassHub
*) nh
->nh_Bindings
.lh_Head
;
290 while(nch
->nch_Node
.ln_Succ
)
292 if(nch
->nch_Device
== pd
)
294 KPRINTF(20, ("HubPowerCycle/DisablePort Dev found (port %ld)!\n", port
));
295 if(port
<= nch
->nch_NumPorts
)
297 nch
->nch_DisablePort
|= 1UL<<port
;
298 if(methodid
== UCM_HubPowerCyclePort
)
300 nch
->nch_PowerCycle
|= 1UL<<port
;
304 Signal(nch
->nch_Task
, (1L<<nch
->nch_TaskMsgPort
->mp_SigBit
));
311 nch
= (struct NepClassHub
*) nch
->nch_Node
.ln_Succ
;
317 case UCM_HubClassScan
:
319 nch
= (struct NepClassHub
*) methoddata
[0];
321 nch
->nch_ClassScan
= TRUE
;
324 Signal(nch
->nch_Task
, (1L<<nch
->nch_TaskMsgPort
->mp_SigBit
));
330 case UCM_AttemptSuspendDevice
:
331 case UCM_AttemptResumeDevice
:
332 case UCM_HubClaimAppBinding
:
333 case UCM_HubReleaseIfBinding
:
334 case UCM_HubReleaseDevBinding
:
335 case UCM_HubSuspendDevice
:
336 case UCM_HubResumeDevice
:
338 struct NepHubMsg nhm
;
340 nch
= (struct NepClassHub
*) methoddata
[0];
341 nhm
.nhm_Result
= (IPTR
) NULL
;
342 nhm
.nhm_MethodID
= methodid
;
343 nhm
.nhm_Params
= methoddata
;
344 if((ps
= OpenLibrary("poseidon.library", 4)))
346 if(nch
->nch_Task
== FindTask(NULL
))
348 // if we would send the message to ourself, we would deadlock, so handle this directly
349 GM_UNIQUENAME(nHandleHubMethod
)(nch
, &nhm
);
351 nhm
.nhm_Msg
.mn_ReplyPort
= CreateMsgPort();
352 nhm
.nhm_Msg
.mn_Length
= sizeof(struct NepHubMsg
);
354 if(nch
->nch_Task
&& nhm
.nhm_Msg
.mn_ReplyPort
)
356 PutMsg(nch
->nch_CtrlMsgPort
, &nhm
.nhm_Msg
);
358 while(!GetMsg(nhm
.nhm_Msg
.mn_ReplyPort
))
360 psdBorrowLocksWait(nch
->nch_Task
, 1UL<<nhm
.nhm_Msg
.mn_ReplyPort
->mp_SigBit
);
365 DeleteMsgPort(nhm
.nhm_Msg
.mn_ReplyPort
);
369 return(nhm
.nhm_Result
);
381 #define ps nch->nch_Base
383 /* /// "nHubTask()" */
384 AROS_UFH0(void, GM_UNIQUENAME(nHubTask
))
388 struct NepClassHub
*nch
;
394 struct UsbPortStatus uhps
;
395 struct UsbHubStatus uhhs
;
397 struct PsdDevice
*pd
;
399 struct NepHubMsg
*nhm
;
401 if((nch
= GM_UNIQUENAME(nAllocHub
)()))
404 if(nch
->nch_ReadySigTask
)
406 Signal(nch
->nch_ReadySigTask
, 1L<<nch
->nch_ReadySignal
);
410 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++)
412 if(((nch
->nch_Downstream
)[num
-1] = pd
= GM_UNIQUENAME(nConfigurePort
)(nch
, num
)))
414 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
415 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
416 "Detected device '%s' at port %ld. I like it.",
423 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
424 "Hub has added %ld device(s). That'll be fun!",
428 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++)
430 if((pd
= (nch
->nch_Downstream
)[num
-1]))
435 sigmask
= (1L<<nch
->nch_TaskMsgPort
->mp_SigBit
)|(1L<<nch
->nch_CtrlMsgPort
->mp_SigBit
)|SIGBREAKF_CTRL_C
;
436 nch
->nch_Running
= TRUE
;
437 nch
->nch_IOStarted
= FALSE
;
440 if(nch
->nch_Running
&& (!nch
->nch_IOStarted
))
442 psdSendPipe(nch
->nch_EP1Pipe
, nch
->nch_PortChanges
, (nch
->nch_NumPorts
+8)>>3);
443 nch
->nch_IOStarted
= TRUE
;
445 sigs
= Wait(sigmask
);
446 while((nhm
= (struct NepHubMsg
*) GetMsg(nch
->nch_CtrlMsgPort
)))
448 GM_UNIQUENAME(nHandleHubMethod
)(nch
, nhm
);
450 ReplyMsg((struct Message
*) nhm
);
452 if(nch
->nch_DisablePort
)
454 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++)
456 if((nch
->nch_DisablePort
) & (1L<<num
))
458 nch
->nch_DisablePort
&= ~(1L<<num
);
460 if((pd
= (nch
->nch_Downstream
)[num
-1]))
462 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsConnected
, FALSE
, TAG_END
);
463 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
464 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
465 "Zapping device '%s' at port %ld!",
468 psdSendEvent(EHMB_REMDEVICE
, pd
, NULL
);
469 (nch
->nch_Downstream
)[num
-1] = NULL
;
472 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
473 USR_CLEAR_FEATURE
, UFS_PORT_ENABLE
, (ULONG
) num
);
474 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
477 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
478 "CLEAR_PORT_ENABLE failed: %s (%ld)",
479 psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
480 KPRINTF(1, ("CLEAR_PORT_ENABLE failed %ld.\n", ioerr
));
483 if(nch
->nch_PowerCycle
& (1<<num
))
485 KPRINTF(2, ("Powercycle request for port %lu\n", num
));
486 nch
->nch_PowerCycle
&= ~(1L<<num
);
488 /* Wait for device to settle */
490 if(((nch
->nch_Downstream
)[num
-1] = pd
= GM_UNIQUENAME(nConfigurePort
)(nch
, num
)))
492 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
493 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
494 "Device '%s' returned. Happy happy joy joy.",
502 if(nch
->nch_ClassScan
)
504 nch
->nch_ClassScan
= FALSE
;
505 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++)
507 if((pd
= (nch
->nch_Downstream
)[num
-1]))
509 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
514 while((pp
= (struct PsdPipe
*) GetMsg(nch
->nch_TaskMsgPort
)))
516 if(pp
== nch
->nch_EP1Pipe
)
518 nch
->nch_IOStarted
= FALSE
;
519 ioerr
= psdGetPipeError(nch
->nch_EP1Pipe
);
520 if(ioerr
== UHIOERR_TIMEOUT
)
522 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
523 "Hub involuntarily gone! Disconnecting...");
524 psdSetAttrs(PGA_DEVICE
, nch
->nch_Device
,
525 DA_IsConnected
, FALSE
,
527 nch
->nch_PortChanges
[0] = 0xff;
528 nch
->nch_PortChanges
[1] = 0xff;
529 nch
->nch_PortChanges
[2] = 0xff;
530 nch
->nch_PortChanges
[3] = 0xff;
531 sigs
|= SIGBREAKF_CTRL_C
;
533 if((!ioerr
) || (ioerr
== UHIOERR_TIMEOUT
))
535 KPRINTF(2, ("Port changed at %p, Numports=%ld!\n", nch
->nch_PortChanges
[0], nch
->nch_NumPorts
));
537 if(nch
->nch_PortChanges
[0] & 1)
539 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_IN
|URTF_CLASS
|URTF_DEVICE
,
540 USR_GET_STATUS
, 0, 0);
541 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, &uhhs
, sizeof(struct UsbHubStatus
));
542 uhhs
.wHubStatus
= AROS_WORD2LE(uhhs
.wHubStatus
);
543 uhhs
.wHubChange
= AROS_WORD2LE(uhhs
.wHubChange
);
546 if(uhhs
.wHubStatus
& UHSF_OVER_CURRENT
)
548 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
549 "Hub over-current situation detected! Unpowering ALL ports!");
550 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++)
552 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
553 USR_CLEAR_FEATURE
, UFS_PORT_POWER
, (ULONG
) num
);
554 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
557 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
558 "PORT_POWER for port %ld failed: %s (%ld)",
559 num
, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
560 KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", num
, ioerr
));
563 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
564 USR_CLEAR_FEATURE
, UFS_C_PORT_OVER_CURRENT
, (ULONG
) num
);
565 psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
567 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_DEVICE
,
568 USR_CLEAR_FEATURE
, UFS_C_HUB_OVER_CURRENT
, 0);
569 psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
571 if(uhhs
.wHubChange
& UHSF_LOCAL_POWER_LOST
)
573 struct PsdConfig
*pc
= NULL
;
574 struct PsdHardware
*phw
= NULL
;
575 psdGetAttrs(PGA_DEVICE
, nch
->nch_Device
,
579 if(uhhs
.wHubStatus
& UHSF_LOCAL_POWER_LOST
)
581 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
582 "Hub is no longer self-powered! Low power conditions may occur.");
586 psdSetAttrs(PGA_CONFIG
, pc
, CA_SelfPowered
, FALSE
, TAG_END
);
587 psdCalculatePower(phw
);
590 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
591 "Hub is now self-powered! Yay!");
594 psdSetAttrs(PGA_CONFIG
, pc
, CA_SelfPowered
, TRUE
, TAG_END
);
595 psdCalculatePower(phw
);
598 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_DEVICE
,
599 USR_CLEAR_FEATURE
, UFS_C_HUB_LOCAL_POWER
, 0);
600 psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
605 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++)
607 if(nch
->nch_PortChanges
[num
>>3] & (1L<<(num
& 7)))
609 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_IN
|URTF_CLASS
|URTF_OTHER
,
610 USR_GET_STATUS
, 0, (ULONG
) num
);
611 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, &uhps
, sizeof(struct UsbPortStatus
));
612 uhps
.wPortStatus
= AROS_WORD2LE(uhps
.wPortStatus
);
613 uhps
.wPortChange
= AROS_WORD2LE(uhps
.wPortChange
);
614 if(ioerr
== UHIOERR_TIMEOUT
)
616 uhps
.wPortStatus
= 0;
617 uhps
.wPortChange
= 0xffff;
620 GM_UNIQUENAME(nClearPortStatus
)(nch
, num
);
624 pd
= (nch
->nch_Downstream
)[num
-1];
625 if(uhps
.wPortStatus
& UPSF_PORT_OVER_CURRENT
)
629 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
633 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
634 "Over-current situation detected with %s at port %ld! Unpowering port!",
636 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
637 USR_CLEAR_FEATURE
, UFS_PORT_POWER
, (ULONG
) num
);
638 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
641 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
642 "PORT_POWER for port %ld failed: %s (%ld)",
643 num
, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
644 KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", num
, ioerr
));
647 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
648 USR_CLEAR_FEATURE
, UFS_C_PORT_OVER_CURRENT
, (ULONG
) num
);
649 psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
651 if(uhps
.wPortChange
& UPSF_PORT_SUSPEND
)
653 if((!(uhps
.wPortStatus
& UPSF_PORT_SUSPEND
)) && pd
)
656 psdGetAttrs(PGA_DEVICE
, pd
, DA_IsSuspended
, &oldsusp
, TAG_END
);
657 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsSuspended
, FALSE
, TAG_END
);
658 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
661 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
662 "Device '%s' at port %ld resumed from remote!",
664 psdSendEvent(EHMB_DEVRESUMED
, pd
, NULL
);
665 psdResumeBindings(pd
);
668 else if((uhps
.wPortStatus
& UPSF_PORT_SUSPEND
) && pd
)
670 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsSuspended
, FALSE
, TAG_END
);
671 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
672 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
673 "Device '%s' at port %ld suspended!",
676 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
677 "Bogus suspend/resume change on port %ld.",
681 if(uhps
.wPortChange
& UPSF_PORT_CONNECTION
)
684 if((!(uhps
.wPortStatus
& UPSF_PORT_CONNECTION
)) && pd
)
686 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsConnected
, FALSE
, TAG_END
);
687 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
688 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
689 "Device '%s' at port %ld is gone!",
692 psdSendEvent(EHMB_REMDEVICE
, pd
, NULL
);
693 (nch
->nch_Downstream
)[num
-1] = NULL
;
697 if((uhps
.wPortStatus
& UPSF_PORT_CONNECTION
) && (!pd
))
699 /* Wait for device to settle */
701 if(((nch
->nch_Downstream
)[num
-1] = pd
= GM_UNIQUENAME(nConfigurePort
)(nch
, num
)))
703 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
704 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
705 "New device '%s' at port %ld. Very nice.",
714 /* Bail out on time out. */
715 if(nch
->nch_PortChanges
[0] == 0xff)
721 if(ioerr
!= IOERR_ABORTED
)
723 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
724 "Something weird happened to the status packet, it failed: %s (%ld)",
725 psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
731 KPRINTF(20, ("Bogus message received!\n"));
734 } while(!(sigs
& SIGBREAKF_CTRL_C
));
735 KPRINTF(20, ("Going down the river!\n"));
736 if(nch
->nch_IOStarted
)
738 psdAbortPipe(nch
->nch_EP1Pipe
);
739 psdWaitPipe(nch
->nch_EP1Pipe
);
741 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
, "Oh no! I've been shot! Arrggghh...");
742 GM_UNIQUENAME(nFreeHub
)(nch
);
748 /* /// "nAllocHub()" */
749 struct NepClassHub
* GM_UNIQUENAME(nAllocHub
)(void)
751 struct UsbHubDesc
*uhd
;
752 struct Task
*thistask
;
753 struct NepClassHub
*nch
;
754 struct UsbHubStatus uhhs
;
759 #ifdef AROS_USB30_CODE
764 IPTR ishighspeed
= 0;
767 BOOL overcurrent
= FALSE
;
769 thistask
= FindTask(NULL
);
770 nch
= thistask
->tc_UserData
;
773 if(!(nch
->nch_Base
= OpenLibrary("poseidon.library", 4)))
779 psdGetAttrs(PGA_DEVICE
, nch
->nch_Device
,
780 DA_Hardware
, &nch
->nch_Hardware
,
781 DA_IsHighspeed
, &ishighspeed
,
782 DA_ProductID
, &prodid
,
783 DA_VendorID
, &vendid
,
784 DA_HubDevice
, &parenthub
,
787 nch
->nch_IsRootHub
= (parenthub
? FALSE
: TRUE
);
788 nch
->nch_IsUSB20
= ishighspeed
;
789 // try to select multi TT interface first
790 nch
->nch_Interface
= psdFindInterface(nch
->nch_Device
, NULL
,
791 IFA_Class
, HUB_CLASSCODE
,
793 IFA_AlternateNum
, 0xffffffff,
795 if(!nch
->nch_Interface
)
798 nch
->nch_Interface
= psdFindInterface(nch
->nch_Device
, NULL
,
799 IFA_Class
, HUB_CLASSCODE
,
802 if((vendid
== 0x05E3) && ishighspeed
)
804 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
, "Genesys Logic hubs are broken and will cause failures with USB 2.0 devices.");
805 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
, "If you encounter problems, try the device without the hub.");
806 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
, "If this solves the problem, you need to buy a different USB 2.0 hub.");
809 if(!nch
->nch_Interface
)
811 KPRINTF(1, ("Ooops!?! No interfaces defined?\n"));
814 nch
->nch_EP1
= psdFindEndpoint(nch
->nch_Interface
, NULL
,
816 EA_TransferType
, USEAF_INTERRUPT
,
821 psdAddErrorMsg(RETURN_FAIL
, (STRPTR
) libname
, "Ooops!?! No endpoints defined?");
822 KPRINTF(1, ("Ooops!?! No Endpoints defined?\n"));
825 if((nch
->nch_CtrlMsgPort
= CreateMsgPort()))
827 if((nch
->nch_TaskMsgPort
= CreateMsgPort()))
829 if((nch
->nch_EP0Pipe
= psdAllocPipe(nch
->nch_Device
, nch
->nch_TaskMsgPort
, NULL
)))
831 psdSetAttrs(PGA_PIPE
, nch
->nch_EP0Pipe
,
832 PPA_NakTimeout
, TRUE
,
833 PPA_NakTimeoutTime
, 1000,
835 psdSetAltInterface(nch
->nch_EP0Pipe
, nch
->nch_Interface
);
836 if((nch
->nch_EP1Pipe
= psdAllocPipe(nch
->nch_Device
, nch
->nch_TaskMsgPort
, nch
->nch_EP1
)))
838 psdSetAttrs(PGA_PIPE
, nch
->nch_EP1Pipe
,
839 PPA_AllowRuntPackets
, TRUE
,
841 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_IN
|URTF_CLASS
|URTF_DEVICE
,
842 USR_GET_DESCRIPTOR
, UDT_HUB
<<8, 0);
843 #ifdef AROS_USB30_CODE
844 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, &buf
, 2);
846 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, &buf
, 1);
848 if((!ioerr
) || (ioerr
== UHIOERR_OVERFLOW
))
850 #ifdef AROS_USB30_CODE
855 if((uhd
= psdAllocVec(len
)))
857 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, uhd
, len
);
858 #ifdef AROS_USB30_CODE
859 if(buf
[1]!=UDT_SSHUB
) {
863 nch
->nch_NumPorts
= uhd
->bNbrPorts
;
864 nch
->nch_HubAttr
= AROS_WORD2LE(uhd
->wHubCharacteristics
);
865 nch
->nch_PwrGoodTime
= uhd
->bPwrOn2PwrGood
<<1;
866 nch
->nch_HubCurrent
= uhd
->bHubContrCurrent
;
867 nch
->nch_Removable
= 0;
868 if(nch
->nch_HubAttr
& UHCM_THINK_TIME
)
870 psdSetAttrs(PGA_DEVICE
, nch
->nch_Device
,
871 DA_HubThinkTime
, (nch
->nch_HubAttr
& UHCM_THINK_TIME
)>>UHCS_THINK_TIME
,
875 for(num
= 0; num
< ((nch
->nch_NumPorts
+ 7)>>3); num
++)
877 nch
->nch_Removable
|= ((&uhd
->DeviceRemovable
)[num
])<<(num
<<3);
879 KPRINTF(2, ("Hub with %ld ports\n"
880 " Characteristics 0x%04lx\n"
881 " PowerGood after %ld ms\n"
882 " Power consumption %ld mA\n",
885 nch
->nch_PwrGoodTime
, nch
->nch_HubCurrent
));
888 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_IN
|URTF_CLASS
|URTF_DEVICE
,
889 USR_GET_STATUS
, 0, 0);
890 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, &uhhs
, sizeof(struct UsbHubStatus
));
891 uhhs
.wHubStatus
= AROS_WORD2LE(uhhs
.wHubStatus
);
892 uhhs
.wHubChange
= AROS_WORD2LE(uhhs
.wHubChange
);
895 struct PsdConfig
*pc
= NULL
;
896 struct PsdHardware
*phw
= NULL
;
897 if(uhhs
.wHubStatus
& UHSF_OVER_CURRENT
)
899 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
900 "Hub over-current situation detected! Resolve this first!");
901 //overcurrent = TRUE;
904 psdGetAttrs(PGA_DEVICE
, nch
->nch_Device
,
908 if(uhhs
.wHubStatus
& UHSF_LOCAL_POWER_LOST
)
912 psdSetAttrs(PGA_CONFIG
, pc
, CA_SelfPowered
, FALSE
, TAG_END
);
913 psdCalculatePower(phw
);
918 psdSetAttrs(PGA_CONFIG
, pc
, CA_SelfPowered
, TRUE
, TAG_END
);
919 psdCalculatePower(phw
);
925 if((nch
->nch_Downstream
= psdAllocVec((ULONG
) nch
->nch_NumPorts
*sizeof(APTR
))))
927 /*for(num = 1; num <= nch->nch_NumPorts; num++)
929 GM_UNIQUENAME(nClearPortStatus)(nch, num);
932 KPRINTF(2, ("Powering up ports...\n"));
933 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++)
935 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
936 USR_SET_FEATURE
, UFS_PORT_POWER
, (ULONG
) num
);
937 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
940 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
941 "PORT_POWER for port %ld failed: %s (%ld)",
942 num
, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
943 KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", num
, ioerr
));
946 psdDelayMS((ULONG
) nch
->nch_PwrGoodTime
+ 15);
948 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
949 "Hub with %ld ports successfully configured.",
952 KPRINTF(10, ("%s ready!\n", thistask
->tc_Node
.ln_Name
));
953 nch
->nch_Task
= thistask
;
956 KPRINTF(1, ("No downstream port array memory!\n"));
961 psdAddErrorMsg(RETURN_FAIL
, (STRPTR
) libname
,
962 "GET_HUB_DESCRIPTOR (%ld) failed: %s (%ld)",
963 len
, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
964 KPRINTF(1, ("GET_HUB_DESCRIPTOR (%ld) failed %ld!\n", len
, ioerr
));
966 #ifdef AROS_USB30_CODE
969 KPRINTF(1, ("GET_HUB_DESCRIPTOR (%ld) failed! Descriptor is wrong type\n", len
));
973 KPRINTF(1, ("No Hub Descriptor memory!\n"));
976 psdAddErrorMsg(RETURN_FAIL
, (STRPTR
) libname
,
977 "GET_HUB_DESCRIPTOR (%ld) failed: %s (%ld)",
978 1, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
979 KPRINTF(1, ("GET_HUB_DESCRIPTOR (1) failed %ld!\n", ioerr
));
981 psdFreePipe(nch
->nch_EP1Pipe
);
983 psdFreePipe(nch
->nch_EP0Pipe
);
985 DeleteMsgPort(nch
->nch_TaskMsgPort
);
987 DeleteMsgPort(nch
->nch_CtrlMsgPort
);
990 CloseLibrary(nch
->nch_Base
);
992 nch
->nch_Task
= NULL
;
993 if(nch
->nch_ReadySigTask
)
995 Signal(nch
->nch_ReadySigTask
, 1L<<nch
->nch_ReadySignal
);
1001 /* /// "nFreeHub()" */
1002 void GM_UNIQUENAME(nFreeHub
)(struct NepClassHub
*nch
)
1006 struct PsdDevice
*pd
;
1009 struct Message
*msg
;
1011 KPRINTF(1, ("FreeHub\n"));
1012 psdGetAttrs(PGA_DEVICE
, nch
->nch_Device
, DA_IsConnected
, &isconnected
, TAG_END
);
1013 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++)
1015 KPRINTF(1, ("Iterating Port %ld\n", num
));
1016 /* Remove downstream device */
1017 pd
= (nch
->nch_Downstream
)[num
-1];
1022 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsConnected
, FALSE
, TAG_END
);
1024 psdGetAttrs(PGA_DEVICE
, pd
, DA_ProductName
, &devname
, TAG_END
);
1025 psdAddErrorMsg(RETURN_OK
, (STRPTR
) libname
,
1026 "My death killed device '%s' at port %ld!",
1028 KPRINTF(1, ("FreeDevice %p\n", pd
));
1030 psdSendEvent(EHMB_REMDEVICE
, pd
, NULL
);
1031 (nch
->nch_Downstream
)[num
-1] = NULL
;
1033 /* There's no sense trying to send out commands if the hub is already gone! */
1036 /* power down for port */
1037 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
1038 USR_CLEAR_FEATURE
, UFS_PORT_POWER
, (ULONG
) num
);
1039 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
1042 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1043 "PORT_POWER for port %ld failed: %s (%ld)",
1044 num
, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1045 KPRINTF(1, ("PORT_POWER for port %ld failed %ld!\n", num
, ioerr
));
1049 KPRINTF(1, ("FreePipes\n"));
1050 psdFreePipe(nch
->nch_EP1Pipe
);
1051 psdFreePipe(nch
->nch_EP0Pipe
);
1052 psdFreeVec(nch
->nch_Downstream
);
1053 KPRINTF(1, ("Entering Forbid\n"));
1056 while((msg
= GetMsg(nch
->nch_CtrlMsgPort
)))
1060 DeleteMsgPort(nch
->nch_TaskMsgPort
);
1061 DeleteMsgPort(nch
->nch_CtrlMsgPort
);
1062 CloseLibrary(nch
->nch_Base
);
1063 nch
->nch_Task
= NULL
;
1064 if(nch
->nch_ReadySigTask
)
1066 Signal(nch
->nch_ReadySigTask
, 1L<<nch
->nch_ReadySignal
);
1068 KPRINTF(1, ("Really gone now!\n"));
1072 /* *** HUB Class *** */
1074 /* /// "nClearPortStatus()" */
1075 LONG
GM_UNIQUENAME(nClearPortStatus
)(struct NepClassHub
*nch
, UWORD port
)
1078 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
1079 USR_CLEAR_FEATURE
, UFS_C_PORT_CONNECTION
, (ULONG
) port
);
1080 if((ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0)))
1082 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1083 "CLEAR_PORT_FEATURE (C_PORT_CONNECTION) failed: %s (%ld)",
1084 psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1085 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1089 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
1090 USR_CLEAR_FEATURE
, UFS_C_PORT_ENABLE
, (ULONG
) port
);
1091 if((ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0)))
1093 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1094 "CLEAR_PORT_FEATURE (C_PORT_ENABLE) failed: %s (%ld)",
1095 psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1096 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1100 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
1101 USR_CLEAR_FEATURE
, UFS_C_PORT_SUSPEND
, (ULONG
) port
);
1102 if((ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0)))
1104 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1105 "CLEAR_PORT_FEATURE (C_PORT_SUSPEND) failed: %s (%ld)",
1106 psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1107 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1111 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
1112 USR_CLEAR_FEATURE
, UFS_C_PORT_OVER_CURRENT
, (ULONG
) port
);
1113 if((ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0)))
1115 /*psdAddErrorMsg(RETURN_WARN, (STRPTR) libname,
1116 "CLEAR_PORT_FEATURE (C_OVER_CURRENT) failed: %s (%ld)",
1117 psdNumToStr(NTS_IOERR, ioerr, "unknown"), ioerr);*/
1118 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1121 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
1122 USR_CLEAR_FEATURE
, UFS_C_PORT_RESET
, (ULONG
) port
);
1123 if((ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0)))
1125 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1126 "CLEAR_PORT_FEATURE (C_PORT_RESET) failed: %s (%ld)",
1127 psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1128 KPRINTF(10, ("Some error occurred clearing hub status bits!\n"));
1135 /* /// "nConfigurePort()" */
1136 struct PsdDevice
* GM_UNIQUENAME(nConfigurePort
)(struct NepClassHub
*nch
, UWORD port
)
1141 ULONG delaytime
= 10;
1142 struct UsbPortStatus uhps
;
1143 struct PsdDevice
*pd
;
1145 BOOL washighspeed
= FALSE
;
1146 BOOL islowspeed
= FALSE
;
1148 KPRINTF(2, ("Configuring port %ld of hub 0x%p\n", port
, nch
));
1150 uhps
.wPortStatus
= 0xDEAD;
1151 uhps
.wPortChange
= 0xDA1A;
1153 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_IN
|URTF_CLASS
|URTF_OTHER
,
1154 USR_GET_STATUS
, UFS_PORT_CONNECTION
, (ULONG
) port
);
1155 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, &uhps
, sizeof(struct UsbPortStatus
));
1156 uhps
.wPortStatus
= AROS_WORD2LE(uhps
.wPortStatus
);
1157 uhps
.wPortChange
= AROS_WORD2LE(uhps
.wPortChange
);
1160 KPRINTF(2, ("Status 0x%04x, change 0x%04x\n", uhps
.wPortStatus
, uhps
.wPortChange
));
1162 if(uhps
.wPortStatus
& UPSF_PORT_ENABLE
)
1164 KPRINTF(2, ("Disabling port %u\n", port
));
1166 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
1167 USR_CLEAR_FEATURE
, UFS_PORT_ENABLE
, (ULONG
) port
);
1168 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
1171 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1172 "CLEAR_PORT_ENABLE failed: %s (%ld)",
1173 psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1174 KPRINTF(1, ("CLEAR_PORT_ENABLE failed %ld.\n", ioerr
));
1176 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1177 "Disabling port %ld.", port
);
1180 if(uhps
.wPortStatus
& UPSF_PORT_CONNECTION
)
1182 KPRINTF(2, ("There's something at port %ld!\n", port
));
1184 if((pd
= psdAllocDevice(nch
->nch_Hardware
)))
1186 psdLockWriteDevice(pd
);
1189 psdSetAttrs(PGA_DEVICE
, pd
,
1190 DA_HubDevice
, nch
->nch_Device
,
1191 DA_IsConnected
, TRUE
,
1192 DA_AtHubPortNumber
, port
,
1194 if(uhps
.wPortStatus
& UPSF_PORT_LOW_SPEED
)
1196 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsLowspeed
, TRUE
, TAG_END
);
1197 KPRINTF(2, (" It's a lowspeed device!\n"));
1200 ObtainSemaphore(&nch
->nch_HubBase
->nh_Adr0Sema
);
1201 for(resetretries
= 0; resetretries
< 3; resetretries
++)
1203 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
1204 USR_SET_FEATURE
, UFS_PORT_RESET
, (ULONG
) port
);
1205 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
1208 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1209 "PORT_RESET for port %ld failed: %s (%ld)",
1210 port
, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1211 KPRINTF(1, ("PORT_RESET failed %ld.\n", ioerr
));
1214 if(nch
->nch_IsRootHub
)
1216 // Root hubs need 50ms minimum delay
1219 for(delayretries
= 0; delayretries
< 500; delayretries
+= delaytime
)
1221 psdDelayMS(delaytime
);
1222 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_IN
|URTF_CLASS
|URTF_OTHER
,
1223 USR_GET_STATUS
, UFS_PORT_CONNECTION
, (ULONG
) port
);
1224 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, &uhps
, sizeof(struct UsbPortStatus
));
1225 uhps
.wPortStatus
= AROS_WORD2LE(uhps
.wPortStatus
);
1226 uhps
.wPortChange
= AROS_WORD2LE(uhps
.wPortChange
);
1229 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1230 "GET_PORT_CONNECTION for port %ld failed: %s (%ld)",
1231 port
, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1232 KPRINTF(1, ("GET_PORT_CONNECTION failed %ld.\n", ioerr
));
1235 KPRINTF(2, ("After reset: status 0x%04x, change 0x%04x\n", uhps
.wPortStatus
, uhps
.wPortChange
));
1236 if(!(uhps
.wPortStatus
& UPSF_PORT_CONNECTION
))
1240 if((uhps
.wPortStatus
&
1241 (UPSF_PORT_RESET
|UPSF_PORT_CONNECTION
|UPSF_PORT_ENABLE
|UPSF_PORT_POWER
|UPSF_PORT_OVER_CURRENT
)) ==
1242 (UPSF_PORT_CONNECTION
|UPSF_PORT_ENABLE
|UPSF_PORT_POWER
))
1244 if((uhps
.wPortStatus
& UPSF_PORT_HIGH_SPEED
) || washighspeed
)
1246 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsHighspeed
, TRUE
, TAG_END
);
1247 washighspeed
= TRUE
;
1248 KPRINTF(2, (" It's a highspeed device!\n"));
1252 IPTR needssplit
= 0;
1254 /* Some hubs (Apple Keyboard bultin hub) report speed correctly only after reset */
1255 if (uhps
.wPortStatus
& UPSF_PORT_LOW_SPEED
)
1257 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsLowspeed
, TRUE
, TAG_END
);
1258 KPRINTF(2, (" It's a lowspeed device!\n"));
1262 // inherit needs split from hub
1263 psdGetAttrs(PGA_DEVICE
, nch
->nch_Device
, DA_NeedsSplitTrans
, &needssplit
, TAG_END
);
1264 KPRINTF(2, (" Needs split transfers: %ld\n", needssplit
));
1265 if(nch
->nch_IsUSB20
) /* this is a low/full speed device connected to a 2.0 hub! */
1267 KPRINTF(2, (" Enforcing split transfers\n"));
1270 psdSetAttrs(PGA_DEVICE
, pd
, DA_NeedsSplitTrans
, needssplit
, TAG_END
);
1272 GM_UNIQUENAME(nClearPortStatus
)(nch
, port
);
1273 psdDelayMS((ULONG
) (islowspeed
? 1000 : 100));
1274 if((pp
= psdAllocPipe(pd
, nch
->nch_TaskMsgPort
, NULL
)))
1276 if(psdEnumerateDevice(pp
))
1278 KPRINTF(2, (" Device successfully added!\n"));
1280 psdUnlockDevice(pd
);
1281 psdSendEvent(EHMB_ADDDEVICE
, pd
, NULL
);
1282 ReleaseSemaphore(&nch
->nch_HubBase
->nh_Adr0Sema
);
1289 if(!(uhps
.wPortStatus
& UPSF_PORT_RESET
))
1291 psdAddErrorMsg(RETURN_ERROR
, (STRPTR
) libname
,
1292 "Wrong port status %04lx for port %ld!",
1293 uhps
.wPortStatus
, port
);
1294 KPRINTF(2, ("Wrong port status %04lx for port %ld.\n", uhps
.wPortStatus
, port
));
1297 if(delayretries
> 20)
1302 if((uhps
.wPortStatus
&
1303 (UPSF_PORT_RESET
|UPSF_PORT_CONNECTION
|UPSF_PORT_ENABLE
|UPSF_PORT_POWER
|UPSF_PORT_OVER_CURRENT
|UPSF_PORT_LOW_SPEED
)) ==
1304 (UPSF_PORT_CONNECTION
|UPSF_PORT_POWER
|UPSF_PORT_LOW_SPEED
))
1306 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1307 "Strange port response, power-cycling port %ld",
1309 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
1310 USR_CLEAR_FEATURE
, UFS_PORT_ENABLE
, (ULONG
) port
);
1311 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
1314 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1315 "CLEAR_PORT_ENABLE for port %ld failed: %s (%ld)",
1316 port
, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1317 KPRINTF(1, ("CLEAR_PORT_ENABLE for port %ld failed %ld!\n", port
, ioerr
));
1320 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
1321 USR_CLEAR_FEATURE
, UFS_PORT_POWER
, (ULONG
) port
);
1322 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
1325 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1326 "CLEAR_PORT_POWER for port %ld failed: %s (%ld)",
1327 port
, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1328 KPRINTF(1, ("CLEAR_PORT_POWER for port %ld failed %ld!\n", port
, ioerr
));
1331 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
1332 USR_SET_FEATURE
, UFS_PORT_POWER
, (ULONG
) port
);
1333 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
1336 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1337 "SET_PORT_POWER for port %ld failed: %s (%ld)",
1338 port
, psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1339 KPRINTF(1, ("SET_PORT_POWER for port %ld failed %ld!\n", port
, ioerr
));
1341 psdDelayMS((ULONG
) nch
->nch_PwrGoodTime
+ 15);
1346 psdUnlockDevice(pd
);
1348 /* Disable port! It's too dangerous having a connection with
1349 crazy devices on the bus open */
1350 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
1351 USR_CLEAR_FEATURE
, UFS_PORT_ENABLE
, (ULONG
) port
);
1352 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
1355 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1356 "CLEAR_PORT_ENABLE failed: %s (%ld)",
1357 psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1358 KPRINTF(1, ("CLEAR_PORT_ENABLE failed %ld.\n", ioerr
));
1360 ReleaseSemaphore(&nch
->nch_HubBase
->nh_Adr0Sema
);
1361 GM_UNIQUENAME(nClearPortStatus
)(nch
, port
);
1364 KPRINTF(1, ("AllocDevice() failed.\n"));
1368 psdAddErrorMsg(RETURN_ERROR
, (STRPTR
) libname
,
1369 "GET_PORT_CONNECTION failed: %s (%ld)",
1370 psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1371 KPRINTF(1, ("GET_PORT_CONNECTION failed %ld.\n", ioerr
));
1377 /* /// "nHandleHubMethod()" */
1378 void GM_UNIQUENAME(nHandleHubMethod
)(struct NepClassHub
*nch
, struct NepHubMsg
*nhm
)
1381 struct PsdDevice
*pd
;
1382 nhm
->nhm_Result
= 0;
1383 switch(nhm
->nhm_MethodID
)
1385 case UCM_HubClaimAppBinding
:
1386 nhm
->nhm_Result
= (IPTR
) psdHubClaimAppBindingA((struct TagItem
*) nhm
->nhm_Params
[1]);
1389 case UCM_HubReleaseIfBinding
:
1391 psdHubReleaseIfBinding((struct PsdInterface
*) nhm
->nhm_Params
[1]);
1394 case UCM_HubReleaseDevBinding
:
1395 psdHubReleaseDevBinding((struct PsdDevice
*) nhm
->nhm_Params
[1]);
1398 case UCM_AttemptSuspendDevice
:
1401 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++)
1403 if((pd
= (nch
->nch_Downstream
)[num
-1]))
1405 res
&= psdSuspendDevice(pd
);
1410 // suspending of all downstream devices successful, so stop all activity, too.
1411 psdAbortPipe(nch
->nch_EP1Pipe
);
1412 nch
->nch_Running
= FALSE
;
1413 nhm
->nhm_Result
= TRUE
;
1418 case UCM_AttemptResumeDevice
:
1419 if(!nch
->nch_Running
)
1421 psdWaitPipe(nch
->nch_EP1Pipe
);
1422 psdSendPipe(nch
->nch_EP1Pipe
, nch
->nch_PortChanges
, (nch
->nch_NumPorts
+8)>>3);
1423 nch
->nch_Running
= TRUE
;
1425 nhm
->nhm_Result
= TRUE
;
1426 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++)
1428 if((pd
= (nch
->nch_Downstream
)[num
-1]))
1430 psdResumeDevice(pd
);
1435 case UCM_HubSuspendDevice
:
1436 nhm
->nhm_Result
= GM_UNIQUENAME(nHubSuspendDevice
)(nch
, (struct PsdDevice
*) nhm
->nhm_Params
[1]);
1439 case UCM_HubResumeDevice
:
1440 nhm
->nhm_Result
= GM_UNIQUENAME(nHubResumeDevice
)(nch
, (struct PsdDevice
*) nhm
->nhm_Params
[1]);
1447 /* /// "nHubSuspendDevice()" */
1448 BOOL
GM_UNIQUENAME(nHubSuspendDevice
)(struct NepClassHub
*nch
, struct PsdDevice
*pd
)
1450 APTR binding
= NULL
;
1453 BOOL result
= FALSE
;
1456 psdGetAttrs(PGA_DEVICE
, pd
,
1457 DA_Binding
, &binding
,
1458 DA_BindingClass
, &puc
,
1461 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++)
1463 if(pd
== (nch
->nch_Downstream
)[num
-1])
1465 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
1466 USR_SET_FEATURE
, UFS_PORT_SUSPEND
, num
);
1468 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
1471 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1472 "SET_PORT_SUSPEND failed: %s (%ld)",
1473 psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1474 KPRINTF(1, ("SET_PORT_SUSPEND failed %ld.\n", ioerr
));
1477 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsSuspended
, TRUE
, TAG_END
);
1478 psdSendEvent(EHMB_DEVSUSPENDED
, pd
, NULL
);
1486 /* /// "nHubResumeDevice()" */
1487 BOOL
GM_UNIQUENAME(nHubResumeDevice
)(struct NepClassHub
*nch
, struct PsdDevice
*pd
)
1490 BOOL result
= FALSE
;
1493 for(num
= 1; num
<= nch
->nch_NumPorts
; num
++)
1495 if(pd
== (nch
->nch_Downstream
)[num
-1])
1497 psdPipeSetup(nch
->nch_EP0Pipe
, URTF_CLASS
|URTF_OTHER
,
1498 USR_CLEAR_FEATURE
, UFS_PORT_SUSPEND
, (ULONG
) num
);
1500 ioerr
= psdDoPipe(nch
->nch_EP0Pipe
, NULL
, 0);
1503 psdAddErrorMsg(RETURN_WARN
, (STRPTR
) libname
,
1504 "CLEAR_PORT_SUSPEND failed: %s (%ld)",
1505 psdNumToStr(NTS_IOERR
, ioerr
, "unknown"), ioerr
);
1506 KPRINTF(1, ("CLEAR_PORT_SUSPEND failed %ld.\n", ioerr
));
1508 psdSetAttrs(PGA_DEVICE
, pd
, DA_IsSuspended
, FALSE
, TAG_END
);
1509 psdSendEvent(EHMB_DEVRESUMED
, pd
, NULL
);