1 /* pci_aros.c - pci access abstraction for AROS by Chris Hodges
4 #include <aros/bootloader.h>
5 #include <aros/symbolsets.h>
6 #include <exec/types.h>
8 #include <devices/timer.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>
24 #include "ohciproto.h"
33 #define NewList NEWLIST
35 #undef HiddPCIDeviceAttrBase
36 //#undef HiddUSBDeviceAttrBase
37 //#undef HiddUSBHubAttrBase
38 //#undef HiddUSBDrvAttrBase
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
))
54 struct PCIDevice
*hd
= (struct PCIDevice
*) hook
->h_Data
;
55 struct PCIController
*hc
;
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
));
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"));
84 #ifndef __powerpc__ /* It was not from me. Perhaps on PPC these drivers suffer from CPU cache problems? (sonic) */
88 KPRINTF(10, ("Setting up device...\n"));
90 hc
= AllocPooled(hd
->hd_MemPool
, sizeof(struct PCIController
));
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
);
115 KPRINTF(10, ("Unsupported HCI type %ld\n", hcitype
));
122 /* /// "pciInit()" */
123 BOOL
pciInit(struct PCIDevice
*hd
)
125 struct PCIController
*hc
;
126 struct PCIController
*nexthc
;
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"));
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"));
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) },
154 struct OOP_ABDescr attrbases
[] =
156 { (STRPTR
) IID_Hidd
, &hd
->hd_HiddAB
},
157 { (STRPTR
) IID_Hidd_PCIDevice
, &hd
->hd_HiddPCIDeviceAB
},
161 struct Hook findHook
=
163 h_Entry
: (IPTR (*)()) pciEnumerator
,
167 OOP_ObtainAttrBases(attrbases
);
169 KPRINTF(20, ("Searching for devices...\n"));
171 HIDD_PCI_EnumDevices(hd
->hd_PCIHidd
, &findHook
, (struct TagItem
*) &tags
);
173 KPRINTF(20, ("Unable to create PCIHidd object!\n"));
174 OOP_DisposeObject(hd
->hd_IRQHidd
);
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
));
184 // actually, we should get rid of the allocated memory first, but I don't care as DeletePool() will take care of this eventually
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
);
201 AddTail(&hu
->hu_Controllers
, &hc
->hc_Node
);
205 AddTail(&hd
->hd_Units
, (struct Node
*) hu
);
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
);
220 return OOP_DoMethod(hc
->hc_PCIDeviceObject
, (OOP_Msg
) &msg
);
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
);
232 return OOP_DoMethod(hc
->hc_PCIDeviceObject
, (OOP_Msg
) &msg
);
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
);
244 return OOP_DoMethod(hc
->hc_PCIDeviceObject
, (OOP_Msg
) &msg
);
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
);
257 OOP_DoMethod(hc
->hc_PCIDeviceObject
, (OOP_Msg
) &msg
);
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
);
270 OOP_DoMethod(hc
->hc_PCIDeviceObject
, (OOP_Msg
) &msg
);
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
);
283 OOP_DoMethod(hc
->hc_PCIDeviceObject
, (OOP_Msg
) &msg
);
287 /* /// "pciStrcat()" */
288 void pciStrcat(STRPTR d
, STRPTR s
)
291 while((*d
++ = *s
++));
295 /* /// "pciAllocUnit()" */
296 BOOL
pciAllocUnit(struct PCIUnit
*hu
)
299 struct PCIDevice
*hd
= hu
->hu_Device
;
301 struct PCIController
*hc
;
303 BOOL allocgood
= TRUE
;
304 ULONG usb11ports
= 0;
305 ULONG usb20ports
= 0;
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
;
326 KPRINTF(20, ("Couldn't allocate board, already allocated by %s\n", PCIXGetBoardAttr(hc
->hc_BoardObject
, PCIXTAG_OWNER
)));
329 PCIXReleaseBoard(hc
->hc_BoardObject
);
331 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
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
)
345 allocgood
= uhciInit(hc
,hu
);
354 allocgood
= ohciInit(hc
,hu
);
363 allocgood
= ehciInit(hc
,hu
);
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
;
379 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
381 #if 0 // FIXME this needs to be replaced by something AROS supports
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
;
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
)
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
;
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;
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
;
468 pciStrcat(prodname
, "PCI ");
469 if(ohcicnt
+ uhcicnt
)
471 if(ohcicnt
+ uhcicnt
>1)
473 prodname
[4] = ohcicnt
+ uhcicnt
+ '0';
477 pciStrcat(prodname
, ohcicnt
? "OHCI" : "UHCI");
480 pciStrcat(prodname
, " +");
482 pciStrcat(prodname
, " USB 1.1");
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.)");
495 pciStrcat(prodname
, "Emulated?)");
498 pciStrcat(prodname
, " Host Controller");
500 KPRINTF(10, ("Unit allocated!\n"));
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
},
520 KPRINTF(10, ("*** pciFreeUnit(%p) ***\n", hu
));
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
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
) {
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
;
557 PCIXObtainBoard(hc
->hc_BoardObject
);
558 hc
->hc_Flags
&= ~HCF_ALLOCATED
;
559 PCIXSetBoardAttr(hc
->hc_BoardObject
, PCIXTAG_OWNER
, 0);
560 PCIXReleaseBoard(hc
->hc_BoardObject
);
562 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
567 /* /// "pciExpunge()" */
568 void pciExpunge(struct PCIDevice
*hd
)
570 struct PCIController
*hc
;
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
;
591 struct OOP_ABDescr attrbases
[] =
593 { (STRPTR
) IID_Hidd
, &hd
->hd_HiddAB
},
594 { (STRPTR
) IID_Hidd_PCIDevice
, &hd
->hd_HiddPCIDeviceAB
},
598 OOP_ReleaseAttrBases(attrbases
);
600 OOP_DisposeObject(hd
->hd_PCIHidd
);
604 OOP_DisposeObject(hd
->hd_IRQHidd
);
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
));
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
)
626 struct ACPIBase
*ACPIBase
;
628 ACPIBase
= OpenResource("acpi.resource");
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'));
639 /* Yes, the last byte in ID is zero */
640 if (strcmp(dsdt
->oem_table_id
, "Macmini") == 0)
642 base
->hd_Flags
= HDF_FORCEPOWER
;
649 BootLoaderBase
= OpenResource("bootloader.resource");
652 struct List
*args
= GetBootInfo(BL_Args
);
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
;
672 ADD2INITLIB(getArguments
, 10)