blob: 42b23049a7fcde2f38d5b6c9f3dbeb17c671951b [file] [log] [blame]
#include <linux/pci.h>
#include <linux/module.h>
#include "pci.h"
#undef DEBUG
#ifdef DEBUG
#define DBG(x...) printk(x)
#else
#define DBG(x...)
#endif
int pci_hotplug (struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size)
{
struct pci_dev *pdev;
char *scratch;
int i = 0;
int length = 0;
if (!dev)
return -ENODEV;
pdev = to_pci_dev(dev);
if (!pdev)
return -ENODEV;
scratch = buffer;
/* stuff we want to pass to /sbin/hotplug */
envp[i++] = scratch;
length += scnprintf (scratch, buffer_size - length, "PCI_CLASS=%04X",
pdev->class);
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
envp[i++] = scratch;
length += scnprintf (scratch, buffer_size - length, "PCI_ID=%04X:%04X",
pdev->vendor, pdev->device);
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
envp[i++] = scratch;
length += scnprintf (scratch, buffer_size - length,
"PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor,
pdev->subsystem_device);
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
++length;
scratch += length;
envp[i++] = scratch;
length += scnprintf (scratch, buffer_size - length, "PCI_SLOT_NAME=%s",
pci_name(pdev));
if ((buffer_size - length <= 0) || (i >= num_envp))
return -ENOMEM;
envp[i] = NULL;
return 0;
}
static int pci_visit_bus (struct pci_visit * fn, struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_parent)
{
struct list_head *ln;
struct pci_dev *dev;
struct pci_dev_wrapped wrapped_dev;
int result = 0;
DBG("scanning bus %02x\n", wrapped_bus->bus->number);
if (fn->pre_visit_pci_bus) {
result = fn->pre_visit_pci_bus(wrapped_bus, wrapped_parent);
if (result)
return result;
}
ln = wrapped_bus->bus->devices.next;
while (ln != &wrapped_bus->bus->devices) {
dev = pci_dev_b(ln);
ln = ln->next;
memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped));
wrapped_dev.dev = dev;
result = pci_visit_dev(fn, &wrapped_dev, wrapped_bus);
if (result)
return result;
}
if (fn->post_visit_pci_bus)
result = fn->post_visit_pci_bus(wrapped_bus, wrapped_parent);
return result;
}
static int pci_visit_bridge (struct pci_visit * fn,
struct pci_dev_wrapped *wrapped_dev,
struct pci_bus_wrapped *wrapped_parent)
{
struct pci_bus *bus;
struct pci_bus_wrapped wrapped_bus;
int result = 0;
DBG("scanning bridge %02x, %02x\n", PCI_SLOT(wrapped_dev->dev->devfn),
PCI_FUNC(wrapped_dev->dev->devfn));
if (fn->visit_pci_dev) {
result = fn->visit_pci_dev(wrapped_dev, wrapped_parent);
if (result)
return result;
}
bus = wrapped_dev->dev->subordinate;
if (bus) {
memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
wrapped_bus.bus = bus;
result = pci_visit_bus(fn, &wrapped_bus, wrapped_dev);
}
return result;
}
/**
* pci_visit_dev - scans the pci buses.
* Every bus and every function is presented to a custom
* function that can act upon it.
*/
int pci_visit_dev(struct pci_visit *fn, struct pci_dev_wrapped *wrapped_dev,
struct pci_bus_wrapped *wrapped_parent)
{
struct pci_dev* dev = wrapped_dev ? wrapped_dev->dev : NULL;
int result = 0;
if (!dev)
return 0;
if (fn->pre_visit_pci_dev) {
result = fn->pre_visit_pci_dev(wrapped_dev, wrapped_parent);
if (result)
return result;
}
switch (dev->class >> 8) {
case PCI_CLASS_BRIDGE_PCI:
result = pci_visit_bridge(fn, wrapped_dev,
wrapped_parent);
if (result)
return result;
break;
default:
DBG("scanning device %02x, %02x\n",
PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
if (fn->visit_pci_dev) {
result = fn->visit_pci_dev (wrapped_dev,
wrapped_parent);
if (result)
return result;
}
}
if (fn->post_visit_pci_dev)
result = fn->post_visit_pci_dev(wrapped_dev, wrapped_parent);
return result;
}
EXPORT_SYMBOL(pci_visit_dev);