Linux-2.6.12-rc2
[GitHub/exynos8895/android_kernel_samsung_universal8895.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);