Minor cleanup and fixing string descriptor for language
[AROS.git] / rom / usb / vusbhc / vxhci / vxhci_device.c
blob97c17d54d530305a1c824ee9af30f1a33f63224a
1 /*
2 Copyright © 2014, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Virtual XHCI USB host controller
6 Lang: English
7 */
9 #ifdef DEBUG
10 #undef DEBUG
11 #endif
12 #define DEBUG 1
14 #include <aros/macros.h>
16 #include <proto/exec.h>
17 #include <proto/stdc.h>
18 #include <proto/arossupport.h>
20 #include <devices/usb.h>
21 #include <devices/usb_hub.h>
22 #include <devices/newstyle.h>
23 #include <devices/usbhardware.h>
25 #include "vxhci_device.h"
27 #include LC_LIBDEFS_FILE
29 struct VXHCIUnit *VXHCI_AddNewUnit(ULONG unitnum, UWORD bcdusb);
30 struct VXHCIPort *VXHCI_AddNewPort(struct VXHCIUnit *unit, ULONG portnum);
32 static int GM_UNIQUENAME(Init)(LIBBASETYPEPTR VXHCIBase) {
33 mybug(0,("[VXHCI] Init: Entering function\n"));
35 struct VXHCIUnit *unit;
36 ULONG i;
38 NEWLIST(&VXHCIBase->unit_list);
39 VXHCIBase->unit_count = 0;
41 for (i=0; i<VXHCI_NUMCONTROLLERS; i++) {
43 #ifdef VXHCI_NUMPORTS20
44 unit = VXHCI_AddNewUnit(VXHCIBase->unit_count, 0x210);
45 if(unit == NULL) {
46 mybug(-1, ("[VXHCI] Init: Failed to create new unit!\n"));
49 Free previous units if any exists
52 ForeachNode(&VXHCIBase->unit_list, unit) {
53 mybug(-1,("[VXHCI] Init: Removing unit structure %s at %p\n", unit->node.ln_Name, unit));
54 REMOVE(unit);
55 FreeVec(unit);
57 return FALSE;
58 } else {
59 AddTail(&VXHCIBase->unit_list,(struct Node *)unit);
60 VXHCIBase->unit_count++;
62 #endif
64 unit = VXHCI_AddNewUnit(VXHCIBase->unit_count, 0x310);
65 if(unit == NULL) {
66 mybug(-1, ("[VXHCI] Init: Failed to create new unit!\n"));
69 Free previous units if any exists
72 ForeachNode(&VXHCIBase->unit_list, unit) {
73 mybug(-1,("[VXHCI] Init: Removing unit structure %s at %p\n", unit->node.ln_Name, unit));
74 REMOVE(unit);
75 FreeVec(unit);
77 return FALSE;
78 } else {
79 AddTail(&VXHCIBase->unit_list,(struct Node *)unit);
80 VXHCIBase->unit_count++;
85 D(ForeachNode(&VXHCIBase->unit_list, unit) {
86 mybug(-1, ("[VXHCI] Init: Created unit %d at %p %s\n", unit->number, unit, unit->name));
87 struct VXHCIPort *port;
88 ForeachNode(&unit->roothub.port_list, port) {
89 mybug(-1, (" port %d at %p %s\n", port->number, port, port->name));
91 mybug(-1,("\n"));
92 });
94 return TRUE;
97 static int GM_UNIQUENAME(Open)(LIBBASETYPEPTR VXHCIBase, struct IOUsbHWReq *ioreq, ULONG unitnum, ULONG flags) {
98 mybug(0, ("[VXHCI] Open: Entering function\n"));
99 mybug(0, ("[VXHCI] Open: Unit %d\n", unitnum));
101 struct VXHCIUnit *unit;
103 /* Default to open failure. */
104 ioreq->iouh_Req.io_Error = IOERR_OPENFAIL;
105 ioreq->iouh_Req.io_Unit = NULL;
108 Number of units eg. virtual xhci controllers.
109 Host controller is divided into individual units if it has both usb2.0 and usb3.0 ports
111 if(unitnum<VXHCIBase->unit_count) {
113 if(ioreq->iouh_Req.io_Message.mn_Length < sizeof(struct IOUsbHWReq)) {
114 mybug(-1, ("[VXHCI] Open: Invalid MN_LENGTH!\n"));
115 ioreq->iouh_Req.io_Error = IOERR_BADLENGTH;
118 ioreq->iouh_Req.io_Unit = NULL;
120 ForeachNode(&VXHCIBase->unit_list, unit) {
121 mybug(0, ("[VXHCI] Open: Opening unit number %d\n", unitnum));
122 if(unit->number == unitnum) {
123 mybug(0, (" Found unit from node list %s %p\n\n", unit->name, unit));
124 ioreq->iouh_Req.io_Unit = (struct Unit *) unit;
125 break;
129 if(ioreq->iouh_Req.io_Unit != NULL) {
131 /* Opened ok! */
132 ioreq->iouh_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
133 ioreq->iouh_Req.io_Error = 0;
135 return TRUE;
136 } else {
137 return FALSE;
141 return FALSE;
144 static int GM_UNIQUENAME(Close)(LIBBASETYPEPTR VXHCIBase, struct IOUsbHWReq *ioreq) {
145 mybug(0, ("[VXHCI] Close: Entering function\n"));
147 ioreq->iouh_Req.io_Unit = (APTR) -1;
148 ioreq->iouh_Req.io_Device = (APTR) -1;
150 return TRUE;
153 ADD2INITLIB(GM_UNIQUENAME(Init), 0)
154 ADD2OPENDEV(GM_UNIQUENAME(Open), 0)
155 ADD2CLOSEDEV(GM_UNIQUENAME(Close), 0)
157 AROS_LH1(void, BeginIO, AROS_LHA(struct IOUsbHWReq *, ioreq, A1), struct VXHCIBase *, VXHCIBase, 5, VXHCI) {
158 AROS_LIBFUNC_INIT
159 mybug(0, ("[VXHCI] BeginIO: Entering function\n"));
161 WORD ret = RC_OK;
163 ioreq->iouh_Req.io_Message.mn_Node.ln_Type = NT_MESSAGE;
164 ioreq->iouh_Req.io_Error = UHIOERR_NO_ERROR;
166 struct VXHCIUnit *unit = (struct VXHCIUnit *) ioreq->iouh_Req.io_Unit;
168 if(unit != NULL) {
170 switch (ioreq->iouh_Req.io_Command) {
171 case CMD_RESET:
172 mybug_unit(0, ("CMD_RESET\n"));
173 break;
174 case CMD_FLUSH:
175 mybug_unit(0, ("CMD_FLUSH\n"));
176 break;
177 case UHCMD_QUERYDEVICE:
178 mybug_unit(0, ("UHCMD_QUERYDEVICE\n"));
179 ret = cmdQueryDevice(ioreq);
180 break;
181 case UHCMD_USBRESET:
182 mybug_unit(0, ("UHCMD_USBRESET\n"));
183 ret = cmdUsbReset(ioreq);
184 break;
185 case UHCMD_USBRESUME:
186 mybug_unit(0, ("UHCMD_USBRESUME\n"));
187 break;
188 case UHCMD_USBSUSPEND:
189 mybug_unit(0, ("UHCMD_USBSUSPEND\n"));
190 break;
191 case UHCMD_USBOPER:
192 mybug_unit(0, ("UHCMD_USBOPER\n"));
193 //ret = cmdUsbOper(ioreq);
194 break;
195 case UHCMD_CONTROLXFER:
196 mybug_unit(0, ("UHCMD_CONTROLXFER unit %p %s\n", unit, unit->name));
197 ret = cmdControlXFer(ioreq);
198 break;
199 case UHCMD_BULKXFER:
200 mybug_unit(0, ("UHCMD_BULKXFER\n"));
201 break;
202 case UHCMD_INTXFER:
203 mybug_unit(0, ("UHCMD_INTXFER unit %p %s\n", unit, unit->name));
204 ret = cmdIntXFer(ioreq);
205 break;
206 case UHCMD_ISOXFER:
207 mybug_unit(0, ("UHCMD_ISOXFER\n"));
208 break;
210 /* Poseidon doesn't actually check this, ever... */
211 case NSCMD_DEVICEQUERY:
212 mybug_unit(0, ("NSCMD_DEVICEQUERY\n"));
214 static const UWORD NSDSupported[] = {
215 CMD_FLUSH, CMD_RESET,
216 UHCMD_QUERYDEVICE,
217 UHCMD_USBRESET,
218 UHCMD_USBRESUME,
219 UHCMD_USBSUSPEND,
220 UHCMD_USBOPER,
221 UHCMD_CONTROLXFER ,
222 UHCMD_ISOXFER,
223 UHCMD_INTXFER,
224 UHCMD_BULKXFER,
225 NSCMD_DEVICEQUERY,
229 struct NSDeviceQueryResult *nsdq = (struct NSDeviceQueryResult *)((struct IOStdReq *)(ioreq))->io_Data;
230 nsdq->DevQueryFormat = 0;
231 nsdq->SizeAvailable = sizeof(struct NSDeviceQueryResult);
232 nsdq->DeviceType = NSDEVTYPE_USBHARDWARE;
233 nsdq->DeviceSubType = 0;
234 nsdq->SupportedCommands = (UWORD *)NSDSupported;
235 ret = RC_OK;
236 break;
237 default:
238 mybug_unit(-1, ("IOERR_NOCMD\n"));
239 ret = IOERR_NOCMD;
240 break;
242 } else {
243 /* We have aborted the request as unit is invalid */
244 ret = IOERR_ABORTED;
247 if(ret != RC_DONTREPLY) {
248 /* Set error codes */
249 if (ret != RC_OK) {
250 ioreq->iouh_Req.io_Error = ret & 0xff;
252 /* Terminate the iorequest */
253 ioreq->iouh_Req.io_Message.mn_Node.ln_Type = NT_FREEMSG;
254 /* If not quick I/O, reply the message */
255 if(!(ioreq->iouh_Req.io_Flags & IOF_QUICK)) {
256 ReplyMsg(&ioreq->iouh_Req.io_Message);
260 AROS_LIBFUNC_EXIT
263 AROS_LH1(LONG, AbortIO, AROS_LHA(struct IOUsbHWReq *, ioreq, A1), struct VXHCIBase *, VXHCIBase, 6, VXHCI) {
264 AROS_LIBFUNC_INIT
265 mybug(-1, ("[VXHCI] AbortIO: Entering function\n"));
267 struct VXHCIUnit *unit = (struct VXHCIUnit *) ioreq->iouh_Req.io_Unit;
269 mybug_unit(-1, ("Nothing done!\n\n"));
271 return TRUE;
272 AROS_LIBFUNC_EXIT
275 struct VXHCIUnit *VXHCI_AddNewUnit(ULONG unitnum, UWORD bcdusb) {
277 struct VXHCIUnit *unit;
278 struct VXHCIPort *port;
280 ULONG i, imax;
282 unit = AllocVec(sizeof(struct VXHCIUnit), MEMF_ANY|MEMF_CLEAR);
283 if(unit == NULL) {
284 mybug(-1, ("[VXHCI] VXHCI_AddNewUnit: Failed to create new unit structure\n"));
285 return NULL;
286 } else {
287 unit->node.ln_Type = NT_USER;
288 unit->number = unitnum;
289 unit->node.ln_Name = (STRPTR)&unit->name;
290 unit->state = UHSF_SUSPENDED;
292 NEWLIST(&unit->roothub.port_list);
294 /* Set the correct bcdUSB and bcdDevice for the hub device descriptor */
295 if(bcdusb>=0x0300) {
296 unit->roothub.devdesc.bcdUSB = AROS_WORD2LE(0x0300);
297 } else {
298 unit->roothub.devdesc.bcdUSB = AROS_WORD2LE(0x0200);
301 unit->roothub.devdesc.bcdDevice = AROS_WORD2LE(bcdusb);
303 sprintf(unit->name, "VXHCI_USB%x%x[%d]", (AROS_LE2WORD(unit->roothub.devdesc.bcdUSB)>>8)&0xf, (AROS_LE2WORD(unit->roothub.devdesc.bcdUSB)>>4)&0xf, unit->number);
305 #ifdef VXHCI_NUMPORTS20
306 if( (bcdusb >= 0x0200) && (bcdusb < 0x0300) ) {
307 unit->roothub.devdesc.bMaxPacketSize0 = 8;
308 unit->roothub.devdesc.bDeviceProtocol = 1;
309 unit->roothub.config.epdesc.wMaxPacketSize = AROS_WORD2LE(8);
310 imax = VXHCI_NUMPORTS20;
311 } else {
312 unit->roothub.devdesc.bMaxPacketSize0 = 9;
313 unit->roothub.devdesc.bDeviceProtocol = 3;
314 unit->roothub.config.epdesc.wMaxPacketSize = AROS_WORD2LE(1024);
315 imax = VXHCI_NUMPORTS30;
317 #else
318 unit->roothub.devdesc.bMaxPacketSize0 = 9;
319 unit->roothub.devdesc.bDeviceProtocol = 3;
320 unit->roothub.config.epdesc.wMaxPacketSize = AROS_WORD2LE(1024);
321 imax = VXHCI_NUMPORTS30;
322 #endif
324 for (i=0; i<imax; i++) {
326 port = VXHCI_AddNewPort(unit, i);
327 if(port == NULL) {
328 mybug(-1, ("[VXHCI] VXHCI_AddNewUnit: Failed to create new port structure\n"));
331 Free previous ports if any exists and delete this unit
334 ForeachNode(&unit->roothub.port_list, port) {
335 mybug(-1, ("[VXHCI] VXHCI_AddNewUnit: Removing port structure %s at %p\n", port->node.ln_Name, port));
336 REMOVE(port);
337 FreeVec(port);
339 FreeVec(unit);
340 return NULL;
341 } else {
342 AddTail(&unit->roothub.port_list,(struct Node *)port);
343 unit->roothub.port_count++;
347 /* This is our root hub device descriptor */
348 unit->roothub.devdesc.bLength = sizeof(struct UsbStdDevDesc);
349 unit->roothub.devdesc.bDescriptorType = UDT_DEVICE;
350 //unit->roothub.devdesc.bcdUSB = AROS_WORD2LE(0xJJMN);
351 unit->roothub.devdesc.bDeviceClass = HUB_CLASSCODE;
352 //unit->roothub.devdesc.bDeviceSubClass = 0;
353 //unit->roothub.devdesc.bDeviceProtocol = 0;
354 //unit->roothub.devdesc.bMaxPacketSize0 = 9; // Valid values are 8, 9(SuperSpeed), 16, 32, 64
355 //unit->roothub.devdesc.idVendor = AROS_WORD2LE(0x0000);
356 //unit->roothub.devdesc.idProduct = AROS_WORD2LE(0x0000);
357 //unit->roothub.devdesc.bcdDevice = AROS_WORD2LE(0xJJMN);
358 unit->roothub.devdesc.iManufacturer = 1;
359 unit->roothub.devdesc.iProduct = 2;
360 //unit->roothub.devdesc.iSerialNumber = 0;
361 unit->roothub.devdesc.bNumConfigurations = 1;
363 /* This is our root hub config descriptor */
364 unit->roothub.config.cfgdesc.bLength = sizeof(struct UsbStdCfgDesc);
365 unit->roothub.config.cfgdesc.bLength = sizeof(struct UsbStdCfgDesc);
366 unit->roothub.config.cfgdesc.bDescriptorType = UDT_CONFIGURATION;
367 unit->roothub.config.cfgdesc.wTotalLength = AROS_WORD2LE(sizeof(struct RHConfig));
368 unit->roothub.config.cfgdesc.bNumInterfaces = 1;
369 unit->roothub.config.cfgdesc.bConfigurationValue = 1;
370 unit->roothub.config.cfgdesc.iConfiguration = 3;
371 unit->roothub.config.cfgdesc.bmAttributes = (USCAF_ONE|USCAF_SELF_POWERED);
372 //unit->roothub.config.cfgdesc.bMaxPower = 0;
374 unit->roothub.config.ifdesc.bLength = sizeof(struct UsbStdIfDesc);
375 unit->roothub.config.ifdesc.bDescriptorType = UDT_INTERFACE;
376 //unit->roothub.config.ifdesc.bInterfaceNumber = 0;
377 //unit->roothub.config.ifdesc.bAlternateSetting = 0;
378 unit->roothub.config.ifdesc.bNumEndpoints = 1;
379 unit->roothub.config.ifdesc.bInterfaceClass = HUB_CLASSCODE;
380 //unit->roothub.config.ifdesc.bInterfaceSubClass = 0;
381 //unit->roothub.config.ifdesc.bInterfaceProtocol = 0;
382 unit->roothub.config.ifdesc.iInterface = 4;
384 unit->roothub.config.epdesc.bLength = sizeof(struct UsbStdEPDesc);
385 unit->roothub.config.epdesc.bDescriptorType = UDT_ENDPOINT;
386 unit->roothub.config.epdesc.bEndpointAddress = (URTF_IN|1);
387 unit->roothub.config.epdesc.bmAttributes = USEAF_INTERRUPT;
388 //unit->roothub.config.epdesc.wMaxPacketSize = AROS_WORD2LE(8);
389 unit->roothub.config.epdesc.bInterval = 12;
391 /* This is our root hub hub descriptor */
392 if( (bcdusb >= 0x0200) && (bcdusb < 0x0300) ) {
393 unit->roothub.hubdesc.usb20.bLength = sizeof(struct UsbHubDesc);
394 unit->roothub.hubdesc.usb20.bDescriptorType = UDT_HUB;
395 unit->roothub.hubdesc.usb20.bNbrPorts = (UBYTE) unit->roothub.port_count;
396 unit->roothub.hubdesc.usb20.wHubCharacteristics = AROS_WORD2LE(UHCF_INDIVID_POWER|UHCF_INDIVID_OVP);
397 //unit->roothub.hubdesc.usb20.bPwrOn2PwrGood = 0;
398 unit->roothub.hubdesc.usb20.bHubContrCurrent = 1;
399 unit->roothub.hubdesc.usb20.DeviceRemovable = 1;
400 //unit->roothub.hubdesc.usb20.PortPwrCtrlMask = 0;
401 } else {
402 unit->roothub.hubdesc.usb30.bLength = sizeof(struct UsbSSHubDesc);
403 unit->roothub.hubdesc.usb30.bDescriptorType = UDT_SSHUB;
404 unit->roothub.hubdesc.usb30.bNbrPorts = (UBYTE) unit->roothub.port_count;;
405 unit->roothub.hubdesc.usb30.wHubCharacteristics = AROS_WORD2LE(UHCF_INDIVID_POWER|UHCF_INDIVID_OVP);
406 //unit->roothub.hubdesc.usb30.bPwrOn2PwrGood = 0;
407 unit->roothub.hubdesc.usb30.bHubContrCurrent = 10;
408 //unit->roothub.hubdesc.usb30.bHubHdrDecLat = 0;
409 //unit->roothub.hubdesc.usb30.wHubDelay = 0;
410 //unit->roothub.hubdesc.usb30.DeviceRemovable = 0;
413 D( mybug(0, ("[VXHCI] VXHCI_AddNewUnit:\n"));
414 mybug(0, (" Created new unit numbered %d at %p\n",unit->number, unit));
415 mybug(0, (" Unit node name %s\n", unit->node.ln_Name));
417 switch(unit->state) {
418 case UHSF_SUSPENDED:
419 mybug(0, (" Unit state: UHSF_SUSPENDED\n"));
420 break;
421 case UHSF_OPERATIONAL:
422 mybug(0, (" Unit state: UHSF_OPERATIONAL\n"));
423 break;
424 default:
425 mybug(0, (" Unit state: %lx (Error?)\n", unit->state));
426 break;
427 } );
429 return unit;
433 struct VXHCIPort *VXHCI_AddNewPort(struct VXHCIUnit *unit, ULONG portnum) {
434 struct VXHCIPort *port;
436 port = AllocVec(sizeof(struct VXHCIPort), MEMF_ANY|MEMF_CLEAR);
437 if(port == NULL) {
438 mybug(-1, ("[VXHCI] VXHCI_AddNewPort: Failed to create new port structure\n"));
439 return NULL;
440 } else {
441 port->node.ln_Type = NT_USER;
442 /* Poseidon treats port number 0 as roothub */
443 port->number = portnum+1;
445 sprintf(port->name, "VXHCI_USB%x%x[%d:%d]", (AROS_LE2WORD(unit->roothub.devdesc.bcdUSB)>>8)&0xf, (AROS_LE2WORD(unit->roothub.devdesc.bcdUSB)>>4)&0xf, unit->number, port->number);
446 port->node.ln_Name = (STRPTR)&port->name;
449 mybug(0, ("[VXHCI] VXHCI_AddNewPort:\n"));
450 mybug(0, (" Created new port numbered %d at %p\n",port->number, port));
451 mybug(0, (" Port node name %s\n", port->node.ln_Name));
453 return port;