blob: 64d0515b76bd5ade5136b46a566f78d9c23ba831 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * cistpl.c -- 16-bit PCMCIA Card Information Structure parser
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * The initial developer of the original code is David A. Hinds
9 * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
10 * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
11 *
12 * (C) 1999 David A. Hinds
13 */
14
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/module.h>
16#include <linux/moduleparam.h>
17#include <linux/kernel.h>
18#include <linux/string.h>
19#include <linux/major.h>
20#include <linux/errno.h>
21#include <linux/timer.h>
22#include <linux/slab.h>
23#include <linux/mm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <linux/pci.h>
25#include <linux/ioport.h>
Dominik Brodowski9fea84f2009-12-07 22:11:45 +010026#include <linux/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <asm/byteorder.h>
Daniel Ritzdc0cf6a2007-10-16 01:23:52 -070028#include <asm/unaligned.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <pcmcia/ss.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <pcmcia/cisreg.h>
32#include <pcmcia/cistpl.h>
33#include "cs_internal.h"
34
35static const u_char mantissa[] = {
36 10, 12, 13, 15, 20, 25, 30, 35,
37 40, 45, 50, 55, 60, 70, 80, 90
38};
39
40static const u_int exponent[] = {
41 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000
42};
43
44/* Convert an extended speed byte to a time in nanoseconds */
45#define SPEED_CVT(v) \
46 (mantissa[(((v)>>3)&15)-1] * exponent[(v)&7] / 10)
47/* Convert a power byte to a current in 0.1 microamps */
48#define POWER_CVT(v) \
49 (mantissa[((v)>>3)&15] * exponent[(v)&7] / 10)
50#define POWER_SCALE(v) (exponent[(v)&7])
51
52/* Upper limit on reasonable # of tuples */
53#define MAX_TUPLES 200
54
Dominik Brodowskia3d0d4d2010-07-24 17:43:10 +020055/* Bits in IRQInfo1 field */
56#define IRQ_INFO2_VALID 0x10
57
Pavel Machek37f77952005-09-07 16:00:26 -070058/* 16-bit CIS? */
59static int cis_width;
60module_param(cis_width, int, 0444);
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
62void release_cis_mem(struct pcmcia_socket *s)
63{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +010064 mutex_lock(&s->ops_mutex);
65 if (s->cis_mem.flags & MAP_ACTIVE) {
66 s->cis_mem.flags &= ~MAP_ACTIVE;
67 s->ops->set_mem_map(s, &s->cis_mem);
68 if (s->cis_mem.res) {
69 release_resource(s->cis_mem.res);
70 kfree(s->cis_mem.res);
71 s->cis_mem.res = NULL;
72 }
73 iounmap(s->cis_virt);
74 s->cis_virt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 }
Dominik Brodowski6e83ee02010-03-02 08:57:33 +010076 mutex_unlock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070077}
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
Dominik Brodowski6e83ee02010-03-02 08:57:33 +010079/**
80 * set_cis_map() - map the card memory at "card_offset" into virtual space.
81 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070082 * If flags & MAP_ATTRIB, map the attribute space, otherwise
83 * map the memory space.
Dominik Brodowski7ab248552010-02-17 18:00:07 +010084 *
85 * Must be called with ops_mutex held.
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 */
Dominik Brodowski6e83ee02010-03-02 08:57:33 +010087static void __iomem *set_cis_map(struct pcmcia_socket *s,
88 unsigned int card_offset, unsigned int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -070089{
Dominik Brodowski2e5a3e72005-07-28 01:07:23 -070090 pccard_mem_map *mem = &s->cis_mem;
91 int ret;
Dominik Brodowski2ad0a0a2005-06-27 16:28:58 -070092
Dominik Brodowski2e5a3e72005-07-28 01:07:23 -070093 if (!(s->features & SS_CAP_STATIC_MAP) && (mem->res == NULL)) {
Dominik Brodowski6e83ee02010-03-02 08:57:33 +010094 mem->res = pcmcia_find_mem_region(0, s->map_size,
95 s->map_size, 0, s);
Dominik Brodowski2e5a3e72005-07-28 01:07:23 -070096 if (mem->res == NULL) {
Dominik Brodowski2e55bf62008-08-02 18:08:38 +020097 dev_printk(KERN_NOTICE, &s->dev,
98 "cs: unable to map card memory!\n");
Dominik Brodowski2e5a3e72005-07-28 01:07:23 -070099 return NULL;
100 }
101 s->cis_virt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 }
Dominik Brodowski2ad0a0a2005-06-27 16:28:58 -0700103
Dominik Brodowski2e5a3e72005-07-28 01:07:23 -0700104 if (!(s->features & SS_CAP_STATIC_MAP) && (!s->cis_virt))
105 s->cis_virt = ioremap(mem->res->start, s->map_size);
106
107 mem->card_start = card_offset;
108 mem->flags = flags;
109
110 ret = s->ops->set_mem_map(s, mem);
111 if (ret) {
112 iounmap(s->cis_virt);
113 s->cis_virt = NULL;
114 return NULL;
115 }
116
117 if (s->features & SS_CAP_STATIC_MAP) {
118 if (s->cis_virt)
119 iounmap(s->cis_virt);
120 s->cis_virt = ioremap(mem->static_start, s->map_size);
121 }
122
123 return s->cis_virt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124}
125
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
127/* Bits in attr field */
128#define IS_ATTR 1
129#define IS_INDIRECT 8
130
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100131/**
132 * pcmcia_read_cis_mem() - low-level function to read CIS memory
Dominik Brodowski059f6672010-03-30 18:07:50 +0200133 *
134 * must be called with ops_mutex held
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100135 */
Dominik Brodowskie6ea0b9e2005-06-27 16:28:52 -0700136int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 u_int len, void *ptr)
138{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100139 void __iomem *sys, *end;
140 unsigned char *buf = ptr;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100141
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100142 dev_dbg(&s->dev, "pcmcia_read_cis_mem(%d, %#x, %u)\n", attr, addr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100144 if (attr & IS_INDIRECT) {
145 /* Indirect accesses use a bunch of special registers at fixed
146 locations in common memory */
147 u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN;
148 if (attr & IS_ATTR) {
149 addr *= 2;
150 flags = ICTRL0_AUTOINC;
151 }
152
153 sys = set_cis_map(s, 0, MAP_ACTIVE |
154 ((cis_width) ? MAP_16BIT : 0));
155 if (!sys) {
156 dev_dbg(&s->dev, "could not map memory\n");
157 memset(ptr, 0xff, len);
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100158 return -1;
159 }
160
161 writeb(flags, sys+CISREG_ICTRL0);
162 writeb(addr & 0xff, sys+CISREG_IADDR0);
163 writeb((addr>>8) & 0xff, sys+CISREG_IADDR1);
164 writeb((addr>>16) & 0xff, sys+CISREG_IADDR2);
165 writeb((addr>>24) & 0xff, sys+CISREG_IADDR3);
166 for ( ; len > 0; len--, buf++)
167 *buf = readb(sys+CISREG_IDATA0);
168 } else {
169 u_int inc = 1, card_offset, flags;
170
Alan Coxb38a4bd2014-12-10 15:06:10 +0000171 if (addr > CISTPL_MAX_CIS_SIZE) {
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100172 dev_dbg(&s->dev,
173 "attempt to read CIS mem at addr %#x", addr);
Alan Coxb38a4bd2014-12-10 15:06:10 +0000174 memset(ptr, 0xff, len);
175 return -1;
176 }
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100177
178 flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
179 if (attr) {
180 flags |= MAP_ATTRIB;
181 inc++;
182 addr *= 2;
183 }
184
185 card_offset = addr & ~(s->map_size-1);
186 while (len) {
187 sys = set_cis_map(s, card_offset, flags);
188 if (!sys) {
189 dev_dbg(&s->dev, "could not map memory\n");
190 memset(ptr, 0xff, len);
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100191 return -1;
192 }
193 end = sys + s->map_size;
194 sys = sys + (addr & (s->map_size-1));
195 for ( ; len > 0; len--, buf++, sys += inc) {
196 if (sys == end)
197 break;
198 *buf = readb(sys);
199 }
200 card_offset += s->map_size;
201 addr = 0;
202 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 }
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100204 dev_dbg(&s->dev, " %#2.2x %#2.2x %#2.2x %#2.2x ...\n",
205 *(u_char *)(ptr+0), *(u_char *)(ptr+1),
206 *(u_char *)(ptr+2), *(u_char *)(ptr+3));
207 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208}
Dominik Brodowski1a8d4662005-06-27 16:28:53 -0700209
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100211/**
212 * pcmcia_write_cis_mem() - low-level function to write CIS memory
213 *
Dominik Brodowski059f6672010-03-30 18:07:50 +0200214 * Probably only useful for writing one-byte registers. Must be called
215 * with ops_mutex held.
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100216 */
Dominik Brodowski1d5cc192010-07-24 12:23:21 +0200217int pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 u_int len, void *ptr)
219{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100220 void __iomem *sys, *end;
221 unsigned char *buf = ptr;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100222
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100223 dev_dbg(&s->dev,
224 "pcmcia_write_cis_mem(%d, %#x, %u)\n", attr, addr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100226 if (attr & IS_INDIRECT) {
227 /* Indirect accesses use a bunch of special registers at fixed
228 locations in common memory */
229 u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN;
230 if (attr & IS_ATTR) {
231 addr *= 2;
232 flags = ICTRL0_AUTOINC;
233 }
234
235 sys = set_cis_map(s, 0, MAP_ACTIVE |
236 ((cis_width) ? MAP_16BIT : 0));
237 if (!sys) {
238 dev_dbg(&s->dev, "could not map memory\n");
Dominik Brodowski1d5cc192010-07-24 12:23:21 +0200239 return -EINVAL;
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100240 }
241
242 writeb(flags, sys+CISREG_ICTRL0);
243 writeb(addr & 0xff, sys+CISREG_IADDR0);
244 writeb((addr>>8) & 0xff, sys+CISREG_IADDR1);
245 writeb((addr>>16) & 0xff, sys+CISREG_IADDR2);
246 writeb((addr>>24) & 0xff, sys+CISREG_IADDR3);
247 for ( ; len > 0; len--, buf++)
248 writeb(*buf, sys+CISREG_IDATA0);
249 } else {
250 u_int inc = 1, card_offset, flags;
251
252 flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
253 if (attr & IS_ATTR) {
254 flags |= MAP_ATTRIB;
255 inc++;
256 addr *= 2;
257 }
258
259 card_offset = addr & ~(s->map_size-1);
260 while (len) {
261 sys = set_cis_map(s, card_offset, flags);
262 if (!sys) {
263 dev_dbg(&s->dev, "could not map memory\n");
Dominik Brodowski1d5cc192010-07-24 12:23:21 +0200264 return -EINVAL;
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100265 }
266
267 end = sys + s->map_size;
268 sys = sys + (addr & (s->map_size-1));
269 for ( ; len > 0; len--, buf++, sys += inc) {
270 if (sys == end)
271 break;
272 writeb(*buf, sys);
273 }
274 card_offset += s->map_size;
275 addr = 0;
276 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 }
Dominik Brodowski1d5cc192010-07-24 12:23:21 +0200278 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279}
Dominik Brodowski1a8d4662005-06-27 16:28:53 -0700280
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100282/**
283 * read_cis_cache() - read CIS memory or its associated cache
284 *
285 * This is a wrapper around read_cis_mem, with the same interface,
286 * but which caches information, for cards whose CIS may not be
287 * readable all the time.
288 */
Dominik Brodowskid7005182010-02-17 18:01:31 +0100289static int read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr,
290 size_t len, void *ptr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291{
Dominik Brodowski57197b92010-01-02 17:27:33 +0100292 struct cis_cache_entry *cis;
Dominik Brodowskid7005182010-02-17 18:01:31 +0100293 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
Dominik Brodowski57197b92010-01-02 17:27:33 +0100295 if (s->state & SOCKET_CARDBUS)
Dominik Brodowskid7005182010-02-17 18:01:31 +0100296 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
Dominik Brodowski8680c4b2010-01-12 22:05:36 +0100298 mutex_lock(&s->ops_mutex);
Dominik Brodowski57197b92010-01-02 17:27:33 +0100299 if (s->fake_cis) {
300 if (s->fake_cis_len >= addr+len)
301 memcpy(ptr, s->fake_cis+addr, len);
Dominik Brodowskid7005182010-02-17 18:01:31 +0100302 else {
Dominik Brodowski57197b92010-01-02 17:27:33 +0100303 memset(ptr, 0xff, len);
Dominik Brodowskid7005182010-02-17 18:01:31 +0100304 ret = -EINVAL;
305 }
Dominik Brodowski8680c4b2010-01-12 22:05:36 +0100306 mutex_unlock(&s->ops_mutex);
Dominik Brodowskid7005182010-02-17 18:01:31 +0100307 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309
Dominik Brodowski57197b92010-01-02 17:27:33 +0100310 list_for_each_entry(cis, &s->cis_cache, node) {
311 if (cis->addr == addr && cis->len == len && cis->attr == attr) {
312 memcpy(ptr, cis->cache, len);
Dominik Brodowski8680c4b2010-01-12 22:05:36 +0100313 mutex_unlock(&s->ops_mutex);
Dominik Brodowskid7005182010-02-17 18:01:31 +0100314 return 0;
Dominik Brodowski57197b92010-01-02 17:27:33 +0100315 }
316 }
317
Dominik Brodowskie6ea0b9e2005-06-27 16:28:52 -0700318 ret = pcmcia_read_cis_mem(s, attr, addr, len, ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319
320 if (ret == 0) {
321 /* Copy data into the cache */
322 cis = kmalloc(sizeof(struct cis_cache_entry) + len, GFP_KERNEL);
323 if (cis) {
324 cis->addr = addr;
325 cis->len = len;
326 cis->attr = attr;
327 memcpy(cis->cache, ptr, len);
328 list_add(&cis->node, &s->cis_cache);
329 }
330 }
Dominik Brodowski059f6672010-03-30 18:07:50 +0200331 mutex_unlock(&s->ops_mutex);
332
Dominik Brodowskid7005182010-02-17 18:01:31 +0100333 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334}
335
336static void
337remove_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, u_int len)
338{
339 struct cis_cache_entry *cis;
340
Dominik Brodowski8680c4b2010-01-12 22:05:36 +0100341 mutex_lock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342 list_for_each_entry(cis, &s->cis_cache, node)
343 if (cis->addr == addr && cis->len == len && cis->attr == attr) {
344 list_del(&cis->node);
345 kfree(cis);
346 break;
347 }
Dominik Brodowski8680c4b2010-01-12 22:05:36 +0100348 mutex_unlock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349}
350
Dominik Brodowski904e3772010-01-02 12:28:04 +0100351/**
352 * destroy_cis_cache() - destroy the CIS cache
353 * @s: pcmcia_socket for which CIS cache shall be destroyed
354 *
Dominik Brodowski8680c4b2010-01-12 22:05:36 +0100355 * This destroys the CIS cache but keeps any fake CIS alive. Must be
356 * called with ops_mutex held.
Dominik Brodowski904e3772010-01-02 12:28:04 +0100357 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358void destroy_cis_cache(struct pcmcia_socket *s)
359{
360 struct list_head *l, *n;
Dominik Brodowski904e3772010-01-02 12:28:04 +0100361 struct cis_cache_entry *cis;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700362
363 list_for_each_safe(l, n, &s->cis_cache) {
Dominik Brodowski904e3772010-01-02 12:28:04 +0100364 cis = list_entry(l, struct cis_cache_entry, node);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 list_del(&cis->node);
366 kfree(cis);
367 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100370/**
371 * verify_cis_cache() - does the CIS match what is in the CIS cache?
372 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373int verify_cis_cache(struct pcmcia_socket *s)
374{
375 struct cis_cache_entry *cis;
376 char *buf;
Dominik Brodowskid7005182010-02-17 18:01:31 +0100377 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700378
Dominik Brodowski57197b92010-01-02 17:27:33 +0100379 if (s->state & SOCKET_CARDBUS)
380 return -EINVAL;
381
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 buf = kmalloc(256, GFP_KERNEL);
Dominik Brodowskie6895972008-11-02 19:55:45 +0100383 if (buf == NULL) {
Dominik Brodowski11683862008-08-03 10:22:47 +0200384 dev_printk(KERN_WARNING, &s->dev,
385 "no memory for verifying CIS\n");
386 return -ENOMEM;
Dominik Brodowskie6895972008-11-02 19:55:45 +0100387 }
Dominik Brodowski059f6672010-03-30 18:07:50 +0200388 mutex_lock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 list_for_each_entry(cis, &s->cis_cache, node) {
390 int len = cis->len;
391
392 if (len > 256)
393 len = 256;
Dominik Brodowski57197b92010-01-02 17:27:33 +0100394
Dominik Brodowskid7005182010-02-17 18:01:31 +0100395 ret = pcmcia_read_cis_mem(s, cis->attr, cis->addr, len, buf);
396 if (ret || memcmp(buf, cis->cache, len) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 kfree(buf);
Dominik Brodowski059f6672010-03-30 18:07:50 +0200398 mutex_unlock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 return -1;
400 }
401 }
402 kfree(buf);
Dominik Brodowski059f6672010-03-30 18:07:50 +0200403 mutex_unlock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404 return 0;
405}
406
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100407/**
408 * pcmcia_replace_cis() - use a replacement CIS instead of the card's CIS
409 *
410 * For really bad cards, we provide a facility for uploading a
411 * replacement CIS.
412 */
Dominik Brodowski53efec92008-07-28 19:44:05 +0200413int pcmcia_replace_cis(struct pcmcia_socket *s,
414 const u8 *data, const size_t len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415{
Dominik Brodowski11683862008-08-03 10:22:47 +0200416 if (len > CISTPL_MAX_CIS_SIZE) {
417 dev_printk(KERN_WARNING, &s->dev, "replacement CIS too big\n");
418 return -EINVAL;
419 }
Dominik Brodowski8680c4b2010-01-12 22:05:36 +0100420 mutex_lock(&s->ops_mutex);
Dominik Brodowski11683862008-08-03 10:22:47 +0200421 kfree(s->fake_cis);
422 s->fake_cis = kmalloc(len, GFP_KERNEL);
423 if (s->fake_cis == NULL) {
424 dev_printk(KERN_WARNING, &s->dev, "no memory to replace CIS\n");
Dominik Brodowski8680c4b2010-01-12 22:05:36 +0100425 mutex_unlock(&s->ops_mutex);
Dominik Brodowski11683862008-08-03 10:22:47 +0200426 return -ENOMEM;
427 }
428 s->fake_cis_len = len;
429 memcpy(s->fake_cis, data, len);
Dominik Brodowskid7005182010-02-17 18:01:31 +0100430 dev_info(&s->dev, "Using replacement CIS\n");
Dominik Brodowski8680c4b2010-01-12 22:05:36 +0100431 mutex_unlock(&s->ops_mutex);
Dominik Brodowski11683862008-08-03 10:22:47 +0200432 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100435/* The high-level CIS tuple services */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436
437typedef struct tuple_flags {
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100438 u_int link_space:4;
439 u_int has_link:1;
440 u_int mfc_fn:3;
441 u_int space:4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442} tuple_flags;
443
444#define LINK_SPACE(f) (((tuple_flags *)(&(f)))->link_space)
445#define HAS_LINK(f) (((tuple_flags *)(&(f)))->has_link)
446#define MFC_FN(f) (((tuple_flags *)(&(f)))->mfc_fn)
447#define SPACE(f) (((tuple_flags *)(&(f)))->space)
448
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100449int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function,
450 tuple_t *tuple)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100452 if (!s)
453 return -EINVAL;
Dominik Brodowski57197b92010-01-02 17:27:33 +0100454
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100455 if (!(s->state & SOCKET_PRESENT) || (s->state & SOCKET_CARDBUS))
456 return -ENODEV;
457 tuple->TupleLink = tuple->Flags = 0;
Dominik Brodowski57197b92010-01-02 17:27:33 +0100458
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100459 /* Assume presence of a LONGLINK_C to address 0 */
460 tuple->CISOffset = tuple->LinkOffset = 0;
461 SPACE(tuple->Flags) = HAS_LINK(tuple->Flags) = 1;
Dominik Brodowski57197b92010-01-02 17:27:33 +0100462
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100463 if ((s->functions > 1) && !(tuple->Attributes & TUPLE_RETURN_COMMON)) {
464 cisdata_t req = tuple->DesiredTuple;
465 tuple->DesiredTuple = CISTPL_LONGLINK_MFC;
466 if (pccard_get_next_tuple(s, function, tuple) == 0) {
467 tuple->DesiredTuple = CISTPL_LINKTARGET;
468 if (pccard_get_next_tuple(s, function, tuple) != 0)
469 return -ENOSPC;
470 } else
471 tuple->CISOffset = tuple->TupleLink = 0;
472 tuple->DesiredTuple = req;
473 }
474 return pccard_get_next_tuple(s, function, tuple);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476
477static int follow_link(struct pcmcia_socket *s, tuple_t *tuple)
478{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100479 u_char link[5];
480 u_int ofs;
481 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100483 if (MFC_FN(tuple->Flags)) {
484 /* Get indirect link from the MFC tuple */
485 ret = read_cis_cache(s, LINK_SPACE(tuple->Flags),
486 tuple->LinkOffset, 5, link);
487 if (ret)
488 return -1;
489 ofs = get_unaligned_le32(link + 1);
490 SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR);
491 /* Move to the next indirect link */
492 tuple->LinkOffset += 5;
493 MFC_FN(tuple->Flags)--;
494 } else if (HAS_LINK(tuple->Flags)) {
495 ofs = tuple->LinkOffset;
496 SPACE(tuple->Flags) = LINK_SPACE(tuple->Flags);
497 HAS_LINK(tuple->Flags) = 0;
498 } else
Dominik Brodowskid7005182010-02-17 18:01:31 +0100499 return -1;
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100500
501 if (SPACE(tuple->Flags)) {
502 /* This is ugly, but a common CIS error is to code the long
503 link offset incorrectly, so we check the right spot... */
504 ret = read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link);
505 if (ret)
506 return -1;
507 if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) &&
508 (strncmp(link+2, "CIS", 3) == 0))
509 return ofs;
510 remove_cis_cache(s, SPACE(tuple->Flags), ofs, 5);
511 /* Then, we try the wrong spot... */
512 ofs = ofs >> 1;
513 }
Dominik Brodowskid7005182010-02-17 18:01:31 +0100514 ret = read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link);
515 if (ret)
516 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) &&
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100518 (strncmp(link+2, "CIS", 3) == 0))
519 return ofs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 remove_cis_cache(s, SPACE(tuple->Flags), ofs, 5);
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100521 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522}
523
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100524int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function,
525 tuple_t *tuple)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100527 u_char link[2], tmp;
528 int ofs, i, attr;
529 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100531 if (!s)
532 return -EINVAL;
533 if (!(s->state & SOCKET_PRESENT) || (s->state & SOCKET_CARDBUS))
534 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100536 link[1] = tuple->TupleLink;
537 ofs = tuple->CISOffset + tuple->TupleLink;
538 attr = SPACE(tuple->Flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100540 for (i = 0; i < MAX_TUPLES; i++) {
541 if (link[1] == 0xff)
542 link[0] = CISTPL_END;
543 else {
544 ret = read_cis_cache(s, attr, ofs, 2, link);
545 if (ret)
546 return -1;
547 if (link[0] == CISTPL_NULL) {
548 ofs++;
549 continue;
550 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 }
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100552
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100553 /* End of chain? Follow long link if possible */
554 if (link[0] == CISTPL_END) {
555 ofs = follow_link(s, tuple);
556 if (ofs < 0)
557 return -ENOSPC;
558 attr = SPACE(tuple->Flags);
559 ret = read_cis_cache(s, attr, ofs, 2, link);
560 if (ret)
561 return -1;
562 }
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100563
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100564 /* Is this a link tuple? Make a note of it */
565 if ((link[0] == CISTPL_LONGLINK_A) ||
566 (link[0] == CISTPL_LONGLINK_C) ||
567 (link[0] == CISTPL_LONGLINK_MFC) ||
568 (link[0] == CISTPL_LINKTARGET) ||
569 (link[0] == CISTPL_INDIRECT) ||
570 (link[0] == CISTPL_NO_LINK)) {
571 switch (link[0]) {
572 case CISTPL_LONGLINK_A:
573 HAS_LINK(tuple->Flags) = 1;
574 LINK_SPACE(tuple->Flags) = attr | IS_ATTR;
575 ret = read_cis_cache(s, attr, ofs+2, 4,
576 &tuple->LinkOffset);
577 if (ret)
578 return -1;
579 break;
580 case CISTPL_LONGLINK_C:
581 HAS_LINK(tuple->Flags) = 1;
582 LINK_SPACE(tuple->Flags) = attr & ~IS_ATTR;
583 ret = read_cis_cache(s, attr, ofs+2, 4,
584 &tuple->LinkOffset);
585 if (ret)
586 return -1;
587 break;
588 case CISTPL_INDIRECT:
589 HAS_LINK(tuple->Flags) = 1;
590 LINK_SPACE(tuple->Flags) = IS_ATTR |
591 IS_INDIRECT;
592 tuple->LinkOffset = 0;
593 break;
594 case CISTPL_LONGLINK_MFC:
595 tuple->LinkOffset = ofs + 3;
596 LINK_SPACE(tuple->Flags) = attr;
597 if (function == BIND_FN_ALL) {
598 /* Follow all the MFC links */
599 ret = read_cis_cache(s, attr, ofs+2,
600 1, &tmp);
601 if (ret)
602 return -1;
603 MFC_FN(tuple->Flags) = tmp;
604 } else {
605 /* Follow exactly one of the links */
606 MFC_FN(tuple->Flags) = 1;
607 tuple->LinkOffset += function * 5;
608 }
609 break;
610 case CISTPL_NO_LINK:
611 HAS_LINK(tuple->Flags) = 0;
612 break;
613 }
614 if ((tuple->Attributes & TUPLE_RETURN_LINK) &&
615 (tuple->DesiredTuple == RETURN_FIRST_TUPLE))
616 break;
617 } else
618 if (tuple->DesiredTuple == RETURN_FIRST_TUPLE)
619 break;
620
621 if (link[0] == tuple->DesiredTuple)
622 break;
623 ofs += link[1] + 2;
624 }
625 if (i == MAX_TUPLES) {
626 dev_dbg(&s->dev, "cs: overrun in pcmcia_get_next_tuple\n");
627 return -ENOSPC;
628 }
629
630 tuple->TupleCode = link[0];
631 tuple->TupleLink = link[1];
632 tuple->CISOffset = ofs + 2;
633 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple)
637{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100638 u_int len;
639 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100641 if (!s)
642 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100644 if (tuple->TupleLink < tuple->TupleOffset)
645 return -ENOSPC;
646 len = tuple->TupleLink - tuple->TupleOffset;
647 tuple->TupleDataLen = tuple->TupleLink;
648 if (len == 0)
649 return 0;
650 ret = read_cis_cache(s, SPACE(tuple->Flags),
651 tuple->CISOffset + tuple->TupleOffset,
652 min(len, (u_int) tuple->TupleDataMax),
653 tuple->TupleData);
654 if (ret)
655 return -1;
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200656 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658
659
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100660/* Parsing routines for individual tuples */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661
662static int parse_device(tuple_t *tuple, cistpl_device_t *device)
663{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100664 int i;
665 u_char scale;
666 u_char *p, *q;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100668 p = (u_char *)tuple->TupleData;
669 q = p + tuple->TupleDataLen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100671 device->ndev = 0;
672 for (i = 0; i < CISTPL_MAX_DEVICES; i++) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100673
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100674 if (*p == 0xff)
675 break;
676 device->dev[i].type = (*p >> 4);
677 device->dev[i].wp = (*p & 0x08) ? 1 : 0;
678 switch (*p & 0x07) {
679 case 0:
680 device->dev[i].speed = 0;
681 break;
682 case 1:
683 device->dev[i].speed = 250;
684 break;
685 case 2:
686 device->dev[i].speed = 200;
687 break;
688 case 3:
689 device->dev[i].speed = 150;
690 break;
691 case 4:
692 device->dev[i].speed = 100;
693 break;
694 case 7:
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100695 if (++p == q)
696 return -EINVAL;
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100697 device->dev[i].speed = SPEED_CVT(*p);
698 while (*p & 0x80)
699 if (++p == q)
700 return -EINVAL;
701 break;
702 default:
703 return -EINVAL;
704 }
705
706 if (++p == q)
707 return -EINVAL;
708 if (*p == 0xff)
709 break;
710 scale = *p & 7;
711 if (scale == 7)
712 return -EINVAL;
713 device->dev[i].size = ((*p >> 3) + 1) * (512 << (scale*2));
714 device->ndev++;
715 if (++p == q)
716 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 }
718
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100719 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720}
721
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722
723static int parse_checksum(tuple_t *tuple, cistpl_checksum_t *csum)
724{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100725 u_char *p;
726 if (tuple->TupleDataLen < 5)
727 return -EINVAL;
728 p = (u_char *) tuple->TupleData;
729 csum->addr = tuple->CISOffset + get_unaligned_le16(p) - 2;
730 csum->len = get_unaligned_le16(p + 2);
731 csum->sum = *(p + 4);
732 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733}
734
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735
736static int parse_longlink(tuple_t *tuple, cistpl_longlink_t *link)
737{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100738 if (tuple->TupleDataLen < 4)
739 return -EINVAL;
740 link->addr = get_unaligned_le32(tuple->TupleData);
741 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742}
743
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100745static int parse_longlink_mfc(tuple_t *tuple, cistpl_longlink_mfc_t *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100747 u_char *p;
748 int i;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100749
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100750 p = (u_char *)tuple->TupleData;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100751
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100752 link->nfn = *p; p++;
753 if (tuple->TupleDataLen <= link->nfn*5)
754 return -EINVAL;
755 for (i = 0; i < link->nfn; i++) {
756 link->fn[i].space = *p; p++;
757 link->fn[i].addr = get_unaligned_le32(p);
758 p += 4;
759 }
760 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761}
762
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763
764static int parse_strings(u_char *p, u_char *q, int max,
765 char *s, u_char *ofs, u_char *found)
766{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100767 int i, j, ns;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100769 if (p == q)
770 return -EINVAL;
771 ns = 0; j = 0;
772 for (i = 0; i < max; i++) {
773 if (*p == 0xff)
774 break;
775 ofs[i] = j;
776 ns++;
777 for (;;) {
778 s[j++] = (*p == 0xff) ? '\0' : *p;
779 if ((*p == '\0') || (*p == 0xff))
780 break;
781 if (++p == q)
782 return -EINVAL;
783 }
784 if ((*p == 0xff) || (++p == q))
785 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786 }
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100787 if (found) {
788 *found = ns;
789 return 0;
790 }
791
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +0200792 return (ns == max) ? 0 : -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793}
794
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
796static int parse_vers_1(tuple_t *tuple, cistpl_vers_1_t *vers_1)
797{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100798 u_char *p, *q;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100799
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100800 p = (u_char *)tuple->TupleData;
801 q = p + tuple->TupleDataLen;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100802
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100803 vers_1->major = *p; p++;
804 vers_1->minor = *p; p++;
805 if (p >= q)
806 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100808 return parse_strings(p, q, CISTPL_VERS_1_MAX_PROD_STRINGS,
809 vers_1->str, vers_1->ofs, &vers_1->ns);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810}
811
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812
813static int parse_altstr(tuple_t *tuple, cistpl_altstr_t *altstr)
814{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100815 u_char *p, *q;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100816
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100817 p = (u_char *)tuple->TupleData;
818 q = p + tuple->TupleDataLen;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100819
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100820 return parse_strings(p, q, CISTPL_MAX_ALTSTR_STRINGS,
821 altstr->str, altstr->ofs, &altstr->ns);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822}
823
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824
825static int parse_jedec(tuple_t *tuple, cistpl_jedec_t *jedec)
826{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100827 u_char *p, *q;
828 int nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100830 p = (u_char *)tuple->TupleData;
831 q = p + tuple->TupleDataLen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100833 for (nid = 0; nid < CISTPL_MAX_DEVICES; nid++) {
834 if (p > q-2)
835 break;
836 jedec->id[nid].mfr = p[0];
837 jedec->id[nid].info = p[1];
838 p += 2;
839 }
840 jedec->nid = nid;
841 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842}
843
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844
845static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m)
846{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100847 if (tuple->TupleDataLen < 4)
848 return -EINVAL;
849 m->manf = get_unaligned_le16(tuple->TupleData);
850 m->card = get_unaligned_le16(tuple->TupleData + 2);
851 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852}
853
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854
855static int parse_funcid(tuple_t *tuple, cistpl_funcid_t *f)
856{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100857 u_char *p;
858 if (tuple->TupleDataLen < 2)
859 return -EINVAL;
860 p = (u_char *)tuple->TupleData;
861 f->func = p[0];
862 f->sysinit = p[1];
863 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864}
865
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866
867static int parse_funce(tuple_t *tuple, cistpl_funce_t *f)
868{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100869 u_char *p;
870 int i;
871 if (tuple->TupleDataLen < 1)
872 return -EINVAL;
873 p = (u_char *)tuple->TupleData;
874 f->type = p[0];
875 for (i = 1; i < tuple->TupleDataLen; i++)
876 f->data[i-1] = p[i];
877 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878}
879
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880
881static int parse_config(tuple_t *tuple, cistpl_config_t *config)
882{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100883 int rasz, rmsz, i;
884 u_char *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100886 p = (u_char *)tuple->TupleData;
887 rasz = *p & 0x03;
888 rmsz = (*p & 0x3c) >> 2;
889 if (tuple->TupleDataLen < rasz+rmsz+4)
890 return -EINVAL;
891 config->last_idx = *(++p);
892 p++;
893 config->base = 0;
894 for (i = 0; i <= rasz; i++)
895 config->base += p[i] << (8*i);
896 p += rasz+1;
897 for (i = 0; i < 4; i++)
898 config->rmask[i] = 0;
899 for (i = 0; i <= rmsz; i++)
900 config->rmask[i>>2] += p[i] << (8*(i%4));
901 config->subtuples = tuple->TupleDataLen - (rasz+rmsz+4);
902 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903}
904
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100905/* The following routines are all used to parse the nightmarish
906 * config table entries.
907 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100909static u_char *parse_power(u_char *p, u_char *q, cistpl_power_t *pwr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100911 int i;
912 u_int scale;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100914 if (p == q)
915 return NULL;
916 pwr->present = *p;
917 pwr->flags = 0;
918 p++;
919 for (i = 0; i < 7; i++)
920 if (pwr->present & (1<<i)) {
921 if (p == q)
922 return NULL;
923 pwr->param[i] = POWER_CVT(*p);
924 scale = POWER_SCALE(*p);
925 while (*p & 0x80) {
926 if (++p == q)
927 return NULL;
928 if ((*p & 0x7f) < 100)
929 pwr->param[i] +=
930 (*p & 0x7f) * scale / 100;
931 else if (*p == 0x7d)
932 pwr->flags |= CISTPL_POWER_HIGHZ_OK;
933 else if (*p == 0x7e)
934 pwr->param[i] = 0;
935 else if (*p == 0x7f)
936 pwr->flags |= CISTPL_POWER_HIGHZ_REQ;
937 else
938 return NULL;
939 }
940 p++;
941 }
942 return p;
943}
944
945
946static u_char *parse_timing(u_char *p, u_char *q, cistpl_timing_t *timing)
947{
948 u_char scale;
949
950 if (p == q)
951 return NULL;
952 scale = *p;
953 if ((scale & 3) != 3) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100954 if (++p == q)
955 return NULL;
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100956 timing->wait = SPEED_CVT(*p);
957 timing->waitscale = exponent[scale & 3];
958 } else
959 timing->wait = 0;
960 scale >>= 2;
961 if ((scale & 7) != 7) {
962 if (++p == q)
963 return NULL;
964 timing->ready = SPEED_CVT(*p);
965 timing->rdyscale = exponent[scale & 7];
966 } else
967 timing->ready = 0;
968 scale >>= 3;
969 if (scale != 7) {
970 if (++p == q)
971 return NULL;
972 timing->reserved = SPEED_CVT(*p);
973 timing->rsvscale = exponent[scale];
974 } else
975 timing->reserved = 0;
976 p++;
977 return p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978}
979
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980
981static u_char *parse_io(u_char *p, u_char *q, cistpl_io_t *io)
982{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100983 int i, j, bsz, lsz;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100985 if (p == q)
986 return NULL;
987 io->flags = *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100989 if (!(*p & 0x80)) {
990 io->nwin = 1;
991 io->win[0].base = 0;
992 io->win[0].len = (1 << (io->flags & CISTPL_IO_LINES_MASK));
993 return p+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 }
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100995
996 if (++p == q)
997 return NULL;
998 io->nwin = (*p & 0x0f) + 1;
999 bsz = (*p & 0x30) >> 4;
1000 if (bsz == 3)
1001 bsz++;
1002 lsz = (*p & 0xc0) >> 6;
1003 if (lsz == 3)
1004 lsz++;
1005 p++;
1006
1007 for (i = 0; i < io->nwin; i++) {
1008 io->win[i].base = 0;
1009 io->win[i].len = 1;
1010 for (j = 0; j < bsz; j++, p++) {
1011 if (p == q)
1012 return NULL;
1013 io->win[i].base += *p << (j*8);
1014 }
1015 for (j = 0; j < lsz; j++, p++) {
1016 if (p == q)
1017 return NULL;
1018 io->win[i].len += *p << (j*8);
1019 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 }
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001021 return p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022}
1023
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024
1025static u_char *parse_mem(u_char *p, u_char *q, cistpl_mem_t *mem)
1026{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001027 int i, j, asz, lsz, has_ha;
1028 u_int len, ca, ha;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001030 if (p == q)
1031 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001033 mem->nwin = (*p & 0x07) + 1;
1034 lsz = (*p & 0x18) >> 3;
1035 asz = (*p & 0x60) >> 5;
1036 has_ha = (*p & 0x80);
1037 if (++p == q)
1038 return NULL;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001039
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001040 for (i = 0; i < mem->nwin; i++) {
1041 len = ca = ha = 0;
1042 for (j = 0; j < lsz; j++, p++) {
1043 if (p == q)
1044 return NULL;
1045 len += *p << (j*8);
1046 }
1047 for (j = 0; j < asz; j++, p++) {
1048 if (p == q)
1049 return NULL;
1050 ca += *p << (j*8);
1051 }
1052 if (has_ha)
1053 for (j = 0; j < asz; j++, p++) {
1054 if (p == q)
1055 return NULL;
1056 ha += *p << (j*8);
1057 }
1058 mem->win[i].len = len << 8;
1059 mem->win[i].card_addr = ca << 8;
1060 mem->win[i].host_addr = ha << 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 }
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001062 return p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063}
1064
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
1066static u_char *parse_irq(u_char *p, u_char *q, cistpl_irq_t *irq)
1067{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001068 if (p == q)
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +02001069 return NULL;
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001070 irq->IRQInfo1 = *p; p++;
1071 if (irq->IRQInfo1 & IRQ_INFO2_VALID) {
1072 if (p+2 > q)
1073 return NULL;
1074 irq->IRQInfo2 = (p[1]<<8) + p[0];
1075 p += 2;
1076 }
1077 return p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078}
1079
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080
1081static int parse_cftable_entry(tuple_t *tuple,
1082 cistpl_cftable_entry_t *entry)
1083{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001084 u_char *p, *q, features;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001086 p = tuple->TupleData;
1087 q = p + tuple->TupleDataLen;
1088 entry->index = *p & 0x3f;
1089 entry->flags = 0;
1090 if (*p & 0x40)
1091 entry->flags |= CISTPL_CFTABLE_DEFAULT;
1092 if (*p & 0x80) {
1093 if (++p == q)
1094 return -EINVAL;
1095 if (*p & 0x10)
1096 entry->flags |= CISTPL_CFTABLE_BVDS;
1097 if (*p & 0x20)
1098 entry->flags |= CISTPL_CFTABLE_WP;
1099 if (*p & 0x40)
1100 entry->flags |= CISTPL_CFTABLE_RDYBSY;
1101 if (*p & 0x80)
1102 entry->flags |= CISTPL_CFTABLE_MWAIT;
1103 entry->interface = *p & 0x0f;
1104 } else
1105 entry->interface = 0;
1106
1107 /* Process optional features */
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +02001108 if (++p == q)
1109 return -EINVAL;
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001110 features = *p; p++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001112 /* Power options */
1113 if ((features & 3) > 0) {
1114 p = parse_power(p, q, &entry->vcc);
1115 if (p == NULL)
1116 return -EINVAL;
1117 } else
1118 entry->vcc.present = 0;
1119 if ((features & 3) > 1) {
1120 p = parse_power(p, q, &entry->vpp1);
1121 if (p == NULL)
1122 return -EINVAL;
1123 } else
1124 entry->vpp1.present = 0;
1125 if ((features & 3) > 2) {
1126 p = parse_power(p, q, &entry->vpp2);
1127 if (p == NULL)
1128 return -EINVAL;
1129 } else
1130 entry->vpp2.present = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001132 /* Timing options */
1133 if (features & 0x04) {
1134 p = parse_timing(p, q, &entry->timing);
1135 if (p == NULL)
1136 return -EINVAL;
1137 } else {
1138 entry->timing.wait = 0;
1139 entry->timing.ready = 0;
1140 entry->timing.reserved = 0;
1141 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001143 /* I/O window options */
1144 if (features & 0x08) {
1145 p = parse_io(p, q, &entry->io);
1146 if (p == NULL)
1147 return -EINVAL;
1148 } else
1149 entry->io.nwin = 0;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001150
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001151 /* Interrupt options */
1152 if (features & 0x10) {
1153 p = parse_irq(p, q, &entry->irq);
1154 if (p == NULL)
1155 return -EINVAL;
1156 } else
1157 entry->irq.IRQInfo1 = 0;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001158
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001159 switch (features & 0x60) {
1160 case 0x00:
1161 entry->mem.nwin = 0;
1162 break;
1163 case 0x20:
1164 entry->mem.nwin = 1;
1165 entry->mem.win[0].len = get_unaligned_le16(p) << 8;
1166 entry->mem.win[0].card_addr = 0;
1167 entry->mem.win[0].host_addr = 0;
1168 p += 2;
1169 if (p > q)
1170 return -EINVAL;
1171 break;
1172 case 0x40:
1173 entry->mem.nwin = 1;
1174 entry->mem.win[0].len = get_unaligned_le16(p) << 8;
1175 entry->mem.win[0].card_addr = get_unaligned_le16(p + 2) << 8;
1176 entry->mem.win[0].host_addr = 0;
1177 p += 4;
1178 if (p > q)
1179 return -EINVAL;
1180 break;
1181 case 0x60:
1182 p = parse_mem(p, q, &entry->mem);
1183 if (p == NULL)
1184 return -EINVAL;
1185 break;
1186 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001188 /* Misc features */
1189 if (features & 0x80) {
1190 if (p == q)
1191 return -EINVAL;
1192 entry->flags |= (*p << 8);
1193 while (*p & 0x80)
1194 if (++p == q)
1195 return -EINVAL;
1196 p++;
1197 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001199 entry->subtuples = q-p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001201 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202}
1203
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205static int parse_device_geo(tuple_t *tuple, cistpl_device_geo_t *geo)
1206{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001207 u_char *p, *q;
1208 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001210 p = (u_char *)tuple->TupleData;
1211 q = p + tuple->TupleDataLen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001213 for (n = 0; n < CISTPL_MAX_DEVICES; n++) {
1214 if (p > q-6)
1215 break;
1216 geo->geo[n].buswidth = p[0];
1217 geo->geo[n].erase_block = 1 << (p[1]-1);
1218 geo->geo[n].read_block = 1 << (p[2]-1);
1219 geo->geo[n].write_block = 1 << (p[3]-1);
1220 geo->geo[n].partition = 1 << (p[4]-1);
1221 geo->geo[n].interleave = 1 << (p[5]-1);
1222 p += 6;
1223 }
1224 geo->ngeo = n;
1225 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226}
1227
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228
1229static int parse_vers_2(tuple_t *tuple, cistpl_vers_2_t *v2)
1230{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001231 u_char *p, *q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001233 if (tuple->TupleDataLen < 10)
1234 return -EINVAL;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001235
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001236 p = tuple->TupleData;
1237 q = p + tuple->TupleDataLen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001239 v2->vers = p[0];
1240 v2->comply = p[1];
1241 v2->dindex = get_unaligned_le16(p + 2);
1242 v2->vspec8 = p[6];
1243 v2->vspec9 = p[7];
1244 v2->nhdr = p[8];
1245 p += 9;
1246 return parse_strings(p, q, 2, v2->str, &v2->vendor, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247}
1248
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249
1250static int parse_org(tuple_t *tuple, cistpl_org_t *org)
1251{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001252 u_char *p, *q;
1253 int i;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001254
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001255 p = tuple->TupleData;
1256 q = p + tuple->TupleDataLen;
1257 if (p == q)
1258 return -EINVAL;
1259 org->data_org = *p;
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +02001260 if (++p == q)
1261 return -EINVAL;
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001262 for (i = 0; i < 30; i++) {
1263 org->desc[i] = *p;
1264 if (*p == '\0')
1265 break;
1266 if (++p == q)
1267 return -EINVAL;
1268 }
1269 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270}
1271
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272
1273static int parse_format(tuple_t *tuple, cistpl_format_t *fmt)
1274{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001275 u_char *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001277 if (tuple->TupleDataLen < 10)
1278 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001280 p = tuple->TupleData;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001282 fmt->type = p[0];
1283 fmt->edc = p[1];
1284 fmt->offset = get_unaligned_le32(p + 2);
1285 fmt->length = get_unaligned_le32(p + 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001287 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288}
1289
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290
Dominik Brodowski2f3061e2008-08-31 15:50:33 +02001291int pcmcia_parse_tuple(tuple_t *tuple, cisparse_t *parse)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001292{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001293 int ret = 0;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001294
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001295 if (tuple->TupleDataLen > tuple->TupleDataMax)
1296 return -EINVAL;
1297 switch (tuple->TupleCode) {
1298 case CISTPL_DEVICE:
1299 case CISTPL_DEVICE_A:
1300 ret = parse_device(tuple, &parse->device);
1301 break;
1302 case CISTPL_CHECKSUM:
1303 ret = parse_checksum(tuple, &parse->checksum);
1304 break;
1305 case CISTPL_LONGLINK_A:
1306 case CISTPL_LONGLINK_C:
1307 ret = parse_longlink(tuple, &parse->longlink);
1308 break;
1309 case CISTPL_LONGLINK_MFC:
1310 ret = parse_longlink_mfc(tuple, &parse->longlink_mfc);
1311 break;
1312 case CISTPL_VERS_1:
1313 ret = parse_vers_1(tuple, &parse->version_1);
1314 break;
1315 case CISTPL_ALTSTR:
1316 ret = parse_altstr(tuple, &parse->altstr);
1317 break;
1318 case CISTPL_JEDEC_A:
1319 case CISTPL_JEDEC_C:
1320 ret = parse_jedec(tuple, &parse->jedec);
1321 break;
1322 case CISTPL_MANFID:
1323 ret = parse_manfid(tuple, &parse->manfid);
1324 break;
1325 case CISTPL_FUNCID:
1326 ret = parse_funcid(tuple, &parse->funcid);
1327 break;
1328 case CISTPL_FUNCE:
1329 ret = parse_funce(tuple, &parse->funce);
1330 break;
1331 case CISTPL_CONFIG:
1332 ret = parse_config(tuple, &parse->config);
1333 break;
1334 case CISTPL_CFTABLE_ENTRY:
1335 ret = parse_cftable_entry(tuple, &parse->cftable_entry);
1336 break;
1337 case CISTPL_DEVICE_GEO:
1338 case CISTPL_DEVICE_GEO_A:
1339 ret = parse_device_geo(tuple, &parse->device_geo);
1340 break;
1341 case CISTPL_VERS_2:
1342 ret = parse_vers_2(tuple, &parse->vers_2);
1343 break;
1344 case CISTPL_ORG:
1345 ret = parse_org(tuple, &parse->org);
1346 break;
1347 case CISTPL_FORMAT:
1348 case CISTPL_FORMAT_A:
1349 ret = parse_format(tuple, &parse->format);
1350 break;
1351 case CISTPL_NO_LINK:
1352 case CISTPL_LINKTARGET:
1353 ret = 0;
1354 break;
1355 default:
1356 ret = -EINVAL;
1357 break;
1358 }
1359 if (ret)
1360 pr_debug("parse_tuple failed %d\n", ret);
1361 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362}
Dominik Brodowski2f3061e2008-08-31 15:50:33 +02001363EXPORT_SYMBOL(pcmcia_parse_tuple);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001366/**
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001367 * pccard_validate_cis() - check whether card has a sensible CIS
1368 * @s: the struct pcmcia_socket we are to check
1369 * @info: returns the number of tuples in the (valid) CIS, or 0
1370 *
1371 * This tries to determine if a card has a sensible CIS. In @info, it
1372 * returns the number of tuples in the CIS, or 0 if the CIS looks bad. The
1373 * checks include making sure several critical tuples are present and
1374 * valid; seeing if the total number of tuples is reasonable; and
1375 * looking for tuples that use reserved codes.
1376 *
1377 * The function returns 0 on success.
1378 */
Dominik Brodowski84897fc2009-10-18 23:51:09 +02001379int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380{
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001381 tuple_t *tuple;
1382 cisparse_t *p;
1383 unsigned int count = 0;
1384 int ret, reserved, dev_ok = 0, ident_ok = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001386 if (!s)
1387 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388
Alan Cox84026412014-12-10 15:06:40 +00001389 if (s->functions || !(s->state & SOCKET_PRESENT)) {
Dominik Brodowskia8408c12010-04-17 17:37:33 +02001390 WARN_ON(1);
1391 return -EINVAL;
1392 }
1393
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001394 /* We do not want to validate the CIS cache... */
Dominik Brodowski8680c4b2010-01-12 22:05:36 +01001395 mutex_lock(&s->ops_mutex);
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001396 destroy_cis_cache(s);
Dominik Brodowski8680c4b2010-01-12 22:05:36 +01001397 mutex_unlock(&s->ops_mutex);
Dominik Brodowski904e3772010-01-02 12:28:04 +01001398
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001399 tuple = kmalloc(sizeof(*tuple), GFP_KERNEL);
1400 if (tuple == NULL) {
1401 dev_warn(&s->dev, "no memory to validate CIS\n");
1402 return -ENOMEM;
1403 }
1404 p = kmalloc(sizeof(*p), GFP_KERNEL);
1405 if (p == NULL) {
1406 kfree(tuple);
1407 dev_warn(&s->dev, "no memory to validate CIS\n");
1408 return -ENOMEM;
1409 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001410
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001411 count = reserved = 0;
1412 tuple->DesiredTuple = RETURN_FIRST_TUPLE;
1413 tuple->Attributes = TUPLE_RETURN_COMMON;
1414 ret = pccard_get_first_tuple(s, BIND_FN_ALL, tuple);
Dominik Brodowski4c89e882008-08-03 10:07:45 +02001415 if (ret != 0)
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001416 goto done;
1417
1418 /* First tuple should be DEVICE; we should really have either that
1419 or a CFTABLE_ENTRY of some sort */
1420 if ((tuple->TupleCode == CISTPL_DEVICE) ||
1421 (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_CFTABLE_ENTRY, p)) ||
1422 (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_CFTABLE_ENTRY_CB, p)))
1423 dev_ok++;
1424
1425 /* All cards should have a MANFID tuple, and/or a VERS_1 or VERS_2
1426 tuple, for card identification. Certain old D-Link and Linksys
1427 cards have only a broken VERS_2 tuple; hence the bogus test. */
1428 if ((pccard_read_tuple(s, BIND_FN_ALL, CISTPL_MANFID, p) == 0) ||
1429 (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_VERS_1, p) == 0) ||
1430 (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_VERS_2, p) != -ENOSPC))
1431 ident_ok++;
1432
1433 if (!dev_ok && !ident_ok)
1434 goto done;
1435
1436 for (count = 1; count < MAX_TUPLES; count++) {
1437 ret = pccard_get_next_tuple(s, BIND_FN_ALL, tuple);
1438 if (ret != 0)
1439 break;
1440 if (((tuple->TupleCode > 0x23) && (tuple->TupleCode < 0x40)) ||
1441 ((tuple->TupleCode > 0x47) && (tuple->TupleCode < 0x80)) ||
1442 ((tuple->TupleCode > 0x90) && (tuple->TupleCode < 0xff)))
1443 reserved++;
1444 }
1445 if ((count == MAX_TUPLES) || (reserved > 5) ||
1446 ((!dev_ok || !ident_ok) && (count > 10)))
1447 count = 0;
1448
1449 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450
1451done:
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001452 /* invalidate CIS cache on failure */
1453 if (!dev_ok || !ident_ok || !count) {
Alan Cox1c6c9b12014-12-10 15:07:14 +00001454#if defined(CONFIG_MTD_PCMCIA_ANONYMOUS)
1455 /* Set up as an anonymous card. If we don't have anonymous
1456 memory support then just error the card as there is no
1457 point trying to second guess.
1458
1459 Note: some cards have just a device entry, it may be
1460 worth extending support to cover these in future */
1461 if (!dev_ok || !ident_ok) {
1462 dev_info(&s->dev, "no CIS, assuming an anonymous memory card.\n");
1463 pcmcia_replace_cis(s, "\xFF", 1);
1464 count = 1;
1465 ret = 0;
1466 } else
1467#endif
1468 {
1469 mutex_lock(&s->ops_mutex);
1470 destroy_cis_cache(s);
1471 mutex_unlock(&s->ops_mutex);
1472 ret = -EIO;
1473 }
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001474 }
Dominik Brodowski904e3772010-01-02 12:28:04 +01001475
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001476 if (info)
1477 *info = count;
1478 kfree(tuple);
1479 kfree(p);
1480 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001481}
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001482
1483
1484#define to_socket(_dev) container_of(_dev, struct pcmcia_socket, dev)
1485
1486static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf,
1487 loff_t off, size_t count)
1488{
1489 tuple_t tuple;
1490 int status, i;
1491 loff_t pointer = 0;
1492 ssize_t ret = 0;
1493 u_char *tuplebuffer;
1494 u_char *tempbuffer;
1495
1496 tuplebuffer = kmalloc(sizeof(u_char) * 256, GFP_KERNEL);
1497 if (!tuplebuffer)
1498 return -ENOMEM;
1499
1500 tempbuffer = kmalloc(sizeof(u_char) * 258, GFP_KERNEL);
1501 if (!tempbuffer) {
1502 ret = -ENOMEM;
1503 goto free_tuple;
1504 }
1505
1506 memset(&tuple, 0, sizeof(tuple_t));
1507
1508 tuple.Attributes = TUPLE_RETURN_LINK | TUPLE_RETURN_COMMON;
1509 tuple.DesiredTuple = RETURN_FIRST_TUPLE;
1510 tuple.TupleOffset = 0;
1511
1512 status = pccard_get_first_tuple(s, BIND_FN_ALL, &tuple);
1513 while (!status) {
1514 tuple.TupleData = tuplebuffer;
1515 tuple.TupleDataMax = 255;
1516 memset(tuplebuffer, 0, sizeof(u_char) * 255);
1517
1518 status = pccard_get_tuple_data(s, &tuple);
1519 if (status)
1520 break;
1521
1522 if (off < (pointer + 2 + tuple.TupleDataLen)) {
1523 tempbuffer[0] = tuple.TupleCode & 0xff;
1524 tempbuffer[1] = tuple.TupleLink & 0xff;
1525 for (i = 0; i < tuple.TupleDataLen; i++)
1526 tempbuffer[i + 2] = tuplebuffer[i] & 0xff;
1527
1528 for (i = 0; i < (2 + tuple.TupleDataLen); i++) {
1529 if (((i + pointer) >= off) &&
1530 (i + pointer) < (off + count)) {
1531 buf[ret] = tempbuffer[i];
1532 ret++;
1533 }
1534 }
1535 }
1536
1537 pointer += 2 + tuple.TupleDataLen;
1538
1539 if (pointer >= (off + count))
1540 break;
1541
1542 if (tuple.TupleCode == CISTPL_END)
1543 break;
1544 status = pccard_get_next_tuple(s, BIND_FN_ALL, &tuple);
1545 }
1546
1547 kfree(tempbuffer);
1548 free_tuple:
1549 kfree(tuplebuffer);
1550
1551 return ret;
1552}
1553
1554
Chris Wright2c3c8be2010-05-12 18:28:57 -07001555static ssize_t pccard_show_cis(struct file *filp, struct kobject *kobj,
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001556 struct bin_attribute *bin_attr,
1557 char *buf, loff_t off, size_t count)
1558{
1559 unsigned int size = 0x200;
1560
1561 if (off >= size)
1562 count = 0;
1563 else {
1564 struct pcmcia_socket *s;
Dominik Brodowskia8408c12010-04-17 17:37:33 +02001565 unsigned int chains = 1;
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001566
1567 if (off + count > size)
1568 count = size - off;
1569
1570 s = to_socket(container_of(kobj, struct device, kobj));
1571
1572 if (!(s->state & SOCKET_PRESENT))
1573 return -ENODEV;
Dominik Brodowskia8408c12010-04-17 17:37:33 +02001574 if (!s->functions && pccard_validate_cis(s, &chains))
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001575 return -EIO;
1576 if (!chains)
1577 return -ENODATA;
1578
1579 count = pccard_extract_cis(s, buf, off, count);
1580 }
1581
1582 return count;
1583}
1584
1585
Chris Wright2c3c8be2010-05-12 18:28:57 -07001586static ssize_t pccard_store_cis(struct file *filp, struct kobject *kobj,
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001587 struct bin_attribute *bin_attr,
1588 char *buf, loff_t off, size_t count)
1589{
1590 struct pcmcia_socket *s;
1591 int error;
1592
1593 s = to_socket(container_of(kobj, struct device, kobj));
1594
1595 if (off)
1596 return -EINVAL;
1597
1598 if (count >= CISTPL_MAX_CIS_SIZE)
1599 return -EINVAL;
1600
1601 if (!(s->state & SOCKET_PRESENT))
1602 return -ENODEV;
1603
1604 error = pcmcia_replace_cis(s, buf, count);
1605 if (error)
1606 return -EIO;
1607
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +01001608 pcmcia_parse_uevents(s, PCMCIA_UEVENT_REQUERY);
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001609
1610 return count;
1611}
1612
1613
1614struct bin_attribute pccard_cis_attr = {
1615 .attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR },
1616 .size = 0x200,
1617 .read = pccard_show_cis,
1618 .write = pccard_store_cis,
1619};