make the linux-ppc packags be in synch with other platforms
[tangerine.git] / arch / common / hidd.pci / pciclass.c
blobc77668ff4ff9d75622eef9c25750ba6e06076774
1 /*
2 Copyright (C) 2004-2006, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <exec/types.h>
7 #include <hidd/hidd.h>
8 #include <hidd/pci.h>
9 #include <oop/oop.h>
11 #include <utility/tagitem.h>
12 #include <utility/hooks.h>
14 #include <proto/exec.h>
15 #include <proto/utility.h>
16 #include <proto/oop.h>
18 #include <aros/symbolsets.h>
20 #include "pci.h"
22 #define DEBUG 1
23 #include <aros/debug.h>
24 #include <aros/atomic.h>
27 There are no static AttrBases in this class. Therefore it might be placed
28 directly in ROM without any harm
30 #undef HiddPCIAttrBase
31 #undef HiddPCIDeviceAttrBase
33 #define HiddPCIAttrBase (PSD(cl)->hiddPCIAB)
34 #define HiddPCIDeviceAttrBase (PSD(cl)->hiddPCIDeviceAB)
35 #define HiddAttrBase (PSD(cl)->hiddAB)
37 /*
38 Returns 0 for no device, 1 for non-multi device and 2 for
39 a multifunction device
41 cl points to the base pci class which is used to extract static data
42 o points to the driver class which is used to read from config space
44 static int isPCIDeviceAvailable(OOP_Class *cl, OOP_Object *o, UBYTE bus, UBYTE dev, UBYTE sub)
46 UWORD Vend;
47 UBYTE Type;
49 struct pHidd_PCIDriver_ReadConfigWord rw;
50 struct pHidd_PCIDriver_ReadConfigByte rb;
52 rw.mID = PSD(cl)->mid_RW;
53 rb.mID = PSD(cl)->mid_RB;
55 rw.bus = bus;
56 rw.dev = dev;
57 rw.sub = sub;
58 rw.reg = PCICS_VENDOR;
60 Vend = OOP_DoMethod(o, (OOP_Msg)&rw);
62 if ((Vend == 0xffff) || (Vend == 0x0000))
64 /* 0xffff is an invalid vendor ID, and so is 0x0000
65 * (Well, actually 0x0000 belongs to Gammagraphx, but this really
66 * clashes with multifunc device scanning, so lets just hope nobody
67 * has a card from them :) )
70 return 0;
73 rb.bus = bus;
74 rb.dev = dev;
75 rb.sub = sub;
76 rb.reg = PCICS_HEADERTYPE;
78 Type = OOP_DoMethod(o, (OOP_Msg)&rb);
80 if ((Type & PCIHT_MULTIFUNC) == PCIHT_MULTIFUNC)
81 return 2;
83 return 1;
87 PCI::AddHardwareDriver(OOP_Class *driverClass)
89 Adds new PCI hardware driver to the PCI subsystem. A PCI hardware driver
90 is a class which delivers Read/Write to the PCI config space.
92 The PCI bus handled through driver added is scanned, and all available
93 PCI devices are added to the device chain.
95 void PCI__Hidd_PCI__AddHardwareDriver(OOP_Class *cl, OOP_Object *o,
96 struct pHidd_PCI_AddHardwareDriver *msg)
98 struct DriverNode *dn = NULL;
100 D(bug("[PCI] Adding Driver class 0x%08x\n", msg->driverClass));
102 if (msg->driverClass != NULL)
104 // Get some extra memory for driver node
105 dn = AllocPooled(PSD(cl)->MemPool, sizeof(struct DriverNode));
106 if (dn)
108 int bus;
109 int dev;
110 int sub;
111 int type;
112 IPTR subbus, bridge;
114 OOP_Object *drv;
115 struct TagItem devtags[] = {
116 { aHidd_PCIDevice_Bus, 0 },
117 { aHidd_PCIDevice_Dev, 0 },
118 { aHidd_PCIDevice_Sub, 0 },
119 { aHidd_PCIDevice_Driver, 0 },
120 { TAG_DONE, 0UL }
122 struct PciDevice *pcidev;
123 STRPTR string, string2;
125 dn->driverClass = msg->driverClass;
126 drv = dn->driverObject = OOP_NewObject(dn->driverClass, NULL, NULL);
127 dn->highBus = 0;
129 OOP_GetAttr(drv, aHidd_Name, (APTR)&string);
130 OOP_GetAttr(drv, aHidd_HardwareName, (APTR)&string2);
131 D(bug("[PCI] Adding driver %s (%s) to the system\n", string, string2));
133 NEWLIST(&dn->devices);
135 devtags[3].ti_Data = (IPTR)drv;
137 // Scan whole PCI bus looking for devices available
138 // There is no need for semaphore protected list operations at this
139 // point, because driver is still not public.
140 bus = 0;
143 D(bug("[PCI] Scanning bus %d\n",bus));
145 devtags[0].ti_Data = bus;
147 for (dev=0; dev < 32; dev++)
149 devtags[1].ti_Data = dev;
150 devtags[2].ti_Data = 0;
152 /* Knock knock! Is any device here? */
153 type = isPCIDeviceAvailable(cl, drv, bus,dev,0);
154 switch(type)
156 /* Regular device */
157 case 1:
158 pcidev = (struct PciDevice *)AllocPooled(PSD(cl)->MemPool,
159 sizeof(struct Device));
160 pcidev->device = OOP_NewObject(NULL, CLID_Hidd_PCIDevice,
161 (struct TagItem *)&devtags);
163 OOP_GetAttr(pcidev->device, aHidd_PCIDevice_isBridge, &bridge);
164 if (bridge)
166 OOP_GetAttr(pcidev->device, aHidd_PCIDevice_SubBus, &subbus);
167 if (subbus > dn->highBus)
168 dn->highBus = subbus;
170 AddTail(&dn->devices, (struct Node *)pcidev);
171 break;
172 /* Cool! Multifunction device, search subfunctions then */
173 case 2:
174 pcidev = (struct PciDevice *)AllocPooled(PSD(cl)->MemPool,
175 sizeof(struct Device));
176 pcidev->device = OOP_NewObject(NULL, CLID_Hidd_PCIDevice,
177 (struct TagItem *)&devtags);
179 OOP_GetAttr(pcidev->device, aHidd_PCIDevice_isBridge, &bridge);
180 if (bridge)
182 OOP_GetAttr(pcidev->device, aHidd_PCIDevice_SubBus, &subbus);
183 if (subbus > dn->highBus)
184 dn->highBus = subbus;
186 AddTail(&dn->devices, (struct Node *)pcidev);
188 for (sub=1; sub < 8; sub++)
190 devtags[2].ti_Data = sub;
191 if (isPCIDeviceAvailable(cl, drv, bus, dev, sub))
193 pcidev = (struct PciDevice *)AllocPooled(PSD(cl)->MemPool,
194 sizeof(struct Device));
195 pcidev->device = OOP_NewObject(NULL, CLID_Hidd_PCIDevice,
196 (struct TagItem *)&devtags);
197 OOP_GetAttr(pcidev->device, aHidd_PCIDevice_isBridge, &bridge);
198 if (bridge)
200 OOP_GetAttr(pcidev->device, aHidd_PCIDevice_SubBus, &subbus);
201 if (subbus > dn->highBus)
202 dn->highBus = subbus;
204 AddTail(&dn->devices, (struct Node *)pcidev);
207 break;
208 default:
209 break;
212 bus++;
213 } while (bus <= dn->highBus);
215 // Add the driver to the end of drivers list
217 ObtainSemaphore(&PSD(cl)->driver_lock);
218 AddTail(&PSD(cl)->drivers, (struct Node*)dn);
219 ReleaseSemaphore(&PSD(cl)->driver_lock);
225 PCI::EnumDevices(struct Hook *Callback, struct TagItem **requirements)
227 This method calls the callback hook for every PCI device in the system
228 that mets requirements specified (or every device if tags=NULL). It
229 iterates not only through one PCI bus, but instead through all buses
230 managed by all drivers present in the system.
232 void PCI__Hidd_PCI__EnumDevices(OOP_Class *cl, OOP_Object *o, struct pHidd_PCI_EnumDevices *msg)
234 ULONG VendorID, ProductID, RevisionID, Interface, _Class, SubClass,
235 SubsystemVendorID, SubsystemID;
237 IPTR value;
238 struct DriverNode *dn;
239 struct PciDevice *dev;
240 BOOL ok;
242 /* Get requirements */
243 VendorID = GetTagData(tHidd_PCI_VendorID, 0xffffffff, msg->requirements);
244 ProductID = GetTagData(tHidd_PCI_ProductID, 0xffffffff, msg->requirements);
245 RevisionID = GetTagData(tHidd_PCI_RevisionID, 0xffffffff, msg->requirements);
246 Interface = GetTagData(tHidd_PCI_Interface, 0xffffffff, msg->requirements);
247 _Class = GetTagData(tHidd_PCI_Class, 0xffffffff, msg->requirements);
248 SubClass = GetTagData(tHidd_PCI_SubClass, 0xffffffff, msg->requirements);
249 SubsystemID = GetTagData(tHidd_PCI_SubsystemID, 0xffffffff, msg->requirements);
250 SubsystemVendorID = GetTagData(tHidd_PCI_SubsystemVendorID, 0xffffffff, msg->requirements);
252 /* Lock driver list for exclusive use */
253 ObtainSemaphore(&PSD(cl)->driver_lock);
255 /* For every driver in the system... */
256 ForeachNode(&PSD(cl)->drivers, dn)
258 /* ...and for every device handled by this driver */
259 ForeachNode(&dn->devices, dev)
261 /* check the requirements with it's properties */
262 ok = TRUE;
263 if (VendorID != 0xffffffff)
265 OOP_GetAttr(dev->device, aHidd_PCIDevice_VendorID, &value);
266 ok &= (value == VendorID);
269 if (ProductID != 0xffffffff)
271 OOP_GetAttr(dev->device, aHidd_PCIDevice_ProductID, &value);
272 ok &= (value == ProductID);
275 if (RevisionID != 0xffffffff)
277 OOP_GetAttr(dev->device, aHidd_PCIDevice_RevisionID, &value);
278 ok &= (value == RevisionID);
281 if (Interface != 0xffffffff)
283 OOP_GetAttr(dev->device, aHidd_PCIDevice_Interface, &value);
284 ok &= (value == Interface);
287 if (_Class != 0xffffffff)
289 OOP_GetAttr(dev->device, aHidd_PCIDevice_Class, &value);
290 ok &= (value == _Class);
293 if (SubClass != 0xffffffff)
295 OOP_GetAttr(dev->device, aHidd_PCIDevice_SubClass, &value);
296 ok &= (value == SubClass);
299 if (SubsystemVendorID != 0xffffffff)
301 OOP_GetAttr(dev->device, aHidd_PCIDevice_SubsystemVendorID, &value);
302 ok &= (value == SubsystemVendorID);
305 if (SubsystemID != 0xffffffff)
307 OOP_GetAttr(dev->device, aHidd_PCIDevice_SubsystemID, &value);
308 ok &= (value == SubsystemID);
311 /* If requirements met, call Hook */
312 if (ok)
314 CALLHOOKPKT(msg->callback, dev->device, NULL);
319 ReleaseSemaphore(&PSD(cl)->driver_lock);
322 BOOL PCI__Hidd_PCI__RemHardwareDriver(OOP_Class *cl, OOP_Object *o, struct pHidd_PCI_RemHardwareDriver *msg)
324 struct DriverNode *dn = NULL, *next = NULL, *rem = NULL;
325 BOOL freed = FALSE;
327 D(bug("[PCI] Removing hardware driver %x\n",msg->driverClass));
329 Removing HW driver allowed only if classes unused. That means the users
330 count should be == 1 (only driver itself uses pci to remove its class)
332 Forbid();
333 if (PSD(cl)->users == 1)
335 /* Get exclusive lock on driver list */
336 ObtainSemaphore(&PSD(cl)->driver_lock);
337 ForeachNodeSafe(&PSD(cl)->drivers, dn, next)
339 if (dn->driverClass == msg->driverClass)
341 Remove((struct Node *)dn);
342 rem = dn;
345 ReleaseSemaphore(&PSD(cl)->driver_lock);
347 /* If driver removed, rem contains pointer to removed DriverNode */
348 if (rem)
350 struct PciDevice *dev, *next;
352 /* For every device */
353 ForeachNodeSafe(&rem->devices, dev, next)
355 /* Dispose PCIDevice object instance */
356 OOP_DisposeObject(dev->device);
358 /* Remove device from device list */
359 Remove((struct Node *)dev);
361 /* Free memory used for device struct */
362 FreePooled(PSD(cl)->MemPool, dev, sizeof(struct PciDevice));
365 /* Dispose driver */
366 OOP_DisposeObject(rem->driverObject);
368 /* And free memory for DriverNode */
369 FreePooled(PSD(cl)->MemPool, rem, sizeof(struct DriverNode));
371 /* Driver removed and everything freed */
372 freed = TRUE;
375 Permit();
377 D(bug("[PCI] PCI::RemHardwareDriver() %s\n", freed?"succeeded":"failed"));
379 return freed;
382 OOP_Object *PCI__Root__New(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
384 AROS_ATOMIC_INC(PSD(cl)->users);
385 return (OOP_Object *)OOP_DoSuperMethod(cl, o, msg);
388 VOID PCI__Root__Dispose(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
390 AROS_ATOMIC_DEC(PSD(cl)->users);
391 OOP_DoSuperMethod(cl, o, msg);
394 /* Class initialization and destruction */
396 static int PCI_ExpungeClass(LIBBASETYPEPTR LIBBASE)
398 D(bug("[PCI] Base Class destruction\n"));
400 OOP_ReleaseAttrBase(IID_Hidd_PCI);
401 OOP_ReleaseAttrBase(IID_Hidd_PCIDevice);
402 OOP_ReleaseAttrBase(IID_Hidd_PCIDriver);
403 OOP_ReleaseAttrBase(IID_Hidd);
405 return TRUE;
408 static int PCI_InitClass(LIBBASETYPEPTR LIBBASE)
410 D(bug("[PCI] base class initialization\n"));
412 LIBBASE->psd.hiddPCIAB = OOP_ObtainAttrBase(IID_Hidd_PCI);
413 LIBBASE->psd.hiddPCIDeviceAB = OOP_ObtainAttrBase(IID_Hidd_PCIDevice);
414 LIBBASE->psd.hiddPCIDriverAB = OOP_ObtainAttrBase(IID_Hidd_PCIDriver);
415 LIBBASE->psd.hiddAB = OOP_ObtainAttrBase(IID_Hidd);
417 if (LIBBASE->psd.hiddPCIAB && LIBBASE->psd.hiddPCIDeviceAB && LIBBASE->psd.hiddPCIDriverAB && LIBBASE->psd.hiddAB)
419 D(bug("[PCI] Everything OK\n"));
420 return TRUE;
423 return FALSE;
426 ADD2INITLIB(PCI_InitClass, 0)
427 ADD2EXPUNGELIB(PCI_ExpungeClass, 0)