ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / pci / search.c
1 /*
2  *      PCI searching functions.
3  *
4  *      Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter,
5  *                              David Mosberger-Tang
6  *      Copyright 1997 -- 2000 Martin Mares <mj@ucw.cz>
7  *      Copyright 2003 -- Greg Kroah-Hartman <greg@kroah.com>
8  */
9
10 #include <linux/init.h>
11 #include <linux/pci.h>
12 #include <linux/module.h>
13 #include <linux/interrupt.h>
14
15 spinlock_t pci_bus_lock = SPIN_LOCK_UNLOCKED;
16
17 static struct pci_bus * __devinit
18 pci_do_find_bus(struct pci_bus* bus, unsigned char busnr)
19 {
20         struct pci_bus* child;
21         struct list_head *tmp;
22
23         if(bus->number == busnr)
24                 return bus;
25
26         list_for_each(tmp, &bus->children) {
27                 child = pci_do_find_bus(pci_bus_b(tmp), busnr);
28                 if(child)
29                         return child;
30         }
31         return NULL;
32 }
33
34 /**
35  * pci_find_bus - locate PCI bus from a given domain and bus number
36  * @domain: number of PCI domain to search
37  * @busnr: number of desired PCI bus
38  *
39  * Given a PCI bus number and domain number, the desired PCI bus is located
40  * in the global list of PCI buses.  If the bus is found, a pointer to its
41  * data structure is returned.  If no bus is found, %NULL is returned.
42  */
43 struct pci_bus * __devinit pci_find_bus(int domain, int busnr)
44 {
45         struct pci_bus *bus = NULL;
46         struct pci_bus *tmp_bus;
47
48         while ((bus = pci_find_next_bus(bus)) != NULL)  {
49                 if (pci_domain_nr(bus) != domain)
50                         continue;
51                 tmp_bus = pci_do_find_bus(bus, busnr);
52                 if (tmp_bus)
53                         return tmp_bus;
54         }
55         return NULL;
56 }
57
58 /**
59  * pci_find_next_bus - begin or continue searching for a PCI bus
60  * @from: Previous PCI bus found, or %NULL for new search.
61  *
62  * Iterates through the list of known PCI busses.  A new search is
63  * initiated by passing %NULL to the @from argument.  Otherwise if
64  * @from is not %NULL, searches continue from next device on the
65  * global list.
66  */
67 struct pci_bus * 
68 pci_find_next_bus(const struct pci_bus *from)
69 {
70         struct list_head *n;
71         struct pci_bus *b = NULL;
72
73         WARN_ON(in_interrupt());
74         spin_lock(&pci_bus_lock);
75         n = from ? from->node.next : pci_root_buses.next;
76         if (n != &pci_root_buses)
77                 b = pci_bus_b(n);
78         spin_unlock(&pci_bus_lock);
79         return b;
80 }
81
82 /**
83  * pci_find_slot - locate PCI device from a given PCI slot
84  * @bus: number of PCI bus on which desired PCI device resides
85  * @devfn: encodes number of PCI slot in which the desired PCI 
86  * device resides and the logical device number within that slot 
87  * in case of multi-function devices.
88  *
89  * Given a PCI bus and slot/function number, the desired PCI device 
90  * is located in system global list of PCI devices.  If the device
91  * is found, a pointer to its data structure is returned.  If no 
92  * device is found, %NULL is returned.
93  */
94 struct pci_dev *
95 pci_find_slot(unsigned int bus, unsigned int devfn)
96 {
97         struct pci_dev *dev = NULL;
98
99         while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
100                 if (dev->bus->number == bus && dev->devfn == devfn)
101                         return dev;
102         }
103         return NULL;
104 }
105
106 /**
107  * pci_get_slot - locate PCI device for a given PCI slot
108  * @bus: PCI bus on which desired PCI device resides
109  * @devfn: encodes number of PCI slot in which the desired PCI 
110  * device resides and the logical device number within that slot 
111  * in case of multi-function devices.
112  *
113  * Given a PCI bus and slot/function number, the desired PCI device 
114  * is located in the list of PCI devices.
115  * If the device is found, its reference count is increased and this
116  * function returns a pointer to its data structure.  The caller must
117  * decrement the reference count by calling pci_dev_put().
118  * If no device is found, %NULL is returned.
119  */
120 struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn)
121 {
122         struct list_head *tmp;
123         struct pci_dev *dev;
124
125         WARN_ON(in_interrupt());
126         spin_lock(&pci_bus_lock);
127
128         list_for_each(tmp, &bus->devices) {
129                 dev = pci_dev_b(tmp);
130                 if (dev->devfn == devfn)
131                         goto out;
132         }
133
134         dev = NULL;
135  out:
136         pci_dev_get(dev);
137         spin_unlock(&pci_bus_lock);
138         return dev;
139 }
140
141 /**
142  * pci_find_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
143  * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
144  * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
145  * @ss_vendor: PCI subsystem vendor id to match, or %PCI_ANY_ID to match all vendor ids
146  * @ss_device: PCI subsystem device id to match, or %PCI_ANY_ID to match all device ids
147  * @from: Previous PCI device found in search, or %NULL for new search.
148  *
149  * Iterates through the list of known PCI devices.  If a PCI device is
150  * found with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its
151  * device structure is returned.  Otherwise, %NULL is returned.
152  * A new search is initiated by passing %NULL to the @from argument.
153  * Otherwise if @from is not %NULL, searches continue from next device on the global list.
154  *
155  * NOTE: Do not use this function anymore, use pci_get_subsys() instead, as
156  * the pci device returned by this function can disappear at any moment in
157  * time.
158  */
159 struct pci_dev *
160 pci_find_subsys(unsigned int vendor, unsigned int device,
161                 unsigned int ss_vendor, unsigned int ss_device,
162                 const struct pci_dev *from)
163 {
164         struct list_head *n;
165         struct pci_dev *dev;
166
167         WARN_ON(in_interrupt());
168         spin_lock(&pci_bus_lock);
169         n = from ? from->global_list.next : pci_devices.next;
170
171         while (n && (n != &pci_devices)) {
172                 dev = pci_dev_g(n);
173                 if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
174                     (device == PCI_ANY_ID || dev->device == device) &&
175                     (ss_vendor == PCI_ANY_ID || dev->subsystem_vendor == ss_vendor) &&
176                     (ss_device == PCI_ANY_ID || dev->subsystem_device == ss_device))
177                         goto exit;
178                 n = n->next;
179         }
180         dev = NULL;
181 exit:
182         spin_unlock(&pci_bus_lock);
183         return dev;
184 }
185
186 /**
187  * pci_find_device - begin or continue searching for a PCI device by vendor/device id
188  * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
189  * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
190  * @from: Previous PCI device found in search, or %NULL for new search.
191  *
192  * Iterates through the list of known PCI devices.  If a PCI device is
193  * found with a matching @vendor and @device, a pointer to its device structure is
194  * returned.  Otherwise, %NULL is returned.
195  * A new search is initiated by passing %NULL to the @from argument.
196  * Otherwise if @from is not %NULL, searches continue from next device on the global list.
197  * 
198  * NOTE: Do not use this function anymore, use pci_get_device() instead, as
199  * the pci device returned by this function can disappear at any moment in
200  * time.
201  */
202 struct pci_dev *
203 pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from)
204 {
205         return pci_find_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
206 }
207
208 /**
209  * pci_get_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
210  * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
211  * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
212  * @ss_vendor: PCI subsystem vendor id to match, or %PCI_ANY_ID to match all vendor ids
213  * @ss_device: PCI subsystem device id to match, or %PCI_ANY_ID to match all device ids
214  * @from: Previous PCI device found in search, or %NULL for new search.
215  *
216  * Iterates through the list of known PCI devices.  If a PCI device is
217  * found with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its
218  * device structure is returned, and the reference count to the device is
219  * incremented.  Otherwise, %NULL is returned.  A new search is initiated by
220  * passing %NULL to the @from argument.  Otherwise if @from is not %NULL,
221  * searches continue from next device on the global list.
222  * The reference count for @from is always decremented if it is not %NULL.
223  */
224 struct pci_dev * 
225 pci_get_subsys(unsigned int vendor, unsigned int device,
226                unsigned int ss_vendor, unsigned int ss_device,
227                struct pci_dev *from)
228 {
229         struct list_head *n;
230         struct pci_dev *dev;
231
232         WARN_ON(in_interrupt());
233         spin_lock(&pci_bus_lock);
234         n = from ? from->global_list.next : pci_devices.next;
235
236         while (n && (n != &pci_devices)) {
237                 dev = pci_dev_g(n);
238                 if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
239                     (device == PCI_ANY_ID || dev->device == device) &&
240                     (ss_vendor == PCI_ANY_ID || dev->subsystem_vendor == ss_vendor) &&
241                     (ss_device == PCI_ANY_ID || dev->subsystem_device == ss_device))
242                         goto exit;
243                 n = n->next;
244         }
245         dev = NULL;
246 exit:
247         pci_dev_put(from);
248         dev = pci_dev_get(dev);
249         spin_unlock(&pci_bus_lock);
250         return dev;
251 }
252
253 /**
254  * pci_get_device - begin or continue searching for a PCI device by vendor/device id
255  * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
256  * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
257  * @from: Previous PCI device found in search, or %NULL for new search.
258  *
259  * Iterates through the list of known PCI devices.  If a PCI device is
260  * found with a matching @vendor and @device, a pointer to its device structure is
261  * returned.  Otherwise, %NULL is returned.
262  * A new search is initiated by passing %NULL to the @from argument.
263  * Otherwise if @from is not %NULL, searches continue from next device on the global list.
264  *
265  * Iterates through the list of known PCI devices.  If a PCI device is
266  * found with a matching @vendor and @device, the reference count to the
267  * device is incremented and a pointer to its device structure is returned.
268  * Otherwise, %NULL is returned.  A new search is initiated by passing %NULL
269  * to the @from argument.  Otherwise if @from is not %NULL, searches continue
270  * from next device on the global list.  The reference count for @from is
271  * always decremented if it is not %NULL.
272  */
273 struct pci_dev *
274 pci_get_device(unsigned int vendor, unsigned int device, struct pci_dev *from)
275 {
276         return pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
277 }
278
279
280 /**
281  * pci_find_device_reverse - begin or continue searching for a PCI device by vendor/device id
282  * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
283  * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
284  * @from: Previous PCI device found in search, or %NULL for new search.
285  *
286  * Iterates through the list of known PCI devices in the reverse order of pci_find_device().
287  * If a PCI device is found with a matching @vendor and @device, a pointer to
288  * its device structure is returned.  Otherwise, %NULL is returned.
289  * A new search is initiated by passing %NULL to the @from argument.
290  * Otherwise if @from is not %NULL, searches continue from previous device on the global list.
291  */
292 struct pci_dev *
293 pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct pci_dev *from)
294 {
295         struct list_head *n;
296         struct pci_dev *dev;
297
298         WARN_ON(in_interrupt());
299         spin_lock(&pci_bus_lock);
300         n = from ? from->global_list.prev : pci_devices.prev;
301
302         while (n && (n != &pci_devices)) {
303                 dev = pci_dev_g(n);
304                 if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
305                     (device == PCI_ANY_ID || dev->device == device))
306                         goto exit;
307                 n = n->prev;
308         }
309         dev = NULL;
310 exit:
311         spin_unlock(&pci_bus_lock);
312         return dev;
313 }
314
315
316 /**
317  * pci_find_class - begin or continue searching for a PCI device by class
318  * @class: search for a PCI device with this class designation
319  * @from: Previous PCI device found in search, or %NULL for new search.
320  *
321  * Iterates through the list of known PCI devices.  If a PCI device is
322  * found with a matching @class, a pointer to its device structure is
323  * returned.  Otherwise, %NULL is returned.
324  * A new search is initiated by passing %NULL to the @from argument.
325  * Otherwise if @from is not %NULL, searches continue from next device
326  * on the global list.
327  */
328 struct pci_dev *
329 pci_find_class(unsigned int class, const struct pci_dev *from)
330 {
331         struct list_head *n;
332         struct pci_dev *dev;
333
334         spin_lock(&pci_bus_lock);
335         n = from ? from->global_list.next : pci_devices.next;
336
337         while (n && (n != &pci_devices)) {
338                 dev = pci_dev_g(n);
339                 if (dev->class == class)
340                         goto exit;
341                 n = n->next;
342         }
343         dev = NULL;
344 exit:
345         spin_unlock(&pci_bus_lock);
346         return dev;
347 }
348
349 EXPORT_SYMBOL(pci_find_bus);
350 EXPORT_SYMBOL(pci_find_class);
351 EXPORT_SYMBOL(pci_find_device);
352 EXPORT_SYMBOL(pci_find_device_reverse);
353 EXPORT_SYMBOL(pci_find_slot);
354 EXPORT_SYMBOL(pci_find_subsys);
355 EXPORT_SYMBOL(pci_get_device);
356 EXPORT_SYMBOL(pci_get_subsys);
357 EXPORT_SYMBOL(pci_get_slot);