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