2 Copyright © 2004-2014, The AROS Development Team. All rights reserved.
6 #include <aros/debug.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>
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
)
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 :) )
44 Type
= HIDD_PCIDriver_ReadConfigByte(o
, NULL
, bus
, dev
, sub
, PCICS_HEADERTYPE
);
46 if ((Type
& PCIHT_MULTIFUNC
) == PCIHT_MULTIFUNC
)
52 static OOP_Object
*InsertDevice(OOP_Class
*cl
, ULONG
*highBus
, struct TagItem
*devtags
)
54 struct pcibase
*pciBase
= (struct pcibase
*)cl
->UserData
;
58 pcidev
= OOP_NewObject(pciBase
->psd
.pciDeviceClass
, NULL
, devtags
);
61 OOP_GetAttr(pcidev
, aHidd_PCIDevice_isBridge
, &bridge
);
64 OOP_GetAttr(pcidev
, aHidd_PCIDevice_SubBus
, &subbus
);
65 if (subbus
> *highBus
)
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
);
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
;
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 },
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);
129 devtags
[4].ti_Data
= HIDD_PCIDriver_HasExtendedConfig(drv
, bus
, dev
, 0);
130 InsertDevice(cl
, &highBus
, devtags
);
133 /* Cool! Multifunction device, search subfunctions then */
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
);
151 /* Succesful, add the driver to the end of drivers list */
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 /*****************************************************************************************
171 moHidd_PCI_EnumDevices
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);
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.
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)
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]
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
;
232 IPTR matchVal
[sizeof(attrTable
)];
237 for (i
= 0; i
< sizeof(attrTable
); i
++)
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 */
260 for (i
= 0; i
< sizeof(attrTable
); i
++)
262 if (matchVal
[i
] != ~0)
266 OOP_GetAttr(dev
, pciBase
->psd
.hiddPCIDeviceAB
+ attrTable
[i
], &value
);
267 ok
&= (value
== matchVal
[i
]);
271 /* If requirements met, call Hook */
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
;
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
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
))
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
)
323 OOP_GetAttr(dev
, aHidd_PCIDevice_Owner
, &owner
);
330 ReleaseSemaphore(&pciBase
->psd
.dev_lock
);
331 D(bug("[PCI] PCI::RemoveDriver() failed, driver in use\n"));
335 ForeachNodeSafe(&pciBase
->psd
.devices
, dev
, next
)
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 /*****************************************************************************************
349 moHidd_PCI_AddHardwareDriver
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);
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.
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().
381 moHidd_PCI_RemHardwareDriver
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
))
400 if (OOP_OCLASS(driverObject
) == driverClass
)
402 h
->h_Data
= driverObject
;
411 /*****************************************************************************************
414 moHidd_PCI_RemHardwareDriver
417 void OOP_DoMethod(OOP_Object *obj, struct pHidd_PCI_RemHardwareDriver *Msg);
419 void HIDD_PCI_RemHardwareDriver(OOP_Object *obj, OOP_Class *driverClass);
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.
431 obj - A PCI subsystem object.
432 driverClass - A pointer to a driver class.
444 moHidd_PCI_AddHardwareDriver
448 *****************************************************************************************/
450 BOOL
PCI__Hidd_PCI__RemHardwareDriver(OOP_Class
*cl
, OOP_Object
*o
,
451 struct pHidd_PCI_RemHardwareDriver
*msg
)
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
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
);
480 } while (searchHook
.h_Data
);
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
;
492 struct TagItem new_tags
[] =
494 {aHW_ClassName
, (IPTR
)"PCI"},
497 struct pRoot_New new_msg
=
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
)