]> git.hungrycats.org Git - linux/commitdiff
[PATCH] pcmcia: add pcmcia_device(s)
authorDominik Brodowski <linux@dominikbrodowski.de>
Tue, 11 Jan 2005 11:20:06 +0000 (03:20 -0800)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Tue, 11 Jan 2005 11:20:06 +0000 (03:20 -0800)
Add pcmcia_device(s).

Signed-off-by: Dominik Brodowski <linux@brodo.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
drivers/pcmcia/ds.c
include/pcmcia/ds.h

index b2f42d04503d5dc80306fa4ce2224ac7a96d50b5..a37746187881aa69552e33eb145633e2d3327e19 100644 (file)
@@ -101,7 +101,15 @@ struct pcmcia_bus_socket {
        wait_queue_head_t       queue, request;
        socket_bind_t           *bind;
        struct pcmcia_socket    *parent;
+
+       /* the PCMCIA devices connected to this socket (normally one, more
+        * for multifunction devices: */
+       struct list_head        devices_list;
+       u8                      device_count; /* the number of devices, used
+                                              * only internally and subject
+                                              * to incorrectness and change */
 };
+static spinlock_t pcmcia_dev_list_lock;
 
 #define DS_SOCKET_PRESENT              0x01
 #define DS_SOCKET_BUSY                 0x02
@@ -328,6 +336,16 @@ static int proc_read_drivers(char *buf, char **start, off_t pos,
 }
 #endif
 
+/* pcmcia_device handling */
+
+static void pcmcia_release_dev(struct device *dev)
+{
+       struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+       p_dev->socket->pcmcia->device_count = 0;
+       kfree(p_dev);
+}
+
+
 /*======================================================================
 
     These manage a ring buffer of events pending for one user process
@@ -491,8 +509,10 @@ static int bind_mtd(struct pcmcia_bus_socket *bus_sock, mtd_info_t *mtd_info)
 static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info)
 {
        struct pcmcia_driver *driver;
+       struct pcmcia_device *p_dev;
        socket_bind_t *b;
        client_t *client;
+       unsigned long flags;
 
        if (!s)
                return -EINVAL;
@@ -543,6 +563,38 @@ static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info)
        b->next = s->bind;
        s->bind = b;
 
+       /* Currently, the userspace pcmcia cardmgr detects pcmcia devices.
+        * Here this information is translated into a kernel
+        * struct pcmcia_device.
+        */
+
+       p_dev = kmalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
+       if (!p_dev) {
+               /* FIXME: client isn't freed here */
+               goto no_p_dev;
+       }
+       memset(p_dev, 0, sizeof(struct pcmcia_device));
+
+       p_dev->socket = s->parent;
+       p_dev->device_no = (s->device_count++);
+       p_dev->func   = bind_info->function;
+
+       p_dev->dev.bus = &pcmcia_bus_type;
+       p_dev->dev.parent = s->parent->dev.dev;
+       p_dev->dev.release = pcmcia_release_dev;
+       sprintf (p_dev->dev.bus_id, "pcmcia%d.%d", p_dev->socket->sock, p_dev->device_no);
+       p_dev->dev.driver = &driver->drv;
+       if (device_register(&p_dev->dev)) {
+               /* FIXME: client isn't freed here */
+               kfree(p_dev);
+               goto no_p_dev;
+       }
+       spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+       list_add_tail(&p_dev->socket_device_list, &s->devices_list);
+       spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+
+ no_p_dev:
+
        driver->use_count++;
        if (driver->attach) {
                b->instance = driver->attach();
@@ -632,6 +684,8 @@ static int get_device_info(struct pcmcia_bus_socket *s, bind_info_t *bind_info,
 static int unbind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info)
 {
     socket_bind_t **b, *c;
+    struct pcmcia_device *p_dev;
+    unsigned long flags;
 
     ds_dbg(2, "unbind_request(%d, '%s')\n", s->parent->sock,
          (char *)bind_info->dev_info);
@@ -652,6 +706,22 @@ static int unbind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info)
     module_put(c->driver->owner);
     *b = c->next;
     kfree(c);
+
+ restart:
+    /* unregister the pcmcia_device */
+    spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+    list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
+           if (p_dev->func == bind_info->function) {
+                   list_del(&p_dev->socket_device_list);
+                   spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+
+                   device_unregister(&p_dev->dev);
+
+                   /* multiple devices may be registered to this "function" */
+                   goto restart;
+           }
+    }
+    spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
     return 0;
 } /* unbind_request */
 
@@ -1034,6 +1104,7 @@ static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev)
 
        init_waitqueue_head(&s->queue);
        init_waitqueue_head(&s->request);
+       INIT_LIST_HEAD(&s->devices_list);
 
        /* initialize data */
        s->parent = socket;
@@ -1090,6 +1161,8 @@ static int __init init_pcmcia_bus(void)
 {
        int i;
 
+       spin_lock_init(&pcmcia_dev_list_lock);
+
        bus_register(&pcmcia_bus_type);
        class_interface_register(&pcmcia_bus_interface);
 
index ec0c0b9c1a065c2816d86591e8b2ae06828f379c..35437bc8303b7cc70097306ac55a1d65ab0a7178 100644 (file)
@@ -127,6 +127,8 @@ typedef struct dev_link_t {
     ((l) && ((l->state & ~DEV_BUSY) == (DEV_CONFIG|DEV_PRESENT)))
 
 
+struct pcmcia_socket;
+
 extern struct bus_type pcmcia_bus_type;
 
 struct pcmcia_driver {
@@ -141,6 +143,26 @@ struct pcmcia_driver {
 int pcmcia_register_driver(struct pcmcia_driver *driver);
 void pcmcia_unregister_driver(struct pcmcia_driver *driver);
 
+struct pcmcia_device {
+       /* the socket and the device_no [for multifunction devices]
+          uniquely define a pcmcia_device */
+       struct pcmcia_socket    *socket;
+
+       u8                      device_no;
+
+       /* the hardware "function" device; certain subdevices can
+        * share one hardware "function" device. */
+       u8                      func;
+
+       struct list_head        socket_device_list;
+
+       struct device           dev;
+};
+
+#define to_pcmcia_dev(n) container_of(n, struct pcmcia_device, dev)
+#define to_pcmcia_drv(n) container_of(n, struct pcmcia_driver, drv)
+
+
 /* error reporting */
 void cs_error(client_handle_t handle, int func, int ret);