scripts: add crosstools packages for i386 and armhf
[AROS.git] / rom / hidds / pci / pciclass.c
blob5f17c91eef001207aade31eb576268de539ff494
1 /*
2 Copyright © 2004-2014, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <aros/debug.h>
7 #include <hidd/hidd.h>
8 #include <hidd/pci.h>
9 #include <oop/oop.h>
10 #include <utility/tagitem.h>
11 #include <utility/hooks.h>
13 #include <proto/exec.h>
14 #include <proto/utility.h>
15 #include <proto/oop.h>
17 #include "pci.h"
19 /*
20 Returns 0 for no device, 1 for non-multi device and 2 for
21 a multifunction device
23 cl points to the base pci class which is used to extract static data
24 o points to the driver class which is used to read from config space
26 static int isPCIDeviceAvailable(OOP_Class *cl, OOP_Object *o, UBYTE bus, UBYTE dev, UBYTE sub)
28 UWORD Vend;
29 UBYTE Type;
31 Vend = HIDD_PCIDriver_ReadConfigWord(o, NULL, bus, dev, sub, PCICS_VENDOR);
33 if ((Vend == 0xffff) || (Vend == 0x0000))
35 /* 0xffff is an invalid vendor ID, and so is 0x0000
36 * (Well, actually 0x0000 belongs to Gammagraphx, but this really
37 * clashes with multifunc device scanning, so lets just hope nobody
38 * has a card from them :) )
41 return 0;
44 Type = HIDD_PCIDriver_ReadConfigByte(o, NULL, bus, dev, sub, PCICS_HEADERTYPE);
46 if ((Type & PCIHT_MULTIFUNC) == PCIHT_MULTIFUNC)
47 return 2;
49 return 1;
52 static OOP_Object *InsertDevice(OOP_Class *cl, ULONG *highBus, struct TagItem *devtags)
54 struct pcibase *pciBase = (struct pcibase *)cl->UserData;
55 OOP_Object *pcidev;
56 IPTR bridge, subbus;
58 pcidev = OOP_NewObject(pciBase->psd.pciDeviceClass, NULL, devtags);
59 if (pcidev)
61 OOP_GetAttr(pcidev, aHidd_PCIDevice_isBridge, &bridge);
62 if (bridge)
64 OOP_GetAttr(pcidev, aHidd_PCIDevice_SubBus, &subbus);
65 if (subbus > *highBus)
66 *highBus = subbus;
70 * Device class is our private and derived from rootclass.
71 * This makes casting to struct Node * safe.
73 ObtainSemaphore(&pciBase->psd.dev_lock);
74 ADDTAIL(&pciBase->psd.devices, pcidev);
75 ReleaseSemaphore(&pciBase->psd.dev_lock);
77 return pcidev;
81 * PCI::SetUpDriver(OOP_Object *driverObject)
83 * A new PCI hardware driver is being added to the PCI subsystem.
84 * The PCI bus handled through driver added is scanned, and all available
85 * PCI devices are added to the device chain.
87 BOOL PCI__HW__SetUpDriver(OOP_Class *cl, OOP_Object *o,
88 struct pHW_SetUpDriver *msg)
90 OOP_Object *drv = msg->driverObject;
91 ULONG highBus = 0;
92 ULONG bus, dev, sub, type;
94 struct TagItem devtags[] =
96 { aHidd_PCIDevice_Bus , 0 },
97 { aHidd_PCIDevice_Dev , 0 },
98 { aHidd_PCIDevice_Sub , 0 },
99 { aHidd_PCIDevice_Driver , (IPTR)drv },
100 { aHidd_PCIDevice_ExtendedConfig, 0 },
101 { TAG_DONE , 0 }
104 D(bug("[PCI] Adding Driver 0x%p class 0x%p\n", drv, OOP_OCLASS(drv)));
107 * Scan the whole PCI bus looking for devices available
108 * There is no need for semaphore protected list operations at this
109 * point, because the driver is still not public.
111 for (bus = 0; bus <= highBus; bus++)
113 D(bug("[PCI] Scanning bus %d\n",bus));
115 devtags[0].ti_Data = bus;
117 for (dev=0; dev < 32; dev++)
119 devtags[1].ti_Data = dev;
120 devtags[2].ti_Data = 0;
122 /* Knock knock! Is any device here? */
123 type = isPCIDeviceAvailable(cl, drv, bus, dev, 0);
125 switch(type)
127 /* Regular device */
128 case 1:
129 devtags[4].ti_Data = HIDD_PCIDriver_HasExtendedConfig(drv, bus, dev, 0);
130 InsertDevice(cl, &highBus, devtags);
131 break;
133 /* Cool! Multifunction device, search subfunctions then */
134 case 2:
135 devtags[4].ti_Data = HIDD_PCIDriver_HasExtendedConfig(drv, bus, dev, 0);
136 InsertDevice(cl, &highBus, devtags);
138 for (sub=1; sub < 8; sub++)
140 devtags[2].ti_Data = sub;
141 if (isPCIDeviceAvailable(cl, drv, bus, dev, sub)) {
142 devtags[4].ti_Data = HIDD_PCIDriver_HasExtendedConfig(drv, bus, dev, sub);
143 InsertDevice(cl, &highBus, devtags);
146 break;
151 /* Succesful, add the driver to the end of drivers list */
152 return TRUE;
155 static const UBYTE attrTable[] =
157 aoHidd_PCIDevice_VendorID,
158 aoHidd_PCIDevice_ProductID,
159 aoHidd_PCIDevice_RevisionID,
160 aoHidd_PCIDevice_Interface,
161 aoHidd_PCIDevice_Class,
162 aoHidd_PCIDevice_SubClass,
163 aoHidd_PCIDevice_SubsystemVendorID,
164 aoHidd_PCIDevice_SubsystemID,
165 aoHidd_PCIDevice_Driver
168 /*****************************************************************************************
170 NAME
171 moHidd_PCI_EnumDevices
173 SYNOPSIS
174 void OOP_DoMethod(OOP_Object *obj, struct pHidd_PCI_EnumDrivers *Msg);
176 void HIDD_PCI_EnumDevices(OOP_Object *obj, struct Hook *callback,
177 const struct TagItem *requirements);
179 LOCATION
180 CLID_Hidd_PCI
182 FUNCTION
183 This method calls the callback hook for every PCI device in the system
184 that meets requirements specified (or every device if tags=NULL). It
185 iterates not only through one PCI bus, but instead through all buses
186 managed by all drivers present in the system.
188 INPUTS
189 obj - A PCI subsystem object.
190 callback - A user-supplied hook which will be called for every device.
191 requirements - A TagList specifying search parameters.
193 The hook will be called with the following parameters:
194 AROS_UFHA(struct Hook *, hook , A0)
195 - A pointer to hook structure itself
196 AROS_UFHA(OOP_Object * , deviceObject, A2)
197 - A PCI device object
198 AROS_UFHA(APTR , unused , A1)
199 - Not used
201 The following tags are accepted as search parameters:
202 tHidd_PCI_VendorID - vendor ID
203 tHidd_PCI_ProductID - product ID
204 tHidd_PCI_RevisionID - revision ID
205 tHidd_PCI_Interface - PCI interface ID
206 tHidd_PCI_Class - PCI class ID
207 tHidd_PCI_SubClass - PCI subclass ID
208 tHidd_PCI_SubsystemVendorID - subsystem vendor ID
209 tHidd_PCI_SubsystemID - subsystem ID
210 tHidd_PCI_Driver - a pointer to bus driver object [V4]
212 RESULT
213 None.
215 NOTES
217 EXAMPLE
219 BUGS
221 SEE ALSO
223 INTERNALS
225 *****************************************************************************************/
227 void PCI__Hidd_PCI__EnumDevices(OOP_Class *cl, OOP_Object *o, struct pHidd_PCI_EnumDevices *msg)
229 struct pcibase *pciBase = (struct pcibase *)cl->UserData;
230 struct TagItem *tstate = (struct TagItem *)msg->requirements;
231 struct TagItem *tag;
232 IPTR matchVal[sizeof(attrTable)];
233 ULONG i;
234 OOP_Object *dev;
235 BOOL ok;
237 for (i = 0; i < sizeof(attrTable); i++)
239 matchVal[i] = ~0;
242 /* Get requirements */
243 while ((tag = NextTagItem(&tstate)))
245 ULONG idx = tag->ti_Tag - TAG_USER;
247 if (idx < sizeof(attrTable))
248 matchVal[idx] = tag->ti_Data;
251 /* Lock devices list for shared use */
252 ObtainSemaphoreShared(&pciBase->psd.dev_lock);
254 /* For every device in the system... */
255 ForeachNode(&pciBase->psd.devices, dev)
257 /* check the requirements with its properties */
258 ok = TRUE;
260 for (i = 0; i < sizeof(attrTable); i++)
262 if (matchVal[i] != ~0)
264 IPTR value;
266 OOP_GetAttr(dev, pciBase->psd.hiddPCIDeviceAB + attrTable[i], &value);
267 ok &= (value == matchVal[i]);
271 /* If requirements met, call Hook */
272 if (ok)
274 CALLHOOKPKT(msg->callback, dev, NULL);
278 ReleaseSemaphore(&pciBase->psd.dev_lock);
281 BOOL PCI__HW__RemoveDriver(OOP_Class *cl, OOP_Object *o, struct pHW_RemoveDriver *msg)
283 struct pcibase *pciBase = (struct pcibase *)cl->UserData;
284 OOP_Object *dev, *next, *drv;
285 IPTR disallow = 0;
287 D(bug("[PCI] Removing hardware driver 0x%p\n", msg->driverObject));
290 * Get exclusive lock on devices list.
291 * If we cannot do this, then either enumeration is running or
292 * another driver is being added. We simply cannot remove the driver
293 * in this case.
294 * Well, in the latter case we actually could remove our driver, but
295 * i believe this is extremely rare situation.
297 if (!AttemptSemaphore(&pciBase->psd.dev_lock))
298 return FALSE;
301 * Now we can check if we can remove our devices.
302 * We think we can remove them if nobody has owned any of them.
303 * Drivers which behave badly will not own devices, or they will
304 * defer owning after enumeration loop has ended. So, removing a
305 * driver is still very dangerous.
306 * This can be improved if we implement map/unmnap and
307 * AddInterrupt/RemoveInterrupt accounting in our drivers. The
308 * driver would allow to expunge itself only if its internal counter
309 * of used resources is zero.
310 * PCI API wrappers (like prometheus.library) also build their
311 * own reflection of devices list, so we will have to implement either
312 * some ways to disable expunging, or (better) to get notifications
313 * about devices list being updated. With this notification we can
314 * have full hotplug support.
316 ForeachNode(&pciBase->psd.devices, dev)
318 OOP_GetAttr(dev, aHidd_PCIDevice_Driver, (IPTR *)&drv);
319 if (drv == msg->driverObject)
321 IPTR owner;
323 OOP_GetAttr(dev, aHidd_PCIDevice_Owner, &owner);
324 disallow |= owner;
328 if (disallow)
330 ReleaseSemaphore(&pciBase->psd.dev_lock);
331 D(bug("[PCI] PCI::RemoveDriver() failed, driver in use\n"));
332 return FALSE;
335 ForeachNodeSafe(&pciBase->psd.devices, dev, next)
337 REMOVE(dev);
338 OOP_DisposeObject(dev);
341 ReleaseSemaphore(&pciBase->psd.dev_lock);
342 D(bug("[PCI] PCI::RemHardwareDriver() succeeded\n"));
343 return OOP_DoSuperMethod(cl, o, &msg->mID);
346 /*****************************************************************************************
348 NAME
349 moHidd_PCI_AddHardwareDriver
351 SYNOPSIS
352 OOP_Object *OOP_DoMethod(OOP_Object *obj, struct pHidd_PCI_AddHardwareDriver *Msg);
354 OOP_Object *HIDD_PCI_AddHardwareDriver(OOP_Object *obj, OOP_Class *driverClass);
356 LOCATION
357 CLID_Hidd_PCI
359 FUNCTION
360 Creates a bus driver object and registers it in the system.
362 Since V4 this interface is obsolete and deprecated. Use moHW_AddDriver
363 method in order to install the driver.
365 INPUTS
366 obj - A PCI subsystem object.
367 driverClass - A pointer to OOP class of the driver. In order to create an object
368 of some previously registered public class, use
369 oop.library/OOP_FindClass().
371 RESULT
372 None.
374 NOTES
376 EXAMPLE
378 BUGS
380 SEE ALSO
381 moHidd_PCI_RemHardwareDriver
383 INTERNALS
385 *****************************************************************************************/
387 void PCI__Hidd_PCI__AddHardwareDriver(OOP_Class *cl, OOP_Object *o,
388 struct pHidd_PCI_AddHardwareDriver *msg)
390 HW_AddDriver(o, msg->driverClass, NULL);
393 AROS_UFH3(static BOOL, searchFunc,
394 AROS_UFHA(struct Hook *, h, A0),
395 AROS_UFHA(OOP_Object *, driverObject, A2),
396 AROS_UFHA(OOP_Class *, driverClass, A1))
398 AROS_USERFUNC_INIT
400 if (OOP_OCLASS(driverObject) == driverClass)
402 h->h_Data = driverObject;
403 return TRUE;
406 return FALSE;
408 AROS_USERFUNC_EXIT
411 /*****************************************************************************************
413 NAME
414 moHidd_PCI_RemHardwareDriver
416 SYNOPSIS
417 void OOP_DoMethod(OOP_Object *obj, struct pHidd_PCI_RemHardwareDriver *Msg);
419 void HIDD_PCI_RemHardwareDriver(OOP_Object *obj, OOP_Class *driverClass);
421 LOCATION
422 CLID_Hidd_PCI
424 FUNCTION
425 Unregisters and disposes bus driver objects of the given class.
427 Since V4 this interface is obsolete and deprecated. Use moHW_RemoveDriver
428 method in order to remove drivers.
430 INPUTS
431 obj - A PCI subsystem object.
432 driverClass - A pointer to a driver class.
434 RESULT
435 None
437 NOTES
439 EXAMPLE
441 BUGS
443 SEE ALSO
444 moHidd_PCI_AddHardwareDriver
446 INTERNALS
448 *****************************************************************************************/
450 BOOL PCI__Hidd_PCI__RemHardwareDriver(OOP_Class *cl, OOP_Object *o,
451 struct pHidd_PCI_RemHardwareDriver *msg)
453 BOOL ok = FALSE;
454 struct Hook searchHook =
456 .h_Entry = (HOOKFUNC)searchFunc
460 * A very stupid and slow algorithm.
461 * Find a driver using Enum method, remember it, then remove.
462 * Repeat until search succeeds.
463 * We cannot remove drivers inside enumeration hook because EnumDrivers
464 * locks internal objects list in shared mode. RemoveDriver locks the
465 * same list in exclusive mode, and it's impossible to change semaphore's
466 * mode on the fly.
470 searchHook.h_Data = NULL;
472 HW_EnumDrivers(o, &searchHook, msg->driverClass);
474 if (searchHook.h_Data)
476 ok = HW_RemoveDriver(o, searchHook.h_Data);
477 if (!ok)
478 break;
480 } while (searchHook.h_Data);
482 return ok;
485 OOP_Object *PCI__Root__New(OOP_Class *cl, OOP_Object *o, struct pRoot_New *msg)
487 struct pcibase *pciBase = (struct pcibase *)cl->UserData;
488 struct pci_staticdata *psd = &pciBase->psd;
490 if (!psd->pciObject)
492 struct TagItem new_tags[] =
494 {aHW_ClassName, (IPTR)"PCI"},
495 {TAG_DONE , 0 }
497 struct pRoot_New new_msg =
499 .mID = msg->mID,
500 .attrList = new_tags
503 psd->pciObject = (OOP_Object *)OOP_DoSuperMethod(cl, o, &new_msg.mID);
505 return psd->pciObject;
508 VOID PCI__Root__Dispose(OOP_Class *cl, OOP_Object *o, OOP_Msg msg)