[PATCH] pcmcia: add pcmcia_disable_device
[firefly-linux-kernel-4.4.55.git] / drivers / char / pcmcia / cm4040_cs.c
index 3622fd39c47b5fdc9048559a6d703f6f89db0ebd..1c355bd2be8803f86f78f956721869d5c14ea82e 100644 (file)
@@ -3,12 +3,13 @@
  *
  * (c) 2000-2004 Omnikey AG (http://www.omnikey.com/)
  *
- * (C) 2005 Harald Welte <laforge@gnumonks.org>
+ * (C) 2005-2006 Harald Welte <laforge@gnumonks.org>
  *     - add support for poll()
  *     - driver cleanup
  *     - add waitqueues
  *     - adhere to linux kernel coding style and policies
  *     - support 2.6.13 "new style" pcmcia interface
+ *     - add class interface for udev device creation
  *
  * The device basically is a USB CCID compliant device that has been
  * attached to an I/O-Mapped FIFO.
@@ -53,7 +54,7 @@ module_param(pc_debug, int, 0600);
 #endif
 
 static char *version =
-"OMNIKEY CardMan 4040 v1.1.0gm4 - All bugs added by Harald Welte";
+"OMNIKEY CardMan 4040 v1.1.0gm5 - All bugs added by Harald Welte";
 
 #define        CCID_DRIVER_BULK_DEFAULT_TIMEOUT        (150*HZ)
 #define        CCID_DRIVER_ASYNC_POWERUP_TIMEOUT       (35*HZ)
@@ -65,9 +66,9 @@ static char *version =
 #define POLL_PERIOD                            msecs_to_jiffies(10)
 
 static void reader_release(dev_link_t *link);
-static void reader_detach(dev_link_t *link);
 
 static int major;
+static struct class *cmx_class;
 
 #define                BS_READABLE     0x01
 #define                BS_WRITABLE     0x02
@@ -86,7 +87,6 @@ struct reader_dev {
        struct timer_list       poll_timer;
 };
 
-static dev_info_t dev_info = MODULE_NAME;
 static dev_link_t *dev_table[CM_MAX_DEV];
 
 #ifndef PCMCIA_DEBUG
@@ -629,43 +629,6 @@ cs_release:
        link->state &= ~DEV_CONFIG_PENDING;
 }
 
