diff options
Diffstat (limited to 'drivers/uwb/umc-bus.c')
| -rw-r--r-- | drivers/uwb/umc-bus.c | 80 |
1 files changed, 54 insertions, 26 deletions
diff --git a/drivers/uwb/umc-bus.c b/drivers/uwb/umc-bus.c index 2d8d62d9f53..88a290f57ea 100644 --- a/drivers/uwb/umc-bus.c +++ b/drivers/uwb/umc-bus.c @@ -8,26 +8,52 @@ #include <linux/kernel.h> #include <linux/sysfs.h> #include <linux/workqueue.h> +#include <linux/module.h> #include <linux/uwb/umc.h> #include <linux/pci.h> -static int umc_bus_unbind_helper(struct device *dev, void *data) +static int umc_bus_pre_reset_helper(struct device *dev, void *data) { - struct device *parent = data; + int ret = 0; - if (dev->parent == parent && dev->driver) - device_release_driver(dev); - return 0; + if (dev->driver) { + struct umc_dev *umc = to_umc_dev(dev); + struct umc_driver *umc_drv = to_umc_driver(dev->driver); + + if (umc_drv->pre_reset) + ret = umc_drv->pre_reset(umc); + else + device_release_driver(dev); + } + return ret; +} + +static int umc_bus_post_reset_helper(struct device *dev, void *data) +{ + int ret = 0; + + if (dev->driver) { + struct umc_dev *umc = to_umc_dev(dev); + struct umc_driver *umc_drv = to_umc_driver(dev->driver); + + if (umc_drv->post_reset) + ret = umc_drv->post_reset(umc); + } else + ret = device_attach(dev); + + return ret; } /** * umc_controller_reset - reset the whole UMC controller * @umc: the UMC device for the radio controller. * - * Drivers will be unbound from all UMC devices belonging to the - * controller and then the radio controller will be rebound. The - * radio controller is expected to do a full hardware reset when it is - * probed. + * Drivers or all capabilities of the controller will have their + * pre_reset methods called or be unbound from their device. Then all + * post_reset methods will be called or the drivers will be rebound. + * + * Radio controllers must provide pre_reset and post_reset methods and + * reset the hardware in their start method. * * If this is called while a probe() or remove() is in progress it * will return -EAGAIN and not perform the reset. @@ -35,15 +61,14 @@ static int umc_bus_unbind_helper(struct device *dev, void *data) int umc_controller_reset(struct umc_dev *umc) { struct device *parent = umc->dev.parent; - int ret; + int ret = 0; - if (down_trylock(&parent->sem)) + if (!device_trylock(parent)) return -EAGAIN; - bus_for_each_dev(&umc_bus_type, NULL, parent, umc_bus_unbind_helper); - ret = device_attach(&umc->dev); - if (ret == 1) - ret = 0; - up(&parent->sem); + ret = device_for_each_child(parent, parent, umc_bus_pre_reset_helper); + if (ret >= 0) + ret = device_for_each_child(parent, parent, umc_bus_post_reset_helper); + device_unlock(parent); return ret; } @@ -60,7 +85,7 @@ int umc_match_pci_id(struct umc_driver *umc_drv, struct umc_dev *umc) const struct pci_device_id *id_table = umc_drv->match_data; struct pci_dev *pci; - if (umc->dev.parent->bus != &pci_bus_type) + if (!dev_is_pci(umc->dev.parent)) return 0; pci = to_pci_dev(umc->dev.parent); @@ -75,10 +100,10 @@ static int umc_bus_rescan_helper(struct device *dev, void *data) if (!dev->driver) ret = device_attach(dev); - return ret < 0 ? ret : 0; + return ret; } -static void umc_bus_rescan(void) +static void umc_bus_rescan(struct device *parent) { int err; @@ -86,7 +111,7 @@ static void umc_bus_rescan(void) * We can't use bus_rescan_devices() here as it deadlocks when * it tries to retake the dev->parent semaphore. */ - err = bus_for_each_dev(&umc_bus_type, NULL, NULL, umc_bus_rescan_helper); + err = device_for_each_child(parent, NULL, umc_bus_rescan_helper); if (err < 0) printk(KERN_WARNING "%s: rescan of bus failed: %d\n", KBUILD_MODNAME, err); @@ -120,7 +145,7 @@ static int umc_device_probe(struct device *dev) if (err) put_device(dev); else - umc_bus_rescan(); + umc_bus_rescan(dev->parent); return err; } @@ -176,6 +201,7 @@ static ssize_t capability_id_show(struct device *dev, struct device_attribute *a return sprintf(buf, "0x%02x\n", umc->cap_id); } +static DEVICE_ATTR_RO(capability_id); static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -183,12 +209,14 @@ static ssize_t version_show(struct device *dev, struct device_attribute *attr, c return sprintf(buf, "0x%04x\n", umc->version); } +static DEVICE_ATTR_RO(version); -static struct device_attribute umc_dev_attrs[] = { - __ATTR_RO(capability_id), - __ATTR_RO(version), - __ATTR_NULL, +static struct attribute *umc_dev_attrs[] = { + &dev_attr_capability_id.attr, + &dev_attr_version.attr, + NULL, }; +ATTRIBUTE_GROUPS(umc_dev); struct bus_type umc_bus_type = { .name = "umc", @@ -197,7 +225,7 @@ struct bus_type umc_bus_type = { .remove = umc_device_remove, .suspend = umc_device_suspend, .resume = umc_device_resume, - .dev_attrs = umc_dev_attrs, + .dev_groups = umc_dev_groups, }; EXPORT_SYMBOL_GPL(umc_bus_type); |
