make sure we open kernel resource. slightly change the device name (since we _could_...
[AROS.git] / arch / arm-native / soc / broadcom / 2708 / usb / usb2otg / usb2otg_hub.c
blobae3f797d73ff9e3df8cca930b730c288f8947ccc
1 /*
2 Copyright © 2013-2015, 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 <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);
27 BOOL cmdgood;
28 ULONG cnt;
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);
37 #endif
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);
45 switch (rt)
47 case (URTF_STANDARD|URTF_DEVICE):
48 switch (req)
50 case USR_SET_ADDRESS:
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;
60 return (0);
62 case USR_SET_CONFIGURATION:
63 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Set Device Configuration to #%ld\n", val));
64 ioreq->iouh_Actual = len;
65 return (0);
67 break;
69 case (URTF_IN|URTF_STANDARD|URTF_DEVICE):
70 switch (req)
72 case USR_GET_STATUS:
73 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: GetStatus (%ld)\n", len));
74 if (len == 2);
76 UWORD *mptr = ioreq->iouh_Data;
77 *mptr++ = AROS_WORD2LE(U_GSF_SELF_POWERED);
78 return (0);
80 break;
82 case USR_GET_DESCRIPTOR:
83 switch (val >> 8)
85 case UDT_DEVICE:
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);
90 return (0);
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);
97 return (0);
99 case UDT_STRING:
100 if (val & 0xFF) /* get lang array */
102 CONST_STRPTR source = NULL;
103 UWORD *mptr = ioreq->iouh_Data;
104 UWORD slen;
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);
114 if (len > 1)
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;
123 if (!(*source))
125 break;
129 } else {
130 UWORD *mptr = ioreq->iouh_Data;
131 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: GetLangArray %04lx (%ld)\n", val, len));
132 if (len > 1)
134 ioreq->iouh_Actual = 2;
135 mptr[0] = AROS_WORD2BE((4 << 8)|UDT_STRING);
136 if (len > 3)
138 ioreq->iouh_Actual += 2;
139 mptr[1] = AROS_WORD2LE(0x0409);
143 return (0);
145 default:
146 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Unsupported Descriptor %04lx\n", idx));
147 break;
149 break;
151 case USR_GET_CONFIGURATION:
152 if (len == 1)
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;
157 return (0);
159 break;
161 break;
163 case (URTF_CLASS|URTF_OTHER):
165 switch (req)
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);
175 cmdgood = FALSE;
177 ULONG oldval = *((volatile unsigned int *)USB2OTG_HOSTPORT) & ~(USB2OTG_HOSTPORT_PRTENCHNG|USB2OTG_HOSTPORT_PRTCONNSTS);
178 ULONG newval = oldval;
180 switch (val)
182 case UFS_PORT_ENABLE:
183 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Enabling Port #%ld\n", idx));
185 newval |= USB2OTG_HOSTPORT_PRTENA;
186 cmdgood = TRUE;
188 break;
190 case UFS_PORT_SUSPEND:
191 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Suspending Port #%ld\n", idx));
193 newval |= USB2OTG_HOSTPORT_PRTSUSP;
194 cmdgood = TRUE;
196 break;
198 case UFS_PORT_RESET:
199 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Resetting Port #%ld\n", idx));
201 newval |= USB2OTG_HOSTPORT_PRTRST;
202 cmdgood = TRUE;
204 break;
206 case UFS_PORT_POWER:
207 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Powering Port #%ld\n", idx));
209 newval |= USB2OTG_HOSTPORT_PRTPWR;
210 cmdgood = TRUE;
212 break;
215 case UFS_PORT_LOW_SPEED:
216 case UFS_C_PORT_CONNECTION:
217 case UFS_C_PORT_OVER_CURRENT:
219 default:
220 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_SET_FEATURE - Unhandled feature %ld for Port #%ld\n", val, idx));
221 break;
223 if (cmdgood)
225 *((volatile unsigned int *)USB2OTG_HOSTPORT) = newval;
227 return (0);
230 break;
233 case USR_CLEAR_FEATURE:
235 if ((!idx) || (idx > 1))
237 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld out of range\n", idx));
238 return (UHIOERR_STALL);
241 cmdgood = FALSE;
243 ULONG oldval = *((volatile unsigned int *)USB2OTG_HOSTPORT) & ~(USB2OTG_HOSTPORT_PRTENCHNG|USB2OTG_HOSTPORT_PRTCONNSTS);
244 ULONG newval = oldval;
246 switch (val)
248 case UFS_PORT_ENABLE:
249 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Enable\n", idx));
251 newval &= ~USB2OTG_HOSTPORT_PRTENA;
252 cmdgood = TRUE;
254 break;
256 case UFS_PORT_SUSPEND:
257 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Suspend\n", idx));
259 newval &= ~USB2OTG_HOSTPORT_PRTSUSP;
260 cmdgood = TRUE;
262 break;
264 case UFS_PORT_POWER:
265 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Power\n", idx));
267 newval &= ~USB2OTG_HOSTPORT_PRTPWR;
268 cmdgood = TRUE;
270 break;
272 case UFS_C_PORT_CONNECTION:
273 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Connect Change\n", idx));
275 newval &= ~USB2OTG_HOSTPORT_PRTCONNDET;
276 otg_Unit->hu_HubPortChanged = TRUE;
277 cmdgood = TRUE;
279 break;
281 case UFS_C_PORT_ENABLE:
282 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Enable Change\n", idx));
284 newval &= ~USB2OTG_HOSTPORT_PRTENCHNG;
285 otg_Unit->hu_HubPortChanged = TRUE;
286 cmdgood = TRUE;
288 break;
290 case UFS_C_PORT_SUSPEND:
291 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Suspend Change\n", idx));
293 newval &= ~USB2OTG_HOSTPORT_PRTRES;
294 otg_Unit->hu_HubPortChanged = TRUE;
295 cmdgood = TRUE;
297 break;
299 case UFS_C_PORT_OVER_CURRENT:
300 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Over-Current Change\n", idx));
302 newval &= ~USB2OTG_HOSTPORT_PRTOVRCURRCHNG;
303 otg_Unit->hu_HubPortChanged = TRUE;
304 cmdgood = TRUE;
306 break;
308 case UFS_C_PORT_RESET:
309 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Reset Change\n", idx));
311 newval &= ~USB2OTG_HOSTPORT_PRTRST;
312 otg_Unit->hu_HubPortChanged = TRUE;
313 cmdgood = TRUE;
315 break;
317 default:
318 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE - Unhandled feature %ld for Port #%ld\n", val, idx));
319 break;
321 if (cmdgood)
323 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld CLEAR_FEATURE %04lx->%04lx\n", idx, oldval, newval));
324 *((volatile unsigned int *)USB2OTG_HOSTPORT) = newval;
326 return (0);
328 break;
331 break;
334 case (URTF_IN|URTF_CLASS|URTF_OTHER):
336 switch (req)
338 case USR_GET_STATUS:
340 UWORD *mptr = ioreq->iouh_Data;
342 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Get Port #%ld Status..\n", idx));
344 if (len != sizeof(struct UsbPortStatus))
346 return (UHIOERR_STALL);
348 if ((!idx) || (idx > 1))
350 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld out of range\n", idx));
351 return (UHIOERR_STALL);
354 ULONG oldval = *((volatile unsigned int *)USB2OTG_HOSTPORT);
356 *mptr = 0;
357 if (oldval & USB2OTG_HOSTPORT_PRTPWR) *mptr |= AROS_WORD2LE(UPSF_PORT_POWER);
358 if (oldval & USB2OTG_HOSTPORT_PRTENA) *mptr |= AROS_WORD2LE(UPSF_PORT_ENABLE);
359 if (oldval & USB2OTG_HOSTPORT_PRTCONNSTS) *mptr |= AROS_WORD2LE(UPSF_PORT_CONNECTION);
360 if (oldval & USB2OTG_HOSTPORT_PRTSPD_LOW) *mptr |= AROS_WORD2LE(UPSF_PORT_LOW_SPEED);
361 if (oldval & USB2OTG_HOSTPORT_PRTRST) *mptr |= AROS_WORD2LE(UPSF_PORT_RESET);
362 if (oldval & USB2OTG_HOSTPORT_PRTSUSP) *mptr |= AROS_WORD2LE(UPSF_PORT_SUSPEND);
364 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld is %s\n", idx, (oldval & USB2OTG_HOSTPORT_PRTSPD_LOW) ? "LOWSPEED" : "FULLSPEED"));
365 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld Status %08lx\n", idx, *mptr));
367 mptr++;
368 *mptr = 0;
369 if (oldval & USB2OTG_HOSTPORT_PRTENCHNG) *mptr |= AROS_WORD2LE(UPSF_PORT_ENABLE);
370 if (oldval & USB2OTG_HOSTPORT_PRTCONNDET) *mptr |= AROS_WORD2LE(UPSF_PORT_CONNECTION);
371 if (oldval & USB2OTG_HOSTPORT_PRTRES) *mptr |= AROS_WORD2LE(UPSF_PORT_SUSPEND|UPSF_PORT_ENABLE);
373 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld Change %08lx\n", idx, *mptr));
375 return (0);
378 break;
381 case (URTF_IN|URTF_CLASS|URTF_DEVICE):
383 switch (req)
385 case USR_GET_STATUS:
387 UWORD *mptr = ioreq->iouh_Data;
389 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: GetHubStatus (%ld)\n", len));
391 if (len < sizeof(struct UsbHubStatus))
393 return(UHIOERR_STALL);
396 *mptr++ = 0;
397 *mptr++ = 0;
398 ioreq->iouh_Actual = 4;
399 return (0);
402 case USR_GET_DESCRIPTOR:
404 switch (val >> 8)
406 case UDT_HUB:
408 ULONG hubdesclen = 9;
409 ULONG powergood = 1;
411 struct UsbHubDesc *uhd = (struct UsbHubDesc *) ioreq->iouh_Data;
412 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: GetHubDescriptor (%ld)\n", len));
414 ioreq->iouh_Actual = (len > hubdesclen) ? hubdesclen : len;
415 CopyMem((APTR)&OTGRootHubDesc, ioreq->iouh_Data, ioreq->iouh_Actual);
417 if (ioreq->iouh_Length)
419 uhd->bLength = hubdesclen;
422 if (ioreq->iouh_Length >= hubdesclen)
424 if (hubdesclen == 9)
426 uhd->DeviceRemovable = 0;
427 uhd->PortPwrCtrlMask = (1 << 3) - 2;
428 } else {
429 // each field is 16 bits wide
430 uhd->DeviceRemovable = 0;
431 uhd->PortPwrCtrlMask = 0;
432 ((UBYTE *)ioreq->iouh_Data)[9] = (1 << 3) - 2;
433 ((UBYTE *)ioreq->iouh_Data)[10] = ((1 << 3) - 2) >> 8;
436 return (0);
439 default:
440 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Unsupported Descriptor %04lx\n", idx));
441 break;
443 break;
449 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Unsupported command %02lx %02lx %04lx %04lx %04lx!\n", rt, req, idx, val, len));
451 return (UHIOERR_STALL);
454 WORD FNAME_ROOTHUB(cmdIntXFer)(struct IOUsbHWReq *ioreq,
455 struct USB2OTGUnit *otg_Unit,
456 LIBBASETYPEPTR USB2OTGBase)
458 D(bug("[USB2OTG:Hub] UHCMD_INTXFER()\n"));
460 if ((ioreq->iouh_Endpoint != 1) || (!ioreq->iouh_Length))
462 return UHIOERR_STALL;
465 if (otg_Unit->hu_HubPortChanged)
467 D(bug("[USB2OTG:Hub] UHCMD_INTXFER: Registering Immediate Portchange\n"));
469 if (ioreq->iouh_Length == 1)
471 *((UBYTE *) ioreq->iouh_Data) = 1;
472 ioreq->iouh_Actual = 1;
474 else
476 ((UBYTE *) ioreq->iouh_Data)[0] = 1;
477 ((UBYTE *) ioreq->iouh_Data)[1] = 0;
478 ioreq->iouh_Actual = 2;
480 otg_Unit->hu_HubPortChanged = FALSE;
482 return 0;
485 D(bug("[USB2OTG:Hub] UHCMD_INTXFER: Queueing request\n"));
487 ioreq->iouh_Req.io_Flags &= ~IOF_QUICK;
488 Disable();
489 AddTail(&otg_Unit->hu_IOPendingQueue, (struct Node *)ioreq);
490 Enable();
492 return RC_DONTREPLY;
495 void FNAME_ROOTHUB(PendingIO)(struct USB2OTGUnit *otg_Unit)
497 struct IOUsbHWReq *ioreq;
499 if (otg_Unit->hu_HubPortChanged && otg_Unit->hu_IOPendingQueue.lh_Head->ln_Succ)
501 D(bug("[USB2OTG:Hub] PendingIO: PortChange detected\n"));
502 Disable();
503 ioreq = (struct IOUsbHWReq *) otg_Unit->hu_IOPendingQueue.lh_Head;
504 while (((struct Node *) ioreq)->ln_Succ)
506 Remove(&ioreq->iouh_Req.io_Message.mn_Node);
507 if (ioreq->iouh_Length == 1)
509 *((UBYTE *) ioreq->iouh_Data) = 1;
510 ioreq->iouh_Actual = 1;
511 } else {
512 ((UBYTE *) ioreq->iouh_Data)[0] = 1;
513 ((UBYTE *) ioreq->iouh_Data)[1] = 0;
514 ioreq->iouh_Actual = 2;
516 ReplyMsg(&ioreq->iouh_Req.io_Message);
517 ioreq = (struct IOUsbHWReq *) otg_Unit->hu_IOPendingQueue.lh_Head;
519 otg_Unit->hu_HubPortChanged = FALSE;
520 Enable();