blob: 4ff725ca2c74e8884461cac564cb4ba86693bcc1 [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
Dominik Brodowskia8408c12010-04-17 17:37:33 +02001389 if (s->functions) {
1390 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) {
Dominik Brodowski8680c4b2010-01-12 22:05:36 +01001454 mutex_lock(&s->ops_mutex);
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001455 destroy_cis_cache(s);
Dominik Brodowski8680c4b2010-01-12 22:05:36 +01001456 mutex_unlock(&s->ops_mutex);
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001457 ret = -EIO;
1458 }
Dominik Brodowski904e3772010-01-02 12:28:04 +01001459
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001460 if (info)
1461 *info = count;
1462 kfree(tuple);
1463 kfree(p);
1464 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465}
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001466
1467
1468#define to_socket(_dev) container_of(_dev, struct pcmcia_socket, dev)
1469
1470static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf,
1471 loff_t off, size_t count)
1472{
1473 tuple_t tuple;
1474 int status, i;
1475 loff_t pointer = 0;
1476 ssize_t ret = 0;
1477 u_char *tuplebuffer;
1478 u_char *tempbuffer;
1479
1480 tuplebuffer = kmalloc(sizeof(u_char) * 256, GFP_KERNEL);
1481 if (!tuplebuffer)
1482 return -ENOMEM;
1483
1484 tempbuffer = kmalloc(sizeof(u_char) * 258, GFP_KERNEL);
1485 if (!tempbuffer) {
1486 ret = -ENOMEM;
1487 goto free_tuple;
1488 }
1489
1490 memset(&tuple, 0, sizeof(tuple_t));
1491
1492 tuple.Attributes = TUPLE_RETURN_LINK | TUPLE_RETURN_COMMON;
1493 tuple.DesiredTuple = RETURN_FIRST_TUPLE;
1494 tuple.TupleOffset = 0;
1495
1496 status = pccard_get_first_tuple(s, BIND_FN_ALL, &tuple);
1497 while (!status) {
1498 tuple.TupleData = tuplebuffer;
1499 tuple.TupleDataMax = 255;
1500 memset(tuplebuffer, 0, sizeof(u_char) * 255);
1501
1502 status = pccard_get_tuple_data(s, &tuple);
1503 if (status)
1504 break;
1505
1506 if (off < (pointer + 2 + tuple.TupleDataLen)) {
1507 tempbuffer[0] = tuple.TupleCode & 0xff;
1508 tempbuffer[1] = tuple.TupleLink & 0xff;
1509 for (i = 0; i < tuple.TupleDataLen; i++)
1510 tempbuffer[i + 2] = tuplebuffer[i] & 0xff;
1511
1512 for (i = 0; i < (2 + tuple.TupleDataLen); i++) {
1513 if (((i + pointer) >= off) &&
1514 (i + pointer) < (off + count)) {
1515 buf[ret] = tempbuffer[i];
1516 ret++;
1517 }
1518 }
1519 }
1520
1521 pointer += 2 + tuple.TupleDataLen;
1522
1523 if (pointer >= (off + count))
1524 break;
1525
1526 if (tuple.TupleCode == CISTPL_END)
1527 break;
1528 status = pccard_get_next_tuple(s, BIND_FN_ALL, &tuple);
1529 }
1530
1531 kfree(tempbuffer);
1532 free_tuple:
1533 kfree(tuplebuffer);
1534
1535 return ret;
1536}
1537
1538
Chris Wright2c3c8be2010-05-12 18:28:57 -07001539static ssize_t pccard_show_cis(struct file *filp, struct kobject *kobj,
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001540 struct bin_attribute *bin_attr,
1541 char *buf, loff_t off, size_t count)
1542{
1543 unsigned int size = 0x200;
1544
1545 if (off >= size)
1546 count = 0;
1547 else {
1548 struct pcmcia_socket *s;
Dominik Brodowskia8408c12010-04-17 17:37:33 +02001549 unsigned int chains = 1;
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001550
1551 if (off + count > size)
1552 count = size - off;
1553
1554 s = to_socket(container_of(kobj, struct device, kobj));
1555
1556 if (!(s->state & SOCKET_PRESENT))
1557 return -ENODEV;
Dominik Brodowskia8408c12010-04-17 17:37:33 +02001558 if (!s->functions && pccard_validate_cis(s, &chains))
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001559 return -EIO;
1560 if (!chains)
1561 return -ENODATA;
1562
1563 count = pccard_extract_cis(s, buf, off, count);
1564 }
1565
1566 return count;
1567}
1568
1569
Chris Wright2c3c8be2010-05-12 18:28:57 -07001570static ssize_t pccard_store_cis(struct file *filp, struct kobject *kobj,
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001571 struct bin_attribute *bin_attr,
1572 char *buf, loff_t off, size_t count)
1573{
1574 struct pcmcia_socket *s;
1575 int error;
1576
1577 s = to_socket(container_of(kobj, struct device, kobj));
1578
1579 if (off)
1580 return -EINVAL;
1581
1582 if (count >= CISTPL_MAX_CIS_SIZE)
1583 return -EINVAL;
1584
1585 if (!(s->state & SOCKET_PRESENT))
1586 return -ENODEV;
1587
1588 error = pcmcia_replace_cis(s, buf, count);
1589 if (error)
1590 return -EIO;
1591
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +01001592 pcmcia_parse_uevents(s, PCMCIA_UEVENT_REQUERY);
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001593
1594 return count;
1595}
1596
1597
1598struct bin_attribute pccard_cis_attr = {
1599 .attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR },
1600 .size = 0x200,
1601 .read = pccard_show_cis,
1602 .write = pccard_store_cis,
1603};