2 Copyright © 2013-2019, The AROS Development Team. All rights reserved.
7 #include <aros/debug.h>
9 #include <proto/exec.h>
10 #include <proto/kernel.h>
11 #include <proto/utility.h>
13 #include <devices/usb_hub.h>
15 #include "usb2otg_intern.h"
16 #include "usb2otg_hub.h"
18 WORD
FNAME_ROOTHUB(cmdControlXFer
)(struct IOUsbHWReq
*ioreq
,
19 struct USB2OTGUnit
*otg_Unit
,
20 LIBBASETYPEPTR USB2OTGBase
)
22 UWORD rt
= ioreq
->iouh_SetupData
.bmRequestType
;
23 UWORD req
= ioreq
->iouh_SetupData
.bRequest
;
24 UWORD idx
= AROS_WORD2LE(ioreq
->iouh_SetupData
.wIndex
);
25 UWORD val
= AROS_WORD2LE(ioreq
->iouh_SetupData
.wValue
);
26 UWORD len
= AROS_WORD2LE(ioreq
->iouh_SetupData
.wLength
);
30 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER(%ld:%ld)\n", rt
, req
));
32 #if defined(OTG_FORCEHOSTMODE)
33 if (ioreq
->iouh_Endpoint
)
35 return (UHIOERR_STALL
);
39 if (len
!= ioreq
->iouh_Length
)
41 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: IOReq Len mismatch! %ld != %ld\n", len
, ioreq
->iouh_Length
));
42 return (UHIOERR_STALL
);
47 case (URTF_STANDARD
|URTF_DEVICE
):
51 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Set Device Address to #%ld\n", val
));
52 otg_Unit
->hu_HubAddr
= val
;
53 ioreq
->iouh_Actual
= len
;
54 #if (0) // In host mode do not set address!
55 unsigned int otg_RegVal
= rd32le(USB2OTG_DEVCFG
);
56 otg_RegVal
&= ~(0x7F << 4);
57 otg_RegVal
|= ((val
& 0x7F) << 4);
58 wr32le(USB2OTG_DEVCFG
, otg_RegVal
);
62 case USR_SET_CONFIGURATION
:
63 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Set Device Configuration to #%ld\n", val
));
64 ioreq
->iouh_Actual
= len
;
69 case (URTF_IN
|URTF_STANDARD
|URTF_DEVICE
):
73 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: GetStatus (%ld)\n", len
));
76 UWORD
*mptr
= ioreq
->iouh_Data
;
77 *mptr
++ = AROS_WORD2LE(U_GSF_SELF_POWERED
);
82 case USR_GET_DESCRIPTOR
:
86 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: GetDeviceDescriptor (%ld)\n", len
));
87 ioreq
->iouh_Actual
= (len
> sizeof(struct UsbStdDevDesc
)) ? sizeof(struct UsbStdDevDesc
) : len
;
88 CopyMem((APTR
)&OTGRootHubDevDesc
, ioreq
->iouh_Data
, ioreq
->iouh_Actual
);
92 case UDT_CONFIGURATION
:
93 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: GetConfigDescriptor (%ld)\n", len
));
94 ioreq
->iouh_Actual
= (len
> sizeof(struct OTGHubCfg
)) ? sizeof(struct OTGHubCfg
) : len
;
95 CopyMem((APTR
)&OTGRootHubCfg
, ioreq
->iouh_Data
, ioreq
->iouh_Actual
);
100 if (val
& 0xFF) /* get lang array */
102 CONST_STRPTR source
= NULL
;
103 UWORD
*mptr
= ioreq
->iouh_Data
;
105 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: GetString %04lx (%ld)\n", val
, len
));
106 if ((val
& 0xFF) > 4) /* index too high? */
108 return (UHIOERR_STALL
);
111 source
= OTGRootHubStrings
[(val
& 0xFF) - 1];
112 slen
= strlen(source
);
116 ioreq
->iouh_Actual
= 2;
117 *mptr
++ = AROS_WORD2BE(((slen
+ 1) << 9)|UDT_STRING
);
118 /* "expand" string to utf16 */
119 while ((ioreq
->iouh_Actual
+ 1) < len
)
121 *mptr
++ = AROS_WORD2LE(*source
++);
122 ioreq
->iouh_Actual
+= 2;
130 UWORD
*mptr
= ioreq
->iouh_Data
;
131 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: GetLangArray %04lx (%ld)\n", val
, len
));
134 ioreq
->iouh_Actual
= 2;
135 mptr
[0] = AROS_WORD2BE((4 << 8)|UDT_STRING
);
138 ioreq
->iouh_Actual
+= 2;
139 mptr
[1] = AROS_WORD2LE(0x0409);
146 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Unsupported Descriptor %04lx\n", idx
));
151 case USR_GET_CONFIGURATION
:
154 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: GetConfiguration\n"));
155 ((UBYTE
*) ioreq
->iouh_Data
)[0] = 1; // TODO: Expose 3 configurations? 1 = Host + Device, 2 = Host Only, 3 = Device Only?
156 ioreq
->iouh_Actual
= len
;
163 case (URTF_CLASS
|URTF_OTHER
):
167 case USR_SET_FEATURE
:
169 if ((!idx
) || (idx
> 1))
171 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld out of range\n", idx
));
172 return (UHIOERR_STALL
);
178 ULONG oldval
= *((volatile unsigned int *)USB2OTG_HOSTPORT
) & ~(USB2OTG_HOSTPORT_PRTENCHNG
|USB2OTG_HOSTPORT_PRTCONNSTS
);
179 ULONG newval
= oldval
;
181 unsigned int otg_RegVal
;
185 case UFS_PORT_ENABLE
:
186 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld enable requested although OTG cannot do that!\n", idx
));
189 case UFS_PORT_SUSPEND
:
190 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Suspending Port #%ld\n", idx
));
192 otg_RegVal
= rd32le(USB2OTG_HOSTPORT
);
193 otg_RegVal
&= ~USB2OTG_HOSTPORT_SC_BITS
;
194 otg_RegVal
|= USB2OTG_HOSTPORT_PRTSUSP
;
195 wr32le(USB2OTG_HOSTPORT
, otg_RegVal
);
202 struct MsgPort
*port
= CreateMsgPort();
203 struct timerequest
*req
= (struct timerequest
*)CreateIORequest(port
, sizeof(struct timerequest
));
204 OpenDevice("timer.device", UNIT_MICROHZ
, (struct IORequest
*) req
, 0);
206 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Resetting Port #%ld\n", idx
));
208 req
->tr_node
.io_Command
= TR_ADDREQUEST
;
209 req
->tr_time
.tv_secs
= 0;
210 req
->tr_time
.tv_micro
= 10000;
211 DoIO((struct IORequest
*)req
);
212 D(bug("[USB2OTG:Hub] Pause done...\n"));
213 D(bug("[USB2OTG:Hub] port:%08x\n", rd32le(USB2OTG_HOSTPORT
)));
215 otg_RegVal
= rd32le(USB2OTG_HOSTPORT
);
216 otg_RegVal
&= ~USB2OTG_HOSTPORT_SC_BITS
;
217 otg_RegVal
|= USB2OTG_HOSTPORT_PRTRST
;
218 wr32le(USB2OTG_HOSTPORT
, otg_RegVal
);
220 D(bug("[USB2OTG:Hub] port:%08x\n", rd32le(USB2OTG_HOSTPORT
)));
222 req
->tr_time
.tv_secs
= 0;
223 req
->tr_time
.tv_micro
= 60000;
224 DoIO((struct IORequest
*)req
);
225 D(bug("[USB2OTG:Hub] Pause with port reset done...\n"));
226 D(bug("[USB2OTG:Hub] port:%08x\n", rd32le(USB2OTG_HOSTPORT
)));
228 otg_RegVal
= rd32le(USB2OTG_HOSTPORT
);
229 otg_RegVal
&= ~USB2OTG_HOSTPORT_SC_BITS
;
230 otg_RegVal
&= ~USB2OTG_HOSTPORT_PRTRST
;
231 wr32le(USB2OTG_HOSTPORT
, otg_RegVal
);
233 D(bug("[USB2OTG:Hub] port:%08x\n", rd32le(USB2OTG_HOSTPORT
)));
235 req
->tr_time
.tv_secs
= 0;
236 req
->tr_time
.tv_micro
= 10000;
237 DoIO((struct IORequest
*)req
);
238 D(bug("[USB2OTG:Hub] Pause after deasserting reset done...\n"));
239 D(bug("[USB2OTG:Hub] port:%08x\n", rd32le(USB2OTG_HOSTPORT
)));
241 CloseDevice((struct IORequest
*)req
);
242 DeleteIORequest((struct IORequest
*)req
);
250 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Powering Port #%ld\n", idx
));
252 otg_RegVal
= rd32le(USB2OTG_HOSTPORT
);
253 otg_RegVal
&= ~USB2OTG_HOSTPORT_SC_BITS
;
254 otg_RegVal
|= USB2OTG_HOSTPORT_PRTPWR
;
255 wr32le(USB2OTG_HOSTPORT
, otg_RegVal
);
261 case UFS_PORT_LOW_SPEED:
262 case UFS_C_PORT_CONNECTION:
263 case UFS_C_PORT_OVER_CURRENT:
266 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_SET_FEATURE - Unhandled feature %ld for Port #%ld\n", val
, idx
));
272 *((volatile unsigned int *)USB2OTG_HOSTPORT
) = newval
;
280 case USR_CLEAR_FEATURE
:
282 if ((!idx
) || (idx
> 1))
284 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld out of range\n", idx
));
285 return (UHIOERR_STALL
);
290 ULONG oldval
= rd32le(USB2OTG_HOSTPORT
) & ~USB2OTG_HOSTPORT_SC_BITS
;
291 ULONG newval
= oldval
;
295 case UFS_PORT_ENABLE
:
296 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Enable\n", idx
));
298 newval
|= USB2OTG_HOSTPORT_PRTENA
;
303 case UFS_PORT_SUSPEND
:
304 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Suspend\n", idx
));
306 newval
|= USB2OTG_HOSTPORT_PRTRES
;
312 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Power\n", idx
));
314 newval
&= ~USB2OTG_HOSTPORT_PRTPWR
;
319 case UFS_C_PORT_CONNECTION
:
320 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Connect Change\n", idx
));
322 newval
|= USB2OTG_HOSTPORT_PRTCONNDET
;
323 otg_Unit
->hu_HubPortChanged
= TRUE
;
328 case UFS_C_PORT_ENABLE
:
329 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Enable Change\n", idx
));
331 newval
|= USB2OTG_HOSTPORT_PRTENCHNG
;
332 otg_Unit
->hu_HubPortChanged
= TRUE
;
337 case UFS_C_PORT_SUSPEND
:
338 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Suspend Change\n", idx
));
340 // newval |= USB2OTG_HOSTPORT_PRTRES;
341 otg_Unit
->hu_HubPortChanged
= TRUE
;
346 case UFS_C_PORT_OVER_CURRENT
:
347 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Over-Current Change\n", idx
));
349 newval
|= USB2OTG_HOSTPORT_PRTOVRCURRCHNG
;
350 otg_Unit
->hu_HubPortChanged
= TRUE
;
355 case UFS_C_PORT_RESET
:
356 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Reset Change\n", idx
));
358 newval
&= ~USB2OTG_HOSTPORT_PRTRST
;
359 otg_Unit
->hu_HubPortChanged
= TRUE
;
365 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE - Unhandled feature %ld for Port #%ld\n", val
, idx
));
370 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld CLEAR_FEATURE %04lx->%04lx\n", idx
, oldval
, newval
));
371 wr32le(USB2OTG_HOSTPORT
, newval
);
381 case (URTF_IN
|URTF_CLASS
|URTF_OTHER
):
387 UWORD
*mptr
= ioreq
->iouh_Data
;
389 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Get Port #%ld Status..\n", idx
));
391 if (len
!= sizeof(struct UsbPortStatus
))
393 return (UHIOERR_STALL
);
395 if ((!idx
) || (idx
> 1))
397 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld out of range\n", idx
));
398 return (UHIOERR_STALL
);
401 ULONG oldval
= rd32le(USB2OTG_HOSTPORT
);
404 if (oldval
& USB2OTG_HOSTPORT_PRTPWR
) *mptr
|= AROS_WORD2LE(UPSF_PORT_POWER
);
405 if (oldval
& USB2OTG_HOSTPORT_PRTENA
) *mptr
|= AROS_WORD2LE(UPSF_PORT_ENABLE
);
406 if (oldval
& USB2OTG_HOSTPORT_PRTCONNSTS
) *mptr
|= AROS_WORD2LE(UPSF_PORT_CONNECTION
);
407 if (oldval
& USB2OTG_HOSTPORT_PRTRST
) *mptr
|= AROS_WORD2LE(UPSF_PORT_RESET
);
408 if (oldval
& USB2OTG_HOSTPORT_PRTSUSP
) *mptr
|= AROS_WORD2LE(UPSF_PORT_SUSPEND
);
410 switch ((oldval
>> 17) & 3)
413 *mptr
|= AROS_WORD2LE(UPSF_PORT_HIGH_SPEED
);
416 *mptr
|= AROS_WORD2LE(UPSF_PORT_LOW_SPEED
);
422 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld is %s\n", idx
, (oldval
& USB2OTG_HOSTPORT_PRTSPD_LOW
) ? "LOWSPEED" : "FULLSPEED"));
423 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld Status %08lx\n", idx
, AROS_LE2WORD(*mptr
)));
427 if (oldval
& USB2OTG_HOSTPORT_PRTENCHNG
) *mptr
|= AROS_WORD2LE(UPSF_PORT_ENABLE
);
428 if (oldval
& USB2OTG_HOSTPORT_PRTCONNDET
) *mptr
|= AROS_WORD2LE(UPSF_PORT_CONNECTION
);
429 if (oldval
& USB2OTG_HOSTPORT_PRTRES
) *mptr
|= AROS_WORD2LE(UPSF_PORT_SUSPEND
|UPSF_PORT_ENABLE
);
431 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld Change %08lx\n", idx
, AROS_LE2WORD(*mptr
)));
439 case (URTF_IN
|URTF_CLASS
|URTF_DEVICE
):
445 UWORD
*mptr
= ioreq
->iouh_Data
;
447 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: GetHubStatus (%ld)\n", len
));
449 if (len
< sizeof(struct UsbHubStatus
))
451 return(UHIOERR_STALL
);
456 ioreq
->iouh_Actual
= 4;
460 case USR_GET_DESCRIPTOR
:
466 ULONG hubdesclen
= 9;
467 //ULONG powergood = 1;
469 struct UsbHubDesc
*uhd
= (struct UsbHubDesc
*) ioreq
->iouh_Data
;
470 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: GetHubDescriptor (%ld)\n", len
));
472 ioreq
->iouh_Actual
= (len
> hubdesclen
) ? hubdesclen
: len
;
473 CopyMem((APTR
)&OTGRootHubDesc
, ioreq
->iouh_Data
, ioreq
->iouh_Actual
);
475 if (ioreq
->iouh_Length
)
477 uhd
->bLength
= hubdesclen
;
480 if (ioreq
->iouh_Length
>= hubdesclen
)
484 uhd
->DeviceRemovable
= 0;
485 uhd
->PortPwrCtrlMask
= (1 << 3) - 2;
487 // each field is 16 bits wide
488 uhd
->DeviceRemovable
= 0;
489 uhd
->PortPwrCtrlMask
= 0;
490 ((UBYTE
*)ioreq
->iouh_Data
)[9] = (1 << 3) - 2;
491 ((UBYTE
*)ioreq
->iouh_Data
)[10] = ((1 << 3) - 2) >> 8;
498 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Unsupported Descriptor %04lx\n", idx
));
507 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Unsupported command %02lx %02lx %04lx %04lx %04lx!\n", rt
, req
, idx
, val
, len
));
509 return (UHIOERR_STALL
);
512 WORD
FNAME_ROOTHUB(cmdIntXFer
)(struct IOUsbHWReq
*ioreq
,
513 struct USB2OTGUnit
*otg_Unit
,
514 LIBBASETYPEPTR USB2OTGBase
)
516 D(bug("[USB2OTG:Hub] UHCMD_INTXFER()\n"));
518 if ((ioreq
->iouh_Endpoint
!= 1) || (!ioreq
->iouh_Length
))
520 return UHIOERR_STALL
;
523 if (otg_Unit
->hu_HubPortChanged
)
525 D(bug("[USB2OTG:Hub] UHCMD_INTXFER: Registering Immediate Portchange\n"));
527 if (ioreq
->iouh_Length
== 1)
529 *((UBYTE
*) ioreq
->iouh_Data
) = 1;
530 ioreq
->iouh_Actual
= 1;
534 ((UBYTE
*) ioreq
->iouh_Data
)[0] = 1;
535 ((UBYTE
*) ioreq
->iouh_Data
)[1] = 0;
536 ioreq
->iouh_Actual
= 2;
538 otg_Unit
->hu_HubPortChanged
= FALSE
;
543 D(bug("[USB2OTG:Hub] UHCMD_INTXFER: Queueing request\n"));
545 ioreq
->iouh_Req
.io_Flags
&= ~IOF_QUICK
;
547 AddTail(&otg_Unit
->hu_IOPendingQueue
, (struct Node
*)ioreq
);
553 void FNAME_ROOTHUB(PendingIO
)(struct USB2OTGUnit
*otg_Unit
)
555 struct IOUsbHWReq
*ioreq
;
557 D(bug("[USB2OTG:Hub] PendingIO(0x%p)\n", otg_Unit
));
559 if (otg_Unit
->hu_HubPortChanged
&& otg_Unit
->hu_IOPendingQueue
.lh_Head
->ln_Succ
)
561 D(bug("[USB2OTG:Hub] PendingIO: PortChange detected\n"));
563 ioreq
= (struct IOUsbHWReq
*) otg_Unit
->hu_IOPendingQueue
.lh_Head
;
564 while (((struct Node
*) ioreq
)->ln_Succ
)
566 Remove(&ioreq
->iouh_Req
.io_Message
.mn_Node
);
567 if (ioreq
->iouh_Length
== 1)
569 *((UBYTE
*) ioreq
->iouh_Data
) = 1;
570 ioreq
->iouh_Actual
= 1;
572 ((UBYTE
*) ioreq
->iouh_Data
)[0] = 1;
573 ((UBYTE
*) ioreq
->iouh_Data
)[1] = 0;
574 ioreq
->iouh_Actual
= 2;
576 ReplyMsg(&ioreq
->iouh_Req
.io_Message
);
577 ioreq
= (struct IOUsbHWReq
*) otg_Unit
->hu_IOPendingQueue
.lh_Head
;
579 otg_Unit
->hu_HubPortChanged
= FALSE
;