2 Copyright © 2004-2017, The AROS Development Team. All rights reserved.
5 Desc: PCI direct driver for i386 native.
9 #define __OOP_NOATTRBASES__
13 #include <aros/debug.h>
14 #include <aros/symbolsets.h>
17 #include <utility/tagitem.h>
19 #include <proto/exec.h>
20 #include <proto/utility.h>
21 #include <proto/oop.h>
22 #include <proto/acpica.h>
24 #include <acpica/acnames.h>
25 #include <acpica/accommon.h>
29 #undef HiddPCIDriverAttrBase
31 #undef HiddPCIDeviceAttrBase
33 #define HiddPCIDriverAttrBase (PSD(cl)->hiddPCIDriverAB)
34 #define HiddAttrBase (PSD(cl)->hiddAB)
35 #define HiddPCIDeviceAttrBase (PSD(cl)->hidd_PCIDeviceAB)
38 We overload the New method in order to introduce the Hidd Name and
39 HardwareName attributes.
41 OOP_Object
*PCPCI__Root__New(OOP_Class
*cl
, OOP_Object
*o
, struct pRoot_New
*msg
)
43 struct pRoot_New mymsg
;
44 struct TagItem mytags
[] =
46 { aHidd_Name
, (IPTR
)"pcipc.hidd" },
47 { aHidd_HardwareName
, (IPTR
)"IA32 native direct access PCI driver" },
52 mymsg
.attrList
= mytags
;
56 mytags
[2].ti_Tag
= TAG_MORE
;
57 mytags
[2].ti_Data
= (IPTR
)msg
->attrList
;
60 return (OOP_Object
*)OOP_DoSuperMethod(cl
, o
, &mymsg
.mID
);
63 IPTR
PCPCI__Hidd_PCIDriver__HasExtendedConfig(OOP_Class
*cl
, OOP_Object
*o
,
64 struct pHidd_PCIDriver_HasExtendedConfig
*msg
)
68 if(PSD(cl
)->pcipc_acpiMcfgTbl
) {
70 const ACPI_TABLE_MCFG
*mcfg_tbl
= (APTR
)PSD(cl
)->pcipc_acpiMcfgTbl
;
71 const ACPI_MCFG_ALLOCATION
*mcfg_alloc
= (APTR
)mcfg_tbl
+ sizeof(ACPI_TABLE_MCFG
);
74 if( (msg
->bus
<= mcfg_alloc
->EndBusNumber
) && (msg
->bus
>= mcfg_alloc
->StartBusNumber
) ) {
77 FIXME: Check the validity of the extended configuration space
82 mmio
= ((IPTR
)mcfg_alloc
->Address
) + (((msg
->bus
&255)<<20) | ((msg
->dev
&31)<<15) | ((msg
->sub
&7)<<12));
85 Absence of any Extended Capabilities is required to be indicated
86 by an Extended Capability header with a Capability ID of 0000h,
87 a Capability Version of 0h, and a Next Capability Offset of 0h.
89 For PCI devices OnMyHardware(TM) extended capability header at 0x100 reads 0xffffffff.
91 0xffffffff is non valid extended capability header as it would point
92 the next capability outside configuration space.
94 If we get extended capability header set with all ones then we won't use ECAM.
95 (PCI device in mmio space, not PCIe)
98 extcap
= (APTR
) (mmio
+ 0x100);
99 D(bug("HasExtendedConfig: bus %d dev %d sub %d extcap %08x\n", msg
->bus
, msg
->dev
, msg
->sub
, *extcap
));
100 if(*extcap
== 0xffffffff) {
101 D(bug(" Device is PCI not PCIe\n"));
107 D(bug("HasExtendedConfig: Device not found! bus %d dev %d sub %d \n", msg
->bus
, msg
->dev
, msg
->sub
));
111 }while((APTR
)mcfg_alloc
< ((APTR
)mcfg_tbl
+ mcfg_tbl
->Header
.Length
));
117 ULONG
PCPCI__Hidd_PCIDriver__ReadConfigLong(OOP_Class
*cl
, OOP_Object
*o
,
118 struct pHidd_PCIDriver_ReadConfigLong
*msg
)
121 We NEED the device object as it houses the ExtendedConfig attribute per device.
122 We know that the value stored in ExtendedConfig is the mmio base as returned by PCPCI__Hidd_PCIDriver__HasExtendedConfig.
123 If we get ExtendedConfig we will use ECAM method.
125 While the bus is being enumerated we automagically skip ECAM until ExtendedConfig attribute is set and we have a valid device object.
130 OOP_GetAttr(msg
->device
, aHidd_PCIDevice_ExtendedConfig
, &mmio
);
132 /* This is the ECAM access method for long read */
133 volatile ULONG
*longreg
;
135 longreg
= (APTR
) (mmio
+ (msg
->reg
& 0xffc));
137 D(bug("ECAM.read longreg %p %08x\n", longreg
, *longreg
));
142 Last good long register without ECAM,
143 macros in CAM methods take care of the alignment.
144 we don't want to return some random value.
146 if(msg
->reg
< 0x100) {
147 return PSD(cl
)->ReadConfigLong(msg
->bus
, msg
->dev
, msg
->sub
, msg
->reg
);
153 UWORD
PCPCI__Hidd_PCIDriver__ReadConfigWord(OOP_Class
*cl
, OOP_Object
*o
,
154 struct pHidd_PCIDriver_ReadConfigWord
*msg
)
156 return ReadConfigWord(PSD(cl
), msg
->bus
, msg
->dev
, msg
->sub
, msg
->reg
);
159 UBYTE
PCPCI__Hidd_PCIDriver__ReadConfigByte(OOP_Class
*cl
, OOP_Object
*o
,
160 struct pHidd_PCIDriver_ReadConfigByte
*msg
)
164 temp
.ul
= PSD(cl
)->ReadConfigLong(msg
->bus
, msg
->dev
, msg
->sub
, msg
->reg
);
165 return temp
.ub
[msg
->reg
& 3];
168 void PCPCI__Hidd_PCIDriver__WriteConfigLong(OOP_Class
*cl
, OOP_Object
*o
,
169 struct pHidd_PCIDriver_WriteConfigLong
*msg
)
173 OOP_GetAttr(msg
->device
, aHidd_PCIDevice_ExtendedConfig
, &mmio
);
175 /* This is the ECAM access method for long write */
176 volatile ULONG
*longreg
;
177 longreg
= (APTR
) (mmio
+ (msg
->reg
& 0xffc));
178 D(bug("ECAM.write.old longreg %p %08x = %08x\n", longreg
, *longreg
, msg
->val
));
180 D(bug("ECAM.write.new longreg %p %08x == %08x?\n", longreg
, *longreg
, msg
->val
));
183 Last good long register without ECAM,
184 macros in CAM methods take care of the alignment.
185 we don't want to store the value in some random address.
187 if(msg
->reg
< 0x100) {
188 PSD(cl
)->WriteConfigLong(msg
->bus
, msg
->dev
, msg
->sub
, msg
->reg
, msg
->val
);
195 /* Class initialization and destruction */
197 ACPI_STATUS
callback(ACPI_HANDLE Object
, ULONG nesting_level
, void *Context
, void **RerturnValue
)
200 RetVal
.Length
= ACPI_ALLOCATE_BUFFER
;
203 bug("callback. Object = %p, nesting_level=%d, Context=%p\n", Object
, nesting_level
, Context
);
205 status
= AcpiEvaluateObject(Object
, "_PRT", NULL
, &RetVal
);
207 bug("result of PRT evaluate=%d\n", status
);
209 if (!ACPI_FAILURE(status
))
211 bug("RetVal.Length=%d\n", RetVal
.Length
);
212 bug("RetVal.Pointer=%p\n", RetVal
.Pointer
);
213 ACPI_OBJECT
*RObject
= RetVal
.Pointer
;
214 bug("Object->Type =%d\n", RObject
->Type
);
215 bug("Object->Package.Count=%d\n", RObject
->Package
.Count
);
216 for (unsigned int i
=0; i
< RObject
->Package
.Count
; i
++)
218 ACPI_OBJECT
*item
= &RObject
->Package
.Elements
[i
];
219 bug("%03d: %p Type=%d Count=%d \n ", i
, item
, item
->Type
, item
->Package
.Count
);
220 for (unsigned int j
=0; j
< item
->Package
.Count
; j
++)
222 ACPI_OBJECT
*jitem
= &item
->Package
.Elements
[j
];
223 bug("%08x ", jitem
->Integer
.Value
);
233 static int PCPCI_InitClass(LIBBASETYPEPTR LIBBASE
)
235 struct pcipc_staticdata
*_psd
= &LIBBASE
->psd
;
236 struct pHidd_PCI_AddHardwareDriver msg
, *pmsg
= &msg
;
239 D(bug("[PCI.PC] Driver initialization\n"));
241 /* Open ACPI and cache the pointer to the MCFG table.. */
242 ACPICABase
= OpenLibrary("acpica.library", 0);
244 AcpiGetTable(ACPI_SIG_MCFG
, 1, (ACPI_TABLE_HEADER
**)&_psd
->pcipc_acpiMcfgTbl
);
246 _psd
->hiddPCIDriverAB
= OOP_ObtainAttrBase(IID_Hidd_PCIDriver
);
247 _psd
->hiddAB
= OOP_ObtainAttrBase(IID_Hidd
);
248 _psd
->hidd_PCIDeviceAB
= OOP_ObtainAttrBase(IID_Hidd_PCIDevice
);
249 if (_psd
->hiddPCIDriverAB
== 0 || _psd
->hiddAB
== 0 || _psd
->hidd_PCIDeviceAB
== 0)
251 D(bug("[PCI.PC] ObtainAttrBases failed\n"));
256 AcpiGetDevices("PNP0A03", callback
, LIBBASE
, NULL
);
258 /* Default to using config mechanism 1 */
259 _psd
->ReadConfigLong
= ReadConfig1Long
;
260 _psd
->WriteConfigLong
= WriteConfig1Long
;
262 PCIPC_ProbeConfMech(&LIBBASE
->psd
);
264 msg
.driverClass
= _psd
->driverClass
;
265 msg
.mID
= OOP_GetMethodID(IID_Hidd_PCI
, moHidd_PCI_AddHardwareDriver
);
266 D(bug("[PCI.PC] Registering Driver with PCI base class..\n"));
268 pci
= OOP_NewObject(NULL
, CLID_Hidd_PCI
, NULL
);
269 OOP_DoMethod(pci
, (OOP_Msg
)pmsg
);
270 OOP_DisposeObject(pci
);
272 D(bug("[PCI.PC] Driver initialization finished\n"));
277 static int PCPCI_ExpungeClass(LIBBASETYPEPTR LIBBASE
)
279 struct pcipc_staticdata
*_psd
= &LIBBASE
->psd
;
281 D(bug("[PCI.PC] Class destruction\n"));
283 OOP_ReleaseAttrBase(IID_Hidd_PCIDevice
);
284 OOP_ReleaseAttrBase(IID_Hidd_PCIDriver
);
285 OOP_ReleaseAttrBase(IID_Hidd
);
288 CloseLibrary(ACPICABase
);
293 ADD2INITLIB(PCPCI_InitClass
, 0)
294 ADD2EXPUNGELIB(PCPCI_ExpungeClass
, 0)