summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/pcmcia/cs_internal.h2
-rw-r--r--drivers/pcmcia/ds.c4
-rw-r--r--drivers/pcmcia/rsrc_mgr.c6
-rw-r--r--drivers/pcmcia/rsrc_nonstatic.c123
-rw-r--r--include/pcmcia/ss.h2
5 files changed, 75 insertions, 62 deletions
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index 55867bc..634426b 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -117,7 +117,7 @@ int verify_cis_cache(struct pcmcia_socket *s);
int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function, cisdata_t code, void *parse);
/* In rsrc_mgr */
-void pcmcia_validate_mem(struct pcmcia_socket *s);
+int pcmcia_validate_mem(struct pcmcia_socket *s);
struct resource *pcmcia_find_io_region(unsigned long base, int num, unsigned long align,
struct pcmcia_socket *s);
int pcmcia_adjust_io_region(struct resource *res, unsigned long r_start,
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 6fb7639..b120794 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -583,7 +583,9 @@ static int pcmcia_card_add(struct pcmcia_socket *s)
if (!(s->resource_setup_done))
return -EAGAIN; /* try again, but later... */
- pcmcia_validate_mem(s);
+ if (pcmcia_validate_mem(s))
+ return -EAGAIN; /* try again, but later... */
+
ret = pccard_validate_cis(s, BIND_FN_ALL, &cisinfo);
if (ret || !cisinfo.Chains) {
ds_dbg(0, "invalid CIS or invalid resources\n");
diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c
index 0668384..b02598a 100644
--- a/drivers/pcmcia/rsrc_mgr.c
+++ b/drivers/pcmcia/rsrc_mgr.c
@@ -98,10 +98,12 @@ int pcmcia_adjust_resource_info(adjust_t *adj)
}
EXPORT_SYMBOL(pcmcia_adjust_resource_info);
-void pcmcia_validate_mem(struct pcmcia_socket *s)
+int pcmcia_validate_mem(struct pcmcia_socket *s)
{
if (s->resource_ops->validate_mem)
- s->resource_ops->validate_mem(s);
+ return s->resource_ops->validate_mem(s);
+ /* if there is no callback, we can assume that everything is OK */
+ return 0;
}
EXPORT_SYMBOL(pcmcia_validate_mem);
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c
index 00960a3..ebfcab5 100644
--- a/drivers/pcmcia/rsrc_nonstatic.c
+++ b/drivers/pcmcia/rsrc_nonstatic.c
@@ -407,56 +407,62 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s)
static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s)
{
- struct socket_data *s_data = s->resource_data;
- u_long ok;
- if (m == &s_data->mem_db)
- return 0;
- ok = inv_probe(m->next, s);
- if (ok) {
- if (m->base >= 0x100000)
- sub_interval(&s_data->mem_db, m->base, m->num);
- return ok;
- }
- if (m->base < 0x100000)
- return 0;
- return do_mem_probe(m->base, m->num, s);
+ struct socket_data *s_data = s->resource_data;
+ u_long ok;
+ if (m == &s_data->mem_db)
+ return 0;
+ ok = inv_probe(m->next, s);
+ if (ok) {
+ if (m->base >= 0x100000)
+ sub_interval(&s_data->mem_db, m->base, m->num);
+ return ok;
+ }
+ if (m->base < 0x100000)
+ return 0;
+ return do_mem_probe(m->base, m->num, s);
}
-static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
+static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
{
- struct resource_map *m, mm;
- static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
- u_long b, i, ok = 0;
- struct socket_data *s_data = s->resource_data;
+ struct resource_map *m, mm;
+ static unsigned char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
+ unsigned long b, i, ok = 0;
+ struct socket_data *s_data = s->resource_data;
- /* We do up to four passes through the list */
- if (probe_mask & MEM_PROBE_HIGH) {
- if (inv_probe(s_data->mem_db.next, s) > 0)
- return;
- printk(KERN_NOTICE "cs: warning: no high memory space "
- "available!\n");
- }
- if ((probe_mask & MEM_PROBE_LOW) == 0)
- return;
- for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
- mm = *m;
- /* Only probe < 1 MB */
- if (mm.base >= 0x100000) continue;
- if ((mm.base | mm.num) & 0xffff) {
- ok += do_mem_probe(mm.base, mm.num, s);
- continue;
+ /* We do up to four passes through the list */
+ if (probe_mask & MEM_PROBE_HIGH) {
+ if (inv_probe(s_data->mem_db.next, s) > 0)
+ return 0;
+ printk(KERN_NOTICE "cs: warning: no high memory space "
+ "available!\n");
+ return -ENODEV;
}
- /* Special probe for 64K-aligned block */
- for (i = 0; i < 4; i++) {
- b = order[i] << 12;
- if ((b >= mm.base) && (b+0x10000 <= mm.base+mm.num)) {
- if (ok >= mem_limit)
- sub_interval(&s_data->mem_db, b, 0x10000);
- else
- ok += do_mem_probe(b, 0x10000, s);
- }
+
+ for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
+ mm = *m;
+ /* Only probe < 1 MB */
+ if (mm.base >= 0x100000)
+ continue;
+ if ((mm.base | mm.num) & 0xffff) {
+ ok += do_mem_probe(mm.base, mm.num, s);
+ continue;
+ }
+ /* Special probe for 64K-aligned block */
+ for (i = 0; i < 4; i++) {
+ b = order[i] << 12;
+ if ((b >= mm.base) && (b+0x10000 <= mm.base+mm.num)) {
+ if (ok >= mem_limit)
+ sub_interval(&s_data->mem_db, b, 0x10000);
+ else
+ ok += do_mem_probe(b, 0x10000, s);
+ }
+ }
}
- }
+
+ if (ok > 0)
+ return 0;
+
+ return -ENODEV;
}
#else /* CONFIG_PCMCIA_PROBE */
@@ -478,27 +484,30 @@ static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
/*
* Locking note: Must be called with skt_sem held!
*/
-static void pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s)
+static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s)
{
struct socket_data *s_data = s->resource_data;
- if (probe_mem) {
- unsigned int probe_mask;
+ unsigned int probe_mask = MEM_PROBE_LOW;
+ int ret = 0;
- down(&rsrc_sem);
+ if (!probe_mem)
+ return 0;
- probe_mask = MEM_PROBE_LOW;
- if (s->features & SS_CAP_PAGE_REGS)
- probe_mask = MEM_PROBE_HIGH;
+ down(&rsrc_sem);
- if (probe_mask & ~s_data->rsrc_mem_probe) {
+ if (s->features & SS_CAP_PAGE_REGS)
+ probe_mask = MEM_PROBE_HIGH;
+
+ if (probe_mask & ~s_data->rsrc_mem_probe) {
+ if (s->state & SOCKET_PRESENT)
+ ret = validate_mem(s, probe_mask);
+ if (!ret)
s_data->rsrc_mem_probe |= probe_mask;
+ }
- if (s->state & SOCKET_PRESENT)
- validate_mem(s, probe_mask);
- }
+ up(&rsrc_sem);
- up(&rsrc_sem);
- }
+ return ret;
}
struct pcmcia_align_data {
diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h
index 9f7dab8..2889a69 100644
--- a/include/pcmcia/ss.h
+++ b/include/pcmcia/ss.h
@@ -125,7 +125,7 @@ struct pccard_operations {
};
struct pccard_resource_ops {
- void (*validate_mem) (struct pcmcia_socket *s);
+ int (*validate_mem) (struct pcmcia_socket *s);
int (*adjust_io_region) (struct resource *res,
unsigned long r_start,
unsigned long r_end,
OpenPOWER on IntegriCloud