11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cistpl.c -- 16-bit PCMCIA Card Information Structure parser 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License version 2 as 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * published by the Free Software Foundation. 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The initial developer of the original code is David A. Hinds 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (C) 1999 David A. Hinds 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/major.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 269fea84f46a821aa1ff2d034ffda8ad33bff48015Dominik Brodowski#include <linux/io.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/byteorder.h> 28dc0cf6a263d5a094d8c17287407aad1032a613b3Daniel Ritz#include <asm/unaligned.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/ss.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/cisreg.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/cistpl.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "cs_internal.h" 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const u_char mantissa[] = { 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10, 12, 13, 15, 20, 25, 30, 35, 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40, 45, 50, 55, 60, 70, 80, 90 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const u_int exponent[] = { 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Convert an extended speed byte to a time in nanoseconds */ 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SPEED_CVT(v) \ 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (mantissa[(((v)>>3)&15)-1] * exponent[(v)&7] / 10) 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Convert a power byte to a current in 0.1 microamps */ 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define POWER_CVT(v) \ 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (mantissa[((v)>>3)&15] * exponent[(v)&7] / 10) 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define POWER_SCALE(v) (exponent[(v)&7]) 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Upper limit on reasonable # of tuples */ 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAX_TUPLES 200 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 55a3d0d4d8dd45779b6e174a8567ffb9b485e472afDominik Brodowski/* Bits in IRQInfo1 field */ 56a3d0d4d8dd45779b6e174a8567ffb9b485e472afDominik Brodowski#define IRQ_INFO2_VALID 0x10 57a3d0d4d8dd45779b6e174a8567ffb9b485e472afDominik Brodowski 5837f779554404ddca981ac4b4cc6692fc09b71e96Pavel Machek/* 16-bit CIS? */ 5937f779554404ddca981ac4b4cc6692fc09b71e96Pavel Machekstatic int cis_width; 6037f779554404ddca981ac4b4cc6692fc09b71e96Pavel Machekmodule_param(cis_width, int, 0444); 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid release_cis_mem(struct pcmcia_socket *s) 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 646e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski mutex_lock(&s->ops_mutex); 656e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (s->cis_mem.flags & MAP_ACTIVE) { 666e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski s->cis_mem.flags &= ~MAP_ACTIVE; 676e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski s->ops->set_mem_map(s, &s->cis_mem); 686e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (s->cis_mem.res) { 696e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski release_resource(s->cis_mem.res); 706e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski kfree(s->cis_mem.res); 716e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski s->cis_mem.res = NULL; 726e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 736e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski iounmap(s->cis_virt); 746e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski s->cis_virt = NULL; 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 766e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski mutex_unlock(&s->ops_mutex); 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 796e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski/** 806e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski * set_cis_map() - map the card memory at "card_offset" into virtual space. 816e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski * 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If flags & MAP_ATTRIB, map the attribute space, otherwise 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * map the memory space. 847ab24855482fbc47712de46c05726d59cd0748e2Dominik Brodowski * 857ab24855482fbc47712de46c05726d59cd0748e2Dominik Brodowski * Must be called with ops_mutex held. 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 876e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowskistatic void __iomem *set_cis_map(struct pcmcia_socket *s, 886e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski unsigned int card_offset, unsigned int flags) 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 902e5a3e79091615c5eae871ad9e794ed48753ae05Dominik Brodowski pccard_mem_map *mem = &s->cis_mem; 912e5a3e79091615c5eae871ad9e794ed48753ae05Dominik Brodowski int ret; 922e5a3e79091615c5eae871ad9e794ed48753ae05Dominik Brodowski 932e5a3e79091615c5eae871ad9e794ed48753ae05Dominik Brodowski if (!(s->features & SS_CAP_STATIC_MAP) && (mem->res == NULL)) { 946e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski mem->res = pcmcia_find_mem_region(0, s->map_size, 956e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski s->map_size, 0, s); 962e5a3e79091615c5eae871ad9e794ed48753ae05Dominik Brodowski if (mem->res == NULL) { 972e55bf6b99fb05f3f4228e7f1381624ac8ac7e3dDominik Brodowski dev_printk(KERN_NOTICE, &s->dev, 982e55bf6b99fb05f3f4228e7f1381624ac8ac7e3dDominik Brodowski "cs: unable to map card memory!\n"); 992e5a3e79091615c5eae871ad9e794ed48753ae05Dominik Brodowski return NULL; 1002e5a3e79091615c5eae871ad9e794ed48753ae05Dominik Brodowski } 1012e5a3e79091615c5eae871ad9e794ed48753ae05Dominik Brodowski s->cis_virt = NULL; 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1032ad0a0a793cbd87a87488d59abc744374669498fDominik Brodowski 1042e5a3e79091615c5eae871ad9e794ed48753ae05Dominik Brodowski if (!(s->features & SS_CAP_STATIC_MAP) && (!s->cis_virt)) 1052e5a3e79091615c5eae871ad9e794ed48753ae05Dominik Brodowski s->cis_virt = ioremap(mem->res->start, s->map_size); 1062e5a3e79091615c5eae871ad9e794ed48753ae05Dominik Brodowski 1072e5a3e79091615c5eae871ad9e794ed48753ae05Dominik Brodowski mem->card_start = card_offset; 1082e5a3e79091615c5eae871ad9e794ed48753ae05Dominik Brodowski mem->flags = flags; 1092e5a3e79091615c5eae871ad9e794ed48753ae05Dominik Brodowski 1102e5a3e79091615c5eae871ad9e794ed48753ae05Dominik Brodowski ret = s->ops->set_mem_map(s, mem); 1112e5a3e79091615c5eae871ad9e794ed48753ae05Dominik Brodowski if (ret) { 1122e5a3e79091615c5eae871ad9e794ed48753ae05Dominik Brodowski iounmap(s->cis_virt); 1132e5a3e79091615c5eae871ad9e794ed48753ae05Dominik Brodowski s->cis_virt = NULL; 1142e5a3e79091615c5eae871ad9e794ed48753ae05Dominik Brodowski return NULL; 1152e5a3e79091615c5eae871ad9e794ed48753ae05Dominik Brodowski } 1162e5a3e79091615c5eae871ad9e794ed48753ae05Dominik Brodowski 1172e5a3e79091615c5eae871ad9e794ed48753ae05Dominik Brodowski if (s->features & SS_CAP_STATIC_MAP) { 1182e5a3e79091615c5eae871ad9e794ed48753ae05Dominik Brodowski if (s->cis_virt) 1192e5a3e79091615c5eae871ad9e794ed48753ae05Dominik Brodowski iounmap(s->cis_virt); 1202e5a3e79091615c5eae871ad9e794ed48753ae05Dominik Brodowski s->cis_virt = ioremap(mem->static_start, s->map_size); 1212e5a3e79091615c5eae871ad9e794ed48753ae05Dominik Brodowski } 1222e5a3e79091615c5eae871ad9e794ed48753ae05Dominik Brodowski 1232e5a3e79091615c5eae871ad9e794ed48753ae05Dominik Brodowski return s->cis_virt; 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Bits in attr field */ 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IS_ATTR 1 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IS_INDIRECT 8 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1316e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski/** 1326e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski * pcmcia_read_cis_mem() - low-level function to read CIS memory 133059f667d9f81082e94dead14ff3fa7b3b42c98a0Dominik Brodowski * 134059f667d9f81082e94dead14ff3fa7b3b42c98a0Dominik Brodowski * must be called with ops_mutex held 1356e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski */ 136e6ea0b9ec5131ac360581d6924fed536758bd024Dominik Brodowskiint pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int len, void *ptr) 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1396e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski void __iomem *sys, *end; 1406e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski unsigned char *buf = ptr; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1426e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski dev_dbg(&s->dev, "pcmcia_read_cis_mem(%d, %#x, %u)\n", attr, addr, len); 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1446e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (attr & IS_INDIRECT) { 1456e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski /* Indirect accesses use a bunch of special registers at fixed 1466e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski locations in common memory */ 1476e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN; 1486e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (attr & IS_ATTR) { 1496e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski addr *= 2; 1506e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski flags = ICTRL0_AUTOINC; 1516e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1536e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski sys = set_cis_map(s, 0, MAP_ACTIVE | 1546e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ((cis_width) ? MAP_16BIT : 0)); 1556e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (!sys) { 1566e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski dev_dbg(&s->dev, "could not map memory\n"); 1576e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski memset(ptr, 0xff, len); 1586e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -1; 1596e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 1606e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 1616e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski writeb(flags, sys+CISREG_ICTRL0); 1626e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski writeb(addr & 0xff, sys+CISREG_IADDR0); 1636e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski writeb((addr>>8) & 0xff, sys+CISREG_IADDR1); 1646e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski writeb((addr>>16) & 0xff, sys+CISREG_IADDR2); 1656e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski writeb((addr>>24) & 0xff, sys+CISREG_IADDR3); 1666e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski for ( ; len > 0; len--, buf++) 1676e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski *buf = readb(sys+CISREG_IDATA0); 1686e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } else { 1696e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_int inc = 1, card_offset, flags; 1706e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 1716e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (addr > CISTPL_MAX_CIS_SIZE) 1726e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski dev_dbg(&s->dev, 1736e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski "attempt to read CIS mem at addr %#x", addr); 1746e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 1756e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0); 1766e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (attr) { 1776e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski flags |= MAP_ATTRIB; 1786e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski inc++; 1796e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski addr *= 2; 1806e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 1816e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 1826e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski card_offset = addr & ~(s->map_size-1); 1836e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski while (len) { 1846e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski sys = set_cis_map(s, card_offset, flags); 1856e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (!sys) { 1866e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski dev_dbg(&s->dev, "could not map memory\n"); 1876e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski memset(ptr, 0xff, len); 1886e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -1; 1896e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 1906e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski end = sys + s->map_size; 1916e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski sys = sys + (addr & (s->map_size-1)); 1926e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski for ( ; len > 0; len--, buf++, sys += inc) { 1936e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (sys == end) 1946e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 1956e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski *buf = readb(sys); 1966e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 1976e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski card_offset += s->map_size; 1986e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski addr = 0; 1996e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2016e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski dev_dbg(&s->dev, " %#2.2x %#2.2x %#2.2x %#2.2x ...\n", 2026e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski *(u_char *)(ptr+0), *(u_char *)(ptr+1), 2036e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski *(u_char *)(ptr+2), *(u_char *)(ptr+3)); 2046e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return 0; 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2061a8d46631e166a3c79fe1466ce8cfc4721fdf780Dominik Brodowski 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2086e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski/** 2096e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski * pcmcia_write_cis_mem() - low-level function to write CIS memory 2106e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski * 211059f667d9f81082e94dead14ff3fa7b3b42c98a0Dominik Brodowski * Probably only useful for writing one-byte registers. Must be called 212059f667d9f81082e94dead14ff3fa7b3b42c98a0Dominik Brodowski * with ops_mutex held. 2136e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski */ 2141d5cc192d431bce2ebe9fde64054ce903200e179Dominik Brodowskiint pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int len, void *ptr) 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2176e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski void __iomem *sys, *end; 2186e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski unsigned char *buf = ptr; 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2206e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski dev_dbg(&s->dev, 2216e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski "pcmcia_write_cis_mem(%d, %#x, %u)\n", attr, addr, len); 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2236e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (attr & IS_INDIRECT) { 2246e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski /* Indirect accesses use a bunch of special registers at fixed 2256e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski locations in common memory */ 2266e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN; 2276e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (attr & IS_ATTR) { 2286e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski addr *= 2; 2296e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski flags = ICTRL0_AUTOINC; 2306e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2326e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski sys = set_cis_map(s, 0, MAP_ACTIVE | 2336e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ((cis_width) ? MAP_16BIT : 0)); 2346e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (!sys) { 2356e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski dev_dbg(&s->dev, "could not map memory\n"); 2361d5cc192d431bce2ebe9fde64054ce903200e179Dominik Brodowski return -EINVAL; 2376e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 2381a8d46631e166a3c79fe1466ce8cfc4721fdf780Dominik Brodowski 2396e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski writeb(flags, sys+CISREG_ICTRL0); 2406e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski writeb(addr & 0xff, sys+CISREG_IADDR0); 2416e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski writeb((addr>>8) & 0xff, sys+CISREG_IADDR1); 2426e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski writeb((addr>>16) & 0xff, sys+CISREG_IADDR2); 2436e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski writeb((addr>>24) & 0xff, sys+CISREG_IADDR3); 2446e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski for ( ; len > 0; len--, buf++) 2456e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski writeb(*buf, sys+CISREG_IDATA0); 2466e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } else { 2476e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_int inc = 1, card_offset, flags; 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2496e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0); 2506e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (attr & IS_ATTR) { 2516e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski flags |= MAP_ATTRIB; 2526e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski inc++; 2536e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski addr *= 2; 2546e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2566e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski card_offset = addr & ~(s->map_size-1); 2576e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski while (len) { 2586e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski sys = set_cis_map(s, card_offset, flags); 2596e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (!sys) { 2606e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski dev_dbg(&s->dev, "could not map memory\n"); 2611d5cc192d431bce2ebe9fde64054ce903200e179Dominik Brodowski return -EINVAL; 2626e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 2636e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 2646e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski end = sys + s->map_size; 2656e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski sys = sys + (addr & (s->map_size-1)); 2666e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski for ( ; len > 0; len--, buf++, sys += inc) { 2676e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (sys == end) 2686e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 2696e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski writeb(*buf, sys); 2706e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 2716e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski card_offset += s->map_size; 2726e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski addr = 0; 2736e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 2746e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 2751d5cc192d431bce2ebe9fde64054ce903200e179Dominik Brodowski return 0; 2766e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski} 2779fea84f46a821aa1ff2d034ffda8ad33bff48015Dominik Brodowski 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2796e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski/** 2806e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski * read_cis_cache() - read CIS memory or its associated cache 2816e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski * 2826e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski * This is a wrapper around read_cis_mem, with the same interface, 2836e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski * but which caches information, for cards whose CIS may not be 2846e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski * readable all the time. 2856e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski */ 286d700518a0e4d17a47321414e5e487ed53f4ae752Dominik Brodowskistatic int read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, 287d700518a0e4d17a47321414e5e487ed53f4ae752Dominik Brodowski size_t len, void *ptr) 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 28957197b9b7712eb19f5344c466e8aefbac1adbe55Dominik Brodowski struct cis_cache_entry *cis; 290d700518a0e4d17a47321414e5e487ed53f4ae752Dominik Brodowski int ret = 0; 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29257197b9b7712eb19f5344c466e8aefbac1adbe55Dominik Brodowski if (s->state & SOCKET_CARDBUS) 293d700518a0e4d17a47321414e5e487ed53f4ae752Dominik Brodowski return -EINVAL; 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2958680c4b3faa298dc768c2a78a94a84d89854eca9Dominik Brodowski mutex_lock(&s->ops_mutex); 29657197b9b7712eb19f5344c466e8aefbac1adbe55Dominik Brodowski if (s->fake_cis) { 29757197b9b7712eb19f5344c466e8aefbac1adbe55Dominik Brodowski if (s->fake_cis_len >= addr+len) 29857197b9b7712eb19f5344c466e8aefbac1adbe55Dominik Brodowski memcpy(ptr, s->fake_cis+addr, len); 299d700518a0e4d17a47321414e5e487ed53f4ae752Dominik Brodowski else { 30057197b9b7712eb19f5344c466e8aefbac1adbe55Dominik Brodowski memset(ptr, 0xff, len); 301d700518a0e4d17a47321414e5e487ed53f4ae752Dominik Brodowski ret = -EINVAL; 302d700518a0e4d17a47321414e5e487ed53f4ae752Dominik Brodowski } 3038680c4b3faa298dc768c2a78a94a84d89854eca9Dominik Brodowski mutex_unlock(&s->ops_mutex); 304d700518a0e4d17a47321414e5e487ed53f4ae752Dominik Brodowski return ret; 30557197b9b7712eb19f5344c466e8aefbac1adbe55Dominik Brodowski } 30657197b9b7712eb19f5344c466e8aefbac1adbe55Dominik Brodowski 30757197b9b7712eb19f5344c466e8aefbac1adbe55Dominik Brodowski list_for_each_entry(cis, &s->cis_cache, node) { 30857197b9b7712eb19f5344c466e8aefbac1adbe55Dominik Brodowski if (cis->addr == addr && cis->len == len && cis->attr == attr) { 30957197b9b7712eb19f5344c466e8aefbac1adbe55Dominik Brodowski memcpy(ptr, cis->cache, len); 3108680c4b3faa298dc768c2a78a94a84d89854eca9Dominik Brodowski mutex_unlock(&s->ops_mutex); 311d700518a0e4d17a47321414e5e487ed53f4ae752Dominik Brodowski return 0; 31257197b9b7712eb19f5344c466e8aefbac1adbe55Dominik Brodowski } 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 315e6ea0b9ec5131ac360581d6924fed536758bd024Dominik Brodowski ret = pcmcia_read_cis_mem(s, attr, addr, len, ptr); 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ret == 0) { 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Copy data into the cache */ 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cis = kmalloc(sizeof(struct cis_cache_entry) + len, GFP_KERNEL); 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cis) { 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cis->addr = addr; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cis->len = len; 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cis->attr = attr; 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(cis->cache, ptr, len); 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_add(&cis->node, &s->cis_cache); 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 328059f667d9f81082e94dead14ff3fa7b3b42c98a0Dominik Brodowski mutex_unlock(&s->ops_mutex); 329059f667d9f81082e94dead14ff3fa7b3b42c98a0Dominik Brodowski 330d700518a0e4d17a47321414e5e487ed53f4ae752Dominik Brodowski return ret; 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsremove_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, u_int len) 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cis_cache_entry *cis; 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3388680c4b3faa298dc768c2a78a94a84d89854eca9Dominik Brodowski mutex_lock(&s->ops_mutex); 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry(cis, &s->cis_cache, node) 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cis->addr == addr && cis->len == len && cis->attr == attr) { 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del(&cis->node); 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(cis); 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3458680c4b3faa298dc768c2a78a94a84d89854eca9Dominik Brodowski mutex_unlock(&s->ops_mutex); 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 348904e377744bfdcea276c27167fa6a609929f39dcDominik Brodowski/** 349904e377744bfdcea276c27167fa6a609929f39dcDominik Brodowski * destroy_cis_cache() - destroy the CIS cache 350904e377744bfdcea276c27167fa6a609929f39dcDominik Brodowski * @s: pcmcia_socket for which CIS cache shall be destroyed 351904e377744bfdcea276c27167fa6a609929f39dcDominik Brodowski * 3528680c4b3faa298dc768c2a78a94a84d89854eca9Dominik Brodowski * This destroys the CIS cache but keeps any fake CIS alive. Must be 3538680c4b3faa298dc768c2a78a94a84d89854eca9Dominik Brodowski * called with ops_mutex held. 354904e377744bfdcea276c27167fa6a609929f39dcDominik Brodowski */ 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid destroy_cis_cache(struct pcmcia_socket *s) 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct list_head *l, *n; 358904e377744bfdcea276c27167fa6a609929f39dcDominik Brodowski struct cis_cache_entry *cis; 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_safe(l, n, &s->cis_cache) { 361904e377744bfdcea276c27167fa6a609929f39dcDominik Brodowski cis = list_entry(l, struct cis_cache_entry, node); 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_del(&cis->node); 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(cis); 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3676e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski/** 3686e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski * verify_cis_cache() - does the CIS match what is in the CIS cache? 3696e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski */ 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint verify_cis_cache(struct pcmcia_socket *s) 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct cis_cache_entry *cis; 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *buf; 374d700518a0e4d17a47321414e5e487ed53f4ae752Dominik Brodowski int ret; 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37657197b9b7712eb19f5344c466e8aefbac1adbe55Dominik Brodowski if (s->state & SOCKET_CARDBUS) 37757197b9b7712eb19f5344c466e8aefbac1adbe55Dominik Brodowski return -EINVAL; 37857197b9b7712eb19f5344c466e8aefbac1adbe55Dominik Brodowski 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds buf = kmalloc(256, GFP_KERNEL); 380e689597fe890cf22e23195037aa668c39b25ae4bDominik Brodowski if (buf == NULL) { 3811168386aa7d850ead2ae135d5a7949a592c6e9a0Dominik Brodowski dev_printk(KERN_WARNING, &s->dev, 3821168386aa7d850ead2ae135d5a7949a592c6e9a0Dominik Brodowski "no memory for verifying CIS\n"); 3831168386aa7d850ead2ae135d5a7949a592c6e9a0Dominik Brodowski return -ENOMEM; 384e689597fe890cf22e23195037aa668c39b25ae4bDominik Brodowski } 385059f667d9f81082e94dead14ff3fa7b3b42c98a0Dominik Brodowski mutex_lock(&s->ops_mutex); 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds list_for_each_entry(cis, &s->cis_cache, node) { 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int len = cis->len; 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (len > 256) 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = 256; 39157197b9b7712eb19f5344c466e8aefbac1adbe55Dominik Brodowski 392d700518a0e4d17a47321414e5e487ed53f4ae752Dominik Brodowski ret = pcmcia_read_cis_mem(s, cis->attr, cis->addr, len, buf); 393d700518a0e4d17a47321414e5e487ed53f4ae752Dominik Brodowski if (ret || memcmp(buf, cis->cache, len) != 0) { 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(buf); 395059f667d9f81082e94dead14ff3fa7b3b42c98a0Dominik Brodowski mutex_unlock(&s->ops_mutex); 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(buf); 400059f667d9f81082e94dead14ff3fa7b3b42c98a0Dominik Brodowski mutex_unlock(&s->ops_mutex); 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4046e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski/** 4056e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski * pcmcia_replace_cis() - use a replacement CIS instead of the card's CIS 4066e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski * 4076e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski * For really bad cards, we provide a facility for uploading a 4086e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski * replacement CIS. 4096e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski */ 41053efec9513cfb1acff602c7ebdd945d677808e9eDominik Brodowskiint pcmcia_replace_cis(struct pcmcia_socket *s, 41153efec9513cfb1acff602c7ebdd945d677808e9eDominik Brodowski const u8 *data, const size_t len) 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4131168386aa7d850ead2ae135d5a7949a592c6e9a0Dominik Brodowski if (len > CISTPL_MAX_CIS_SIZE) { 4141168386aa7d850ead2ae135d5a7949a592c6e9a0Dominik Brodowski dev_printk(KERN_WARNING, &s->dev, "replacement CIS too big\n"); 4151168386aa7d850ead2ae135d5a7949a592c6e9a0Dominik Brodowski return -EINVAL; 4161168386aa7d850ead2ae135d5a7949a592c6e9a0Dominik Brodowski } 4178680c4b3faa298dc768c2a78a94a84d89854eca9Dominik Brodowski mutex_lock(&s->ops_mutex); 4181168386aa7d850ead2ae135d5a7949a592c6e9a0Dominik Brodowski kfree(s->fake_cis); 4191168386aa7d850ead2ae135d5a7949a592c6e9a0Dominik Brodowski s->fake_cis = kmalloc(len, GFP_KERNEL); 4201168386aa7d850ead2ae135d5a7949a592c6e9a0Dominik Brodowski if (s->fake_cis == NULL) { 4211168386aa7d850ead2ae135d5a7949a592c6e9a0Dominik Brodowski dev_printk(KERN_WARNING, &s->dev, "no memory to replace CIS\n"); 4228680c4b3faa298dc768c2a78a94a84d89854eca9Dominik Brodowski mutex_unlock(&s->ops_mutex); 4231168386aa7d850ead2ae135d5a7949a592c6e9a0Dominik Brodowski return -ENOMEM; 4241168386aa7d850ead2ae135d5a7949a592c6e9a0Dominik Brodowski } 4251168386aa7d850ead2ae135d5a7949a592c6e9a0Dominik Brodowski s->fake_cis_len = len; 4261168386aa7d850ead2ae135d5a7949a592c6e9a0Dominik Brodowski memcpy(s->fake_cis, data, len); 427d700518a0e4d17a47321414e5e487ed53f4ae752Dominik Brodowski dev_info(&s->dev, "Using replacement CIS\n"); 4288680c4b3faa298dc768c2a78a94a84d89854eca9Dominik Brodowski mutex_unlock(&s->ops_mutex); 4291168386aa7d850ead2ae135d5a7949a592c6e9a0Dominik Brodowski return 0; 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4326e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski/* The high-level CIS tuple services */ 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldstypedef struct tuple_flags { 4356e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_int link_space:4; 4366e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_int has_link:1; 4376e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_int mfc_fn:3; 4386e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_int space:4; 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} tuple_flags; 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LINK_SPACE(f) (((tuple_flags *)(&(f)))->link_space) 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define HAS_LINK(f) (((tuple_flags *)(&(f)))->has_link) 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MFC_FN(f) (((tuple_flags *)(&(f)))->mfc_fn) 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SPACE(f) (((tuple_flags *)(&(f)))->space) 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4466e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowskiint pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function, 4476e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski tuple_t *tuple) 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4496e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (!s) 4506e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 4516e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 4526e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (!(s->state & SOCKET_PRESENT) || (s->state & SOCKET_CARDBUS)) 4536e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -ENODEV; 4546e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski tuple->TupleLink = tuple->Flags = 0; 4556e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 4566e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski /* Assume presence of a LONGLINK_C to address 0 */ 4576e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski tuple->CISOffset = tuple->LinkOffset = 0; 4586e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski SPACE(tuple->Flags) = HAS_LINK(tuple->Flags) = 1; 4596e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 4606e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if ((s->functions > 1) && !(tuple->Attributes & TUPLE_RETURN_COMMON)) { 4616e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski cisdata_t req = tuple->DesiredTuple; 4626e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski tuple->DesiredTuple = CISTPL_LONGLINK_MFC; 4636e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (pccard_get_next_tuple(s, function, tuple) == 0) { 4646e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski tuple->DesiredTuple = CISTPL_LINKTARGET; 4656e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (pccard_get_next_tuple(s, function, tuple) != 0) 4666e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -ENOSPC; 4676e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } else 4686e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski tuple->CISOffset = tuple->TupleLink = 0; 4696e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski tuple->DesiredTuple = req; 4706e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 4716e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return pccard_get_next_tuple(s, function, tuple); 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int follow_link(struct pcmcia_socket *s, tuple_t *tuple) 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4766e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_char link[5]; 4776e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_int ofs; 4786e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski int ret; 4796e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 4806e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (MFC_FN(tuple->Flags)) { 4816e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski /* Get indirect link from the MFC tuple */ 4826e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ret = read_cis_cache(s, LINK_SPACE(tuple->Flags), 4836e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski tuple->LinkOffset, 5, link); 4846e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (ret) 4856e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -1; 4866e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ofs = get_unaligned_le32(link + 1); 4876e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR); 4886e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski /* Move to the next indirect link */ 4896e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski tuple->LinkOffset += 5; 4906e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski MFC_FN(tuple->Flags)--; 4916e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } else if (HAS_LINK(tuple->Flags)) { 4926e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ofs = tuple->LinkOffset; 4936e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski SPACE(tuple->Flags) = LINK_SPACE(tuple->Flags); 4946e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski HAS_LINK(tuple->Flags) = 0; 4956e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } else 496d700518a0e4d17a47321414e5e487ed53f4ae752Dominik Brodowski return -1; 4976e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 4986e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (SPACE(tuple->Flags)) { 4996e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski /* This is ugly, but a common CIS error is to code the long 5006e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski link offset incorrectly, so we check the right spot... */ 5016e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ret = read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link); 5026e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (ret) 5036e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -1; 5046e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) && 5056e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski (strncmp(link+2, "CIS", 3) == 0)) 5066e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return ofs; 5076e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski remove_cis_cache(s, SPACE(tuple->Flags), ofs, 5); 5086e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski /* Then, we try the wrong spot... */ 5096e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ofs = ofs >> 1; 5106e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 511d700518a0e4d17a47321414e5e487ed53f4ae752Dominik Brodowski ret = read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link); 512d700518a0e4d17a47321414e5e487ed53f4ae752Dominik Brodowski if (ret) 513d700518a0e4d17a47321414e5e487ed53f4ae752Dominik Brodowski return -1; 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) && 5156e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski (strncmp(link+2, "CIS", 3) == 0)) 5166e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return ofs; 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds remove_cis_cache(s, SPACE(tuple->Flags), ofs, 5); 5186e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -1; 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5216e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowskiint pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, 5226e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski tuple_t *tuple) 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5246e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_char link[2], tmp; 5256e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski int ofs, i, attr; 5266e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski int ret; 5279fea84f46a821aa1ff2d034ffda8ad33bff48015Dominik Brodowski 5286e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (!s) 5296e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 5306e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (!(s->state & SOCKET_PRESENT) || (s->state & SOCKET_CARDBUS)) 5316e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -ENODEV; 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5336e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski link[1] = tuple->TupleLink; 5346e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ofs = tuple->CISOffset + tuple->TupleLink; 5356e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski attr = SPACE(tuple->Flags); 5366e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 5376e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski for (i = 0; i < MAX_TUPLES; i++) { 5386e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (link[1] == 0xff) 5396e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski link[0] = CISTPL_END; 5406e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski else { 5416e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ret = read_cis_cache(s, attr, ofs, 2, link); 5426e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (ret) 5436e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -1; 5446e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (link[0] == CISTPL_NULL) { 5456e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ofs++; 5466e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski continue; 5476e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5499fea84f46a821aa1ff2d034ffda8ad33bff48015Dominik Brodowski 5506e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski /* End of chain? Follow long link if possible */ 5516e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (link[0] == CISTPL_END) { 5526e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ofs = follow_link(s, tuple); 5536e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (ofs < 0) 5546e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -ENOSPC; 5556e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski attr = SPACE(tuple->Flags); 5566e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ret = read_cis_cache(s, attr, ofs, 2, link); 5576e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (ret) 5586e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -1; 5596e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5616e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski /* Is this a link tuple? Make a note of it */ 5626e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if ((link[0] == CISTPL_LONGLINK_A) || 5636e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski (link[0] == CISTPL_LONGLINK_C) || 5646e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski (link[0] == CISTPL_LONGLINK_MFC) || 5656e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski (link[0] == CISTPL_LINKTARGET) || 5666e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski (link[0] == CISTPL_INDIRECT) || 5676e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski (link[0] == CISTPL_NO_LINK)) { 5686e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski switch (link[0]) { 5696e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case CISTPL_LONGLINK_A: 5706e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski HAS_LINK(tuple->Flags) = 1; 5716e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski LINK_SPACE(tuple->Flags) = attr | IS_ATTR; 5726e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ret = read_cis_cache(s, attr, ofs+2, 4, 5736e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski &tuple->LinkOffset); 5746e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (ret) 5756e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -1; 5766e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 5776e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case CISTPL_LONGLINK_C: 5786e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski HAS_LINK(tuple->Flags) = 1; 5796e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski LINK_SPACE(tuple->Flags) = attr & ~IS_ATTR; 5806e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ret = read_cis_cache(s, attr, ofs+2, 4, 5816e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski &tuple->LinkOffset); 5826e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (ret) 5836e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -1; 5846e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 5856e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case CISTPL_INDIRECT: 5866e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski HAS_LINK(tuple->Flags) = 1; 5876e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski LINK_SPACE(tuple->Flags) = IS_ATTR | 5886e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski IS_INDIRECT; 5896e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski tuple->LinkOffset = 0; 5906e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 5916e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case CISTPL_LONGLINK_MFC: 5926e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski tuple->LinkOffset = ofs + 3; 5936e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski LINK_SPACE(tuple->Flags) = attr; 5946e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (function == BIND_FN_ALL) { 5956e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski /* Follow all the MFC links */ 5966e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ret = read_cis_cache(s, attr, ofs+2, 5976e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 1, &tmp); 5986e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (ret) 5996e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -1; 6006e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski MFC_FN(tuple->Flags) = tmp; 6016e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } else { 6026e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski /* Follow exactly one of the links */ 6036e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski MFC_FN(tuple->Flags) = 1; 6046e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski tuple->LinkOffset += function * 5; 6056e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 6066e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 6076e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case CISTPL_NO_LINK: 6086e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski HAS_LINK(tuple->Flags) = 0; 6096e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 6106e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 6116e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if ((tuple->Attributes & TUPLE_RETURN_LINK) && 6126e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski (tuple->DesiredTuple == RETURN_FIRST_TUPLE)) 6136e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 6146e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } else 6156e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (tuple->DesiredTuple == RETURN_FIRST_TUPLE) 6166e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 6176e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 6186e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (link[0] == tuple->DesiredTuple) 6196e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 6206e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ofs += link[1] + 2; 6216e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 6226e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (i == MAX_TUPLES) { 6236e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski dev_dbg(&s->dev, "cs: overrun in pcmcia_get_next_tuple\n"); 6246e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -ENOSPC; 6256e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6276e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski tuple->TupleCode = link[0]; 6286e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski tuple->TupleLink = link[1]; 6296e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski tuple->CISOffset = ofs + 2; 6306e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return 0; 6316e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski} 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple) 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6356e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_int len; 6366e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski int ret; 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6386e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (!s) 6396e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6416e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (tuple->TupleLink < tuple->TupleOffset) 6426e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -ENOSPC; 6436e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski len = tuple->TupleLink - tuple->TupleOffset; 6446e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski tuple->TupleDataLen = tuple->TupleLink; 6456e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (len == 0) 6466e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return 0; 6476e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ret = read_cis_cache(s, SPACE(tuple->Flags), 6486e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski tuple->CISOffset + tuple->TupleOffset, 6496e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski min(len, (u_int) tuple->TupleDataMax), 6506e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski tuple->TupleData); 6516e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (ret) 6526e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -1; 6534c89e88bfde6a3c179790e21004f24e09a058290Dominik Brodowski return 0; 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6576e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski/* Parsing routines for individual tuples */ 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int parse_device(tuple_t *tuple, cistpl_device_t *device) 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6616e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski int i; 6626e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_char scale; 6636e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_char *p, *q; 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6656e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p = (u_char *)tuple->TupleData; 6666e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski q = p + tuple->TupleDataLen; 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6686e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski device->ndev = 0; 6696e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski for (i = 0; i < CISTPL_MAX_DEVICES; i++) { 6709fea84f46a821aa1ff2d034ffda8ad33bff48015Dominik Brodowski 6716e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (*p == 0xff) 6726e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 6736e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski device->dev[i].type = (*p >> 4); 6746e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski device->dev[i].wp = (*p & 0x08) ? 1 : 0; 6756e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski switch (*p & 0x07) { 6766e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case 0: 6776e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski device->dev[i].speed = 0; 6786e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 6796e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case 1: 6806e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski device->dev[i].speed = 250; 6816e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 6826e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case 2: 6836e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski device->dev[i].speed = 200; 6846e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 6856e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case 3: 6866e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski device->dev[i].speed = 150; 6876e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 6886e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case 4: 6896e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski device->dev[i].speed = 100; 6906e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 6916e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case 7: 6929fea84f46a821aa1ff2d034ffda8ad33bff48015Dominik Brodowski if (++p == q) 6939fea84f46a821aa1ff2d034ffda8ad33bff48015Dominik Brodowski return -EINVAL; 6946e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski device->dev[i].speed = SPEED_CVT(*p); 6956e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski while (*p & 0x80) 6966e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (++p == q) 6976e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 6986e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 6996e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski default: 7006e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 7016e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7036e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (++p == q) 7046e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 7056e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (*p == 0xff) 7066e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 7076e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski scale = *p & 7; 7086e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (scale == 7) 7096e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 7106e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski device->dev[i].size = ((*p >> 3) + 1) * (512 << (scale*2)); 7116e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski device->ndev++; 7126e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (++p == q) 7136e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 7146e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 7159fea84f46a821aa1ff2d034ffda8ad33bff48015Dominik Brodowski 7166e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return 0; 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int parse_checksum(tuple_t *tuple, cistpl_checksum_t *csum) 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7226e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_char *p; 7236e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (tuple->TupleDataLen < 5) 7246e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 7256e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p = (u_char *) tuple->TupleData; 7266e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski csum->addr = tuple->CISOffset + get_unaligned_le16(p) - 2; 7276e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski csum->len = get_unaligned_le16(p + 2); 7286e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski csum->sum = *(p + 4); 7296e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return 0; 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int parse_longlink(tuple_t *tuple, cistpl_longlink_t *link) 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7356e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (tuple->TupleDataLen < 4) 7366e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 7376e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski link->addr = get_unaligned_le32(tuple->TupleData); 7386e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return 0; 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7426e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowskistatic int parse_longlink_mfc(tuple_t *tuple, cistpl_longlink_mfc_t *link) 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7446e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_char *p; 7456e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski int i; 7466e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 7476e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p = (u_char *)tuple->TupleData; 7486e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 7496e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski link->nfn = *p; p++; 7506e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (tuple->TupleDataLen <= link->nfn*5) 7516e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 7526e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski for (i = 0; i < link->nfn; i++) { 7536e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski link->fn[i].space = *p; p++; 7546e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski link->fn[i].addr = get_unaligned_le32(p); 7556e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p += 4; 7566e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 7576e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return 0; 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int parse_strings(u_char *p, u_char *q, int max, 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *s, u_char *ofs, u_char *found) 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7646e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski int i, j, ns; 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7666e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (p == q) 7676e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 7686e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ns = 0; j = 0; 7696e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski for (i = 0; i < max; i++) { 7706e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (*p == 0xff) 7716e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 7726e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ofs[i] = j; 7736e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ns++; 7746e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski for (;;) { 7756e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski s[j++] = (*p == 0xff) ? '\0' : *p; 7766e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if ((*p == '\0') || (*p == 0xff)) 7776e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 7786e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (++p == q) 7796e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 7806e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 7816e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if ((*p == 0xff) || (++p == q)) 7826e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7846e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (found) { 7856e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski *found = ns; 7866e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return 0; 7876e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 7886e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 7893f9c5f4cb7e00d424a56a6431e9c98b3b17851e4Dominik Brodowski return (ns == max) ? 0 : -EINVAL; 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int parse_vers_1(tuple_t *tuple, cistpl_vers_1_t *vers_1) 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7956e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_char *p, *q; 7969fea84f46a821aa1ff2d034ffda8ad33bff48015Dominik Brodowski 7976e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p = (u_char *)tuple->TupleData; 7986e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski q = p + tuple->TupleDataLen; 7999fea84f46a821aa1ff2d034ffda8ad33bff48015Dominik Brodowski 8006e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski vers_1->major = *p; p++; 8016e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski vers_1->minor = *p; p++; 8026e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (p >= q) 8036e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8056e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return parse_strings(p, q, CISTPL_VERS_1_MAX_PROD_STRINGS, 8066e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski vers_1->str, vers_1->ofs, &vers_1->ns); 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int parse_altstr(tuple_t *tuple, cistpl_altstr_t *altstr) 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8126e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_char *p, *q; 8139fea84f46a821aa1ff2d034ffda8ad33bff48015Dominik Brodowski 8146e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p = (u_char *)tuple->TupleData; 8156e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski q = p + tuple->TupleDataLen; 8169fea84f46a821aa1ff2d034ffda8ad33bff48015Dominik Brodowski 8176e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return parse_strings(p, q, CISTPL_MAX_ALTSTR_STRINGS, 8186e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski altstr->str, altstr->ofs, &altstr->ns); 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int parse_jedec(tuple_t *tuple, cistpl_jedec_t *jedec) 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8246e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_char *p, *q; 8256e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski int nid; 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8276e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p = (u_char *)tuple->TupleData; 8286e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski q = p + tuple->TupleDataLen; 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8306e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski for (nid = 0; nid < CISTPL_MAX_DEVICES; nid++) { 8316e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (p > q-2) 8326e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 8336e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski jedec->id[nid].mfr = p[0]; 8346e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski jedec->id[nid].info = p[1]; 8356e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p += 2; 8366e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 8376e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski jedec->nid = nid; 8386e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return 0; 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m) 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8446e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (tuple->TupleDataLen < 4) 8456e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 8466e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski m->manf = get_unaligned_le16(tuple->TupleData); 8476e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski m->card = get_unaligned_le16(tuple->TupleData + 2); 8486e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return 0; 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int parse_funcid(tuple_t *tuple, cistpl_funcid_t *f) 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8546e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_char *p; 8556e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (tuple->TupleDataLen < 2) 8566e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 8576e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p = (u_char *)tuple->TupleData; 8586e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski f->func = p[0]; 8596e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski f->sysinit = p[1]; 8606e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return 0; 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int parse_funce(tuple_t *tuple, cistpl_funce_t *f) 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8666e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_char *p; 8676e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski int i; 8686e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (tuple->TupleDataLen < 1) 8696e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 8706e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p = (u_char *)tuple->TupleData; 8716e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski f->type = p[0]; 8726e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski for (i = 1; i < tuple->TupleDataLen; i++) 8736e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski f->data[i-1] = p[i]; 8746e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return 0; 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int parse_config(tuple_t *tuple, cistpl_config_t *config) 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8806e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski int rasz, rmsz, i; 8816e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_char *p; 8826e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 8836e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p = (u_char *)tuple->TupleData; 8846e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski rasz = *p & 0x03; 8856e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski rmsz = (*p & 0x3c) >> 2; 8866e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (tuple->TupleDataLen < rasz+rmsz+4) 8876e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 8886e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski config->last_idx = *(++p); 8896e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p++; 8906e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski config->base = 0; 8916e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski for (i = 0; i <= rasz; i++) 8926e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski config->base += p[i] << (8*i); 8936e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p += rasz+1; 8946e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski for (i = 0; i < 4; i++) 8956e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski config->rmask[i] = 0; 8966e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski for (i = 0; i <= rmsz; i++) 8976e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski config->rmask[i>>2] += p[i] << (8*(i%4)); 8986e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski config->subtuples = tuple->TupleDataLen - (rasz+rmsz+4); 8996e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return 0; 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9026e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski/* The following routines are all used to parse the nightmarish 9036e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski * config table entries. 9046e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski */ 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9066e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowskistatic u_char *parse_power(u_char *p, u_char *q, cistpl_power_t *pwr) 9076e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski{ 9086e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski int i; 9096e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_int scale; 9106e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 9116e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (p == q) 9126e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return NULL; 9136e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski pwr->present = *p; 9146e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski pwr->flags = 0; 9156e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p++; 9166e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski for (i = 0; i < 7; i++) 9176e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (pwr->present & (1<<i)) { 9186e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (p == q) 9196e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return NULL; 9206e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski pwr->param[i] = POWER_CVT(*p); 9216e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski scale = POWER_SCALE(*p); 9226e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski while (*p & 0x80) { 9236e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (++p == q) 9246e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return NULL; 9256e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if ((*p & 0x7f) < 100) 9266e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski pwr->param[i] += 9276e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski (*p & 0x7f) * scale / 100; 9286e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski else if (*p == 0x7d) 9296e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski pwr->flags |= CISTPL_POWER_HIGHZ_OK; 9306e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski else if (*p == 0x7e) 9316e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski pwr->param[i] = 0; 9326e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski else if (*p == 0x7f) 9336e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski pwr->flags |= CISTPL_POWER_HIGHZ_REQ; 9346e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski else 9356e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return NULL; 9366e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 9376e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p++; 9386e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 9396e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return p; 9406e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski} 9419fea84f46a821aa1ff2d034ffda8ad33bff48015Dominik Brodowski 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9436e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowskistatic u_char *parse_timing(u_char *p, u_char *q, cistpl_timing_t *timing) 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9456e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_char scale; 9466e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 9476e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (p == q) 9486e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return NULL; 9496e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski scale = *p; 9506e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if ((scale & 3) != 3) { 9519fea84f46a821aa1ff2d034ffda8ad33bff48015Dominik Brodowski if (++p == q) 9529fea84f46a821aa1ff2d034ffda8ad33bff48015Dominik Brodowski return NULL; 9536e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski timing->wait = SPEED_CVT(*p); 9546e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski timing->waitscale = exponent[scale & 3]; 9556e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } else 9566e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski timing->wait = 0; 9576e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski scale >>= 2; 9586e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if ((scale & 7) != 7) { 9596e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (++p == q) 9606e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return NULL; 9616e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski timing->ready = SPEED_CVT(*p); 9626e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski timing->rdyscale = exponent[scale & 7]; 9636e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } else 9646e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski timing->ready = 0; 9656e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski scale >>= 3; 9666e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (scale != 7) { 9676e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (++p == q) 9686e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return NULL; 9696e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski timing->reserved = SPEED_CVT(*p); 9706e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski timing->rsvscale = exponent[scale]; 9716e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } else 9726e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski timing->reserved = 0; 9736e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p++; 9746e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return p; 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9786e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowskistatic u_char *parse_io(u_char *p, u_char *q, cistpl_io_t *io) 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9806e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski int i, j, bsz, lsz; 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9826e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (p == q) 9839fea84f46a821aa1ff2d034ffda8ad33bff48015Dominik Brodowski return NULL; 9846e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski io->flags = *p; 9856e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 9866e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (!(*p & 0x80)) { 9876e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski io->nwin = 1; 9886e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski io->win[0].base = 0; 9896e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski io->win[0].len = (1 << (io->flags & CISTPL_IO_LINES_MASK)); 9906e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return p+1; 9916e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 9926e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 9939fea84f46a821aa1ff2d034ffda8ad33bff48015Dominik Brodowski if (++p == q) 9949fea84f46a821aa1ff2d034ffda8ad33bff48015Dominik Brodowski return NULL; 9956e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski io->nwin = (*p & 0x0f) + 1; 9966e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski bsz = (*p & 0x30) >> 4; 9976e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (bsz == 3) 9986e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski bsz++; 9996e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski lsz = (*p & 0xc0) >> 6; 10006e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (lsz == 3) 10016e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski lsz++; 10026e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p++; 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10046e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski for (i = 0; i < io->nwin; i++) { 10056e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski io->win[i].base = 0; 10066e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski io->win[i].len = 1; 10076e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski for (j = 0; j < bsz; j++, p++) { 10086e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (p == q) 10096e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return NULL; 10106e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski io->win[i].base += *p << (j*8); 10116e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 10126e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski for (j = 0; j < lsz; j++, p++) { 10136e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (p == q) 10146e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return NULL; 10156e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski io->win[i].len += *p << (j*8); 10166e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10186e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return p; 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u_char *parse_mem(u_char *p, u_char *q, cistpl_mem_t *mem) 10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10246e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski int i, j, asz, lsz, has_ha; 10256e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_int len, ca, ha; 10266e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 10276e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (p == q) 10286e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return NULL; 10296e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 10306e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski mem->nwin = (*p & 0x07) + 1; 10316e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski lsz = (*p & 0x18) >> 3; 10326e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski asz = (*p & 0x60) >> 5; 10336e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski has_ha = (*p & 0x80); 10346e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (++p == q) 10356e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return NULL; 10366e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 10376e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski for (i = 0; i < mem->nwin; i++) { 10386e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski len = ca = ha = 0; 10396e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski for (j = 0; j < lsz; j++, p++) { 10406e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (p == q) 10416e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return NULL; 10426e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski len += *p << (j*8); 10436e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 10446e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski for (j = 0; j < asz; j++, p++) { 10456e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (p == q) 10466e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return NULL; 10476e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ca += *p << (j*8); 10486e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 10496e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (has_ha) 10506e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski for (j = 0; j < asz; j++, p++) { 10516e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (p == q) 10526e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return NULL; 10536e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ha += *p << (j*8); 10546e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 10556e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski mem->win[i].len = len << 8; 10566e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski mem->win[i].card_addr = ca << 8; 10576e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski mem->win[i].host_addr = ha << 8; 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10596e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return p; 10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u_char *parse_irq(u_char *p, u_char *q, cistpl_irq_t *irq) 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10656e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (p == q) 10663f9c5f4cb7e00d424a56a6431e9c98b3b17851e4Dominik Brodowski return NULL; 10676e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski irq->IRQInfo1 = *p; p++; 10686e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (irq->IRQInfo1 & IRQ_INFO2_VALID) { 10696e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (p+2 > q) 10706e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return NULL; 10716e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski irq->IRQInfo2 = (p[1]<<8) + p[0]; 10726e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p += 2; 10736e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 10746e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return p; 10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int parse_cftable_entry(tuple_t *tuple, 10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cistpl_cftable_entry_t *entry) 10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10816e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_char *p, *q, features; 10826e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 10836e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p = tuple->TupleData; 10846e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski q = p + tuple->TupleDataLen; 10856e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski entry->index = *p & 0x3f; 10866e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski entry->flags = 0; 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*p & 0x40) 10886e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski entry->flags |= CISTPL_CFTABLE_DEFAULT; 10896e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (*p & 0x80) { 10906e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (++p == q) 10916e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 10926e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (*p & 0x10) 10936e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski entry->flags |= CISTPL_CFTABLE_BVDS; 10946e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (*p & 0x20) 10956e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski entry->flags |= CISTPL_CFTABLE_WP; 10966e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (*p & 0x40) 10976e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski entry->flags |= CISTPL_CFTABLE_RDYBSY; 10986e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (*p & 0x80) 10996e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski entry->flags |= CISTPL_CFTABLE_MWAIT; 11006e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski entry->interface = *p & 0x0f; 11016e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } else 11026e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski entry->interface = 0; 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11046e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski /* Process optional features */ 11056e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (++p == q) 11063f9c5f4cb7e00d424a56a6431e9c98b3b17851e4Dominik Brodowski return -EINVAL; 11076e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski features = *p; p++; 11089fea84f46a821aa1ff2d034ffda8ad33bff48015Dominik Brodowski 11096e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski /* Power options */ 11106e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if ((features & 3) > 0) { 11116e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p = parse_power(p, q, &entry->vcc); 11126e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (p == NULL) 11136e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 11146e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } else 11156e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski entry->vcc.present = 0; 11166e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if ((features & 3) > 1) { 11176e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p = parse_power(p, q, &entry->vpp1); 11186e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (p == NULL) 11196e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 11206e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } else 11216e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski entry->vpp1.present = 0; 11226e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if ((features & 3) > 2) { 11236e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p = parse_power(p, q, &entry->vpp2); 11246e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (p == NULL) 11256e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 11266e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } else 11276e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski entry->vpp2.present = 0; 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11296e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski /* Timing options */ 11306e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (features & 0x04) { 11316e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p = parse_timing(p, q, &entry->timing); 11326e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (p == NULL) 11336e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 11346e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } else { 11356e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski entry->timing.wait = 0; 11366e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski entry->timing.ready = 0; 11376e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski entry->timing.reserved = 0; 11386e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11406e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski /* I/O window options */ 11416e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (features & 0x08) { 11426e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p = parse_io(p, q, &entry->io); 11436e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (p == NULL) 11446e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 11456e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } else 11466e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski entry->io.nwin = 0; 11476e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 11486e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski /* Interrupt options */ 11496e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (features & 0x10) { 11506e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p = parse_irq(p, q, &entry->irq); 11516e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (p == NULL) 11526e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 11536e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } else 11546e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski entry->irq.IRQInfo1 = 0; 11559fea84f46a821aa1ff2d034ffda8ad33bff48015Dominik Brodowski 11566e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski switch (features & 0x60) { 11576e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case 0x00: 11586e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski entry->mem.nwin = 0; 11596e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 11606e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case 0x20: 11616e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski entry->mem.nwin = 1; 11626e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski entry->mem.win[0].len = get_unaligned_le16(p) << 8; 11636e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski entry->mem.win[0].card_addr = 0; 11646e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski entry->mem.win[0].host_addr = 0; 11656e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p += 2; 11666e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (p > q) 11676e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 11686e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 11696e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case 0x40: 11706e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski entry->mem.nwin = 1; 11716e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski entry->mem.win[0].len = get_unaligned_le16(p) << 8; 11726e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski entry->mem.win[0].card_addr = get_unaligned_le16(p + 2) << 8; 11736e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski entry->mem.win[0].host_addr = 0; 11746e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p += 4; 11756e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (p > q) 11766e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 11776e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 11786e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case 0x60: 11796e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p = parse_mem(p, q, &entry->mem); 11806e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (p == NULL) 11816e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 11826e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 11836e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 11846e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 11856e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski /* Misc features */ 11866e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (features & 0x80) { 11876e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (p == q) 11886e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 11896e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski entry->flags |= (*p << 8); 11906e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski while (*p & 0x80) 11916e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (++p == q) 11926e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 11936e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p++; 11946e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 11956e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 11966e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski entry->subtuples = q-p; 11976e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 11986e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return 0; 11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int parse_device_geo(tuple_t *tuple, cistpl_device_geo_t *geo) 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12046e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_char *p, *q; 12056e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski int n; 12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12076e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p = (u_char *)tuple->TupleData; 12086e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski q = p + tuple->TupleDataLen; 12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12106e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski for (n = 0; n < CISTPL_MAX_DEVICES; n++) { 12116e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (p > q-6) 12126e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 12136e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski geo->geo[n].buswidth = p[0]; 12146e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski geo->geo[n].erase_block = 1 << (p[1]-1); 12156e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski geo->geo[n].read_block = 1 << (p[2]-1); 12166e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski geo->geo[n].write_block = 1 << (p[3]-1); 12176e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski geo->geo[n].partition = 1 << (p[4]-1); 12186e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski geo->geo[n].interleave = 1 << (p[5]-1); 12196e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p += 6; 12206e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 12216e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski geo->ngeo = n; 12226e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return 0; 12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int parse_vers_2(tuple_t *tuple, cistpl_vers_2_t *v2) 12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12286e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_char *p, *q; 12296e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 12306e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (tuple->TupleDataLen < 10) 12316e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 12326e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 12336e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p = tuple->TupleData; 12346e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski q = p + tuple->TupleDataLen; 12356e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 12366e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski v2->vers = p[0]; 12376e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski v2->comply = p[1]; 12386e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski v2->dindex = get_unaligned_le16(p + 2); 12396e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski v2->vspec8 = p[6]; 12406e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski v2->vspec9 = p[7]; 12416e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski v2->nhdr = p[8]; 12426e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p += 9; 12436e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return parse_strings(p, q, 2, v2->str, &v2->vendor, NULL); 12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int parse_org(tuple_t *tuple, cistpl_org_t *org) 12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12496e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_char *p, *q; 12506e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski int i; 12516e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 12526e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p = tuple->TupleData; 12536e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski q = p + tuple->TupleDataLen; 12546e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (p == q) 12556e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 12566e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski org->data_org = *p; 12573f9c5f4cb7e00d424a56a6431e9c98b3b17851e4Dominik Brodowski if (++p == q) 12583f9c5f4cb7e00d424a56a6431e9c98b3b17851e4Dominik Brodowski return -EINVAL; 12596e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski for (i = 0; i < 30; i++) { 12606e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski org->desc[i] = *p; 12616e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (*p == '\0') 12626e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 12636e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (++p == q) 12646e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 12656e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 12666e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return 0; 12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int parse_format(tuple_t *tuple, cistpl_format_t *fmt) 12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12726e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski u_char *p; 12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12746e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (tuple->TupleDataLen < 10) 12756e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12776e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski p = tuple->TupleData; 12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12796e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski fmt->type = p[0]; 12806e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski fmt->edc = p[1]; 12816e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski fmt->offset = get_unaligned_le32(p + 2); 12826e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski fmt->length = get_unaligned_le32(p + 6); 12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12846e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return 0; 12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12882f3061eb1086f98990d6495b8c63a1b83f2f59aaDominik Brodowskiint pcmcia_parse_tuple(tuple_t *tuple, cisparse_t *parse) 12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12906e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski int ret = 0; 12916e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski 12926e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (tuple->TupleDataLen > tuple->TupleDataMax) 12936e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return -EINVAL; 12946e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski switch (tuple->TupleCode) { 12956e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case CISTPL_DEVICE: 12966e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case CISTPL_DEVICE_A: 12976e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ret = parse_device(tuple, &parse->device); 12986e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 12996e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case CISTPL_CHECKSUM: 13006e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ret = parse_checksum(tuple, &parse->checksum); 13016e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 13026e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case CISTPL_LONGLINK_A: 13036e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case CISTPL_LONGLINK_C: 13046e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ret = parse_longlink(tuple, &parse->longlink); 13056e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 13066e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case CISTPL_LONGLINK_MFC: 13076e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ret = parse_longlink_mfc(tuple, &parse->longlink_mfc); 13086e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 13096e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case CISTPL_VERS_1: 13106e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ret = parse_vers_1(tuple, &parse->version_1); 13116e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 13126e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case CISTPL_ALTSTR: 13136e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ret = parse_altstr(tuple, &parse->altstr); 13146e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 13156e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case CISTPL_JEDEC_A: 13166e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case CISTPL_JEDEC_C: 13176e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ret = parse_jedec(tuple, &parse->jedec); 13186e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 13196e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case CISTPL_MANFID: 13206e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ret = parse_manfid(tuple, &parse->manfid); 13216e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 13226e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case CISTPL_FUNCID: 13236e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ret = parse_funcid(tuple, &parse->funcid); 13246e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 13256e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case CISTPL_FUNCE: 13266e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ret = parse_funce(tuple, &parse->funce); 13276e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 13286e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case CISTPL_CONFIG: 13296e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ret = parse_config(tuple, &parse->config); 13306e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 13316e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case CISTPL_CFTABLE_ENTRY: 13326e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ret = parse_cftable_entry(tuple, &parse->cftable_entry); 13336e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 13346e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case CISTPL_DEVICE_GEO: 13356e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case CISTPL_DEVICE_GEO_A: 13366e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ret = parse_device_geo(tuple, &parse->device_geo); 13376e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 13386e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case CISTPL_VERS_2: 13396e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ret = parse_vers_2(tuple, &parse->vers_2); 13406e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 13416e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case CISTPL_ORG: 13426e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ret = parse_org(tuple, &parse->org); 13436e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 13446e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case CISTPL_FORMAT: 13456e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case CISTPL_FORMAT_A: 13466e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ret = parse_format(tuple, &parse->format); 13476e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 13486e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case CISTPL_NO_LINK: 13496e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski case CISTPL_LINKTARGET: 13506e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ret = 0; 13516e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 13526e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski default: 13536e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski ret = -EINVAL; 13546e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski break; 13556e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski } 13566e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski if (ret) 13576e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski pr_debug("parse_tuple failed %d\n", ret); 13586e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski return ret; 13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13602f3061eb1086f98990d6495b8c63a1b83f2f59aaDominik BrodowskiEXPORT_SYMBOL(pcmcia_parse_tuple); 13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13629fea84f46a821aa1ff2d034ffda8ad33bff48015Dominik Brodowski 13636e83ee075ed74941ccaad4fec503f6b24646e7e0Dominik Brodowski/** 1364f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski * pccard_validate_cis() - check whether card has a sensible CIS 1365f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski * @s: the struct pcmcia_socket we are to check 1366f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski * @info: returns the number of tuples in the (valid) CIS, or 0 1367f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski * 1368f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski * This tries to determine if a card has a sensible CIS. In @info, it 1369f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski * returns the number of tuples in the CIS, or 0 if the CIS looks bad. The 1370f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski * checks include making sure several critical tuples are present and 1371f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski * valid; seeing if the total number of tuples is reasonable; and 1372f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski * looking for tuples that use reserved codes. 1373f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski * 1374f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski * The function returns 0 on success. 1375f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski */ 137684897fc0524d7cbfc81d0bdf9f92ade6e3c3816bDominik Brodowskiint pccard_validate_cis(struct pcmcia_socket *s, unsigned int *info) 13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1378f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski tuple_t *tuple; 1379f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski cisparse_t *p; 1380f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski unsigned int count = 0; 1381f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski int ret, reserved, dev_ok = 0, ident_ok = 0; 13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1383f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski if (!s) 1384f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski return -EINVAL; 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1386a8408c17d0038b76a83affb1b56dc18fa1e7ed86Dominik Brodowski if (s->functions) { 1387a8408c17d0038b76a83affb1b56dc18fa1e7ed86Dominik Brodowski WARN_ON(1); 1388a8408c17d0038b76a83affb1b56dc18fa1e7ed86Dominik Brodowski return -EINVAL; 1389a8408c17d0038b76a83affb1b56dc18fa1e7ed86Dominik Brodowski } 1390a8408c17d0038b76a83affb1b56dc18fa1e7ed86Dominik Brodowski 1391f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski /* We do not want to validate the CIS cache... */ 13928680c4b3faa298dc768c2a78a94a84d89854eca9Dominik Brodowski mutex_lock(&s->ops_mutex); 1393f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski destroy_cis_cache(s); 13948680c4b3faa298dc768c2a78a94a84d89854eca9Dominik Brodowski mutex_unlock(&s->ops_mutex); 1395904e377744bfdcea276c27167fa6a609929f39dcDominik Brodowski 1396f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski tuple = kmalloc(sizeof(*tuple), GFP_KERNEL); 1397f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski if (tuple == NULL) { 1398f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski dev_warn(&s->dev, "no memory to validate CIS\n"); 1399f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski return -ENOMEM; 1400f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski } 1401f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski p = kmalloc(sizeof(*p), GFP_KERNEL); 1402f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski if (p == NULL) { 1403f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski kfree(tuple); 1404f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski dev_warn(&s->dev, "no memory to validate CIS\n"); 1405f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski return -ENOMEM; 1406f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski } 14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1408f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski count = reserved = 0; 1409f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski tuple->DesiredTuple = RETURN_FIRST_TUPLE; 1410f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski tuple->Attributes = TUPLE_RETURN_COMMON; 1411f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski ret = pccard_get_first_tuple(s, BIND_FN_ALL, tuple); 14124c89e88bfde6a3c179790e21004f24e09a058290Dominik Brodowski if (ret != 0) 1413f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski goto done; 1414f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski 1415f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski /* First tuple should be DEVICE; we should really have either that 1416f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski or a CFTABLE_ENTRY of some sort */ 1417f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski if ((tuple->TupleCode == CISTPL_DEVICE) || 1418f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_CFTABLE_ENTRY, p)) || 1419f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_CFTABLE_ENTRY_CB, p))) 1420f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski dev_ok++; 1421f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski 1422f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski /* All cards should have a MANFID tuple, and/or a VERS_1 or VERS_2 1423f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski tuple, for card identification. Certain old D-Link and Linksys 1424f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski cards have only a broken VERS_2 tuple; hence the bogus test. */ 1425f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski if ((pccard_read_tuple(s, BIND_FN_ALL, CISTPL_MANFID, p) == 0) || 1426f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_VERS_1, p) == 0) || 1427f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_VERS_2, p) != -ENOSPC)) 1428f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski ident_ok++; 1429f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski 1430f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski if (!dev_ok && !ident_ok) 1431f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski goto done; 1432f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski 1433f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski for (count = 1; count < MAX_TUPLES; count++) { 1434f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski ret = pccard_get_next_tuple(s, BIND_FN_ALL, tuple); 1435f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski if (ret != 0) 1436f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski break; 1437f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski if (((tuple->TupleCode > 0x23) && (tuple->TupleCode < 0x40)) || 1438f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski ((tuple->TupleCode > 0x47) && (tuple->TupleCode < 0x80)) || 1439f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski ((tuple->TupleCode > 0x90) && (tuple->TupleCode < 0xff))) 1440f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski reserved++; 1441f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski } 1442f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski if ((count == MAX_TUPLES) || (reserved > 5) || 1443f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski ((!dev_ok || !ident_ok) && (count > 10))) 1444f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski count = 0; 1445f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski 1446f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski ret = 0; 14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone: 1449f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski /* invalidate CIS cache on failure */ 1450f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski if (!dev_ok || !ident_ok || !count) { 14518680c4b3faa298dc768c2a78a94a84d89854eca9Dominik Brodowski mutex_lock(&s->ops_mutex); 1452f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski destroy_cis_cache(s); 14538680c4b3faa298dc768c2a78a94a84d89854eca9Dominik Brodowski mutex_unlock(&s->ops_mutex); 1454f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski ret = -EIO; 1455f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski } 1456f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski 1457f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski if (info) 1458f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski *info = count; 1459f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski kfree(tuple); 1460f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski kfree(p); 1461f131ddc4bd1713385c70606555d4d63bed5ec3fdDominik Brodowski return ret; 14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14636e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 14646e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 14656e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski#define to_socket(_dev) container_of(_dev, struct pcmcia_socket, dev) 14666e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 14676e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowskistatic ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf, 14686e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski loff_t off, size_t count) 14696e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski{ 14706e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski tuple_t tuple; 14716e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski int status, i; 14726e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski loff_t pointer = 0; 14736e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski ssize_t ret = 0; 14746e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski u_char *tuplebuffer; 14756e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski u_char *tempbuffer; 14766e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 14776e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski tuplebuffer = kmalloc(sizeof(u_char) * 256, GFP_KERNEL); 14786e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski if (!tuplebuffer) 14796e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski return -ENOMEM; 14806e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 14816e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski tempbuffer = kmalloc(sizeof(u_char) * 258, GFP_KERNEL); 14826e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski if (!tempbuffer) { 14836e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski ret = -ENOMEM; 14846e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski goto free_tuple; 14856e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski } 14866e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 14876e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski memset(&tuple, 0, sizeof(tuple_t)); 14886e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 14896e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski tuple.Attributes = TUPLE_RETURN_LINK | TUPLE_RETURN_COMMON; 14906e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski tuple.DesiredTuple = RETURN_FIRST_TUPLE; 14916e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski tuple.TupleOffset = 0; 14926e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 14936e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski status = pccard_get_first_tuple(s, BIND_FN_ALL, &tuple); 14946e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski while (!status) { 14956e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski tuple.TupleData = tuplebuffer; 14966e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski tuple.TupleDataMax = 255; 14976e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski memset(tuplebuffer, 0, sizeof(u_char) * 255); 14986e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 14996e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski status = pccard_get_tuple_data(s, &tuple); 15006e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski if (status) 15016e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski break; 15026e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 15036e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski if (off < (pointer + 2 + tuple.TupleDataLen)) { 15046e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski tempbuffer[0] = tuple.TupleCode & 0xff; 15056e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski tempbuffer[1] = tuple.TupleLink & 0xff; 15066e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski for (i = 0; i < tuple.TupleDataLen; i++) 15076e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski tempbuffer[i + 2] = tuplebuffer[i] & 0xff; 15086e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 15096e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski for (i = 0; i < (2 + tuple.TupleDataLen); i++) { 15106e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski if (((i + pointer) >= off) && 15116e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski (i + pointer) < (off + count)) { 15126e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski buf[ret] = tempbuffer[i]; 15136e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski ret++; 15146e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski } 15156e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski } 15166e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski } 15176e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 15186e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski pointer += 2 + tuple.TupleDataLen; 15196e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 15206e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski if (pointer >= (off + count)) 15216e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski break; 15226e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 15236e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski if (tuple.TupleCode == CISTPL_END) 15246e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski break; 15256e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski status = pccard_get_next_tuple(s, BIND_FN_ALL, &tuple); 15266e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski } 15276e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 15286e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski kfree(tempbuffer); 15296e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski free_tuple: 15306e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski kfree(tuplebuffer); 15316e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 15326e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski return ret; 15336e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski} 15346e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 15356e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 15362c3c8bea608866d8bd9dcf92657d57fdcac011c5Chris Wrightstatic ssize_t pccard_show_cis(struct file *filp, struct kobject *kobj, 15376e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski struct bin_attribute *bin_attr, 15386e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski char *buf, loff_t off, size_t count) 15396e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski{ 15406e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski unsigned int size = 0x200; 15416e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 15426e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski if (off >= size) 15436e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski count = 0; 15446e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski else { 15456e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski struct pcmcia_socket *s; 1546a8408c17d0038b76a83affb1b56dc18fa1e7ed86Dominik Brodowski unsigned int chains = 1; 15476e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 15486e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski if (off + count > size) 15496e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski count = size - off; 15506e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 15516e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski s = to_socket(container_of(kobj, struct device, kobj)); 15526e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 15536e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski if (!(s->state & SOCKET_PRESENT)) 15546e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski return -ENODEV; 1555a8408c17d0038b76a83affb1b56dc18fa1e7ed86Dominik Brodowski if (!s->functions && pccard_validate_cis(s, &chains)) 15566e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski return -EIO; 15576e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski if (!chains) 15586e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski return -ENODATA; 15596e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 15606e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski count = pccard_extract_cis(s, buf, off, count); 15616e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski } 15626e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 15636e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski return count; 15646e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski} 15656e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 15666e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 15672c3c8bea608866d8bd9dcf92657d57fdcac011c5Chris Wrightstatic ssize_t pccard_store_cis(struct file *filp, struct kobject *kobj, 15686e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski struct bin_attribute *bin_attr, 15696e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski char *buf, loff_t off, size_t count) 15706e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski{ 15716e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski struct pcmcia_socket *s; 15726e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski int error; 15736e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 15746e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski s = to_socket(container_of(kobj, struct device, kobj)); 15756e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 15766e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski if (off) 15776e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski return -EINVAL; 15786e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 15796e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski if (count >= CISTPL_MAX_CIS_SIZE) 15806e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski return -EINVAL; 15816e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 15826e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski if (!(s->state & SOCKET_PRESENT)) 15836e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski return -ENODEV; 15846e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 15856e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski error = pcmcia_replace_cis(s, buf, count); 15866e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski if (error) 15876e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski return -EIO; 15886e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 1589af461fc1875b6ec18e23b5f670af36c4ed35c84eDominik Brodowski pcmcia_parse_uevents(s, PCMCIA_UEVENT_REQUERY); 15906e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 15916e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski return count; 15926e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski} 15936e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 15946e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski 15956e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowskistruct bin_attribute pccard_cis_attr = { 15966e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski .attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR }, 15976e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski .size = 0x200, 15986e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski .read = pccard_show_cis, 15996e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski .write = pccard_store_cis, 16006e7b51a733fde86d3be748543215a69da04d5bb7Dominik Brodowski}; 1601