]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/pcmcia/pcmcia_resource.c
Merge branch 'master' into csb1725
[mv-sheeva.git] / drivers / pcmcia / pcmcia_resource.c
index 9ba4dade69a4d67cd5b0efc1e4c55a70dbf349c1..0bdda5b3ed550cc74504a7ceea539700b69cb9bd 100644 (file)
@@ -6,7 +6,7 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Copyright (C) 1999       David A. Hinds
- * Copyright (C) 2004-2005   Dominik Brodowski
+ * Copyright (C) 2004-2010   Dominik Brodowski
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -26,7 +26,6 @@
 #include <asm/irq.h>
 
 #include <pcmcia/ss.h>
-#include <pcmcia/cs.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
@@ -56,6 +55,12 @@ struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align,
 }
 
 
+/**
+ * release_io_space() - release IO ports allocated with alloc_io_space()
+ * @s: pcmcia socket
+ * @res: resource to release
+ *
+ */
 static void release_io_space(struct pcmcia_socket *s, struct resource *res)
 {
        resource_size_t num = resource_size(res);
@@ -81,9 +86,14 @@ static void release_io_space(struct pcmcia_socket *s, struct resource *res)
                        }
                }
        }
-} /* release_io_space */
+}
+
 
-/** alloc_io_space
+/**
+ * alloc_io_space() - allocate IO ports for use by a PCMCIA device
+ * @s: pcmcia socket
+ * @res: resource to allocate (begin: begin, end: size)
+ * @lines: number of IO lines decoded by the PCMCIA card
  *
  * Special stuff for managing IO windows, because they are scarce
  */
@@ -135,7 +145,7 @@ static int alloc_io_space(struct pcmcia_socket *s, struct resource *res,
        }
        dev_dbg(&s->dev, "alloc_io_space request result %d: %pR\n", ret, res);
        return ret;
-} /* alloc_io_space */
+}
 
 
 /**
@@ -168,14 +178,14 @@ static int pcmcia_access_config(struct pcmcia_device *p_dev,
                return -EACCES;
        }
 
-       addr = (c->ConfigBase + where) >> 1;
+       addr = (p_dev->config_base + where) >> 1;
 
        ret = accessf(s, 1, addr, 1, val);
 
        mutex_unlock(&s->ops_mutex);
 
        return ret;
-} /* pcmcia_access_config */
+}
 
 
 /**
@@ -204,11 +214,20 @@ int pcmcia_write_config_byte(struct pcmcia_device *p_dev, off_t where, u8 val)
 EXPORT_SYMBOL(pcmcia_write_config_byte);
 
 
-int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t wh,
+/**
+ * pcmcia_map_mem_page() - modify iomem window to point to a different offset
+ * @p_dev: pcmcia device
+ * @res: iomem resource already enabled by pcmcia_request_window()
+ * @offset: card_offset to map
+ *
+ * pcmcia_map_mem_page() modifies what can be read and written by accessing
+ * an iomem range previously enabled by pcmcia_request_window(), by setting
+ * the card_offset value to @offset.
+ */
+int pcmcia_map_mem_page(struct pcmcia_device *p_dev, struct resource *res,
                        unsigned int offset)
 {
        struct pcmcia_socket *s = p_dev->socket;
-       struct resource *res = wh;
        unsigned int w;
        int ret;
 
@@ -223,98 +242,111 @@ int pcmcia_map_mem_page(struct pcmcia_device *p_dev, window_handle_t wh,
                dev_warn(&p_dev->dev, "failed to set_mem_map\n");
        mutex_unlock(&s->ops_mutex);
        return ret;
-} /* pcmcia_map_mem_page */
+}
 EXPORT_SYMBOL(pcmcia_map_mem_page);
 
 
-/** pcmcia_modify_configuration
+/**
+ * pcmcia_fixup_iowidth() - reduce io width to 8bit
+ * @p_dev: pcmcia device
  *
- * Modify a locked socket configuration
+ * pcmcia_fixup_iowidth() allows a PCMCIA device driver to reduce the
+ * IO width to 8bit after having called pcmcia_enable_device()
+ * previously.
  */
