Documented GVF_SAVE_VAR alongside other flags, and removed a query/doubt
[AROS.git] / rom / usb / pciusbhc / ohci / pci.c
blobdd37c93a336d17f910e942e4cdc5037a8b49a4fe
1 /*
2 Copyright © 2002-2009, Chris Hodges. All rights reserved.
3 Copyright © 2009-2012, The AROS Development Team. All rights reserved.
4 $Id$
5 */
7 #include <aros/bootloader.h>
8 #include <exec/types.h>
9 #include <oop/oop.h>
10 #include <devices/timer.h>
11 #include <hidd/hidd.h>
12 #include <hidd/pci.h>
14 #include <proto/bootloader.h>
15 #include <proto/oop.h>
16 #include <proto/utility.h>
17 #include <proto/exec.h>
18 #include <clib/alib_protos.h>
20 #include <string.h>
22 #include "debug.h"
23 #include "chip.h"
24 #include "dev.h"
26 #include "chip_protos.h"
27 #include "cmd_protos.h"
29 #ifdef __i386__
30 #define HAVE_ACPI
31 #endif
32 #ifdef __x86_64__
33 #define HAVE_ACPI
34 #endif
36 #ifdef HAVE_ACPI
37 #include <proto/acpica.h>
38 #endif
40 #undef HiddPCIDeviceAttrBase
41 #undef HiddAttrBase
43 #define HiddPCIDeviceAttrBase (hd->hd_HiddPCIDeviceAB)
44 #define HiddAttrBase (hd->hd_HiddAB)
46 static TEXT product_name[] = "PCI OHCI USB 1.1 Host Controller";
48 AROS_UFH3(void, pciEnumerator,
49 AROS_UFHA(struct Hook *, hook, A0),
50 AROS_UFHA(OOP_Object *, pciDevice, A2), AROS_UFHA(APTR, message, A1))
52 AROS_USERFUNC_INIT
54 struct PCIDevice *hd = (struct PCIDevice *)hook->h_Data;
55 struct PCIController *hc;
56 IPTR bus;
57 IPTR dev;
58 IPTR sub;
59 IPTR intline;
60 ULONG devid;
61 UWORD i;
63 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Bus, &bus);
64 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Dev, &dev);
65 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Sub, &sub);
66 OOP_GetAttr(pciDevice, aHidd_PCIDevice_INTLine, &intline);
68 devid = (bus << 16) | dev;
70 KPRINTF(10, ("Found PCI device 0x%lx Intline=%ld\n", devid, intline));
72 if (intline == 255)
74 // we can't work without the correct interrupt line.
75 // BIOS needs plug & play os option disabled.
76 // Alternatively AROS must support APIC reconfiguration
77 KPRINTF(200, ("ERROR: PCI card has no interrupt line assigned "
78 "by BIOS, disable Plug & Play OS!\n"));
80 else
82 KPRINTF(10, ("Setting up device...\n"));
84 hc = AllocPooled(hd->hd_MemPool, sizeof(struct PCIController));
85 if (hc)
87 hc->hc_Device = hd;
88 hc->hc_DevID = devid;
89 hc->hc_FunctionNum = sub;
90 hc->hc_PCIDeviceObject = pciDevice;
91 hc->hc_PCIIntLine = intline;
93 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Driver,
94 (IPTR *) & hc->hc_PCIDriverObject);
96 for (i = 0; i < XFER_COUNT; i++)
97 NewList(&hc->hc_XferQueues[i]);
98 NewList(&hc->hc_TDQueue);
99 NewList(&hc->hc_AbortQueue);
100 NewList(&hc->hc_PeriodicTDQueue);
101 NewList(&hc->hc_RetireQueue);
102 AddTail(&hd->hd_TempHCIList, &hc->hc_Node);
106 AROS_USERFUNC_EXIT
109 /* /// "pciInit()" */
110 BOOL pciInit(struct PCIDevice *hd)
112 struct PCIController *hc;
113 struct PCIController *nexthc;
114 struct PCIUnit *hu;
115 ULONG unitno = 0;
117 KPRINTF(10, ("*** pciInit(%p) ***\n", hd));
119 NewList(&hd->hd_TempHCIList);
121 if ((hd->hd_PCIHidd =
122 OOP_NewObject(NULL, (STRPTR) CLID_Hidd_PCI, NULL)))
124 struct TagItem tags[] = {
125 {tHidd_PCI_Class, (PCI_CLASS_SERIAL_USB >> 8) & 0xff},
126 {tHidd_PCI_SubClass, (PCI_CLASS_SERIAL_USB & 0xff)},
127 {tHidd_PCI_Interface, 0x10},
128 {TAG_DONE, 0UL}
131 struct OOP_ABDescr attrbases[] = {
132 {(STRPTR) IID_Hidd, &hd->hd_HiddAB},
133 {(STRPTR) IID_Hidd_PCIDevice, &hd->hd_HiddPCIDeviceAB},
134 {NULL, NULL}
137 struct Hook findHook = {
138 h_Entry:(IPTR(*)())pciEnumerator,
139 h_Data:hd,
142 OOP_ObtainAttrBases(attrbases);
144 KPRINTF(20, ("Searching for devices...\n"));
146 HIDD_PCI_EnumDevices(hd->hd_PCIHidd, &findHook,
147 (struct TagItem *)&tags);
149 else
151 KPRINTF(20, ("Unable to create PCIHidd object!\n"));
152 return FALSE;
155 // Create units with a list of host controllers having the same bus
156 // and device number.
157 while (hd->hd_TempHCIList.lh_Head->ln_Succ)
159 hu = AllocPooled(hd->hd_MemPool, sizeof(struct PCIUnit));
160 if (!hu)
162 // actually, we should get rid of the allocated memory first,
163 // but we don't care as DeletePool() will take care of this
164 // eventually
165 return FALSE;
167 hu->hu_Device = hd;
168 hu->hu_UnitNo = unitno;
169 hu->hu_DevID =
170 ((struct PCIController *)hd->hd_TempHCIList.lh_Head)->hc_DevID;
172 NewList(&hu->hu_Controllers);
173 NewList(&hu->hu_RHIOQueue);
175 hc = (struct PCIController *)hd->hd_TempHCIList.lh_Head;
176 while ((nexthc = (struct PCIController *)hc->hc_Node.ln_Succ))
178 if (hc->hc_DevID == hu->hu_DevID)
180 Remove(&hc->hc_Node);
181 hc->hc_Unit = hu;
182 AddTail(&hu->hu_Controllers, &hc->hc_Node);
184 hc = nexthc;
186 AddTail(&hd->hd_Units, (struct Node *)hu);
187 unitno++;
189 return TRUE;
191 /* \\\ */
193 /* /// "pciAllocUnit()" */
194 BOOL pciAllocUnit(struct PCIUnit * hu)
196 struct PCIController *hc;
198 BOOL allocgood = TRUE;
199 ULONG usb11ports = 0;
200 ULONG usb20ports = 0;
201 ULONG cnt;
203 ULONG ohcicnt = 0;
205 KPRINTF(10, ("*** pciAllocUnit(%p) ***\n", hu));
207 // allocate necessary memory
208 hc = (struct PCIController *)hu->hu_Controllers.lh_Head;
209 while (hc->hc_Node.ln_Succ)
211 allocgood = InitController(hc, hu);
212 if (allocgood)
214 ohcicnt++;
217 hc = (struct PCIController *)hc->hc_Node.ln_Succ;
220 if (!allocgood)
222 return FALSE;
225 hc = (struct PCIController *)hu->hu_Controllers.lh_Head;
226 while (hc->hc_Node.ln_Succ)
228 if (hc->hc_complexrouting)
230 ULONG locport = 0;
231 for (cnt = 0; cnt < usb20ports; cnt++)
233 if (((hc->hc_portroute >> (cnt << 2)) & 0xf) ==
234 hc->hc_FunctionNum)
236 KPRINTF(10,
237 ("CHC %ld Port %ld assigned to global Port %ld\n",
238 hc->hc_FunctionNum, locport, cnt));
239 hu->hu_PortMap11[cnt] = hc;
240 hu->hu_PortNum11[cnt] = locport;
241 hc->hc_PortNum20[locport] = cnt;
242 locport++;
246 else
248 for (cnt = usb11ports; cnt < usb11ports + hc->hc_NumPorts;
249 cnt++)
251 hu->hu_PortMap11[cnt] = hc;
252 hu->hu_PortNum11[cnt] = cnt - usb11ports;
253 hc->hc_PortNum20[cnt - usb11ports] = cnt;
256 usb11ports += hc->hc_NumPorts;
257 hc = (struct PCIController *)hc->hc_Node.ln_Succ;
259 if ((usb11ports != usb20ports) && usb20ports)
261 KPRINTF(20,
262 ("Warning! #EHCI Ports (%ld) does not match USB 1.1 Ports (%ld)!\n",
263 usb20ports, usb11ports));
266 hu->hu_RootHub11Ports = usb11ports;
267 hu->hu_RootHub20Ports = usb20ports;
268 hu->hu_RootHubPorts =
269 (usb11ports > usb20ports) ? usb11ports : usb20ports;
270 for (cnt = 0; cnt < hu->hu_RootHubPorts; cnt++)
272 hu->hu_EhciOwned[cnt] = hu->hu_PortMap20[cnt] ? TRUE : FALSE;
275 KPRINTF(10, ("Unit %ld: USB Board %08lx has %ld USB1.1 ports\n",
276 hu->hu_UnitNo, hu->hu_DevID, hu->hu_RootHub11Ports));
278 hu->hu_FrameCounter = 1;
279 hu->hu_RootHubAddr = 0;
281 // put em online
282 hc = (struct PCIController *)hu->hu_Controllers.lh_Head;
283 while (hc->hc_Node.ln_Succ)
285 hc->hc_Flags |= HCF_ONLINE;
286 hc = (struct PCIController *)hc->hc_Node.ln_Succ;
289 // create product name of device
290 CopyMem(product_name, hu->hu_ProductName, sizeof(product_name));
292 KPRINTF(10, ("Unit allocated!\n"));
294 return TRUE;
296 /* \\\ */
298 /* /// "pciFreeUnit()" */
299 void pciFreeUnit(struct PCIUnit *hu)
301 struct PCIDevice *hd = hu->hu_Device;
302 struct PCIController *hc;
304 struct TagItem pciDeactivate[] = {
305 {aHidd_PCIDevice_isIO, FALSE},
306 {aHidd_PCIDevice_isMEM, FALSE},
307 {aHidd_PCIDevice_isMaster, FALSE},
308 {TAG_DONE, 0UL},
311 KPRINTF(10, ("*** pciFreeUnit(%p) ***\n", hu));
313 // put em offline
314 hc = (struct PCIController *)hu->hu_Controllers.lh_Head;
315 while (hc->hc_Node.ln_Succ)
317 hc->hc_Flags &= ~HCF_ONLINE;
318 hc = (struct PCIController *)hc->hc_Node.ln_Succ;
321 FreeController(hc, hu);
323 // FIXME: (x/e/o/u)hciFree routines actually ONLY stops the chip NOT
324 // free anything as below...
325 hc = (struct PCIController *)hu->hu_Controllers.lh_Head;
326 while (hc->hc_Node.ln_Succ)
328 if (hc->hc_PCIMem)
330 HIDD_PCIDriver_FreePCIMem(hc->hc_PCIDriverObject,
331 hc->hc_PCIMem);
332 hc->hc_PCIMem = NULL;
334 hc = (struct PCIController *)hc->hc_Node.ln_Succ;
337 // disable and free board
338 hc = (struct PCIController *)hu->hu_Controllers.lh_Head;
339 while (hc->hc_Node.ln_Succ)
341 // deactivate busmaster and IO/Mem
342 OOP_SetAttrs(hc->hc_PCIDeviceObject, (struct TagItem *)pciDeactivate);
343 if (hc->hc_PCIIntHandler.is_Node.ln_Name)
345 RemIntServer(INTB_KERNEL + hc->hc_PCIIntLine,
346 &hc->hc_PCIIntHandler);
347 hc->hc_PCIIntHandler.is_Node.ln_Name = NULL;
349 hc = (struct PCIController *)hc->hc_Node.ln_Succ;
352 /* \\\ */
354 /* /// "pciExpunge()" */
355 void pciExpunge(struct PCIDevice *hd)
357 struct PCIController *hc;
358 struct PCIUnit *hu;
360 KPRINTF(10, ("*** pciExpunge(%p) ***\n", hd));
362 hu = (struct PCIUnit *)hd->hd_Units.lh_Head;
363 while (((struct Node *)hu)->ln_Succ)
365 Remove((struct Node *)hu);
366 hc = (struct PCIController *)hu->hu_Controllers.lh_Head;
367 while (hc->hc_Node.ln_Succ)
369 Remove(&hc->hc_Node);
370 FreePooled(hd->hd_MemPool, hc, sizeof(struct PCIController));
371 hc = (struct PCIController *)hu->hu_Controllers.lh_Head;
373 FreePooled(hd->hd_MemPool, hu, sizeof(struct PCIUnit));
374 hu = (struct PCIUnit *)hd->hd_Units.lh_Head;
376 if (hd->hd_PCIHidd)
378 struct OOP_ABDescr attrbases[] = {
379 {(STRPTR) IID_Hidd, &hd->hd_HiddAB},
380 {(STRPTR) IID_Hidd_PCIDevice, &hd->hd_HiddPCIDeviceAB},
381 {NULL, NULL}
384 OOP_ReleaseAttrBases(attrbases);
386 OOP_DisposeObject(hd->hd_PCIHidd);
389 /* \\\ */
391 /* /// "pciGetPhysical()" */
392 APTR pciGetPhysical(struct PCIController *hc, APTR virtaddr)
394 //struct PCIDevice *hd = hc->hc_Device;
395 return HIDD_PCIDriver_CPUtoPCI(hc->hc_PCIDriverObject, virtaddr);
397 /* \\\ */
400 * Process some AROS-specific arguments.
401 * 'usbpoweron' helps to bring up USB ports on IntelMac,
402 * whose firmware sets them up incorrectly.
404 static int getArguments(struct PCIDevice *base)
406 APTR BootLoaderBase;
407 #ifdef HAVE_ACPI
408 ACPI_TABLE_HEADER *dsdt;
409 ACPI_STATUS err;
412 * Use ACPI IDs to identify known machines which need HDF_FORCEPOWER
413 * to work. Currently we know only MacMini.
415 err = AcpiGetTable("DSDT", 1, &dsdt);
416 if (err == AE_OK) {
417 /* Yes, the last byte in ID is zero */
418 if (strcmp(dsdt->OemTableId, "Macmini") == 0)
420 base->hd_Flags = HDF_FORCEPOWER;
421 return TRUE;
424 #endif
426 BootLoaderBase = OpenResource("bootloader.resource");
427 if (BootLoaderBase)
429 struct List *args = GetBootInfo(BL_Args);
431 if (args)
433 struct Node *node;
435 for (node = args->lh_Head; node->ln_Succ; node = node->ln_Succ)
437 if (stricmp(node->ln_Name, "forceusbpower") == 0)
439 base->hd_Flags = HDF_FORCEPOWER;
440 break;
446 return TRUE;
449 ADD2INITLIB(getArguments, 10)