Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
428 | giacomo | 1 | /* |
2 | * drivers/pci/pci-driver.c |
||
3 | * |
||
4 | */ |
||
5 | |||
6 | #include <linux/pci.h> |
||
7 | #include <linux/module.h> |
||
8 | #include <linux/init.h> |
||
9 | #include <linux/device.h> |
||
10 | #include <linux/pci-dynids.h> |
||
11 | #include "pci.h" |
||
12 | |||
13 | /* |
||
14 | * Registration of PCI drivers and handling of hot-pluggable devices. |
||
15 | */ |
||
16 | |||
17 | /** |
||
18 | * pci_match_one_device - Tell if a PCI device structure has a matching |
||
19 | * PCI device id structure |
||
20 | * @id: single PCI device id structure to match |
||
21 | * @dev: the PCI device structure to match against |
||
22 | * |
||
23 | * Returns the matching pci_device_id structure or %NULL if there is no match. |
||
24 | */ |
||
25 | |||
26 | static inline const struct pci_device_id * |
||
27 | pci_match_one_device(const struct pci_device_id *id, const struct pci_dev *dev) |
||
28 | { |
||
29 | if ((id->vendor == PCI_ANY_ID || id->vendor == dev->vendor) && |
||
30 | (id->device == PCI_ANY_ID || id->device == dev->device) && |
||
31 | (id->subvendor == PCI_ANY_ID || id->subvendor == dev->subsystem_vendor) && |
||
32 | (id->subdevice == PCI_ANY_ID || id->subdevice == dev->subsystem_device) && |
||
33 | !((id->class ^ dev->class) & id->class_mask)) |
||
34 | return id; |
||
35 | return NULL; |
||
36 | } |
||
37 | |||
38 | /* |
||
39 | * Dynamic device IDs are disabled for !CONFIG_HOTPLUG |
||
40 | */ |
||
41 | |||
42 | #ifdef CONFIG_HOTPLUG |
||
43 | /** |
||
44 | * pci_device_probe_dynamic() |
||
45 | * |
||
46 | * Walk the dynamic ID list looking for a match. |
||
47 | * returns 0 and sets pci_dev->driver when drv claims pci_dev, else error. |
||
48 | */ |
||
49 | static int |
||
50 | pci_device_probe_dynamic(struct pci_driver *drv, struct pci_dev *pci_dev) |
||
51 | { |
||
52 | int error = -ENODEV; |
||
53 | struct list_head *pos; |
||
54 | struct dynid *dynid; |
||
55 | |||
56 | spin_lock(&drv->dynids.lock); |
||
57 | list_for_each(pos, &drv->dynids.list) { |
||
58 | dynid = list_entry(pos, struct dynid, node); |
||
59 | if (pci_match_one_device(&dynid->id, pci_dev)) { |
||
60 | spin_unlock(&drv->dynids.lock); |
||
61 | error = drv->probe(pci_dev, &dynid->id); |
||
62 | if (error >= 0) { |
||
63 | pci_dev->driver = drv; |
||
64 | return 0; |
||
65 | } |
||
66 | return error; |
||
67 | } |
||
68 | } |
||
69 | spin_unlock(&drv->dynids.lock); |
||
70 | return error; |
||
71 | } |
||
72 | |||
73 | static inline void |
||
74 | dynid_init(struct dynid *dynid) |
||
75 | { |
||
76 | memset(dynid, 0, sizeof(*dynid)); |
||
77 | INIT_LIST_HEAD(&dynid->node); |
||
78 | } |
||
79 | |||
80 | /** |
||
81 | * store_new_id |
||
82 | * |
||
83 | * Adds a new dynamic pci device ID to this driver, |
||
84 | * and causes the driver to probe for all devices again. |
||
85 | */ |
||
86 | static inline ssize_t |
||
87 | store_new_id(struct device_driver *driver, const char *buf, size_t count) |
||
88 | { |
||
89 | struct dynid *dynid; |
||
90 | struct bus_type * bus; |
||
91 | struct pci_driver *pdrv = to_pci_driver(driver); |
||
92 | __u32 vendor=PCI_ANY_ID, device=PCI_ANY_ID, subvendor=PCI_ANY_ID, |
||
93 | subdevice=PCI_ANY_ID, class=0, class_mask=0; |
||
94 | unsigned long driver_data=0; |
||
95 | int fields=0; |
||
96 | |||
97 | fields = sscanf(buf, "%x %x %x %x %x %x %lux", |
||
98 | &vendor, &device, &subvendor, &subdevice, |
||
99 | &class, &class_mask, &driver_data); |
||
100 | if (fields < 0) |
||
101 | return -EINVAL; |
||
102 | |||
103 | dynid = kmalloc(sizeof(*dynid), GFP_KERNEL); |
||
104 | if (!dynid) |
||
105 | return -ENOMEM; |
||
106 | dynid_init(dynid); |
||
107 | |||
108 | dynid->id.vendor = vendor; |
||
109 | dynid->id.device = device; |
||
110 | dynid->id.subvendor = subvendor; |
||
111 | dynid->id.subdevice = subdevice; |
||
112 | dynid->id.class = class; |
||
113 | dynid->id.class_mask = class_mask; |
||
114 | dynid->id.driver_data = pdrv->dynids.use_driver_data ? |
||
115 | driver_data : 0UL; |
||
116 | |||
117 | spin_lock(&pdrv->dynids.lock); |
||
118 | list_add_tail(&pdrv->dynids.list, &dynid->node); |
||
119 | spin_unlock(&pdrv->dynids.lock); |
||
120 | |||
121 | bus = get_bus(pdrv->driver.bus); |
||
122 | if (bus) { |
||
123 | if (get_driver(&pdrv->driver)) { |
||
124 | down_write(&bus->subsys.rwsem); |
||
125 | driver_attach(&pdrv->driver); |
||
126 | up_write(&bus->subsys.rwsem); |
||
127 | put_driver(&pdrv->driver); |
||
128 | } |
||
129 | put_bus(bus); |
||
130 | } |
||
131 | |||
132 | return count; |
||
133 | } |
||
134 | |||
135 | static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id); |
||
136 | static inline void |
||
137 | pci_init_dynids(struct pci_dynids *dynids) |
||
138 | { |
||
139 | memset(dynids, 0, sizeof(*dynids)); |
||
140 | spin_lock_init(&dynids->lock); |
||
141 | INIT_LIST_HEAD(&dynids->list); |
||
142 | } |
||
143 | |||
144 | static void |
||
145 | pci_free_dynids(struct pci_driver *drv) |
||
146 | { |
||
147 | struct list_head *pos, *n; |
||
148 | struct dynid *dynid; |
||
149 | |||
150 | spin_lock(&drv->dynids.lock); |
||
151 | list_for_each_safe(pos, n, &drv->dynids.list) { |
||
152 | dynid = list_entry(pos, struct dynid, node); |
||
153 | list_del(&dynid->node); |
||
154 | kfree(dynid); |
||
155 | } |
||
156 | spin_unlock(&drv->dynids.lock); |
||
157 | } |
||
158 | |||
159 | static int |
||
160 | pci_create_newid_file(struct pci_driver *drv) |
||
161 | { |
||
162 | int error = 0; |
||
163 | if (drv->probe != NULL) |
||
164 | error = sysfs_create_file(&drv->driver.kobj, |
||
165 | &driver_attr_new_id.attr); |
||
166 | return error; |
||
167 | } |
||
168 | |||
169 | static int |
||
170 | pci_bus_match_dynids(const struct pci_dev *pci_dev, struct pci_driver *pci_drv) |
||
171 | { |
||
172 | struct list_head *pos; |
||
173 | struct dynid *dynid; |
||
174 | |||
175 | spin_lock(&pci_drv->dynids.lock); |
||
176 | list_for_each(pos, &pci_drv->dynids.list) { |
||
177 | dynid = list_entry(pos, struct dynid, node); |
||
178 | if (pci_match_one_device(&dynid->id, pci_dev)) { |
||
179 | spin_unlock(&pci_drv->dynids.lock); |
||
180 | return 1; |
||
181 | } |
||
182 | } |
||
183 | spin_unlock(&pci_drv->dynids.lock); |
||
184 | return 0; |
||
185 | } |
||
186 | |||
187 | #else /* !CONFIG_HOTPLUG */ |
||
188 | static inline int pci_device_probe_dynamic(struct pci_driver *drv, struct pci_dev *pci_dev) |
||
189 | { |
||
190 | return -ENODEV; |
||
191 | } |
||
192 | static inline void dynid_init(struct dynid *dynid) {} |
||
193 | static inline void pci_init_dynids(struct pci_dynids *dynids) {} |
||
194 | static inline void pci_free_dynids(struct pci_driver *drv) {} |
||
195 | static inline int pci_create_newid_file(struct pci_driver *drv) |
||
196 | { |
||
197 | return 0; |
||
198 | } |
||
199 | static inline int pci_bus_match_dynids(const struct pci_dev *pci_dev, struct pci_driver *pci_drv) |
||
200 | { |
||
201 | return 0; |
||
202 | } |
||
203 | #endif |
||
204 | |||
205 | /** |
||
206 | * pci_match_device - Tell if a PCI device structure has a matching |
||
207 | * PCI device id structure |
||
208 | * @ids: array of PCI device id structures to search in |
||
209 | * @dev: the PCI device structure to match against |
||
210 | * |
||
211 | * Used by a driver to check whether a PCI device present in the |
||
212 | * system is in its list of supported devices.Returns the matching |
||
213 | * pci_device_id structure or %NULL if there is no match. |
||
214 | */ |
||
215 | const struct pci_device_id * |
||
216 | pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev) |
||
217 | { |
||
218 | while (ids->vendor || ids->subvendor || ids->class_mask) { |
||
219 | if (pci_match_one_device(ids, dev)) |
||
220 | return ids; |
||
221 | ids++; |
||
222 | } |
||
223 | return NULL; |
||
224 | } |
||
225 | |||
226 | /** |
||
227 | * pci_device_probe_static() |
||
228 | * |
||
229 | * returns 0 and sets pci_dev->driver when drv claims pci_dev, else error. |
||
230 | */ |
||
231 | static int |
||
232 | pci_device_probe_static(struct pci_driver *drv, struct pci_dev *pci_dev) |
||
233 | { |
||
234 | int error = -ENODEV; |
||
235 | const struct pci_device_id *id; |
||
236 | |||
237 | if (!drv->id_table) |
||
238 | return error; |
||
239 | id = pci_match_device(drv->id_table, pci_dev); |
||
240 | if (id) |
||
241 | error = drv->probe(pci_dev, id); |
||
242 | if (error >= 0) { |
||
243 | pci_dev->driver = drv; |
||
244 | return 0; |
||
245 | } |
||
246 | return error; |
||
247 | } |
||
248 | |||
249 | /** |
||
250 | * __pci_device_probe() |
||
251 | * |
||
252 | * returns 0 on success, else error. |
||
253 | * side-effect: pci_dev->driver is set to drv when drv claims pci_dev. |
||
254 | */ |
||
255 | static int |
||
256 | __pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev) |
||
257 | { |
||
258 | int error = 0; |
||
259 | |||
260 | if (!pci_dev->driver && drv->probe) { |
||
261 | error = pci_device_probe_static(drv, pci_dev); |
||
262 | if (error == -ENODEV) |
||
263 | error = pci_device_probe_dynamic(drv, pci_dev); |
||
264 | } |
||
265 | return error; |
||
266 | } |
||
267 | |||
268 | static int pci_device_probe(struct device * dev) |
||
269 | { |
||
270 | int error = 0; |
||
271 | struct pci_driver *drv; |
||
272 | struct pci_dev *pci_dev; |
||
273 | |||
274 | drv = to_pci_driver(dev->driver); |
||
275 | pci_dev = to_pci_dev(dev); |
||
276 | pci_dev_get(pci_dev); |
||
277 | error = __pci_device_probe(drv, pci_dev); |
||
278 | if (error) |
||
279 | pci_dev_put(pci_dev); |
||
280 | |||
281 | return error; |
||
282 | } |
||
283 | |||
284 | static int pci_device_remove(struct device * dev) |
||
285 | { |
||
286 | struct pci_dev * pci_dev = to_pci_dev(dev); |
||
287 | struct pci_driver * drv = pci_dev->driver; |
||
288 | |||
289 | if (drv) { |
||
290 | if (drv->remove) |
||
291 | drv->remove(pci_dev); |
||
292 | pci_dev->driver = NULL; |
||
293 | } |
||
294 | pci_dev_put(pci_dev); |
||
295 | return 0; |
||
296 | } |
||
297 | |||
298 | static int pci_device_suspend(struct device * dev, u32 state) |
||
299 | { |
||
300 | struct pci_dev * pci_dev = to_pci_dev(dev); |
||
301 | struct pci_driver * drv = pci_dev->driver; |
||
302 | |||
303 | if (drv && drv->suspend) |
||
304 | return drv->suspend(pci_dev,state); |
||
305 | return 0; |
||
306 | } |
||
307 | |||
308 | static int pci_device_resume(struct device * dev) |
||
309 | { |
||
310 | struct pci_dev * pci_dev = to_pci_dev(dev); |
||
311 | struct pci_driver * drv = pci_dev->driver; |
||
312 | |||
313 | if (drv && drv->resume) |
||
314 | drv->resume(pci_dev); |
||
315 | return 0; |
||
316 | } |
||
317 | |||
318 | |||
319 | #define kobj_to_pci_driver(obj) container_of(obj, struct device_driver, kobj) |
||
320 | #define attr_to_driver_attribute(obj) container_of(obj, struct driver_attribute, attr) |
||
321 | |||
322 | static ssize_t |
||
323 | pci_driver_attr_show(struct kobject * kobj, struct attribute *attr, char *buf) |
||
324 | { |
||
325 | struct device_driver *driver = kobj_to_pci_driver(kobj); |
||
326 | struct driver_attribute *dattr = attr_to_driver_attribute(attr); |
||
327 | ssize_t ret = 0; |
||
328 | |||
329 | if (get_driver(driver)) { |
||
330 | if (dattr->show) |
||
331 | ret = dattr->show(driver, buf); |
||
332 | put_driver(driver); |
||
333 | } |
||
334 | return ret; |
||
335 | } |
||
336 | |||
337 | static ssize_t |
||
338 | pci_driver_attr_store(struct kobject * kobj, struct attribute *attr, |
||
339 | const char *buf, size_t count) |
||
340 | { |
||
341 | struct device_driver *driver = kobj_to_pci_driver(kobj); |
||
342 | struct driver_attribute *dattr = attr_to_driver_attribute(attr); |
||
343 | ssize_t ret = 0; |
||
344 | |||
345 | if (get_driver(driver)) { |
||
346 | if (dattr->store) |
||
347 | ret = dattr->store(driver, buf, count); |
||
348 | put_driver(driver); |
||
349 | } |
||
350 | return ret; |
||
351 | } |
||
352 | |||
353 | static struct sysfs_ops pci_driver_sysfs_ops = { |
||
354 | .show = pci_driver_attr_show, |
||
355 | .store = pci_driver_attr_store, |
||
356 | }; |
||
357 | static struct kobj_type pci_driver_kobj_type = { |
||
358 | .sysfs_ops = &pci_driver_sysfs_ops, |
||
359 | }; |
||
360 | |||
361 | static int |
||
362 | pci_populate_driver_dir(struct pci_driver *drv) |
||
363 | { |
||
364 | return pci_create_newid_file(drv); |
||
365 | } |
||
366 | |||
367 | /** |
||
368 | * pci_register_driver - register a new pci driver |
||
369 | * @drv: the driver structure to register |
||
370 | * |
||
371 | * Adds the driver structure to the list of registered drivers |
||
372 | * Returns the number of pci devices which were claimed by the driver |
||
373 | * during registration. The driver remains registered even if the |
||
374 | * return value is zero. |
||
375 | */ |
||
376 | int |
||
377 | pci_register_driver(struct pci_driver *drv) |
||
378 | { |
||
379 | int count = 0; |
||
380 | |||
381 | /* initialize common driver fields */ |
||
382 | drv->driver.name = drv->name; |
||
383 | drv->driver.bus = &pci_bus_type; |
||
384 | drv->driver.probe = pci_device_probe; |
||
385 | drv->driver.remove = pci_device_remove; |
||
386 | drv->driver.kobj.ktype = &pci_driver_kobj_type; |
||
387 | pci_init_dynids(&drv->dynids); |
||
388 | |||
389 | /* register with core */ |
||
390 | count = driver_register(&drv->driver); |
||
391 | |||
392 | if (count >= 0) { |
||
393 | pci_populate_driver_dir(drv); |
||
394 | } |
||
395 | |||
396 | return count ? count : 1; |
||
397 | } |
||
398 | |||
399 | /** |
||
400 | * pci_unregister_driver - unregister a pci driver |
||
401 | * @drv: the driver structure to unregister |
||
402 | * |
||
403 | * Deletes the driver structure from the list of registered PCI drivers, |
||
404 | * gives it a chance to clean up by calling its remove() function for |
||
405 | * each device it was responsible for, and marks those devices as |
||
406 | * driverless. |
||
407 | */ |
||
408 | |||
409 | void |
||
410 | pci_unregister_driver(struct pci_driver *drv) |
||
411 | { |
||
412 | driver_unregister(&drv->driver); |
||
413 | pci_free_dynids(drv); |
||
414 | } |
||
415 | |||
416 | static struct pci_driver pci_compat_driver = { |
||
417 | .name = "compat" |
||
418 | }; |
||
419 | |||
420 | /** |
||
421 | * pci_dev_driver - get the pci_driver of a device |
||
422 | * @dev: the device to query |
||
423 | * |
||
424 | * Returns the appropriate pci_driver structure or %NULL if there is no |
||
425 | * registered driver for the device. |
||
426 | */ |
||
427 | struct pci_driver * |
||
428 | pci_dev_driver(const struct pci_dev *dev) |
||
429 | { |
||
430 | if (dev->driver) |
||
431 | return dev->driver; |
||
432 | else { |
||
433 | int i; |
||
434 | for(i=0; i<=PCI_ROM_RESOURCE; i++) |
||
435 | if (dev->resource[i].flags & IORESOURCE_BUSY) |
||
436 | return &pci_compat_driver; |
||
437 | } |
||
438 | return NULL; |
||
439 | } |
||
440 | |||
441 | /** |
||
442 | * pci_bus_match - Tell if a PCI device structure has a matching PCI device id structure |
||
443 | * @ids: array of PCI device id structures to search in |
||
444 | * @dev: the PCI device structure to match against |
||
445 | * |
||
446 | * Used by a driver to check whether a PCI device present in the |
||
447 | * system is in its list of supported devices.Returns the matching |
||
448 | * pci_device_id structure or %NULL if there is no match. |
||
449 | */ |
||
450 | static int pci_bus_match(struct device * dev, struct device_driver * drv) |
||
451 | { |
||
452 | const struct pci_dev * pci_dev = to_pci_dev(dev); |
||
453 | struct pci_driver * pci_drv = to_pci_driver(drv); |
||
454 | const struct pci_device_id * ids = pci_drv->id_table; |
||
455 | const struct pci_device_id *found_id; |
||
456 | |||
457 | if (!ids) |
||
458 | return 0; |
||
459 | |||
460 | found_id = pci_match_device(ids, pci_dev); |
||
461 | if (found_id) |
||
462 | return 1; |
||
463 | |||
464 | return pci_bus_match_dynids(pci_dev, pci_drv); |
||
465 | } |
||
466 | |||
467 | /** |
||
468 | * pci_dev_get - increments the reference count of the pci device structure |
||
469 | * @dev: the device being referenced |
||
470 | * |
||
471 | * Each live reference to a device should be refcounted. |
||
472 | * |
||
473 | * Drivers for PCI devices should normally record such references in |
||
474 | * their probe() methods, when they bind to a device, and release |
||
475 | * them by calling pci_dev_put(), in their disconnect() methods. |
||
476 | * |
||
477 | * A pointer to the device with the incremented reference counter is returned. |
||
478 | */ |
||
479 | struct pci_dev *pci_dev_get(struct pci_dev *dev) |
||
480 | { |
||
481 | struct device *tmp; |
||
482 | |||
483 | if (!dev) |
||
484 | return NULL; |
||
485 | |||
486 | tmp = get_device(&dev->dev); |
||
487 | if (tmp) |
||
488 | return to_pci_dev(tmp); |
||
489 | else |
||
490 | return NULL; |
||
491 | } |
||
492 | |||
493 | /** |
||
494 | * pci_dev_put - release a use of the pci device structure |
||
495 | * @dev: device that's been disconnected |
||
496 | * |
||
497 | * Must be called when a user of a device is finished with it. When the last |
||
498 | * user of the device calls this function, the memory of the device is freed. |
||
499 | */ |
||
500 | void pci_dev_put(struct pci_dev *dev) |
||
501 | { |
||
502 | if (dev) |
||
503 | put_device(&dev->dev); |
||
504 | } |
||
505 | |||
506 | #ifndef CONFIG_HOTPLUG |
||
507 | int pci_hotplug (struct device *dev, char **envp, int num_envp, |
||
508 | char *buffer, int buffer_size) |
||
509 | { |
||
510 | return -ENODEV; |
||
511 | } |
||
512 | #endif |
||
513 | |||
514 | struct bus_type pci_bus_type = { |
||
515 | .name = "pci", |
||
516 | .match = pci_bus_match, |
||
517 | .hotplug = pci_hotplug, |
||
518 | .suspend = pci_device_suspend, |
||
519 | .resume = pci_device_resume, |
||
520 | }; |
||
521 | |||
522 | static int __init pci_driver_init(void) |
||
523 | { |
||
524 | return bus_register(&pci_bus_type); |
||
525 | } |
||
526 | |||
527 | postcore_initcall(pci_driver_init); |
||
528 | |||
529 | EXPORT_SYMBOL(pci_match_device); |
||
530 | EXPORT_SYMBOL(pci_register_driver); |
||
531 | EXPORT_SYMBOL(pci_unregister_driver); |
||
532 | EXPORT_SYMBOL(pci_dev_driver); |
||
533 | EXPORT_SYMBOL(pci_bus_type); |
||
534 | EXPORT_SYMBOL(pci_dev_get); |
||
535 | EXPORT_SYMBOL(pci_dev_put); |