-int pcmcia_modify_configuration(struct pcmcia_device *p_dev,
-                               modconf_t *mod)
+int pcmcia_fixup_iowidth(struct pcmcia_device *p_dev)
 {
-       struct pcmcia_socket *s;
-       config_t *c;
-       int ret;
-
-       s = p_dev->socket;
+       struct pcmcia_socket *s = p_dev->socket;
+       pccard_io_map io_off = { 0, 0, 0, 0, 1 };
+       pccard_io_map io_on;
+       int i, ret = 0;
 
        mutex_lock(&s->ops_mutex);
-       c = p_dev->function_config;
 
-       if (!(s->state & SOCKET_PRESENT)) {
-               dev_dbg(&p_dev->dev, "No card present\n");
-               ret = -ENODEV;
-               goto unlock;
-       }
-       if (!(c->state & CONFIG_LOCKED)) {
-               dev_dbg(&p_dev->dev, "Configuration isnt't locked\n");
+       dev_dbg(&p_dev->dev, "fixup iowidth to 8bit\n");
+
+       if (!(s->state & SOCKET_PRESENT) ||
+               !(p_dev->function_config->state & CONFIG_LOCKED)) {
+               dev_dbg(&p_dev->dev, "No card? Config not locked?\n");
                ret = -EACCES;
                goto unlock;
        }
 
-       if (mod->Attributes & (CONF_IRQ_CHANGE_VALID | CONF_VCC_CHANGE_VALID)) {
-               dev_dbg(&p_dev->dev,
-                       "changing Vcc or IRQ is not allowed at this time\n");
-               ret = -EINVAL;
-               goto unlock;
-       }
+       io_on.speed = io_speed;
+       for (i = 0; i < MAX_IO_WIN; i++) {
+               if (!s->io[i].res)
+                       continue;
+               io_off.map = i;
+               io_on.map = i;
 
-       /* We only allow changing Vpp1 and Vpp2 to the same value */
-       if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) &&
-           (mod->Attributes & CONF_VPP2_CHANGE_VALID)) {
-               if (mod->Vpp1 != mod->Vpp2) {
-                       dev_dbg(&p_dev->dev,
-                               "Vpp1 and Vpp2 must be the same\n");
-                       ret = -EINVAL;
-                       goto unlock;
-               }
-               s->socket.Vpp = mod->Vpp1;
-               if (s->ops->set_socket(s, &s->socket)) {
-                       dev_printk(KERN_WARNING, &p_dev->dev,
-                                  "Unable to set VPP\n");
-                       ret = -EIO;
-                       goto unlock;
-               }
-       } else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) ||
-                  (mod->Attributes & CONF_VPP2_CHANGE_VALID)) {
-               dev_dbg(&p_dev->dev,
-                       "changing Vcc is not allowed at this time\n");
-               ret = -EINVAL;
-               goto unlock;
+               io_on.flags = MAP_ACTIVE | IO_DATA_PATH_WIDTH_8;
+               io_on.start = s->io[i].res->start;
+               io_on.stop = s->io[i].res->end;
+
+               s->ops->set_io_map(s, &io_off);
+               mdelay(40);
+               s->ops->set_io_map(s, &io_on);
        }
