Annotation of Gnu-Mach/linux/pcmcia-cs/modules/cistpl.c, revision 1.1

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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.