diff options
Diffstat (limited to 'drivers/pcmcia')
-rw-r--r-- | drivers/pcmcia/cardbus.c | 2 | ||||
-rw-r--r-- | drivers/pcmcia/cistpl.c | 1908 | ||||
-rw-r--r-- | drivers/pcmcia/rsrc_mgr.c | 3 |
3 files changed, 942 insertions, 971 deletions
diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c index ac0686efbf75..e6ab2a47d8cb 100644 --- a/drivers/pcmcia/cardbus.c +++ b/drivers/pcmcia/cardbus.c @@ -71,7 +71,7 @@ int __ref cb_alloc(struct pcmcia_socket *s) unsigned int max, pass; s->functions = pci_scan_slot(bus, PCI_DEVFN(0, 0)); - pci_fixup_cardbus(bus); + pci_fixup_cardbus(bus); max = bus->secondary; for (pass = 0; pass < 2; pass++) diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 2f3622dd4b69..f230f6543bff 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c @@ -54,46 +54,44 @@ static const u_int exponent[] = { /* Upper limit on reasonable # of tuples */ #define MAX_TUPLES 200 -/*====================================================================*/ - -/* Parameters that can be set with 'insmod' */ - /* 16-bit CIS? */ static int cis_width; module_param(cis_width, int, 0444); void release_cis_mem(struct pcmcia_socket *s) { - mutex_lock(&s->ops_mutex); - if (s->cis_mem.flags & MAP_ACTIVE) { - s->cis_mem.flags &= ~MAP_ACTIVE; - s->ops->set_mem_map(s, &s->cis_mem); - if (s->cis_mem.res) { - release_resource(s->cis_mem.res); - kfree(s->cis_mem.res); - s->cis_mem.res = NULL; + mutex_lock(&s->ops_mutex); + if (s->cis_mem.flags & MAP_ACTIVE) { + s->cis_mem.flags &= ~MAP_ACTIVE; + s->ops->set_mem_map(s, &s->cis_mem); + if (s->cis_mem.res) { + release_resource(s->cis_mem.res); + kfree(s->cis_mem.res); + s->cis_mem.res = NULL; + } + iounmap(s->cis_virt); + s->cis_virt = NULL; } - iounmap(s->cis_virt); - s->cis_virt = NULL; - } - mutex_unlock(&s->ops_mutex); + mutex_unlock(&s->ops_mutex); } -/* - * Map the card memory at "card_offset" into virtual space. +/** + * set_cis_map() - map the card memory at "card_offset" into virtual space. + * * If flags & MAP_ATTRIB, map the attribute space, otherwise * map the memory space. * * Must be called with ops_mutex held. */ -static void __iomem * -set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flags) +static void __iomem *set_cis_map(struct pcmcia_socket *s, + unsigned int card_offset, unsigned int flags) { pccard_mem_map *mem = &s->cis_mem; int ret; if (!(s->features & SS_CAP_STATIC_MAP) && (mem->res == NULL)) { - mem->res = pcmcia_find_mem_region(0, s->map_size, s->map_size, 0, s); + mem->res = pcmcia_find_mem_region(0, s->map_size, + s->map_size, 0, s); if (mem->res == NULL) { dev_printk(KERN_NOTICE, &s->dev, "cs: unable to map card memory!\n"); @@ -124,165 +122,170 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag 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 +/** + * pcmcia_read_cis_mem() - low-level function to read CIS memory + */ int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, u_int len, void *ptr) { - void __iomem *sys, *end; - unsigned char *buf = ptr; - - dev_dbg(&s->dev, "pcmcia_read_cis_mem(%d, %#x, %u)\n", attr, addr, len); - - mutex_lock(&s->ops_mutex); - 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; - } + void __iomem *sys, *end; + unsigned char *buf = ptr; - sys = set_cis_map(s, 0, MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0)); - if (!sys) { - dev_dbg(&s->dev, "could not map memory\n"); - memset(ptr, 0xff, len); - mutex_unlock(&s->ops_mutex); - return -1; - } + dev_dbg(&s->dev, "pcmcia_read_cis_mem(%d, %#x, %u)\n", attr, addr, len); - 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; - - if (addr > CISTPL_MAX_CIS_SIZE) - dev_dbg(&s->dev, "attempt to read CIS mem at addr %#x", addr); - - flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0); - if (attr) { - flags |= MAP_ATTRIB; - inc++; - addr *= 2; - } + mutex_lock(&s->ops_mutex); + 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; + } - card_offset = addr & ~(s->map_size-1); - while (len) { - sys = set_cis_map(s, card_offset, flags); - if (!sys) { - dev_dbg(&s->dev, "could not map memory\n"); - memset(ptr, 0xff, len); - mutex_unlock(&s->ops_mutex); - return -1; - } - end = sys + s->map_size; - sys = sys + (addr & (s->map_size-1)); - for ( ; len > 0; len--, buf++, sys += inc) { - if (sys == end) - break; - *buf = readb(sys); - } - card_offset += s->map_size; - addr = 0; + sys = set_cis_map(s, 0, MAP_ACTIVE | + ((cis_width) ? MAP_16BIT : 0)); + if (!sys) { + dev_dbg(&s->dev, "could not map memory\n"); + memset(ptr, 0xff, len); + mutex_unlock(&s->ops_mutex); + return -1; + } + + 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; + + if (addr > CISTPL_MAX_CIS_SIZE) + dev_dbg(&s->dev, + "attempt to read CIS mem at addr %#x", addr); + + flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0); + if (attr) { + flags |= MAP_ATTRIB; + inc++; + addr *= 2; + } + + card_offset = addr & ~(s->map_size-1); + while (len) { + sys = set_cis_map(s, card_offset, flags); + if (!sys) { + dev_dbg(&s->dev, "could not map memory\n"); + memset(ptr, 0xff, len); + mutex_unlock(&s->ops_mutex); + return -1; + } + end = sys + s->map_size; + sys = sys + (addr & (s->map_size-1)); + for ( ; len > 0; len--, buf++, sys += inc) { + if (sys == end) + break; + *buf = readb(sys); + } + card_offset += s->map_size; + addr = 0; + } } - } - mutex_unlock(&s->ops_mutex); - dev_dbg(&s->dev, " %#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; + mutex_unlock(&s->ops_mutex); + dev_dbg(&s->dev, " %#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; } +/** + * pcmcia_write_cis_mem() - low-level function to write CIS memory + * + * Probably only useful for writing one-byte registers. + */ void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, u_int len, void *ptr) { - void __iomem *sys, *end; - unsigned char *buf = ptr; - - dev_dbg(&s->dev, "pcmcia_write_cis_mem(%d, %#x, %u)\n", attr, addr, len); - - mutex_lock(&s->ops_mutex); - 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; - } + void __iomem *sys, *end; + unsigned char *buf = ptr; - sys = set_cis_map(s, 0, MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0)); - if (!sys) { - dev_dbg(&s->dev, "could not map memory\n"); - mutex_unlock(&s->ops_mutex); - return; /* FIXME: Error */ - } + dev_dbg(&s->dev, + "pcmcia_write_cis_mem(%d, %#x, %u)\n", attr, addr, len); - 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; - } + mutex_lock(&s->ops_mutex); + 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; + } - card_offset = addr & ~(s->map_size-1); - while (len) { - sys = set_cis_map(s, card_offset, flags); - if (!sys) { - dev_dbg(&s->dev, "could not map memory\n"); - mutex_unlock(&s->ops_mutex); - return; /* FIXME: error */ - } - - end = sys + s->map_size; - sys = sys + (addr & (s->map_size-1)); - for ( ; len > 0; len--, buf++, sys += inc) { - if (sys == end) - break; - writeb(*buf, sys); - } - card_offset += s->map_size; - addr = 0; - } - } - mutex_unlock(&s->ops_mutex); -} + sys = set_cis_map(s, 0, MAP_ACTIVE | + ((cis_width) ? MAP_16BIT : 0)); + if (!sys) { + dev_dbg(&s->dev, "could not map memory\n"); + mutex_unlock(&s->ops_mutex); + 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->map_size-1); + while (len) { + sys = set_cis_map(s, card_offset, flags); + if (!sys) { + dev_dbg(&s->dev, "could not map memory\n"); + mutex_unlock(&s->ops_mutex); + return; /* FIXME: error */ + } - This is a wrapper around read_cis_mem, with the same interface, - but which caches information, for cards whose CIS may not be - readable all the time. + end = sys + s->map_size; + sys = sys + (addr & (s->map_size-1)); + for ( ; len > 0; len--, buf++, sys += inc) { + if (sys == end) + break; + writeb(*buf, sys); + } + card_offset += s->map_size; + addr = 0; + } + } + mutex_unlock(&s->ops_mutex); +} -======================================================================*/ +/** + * read_cis_cache() - read CIS memory or its associated cache + * + * This is a wrapper around read_cis_mem, with the same interface, + * but which caches information, for cards whose CIS may not be + * readable all the time. + */ static int read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, size_t len, void *ptr) { @@ -353,7 +356,6 @@ remove_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, u_int len) * This destroys the CIS cache but keeps any fake CIS alive. Must be * called with ops_mutex held. */ - void destroy_cis_cache(struct pcmcia_socket *s) { struct list_head *l, *n; @@ -366,13 +368,9 @@ void destroy_cis_cache(struct pcmcia_socket *s) } } -/*====================================================================== - - This verifies if the CIS of a card matches what is in the CIS - cache. - -======================================================================*/ - +/** + * verify_cis_cache() - does the CIS match what is in the CIS cache? + */ int verify_cis_cache(struct pcmcia_socket *s) { struct cis_cache_entry *cis; @@ -404,13 +402,12 @@ int verify_cis_cache(struct pcmcia_socket *s) return 0; } -/*====================================================================== - - For really bad cards, we provide a facility for uploading a - replacement CIS. - -======================================================================*/ - +/** + * pcmcia_replace_cis() - use a replacement CIS instead of the card's CIS + * + * For really bad cards, we provide a facility for uploading a + * replacement CIS. + */ int pcmcia_replace_cis(struct pcmcia_socket *s, const u8 *data, const size_t len) { @@ -433,17 +430,13 @@ int pcmcia_replace_cis(struct pcmcia_socket *s, return 0; } -/*====================================================================== - - The high-level CIS tuple services - -======================================================================*/ +/* The high-level CIS tuple services */ typedef struct tuple_flags { - u_int link_space:4; - u_int has_link:1; - u_int mfc_fn:3; - u_int space:4; + u_int link_space:4; + u_int has_link:1; + u_int mfc_fn:3; + u_int space:4; } tuple_flags; #define LINK_SPACE(f) (((tuple_flags *)(&(f)))->link_space) @@ -451,982 +444,961 @@ typedef struct tuple_flags { #define MFC_FN(f) (((tuple_flags *)(&(f)))->mfc_fn) #define SPACE(f) (((tuple_flags *)(&(f)))->space) -int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function, tuple_t *tuple) +int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function, + tuple_t *tuple) { - if (!s) - return -EINVAL; - - if (!(s->state & SOCKET_PRESENT) || (s->state & SOCKET_CARDBUS)) - return -ENODEV; - tuple->TupleLink = tuple->Flags = 0; - - /* Assume presence of a LONGLINK_C to address 0 */ - tuple->CISOffset = tuple->LinkOffset = 0; - SPACE(tuple->Flags) = HAS_LINK(tuple->Flags) = 1; - - if ((s->functions > 1) && !(tuple->Attributes & TUPLE_RETURN_COMMON)) { - cisdata_t req = tuple->DesiredTuple; - tuple->DesiredTuple = CISTPL_LONGLINK_MFC; - if (pccard_get_next_tuple(s, function, tuple) == 0) { - tuple->DesiredTuple = CISTPL_LINKTARGET; - if (pccard_get_next_tuple(s, function, tuple) != 0) - return -ENOSPC; - } else - tuple->CISOffset = tuple->TupleLink = 0; - tuple->DesiredTuple = req; - } - return pccard_get_next_tuple(s, function, tuple); + if (!s) + return -EINVAL; + + if (!(s->state & SOCKET_PRESENT) || (s->state & SOCKET_CARDBUS)) + return -ENODEV; + tuple->TupleLink = tuple->Flags = 0; + + /* Assume presence of a LONGLINK_C to address 0 */ + tuple->CISOffset = tuple->LinkOffset = 0; + SPACE(tuple->Flags) = HAS_LINK(tuple->Flags) = 1; + + if ((s->functions > 1) && !(tuple->Attributes & TUPLE_RETURN_COMMON)) { + cisdata_t req = tuple->DesiredTuple; + tuple->DesiredTuple = CISTPL_LONGLINK_MFC; + if (pccard_get_next_tuple(s, function, tuple) == 0) { + tuple->DesiredTuple = CISTPL_LINKTARGET; + if (pccard_get_next_tuple(s, function, tuple) != 0) + return -ENOSPC; + } else + tuple->CISOffset = tuple->TupleLink = 0; + tuple->DesiredTuple = req; + } + return pccard_get_next_tuple(s, function, tuple); } static int follow_link(struct pcmcia_socket *s, tuple_t *tuple) { - u_char link[5]; - u_int ofs; - int ret; - - if (MFC_FN(tuple->Flags)) { - /* Get indirect link from the MFC tuple */ - ret = read_cis_cache(s, LINK_SPACE(tuple->Flags), - tuple->LinkOffset, 5, link); - if (ret) + u_char link[5]; + u_int ofs; + int ret; + + if (MFC_FN(tuple->Flags)) { + /* Get indirect link from the MFC tuple */ + ret = read_cis_cache(s, LINK_SPACE(tuple->Flags), + tuple->LinkOffset, 5, link); + if (ret) + return -1; + ofs = get_unaligned_le32(link + 1); + SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR); + /* Move to the next indirect link */ + tuple->LinkOffset += 5; + MFC_FN(tuple->Flags)--; + } else if (HAS_LINK(tuple->Flags)) { + ofs = tuple->LinkOffset; + SPACE(tuple->Flags) = LINK_SPACE(tuple->Flags); + HAS_LINK(tuple->Flags) = 0; + } else return -1; - ofs = get_unaligned_le32(link + 1); - SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR); - /* Move to the next indirect link */ - tuple->LinkOffset += 5; - MFC_FN(tuple->Flags)--; - } else if (HAS_LINK(tuple->Flags)) { - ofs = tuple->LinkOffset; - SPACE(tuple->Flags) = LINK_SPACE(tuple->Flags); - HAS_LINK(tuple->Flags) = 0; - } else { - return -1; - } - if (SPACE(tuple->Flags)) { - /* This is ugly, but a common CIS error is to code the long - link offset incorrectly, so we check the right spot... */ + + if (SPACE(tuple->Flags)) { + /* This is ugly, but a common CIS error is to code the long + link offset incorrectly, so we check the right spot... */ + ret = read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link); + if (ret) + return -1; + if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) && + (strncmp(link+2, "CIS", 3) == 0)) + return ofs; + remove_cis_cache(s, SPACE(tuple->Flags), ofs, 5); + /* Then, we try the wrong spot... */ + ofs = ofs >> 1; + } ret = read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link); if (ret) return -1; if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) && - (strncmp(link+2, "CIS", 3) == 0)) - return ofs; + (strncmp(link+2, "CIS", 3) == 0)) + return ofs; remove_cis_cache(s, SPACE(tuple->Flags), ofs, 5); - /* Then, we try the wrong spot... */ - ofs = ofs >> 1; - } - ret = read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link); - if (ret) - return -1; - if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) && - (strncmp(link+2, "CIS", 3) == 0)) - return ofs; - remove_cis_cache(s, SPACE(tuple->Flags), ofs, 5); - return -1; + return -1; } -int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, tuple_t *tuple) +int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, + tuple_t *tuple) { - u_char link[2], tmp; - int ofs, i, attr; - int ret; - - if (!s) - return -EINVAL; - if (!(s->state & SOCKET_PRESENT) || (s->state & SOCKET_CARDBUS)) - return -ENODEV; - - link[1] = tuple->TupleLink; - ofs = tuple->CISOffset + tuple->TupleLink; - attr = SPACE(tuple->Flags); - - for (i = 0; i < MAX_TUPLES; i++) { - if (link[1] == 0xff) { - link[0] = CISTPL_END; - } else { - ret = read_cis_cache(s, attr, ofs, 2, link); - if (ret) - return -1; - if (link[0] == CISTPL_NULL) { - ofs++; continue; - } - } + u_char link[2], tmp; + int ofs, i, attr; + int ret; - /* End of chain? Follow long link if possible */ - if (link[0] == CISTPL_END) { - ofs = follow_link(s, tuple); - if (ofs < 0) - return -ENOSPC; - attr = SPACE(tuple->Flags); - ret = read_cis_cache(s, attr, ofs, 2, link); - if (ret) - return -1; - } + if (!s) + return -EINVAL; + if (!(s->state & SOCKET_PRESENT) || (s->state & SOCKET_CARDBUS)) + return -ENODEV; - /* Is this a link tuple? Make a note of it */ - if ((link[0] == CISTPL_LONGLINK_A) || - (link[0] == CISTPL_LONGLINK_C) || - (link[0] == CISTPL_LONGLINK_MFC) || - (link[0] == CISTPL_LINKTARGET) || - (link[0] == CISTPL_INDIRECT) || - (link[0] == CISTPL_NO_LINK)) { - switch (link[0]) { - case CISTPL_LONGLINK_A: - HAS_LINK(tuple->Flags) = 1; - LINK_SPACE(tuple->Flags) = attr | IS_ATTR; - ret = read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset); - if (ret) - return -1; - break; - case CISTPL_LONGLINK_C: - HAS_LINK(tuple->Flags) = 1; - LINK_SPACE(tuple->Flags) = attr & ~IS_ATTR; - ret = read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset); - if (ret) - return -1; - break; - case CISTPL_INDIRECT: - HAS_LINK(tuple->Flags) = 1; - LINK_SPACE(tuple->Flags) = IS_ATTR | IS_INDIRECT; - tuple->LinkOffset = 0; - break; - case CISTPL_LONGLINK_MFC: - tuple->LinkOffset = ofs + 3; - LINK_SPACE(tuple->Flags) = attr; - if (function == BIND_FN_ALL) { - /* Follow all the MFC links */ - ret = read_cis_cache(s, attr, ofs+2, 1, &tmp); - if (ret) - return -1; - MFC_FN(tuple->Flags) = tmp; - } else { - /* Follow exactly one of the links */ - MFC_FN(tuple->Flags) = 1; - tuple->LinkOffset += function * 5; + link[1] = tuple->TupleLink; + ofs = tuple->CISOffset + tuple->TupleLink; + attr = SPACE(tuple->Flags); + + for (i = 0; i < MAX_TUPLES; i++) { + if (link[1] == 0xff) + link[0] = CISTPL_END; + else { + ret = read_cis_cache(s, attr, ofs, 2, link); + if (ret) + return -1; + if (link[0] == CISTPL_NULL) { + ofs++; + continue; + } } - break; - case CISTPL_NO_LINK: - HAS_LINK(tuple->Flags) = 0; - break; - } - if ((tuple->Attributes & TUPLE_RETURN_LINK) && - (tuple->DesiredTuple == RETURN_FIRST_TUPLE)) - break; - } else - if (tuple->DesiredTuple == RETURN_FIRST_TUPLE) - break; - if (link[0] == tuple->DesiredTuple) - break; - ofs += link[1] + 2; - } - if (i == MAX_TUPLES) { - dev_dbg(&s->dev, "cs: overrun in pcmcia_get_next_tuple\n"); - return -ENOSPC; - } - - tuple->TupleCode = link[0]; - tuple->TupleLink = link[1]; - tuple->CISOffset = ofs + 2; - return 0; -} + /* End of chain? Follow long link if possible */ + if (link[0] == CISTPL_END) { + ofs = follow_link(s, tuple); + if (ofs < 0) + return -ENOSPC; + attr = SPACE(tuple->Flags); + ret = read_cis_cache(s, attr, ofs, 2, link); + if (ret) + return -1; + } -/*====================================================================*/ + /* Is this a link tuple? Make a note of it */ + if ((link[0] == CISTPL_LONGLINK_A) || + (link[0] == CISTPL_LONGLINK_C) || + (link[0] == CISTPL_LONGLINK_MFC) || + (link[0] == CISTPL_LINKTARGET) || + (link[0] == CISTPL_INDIRECT) || + (link[0] == CISTPL_NO_LINK)) { + switch (link[0]) { + case CISTPL_LONGLINK_A: + HAS_LINK(tuple->Flags) = 1; + LINK_SPACE(tuple->Flags) = attr | IS_ATTR; + ret = read_cis_cache(s, attr, ofs+2, 4, + &tuple->LinkOffset); + if (ret) + return -1; + break; + case CISTPL_LONGLINK_C: + HAS_LINK(tuple->Flags) = 1; + LINK_SPACE(tuple->Flags) = attr & ~IS_ATTR; + ret = read_cis_cache(s, attr, ofs+2, 4, + &tuple->LinkOffset); + if (ret) + return -1; + break; + case CISTPL_INDIRECT: + HAS_LINK(tuple->Flags) = 1; + LINK_SPACE(tuple->Flags) = IS_ATTR | + IS_INDIRECT; + tuple->LinkOffset = 0; + break; + case CISTPL_LONGLINK_MFC: + tuple->LinkOffset = ofs + 3; + LINK_SPACE(tuple->Flags) = attr; + if (function == BIND_FN_ALL) { + /* Follow all the MFC links */ + ret = read_cis_cache(s, attr, ofs+2, + 1, &tmp); + if (ret) + return -1; + MFC_FN(tuple->Flags) = tmp; + } else { + /* Follow exactly one of the links */ + MFC_FN(tuple->Flags) = 1; + tuple->LinkOffset += function * 5; + } + break; + case CISTPL_NO_LINK: + HAS_LINK(tuple->Flags) = 0; + break; + } + if ((tuple->Attributes & TUPLE_RETURN_LINK) && + (tuple->DesiredTuple == RETURN_FIRST_TUPLE)) + break; + } else + if (tuple->DesiredTuple == RETURN_FIRST_TUPLE) + break; + + if (link[0] == tuple->DesiredTuple) + break; + ofs += link[1] + 2; + } + if (i == MAX_TUPLES) { + dev_dbg(&s->dev, "cs: overrun in pcmcia_get_next_tuple\n"); + return -ENOSPC; + } -#define _MIN(a, b) (((a) < (b)) ? (a) : (b)) + tuple->TupleCode = link[0]; + tuple->TupleLink = link[1]; + tuple->CISOffset = ofs + 2; + return 0; +} int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple) { - u_int len; - int ret; + u_int len; + int ret; - if (!s) - return -EINVAL; + if (!s) + return -EINVAL; - if (tuple->TupleLink < tuple->TupleOffset) - return -ENOSPC; - len = tuple->TupleLink - tuple->TupleOffset; - tuple->TupleDataLen = tuple->TupleLink; - if (len == 0) + if (tuple->TupleLink < tuple->TupleOffset) + return -ENOSPC; + len = tuple->TupleLink - tuple->TupleOffset; + tuple->TupleDataLen = tuple->TupleLink; + if (len == 0) + return 0; + ret = read_cis_cache(s, SPACE(tuple->Flags), + tuple->CISOffset + tuple->TupleOffset, + min(len, (u_int) tuple->TupleDataMax), + tuple->TupleData); + if (ret) + return -1; return 0; - ret = read_cis_cache(s, SPACE(tuple->Flags), - tuple->CISOffset + tuple->TupleOffset, - _MIN(len, tuple->TupleDataMax), tuple->TupleData); - if (ret) - return -1; - return 0; } -/*====================================================================== - - Parsing routines for individual tuples - -======================================================================*/ +/* Parsing routines for individual tuples */ static int parse_device(tuple_t *tuple, cistpl_device_t *device) { - int i; - u_char scale; - u_char *p, *q; + int i; + u_char scale; + u_char *p, *q; - p = (u_char *)tuple->TupleData; - q = p + tuple->TupleDataLen; + p = (u_char *)tuple->TupleData; + q = p + tuple->TupleDataLen; - device->ndev = 0; - for (i = 0; i < CISTPL_MAX_DEVICES; i++) { + device->ndev = 0; + for (i = 0; i < CISTPL_MAX_DEVICES; i++) { - if (*p == 0xff) - break; - device->dev[i].type = (*p >> 4); - device->dev[i].wp = (*p & 0x08) ? 1 : 0; - switch (*p & 0x07) { - case 0: - device->dev[i].speed = 0; - break; - case 1: - device->dev[i].speed = 250; - break; - case 2: - device->dev[i].speed = 200; - break; - case 3: - device->dev[i].speed = 150; - break; - case 4: - device->dev[i].speed = 100; - break; - case 7: - if (++p == q) - return -EINVAL; - device->dev[i].speed = SPEED_CVT(*p); - while (*p & 0x80) + if (*p == 0xff) + break; + device->dev[i].type = (*p >> 4); + device->dev[i].wp = (*p & 0x08) ? 1 : 0; + switch (*p & 0x07) { + case 0: + device->dev[i].speed = 0; + break; + case 1: + device->dev[i].speed = 250; + break; + case 2: + device->dev[i].speed = 200; + break; + case 3: + device->dev[i].speed = 150; + break; + case 4: + device->dev[i].speed = 100; + break; + case 7: if (++p == q) return -EINVAL; - break; - default: - return -EINVAL; - } + device->dev[i].speed = SPEED_CVT(*p); + while (*p & 0x80) + if (++p == q) + return -EINVAL; + break; + default: + return -EINVAL; + } - if (++p == q) - return -EINVAL; - if (*p == 0xff) - break; - scale = *p & 7; - if (scale == 7) - return -EINVAL; - device->dev[i].size = ((*p >> 3) + 1) * (512 << (scale*2)); - device->ndev++; - if (++p == q) - break; - } + if (++p == q) + return -EINVAL; + if (*p == 0xff) + break; + scale = *p & 7; + if (scale == 7) + return -EINVAL; + device->dev[i].size = ((*p >> 3) + 1) * (512 << (scale*2)); + device->ndev++; + if (++p == q) + break; + } - return 0; + return 0; } -/*====================================================================*/ static int parse_checksum(tuple_t *tuple, cistpl_checksum_t *csum) { - u_char *p; - if (tuple->TupleDataLen < 5) - return -EINVAL; - p = (u_char *) tuple->TupleData; - csum->addr = tuple->CISOffset + get_unaligned_le16(p) - 2; - csum->len = get_unaligned_le16(p + 2); - csum->sum = *(p + 4); - return 0; + u_char *p; + if (tuple->TupleDataLen < 5) + return -EINVAL; + p = (u_char *) tuple->TupleData; + csum->addr = tuple->CISOffset + get_unaligned_le16(p) - 2; + csum->len = get_unaligned_le16(p + 2); + csum->sum = *(p + 4); + return 0; } -/*====================================================================*/ static int parse_longlink(tuple_t *tuple, cistpl_longlink_t *link) { - if (tuple->TupleDataLen < 4) - return -EINVAL; - link->addr = get_unaligned_le32(tuple->TupleData); - return 0; + if (tuple->TupleDataLen < 4) + return -EINVAL; + link->addr = get_unaligned_le32(tuple->TupleData); + return 0; } -/*====================================================================*/ -static int parse_longlink_mfc(tuple_t *tuple, - cistpl_longlink_mfc_t *link) +static int parse_longlink_mfc(tuple_t *tuple, cistpl_longlink_mfc_t *link) { - u_char *p; - int i; - - p = (u_char *)tuple->TupleData; - - link->nfn = *p; p++; - if (tuple->TupleDataLen <= link->nfn*5) - return -EINVAL; - for (i = 0; i < link->nfn; i++) { - link->fn[i].space = *p; p++; - link->fn[i].addr = get_unaligned_le32(p); - p += 4; - } - return 0; + u_char *p; + int i; + + p = (u_char *)tuple->TupleData; + + link->nfn = *p; p++; + if (tuple->TupleDataLen <= link->nfn*5) + return -EINVAL; + for (i = 0; i < link->nfn; i++) { + link->fn[i].space = *p; p++; + link->fn[i].addr = get_unaligned_le32(p); + p += 4; + } + return 0; } -/*====================================================================*/ static int parse_strings(u_char *p, u_char *q, int max, char *s, u_char *ofs, u_char *found) { - int i, j, ns; + int i, j, ns; - if (p == q) - return -EINVAL; - ns = 0; j = 0; - for (i = 0; i < max; i++) { - if (*p == 0xff) - break; - ofs[i] = j; - ns++; - for (;;) { - s[j++] = (*p == 0xff) ? '\0' : *p; - if ((*p == '\0') || (*p == 0xff)) - break; - if (++p == q) - return -EINVAL; + if (p == q) + return -EINVAL; + ns = 0; j = 0; + for (i = 0; i < max; i++) { + if (*p == 0xff) + break; + ofs[i] = j; + ns++; + for (;;) { + s[j++] = (*p == 0xff) ? '\0' : *p; + if ((*p == '\0') || (*p == 0xff)) + break; + if (++p == q) + return -EINVAL; + } + if ((*p == 0xff) || (++p == q)) + break; } - if ((*p == 0xff) || (++p == q)) - break; - } - if (found) { - *found = ns; - return 0; - } else { + if (found) { + *found = ns; + return 0; + } + return (ns == max) ? 0 : -EINVAL; - } } -/*====================================================================*/ static int parse_vers_1(tuple_t *tuple, cistpl_vers_1_t *vers_1) { - u_char *p, *q; + u_char *p, *q; - p = (u_char *)tuple->TupleData; - q = p + tuple->TupleDataLen; + p = (u_char *)tuple->TupleData; + q = p + tuple->TupleDataLen; - vers_1->major = *p; p++; - vers_1->minor = *p; p++; - if (p >= q) - return -EINVAL; + vers_1->major = *p; p++; + vers_1->minor = *p; p++; + if (p >= q) + return -EINVAL; - return parse_strings(p, q, CISTPL_VERS_1_MAX_PROD_STRINGS, - vers_1->str, vers_1->ofs, &vers_1->ns); + return parse_strings(p, q, CISTPL_VERS_1_MAX_PROD_STRINGS, + vers_1->str, vers_1->ofs, &vers_1->ns); } -/*====================================================================*/ static int parse_altstr(tuple_t *tuple, cistpl_altstr_t *altstr) { - u_char *p, *q; + u_char *p, *q; - p = (u_char *)tuple->TupleData; - q = p + tuple->TupleDataLen; + p = (u_char *)tuple->TupleData; + q = p + tuple->TupleDataLen; - return parse_strings(p, q, CISTPL_MAX_ALTSTR_STRINGS, - altstr->str, altstr->ofs, &altstr->ns); + return parse_strings(p, q, CISTPL_MAX_ALTSTR_STRINGS, + altstr->str, altstr->ofs, &altstr->ns); } -/*====================================================================*/ static int parse_jedec(tuple_t *tuple, cistpl_jedec_t *jedec) { - u_char *p, *q; - int nid; + u_char *p, *q; + int nid; - p = (u_char *)tuple->TupleData; - q = p + tuple->TupleDataLen; + p = (u_char *)tuple->TupleData; + q = p + tuple->TupleDataLen; - for (nid = 0; nid < CISTPL_MAX_DEVICES; nid++) { - if (p > q-2) - break; - jedec->id[nid].mfr = p[0]; - jedec->id[nid].info = p[1]; - p += 2; - } - jedec->nid = nid; - return 0; + for (nid = 0; nid < CISTPL_MAX_DEVICES; nid++) { + if (p > q-2) + break; + jedec->id[nid].mfr = p[0]; + jedec->id[nid].info = p[1]; + p += 2; + } + jedec->nid = nid; + return 0; } -/*====================================================================*/ static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m) { - if (tuple->TupleDataLen < 4) - return -EINVAL; - m->manf = get_unaligned_le16(tuple->TupleData); - m->card = get_unaligned_le16(tuple->TupleData + 2); - return 0; + if (tuple->TupleDataLen < 4) + return -EINVAL; + m->manf = get_unaligned_le16(tuple->TupleData); + m->card = get_unaligned_le16(tuple->TupleData + 2); + return 0; } -/*====================================================================*/ static int parse_funcid(tuple_t *tuple, cistpl_funcid_t *f) { - u_char *p; - if (tuple->TupleDataLen < 2) - return -EINVAL; - p = (u_char *)tuple->TupleData; - f->func = p[0]; - f->sysinit = p[1]; - return 0; + u_char *p; + if (tuple->TupleDataLen < 2) + return -EINVAL; + p = (u_char *)tuple->TupleData; + f->func = p[0]; + f->sysinit = p[1]; + return 0; } -/*====================================================================*/ static int parse_funce(tuple_t *tuple, cistpl_funce_t *f) { - u_char *p; - int i; - if (tuple->TupleDataLen < 1) - return -EINVAL; - p = (u_char *)tuple->TupleData; - f->type = p[0]; - for (i = 1; i < tuple->TupleDataLen; i++) - f->data[i-1] = p[i]; - return 0; + u_char *p; + int i; + if (tuple->TupleDataLen < 1) + return -EINVAL; + p = (u_char *)tuple->TupleData; + f->type = p[0]; + for (i = 1; i < tuple->TupleDataLen; i++) + f->data[i-1] = p[i]; + return 0; } -/*====================================================================*/ static int parse_config(tuple_t *tuple, cistpl_config_t *config) { - int rasz, rmsz, i; - u_char *p; - - p = (u_char *)tuple->TupleData; - rasz = *p & 0x03; - rmsz = (*p & 0x3c) >> 2; - if (tuple->TupleDataLen < rasz+rmsz+4) - return -EINVAL; - config->last_idx = *(++p); - p++; - config->base = 0; - for (i = 0; i <= rasz; i++) - config->base += p[i] << (8*i); - p += rasz+1; - for (i = 0; i < 4; i++) - config->rmask[i] = 0; - for (i = 0; i <= rmsz; i++) - config->rmask[i>>2] += p[i] << (8*(i%4)); - config->subtuples = tuple->TupleDataLen - (rasz+rmsz+4); - return 0; + int rasz, rmsz, i; + u_char *p; + + p = (u_char *)tuple->TupleData; + rasz = *p & 0x03; + rmsz = (*p & 0x3c) >> 2; + if (tuple->TupleDataLen < rasz+rmsz+4) + return -EINVAL; + config->last_idx = *(++p); + p++; + config->base = 0; + for (i = 0; i <= rasz; i++) + config->base += p[i] << (8*i); + p += rasz+1; + for (i = 0; i < 4; i++) + config->rmask[i] = 0; + for (i = 0; i <= rmsz; i++) + config->rmask[i>>2] += p[i] << (8*(i%4)); + config->subtuples = tuple->TupleDataLen - (rasz+rmsz+4); + return 0; } -/*====================================================================== +/* The following routines are all used to parse the nightmarish + * config table entries. + */ + +static u_char *parse_power(u_char *p, u_char *q, cistpl_power_t *pwr) +{ + int i; + u_int scale; - The following routines are all used to parse the nightmarish - config table entries. + if (p == q) + return NULL; + pwr->present = *p; + pwr->flags = 0; + p++; + for (i = 0; i < 7; i++) + if (pwr->present & (1<<i)) { + if (p == q) + return NULL; + pwr->param[i] = POWER_CVT(*p); + scale = POWER_SCALE(*p); + while (*p & 0x80) { + if (++p == q) + return NULL; + if ((*p & 0x7f) < 100) + pwr->param[i] += + (*p & 0x7f) * scale / 100; + else if (*p == 0x7d) + pwr->flags |= CISTPL_POWER_HIGHZ_OK; + else if (*p == 0x7e) + pwr->param[i] = 0; + else if (*p == 0x7f) + pwr->flags |= CISTPL_POWER_HIGHZ_REQ; + else + return NULL; + } + p++; + } + return p; +} -======================================================================*/ -static u_char *parse_power(u_char *p, u_char *q, - cistpl_power_t *pwr) +static u_char *parse_timing(u_char *p, u_char *q, cistpl_timing_t *timing) { - int i; - u_int scale; - - if (p == q) - return NULL; - pwr->present = *p; - pwr->flags = 0; - p++; - for (i = 0; i < 7; i++) - if (pwr->present & (1<<i)) { - if (p == q) - return NULL; - pwr->param[i] = POWER_CVT(*p); - scale = POWER_SCALE(*p); - while (*p & 0x80) { + u_char scale; + + if (p == q) + return NULL; + scale = *p; + if ((scale & 3) != 3) { if (++p == q) return NULL; - if ((*p & 0x7f) < 100) - pwr->param[i] += (*p & 0x7f) * scale / 100; - else if (*p == 0x7d) - pwr->flags |= CISTPL_POWER_HIGHZ_OK; - else if (*p == 0x7e) - pwr->param[i] = 0; - else if (*p == 0x7f) - pwr->flags |= CISTPL_POWER_HIGHZ_REQ; - else - return NULL; - } - p++; - } - return p; + timing->wait = SPEED_CVT(*p); + timing->waitscale = exponent[scale & 3]; + } else + timing->wait = 0; + scale >>= 2; + if ((scale & 7) != 7) { + if (++p == q) + return NULL; + timing->ready = SPEED_CVT(*p); + timing->rdyscale = exponent[scale & 7]; + } else + timing->ready = 0; + scale >>= 3; + if (scale != 7) { + if (++p == q) + return NULL; + timing->reserved = SPEED_CVT(*p); + timing->rsvscale = exponent[scale]; + } else + timing->reserved = 0; + p++; + return p; } -/*====================================================================*/ -static u_char *parse_timing(u_char *p, u_char *q, - cistpl_timing_t *timing) +static u_char *parse_io(u_char *p, u_char *q, cistpl_io_t *io) { - u_char scale; + int i, j, bsz, lsz; - if (p == q) - return NULL; - scale = *p; - if ((scale & 3) != 3) { - if (++p == q) - return NULL; - timing->wait = SPEED_CVT(*p); - timing->waitscale = exponent[scale & 3]; - } else - timing->wait = 0; - scale >>= 2; - if ((scale & 7) != 7) { - if (++p == q) + if (p == q) return NULL; - timing->ready = SPEED_CVT(*p); - timing->rdyscale = exponent[scale & 7]; - } else - timing->ready = 0; - scale >>= 3; - if (scale != 7) { + io->flags = *p; + + if (!(*p & 0x80)) { + io->nwin = 1; + io->win[0].base = 0; + io->win[0].len = (1 << (io->flags & CISTPL_IO_LINES_MASK)); + return p+1; + } + if (++p == q) return NULL; - timing->reserved = SPEED_CVT(*p); - timing->rsvscale = exponent[scale]; - } else - timing->reserved = 0; - p++; - return p; -} - -/*====================================================================*/ + io->nwin = (*p & 0x0f) + 1; + bsz = (*p & 0x30) >> 4; + if (bsz == 3) + bsz++; + lsz = (*p & 0xc0) >> 6; + if (lsz == 3) + lsz++; + p++; -static u_char *parse_io(u_char *p, u_char *q, cistpl_io_t *io) -{ - int i, j, bsz, lsz; - - if (p == q) - return NULL; - io->flags = *p; - - if (!(*p & 0x80)) { - io->nwin = 1; - io->win[0].base = 0; - io->win[0].len = (1 << (io->flags & CISTPL_IO_LINES_MASK)); - return p+1; - } - - if (++p == q) - return NULL; - io->nwin = (*p & 0x0f) + 1; - bsz = (*p & 0x30) >> 4; - if (bsz == 3) - bsz++; - lsz = (*p & 0xc0) >> 6; - if (lsz == 3) - lsz++; - p++; - - for (i = 0; i < io->nwin; i++) { - io->win[i].base = 0; - io->win[i].len = 1; - for (j = 0; j < bsz; j++, p++) { - if (p == q) - return NULL; - io->win[i].base += *p << (j*8); - } - for (j = 0; j < lsz; j++, p++) { - if (p == q) - return NULL; - io->win[i].len += *p << (j*8); + for (i = 0; i < io->nwin; i++) { + io->win[i].base = 0; + io->win[i].len = 1; + for (j = 0; j < bsz; j++, p++) { + if (p == q) + return NULL; + io->win[i].base += *p << (j*8); + } + for (j = 0; j < lsz; j++, p++) { + if (p == q) + return NULL; + io->win[i].len += *p << (j*8); + } } - } - return p; + return p; } -/*====================================================================*/ static u_char *parse_mem(u_char *p, u_char *q, cistpl_mem_t *mem) { - int i, j, asz, lsz, has_ha; - u_int len, ca, ha; - - if (p == q) - return NULL; - - mem->nwin = (*p & 0x07) + 1; - lsz = (*p & 0x18) >> 3; - asz = (*p & 0x60) >> 5; - has_ha = (*p & 0x80); - if (++p == q) - return NULL; - - for (i = 0; i < mem->nwin; i++) { - len = ca = ha = 0; - for (j = 0; j < lsz; j++, p++) { - if (p == q) - return NULL; - len += *p << (j*8); - } - for (j = 0; j < asz; j++, p++) { - if (p == q) - return NULL; - ca += *p << (j*8); + int i, j, asz, lsz, has_ha; + u_int len, ca, ha; + + if (p == q) + return NULL; + + mem->nwin = (*p & 0x07) + 1; + lsz = (*p & 0x18) >> 3; + asz = (*p & 0x60) >> 5; + has_ha = (*p & 0x80); + if (++p == q) + return NULL; + + for (i = 0; i < mem->nwin; i++) { + len = ca = ha = 0; + for (j = 0; j < lsz; j++, p++) { + if (p == q) + return NULL; + len += *p << (j*8); + } + for (j = 0; j < asz; j++, p++) { + if (p == q) + return NULL; + ca += *p << (j*8); + } + if (has_ha) + for (j = 0; j < asz; j++, p++) { + if (p == q) + return NULL; + ha += *p << (j*8); + } + mem->win[i].len = len << 8; + mem->win[i].card_addr = ca << 8; + mem->win[i].host_addr = ha << 8; } - if (has_ha) - for (j = 0; j < asz; j++, p++) { - if (p == q) - return NULL; - ha += *p << (j*8); - } - mem->win[i].len = len << 8; - mem->win[i].card_addr = ca << 8; - mem->win[i].host_addr = ha << 8; - } - return p; + return p; } -/*====================================================================*/ static u_char *parse_irq(u_char *p, u_char *q, cistpl_irq_t *irq) { - if (p == q) - return NULL; - irq->IRQInfo1 = *p; p++; - if (irq->IRQInfo1 & IRQ_INFO2_VALID) { - if (p+2 > q) + if (p == q) return NULL; - irq->IRQInfo2 = (p[1]<<8) + p[0]; - p += 2; - } - return p; + irq->IRQInfo1 = *p; p++; + if (irq->IRQInfo1 & IRQ_INFO2_VALID) { + if (p+2 > q) + return NULL; + irq->IRQInfo2 = (p[1]<<8) + p[0]; + p += 2; + } + return p; } -/*====================================================================*/ static int parse_cftable_entry(tuple_t *tuple, cistpl_cftable_entry_t *entry) { - u_char *p, *q, features; - - p = tuple->TupleData; - q = p + tuple->TupleDataLen; - entry->index = *p & 0x3f; - entry->flags = 0; - if (*p & 0x40) - entry->flags |= CISTPL_CFTABLE_DEFAULT; - if (*p & 0x80) { - if (++p == q) - return -EINVAL; - if (*p & 0x10) - entry->flags |= CISTPL_CFTABLE_BVDS; - if (*p & 0x20) - entry->flags |= CISTPL_CFTABLE_WP; + u_char *p, *q, features; + + p = tuple->TupleData; + q = p + tuple->TupleDataLen; + entry->index = *p & 0x3f; + entry->flags = 0; if (*p & 0x40) - entry->flags |= CISTPL_CFTABLE_RDYBSY; - if (*p & 0x80) - entry->flags |= CISTPL_CFTABLE_MWAIT; - entry->interface = *p & 0x0f; - } else - entry->interface = 0; - - /* Process optional features */ - if (++p == q) - return -EINVAL; - features = *p; p++; - - /* Power options */ - if ((features & 3) > 0) { - p = parse_power(p, q, &entry->vcc); - if (p == NULL) - return -EINVAL; - } else - entry->vcc.present = 0; - if ((features & 3) > 1) { - p = parse_power(p, q, &entry->vpp1); - if (p == NULL) - return -EINVAL; - } else - entry->vpp1.present = 0; - if ((features & 3) > 2) { - p = parse_power(p, q, &entry->vpp2); - if (p == NULL) - return -EINVAL; - } else - entry->vpp2.present = 0; + entry->flags |= CISTPL_CFTABLE_DEFAULT; + if (*p & 0x80) { + if (++p == q) + return -EINVAL; + if (*p & 0x10) + entry->flags |= CISTPL_CFTABLE_BVDS; + if (*p & 0x20) + entry->flags |= CISTPL_CFTABLE_WP; + if (*p & 0x40) + entry->flags |= CISTPL_CFTABLE_RDYBSY; + if (*p & 0x80) + entry->flags |= CISTPL_CFTABLE_MWAIT; + entry->interface = *p & 0x0f; + } else + entry->interface = 0; - /* Timing options */ - if (features & 0x04) { - p = parse_timing(p, q, &entry->timing); - if (p == NULL) - return -EINVAL; - } else { - entry->timing.wait = 0; - entry->timing.ready = 0; - entry->timing.reserved = 0; - } - - /* I/O window options */ - if (features & 0x08) { - p = parse_io(p, q, &entry->io); - if (p == NULL) + /* Process optional features */ + if (++p == q) return -EINVAL; - } else - entry->io.nwin = 0; + features = *p; p++; - /* Interrupt options */ - if (features & 0x10) { - p = parse_irq(p, q, &entry->irq); - if (p == NULL) - return -EINVAL; - } else - entry->irq.IRQInfo1 = 0; - - switch (features & 0x60) { - case 0x00: - entry->mem.nwin = 0; - break; - case 0x20: - entry->mem.nwin = 1; - entry->mem.win[0].len = get_unaligned_le16(p) << 8; - entry->mem.win[0].card_addr = 0; - entry->mem.win[0].host_addr = 0; - p += 2; - if (p > q) - return -EINVAL; - break; - case 0x40: - entry->mem.nwin = 1; - entry->mem.win[0].len = get_unaligned_le16(p) << 8; - entry->mem.win[0].card_addr = get_unaligned_le16(p + 2) << 8; - entry->mem.win[0].host_addr = 0; - p += 4; - if (p > q) - return -EINVAL; - break; - case 0x60: - p = parse_mem(p, q, &entry->mem); - if (p == NULL) - return -EINVAL; - break; - } + /* Power options */ + if ((features & 3) > 0) { + p = parse_power(p, q, &entry->vcc); + if (p == NULL) + return -EINVAL; + } else + entry->vcc.present = 0; + if ((features & 3) > 1) { + p = parse_power(p, q, &entry->vpp1); + if (p == NULL) + return -EINVAL; + } else + entry->vpp1.present = 0; + if ((features & 3) > 2) { + p = parse_power(p, q, &entry->vpp2); + if (p == NULL) + return -EINVAL; + } else + entry->vpp2.present = 0; - /* Misc features */ - if (features & 0x80) { - if (p == q) - return -EINVAL; - entry->flags |= (*p << 8); - while (*p & 0x80) - if (++p == q) - return -EINVAL; - p++; - } + /* Timing options */ + if (features & 0x04) { + p = parse_timing(p, q, &entry->timing); + if (p == NULL) + return -EINVAL; + } else { + entry->timing.wait = 0; + entry->timing.ready = 0; + entry->timing.reserved = 0; + } - entry->subtuples = q-p; + /* I/O window options */ + if (features & 0x08) { + p = parse_io(p, q, &entry->io); + if (p == NULL) + return -EINVAL; + } else + entry->io.nwin = 0; + + /* Interrupt options */ + if (features & 0x10) { + p = parse_irq(p, q, &entry->irq); + if (p == NULL) + return -EINVAL; + } else + entry->irq.IRQInfo1 = 0; + + switch (features & 0x60) { + case 0x00: + entry->mem.nwin = 0; + break; + case 0x20: + entry->mem.nwin = 1; + entry->mem.win[0].len = get_unaligned_le16(p) << 8; + entry->mem.win[0].card_addr = 0; + entry->mem.win[0].host_addr = 0; + p += 2; + if (p > q) + return -EINVAL; + break; + case 0x40: + entry->mem.nwin = 1; + entry->mem.win[0].len = get_unaligned_le16(p) << 8; + entry->mem.win[0].card_addr = get_unaligned_le16(p + 2) << 8; + entry->mem.win[0].host_addr = 0; + p += 4; + if (p > q) + return -EINVAL; + break; + case 0x60: + p = parse_mem(p, q, &entry->mem); + if (p == NULL) + return -EINVAL; + break; + } + + /* Misc features */ + if (features & 0x80) { + if (p == q) + return -EINVAL; + entry->flags |= (*p << 8); + while (*p & 0x80) + if (++p == q) + return -EINVAL; + p++; + } + + entry->subtuples = q-p; - return 0; + return 0; } -/*====================================================================*/ static int parse_device_geo(tuple_t *tuple, cistpl_device_geo_t *geo) { - u_char *p, *q; - int n; + u_char *p, *q; + int n; - p = (u_char *)tuple->TupleData; - q = p + tuple->TupleDataLen; + p = (u_char *)tuple->TupleData; + q = p + tuple->TupleDataLen; - for (n = 0; n < CISTPL_MAX_DEVICES; n++) { - if (p > q-6) - break; - geo->geo[n].buswidth = p[0]; - geo->geo[n].erase_block = 1 << (p[1]-1); - geo->geo[n].read_block = 1 << (p[2]-1); - geo->geo[n].write_block = 1 << (p[3]-1); - geo->geo[n].partition = 1 << (p[4]-1); - geo->geo[n].interleave = 1 << (p[5]-1); - p += 6; - } - geo->ngeo = n; - return 0; + for (n = 0; n < CISTPL_MAX_DEVICES; n++) { + if (p > q-6) + break; + geo->geo[n].buswidth = p[0]; + geo->geo[n].erase_block = 1 << (p[1]-1); + geo->geo[n].read_block = 1 << (p[2]-1); + geo->geo[n].write_block = 1 << (p[3]-1); + geo->geo[n].partition = 1 << (p[4]-1); + geo->geo[n].interleave = 1 << (p[5]-1); + p += 6; + } + geo->ngeo = n; + return 0; } -/*====================================================================*/ static int parse_vers_2(tuple_t *tuple, cistpl_vers_2_t *v2) { - u_char *p, *q; - - if (tuple->TupleDataLen < 10) - return -EINVAL; - - p = tuple->TupleData; - q = p + tuple->TupleDataLen; - - v2->vers = p[0]; - v2->comply = p[1]; - v2->dindex = get_unaligned_le16(p + 2); - v2->vspec8 = p[6]; - v2->vspec9 = p[7]; - v2->nhdr = p[8]; - p += 9; - return parse_strings(p, q, 2, v2->str, &v2->vendor, NULL); + u_char *p, *q; + + if (tuple->TupleDataLen < 10) + return -EINVAL; + + p = tuple->TupleData; + q = p + tuple->TupleDataLen; + + v2->vers = p[0]; + v2->comply = p[1]; + v2->dindex = get_unaligned_le16(p + 2); + v2->vspec8 = p[6]; + v2->vspec9 = p[7]; + v2->nhdr = p[8]; + p += 9; + return parse_strings(p, q, 2, v2->str, &v2->vendor, NULL); } -/*====================================================================*/ static int parse_org(tuple_t *tuple, cistpl_org_t *org) { - u_char *p, *q; - int i; - - p = tuple->TupleData; - q = p + tuple->TupleDataLen; - if (p == q) - return -EINVAL; - org->data_org = *p; - if (++p == q) - return -EINVAL; - for (i = 0; i < 30; i++) { - org->desc[i] = *p; - if (*p == '\0') - break; + u_char *p, *q; + int i; + + p = tuple->TupleData; + q = p + tuple->TupleDataLen; + if (p == q) + return -EINVAL; + org->data_org = *p; if (++p == q) return -EINVAL; - } - return 0; + for (i = 0; i < 30; i++) { + org->desc[i] = *p; + if (*p == '\0') + break; + if (++p == q) + return -EINVAL; + } + return 0; } -/*====================================================================*/ static int parse_format(tuple_t *tuple, cistpl_format_t *fmt) { - u_char *p; + u_char *p; - if (tuple->TupleDataLen < 10) - return -EINVAL; + if (tuple->TupleDataLen < 10) + return -EINVAL; - p = tuple->TupleData; + p = tuple->TupleData; - fmt->type = p[0]; - fmt->edc = p[1]; - fmt->offset = get_unaligned_le32(p + 2); - fmt->length = get_unaligned_le32(p + 6); + fmt->type = p[0]; + fmt->edc = p[1]; + fmt->offset = get_unaligned_le32(p + 2); + fmt->length = get_unaligned_le32(p + 6); - return 0; + return 0; } -/*====================================================================*/ int pcmcia_parse_tuple(tuple_t *tuple, cisparse_t *parse) { - int ret = 0; - - if (tuple->TupleDataLen > tuple->TupleDataMax) - return -EINVAL; - switch (tuple->TupleCode) { - case CISTPL_DEVICE: - case CISTPL_DEVICE_A: - ret = parse_device(tuple, &parse->device); - break; - case CISTPL_CHECKSUM: - ret = parse_checksum(tuple, &parse->checksum); - break; - case CISTPL_LONGLINK_A: - case CISTPL_LONGLINK_C: - ret = parse_longlink(tuple, &parse->longlink); - break; - case CISTPL_LONGLINK_MFC: - ret = parse_longlink_mfc(tuple, &parse->longlink_mfc); - break; - case CISTPL_VERS_1: - ret = parse_vers_1(tuple, &parse->version_1); - break; - case CISTPL_ALTSTR: - ret = parse_altstr(tuple, &parse->altstr); - break; - case CISTPL_JEDEC_A: - case CISTPL_JEDEC_C: - ret = parse_jedec(tuple, &parse->jedec); - break; - case CISTPL_MANFID: - ret = parse_manfid(tuple, &parse->manfid); - break; - case CISTPL_FUNCID: - ret = parse_funcid(tuple, &parse->funcid); - break; - case CISTPL_FUNCE: - ret = parse_funce(tuple, &parse->funce); - break; - case CISTPL_CONFIG: - ret = parse_config(tuple, &parse->config); - break; - case CISTPL_CFTABLE_ENTRY: - ret = parse_cftable_entry(tuple, &parse->cftable_entry); - break; - case CISTPL_DEVICE_GEO: - case CISTPL_DEVICE_GEO_A: - ret = parse_device_geo(tuple, &parse->device_geo); - break; - case CISTPL_VERS_2: - ret = parse_vers_2(tuple, &parse->vers_2); - break; - case CISTPL_ORG: - ret = parse_org(tuple, &parse->org); - break; - case CISTPL_FORMAT: - case CISTPL_FORMAT_A: - ret = parse_format(tuple, &parse->format); - break; - case CISTPL_NO_LINK: - case CISTPL_LINKTARGET: - ret = 0; - break; - default: - ret = -EINVAL; - break; - } - if (ret) - pr_debug("parse_tuple failed %d\n", ret); - return ret; + int ret = 0; + + if (tuple->TupleDataLen > tuple->TupleDataMax) + return -EINVAL; + switch (tuple->TupleCode) { + case CISTPL_DEVICE: + case CISTPL_DEVICE_A: + ret = parse_device(tuple, &parse->device); + break; + case CISTPL_CHECKSUM: + ret = parse_checksum(tuple, &parse->checksum); + break; + case CISTPL_LONGLINK_A: + case CISTPL_LONGLINK_C: + ret = parse_longlink(tuple, &parse->longlink); + break; + case CISTPL_LONGLINK_MFC: + ret = parse_longlink_mfc(tuple, &parse->longlink_mfc); + break; + case CISTPL_VERS_1: + ret = parse_vers_1(tuple, &parse->version_1); + break; + case CISTPL_ALTSTR: + ret = parse_altstr(tuple, &parse->altstr); + break; + case CISTPL_JEDEC_A: + case CISTPL_JEDEC_C: + ret = parse_jedec(tuple, &parse->jedec); + break; + case CISTPL_MANFID: + ret = parse_manfid(tuple, &parse->manfid); + break; + case CISTPL_FUNCID: + ret = parse_funcid(tuple, &parse->funcid); + break; + case CISTPL_FUNCE: + ret = parse_funce(tuple, &parse->funce); + break; + case CISTPL_CONFIG: + ret = parse_config(tuple, &parse->config); + break; + case CISTPL_CFTABLE_ENTRY: + ret = parse_cftable_entry(tuple, &parse->cftable_entry); + break; + case CISTPL_DEVICE_GEO: + case CISTPL_DEVICE_GEO_A: + ret = parse_device_geo(tuple, &parse->device_geo); + break; + case CISTPL_VERS_2: + ret = parse_vers_2(tuple, &parse->vers_2); + break; + case CISTPL_ORG: + ret = parse_org(tuple, &parse->org); + break; + case CISTPL_FORMAT: + case CISTPL_FORMAT_A: + ret = parse_format(tuple, &parse->format); + break; + case CISTPL_NO_LINK: + case CISTPL_LINKTARGET: + ret = 0; + break; + default: + ret = -EINVAL; + break; + } + if (ret) + pr_debug("parse_tuple failed %d\n", ret); + return ret; } EXPORT_SYMBOL(pcmcia_parse_tuple); -/*====================================================================== - This is used internally by Card Services to look up CIS stuff. - -======================================================================*/ - -int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function, cisdata_t code, void *parse) +/** + * pccard_read_tuple() - internal CIS tuple access + * @s: the struct pcmcia_socket where the card is inserted + * @function: the device function we loop for + * @code: which CIS code shall we look for? + * @parse: buffer where the tuple shall be parsed (or NULL, if no parse) + * + * pccard_read_tuple() reads out one tuple and attempts to parse it + */ +int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function, + cisdata_t code, void *parse) { - tuple_t tuple; - cisdata_t *buf; - int ret; - - buf = kmalloc(256, GFP_KERNEL); - if (buf == NULL) { - dev_printk(KERN_WARNING, &s->dev, "no memory to read tuple\n"); - return -ENOMEM; - } - tuple.DesiredTuple = code; - tuple.Attributes = 0; - if (function == BIND_FN_ALL) - tuple.Attributes = TUPLE_RETURN_COMMON; - ret = pccard_get_first_tuple(s, function, &tuple); - if (ret != 0) - goto done; - tuple.TupleData = buf; - tuple.TupleOffset = 0; - tuple.TupleDataMax = 255; - ret = pccard_get_tuple_data(s, &tuple); - if (ret != 0) - goto done; - ret = pcmcia_parse_tuple(&tuple, parse); + tuple_t tuple; + cisdata_t *buf; + int ret; + + buf = kmalloc(256, GFP_KERNEL); + if (buf == NULL) { + dev_printk(KERN_WARNING, &s->dev, "no memory to read tuple\n"); + return -ENOMEM; + } + tuple.DesiredTuple = code; + tuple.Attributes = 0; + if (function == BIND_FN_ALL) + tuple.Attributes = TUPLE_RETURN_COMMON; + ret = pccard_get_first_tuple(s, function, &tuple); + if (ret != 0) + goto done; + tuple.TupleData = buf; + tuple.TupleOffset = 0; + tuple.TupleDataMax = 255; + ret = pccard_get_tuple_data(s, &tuple); + if (ret != 0) + goto done; + ret = pcmcia_parse_tuple(&tuple, parse); done: - kfree(buf); - return ret; + kfree(buf); + return ret; } diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index e6f7d410aed6..452c83b512c4 100644 --- a/drivers/pcmcia/rsrc_mgr.c +++ b/drivers/pcmcia/rsrc_mgr.c @@ -79,9 +79,8 @@ static resource_size_t pcmcia_align(void *align_data, #ifdef CONFIG_X86 if (res->flags & IORESOURCE_IO) { - if (start & 0x300) { + if (start & 0x300) start = (start + 0x3ff) & ~0x3ff; - } } #endif |