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