Detab
[AROS.git] / rom / hidds / hidd.pci / pciclass.c
blob3e15e1a9ce3b6ebc9d189731fb3ebd58939b42eb
1 /*
2 Copyright (C) 2004-2013, 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 if (!drv) {
130 FreePooled(PSD(cl)->MemPool, dn, sizeof(*dn));
131 D(bug("[PCI] Driver did not initialize\n"));
132 return;
135 OOP_GetAttr(drv, aHidd_Name, (APTR)&string);
136 OOP_GetAttr(drv, aHidd_HardwareName, (APTR)&string2);
137 D(bug("[PCI] Adding driver %s (%s) to the system\n", string, string2));
139 NEWLIST(&dn->devices);
141 devtags[3].ti_Data = (IPTR)drv;
143 // Scan whole PCI bus looking for devices available
144 // There is no need for semaphore protected list operations at this
145 // point, because driver is still not public.
146 bus = 0;
149 D(bug("[PCI] Scanning bus %d\n",bus));
151 devtags[0].ti_Data = bus;
153 for (dev=0; dev < 32; dev++)
155 devtags[1].ti_Data = dev;
156 devtags[2].ti_Data = 0;
158 /* Knock knock! Is any device here? */
159 type = isPCIDeviceAvailable(cl, drv, bus,dev,0);
160 switch(type)
162 /* Regular device */
163 case 1:
164 pcidev = (struct PciDevice *)AllocPooled(PSD(cl)->MemPool,
165 sizeof(struct PciDevice));
166 pcidev->device = OOP_NewObject(NULL, CLID_Hidd_PCIDevice,
167 (struct TagItem *)&devtags);
169 OOP_GetAttr(pcidev->device, aHidd_PCIDevice_isBridge, &bridge);
170 if (bridge)
172 OOP_GetAttr(pcidev->device, aHidd_PCIDevice_SubBus, &subbus);
173 if (subbus > dn->highBus)
174 dn->highBus = subbus;
176 AddTail(&dn->devices, (struct Node *)pcidev);
177 break;
178 /* Cool! Multifunction device, search subfunctions then */
179 case 2:
180 pcidev = (struct PciDevice *)AllocPooled(PSD(cl)->MemPool,
181 sizeof(struct PciDevice));
182 pcidev->device = OOP_NewObject(NULL, CLID_Hidd_PCIDevice,
183 (struct TagItem *)&devtags);
185 OOP_GetAttr(pcidev->device, aHidd_PCIDevice_isBridge, &bridge);
186 if (bridge)
188 OOP_GetAttr(pcidev->device, aHidd_PCIDevice_SubBus, &subbus);
189 if (subbus > dn->highBus)
190 dn->highBus = subbus;
192 AddTail(&dn->devices, (struct Node *)pcidev);
194 for (sub=1; sub < 8; sub++)
196 devtags[2].ti_Data = sub;
197 if (isPCIDeviceAvailable(cl, drv, bus, dev, sub))
199 pcidev = (struct PciDevice *)AllocPooled(PSD(cl)->MemPool,
200 sizeof(struct PciDevice));
201 pcidev->device = OOP_NewObject(NULL, CLID_Hidd_PCIDevice,
202 (struct TagItem *)&devtags);
203 OOP_GetAttr(pcidev->device, aHidd_PCIDevice_isBridge, &bridge);
204 if (bridge)
206 OOP_GetAttr(pcidev->device, aHidd_PCIDevice_SubBus, &subbus);
207 if (subbus > dn->highBus)
208 dn->highBus = subbus;
210 AddTail(&dn->devices, (struct Node *)pcidev);
213 break;
214 default:
215 break;
218 bus++;
219 } while (bus <= dn->highBus);
221 // Add the driver to the end of drivers list
223 ObtainSemaphore(&PSD(cl)->driver_lock);
224 AddTail(&PSD(cl)->drivers, (struct Node*)dn);
225 ReleaseSemaphore(&PSD(cl)->driver_lock);
231 PCI::EnumDevices(struct Hook *Callback, struct TagItem **requirements)
233 This method calls the callback hook for every PCI device in the system
234 that meets requirements specified (or every device if tags=NULL). It
235 iterates not only through one PCI bus, but instead through all buses
236 managed by all drivers present in the system.
238 void PCI__Hidd_PCI__EnumDevices(OOP_Class *cl, OOP_Object *o, struct pHidd_PCI_EnumDevices *msg)
240 ULONG VendorID, ProductID, RevisionID, Interface, _Class, SubClass,
241 SubsystemVendorID, SubsystemID;
243 IPTR value;
244 struct DriverNode *dn;
245 struct PciDevice *dev;
246 BOOL ok;
248 /* Get requirements */
249 VendorID = GetTagData(tHidd_PCI_VendorID, 0xffffffff, msg->requirements);
250 ProductID = GetTagData(tHidd_PCI_ProductID, 0xffffffff, msg->requirements);
251 RevisionID = GetTagData(tHidd_PCI_RevisionID, 0xffffffff, msg->requirements);
252 Interface = GetTagData(tHidd_PCI_Interface, 0xffffffff, msg->requirements);
253 _Class = GetTagData(tHidd_PCI_Class, 0xffffffff, msg->requirements);
254 SubClass = GetTagData(tHidd_PCI_SubClass, 0xffffffff, msg->requirements);
255 SubsystemID = GetTagData(tHidd_PCI_SubsystemID, 0xffffffff, msg->requirements);
256 SubsystemVendorID = GetTagData(tHidd_PCI_SubsystemVendorID, 0xffffffff, msg->requirements);
258 /* Lock driver list for exclusive use */
259 ObtainSemaphore(&PSD(cl)->driver_lock);
261 /* For every driver in the system... */
262 ForeachNode(&PSD(cl)->drivers, dn)
264 /* ...and for every device handled by this driver */
265 ForeachNode(&dn->devices, dev)
267 /* check the requirements with its properties */
268 ok = TRUE;
269 if (VendorID != 0xffffffff)
271 OOP_GetAttr(dev->device, aHidd_PCIDevice_VendorID, &value);
272 ok &= (value == VendorID);
275 if (ProductID != 0xffffffff)
277 OOP_GetAttr(dev->device, aHidd_PCIDevice_ProductID, &value);
278 ok &= (value == ProductID);
281 if (RevisionID != 0xffffffff)
283 OOP_GetAttr(dev->device, aHidd_PCIDevice_RevisionID, &value);
284 ok &= (value == RevisionID);
287 if (Interface != 0xffffffff)
289 OOP_GetAttr(dev->device, aHidd_PCIDevice_Interface, &value);
290 ok &= (value == Interface);
293 if (_Class != 0xffffffff)
295 OOP_GetAttr(dev->device, aHidd_PCIDevice_Class, &value);
296 ok &= (value == _Class);
299 if (SubClass != 0xffffffff)
301 OOP_GetAttr(dev->device, aHidd_PCIDevice_SubClass, &value);
302 ok &= (value == SubClass);
305 if (SubsystemVendorID != 0xffffffff)
307 OOP_GetAttr(dev->device, aHidd_PCIDevice_SubsystemVendorID, &value);
308 ok &= (value == SubsystemVendorID);
311 if (SubsystemID != 0xffffffff)
313 OOP_GetAttr(dev->device, aHidd_PCIDevice_SubsystemID, &value);
314 ok &= (value == SubsystemID);
317 /* If requirements met, call Hook */
318 if (ok)
320 CALLHOOKPKT(msg->callback, dev->device, NULL);
325 ReleaseSemaphore(&PSD(cl)->driver_lock);
328 BOOL PCI__Hidd_PCI__RemHardwareDriver(OOP_Class *cl, OOP_Object *o, struct pHidd_PCI_RemHardwareDriver *msg)
330 struct DriverNode *dn = NULL, *next = NULL, *rem = NULL;
331 BOOL freed = FALSE;
333 D(bug("[PCI] Removing hardware driver %x\n",msg->driverClass));
335 Removing HW driver allowed only if classes unused. That means the users
336 count should be == 1 (only driver itself uses pci to remove its class)
338 Forbid();
339 if (PSD(cl)->users == 1)
341 /* Get exclusive lock on driver list */
342 ObtainSemaphore(&PSD(cl)->driver_lock);
343 ForeachNodeSafe(&PSD(cl)->drivers, dn, next)
345 if (dn->driverClass == msg->driverClass)
347 Remove((struct Node *)dn);
348 rem = dn;
351 ReleaseSemaphore(&PSD(cl)->driver_lock);
353 /* If driver removed, rem contains pointer to removed DriverNode */
354 if (rem)
356 struct PciDevice *dev, *next;
358 /* For every device */
359 ForeachNodeSafe(&rem->devices, dev, next)
361 /* Dispose PCIDevice object instance */
362 OOP_DisposeObject(dev->device);
364 /* Remove device from device list */
365 Remove((struct Node *)dev);
367 /* Free memory used for device struct */
368 FreePooled(PSD(cl)->MemPool, dev, sizeof(struct PciDevice));
371 /* Dispose driver */
372 OOP_DisposeObject(rem->driverObject);
374 /* And free memory for DriverNode */
375 FreePooled(PSD(cl)->MemPool, rem, sizeof(struct DriverNode));
377 /* Driver removed and everything freed */
378 freed = TRUE;
381 Permit();
383 D(bug("[PCI] PCI::RemHardwareDriver() %s\n", freed?"succeeded":"failed"));
385 return freed;
388 OOP_Object *PCI__Root__New(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
390 AROS_ATOMIC_INC(PSD(cl)->users);
391 return (OOP_Object *)OOP_DoSuperMethod(cl, o, msg);
394 VOID PCI__Root__Dispose(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)
396 AROS_ATOMIC_DEC(PSD(cl)->users);
397 OOP_DoSuperMethod(cl, o, msg);
400 /* Class initialization and destruction */
402 static int PCI_ExpungeClass(LIBBASETYPEPTR LIBBASE)
404 D(bug("[PCI] Base Class destruction\n"));
406 OOP_ReleaseAttrBase(IID_Hidd_PCI);
407 OOP_ReleaseAttrBase(IID_Hidd_PCIDevice);
408 OOP_ReleaseAttrBase(IID_Hidd_PCIDriver);
409 OOP_ReleaseAttrBase(IID_Hidd);
411 return TRUE;
414 static int PCI_InitClass(LIBBASETYPEPTR LIBBASE)
416 D(bug("[PCI] base class initialization\n"));
418 LIBBASE->psd.hiddPCIAB = OOP_ObtainAttrBase(IID_Hidd_PCI);
419 LIBBASE->psd.hiddPCIDeviceAB = OOP_ObtainAttrBase(IID_Hidd_PCIDevice);
420 LIBBASE->psd.hiddPCIDriverAB = OOP_ObtainAttrBase(IID_Hidd_PCIDriver);
421 LIBBASE->psd.hiddAB = OOP_ObtainAttrBase(IID_Hidd);
423 if (LIBBASE->psd.hiddPCIAB && LIBBASE->psd.hiddPCIDeviceAB && LIBBASE->psd.hiddPCIDriverAB && LIBBASE->psd.hiddAB)
425 D(bug("[PCI] Everything OK\n"));
426 return TRUE;
429 return FALSE;
432 ADD2INITLIB(PCI_InitClass, 0)
433 ADD2EXPUNGELIB(PCI_ExpungeClass, 0)