For every VXHCI controller create only one roothub (and only one unit per controller...
[AROS.git] / rom / usb / vusbhc / vxhci / vxhci_device.c
blob4762ea3919db67aa665158ec2f57a4bf667a7c9d
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/debug.h>
15 #include <aros/macros.h>
16 #include <aros/asmcall.h>
17 #include <aros/symbolsets.h>
19 #include <proto/exec.h>
20 #include <proto/stdc.h>
21 #include <proto/arossupport.h>
23 #include <devices/usb.h>
24 #include <devices/usb_hub.h>
25 #include <devices/newstyle.h>
26 #include <devices/usbhardware.h>
28 #include "vxhci_device.h"
30 #include LC_LIBDEFS_FILE
32 struct VXHCIUnit *VXHCI_AddNewUnit(ULONG unitnum);
33 struct VXHCIPort *VXHCI_AddNewPort(struct VXHCIUnit *unit, ULONG portnum);
35 static int GM_UNIQUENAME(Init)(LIBBASETYPEPTR VXHCIBase) {
36 mybug(0,("[VXHCI] Init: Entering function\n"));
38 struct VXHCIUnit *unit;
39 ULONG i;
41 NEWLIST(&VXHCIBase->unit_list);
42 VXHCIBase->unit_count = 0;
44 for (i=0; i<VXHCI_NUMCONTROLLERS; i++) {
45 unit = VXHCI_AddNewUnit(VXHCIBase->unit_count);
46 if(unit == NULL) {
47 mybug(-1, ("[VXHCI] Init: Failed to create new unit!\n"));
50 Free previous units if any exists
53 ForeachNode(&VXHCIBase->unit_list, unit) {
54 mybug(-1,("[VXHCI] Init: Removing unit structure %s at %p\n", unit->node.ln_Name, unit));
55 REMOVE(unit);
56 FreeVec(unit);
58 return FALSE;
59 } else {
60 AddTail(&VXHCIBase->unit_list,(struct Node *)unit);
61 VXHCIBase->unit_count++;
66 D(ForeachNode(&VXHCIBase->unit_list, unit) {
67 mybug(-1, ("[VXHCI] Init: Created unit %d at %p %s\n", unit->number, unit, unit->name));
68 struct VXHCIPort *port;
69 ForeachNode(&unit->roothub.port_list, port) {
70 mybug(-1, (" port %d at %p %s\n", port->number, port, port->name));
72 mybug(-1,("\n"));
73 });
75 return TRUE;
78 static int GM_UNIQUENAME(Open)(LIBBASETYPEPTR VXHCIBase, struct IOUsbHWReq *ioreq, ULONG unitnum, ULONG flags) {
79 mybug(0, ("[VXHCI] Open: Entering function\n"));
80 mybug(0, ("[VXHCI] Open: Unit %d\n", unitnum));
82 struct VXHCIUnit *unit;
84 /* Default to open failure. */
85 ioreq->iouh_Req.io_Error = IOERR_OPENFAIL;
86 ioreq->iouh_Req.io_Unit = NULL;
89 Number of units eg. virtual xhci controllers.
90 Host controller is divided into individual units if it has both usb2.0 and usb3.0 ports
92 if(unitnum<VXHCIBase->unit_count) {
94 if(ioreq->iouh_Req.io_Message.mn_Length < sizeof(struct IOUsbHWReq)) {
95 mybug(-1, ("[VXHCI] Open: Invalid MN_LENGTH!\n"));
96 ioreq->iouh_Req.io_Error = IOERR_BADLENGTH;
99 ioreq->iouh_Req.io_Unit = NULL;
101 ForeachNode(&VXHCIBase->unit_list, unit) {
102 mybug(0, ("[VXHCI] Open: Opening unit number %d\n", unitnum));
103 if(unit->number == unitnum) {
104 mybug(0, (" Found unit from node list %s %p\n\n", unit->name, unit));
105 ioreq->iouh_Req.io_Unit = (struct Unit *) unit;
106 break;
110 if(ioreq->iouh_Req.io_Unit != NULL) {
112 /* Opened ok! */
113 ioreq->iouh_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
114 ioreq->iouh_Req.io_Error = 0;
116 return TRUE;
117 } else {
118 return FALSE;
122 return FALSE;
125 static int GM_UNIQUENAME(Close)(LIBBASETYPEPTR VXHCIBase, struct IOUsbHWReq *ioreq) {
126 mybug(0, ("[VXHCI] Close: Entering function\n"));
128 ioreq->iouh_Req.io_Unit = (APTR) -1;
129 ioreq->iouh_Req.io_Device = (APTR) -1;
131 return TRUE;
134 ADD2INITLIB(GM_UNIQUENAME(Init), 0)
135 ADD2OPENDEV(GM_UNIQUENAME(Open), 0)
136 ADD2CLOSEDEV(GM_UNIQUENAME(Close), 0)
138 AROS_LH1(void, BeginIO, AROS_LHA(struct IOUsbHWReq *, ioreq, A1), struct VXHCIBase *, VXHCIBase, 5, VXHCI) {
139 AROS_LIBFUNC_INIT
140 mybug(0, ("[VXHCI] BeginIO: Entering function\n"));
142 WORD ret = RC_OK;
144 ioreq->iouh_Req.io_Message.mn_Node.ln_Type = NT_MESSAGE;
145 ioreq->iouh_Req.io_Error = UHIOERR_NO_ERROR;
147 struct VXHCIUnit *unit = (struct VXHCIUnit *) ioreq->iouh_Req.io_Unit;
149 if(unit != NULL) {
151 switch (ioreq->iouh_Req.io_Command) {
152 case CMD_RESET:
153 mybug_unit(0, ("CMD_RESET\n"));
154 break;
155 case CMD_FLUSH:
156 mybug_unit(0, ("CMD_FLUSH\n"));
157 break;
158 case UHCMD_QUERYDEVICE:
159 mybug_unit(0, ("UHCMD_QUERYDEVICE\n"));
160 ret = cmdQueryDevice(ioreq);
161 break;
162 case UHCMD_USBRESET:
163 mybug_unit(0, ("UHCMD_USBRESET\n"));
164 ret = cmdUsbReset(ioreq);
165 break;
166 case UHCMD_USBRESUME:
167 mybug_unit(0, ("UHCMD_USBRESUME\n"));
168 break;
169 case UHCMD_USBSUSPEND:
170 mybug_unit(0, ("UHCMD_USBSUSPEND\n"));
171 break;
172 case UHCMD_USBOPER:
173 mybug_unit(0, ("UHCMD_USBOPER\n"));
174 //ret = cmdUsbOper(ioreq);
175 break;
176 case UHCMD_CONTROLXFER:
177 mybug_unit(0, ("UHCMD_CONTROLXFER unit %p %s\n", unit, unit->name));
178 ret = cmdControlXFer(ioreq);
179 break;
180 case UHCMD_BULKXFER:
181 mybug_unit(0, ("UHCMD_BULKXFER\n"));
182 break;
183 case UHCMD_INTXFER:
184 mybug_unit(0, ("UHCMD_INTXFER unit %p %s\n", unit, unit->name));
185 ret = cmdIntXFer(ioreq);
186 break;
187 case UHCMD_ISOXFER:
188 mybug_unit(0, ("UHCMD_ISOXFER\n"));
189 break;
191 /* Poseidon doesn't actually check this, ever... */
192 case NSCMD_DEVICEQUERY:
193 mybug_unit(0, ("NSCMD_DEVICEQUERY\n"));
195 static const UWORD NSDSupported[] = {
196 CMD_FLUSH, CMD_RESET,
197 UHCMD_QUERYDEVICE,
198 UHCMD_USBRESET,
199 UHCMD_USBRESUME,
200 UHCMD_USBSUSPEND,
201 UHCMD_USBOPER,
202 UHCMD_CONTROLXFER ,
203 UHCMD_ISOXFER,
204 UHCMD_INTXFER,
205 UHCMD_BULKXFER,
206 NSCMD_DEVICEQUERY,
210 struct NSDeviceQueryResult *nsdq = (struct NSDeviceQueryResult *)((struct IOStdReq *)(ioreq))->io_Data;
211 nsdq->DevQueryFormat = 0;
212 nsdq->SizeAvailable = sizeof(struct NSDeviceQueryResult);
213 nsdq->DeviceType = NSDEVTYPE_USBHARDWARE;
214 nsdq->DeviceSubType = 0;
215 nsdq->SupportedCommands = (UWORD *)NSDSupported;
216 ret = RC_OK;
217 break;
218 default:
219 mybug_unit(-1, ("IOERR_NOCMD\n"));
220 ret = IOERR_NOCMD;
221 break;
223 } else {
224 /* We have aborted the request as unit is invalid */
225 ret = IOERR_ABORTED;
228 if(ret != RC_DONTREPLY) {
229 /* Set error codes */
230 if (ret != RC_OK) {
231 ioreq->iouh_Req.io_Error = ret & 0xff;
233 /* Terminate the iorequest */
234 ioreq->iouh_Req.io_Message.mn_Node.ln_Type = NT_FREEMSG;
235 /* If not quick I/O, reply the message */
236 if(!(ioreq->iouh_Req.io_Flags & IOF_QUICK)) {
237 ReplyMsg(&ioreq->iouh_Req.io_Message);
241 AROS_LIBFUNC_EXIT
244 AROS_LH1(LONG, AbortIO, AROS_LHA(struct IOUsbHWReq *, ioreq, A1), struct VXHCIBase *, VXHCIBase, 6, VXHCI) {
245 AROS_LIBFUNC_INIT
246 mybug(-1, ("[VXHCI] AbortIO: Entering function\n"));
248 if(ioreq->iouh_Req.io_Message.mn_Node.ln_Type == NT_MESSAGE) {
249 if(cmdAbortIO(ioreq)) {
250 return(0);
254 return(-1);
255 AROS_LIBFUNC_EXIT
258 struct VXHCIUnit *VXHCI_AddNewUnit(ULONG unitnum) {
260 struct VXHCIUnit *unit;
261 struct VXHCIPort *port;
263 ULONG i, imax;
265 unit = AllocVec(sizeof(struct VXHCIUnit), MEMF_ANY|MEMF_CLEAR);
266 if(unit == NULL) {
267 mybug(-1, ("[VXHCI] VXHCI_AddNewUnit: Failed to create new unit structure\n"));
268 return NULL;
269 } else {
270 unit->node.ln_Type = NT_USER;
271 unit->number = unitnum;
272 unit->node.ln_Name = (STRPTR)&unit->name;
273 unit->state = UHSF_SUSPENDED;
275 NEWLIST(&unit->roothub.port_list);
277 unit->roothub.devdesc.bcdUSB = AROS_WORD2LE(0x0300);
278 unit->roothub.devdesc.bcdDevice = AROS_WORD2LE(0x0300);
280 sprintf(unit->name, "VXHCI_USB30[%d]", unit->number);
282 /* CHECKME: */
283 unit->roothub.devdesc.bMaxPacketSize0 = 9;
284 unit->roothub.devdesc.bDeviceProtocol = 3;
285 unit->roothub.config.epdesc.wMaxPacketSize = AROS_WORD2LE(1024);
287 #ifdef VXHCI_NUMPORTS20
288 imax = VXHCI_NUMPORTS30 + VXHCI_NUMPORTS20;
289 #else
290 imax = VXHCI_NUMPORTS30;
291 #endif
293 for (i=1; i<=imax; i++) {
295 port = VXHCI_AddNewPort(unit, i);
296 if(port == NULL) {
297 mybug(-1, ("[VXHCI] VXHCI_AddNewUnit: Failed to create new port structure\n"));
300 Free previous ports if any exists and delete this unit
303 ForeachNode(&unit->roothub.port_list, port) {
304 mybug(-1, ("[VXHCI] VXHCI_AddNewUnit: Removing port structure %s at %p\n", port->node.ln_Name, port));
305 REMOVE(port);
306 FreeVec(port);
308 FreeVec(unit);
309 return NULL;
310 } else {
311 AddTail(&unit->roothub.port_list,(struct Node *)port);
312 unit->roothub.port_count++;
316 /* This is our root hub device descriptor */
317 unit->roothub.devdesc.bLength = sizeof(struct UsbStdDevDesc);
318 unit->roothub.devdesc.bDescriptorType = UDT_DEVICE;
319 //unit->roothub.devdesc.bcdUSB = AROS_WORD2LE(0xJJMN);
320 unit->roothub.devdesc.bDeviceClass = HUB_CLASSCODE;
321 //unit->roothub.devdesc.bDeviceSubClass = 0;
322 //unit->roothub.devdesc.bDeviceProtocol = 0;
323 //unit->roothub.devdesc.bMaxPacketSize0 = 9; // Valid values are 8, 9(SuperSpeed), 16, 32, 64
324 //unit->roothub.devdesc.idVendor = AROS_WORD2LE(0x0000);
325 //unit->roothub.devdesc.idProduct = AROS_WORD2LE(0x0000);
326 //unit->roothub.devdesc.bcdDevice = AROS_WORD2LE(0xJJMN);
327 unit->roothub.devdesc.iManufacturer = 1;
328 unit->roothub.devdesc.iProduct = 2;
329 //unit->roothub.devdesc.iSerialNumber = 0;
330 unit->roothub.devdesc.bNumConfigurations = 1;
332 /* This is our root hub config descriptor */
333 unit->roothub.config.cfgdesc.bLength = sizeof(struct UsbStdCfgDesc);
334 unit->roothub.config.cfgdesc.bLength = sizeof(struct UsbStdCfgDesc);
335 unit->roothub.config.cfgdesc.bDescriptorType = UDT_CONFIGURATION;
336 unit->roothub.config.cfgdesc.wTotalLength = AROS_WORD2LE(sizeof(struct RHConfig));
337 unit->roothub.config.cfgdesc.bNumInterfaces = 1;
338 unit->roothub.config.cfgdesc.bConfigurationValue = 1;
339 unit->roothub.config.cfgdesc.iConfiguration = 3;
340 unit->roothub.config.cfgdesc.bmAttributes = (USCAF_ONE|USCAF_SELF_POWERED);
341 //unit->roothub.config.cfgdesc.bMaxPower = 0;
343 unit->roothub.config.ifdesc.bLength = sizeof(struct UsbStdIfDesc);
344 unit->roothub.config.ifdesc.bDescriptorType = UDT_INTERFACE;
345 //unit->roothub.config.ifdesc.bInterfaceNumber = 0;
346 //unit->roothub.config.ifdesc.bAlternateSetting = 0;
347 unit->roothub.config.ifdesc.bNumEndpoints = 1;
348 unit->roothub.config.ifdesc.bInterfaceClass = HUB_CLASSCODE;
349 //unit->roothub.config.ifdesc.bInterfaceSubClass = 0;
350 //unit->roothub.config.ifdesc.bInterfaceProtocol = 0;
351 unit->roothub.config.ifdesc.iInterface = 4;
353 unit->roothub.config.epdesc.bLength = sizeof(struct UsbStdEPDesc);
354 unit->roothub.config.epdesc.bDescriptorType = UDT_ENDPOINT;
355 unit->roothub.config.epdesc.bEndpointAddress = (URTF_IN|1);
356 unit->roothub.config.epdesc.bmAttributes = USEAF_INTERRUPT;
357 //unit->roothub.config.epdesc.wMaxPacketSize = AROS_WORD2LE(8);
358 unit->roothub.config.epdesc.bInterval = 12;
360 /* This is our root hub hub descriptor */
361 unit->roothub.hubdesc.bLength = sizeof(struct UsbSSHubDesc);
362 unit->roothub.hubdesc.bDescriptorType = UDT_SSHUB;
363 unit->roothub.hubdesc.bNbrPorts = (UBYTE) unit->roothub.port_count;;
364 unit->roothub.hubdesc.wHubCharacteristics = AROS_WORD2LE(UHCF_INDIVID_POWER|UHCF_INDIVID_OVP);
365 //unit->roothub.hubdesc.bPwrOn2PwrGood = 0;
366 unit->roothub.hubdesc.bHubContrCurrent = 10;
367 //unit->roothub.hubdesc.bHubHdrDecLat = 0;
368 //unit->roothub.hubdesc.wHubDelay = 0;
369 //unit->roothub.hubdesc.DeviceRemovable = 0;
371 unit->roothub.bosdesc.bLength = sizeof(struct UsbStdBOSDesc);
372 unit->roothub.bosdesc.bDescriptorType = UDT_BOS;
373 /* Command interface sets these */
374 //unit->roothub.bosdesc.wTotalLength = 0;
375 //unit->roothub.bosdesc.bNumDeviceCaps = 0;
377 D( mybug(0, ("[VXHCI] VXHCI_AddNewUnit:\n"));
378 mybug(0, (" Created new unit numbered %d at %p\n",unit->number, unit));
379 mybug(0, (" Unit node name %s\n", unit->node.ln_Name));
381 switch(unit->state) {
382 case UHSF_SUSPENDED:
383 mybug(0, (" Unit state: UHSF_SUSPENDED\n"));
384 break;
385 case UHSF_OPERATIONAL:
386 mybug(0, (" Unit state: UHSF_OPERATIONAL\n"));
387 break;
388 default:
389 mybug(0, (" Unit state: %lx (Error?)\n", unit->state));
390 break;
391 } );
393 return unit;
397 struct VXHCIPort *VXHCI_AddNewPort(struct VXHCIUnit *unit, ULONG portnum) {
398 struct VXHCIPort *port;
400 port = AllocVec(sizeof(struct VXHCIPort), MEMF_ANY|MEMF_CLEAR);
401 if(port == NULL) {
402 mybug(-1, ("[VXHCI] VXHCI_AddNewPort: Failed to create new port structure\n"));
403 return NULL;
404 } else {
405 port->node.ln_Type = NT_USER;
406 /* Poseidon treats port number 0 as roothub */
407 port->number = portnum;
408 if(portnum<=VXHCI_NUMPORTS30) {
409 port->usbbcd = 0x0300;
410 sprintf(port->name, "VXHCI_USB30[%d:%d]", unit->number, port->number);
411 } else {
412 port->usbbcd = 0x0210;
413 sprintf(port->name, "VXHCI_USB20[%d:%d]", unit->number, port->number);
415 port->node.ln_Name = (STRPTR)&port->name;
418 mybug(0, ("[VXHCI] VXHCI_AddNewPort:\n"));
419 mybug(0, (" Created new port numbered %d at %p\n",port->number, port));
420 mybug(0, (" Port node name %s\n", port->node.ln_Name));
421 mybug(0, (" Port usbbcd %04x\n", port->usbbcd));
423 return port;