Subversion Repositories shark

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
428 giacomo 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_find_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
108
 * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
109
 * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
110
 * @ss_vendor: PCI subsystem vendor id to match, or %PCI_ANY_ID to match all vendor ids
111
 * @ss_device: PCI subsystem device id to match, or %PCI_ANY_ID to match all device ids
112
 * @from: Previous PCI device found in search, or %NULL for new search.
113
 *
114
 * Iterates through the list of known PCI devices.  If a PCI device is
115
 * found with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its
116
 * device structure is returned.  Otherwise, %NULL is returned.
117
 * A new search is initiated by passing %NULL to the @from argument.
118
 * Otherwise if @from is not %NULL, searches continue from next device on the global list.
119
 *
120
 * NOTE: Do not use this function anymore, use pci_get_subsys() instead, as
121
 * the pci device returned by this function can disappear at any moment in
122
 * time.
123
 */
124
struct pci_dev *
125
pci_find_subsys(unsigned int vendor, unsigned int device,
126
                unsigned int ss_vendor, unsigned int ss_device,
127
                const struct pci_dev *from)
128
{
129
        struct list_head *n;
130
        struct pci_dev *dev;
131
 
132
        WARN_ON(in_interrupt());
133
        spin_lock(&pci_bus_lock);
134
        n = from ? from->global_list.next : pci_devices.next;
135
 
136
        while (n && (n != &pci_devices)) {
137
                dev = pci_dev_g(n);
138
                if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
139
                    (device == PCI_ANY_ID || dev->device == device) &&
140
                    (ss_vendor == PCI_ANY_ID || dev->subsystem_vendor == ss_vendor) &&
141
                    (ss_device == PCI_ANY_ID || dev->subsystem_device == ss_device))
142
                        goto exit;
143
                n = n->next;
144
        }
145
        dev = NULL;
146
exit:
147
        spin_unlock(&pci_bus_lock);
148
        return dev;
149
}
150
 
151
/**
152
 * pci_find_device - begin or continue searching for a PCI device by vendor/device id
153
 * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
154
 * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
155
 * @from: Previous PCI device found in search, or %NULL for new search.
156
 *
157
 * Iterates through the list of known PCI devices.  If a PCI device is
158
 * found with a matching @vendor and @device, a pointer to its device structure is
159
 * returned.  Otherwise, %NULL is returned.
160
 * A new search is initiated by passing %NULL to the @from argument.
161
 * Otherwise if @from is not %NULL, searches continue from next device on the global list.
162
 *
163
 * NOTE: Do not use this function anymore, use pci_get_device() instead, as
164
 * the pci device returned by this function can disappear at any moment in
165
 * time.
166
 */
167
struct pci_dev *
168
pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from)
169
{
170
        return pci_find_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
171
}
172
 
173
/**
174
 * pci_get_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
175
 * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
176
 * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
177
 * @ss_vendor: PCI subsystem vendor id to match, or %PCI_ANY_ID to match all vendor ids
178
 * @ss_device: PCI subsystem device id to match, or %PCI_ANY_ID to match all device ids
179
 * @from: Previous PCI device found in search, or %NULL for new search.
180
 *
181
 * Iterates through the list of known PCI devices.  If a PCI device is
182
 * found with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its
183
 * device structure is returned, and the reference count to the device is
184
 * incremented.  Otherwise, %NULL is returned.  A new search is initiated by
185
 * passing %NULL to the @from argument.  Otherwise if @from is not %NULL,
186
 * searches continue from next device on the global list.
187
 * The reference count for @from is always decremented if it is not %NULL.
188
 */
189
struct pci_dev *
190
pci_get_subsys(unsigned int vendor, unsigned int device,
191
               unsigned int ss_vendor, unsigned int ss_device,
192
               struct pci_dev *from)
193
{
194
        struct list_head *n;
195
        struct pci_dev *dev;
196
 
197
        WARN_ON(in_interrupt());
198
        spin_lock(&pci_bus_lock);
199
        n = from ? from->global_list.next : pci_devices.next;
200
 
201
        while (n && (n != &pci_devices)) {
202
                dev = pci_dev_g(n);
203
                if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
204
                    (device == PCI_ANY_ID || dev->device == device) &&
205
                    (ss_vendor == PCI_ANY_ID || dev->subsystem_vendor == ss_vendor) &&
206
                    (ss_device == PCI_ANY_ID || dev->subsystem_device == ss_device))
207
                        goto exit;
208
                n = n->next;
209
        }
