diff options
Diffstat (limited to 'drivers/base/bus.c')
-rw-r--r-- | drivers/base/bus.c | 133 |
1 files changed, 79 insertions, 54 deletions
diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 2e954d07175a..12173d16bea7 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c | |||
@@ -371,12 +371,20 @@ int bus_add_device(struct device * dev) | |||
371 | if (bus) { | 371 | if (bus) { |
372 | pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id); | 372 | pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id); |
373 | error = device_add_attrs(bus, dev); | 373 | error = device_add_attrs(bus, dev); |
374 | if (!error) { | 374 | if (error) |
375 | sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id); | 375 | goto out; |
376 | sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "subsystem"); | 376 | error = sysfs_create_link(&bus->devices.kobj, |
377 | sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "bus"); | 377 | &dev->kobj, dev->bus_id); |
378 | } | 378 | if (error) |
379 | goto out; | ||
380 | error = sysfs_create_link(&dev->kobj, | ||
381 | &dev->bus->subsys.kset.kobj, "subsystem"); | ||
382 | if (error) | ||
383 | goto out; | ||
384 | error = sysfs_create_link(&dev->kobj, | ||
385 | &dev->bus->subsys.kset.kobj, "bus"); | ||
379 | } | 386 | } |
387 | out: | ||
380 | return error; | 388 | return error; |
381 | } | 389 | } |
382 | 390 | ||
@@ -384,16 +392,24 @@ int bus_add_device(struct device * dev) | |||
384 | * bus_attach_device - add device to bus | 392 | * bus_attach_device - add device to bus |
385 | * @dev: device tried to attach to a driver | 393 | * @dev: device tried to attach to a driver |
386 | * | 394 | * |
395 | * - Add device to bus's list of devices. | ||
387 | * - Try to attach to driver. | 396 | * - Try to attach to driver. |
388 | */ | 397 | */ |
389 | void bus_attach_device(struct device * dev) | 398 | int bus_attach_device(struct device * dev) |
390 | { | 399 | { |
391 | struct bus_type * bus = dev->bus; | 400 | struct bus_type *bus = dev->bus; |
401 | int ret = 0; | ||
392 | 402 | ||
393 | if (bus) { | 403 | if (bus) { |
394 | device_attach(dev); | 404 | dev->is_registered = 1; |
395 | klist_add_tail(&dev->knode_bus, &bus->klist_devices); | 405 | ret = device_attach(dev); |
406 | if (ret >= 0) { | ||
407 | klist_add_tail(&dev->knode_bus, &bus->klist_devices); | ||
408 | ret = 0; | ||
409 | } else | ||
410 | dev->is_registered = 0; | ||
396 | } | 411 | } |
412 | return ret; | ||
397 | } | 413 | } |
398 | 414 | ||
399 | /** | 415 | /** |
@@ -412,7 +428,8 @@ void bus_remove_device(struct device * dev) | |||
412 | sysfs_remove_link(&dev->kobj, "bus"); | 428 | sysfs_remove_link(&dev->kobj, "bus"); |
413 | sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id); | 429 | sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id); |
414 | device_remove_attrs(dev->bus, dev); | 430 | device_remove_attrs(dev->bus, dev); |
415 | klist_remove(&dev->knode_bus); | 431 | dev->is_registered = 0; |
432 | klist_del(&dev->knode_bus); | ||
416 | pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id); | 433 | pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id); |
417 | device_release_driver(dev); | 434 | device_release_driver(dev); |
418 | put_bus(dev->bus); | 435 | put_bus(dev->bus); |
@@ -455,10 +472,17 @@ static void driver_remove_attrs(struct bus_type * bus, struct device_driver * dr | |||
455 | * Thanks to drivers making their tables __devinit, we can't allow manual | 472 | * Thanks to drivers making their tables __devinit, we can't allow manual |
456 | * bind and unbind from userspace unless CONFIG_HOTPLUG is enabled. | 473 | * bind and unbind from userspace unless CONFIG_HOTPLUG is enabled. |
457 | */ | 474 | */ |
458 | static void add_bind_files(struct device_driver *drv) | 475 | static int __must_check add_bind_files(struct device_driver *drv) |
459 | { | 476 | { |
460 | driver_create_file(drv, &driver_attr_unbind); | 477 | int ret; |
461 | driver_create_file(drv, &driver_attr_bind); | 478 | |
479 | ret = driver_create_file(drv, &driver_attr_unbind); | ||
480 | if (ret == 0) { | ||
481 | ret = driver_create_file(drv, &driver_attr_bind); | ||
482 | if (ret) | ||
483 | driver_remove_file(drv, &driver_attr_unbind); | ||
484 | } | ||
485 | return ret; | ||
462 | } | 486 | } |
463 | 487 | ||
464 | static void remove_bind_files(struct device_driver *drv) | 488 | static void remove_bind_files(struct device_driver *drv) |
@@ -467,7 +491,7 @@ static void remove_bind_files(struct device_driver *drv) | |||
467 | driver_remove_file(drv, &driver_attr_unbind); | 491 | driver_remove_file(drv, &driver_attr_unbind); |
468 | } | 492 | } |
469 | #else | 493 | #else |
470 | static inline void add_bind_files(struct device_driver *drv) {} | 494 | static inline int add_bind_files(struct device_driver *drv) { return 0; } |
471 | static inline void remove_bind_files(struct device_driver *drv) {} | 495 | static inline void remove_bind_files(struct device_driver *drv) {} |
472 | #endif | 496 | #endif |
473 | 497 | ||
@@ -476,7 +500,7 @@ static inline void remove_bind_files(struct device_driver *drv) {} | |||
476 | * @drv: driver. | 500 | * @drv: driver. |
477 | * | 501 | * |
478 | */ | 502 | */ |
479 | int bus_add_driver(struct device_driver * drv) | 503 | int bus_add_driver(struct device_driver *drv) |
480 | { | 504 | { |
481 | struct bus_type * bus = get_bus(drv->bus); | 505 | struct bus_type * bus = get_bus(drv->bus); |
482 | int error = 0; | 506 | int error = 0; |
@@ -484,27 +508,39 @@ int bus_add_driver(struct device_driver * drv) | |||
484 | if (bus) { | 508 | if (bus) { |
485 | pr_debug("bus %s: add driver %s\n", bus->name, drv->name); | 509 | pr_debug("bus %s: add driver %s\n", bus->name, drv->name); |
486 | error = kobject_set_name(&drv->kobj, "%s", drv->name); | 510 | error = kobject_set_name(&drv->kobj, "%s", drv->name); |
487 | if (error) { | 511 | if (error) |
488 | put_bus(bus); | 512 | goto out_put_bus; |
489 | return error; | ||
490 | } | ||
491 | drv->kobj.kset = &bus->drivers; | 513 | drv->kobj.kset = &bus->drivers; |
492 | if ((error = kobject_register(&drv->kobj))) { | 514 | if ((error = kobject_register(&drv->kobj))) |
493 | put_bus(bus); | 515 | goto out_put_bus; |
494 | return error; | ||
495 | } | ||
496 | 516 | ||
497 | driver_attach(drv); | 517 | error = driver_attach(drv); |
518 | if (error) | ||
519 | goto out_unregister; | ||
498 | klist_add_tail(&drv->knode_bus, &bus->klist_drivers); | 520 | klist_add_tail(&drv->knode_bus, &bus->klist_drivers); |
499 | module_add_driver(drv->owner, drv); | 521 | module_add_driver(drv->owner, drv); |
500 | 522 | ||
501 | driver_add_attrs(bus, drv); | 523 | error = driver_add_attrs(bus, drv); |
502 | add_bind_files(drv); | 524 | if (error) { |
525 | /* How the hell do we get out of this pickle? Give up */ | ||
526 | printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n", | ||
527 | __FUNCTION__, drv->name); | ||
528 | } | ||
529 | error = add_bind_files(drv); | ||
530 | if (error) { | ||
531 | /* Ditto */ | ||
532 | printk(KERN_ERR "%s: add_bind_files(%s) failed\n", | ||
533 | __FUNCTION__, drv->name); | ||
534 | } | ||
503 | } | 535 | } |
504 | return error; | 536 | return error; |
537 | out_unregister: | ||
538 | kobject_unregister(&drv->kobj); | ||
539 | out_put_bus: | ||
540 | put_bus(bus); | ||
541 | return error; | ||
505 | } | 542 | } |
506 | 543 | ||
507 | |||
508 | /** | 544 | /** |
509 | * bus_remove_driver - delete driver from bus's knowledge. | 545 | * bus_remove_driver - delete driver from bus's knowledge. |
510 | * @drv: driver. | 546 | * @drv: driver. |
@@ -530,16 +566,21 @@ void bus_remove_driver(struct device_driver * drv) | |||
530 | 566 | ||
531 | 567 | ||
532 | /* Helper for bus_rescan_devices's iter */ | 568 | /* Helper for bus_rescan_devices's iter */ |
533 | static int bus_rescan_devices_helper(struct device *dev, void *data) | 569 | static int __must_check bus_rescan_devices_helper(struct device *dev, |
570 | void *data) | ||
534 | { | 571 | { |
572 | int ret = 0; | ||
573 | |||
535 | if (!dev->driver) { | 574 | if (!dev->driver) { |
536 | if (dev->parent) /* Needed for USB */ | 575 | if (dev->parent) /* Needed for USB */ |
537 | down(&dev->parent->sem); | 576 | down(&dev->parent->sem); |
538 | device_attach(dev); | 577 | ret = device_attach(dev); |
539 | if (dev->parent) | 578 | if (dev->parent) |
540 | up(&dev->parent->sem); | 579 | up(&dev->parent->sem); |
580 | if (ret > 0) | ||
581 | ret = 0; | ||
541 | } | 582 | } |
542 | return 0; | 583 | return ret < 0 ? ret : 0; |
543 | } | 584 | } |
544 | 585 | ||
545 | /** | 586 | /** |
@@ -550,9 +591,9 @@ static int bus_rescan_devices_helper(struct device *dev, void *data) | |||
550 | * attached and rescan it against existing drivers to see if it matches | 591 | * attached and rescan it against existing drivers to see if it matches |
551 | * any by calling device_attach() for the unbound devices. | 592 | * any by calling device_attach() for the unbound devices. |
552 | */ | 593 | */ |
553 | void bus_rescan_devices(struct bus_type * bus) | 594 | int bus_rescan_devices(struct bus_type * bus) |
554 | { | 595 | { |
555 | bus_for_each_dev(bus, NULL, NULL, bus_rescan_devices_helper); | 596 | return bus_for_each_dev(bus, NULL, NULL, bus_rescan_devices_helper); |
556 | } | 597 | } |
557 | 598 | ||
558 | /** | 599 | /** |
@@ -564,7 +605,7 @@ void bus_rescan_devices(struct bus_type * bus) | |||
564 | * to use if probing criteria changed during a devices lifetime and | 605 | * to use if probing criteria changed during a devices lifetime and |
565 | * driver attachment should change accordingly. | 606 | * driver attachment should change accordingly. |
566 | */ | 607 | */ |
567 | void device_reprobe(struct device *dev) | 608 | int device_reprobe(struct device *dev) |
568 | { | 609 | { |
569 | if (dev->driver) { | 610 | if (dev->driver) { |
570 | if (dev->parent) /* Needed for USB */ | 611 | if (dev->parent) /* Needed for USB */ |
@@ -573,14 +614,14 @@ void device_reprobe(struct device *dev) | |||
573 | if (dev->parent) | 614 | if (dev->parent) |
574 | up(&dev->parent->sem); | 615 | up(&dev->parent->sem); |
575 | } | 616 | } |
576 | 617 | return bus_rescan_devices_helper(dev, NULL); | |
577 | bus_rescan_devices_helper(dev, NULL); | ||
578 | } | 618 | } |
579 | EXPORT_SYMBOL_GPL(device_reprobe); | 619 | EXPORT_SYMBOL_GPL(device_reprobe); |
580 | 620 | ||
581 | struct bus_type * get_bus(struct bus_type * bus) | 621 | struct bus_type *get_bus(struct bus_type *bus) |
582 | { | 622 | { |
583 | return bus ? container_of(subsys_get(&bus->subsys), struct bus_type, subsys) : NULL; | 623 | return bus ? container_of(subsys_get(&bus->subsys), |
624 | struct bus_type, subsys) : NULL; | ||
584 | } | 625 | } |
585 | 626 | ||
586 | void put_bus(struct bus_type * bus) | 627 | void put_bus(struct bus_type * bus) |
@@ -655,22 +696,6 @@ static void klist_devices_put(struct klist_node *n) | |||
655 | put_device(dev); | 696 | put_device(dev); |
656 | } | 697 | } |
657 | 698 | ||
658 | static void klist_drivers_get(struct klist_node *n) | ||
659 | { | ||
660 | struct device_driver *drv = container_of(n, struct device_driver, | ||
661 | knode_bus); | ||
662 | |||
663 | get_driver(drv); | ||
664 | } | ||
665 | |||
666 | static void klist_drivers_put(struct klist_node *n) | ||
667 | { | ||
668 | struct device_driver *drv = container_of(n, struct device_driver, | ||
669 | knode_bus); | ||
670 | |||
671 | put_driver(drv); | ||
672 | } | ||
673 | |||
674 | /** | 699 | /** |
675 | * bus_register - register a bus with the system. | 700 | * bus_register - register a bus with the system. |
676 | * @bus: bus. | 701 | * @bus: bus. |
@@ -706,7 +731,7 @@ int bus_register(struct bus_type * bus) | |||
706 | goto bus_drivers_fail; | 731 | goto bus_drivers_fail; |
707 | 732 | ||
708 | klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put); | 733 | klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put); |
709 | klist_init(&bus->klist_drivers, klist_drivers_get, klist_drivers_put); | 734 | klist_init(&bus->klist_drivers, NULL, NULL); |
710 | bus_add_attrs(bus); | 735 | bus_add_attrs(bus); |
711 | 736 | ||
712 | pr_debug("bus type '%s' registered\n", bus->name); | 737 | pr_debug("bus type '%s' registered\n", bus->name); |