|
|
1.1 ! root 1: /*====================================================================== ! 2: ! 3: PCMCIA Card Information Structure parser ! 4: ! 5: cistpl.c 1.101 2003/12/15 03:58:03 ! 6: ! 7: The contents of this file are subject to the Mozilla Public ! 8: License Version 1.1 (the "License"); you may not use this file ! 9: except in compliance with the License. You may obtain a copy of ! 10: the License at http://www.mozilla.org/MPL/ ! 11: ! 12: Software distributed under the License is distributed on an "AS ! 13: IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or ! 14: implied. See the License for the specific language governing ! 15: rights and limitations under the License. ! 16: ! 17: The initial developer of the original code is David A. Hinds ! 18: <[email protected]>. Portions created by David A. Hinds ! 19: are Copyright (C) 1999 David A. Hinds. All Rights Reserved. ! 20: ! 21: Alternatively, the contents of this file may be used under the ! 22: terms of the GNU General Public License version 2 (the "GPL"), in ! 23: which case the provisions of the GPL are applicable instead of the ! 24: above. If you wish to allow the use of your version of this file ! 25: only under the terms of the GPL and not to allow others to use ! 26: your version of this file under the MPL, indicate your decision ! 27: by deleting the provisions above and replace them with the notice ! 28: and other provisions required by the GPL. If you do not delete ! 29: the provisions above, a recipient may use your version of this ! 30: file under either the MPL or the GPL. ! 31: ! 32: ======================================================================*/ ! 33: ! 34: #define __NO_VERSION__ ! 35: ! 36: #include <linux/config.h> ! 37: #include <linux/module.h> ! 38: #include <linux/kernel.h> ! 39: #include <linux/string.h> ! 40: #include <linux/major.h> ! 41: #include <linux/errno.h> ! 42: #include <linux/timer.h> ! 43: #include <linux/slab.h> ! 44: #include <linux/mm.h> ! 45: #include <linux/sched.h> ! 46: #include <linux/pci.h> ! 47: #include <linux/ioport.h> ! 48: #include <asm/io.h> ! 49: #include <asm/byteorder.h> ! 50: ! 51: #include <pcmcia/cs_types.h> ! 52: #include <pcmcia/bus_ops.h> ! 53: #include <pcmcia/ss.h> ! 54: #include <pcmcia/cs.h> ! 55: #include <pcmcia/bulkmem.h> ! 56: #include <pcmcia/cisreg.h> ! 57: #include <pcmcia/cistpl.h> ! 58: #include "cs_internal.h" ! 59: ! 60: static const u_char mantissa[] = { ! 61: 10, 12, 13, 15, 20, 25, 30, 35, ! 62: 40, 45, 50, 55, 60, 70, 80, 90 ! 63: }; ! 64: ! 65: static const u_int exponent[] = { ! 66: 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000 ! 67: }; ! 68: ! 69: /* Convert an extended speed byte to a time in nanoseconds */ ! 70: #define SPEED_CVT(v) \ ! 71: (mantissa[(((v)>>3)&15)-1] * exponent[(v)&7] / 10) ! 72: /* Convert a power byte to a current in 0.1 microamps */ ! 73: #define POWER_CVT(v) \ ! 74: (mantissa[((v)>>3)&15] * exponent[(v)&7] / 10) ! 75: #define POWER_SCALE(v) (exponent[(v)&7]) ! 76: ! 77: /* Upper limit on reasonable # of tuples */ ! 78: #define MAX_TUPLES 200 ! 79: ! 80: /*====================================================================*/ ! 81: ! 82: /* Parameters that can be set with 'insmod' */ ! 83: ! 84: #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i") ! 85: ! 86: INT_MODULE_PARM(cis_width, 0); /* 16-bit CIS? */ ! 87: ! 88: /*====================================================================== ! 89: ! 90: Low-level functions to read and write CIS memory. I think the ! 91: write routine is only useful for writing one-byte registers. ! 92: ! 93: ======================================================================*/ ! 94: ! 95: /* Bits in attr field */ ! 96: #define IS_ATTR 1 ! 97: #define IS_INDIRECT 8 ! 98: ! 99: static int setup_cis_mem(socket_info_t *s); ! 100: ! 101: static void set_cis_map(socket_info_t *s, pccard_mem_map *mem) ! 102: { ! 103: s->ss_entry(s->sock, SS_SetMemMap, mem); ! 104: if (s->cap.features & SS_CAP_STATIC_MAP) { ! 105: if (s->cis_virt) ! 106: bus_iounmap(s->cap.bus, s->cis_virt); ! 107: s->cis_virt = bus_ioremap(s->cap.bus, mem->sys_start, ! 108: s->cap.map_size); ! 109: } ! 110: } ! 111: ! 112: int read_cis_mem(socket_info_t *s, int attr, u_int addr, ! 113: u_int len, void *ptr) ! 114: { ! 115: pccard_mem_map *mem = &s->cis_mem; ! 116: u_char *sys, *buf = ptr; ! 117: ! 118: DEBUG(3, "cs: read_cis_mem(%d, %#x, %u)\n", attr, addr, len); ! 119: if (setup_cis_mem(s) != 0) { ! 120: memset(ptr, 0xff, len); ! 121: return -1; ! 122: } ! 123: mem->flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0); ! 124: ! 125: if (attr & IS_INDIRECT) { ! 126: /* Indirect accesses use a bunch of special registers at fixed ! 127: locations in common memory */ ! 128: u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN; ! 129: if (attr & IS_ATTR) { addr *= 2; flags = ICTRL0_AUTOINC; } ! 130: mem->card_start = 0; mem->flags = MAP_ACTIVE; ! 131: set_cis_map(s, mem); ! 132: sys = s->cis_virt; ! 133: bus_writeb(s->cap.bus, flags, sys+CISREG_ICTRL0); ! 134: bus_writeb(s->cap.bus, addr & 0xff, sys+CISREG_IADDR0); ! 135: bus_writeb(s->cap.bus, (addr>>8) & 0xff, sys+CISREG_IADDR1); ! 136: bus_writeb(s->cap.bus, (addr>>16) & 0xff, sys+CISREG_IADDR2); ! 137: bus_writeb(s->cap.bus, (addr>>24) & 0xff, sys+CISREG_IADDR3); ! 138: for ( ; len > 0; len--, buf++) ! 139: *buf = bus_readb(s->cap.bus, sys+CISREG_IDATA0); ! 140: } else { ! 141: u_int inc = 1; ! 142: if (attr) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; } ! 143: sys += (addr & (s->cap.map_size-1)); ! 144: mem->card_start = addr & ~(s->cap.map_size-1); ! 145: while (len) { ! 146: set_cis_map(s, mem); ! 147: sys = s->cis_virt + (addr & (s->cap.map_size-1)); ! 148: for ( ; len > 0; len--, buf++, sys += inc) { ! 149: if (sys == s->cis_virt+s->cap.map_size) break; ! 150: *buf = bus_readb(s->cap.bus, sys); ! 151: } ! 152: mem->card_start += s->cap.map_size; ! 153: addr = 0; ! 154: } ! 155: } ! 156: DEBUG(3, "cs: %#2.2x %#2.2x %#2.2x %#2.2x ...\n", ! 157: *(u_char *)(ptr+0), *(u_char *)(ptr+1), ! 158: *(u_char *)(ptr+2), *(u_char *)(ptr+3)); ! 159: return 0; ! 160: } ! 161: ! 162: void write_cis_mem(socket_info_t *s, int attr, u_int addr, ! 163: u_int len, void *ptr) ! 164: { ! 165: pccard_mem_map *mem = &s->cis_mem; ! 166: u_char *sys, *buf = ptr; ! 167: ! 168: DEBUG(3, "cs: write_cis_mem(%d, %#x, %u)\n", attr, addr, len); ! 169: if (setup_cis_mem(s) != 0) return; ! 170: mem->flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0); ! 171: ! 172: if (attr & IS_INDIRECT) { ! 173: /* Indirect accesses use a bunch of special registers at fixed ! 174: locations in common memory */ ! 175: u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN; ! 176: if (attr & IS_ATTR) { addr *= 2; flags = ICTRL0_AUTOINC; } ! 177: mem->card_start = 0; mem->flags = MAP_ACTIVE; ! 178: set_cis_map(s, mem); ! 179: sys = s->cis_virt; ! 180: bus_writeb(s->cap.bus, flags, sys+CISREG_ICTRL0); ! 181: bus_writeb(s->cap.bus, addr & 0xff, sys+CISREG_IADDR0); ! 182: bus_writeb(s->cap.bus, (addr>>8) & 0xff, sys+CISREG_IADDR1); ! 183: bus_writeb(s->cap.bus, (addr>>16) & 0xff, sys+CISREG_IADDR2); ! 184: bus_writeb(s->cap.bus, (addr>>24) & 0xff, sys+CISREG_IADDR3); ! 185: for ( ; len > 0; len--, buf++) ! 186: bus_writeb(s->cap.bus, *buf, sys+CISREG_IDATA0); ! 187: } else { ! 188: int inc = 1; ! 189: if (attr & IS_ATTR) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; } ! 190: mem->card_start = addr & ~(s->cap.map_size-1); ! 191: while (len) { ! 192: set_cis_map(s, mem); ! 193: sys = s->cis_virt + (addr & (s->cap.map_size-1)); ! 194: for ( ; len > 0; len--, buf++, sys += inc) { ! 195: if (sys == s->cis_virt+s->cap.map_size) break; ! 196: bus_writeb(s->cap.bus, *buf, sys); ! 197: } ! 198: mem->card_start += s->cap.map_size; ! 199: addr = 0; ! 200: } ! 201: } ! 202: } ! 203: ! 204: /*====================================================================== ! 205: ! 206: This is tricky... when we set up CIS memory, we try to validate ! 207: the memory window space allocations. ! 208: ! 209: ======================================================================*/ ! 210: ! 211: /* Scratch pointer to the socket we use for validation */ ! 212: static socket_info_t *vs = NULL; ! 213: ! 214: /* Validation function for cards with a valid CIS */ ! 215: static int cis_readable(u_long base) ! 216: { ! 217: cisinfo_t info1, info2; ! 218: int ret; ! 219: vs->cis_mem.sys_start = base; ! 220: vs->cis_mem.sys_stop = base+vs->cap.map_size-1; ! 221: vs->cis_virt = bus_ioremap(vs->cap.bus, base, vs->cap.map_size); ! 222: ret = validate_cis(vs->clients, &info1); ! 223: /* invalidate mapping and CIS cache */ ! 224: bus_iounmap(vs->cap.bus, vs->cis_virt); vs->cis_used = 0; ! 225: if ((ret != 0) || (info1.Chains == 0)) ! 226: return 0; ! 227: vs->cis_mem.sys_start = base+vs->cap.map_size; ! 228: vs->cis_mem.sys_stop = base+2*vs->cap.map_size-1; ! 229: vs->cis_virt = bus_ioremap(vs->cap.bus, base+vs->cap.map_size, ! 230: vs->cap.map_size); ! 231: ret = validate_cis(vs->clients, &info2); ! 232: bus_iounmap(vs->cap.bus, vs->cis_virt); vs->cis_used = 0; ! 233: return ((ret == 0) && (info1.Chains == info2.Chains)); ! 234: } ! 235: ! 236: /* Validation function for simple memory cards */ ! 237: static int checksum(u_long base) ! 238: { ! 239: int i, a, b, d; ! 240: vs->cis_mem.sys_start = base; ! 241: vs->cis_mem.sys_stop = base+vs->cap.map_size-1; ! 242: vs->cis_virt = bus_ioremap(vs->cap.bus, base, vs->cap.map_size); ! 243: vs->cis_mem.card_start = 0; ! 244: vs->cis_mem.flags = MAP_ACTIVE; ! 245: vs->ss_entry(vs->sock, SS_SetMemMap, &vs->cis_mem); ! 246: /* Don't bother checking every word... */ ! 247: a = 0; b = -1; ! 248: for (i = 0; i < vs->cap.map_size; i += 44) { ! 249: d = bus_readl(vs->cap.bus, vs->cis_virt+i); ! 250: a += d; b &= d; ! 251: } ! 252: bus_iounmap(vs->cap.bus, vs->cis_virt); ! 253: return (b == -1) ? -1 : (a>>1); ! 254: } ! 255: ! 256: static int checksum_match(u_long base) ! 257: { ! 258: int a = checksum(base), b = checksum(base+vs->cap.map_size); ! 259: return ((a == b) && (a >= 0)); ! 260: } ! 261: ! 262: static int setup_cis_mem(socket_info_t *s) ! 263: { ! 264: if (!(s->cap.features & SS_CAP_STATIC_MAP) && ! 265: (s->cis_mem.sys_start == 0)) { ! 266: int low = !(s->cap.features & SS_CAP_PAGE_REGS); ! 267: vs = s; ! 268: validate_mem(cis_readable, checksum_match, low); ! 269: s->cis_mem.sys_start = 0; ! 270: vs = NULL; ! 271: if (find_mem_region(&s->cis_mem.sys_start, s->cap.map_size, ! 272: s->cap.map_size, low, "card services")) { ! 273: printk(KERN_NOTICE "cs: unable to map card memory!\n"); ! 274: return -1; ! 275: } ! 276: s->cis_mem.sys_stop = s->cis_mem.sys_start+s->cap.map_size-1; ! 277: s->cis_virt = bus_ioremap(s->cap.bus, s->cis_mem.sys_start, ! 278: s->cap.map_size); ! 279: } ! 280: return 0; ! 281: } ! 282: ! 283: void release_cis_mem(socket_info_t *s) ! 284: { ! 285: if (s->cis_mem.sys_start != 0) { ! 286: s->cis_mem.flags &= ~MAP_ACTIVE; ! 287: s->ss_entry(s->sock, SS_SetMemMap, &s->cis_mem); ! 288: if (!(s->cap.features & SS_CAP_STATIC_MAP)) ! 289: release_mem_region(s->cis_mem.sys_start, s->cap.map_size); ! 290: bus_iounmap(s->cap.bus, s->cis_virt); ! 291: s->cis_mem.sys_start = 0; ! 292: s->cis_virt = NULL; ! 293: } ! 294: } ! 295: ! 296: /*====================================================================== ! 297: ! 298: This is a wrapper around read_cis_mem, with the same interface, ! 299: but which caches information, for cards whose CIS may not be ! 300: readable all the time. ! 301: ! 302: ======================================================================*/ ! 303: ! 304: static void read_cis_cache(socket_info_t *s, int attr, u_int addr, ! 305: u_int len, void *ptr) ! 306: { ! 307: int i, ret; ! 308: char *caddr; ! 309: ! 310: if (s->fake_cis) { ! 311: if (s->fake_cis_len > addr+len) ! 312: memcpy(ptr, s->fake_cis+addr, len); ! 313: else ! 314: memset(ptr, 0xff, len); ! 315: return; ! 316: } ! 317: caddr = s->cis_cache; ! 318: for (i = 0; i < s->cis_used; i++) { ! 319: if ((s->cis_table[i].addr == addr) && ! 320: (s->cis_table[i].len == len) && ! 321: (s->cis_table[i].attr == attr)) break; ! 322: caddr += s->cis_table[i].len; ! 323: } ! 324: if (i < s->cis_used) { ! 325: memcpy(ptr, caddr, len); ! 326: return; ! 327: } ! 328: #ifdef CONFIG_CARDBUS ! 329: if (s->state & SOCKET_CARDBUS) ! 330: ret = read_cb_mem(s, 0, attr, addr, len, ptr); ! 331: else ! 332: #endif ! 333: ret = read_cis_mem(s, attr, addr, len, ptr); ! 334: /* Copy data into the cache, if there is room */ ! 335: if ((ret == 0) && (i < MAX_CIS_TABLE) && ! 336: (caddr+len < s->cis_cache+MAX_CIS_DATA)) { ! 337: s->cis_table[i].addr = addr; ! 338: s->cis_table[i].len = len; ! 339: s->cis_table[i].attr = attr; ! 340: s->cis_used++; ! 341: memcpy(caddr, ptr, len); ! 342: } ! 343: } ! 344: ! 345: /*====================================================================== ! 346: ! 347: This verifies if the CIS of a card matches what is in the CIS ! 348: cache. ! 349: ! 350: ======================================================================*/ ! 351: ! 352: int verify_cis_cache(socket_info_t *s) ! 353: { ! 354: char *buf, *caddr; ! 355: int i; ! 356: ! 357: buf = kmalloc(256, GFP_KERNEL); ! 358: if (buf == NULL) ! 359: return -1; ! 360: caddr = s->cis_cache; ! 361: for (i = 0; i < s->cis_used; i++) { ! 362: #ifdef CONFIG_CARDBUS ! 363: if (s->state & SOCKET_CARDBUS) ! 364: read_cb_mem(s, 0, s->cis_table[i].attr, s->cis_table[i].addr, ! 365: s->cis_table[i].len, buf); ! 366: else ! 367: #endif ! 368: read_cis_mem(s, s->cis_table[i].attr, s->cis_table[i].addr, ! 369: s->cis_table[i].len, buf); ! 370: if (memcmp(buf, caddr, s->cis_table[i].len) != 0) ! 371: break; ! 372: caddr += s->cis_table[i].len; ! 373: } ! 374: kfree(buf); ! 375: return (i < s->cis_used); ! 376: } ! 377: ! 378: /*====================================================================== ! 379: ! 380: For really bad cards, we provide a facility for uploading a ! 381: replacement CIS. ! 382: ! 383: ======================================================================*/ ! 384: ! 385: int replace_cis(client_handle_t handle, cisdump_t *cis) ! 386: { ! 387: socket_info_t *s; ! 388: if (CHECK_HANDLE(handle)) ! 389: return CS_BAD_HANDLE; ! 390: s = SOCKET(handle); ! 391: if (s->fake_cis != NULL) { ! 392: kfree(s->fake_cis); ! 393: s->fake_cis = NULL; ! 394: } ! 395: if (cis->Length > CISTPL_MAX_CIS_SIZE) ! 396: return CS_BAD_SIZE; ! 397: s->fake_cis = kmalloc(cis->Length, GFP_KERNEL); ! 398: if (s->fake_cis == NULL) ! 399: return CS_OUT_OF_RESOURCE; ! 400: s->fake_cis_len = cis->Length; ! 401: memcpy(s->fake_cis, cis->Data, cis->Length); ! 402: return CS_SUCCESS; ! 403: } ! 404: ! 405: /*====================================================================== ! 406: ! 407: The high-level CIS tuple services ! 408: ! 409: ======================================================================*/ ! 410: ! 411: typedef struct tuple_flags { ! 412: u_int link_space:4; ! 413: u_int has_link:1; ! 414: u_int mfc_fn:3; ! 415: u_int space:4; ! 416: } tuple_flags; ! 417: ! 418: #define LINK_SPACE(f) (((tuple_flags *)(&(f)))->link_space) ! 419: #define HAS_LINK(f) (((tuple_flags *)(&(f)))->has_link) ! 420: #define MFC_FN(f) (((tuple_flags *)(&(f)))->mfc_fn) ! 421: #define SPACE(f) (((tuple_flags *)(&(f)))->space) ! 422: ! 423: int get_next_tuple(client_handle_t handle, tuple_t *tuple); ! 424: ! 425: int get_first_tuple(client_handle_t handle, tuple_t *tuple) ! 426: { ! 427: socket_info_t *s; ! 428: if (CHECK_HANDLE(handle)) ! 429: return CS_BAD_HANDLE; ! 430: s = SOCKET(handle); ! 431: if (!(s->state & SOCKET_PRESENT)) ! 432: return CS_NO_CARD; ! 433: tuple->TupleLink = tuple->Flags = 0; ! 434: #ifdef CONFIG_CARDBUS ! 435: if (s->state & SOCKET_CARDBUS) { ! 436: u_int ptr; ! 437: pcibios_read_config_dword(s->cap.cardbus, 0, 0x28, &ptr); ! 438: tuple->CISOffset = ptr & ~7; ! 439: SPACE(tuple->Flags) = (ptr & 7); ! 440: } else ! 441: #endif ! 442: { ! 443: /* Assume presence of a LONGLINK_C to address 0 */ ! 444: tuple->CISOffset = tuple->LinkOffset = 0; ! 445: SPACE(tuple->Flags) = HAS_LINK(tuple->Flags) = 1; ! 446: } ! 447: if (!(s->state & SOCKET_CARDBUS) && (s->functions > 1) && ! 448: !(tuple->Attributes & TUPLE_RETURN_COMMON)) { ! 449: cisdata_t req = tuple->DesiredTuple; ! 450: tuple->DesiredTuple = CISTPL_LONGLINK_MFC; ! 451: if (get_next_tuple(handle, tuple) == CS_SUCCESS) { ! 452: tuple->DesiredTuple = CISTPL_LINKTARGET; ! 453: if (get_next_tuple(handle, tuple) != CS_SUCCESS) ! 454: return CS_NO_MORE_ITEMS; ! 455: } else ! 456: tuple->CISOffset = tuple->TupleLink = 0; ! 457: tuple->DesiredTuple = req; ! 458: } ! 459: return get_next_tuple(handle, tuple); ! 460: } ! 461: ! 462: static int follow_link(socket_info_t *s, tuple_t *tuple) ! 463: { ! 464: u_char link[5]; ! 465: u_int ofs; ! 466: ! 467: if (MFC_FN(tuple->Flags)) { ! 468: /* Get indirect link from the MFC tuple */ ! 469: read_cis_cache(s, LINK_SPACE(tuple->Flags), ! 470: tuple->LinkOffset, 5, link); ! 471: ofs = le32_to_cpu(*(u_int *)(link+1)); ! 472: SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR); ! 473: /* Move to the next indirect link */ ! 474: tuple->LinkOffset += 5; ! 475: MFC_FN(tuple->Flags)--; ! 476: } else if (HAS_LINK(tuple->Flags)) { ! 477: ofs = tuple->LinkOffset; ! 478: SPACE(tuple->Flags) = LINK_SPACE(tuple->Flags); ! 479: HAS_LINK(tuple->Flags) = 0; ! 480: } else { ! 481: return -1; ! 482: } ! 483: if (!(s->state & SOCKET_CARDBUS) && SPACE(tuple->Flags)) { ! 484: /* This is ugly, but a common CIS error is to code the long ! 485: link offset incorrectly, so we check the right spot... */ ! 486: read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link); ! 487: if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) && ! 488: (strncmp(link+2, "CIS", 3) == 0)) ! 489: return ofs; ! 490: /* Then, we try the wrong spot... */ ! 491: ofs = ofs >> 1; ! 492: } ! 493: read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link); ! 494: if ((link[0] != CISTPL_LINKTARGET) || (link[1] < 3) || ! 495: (strncmp(link+2, "CIS", 3) != 0)) ! 496: return -1; ! 497: return ofs; ! 498: } ! 499: ! 500: int get_next_tuple(client_handle_t handle, tuple_t *tuple) ! 501: { ! 502: socket_info_t *s; ! 503: u_char link[2], tmp; ! 504: int ofs, i, attr; ! 505: ! 506: if (CHECK_HANDLE(handle)) ! 507: return CS_BAD_HANDLE; ! 508: s = SOCKET(handle); ! 509: if (!(s->state & SOCKET_PRESENT)) ! 510: return CS_NO_CARD; ! 511: ! 512: link[1] = tuple->TupleLink; ! 513: ofs = tuple->CISOffset + tuple->TupleLink; ! 514: attr = SPACE(tuple->Flags); ! 515: ! 516: for (i = 0; i < MAX_TUPLES; i++) { ! 517: if (link[1] == 0xff) { ! 518: link[0] = CISTPL_END; ! 519: } else { ! 520: read_cis_cache(s, attr, ofs, 2, link); ! 521: if (link[0] == CISTPL_NULL) { ! 522: ofs++; continue; ! 523: } ! 524: } ! 525: ! 526: /* End of chain? Follow long link if possible */ ! 527: if (link[0] == CISTPL_END) { ! 528: if ((ofs = follow_link(s, tuple)) < 0) ! 529: return CS_NO_MORE_ITEMS; ! 530: attr = SPACE(tuple->Flags); ! 531: read_cis_cache(s, attr, ofs, 2, link); ! 532: } ! 533: ! 534: /* Is this a link tuple? Make a note of it */ ! 535: if ((link[0] == CISTPL_LONGLINK_A) || ! 536: (link[0] == CISTPL_LONGLINK_C) || ! 537: (link[0] == CISTPL_LONGLINK_MFC) || ! 538: (link[0] == CISTPL_LINKTARGET) || ! 539: (link[0] == CISTPL_INDIRECT) || ! 540: (link[0] == CISTPL_NO_LINK)) { ! 541: switch (link[0]) { ! 542: case CISTPL_LONGLINK_A: ! 543: HAS_LINK(tuple->Flags) = 1; ! 544: LINK_SPACE(tuple->Flags) = attr | IS_ATTR; ! 545: read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset); ! 546: break; ! 547: case CISTPL_LONGLINK_C: ! 548: HAS_LINK(tuple->Flags) = 1; ! 549: LINK_SPACE(tuple->Flags) = attr & ~IS_ATTR; ! 550: read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset); ! 551: break; ! 552: case CISTPL_INDIRECT: ! 553: HAS_LINK(tuple->Flags) = 1; ! 554: LINK_SPACE(tuple->Flags) = IS_ATTR | IS_INDIRECT; ! 555: tuple->LinkOffset = 0; ! 556: break; ! 557: case CISTPL_LONGLINK_MFC: ! 558: tuple->LinkOffset = ofs + 3; ! 559: LINK_SPACE(tuple->Flags) = attr; ! 560: if (handle->Function == BIND_FN_ALL) { ! 561: /* Follow all the MFC links */ ! 562: read_cis_cache(s, attr, ofs+2, 1, &tmp); ! 563: MFC_FN(tuple->Flags) = tmp; ! 564: } else { ! 565: /* Follow exactly one of the links */ ! 566: MFC_FN(tuple->Flags) = 1; ! 567: tuple->LinkOffset += handle->Function * 5; ! 568: } ! 569: break; ! 570: case CISTPL_NO_LINK: ! 571: HAS_LINK(tuple->Flags) = 0; ! 572: break; ! 573: } ! 574: if ((tuple->Attributes & TUPLE_RETURN_LINK) && ! 575: (tuple->DesiredTuple == RETURN_FIRST_TUPLE)) ! 576: break; ! 577: } else ! 578: if (tuple->DesiredTuple == RETURN_FIRST_TUPLE) ! 579: break; ! 580: ! 581: if (link[0] == tuple->DesiredTuple) ! 582: break; ! 583: ofs += link[1] + 2; ! 584: } ! 585: if (i == MAX_TUPLES) { ! 586: DEBUG(1, "cs: overrun in get_next_tuple for socket %d\n", ! 587: handle->Socket); ! 588: return CS_NO_MORE_ITEMS; ! 589: } ! 590: ! 591: tuple->TupleCode = link[0]; ! 592: tuple->TupleLink = link[1]; ! 593: tuple->CISOffset = ofs + 2; ! 594: return CS_SUCCESS; ! 595: } ! 596: ! 597: /*====================================================================*/ ! 598: ! 599: #define _MIN(a, b) (((a) < (b)) ? (a) : (b)) ! 600: ! 601: int get_tuple_data(client_handle_t handle, tuple_t *tuple) ! 602: { ! 603: socket_info_t *s; ! 604: u_int len; ! 605: ! 606: if (CHECK_HANDLE(handle)) ! 607: return CS_BAD_HANDLE; ! 608: ! 609: s = SOCKET(handle); ! 610: ! 611: if (tuple->TupleLink < tuple->TupleOffset) ! 612: return CS_NO_MORE_ITEMS; ! 613: len = tuple->TupleLink - tuple->TupleOffset; ! 614: tuple->TupleDataLen = tuple->TupleLink; ! 615: if (len == 0) ! 616: return CS_SUCCESS; ! 617: read_cis_cache(s, SPACE(tuple->Flags), ! 618: tuple->CISOffset + tuple->TupleOffset, ! 619: _MIN(len, tuple->TupleDataMax), tuple->TupleData); ! 620: return CS_SUCCESS; ! 621: } ! 622: ! 623: /*====================================================================== ! 624: ! 625: Parsing routines for individual tuples ! 626: ! 627: ======================================================================*/ ! 628: ! 629: static int parse_device(tuple_t *tuple, cistpl_device_t *device) ! 630: { ! 631: int i; ! 632: u_char scale; ! 633: u_char *p, *q; ! 634: ! 635: p = (u_char *)tuple->TupleData; ! 636: q = p + tuple->TupleDataLen; ! 637: ! 638: device->ndev = 0; ! 639: for (i = 0; i < CISTPL_MAX_DEVICES; i++) { ! 640: ! 641: if (*p == 0xff) break; ! 642: device->dev[i].type = (*p >> 4); ! 643: device->dev[i].wp = (*p & 0x08) ? 1 : 0; ! 644: switch (*p & 0x07) { ! 645: case 0: device->dev[i].speed = 0; break; ! 646: case 1: device->dev[i].speed = 250; break; ! 647: case 2: device->dev[i].speed = 200; break; ! 648: case 3: device->dev[i].speed = 150; break; ! 649: case 4: device->dev[i].speed = 100; break; ! 650: case 7: ! 651: if (++p == q) return CS_BAD_TUPLE; ! 652: device->dev[i].speed = SPEED_CVT(*p); ! 653: while (*p & 0x80) ! 654: if (++p == q) return CS_BAD_TUPLE; ! 655: break; ! 656: default: ! 657: return CS_BAD_TUPLE; ! 658: } ! 659: ! 660: if (++p == q) return CS_BAD_TUPLE; ! 661: if (*p == 0xff) break; ! 662: scale = *p & 7; ! 663: if (scale == 7) return CS_BAD_TUPLE; ! 664: device->dev[i].size = ((*p >> 3) + 1) * (512 << (scale*2)); ! 665: device->ndev++; ! 666: if (++p == q) break; ! 667: } ! 668: ! 669: return CS_SUCCESS; ! 670: } ! 671: ! 672: /*====================================================================*/ ! 673: ! 674: static int parse_checksum(tuple_t *tuple, cistpl_checksum_t *csum) ! 675: { ! 676: u_char *p; ! 677: if (tuple->TupleDataLen < 5) ! 678: return CS_BAD_TUPLE; ! 679: p = (u_char *)tuple->TupleData; ! 680: csum->addr = tuple->CISOffset+(short)le16_to_cpu(*(u_short *)p)-2; ! 681: csum->len = le16_to_cpu(*(u_short *)(p + 2)); ! 682: csum->sum = *(p+4); ! 683: return CS_SUCCESS; ! 684: } ! 685: ! 686: /*====================================================================*/ ! 687: ! 688: static int parse_longlink(tuple_t *tuple, cistpl_longlink_t *link) ! 689: { ! 690: if (tuple->TupleDataLen < 4) ! 691: return CS_BAD_TUPLE; ! 692: link->addr = le32_to_cpu(*(u_int *)tuple->TupleData); ! 693: return CS_SUCCESS; ! 694: } ! 695: ! 696: /*====================================================================*/ ! 697: ! 698: static int parse_longlink_mfc(tuple_t *tuple, ! 699: cistpl_longlink_mfc_t *link) ! 700: { ! 701: u_char *p; ! 702: int i; ! 703: ! 704: p = (u_char *)tuple->TupleData; ! 705: ! 706: link->nfn = *p; p++; ! 707: if (tuple->TupleDataLen <= link->nfn*5) ! 708: return CS_BAD_TUPLE; ! 709: for (i = 0; i < link->nfn; i++) { ! 710: link->fn[i].space = *p; p++; ! 711: link->fn[i].addr = le32_to_cpu(*(u_int *)p); p += 4; ! 712: } ! 713: return CS_SUCCESS; ! 714: } ! 715: ! 716: /*====================================================================*/ ! 717: ! 718: static int parse_strings(u_char *p, u_char *q, int max, ! 719: char *s, u_char *ofs, u_char *found) ! 720: { ! 721: int i, j, ns; ! 722: ! 723: if (p == q) return CS_BAD_TUPLE; ! 724: ns = 0; j = 0; ! 725: for (i = 0; i < max; i++) { ! 726: if (*p == 0xff) break; ! 727: ofs[i] = j; ! 728: ns++; ! 729: for (;;) { ! 730: s[j++] = (*p == 0xff) ? '\0' : *p; ! 731: if ((*p == '\0') || (*p == 0xff)) break; ! 732: if (++p == q) return CS_BAD_TUPLE; ! 733: } ! 734: if ((*p == 0xff) || (++p == q)) break; ! 735: } ! 736: if (found) { ! 737: *found = ns; ! 738: return CS_SUCCESS; ! 739: } else { ! 740: return (ns == max) ? CS_SUCCESS : CS_BAD_TUPLE; ! 741: } ! 742: } ! 743: ! 744: /*====================================================================*/ ! 745: ! 746: static int parse_vers_1(tuple_t *tuple, cistpl_vers_1_t *vers_1) ! 747: { ! 748: u_char *p, *q; ! 749: ! 750: p = (u_char *)tuple->TupleData; ! 751: q = p + tuple->TupleDataLen; ! 752: ! 753: vers_1->major = *p; p++; ! 754: vers_1->minor = *p; p++; ! 755: if (p >= q) return CS_BAD_TUPLE; ! 756: ! 757: return parse_strings(p, q, CISTPL_VERS_1_MAX_PROD_STRINGS, ! 758: vers_1->str, vers_1->ofs, &vers_1->ns); ! 759: } ! 760: ! 761: /*====================================================================*/ ! 762: ! 763: static int parse_altstr(tuple_t *tuple, cistpl_altstr_t *altstr) ! 764: { ! 765: u_char *p, *q; ! 766: ! 767: p = (u_char *)tuple->TupleData; ! 768: q = p + tuple->TupleDataLen; ! 769: ! 770: return parse_strings(p, q, CISTPL_MAX_ALTSTR_STRINGS, ! 771: altstr->str, altstr->ofs, &altstr->ns); ! 772: } ! 773: ! 774: /*====================================================================*/ ! 775: ! 776: static int parse_jedec(tuple_t *tuple, cistpl_jedec_t *jedec) ! 777: { ! 778: u_char *p, *q; ! 779: int nid; ! 780: ! 781: p = (u_char *)tuple->TupleData; ! 782: q = p + tuple->TupleDataLen; ! 783: ! 784: for (nid = 0; nid < CISTPL_MAX_DEVICES; nid++) { ! 785: if (p > q-2) break; ! 786: jedec->id[nid].mfr = p[0]; ! 787: jedec->id[nid].info = p[1]; ! 788: p += 2; ! 789: } ! 790: jedec->nid = nid; ! 791: return CS_SUCCESS; ! 792: } ! 793: ! 794: /*====================================================================*/ ! 795: ! 796: static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m) ! 797: { ! 798: u_short *p; ! 799: if (tuple->TupleDataLen < 4) ! 800: return CS_BAD_TUPLE; ! 801: p = (u_short *)tuple->TupleData; ! 802: m->manf = le16_to_cpu(p[0]); ! 803: m->card = le16_to_cpu(p[1]); ! 804: return CS_SUCCESS; ! 805: } ! 806: ! 807: /*====================================================================*/ ! 808: ! 809: static int parse_funcid(tuple_t *tuple, cistpl_funcid_t *f) ! 810: { ! 811: u_char *p; ! 812: if (tuple->TupleDataLen < 2) ! 813: return CS_BAD_TUPLE; ! 814: p = (u_char *)tuple->TupleData; ! 815: f->func = p[0]; ! 816: f->sysinit = p[1]; ! 817: return CS_SUCCESS; ! 818: } ! 819: ! 820: /*====================================================================*/ ! 821: ! 822: static int parse_funce(tuple_t *tuple, cistpl_funce_t *f) ! 823: { ! 824: u_char *p; ! 825: int i; ! 826: if (tuple->TupleDataLen < 1) ! 827: return CS_BAD_TUPLE; ! 828: p = (u_char *)tuple->TupleData; ! 829: f->type = p[0]; ! 830: for (i = 1; i < tuple->TupleDataLen; i++) ! 831: f->data[i-1] = p[i]; ! 832: return CS_SUCCESS; ! 833: } ! 834: ! 835: /*====================================================================*/ ! 836: ! 837: static int parse_config(tuple_t *tuple, cistpl_config_t *config) ! 838: { ! 839: int rasz, rmsz, i; ! 840: u_char *p; ! 841: ! 842: p = (u_char *)tuple->TupleData; ! 843: rasz = *p & 0x03; ! 844: rmsz = (*p & 0x3c) >> 2; ! 845: if (tuple->TupleDataLen < rasz+rmsz+4) ! 846: return CS_BAD_TUPLE; ! 847: config->last_idx = *(++p); ! 848: p++; ! 849: config->base = 0; ! 850: for (i = 0; i <= rasz; i++) ! 851: config->base += p[i] << (8*i); ! 852: p += rasz+1; ! 853: for (i = 0; i < 4; i++) ! 854: config->rmask[i] = 0; ! 855: for (i = 0; i <= rmsz; i++) ! 856: config->rmask[i>>2] += p[i] << (8*(i%4)); ! 857: config->subtuples = tuple->TupleDataLen - (rasz+rmsz+4); ! 858: return CS_SUCCESS; ! 859: } ! 860: ! 861: /*====================================================================== ! 862: ! 863: The following routines are all used to parse the nightmarish ! 864: config table entries. ! 865: ! 866: ======================================================================*/ ! 867: ! 868: static u_char *parse_power(u_char *p, u_char *q, ! 869: cistpl_power_t *pwr) ! 870: { ! 871: int i; ! 872: u_int scale; ! 873: ! 874: if (p == q) return NULL; ! 875: pwr->present = *p; ! 876: pwr->flags = 0; ! 877: p++; ! 878: for (i = 0; i < 7; i++) ! 879: if (pwr->present & (1<<i)) { ! 880: if (p == q) return NULL; ! 881: pwr->param[i] = POWER_CVT(*p); ! 882: scale = POWER_SCALE(*p); ! 883: while (*p & 0x80) { ! 884: if (++p == q) return NULL; ! 885: if ((*p & 0x7f) < 100) ! 886: pwr->param[i] += (*p & 0x7f) * scale / 100; ! 887: else if (*p == 0x7d) ! 888: pwr->flags |= CISTPL_POWER_HIGHZ_OK; ! 889: else if (*p == 0x7e) ! 890: pwr->param[i] = 0; ! 891: else if (*p == 0x7f) ! 892: pwr->flags |= CISTPL_POWER_HIGHZ_REQ; ! 893: else ! 894: return NULL; ! 895: } ! 896: p++; ! 897: } ! 898: return p; ! 899: } ! 900: ! 901: /*====================================================================*/ ! 902: ! 903: static u_char *parse_timing(u_char *p, u_char *q, ! 904: cistpl_timing_t *timing) ! 905: { ! 906: u_char scale; ! 907: ! 908: if (p == q) return NULL; ! 909: scale = *p; ! 910: if ((scale & 3) != 3) { ! 911: if (++p == q) return NULL; ! 912: timing->wait = SPEED_CVT(*p); ! 913: timing->waitscale = exponent[scale & 3]; ! 914: } else ! 915: timing->wait = 0; ! 916: scale >>= 2; ! 917: if ((scale & 7) != 7) { ! 918: if (++p == q) return NULL; ! 919: timing->ready = SPEED_CVT(*p); ! 920: timing->rdyscale = exponent[scale & 7]; ! 921: } else ! 922: timing->ready = 0; ! 923: scale >>= 3; ! 924: if (scale != 7) { ! 925: if (++p == q) return NULL; ! 926: timing->reserved = SPEED_CVT(*p); ! 927: timing->rsvscale = exponent[scale]; ! 928: } else ! 929: timing->reserved = 0; ! 930: p++; ! 931: return p; ! 932: } ! 933: ! 934: /*====================================================================*/ ! 935: ! 936: static u_char *parse_io(u_char *p, u_char *q, cistpl_io_t *io) ! 937: { ! 938: int i, j, bsz, lsz; ! 939: ! 940: if (p == q) return NULL; ! 941: io->flags = *p; ! 942: ! 943: if (!(*p & 0x80)) { ! 944: io->nwin = 1; ! 945: io->win[0].base = 0; ! 946: io->win[0].len = (1 << (io->flags & CISTPL_IO_LINES_MASK)); ! 947: return p+1; ! 948: } ! 949: ! 950: if (++p == q) return NULL; ! 951: io->nwin = (*p & 0x0f) + 1; ! 952: bsz = (*p & 0x30) >> 4; ! 953: if (bsz == 3) bsz++; ! 954: lsz = (*p & 0xc0) >> 6; ! 955: if (lsz == 3) lsz++; ! 956: p++; ! 957: ! 958: for (i = 0; i < io->nwin; i++) { ! 959: io->win[i].base = 0; ! 960: io->win[i].len = 1; ! 961: for (j = 0; j < bsz; j++, p++) { ! 962: if (p == q) return NULL; ! 963: io->win[i].base += *p << (j*8); ! 964: } ! 965: for (j = 0; j < lsz; j++, p++) { ! 966: if (p == q) return NULL; ! 967: io->win[i].len += *p << (j*8); ! 968: } ! 969: } ! 970: return p; ! 971: } ! 972: ! 973: /*====================================================================*/ ! 974: ! 975: static u_char *parse_mem(u_char *p, u_char *q, cistpl_mem_t *mem) ! 976: { ! 977: int i, j, asz, lsz, has_ha; ! 978: u_int len, ca, ha; ! 979: ! 980: if (p == q) return NULL; ! 981: ! 982: mem->nwin = (*p & 0x07) + 1; ! 983: lsz = (*p & 0x18) >> 3; ! 984: asz = (*p & 0x60) >> 5; ! 985: has_ha = (*p & 0x80); ! 986: if (++p == q) return NULL; ! 987: ! 988: for (i = 0; i < mem->nwin; i++) { ! 989: len = ca = ha = 0; ! 990: for (j = 0; j < lsz; j++, p++) { ! 991: if (p == q) return NULL; ! 992: len += *p << (j*8); ! 993: } ! 994: for (j = 0; j < asz; j++, p++) { ! 995: if (p == q) return NULL; ! 996: ca += *p << (j*8); ! 997: } ! 998: if (has_ha) ! 999: for (j = 0; j < asz; j++, p++) { ! 1000: if (p == q) return NULL; ! 1001: ha += *p << (j*8); ! 1002: } ! 1003: mem->win[i].len = len << 8; ! 1004: mem->win[i].card_addr = ca << 8; ! 1005: mem->win[i].host_addr = ha << 8; ! 1006: } ! 1007: return p; ! 1008: } ! 1009: ! 1010: /*====================================================================*/ ! 1011: ! 1012: static u_char *parse_irq(u_char *p, u_char *q, cistpl_irq_t *irq) ! 1013: { ! 1014: if (p == q) return NULL; ! 1015: irq->IRQInfo1 = *p; p++; ! 1016: if (irq->IRQInfo1 & IRQ_INFO2_VALID) { ! 1017: if (p+2 > q) return NULL; ! 1018: irq->IRQInfo2 = (p[1]<<8) + p[0]; ! 1019: p += 2; ! 1020: } ! 1021: return p; ! 1022: } ! 1023: ! 1024: /*====================================================================*/ ! 1025: ! 1026: static int parse_cftable_entry(tuple_t *tuple, ! 1027: cistpl_cftable_entry_t *entry) ! 1028: { ! 1029: u_char *p, *q, features; ! 1030: ! 1031: p = tuple->TupleData; ! 1032: q = p + tuple->TupleDataLen; ! 1033: entry->index = *p & 0x3f; ! 1034: entry->flags = 0; ! 1035: if (*p & 0x40) ! 1036: entry->flags |= CISTPL_CFTABLE_DEFAULT; ! 1037: if (*p & 0x80) { ! 1038: if (++p == q) return CS_BAD_TUPLE; ! 1039: if (*p & 0x10) ! 1040: entry->flags |= CISTPL_CFTABLE_BVDS; ! 1041: if (*p & 0x20) ! 1042: entry->flags |= CISTPL_CFTABLE_WP; ! 1043: if (*p & 0x40) ! 1044: entry->flags |= CISTPL_CFTABLE_RDYBSY; ! 1045: if (*p & 0x80) ! 1046: entry->flags |= CISTPL_CFTABLE_MWAIT; ! 1047: entry->interface = *p & 0x0f; ! 1048: } else ! 1049: entry->interface = 0; ! 1050: ! 1051: /* Process optional features */ ! 1052: if (++p == q) return CS_BAD_TUPLE; ! 1053: features = *p; p++; ! 1054: ! 1055: /* Power options */ ! 1056: if ((features & 3) > 0) { ! 1057: p = parse_power(p, q, &entry->vcc); ! 1058: if (p == NULL) return CS_BAD_TUPLE; ! 1059: } else ! 1060: entry->vcc.present = 0; ! 1061: if ((features & 3) > 1) { ! 1062: p = parse_power(p, q, &entry->vpp1); ! 1063: if (p == NULL) return CS_BAD_TUPLE; ! 1064: } else ! 1065: entry->vpp1.present = 0; ! 1066: if ((features & 3) > 2) { ! 1067: p = parse_power(p, q, &entry->vpp2); ! 1068: if (p == NULL) return CS_BAD_TUPLE; ! 1069: } else ! 1070: entry->vpp2.present = 0; ! 1071: ! 1072: /* Timing options */ ! 1073: if (features & 0x04) { ! 1074: p = parse_timing(p, q, &entry->timing); ! 1075: if (p == NULL) return CS_BAD_TUPLE; ! 1076: } else { ! 1077: entry->timing.wait = 0; ! 1078: entry->timing.ready = 0; ! 1079: entry->timing.reserved = 0; ! 1080: } ! 1081: ! 1082: /* I/O window options */ ! 1083: if (features & 0x08) { ! 1084: p = parse_io(p, q, &entry->io); ! 1085: if (p == NULL) return CS_BAD_TUPLE; ! 1086: } else ! 1087: entry->io.nwin = 0; ! 1088: ! 1089: /* Interrupt options */ ! 1090: if (features & 0x10) { ! 1091: p = parse_irq(p, q, &entry->irq); ! 1092: if (p == NULL) return CS_BAD_TUPLE; ! 1093: } else ! 1094: entry->irq.IRQInfo1 = 0; ! 1095: ! 1096: switch (features & 0x60) { ! 1097: case 0x00: ! 1098: entry->mem.nwin = 0; ! 1099: break; ! 1100: case 0x20: ! 1101: entry->mem.nwin = 1; ! 1102: entry->mem.win[0].len = le16_to_cpu(*(u_short *)p) << 8; ! 1103: entry->mem.win[0].card_addr = 0; ! 1104: entry->mem.win[0].host_addr = 0; ! 1105: p += 2; ! 1106: if (p > q) return CS_BAD_TUPLE; ! 1107: break; ! 1108: case 0x40: ! 1109: entry->mem.nwin = 1; ! 1110: entry->mem.win[0].len = le16_to_cpu(*(u_short *)p) << 8; ! 1111: entry->mem.win[0].card_addr = ! 1112: le16_to_cpu(*(u_short *)(p+2)) << 8; ! 1113: entry->mem.win[0].host_addr = 0; ! 1114: p += 4; ! 1115: if (p > q) return CS_BAD_TUPLE; ! 1116: break; ! 1117: case 0x60: ! 1118: p = parse_mem(p, q, &entry->mem); ! 1119: if (p == NULL) return CS_BAD_TUPLE; ! 1120: break; ! 1121: } ! 1122: ! 1123: /* Misc features */ ! 1124: if (features & 0x80) { ! 1125: if (p == q) return CS_BAD_TUPLE; ! 1126: entry->flags |= (*p << 8); ! 1127: while (*p & 0x80) ! 1128: if (++p == q) return CS_BAD_TUPLE; ! 1129: p++; ! 1130: } ! 1131: ! 1132: entry->subtuples = q-p; ! 1133: ! 1134: return CS_SUCCESS; ! 1135: } ! 1136: ! 1137: /*====================================================================*/ ! 1138: ! 1139: #ifdef CONFIG_CARDBUS ! 1140: ! 1141: static int parse_bar(tuple_t *tuple, cistpl_bar_t *bar) ! 1142: { ! 1143: u_char *p; ! 1144: if (tuple->TupleDataLen < 6) ! 1145: return CS_BAD_TUPLE; ! 1146: p = (u_char *)tuple->TupleData; ! 1147: bar->attr = *p; ! 1148: p += 2; ! 1149: bar->size = le32_to_cpu(*(u_int *)p); ! 1150: return CS_SUCCESS; ! 1151: } ! 1152: ! 1153: static int parse_config_cb(tuple_t *tuple, cistpl_config_t *config) ! 1154: { ! 1155: u_char *p; ! 1156: ! 1157: p = (u_char *)tuple->TupleData; ! 1158: if ((*p != 3) || (tuple->TupleDataLen < 6)) ! 1159: return CS_BAD_TUPLE; ! 1160: config->last_idx = *(++p); ! 1161: p++; ! 1162: config->base = le32_to_cpu(*(u_int *)p); ! 1163: config->subtuples = tuple->TupleDataLen - 6; ! 1164: return CS_SUCCESS; ! 1165: } ! 1166: ! 1167: static int parse_cftable_entry_cb(tuple_t *tuple, ! 1168: cistpl_cftable_entry_cb_t *entry) ! 1169: { ! 1170: u_char *p, *q, features; ! 1171: ! 1172: p = tuple->TupleData; ! 1173: q = p + tuple->TupleDataLen; ! 1174: entry->index = *p & 0x3f; ! 1175: entry->flags = 0; ! 1176: if (*p & 0x40) ! 1177: entry->flags |= CISTPL_CFTABLE_DEFAULT; ! 1178: ! 1179: /* Process optional features */ ! 1180: if (++p == q) return CS_BAD_TUPLE; ! 1181: features = *p; p++; ! 1182: ! 1183: /* Power options */ ! 1184: if ((features & 3) > 0) { ! 1185: p = parse_power(p, q, &entry->vcc); ! 1186: if (p == NULL) return CS_BAD_TUPLE; ! 1187: } else ! 1188: entry->vcc.present = 0; ! 1189: if ((features & 3) > 1) { ! 1190: p = parse_power(p, q, &entry->vpp1); ! 1191: if (p == NULL) return CS_BAD_TUPLE; ! 1192: } else ! 1193: entry->vpp1.present = 0; ! 1194: if ((features & 3) > 2) { ! 1195: p = parse_power(p, q, &entry->vpp2); ! 1196: if (p == NULL) return CS_BAD_TUPLE; ! 1197: } else ! 1198: entry->vpp2.present = 0; ! 1199: ! 1200: /* I/O window options */ ! 1201: if (features & 0x08) { ! 1202: if (p == q) return CS_BAD_TUPLE; ! 1203: entry->io = *p; p++; ! 1204: } else ! 1205: entry->io = 0; ! 1206: ! 1207: /* Interrupt options */ ! 1208: if (features & 0x10) { ! 1209: p = parse_irq(p, q, &entry->irq); ! 1210: if (p == NULL) return CS_BAD_TUPLE; ! 1211: } else ! 1212: entry->irq.IRQInfo1 = 0; ! 1213: ! 1214: if (features & 0x20) { ! 1215: if (p == q) return CS_BAD_TUPLE; ! 1216: entry->mem = *p; p++; ! 1217: } else ! 1218: entry->mem = 0; ! 1219: ! 1220: /* Misc features */ ! 1221: if (features & 0x80) { ! 1222: if (p == q) return CS_BAD_TUPLE; ! 1223: entry->flags |= (*p << 8); ! 1224: if (*p & 0x80) { ! 1225: if (++p == q) return CS_BAD_TUPLE; ! 1226: entry->flags |= (*p << 16); ! 1227: } ! 1228: while (*p & 0x80) ! 1229: if (++p == q) return CS_BAD_TUPLE; ! 1230: p++; ! 1231: } ! 1232: ! 1233: entry->subtuples = q-p; ! 1234: ! 1235: return CS_SUCCESS; ! 1236: } ! 1237: ! 1238: #endif ! 1239: ! 1240: /*====================================================================*/ ! 1241: ! 1242: static int parse_device_geo(tuple_t *tuple, cistpl_device_geo_t *geo) ! 1243: { ! 1244: u_char *p, *q; ! 1245: int n; ! 1246: ! 1247: p = (u_char *)tuple->TupleData; ! 1248: q = p + tuple->TupleDataLen; ! 1249: ! 1250: for (n = 0; n < CISTPL_MAX_DEVICES; n++) { ! 1251: if (p > q-6) break; ! 1252: geo->geo[n].buswidth = p[0]; ! 1253: geo->geo[n].erase_block = 1 << (p[1]-1); ! 1254: geo->geo[n].read_block = 1 << (p[2]-1); ! 1255: geo->geo[n].write_block = 1 << (p[3]-1); ! 1256: geo->geo[n].partition = 1 << (p[4]-1); ! 1257: geo->geo[n].interleave = 1 << (p[5]-1); ! 1258: p += 6; ! 1259: } ! 1260: geo->ngeo = n; ! 1261: return CS_SUCCESS; ! 1262: } ! 1263: ! 1264: /*====================================================================*/ ! 1265: ! 1266: static int parse_vers_2(tuple_t *tuple, cistpl_vers_2_t *v2) ! 1267: { ! 1268: u_char *p, *q; ! 1269: ! 1270: if (tuple->TupleDataLen < 10) ! 1271: return CS_BAD_TUPLE; ! 1272: ! 1273: p = tuple->TupleData; ! 1274: q = p + tuple->TupleDataLen; ! 1275: ! 1276: v2->vers = p[0]; ! 1277: v2->comply = p[1]; ! 1278: v2->dindex = le16_to_cpu(*(u_short *)(p+2)); ! 1279: v2->vspec8 = p[6]; ! 1280: v2->vspec9 = p[7]; ! 1281: v2->nhdr = p[8]; ! 1282: p += 9; ! 1283: return parse_strings(p, q, 2, v2->str, &v2->vendor, NULL); ! 1284: } ! 1285: ! 1286: /*====================================================================*/ ! 1287: ! 1288: static int parse_org(tuple_t *tuple, cistpl_org_t *org) ! 1289: { ! 1290: u_char *p, *q; ! 1291: int i; ! 1292: ! 1293: p = tuple->TupleData; ! 1294: q = p + tuple->TupleDataLen; ! 1295: if (p == q) return CS_BAD_TUPLE; ! 1296: org->data_org = *p; ! 1297: if (++p == q) return CS_BAD_TUPLE; ! 1298: for (i = 0; i < 30; i++) { ! 1299: org->desc[i] = *p; ! 1300: if (*p == '\0') break; ! 1301: if (++p == q) return CS_BAD_TUPLE; ! 1302: } ! 1303: return CS_SUCCESS; ! 1304: } ! 1305: ! 1306: /*====================================================================*/ ! 1307: ! 1308: static int parse_format(tuple_t *tuple, cistpl_format_t *fmt) ! 1309: { ! 1310: u_char *p; ! 1311: ! 1312: if (tuple->TupleDataLen < 10) ! 1313: return CS_BAD_TUPLE; ! 1314: ! 1315: p = tuple->TupleData; ! 1316: ! 1317: fmt->type = p[0]; ! 1318: fmt->edc = p[1]; ! 1319: fmt->offset = le32_to_cpu(*(u_int *)(p+2)); ! 1320: fmt->length = le32_to_cpu(*(u_int *)(p+6)); ! 1321: ! 1322: return CS_SUCCESS; ! 1323: } ! 1324: ! 1325: /*====================================================================*/ ! 1326: ! 1327: int parse_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) ! 1328: { ! 1329: int ret = CS_SUCCESS; ! 1330: ! 1331: if (tuple->TupleDataLen > tuple->TupleDataMax) ! 1332: return CS_BAD_TUPLE; ! 1333: switch (tuple->TupleCode) { ! 1334: case CISTPL_DEVICE: ! 1335: case CISTPL_DEVICE_A: ! 1336: ret = parse_device(tuple, &parse->device); ! 1337: break; ! 1338: #ifdef CONFIG_CARDBUS ! 1339: case CISTPL_BAR: ! 1340: ret = parse_bar(tuple, &parse->bar); ! 1341: break; ! 1342: case CISTPL_CONFIG_CB: ! 1343: ret = parse_config_cb(tuple, &parse->config); ! 1344: break; ! 1345: case CISTPL_CFTABLE_ENTRY_CB: ! 1346: ret = parse_cftable_entry_cb(tuple, &parse->cftable_entry_cb); ! 1347: break; ! 1348: #endif ! 1349: case CISTPL_CHECKSUM: ! 1350: ret = parse_checksum(tuple, &parse->checksum); ! 1351: break; ! 1352: case CISTPL_LONGLINK_A: ! 1353: case CISTPL_LONGLINK_C: ! 1354: ret = parse_longlink(tuple, &parse->longlink); ! 1355: break; ! 1356: case CISTPL_LONGLINK_MFC: ! 1357: ret = parse_longlink_mfc(tuple, &parse->longlink_mfc); ! 1358: break; ! 1359: case CISTPL_VERS_1: ! 1360: ret = parse_vers_1(tuple, &parse->version_1); ! 1361: break; ! 1362: case CISTPL_ALTSTR: ! 1363: ret = parse_altstr(tuple, &parse->altstr); ! 1364: break; ! 1365: case CISTPL_JEDEC_A: ! 1366: case CISTPL_JEDEC_C: ! 1367: ret = parse_jedec(tuple, &parse->jedec); ! 1368: break; ! 1369: case CISTPL_MANFID: ! 1370: ret = parse_manfid(tuple, &parse->manfid); ! 1371: break; ! 1372: case CISTPL_FUNCID: ! 1373: ret = parse_funcid(tuple, &parse->funcid); ! 1374: break; ! 1375: case CISTPL_FUNCE: ! 1376: ret = parse_funce(tuple, &parse->funce); ! 1377: break; ! 1378: case CISTPL_CONFIG: ! 1379: ret = parse_config(tuple, &parse->config); ! 1380: break; ! 1381: case CISTPL_CFTABLE_ENTRY: ! 1382: ret = parse_cftable_entry(tuple, &parse->cftable_entry); ! 1383: break; ! 1384: case CISTPL_DEVICE_GEO: ! 1385: case CISTPL_DEVICE_GEO_A: ! 1386: ret = parse_device_geo(tuple, &parse->device_geo); ! 1387: break; ! 1388: case CISTPL_VERS_2: ! 1389: ret = parse_vers_2(tuple, &parse->vers_2); ! 1390: break; ! 1391: case CISTPL_ORG: ! 1392: ret = parse_org(tuple, &parse->org); ! 1393: break; ! 1394: case CISTPL_FORMAT: ! 1395: case CISTPL_FORMAT_A: ! 1396: ret = parse_format(tuple, &parse->format); ! 1397: break; ! 1398: case CISTPL_NO_LINK: ! 1399: case CISTPL_LINKTARGET: ! 1400: ret = CS_SUCCESS; ! 1401: break; ! 1402: default: ! 1403: ret = CS_UNSUPPORTED_FUNCTION; ! 1404: break; ! 1405: } ! 1406: return ret; ! 1407: } ! 1408: ! 1409: /*====================================================================== ! 1410: ! 1411: This is used internally by Card Services to look up CIS stuff. ! 1412: ! 1413: ======================================================================*/ ! 1414: ! 1415: int read_tuple(client_handle_t handle, cisdata_t code, void *parse) ! 1416: { ! 1417: tuple_t tuple; ! 1418: cisdata_t *buf; ! 1419: int ret; ! 1420: ! 1421: buf = kmalloc(255, GFP_KERNEL); ! 1422: if (buf == NULL) ! 1423: return CS_OUT_OF_RESOURCE; ! 1424: tuple.DesiredTuple = code; ! 1425: tuple.Attributes = TUPLE_RETURN_COMMON; ! 1426: ret = CardServices(GetFirstTuple, handle, &tuple, NULL); ! 1427: if (ret != CS_SUCCESS) goto done; ! 1428: tuple.TupleData = buf; ! 1429: tuple.TupleOffset = 0; ! 1430: tuple.TupleDataMax = 255; ! 1431: ret = CardServices(GetTupleData, handle, &tuple, NULL); ! 1432: if (ret != CS_SUCCESS) goto done; ! 1433: ret = CardServices(ParseTuple, handle, &tuple, parse); ! 1434: done: ! 1435: kfree(buf); ! 1436: return ret; ! 1437: } ! 1438: ! 1439: /*====================================================================== ! 1440: ! 1441: This tries to determine if a card has a sensible CIS. It returns ! 1442: the number of tuples in the CIS, or 0 if the CIS looks bad. The ! 1443: checks include making sure several critical tuples are present and ! 1444: valid; seeing if the total number of tuples is reasonable; and ! 1445: looking for tuples that use reserved codes. ! 1446: ! 1447: ======================================================================*/ ! 1448: ! 1449: int validate_cis(client_handle_t handle, cisinfo_t *info) ! 1450: { ! 1451: tuple_t tuple; ! 1452: cisparse_t *p; ! 1453: int ret, reserved, dev_ok = 0, ident_ok = 0; ! 1454: ! 1455: if (CHECK_HANDLE(handle)) ! 1456: return CS_BAD_HANDLE; ! 1457: p = kmalloc(sizeof(*p), GFP_KERNEL); ! 1458: if (p == NULL) ! 1459: return CS_OUT_OF_RESOURCE; ! 1460: ! 1461: info->Chains = reserved = 0; ! 1462: tuple.DesiredTuple = RETURN_FIRST_TUPLE; ! 1463: tuple.Attributes = TUPLE_RETURN_COMMON; ! 1464: ret = get_first_tuple(handle, &tuple); ! 1465: if (ret != CS_SUCCESS) ! 1466: goto done; ! 1467: ! 1468: /* First tuple should be DEVICE; we should really have either that ! 1469: or a CFTABLE_ENTRY of some sort */ ! 1470: if ((tuple.TupleCode == CISTPL_DEVICE) || ! 1471: (read_tuple(handle, CISTPL_CFTABLE_ENTRY, p) == CS_SUCCESS) || ! 1472: (read_tuple(handle, CISTPL_CFTABLE_ENTRY_CB, p) == CS_SUCCESS)) ! 1473: dev_ok++; ! 1474: ! 1475: /* All cards should have a MANFID tuple, and/or a VERS_1 or VERS_2 ! 1476: tuple, for card identification. Certain old D-Link and Linksys ! 1477: cards have only a broken VERS_2 tuple; hence the bogus test. */ ! 1478: if ((read_tuple(handle, CISTPL_MANFID, p) == CS_SUCCESS) || ! 1479: (read_tuple(handle, CISTPL_VERS_1, p) == CS_SUCCESS) || ! 1480: (read_tuple(handle, CISTPL_VERS_2, p) != CS_NO_MORE_ITEMS)) ! 1481: ident_ok++; ! 1482: ! 1483: if (!dev_ok && !ident_ok) ! 1484: goto done; ! 1485: ! 1486: for (info->Chains = 1; info->Chains < MAX_TUPLES; info->Chains++) { ! 1487: ret = get_next_tuple(handle, &tuple); ! 1488: if (ret != CS_SUCCESS) break; ! 1489: if (((tuple.TupleCode > 0x23) && (tuple.TupleCode < 0x40)) || ! 1490: ((tuple.TupleCode > 0x47) && (tuple.TupleCode < 0x80)) || ! 1491: ((tuple.TupleCode > 0x90) && (tuple.TupleCode < 0xff))) ! 1492: reserved++; ! 1493: } ! 1494: if ((info->Chains == MAX_TUPLES) || (reserved > 5) || ! 1495: ((!dev_ok || !ident_ok) && (info->Chains > 10))) ! 1496: info->Chains = 0; ! 1497: ! 1498: done: ! 1499: kfree(p); ! 1500: return CS_SUCCESS; ! 1501: } ! 1502:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.