linux/drivers/misc/tifm_core.c
<<
>>
Prefs
   1/*
   2 *  tifm_core.c - TI FlashMedia driver
   3 *
   4 *  Copyright (C) 2006 Alex Dubov <oakad@yahoo.com>
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 *
  10 */
  11
  12#include <linux/tifm.h>
  13#include <linux/slab.h>
  14#include <linux/init.h>
  15#include <linux/idr.h>
  16#include <linux/module.h>
  17
  18#define DRIVER_NAME "tifm_core"
  19#define DRIVER_VERSION "0.8"
  20
  21static struct workqueue_struct *workqueue;
  22static DEFINE_IDR(tifm_adapter_idr);
  23static DEFINE_SPINLOCK(tifm_adapter_lock);
  24
  25static const char *tifm_media_type_name(unsigned char type, unsigned char nt)
  26{
  27        const char *card_type_name[3][3] = {
  28                { "SmartMedia/xD", "MemoryStick", "MMC/SD" },
  29                { "XD", "MS", "SD"},
  30                { "xd", "ms", "sd"}
  31        };
  32
  33        if (nt > 2 || type < 1 || type > 3)
  34                return NULL;
  35        return card_type_name[nt][type - 1];
  36}
  37
  38static int tifm_dev_match(struct tifm_dev *sock, struct tifm_device_id *id)
  39{
  40        if (sock->type == id->type)
  41                return 1;
  42        return 0;
  43}
  44
  45static int tifm_bus_match(struct device *dev, struct device_driver *drv)
  46{
  47        struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
  48        struct tifm_driver *fm_drv = container_of(drv, struct tifm_driver,
  49                                                  driver);
  50        struct tifm_device_id *ids = fm_drv->id_table;
  51
  52        if (ids) {
  53                while (ids->type) {
  54                        if (tifm_dev_match(sock, ids))
  55                                return 1;
  56                        ++ids;
  57                }
  58        }
  59        return 0;
  60}
  61
  62static int tifm_uevent(struct device *dev, struct kobj_uevent_env *env)
  63{
  64        struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
  65
  66        if (add_uevent_var(env, "TIFM_CARD_TYPE=%s", tifm_media_type_name(sock->type, 1)))
  67                return -ENOMEM;
  68
  69        return 0;
  70}
  71
  72static int tifm_device_probe(struct device *dev)
  73{
  74        struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
  75        struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,
  76                                               driver);
  77        int rc = -ENODEV;
  78
  79        get_device(dev);
  80        if (dev->driver && drv->probe) {
  81                rc = drv->probe(sock);
  82                if (!rc)
  83                        return 0;
  84        }
  85        put_device(dev);
  86        return rc;
  87}
  88
  89static void tifm_dummy_event(struct tifm_dev *sock)
  90{
  91        return;
  92}
  93
  94static int tifm_device_remove(struct device *dev)
  95{
  96        struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
  97        struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,
  98                                               driver);
  99
 100        if (dev->driver && drv->remove) {
 101                sock->card_event = tifm_dummy_event;
 102                sock->data_event = tifm_dummy_event;
 103                drv->remove(sock);
 104                sock->dev.driver = NULL;
 105        }
 106
 107        put_device(dev);
 108        return 0;
 109}
 110
 111#ifdef CONFIG_PM
 112
 113static int tifm_device_suspend(struct device *dev, pm_message_t state)
 114{
 115        struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
 116        struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,
 117                                               driver);
 118
 119        if (dev->driver && drv->suspend)
 120                return drv->suspend(sock, state);
 121        return 0;
 122}
 123
 124static int tifm_device_resume(struct device *dev)
 125{
 126        struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
 127        struct tifm_driver *drv = container_of(dev->driver, struct tifm_driver,
 128                                               driver);
 129
 130        if (dev->driver && drv->resume)
 131                return drv->resume(sock);
 132        return 0;
 133}
 134
 135#else
 136
 137#define tifm_device_suspend NULL
 138#define tifm_device_resume NULL
 139
 140#endif /* CONFIG_PM */
 141
 142static ssize_t type_show(struct device *dev, struct device_attribute *attr,
 143                         char *buf)
 144{
 145        struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
 146        return sprintf(buf, "%x", sock->type);
 147}
 148static DEVICE_ATTR_RO(type);
 149
 150static struct attribute *tifm_dev_attrs[] = {
 151        &dev_attr_type.attr,
 152        NULL,
 153};
 154ATTRIBUTE_GROUPS(tifm_dev);
 155
 156static struct bus_type tifm_bus_type = {
 157        .name      = "tifm",
 158        .dev_groups = tifm_dev_groups,
 159        .match     = tifm_bus_match,
 160        .uevent    = tifm_uevent,
 161        .probe     = tifm_device_probe,
 162        .remove    = tifm_device_remove,
 163        .suspend   = tifm_device_suspend,
 164        .resume    = tifm_device_resume
 165};
 166
 167static void tifm_free(struct device *dev)
 168{
 169        struct tifm_adapter *fm = container_of(dev, struct tifm_adapter, dev);
 170
 171        kfree(fm);
 172}
 173
 174static struct class tifm_adapter_class = {
 175        .name    = "tifm_adapter",
 176        .dev_release = tifm_free
 177};
 178
 179struct tifm_adapter *tifm_alloc_adapter(unsigned int num_sockets,
 180                                        struct device *dev)
 181{
 182        struct tifm_adapter *fm;
 183
 184        fm = kzalloc(sizeof(struct tifm_adapter)
 185                     + sizeof(struct tifm_dev*) * num_sockets, GFP_KERNEL);
 186        if (fm) {
 187                fm->dev.class = &tifm_adapter_class;
 188                fm->dev.parent = dev;
 189                device_initialize(&fm->dev);
 190                spin_lock_init(&fm->lock);
 191                fm->num_sockets = num_sockets;
 192        }
 193        return fm;
 194}
 195EXPORT_SYMBOL(tifm_alloc_adapter);
 196
 197int tifm_add_adapter(struct tifm_adapter *fm)
 198{
 199        int rc;
 200
 201        idr_preload(GFP_KERNEL);
 202        spin_lock(&tifm_adapter_lock);
 203        rc = idr_alloc(&tifm_adapter_idr, fm, 0, 0, GFP_NOWAIT);
 204        if (rc >= 0)
 205                fm->id = rc;
 206        spin_unlock(&tifm_adapter_lock);
 207        idr_preload_end();
 208        if (rc < 0)
 209                return rc;
 210
 211        dev_set_name(&fm->dev, "tifm%u", fm->id);
 212        rc = device_add(&fm->dev);
 213        if (rc) {
 214                spin_lock(&tifm_adapter_lock);
 215                idr_remove(&tifm_adapter_idr, fm->id);
 216                spin_unlock(&tifm_adapter_lock);
 217        }
 218
 219        return rc;
 220}
 221EXPORT_SYMBOL(tifm_add_adapter);
 222
 223void tifm_remove_adapter(struct tifm_adapter *fm)
 224{
 225        unsigned int cnt;
 226
 227        flush_workqueue(workqueue);
 228        for (cnt = 0; cnt < fm->num_sockets; ++cnt) {
 229                if (fm->sockets[cnt])
 230                        device_unregister(&fm->sockets[cnt]->dev);
 231        }
 232
 233        spin_lock(&tifm_adapter_lock);
 234        idr_remove(&tifm_adapter_idr, fm->id);
 235        spin_unlock(&tifm_adapter_lock);
 236        device_del(&fm->dev);
 237}
 238EXPORT_SYMBOL(tifm_remove_adapter);
 239
 240void tifm_free_adapter(struct tifm_adapter *fm)
 241{
 242        put_device(&fm->dev);
 243}
 244EXPORT_SYMBOL(tifm_free_adapter);
 245
 246void tifm_free_device(struct device *dev)
 247{
 248        struct tifm_dev *sock = container_of(dev, struct tifm_dev, dev);
 249        kfree(sock);
 250}
 251EXPORT_SYMBOL(tifm_free_device);
 252
 253struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id,
 254                                   unsigned char type)
 255{
 256        struct tifm_dev *sock = NULL;
 257
 258        if (!tifm_media_type_name(type, 0))
 259                return sock;
 260
 261        sock = kzalloc(sizeof(struct tifm_dev), GFP_KERNEL);
 262        if (sock) {
 263                spin_lock_init(&sock->lock);
 264                sock->type = type;
 265                sock->socket_id = id;
 266                sock->card_event = tifm_dummy_event;
 267                sock->data_event = tifm_dummy_event;
 268
 269                sock->dev.parent = fm->dev.parent;
 270                sock->dev.bus = &tifm_bus_type;
 271                sock->dev.dma_mask = fm->dev.parent->dma_mask;
 272                sock->dev.release = tifm_free_device;
 273
 274                dev_set_name(&sock->dev, "tifm_%s%u:%u",
 275                             tifm_media_type_name(type, 2), fm->id, id);
 276                printk(KERN_INFO DRIVER_NAME
 277                       ": %s card detected in socket %u:%u\n",
 278                       tifm_media_type_name(type, 0), fm->id, id);
 279        }
 280        return sock;
 281}
 282EXPORT_SYMBOL(tifm_alloc_device);
 283
 284void tifm_eject(struct tifm_dev *sock)
 285{
 286        struct tifm_adapter *fm = dev_get_drvdata(sock->dev.parent);
 287        fm->eject(fm, sock);
 288}
 289EXPORT_SYMBOL(tifm_eject);
 290
 291int tifm_has_ms_pif(struct tifm_dev *sock)
 292{
 293        struct tifm_adapter *fm = dev_get_drvdata(sock->dev.parent);
 294        return fm->has_ms_pif(fm, sock);
 295}
 296EXPORT_SYMBOL(tifm_has_ms_pif);
 297
 298int tifm_map_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
 299                int direction)
 300{
 301        return pci_map_sg(to_pci_dev(sock->dev.parent), sg, nents, direction);
 302}
 303EXPORT_SYMBOL(tifm_map_sg);
 304
 305void tifm_unmap_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
 306                   int direction)
 307{
 308        pci_unmap_sg(to_pci_dev(sock->dev.parent), sg, nents, direction);
 309}
 310EXPORT_SYMBOL(tifm_unmap_sg);
 311
 312void tifm_queue_work(struct work_struct *work)
 313{
 314        queue_work(workqueue, work);
 315}
 316EXPORT_SYMBOL(tifm_queue_work);
 317
 318int tifm_register_driver(struct tifm_driver *drv)
 319{
 320        drv->driver.bus = &tifm_bus_type;
 321
 322        return driver_register(&drv->driver);
 323}
 324EXPORT_SYMBOL(tifm_register_driver);
 325
 326void tifm_unregister_driver(struct tifm_driver *drv)
 327{
 328        driver_unregister(&drv->driver);
 329}
 330EXPORT_SYMBOL(tifm_unregister_driver);
 331
 332static int __init tifm_init(void)
 333{
 334        int rc;
 335
 336        workqueue = create_freezable_workqueue("tifm");
 337        if (!workqueue)
 338                return -ENOMEM;
 339
 340        rc = bus_register(&tifm_bus_type);
 341
 342        if (rc)
 343                goto err_out_wq;
 344
 345        rc = class_register(&tifm_adapter_class);
 346        if (!rc)
 347                return 0;
 348
 349        bus_unregister(&tifm_bus_type);
 350
 351err_out_wq:
 352        destroy_workqueue(workqueue);
 353
 354        return rc;
 355}
 356
 357static void __exit tifm_exit(void)
 358{
 359        class_unregister(&tifm_adapter_class);
 360        bus_unregister(&tifm_bus_type);
 361        destroy_workqueue(workqueue);
 362}
 363
 364subsys_initcall(tifm_init);
 365module_exit(tifm_exit);
 366
 367MODULE_LICENSE("GPL");
 368MODULE_AUTHOR("Alex Dubov");
 369MODULE_DESCRIPTION("TI FlashMedia core driver");
 370MODULE_LICENSE("GPL");
 371MODULE_VERSION(DRIVER_VERSION);
 372