2 Copyright © 2014, The AROS Development Team. All rights reserved.
5 Desc: PCI 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/oop.h>
20 #include <proto/exec.h>
21 #include <proto/stdc.h>
22 #include <proto/arossupport.h>
24 #include <devices/usb.h>
25 #include <devices/usb_hub.h>
26 #include <devices/newstyle.h>
27 #include <devices/usbhardware.h>
33 #include <hidd/hidd.h>
35 #include "pcixhci_device.h"
37 #include LC_LIBDEFS_FILE
40 Keep this one short and simple
42 static AROS_UFH3(void, GM_UNIQUENAME(Enumerator
), AROS_UFHA(struct Hook
*, hook
, A0
), AROS_UFHA(OOP_Object
*, pciDevice
, A2
), AROS_UFHA(APTR
, message
, A1
)) {
45 LIBBASETYPE
*LIBBASE
= (LIBBASETYPE
*)hook
->h_Data
;
47 mybug(-1, ("\n[PCIXHCI] Enumerator: Found PCI XHCI host controller\n"));
49 struct PCIXHCIHost
*host
;
51 host
= AllocVec(sizeof(struct PCIXHCIHost
), MEMF_ANY
|MEMF_CLEAR
);
53 host
->node
.ln_Type
= NT_USER
;
54 host
->node
.ln_Name
= (STRPTR
)&host
->name
;
56 host
->pcidevice
= pciDevice
;
58 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Bus
, &host
->bus
);
59 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Dev
, &host
->dev
);
60 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Sub
, &host
->sub
);
61 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_INTLine
, &host
->intline
);
62 OOP_GetAttr(pciDevice
, aHidd_PCIDevice_Driver
, (IPTR
*)&host
->pcidriver
);
63 AddTail(&LIBBASE
->host_list
, (struct Node
*)host
);
65 mybug(-1, ("\n[PCIXHCI] Enumerator: Failed to allocate host controller structure!\n\n"));
71 BOOL
PCIXHCI_Discover(LIBBASETYPEPTR LIBBASE
) {
72 mybug(0, ("[PCIXHCI] PCIXHCI_Discover: Entering function\n"));
74 NEWLIST(&LIBBASE
->unit_list
);
75 NEWLIST(&LIBBASE
->host_list
);
77 if ( (LIBBASE
->pci
= OOP_NewObject(NULL
, (STRPTR
)CLID_Hidd_PCI
, NULL
)) ) {
78 struct TagItem tags
[] = {
79 { tHidd_PCI_Class
, PCI_BASE_CLASS_SERIAL
},
80 { tHidd_PCI_SubClass
, PCI_SUB_CLASS_USB
},
81 { tHidd_PCI_Interface
, PCI_INTERFACE_XHCI
},
85 struct OOP_ABDescr attrbases
[] = {
86 { (STRPTR
)IID_Hidd
, &HiddAttrBase
},
87 { (STRPTR
)IID_Hidd_PCIDevice
, &HiddPCIDeviceAttrBase
},
91 struct Hook FindHook
= {
92 h_Entry
: (IPTR (*)())GM_UNIQUENAME(Enumerator
),
96 OOP_ObtainAttrBases(attrbases
);
97 HIDD_PCI_EnumDevices(LIBBASE
->pci
, &FindHook
, (struct TagItem
*)&tags
);
99 struct PCIXHCIHost
*host
;
102 ForeachNode(&LIBBASE
->host_list
, host
) {
103 mybug(-1, ("[PCIXHCI] *pcidevice = %p\n", host
->pcidevice
));
104 mybug(-1, ("[PCIXHCI] *pcidriver = %p\n", host
->pcidriver
));
105 mybug(-1, ("[PCIXHCI] bus = %x\n", host
->bus
));
106 mybug(-1, ("[PCIXHCI] dev = %x\n", host
->dev
));
107 mybug(-1, ("[PCIXHCI] sub = %x\n", host
->sub
));
108 mybug(-1, ("[PCIXHCI] intline = %d\n\n", host
->intline
));
110 /* Try to obtain the host controller */
111 owner
= HIDD_PCIDevice_Obtain(host
->pcidevice
, LIBBASE
->library
.lib_Node
.ln_Name
);
113 mybug(-1, ("[PCIXHCI] Host controller already reserved for %s\n", owner
));
118 if(!IsListEmpty(&LIBBASE
->host_list
)) {
120 /* Examine host controller(s) and interrogate for ports */
122 struct PCIXHCIUnit
*unit
;
125 LIBBASE
->unit_count
= 0;
127 for (i
=0; i
<PCIXHCI_NUMCONTROLLERS
; i
++) {
129 #ifdef PCIXHCI_NUMPORTS20
130 unit
= PCIXHCI_AddNewUnit(LIBBASE
->unit_count
, 0x210);
132 mybug(-1, ("[PCIXHCI] Init: Failed to create new unit!\n"));
135 Free previous units if any exists
138 ForeachNode(&LIBBASE
->unit_list
, unit
) {
139 mybug(-1,("[PCIXHCI] Init: Removing unit structure %s at %p\n", unit
->node
.ln_Name
, unit
));
145 AddTail(&LIBBASE
->unit_list
,(struct Node
*)unit
);
146 LIBBASE
->unit_count
++;
150 unit
= PCIXHCI_AddNewUnit(LIBBASE
->unit_count
, 0x311);
152 mybug(-1, ("[PCIXHCI] Init: Failed to create new unit!\n"));
155 Free previous units if any exists
158 ForeachNode(&LIBBASE
->unit_list
, unit
) {
159 mybug(-1,("[PCIXHCI] Init: Removing unit structure %s at %p\n", unit
->node
.ln_Name
, unit
));
165 AddTail(&LIBBASE
->unit_list
,(struct Node
*)unit
);
166 LIBBASE
->unit_count
++;
171 D(ForeachNode(&LIBBASE
->unit_list
, unit
) {
172 mybug(-1, ("[PCIXHCI] Init: Created unit %d at %p %s\n", unit
->number
, unit
, unit
->name
));
173 struct PCIXHCIPort
*port
;
174 ForeachNode(&unit
->roothub
.port_list
, port
) {
175 mybug(-1, (" port %d at %p %s\n", port
->number
, port
, port
->name
));
187 struct PCIXHCIUnit
*PCIXHCI_AddNewUnit(ULONG unitnum
, UWORD bcdusb
) {
189 struct PCIXHCIUnit
*unit
;
190 struct PCIXHCIPort
*port
;
194 unit
= AllocVec(sizeof(struct PCIXHCIUnit
), MEMF_ANY
|MEMF_CLEAR
);
196 mybug(-1, ("[PCIXHCI] PCIXHCI_AddNewUnit: Failed to create new unit structure\n"));
199 unit
->node
.ln_Type
= NT_USER
;
200 unit
->number
= unitnum
;
201 unit
->node
.ln_Name
= (STRPTR
)&unit
->name
;
202 unit
->state
= UHSF_SUSPENDED
;
204 NEWLIST(&unit
->roothub
.port_list
);
206 /* Set the correct bcdUSB and bcdDevice for the hub device descriptor */
208 unit
->roothub
.devdesc
.bcdUSB
= AROS_WORD2LE(0x0300);
210 unit
->roothub
.devdesc
.bcdUSB
= AROS_WORD2LE(0x0200);
213 unit
->roothub
.devdesc
.bcdDevice
= AROS_WORD2LE(bcdusb
);
215 sprintf(unit
->name
, "PCIXHCI_USB%x%x[%d]", (AROS_LE2WORD(unit
->roothub
.devdesc
.bcdUSB
)>>8)&0xf, (AROS_LE2WORD(unit
->roothub
.devdesc
.bcdUSB
)>>4)&0xf, unit
->number
);
217 #ifdef PCIXHCI_NUMPORTS20
218 if( (bcdusb
>= 0x0200) && (bcdusb
< 0x0300) ) {
219 unit
->roothub
.devdesc
.bMaxPacketSize0
= 8;
220 unit
->roothub
.devdesc
.bDeviceProtocol
= 1;
221 unit
->roothub
.config
.epdesc
.wMaxPacketSize
= AROS_WORD2LE(8);
222 imax
= PCIXHCI_NUMPORTS20
;
224 unit
->roothub
.devdesc
.bMaxPacketSize0
= 9;
225 unit
->roothub
.devdesc
.bDeviceProtocol
= 3;
226 unit
->roothub
.config
.epdesc
.wMaxPacketSize
= AROS_WORD2LE(1024);
227 imax
= PCIXHCI_NUMPORTS30
;
230 unit
->roothub
.devdesc
.bMaxPacketSize0
= 9;
231 unit
->roothub
.devdesc
.bDeviceProtocol
= 3;
232 unit
->roothub
.config
.epdesc
.wMaxPacketSize
= AROS_WORD2LE(1024);
233 imax
= PCIXHCI_NUMPORTS30
;
236 for (i
=0; i
<imax
; i
++) {
238 port
= PCIXHCI_AddNewPort(unit
, i
);
240 mybug(-1, ("[PCIXHCI] PCIXHCI_AddNewUnit: Failed to create new port structure\n"));
243 Free previous ports if any exists and delete this unit
246 ForeachNode(&unit
->roothub
.port_list
, port
) {
247 mybug(-1, ("[PCIXHCI] PCIXHCI_AddNewUnit: Removing port structure %s at %p\n", port
->node
.ln_Name
, port
));
254 AddTail(&unit
->roothub
.port_list
,(struct Node
*)port
);
255 unit
->roothub
.port_count
++;
259 /* This is our root hub device descriptor */
260 unit
->roothub
.devdesc
.bLength
= sizeof(struct UsbStdDevDesc
);
261 unit
->roothub
.devdesc
.bDescriptorType
= UDT_DEVICE
;
262 //unit->roothub.devdesc.bcdUSB = AROS_WORD2LE(0xJJMN);
263 unit
->roothub
.devdesc
.bDeviceClass
= HUB_CLASSCODE
;
264 //unit->roothub.devdesc.bDeviceSubClass = 0;
265 //unit->roothub.devdesc.bDeviceProtocol = 0;
266 //unit->roothub.devdesc.bMaxPacketSize0 = 9; // Valid values are 8, 9(SuperSpeed), 16, 32, 64
267 //unit->roothub.devdesc.idVendor = AROS_WORD2LE(0x0000);
268 //unit->roothub.devdesc.idProduct = AROS_WORD2LE(0x0000);
269 //unit->roothub.devdesc.bcdDevice = AROS_WORD2LE(0xJJMN);
270 unit
->roothub
.devdesc
.iManufacturer
= 1;
271 unit
->roothub
.devdesc
.iProduct
= 2;
272 //unit->roothub.devdesc.iSerialNumber = 0;
273 unit
->roothub
.devdesc
.bNumConfigurations
= 1;
275 /* This is our root hub config descriptor */
276 unit
->roothub
.config
.cfgdesc
.bLength
= sizeof(struct UsbStdCfgDesc
);
277 unit
->roothub
.config
.cfgdesc
.bLength
= sizeof(struct UsbStdCfgDesc
);
278 unit
->roothub
.config
.cfgdesc
.bDescriptorType
= UDT_CONFIGURATION
;
279 unit
->roothub
.config
.cfgdesc
.wTotalLength
= AROS_WORD2LE(sizeof(struct RHConfig
));
280 unit
->roothub
.config
.cfgdesc
.bNumInterfaces
= 1;
281 unit
->roothub
.config
.cfgdesc
.bConfigurationValue
= 1;
282 unit
->roothub
.config
.cfgdesc
.iConfiguration
= 3;
283 unit
->roothub
.config
.cfgdesc
.bmAttributes
= (USCAF_ONE
|USCAF_SELF_POWERED
);
284 //unit->roothub.config.cfgdesc.bMaxPower = 0;
286 unit
->roothub
.config
.ifdesc
.bLength
= sizeof(struct UsbStdIfDesc
);
287 unit
->roothub
.config
.ifdesc
.bDescriptorType
= UDT_INTERFACE
;
288 //unit->roothub.config.ifdesc.bInterfaceNumber = 0;
289 //unit->roothub.config.ifdesc.bAlternateSetting = 0;
290 unit
->roothub
.config
.ifdesc
.bNumEndpoints
= 1;
291 unit
->roothub
.config
.ifdesc
.bInterfaceClass
= HUB_CLASSCODE
;
292 //unit->roothub.config.ifdesc.bInterfaceSubClass = 0;
293 //unit->roothub.config.ifdesc.bInterfaceProtocol = 0;
294 unit
->roothub
.config
.ifdesc
.iInterface
= 4;
296 unit
->roothub
.config
.epdesc
.bLength
= sizeof(struct UsbStdEPDesc
);
297 unit
->roothub
.config
.epdesc
.bDescriptorType
= UDT_ENDPOINT
;
298 unit
->roothub
.config
.epdesc
.bEndpointAddress
= (URTF_IN
|1);
299 unit
->roothub
.config
.epdesc
.bmAttributes
= USEAF_INTERRUPT
;
300 //unit->roothub.config.epdesc.wMaxPacketSize = AROS_WORD2LE(8);
301 unit
->roothub
.config
.epdesc
.bInterval
= 12;
303 /* This is our root hub hub descriptor */
304 if( (bcdusb
>= 0x0200) && (bcdusb
< 0x0300) ) {
305 unit
->roothub
.hubdesc
.usb20
.bLength
= sizeof(struct UsbHubDesc
);
306 unit
->roothub
.hubdesc
.usb20
.bDescriptorType
= UDT_HUB
;
307 unit
->roothub
.hubdesc
.usb20
.bNbrPorts
= (UBYTE
) unit
->roothub
.port_count
;
308 unit
->roothub
.hubdesc
.usb20
.wHubCharacteristics
= AROS_WORD2LE(UHCF_INDIVID_POWER
|UHCF_INDIVID_OVP
);
309 //unit->roothub.hubdesc.usb20.bPwrOn2PwrGood = 0;
310 unit
->roothub
.hubdesc
.usb20
.bHubContrCurrent
= 1;
311 unit
->roothub
.hubdesc
.usb20
.DeviceRemovable
= 0;
312 //unit->roothub.hubdesc.usb20.PortPwrCtrlMask = 0;
314 unit
->roothub
.hubdesc
.usb30
.bLength
= sizeof(struct UsbSSHubDesc
);
315 unit
->roothub
.hubdesc
.usb30
.bDescriptorType
= UDT_SSHUB
;
316 unit
->roothub
.hubdesc
.usb30
.bNbrPorts
= (UBYTE
) unit
->roothub
.port_count
;;
317 unit
->roothub
.hubdesc
.usb30
.wHubCharacteristics
= AROS_WORD2LE(UHCF_INDIVID_POWER
|UHCF_INDIVID_OVP
);
318 //unit->roothub.hubdesc.usb30.bPwrOn2PwrGood = 0;
319 unit
->roothub
.hubdesc
.usb30
.bHubContrCurrent
= 10;
320 //unit->roothub.hubdesc.usb30.bHubHdrDecLat = 0;
321 //unit->roothub.hubdesc.usb30.wHubDelay = 0;
322 //unit->roothub.hubdesc.usb30.DeviceRemovable = 0;
325 D( mybug(0, ("[PCIXHCI] PCIXHCI_AddNewUnit:\n"));
326 mybug(0, (" Created new unit numbered %d at %p\n",unit
->number
, unit
));
327 mybug(0, (" Unit node name %s\n", unit
->node
.ln_Name
));
329 switch(unit
->state
) {
331 mybug(0, (" Unit state: UHSF_SUSPENDED\n"));
333 case UHSF_OPERATIONAL
:
334 mybug(0, (" Unit state: UHSF_OPERATIONAL\n"));
337 mybug(0, (" Unit state: %lx (Error?)\n", unit
->state
));
345 struct PCIXHCIPort
*PCIXHCI_AddNewPort(struct PCIXHCIUnit
*unit
, ULONG portnum
) {
346 struct PCIXHCIPort
*port
;
348 port
= AllocVec(sizeof(struct PCIXHCIPort
), MEMF_ANY
|MEMF_CLEAR
);
350 mybug(-1, ("[PCIXHCI] PCIXHCI_AddNewPort: Failed to create new port structure\n"));
353 port
->node
.ln_Type
= NT_USER
;
354 /* Poseidon treats port number 0 as a place for roothub */
355 port
->number
= portnum
+1;
357 sprintf(port
->name
, "PCIXHCI_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
);
358 port
->node
.ln_Name
= (STRPTR
)&port
->name
;
361 mybug(0, ("[PCIXHCI] PCIXHCI_AddNewPort:\n"));
362 mybug(0, (" Created new port numbered %d at %p\n",port
->number
, port
));
363 mybug(0, (" Port node name %s\n", port
->node
.ln_Name
));