static void do_io_probe(ioaddr_t base, ioaddr_t num) { ioaddr_t i, j, bad, any; u_char *b, hole, most; printk(KERN_INFO "cs: IO port probe 0x%04x-0x%04x:", base, base+num-1); /* First, what does a floating port look like? */ b = kmalloc(256, GFP_KERNEL); if (!b) { printk(KERN_INFO " kmalloc failed!\n"); return; } memset(b, 0, 256); for (i = base, most = 0; i < base+num; i += 8) { if (check_region(i, 8) || check_io_region(i, 8)) continue; hole = inb(i); for (j = 1; j < 8; j++) if (inb(i+j) != hole) break; if ((j == 8) && (++b[hole] > b[most])) most = hole; if (b[most] == 127) break; } kfree(b); bad = any = 0; for (i = base; i < base+num; i += 8) { if (check_region(i, 8) || check_io_region(i, 8)) continue; for (j = 0; j < 8; j++) if (inb(i+j) != most) break; if (j < 8) { if (!any) printk(" excluding"); if (!bad) bad = any = i; } else { if (bad) { sub_interval(&io_db, bad, i-bad); printk(" %#04x-%#04x", bad, i-1); bad = 0; } } } if (bad) { if ((num > 16) && (bad == base) && (i == base+num)) { printk(" nothing: probe failed.\n"); return; } else { sub_interval(&io_db, bad, i-bad); printk(" %#04x-%#04x", bad, i-1); } } printk(any ? "\n" : " clean.\n"); }
static int do_mem_probe(u_long base, u_long num, int (*is_valid)(u_long), int (*do_cksum)(u_long)) { 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); for (i = j = base; i < base+num; i = j + step) { if (!fail) { for (j = i; j < base+num; j += step) if ((check_mem_region(j, step) == 0) && is_valid(j)) break; fail = ((i == base) && (j == base+num)); } if (fail) { for (j = i; j < base+num; j += 2*step) if ((check_mem_region(j, 2*step) == 0) && do_cksum(j) && do_cksum(j+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); }
static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end) { struct socket_data *data = s->resource_data; unsigned long size = end - start + 1; int ret = 0; if (end < start) return -EINVAL; down(&rsrc_sem); switch (action) { case ADD_MANAGED_RESOURCE: ret = add_interval(&data->mem_db, start, size); break; case REMOVE_MANAGED_RESOURCE: ret = sub_interval(&data->mem_db, start, size); if (!ret) { struct pcmcia_socket *socket; down_read(&pcmcia_socket_list_rwsem); list_for_each_entry(socket, &pcmcia_socket_list, socket_list) release_cis_mem(socket); up_read(&pcmcia_socket_list_rwsem); } break; default: ret = -EINVAL; } up(&rsrc_sem); return ret; }
static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end) { struct socket_data *data = s->resource_data; unsigned long size = end - start + 1; int ret = 0; if (end < start) return -EINVAL; if (end > IO_SPACE_LIMIT) return -EINVAL; down(&rsrc_sem); switch (action) { case ADD_MANAGED_RESOURCE: if (add_interval(&data->io_db, start, size) != 0) { ret = -EBUSY; break; } #ifdef CONFIG_PCMCIA_PROBE if (probe_io) do_io_probe(s, start, size); #endif break; case REMOVE_MANAGED_RESOURCE: sub_interval(&data->io_db, start, size); break; default: ret = -EINVAL; break; } up(&rsrc_sem); return ret; }
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); }
static u_long inv_probe(int (*is_valid)(u_long), int (*do_cksum)(u_long), resource_map_t *m) { u_long ok; if (m == &mem_db) return 0; ok = inv_probe(is_valid, do_cksum, m->next); 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, is_valid, do_cksum); }
static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) { 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 0; dev_printk(KERN_NOTICE, &s->dev, "cs: warning: no high memory space available!\n"); return -ENODEV; } 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; }
static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s) { struct socket_data *s_data = s->resource_data; 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); /* don't allow too large steps */ if (step > 0x800000) step = 0x800000; /* 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(&s_data->mem_db, i, j-i); bad += j-i; } } printk(bad ? "\n" : " clean.\n"); return (num - bad); }
void validate_mem(int (*is_valid)(u_long), int (*do_cksum)(u_long), int force_low, socket_info_t *s) { resource_map_t *m, *n; static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 }; static int hi = 0, lo = 0; u_long b, i, ok = 0; if (!probe_mem) return; /* We do up to four passes through the list */ if (!force_low) { if (hi++ || (inv_probe(is_valid, do_cksum, mem_db.next, s) > 0)) return; printk(KERN_NOTICE "cs: warning: no high memory space " "available!\n"); } if (lo++) return; for (m = mem_db.next; m != &mem_db; m = n) { n = m->next; /* Only probe < 1 MB */ if (m->base >= 0x100000) continue; if ((m->base | m->num) & 0xffff) { ok += do_mem_probe(m->base, m->num, is_valid, do_cksum, s); continue; } /* Special probe for 64K-aligned block */ for (i = 0; i < 4; i++) { b = order[i] << 12; if ((b >= m->base) && (b+0x10000 <= m->base+m->num)) { if (ok >= mem_limit) sub_interval(&mem_db, b, 0x10000); else ok += do_mem_probe(b, 0x10000, is_valid, do_cksum, s); } } } }
static void do_io_probe(struct pcmcia_socket *s, kio_addr_t base, kio_addr_t num) { struct resource *res; struct socket_data *s_data = s->resource_data; kio_addr_t i, j, bad; int any; u_char *b, hole, most; printk(KERN_INFO "cs: IO port probe %#lx-%#lx:", base, base+num-1); /* First, what does a floating port look like? */ b = kmalloc(256, GFP_KERNEL); if (!b) { printk(KERN_ERR "do_io_probe: unable to kmalloc 256 bytes"); return; } memset(b, 0, 256); for (i = base, most = 0; i < base+num; i += 8) { res = claim_region(NULL, i, 8, IORESOURCE_IO, "PCMCIA IO probe"); if (!res) continue; hole = inb(i); for (j = 1; j < 8; j++) if (inb(i+j) != hole) break; free_region(res); if ((j == 8) && (++b[hole] > b[most])) most = hole; if (b[most] == 127) break; } kfree(b); bad = any = 0; for (i = base; i < base+num; i += 8) { res = claim_region(NULL, i, 8, IORESOURCE_IO, "PCMCIA IO probe"); if (!res) continue; for (j = 0; j < 8; j++) if (inb(i+j) != most) break; free_region(res); if (j < 8) { if (!any) printk(" excluding"); if (!bad) bad = any = i; } else { if (bad) { sub_interval(&s_data->io_db, bad, i-bad); printk(" %#lx-%#lx", bad, i-1); bad = 0; } } } if (bad) { if ((num > 16) && (bad == base) && (i == base+num)) { printk(" nothing: probe failed.\n"); return; } else { sub_interval(&s_data->io_db, bad, i-bad); printk(" %#lx-%#lx", bad, i-1); } } printk(any ? "\n" : " clean.\n"); }