linux/drivers/mcb/mcb-core.c
<<
>>
Prefs
   1/*
   2 * MEN Chameleon Bus.
   3 *
   4 * Copyright (C) 2013 MEN Mikroelektronik GmbH (www.men.de)
   5 * Author: Johannes Thumshirn <johannes.thumshirn@men.de>
   6 *
   7 * This program is free software; you can redistribute it and/or modify it
   8 * under the terms of the GNU General Public License as published by the Free
   9 * Software Foundation; version 2 of the License.
  10 */
  11#include <linux/kernel.h>
  12#include <linux/module.h>
  13#include <linux/slab.h>
  14#include <linux/types.h>
  15#include <linux/idr.h>
  16#include <linux/mcb.h>
  17
  18static DEFINE_IDA(mcb_ida);
  19
  20static const struct mcb_device_id *mcb_match_id(const struct mcb_device_id *ids,
  21                                                struct mcb_device *dev)
  22{
  23        if (ids) {
  24                while (ids->device) {
  25                        if (ids->device == dev->id)
  26                                return ids;
  27                        ids++;
  28                }
  29        }
  30
  31        return NULL;
  32}
  33
  34static int mcb_match(struct device *dev, struct device_driver *drv)
  35{
  36        struct mcb_driver *mdrv = to_mcb_driver(drv);
  37        struct mcb_device *mdev = to_mcb_device(dev);
  38        const struct mcb_device_id *found_id;
  39
  40        found_id = mcb_match_id(mdrv->id_table, mdev);
  41        if (found_id)
  42                return 1;
  43
  44        return 0;
  45}
  46
  47static int mcb_uevent(struct device *dev, struct kobj_uevent_env *env)
  48{
  49        struct mcb_device *mdev = to_mcb_device(dev);
  50        int ret;
  51
  52        ret = add_uevent_var(env, "MODALIAS=mcb:16z%03d", mdev->id);
  53        if (ret)
  54                return -ENOMEM;
  55
  56        return 0;
  57}
  58
  59static int mcb_probe(struct device *dev)
  60{
  61        struct mcb_driver *mdrv = to_mcb_driver(dev->driver);
  62        struct mcb_device *mdev = to_mcb_device(dev);
  63        const struct mcb_device_id *found_id;
  64
  65        found_id = mcb_match_id(mdrv->id_table, mdev);
  66        if (!found_id)
  67                return -ENODEV;
  68
  69        return mdrv->probe(mdev, found_id);
  70}
  71
  72static int mcb_remove(struct device *dev)
  73{
  74        struct mcb_driver *mdrv = to_mcb_driver(dev->driver);
  75        struct mcb_device *mdev = to_mcb_device(dev);
  76
  77        mdrv->remove(mdev);
  78
  79        put_device(&mdev->dev);
  80
  81        return 0;
  82}
  83
  84static void mcb_shutdown(struct device *dev)
  85{
  86        struct mcb_device *mdev = to_mcb_device(dev);
  87        struct mcb_driver *mdrv = mdev->driver;
  88
  89        if (mdrv && mdrv->shutdown)
  90                mdrv->shutdown(mdev);
  91}
  92
  93static struct bus_type mcb_bus_type = {
  94        .name = "mcb",
  95        .match = mcb_match,
  96        .uevent = mcb_uevent,
  97        .probe = mcb_probe,
  98        .remove = mcb_remove,
  99        .shutdown = mcb_shutdown,
 100};
 101
 102/**
 103 * __mcb_register_driver() - Register a @mcb_driver at the system
 104 * @drv: The @mcb_driver
 105 * @owner: The @mcb_driver's module
 106 * @mod_name: The name of the @mcb_driver's module
 107 *
 108 * Register a @mcb_driver at the system. Perform some sanity checks, if
 109 * the .probe and .remove methods are provided by the driver.
 110 */
 111int __mcb_register_driver(struct mcb_driver *drv, struct module *owner,
 112                        const char *mod_name)
 113{
 114        if (!drv->probe || !drv->remove)
 115                return -EINVAL;
 116
 117        drv->driver.owner = owner;
 118        drv->driver.bus = &mcb_bus_type;
 119        drv->driver.mod_name = mod_name;
 120
 121        return driver_register(&drv->driver);
 122}
 123EXPORT_SYMBOL_GPL(__mcb_register_driver);
 124
 125/**
 126 * mcb_unregister_driver() - Unregister a @mcb_driver from the system
 127 * @drv: The @mcb_driver
 128 *
 129 * Unregister a @mcb_driver from the system.
 130 */
 131void mcb_unregister_driver(struct mcb_driver *drv)
 132{
 133        driver_unregister(&drv->driver);
 134}
 135EXPORT_SYMBOL_GPL(mcb_unregister_driver);
 136
 137static void mcb_release_dev(struct device *dev)
 138{
 139        struct mcb_device *mdev = to_mcb_device(dev);
 140
 141        mcb_bus_put(mdev->bus);
 142        kfree(mdev);
 143}
 144
 145/**
 146 * mcb_device_register() - Register a mcb_device
 147 * @bus: The @mcb_bus of the device
 148 * @dev: The @mcb_device
 149 *
 150 * Register a specific @mcb_device at a @mcb_bus and the system itself.
 151 */
 152int mcb_device_register(struct mcb_bus *bus, struct mcb_device *dev)
 153{
 154        int ret;
 155        int device_id;
 156
 157        device_initialize(&dev->dev);
 158        dev->dev.bus = &mcb_bus_type;
 159        dev->dev.parent = bus->dev.parent;
 160        dev->dev.release = mcb_release_dev;
 161
 162        device_id = dev->id;
 163        dev_set_name(&dev->dev, "mcb%d-16z%03d-%d:%d:%d",
 164                bus->bus_nr, device_id, dev->inst, dev->group, dev->var);
 165
 166        ret = device_add(&dev->dev);
 167        if (ret < 0) {
 168                pr_err("Failed registering device 16z%03d on bus mcb%d (%d)\n",
 169                        device_id, bus->bus_nr, ret);
 170                goto out;
 171        }
 172
 173        return 0;
 174
 175out:
 176
 177        return ret;
 178}
 179EXPORT_SYMBOL_GPL(mcb_device_register);
 180
 181/**
 182 * mcb_alloc_bus() - Allocate a new @mcb_bus
 183 *
 184 * Allocate a new @mcb_bus.
 185 */
 186struct mcb_bus *mcb_alloc_bus(struct device *carrier)
 187{
 188        struct mcb_bus *bus;
 189        int bus_nr;
 190
 191        bus = kzalloc(sizeof(struct mcb_bus), GFP_KERNEL);
 192        if (!bus)
 193                return ERR_PTR(-ENOMEM);
 194
 195        bus_nr = ida_simple_get(&mcb_ida, 0, 0, GFP_KERNEL);
 196        if (bus_nr < 0) {
 197                kfree(bus);
 198                return ERR_PTR(bus_nr);
 199        }
 200
 201        INIT_LIST_HEAD(&bus->children);
 202        bus->bus_nr = bus_nr;
 203        bus->carrier = carrier;
 204        return bus;
 205}
 206EXPORT_SYMBOL_GPL(mcb_alloc_bus);
 207
 208static int __mcb_devices_unregister(struct device *dev, void *data)
 209{
 210        device_unregister(dev);
 211        return 0;
 212}
 213
 214static void mcb_devices_unregister(struct mcb_bus *bus)
 215{
 216        bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_devices_unregister);
 217}
 218/**
 219 * mcb_release_bus() - Free a @mcb_bus
 220 * @bus: The @mcb_bus to release
 221 *
 222 * Release an allocated @mcb_bus from the system.
 223 */
 224void mcb_release_bus(struct mcb_bus *bus)
 225{
 226        mcb_devices_unregister(bus);
 227
 228        ida_simple_remove(&mcb_ida, bus->bus_nr);
 229
 230        kfree(bus);
 231}
 232EXPORT_SYMBOL_GPL(mcb_release_bus);
 233
 234/**
 235 * mcb_bus_put() - Increment refcnt
 236 * @bus: The @mcb_bus
 237 *
 238 * Get a @mcb_bus' ref
 239 */
 240struct mcb_bus *mcb_bus_get(struct mcb_bus *bus)
 241{
 242        if (bus)
 243                get_device(&bus->dev);
 244
 245        return bus;
 246}
 247EXPORT_SYMBOL_GPL(mcb_bus_get);
 248
 249/**
 250 * mcb_bus_put() - Decrement refcnt
 251 * @bus: The @mcb_bus
 252 *
 253 * Release a @mcb_bus' ref
 254 */
 255void mcb_bus_put(struct mcb_bus *bus)
 256{
 257        if (bus)
 258                put_device(&bus->dev);
 259}
 260EXPORT_SYMBOL_GPL(mcb_bus_put);
 261
 262/**
 263 * mcb_alloc_dev() - Allocate a device
 264 * @bus: The @mcb_bus the device is part of
 265 *
 266 * Allocate a @mcb_device and add bus.
 267 */
 268struct mcb_device *mcb_alloc_dev(struct mcb_bus *bus)
 269{
 270        struct mcb_device *dev;
 271
 272        dev = kzalloc(sizeof(struct mcb_device), GFP_KERNEL);
 273        if (!dev)
 274                return NULL;
 275
 276        INIT_LIST_HEAD(&dev->bus_list);
 277        dev->bus = bus;
 278
 279        return dev;
 280}
 281EXPORT_SYMBOL_GPL(mcb_alloc_dev);
 282
 283/**
 284 * mcb_free_dev() - Free @mcb_device
 285 * @dev: The device to free
 286 *
 287 * Free a @mcb_device
 288 */
 289void mcb_free_dev(struct mcb_device *dev)
 290{
 291        kfree(dev);
 292}
 293EXPORT_SYMBOL_GPL(mcb_free_dev);
 294
 295static int __mcb_bus_add_devices(struct device *dev, void *data)
 296{
 297        struct mcb_device *mdev = to_mcb_device(dev);
 298        int retval;
 299
 300        if (mdev->is_added)
 301                return 0;
 302
 303        retval = device_attach(dev);
 304        if (retval < 0)
 305                dev_err(dev, "Error adding device (%d)\n", retval);
 306
 307        mdev->is_added = true;
 308
 309        return 0;
 310}
 311
 312static int __mcb_bus_add_child(struct device *dev, void *data)
 313{
 314        struct mcb_device *mdev = to_mcb_device(dev);
 315        struct mcb_bus *child;
 316
 317        BUG_ON(!mdev->is_added);
 318        child = mdev->subordinate;
 319
 320        if (child)
 321                mcb_bus_add_devices(child);
 322
 323        return 0;
 324}
 325
 326/**
 327 * mcb_bus_add_devices() - Add devices in the bus' internal device list
 328 * @bus: The @mcb_bus we add the devices
 329 *
 330 * Add devices in the bus' internal device list to the system.
 331 */
 332void mcb_bus_add_devices(const struct mcb_bus *bus)
 333{
 334        bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_bus_add_devices);
 335        bus_for_each_dev(&mcb_bus_type, NULL, NULL, __mcb_bus_add_child);
 336
 337}
 338EXPORT_SYMBOL_GPL(mcb_bus_add_devices);
 339
 340/**
 341 * mcb_request_mem() - Request memory
 342 * @dev: The @mcb_device the memory is for
 343 * @name: The name for the memory reference.
 344 *
 345 * Request memory for a @mcb_device. If @name is NULL the driver name will
 346 * be used.
 347 */
 348struct resource *mcb_request_mem(struct mcb_device *dev, const char *name)
 349{
 350        struct resource *mem;
 351        u32 size;
 352
 353        if (!name)
 354                name = dev->dev.driver->name;
 355
 356        size = resource_size(&dev->mem);
 357
 358        mem = request_mem_region(dev->mem.start, size, name);
 359        if (!mem)
 360                return ERR_PTR(-EBUSY);
 361
 362        return mem;
 363}
 364EXPORT_SYMBOL_GPL(mcb_request_mem);
 365
 366/**
 367 * mcb_release_mem() - Release memory requested by device
 368 * @dev: The @mcb_device that requested the memory
 369 *
 370 * Release memory that was prior requested via @mcb_request_mem().
 371 */
 372void mcb_release_mem(struct resource *mem)
 373{
 374        u32 size;
 375
 376        size = resource_size(mem);
 377        release_mem_region(mem->start, size);
 378}
 379EXPORT_SYMBOL_GPL(mcb_release_mem);
 380
 381static int __mcb_get_irq(struct mcb_device *dev)
 382{
 383        struct resource *irq = &dev->irq;
 384
 385        return irq->start;
 386}
 387
 388/**
 389 * mcb_get_irq() - Get device's IRQ number
 390 * @dev: The @mcb_device the IRQ is for
 391 *
 392 * Get the IRQ number of a given @mcb_device.
 393 */
 394int mcb_get_irq(struct mcb_device *dev)
 395{
 396        struct mcb_bus *bus = dev->bus;
 397
 398        if (bus->get_irq)
 399                return bus->get_irq(dev);
 400
 401        return __mcb_get_irq(dev);
 402}
 403EXPORT_SYMBOL_GPL(mcb_get_irq);
 404
 405static int mcb_init(void)
 406{
 407        return bus_register(&mcb_bus_type);
 408}
 409
 410static void mcb_exit(void)
 411{
 412        ida_destroy(&mcb_ida);
 413        bus_unregister(&mcb_bus_type);
 414}
 415
 416/* mcb must be initialized after PCI but before the chameleon drivers.
 417 * That means we must use some initcall between subsys_initcall and
 418 * device_initcall.
 419 */
 420fs_initcall(mcb_init);
 421module_exit(mcb_exit);
 422
 423MODULE_DESCRIPTION("MEN Chameleon Bus Driver");
 424MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>");
 425MODULE_LICENSE("GPL v2");
 426