Documented GVF_SAVE_VAR alongside other flags, and removed a query/doubt
[AROS.git] / rom / usb / pciusb / pci_aros.c
blob0c06b13ec1ee5aa9a4dc24b8cbd5d1da9d385614
1 /* pci_aros.c - pci access abstraction for AROS by Chris Hodges
2 */
4 #include <aros/bootloader.h>
5 #include <aros/symbolsets.h>
6 #include <exec/types.h>
7 #include <oop/oop.h>
8 #include <devices/timer.h>
9 #include <hidd/hidd.h>
10 #include <hidd/pci.h>
12 #include <proto/bootloader.h>
13 #include <proto/oop.h>
14 #include <proto/utility.h>
15 #include <proto/exec.h>
17 #include <inttypes.h>
18 #include <string.h>
20 #include "uhwcmd.h"
21 #include "ohciproto.h"
23 #ifdef HAVE_ACPICA
24 #include <proto/acpica.h>
25 /* acpica.library is optional */
26 struct Library *ACPICABase = NULL;
27 #endif
29 #define NewList NEWLIST
31 #undef HiddPCIDeviceAttrBase
32 #undef HiddAttrBase
33 #undef HiddPCIDeviceBase
35 #define HiddPCIDeviceAttrBase (hd->hd_HiddPCIDeviceAB)
36 #define HiddAttrBase (hd->hd_HiddAB)
37 #define HiddPCIDeviceBase (hd->hd_HiddPCIDeviceMB)
39 AROS_UFH3(void, pciEnumerator,
40 AROS_UFHA(struct Hook *, hook, A0),
41 AROS_UFHA(OOP_Object *, pciDevice, A2),
42 AROS_UFHA(APTR, message, A1))
44 AROS_USERFUNC_INIT
46 struct PCIDevice *hd = (struct PCIDevice *) hook->h_Data;
47 struct PCIController *hc;
48 IPTR hcitype;
49 IPTR bus;
50 IPTR dev;
51 IPTR sub;
52 IPTR intline;
53 ULONG devid;
55 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Interface, &hcitype);
56 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Bus, &bus);
57 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Dev, &dev);
58 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Sub, &sub);
59 OOP_GetAttr(pciDevice, aHidd_PCIDevice_INTLine, &intline);
61 devid = (bus<<16)|dev;
63 KPRINTF(10, ("Found PCI device 0x%lx of type %ld, Intline=%ld\n", devid, hcitype, intline));
65 if(intline == 255)
67 // we can't work without the correct interrupt line
68 // BIOS needs plug & play os option disabled. Alternatively AROS must support APIC reconfiguration
69 KPRINTF(200, ("ERROR: PCI card has no interrupt line assigned by BIOS, disable Plug & Play OS!\n"));
71 else
73 switch (hcitype)
75 case HCITYPE_OHCI:
76 case HCITYPE_EHCI:
77 case HCITYPE_UHCI:
78 KPRINTF(10, ("Setting up device...\n"));
80 hc = AllocPooled(hd->hd_MemPool, sizeof(struct PCIController));
81 if (hc)
83 hc->hc_Device = hd;
84 hc->hc_DevID = devid;
85 hc->hc_FunctionNum = sub;
86 hc->hc_HCIType = hcitype;
87 hc->hc_PCIDeviceObject = pciDevice;
88 hc->hc_PCIIntLine = intline;
90 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Driver, (IPTR *) &hc->hc_PCIDriverObject);
92 NewList(&hc->hc_CtrlXFerQueue);
93 NewList(&hc->hc_IntXFerQueue);
94 NewList(&hc->hc_IsoXFerQueue);
95 NewList(&hc->hc_BulkXFerQueue);
96 NewList(&hc->hc_TDQueue);
97 NewList(&hc->hc_AbortQueue);
98 NewList(&hc->hc_PeriodicTDQueue);
99 NewList(&hc->hc_OhciRetireQueue);
100 AddTail(&hd->hd_TempHCIList, &hc->hc_Node);
102 break;
104 default:
105 KPRINTF(10, ("Unsupported HCI type %ld\n", hcitype));
109 AROS_USERFUNC_EXIT
112 /* /// "pciInit()" */
113 BOOL pciInit(struct PCIDevice *hd)
115 struct PCIController *hc;
116 struct PCIController *nexthc;
117 struct PCIUnit *hu;
118 ULONG unitno = 0;
120 KPRINTF(10, ("*** pciInit(%p) ***\n", hd));
122 NewList(&hd->hd_TempHCIList);
124 if((hd->hd_PCIHidd = OOP_NewObject(NULL, (STRPTR) CLID_Hidd_PCI, NULL)))
126 struct TagItem tags[] =
128 { tHidd_PCI_Class, (PCI_CLASS_SERIAL_USB>>8) & 0xff },
129 { tHidd_PCI_SubClass, (PCI_CLASS_SERIAL_USB & 0xff) },
130 { TAG_DONE, 0UL }
133 struct OOP_ABDescr attrbases[] =
135 { (STRPTR) IID_Hidd, &hd->hd_HiddAB },
136 { (STRPTR) IID_Hidd_PCIDevice, &hd->hd_HiddPCIDeviceAB },
137 { NULL, NULL }
140 struct Hook findHook =
142 h_Entry: (IPTR (*)()) pciEnumerator,
143 h_Data: hd,
146 OOP_ObtainAttrBases(attrbases);
147 hd->hd_HiddPCIDeviceMB = OOP_GetMethodID(IID_Hidd_PCIDevice, 0);
149 KPRINTF(20, ("Searching for devices...\n"));
151 HIDD_PCI_EnumDevices(hd->hd_PCIHidd, &findHook, (struct TagItem *) &tags);
152 } else {
153 KPRINTF(20, ("Unable to create PCIHidd object!\n"));
154 return FALSE;
157 // Create units with a list of host controllers having the same bus and device number.
158 while(hd->hd_TempHCIList.lh_Head->ln_Succ)
160 hu = AllocPooled(hd->hd_MemPool, sizeof(struct PCIUnit));
161 if(!hu)
163 // actually, we should get rid of the allocated memory first, but I don't care as DeletePool() will take care of this eventually
164 return FALSE;
166 hu->hu_Device = hd;
167 hu->hu_UnitNo = unitno;
168 hu->hu_DevID = ((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 /* /// "PCIXReadConfigByte()" */
192 UBYTE PCIXReadConfigByte(struct PCIController *hc, UBYTE offset)
194 struct PCIDevice *hd = hc->hc_Device;
196 return HIDD_PCIDevice_ReadConfigByte(hc->hc_PCIDeviceObject, offset);
198 /* \\\ */
200 /* /// "PCIXReadConfigWord()" */
201 UWORD PCIXReadConfigWord(struct PCIController *hc, UBYTE offset)
203 struct PCIDevice *hd = hc->hc_Device;
205 return HIDD_PCIDevice_ReadConfigWord(hc->hc_PCIDeviceObject, offset);
207 /* \\\ */
209 /* /// "PCIXReadConfigLong()" */
210 ULONG PCIXReadConfigLong(struct PCIController *hc, UBYTE offset)
212 struct PCIDevice *hd = hc->hc_Device;
214 return HIDD_PCIDevice_ReadConfigLong(hc->hc_PCIDeviceObject, offset);
216 /* \\\ */
218 /* /// "PCIXWriteConfigByte()" */
219 void PCIXWriteConfigByte(struct PCIController *hc, ULONG offset, UBYTE value)
221 struct PCIDevice *hd = hc->hc_Device;
223 HIDD_PCIDevice_WriteConfigByte(hc->hc_PCIDeviceObject, offset, value);
225 /* \\\ */
227 /* /// "PCIXWriteConfigWord()" */
228 void PCIXWriteConfigWord(struct PCIController *hc, ULONG offset, UWORD value)
230 struct PCIDevice *hd = hc->hc_Device;
232 HIDD_PCIDevice_WriteConfigWord(hc->hc_PCIDeviceObject, offset, value);
234 /* \\\ */
236 /* /// "PCIXWriteConfigLong()" */
237 void PCIXWriteConfigLong(struct PCIController *hc, ULONG offset, ULONG value)
239 struct PCIDevice *hd = hc->hc_Device;
241 HIDD_PCIDevice_WriteConfigLong(hc->hc_PCIDeviceObject, offset, value);
243 /* \\\ */
245 BOOL PCIXAddInterrupt(struct PCIController *hc, struct Interrupt *interrupt)
247 struct PCIDevice *hd = hc->hc_Device;
249 return HIDD_PCIDevice_AddInterrupt(hc->hc_PCIDeviceObject, interrupt);
252 /* /// "pciStrcat()" */
253 void pciStrcat(STRPTR d, STRPTR s)
255 while(*d) d++;
256 while((*d++ = *s++));
258 /* \\\ */
260 /* /// "pciAllocUnit()" */
261 BOOL pciAllocUnit(struct PCIUnit *hu)
263 struct PCIDevice *hd = hu->hu_Device;
264 struct PCIController *hc;
266 BOOL allocgood = TRUE;
267 ULONG usb11ports = 0;
268 ULONG usb20ports = 0;
269 ULONG cnt;
271 ULONG ohcicnt = 0;
272 ULONG uhcicnt = 0;
273 ULONG ehcicnt = 0;
275 STRPTR prodname;
277 KPRINTF(10, ("*** pciAllocUnit(%p) ***\n", hu));
279 hc = (struct PCIController *) hu->hu_Controllers.lh_Head;
280 while(hc->hc_Node.ln_Succ)
282 CONST_STRPTR owner;
284 owner = HIDD_PCIDevice_Obtain(hc->hc_PCIDeviceObject, hd->hd_Library.lib_Node.ln_Name);
285 if (!owner)
286 hc->hc_Flags |= HCF_ALLOCATED;
287 else
289 KPRINTF(20, ("Couldn't allocate board, already allocated by %s\n", owner));
290 allocgood = FALSE;
293 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
296 if(allocgood)
298 // allocate necessary memory
299 hc = (struct PCIController *) hu->hu_Controllers.lh_Head;
300 while(hc->hc_Node.ln_Succ)
302 switch(hc->hc_HCIType)
304 case HCITYPE_UHCI:
306 allocgood = uhciInit(hc,hu);
307 if(allocgood) {
308 uhcicnt++;
310 break;
313 case HCITYPE_OHCI:
315 allocgood = ohciInit(hc,hu);
316 if(allocgood) {
317 ohcicnt++;
319 break;
322 case HCITYPE_EHCI:
324 allocgood = ehciInit(hc,hu);
325 if(allocgood) {
326 ehcicnt++;
327 if(usb20ports) {
328 KPRINTF(200, ("WARNING: More than one EHCI controller per board?!?\n"));
330 usb20ports = hc->hc_NumPorts;
332 for(cnt = 0; cnt < usb20ports; cnt++) {
333 hu->hu_PortMap20[cnt] = hc;
334 hc->hc_PortNum20[cnt] = cnt;
337 break;
340 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
344 if(!allocgood)
346 // free previously allocated boards
347 hc = (struct PCIController *) hu->hu_Controllers.lh_Head;
348 while(hc->hc_Node.ln_Succ)
350 if (hc->hc_Flags & HCF_ALLOCATED)
352 hc->hc_Flags &= ~HCF_ALLOCATED;
353 HIDD_PCIDevice_Release(hc->hc_PCIDeviceObject);
356 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
358 return FALSE;
361 hc = (struct PCIController *) hu->hu_Controllers.lh_Head;
362 while(hc->hc_Node.ln_Succ)
364 if((hc->hc_HCIType == HCITYPE_UHCI) || (hc->hc_HCIType == HCITYPE_OHCI))
366 if(hc->hc_complexrouting)
368 ULONG locport = 0;
369 for(cnt = 0; cnt < usb20ports; cnt++)
371 if(((hc->hc_portroute >> (cnt<<2)) & 0xf) == hc->hc_FunctionNum)
373 KPRINTF(10, ("CHC %ld Port %ld assigned to global Port %ld\n", hc->hc_FunctionNum, locport, cnt));
374 hu->hu_PortMap11[cnt] = hc;
375 hu->hu_PortNum11[cnt] = locport;
376 hc->hc_PortNum20[locport] = cnt;
377 locport++;
380 } else {
381 for(cnt = usb11ports; cnt < usb11ports + hc->hc_NumPorts; cnt++)
383 hu->hu_PortMap11[cnt] = hc;
384 hu->hu_PortNum11[cnt] = cnt - usb11ports;
385 hc->hc_PortNum20[cnt - usb11ports] = cnt;
388 usb11ports += hc->hc_NumPorts;
390 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
392 if((usb11ports != usb20ports) && usb20ports)
394 KPRINTF(20, ("Warning! #EHCI Ports (%ld) does not match USB 1.1 Ports (%ld)!\n", usb20ports, usb11ports));
397 hu->hu_RootHub11Ports = usb11ports;
398 hu->hu_RootHub20Ports = usb20ports;
399 hu->hu_RootHubPorts = (usb11ports > usb20ports) ? usb11ports : usb20ports;
401 for(cnt = 0; cnt < hu->hu_RootHubPorts; cnt++)
403 hu->hu_EhciOwned[cnt] = hu->hu_PortMap20[cnt] ? TRUE : FALSE;
406 KPRINTF(10, ("Unit %ld: USB Board %08lx has %ld USB1.1 and %ld USB2.0 ports!\n", hu->hu_UnitNo, hu->hu_DevID, hu->hu_RootHub11Ports, hu->hu_RootHub20Ports));
408 hu->hu_FrameCounter = 1;
409 hu->hu_RootHubAddr = 0;
411 // put em online
412 hc = (struct PCIController *) hu->hu_Controllers.lh_Head;
413 while(hc->hc_Node.ln_Succ)
415 hc->hc_Flags |= HCF_ONLINE;
416 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
419 // create product name of device
420 prodname = hu->hu_ProductName;
421 *prodname = 0;
422 pciStrcat(prodname, "PCI ");
423 if(ohcicnt + uhcicnt)
425 if(ohcicnt + uhcicnt >1)
427 prodname[4] = ohcicnt + uhcicnt + '0';
428 prodname[5] = 'x';
429 prodname[6] = 0;
431 pciStrcat(prodname, ohcicnt ? "OHCI" : "UHCI");
432 if(ehcicnt)
434 pciStrcat(prodname, " +");
435 } else{
436 pciStrcat(prodname, " USB 1.1");
439 if(ehcicnt)
441 pciStrcat(prodname, " EHCI USB 2.0");
443 #if 0 // user can use pcitool to check what the chipset is and not guess it from this
444 pciStrcat(prodname, " Host Controller (");
445 if(ohcicnt + uhcicnt)
447 pciStrcat(prodname, ohcicnt ? "NEC)" : "VIA, Intel, ALI, etc.)");
448 } else {
449 pciStrcat(prodname, "Emulated?)");
451 #else
452 pciStrcat(prodname, " Host Controller");
453 #endif
454 KPRINTF(10, ("Unit allocated!\n"));
456 return TRUE;
458 /* \\\ */
460 /* /// "pciFreeUnit()" */
461 void pciFreeUnit(struct PCIUnit *hu)
463 struct PCIDevice *hd = hu->hu_Device;
464 struct PCIController *hc;
466 struct TagItem pciDeactivate[] =
468 { aHidd_PCIDevice_isIO, FALSE },
469 { aHidd_PCIDevice_isMEM, FALSE },
470 { aHidd_PCIDevice_isMaster, FALSE },
471 { TAG_DONE, 0UL },
474 KPRINTF(10, ("*** pciFreeUnit(%p) ***\n", hu));
476 // put em offline
477 hc = (struct PCIController *) hu->hu_Controllers.lh_Head;
478 while(hc->hc_Node.ln_Succ)
480 hc->hc_Flags &= ~HCF_ONLINE;
481 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
484 // doing this in three steps to avoid these damn host errors
485 ehciFree(hc, hu);
486 ohciFree(hc, hu);
487 uhciFree(hc, hu);
489 //FIXME: (x/e/o/u)hciFree routines actually ONLY stops the chip NOT free anything as below...
490 hc = (struct PCIController *) hu->hu_Controllers.lh_Head;
491 while(hc->hc_Node.ln_Succ) {
492 if(hc->hc_PCIMem) {
493 HIDD_PCIDriver_FreePCIMem(hc->hc_PCIDriverObject, hc->hc_PCIMem);
494 hc->hc_PCIMem = NULL;
496 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
499 // disable and free board
500 hc = (struct PCIController *) hu->hu_Controllers.lh_Head;
501 while(hc->hc_Node.ln_Succ)
503 OOP_SetAttrs(hc->hc_PCIDeviceObject, (struct TagItem *) pciDeactivate); // deactivate busmaster and IO/Mem
504 if(hc->hc_PCIIntHandler.is_Node.ln_Name)
506 HIDD_PCIDevice_RemoveInterrupt(hc->hc_PCIDeviceObject, &hc->hc_PCIIntHandler);
507 hc->hc_PCIIntHandler.is_Node.ln_Name = NULL;
510 hc->hc_Flags &= ~HCF_ALLOCATED;
511 HIDD_PCIDevice_Release(hc->hc_PCIDeviceObject);
512 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
515 /* \\\ */
517 /* /// "pciExpunge()" */
518 void pciExpunge(struct PCIDevice *hd)
520 struct PCIController *hc;
521 struct PCIUnit *hu;
523 KPRINTF(10, ("*** pciExpunge(%p) ***\n", hd));
525 hu = (struct PCIUnit *) hd->hd_Units.lh_Head;
526 while(((struct Node *) hu)->ln_Succ)
528 Remove((struct Node *) hu);
529 hc = (struct PCIController *) hu->hu_Controllers.lh_Head;
530 while(hc->hc_Node.ln_Succ)
532 Remove(&hc->hc_Node);
533 FreePooled(hd->hd_MemPool, hc, sizeof(struct PCIController));
534 hc = (struct PCIController *) hu->hu_Controllers.lh_Head;
536 FreePooled(hd->hd_MemPool, hu, sizeof(struct PCIUnit));
537 hu = (struct PCIUnit *) hd->hd_Units.lh_Head;
539 if(hd->hd_PCIHidd)
541 struct OOP_ABDescr attrbases[] =
543 { (STRPTR) IID_Hidd, &hd->hd_HiddAB },
544 { (STRPTR) IID_Hidd_PCIDevice, &hd->hd_HiddPCIDeviceAB },
545 { NULL, NULL }
548 OOP_ReleaseAttrBases(attrbases);
550 OOP_DisposeObject(hd->hd_PCIHidd);
553 /* \\\ */
555 /* /// "pciGetPhysical()" */
556 APTR pciGetPhysical(struct PCIController *hc, APTR virtaddr)
558 //struct PCIDevice *hd = hc->hc_Device;
559 return(HIDD_PCIDriver_CPUtoPCI(hc->hc_PCIDriverObject, virtaddr));
561 /* \\\ */
564 * Process some AROS-specific arguments.
565 * 'usbpoweron' helps to bring up USB ports on IntelMac,
566 * whose firmware sets them up incorrectly.
568 static int getArguments(struct PCIDevice *base)
570 APTR BootLoaderBase;
571 #ifdef HAVE_ACPICA
573 if ((ACPICABase = OpenLibrary("acpica.library", 0))) {
575 * Use ACPI IDs to identify known machines which need HDF_FORCEPOWER to work.
576 * Currently we know only MacMini.
578 ACPI_TABLE_HEADER *dsdt;
579 ACPI_STATUS err;
581 err = AcpiGetTable("DSDT", 1, &dsdt);
582 if (err == AE_OK) {
583 /* Yes, the last byte in ID is zero */
584 if (strcmp(dsdt->OemTableId, "Macmini") == 0)
586 base->hd_Flags = HDF_FORCEPOWER;
587 return TRUE;
590 CloseLibrary(ACPICABase);
591 ACPICABase = NULL;
593 #endif
595 BootLoaderBase = OpenResource("bootloader.resource");
596 if (BootLoaderBase)
598 struct List *args = GetBootInfo(BL_Args);
600 if (args)
602 struct Node *node;
604 for (node = args->lh_Head; node->ln_Succ; node = node->ln_Succ)
606 if (stricmp(node->ln_Name, "forceusbpower") == 0)
608 base->hd_Flags = HDF_FORCEPOWER;
609 break;
615 return TRUE;
618 ADD2INITLIB(getArguments, 10)