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 <proto/bootloader.h>
13 #include <proto/oop.h>
14 #include <proto/utility.h>
15 #include <proto/exec.h>
21 #include "ohciproto.h"
24 #include <proto/acpica.h>
25 /* acpica.library is optional */
26 struct Library
*ACPICABase
= NULL
;
29 #define NewList NEWLIST
31 #undef HiddPCIDeviceAttrBase
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
))
46 struct PCIDevice
*hd
= (struct PCIDevice
*) hook
->h_Data
;
47 struct PCIController
*hc
;
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
));
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"));
78 KPRINTF(10, ("Setting up device...\n"));
80 hc
= AllocPooled(hd
->hd_MemPool
, sizeof(struct PCIController
));
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
);
105 KPRINTF(10, ("Unsupported HCI type %ld\n", hcitype
));
112 /* /// "pciInit()" */
113 BOOL
pciInit(struct PCIDevice
*hd
)
115 struct PCIController
*hc
;
116 struct PCIController
*nexthc
;
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) },
133 struct OOP_ABDescr attrbases
[] =
135 { (STRPTR
) IID_Hidd
, &hd
->hd_HiddAB
},
136 { (STRPTR
) IID_Hidd_PCIDevice
, &hd
->hd_HiddPCIDeviceAB
},
140 struct Hook findHook
=
142 h_Entry
: (IPTR (*)()) pciEnumerator
,
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
);
153 KPRINTF(20, ("Unable to create PCIHidd object!\n"));
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
));
163 // actually, we should get rid of the allocated memory first, but I don't care as DeletePool() will take care of this eventually
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
);
180 AddTail(&hu
->hu_Controllers
, &hc
->hc_Node
);
184 AddTail(&hd
->hd_Units
, (struct Node
*) hu
);
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
);
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
);
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
);
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
);
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
);
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
);
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
)
256 while((*d
++ = *s
++));
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;
277 KPRINTF(10, ("*** pciAllocUnit(%p) ***\n", hu
));
279 hc
= (struct PCIController
*) hu
->hu_Controllers
.lh_Head
;
280 while(hc
->hc_Node
.ln_Succ
)
284 owner
= HIDD_PCIDevice_Obtain(hc
->hc_PCIDeviceObject
, hd
->hd_Library
.lib_Node
.ln_Name
);
286 hc
->hc_Flags
|= HCF_ALLOCATED
;
289 KPRINTF(20, ("Couldn't allocate board, already allocated by %s\n", owner
));
293 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
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
)
306 allocgood
= uhciInit(hc
,hu
);
315 allocgood
= ohciInit(hc
,hu
);
324 allocgood
= ehciInit(hc
,hu
);
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
;
340 hc
= (struct PCIController
*) hc
->hc_Node
.ln_Succ
;
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
;
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
)
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
;
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;
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
;
422 pciStrcat(prodname
, "PCI ");
423 if(ohcicnt
+ uhcicnt
)
425 if(ohcicnt
+ uhcicnt
>1)
427 prodname
[4] = ohcicnt
+ uhcicnt
+ '0';
431 pciStrcat(prodname
, ohcicnt
? "OHCI" : "UHCI");
434 pciStrcat(prodname
, " +");
436 pciStrcat(prodname
, " USB 1.1");
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.)");
449 pciStrcat(prodname
, "Emulated?)");
452 pciStrcat(prodname
, " Host Controller");
454 KPRINTF(10, ("Unit allocated!\n"));
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
},
474 KPRINTF(10, ("*** pciFreeUnit(%p) ***\n", hu
));
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
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
) {
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
;
517 /* /// "pciExpunge()" */
518 void pciExpunge(struct PCIDevice
*hd
)
520 struct PCIController
*hc
;
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
;
541 struct OOP_ABDescr attrbases
[] =
543 { (STRPTR
) IID_Hidd
, &hd
->hd_HiddAB
},
544 { (STRPTR
) IID_Hidd_PCIDevice
, &hd
->hd_HiddPCIDeviceAB
},
548 OOP_ReleaseAttrBases(attrbases
);
550 OOP_DisposeObject(hd
->hd_PCIHidd
);
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
));
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
)
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
;
581 err
= AcpiGetTable("DSDT", 1, &dsdt
);
583 /* Yes, the last byte in ID is zero */
584 if (strcmp(dsdt
->OemTableId
, "Macmini") == 0)
586 base
->hd_Flags
= HDF_FORCEPOWER
;
590 CloseLibrary(ACPICABase
);
595 BootLoaderBase
= OpenResource("bootloader.resource");
598 struct List
*args
= GetBootInfo(BL_Args
);
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
;
618 ADD2INITLIB(getArguments
, 10)