-static int reader_event(event_t event, int priority,
-                       event_callback_args_t *args)
-{
-       dev_link_t *link;
-       struct reader_dev *dev;
-       int devno;
-
-       link = args->client_data;
-       dev = link->priv;
-       DEBUGP(3, dev, "-> reader_event\n");
-       for (devno = 0; devno < CM_MAX_DEV; devno++) {
-               if (dev_table[devno] == link)
-                       break;
-       }
-       if (devno == CM_MAX_DEV)
-               return CS_BAD_ADAPTER;
-
-       switch (event) {
-               case CS_EVENT_CARD_INSERTION:
-                       DEBUGP(5, dev, "CS_EVENT_CARD_INSERTION\n");
-                       link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
-                       reader_config(link, devno);
-                       break;
-               case CS_EVENT_CARD_REMOVAL:
-                       DEBUGP(5, dev, "CS_EVENT_CARD_REMOVAL\n");
-                       link->state &= ~DEV_PRESENT;
-                       break;
-
-               default:
-                       DEBUGP(5, dev, "reader_event: unknown event %.2x\n",
-                              event);
-                       break;
-       }
-       DEBUGP(3, dev, "<- reader_event\n");
-       return CS_SUCCESS;
-}
-
 static int reader_suspend(struct pcmcia_device *p_dev)
 {
        dev_link_t *link = dev_to_instance(p_dev);
@@ -691,15 +654,13 @@ static int reader_resume(struct pcmcia_device *p_dev)
 static void reader_release(dev_link_t *link)
 {
        cm4040_reader_release(link->priv);
-       pcmcia_release_configuration(link->handle);
-       pcmcia_release_io(link->handle, &link->io);
+       pcmcia_disable_device(link->handle);
 }
 
-static dev_link_t *reader_attach(void)
+static int reader_attach(struct pcmcia_device *p_dev)
 {
        struct reader_dev *dev;
        dev_link_t *link;
-       client_reg_t client_reg;
        int i;
 
        for (i = 0; i < CM_MAX_DEV; i++) {
@@ -708,11 +669,11 @@ static dev_link_t *reader_attach(void)
        }
 
        if (i == CM_MAX_DEV)
-               return NULL;
+               return -ENODEV;
 
        dev = kzalloc(sizeof(struct reader_dev), GFP_KERNEL);
        if (dev == NULL)
-               return NULL;
+               return -ENOMEM;
 
        dev->timeout = CCID_DRIVER_MINIMUM_TIMEOUT;
        dev->buffer_status = 0;
@@ -723,20 +684,6 @@ static dev_link_t *reader_attach(void)
        link->conf.IntType = INT_MEMORY_AND_IO;
        dev_table[i] = link;
 
-       client_reg.dev_info = &dev_info;
-       client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
-       client_reg.EventMask=
-               CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-               CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
-               CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
-       client_reg.Version = 0x0210;
-       client_reg.event_callback_args.client_data = link;
-       i = pcmcia_register_client(&link->handle, &client_reg);
-       if (i) {
-               cs_error(link->handle, RegisterClient, i);
-               reader_detach(link);
-               return NULL;
-       }
        init_waitqueue_head(&dev->devq);
        init_waitqueue_head(&dev->poll_wait);
        init_waitqueue_head(&dev->read_wait);
@@ -744,39 +691,42 @@ static dev_link_t *reader_attach(void)
        init_timer(&dev->poll_timer);
        dev->poll_timer.function = &cm4040_do_poll;
 
-       return link;
-}
+       link->handle = p_dev;
+       p_dev->instance = link;
 
-static void reader_detach_by_devno(int devno, dev_link_t *link)
-{
-       struct reader_dev *dev = link->priv;
+       link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+       reader_config(link, i);
 
-       if (link->state & DEV_CONFIG) {
-               DEBUGP(5, dev, "device still configured (try to release it)\n");
-               reader_release(link);
-       }
+       class_device_create(cmx_class, NULL, MKDEV(major, i), NULL,
+                           "cmx%d", i);
 
-       pcmcia_deregister_client(link->handle);
-       dev_table[devno] = NULL;
-       DEBUGP(5, dev, "freeing dev=%p\n", dev);
-       cm4040_stop_poll(dev);
-       kfree(dev);
-       return;
+       return 0;
 }
 
-static void reader_detach(dev_link_t *link)
+static void reader_detach(struct pcmcia_device *p_dev)
 {
-       int i;
+       dev_link_t *link = dev_to_instance(p_dev);
+       struct reader_dev *dev = link->priv;
+       int devno;
 
        /* find device */
-       for (i = 0; i < CM_MAX_DEV; i++) {
-               if (dev_table[i] == link)
+       for (devno = 0; devno < CM_MAX_DEV; devno++) {
+               if (dev_table[devno] == link)
                        break;
        }
-       if (i == CM_MAX_DEV)
+       if (devno == CM_MAX_DEV)
                return;
 
-       reader_detach_by_devno(i, link);
+       link->state &= ~DEV_PRESENT;
+
+       if (link->state & DEV_CONFIG)
+               reader_release(link);
+
+       dev_table[devno] = NULL;
+       kfree(dev);
+
+       class_device_destroy(cmx_class, MKDEV(major, devno));
+
        return;
 }
 
@@ -802,18 +752,26 @@ static struct pcmcia_driver reader_driver = {
        .drv            = {
                .name   = "cm4040_cs",
        },
-       .attach         = reader_attach,
-       .detach         = reader_detach,
+       .probe          = reader_attach,
+       .remove         = reader_detach,
        .suspend        = reader_suspend,
        .resume         = reader_resume,
-       .event          = reader_event,
        .id_table       = cm4040_ids,
 };
 
 static int __init cm4040_init(void)
 {
+       int rc;
+
        printk(KERN_INFO "%s\n", version);
-       pcmcia_register_driver(&reader_driver);
+       cmx_class = class_create(THIS_MODULE, "cardman_4040");
+       if (!cmx_class)
+               return -1;
+
+       rc = pcmcia_register_driver(&reader_driver);
+       if (rc < 0)
+               return rc;
+
        major = register_chrdev(0, DEVICE_NAME, &reader_fops);
        if (major < 0) {
                printk(KERN_WARNING MODULE_NAME
@@ -825,15 +783,10 @@ static int __init cm4040_init(void)
 
 static void __exit cm4040_exit(void)
 {
-       int i;
-
        printk(KERN_INFO MODULE_NAME ": unloading\n");
        pcmcia_unregister_driver(&reader_driver);
-       for (i = 0; i < CM_MAX_DEV; i++) {
-               if (dev_table[i])
-                       reader_detach_by_devno(i, dev_table[i]);
-       }
        unregister_chrdev(major, DEVICE_NAME);
+       class_destroy(cmx_class);
 }
 
 module_init(cm4040_init);