drivers/pcmcia/cistpl.c | 290 ++++++++++++++++++++++++++---------------------- 1 files changed, 160 insertions(+), 130 deletions(-) diff -puN drivers/pcmcia/cistpl.c~pcmcia-8 drivers/pcmcia/cistpl.c --- 25/drivers/pcmcia/cistpl.c~pcmcia-8 2003-03-21 20:04:42.000000000 -0800 +++ 25-akpm/drivers/pcmcia/cistpl.c 2003-03-21 20:04:42.000000000 -0800 @@ -84,121 +84,6 @@ INT_MODULE_PARM(cis_width, 0); /* 16-bi /*====================================================================== - Low-level functions to read and write CIS memory. I think the - write routine is only useful for writing one-byte registers. - -======================================================================*/ - -/* Bits in attr field */ -#define IS_ATTR 1 -#define IS_INDIRECT 8 - -static int setup_cis_mem(socket_info_t *s); - -static void set_cis_map(socket_info_t *s, pccard_mem_map *mem) -{ - s->ss_entry->set_mem_map(s->sock, mem); - if (s->cap.features & SS_CAP_STATIC_MAP) { - if (s->cis_virt) - iounmap(s->cis_virt); - s->cis_virt = ioremap(mem->sys_start, s->cap.map_size); - } -} - -int read_cis_mem(socket_info_t *s, int attr, u_int addr, - u_int len, void *ptr) -{ - pccard_mem_map *mem = &s->cis_mem; - u_char *sys, *buf = ptr; - - DEBUG(3, "cs: read_cis_mem(%d, %#x, %u)\n", attr, addr, len); - if (setup_cis_mem(s) != 0) { - memset(ptr, 0xff, len); - return -1; - } - mem->flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0); - - if (attr & IS_INDIRECT) { - /* Indirect accesses use a bunch of special registers at fixed - locations in common memory */ - u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN; - if (attr & IS_ATTR) { addr *= 2; flags = ICTRL0_AUTOINC; } - mem->card_start = 0; mem->flags = MAP_ACTIVE; - set_cis_map(s, mem); - sys = s->cis_virt; - writeb(flags, sys+CISREG_ICTRL0); - writeb(addr & 0xff, sys+CISREG_IADDR0); - writeb((addr>>8) & 0xff, sys+CISREG_IADDR1); - writeb((addr>>16) & 0xff, sys+CISREG_IADDR2); - writeb((addr>>24) & 0xff, sys+CISREG_IADDR3); - for ( ; len > 0; len--, buf++) - *buf = readb(sys+CISREG_IDATA0); - } else { - u_int inc = 1; - if (attr) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; } - sys += (addr & (s->cap.map_size-1)); - mem->card_start = addr & ~(s->cap.map_size-1); - while (len) { - set_cis_map(s, mem); - sys = s->cis_virt + (addr & (s->cap.map_size-1)); - for ( ; len > 0; len--, buf++, sys += inc) { - if (sys == s->cis_virt+s->cap.map_size) break; - *buf = readb(sys); - } - mem->card_start += s->cap.map_size; - addr = 0; - } - } - DEBUG(3, "cs: %#2.2x %#2.2x %#2.2x %#2.2x ...\n", - *(u_char *)(ptr+0), *(u_char *)(ptr+1), - *(u_char *)(ptr+2), *(u_char *)(ptr+3)); - return 0; -} - -void write_cis_mem(socket_info_t *s, int attr, u_int addr, - u_int len, void *ptr) -{ - pccard_mem_map *mem = &s->cis_mem; - u_char *sys, *buf = ptr; - - DEBUG(3, "cs: write_cis_mem(%d, %#x, %u)\n", attr, addr, len); - if (setup_cis_mem(s) != 0) return; - mem->flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0); - - if (attr & IS_INDIRECT) { - /* Indirect accesses use a bunch of special registers at fixed - locations in common memory */ - u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN; - if (attr & IS_ATTR) { addr *= 2; flags = ICTRL0_AUTOINC; } - mem->card_start = 0; mem->flags = MAP_ACTIVE; - set_cis_map(s, mem); - sys = s->cis_virt; - writeb(flags, sys+CISREG_ICTRL0); - writeb(addr & 0xff, sys+CISREG_IADDR0); - writeb((addr>>8) & 0xff, sys+CISREG_IADDR1); - writeb((addr>>16) & 0xff, sys+CISREG_IADDR2); - writeb((addr>>24) & 0xff, sys+CISREG_IADDR3); - for ( ; len > 0; len--, buf++) - writeb(*buf, sys+CISREG_IDATA0); - } else { - int inc = 1; - if (attr & IS_ATTR) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; } - mem->card_start = addr & ~(s->cap.map_size-1); - while (len) { - set_cis_map(s, mem); - sys = s->cis_virt + (addr & (s->cap.map_size-1)); - for ( ; len > 0; len--, buf++, sys += inc) { - if (sys == s->cis_virt+s->cap.map_size) break; - writeb(*buf, sys); - } - mem->card_start += s->cap.map_size; - addr = 0; - } - } -} - -/*====================================================================== - This is tricky... when we set up CIS memory, we try to validate the memory window space allocations. @@ -256,36 +141,181 @@ static int checksum_match(u_long base) return ((a == b) && (a >= 0)); } -static int setup_cis_mem(socket_info_t *s) +void release_cis_mem(socket_info_t *s) +{ + if (s->cis_mem.sys_start != 0) { + s->cis_mem.flags &= ~MAP_ACTIVE; + s->ss_entry->set_mem_map(s->sock, &s->cis_mem); + if (!(s->cap.features & SS_CAP_STATIC_MAP)) + release_mem_region(s->cis_mem.sys_start, s->cap.map_size); + iounmap(s->cis_virt); + s->cis_mem.sys_start = 0; + s->cis_virt = NULL; + } +} + +/* + * Map the card memory at "card_offset" into virtual space. + * If flags & MAP_ATTRIB, map the attribute space, otherwise + * map the memory space. + */ +static unsigned char * +set_cis_map(socket_info_t *s, unsigned int card_offset, unsigned int flags) { + pccard_mem_map *mem = &s->cis_mem; if (!(s->cap.features & SS_CAP_STATIC_MAP) && - (s->cis_mem.sys_start == 0)) { + mem->sys_start == 0) { int low = !(s->cap.features & SS_CAP_PAGE_REGS); vs = s; validate_mem(cis_readable, checksum_match, low, s); - s->cis_mem.sys_start = 0; + mem->sys_start = 0; vs = NULL; - if (find_mem_region(&s->cis_mem.sys_start, s->cap.map_size, + if (find_mem_region(&mem->sys_start, s->cap.map_size, s->cap.map_size, low, "card services", s)) { printk(KERN_NOTICE "cs: unable to map card memory!\n"); + return NULL; + } + mem->sys_stop = mem->sys_start+s->cap.map_size-1; + s->cis_virt = ioremap(mem->sys_start, s->cap.map_size); + } + mem->card_start = card_offset; + mem->flags = flags; + s->ss_entry->set_mem_map(s->sock, mem); + if (s->cap.features & SS_CAP_STATIC_MAP) { + if (s->cis_virt) + iounmap(s->cis_virt); + s->cis_virt = ioremap(mem->sys_start, s->cap.map_size); + } + return s->cis_virt; +} + +/*====================================================================== + + Low-level functions to read and write CIS memory. I think the + write routine is only useful for writing one-byte registers. + +======================================================================*/ + +/* Bits in attr field */ +#define IS_ATTR 1 +#define IS_INDIRECT 8 + +int read_cis_mem(socket_info_t *s, int attr, u_int addr, + u_int len, void *ptr) +{ + u_char *sys, *end, *buf = ptr; + + DEBUG(3, "cs: read_cis_mem(%d, %#x, %u)\n", attr, addr, len); + + if (attr & IS_INDIRECT) { + /* Indirect accesses use a bunch of special registers at fixed + locations in common memory */ + u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN; + if (attr & IS_ATTR) { + addr *= 2; + flags = ICTRL0_AUTOINC; + } + + sys = set_cis_map(s, 0, MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0)); + if (!sys) { + memset(ptr, 0xff, len); return -1; } - s->cis_mem.sys_stop = s->cis_mem.sys_start+s->cap.map_size-1; - s->cis_virt = ioremap(s->cis_mem.sys_start, s->cap.map_size); + + writeb(flags, sys+CISREG_ICTRL0); + writeb(addr & 0xff, sys+CISREG_IADDR0); + writeb((addr>>8) & 0xff, sys+CISREG_IADDR1); + writeb((addr>>16) & 0xff, sys+CISREG_IADDR2); + writeb((addr>>24) & 0xff, sys+CISREG_IADDR3); + for ( ; len > 0; len--, buf++) + *buf = readb(sys+CISREG_IDATA0); + } else { + u_int inc = 1, card_offset, flags; + + flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0); + if (attr) { + flags |= MAP_ATTRIB; + inc++; + addr *= 2; + } + + card_offset = addr & ~(s->cap.map_size-1); + while (len) { + sys = set_cis_map(s, card_offset, flags); + if (!sys) { + memset(ptr, 0xff, len); + return -1; + } + end = sys + s->cap.map_size; + sys = sys + (addr & (s->cap.map_size-1)); + for ( ; len > 0; len--, buf++, sys += inc) { + if (sys == end) + break; + *buf = readb(sys); + } + card_offset += s->cap.map_size; + addr = 0; + } } + DEBUG(3, "cs: %#2.2x %#2.2x %#2.2x %#2.2x ...\n", + *(u_char *)(ptr+0), *(u_char *)(ptr+1), + *(u_char *)(ptr+2), *(u_char *)(ptr+3)); return 0; } -void release_cis_mem(socket_info_t *s) +void write_cis_mem(socket_info_t *s, int attr, u_int addr, + u_int len, void *ptr) { - if (s->cis_mem.sys_start != 0) { - s->cis_mem.flags &= ~MAP_ACTIVE; - s->ss_entry->set_mem_map(s->sock, &s->cis_mem); - if (!(s->cap.features & SS_CAP_STATIC_MAP)) - release_mem_region(s->cis_mem.sys_start, s->cap.map_size); - iounmap(s->cis_virt); - s->cis_mem.sys_start = 0; - s->cis_virt = NULL; + u_char *sys, *end, *buf = ptr; + + DEBUG(3, "cs: write_cis_mem(%d, %#x, %u)\n", attr, addr, len); + + if (attr & IS_INDIRECT) { + /* Indirect accesses use a bunch of special registers at fixed + locations in common memory */ + u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN; + if (attr & IS_ATTR) { + addr *= 2; + flags = ICTRL0_AUTOINC; + } + + sys = set_cis_map(s, 0, MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0)); + if (!sys) + return; /* FIXME: Error */ + + writeb(flags, sys+CISREG_ICTRL0); + writeb(addr & 0xff, sys+CISREG_IADDR0); + writeb((addr>>8) & 0xff, sys+CISREG_IADDR1); + writeb((addr>>16) & 0xff, sys+CISREG_IADDR2); + writeb((addr>>24) & 0xff, sys+CISREG_IADDR3); + for ( ; len > 0; len--, buf++) + writeb(*buf, sys+CISREG_IDATA0); + } else { + u_int inc = 1, card_offset, flags; + + flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0); + if (attr & IS_ATTR) { + flags |= MAP_ATTRIB; + inc++; + addr *= 2; + } + + card_offset = addr & ~(s->cap.map_size-1); + while (len) { + sys = set_cis_map(s, card_offset, flags); + if (!sys) + return; /* FIXME: error */ + + end = sys + s->cap.map_size; + sys = sys + (addr & (s->cap.map_size-1)); + for ( ; len > 0; len--, buf++, sys += inc) { + if (sys == end) + break; + writeb(*buf, sys); + } + card_offset += s->cap.map_size; + addr = 0; + } } } _