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