2 Copyright © 2013, 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 <asm/bcm2835.h>
14 #include <hardware/usb2otg.h>
15 #include <devices/usb_hub.h>
17 #include "usb2otg_intern.h"
18 #include "usb2otg_hub.h"
20 WORD
FNAME_ROOTHUB(cmdControlXFer
)(struct IOUsbHWReq
*ioreq
,
21 struct USB2OTGUnit
*otg_Unit
,
22 LIBBASETYPEPTR USB2OTGBase
)
24 UWORD rt
= ioreq
->iouh_SetupData
.bmRequestType
;
25 UWORD req
= ioreq
->iouh_SetupData
.bRequest
;
26 UWORD idx
= AROS_WORD2LE(ioreq
->iouh_SetupData
.wIndex
);
27 UWORD val
= AROS_WORD2LE(ioreq
->iouh_SetupData
.wValue
);
28 UWORD len
= AROS_WORD2LE(ioreq
->iouh_SetupData
.wLength
);
32 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER(%ld:%ld)\n", rt
, req
));
34 #if defined(OTG_FORCEHOSTMODE)
35 if (ioreq
->iouh_Endpoint
)
37 return (UHIOERR_STALL
);
41 if (len
!= ioreq
->iouh_Length
)
43 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: IOReq Len mismatch! %ld != %ld\n", len
, ioreq
->iouh_Length
));
44 return (UHIOERR_STALL
);
49 case (URTF_STANDARD
|URTF_DEVICE
):
53 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Set Device Address to #%ld\n", val
));
54 otg_Unit
->hu_HubAddr
= val
;
55 ioreq
->iouh_Actual
= len
;
57 unsigned int otg_RegVal
= *((volatile unsigned int *)USB2OTG_DEVCFG
);
58 otg_RegVal
&= ~(0x7F << 4);
59 otg_RegVal
|= ((val
& 0x7F) << 4);
60 *((volatile unsigned int *)USB2OTG_DEVCFG
) = otg_RegVal
;
64 case USR_SET_CONFIGURATION
:
65 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Set Device Configuration to #%ld\n", val
));
66 ioreq
->iouh_Actual
= len
;
71 case (URTF_IN
|URTF_STANDARD
|URTF_DEVICE
):
75 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: GetStatus (%ld)\n", len
));
78 UWORD
*mptr
= ioreq
->iouh_Data
;
79 *mptr
++ = AROS_WORD2LE(U_GSF_SELF_POWERED
);
84 case USR_GET_DESCRIPTOR
:
88 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: GetDeviceDescriptor (%ld)\n", len
));
89 ioreq
->iouh_Actual
= (len
> sizeof(struct UsbStdDevDesc
)) ? sizeof(struct UsbStdDevDesc
) : len
;
90 CopyMem((APTR
)&OTGRootHubDevDesc
, ioreq
->iouh_Data
, ioreq
->iouh_Actual
);
94 case UDT_CONFIGURATION
:
95 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: GetConfigDescriptor (%ld)\n", len
));
96 ioreq
->iouh_Actual
= (len
> sizeof(struct OTGHubCfg
)) ? sizeof(struct OTGHubCfg
) : len
;
97 CopyMem((APTR
)&OTGRootHubCfg
, ioreq
->iouh_Data
, ioreq
->iouh_Actual
);
102 if (val
& 0xFF) /* get lang array */
104 CONST_STRPTR source
= NULL
;
105 UWORD
*mptr
= ioreq
->iouh_Data
;
107 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: GetString %04lx (%ld)\n", val
, len
));
108 if ((val
& 0xFF) > 4) /* index too high? */
110 return (UHIOERR_STALL
);
113 source
= OTGRootHubStrings
[(val
& 0xFF) - 1];
114 slen
= strlen(source
);
118 ioreq
->iouh_Actual
= 2;
119 *mptr
++ = AROS_WORD2BE((slen
<< 9)|UDT_STRING
);
120 /* "expand" string to utf16 */
121 while ((ioreq
->iouh_Actual
+ 1) < len
)
123 *mptr
++ = AROS_WORD2LE(*source
++);
124 ioreq
->iouh_Actual
+= 2;
132 UWORD
*mptr
= ioreq
->iouh_Data
;
133 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: GetLangArray %04lx (%ld)\n", val
, len
));
136 ioreq
->iouh_Actual
= 2;
137 mptr
[0] = AROS_WORD2BE((4 << 8)|UDT_STRING
);
140 ioreq
->iouh_Actual
+= 2;
141 mptr
[1] = AROS_WORD2LE(0x0409);
148 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Unsupported Descriptor %04lx\n", idx
));
153 case USR_GET_CONFIGURATION
:
156 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: GetConfiguration\n"));
157 ((UBYTE
*) ioreq
->iouh_Data
)[0] = 1; // TODO: Expose 3 configurations? 1 = Host + Device, 2 = Host Only, 3 = Device Only?
158 ioreq
->iouh_Actual
= len
;
165 case (URTF_CLASS
|URTF_OTHER
):
169 case USR_SET_FEATURE
:
171 if ((!idx
) || (idx
> 1))
173 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld out of range\n", idx
));
174 return (UHIOERR_STALL
);
179 ULONG oldval
= *((volatile unsigned int *)USB2OTG_HOSTPORT
) & ~(USB2OTG_HOSTPORT_PRTENCHNG
|USB2OTG_HOSTPORT_PRTCONNSTS
);
180 ULONG newval
= oldval
;
184 case UFS_PORT_ENABLE
:
185 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Enabling Port #%ld\n", idx
));
187 newval
|= USB2OTG_HOSTPORT_PRTENA
;
192 case UFS_PORT_SUSPEND
:
193 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Suspending Port #%ld\n", idx
));
195 newval
|= USB2OTG_HOSTPORT_PRTSUSP
;
201 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Resetting Port #%ld\n", idx
));
203 newval
|= USB2OTG_HOSTPORT_PRTRST
;
209 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Powering Port #%ld\n", idx
));
211 newval
|= USB2OTG_HOSTPORT_PRTPWR
;
217 case UFS_PORT_LOW_SPEED:
218 case UFS_C_PORT_CONNECTION:
219 case UFS_C_PORT_OVER_CURRENT:
222 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_SET_FEATURE - Unhandled feature %ld for Port #%ld\n", val
, idx
));
227 *((volatile unsigned int *)USB2OTG_HOSTPORT
) = newval
;
235 case USR_CLEAR_FEATURE
:
237 if ((!idx
) || (idx
> 1))
239 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld out of range\n", idx
));
240 return (UHIOERR_STALL
);
245 ULONG oldval
= *((volatile unsigned int *)USB2OTG_HOSTPORT
) & ~(USB2OTG_HOSTPORT_PRTENCHNG
|USB2OTG_HOSTPORT_PRTCONNSTS
);
246 ULONG newval
= oldval
;
250 case UFS_PORT_ENABLE
:
251 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Enable\n", idx
));
253 newval
&= ~USB2OTG_HOSTPORT_PRTENA
;
258 case UFS_PORT_SUSPEND
:
259 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Suspend\n", idx
));
261 newval
&= ~USB2OTG_HOSTPORT_PRTSUSP
;
267 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Power\n", idx
));
269 newval
&= ~USB2OTG_HOSTPORT_PRTPWR
;
274 case UFS_C_PORT_CONNECTION
:
275 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Connect Change\n", idx
));
277 newval
&= ~USB2OTG_HOSTPORT_PRTCONNDET
;
278 otg_Unit
->hu_HubPortChanged
= TRUE
;
283 case UFS_C_PORT_ENABLE
:
284 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Enable Change\n", idx
));
286 newval
&= ~USB2OTG_HOSTPORT_PRTENCHNG
;
287 otg_Unit
->hu_HubPortChanged
= TRUE
;
292 case UFS_C_PORT_SUSPEND
:
293 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Suspend Change\n", idx
));
295 newval
&= ~USB2OTG_HOSTPORT_PRTRES
;
296 otg_Unit
->hu_HubPortChanged
= TRUE
;
301 case UFS_C_PORT_OVER_CURRENT
:
302 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Over-Current Change\n", idx
));
304 newval
&= ~USB2OTG_HOSTPORT_PRTOVRCURRCHNG
;
305 otg_Unit
->hu_HubPortChanged
= TRUE
;
310 case UFS_C_PORT_RESET
:
311 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Reset Change\n", idx
));
313 newval
&= ~USB2OTG_HOSTPORT_PRTRST
;
314 otg_Unit
->hu_HubPortChanged
= TRUE
;
320 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE - Unhandled feature %ld for Port #%ld\n", val
, idx
));
325 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld CLEAR_FEATURE %04lx->%04lx\n", idx
, oldval
, newval
));
326 *((volatile unsigned int *)USB2OTG_HOSTPORT
) = newval
;
336 case (URTF_IN
|URTF_CLASS
|URTF_OTHER
):
342 UWORD
*mptr
= ioreq
->iouh_Data
;
344 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Get Port #%ld Status..\n", idx
));
346 if (len
!= sizeof(struct UsbPortStatus
))
348 return (UHIOERR_STALL
);
350 if ((!idx
) || (idx
> 1))
352 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld out of range\n", idx
));
353 return (UHIOERR_STALL
);
356 ULONG oldval
= *((volatile unsigned int *)USB2OTG_HOSTPORT
);
359 if (oldval
& USB2OTG_HOSTPORT_PRTPWR
) *mptr
|= AROS_WORD2LE(UPSF_PORT_POWER
);
360 if (oldval
& USB2OTG_HOSTPORT_PRTENA
) *mptr
|= AROS_WORD2LE(UPSF_PORT_ENABLE
);
361 if (oldval
& USB2OTG_HOSTPORT_PRTCONNSTS
) *mptr
|= AROS_WORD2LE(UPSF_PORT_CONNECTION
);
362 if (oldval
& USB2OTG_HOSTPORT_PRTSPD_LOW
) *mptr
|= AROS_WORD2LE(UPSF_PORT_LOW_SPEED
);
363 if (oldval
& USB2OTG_HOSTPORT_PRTRST
) *mptr
|= AROS_WORD2LE(UPSF_PORT_RESET
);
364 if (oldval
& USB2OTG_HOSTPORT_PRTSUSP
) *mptr
|= AROS_WORD2LE(UPSF_PORT_SUSPEND
);
366 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld is %s\n", idx
, (oldval
& USB2OTG_HOSTPORT_PRTSPD_LOW
) ? "LOWSPEED" : "FULLSPEED"));
367 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld Status %08lx\n", idx
, *mptr
));
371 if (oldval
& USB2OTG_HOSTPORT_PRTENCHNG
) *mptr
|= AROS_WORD2LE(UPSF_PORT_ENABLE
);
372 if (oldval
& USB2OTG_HOSTPORT_PRTCONNDET
) *mptr
|= AROS_WORD2LE(UPSF_PORT_CONNECTION
);
373 if (oldval
& USB2OTG_HOSTPORT_PRTRES
) *mptr
|= AROS_WORD2LE(UPSF_PORT_SUSPEND
|UPSF_PORT_ENABLE
);
375 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld Change %08lx\n", idx
, *mptr
));
383 case (URTF_IN
|URTF_CLASS
|URTF_DEVICE
):
389 UWORD
*mptr
= ioreq
->iouh_Data
;
391 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: GetHubStatus (%ld)\n", len
));
393 if (len
< sizeof(struct UsbHubStatus
))
395 return(UHIOERR_STALL
);
400 ioreq
->iouh_Actual
= 4;
404 case USR_GET_DESCRIPTOR
:
410 ULONG hubdesclen
= 9;
413 struct UsbHubDesc
*uhd
= (struct UsbHubDesc
*) ioreq
->iouh_Data
;
414 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: GetHubDescriptor (%ld)\n", len
));
416 ioreq
->iouh_Actual
= (len
> hubdesclen
) ? hubdesclen
: len
;
417 CopyMem((APTR
)&OTGRootHubDesc
, ioreq
->iouh_Data
, ioreq
->iouh_Actual
);
419 if (ioreq
->iouh_Length
)
421 uhd
->bLength
= hubdesclen
;
424 if (ioreq
->iouh_Length
>= hubdesclen
)
428 uhd
->DeviceRemovable
= 0;
429 uhd
->PortPwrCtrlMask
= (1 << 3) - 2;
431 // each field is 16 bits wide
432 uhd
->DeviceRemovable
= 0;
433 uhd
->PortPwrCtrlMask
= 0;
434 ((UBYTE
*)ioreq
->iouh_Data
)[9] = (1 << 3) - 2;
435 ((UBYTE
*)ioreq
->iouh_Data
)[10] = ((1 << 3) - 2) >> 8;
442 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Unsupported Descriptor %04lx\n", idx
));
451 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Unsupported command %02lx %02lx %04lx %04lx %04lx!\n", rt
, req
, idx
, val
, len
));
453 return (UHIOERR_STALL
);
456 WORD
FNAME_ROOTHUB(cmdIntXFer
)(struct IOUsbHWReq
*ioreq
,
457 struct USB2OTGUnit
*otg_Unit
,
458 LIBBASETYPEPTR USB2OTGBase
)
460 D(bug("[USB2OTG:Hub] UHCMD_INTXFER()\n"));
462 if ((ioreq
->iouh_Endpoint
!= 1) || (!ioreq
->iouh_Length
))
464 return UHIOERR_STALL
;
467 if (otg_Unit
->hu_HubPortChanged
)
469 D(bug("[USB2OTG:Hub] UHCMD_INTXFER: Registering Immediate Portchange\n"));
471 if (ioreq
->iouh_Length
== 1)
473 *((UBYTE
*) ioreq
->iouh_Data
) = 1;
474 ioreq
->iouh_Actual
= 1;
478 ((UBYTE
*) ioreq
->iouh_Data
)[0] = 1;
479 ((UBYTE
*) ioreq
->iouh_Data
)[1] = 0;
480 ioreq
->iouh_Actual
= 2;
482 otg_Unit
->hu_HubPortChanged
= FALSE
;
487 D(bug("[USB2OTG:Hub] UHCMD_INTXFER: Queueing request\n"));
489 ioreq
->iouh_Req
.io_Flags
&= ~IOF_QUICK
;
491 AddTail(&otg_Unit
->hu_IOPendingQueue
, (struct Node
*)ioreq
);
497 void FNAME_ROOTHUB(PendingIO
)(struct USB2OTGUnit
*otg_Unit
)
499 struct IOUsbHWReq
*ioreq
;
501 if (otg_Unit
->hu_HubPortChanged
&& otg_Unit
->hu_IOPendingQueue
.lh_Head
->ln_Succ
)
503 D(bug("[USB2OTG:Hub] PendingIO: PortChange detected\n"));
505 ioreq
= (struct IOUsbHWReq
*) otg_Unit
->hu_IOPendingQueue
.lh_Head
;
506 while (((struct Node
*) ioreq
)->ln_Succ
)
508 Remove(&ioreq
->iouh_Req
.io_Message
.mn_Node
);
509 if (ioreq
->iouh_Length
== 1)
511 *((UBYTE
*) ioreq
->iouh_Data
) = 1;
512 ioreq
->iouh_Actual
= 1;
514 ((UBYTE
*) ioreq
->iouh_Data
)[0] = 1;
515 ((UBYTE
*) ioreq
->iouh_Data
)[1] = 0;
516 ioreq
->iouh_Actual
= 2;
518 ReplyMsg(&ioreq
->iouh_Req
.io_Message
);
519 ioreq
= (struct IOUsbHWReq
*) otg_Unit
->hu_IOPendingQueue
.lh_Head
;
521 otg_Unit
->hu_HubPortChanged
= FALSE
;