210
        dev = NULL;
211
exit:
212
        pci_dev_put(from);
213
        dev = pci_dev_get(dev);
214
        spin_unlock(&pci_bus_lock);
215
        return dev;
216
}
217
 
218
/**
219
 * pci_get_device - begin or continue searching for a PCI device by vendor/device id
220
 * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
221
 * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
222
 * @from: Previous PCI device found in search, or %NULL for new search.
223
 *
224
 * Iterates through the list of known PCI devices.  If a PCI device is
225
 * found with a matching @vendor and @device, a pointer to its device structure is
226
 * returned.  Otherwise, %NULL is returned.
227
 * A new search is initiated by passing %NULL to the @from argument.
228
 * Otherwise if @from is not %NULL, searches continue from next device on the global list.
229
 *
230
 * Iterates through the list of known PCI devices.  If a PCI device is
231
 * found with a matching @vendor and @device, the reference count to the
232
 * device is incremented and a pointer to its device structure is returned.
233
 * Otherwise, %NULL is returned.  A new search is initiated by passing %NULL
234
 * to the @from argument.  Otherwise if @from is not %NULL, searches continue
235
 * from next device on the global list.  The reference count for @from is
236
 * always decremented if it is not %NULL.
237
 */
238
struct pci_dev *
239
pci_get_device(unsigned int vendor, unsigned int device, struct pci_dev *from)
240
{
241
        return pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
242
}
243
 
244
 
245
/**
246
 * pci_find_device_reverse - begin or continue searching for a PCI device by vendor/device id
247
 * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
248
 * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
249
 * @from: Previous PCI device found in search, or %NULL for new search.
250
 *
251
 * Iterates through the list of known PCI devices in the reverse order of pci_find_device().
252
 * If a PCI device is found with a matching @vendor and @device, a pointer to
253
 * its device structure is returned.  Otherwise, %NULL is returned.
254
 * A new search is initiated by passing %NULL to the @from argument.
255
 * Otherwise if @from is not %NULL, searches continue from previous device on the global list.
256
 */
257
struct pci_dev *
258
pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct pci_dev *from)
259
{
260
        struct list_head *n;
261
        struct pci_dev *dev;
262
 
263
        WARN_ON(in_interrupt());
264
        spin_lock(&pci_bus_lock);
265
        n = from ? from->global_list.prev : pci_devices.prev;
266
 
267
        while (n && (n != &pci_devices)) {
268
                dev = pci_dev_g(n);
269
                if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
270
                    (device == PCI_ANY_ID || dev->device == device))
271
                        goto exit;
272
                n = n->prev;
273
        }
274
        dev = NULL;
275
exit:
276
        spin_unlock(&pci_bus_lock);
277
        return dev;
278
}
279
 
280
 
281
/**
282
 * pci_find_class - begin or continue searching for a PCI device by class
283
 * @class: search for a PCI device with this class designation
284
 * @from: Previous PCI device found in search, or %NULL for new search.
285
 *
286
 * Iterates through the list of known PCI devices.  If a PCI device is
287
 * found with a matching @class, a pointer to its device structure is
288
 * 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 next device
291
 * on the global list.
292
 */
293
struct pci_dev *
294
pci_find_class(unsigned int class, const struct pci_dev *from)
295
{
296
        struct list_head *n;
297
        struct pci_dev *dev;
298
 
299
        spin_lock(&pci_bus_lock);
300
        n = from ? from->global_list.next : pci_devices.next;
301
 
302
        while (n && (n != &pci_devices)) {
303
                dev = pci_dev_g(n);
304
                if (dev->class == class)
305
                        goto exit;
306
                n = n->next;
307
        }
308
        dev = NULL;
309
exit:
310
        spin_unlock(&pci_bus_lock);
311
        return dev;
312
}
313
 
314
EXPORT_SYMBOL(pci_find_bus);
315
EXPORT_SYMBOL(pci_find_class);
316
EXPORT_SYMBOL(pci_find_device);
317
EXPORT_SYMBOL(pci_find_device_reverse);
318
EXPORT_SYMBOL(pci_find_slot);
319
EXPORT_SYMBOL(pci_find_subsys);
320
EXPORT_SYMBOL(pci_get_device);
321
EXPORT_SYMBOL(pci_get_subsys);