2 Copyright © 2004-2017, The AROS Development Team. All rights reserved.
7 #include <aros/debug.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>
21 Returns 0 for no device, 1 for non-multi device and 2 for
22 a multifunction device
24 cl points to the base pci class which is used to extract static data
25 o points to the driver class which is used to read from config space
27 static int isPCIDeviceAvailable(OOP_Class
*cl
, OOP_Object
*o
, UBYTE bus
, UBYTE dev
, UBYTE sub
)
32 Vend
= HIDD_PCIDriver_ReadConfigWord(o
, NULL
, bus
, dev
, sub
, PCICS_VENDOR
);
34 if ((Vend
== 0xffff) || (Vend
== 0x0000))
36 /* 0xffff is an invalid vendor ID, and so is 0x0000
37 * (Well, actually 0x0000 belongs to Gammagraphx, but this really
38 * clashes with multifunc device scanning, so lets just hope nobody
39 * has a card from them :) )
45 Type
= HIDD_PCIDriver_ReadConfigByte(o
, NULL
, bus
, dev
, sub
, PCICS_HEADERTYPE
);
47 if ((Type
& PCIHT_MULTIFUNC
) == PCIHT_MULTIFUNC
)
53 static OOP_Object
*InsertDevice(OOP_Class
*cl
, ULONG
*highBus
, struct TagItem
*devtags
)
55 struct pcibase
*pciBase
= (struct pcibase
*)cl
->UserData
;
59 pcidev
= OOP_NewObject(pciBase
->psd
.pciDeviceClass
, NULL
, devtags
);
62 OOP_GetAttr(pcidev
, aHidd_PCIDevice_isBridge
, &bridge
);
65 OOP_GetAttr(pcidev
, aHidd_PCIDevice_SubBus
, &subbus
);
66 if (subbus
> *highBus
)
71 * Device class is our private and derived from rootclass.
72 * This makes casting to struct Node * safe.
74 ObtainSemaphore(&pciBase
->psd
.dev_lock
);
75 ADDTAIL(&pciBase
->psd
.devices
, pcidev
);
76 ReleaseSemaphore(&pciBase
->psd
.dev_lock
);
82 * PCI::SetUpDriver(OOP_Object *driverObject)
84 * A new PCI hardware driver is being added to the PCI subsystem.
85 * The PCI bus handled through driver added is scanned, and all available
86 * PCI devices are added to the device chain.
88 BOOL
PCI__HW__SetUpDriver(OOP_Class
*cl
, OOP_Object
*o
,
89 struct pHW_SetUpDriver
*msg
)
91 OOP_Object
*drv
= msg
->driverObject
;
93 ULONG bus
, dev
, sub
, type
;
95 struct MinList
*irq_routing
;
97 struct TagItem devtags
[] =
99 { aHidd_PCIDevice_Bus
, 0 },
100 { aHidd_PCIDevice_Dev
, 0 },
101 { aHidd_PCIDevice_Sub
, 0 },
102 { aHidd_PCIDevice_Driver
, (IPTR
)drv
},
103 { aHidd_PCIDevice_ExtendedConfig
, 0 },
107 OOP_GetAttr(drv
, aHidd_PCIDriver_IRQRoutingTable
, (IPTR
*)&irq_routing
);
109 D(bug("[PCI] Adding Driver 0x%p class 0x%p\n", drv
, OOP_OCLASS(drv
)));
111 D(bug("[PCI] drivers IRQ routing table at 0x%p\n", irq_routing
));
114 * Scan the whole PCI bus looking for devices available
115 * There is no need for semaphore protected list operations at this
116 * point, because the driver is still not public.
118 for (bus
= 0; bus
<= highBus
; bus
++)
120 D(bug("[PCI] Scanning bus %d\n",bus
));
122 devtags
[0].ti_Data
= bus
;
124 for (dev
=0; dev
< 32; dev
++)
126 devtags
[1].ti_Data
= dev
;
127 devtags
[2].ti_Data
= 0;
129 /* Knock knock! Is any device here? */
130 type
= isPCIDeviceAvailable(cl
, drv
, bus
, dev
, 0);
136 devtags
[4].ti_Data
= HIDD_PCIDriver_HasExtendedConfig(drv
, bus
, dev
, 0);
137 InsertDevice(cl
, &highBus
, devtags
);
140 /* Cool! Multifunction device, search subfunctions then */
142 devtags
[4].ti_Data
= HIDD_PCIDriver_HasExtendedConfig(drv
, bus
, dev
, 0);
143 InsertDevice(cl
, &highBus
, devtags
);
145 for (sub
=1; sub
< 8; sub
++)
147 devtags
[2].ti_Data
= sub
;
148 if (isPCIDeviceAvailable(cl
, drv
, bus
, dev
, sub
)) {
149 devtags
[4].ti_Data
= HIDD_PCIDriver_HasExtendedConfig(drv
, bus
, dev
, sub
);
150 InsertDevice(cl
, &highBus
, devtags
);
160 struct pcibase
*pciBase
= (struct pcibase
*)cl
->UserData
;
163 D(bug("[PCI] Checking IRQ routing for newly added devices\n"));
165 ForeachNode(&pciBase
->psd
.devices
, pcidev
)
170 OOP_GetAttr(pcidev
, aHidd_PCIDevice_Driver
, &d
);
171 OOP_GetAttr(pcidev
, aHidd_PCIDevice_IRQLine
, &line
);
172 if (d
== (IPTR
)drv
&& line
)
175 struct PCI_IRQRoutingEntry
*e
;
177 OOP_GetAttr(pcidev
, aHidd_PCIDevice_Bus
, &bus
);
178 OOP_GetAttr(pcidev
, aHidd_PCIDevice_Dev
, &dev
);
179 OOP_GetAttr(pcidev
, aHidd_PCIDevice_Sub
, &sub
);
181 D(bug("[PCI] Device %d:%02x.%02x uses INT%c and may need IRQ fixup\n", bus
, dev
, sub
, 'A' + line
- 1));
185 ForeachNode(irq_routing
, e
)
187 if ((e
->re_PCIDevNum
== dev
) &&
188 (e
->re_PCIFuncNum
== 0xffff || e
->re_PCIFuncNum
== sub
) &&
189 (e
->re_IRQPin
== line
))
191 struct TagItem attr
[] =
193 {aHidd_PCIDevice_INTLine
, e
->re_IRQ
},
197 D(bug("[PCI] Setting INTLine to %02x\n", e
->re_IRQ
));
198 OOP_SetAttrs(pcidev
, attr
);
205 D(bug("[PCI] Device is on bus %d, looking for it...\n", bus
));
207 ForeachNode(&pciBase
->psd
.devices
, pcibus
)
212 if (pcibus
== pcidev
)
215 OOP_GetAttr(pcibus
, aHidd_PCIDevice_Driver
, &d
);
216 OOP_GetAttr(pcibus
, aHidd_PCIDevice_isBridge
, &isBridge
);
218 if (d
== (IPTR
)drv
&& isBridge
)
221 OOP_GetAttr(pcibus
, aHidd_PCIDevice_SubBus
, &subbus
);
225 IPTR bbus
, bdev
, bsub
;
226 struct PCI_IRQRoutingEntry
*e
;
227 IPTR new_line
= 1 + (line
- 1 + dev
) % 4;
229 OOP_GetAttr(pcibus
, aHidd_PCIDevice_Bus
, &bbus
);
230 OOP_GetAttr(pcibus
, aHidd_PCIDevice_Dev
, &bdev
);
231 OOP_GetAttr(pcibus
, aHidd_PCIDevice_Sub
, &bsub
);
233 D(bug("[PCI] Found match. PCI-PCI bridge at %x:%02x.%02x (%p)\n",
234 bbus
, bdev
, bsub
, pcibus
));
236 D(bug("[PCI] Swizzling the IRQPin from INT%c to INT%c\n", 'A' + line
- 1,
237 'A' + new_line
- 1));
239 ForeachNode(irq_routing
, e
)
241 if ((e
->re_PCIDevNum
== bdev
) &&
242 (e
->re_PCIFuncNum
== 0xffff || e
->re_PCIFuncNum
== bsub
) &&
243 (e
->re_IRQPin
== new_line
))
245 struct TagItem attr
[] =
247 {aHidd_PCIDevice_INTLine
, e
->re_IRQ
},
250 D(bug("[PCI] Setting INTLine to %02x\n", e
->re_IRQ
));
251 OOP_SetAttrs(pcidev
, attr
);
262 /* Succesful, add the driver to the end of drivers list */
266 static const UBYTE attrTable
[] =
268 aoHidd_PCIDevice_VendorID
,
269 aoHidd_PCIDevice_ProductID
,
270 aoHidd_PCIDevice_RevisionID
,
271 aoHidd_PCIDevice_Interface
,
272 aoHidd_PCIDevice_Class
,
273 aoHidd_PCIDevice_SubClass
,
274 aoHidd_PCIDevice_SubsystemVendorID
,
275 aoHidd_PCIDevice_SubsystemID
,
276 aoHidd_PCIDevice_Driver
279 /*****************************************************************************************
282 moHidd_PCI_EnumDevices
285 void OOP_DoMethod(OOP_Object *obj, struct pHidd_PCI_EnumDrivers *Msg);
287 void HIDD_PCI_EnumDevices(OOP_Object *obj, struct Hook *callback,
288 const struct TagItem *requirements);
294 This method calls the callback hook for every PCI device in the system
295 that meets requirements specified (or every device if tags=NULL). It
296 iterates not only through one PCI bus, but instead through all buses
297 managed by all drivers present in the system.
300 obj - A PCI subsystem object.
301 callback - A user-supplied hook which will be called for every device.
302 requirements - A TagList specifying search parameters.
304 The hook will be called with the following parameters:
305 AROS_UFHA(struct Hook *, hook , A0)
306 - A pointer to hook structure itself
307 AROS_UFHA(OOP_Object * , deviceObject, A2)
308 - A PCI device object
309 AROS_UFHA(APTR , unused , A1)
312 The following tags are accepted as search parameters:
313 tHidd_PCI_VendorID - vendor ID
314 tHidd_PCI_ProductID - product ID
315 tHidd_PCI_RevisionID - revision ID
316 tHidd_PCI_Interface - PCI interface ID
317 tHidd_PCI_Class - PCI class ID
318 tHidd_PCI_SubClass - PCI subclass ID
319 tHidd_PCI_SubsystemVendorID - subsystem vendor ID
320 tHidd_PCI_SubsystemID - subsystem ID
321 tHidd_PCI_Driver - a pointer to bus driver object [V4]
336 *****************************************************************************************/
338 void PCI__Hidd_PCI__EnumDevices(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_PCI_EnumDevices
*msg
)
340 struct pcibase
*pciBase
= (struct pcibase
*)cl
->UserData
;
341 struct TagItem
*tstate
= (struct TagItem
*)msg
->requirements
;
343 IPTR matchVal
[sizeof(attrTable
)];
348 for (i
= 0; i
< sizeof(attrTable
); i
++)
353 /* Get requirements */
354 while ((tag
= NextTagItem(&tstate
)))
356 ULONG idx
= tag
->ti_Tag
- TAG_USER
;
358 if (idx
< sizeof(attrTable
))
359 matchVal
[idx
] = tag
->ti_Data
;
362 /* Lock devices list for shared use */
363 ObtainSemaphoreShared(&pciBase
->psd
.dev_lock
);
365 /* For every device in the system... */
366 ForeachNode(&pciBase
->psd
.devices
, dev
)
368 /* check the requirements with its properties */
371 for (i
= 0; i
< sizeof(attrTable
); i
++)
373 if (matchVal
[i
] != ~0)
377 OOP_GetAttr(dev
, pciBase
->psd
.hiddPCIDeviceAB
+ attrTable
[i
], &value
);
378 ok
&= (value
== matchVal
[i
]);
382 /* If requirements met, call Hook */
385 CALLHOOKPKT(msg
->callback
, dev
, NULL
);
389 ReleaseSemaphore(&pciBase
->psd
.dev_lock
);
392 BOOL
PCI__HW__RemoveDriver(OOP_Class
*cl
, OOP_Object
*o
, struct pHW_RemoveDriver
*msg
)
394 struct pcibase
*pciBase
= (struct pcibase
*)cl
->UserData
;
395 OOP_Object
*dev
, *next
, *drv
;
398 D(bug("[PCI] Removing hardware driver 0x%p\n", msg
->driverObject
));
401 * Get exclusive lock on devices list.
402 * If we cannot do this, then either enumeration is running or
403 * another driver is being added. We simply cannot remove the driver
405 * Well, in the latter case we actually could remove our driver, but
406 * i believe this is extremely rare situation.
408 if (!AttemptSemaphore(&pciBase
->psd
.dev_lock
))
412 * Now we can check if we can remove our devices.
413 * We think we can remove them if nobody has owned any of them.
414 * Drivers which behave badly will not own devices, or they will
415 * defer owning after enumeration loop has ended. So, removing a
416 * driver is still very dangerous.
417 * This can be improved if we implement map/unmnap and
418 * AddInterrupt/RemoveInterrupt accounting in our drivers. The
419 * driver would allow to expunge itself only if its internal counter
420 * of used resources is zero.
421 * PCI API wrappers (like prometheus.library) also build their
422 * own reflection of devices list, so we will have to implement either
423 * some ways to disable expunging, or (better) to get notifications
424 * about devices list being updated. With this notification we can
425 * have full hotplug support.
427 ForeachNode(&pciBase
->psd
.devices
, dev
)
429 OOP_GetAttr(dev
, aHidd_PCIDevice_Driver
, (IPTR
*)&drv
);
430 if (drv
== msg
->driverObject
)
434 OOP_GetAttr(dev
, aHidd_PCIDevice_Owner
, &owner
);
441 ReleaseSemaphore(&pciBase
->psd
.dev_lock
);
442 D(bug("[PCI] PCI::RemoveDriver() failed, driver in use\n"));
446 ForeachNodeSafe(&pciBase
->psd
.devices
, dev
, next
)
449 OOP_DisposeObject(dev
);
452 ReleaseSemaphore(&pciBase
->psd
.dev_lock
);
453 D(bug("[PCI] PCI::RemHardwareDriver() succeeded\n"));
454 return OOP_DoSuperMethod(cl
, o
, &msg
->mID
);
457 /*****************************************************************************************
460 moHidd_PCI_AddHardwareDriver
463 OOP_Object *OOP_DoMethod(OOP_Object *obj, struct pHidd_PCI_AddHardwareDriver *Msg);
465 OOP_Object *HIDD_PCI_AddHardwareDriver(OOP_Object *obj, OOP_Class *driverClass);
471 Creates a bus driver object and registers it in the system.
473 Since V4 this interface is obsolete and deprecated. Use moHW_AddDriver
474 method in order to install the driver.
477 obj - A PCI subsystem object.
478 driverClass - A pointer to OOP class of the driver. In order to create an object
479 of some previously registered public class, use
480 oop.library/OOP_FindClass().
492 moHidd_PCI_RemHardwareDriver
496 *****************************************************************************************/
498 void PCI__Hidd_PCI__AddHardwareDriver(OOP_Class
*cl
, OOP_Object
*o
,
499 struct pHidd_PCI_AddHardwareDriver
*msg
)
501 HW_AddDriver(o
, msg
->driverClass
, NULL
);
504 AROS_UFH3(static BOOL
, searchFunc
,
505 AROS_UFHA(struct Hook
*, h
, A0
),
506 AROS_UFHA(OOP_Object
*, driverObject
, A2
),
507 AROS_UFHA(OOP_Class
*, driverClass
, A1
))
511 if (OOP_OCLASS(driverObject
) == driverClass
)
513 h
->h_Data
= driverObject
;
522 /*****************************************************************************************
525 moHidd_PCI_RemHardwareDriver
528 void OOP_DoMethod(OOP_Object *obj, struct pHidd_PCI_RemHardwareDriver *Msg);
530 void HIDD_PCI_RemHardwareDriver(OOP_Object *obj, OOP_Class *driverClass);
536 Unregisters and disposes bus driver objects of the given class.
538 Since V4 this interface is obsolete and deprecated. Use moHW_RemoveDriver
539 method in order to remove drivers.
542 obj - A PCI subsystem object.
543 driverClass - A pointer to a driver class.
555 moHidd_PCI_AddHardwareDriver
559 *****************************************************************************************/
561 BOOL
PCI__Hidd_PCI__RemHardwareDriver(OOP_Class
*cl
, OOP_Object
*o
,
562 struct pHidd_PCI_RemHardwareDriver
*msg
)
565 struct Hook searchHook
=
567 .h_Entry
= (HOOKFUNC
)searchFunc
571 * A very stupid and slow algorithm.
572 * Find a driver using Enum method, remember it, then remove.
573 * Repeat until search succeeds.
574 * We cannot remove drivers inside enumeration hook because EnumDrivers
575 * locks internal objects list in shared mode. RemoveDriver locks the
576 * same list in exclusive mode, and it's impossible to change semaphore's
581 searchHook
.h_Data
= NULL
;
583 HW_EnumDrivers(o
, &searchHook
, msg
->driverClass
);
585 if (searchHook
.h_Data
)
587 ok
= HW_RemoveDriver(o
, searchHook
.h_Data
);
591 } while (searchHook
.h_Data
);
596 OOP_Object
*PCI__Root__New(OOP_Class
*cl
, OOP_Object
*o
, struct pRoot_New
*msg
)
598 struct pcibase
*pciBase
= (struct pcibase
*)cl
->UserData
;
599 struct pci_staticdata
*psd
= &pciBase
->psd
;
603 struct TagItem new_tags
[] =
605 {aHW_ClassName
, (IPTR
)"PCI Local Bus"},
608 struct pRoot_New new_msg
=
614 psd
->pciObject
= (OOP_Object
*)OOP_DoSuperMethod(cl
, o
, &new_msg
.mID
);
616 return psd
->pciObject
;
619 VOID
PCI__Root__Dispose(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
)