+unlock:
+       mutex_unlock(&s->ops_mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL(pcmcia_fixup_iowidth);
+
+
+/**
+ * pcmcia_fixup_vpp() - set Vpp to a new voltage level
+ * @p_dev: pcmcia device
+ * @new_vpp: new Vpp voltage
+ *
+ * pcmcia_fixup_vpp() allows a PCMCIA device driver to set Vpp to
+ * a new voltage level between calls to pcmcia_enable_device()
+ * and pcmcia_disable_device().
+ */
+int pcmcia_fixup_vpp(struct pcmcia_device *p_dev, unsigned char new_vpp)
+{
+       struct pcmcia_socket *s = p_dev->socket;
+       int ret = 0;
 
-       if (mod->Attributes & CONF_IO_CHANGE_WIDTH) {
-               pccard_io_map io_off = { 0, 0, 0, 0, 1 };
-               pccard_io_map io_on;
-               int i;
+       mutex_lock(&s->ops_mutex);
 
-               io_on.speed = io_speed;
-               for (i = 0; i < MAX_IO_WIN; i++) {
-                       if (!s->io[i].res)
-                               continue;
-                       io_off.map = i;
-                       io_on.map = i;
+       dev_dbg(&p_dev->dev, "fixup Vpp to %d\n", new_vpp);
 
-                       io_on.flags = MAP_ACTIVE | IO_DATA_PATH_WIDTH_8;
-                       io_on.start = s->io[i].res->start;
-                       io_on.stop = s->io[i].res->end;
+       if (!(s->state & SOCKET_PRESENT) ||
+               !(p_dev->function_config->state & CONFIG_LOCKED)) {
+               dev_dbg(&p_dev->dev, "No card? Config not locked?\n");
+               ret = -EACCES;
+               goto unlock;
+       }
 
-                       s->ops->set_io_map(s, &io_off);
-                       mdelay(40);
-                       s->ops->set_io_map(s, &io_on);
-               }
+       s->socket.Vpp = new_vpp;
+       if (s->ops->set_socket(s, &s->socket)) {
+               dev_warn(&p_dev->dev, "Unable to set VPP\n");
+               ret = -EIO;
+               goto unlock;
        }
-       ret = 0;
+       p_dev->vpp = new_vpp;
+
 unlock:
        mutex_unlock(&s->ops_mutex);
 
        return ret;
-} /* modify_configuration */
-EXPORT_SYMBOL(pcmcia_modify_configuration);
+}
+EXPORT_SYMBOL(pcmcia_fixup_vpp);
 
 
+/**
+ * pcmcia_release_configuration() - physically disable a PCMCIA device
+ * @p_dev: pcmcia device
+ *
+ * pcmcia_release_configuration() is the 1:1 counterpart to
+ * pcmcia_enable_device(): If a PCMCIA device is no longer used by any
+ * driver, the Vpp voltage is set to 0, IRQs will no longer be generated,
+ * and I/O ranges will be disabled. As pcmcia_release_io() and
+ * pcmcia_release_window() still need to be called, device drivers are
+ * expected to call pcmcia_disable_device() instead.
+ */
 int pcmcia_release_configuration(struct pcmcia_device *p_dev)
 {
        pccard_io_map io = { 0, 0, 0, 0, 1 };
@@ -327,7 +359,7 @@ int pcmcia_release_configuration(struct pcmcia_device *p_dev)
        if (p_dev->_locked) {
                p_dev->_locked = 0;
                if (--(s->lock_count) == 0) {
-                       s->socket.flags = SS_OUTPUT_ENA;   /* Is this correct? */
+                       s->socket.flags = SS_OUTPUT_ENA; /* Is this correct? */
                        s->socket.Vpp = 0;
                        s->socket.io_irq = 0;
                        s->ops->set_socket(s, &s->socket);
@@ -349,16 +381,18 @@ int pcmcia_release_configuration(struct pcmcia_device *p_dev)
        mutex_unlock(&s->ops_mutex);
 
        return 0;
-} /* pcmcia_release_configuration */
+}
 
 
-/** pcmcia_release_io
+/**
+ * pcmcia_release_io() - release I/O allocated by a PCMCIA device
+ * @p_dev: pcmcia device
  *
- * Release_io() releases the I/O ranges allocated by a client.  This
- * may be invoked some time after a card ejection has already dumped
- * the actual socket configuration, so if the client is "stale", we
- * don't bother checking the port ranges against the current socket
- * values.
+ * pcmcia_release_io() releases the I/O ranges allocated by a PCMCIA
+ * device.  This may be invoked some time after a card ejection has
+ * already dumped the actual socket configuration, so if the client is
+ * "stale", we don't bother checking the port ranges against the
+ * current socket values.
  */
 static int pcmcia_release_io(struct pcmcia_device *p_dev)
 {
@@ -387,6 +421,14 @@ out:
 } /* pcmcia_release_io */
 
 
+/**
+ * pcmcia_release_window() - release reserved iomem for PCMCIA devices
+ * @p_dev: pcmcia device
+ * @res: iomem resource to release
+ *
+ * pcmcia_release_window() releases &struct resource *res which was
+ * previously reserved by calling pcmcia_request_window().
+ */
 int pcmcia_release_window(struct pcmcia_device *p_dev, struct resource *res)
 {
        struct pcmcia_socket *s = p_dev->socket;
@@ -420,6 +462,8 @@ int pcmcia_release_window(struct pcmcia_device *p_dev, struct resource *res)
                kfree(win->res);
                win->res = NULL;
        }
+       res->start = res->end = 0;
+       res->flags = IORESOURCE_MEM;
        p_dev->_win &= ~CLIENT_WIN_REQ(w);
        mutex_unlock(&s->ops_mutex);
 
@@ -428,23 +472,30 @@ int pcmcia_release_window(struct pcmcia_device *p_dev, struct resource *res)
 EXPORT_SYMBOL(pcmcia_release_window);
 
 
-int pcmcia_request_configuration(struct pcmcia_device *p_dev,
-                                config_req_t *req)
+/**
+ * pcmcia_enable_device() - set up and activate a PCMCIA device
+ * @p_dev: the associated PCMCIA device
+ *
+ * pcmcia_enable_device() physically enables a PCMCIA device. It parses
+ * the flags passed to in @flags and stored in @p_dev->flags and sets up
+ * the Vpp voltage, enables the speaker line, I/O ports and store proper
+ * values to configuration registers.
+ */
+int pcmcia_enable_device(struct pcmcia_device *p_dev)
 {
        int i;
-       u_int base;
+       unsigned int base;
        struct pcmcia_socket *s = p_dev->socket;
        config_t *c;
        pccard_io_map iomap;
+       unsigned char status = 0;
+       unsigned char ext_status = 0;
+       unsigned char option = 0;
+       unsigned int flags = p_dev->config_flags;
 
        if (!(s->state & SOCKET_PRESENT))
                return -ENODEV;
 
-       if (req->IntType & INT_CARDBUS) {
-               dev_dbg(&p_dev->dev, "IntType may not be INT_CARDBUS\n");
-               return -EINVAL;
-       }
-
        mutex_lock(&s->ops_mutex);
        c = p_dev->function_config;
        if (c->state & CONFIG_LOCKED) {
@@ -454,7 +505,7 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
        }
 
        /* Do power control.  We don't allow changes in Vcc. */
-       s->socket.Vpp = req->Vpp;
+       s->socket.Vpp = p_dev->vpp;
        if (s->ops->set_socket(s, &s->socket)) {
                mutex_unlock(&s->ops_mutex);
                dev_printk(KERN_WARNING, &p_dev->dev,
@@ -463,64 +514,74 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
        }
 
        /* Pick memory or I/O card, DMA mode, interrupt */
-       c->IntType = req->IntType;
-       c->Attributes = req->Attributes;
-       if (req->IntType & INT_MEMORY_AND_IO)
+       if (p_dev->_io || flags & CONF_ENABLE_IRQ)
+               flags |= CONF_ENABLE_IOCARD;
+       if (flags & CONF_ENABLE_IOCARD)
                s->socket.flags |= SS_IOCARD;
-       if (req->IntType & INT_ZOOMED_VIDEO)
-               s->socket.flags |= SS_ZVCARD | SS_IOCARD;
-       if (req->Attributes & CONF_ENABLE_DMA)
-               s->socket.flags |= SS_DMA_MODE;
-       if (req->Attributes & CONF_ENABLE_SPKR)
+       if (flags & CONF_ENABLE_SPKR) {
                s->socket.flags |= SS_SPKR_ENA;
-       if (req->Attributes & CONF_ENABLE_IRQ)
+               status = CCSR_AUDIO_ENA;
+               if (!(p_dev->config_regs & PRESENT_STATUS))
+                       dev_warn(&p_dev->dev, "speaker requested, but "
+                                             "PRESENT_STATUS not set!\n");
+       }
+       if (flags & CONF_ENABLE_IRQ)
                s->socket.io_irq = s->pcmcia_irq;
        else
                s->socket.io_irq = 0;
+       if (flags & CONF_ENABLE_ESR) {
+               p_dev->config_regs |= PRESENT_EXT_STATUS;
+               ext_status = ESR_REQ_ATTN_ENA;
+       }
        s->ops->set_socket(s, &s->socket);
        s->lock_count++;
 
+       dev_dbg(&p_dev->dev,
+               "enable_device: V %d, flags %x, base %x, regs %x, idx %x\n",
+               p_dev->vpp, flags, p_dev->config_base, p_dev->config_regs,
+               p_dev->config_index);
+
        /* Set up CIS configuration registers */
-       base = c->ConfigBase = req->ConfigBase;
-       c->CardValues = req->Present;
-       if (req->Present & PRESENT_COPY) {
-               c->Copy = req->Copy;
-               pcmcia_write_cis_mem(s, 1, (base + CISREG_SCR)>>1, 1, &c->Copy);
-       }
-       if (req->Present & PRESENT_OPTION) {
+       base = p_dev->config_base;
+       if (p_dev->config_regs & PRESENT_COPY) {
+               u16 tmp = 0;
+               dev_dbg(&p_dev->dev, "clearing CISREG_SCR\n");
+               pcmcia_write_cis_mem(s, 1, (base + CISREG_SCR)>>1, 1, &tmp);
+       }
+       if (p_dev->config_regs & PRESENT_PIN_REPLACE) {
+               u16 tmp = 0;
+               dev_dbg(&p_dev->dev, "clearing CISREG_PRR\n");
+               pcmcia_write_cis_mem(s, 1, (base + CISREG_PRR)>>1, 1, &tmp);
+       }
+       if (p_dev->config_regs & PRESENT_OPTION) {
                if (s->functions == 1) {
-                       c->Option = req->ConfigIndex & COR_CONFIG_MASK;
+                       option = p_dev->config_index & COR_CONFIG_MASK;
                } else {
-                       c->Option = req->ConfigIndex & COR_MFC_CONFIG_MASK;
-                       c->Option |= COR_FUNC_ENA|COR_IREQ_ENA;
-                       if (req->Present & PRESENT_IOBASE_0)
-                               c->Option |= COR_ADDR_DECODE;
+                       option = p_dev->config_index & COR_MFC_CONFIG_MASK;
+                       option |= COR_FUNC_ENA|COR_IREQ_ENA;
+                       if (p_dev->config_regs & PRESENT_IOBASE_0)
+                               option |= COR_ADDR_DECODE;
                }
-               if ((req->Attributes & CONF_ENABLE_IRQ) &&
-                       !(req->Attributes & CONF_ENABLE_PULSE_IRQ))
-                       c->Option |= COR_LEVEL_REQ;
-               pcmcia_write_cis_mem(s, 1, (base + CISREG_COR)>>1, 1, &c->Option);
+               if ((flags & CONF_ENABLE_IRQ) &&
+                       !(flags & CONF_ENABLE_PULSE_IRQ))
+                       option |= COR_LEVEL_REQ;
+               pcmcia_write_cis_mem(s, 1, (base + CISREG_COR)>>1, 1, &option);
                mdelay(40);
        }
-       if (req->Present & PRESENT_STATUS) {
-               c->Status = req->Status;
-               pcmcia_write_cis_mem(s, 1, (base + CISREG_CCSR)>>1, 1, &c->Status);
-       }
-       if (req->Present & PRESENT_PIN_REPLACE) {
-               c->Pin = req->Pin;
-               pcmcia_write_cis_mem(s, 1, (base + CISREG_PRR)>>1, 1, &c->Pin);
-       }
-       if (req->Present & PRESENT_EXT_STATUS) {
-               c->ExtStatus = req->ExtStatus;
-               pcmcia_write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1, &c->ExtStatus);
-       }
-       if (req->Present & PRESENT_IOBASE_0) {
+       if (p_dev->config_regs & PRESENT_STATUS)
+               pcmcia_write_cis_mem(s, 1, (base + CISREG_CCSR)>>1, 1, &status);
+
+       if (p_dev->config_regs & PRESENT_EXT_STATUS)
+               pcmcia_write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1,
+                                       &ext_status);
+
+       if (p_dev->config_regs & PRESENT_IOBASE_0) {
                u8 b = c->io[0].start & 0xff;
                pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &b);
                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) {
+       if (p_dev->config_regs & PRESENT_IOSIZE) {
                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);
        }
@@ -551,14 +612,15 @@ int pcmcia_request_configuration(struct pcmcia_device *p_dev,
        p_dev->_locked = 1;
        mutex_unlock(&s->ops_mutex);
        return 0;
-} /* pcmcia_request_configuration */
-EXPORT_SYMBOL(pcmcia_request_configuration);
+} /* pcmcia_enable_device */
+EXPORT_SYMBOL(pcmcia_enable_device);
 
 
 /**
  * pcmcia_request_io() - attempt to reserve port ranges for PCMCIA devices
+ * @p_dev: the associated PCMCIA device
  *
- * pcmcia_request_io() attepts to reserve the IO port ranges specified in
+ * pcmcia_request_io() attempts 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"
  * reflects the number of ports requested. The number of IO lines requested
@@ -622,11 +684,13 @@ EXPORT_SYMBOL(pcmcia_request_io);
 
 /**
  * pcmcia_request_irq() - attempt to request a IRQ for a PCMCIA device
+ * @p_dev: the associated PCMCIA device
+ * @handler: IRQ handler to register
  *
- * pcmcia_request_irq() is a wrapper around request_irq which will allow
+ * pcmcia_request_irq() is a wrapper around request_irq() which allows
  * the PCMCIA core to clean up the registration in pcmcia_disable_device().
  * Drivers are free to use request_irq() directly, but then they need to
- * call free_irq themselfves, too. Also, only IRQF_SHARED capable IRQ
+ * call free_irq() themselfves, too. Also, only %IRQF_SHARED capable IRQ
  * handlers are allowed.
  */
 int __must_check pcmcia_request_irq(struct pcmcia_device *p_dev,
@@ -649,12 +713,14 @@ EXPORT_SYMBOL(pcmcia_request_irq);
 
 /**
  * pcmcia_request_exclusive_irq() - attempt to request an exclusive IRQ first
+ * @p_dev: the associated PCMCIA device
+ * @handler: IRQ handler to register
  *
- * pcmcia_request_exclusive_irq() is a wrapper around request_irq which
+ * pcmcia_request_exclusive_irq() is a wrapper around request_irq() which
  * attempts first to request an exclusive IRQ. If it fails, it also accepts
  * a shared IRQ, but prints out a warning. PCMCIA drivers should allow for
  * IRQ sharing and either use request_irq directly (then they need to call
- * free_irq themselves, too), or the pcmcia_request_irq() function.
+ * free_irq() themselves, too), or the pcmcia_request_irq() function.
  */
 int __must_check
 __pcmcia_request_exclusive_irq(struct pcmcia_device *p_dev,
@@ -795,38 +861,47 @@ int pcmcia_setup_irq(struct pcmcia_device *p_dev)
 }
 
 
-/** pcmcia_request_window
+/**
+ * pcmcia_request_window() - attempt to reserve iomem for PCMCIA devices
+ * @p_dev: the associated PCMCIA device
+ * @res: &struct resource pointing to p_dev->resource[2..5]
+ * @speed: access speed
  *
- * Request_window() establishes a mapping between card memory space
- * and system memory space.
+ * pcmcia_request_window() attepts to reserve an iomem ranges specified in
+ * &struct resource @res pointing to one of the entries in
+ * &struct pcmcia_device @p_dev->resource[2..5]. The "start" value is the
+ * requested start of the IO mem resource; "end" reflects the size
+ * requested.
  */
-int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_handle_t *wh)
+int pcmcia_request_window(struct pcmcia_device *p_dev, struct resource *res,
+                       unsigned int speed)
 {
        struct pcmcia_socket *s = p_dev->socket;
        pccard_mem_map *win;
        u_long align;
-       struct resource *res;
        int w;
 
+       dev_dbg(&p_dev->dev, "request_window %pR %d\n", res, speed);
+
        if (!(s->state & SOCKET_PRESENT)) {
                dev_dbg(&p_dev->dev, "No card present\n");
                return -ENODEV;
        }
 
        /* Window size defaults to smallest available */
-       if (req->Size == 0)
-               req->Size = s->map_size;
-       align = (s->features & SS_CAP_MEM_ALIGN) ? req->Size : s->map_size;
-       if (req->Size & (s->map_size-1)) {
+       if (res->end == 0)
+               res->end = s->map_size;
+       align = (s->features & SS_CAP_MEM_ALIGN) ? res->end : s->map_size;
+       if (res->end & (s->map_size-1)) {
                dev_dbg(&p_dev->dev, "invalid map size\n");
                return -EINVAL;
        }
-       if ((req->Base && (s->features & SS_CAP_STATIC_MAP)) ||
-           (req->Base & (align-1))) {
+       if ((res->start && (s->features & SS_CAP_STATIC_MAP)) ||
+           (res->start & (align-1))) {
                dev_dbg(&p_dev->dev, "invalid base address\n");
                return -EINVAL;
        }
-       if (req->Base)
+       if (res->start)
                align = 0;
 
        /* Allocate system memory window */
@@ -843,7 +918,7 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha
        win = &s->win[w];
 
        if (!(s->features & SS_CAP_STATIC_MAP)) {
-               win->res = pcmcia_find_mem_region(req->Base, req->Size, align,
+               win->res = pcmcia_find_mem_region(res->start, res->end, align,
                                                0, s);
                if (!win->res) {
                        dev_dbg(&p_dev->dev, "allocating mem region failed\n");
@@ -855,8 +930,8 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha
 
        /* Configure the socket controller */
        win->map = w+1;
-       win->flags = req->Attributes;
-       win->speed = req->AccessSpeed;
+       win->flags = res->flags & WIN_FLAGS_MAP;
+       win->speed = speed;
        win->card_start = 0;
 
        if (s->ops->set_mem_map(s, win) != 0) {
@@ -868,17 +943,14 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha
 
        /* Return window handle */
        if (s->features & SS_CAP_STATIC_MAP)
-               req->Base = win->static_start;
+               res->start = win->static_start;
        else
-               req->Base = win->res->start;
+               res->start = win->res->start;
 
        /* convert to new-style resources */
-       res = p_dev->resource[w + MAX_IO_WIN];
-       res->start = req->Base;
-       res->end = req->Base + req->Size - 1;
-       res->flags &= ~IORESOURCE_BITS;
-       res->flags |= (req->Attributes & WIN_FLAGS_MAP) | (win->map << 2);
-       res->flags |= IORESOURCE_MEM;
+       res->end += res->start - 1;
+       res->flags &= ~WIN_FLAGS_REQ;
+       res->flags |= (win->map << 2) | IORESOURCE_MEM;
        res->parent = win->res;
        if (win->res)
                request_resource(&iomem_resource, res);
@@ -886,15 +958,30 @@ int pcmcia_request_window(struct pcmcia_device *p_dev, win_req_t *req, window_ha
        dev_dbg(&p_dev->dev, "request_window results in %pR\n", res);
 
        mutex_unlock(&s->ops_mutex);
-       *wh = res;
 
        return 0;
 } /* pcmcia_request_window */
 EXPORT_SYMBOL(pcmcia_request_window);
 
+
+/**
+ * pcmcia_disable_device() - disable and clean up a PCMCIA device
+ * @p_dev: the associated PCMCIA device
+ *
+ * pcmcia_disable_device() is the driver-callable counterpart to
+ * pcmcia_enable_device(): If a PCMCIA device is no longer used,
+ * drivers are expected to clean up and disable the device by calling
+ * this function. Any I/O ranges (iomem and ioports) will be released,
+ * the Vpp voltage will be set to 0, and IRQs will no longer be
+ * generated -- at least if there is no other card function (of
+ * multifunction devices) being used.
+ */
 void pcmcia_disable_device(struct pcmcia_device *p_dev)
 {
        int i;
+
+       dev_dbg(&p_dev->dev, "disabling device\n");
+
        for (i = 0; i < MAX_WIN; i++) {
                struct resource *res = p_dev->resource[MAX_IO_WIN + i];
                if (res->flags & WIN_FLAGS_REQ)