summaryrefslogtreecommitdiffstats
path: root/drivers/pcmcia
diff options
context:
space:
mode:
authorDominik Brodowski <linux@dominikbrodowski.net>2010-03-20 13:10:47 +0100
committerDominik Brodowski <linux@dominikbrodowski.net>2010-05-10 10:23:19 +0200
commitb19a7275dec4b470ea9abaae6129d21a0d75ab2f (patch)
tree9a3824270dee0494a198f969ae5b8c53e4950165 /drivers/pcmcia
parent49b1153adfe18a3cce7e70aa26c690f275917cd0 (diff)
downloadlinux-b19a7275dec4b470ea9abaae6129d21a0d75ab2f.tar.bz2
pcmcia: clarify alloc_io_space, move it to resource handlers
Clean up the alloc_io_space() function by moving most of it to the actual resource_ops. This allows for a bit less re-directions. Future cleanups will follow, and will make up for the code duplication currently present between rsrc_iodyn and rsrc_nonstatic (which are hardly ever built at the same time anyway, therefore no increase in built size). Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
Diffstat (limited to 'drivers/pcmcia')
-rw-r--r--drivers/pcmcia/cs_internal.h12
-rw-r--r--drivers/pcmcia/pcmcia_resource.c71
-rw-r--r--drivers/pcmcia/rsrc_iodyn.c92
-rw-r--r--drivers/pcmcia/rsrc_mgr.c14
-rw-r--r--drivers/pcmcia/rsrc_nonstatic.c105
5 files changed, 195 insertions, 99 deletions
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index ab000ea67296..4126a75445ea 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -52,13 +52,11 @@ struct cis_cache_entry {
struct pccard_resource_ops {
int (*validate_mem) (struct pcmcia_socket *s);
- int (*adjust_io_region) (struct resource *res,
- unsigned long r_start,
- unsigned long r_end,
- struct pcmcia_socket *s);
- struct resource* (*find_io) (unsigned long base, int num,
- unsigned long align,
- struct pcmcia_socket *s);
+ int (*find_io) (struct pcmcia_socket *s,
+ unsigned int attr,
+ unsigned int *base,
+ unsigned int num,
+ unsigned int align);
struct resource* (*find_mem) (unsigned long base, unsigned long num,
unsigned long align, int low,
struct pcmcia_socket *s);
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index 9c5f9cd5e03d..c6419c18a6c8 100644
--- a/drivers/pcmcia/pcmcia_resource.c
+++ b/drivers/pcmcia/pcmcia_resource.c
@@ -40,23 +40,6 @@ static int io_speed;
module_param(io_speed, int, 0444);
-static int pcmcia_adjust_io_region(struct resource *res, unsigned long start,
- unsigned long end, struct pcmcia_socket *s)
-{
- if (s->resource_ops->adjust_io_region)
- return s->resource_ops->adjust_io_region(res, start, end, s);
- return -ENOMEM;
-}
-
-static struct resource *pcmcia_find_io_region(unsigned long base, int num,
- unsigned long align,
- struct pcmcia_socket *s)
-{
- if (s->resource_ops->find_io)
- return s->resource_ops->find_io(base, num, align, s);
- return NULL;
-}
-
int pcmcia_validate_mem(struct pcmcia_socket *s)
{
if (s->resource_ops->validate_mem)
@@ -82,8 +65,7 @@ struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align,
static int alloc_io_space(struct pcmcia_socket *s, u_int attr,
unsigned int *base, unsigned int num, u_int lines)
{
- int i;
- unsigned int try, align;
+ unsigned int align;
align = (*base) ? (lines ? 1<<lines : 0) : 1;
if (align && (align < num)) {
@@ -100,50 +82,8 @@ static int alloc_io_space(struct pcmcia_socket *s, u_int attr,
*base, align);
align = 0;
}
- if ((s->features & SS_CAP_STATIC_MAP) && s->io_offset) {
- *base = s->io_offset | (*base & 0x0fff);
- return 0;
- }
- /* Check for an already-allocated window that must conflict with
- * what was asked for. It is a hack because it does not catch all
- * potential conflicts, just the most obvious ones.
- */
- for (i = 0; i < MAX_IO_WIN; i++)
- if ((s->io[i].res) && *base &&
- ((s->io[i].res->start & (align-1)) == *base))
- return 1;
- for (i = 0; i < MAX_IO_WIN; i++) {
- if (!s->io[i].res) {
- s->io[i].res = pcmcia_find_io_region(*base, num, align, s);
- if (s->io[i].res) {
- *base = s->io[i].res->start;
- s->io[i].res->flags = (s->io[i].res->flags & ~IORESOURCE_BITS) | (attr & IORESOURCE_BITS);
- s->io[i].InUse = num;
- break;
- } else
- return 1;
- } else if ((s->io[i].res->flags & IORESOURCE_BITS) != (attr & IORESOURCE_BITS))
- continue;
- /* Try to extend top of window */
- try = s->io[i].res->end + 1;
- if ((*base == 0) || (*base == try))
- if (pcmcia_adjust_io_region(s->io[i].res, s->io[i].res->start,
- s->io[i].res->end + num, s) == 0) {
- *base = try;
- s->io[i].InUse += num;
- break;
- }
- /* Try to extend bottom of window */
- try = s->io[i].res->start - num;
- if ((*base == 0) || (*base == try))
- if (pcmcia_adjust_io_region(s->io[i].res, s->io[i].res->start - num,
- s->io[i].res->end, s) == 0) {
- *base = try;
- s->io[i].InUse += num;
- break;
- }
- }
- return (i == MAX_IO_WIN);
+
+ return s->resource_ops->find_io(s, attr, base, num, align);
} /* alloc_io_space */
@@ -683,7 +623,8 @@ EXPORT_SYMBOL(pcmcia_request_irq);
* free_irq themselves, too), or the pcmcia_request_irq() function.
*/
int __must_check
-pcmcia_request_exclusive_irq(struct pcmcia_device *p_dev, irq_handler_t handler)
+__pcmcia_request_exclusive_irq(struct pcmcia_device *p_dev,
+ irq_handler_t handler)
{
int ret;
@@ -705,7 +646,7 @@ pcmcia_request_exclusive_irq(struct pcmcia_device *p_dev, irq_handler_t handler)
return ret;
} /* pcmcia_request_exclusive_irq */
-EXPORT_SYMBOL(pcmcia_request_exclusive_irq);
+EXPORT_SYMBOL(__pcmcia_request_exclusive_irq);
#ifdef CONFIG_PCMCIA_PROBE
diff --git a/drivers/pcmcia/rsrc_iodyn.c b/drivers/pcmcia/rsrc_iodyn.c
index 3fa808b582f6..779137561580 100644
--- a/drivers/pcmcia/rsrc_iodyn.c
+++ b/drivers/pcmcia/rsrc_iodyn.c
@@ -56,15 +56,9 @@ static resource_size_t pcmcia_align(void *align_data,
}
-static int iodyn_adjust_io_region(struct resource *res, unsigned long r_start,
- unsigned long r_end, struct pcmcia_socket *s)
-{
- return adjust_resource(res, r_start, r_end - r_start + 1);
-}
-
-
-static struct resource *iodyn_find_io_region(unsigned long base, int num,
- unsigned long align, struct pcmcia_socket *s)
+static struct resource *__iodyn_find_io_region(struct pcmcia_socket *s,
+ unsigned long base, int num,
+ unsigned long align)
{
struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO,
dev_name(&s->dev));
@@ -72,9 +66,6 @@ static struct resource *iodyn_find_io_region(unsigned long base, int num,
unsigned long min = base;
int ret;
- if (align == 0)
- align = 0x10000;
-
data.mask = align - 1;
data.offset = base & data.mask;
@@ -94,10 +85,83 @@ static struct resource *iodyn_find_io_region(unsigned long base, int num,
return res;
}
+static int iodyn_find_io(struct pcmcia_socket *s, unsigned int attr,
+ unsigned int *base, unsigned int num,
+ unsigned int align)
+{
+ int i, ret = 0;
+
+ /* Check for an already-allocated window that must conflict with
+ * what was asked for. It is a hack because it does not catch all
+ * potential conflicts, just the most obvious ones.
+ */
+ for (i = 0; i < MAX_IO_WIN; i++) {
+ if (!s->io[i].res)
+ continue;
+
+ if (!*base)
+ continue;
+
+ if ((s->io[i].res->start & (align-1)) == *base)
+ return -EBUSY;
+ }
+
+ for (i = 0; i < MAX_IO_WIN; i++) {
+ struct resource *res = s->io[i].res;
+ unsigned int try;
+
+ if (res && (res->flags & IORESOURCE_BITS) !=
+ (attr & IORESOURCE_BITS))
+ continue;
+
+ if (!res) {
+ if (align == 0)
+ align = 0x10000;
+
+ res = s->io[i].res = __iodyn_find_io_region(s, *base,
+ num, align);
+ if (!res)
+ return -EINVAL;
+
+ *base = res->start;
+ s->io[i].res->flags =
+ ((res->flags & ~IORESOURCE_BITS) |
+ (attr & IORESOURCE_BITS));
+ s->io[i].InUse = num;
+ return 0;
+ }
+
+ /* Try to extend top of window */
+ try = res->end + 1;
+ if ((*base == 0) || (*base == try)) {
+ if (adjust_resource(s->io[i].res, res->start,
+ res->end - res->start + num + 1))
+ continue;
+ *base = try;
+ s->io[i].InUse += num;
+ return 0;
+ }
+
+ /* Try to extend bottom of window */
+ try = res->start - num;
+ if ((*base == 0) || (*base == try)) {
+ if (adjust_resource(s->io[i].res,
+ res->start - num,
+ res->end - res->start + num + 1))
+ continue;
+ *base = try;
+ s->io[i].InUse += num;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+
struct pccard_resource_ops pccard_iodyn_ops = {
.validate_mem = NULL,
- .adjust_io_region = iodyn_adjust_io_region,
- .find_io = iodyn_find_io_region,
+ .find_io = iodyn_find_io,
.find_mem = NULL,
.add_io = NULL,
.add_mem = NULL,
diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c
index 71838cae890c..142efac3c387 100644
--- a/drivers/pcmcia/rsrc_mgr.c
+++ b/drivers/pcmcia/rsrc_mgr.c
@@ -46,11 +46,21 @@ struct resource *pcmcia_make_resource(unsigned long start, unsigned long end,
return res;
}
+static int static_find_io(struct pcmcia_socket *s, unsigned int attr,
+ unsigned int *base, unsigned int num,
+ unsigned int align)
+{
+ if (!s->io_offset)
+ return -EINVAL;
+ *base = s->io_offset | (*base & 0x0fff);
+
+ return 0;
+}
+
struct pccard_resource_ops pccard_static_ops = {
.validate_mem = NULL,
- .adjust_io_region = NULL,
- .find_io = NULL,
+ .find_io = static_find_io,
.find_mem = NULL,
.add_io = NULL,
.add_mem = NULL,
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c
index c5ebc603b058..ba5256debde2 100644
--- a/drivers/pcmcia/rsrc_nonstatic.c
+++ b/drivers/pcmcia/rsrc_nonstatic.c
@@ -649,8 +649,9 @@ pcmcia_align(void *align_data, const struct resource *res,
* Adjust an existing IO region allocation, but making sure that we don't
* encroach outside the resources which the user supplied.
*/
-static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_start,
- unsigned long r_end, struct pcmcia_socket *s)
+static int __nonstatic_adjust_io_region(struct pcmcia_socket *s,
+ unsigned long r_start,
+ unsigned long r_end)
{
struct resource_map *m;
struct socket_data *s_data = s->resource_data;
@@ -663,8 +664,7 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star
if (start > r_start || r_end > end)
continue;
- ret = adjust_resource(res, r_start, r_end - r_start + 1);
- break;
+ ret = 0;
}
return ret;
@@ -683,8 +683,9 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star
======================================================================*/
-static struct resource *nonstatic_find_io_region(unsigned long base, int num,
- unsigned long align, struct pcmcia_socket *s)
+static struct resource *__nonstatic_find_io_region(struct pcmcia_socket *s,
+ unsigned long base, int num,
+ unsigned long align)
{
struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO,
dev_name(&s->dev));
@@ -693,9 +694,6 @@ static struct resource *nonstatic_find_io_region(unsigned long base, int num,
unsigned long min = base;
int ret;
- if (align == 0)
- align = 0x10000;
-
data.mask = align - 1;
data.offset = base & data.mask;
data.map = &s_data->io_db;
@@ -716,6 +714,92 @@ static struct resource *nonstatic_find_io_region(unsigned long base, int num,
return res;
}
+static int nonstatic_find_io(struct pcmcia_socket *s, unsigned int attr,
+ unsigned int *base, unsigned int num,
+ unsigned int align)
+{
+ int i, ret = 0;
+
+ /* Check for an already-allocated window that must conflict with
+ * what was asked for. It is a hack because it does not catch all
+ * potential conflicts, just the most obvious ones.
+ */
+ for (i = 0; i < MAX_IO_WIN; i++) {
+ if (!s->io[i].res)
+ continue;
+
+ if (!*base)
+ continue;
+
+ if ((s->io[i].res->start & (align-1)) == *base)
+ return -EBUSY;
+ }
+
+ for (i = 0; i < MAX_IO_WIN; i++) {
+ struct resource *res = s->io[i].res;
+ unsigned int try;
+
+ if (res && (res->flags & IORESOURCE_BITS) !=
+ (attr & IORESOURCE_BITS))
+ continue;
+
+ if (!res) {
+ if (align == 0)
+ align = 0x10000;
+
+ res = s->io[i].res = __nonstatic_find_io_region(s,
+ *base, num,
+ align);
+ if (!res)
+ return -EINVAL;
+
+ *base = res->start;
+ s->io[i].res->flags =
+ ((res->flags & ~IORESOURCE_BITS) |
+ (attr & IORESOURCE_BITS));
+ s->io[i].InUse = num;
+ return 0;
+ }
+
+ /* Try to extend top of window */
+ try = res->end + 1;
+ if ((*base == 0) || (*base == try)) {
+ ret = __nonstatic_adjust_io_region(s, res->start,
+ res->end + num);
+ if (!ret) {
+ ret = adjust_resource(s->io[i].res, res->start,
+ res->end - res->start + num + 1);
+ if (ret)
+ continue;
+ *base = try;
+ s->io[i].InUse += num;
+ return 0;
+ }
+ }
+
+ /* Try to extend bottom of window */
+ try = res->start - num;
+ if ((*base == 0) || (*base == try)) {
+ ret = __nonstatic_adjust_io_region(s,
+ res->start - num,
+ res->end);
+ if (!ret) {
+ ret = adjust_resource(s->io[i].res,
+ res->start - num,
+ res->end - res->start + num + 1);
+ if (ret)
+ continue;
+ *base = try;
+ s->io[i].InUse += num;
+ return 0;
+ }
+ }
+ }
+
+ return -EINVAL;
+}
+
+
static struct resource *nonstatic_find_mem_region(u_long base, u_long num,
u_long align, int low, struct pcmcia_socket *s)
{
@@ -946,8 +1030,7 @@ static void nonstatic_release_resource_db(struct pcmcia_socket *s)
struct pccard_resource_ops pccard_nonstatic_ops = {
.validate_mem = pcmcia_nonstatic_validate_mem,
- .adjust_io_region = nonstatic_adjust_io_region,
- .find_io = nonstatic_find_io_region,
+ .find_io = nonstatic_find_io,
.find_mem = nonstatic_find_mem_region,
.add_io = adjust_io,
.add_mem = adjust_memory,