pcmcia: use struct resource for PCMCIA devices
authorDominik Brodowski <linux@dominikbrodowski.net>
Sat, 24 Jul 2010 11:14:44 +0000 (13:14 +0200)
committerDominik Brodowski <linux@dominikbrodowski.net>
Tue, 3 Aug 2010 07:02:44 +0000 (09:02 +0200)
Introduce a new field into struct pcmcia_device named "resource" and of
type struct resource *, which contains the IO port ranges allocated for
this device. Memory window ranges and registration with the resource
trees will follow at a later date.

Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
drivers/pcmcia/cs_internal.h
drivers/pcmcia/ds.c
drivers/pcmcia/pcmcia_resource.c
include/pcmcia/cs.h
include/pcmcia/ds.h

index cebd40da8b9bdf923e63ecdf5ebc7cc6e51b9c0d..a85558fc71f3851fdec4e6a24c85375748a6f2ab 100644 (file)
@@ -35,7 +35,9 @@ typedef struct config_t {
        unsigned int    ConfigBase;
        unsigned char   Status, Pin, Copy, Option, ExtStatus;
        unsigned int    CardValues;
-       io_req_t        io;
+
+       struct resource io[MAX_IO_WIN]; /* io ports */
+
        struct {
                u_int   Attributes;
        } irq;
index bacfc55f2026c7d736f2bd8c2f1e825a8cd47d6d..7ddd19a4033d7a06903944835b9450ab9cfc6423 100644 (file)
@@ -531,7 +531,6 @@ static struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s,
        list_for_each_entry(tmp_dev, &s->devices_list, socket_device_list)
                if (p_dev->func == tmp_dev->func) {
                        p_dev->function_config = tmp_dev->function_config;
-                       p_dev->io = tmp_dev->io;
                        p_dev->irq = tmp_dev->irq;
                        kref_get(&p_dev->function_config->ref);
                }
@@ -544,15 +543,23 @@ static struct pcmcia_device *pcmcia_device_add(struct pcmcia_socket *s,
                        "IRQ setup failed -- device might not work\n");
 
        if (!p_dev->function_config) {
+               config_t *c;
                dev_dbg(&p_dev->dev, "creating config_t\n");
-               p_dev->function_config = kzalloc(sizeof(struct config_t),
-                                                GFP_KERNEL);
-               if (!p_dev->function_config) {
+               c = kzalloc(sizeof(struct config_t), GFP_KERNEL);
+               if (!c) {
                        mutex_unlock(&s->ops_mutex);
                        goto err_unreg;
                }
-               kref_init(&p_dev->function_config->ref);
+               p_dev->function_config = c;
+               kref_init(&c->ref);
+               for (i = 0; i < MAX_IO_WIN; i++) {
+                       c->io[i].name = dev_name(&p_dev->dev);
+                       c->io[i].flags = IORESOURCE_IO;
+               }
        }
+       for (i = 0; i < MAX_IO_WIN; i++)
+               p_dev->resource[i] = &p_dev->function_config->io[i];
+
        mutex_unlock(&s->ops_mutex);
 
        dev_printk(KERN_NOTICE, &p_dev->dev,
index 563750e77eaf0c69319a26e6bb9b51516163aefe..fcd48dae79bca281c4fd44f827e5dd0d276b5dce 100644 (file)
@@ -60,43 +60,60 @@ struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align,
  *
  * Special stuff for managing IO windows, because they are scarce
  */
-
-static int alloc_io_space(struct pcmcia_socket *s, u_int attr,
-                         unsigned int *base, unsigned int num, u_int lines)
+static int alloc_io_space(struct pcmcia_socket *s, struct resource *res,
+                       unsigned int lines)
 {
        unsigned int align;
+       unsigned int base = res->start;
+       unsigned int num = res->end;
+       int ret;
+
+       res->flags |= IORESOURCE_IO;
 
-       align = (*base) ? (lines ? 1<<lines : 0) : 1;
+       dev_dbg(&s->dev, "alloc_io_space request for %pR\n", res);
+
+       align = base ? (lines ? 1<<lines : 0) : 1;
        if (align && (align < num)) {
-               if (*base) {
-                       dev_dbg(&s->dev, "odd IO request: num %#x align %#x\n",
-                              num, align);
+               if (base) {
+                       dev_dbg(&s->dev, "odd IO request\n");
                        align = 0;
                } else
                        while (align && (align < num))
                                align <<= 1;
        }
-       if (*base & ~(align-1)) {
-               dev_dbg(&s->dev, "odd IO request: base %#x align %#x\n",
-                      *base, align);
+       if (base & ~(align-1)) {
+               dev_dbg(&s->dev, "odd IO request\n");
                align = 0;
        }
 
-       return s->resource_ops->find_io(s, attr, base, num, align);
+       ret = s->resource_ops->find_io(s, res->flags, &base, num, align);
+       if (ret) {
+               dev_dbg(&s->dev, "alloc_io_space request returned %d", ret);
+               return -EINVAL;
+       }
+
+       res->start = base;
+       res->end = res->start + num - 1;
+       dev_dbg(&s->dev, "alloc_io_space request returned %pR, %d\n", res, ret);
+       return 0;
 } /* alloc_io_space */
 
 
-static void release_io_space(struct pcmcia_socket *s, unsigned int base,
-                            unsigned int num)
+static void release_io_space(struct pcmcia_socket *s, struct resource *res)
 {
+       resource_size_t num = resource_size(res);
        int i;
 
+       dev_dbg(&s->dev, "release_io_space for %pR\n", res);
+
        for (i = 0; i < MAX_IO_WIN; i++) {
                if (!s->io[i].res)
                        continue;
-               if ((s->io[i].res->start <= base) &&
-                   (s->io[i].res->end >= base+num-1)) {
+               if ((s->io[i].res->start <= res->start) &&
+                   (s->io[i].res->end >= res->end)) {
                        s->io[i].InUse -= num;
+                       res->start = res->end = 0;
+                       res->flags = IORESOURCE_IO;
                        /* Free the window if no one else is using it */
                        if (s->io[i].InUse == 0) {
                                release_resource(s->io[i].res);
@@ -329,31 +346,25 @@ int pcmcia_release_configuration(struct pcmcia_device *p_dev)
  * don't bother checking the port ranges against the current socket
  * values.
  */
-static int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req)
+static int pcmcia_release_io(struct pcmcia_device *p_dev)
 {
        struct pcmcia_socket *s = p_dev->socket;
        int ret = -EINVAL;
        config_t *c;
 
        mutex_lock(&s->ops_mutex);
-       c = p_dev->function_config;
-
        if (!p_dev->_io)
                goto out;
 
-       p_dev->_io = 0;
+       c = p_dev->function_config;
 
-       if ((c->io.BasePort1 != req->BasePort1) ||
-           (c->io.NumPorts1 != req->NumPorts1) ||
-           (c->io.BasePort2 != req->BasePort2) ||
-           (c->io.NumPorts2 != req->NumPorts2))
-               goto out;
+       release_io_space(s, &c->io[0]);
 
-       c->state &= ~CONFIG_IO_REQ;
+       if (c->io[1].end)
+               release_io_space(s, &c->io[1]);
 
-       release_io_space(s, req->BasePort1, req->NumPorts1);
-       if (req->NumPorts2)
-               release_io_space(s, req->BasePort2, req->NumPorts2);
+       p_dev->_io = 0;
+       c->state &= ~CONFIG_IO_REQ;
 
 out:
        mutex_unlock(&s->ops_mutex);
@@ -486,13 +497,13 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
                pcmcia_write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1, &c->ExtStatus);
        }
        if (req->Present & PRESENT_IOBASE_0) {
-               u_char b = c->io.BasePort1 & 0xff;
+               u8 b = c->io[0].start & 0xff;
                pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &b);
-               b = (c->io.BasePort1 >> 8) & 0xff;
+               b = (c->io[0].start >> 8) & 0xff;
                pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_1)>>1, 1, &b);
        }
        if (req->Present & PRESENT_IOSIZE) {
-               u_char b = c->io.NumPorts1 + c->io.NumPorts2 - 1;
+               u8 b = resource_size(&c->io[0]) + resource_size(&c->io[1]) - 1;
                pcmcia_write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &b);
        }
 
@@ -526,28 +537,42 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
 EXPORT_SYMBOL(pcmcia_request_configuration);
 
 
-/** pcmcia_request_io
+/**
+ * pcmcia_request_io() - attempt to reserve port ranges for PCMCIA devices
+ *
+ * pcmcia_request_io() attepts to reserve the IO port ranges specified in
+ * struct pcmcia_device *p_dev->resource[0] and *p_dev->resource[1]. The
+ * "start" value is the requested start of the IO port resource; "end"
+ * relfects the number of ports requested.
  *
- * Request_io() reserves ranges of port addresses for a socket.
- * I have not implemented range sharing or alias addressing.
+ * If io_req_t is passed, those values are converted automatically.
  */
 int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req)
 {
        struct pcmcia_socket *s = p_dev->socket;
        config_t *c;
        int ret = -EINVAL;
+       unsigned int lines = req->IOAddrLines;
 
        mutex_lock(&s->ops_mutex);
 
        if (!(s->state & SOCKET_PRESENT)) {
-               dev_dbg(&s->dev, "No card present\n");
+               dev_dbg(&s->dev, "pcmcia_request_io: No card present\n");
                goto out;
        }
 
-       if (!req)
-               goto out;
-
        c = p_dev->function_config;
+       if (req) {
+               c->io[0].start = req->BasePort1;
+               c->io[0].end = req->NumPorts1;
+               c->io[0].flags |= req->Attributes1;
+               c->io[1].start = req->BasePort2;
+               c->io[1].end = req->NumPorts2;
+               c->io[1].flags |= req->Attributes2;
+       }
+
+       dev_dbg(&s->dev, "pcmcia_request_io: %pR , %pR", &c->io[0], &c->io[1]);
+
        if (c->state & CONFIG_LOCKED) {
                dev_dbg(&s->dev, "Configuration is locked\n");
                goto out;
@@ -556,40 +581,30 @@ int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req)
                dev_dbg(&s->dev, "IO already configured\n");
                goto out;
        }
-       if (req->Attributes1 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS)) {
-               dev_dbg(&s->dev, "bad attribute setting for IO region 1\n");
-               goto out;
-       }
-       if ((req->NumPorts2 > 0) &&
-           (req->Attributes2 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS))) {
-               dev_dbg(&s->dev, "bad attribute setting for IO region 2\n");
-               goto out;
-       }
 
-       dev_dbg(&s->dev, "trying to allocate resource 1\n");
-       ret = alloc_io_space(s, req->Attributes1, &req->BasePort1,
-                            req->NumPorts1, req->IOAddrLines);
-       if (ret) {
-               dev_dbg(&s->dev, "allocation of resource 1 failed\n");
+       ret = alloc_io_space(s, &c->io[0], lines);
+       if (ret)
                goto out;
-       }
 
-       if (req->NumPorts2) {
-               dev_dbg(&s->dev, "trying to allocate resource 2\n");
-               ret = alloc_io_space(s, req->Attributes2, &req->BasePort2,
-                                    req->NumPorts2, req->IOAddrLines);
+       if (c->io[1].end) {
+               ret = alloc_io_space(s, &c->io[1], lines);
                if (ret) {
-                       dev_dbg(&s->dev, "allocation of resource 2 failed\n");
-                       release_io_space(s, req->BasePort1, req->NumPorts1);
+                       release_io_space(s, &c->io[0]);
                        goto out;
                }
-       }
+       } else
+               c->io[1].start = 0;
 
-       c->io = *req;
        c->state |= CONFIG_IO_REQ;
        p_dev->_io = 1;
-       dev_dbg(&s->dev, "allocating resources succeeded: %d\n", ret);
 
+       if (!ret) {
+               req->BasePort1 = c->io[0].start;
+               req->BasePort2 = c->io[1].start;
+       }
+
+       dev_dbg(&s->dev, "pcmcia_request_io succeeded: %pR , %pR",
+               &c->io[0], &c->io[1]);
 out:
        mutex_unlock(&s->ops_mutex);
 
@@ -869,7 +884,7 @@ EXPORT_SYMBOL(pcmcia_request_window);
 void pcmcia_disable_device(struct pcmcia_device *p_dev)
 {
        pcmcia_release_configuration(p_dev);
-       pcmcia_release_io(p_dev, &p_dev->io);
+       pcmcia_release_io(p_dev);
        if (p_dev->_irq) {
                free_irq(p_dev->irq, p_dev->priv);
                p_dev->_irq = 0;
index 7be0fcf78502d05bf6f019dc69b74dc7072de62d..0cd8c70d8aaa8c6b40d58f8ada54d48bc8d2a868 100644 (file)
@@ -68,9 +68,6 @@ typedef struct io_req_t {
 } io_req_t;
 
 /* Attributes for RequestIO and ReleaseIO */
-#define IO_SHARED              0x01
-#define IO_FIRST_SHARED                0x02
-#define IO_FORCE_ALIAS_ACCESS  0x04
 #define IO_DATA_PATH_WIDTH     0x18
 #define IO_DATA_PATH_WIDTH_8   0x00
 #define IO_DATA_PATH_WIDTH_16  0x08
index d494ce417b4f3d89068f82c3dd216bd872b53044..3dafd7db34dfa890dc78f338404f1723dfdff8d9 100644 (file)
@@ -80,13 +80,13 @@ struct pcmcia_device {
        struct list_head        socket_device_list;
 
        /* deprecated, will be cleaned up soon */
-       u_int                   open;
        io_req_t                io;
        config_req_t            conf;
        window_handle_t         win;
 
        /* device setup */
        unsigned int            irq;
+       struct resource         *resource[MAX_IO_WIN];
 
        /* Is the device suspended? */
        u16                     suspended:1;
@@ -120,6 +120,7 @@ struct pcmcia_device {
 
        /* data private to drivers */
        void                    *priv;
+       unsigned int            open;
 };
 
 #define to_pcmcia_dev(n) container_of(n, struct pcmcia_device, dev)