Linux-2.6.12-rc2
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / pci / hotplug.c
blobd471b3ea5d12fb812f4782e7100fe5d22fe79f3d
1 #include <linux/kernel.h>
2 #include <linux/pci.h>
3 #include <linux/module.h>
4 #include "pci.h"
6 int pci_hotplug (struct device *dev, char **envp, int num_envp,
7 char *buffer, int buffer_size)
9 struct pci_dev *pdev;
10 char *scratch;
11 int i = 0;
12 int length = 0;
14 if (!dev)
15 return -ENODEV;
17 pdev = to_pci_dev(dev);
18 if (!pdev)
19 return -ENODEV;
21 scratch = buffer;
23 /* stuff we want to pass to /sbin/hotplug */
24 envp[i++] = scratch;
25 length += scnprintf (scratch, buffer_size - length, "PCI_CLASS=%04X",
26 pdev->class);
27 if ((buffer_size - length <= 0) || (i >= num_envp))
28 return -ENOMEM;
29 ++length;
30 scratch += length;
32 envp[i++] = scratch;
33 length += scnprintf (scratch, buffer_size - length, "PCI_ID=%04X:%04X",
34 pdev->vendor, pdev->device);
35 if ((buffer_size - length <= 0) || (i >= num_envp))
36 return -ENOMEM;
37 ++length;
38 scratch += length;
40 envp[i++] = scratch;
41 length += scnprintf (scratch, buffer_size - length,
42 "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor,
43 pdev->subsystem_device);
44 if ((buffer_size - length <= 0) || (i >= num_envp))
45 return -ENOMEM;
46 ++length;
47 scratch += length;
49 envp[i++] = scratch;
50 length += scnprintf (scratch, buffer_size - length, "PCI_SLOT_NAME=%s",
51 pci_name(pdev));
52 if ((buffer_size - length <= 0) || (i >= num_envp))
53 return -ENOMEM;
55 envp[i] = NULL;
57 return 0;
60 static int pci_visit_bus (struct pci_visit * fn, struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_parent)
62 struct list_head *ln;
63 struct pci_dev *dev;
64 struct pci_dev_wrapped wrapped_dev;
65 int result = 0;
67 pr_debug("PCI: Scanning bus %04x:%02x\n", pci_domain_nr(wrapped_bus->bus),
68 wrapped_bus->bus->number);
70 if (fn->pre_visit_pci_bus) {
71 result = fn->pre_visit_pci_bus(wrapped_bus, wrapped_parent);
72 if (result)
73 return result;
76 ln = wrapped_bus->bus->devices.next;
77 while (ln != &wrapped_bus->bus->devices) {
78 dev = pci_dev_b(ln);
79 ln = ln->next;
81 memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped));
82 wrapped_dev.dev = dev;
84 result = pci_visit_dev(fn, &wrapped_dev, wrapped_bus);
85 if (result)
86 return result;
89 if (fn->post_visit_pci_bus)
90 result = fn->post_visit_pci_bus(wrapped_bus, wrapped_parent);
92 return result;
95 static int pci_visit_bridge (struct pci_visit * fn,
96 struct pci_dev_wrapped *wrapped_dev,
97 struct pci_bus_wrapped *wrapped_parent)
99 struct pci_bus *bus;
100 struct pci_bus_wrapped wrapped_bus;
101 int result = 0;
103 pr_debug("PCI: Scanning bridge %s\n", pci_name(wrapped_dev->dev));
105 if (fn->visit_pci_dev) {
106 result = fn->visit_pci_dev(wrapped_dev, wrapped_parent);
107 if (result)
108 return result;
111 bus = wrapped_dev->dev->subordinate;
112 if (bus) {
113 memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
114 wrapped_bus.bus = bus;
116 result = pci_visit_bus(fn, &wrapped_bus, wrapped_dev);
118 return result;
122 * pci_visit_dev - scans the pci buses.
123 * Every bus and every function is presented to a custom
124 * function that can act upon it.
126 int pci_visit_dev(struct pci_visit *fn, struct pci_dev_wrapped *wrapped_dev,
127 struct pci_bus_wrapped *wrapped_parent)
129 struct pci_dev* dev = wrapped_dev ? wrapped_dev->dev : NULL;
130 int result = 0;
132 if (!dev)
133 return 0;
135 if (fn->pre_visit_pci_dev) {
136 result = fn->pre_visit_pci_dev(wrapped_dev, wrapped_parent);
137 if (result)
138 return result;
141 switch (dev->class >> 8) {
142 case PCI_CLASS_BRIDGE_PCI:
143 result = pci_visit_bridge(fn, wrapped_dev,
144 wrapped_parent);
145 if (result)
146 return result;
147 break;
148 default:
149 pr_debug("PCI: Scanning device %s\n", pci_name(dev));
150 if (fn->visit_pci_dev) {
151 result = fn->visit_pci_dev (wrapped_dev,
152 wrapped_parent);
153 if (result)
154 return result;
158 if (fn->post_visit_pci_dev)
159 result = fn->post_visit_pci_dev(wrapped_dev, wrapped_parent);
161 return result;
163 EXPORT_SYMBOL(pci_visit_dev);