linux/drivers/uwb/umc-bus.c
<<
>>
Prefs
   1/*
   2 * Bus for UWB Multi-interface Controller capabilities.
   3 *
   4 * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
   5 *
   6 * This file is released under the GNU GPL v2.
   7 */
   8#include <linux/kernel.h>
   9#include <linux/sysfs.h>
  10#include <linux/workqueue.h>
  11#include <linux/uwb/umc.h>
  12#include <linux/pci.h>
  13
  14static int umc_bus_pre_reset_helper(struct device *dev, void *data)
  15{
  16        int ret = 0;
  17
  18        if (dev->driver) {
  19                struct umc_dev *umc = to_umc_dev(dev);
  20                struct umc_driver *umc_drv = to_umc_driver(dev->driver);
  21
  22                if (umc_drv->pre_reset)
  23                        ret = umc_drv->pre_reset(umc);
  24                else
  25                        device_release_driver(dev);
  26        }
  27        return ret;
  28}
  29
  30static int umc_bus_post_reset_helper(struct device *dev, void *data)
  31{
  32        int ret = 0;
  33
  34        if (dev->driver) {
  35                struct umc_dev *umc = to_umc_dev(dev);
  36                struct umc_driver *umc_drv = to_umc_driver(dev->driver);
  37
  38                if (umc_drv->post_reset)
  39                        ret = umc_drv->post_reset(umc);
  40        } else
  41                ret = device_attach(dev);
  42
  43        return ret;
  44}
  45
  46/**
  47 * umc_controller_reset - reset the whole UMC controller
  48 * @umc: the UMC device for the radio controller.
  49 *
  50 * Drivers or all capabilities of the controller will have their
  51 * pre_reset methods called or be unbound from their device.  Then all
  52 * post_reset methods will be called or the drivers will be rebound.
  53 *
  54 * Radio controllers must provide pre_reset and post_reset methods and
  55 * reset the hardware in their start method.
  56 *
  57 * If this is called while a probe() or remove() is in progress it
  58 * will return -EAGAIN and not perform the reset.
  59 */
  60int umc_controller_reset(struct umc_dev *umc)
  61{
  62        struct device *parent = umc->dev.parent;
  63        int ret = 0;
  64
  65        if (device_trylock(parent))
  66                return -EAGAIN;
  67        ret = device_for_each_child(parent, parent, umc_bus_pre_reset_helper);
  68        if (ret >= 0)
  69                ret = device_for_each_child(parent, parent, umc_bus_post_reset_helper);
  70        device_unlock(parent);
  71
  72        return ret;
  73}
  74EXPORT_SYMBOL_GPL(umc_controller_reset);
  75
  76/**
  77 * umc_match_pci_id - match a UMC driver to a UMC device's parent PCI device.
  78 * @umc_drv: umc driver with match_data pointing to a zero-terminated
  79 * table of pci_device_id's.
  80 * @umc: umc device whose parent is to be matched.
  81 */
  82int umc_match_pci_id(struct umc_driver *umc_drv, struct umc_dev *umc)
  83{
  84        const struct pci_device_id *id_table = umc_drv->match_data;
  85        struct pci_dev *pci;
  86
  87        if (umc->dev.parent->bus != &pci_bus_type)
  88                return 0;
  89
  90        pci = to_pci_dev(umc->dev.parent);
  91        return pci_match_id(id_table, pci) != NULL;
  92}
  93EXPORT_SYMBOL_GPL(umc_match_pci_id);
  94
  95static int umc_bus_rescan_helper(struct device *dev, void *data)
  96{
  97        int ret = 0;
  98
  99        if (!dev->driver)
 100                ret = device_attach(dev);
 101
 102        return ret;
 103}
 104
 105static void umc_bus_rescan(struct device *parent)
 106{
 107        int err;
 108
 109        /*
 110         * We can't use bus_rescan_devices() here as it deadlocks when
 111         * it tries to retake the dev->parent semaphore.
 112         */
 113        err = device_for_each_child(parent, NULL, umc_bus_rescan_helper);
 114        if (err < 0)
 115                printk(KERN_WARNING "%s: rescan of bus failed: %d\n",
 116                       KBUILD_MODNAME, err);
 117}
 118
 119static int umc_bus_match(struct device *dev, struct device_driver *drv)
 120{
 121        struct umc_dev *umc = to_umc_dev(dev);
 122        struct umc_driver *umc_driver = to_umc_driver(drv);
 123
 124        if (umc->cap_id == umc_driver->cap_id) {
 125                if (umc_driver->match)
 126                        return umc_driver->match(umc_driver, umc);
 127                else
 128                        return 1;
 129        }
 130        return 0;
 131}
 132
 133static int umc_device_probe(struct device *dev)
 134{
 135        struct umc_dev *umc;
 136        struct umc_driver *umc_driver;
 137        int err;
 138
 139        umc_driver = to_umc_driver(dev->driver);
 140        umc = to_umc_dev(dev);
 141
 142        get_device(dev);
 143        err = umc_driver->probe(umc);
 144        if (err)
 145                put_device(dev);
 146        else
 147                umc_bus_rescan(dev->parent);
 148
 149        return err;
 150}
 151
 152static int umc_device_remove(struct device *dev)
 153{
 154        struct umc_dev *umc;
 155        struct umc_driver *umc_driver;
 156
 157        umc_driver = to_umc_driver(dev->driver);
 158        umc = to_umc_dev(dev);
 159
 160        umc_driver->remove(umc);
 161        put_device(dev);
 162        return 0;
 163}
 164
 165static int umc_device_suspend(struct device *dev, pm_message_t state)
 166{
 167        struct umc_dev *umc;
 168        struct umc_driver *umc_driver;
 169        int err = 0;
 170
 171        umc = to_umc_dev(dev);
 172
 173        if (dev->driver) {
 174                umc_driver = to_umc_driver(dev->driver);
 175                if (umc_driver->suspend)
 176                        err = umc_driver->suspend(umc, state);
 177        }
 178        return err;
 179}
 180
 181static int umc_device_resume(struct device *dev)
 182{
 183        struct umc_dev *umc;
 184        struct umc_driver *umc_driver;
 185        int err = 0;
 186
 187        umc = to_umc_dev(dev);
 188
 189        if (dev->driver) {
 190                umc_driver = to_umc_driver(dev->driver);
 191                if (umc_driver->resume)
 192                        err = umc_driver->resume(umc);
 193        }
 194        return err;
 195}
 196
 197static ssize_t capability_id_show(struct device *dev, struct device_attribute *attr, char *buf)
 198{
 199        struct umc_dev *umc = to_umc_dev(dev);
 200
 201        return sprintf(buf, "0x%02x\n", umc->cap_id);
 202}
 203
 204static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf)
 205{
 206        struct umc_dev *umc = to_umc_dev(dev);
 207
 208        return sprintf(buf, "0x%04x\n", umc->version);
 209}
 210
 211static struct device_attribute umc_dev_attrs[] = {
 212        __ATTR_RO(capability_id),
 213        __ATTR_RO(version),
 214        __ATTR_NULL,
 215};
 216
 217struct bus_type umc_bus_type = {
 218        .name           = "umc",
 219        .match          = umc_bus_match,
 220        .probe          = umc_device_probe,
 221        .remove         = umc_device_remove,
 222        .suspend        = umc_device_suspend,
 223        .resume         = umc_device_resume,
 224        .dev_attrs      = umc_dev_attrs,
 225};
 226EXPORT_SYMBOL_GPL(umc_bus_type);
 227
 228static int __init umc_bus_init(void)
 229{
 230        return bus_register(&umc_bus_type);
 231}
 232module_init(umc_bus_init);
 233
 234static void __exit umc_bus_exit(void)
 235{
 236        bus_unregister(&umc_bus_type);
 237}
 238module_exit(umc_bus_exit);
 239
 240MODULE_DESCRIPTION("UWB Multi-interface Controller capability bus");
 241MODULE_AUTHOR("Cambridge Silicon Radio Ltd.");
 242MODULE_LICENSE("GPL");
 243