Enumerator fills host controller list
[AROS.git] / rom / usb / pciusbhc / xhci / pcixhci_discover.c
blob108e8cfb82e4b261e51ef0463fc25d837469db15
1 /*
2 Copyright © 2014, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: PCI 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/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>
29 #include <asm/io.h>
30 #include <inttypes.h>
32 #include <hidd/pci.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)) {
43 AROS_USERFUNC_INIT
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);
52 if(host != NULL) {
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);
64 } else {
65 mybug(-1, ("\n[PCIXHCI] Enumerator: Failed to allocate host controller structure!\n\n"));
68 AROS_USERFUNC_EXIT
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 },
82 { TAG_DONE, 0UL }
85 struct OOP_ABDescr attrbases[] = {
86 { (STRPTR)IID_Hidd, &HiddAttrBase },
87 { (STRPTR)IID_Hidd_PCIDevice, &HiddPCIDeviceAttrBase },
88 { NULL, NULL }
91 struct Hook FindHook = {
92 h_Entry: (IPTR (*)())GM_UNIQUENAME(Enumerator),
93 h_Data: LIBBASE,
96 OOP_ObtainAttrBases(attrbases);
97 HIDD_PCI_EnumDevices(LIBBASE->pci, &FindHook, (struct TagItem *)&tags);
99 struct PCIXHCIHost *host;
100 CONST_STRPTR owner;
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);
112 if (owner) {
113 mybug(-1, ("[PCIXHCI] Host controller already reserved for %s\n", owner));
114 REMOVE(host);
118 if(!IsListEmpty(&LIBBASE->host_list)) {
120 /* Examine host controller(s) and interrogate for ports */
122 struct PCIXHCIUnit *unit;
123 ULONG i;
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);
131 if(unit == NULL) {
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));
140 REMOVE(unit);
141 FreeVec(unit);
143 return FALSE;
144 } else {
145 AddTail(&LIBBASE->unit_list,(struct Node *)unit);
146 LIBBASE->unit_count++;
148 #endif
150 unit = PCIXHCI_AddNewUnit(LIBBASE->unit_count, 0x311);
151 if(unit == NULL) {
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));
160 REMOVE(unit);
161 FreeVec(unit);
163 return FALSE;
164 } else {
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));
177 mybug(-1,("\n"));
180 return TRUE;
184 return FALSE;
187 struct PCIXHCIUnit *PCIXHCI_AddNewUnit(ULONG unitnum, UWORD bcdusb) {
189 struct PCIXHCIUnit *unit;
190 struct PCIXHCIPort *port;
192 ULONG i, imax;
194 unit = AllocVec(sizeof(struct PCIXHCIUnit), MEMF_ANY|MEMF_CLEAR);
195 if(unit == NULL) {
196 mybug(-1, ("[PCIXHCI] PCIXHCI_AddNewUnit: Failed to create new unit structure\n"));
197 return NULL;
198 } else {
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 */
207 if(bcdusb>=0x0300) {
208 unit->roothub.devdesc.bcdUSB = AROS_WORD2LE(0x0300);
209 } else {
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;
223 } else {
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;
229 #else
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;
234 #endif
236 for (i=0; i<imax; i++) {
238 port = PCIXHCI_AddNewPort(unit, i);
239 if(port == NULL) {
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));
248 REMOVE(port);
249 FreeVec(port);
251 FreeVec(unit);
252 return NULL;
253 } else {
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;
313 } else {
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) {
330 case UHSF_SUSPENDED:
331 mybug(0, (" Unit state: UHSF_SUSPENDED\n"));
332 break;
333 case UHSF_OPERATIONAL:
334 mybug(0, (" Unit state: UHSF_OPERATIONAL\n"));
335 break;
336 default:
337 mybug(0, (" Unit state: %lx (Error?)\n", unit->state));
338 break;
339 } );
341 return unit;
345 struct PCIXHCIPort *PCIXHCI_AddNewPort(struct PCIXHCIUnit *unit, ULONG portnum) {
346 struct PCIXHCIPort *port;
348 port = AllocVec(sizeof(struct PCIXHCIPort), MEMF_ANY|MEMF_CLEAR);
349 if(port == NULL) {
350 mybug(-1, ("[PCIXHCI] PCIXHCI_AddNewPort: Failed to create new port structure\n"));
351 return NULL;
352 } else {
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));
365 return port;