#include <linux/pci.h>
#include <linux/errno.h>
#include <linux/ioport.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+
+#include "pci.h"
/**
* pci_bus_alloc_resource - allocate a resource from a parent bus
return ret;
}
+/**
+ * pci_bus_add_devices - insert newly discovered PCI devices
+ * @bus: bus to check for new devices
+ *
+ * Add newly discovered PCI devices (which are on the bus->devices
+ * list) to the global PCI device list, add the sysfs and procfs
+ * entries. Where a bridge is found, add the discovered bus to
+ * the parents list of child buses, and recurse.
+ *
+ * Call hotplug for each new devices.
+ */
+void __devinit pci_bus_add_devices(struct pci_bus *bus)
+{
+ struct pci_dev *dev;
+
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ /*
+ * Skip already-present devices (which are on the
+ * global device list.)
+ */
+ if (!list_empty(&dev->global_list))
+ continue;
+
+ device_register(&dev->dev);
+ list_add_tail(&dev->global_list, &pci_devices);
+#ifdef CONFIG_PROC_FS
+ pci_proc_attach_device(dev);
+#endif
+ pci_create_sysfs_dev_files(dev);
+
+ /*
+ * If there is an unattached subordinate bus, attach
+ * it and then scan for unattached PCI devices.
+ */
+ if (dev->subordinate && list_empty(&dev->subordinate->node)) {
+ list_add_tail(&dev->subordinate->node, &dev->bus->children);
+ pci_bus_add_devices(dev->subordinate);
+ }
+ }
+}
+
void pci_enable_bridges(struct pci_bus *bus)
{
struct pci_dev *dev;
}
EXPORT_SYMBOL(pci_bus_alloc_resource);
+EXPORT_SYMBOL(pci_bus_add_devices);
EXPORT_SYMBOL(pci_enable_bridges);
b = kmalloc(sizeof(*b), GFP_KERNEL);
if (b) {
memset(b, 0, sizeof(*b));
+ INIT_LIST_HEAD(&b->node);
INIT_LIST_HEAD(&b->children);
INIT_LIST_HEAD(&b->devices);
}
return dev;
}
-struct pci_dev * __devinit pci_scan_slot(struct pci_bus *bus, int devfn)
+/**
+ * pci_scan_slot - scan a PCI slot on a bus for devices.
+ * @bus: PCI bus to scan
+ * @devfn: slot number to scan (must have zero function.)
+ *
+ * Scan a PCI slot on the specified PCI bus for devices, adding
+ * discovered devices to the @bus->devices list. New devices
+ * will have an empty dev->global_list head.
+ */
+int __devinit pci_scan_slot(struct pci_bus *bus, int devfn)
{
- struct pci_dev *first_dev = NULL;
- int func;
+ int func, nr = 0;
for (func = 0; func < 8; func++, devfn++) {
struct pci_dev *dev;
if (!dev)
continue;
- if (func == 0) {
- first_dev = dev;
- } else {
+ if (func != 0)
dev->multifunction = 1;
- }
/* Fix up broken headers */
pci_fixup_device(PCI_FIXUP_HEADER, dev);
/*
- * Link the device to both the global PCI device chain and
- * the per-bus list of devices and add the /proc entry.
- * Note: this also runs the hotplug notifiers (bad!) --rmk
+ * Add the device to our list of discovered devices
+ * and the bus list for fixup functions, etc.
*/
- device_register(&dev->dev);
- pci_insert_device (dev, bus);
+ INIT_LIST_HEAD(&dev->global_list);
+ list_add_tail(&dev->bus_list, &bus->devices);
+ nr++;
/*
* If this is a single function device,
if (!dev->multifunction)
break;
}
- return first_dev;
+ return nr;
}
-unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus)
+static unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)
{
- unsigned int devfn, max, pass;
- struct list_head *ln;
+ unsigned int devfn, pass, max = bus->secondary;
struct pci_dev *dev;
DBG("Scanning bus %02x\n", bus->number);
- max = bus->secondary;
/* Go find them, Rover! */
for (devfn = 0; devfn < 0x100; devfn += 8)
return max;
}
+unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus)
+{
+ unsigned int max;
+
+ max = pci_scan_child_bus(bus);
+
+ /*
+ * Make the discovered devices available.
+ */
+ pci_bus_add_devices(bus);
+
+ return max;
+}
+
int __devinit pci_bus_exists(const struct list_head *list, int nr)
{
const struct pci_bus *b;