2 Copyright © 2014, The AROS Development Team. All rights reserved.
5 Desc: Virtual XHCI USB host controller
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
;
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
);
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
));
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
));
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
;
110 if(ioreq
->iouh_Req
.io_Unit
!= NULL
) {
113 ioreq
->iouh_Req
.io_Message
.mn_Node
.ln_Type
= NT_REPLYMSG
;
114 ioreq
->iouh_Req
.io_Error
= 0;
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;
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
) {
140 mybug(0, ("[VXHCI] BeginIO: Entering function\n"));
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
;
151 switch (ioreq
->iouh_Req
.io_Command
) {
153 mybug_unit(0, ("CMD_RESET\n"));
156 mybug_unit(0, ("CMD_FLUSH\n"));
158 case UHCMD_QUERYDEVICE
:
159 mybug_unit(0, ("UHCMD_QUERYDEVICE\n"));
160 ret
= cmdQueryDevice(ioreq
);
163 mybug_unit(0, ("UHCMD_USBRESET\n"));
164 ret
= cmdUsbReset(ioreq
);
166 case UHCMD_USBRESUME
:
167 mybug_unit(0, ("UHCMD_USBRESUME\n"));
169 case UHCMD_USBSUSPEND
:
170 mybug_unit(0, ("UHCMD_USBSUSPEND\n"));
173 mybug_unit(0, ("UHCMD_USBOPER\n"));
174 //ret = cmdUsbOper(ioreq);
176 case UHCMD_CONTROLXFER
:
177 mybug_unit(0, ("UHCMD_CONTROLXFER unit %p %s\n", unit
, unit
->name
));
178 ret
= cmdControlXFer(ioreq
);
181 mybug_unit(0, ("UHCMD_BULKXFER\n"));
184 mybug_unit(0, ("UHCMD_INTXFER unit %p %s\n", unit
, unit
->name
));
185 ret
= cmdIntXFer(ioreq
);
188 mybug_unit(0, ("UHCMD_ISOXFER\n"));
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
,
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
;
219 mybug_unit(-1, ("IOERR_NOCMD\n"));
224 /* We have aborted the request as unit is invalid */
228 if(ret
!= RC_DONTREPLY
) {
229 /* Set error codes */
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
);
244 AROS_LH1(LONG
, AbortIO
, AROS_LHA(struct IOUsbHWReq
*, ioreq
, A1
), struct VXHCIBase
*, VXHCIBase
, 6, VXHCI
) {
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
)) {
258 struct VXHCIUnit
*VXHCI_AddNewUnit(ULONG unitnum
) {
260 struct VXHCIUnit
*unit
;
261 struct VXHCIPort
*port
;
265 unit
= AllocVec(sizeof(struct VXHCIUnit
), MEMF_ANY
|MEMF_CLEAR
);
267 mybug(-1, ("[VXHCI] VXHCI_AddNewUnit: Failed to create new unit structure\n"));
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
);
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
;
290 imax
= VXHCI_NUMPORTS30
;
293 for (i
=1; i
<=imax
; i
++) {
295 port
= VXHCI_AddNewPort(unit
, i
);
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
));
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
) {
383 mybug(0, (" Unit state: UHSF_SUSPENDED\n"));
385 case UHSF_OPERATIONAL
:
386 mybug(0, (" Unit state: UHSF_OPERATIONAL\n"));
389 mybug(0, (" Unit state: %lx (Error?)\n", unit
->state
));
397 struct VXHCIPort
*VXHCI_AddNewPort(struct VXHCIUnit
*unit
, ULONG portnum
) {
398 struct VXHCIPort
*port
;
400 port
= AllocVec(sizeof(struct VXHCIPort
), MEMF_ANY
|MEMF_CLEAR
);
402 mybug(-1, ("[VXHCI] VXHCI_AddNewPort: Failed to create new port structure\n"));
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
);
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
));