place-holder for restructure
[AROS.git] / arch / arm-raspi / usb / usb2otg / usb2otg_hub.c
blob669b2837299a8697789795d5d33cc9002299d8ec
1 /*
2 Copyright © 2013, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #define DEBUG 1
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);
29 BOOL cmdgood;
30 ULONG cnt;
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);
39 #endif
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);
47 switch (rt)
49 case (URTF_STANDARD|URTF_DEVICE):
50 switch (req)
52 case USR_SET_ADDRESS:
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;
62 return (0);
64 case USR_SET_CONFIGURATION:
65 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Set Device Configuration to #%ld\n", val));
66 ioreq->iouh_Actual = len;
67 return (0);
69 break;
71 case (URTF_IN|URTF_STANDARD|URTF_DEVICE):
72 switch (req)
74 case USR_GET_STATUS:
75 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: GetStatus (%ld)\n", len));
76 if (len == 2);
78 UWORD *mptr = ioreq->iouh_Data;
79 *mptr++ = AROS_WORD2LE(U_GSF_SELF_POWERED);
80 return (0);
82 break;
84 case USR_GET_DESCRIPTOR:
85 switch (val >> 8)
87 case UDT_DEVICE:
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);
92 return (0);
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);
99 return (0);
101 case UDT_STRING:
102 if (val & 0xFF) /* get lang array */
104 CONST_STRPTR source = NULL;
105 UWORD *mptr = ioreq->iouh_Data;
106 UWORD slen;
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);
116 if (len > 1)
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;
125 if (!(*source))
127 break;
131 } else {
132 UWORD *mptr = ioreq->iouh_Data;
133 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: GetLangArray %04lx (%ld)\n", val, len));
134 if (len > 1)
136 ioreq->iouh_Actual = 2;
137 mptr[0] = AROS_WORD2BE((4 << 8)|UDT_STRING);
138 if (len > 3)
140 ioreq->iouh_Actual += 2;
141 mptr[1] = AROS_WORD2LE(0x0409);
145 return (0);
147 default:
148 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Unsupported Descriptor %04lx\n", idx));
149 break;
151 break;
153 case USR_GET_CONFIGURATION:
154 if (len == 1)
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;
159 return (0);
161 break;
163 break;
165 case (URTF_CLASS|URTF_OTHER):
167 switch (req)
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);
177 cmdgood = FALSE;
179 ULONG oldval = *((volatile unsigned int *)USB2OTG_HOSTPORT) & ~(USB2OTG_HOSTPORT_PRTENCHNG|USB2OTG_HOSTPORT_PRTCONNSTS);
180 ULONG newval = oldval;
182 switch (val)
184 case UFS_PORT_ENABLE:
185 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Enabling Port #%ld\n", idx));
187 newval |= USB2OTG_HOSTPORT_PRTENA;
188 cmdgood = TRUE;
190 break;
192 case UFS_PORT_SUSPEND:
193 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Suspending Port #%ld\n", idx));
195 newval |= USB2OTG_HOSTPORT_PRTSUSP;
196 cmdgood = TRUE;
198 break;
200 case UFS_PORT_RESET:
201 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Resetting Port #%ld\n", idx));
203 newval |= USB2OTG_HOSTPORT_PRTRST;
204 cmdgood = TRUE;
206 break;
208 case UFS_PORT_POWER:
209 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Powering Port #%ld\n", idx));
211 newval |= USB2OTG_HOSTPORT_PRTPWR;
212 cmdgood = TRUE;
214 break;
217 case UFS_PORT_LOW_SPEED:
218 case UFS_C_PORT_CONNECTION:
219 case UFS_C_PORT_OVER_CURRENT:
221 default:
222 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_SET_FEATURE - Unhandled feature %ld for Port #%ld\n", val, idx));
223 break;
225 if (cmdgood)
227 *((volatile unsigned int *)USB2OTG_HOSTPORT) = newval;
229 return (0);
232 break;
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);
243 cmdgood = FALSE;
245 ULONG oldval = *((volatile unsigned int *)USB2OTG_HOSTPORT) & ~(USB2OTG_HOSTPORT_PRTENCHNG|USB2OTG_HOSTPORT_PRTCONNSTS);
246 ULONG newval = oldval;
248 switch (val)
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;
254 cmdgood = TRUE;
256 break;
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;
262 cmdgood = TRUE;
264 break;
266 case UFS_PORT_POWER:
267 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Power\n", idx));
269 newval &= ~USB2OTG_HOSTPORT_PRTPWR;
270 cmdgood = TRUE;
272 break;
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;
279 cmdgood = TRUE;
281 break;
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;
288 cmdgood = TRUE;
290 break;
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;
297 cmdgood = TRUE;
299 break;
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;
306 cmdgood = TRUE;
308 break;
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;
315 cmdgood = TRUE;
317 break;
319 default:
320 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE - Unhandled feature %ld for Port #%ld\n", val, idx));
321 break;
323 if (cmdgood)
325 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld CLEAR_FEATURE %04lx->%04lx\n", idx, oldval, newval));
326 *((volatile unsigned int *)USB2OTG_HOSTPORT) = newval;
328 return (0);
330 break;
333 break;
336 case (URTF_IN|URTF_CLASS|URTF_OTHER):
338 switch (req)
340 case USR_GET_STATUS:
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);
358 *mptr = 0;
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));
369 mptr++;
370 *mptr = 0;
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));
377 return (0);
380 break;
383 case (URTF_IN|URTF_CLASS|URTF_DEVICE):
385 switch (req)
387 case USR_GET_STATUS:
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);
398 *mptr++ = 0;
399 *mptr++ = 0;
400 ioreq->iouh_Actual = 4;
401 return (0);
404 case USR_GET_DESCRIPTOR:
406 switch (val >> 8)
408 case UDT_HUB:
410 ULONG hubdesclen = 9;
411 ULONG powergood = 1;
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)
426 if (hubdesclen == 9)
428 uhd->DeviceRemovable = 0;
429 uhd->PortPwrCtrlMask = (1 << 3) - 2;
430 } else {
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;
438 return (0);
441 default:
442 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Unsupported Descriptor %04lx\n", idx));
443 break;
445 break;
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;
476 else
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;
484 return 0;
487 D(bug("[USB2OTG:Hub] UHCMD_INTXFER: Queueing request\n"));
489 ioreq->iouh_Req.io_Flags &= ~IOF_QUICK;
490 Disable();
491 AddTail(&otg_Unit->hu_IOPendingQueue, (struct Node *)ioreq);
492 Enable();
494 return RC_DONTREPLY;
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"));
504 Disable();
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;
513 } else {
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;
522 Enable();