PopFile image fits better.
[AROS.git] / rom / usb / pciusb / pci_aros.c
blob8dd959b0051c4014757eb28bdf86a84527de0aac
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>
11 #include <hidd/irq.h>
12 #include <resources/acpi.h>
14 #include <proto/acpi.h>
15 #include <proto/bootloader.h>
16 #include <proto/oop.h>
17 #include <proto/utility.h>
18 #include <proto/exec.h>
20 #include <inttypes.h>
21 #include <string.h>
23 #include "uhwcmd.h"
24 #include "ohciproto.h"
26 #ifdef __i386__
27 #define HAVE_ACPI
28 #endif
29 #ifdef __x86_64__
30 #define HAVE_ACPI
31 #endif
33 #define NewList NEWLIST
35 #undef HiddPCIDeviceAttrBase
36 //#undef HiddUSBDeviceAttrBase
37 //#undef HiddUSBHubAttrBase
38 //#undef HiddUSBDrvAttrBase
39 #undef HiddAttrBase
41 #define HiddPCIDeviceAttrBase (hd->hd_HiddPCIDeviceAB)
42 //#define HiddUSBDeviceAttrBase (hd->hd_HiddUSBDeviceAB)
43 //#define HiddUSBHubAttrBase (hd->hd_HiddUSBHubAB)
44 //#define HiddUSBDrvAttrBase (hd->hd_HiddUSBDrvAB)
45 #define HiddAttrBase (hd->hd_HiddAB)
47 AROS_UFH3(void, pciEnumerator,
48 AROS_UFHA(struct Hook *, hook, A0),
49 AROS_UFHA(OOP_Object *, pciDevice, A2),
50 AROS_UFHA(APTR, message, A1))
52 AROS_USERFUNC_INIT
54 struct PCIDevice *hd = (struct PCIDevice *) hook->h_Data;
55 struct PCIController *hc;
56 IPTR hcitype;
57 IPTR bus;
58 IPTR dev;
59 IPTR sub;
60 IPTR intline;
61 ULONG devid;
63 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Interface, &hcitype);
64 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Bus, &bus);
65 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Dev, &dev);
66 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Dev, &sub);
67 OOP_GetAttr(pciDevice, aHidd_PCIDevice_INTLine, &intline);
69 devid = (bus<<16)|dev;
71 KPRINTF(10, ("Found PCI device 0x%lx of type %ld, Intline=%ld\n", devid, hcitype, intline));
73 if(intline == 255)
75 // we can't work without the correct interrupt line
76 // BIOS needs plug & play os option disabled. Alternatively AROS must support APIC reconfiguration
77 KPRINTF(200, ("ERROR: PCI card has no interrupt line assigned by BIOS, disable Plug & Play OS!\n"));
79 else
81 switch (hcitype)
83 case HCITYPE_OHCI:
84 #ifndef __powerpc__ /* It was not from me. Perhaps on PPC these drivers suffer from CPU cache problems? (sonic) */
85 case HCITYPE_EHCI:
86 case HCITYPE_UHCI:
87 #endif
88 KPRINTF(10, ("Setting up device...\n"));
90 hc = AllocPooled(hd->hd_MemPool, sizeof(struct PCIController));
91 if (hc)
93 hc->hc_Device = hd;
94 hc->hc_DevID = devid;
95 hc->hc_FunctionNum = sub;
96 hc->hc_HCIType = hcitype;
97 hc->hc_PCIDeviceObject = pciDevice;
98 hc->hc_PCIIntLine = intline;
100 OOP_GetAttr(pciDevice, aHidd_PCIDevice_Driver, (IPTR *) &hc->hc_PCIDriverObject);
102 NewList(&hc->hc_CtrlXFerQueue);
103 NewList(&hc->hc_IntXFerQueue);
104 NewList(&hc->hc_IsoXFerQueue);
105 NewList(&hc->hc_BulkXFerQueue);
106 NewList(&hc->hc_TDQueue);
107 NewList(&hc->hc_AbortQueue);
108 NewList(&hc->hc_PeriodicTDQueue);
109 NewList(&hc->hc_OhciRetireQueue);
110 AddTail(&hd->hd_TempHCIList, &hc->hc_Node);
112 break;
114 default:
115 KPRINTF(10, ("Unsupported HCI type %ld\n", hcitype));
119 AROS_USERFUNC_EXIT
122 /* /// "pciInit()" */
123 BOOL pciInit(struct PCIDevice *hd)
125 struct PCIController *hc;
126 struct PCIController *nexthc;
127 struct PCIUnit *hu;
128 ULONG unitno = 0;
130 KPRINTF(10, ("*** pciInit(%p) ***\n", hd));
131 /* if(sizeof(IPTR) > 4)
133 KPRINTF(200, ("I said the pciusb.device is not 64bit compatible right now. Go away!\n"));
134 return FALSE;
137 NewList(&hd->hd_TempHCIList);
139 if(!(hd->hd_IRQHidd = OOP_NewObject(NULL, (STRPTR) CLID_Hidd_IRQ, NULL)))
141 KPRINTF(20, ("Unable to create IRQHidd object!\n"));
142 return FALSE;
145 if((hd->hd_PCIHidd = OOP_NewObject(NULL, (STRPTR) CLID_Hidd_PCI, NULL)))
147 struct TagItem tags[] =
149 { tHidd_PCI_Class, (PCI_CLASS_SERIAL_USB>>8) & 0xff },
150 { tHidd_PCI_SubClass, (PCI_CLASS_SERIAL_USB & 0xff) },
151 { TAG_DONE, 0UL }
154 struct OOP_ABDescr attrbases[] =
156 { (STRPTR) IID_Hidd, &hd->hd_HiddAB },
157 { (STRPTR) IID_Hidd_PCIDevice, &hd->hd_HiddPCIDeviceAB },
158 { NULL, NULL }
161 struct Hook findHook =
163 h_Entry: (IPTR (*)()) pciEnumerator,
164 h_Data: hd,
167 OOP_ObtainAttrBases(attrbases);
169 KPRINTF(20, ("Searching for devices...\n"));
171 HIDD_PCI_EnumDevices(hd->hd_PCIHidd, &findHook, (struct TagItem *) &tags);
172 } else {
173 KPRINTF(20, ("Unable to create PCIHidd object!\n"));
174 OOP_DisposeObject(hd->hd_IRQHidd);
175 return FALSE;
178 // Create units with a list of host controllers having the same bus and device number.
179 while(hd->hd_TempHCIList.lh_Head->ln_Succ)
181 hu = AllocPooled(hd->hd_MemPool, sizeof(struct PCIUnit));
182 if(!hu)
184 // actually, we should get rid of the allocated memory first, but I don't care as DeletePool() will take care of this eventually
185 return FALSE;
187 hu->hu_Device = hd;
188 hu->hu_UnitNo = unitno;
189 hu->hu_DevID = ((struct PCIController *) hd->hd_TempHCIList.lh_Head)->hc_DevID;
191 NewList(&hu->hu_Controllers);
192 NewList(&hu->hu_RHIOQueue);
194 hc = (struct PCIController *) hd->hd_TempHCIList.lh_Head;
195 while((nexthc = (struct PCIController *) hc->hc_Node.ln_Succ))
197 if(hc->hc_DevID == hu->hu_DevID)
199 Remove(&hc->hc_Node);
200 hc->hc_Unit = hu;
201 AddTail(&hu->hu_Controllers, &hc->hc_Node);
203 hc = nexthc;
205 AddTail(&hd->hd_Units, (struct Node *) hu);
206 unitno++;
208 return TRUE;
210 /* \\\ */
212 /* /// "PCIXReadConfigByte()" */
213 UBYTE PCIXReadConfigByte(struct PCIController *hc, UBYTE offset)
215 struct pHidd_PCIDevice_ReadConfigByte msg;
217 msg.mID = OOP_GetMethodID(CLID_Hidd_PCIDevice, moHidd_PCIDevice_ReadConfigByte);
218 msg.reg = offset;
220 return OOP_DoMethod(hc->hc_PCIDeviceObject, (OOP_Msg) &msg);
222 /* \\\ */
224 /* /// "PCIXReadConfigWord()" */
225 UWORD PCIXReadConfigWord(struct PCIController *hc, UBYTE offset)
227 struct pHidd_PCIDevice_ReadConfigWord msg;
229 msg.mID = OOP_GetMethodID(CLID_Hidd_PCIDevice, moHidd_PCIDevice_ReadConfigWord);
230 msg.reg = offset;
232 return OOP_DoMethod(hc->hc_PCIDeviceObject, (OOP_Msg) &msg);
234 /* \\\ */
236 /* /// "PCIXReadConfigLong()" */
237 ULONG PCIXReadConfigLong(struct PCIController *hc, UBYTE offset)
239 struct pHidd_PCIDevice_ReadConfigLong msg;
241 msg.mID = OOP_GetMethodID(CLID_Hidd_PCIDevice, moHidd_PCIDevice_ReadConfigLong);
242 msg.reg = offset;
244 return OOP_DoMethod(hc->hc_PCIDeviceObject, (OOP_Msg) &msg);
246 /* \\\ */
248 /* /// "PCIXWriteConfigByte()" */
249 void PCIXWriteConfigByte(struct PCIController *hc, ULONG offset, UBYTE value)
251 struct pHidd_PCIDevice_WriteConfigByte msg;
253 msg.mID = OOP_GetMethodID(CLID_Hidd_PCIDevice, moHidd_PCIDevice_WriteConfigByte);
254 msg.reg = offset;
255 msg.val = value;
257 OOP_DoMethod(hc->hc_PCIDeviceObject, (OOP_Msg) &msg);
259 /* \\\ */
261 /* /// "PCIXWriteConfigWord()" */
262 void PCIXWriteConfigWord(struct PCIController *hc, ULONG offset, UWORD value)
264 struct pHidd_PCIDevice_WriteConfigWord msg;
266 msg.mID = OOP_GetMethodID(CLID_Hidd_PCIDevice, moHidd_PCIDevice_WriteConfigWord);
267 msg.reg = offset;
268 msg.val = value;
270 OOP_DoMethod(hc->hc_PCIDeviceObject, (OOP_Msg) &msg);
272 /* \\\ */
274 /* /// "PCIXWriteConfigLong()" */
275 void PCIXWriteConfigLong(struct PCIController *hc, ULONG offset, ULONG value)
277 struct pHidd_PCIDevice_WriteConfigLong msg;
279 msg.mID = OOP_GetMethodID(CLID_Hidd_PCIDevice, moHidd_PCIDevice_WriteConfigLong);
280 msg.reg = offset;
281 msg.val = value;
283 OOP_DoMethod(hc->hc_PCIDeviceObject, (OOP_Msg) &msg);
285 /* \\\ */
287 /* /// "pciStrcat()" */
288 void pciStrcat(STRPTR d, STRPTR s)
290 while(*d) d++;
291 while((*d++ = *s++));
293 /* \\\ */
295 /* /// "pciAllocUnit()" */
296 BOOL pciAllocUnit(struct PCIUnit *hu)
298 #if 0
299 struct PCIDevice *hd = hu->hu_Device;
300 #endif
301 struct PCIController *hc;
303 BOOL allocgood = TRUE;
304 ULONG usb11ports = 0;
305 ULONG usb20ports = 0;
307 ULONG cnt;
309 ULONG ohcicnt = 0;
310 ULONG uhcicnt = 0;
311 ULONG ehcicnt = 0;
313 STRPTR prodname;
315 KPRINTF(10, ("*** pciAllocUnit(%p) ***\n", hu));
317 #if 0 // FIXME this needs to be replaced by something AROS supports
318 hc = (struct PCIController *) hu->hu_Controllers.lh_Head;
319 while(hc->hc_Node.ln_Succ)
321 PCIXObtainBoard(hc->hc_BoardObject);
322 if (PCIXSetBoardAttr(hc->hc_BoardObject, PCIXTAG_OWNER, (ULONG) hd->hd_Library.lib_Node.ln_Name))
323 hc->hc_Flags |= HCF_BOARD_ALLOCATED;
324 else
326 KPRINTF(20, ("Couldn't allocate board, already allocated by %s\n", PCIXGetBoardAttr(hc->hc_BoardObject, PCIXTAG_OWNER)));
327 allocgood = FALSE;
329 PCIXReleaseBoard(hc->hc_BoardObject);
331 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
334 if(allocgood)
336 #endif
337 // allocate necessary memory
338 hc = (struct PCIController *) hu->hu_Controllers.lh_Head;
339 while(hc->hc_Node.ln_Succ)
341 switch(hc->hc_HCIType)
343 case HCITYPE_UHCI:
345 allocgood = uhciInit(hc,hu);
346 if(allocgood) {
347 uhcicnt++;
349 break;
352 case HCITYPE_OHCI:
354 allocgood = ohciInit(hc,hu);
355 if(allocgood) {
356 ohcicnt++;
358 break;
361 case HCITYPE_EHCI:
363 allocgood = ehciInit(hc,hu);
364 if(allocgood) {
365 ehcicnt++;
366 if(usb20ports) {
367 KPRINTF(200, ("WARNING: More than one EHCI controller per board?!?\n"));
369 usb20ports = hc->hc_NumPorts;
371 for(cnt = 0; cnt < usb20ports; cnt++) {
372 hu->hu_PortMap20[cnt] = hc;
373 hc->hc_PortNum20[cnt] = cnt;
376 break;
379 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
381 #if 0 // FIXME this needs to be replaced by something AROS supports
384 if(!allocgood)
386 // free previously allocated boards
387 hc = (struct PCIController *) hu->hu_Controllers.lh_Head;
388 while(hc->hc_Node.ln_Succ)
390 PCIXObtainBoard(hc->hc_BoardObject);
391 if (hc->hc_Flags & HCF_ALLOCATED)
393 hc->hc_Flags &= ~HCF_ALLOCATED;
394 PCIXSetBoardAttr(hc->hc_BoardObject, PCIXTAG_OWNER, 0);
396 PCIXReleaseBoard(hc->hc_BoardObject);
398 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
400 #else
401 if(!allocgood)
403 #endif
404 return FALSE;
407 hc = (struct PCIController *) hu->hu_Controllers.lh_Head;
408 while(hc->hc_Node.ln_Succ)
410 if((hc->hc_HCIType == HCITYPE_UHCI) || (hc->hc_HCIType == HCITYPE_OHCI))
412 if(hc->hc_complexrouting)
414 ULONG locport = 0;
415 for(cnt = 0; cnt < usb20ports; cnt++)
417 if(((hc->hc_portroute >> (cnt<<2)) & 0xf) == hc->hc_FunctionNum)
419 KPRINTF(10, ("CHC %ld Port %ld assigned to global Port %ld\n", hc->hc_FunctionNum, locport, cnt));
420 hu->hu_PortMap11[cnt] = hc;
421 hu->hu_PortNum11[cnt] = locport;
422 hc->hc_PortNum20[locport] = cnt;
423 locport++;
426 } else {
427 for(cnt = usb11ports; cnt < usb11ports + hc->hc_NumPorts; cnt++)
429 hu->hu_PortMap11[cnt] = hc;
430 hu->hu_PortNum11[cnt] = cnt - usb11ports;
431 hc->hc_PortNum20[cnt - usb11ports] = cnt;
434 usb11ports += hc->hc_NumPorts;
436 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
438 if((usb11ports != usb20ports) && usb20ports)
440 KPRINTF(20, ("Warning! #EHCI Ports (%ld) does not match USB 1.1 Ports (%ld)!\n", usb20ports, usb11ports));
443 hu->hu_RootHub11Ports = usb11ports;
444 hu->hu_RootHub20Ports = usb20ports;
445 hu->hu_RootHubPorts = (usb11ports > usb20ports) ? usb11ports : usb20ports;
447 for(cnt = 0; cnt < hu->hu_RootHubPorts; cnt++)
449 hu->hu_EhciOwned[cnt] = hu->hu_PortMap20[cnt] ? TRUE : FALSE;
452 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));
454 hu->hu_FrameCounter = 1;
455 hu->hu_RootHubAddr = 0;
457 // put em online
458 hc = (struct PCIController *) hu->hu_Controllers.lh_Head;
459 while(hc->hc_Node.ln_Succ)
461 hc->hc_Flags |= HCF_ONLINE;
462 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
465 // create product name of device
466 prodname = hu->hu_ProductName;
467 *prodname = 0;
468 pciStrcat(prodname, "PCI ");
469 if(ohcicnt + uhcicnt)
471 if(ohcicnt + uhcicnt >1)
473 prodname[4] = ohcicnt + uhcicnt + '0';
474 prodname[5] = 'x';
475 prodname[6] = 0;
477 pciStrcat(prodname, ohcicnt ? "OHCI" : "UHCI");
478 if(ehcicnt)
480 pciStrcat(prodname, " +");
481 } else{
482 pciStrcat(prodname, " USB 1.1");
485 if(ehcicnt)
487 pciStrcat(prodname, " EHCI USB 2.0");
489 #if 0 // user can use pcitool to check what the chipset is and not guess it from this
490 pciStrcat(prodname, " Host Controller (");
491 if(ohcicnt + uhcicnt)
493 pciStrcat(prodname, ohcicnt ? "NEC)" : "VIA, Intel, ALI, etc.)");
494 } else {
495 pciStrcat(prodname, "Emulated?)");
497 #else
498 pciStrcat(prodname, " Host Controller");
499 #endif
500 KPRINTF(10, ("Unit allocated!\n"));
502 return TRUE;
504 /* \\\ */
506 /* /// "pciFreeUnit()" */
507 void pciFreeUnit(struct PCIUnit *hu)
509 struct PCIDevice *hd = hu->hu_Device;
510 struct PCIController *hc;
512 struct TagItem pciDeactivate[] =
514 { aHidd_PCIDevice_isIO, FALSE },
515 { aHidd_PCIDevice_isMEM, FALSE },
516 { aHidd_PCIDevice_isMaster, FALSE },
517 { TAG_DONE, 0UL },
520 KPRINTF(10, ("*** pciFreeUnit(%p) ***\n", hu));
522 // put em offline
523 hc = (struct PCIController *) hu->hu_Controllers.lh_Head;
524 while(hc->hc_Node.ln_Succ)
526 hc->hc_Flags &= ~HCF_ONLINE;
527 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
530 // doing this in three steps to avoid these damn host errors
531 ehciFree(hc, hu);
532 ohciFree(hc, hu);
533 uhciFree(hc, hu);
535 //FIXME: (x/e/o/u)hciFree routines actually ONLY stops the chip NOT free anything as below...
536 hc = (struct PCIController *) hu->hu_Controllers.lh_Head;
537 while(hc->hc_Node.ln_Succ) {
538 if(hc->hc_PCIMem) {
539 HIDD_PCIDriver_FreePCIMem(hc->hc_PCIDriverObject, hc->hc_PCIMem);
540 hc->hc_PCIMem = NULL;
542 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
545 // disable and free board
546 hc = (struct PCIController *) hu->hu_Controllers.lh_Head;
547 while(hc->hc_Node.ln_Succ)
549 OOP_SetAttrs(hc->hc_PCIDeviceObject, (struct TagItem *) pciDeactivate); // deactivate busmaster and IO/Mem
550 if(hc->hc_PCIIntHandler.h_Node.ln_Name)
552 HIDD_IRQ_RemHandler(hd->hd_IRQHidd, &hc->hc_PCIIntHandler);
553 hc->hc_PCIIntHandler.h_Node.ln_Name = NULL;
555 #if 0
557 PCIXObtainBoard(hc->hc_BoardObject);
558 hc->hc_Flags &= ~HCF_ALLOCATED;
559 PCIXSetBoardAttr(hc->hc_BoardObject, PCIXTAG_OWNER, 0);
560 PCIXReleaseBoard(hc->hc_BoardObject);
561 #endif
562 hc = (struct PCIController *) hc->hc_Node.ln_Succ;
565 /* \\\ */
567 /* /// "pciExpunge()" */
568 void pciExpunge(struct PCIDevice *hd)
570 struct PCIController *hc;
571 struct PCIUnit *hu;
573 KPRINTF(10, ("*** pciExpunge(%p) ***\n", hd));
575 hu = (struct PCIUnit *) hd->hd_Units.lh_Head;
576 while(((struct Node *) hu)->ln_Succ)
578 Remove((struct Node *) hu);
579 hc = (struct PCIController *) hu->hu_Controllers.lh_Head;
580 while(hc->hc_Node.ln_Succ)
582 Remove(&hc->hc_Node);
583 FreePooled(hd->hd_MemPool, hc, sizeof(struct PCIController));
584 hc = (struct PCIController *) hu->hu_Controllers.lh_Head;
586 FreePooled(hd->hd_MemPool, hu, sizeof(struct PCIUnit));
587 hu = (struct PCIUnit *) hd->hd_Units.lh_Head;
589 if(hd->hd_PCIHidd)
591 struct OOP_ABDescr attrbases[] =
593 { (STRPTR) IID_Hidd, &hd->hd_HiddAB },
594 { (STRPTR) IID_Hidd_PCIDevice, &hd->hd_HiddPCIDeviceAB },
595 { NULL, NULL }
598 OOP_ReleaseAttrBases(attrbases);
600 OOP_DisposeObject(hd->hd_PCIHidd);
602 if(hd->hd_IRQHidd)
604 OOP_DisposeObject(hd->hd_IRQHidd);
607 /* \\\ */
609 /* /// "pciGetPhysical()" */
610 APTR pciGetPhysical(struct PCIController *hc, APTR virtaddr)
612 //struct PCIDevice *hd = hc->hc_Device;
613 return(HIDD_PCIDriver_CPUtoPCI(hc->hc_PCIDriverObject, virtaddr));
615 /* \\\ */
618 * Process some AROS-specific arguments.
619 * 'usbpoweron' helps to bring up USB ports on IntelMac,
620 * whose firmware sets them up incorrectly.
622 static int getArguments(struct PCIDevice *base)
624 APTR BootLoaderBase;
625 #ifdef HAVE_ACPI
626 struct ACPIBase *ACPIBase;
628 ACPIBase = OpenResource("acpi.resource");
629 if (ACPIBase)
632 * Use ACPI IDs to identify known machines which need HDF_FORCEPOWER to work.
633 * Currently we know only MacMini.
635 struct ACPI_TABLE_DEF_HEADER *dsdt = ACPI_FindSDT(ACPI_MAKE_ID('D','S','D','T'));
637 if (dsdt)
639 /* Yes, the last byte in ID is zero */
640 if (strcmp(dsdt->oem_table_id, "Macmini") == 0)
642 base->hd_Flags = HDF_FORCEPOWER;
643 return TRUE;
647 #endif
649 BootLoaderBase = OpenResource("bootloader.resource");
650 if (BootLoaderBase)
652 struct List *args = GetBootInfo(BL_Args);
654 if (args)
656 struct Node *node;
658 for (node = args->lh_Head; node->ln_Succ; node = node->ln_Succ)
660 if (stricmp(node->ln_Name, "forceusbpower") == 0)
662 base->hd_Flags = HDF_FORCEPOWER;
663 break;
669 return TRUE;
672 ADD2INITLIB(getArguments, 10)