2 Copyright © 2013-2015, 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
;
55 unsigned int otg_RegVal
= *((volatile unsigned int *)USB2OTG_DEVCFG
);
56 otg_RegVal
&= ~(0x7F << 4);
57 otg_RegVal
|= ((val
& 0x7F) << 4);
58 *((volatile unsigned int *)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
<< 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
, ns
;
185 case UFS_PORT_ENABLE
:
186 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Enabling Port #%ld\n", idx
));
188 otg_RegVal
= *((volatile unsigned int *)USB2OTG_HOSTPORT
);
189 otg_RegVal
|= USB2OTG_HOSTPORT_PRTENA
;
190 *((volatile unsigned int *)USB2OTG_HOSTPORT
) = otg_RegVal
;
195 case UFS_PORT_SUSPEND
:
196 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Suspending Port #%ld\n", idx
));
198 otg_RegVal
= *((volatile unsigned int *)USB2OTG_HOSTPORT
);
199 otg_RegVal
|= USB2OTG_HOSTPORT_PRTSUSP
;
200 *((volatile unsigned int *)USB2OTG_HOSTPORT
) = otg_RegVal
;
207 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Resetting Port #%ld\n", idx
));
209 for (ns
= 0; ns
< 100000; ns
++) { asm volatile("mov r0, r0\n"); } // see USB 2.0 spec
211 otg_RegVal
= *((volatile unsigned int *)USB2OTG_HOSTPORT
);
212 otg_RegVal
&= ~(USB2OTG_HOSTPORT_PRTCONNSTS
|USB2OTG_HOSTPORT_PRTENA
|USB2OTG_HOSTPORT_PRTENCHNG
|USB2OTG_HOSTPORT_PRTOVRCURRCHNG
);
213 otg_RegVal
|= USB2OTG_HOSTPORT_PRTRST
;
214 *((volatile unsigned int *)USB2OTG_HOSTPORT
) = otg_RegVal
;
216 for (ns
= 0; ns
< 50000; ns
++) { asm volatile("mov r0, r0\n"); } // see USB 2.0 spec (tDRSTR)
218 otg_RegVal
= *((volatile unsigned int *)USB2OTG_HOSTPORT
);
219 otg_RegVal
&= ~(USB2OTG_HOSTPORT_PRTCONNSTS
|USB2OTG_HOSTPORT_PRTENA
|USB2OTG_HOSTPORT_PRTENCHNG
|USB2OTG_HOSTPORT_PRTOVRCURRCHNG
| USB2OTG_HOSTPORT_PRTRST
);
220 *((volatile unsigned int *)USB2OTG_HOSTPORT
) = otg_RegVal
;
222 for (ns
= 0; ns
< 20000; ns
++) { asm volatile("mov r0, r0\n"); } // see USB 2.0 spec (tRSTRCY)
228 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Powering Port #%ld\n", idx
));
230 otg_RegVal
= *((volatile unsigned int *)USB2OTG_HOSTPORT
);
231 otg_RegVal
|= USB2OTG_HOSTPORT_PRTPWR
;
232 *((volatile unsigned int *)USB2OTG_HOSTPORT
) = otg_RegVal
;
238 case UFS_PORT_LOW_SPEED:
239 case UFS_C_PORT_CONNECTION:
240 case UFS_C_PORT_OVER_CURRENT:
243 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_SET_FEATURE - Unhandled feature %ld for Port #%ld\n", val
, idx
));
249 *((volatile unsigned int *)USB2OTG_HOSTPORT
) = newval
;
257 case USR_CLEAR_FEATURE
:
259 if ((!idx
) || (idx
> 1))
261 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld out of range\n", idx
));
262 return (UHIOERR_STALL
);
267 ULONG oldval
= *((volatile unsigned int *)USB2OTG_HOSTPORT
) & ~(USB2OTG_HOSTPORT_PRTENCHNG
|USB2OTG_HOSTPORT_PRTCONNSTS
);
268 ULONG newval
= oldval
;
272 case UFS_PORT_ENABLE
:
273 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Enable\n", idx
));
275 newval
&= ~USB2OTG_HOSTPORT_PRTENA
;
280 case UFS_PORT_SUSPEND
:
281 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Suspend\n", idx
));
283 newval
&= ~USB2OTG_HOSTPORT_PRTSUSP
;
289 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Power\n", idx
));
291 newval
&= ~USB2OTG_HOSTPORT_PRTPWR
;
296 case UFS_C_PORT_CONNECTION
:
297 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Connect Change\n", idx
));
299 newval
&= ~USB2OTG_HOSTPORT_PRTCONNDET
;
300 otg_Unit
->hu_HubPortChanged
= TRUE
;
305 case UFS_C_PORT_ENABLE
:
306 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Enable Change\n", idx
));
308 newval
&= ~USB2OTG_HOSTPORT_PRTENCHNG
;
309 otg_Unit
->hu_HubPortChanged
= TRUE
;
314 case UFS_C_PORT_SUSPEND
:
315 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Suspend Change\n", idx
));
317 newval
&= ~USB2OTG_HOSTPORT_PRTRES
;
318 otg_Unit
->hu_HubPortChanged
= TRUE
;
323 case UFS_C_PORT_OVER_CURRENT
:
324 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Over-Current Change\n", idx
));
326 newval
&= ~USB2OTG_HOSTPORT_PRTOVRCURRCHNG
;
327 otg_Unit
->hu_HubPortChanged
= TRUE
;
332 case UFS_C_PORT_RESET
:
333 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Reset Change\n", idx
));
335 newval
&= ~USB2OTG_HOSTPORT_PRTRST
;
336 otg_Unit
->hu_HubPortChanged
= TRUE
;
342 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE - Unhandled feature %ld for Port #%ld\n", val
, idx
));
347 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld CLEAR_FEATURE %04lx->%04lx\n", idx
, oldval
, newval
));
348 *((volatile unsigned int *)USB2OTG_HOSTPORT
) = newval
;
358 case (URTF_IN
|URTF_CLASS
|URTF_OTHER
):
364 UWORD
*mptr
= ioreq
->iouh_Data
;
366 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Get Port #%ld Status..\n", idx
));
368 if (len
!= sizeof(struct UsbPortStatus
))
370 return (UHIOERR_STALL
);
372 if ((!idx
) || (idx
> 1))
374 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld out of range\n", idx
));
375 return (UHIOERR_STALL
);
378 ULONG oldval
= *((volatile unsigned int *)USB2OTG_HOSTPORT
);
381 if (oldval
& USB2OTG_HOSTPORT_PRTPWR
) *mptr
|= AROS_WORD2LE(UPSF_PORT_POWER
);
382 if (oldval
& USB2OTG_HOSTPORT_PRTENA
) *mptr
|= AROS_WORD2LE(UPSF_PORT_ENABLE
);
383 if (oldval
& USB2OTG_HOSTPORT_PRTCONNSTS
) *mptr
|= AROS_WORD2LE(UPSF_PORT_CONNECTION
);
384 if (oldval
& USB2OTG_HOSTPORT_PRTSPD_LOW
) *mptr
|= AROS_WORD2LE(UPSF_PORT_LOW_SPEED
);
385 if (oldval
& USB2OTG_HOSTPORT_PRTRST
) *mptr
|= AROS_WORD2LE(UPSF_PORT_RESET
);
386 if (oldval
& USB2OTG_HOSTPORT_PRTSUSP
) *mptr
|= AROS_WORD2LE(UPSF_PORT_SUSPEND
);
388 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld is %s\n", idx
, (oldval
& USB2OTG_HOSTPORT_PRTSPD_LOW
) ? "LOWSPEED" : "FULLSPEED"));
389 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld Status %08lx\n", idx
, *mptr
));
393 if (oldval
& USB2OTG_HOSTPORT_PRTENCHNG
) *mptr
|= AROS_WORD2LE(UPSF_PORT_ENABLE
);
394 if (oldval
& USB2OTG_HOSTPORT_PRTCONNDET
) *mptr
|= AROS_WORD2LE(UPSF_PORT_CONNECTION
);
395 if (oldval
& USB2OTG_HOSTPORT_PRTRES
) *mptr
|= AROS_WORD2LE(UPSF_PORT_SUSPEND
|UPSF_PORT_ENABLE
);
397 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld Change %08lx\n", idx
, *mptr
));
405 case (URTF_IN
|URTF_CLASS
|URTF_DEVICE
):
411 UWORD
*mptr
= ioreq
->iouh_Data
;
413 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: GetHubStatus (%ld)\n", len
));
415 if (len
< sizeof(struct UsbHubStatus
))
417 return(UHIOERR_STALL
);
422 ioreq
->iouh_Actual
= 4;
426 case USR_GET_DESCRIPTOR
:
432 ULONG hubdesclen
= 9;
435 struct UsbHubDesc
*uhd
= (struct UsbHubDesc
*) ioreq
->iouh_Data
;
436 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: GetHubDescriptor (%ld)\n", len
));
438 ioreq
->iouh_Actual
= (len
> hubdesclen
) ? hubdesclen
: len
;
439 CopyMem((APTR
)&OTGRootHubDesc
, ioreq
->iouh_Data
, ioreq
->iouh_Actual
);
441 if (ioreq
->iouh_Length
)
443 uhd
->bLength
= hubdesclen
;
446 if (ioreq
->iouh_Length
>= hubdesclen
)
450 uhd
->DeviceRemovable
= 0;
451 uhd
->PortPwrCtrlMask
= (1 << 3) - 2;
453 // each field is 16 bits wide
454 uhd
->DeviceRemovable
= 0;
455 uhd
->PortPwrCtrlMask
= 0;
456 ((UBYTE
*)ioreq
->iouh_Data
)[9] = (1 << 3) - 2;
457 ((UBYTE
*)ioreq
->iouh_Data
)[10] = ((1 << 3) - 2) >> 8;
464 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Unsupported Descriptor %04lx\n", idx
));
473 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Unsupported command %02lx %02lx %04lx %04lx %04lx!\n", rt
, req
, idx
, val
, len
));
475 return (UHIOERR_STALL
);
478 WORD
FNAME_ROOTHUB(cmdIntXFer
)(struct IOUsbHWReq
*ioreq
,
479 struct USB2OTGUnit
*otg_Unit
,
480 LIBBASETYPEPTR USB2OTGBase
)
482 D(bug("[USB2OTG:Hub] UHCMD_INTXFER()\n"));
484 if ((ioreq
->iouh_Endpoint
!= 1) || (!ioreq
->iouh_Length
))
486 return UHIOERR_STALL
;
489 if (otg_Unit
->hu_HubPortChanged
)
491 D(bug("[USB2OTG:Hub] UHCMD_INTXFER: Registering Immediate Portchange\n"));
493 if (ioreq
->iouh_Length
== 1)
495 *((UBYTE
*) ioreq
->iouh_Data
) = 1;
496 ioreq
->iouh_Actual
= 1;
500 ((UBYTE
*) ioreq
->iouh_Data
)[0] = 1;
501 ((UBYTE
*) ioreq
->iouh_Data
)[1] = 0;
502 ioreq
->iouh_Actual
= 2;
504 otg_Unit
->hu_HubPortChanged
= FALSE
;
509 D(bug("[USB2OTG:Hub] UHCMD_INTXFER: Queueing request\n"));
511 ioreq
->iouh_Req
.io_Flags
&= ~IOF_QUICK
;
513 AddTail(&otg_Unit
->hu_IOPendingQueue
, (struct Node
*)ioreq
);
519 void FNAME_ROOTHUB(PendingIO
)(struct USB2OTGUnit
*otg_Unit
)
521 struct IOUsbHWReq
*ioreq
;
523 D(bug("[USB2OTG:Hub] PendingIO(0x%p)\n", otg_Unit
));
525 if (otg_Unit
->hu_HubPortChanged
&& otg_Unit
->hu_IOPendingQueue
.lh_Head
->ln_Succ
)
527 D(bug("[USB2OTG:Hub] PendingIO: PortChange detected\n"));
529 ioreq
= (struct IOUsbHWReq
*) otg_Unit
->hu_IOPendingQueue
.lh_Head
;
530 while (((struct Node
*) ioreq
)->ln_Succ
)
532 Remove(&ioreq
->iouh_Req
.io_Message
.mn_Node
);
533 if (ioreq
->iouh_Length
== 1)
535 *((UBYTE
*) ioreq
->iouh_Data
) = 1;
536 ioreq
->iouh_Actual
= 1;
538 ((UBYTE
*) ioreq
->iouh_Data
)[0] = 1;
539 ((UBYTE
*) ioreq
->iouh_Data
)[1] = 0;
540 ioreq
->iouh_Actual
= 2;
542 ReplyMsg(&ioreq
->iouh_Req
.io_Message
);
543 ioreq
= (struct IOUsbHWReq
*) otg_Unit
->hu_IOPendingQueue
.lh_Head
;
545 otg_Unit
->hu_HubPortChanged
= FALSE
;