-static int
-checksum_match(struct pcmcia_socket *s, unsigned long base, unsigned long size)
-{
- struct resource *res1, *res2;
- int a = -1, b = -1;
-
- res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "cs memory probe");
- res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM, "cs memory probe");
-
- if (res1 && res2) {
- a = checksum(s, res1);
- b = checksum(s, res2);
- }
-
- free_region(res2);
- free_region(res1);
-
- return (a == b) && (a >= 0);
-}
-
-/*======================================================================
-
- The memory probe. If the memory list includes a 64K-aligned block
- below 1MB, we probe in 64K chunks, and as soon as we accumulate at
- least mem_limit free space, we quit.
-
-======================================================================*/
-
-static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s)
-{
- u_long i, j, bad, fail, step;
-
- printk(KERN_INFO "cs: memory probe 0x%06lx-0x%06lx:",
- base, base+num-1);
- bad = fail = 0;
- step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
- /* cis_readable wants to map 2x map_size */
- if (step < 2 * s->map_size)
- step = 2 * s->map_size;
- for (i = j = base; i < base+num; i = j + step) {
- if (!fail) {
- for (j = i; j < base+num; j += step) {
- if (cis_readable(s, j, step))
- break;
- }
- fail = ((i == base) && (j == base+num));
- }
- if (fail) {
- for (j = i; j < base+num; j += 2*step)
- if (checksum_match(s, j, step) &&
- checksum_match(s, j + step, step))
- break;
- }
- if (i != j) {
- if (!bad) printk(" excluding");
- printk(" %#05lx-%#05lx", i, j-1);
- sub_interval(&mem_db, i, j-i);
- bad += j-i;
- }
- }
- printk(bad ? "\n" : " clean.\n");
- return (num - bad);
-}
-
-#ifdef CONFIG_PCMCIA_PROBE
-
-static u_long inv_probe(resource_map_t *m, struct pcmcia_socket *s)
-{
- u_long ok;
- if (m == &mem_db)
- return 0;
- ok = inv_probe(m->next, s);
- if (ok) {
- if (m->base >= 0x100000)
- sub_interval(&mem_db, m->base, m->num);
- return ok;
- }
- if (m->base < 0x100000)
- return 0;
- return do_mem_probe(m->base, m->num, s);
-}
-
-void validate_mem(struct pcmcia_socket *s)
-{
- resource_map_t *m, mm;
- static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
- static int hi = 0, lo = 0;
- u_long b, i, ok = 0;
- int force_low = !(s->features & SS_CAP_PAGE_REGS);
-
- if (!probe_mem)
- return;
-
- down(&rsrc_sem);
- /* We do up to four passes through the list */
- if (!force_low) {
- if (hi++ || (inv_probe(mem_db.next, s) > 0))
- goto out;
- printk(KERN_NOTICE "cs: warning: no high memory space "
- "available!\n");
- }
- if (lo++)
- goto out;
- for (m = mem_db.next; m != &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(&mem_db, b, 0x10000);
- else
- ok += do_mem_probe(b, 0x10000, s);
- }
- }
- }
- out:
- up(&rsrc_sem);
-}
-
-#else /* CONFIG_PCMCIA_PROBE */
-
-void validate_mem(struct pcmcia_socket *s)
-{
- resource_map_t *m, mm;
- static int done = 0;
-
- if (probe_mem && done++ == 0) {
- down(&rsrc_sem);
- for (m = mem_db.next; m != &mem_db; m = mm.next) {
- mm = *m;
- if (do_mem_probe(mm.base, mm.num, s))
- break;
- }
- up(&rsrc_sem);
- }
-}
-
-#endif /* CONFIG_PCMCIA_PROBE */
-
-struct pcmcia_align_data {
- unsigned long mask;
- unsigned long offset;
- resource_map_t *map;
-};
-
-static void
-pcmcia_common_align(void *align_data, struct resource *res,
- unsigned long size, unsigned long align)
-{
- struct pcmcia_align_data *data = align_data;
- unsigned long start;
- /*
- * Ensure that we have the correct start address
- */
- start = (res->start & ~data->mask) + data->offset;
- if (start < res->start)
- start += data->mask + 1;
- res->start = start;
-}
-
-static void
-pcmcia_align(void *align_data, struct resource *res,
- unsigned long size, unsigned long align)
-{
- struct pcmcia_align_data *data = align_data;
- resource_map_t *m;
-
- pcmcia_common_align(data, res, size, align);
-
- for (m = data->map->next; m != data->map; m = m->next) {
- unsigned long start = m->base;
- unsigned long end = m->base + m->num - 1;
-
- /*
- * If the lower resources are not available, try aligning
- * to this entry of the resource database to see if it'll
- * fit here.
- */
- if (res->start < start) {
- res->start = start;
- pcmcia_common_align(data, res, size, align);
- }
-
- /*
- * If we're above the area which was passed in, there's
- * no point proceeding.
- */
- if (res->start >= res->end)
- break;
-
- if ((res->start + size - 1) <= end)
- break;
- }
-
- /*
- * If we failed to find something suitable, ensure we fail.
- */
- if (m == data->map)
- res->start = res->end;
-}
-
-/*
- * Adjust an existing IO region allocation, but making sure that we don't
- * encroach outside the resources which the user supplied.
- */