Fixed weird formatting.
[AROS.git] / rom / usb / pciusbhc / ohci / pci.c
blobd33eb6e9089585a31cba08c6fa8a56c9a234baad
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>
13 #include <resources/acpi.h>
15 #include <proto/acpi.h>
16 #include <proto/bootloader.h>
17 #include <proto/oop.h>
18 #include <proto/utility.h>
19 #include <proto/exec.h>
20 #include <clib/alib_protos.h>
22 #include <string.h>
24 #include "debug.h"
25 #include "chip.h"
26 #include "dev.h"
28 #include "chip_protos.h"
29 #include "cmd_protos.h"
31 #ifdef __i386__
32 #define HAVE_ACPI
33 #endif
34 #ifdef __x86_64__
35 #define HAVE_ACPI
36 #endif
38 #undef HiddPCIDeviceAttrBase
39 #undef HiddAttrBase
41 #define HiddPCIDeviceAttrBase (hd->hd_HiddPCIDeviceAB)
42 #define HiddAttrBase (hd->hd_HiddAB)
44 static TEXT product_name[] = "PCI OHCI USB 1.1 Host Controller";
46 AROS_UFH3(void, pciEnumerator,
47 AROS_UFHA(struct Hook *, hook, A0),
48 AROS_UFHA(OOP_Object *, pciDevice, A2), AROS_UFHA(APTR, message, A1))
50 AROS_USERFUNC_INIT
52 struct PCIDevice *hd = (struct PCIDevice *)hook->h_Data;
53 struct PCIController *hc;
54 IPTR bus;
55 IPTR dev;
56 IPTR sub;
57 IPTR intline;
58 ULONG devid;
59 UWORD i;
61 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Bus, &bus);
62 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Dev, &dev);
63 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Dev, &sub);
64 OOP_GetAttr(pciDevice, aHidd_PCIDevice_INTLine, &intline);
66 devid = (bus << 16) | dev;
68 KPRINTF(10, ("Found PCI device 0x%lx Intline=%ld\n", devid, intline));
70 if (intline == 255)
72 // we can't work without the correct interrupt line.
73 // BIOS needs plug & play os option disabled.
74 // Alternatively AROS must support APIC reconfiguration
75 KPRINTF(200, ("ERROR: PCI card has no interrupt line assigned "
76 "by BIOS, disable Plug & Play OS!\n"));
78 else
80 KPRINTF(10, ("Setting up device...\n"));
82 hc = AllocPooled(hd->hd_MemPool, sizeof(struct PCIController));
83 if (hc)
85 hc->hc_Device = hd;
86 hc->hc_DevID = devid;
87 hc->hc_FunctionNum = sub;
88 hc->hc_PCIDeviceObject = pciDevice;
89 hc->hc_PCIIntLine = intline;
91 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Driver,
92 (IPTR *) & hc->hc_PCIDriverObject);
94 for (i = 0; i < XFER_COUNT; i++)
95 NewList(&hc->hc_XferQueues[i]);
96 NewList(&hc->hc_TDQueue);
97 NewList(&hc->hc_AbortQueue);
98 NewList(&hc->hc_PeriodicTDQueue);
99 NewList(&hc->hc_RetireQueue);
100 AddTail(&hd->hd_TempHCIList, &hc->hc_Node);
104 AROS_USERFUNC_EXIT
107 /* /// "pciInit()" */
108 BOOL pciInit(struct PCIDevice *hd)
110 struct PCIController *hc;
111 struct PCIController *nexthc;
112 struct PCIUnit *hu;
113 ULONG unitno = 0;
115 KPRINTF(10, ("*** pciInit(%p) ***\n", hd));
117 NewList(&hd->hd_TempHCIList);
119 if ((hd->hd_PCIHidd =
120 OOP_NewObject(NULL, (STRPTR) CLID_Hidd_PCI, NULL)))
122 struct TagItem tags[] = {
123 {tHidd_PCI_Class, (PCI_CLASS_SERIAL_USB >> 8) & 0xff},
124 {tHidd_PCI_SubClass, (PCI_CLASS_SERIAL_USB & 0xff)},
125 {tHidd_PCI_Interface, 0x10},
126 {TAG_DONE, 0UL}
129 struct OOP_ABDescr attrbases[] = {
130 {(STRPTR) IID_Hidd, &hd->hd_HiddAB},
131 {(STRPTR) IID_Hidd_PCIDevice, &hd->hd_HiddPCIDeviceAB},
132 {NULL, NULL}
135 struct Hook findHook = {
136 h_Entry:(IPTR(*)())pciEnumerator,
137 h_Data:hd,
140 OOP_ObtainAttrBases(attrbases);
142 KPRINTF(20, ("Searching for devices...\n"));
144 HIDD_PCI_EnumDevices(hd->hd_PCIHidd, &findHook,
145 (struct TagItem *)&tags);
147 else
149 KPRINTF(20, ("Unable to create PCIHidd object!\n"));
150 return FALSE;
153 // Create units with a list of host controllers having the same bus
154 // and device number.
155 while (hd->hd_TempHCIList.lh_Head->ln_Succ)
157 hu = AllocPooled(hd->hd_MemPool, sizeof(struct PCIUnit));
158 if (!hu)
160 // actually, we should get rid of the allocated memory first,
161 // but we don't care as DeletePool() will take care of this
162 // eventually
163 return FALSE;
165 hu->hu_Device = hd;
166 hu->hu_UnitNo = unitno;
167 hu->hu_DevID =
168 ((struct PCIController *)hd->hd_TempHCIList.lh_Head)->hc_DevID;
170 NewList(&hu->hu_Controllers);
171 NewList(&hu->hu_RHIOQueue);
173 hc = (struct PCIController *)hd->hd_TempHCIList.lh_Head;
174 while ((nexthc = (struct PCIController *)hc->hc_Node.ln_Succ))
176 if (hc->hc_DevID == hu->hu_DevID)
178 Remove(&hc->hc_Node);
179 hc->hc_Unit = hu;
180 AddTail(&hu->hu_Controllers, &hc->hc_Node);
182 hc = nexthc;
184 AddTail(&hd->hd_Units, (struct Node *)hu);
185 unitno++;
187 return TRUE;
189 /* \\\ */
191 /* /// "pciAllocUnit()" */
192 BOOL pciAllocUnit(struct PCIUnit * hu)
194 struct PCIController *hc;
196 BOOL allocgood = TRUE;
197 ULONG usb11ports = 0;
198 ULONG usb20ports = 0;
199 ULONG cnt;
201 ULONG ohcicnt = 0;
203 KPRINTF(10, ("*** pciAllocUnit(%p) ***\n", hu));
205 // allocate necessary memory
206 hc = (struct PCIController *)hu->hu_Controllers.lh_Head;
207 while (hc->hc_Node.ln_Succ)
209 allocgood = InitController(hc, hu);
210 if (allocgood)
212 ohcicnt++;
215 hc = (struct PCIController *)hc->hc_Node.ln_Succ;
218 if (!allocgood)
220 return FALSE;
223 hc = (struct PCIController *)hu->hu_Controllers.lh_Head;
224 while (hc->hc_Node.ln_Succ)
226 if (hc->hc_complexrouting)
228 ULONG locport = 0;
229 for (cnt = 0; cnt < usb20ports; cnt++)
231 if (((hc->hc_portroute >> (cnt << 2)) & 0xf) ==
232 hc->hc_FunctionNum)
234 KPRINTF(10,
235 ("CHC %ld Port %ld assigned to global Port %ld\n",
236 hc->hc_FunctionNum, locport, cnt));
237 hu->hu_PortMap11[cnt] = hc;
238 hu->hu_PortNum11[cnt] = locport;
239 hc->hc_PortNum20[locport] = cnt;
240 locport++;
244 else
246 for (cnt = usb11ports; cnt < usb11ports + hc->hc_NumPorts;
247 cnt++)
249 hu->hu_PortMap11[cnt] = hc;
250 hu->hu_PortNum11[cnt] = cnt - usb11ports;
251 hc->hc_PortNum20[cnt - usb11ports] = cnt;
254 usb11ports += hc->hc_NumPorts;
255 hc = (struct PCIController *)hc->hc_Node.ln_Succ;
257 if ((usb11ports != usb20ports) && usb20ports)
259 KPRINTF(20,
260 ("Warning! #EHCI Ports (%ld) does not match USB 1.1 Ports (%ld)!\n",
261 usb20ports, usb11ports));
264 hu->hu_RootHub11Ports = usb11ports;
265 hu->hu_RootHub20Ports = usb20ports;
266 hu->hu_RootHubPorts =
267 (usb11ports > usb20ports) ? usb11ports : usb20ports;
268 for (cnt = 0; cnt < hu->hu_RootHubPorts; cnt++)
270 hu->hu_EhciOwned[cnt] = hu->hu_PortMap20[cnt] ? TRUE : FALSE;
273 KPRINTF(10, ("Unit %ld: USB Board %08lx has %ld USB1.1 ports\n",
274 hu->hu_UnitNo, hu->hu_DevID, hu->hu_RootHub11Ports));
276 hu->hu_FrameCounter = 1;
277 hu->hu_RootHubAddr = 0;
279 // put em online
280 hc = (struct PCIController *)hu->hu_Controllers.lh_Head;
281 while (hc->hc_Node.ln_Succ)
283 hc->hc_Flags |= HCF_ONLINE;
284 hc = (struct PCIController *)hc->hc_Node.ln_Succ;
287 // create product name of device
288 CopyMem(product_name, hu->hu_ProductName, sizeof(product_name));
290 KPRINTF(10, ("Unit allocated!\n"));
292 return TRUE;
294 /* \\\ */
296 /* /// "pciFreeUnit()" */
297 void pciFreeUnit(struct PCIUnit *hu)
299 struct PCIDevice *hd = hu->hu_Device;
300 struct PCIController *hc;
302 struct TagItem pciDeactivate[] = {
303 {aHidd_PCIDevice_isIO, FALSE},
304 {aHidd_PCIDevice_isMEM, FALSE},
305 {aHidd_PCIDevice_isMaster, FALSE},
306 {TAG_DONE, 0UL},
309 KPRINTF(10, ("*** pciFreeUnit(%p) ***\n", hu));
311 // put em offline
312 hc = (struct PCIController *)hu->hu_Controllers.lh_Head;
313 while (hc->hc_Node.ln_Succ)
315 hc->hc_Flags &= ~HCF_ONLINE;
316 hc = (struct PCIController *)hc->hc_Node.ln_Succ;
319 FreeController(hc, hu);
321 // FIXME: (x/e/o/u)hciFree routines actually ONLY stops the chip NOT
322 // free anything as below...
323 hc = (struct PCIController *)hu->hu_Controllers.lh_Head;
324 while (hc->hc_Node.ln_Succ)
326 if (hc->hc_PCIMem)
328 HIDD_PCIDriver_FreePCIMem(hc->hc_PCIDriverObject,
329 hc->hc_PCIMem);
330 hc->hc_PCIMem = NULL;
332 hc = (struct PCIController *)hc->hc_Node.ln_Succ;
335 // disable and free board
336 hc = (struct PCIController *)hu->hu_Controllers.lh_Head;
337 while (hc->hc_Node.ln_Succ)
339 // deactivate busmaster and IO/Mem
340 OOP_SetAttrs(hc->hc_PCIDeviceObject, (struct TagItem *)pciDeactivate);
341 if (hc->hc_PCIIntHandler.is_Node.ln_Name)
343 RemIntServer(INTB_KERNEL + hc->hc_PCIIntLine,
344 &hc->hc_PCIIntHandler);
345 hc->hc_PCIIntHandler.is_Node.ln_Name = NULL;
347 hc = (struct PCIController *)hc->hc_Node.ln_Succ;
350 /* \\\ */
352 /* /// "pciExpunge()" */
353 void pciExpunge(struct PCIDevice *hd)
355 struct PCIController *hc;
356 struct PCIUnit *hu;
358 KPRINTF(10, ("*** pciExpunge(%p) ***\n", hd));
360 hu = (struct PCIUnit *)hd->hd_Units.lh_Head;
361 while (((struct Node *)hu)->ln_Succ)
363 Remove((struct Node *)hu);
364 hc = (struct PCIController *)hu->hu_Controllers.lh_Head;
365 while (hc->hc_Node.ln_Succ)
367 Remove(&hc->hc_Node);
368 FreePooled(hd->hd_MemPool, hc, sizeof(struct PCIController));
369 hc = (struct PCIController *)hu->hu_Controllers.lh_Head;
371 FreePooled(hd->hd_MemPool, hu, sizeof(struct PCIUnit));
372 hu = (struct PCIUnit *)hd->hd_Units.lh_Head;
374 if (hd->hd_PCIHidd)
376 struct OOP_ABDescr attrbases[] = {
377 {(STRPTR) IID_Hidd, &hd->hd_HiddAB},
378 {(STRPTR) IID_Hidd_PCIDevice, &hd->hd_HiddPCIDeviceAB},
379 {NULL, NULL}
382 OOP_ReleaseAttrBases(attrbases);
384 OOP_DisposeObject(hd->hd_PCIHidd);
387 /* \\\ */
389 /* /// "pciGetPhysical()" */
390 APTR pciGetPhysical(struct PCIController *hc, APTR virtaddr)
392 //struct PCIDevice *hd = hc->hc_Device;
393 return HIDD_PCIDriver_CPUtoPCI(hc->hc_PCIDriverObject, virtaddr);
395 /* \\\ */
398 * Process some AROS-specific arguments.
399 * 'usbpoweron' helps to bring up USB ports on IntelMac,
400 * whose firmware sets them up incorrectly.
402 static int getArguments(struct PCIDevice *base)
404 APTR BootLoaderBase;
405 #ifdef HAVE_ACPI
406 struct ACPIBase *ACPIBase;
408 ACPIBase = OpenResource("acpi.resource");
409 if (ACPIBase)
412 * Use ACPI IDs to identify known machines which need HDF_FORCEPOWER
413 * to work. Currently we know only MacMini.
415 struct ACPI_TABLE_DEF_HEADER *dsdt =
416 ACPI_FindSDT(ACPI_MAKE_ID('D', 'S', 'D', 'T'));
418 if (dsdt)
420 /* Yes, the last byte in ID is zero */
421 if (strcmp(dsdt->oem_table_id, "Macmini") == 0)
423 base->hd_Flags = HDF_FORCEPOWER;
424 return TRUE;
428 #endif
430 BootLoaderBase = OpenResource("bootloader.resource");
431 if (BootLoaderBase)
433 struct List *args = GetBootInfo(BL_Args);
435 if (args)
437 struct Node *node;
439 for (node = args->lh_Head; node->ln_Succ; node = node->ln_Succ)
441 if (stricmp(node->ln_Name, "forceusbpower") == 0)
443 base->hd_Flags = HDF_FORCEPOWER;
444 break;
450 return TRUE;
453 ADD2INITLIB(getArguments, 10)