Linux-2.6.12-rc2
[linux-flexiantxendom0-natty.git] / drivers / pci / hotplug.c
1 #include <linux/kernel.h>
2 #include <linux/pci.h>
3 #include <linux/module.h>
4 #include "pci.h"
5
6 int pci_hotplug (struct device *dev, char **envp, int num_envp,
7                  char *buffer, int buffer_size)
8 {
9         struct pci_dev *pdev;
10         char *scratch;
11         int i = 0;
12         int length = 0;
13
14         if (!dev)
15                 return -ENODEV;
16
17         pdev = to_pci_dev(dev);
18         if (!pdev)
19                 return -ENODEV;
20
21         scratch = buffer;
22
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;
31
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;
39
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;
48
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;
54
55         envp[i] = NULL;
56
57         return 0;
58 }
59
60 static int pci_visit_bus (struct pci_visit * fn, struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_parent)
61 {
62         struct list_head *ln;
63         struct pci_dev *dev;
64         struct pci_dev_wrapped wrapped_dev;
65         int result = 0;
66
67         pr_debug("PCI: Scanning bus %04x:%02x\n", pci_domain_nr(wrapped_bus->bus),
68                 wrapped_bus->bus->number);
69
70         if (fn->pre_visit_pci_bus) {
71                 result = fn->pre_visit_pci_bus(wrapped_bus, wrapped_parent);
72                 if (result)
73                         return result;
74         }
75
76         ln = wrapped_bus->bus->devices.next; 
77         while (ln != &wrapped_bus->bus->devices) {
78                 dev = pci_dev_b(ln);
79                 ln = ln->next;
80
81                 memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped));
82                 wrapped_dev.dev = dev;
83
84                 result = pci_visit_dev(fn, &wrapped_dev, wrapped_bus);
85                 if (result)
86                         return result;
87         }
88
89         if (fn->post_visit_pci_bus)
90                 result = fn->post_visit_pci_bus(wrapped_bus, wrapped_parent);
91
92         return result;
93 }
94
95 static int pci_visit_bridge (struct pci_visit * fn,
96                              struct pci_dev_wrapped *wrapped_dev,
97                              struct pci_bus_wrapped *wrapped_parent)
98 {
99         struct pci_bus *bus;
100         struct pci_bus_wrapped wrapped_bus;
101         int result = 0;
102
103         pr_debug("PCI: Scanning bridge %s\n", pci_name(wrapped_dev->dev));
104
105         if (fn->visit_pci_dev) {
106                 result = fn->visit_pci_dev(wrapped_dev, wrapped_parent);
107                 if (result)
108                         return result;
109         }
110
111         bus = wrapped_dev->dev->subordinate;
112         if (bus) {
113                 memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
114                 wrapped_bus.bus = bus;
115
116                 result = pci_visit_bus(fn, &wrapped_bus, wrapped_dev);
117         }
118         return result;
119 }
120
121 /**
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.
125  */
126 int pci_visit_dev(struct pci_visit *fn, struct pci_dev_wrapped *wrapped_dev,
127                   struct pci_bus_wrapped *wrapped_parent)
128 {
129         struct pci_dev* dev = wrapped_dev ? wrapped_dev->dev : NULL;
130         int result = 0;
131
132         if (!dev)
133                 return 0;
134
135         if (fn->pre_visit_pci_dev) {
136                 result = fn->pre_visit_pci_dev(wrapped_dev, wrapped_parent);
137                 if (result)
138                         return result;
139         }
140
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;
155                         }
156         }
157
158         if (fn->post_visit_pci_dev)
159                 result = fn->post_visit_pci_dev(wrapped_dev, wrapped_parent);
160
161         return result;
162 }
163 EXPORT_SYMBOL(pci_visit_dev);