ACPICABase must be a global variable if acpica.library is to be
[AROS.git] / arch / all-pc / hidds / pcipc / driverclass.c
blobe4942873cf963a6953dc7a5acda9437a0b090637
1 /*
2 Copyright © 2004-2014, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: PCI direct driver for i386 native.
6 Lang: English
7 */
9 #define __OOP_NOATTRBASES__
11 #include <aros/debug.h>
12 #include <aros/symbolsets.h>
13 #include <hidd/pci.h>
14 #include <oop/oop.h>
15 #include <utility/tagitem.h>
17 #include <proto/exec.h>
18 #include <proto/utility.h>
19 #include <proto/oop.h>
20 #include <proto/acpica.h>
22 #include "pci.h"
24 #undef HiddPCIDriverAttrBase
25 #undef HiddAttrBase
26 #undef HiddPCIDeviceAttrBase
28 #define HiddPCIDriverAttrBase (PSD(cl)->hiddPCIDriverAB)
29 #define HiddAttrBase (PSD(cl)->hiddAB)
30 #define HiddPCIDeviceAttrBase (PSD(cl)->hidd_PCIDeviceAB)
32 /* ACPICABase is optional */
33 struct Library *ACPICABase;
36 We overload the New method in order to introduce the Hidd Name and
37 HardwareName attributes.
39 OOP_Object *PCPCI__Root__New(OOP_Class *cl, OOP_Object *o, struct pRoot_New *msg)
41 struct pRoot_New mymsg;
42 struct TagItem mytags[] =
44 { aHidd_Name , (IPTR)"PCINative" },
45 { aHidd_HardwareName, (IPTR)"IA32 native direct access PCI driver" },
46 { TAG_DONE , 0 }
49 mymsg.mID = msg->mID;
50 mymsg.attrList = mytags;
52 if (msg->attrList)
54 mytags[2].ti_Tag = TAG_MORE;
55 mytags[2].ti_Data = (IPTR)msg->attrList;
58 return (OOP_Object *)OOP_DoSuperMethod(cl, o, &mymsg.mID);
61 IPTR PCPCI__Hidd_PCIDriver__HasExtendedConfig(OOP_Class *cl, OOP_Object *o,
62 struct pHidd_PCIDriver_HasExtendedConfig *msg)
64 IPTR mmio = 0;
66 if(PSD(cl)->mcfg_tbl) {
68 const ACPI_TABLE_MCFG *mcfg_tbl = (APTR)PSD(cl)->mcfg_tbl;
69 const ACPI_MCFG_ALLOCATION *mcfg_alloc = (APTR)mcfg_tbl + sizeof(ACPI_TABLE_MCFG);
71 do {
72 if( (msg->bus <= mcfg_alloc->EndBusNumber) && (msg->bus >= mcfg_alloc->StartBusNumber) ) {
75 FIXME: Check the validity of the extended configuration space
78 ULONG *extcap;
80 mmio = ((IPTR)mcfg_alloc->Address) + (((msg->bus&255)<<20) | ((msg->dev&31)<<15) | ((msg->sub&7)<<12));
83 Absence of any Extended Capabilities is required to be indicated
84 by an Extended Capability header with a Capability ID of 0000h,
85 a Capability Version of 0h, and a Next Capability Offset of 0h.
87 For PCI devices OnMyHardware(TM) extended capability header at 0x100 reads 0xffffffff.
89 0xffffffff is non valid extended capability header as it would point
90 the next capability outside configuration space.
92 If we get extended capability header set with all ones then we won't use ECAM.
93 (PCI device in mmio space, not PCIe)
96 extcap = (APTR) (mmio + 0x100);
97 D(bug("HasExtendedConfig: bus %d dev %d sub %d extcap %08x\n", msg->bus, msg->dev, msg->sub, *extcap));
98 if(*extcap == 0xffffffff) {
99 D(bug(" Device is PCI not PCIe\n"));
100 mmio = 0;
103 break;
104 }else{
105 D(bug("HasExtendedConfig: Device not found! bus %d dev %d sub %d \n", msg->bus, msg->dev, msg->sub));
108 mcfg_alloc++;
109 }while((APTR)mcfg_alloc < ((APTR)mcfg_tbl + mcfg_tbl->Header.Length));
112 return mmio;
115 ULONG PCPCI__Hidd_PCIDriver__ReadConfigLong(OOP_Class *cl, OOP_Object *o,
116 struct pHidd_PCIDriver_ReadConfigLong *msg)
119 We NEED the device object as it houses the ExtendedConfig attribute per device.
120 We know that the value stored in ExtendedConfig is the mmio base as returned by PCPCI__Hidd_PCIDriver__HasExtendedConfig.
121 If we get ExtendedConfig we will use ECAM method.
123 While the bus is being enumerated we automagically skip ECAM until ExtendedConfig attribute is set and we have a valid device object.
126 IPTR mmio = 0;
128 OOP_GetAttr(msg->device, aHidd_PCIDevice_ExtendedConfig, &mmio);
129 if(mmio) {
130 /* This is the ECAM access method for long read */
131 volatile ULONG *longreg;
133 longreg = (APTR) (mmio + (msg->reg & 0xffc));
135 D(bug("ECAM.read longreg %p %08x\n", longreg, *longreg));
136 return *longreg;
140 Last good long register without ECAM,
141 macros in CAM methods take care of the alignment.
142 we don't want to return some random value.
144 if(msg->reg < 0x100) {
145 return PSD(cl)->ReadConfigLong(msg->bus, msg->dev, msg->sub, msg->reg);
146 } else {
147 return 0xffffffff;
151 UWORD PCPCI__Hidd_PCIDriver__ReadConfigWord(OOP_Class *cl, OOP_Object *o,
152 struct pHidd_PCIDriver_ReadConfigWord *msg)
154 return ReadConfigWord(PSD(cl), msg->bus, msg->dev, msg->sub, msg->reg);
157 UBYTE PCPCI__Hidd_PCIDriver__ReadConfigByte(OOP_Class *cl, OOP_Object *o,
158 struct pHidd_PCIDriver_ReadConfigByte *msg)
160 pcicfg temp;
162 temp.ul = PSD(cl)->ReadConfigLong(msg->bus, msg->dev, msg->sub, msg->reg);
163 return temp.ub[msg->reg & 3];
166 void PCPCI__Hidd_PCIDriver__WriteConfigLong(OOP_Class *cl, OOP_Object *o,
167 struct pHidd_PCIDriver_WriteConfigLong *msg)
169 IPTR mmio = 0;
171 OOP_GetAttr(msg->device, aHidd_PCIDevice_ExtendedConfig, &mmio);
172 if(mmio) {
173 /* This is the ECAM access method for long write */
174 volatile ULONG *longreg;
175 longreg = (APTR) (mmio + (msg->reg & 0xffc));
176 D(bug("ECAM.write.old longreg %p %08x = %08x\n", longreg, *longreg, msg->val));
177 *longreg = msg->val;
178 D(bug("ECAM.write.new longreg %p %08x == %08x?\n", longreg, *longreg, msg->val));
179 } else {
181 Last good long register without ECAM,
182 macros in CAM methods take care of the alignment.
183 we don't want to store the value in some random address.
185 if(msg->reg < 0x100) {
186 PSD(cl)->WriteConfigLong(msg->bus, msg->dev, msg->sub, msg->reg, msg->val);
191 /* Class initialization and destruction */
193 static int PCPCI_InitClass(LIBBASETYPEPTR LIBBASE)
195 OOP_Object *pci;
197 D(bug("[PCI.PC] Driver initialization\n"));
199 struct pHidd_PCI_AddHardwareDriver msg,*pmsg=&msg;
202 We only (try to) fetch the mcfg_table, no need to keep ACPI library open.
204 ACPICABase = OpenLibrary("acpica.library", 0);
205 if(ACPICABase) {
206 if(AcpiGetTable("MCFG", 1, (ACPI_TABLE_HEADER **)&LIBBASE->psd.mcfg_tbl) != AE_OK) {
207 LIBBASE->psd.mcfg_tbl = NULL;
209 CloseLibrary(ACPICABase);
212 LIBBASE->psd.hiddPCIDriverAB = OOP_ObtainAttrBase(IID_Hidd_PCIDriver);
213 LIBBASE->psd.hiddAB = OOP_ObtainAttrBase(IID_Hidd);
214 LIBBASE->psd.hidd_PCIDeviceAB = OOP_ObtainAttrBase(IID_Hidd_PCIDevice);
215 if (LIBBASE->psd.hiddPCIDriverAB == 0 || LIBBASE->psd.hiddAB == 0 || LIBBASE->psd.hidd_PCIDeviceAB == 0)
217 D(bug("[PCI.PC] ObtainAttrBases failed\n"));
218 return FALSE;
221 /* By default we use mechanism 1 */
222 LIBBASE->psd.ReadConfigLong = ReadConfig1Long;
223 LIBBASE->psd.WriteConfigLong = WriteConfig1Long;
225 ProbePCI(&LIBBASE->psd);
227 msg.driverClass = LIBBASE->psd.driverClass;
228 msg.mID = OOP_GetMethodID(IID_Hidd_PCI, moHidd_PCI_AddHardwareDriver);
229 D(bug("[PCI.PC] Registering Driver with PCI base class..\n"));
231 pci = OOP_NewObject(NULL, CLID_Hidd_PCI, NULL);
232 OOP_DoMethod(pci, (OOP_Msg)pmsg);
233 OOP_DisposeObject(pci);
235 D(bug("[PCI.PC] Driver initialization finished\n"));
237 return TRUE;
240 static int PCPCI_ExpungeClass(LIBBASETYPEPTR LIBBASE)
242 D(bug("[PCI.PC] Class destruction\n"));
244 OOP_ReleaseAttrBase(IID_Hidd_PCIDevice);
245 OOP_ReleaseAttrBase(IID_Hidd_PCIDriver);
246 OOP_ReleaseAttrBase(IID_Hidd);
248 return TRUE;
251 ADD2INITLIB(PCPCI_InitClass, 0)
252 ADD2EXPUNGELIB(PCPCI_ExpungeClass, 0)