revert between 56095 -> 55830 in arch
[AROS.git] / arch / arm-native / soc / broadcom / 2708 / usb / usb2otg / usb2otg_hub.c
blob3009220cee2562a0b9be95b3032c2cba9dfa09b9
1 /*
2 Copyright © 2013-2019, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #define DEBUG 0
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;
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);
59 #endif
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 + 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;
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 #if (0)
178 ULONG oldval = *((volatile unsigned int *)USB2OTG_HOSTPORT) & ~(USB2OTG_HOSTPORT_PRTENCHNG|USB2OTG_HOSTPORT_PRTCONNSTS);
179 ULONG newval = oldval;
180 #else
181 unsigned int otg_RegVal;
182 #endif
183 switch (val)
185 case UFS_PORT_ENABLE:
186 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld enable requested although OTG cannot do that!\n", idx));
187 break;
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);
196 cmdgood = TRUE;
198 break;
200 case UFS_PORT_RESET:
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);
243 DeleteMsgPort(port);
245 cmdgood = TRUE;
247 break;
249 case UFS_PORT_POWER:
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);
256 cmdgood = TRUE;
258 break;
261 case UFS_PORT_LOW_SPEED:
262 case UFS_C_PORT_CONNECTION:
263 case UFS_C_PORT_OVER_CURRENT:
265 default:
266 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_SET_FEATURE - Unhandled feature %ld for Port #%ld\n", val, idx));
267 break;
269 if (cmdgood)
271 #if (0)
272 *((volatile unsigned int *)USB2OTG_HOSTPORT) = newval;
273 #endif
274 return (0);
277 break;
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);
288 cmdgood = FALSE;
290 ULONG oldval = rd32le(USB2OTG_HOSTPORT) & ~USB2OTG_HOSTPORT_SC_BITS;
291 ULONG newval = oldval;
293 switch (val)
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;
299 cmdgood = TRUE;
301 break;
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;
307 cmdgood = TRUE;
309 break;
311 case UFS_PORT_POWER:
312 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE Port #%ld Power\n", idx));
314 newval &= ~USB2OTG_HOSTPORT_PRTPWR;
315 cmdgood = TRUE;
317 break;
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;
324 cmdgood = TRUE;
326 break;
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;
333 cmdgood = TRUE;
335 break;
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;
342 cmdgood = TRUE;
344 break;
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;
351 cmdgood = TRUE;
353 break;
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;
360 cmdgood = TRUE;
362 break;
364 default:
365 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: USR_CLEAR_FEATURE - Unhandled feature %ld for Port #%ld\n", val, idx));
366 break;
368 if (cmdgood)
370 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Port #%ld CLEAR_FEATURE %04lx->%04lx\n", idx, oldval, newval));
371 wr32le(USB2OTG_HOSTPORT, newval);
373 return (0);
375 break;
378 break;
381 case (URTF_IN|URTF_CLASS|URTF_OTHER):
383 switch (req)
385 case USR_GET_STATUS:
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);
403 *mptr = 0;
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)
412 case 0:
413 *mptr |= AROS_WORD2LE(UPSF_PORT_HIGH_SPEED);
414 break;
415 case 2:
416 *mptr |= AROS_WORD2LE(UPSF_PORT_LOW_SPEED);
417 break;
418 default:
419 break;
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)));
425 mptr++;
426 *mptr = 0;
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)));
433 return (0);
436 break;
439 case (URTF_IN|URTF_CLASS|URTF_DEVICE):
441 switch (req)
443 case USR_GET_STATUS:
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);
454 *mptr++ = 0;
455 *mptr++ = 0;
456 ioreq->iouh_Actual = 4;
457 return (0);
460 case USR_GET_DESCRIPTOR:
462 switch (val >> 8)
464 case UDT_HUB:
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)
482 if (hubdesclen == 9)
484 uhd->DeviceRemovable = 0;
485 uhd->PortPwrCtrlMask = (1 << 3) - 2;
486 } else {
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;
494 return (0);
497 default:
498 D(bug("[USB2OTG:Hub] UHCMD_CONTROLXFER: Unsupported Descriptor %04lx\n", idx));
499 break;
501 break;
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;
532 else
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;
540 return 0;
543 D(bug("[USB2OTG:Hub] UHCMD_INTXFER: Queueing request\n"));
545 ioreq->iouh_Req.io_Flags &= ~IOF_QUICK;
546 Disable();
547 AddTail(&otg_Unit->hu_IOPendingQueue, (struct Node *)ioreq);
548 Enable();
550 return RC_DONTREPLY;
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"));
562 Disable();
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;
571 } else {
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;
580 Enable();