ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / pci / hotplug.c
1 #include <linux/pci.h>
2 #include <linux/module.h>
3 #include "pci.h"
4
5 #undef DEBUG
6
7 #ifdef DEBUG
8 #define DBG(x...) printk(x)
9 #else
10 #define DBG(x...)
11 #endif
12
13 int pci_hotplug (struct device *dev, char **envp, int num_envp,
14                  char *buffer, int buffer_size)
15 {
16         struct pci_dev *pdev;
17         char *scratch;
18         int i = 0;
19         int length = 0;
20
21         if (!dev)
22                 return -ENODEV;
23
24         pdev = to_pci_dev(dev);
25         if (!pdev)
26                 return -ENODEV;
27
28         scratch = buffer;
29
30         /* stuff we want to pass to /sbin/hotplug */
31         envp[i++] = scratch;
32         length += scnprintf (scratch, buffer_size - length, "PCI_CLASS=%04X",
33                             pdev->class);
34         if ((buffer_size - length <= 0) || (i >= num_envp))
35                 return -ENOMEM;
36         ++length;
37         scratch += length;
38
39         envp[i++] = scratch;
40         length += scnprintf (scratch, buffer_size - length, "PCI_ID=%04X:%04X",
41                             pdev->vendor, pdev->device);
42         if ((buffer_size - length <= 0) || (i >= num_envp))
43                 return -ENOMEM;
44         ++length;
45         scratch += length;
46
47         envp[i++] = scratch;
48         length += scnprintf (scratch, buffer_size - length,
49                             "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor,
50                             pdev->subsystem_device);
51         if ((buffer_size - length <= 0) || (i >= num_envp))
52                 return -ENOMEM;
53         ++length;
54         scratch += length;
55
56         envp[i++] = scratch;
57         length += scnprintf (scratch, buffer_size - length, "PCI_SLOT_NAME=%s",
58                             pci_name(pdev));
59         if ((buffer_size - length <= 0) || (i >= num_envp))
60                 return -ENOMEM;
61
62         envp[i] = 0;
63
64         return 0;
65 }
66
67 static int pci_visit_bus (struct pci_visit * fn, struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_parent)
68 {
69         struct list_head *ln;
70         struct pci_dev *dev;
71         struct pci_dev_wrapped wrapped_dev;
72         int result = 0;
73
74         DBG("scanning bus %02x\n", wrapped_bus->bus->number);
75
76         if (fn->pre_visit_pci_bus) {
77                 result = fn->pre_visit_pci_bus(wrapped_bus, wrapped_parent);
78                 if (result)
79                         return result;
80         }
81
82         ln = wrapped_bus->bus->devices.next; 
83         while (ln != &wrapped_bus->bus->devices) {
84                 dev = pci_dev_b(ln);
85                 ln = ln->next;
86
87                 memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped));
88                 wrapped_dev.dev = dev;
89
90                 result = pci_visit_dev(fn, &wrapped_dev, wrapped_bus);
91                 if (result)
92                         return result;
93         }
94
95         if (fn->post_visit_pci_bus)
96                 result = fn->post_visit_pci_bus(wrapped_bus, wrapped_parent);
97
98         return result;
99 }
100
101 static int pci_visit_bridge (struct pci_visit * fn,
102                              struct pci_dev_wrapped *wrapped_dev,
103                              struct pci_bus_wrapped *wrapped_parent)
104 {
105         struct pci_bus *bus;
106         struct pci_bus_wrapped wrapped_bus;
107         int result = 0;
108
109         DBG("scanning bridge %02x, %02x\n", PCI_SLOT(wrapped_dev->dev->devfn),
110             PCI_FUNC(wrapped_dev->dev->devfn));
111
112         if (fn->visit_pci_dev) {
113                 result = fn->visit_pci_dev(wrapped_dev, wrapped_parent);
114                 if (result)
115                         return result;
116         }
117
118         bus = wrapped_dev->dev->subordinate;
119         if (bus) {
120                 memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
121                 wrapped_bus.bus = bus;
122
123                 result = pci_visit_bus(fn, &wrapped_bus, wrapped_dev);
124         }
125         return result;
126 }
127
128 /**
129  * pci_visit_dev - scans the pci buses.
130  * Every bus and every function is presented to a custom
131  * function that can act upon it.
132  */
133 int pci_visit_dev(struct pci_visit *fn, struct pci_dev_wrapped *wrapped_dev,
134                   struct pci_bus_wrapped *wrapped_parent)
135 {
136         struct pci_dev* dev = wrapped_dev ? wrapped_dev->dev : NULL;
137         int result = 0;
138
139         if (!dev)
140                 return 0;
141
142         if (fn->pre_visit_pci_dev) {
143                 result = fn->pre_visit_pci_dev(wrapped_dev, wrapped_parent);
144                 if (result)
145                         return result;
146         }
147
148         switch (dev->class >> 8) {
149                 case PCI_CLASS_BRIDGE_PCI:
150                         result = pci_visit_bridge(fn, wrapped_dev,
151                                                   wrapped_parent);
152                         if (result)
153                                 return result;
154                         break;
155                 default:
156                         DBG("scanning device %02x, %02x\n",
157                             PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
158                         if (fn->visit_pci_dev) {
159                                 result = fn->visit_pci_dev (wrapped_dev,
160                                                             wrapped_parent);
161                                 if (result)
162                                         return result;
163                         }
164         }
165
166         if (fn->post_visit_pci_dev)
167                 result = fn->post_visit_pci_dev(wrapped_dev, wrapped_parent);
168
169         return result;
170 }
171 EXPORT_SYMBOL(pci_visit_dev);
172