blob: 9ad66c9848e338b72bd7242d052158ca3a61c081 [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
30#include <pcmcia/cs_types.h>
31#include <pcmcia/ss.h>
32#include <pcmcia/cs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <pcmcia/cisreg.h>
34#include <pcmcia/cistpl.h>
35#include "cs_internal.h"
36
37static const u_char mantissa[] = {
38 10, 12, 13, 15, 20, 25, 30, 35,
39 40, 45, 50, 55, 60, 70, 80, 90
40};
41
42static const u_int exponent[] = {
43 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000
44};
45
46/* Convert an extended speed byte to a time in nanoseconds */
47#define SPEED_CVT(v) \
48 (mantissa[(((v)>>3)&15)-1] * exponent[(v)&7] / 10)
49/* Convert a power byte to a current in 0.1 microamps */
50#define POWER_CVT(v) \
51 (mantissa[((v)>>3)&15] * exponent[(v)&7] / 10)
52#define POWER_SCALE(v) (exponent[(v)&7])
53
54/* Upper limit on reasonable # of tuples */
55#define MAX_TUPLES 200
56
57/*====================================================================*/
58
59/* Parameters that can be set with 'insmod' */
60
Pavel Machek37f77952005-09-07 16:00:26 -070061/* 16-bit CIS? */
62static int cis_width;
63module_param(cis_width, int, 0444);
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
65void release_cis_mem(struct pcmcia_socket *s)
66{
Dominik Brodowski6b8e0872010-01-12 21:42:51 +010067 mutex_lock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 if (s->cis_mem.flags & MAP_ACTIVE) {
69 s->cis_mem.flags &= ~MAP_ACTIVE;
70 s->ops->set_mem_map(s, &s->cis_mem);
71 if (s->cis_mem.res) {
72 release_resource(s->cis_mem.res);
73 kfree(s->cis_mem.res);
74 s->cis_mem.res = NULL;
75 }
76 iounmap(s->cis_virt);
77 s->cis_virt = NULL;
78 }
Dominik Brodowski6b8e0872010-01-12 21:42:51 +010079 mutex_unlock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070080}
Linus Torvalds1da177e2005-04-16 15:20:36 -070081
82/*
83 * Map the card memory at "card_offset" into virtual space.
84 * If flags & MAP_ATTRIB, map the attribute space, otherwise
85 * map the memory space.
86 */
87static void __iomem *
88set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flags)
89{
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 Brodowski6b8e0872010-01-12 21:42:51 +010093 mutex_lock(&s->ops_mutex);
Dominik Brodowski2e5a3e72005-07-28 01:07:23 -070094 if (!(s->features & SS_CAP_STATIC_MAP) && (mem->res == NULL)) {
95 mem->res = pcmcia_find_mem_region(0, s->map_size, s->map_size, 0, s);
96 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 Brodowski6b8e0872010-01-12 21:42:51 +010099 mutex_unlock(&s->ops_mutex);
Dominik Brodowski2e5a3e72005-07-28 01:07:23 -0700100 return NULL;
101 }
102 s->cis_virt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 }
Dominik Brodowski2ad0a0a2005-06-27 16:28:58 -0700104
Dominik Brodowski2e5a3e72005-07-28 01:07:23 -0700105 if (!(s->features & SS_CAP_STATIC_MAP) && (!s->cis_virt))
106 s->cis_virt = ioremap(mem->res->start, s->map_size);
107
108 mem->card_start = card_offset;
109 mem->flags = flags;
110
111 ret = s->ops->set_mem_map(s, mem);
112 if (ret) {
113 iounmap(s->cis_virt);
114 s->cis_virt = NULL;
Dominik Brodowski6b8e0872010-01-12 21:42:51 +0100115 mutex_unlock(&s->ops_mutex);
Dominik Brodowski2e5a3e72005-07-28 01:07:23 -0700116 return NULL;
117 }
118
119 if (s->features & SS_CAP_STATIC_MAP) {
120 if (s->cis_virt)
121 iounmap(s->cis_virt);
122 s->cis_virt = ioremap(mem->static_start, s->map_size);
123 }
124
Dominik Brodowski6b8e0872010-01-12 21:42:51 +0100125 mutex_unlock(&s->ops_mutex);
Dominik Brodowski2e5a3e72005-07-28 01:07:23 -0700126 return s->cis_virt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127}
128
129/*======================================================================
130
131 Low-level functions to read and write CIS memory. I think the
132 write routine is only useful for writing one-byte registers.
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100133
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134======================================================================*/
135
136/* Bits in attr field */
137#define IS_ATTR 1
138#define IS_INDIRECT 8
139
Dominik Brodowskie6ea0b9e2005-06-27 16:28:52 -0700140int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 u_int len, void *ptr)
142{
143 void __iomem *sys, *end;
144 unsigned char *buf = ptr;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100145
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200146 dev_dbg(&s->dev, "pcmcia_read_cis_mem(%d, %#x, %u)\n", attr, addr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147
148 if (attr & IS_INDIRECT) {
149 /* Indirect accesses use a bunch of special registers at fixed
150 locations in common memory */
151 u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN;
152 if (attr & IS_ATTR) {
153 addr *= 2;
154 flags = ICTRL0_AUTOINC;
155 }
156
157 sys = set_cis_map(s, 0, MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0));
158 if (!sys) {
159 memset(ptr, 0xff, len);
160 return -1;
161 }
162
163 writeb(flags, sys+CISREG_ICTRL0);
164 writeb(addr & 0xff, sys+CISREG_IADDR0);
165 writeb((addr>>8) & 0xff, sys+CISREG_IADDR1);
166 writeb((addr>>16) & 0xff, sys+CISREG_IADDR2);
167 writeb((addr>>24) & 0xff, sys+CISREG_IADDR3);
168 for ( ; len > 0; len--, buf++)
169 *buf = readb(sys+CISREG_IDATA0);
170 } else {
171 u_int inc = 1, card_offset, flags;
172
173 flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
174 if (attr) {
175 flags |= MAP_ATTRIB;
176 inc++;
177 addr *= 2;
178 }
179
180 card_offset = addr & ~(s->map_size-1);
181 while (len) {
182 sys = set_cis_map(s, card_offset, flags);
183 if (!sys) {
184 memset(ptr, 0xff, len);
185 return -1;
186 }
187 end = sys + s->map_size;
188 sys = sys + (addr & (s->map_size-1));
189 for ( ; len > 0; len--, buf++, sys += inc) {
190 if (sys == end)
191 break;
192 *buf = readb(sys);
193 }
194 card_offset += s->map_size;
195 addr = 0;
196 }
197 }
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200198 dev_dbg(&s->dev, " %#2.2x %#2.2x %#2.2x %#2.2x ...\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 *(u_char *)(ptr+0), *(u_char *)(ptr+1),
200 *(u_char *)(ptr+2), *(u_char *)(ptr+3));
201 return 0;
202}
Dominik Brodowski1a8d4662005-06-27 16:28:53 -0700203
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204
Dominik Brodowskie6ea0b9e2005-06-27 16:28:52 -0700205void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 u_int len, void *ptr)
207{
208 void __iomem *sys, *end;
209 unsigned char *buf = ptr;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100210
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200211 dev_dbg(&s->dev, "pcmcia_write_cis_mem(%d, %#x, %u)\n", attr, addr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
213 if (attr & IS_INDIRECT) {
214 /* Indirect accesses use a bunch of special registers at fixed
215 locations in common memory */
216 u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN;
217 if (attr & IS_ATTR) {
218 addr *= 2;
219 flags = ICTRL0_AUTOINC;
220 }
221
222 sys = set_cis_map(s, 0, MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0));
223 if (!sys)
224 return; /* FIXME: Error */
225
226 writeb(flags, sys+CISREG_ICTRL0);
227 writeb(addr & 0xff, sys+CISREG_IADDR0);
228 writeb((addr>>8) & 0xff, sys+CISREG_IADDR1);
229 writeb((addr>>16) & 0xff, sys+CISREG_IADDR2);
230 writeb((addr>>24) & 0xff, sys+CISREG_IADDR3);
231 for ( ; len > 0; len--, buf++)
232 writeb(*buf, sys+CISREG_IDATA0);
233 } else {
234 u_int inc = 1, card_offset, flags;
235
236 flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
237 if (attr & IS_ATTR) {
238 flags |= MAP_ATTRIB;
239 inc++;
240 addr *= 2;
241 }
242
243 card_offset = addr & ~(s->map_size-1);
244 while (len) {
245 sys = set_cis_map(s, card_offset, flags);
246 if (!sys)
247 return; /* FIXME: error */
248
249 end = sys + s->map_size;
250 sys = sys + (addr & (s->map_size-1));
251 for ( ; len > 0; len--, buf++, sys += inc) {
252 if (sys == end)
253 break;
254 writeb(*buf, sys);
255 }
256 card_offset += s->map_size;
257 addr = 0;
258 }
259 }
260}
Dominik Brodowski1a8d4662005-06-27 16:28:53 -0700261
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
263/*======================================================================
264
265 This is a wrapper around read_cis_mem, with the same interface,
266 but which caches information, for cards whose CIS may not be
267 readable all the time.
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100268
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269======================================================================*/
270
271static void read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr,
Dominik Brodowski53efec92008-07-28 19:44:05 +0200272 size_t len, void *ptr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273{
Dominik Brodowski57197b92010-01-02 17:27:33 +0100274 struct cis_cache_entry *cis;
275 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276
Dominik Brodowski57197b92010-01-02 17:27:33 +0100277 if (s->state & SOCKET_CARDBUS)
278 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279
Dominik Brodowski57197b92010-01-02 17:27:33 +0100280 if (s->fake_cis) {
281 if (s->fake_cis_len >= addr+len)
282 memcpy(ptr, s->fake_cis+addr, len);
283 else
284 memset(ptr, 0xff, len);
285 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
Dominik Brodowski57197b92010-01-02 17:27:33 +0100288 list_for_each_entry(cis, &s->cis_cache, node) {
289 if (cis->addr == addr && cis->len == len && cis->attr == attr) {
290 memcpy(ptr, cis->cache, len);
291 return;
292 }
293 }
294
Dominik Brodowskie6ea0b9e2005-06-27 16:28:52 -0700295 ret = pcmcia_read_cis_mem(s, attr, addr, len, ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
297 if (ret == 0) {
298 /* Copy data into the cache */
299 cis = kmalloc(sizeof(struct cis_cache_entry) + len, GFP_KERNEL);
300 if (cis) {
301 cis->addr = addr;
302 cis->len = len;
303 cis->attr = attr;
304 memcpy(cis->cache, ptr, len);
305 list_add(&cis->node, &s->cis_cache);
306 }
307 }
308}
309
310static void
311remove_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, u_int len)
312{
313 struct cis_cache_entry *cis;
314
315 list_for_each_entry(cis, &s->cis_cache, node)
316 if (cis->addr == addr && cis->len == len && cis->attr == attr) {
317 list_del(&cis->node);
318 kfree(cis);
319 break;
320 }
321}
322
Dominik Brodowski904e3772010-01-02 12:28:04 +0100323/**
324 * destroy_cis_cache() - destroy the CIS cache
325 * @s: pcmcia_socket for which CIS cache shall be destroyed
326 *
327 * This destroys the CIS cache but keeps any fake CIS alive.
328 */
329
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330void destroy_cis_cache(struct pcmcia_socket *s)
331{
332 struct list_head *l, *n;
Dominik Brodowski904e3772010-01-02 12:28:04 +0100333 struct cis_cache_entry *cis;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334
335 list_for_each_safe(l, n, &s->cis_cache) {
Dominik Brodowski904e3772010-01-02 12:28:04 +0100336 cis = list_entry(l, struct cis_cache_entry, node);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337 list_del(&cis->node);
338 kfree(cis);
339 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
342/*======================================================================
343
344 This verifies if the CIS of a card matches what is in the CIS
345 cache.
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100346
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347======================================================================*/
348
349int verify_cis_cache(struct pcmcia_socket *s)
350{
351 struct cis_cache_entry *cis;
352 char *buf;
353
Dominik Brodowski57197b92010-01-02 17:27:33 +0100354 if (s->state & SOCKET_CARDBUS)
355 return -EINVAL;
356
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 buf = kmalloc(256, GFP_KERNEL);
Dominik Brodowskie6895972008-11-02 19:55:45 +0100358 if (buf == NULL) {
Dominik Brodowski11683862008-08-03 10:22:47 +0200359 dev_printk(KERN_WARNING, &s->dev,
360 "no memory for verifying CIS\n");
361 return -ENOMEM;
Dominik Brodowskie6895972008-11-02 19:55:45 +0100362 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 list_for_each_entry(cis, &s->cis_cache, node) {
364 int len = cis->len;
365
366 if (len > 256)
367 len = 256;
Dominik Brodowski57197b92010-01-02 17:27:33 +0100368
369 pcmcia_read_cis_mem(s, cis->attr, cis->addr, len, buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370
371 if (memcmp(buf, cis->cache, len) != 0) {
372 kfree(buf);
373 return -1;
374 }
375 }
376 kfree(buf);
377 return 0;
378}
379
380/*======================================================================
381
382 For really bad cards, we provide a facility for uploading a
383 replacement CIS.
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100384
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385======================================================================*/
386
Dominik Brodowski53efec92008-07-28 19:44:05 +0200387int pcmcia_replace_cis(struct pcmcia_socket *s,
388 const u8 *data, const size_t len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389{
Dominik Brodowski11683862008-08-03 10:22:47 +0200390 if (len > CISTPL_MAX_CIS_SIZE) {
391 dev_printk(KERN_WARNING, &s->dev, "replacement CIS too big\n");
392 return -EINVAL;
393 }
394 kfree(s->fake_cis);
395 s->fake_cis = kmalloc(len, GFP_KERNEL);
396 if (s->fake_cis == NULL) {
397 dev_printk(KERN_WARNING, &s->dev, "no memory to replace CIS\n");
398 return -ENOMEM;
399 }
400 s->fake_cis_len = len;
401 memcpy(s->fake_cis, data, len);
402 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700404
405/*======================================================================
406
407 The high-level CIS tuple services
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100408
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409======================================================================*/
410
411typedef struct tuple_flags {
412 u_int link_space:4;
413 u_int has_link:1;
414 u_int mfc_fn:3;
415 u_int space:4;
416} tuple_flags;
417
418#define LINK_SPACE(f) (((tuple_flags *)(&(f)))->link_space)
419#define HAS_LINK(f) (((tuple_flags *)(&(f)))->has_link)
420#define MFC_FN(f) (((tuple_flags *)(&(f)))->mfc_fn)
421#define SPACE(f) (((tuple_flags *)(&(f)))->space)
422
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function, tuple_t *tuple)
424{
425 if (!s)
Dominik Brodowskiffb8da22008-08-03 11:18:00 +0200426 return -EINVAL;
Dominik Brodowski57197b92010-01-02 17:27:33 +0100427
428 if (!(s->state & SOCKET_PRESENT) || (s->state & SOCKET_CARDBUS))
Dominik Brodowski3939c1ef2008-08-03 11:10:56 +0200429 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 tuple->TupleLink = tuple->Flags = 0;
Dominik Brodowski57197b92010-01-02 17:27:33 +0100431
432 /* Assume presence of a LONGLINK_C to address 0 */
433 tuple->CISOffset = tuple->LinkOffset = 0;
434 SPACE(tuple->Flags) = HAS_LINK(tuple->Flags) = 1;
435
436 if ((s->functions > 1) && !(tuple->Attributes & TUPLE_RETURN_COMMON)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 cisdata_t req = tuple->DesiredTuple;
438 tuple->DesiredTuple = CISTPL_LONGLINK_MFC;
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200439 if (pccard_get_next_tuple(s, function, tuple) == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 tuple->DesiredTuple = CISTPL_LINKTARGET;
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200441 if (pccard_get_next_tuple(s, function, tuple) != 0)
Dominik Brodowski635d19b2008-08-03 11:47:29 +0200442 return -ENOSPC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 } else
444 tuple->CISOffset = tuple->TupleLink = 0;
445 tuple->DesiredTuple = req;
446 }
447 return pccard_get_next_tuple(s, function, tuple);
448}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449
450static int follow_link(struct pcmcia_socket *s, tuple_t *tuple)
451{
452 u_char link[5];
453 u_int ofs;
454
455 if (MFC_FN(tuple->Flags)) {
456 /* Get indirect link from the MFC tuple */
457 read_cis_cache(s, LINK_SPACE(tuple->Flags),
458 tuple->LinkOffset, 5, link);
Harvey Harrison6b1e6f62008-04-29 01:03:39 -0700459 ofs = get_unaligned_le32(link + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR);
461 /* Move to the next indirect link */
462 tuple->LinkOffset += 5;
463 MFC_FN(tuple->Flags)--;
464 } else if (HAS_LINK(tuple->Flags)) {
465 ofs = tuple->LinkOffset;
466 SPACE(tuple->Flags) = LINK_SPACE(tuple->Flags);
467 HAS_LINK(tuple->Flags) = 0;
468 } else {
469 return -1;
470 }
Dominik Brodowski57197b92010-01-02 17:27:33 +0100471 if (SPACE(tuple->Flags)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 /* This is ugly, but a common CIS error is to code the long
473 link offset incorrectly, so we check the right spot... */
474 read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link);
475 if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) &&
476 (strncmp(link+2, "CIS", 3) == 0))
477 return ofs;
478 remove_cis_cache(s, SPACE(tuple->Flags), ofs, 5);
479 /* Then, we try the wrong spot... */
480 ofs = ofs >> 1;
481 }
482 read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link);
483 if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) &&
484 (strncmp(link+2, "CIS", 3) == 0))
485 return ofs;
486 remove_cis_cache(s, SPACE(tuple->Flags), ofs, 5);
487 return -1;
488}
489
490int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, tuple_t *tuple)
491{
492 u_char link[2], tmp;
493 int ofs, i, attr;
494
495 if (!s)
Dominik Brodowskiffb8da22008-08-03 11:18:00 +0200496 return -EINVAL;
Dominik Brodowski57197b92010-01-02 17:27:33 +0100497 if (!(s->state & SOCKET_PRESENT) || (s->state & SOCKET_CARDBUS))
Dominik Brodowski3939c1ef2008-08-03 11:10:56 +0200498 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499
500 link[1] = tuple->TupleLink;
501 ofs = tuple->CISOffset + tuple->TupleLink;
502 attr = SPACE(tuple->Flags);
503
504 for (i = 0; i < MAX_TUPLES; i++) {
505 if (link[1] == 0xff) {
506 link[0] = CISTPL_END;
507 } else {
508 read_cis_cache(s, attr, ofs, 2, link);
509 if (link[0] == CISTPL_NULL) {
510 ofs++; continue;
511 }
512 }
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100513
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 /* End of chain? Follow long link if possible */
515 if (link[0] == CISTPL_END) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100516 ofs = follow_link(s, tuple);
517 if (ofs < 0)
Dominik Brodowski635d19b2008-08-03 11:47:29 +0200518 return -ENOSPC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 attr = SPACE(tuple->Flags);
520 read_cis_cache(s, attr, ofs, 2, link);
521 }
522
523 /* Is this a link tuple? Make a note of it */
524 if ((link[0] == CISTPL_LONGLINK_A) ||
525 (link[0] == CISTPL_LONGLINK_C) ||
526 (link[0] == CISTPL_LONGLINK_MFC) ||
527 (link[0] == CISTPL_LINKTARGET) ||
528 (link[0] == CISTPL_INDIRECT) ||
529 (link[0] == CISTPL_NO_LINK)) {
530 switch (link[0]) {
531 case CISTPL_LONGLINK_A:
532 HAS_LINK(tuple->Flags) = 1;
533 LINK_SPACE(tuple->Flags) = attr | IS_ATTR;
534 read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset);
535 break;
536 case CISTPL_LONGLINK_C:
537 HAS_LINK(tuple->Flags) = 1;
538 LINK_SPACE(tuple->Flags) = attr & ~IS_ATTR;
539 read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset);
540 break;
541 case CISTPL_INDIRECT:
542 HAS_LINK(tuple->Flags) = 1;
543 LINK_SPACE(tuple->Flags) = IS_ATTR | IS_INDIRECT;
544 tuple->LinkOffset = 0;
545 break;
546 case CISTPL_LONGLINK_MFC:
547 tuple->LinkOffset = ofs + 3;
548 LINK_SPACE(tuple->Flags) = attr;
549 if (function == BIND_FN_ALL) {
550 /* Follow all the MFC links */
551 read_cis_cache(s, attr, ofs+2, 1, &tmp);
552 MFC_FN(tuple->Flags) = tmp;
553 } else {
554 /* Follow exactly one of the links */
555 MFC_FN(tuple->Flags) = 1;
556 tuple->LinkOffset += function * 5;
557 }
558 break;
559 case CISTPL_NO_LINK:
560 HAS_LINK(tuple->Flags) = 0;
561 break;
562 }
563 if ((tuple->Attributes & TUPLE_RETURN_LINK) &&
564 (tuple->DesiredTuple == RETURN_FIRST_TUPLE))
565 break;
566 } else
567 if (tuple->DesiredTuple == RETURN_FIRST_TUPLE)
568 break;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100569
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 if (link[0] == tuple->DesiredTuple)
571 break;
572 ofs += link[1] + 2;
573 }
574 if (i == MAX_TUPLES) {
Dominik Brodowskid50dbec2009-10-23 12:51:28 +0200575 dev_dbg(&s->dev, "cs: overrun in pcmcia_get_next_tuple\n");
Dominik Brodowski635d19b2008-08-03 11:47:29 +0200576 return -ENOSPC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 }
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100578
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 tuple->TupleCode = link[0];
580 tuple->TupleLink = link[1];
581 tuple->CISOffset = ofs + 2;
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200582 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584
585/*====================================================================*/
586
587#define _MIN(a, b) (((a) < (b)) ? (a) : (b))
588
589int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple)
590{
591 u_int len;
592
593 if (!s)
Dominik Brodowskiffb8da22008-08-03 11:18:00 +0200594 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595
596 if (tuple->TupleLink < tuple->TupleOffset)
Dominik Brodowski635d19b2008-08-03 11:47:29 +0200597 return -ENOSPC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 len = tuple->TupleLink - tuple->TupleOffset;
599 tuple->TupleDataLen = tuple->TupleLink;
600 if (len == 0)
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200601 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 read_cis_cache(s, SPACE(tuple->Flags),
603 tuple->CISOffset + tuple->TupleOffset,
604 _MIN(len, tuple->TupleDataMax), tuple->TupleData);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200605 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607
608
609/*======================================================================
610
611 Parsing routines for individual tuples
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100612
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613======================================================================*/
614
615static int parse_device(tuple_t *tuple, cistpl_device_t *device)
616{
617 int i;
618 u_char scale;
619 u_char *p, *q;
620
621 p = (u_char *)tuple->TupleData;
622 q = p + tuple->TupleDataLen;
623
624 device->ndev = 0;
625 for (i = 0; i < CISTPL_MAX_DEVICES; i++) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100626
627 if (*p == 0xff)
628 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 device->dev[i].type = (*p >> 4);
630 device->dev[i].wp = (*p & 0x08) ? 1 : 0;
631 switch (*p & 0x07) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100632 case 0:
633 device->dev[i].speed = 0;
634 break;
635 case 1:
636 device->dev[i].speed = 250;
637 break;
638 case 2:
639 device->dev[i].speed = 200;
640 break;
641 case 3:
642 device->dev[i].speed = 150;
643 break;
644 case 4:
645 device->dev[i].speed = 100;
646 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 case 7:
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +0200648 if (++p == q)
649 return -EINVAL;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100650 device->dev[i].speed = SPEED_CVT(*p);
651 while (*p & 0x80)
652 if (++p == q)
653 return -EINVAL;
654 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 default:
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100656 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 }
658
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +0200659 if (++p == q)
660 return -EINVAL;
661 if (*p == 0xff)
662 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 scale = *p & 7;
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +0200664 if (scale == 7)
665 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 device->dev[i].size = ((*p >> 3) + 1) * (512 << (scale*2));
667 device->ndev++;
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +0200668 if (++p == q)
669 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 }
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100671
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200672 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673}
674
675/*====================================================================*/
676
677static int parse_checksum(tuple_t *tuple, cistpl_checksum_t *csum)
678{
679 u_char *p;
680 if (tuple->TupleDataLen < 5)
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +0200681 return -EINVAL;
Daniel Ritzdc0cf6a2007-10-16 01:23:52 -0700682 p = (u_char *) tuple->TupleData;
Harvey Harrison6b1e6f62008-04-29 01:03:39 -0700683 csum->addr = tuple->CISOffset + get_unaligned_le16(p) - 2;
684 csum->len = get_unaligned_le16(p + 2);
Daniel Ritzdc0cf6a2007-10-16 01:23:52 -0700685 csum->sum = *(p + 4);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200686 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687}
688
689/*====================================================================*/
690
691static int parse_longlink(tuple_t *tuple, cistpl_longlink_t *link)
692{
693 if (tuple->TupleDataLen < 4)
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +0200694 return -EINVAL;
Harvey Harrison6b1e6f62008-04-29 01:03:39 -0700695 link->addr = get_unaligned_le32(tuple->TupleData);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200696 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697}
698
699/*====================================================================*/
700
701static int parse_longlink_mfc(tuple_t *tuple,
702 cistpl_longlink_mfc_t *link)
703{
704 u_char *p;
705 int i;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100706
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 p = (u_char *)tuple->TupleData;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100708
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 link->nfn = *p; p++;
710 if (tuple->TupleDataLen <= link->nfn*5)
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +0200711 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712 for (i = 0; i < link->nfn; i++) {
713 link->fn[i].space = *p; p++;
Harvey Harrison6b1e6f62008-04-29 01:03:39 -0700714 link->fn[i].addr = get_unaligned_le32(p);
Daniel Ritzdc0cf6a2007-10-16 01:23:52 -0700715 p += 4;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716 }
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200717 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718}
719
720/*====================================================================*/
721
722static int parse_strings(u_char *p, u_char *q, int max,
723 char *s, u_char *ofs, u_char *found)
724{
725 int i, j, ns;
726
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +0200727 if (p == q)
728 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 ns = 0; j = 0;
730 for (i = 0; i < max; i++) {
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +0200731 if (*p == 0xff)
732 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 ofs[i] = j;
734 ns++;
735 for (;;) {
736 s[j++] = (*p == 0xff) ? '\0' : *p;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100737 if ((*p == '\0') || (*p == 0xff))
738 break;
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +0200739 if (++p == q)
740 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 }
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100742 if ((*p == 0xff) || (++p == q))
743 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 }
745 if (found) {
746 *found = ns;
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200747 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 } else {
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +0200749 return (ns == max) ? 0 : -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 }
751}
752
753/*====================================================================*/
754
755static int parse_vers_1(tuple_t *tuple, cistpl_vers_1_t *vers_1)
756{
757 u_char *p, *q;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100758
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 p = (u_char *)tuple->TupleData;
760 q = p + tuple->TupleDataLen;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100761
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 vers_1->major = *p; p++;
763 vers_1->minor = *p; p++;
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +0200764 if (p >= q)
765 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766
767 return parse_strings(p, q, CISTPL_VERS_1_MAX_PROD_STRINGS,
768 vers_1->str, vers_1->ofs, &vers_1->ns);
769}
770
771/*====================================================================*/
772
773static int parse_altstr(tuple_t *tuple, cistpl_altstr_t *altstr)
774{
775 u_char *p, *q;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100776
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 p = (u_char *)tuple->TupleData;
778 q = p + tuple->TupleDataLen;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100779
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 return parse_strings(p, q, CISTPL_MAX_ALTSTR_STRINGS,
781 altstr->str, altstr->ofs, &altstr->ns);
782}
783
784/*====================================================================*/
785
786static int parse_jedec(tuple_t *tuple, cistpl_jedec_t *jedec)
787{
788 u_char *p, *q;
789 int nid;
790
791 p = (u_char *)tuple->TupleData;
792 q = p + tuple->TupleDataLen;
793
794 for (nid = 0; nid < CISTPL_MAX_DEVICES; nid++) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100795 if (p > q-2)
796 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 jedec->id[nid].mfr = p[0];
798 jedec->id[nid].info = p[1];
799 p += 2;
800 }
801 jedec->nid = nid;
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200802 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803}
804
805/*====================================================================*/
806
807static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m)
808{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 if (tuple->TupleDataLen < 4)
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +0200810 return -EINVAL;
Harvey Harrison6b1e6f62008-04-29 01:03:39 -0700811 m->manf = get_unaligned_le16(tuple->TupleData);
812 m->card = get_unaligned_le16(tuple->TupleData + 2);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200813 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814}
815
816/*====================================================================*/
817
818static int parse_funcid(tuple_t *tuple, cistpl_funcid_t *f)
819{
820 u_char *p;
821 if (tuple->TupleDataLen < 2)
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +0200822 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 p = (u_char *)tuple->TupleData;
824 f->func = p[0];
825 f->sysinit = p[1];
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200826 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827}
828
829/*====================================================================*/
830
831static int parse_funce(tuple_t *tuple, cistpl_funce_t *f)
832{
833 u_char *p;
834 int i;
835 if (tuple->TupleDataLen < 1)
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +0200836 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 p = (u_char *)tuple->TupleData;
838 f->type = p[0];
839 for (i = 1; i < tuple->TupleDataLen; i++)
840 f->data[i-1] = p[i];
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200841 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842}
843
844/*====================================================================*/
845
846static int parse_config(tuple_t *tuple, cistpl_config_t *config)
847{
848 int rasz, rmsz, i;
849 u_char *p;
850
851 p = (u_char *)tuple->TupleData;
852 rasz = *p & 0x03;
853 rmsz = (*p & 0x3c) >> 2;
854 if (tuple->TupleDataLen < rasz+rmsz+4)
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +0200855 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 config->last_idx = *(++p);
857 p++;
858 config->base = 0;
859 for (i = 0; i <= rasz; i++)
860 config->base += p[i] << (8*i);
861 p += rasz+1;
862 for (i = 0; i < 4; i++)
863 config->rmask[i] = 0;
864 for (i = 0; i <= rmsz; i++)
865 config->rmask[i>>2] += p[i] << (8*(i%4));
866 config->subtuples = tuple->TupleDataLen - (rasz+rmsz+4);
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200867 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868}
869
870/*======================================================================
871
872 The following routines are all used to parse the nightmarish
873 config table entries.
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100874
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875======================================================================*/
876
877static u_char *parse_power(u_char *p, u_char *q,
878 cistpl_power_t *pwr)
879{
880 int i;
881 u_int scale;
882
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100883 if (p == q)
884 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 pwr->present = *p;
886 pwr->flags = 0;
887 p++;
888 for (i = 0; i < 7; i++)
889 if (pwr->present & (1<<i)) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100890 if (p == q)
891 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 pwr->param[i] = POWER_CVT(*p);
893 scale = POWER_SCALE(*p);
894 while (*p & 0x80) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100895 if (++p == q)
896 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 if ((*p & 0x7f) < 100)
898 pwr->param[i] += (*p & 0x7f) * scale / 100;
899 else if (*p == 0x7d)
900 pwr->flags |= CISTPL_POWER_HIGHZ_OK;
901 else if (*p == 0x7e)
902 pwr->param[i] = 0;
903 else if (*p == 0x7f)
904 pwr->flags |= CISTPL_POWER_HIGHZ_REQ;
905 else
906 return NULL;
907 }
908 p++;
909 }
910 return p;
911}
912
913/*====================================================================*/
914
915static u_char *parse_timing(u_char *p, u_char *q,
916 cistpl_timing_t *timing)
917{
918 u_char scale;
919
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100920 if (p == q)
921 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 scale = *p;
923 if ((scale & 3) != 3) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100924 if (++p == q)
925 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926 timing->wait = SPEED_CVT(*p);
927 timing->waitscale = exponent[scale & 3];
928 } else
929 timing->wait = 0;
930 scale >>= 2;
931 if ((scale & 7) != 7) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100932 if (++p == q)
933 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934 timing->ready = SPEED_CVT(*p);
935 timing->rdyscale = exponent[scale & 7];
936 } else
937 timing->ready = 0;
938 scale >>= 3;
939 if (scale != 7) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100940 if (++p == q)
941 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 timing->reserved = SPEED_CVT(*p);
943 timing->rsvscale = exponent[scale];
944 } else
945 timing->reserved = 0;
946 p++;
947 return p;
948}
949
950/*====================================================================*/
951
952static u_char *parse_io(u_char *p, u_char *q, cistpl_io_t *io)
953{
954 int i, j, bsz, lsz;
955
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100956 if (p == q)
957 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 io->flags = *p;
959
960 if (!(*p & 0x80)) {
961 io->nwin = 1;
962 io->win[0].base = 0;
963 io->win[0].len = (1 << (io->flags & CISTPL_IO_LINES_MASK));
964 return p+1;
965 }
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100966
967 if (++p == q)
968 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 io->nwin = (*p & 0x0f) + 1;
970 bsz = (*p & 0x30) >> 4;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100971 if (bsz == 3)
972 bsz++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 lsz = (*p & 0xc0) >> 6;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100974 if (lsz == 3)
975 lsz++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 p++;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100977
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 for (i = 0; i < io->nwin; i++) {
979 io->win[i].base = 0;
980 io->win[i].len = 1;
981 for (j = 0; j < bsz; j++, p++) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100982 if (p == q)
983 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984 io->win[i].base += *p << (j*8);
985 }
986 for (j = 0; j < lsz; j++, p++) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100987 if (p == q)
988 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989 io->win[i].len += *p << (j*8);
990 }
991 }
992 return p;
993}
994
995/*====================================================================*/
996
997static u_char *parse_mem(u_char *p, u_char *q, cistpl_mem_t *mem)
998{
999 int i, j, asz, lsz, has_ha;
1000 u_int len, ca, ha;
1001
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001002 if (p == q)
1003 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004
1005 mem->nwin = (*p & 0x07) + 1;
1006 lsz = (*p & 0x18) >> 3;
1007 asz = (*p & 0x60) >> 5;
1008 has_ha = (*p & 0x80);
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001009 if (++p == q)
1010 return NULL;
1011
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 for (i = 0; i < mem->nwin; i++) {
1013 len = ca = ha = 0;
1014 for (j = 0; j < lsz; j++, p++) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001015 if (p == q)
1016 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 len += *p << (j*8);
1018 }
1019 for (j = 0; j < asz; j++, p++) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001020 if (p == q)
1021 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 ca += *p << (j*8);
1023 }
1024 if (has_ha)
1025 for (j = 0; j < asz; j++, p++) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001026 if (p == q)
1027 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 ha += *p << (j*8);
1029 }
1030 mem->win[i].len = len << 8;
1031 mem->win[i].card_addr = ca << 8;
1032 mem->win[i].host_addr = ha << 8;
1033 }
1034 return p;
1035}
1036
1037/*====================================================================*/
1038
1039static u_char *parse_irq(u_char *p, u_char *q, cistpl_irq_t *irq)
1040{
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +02001041 if (p == q)
1042 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 irq->IRQInfo1 = *p; p++;
1044 if (irq->IRQInfo1 & IRQ_INFO2_VALID) {
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +02001045 if (p+2 > q)
1046 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 irq->IRQInfo2 = (p[1]<<8) + p[0];
1048 p += 2;
1049 }
1050 return p;
1051}
1052
1053/*====================================================================*/
1054
1055static int parse_cftable_entry(tuple_t *tuple,
1056 cistpl_cftable_entry_t *entry)
1057{
1058 u_char *p, *q, features;
1059
1060 p = tuple->TupleData;
1061 q = p + tuple->TupleDataLen;
1062 entry->index = *p & 0x3f;
1063 entry->flags = 0;
1064 if (*p & 0x40)
1065 entry->flags |= CISTPL_CFTABLE_DEFAULT;
1066 if (*p & 0x80) {
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +02001067 if (++p == q)
1068 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 if (*p & 0x10)
1070 entry->flags |= CISTPL_CFTABLE_BVDS;
1071 if (*p & 0x20)
1072 entry->flags |= CISTPL_CFTABLE_WP;
1073 if (*p & 0x40)
1074 entry->flags |= CISTPL_CFTABLE_RDYBSY;
1075 if (*p & 0x80)
1076 entry->flags |= CISTPL_CFTABLE_MWAIT;
1077 entry->interface = *p & 0x0f;
1078 } else
1079 entry->interface = 0;
1080
1081 /* Process optional features */
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +02001082 if (++p == q)
1083 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 features = *p; p++;
1085
1086 /* Power options */
1087 if ((features & 3) > 0) {
1088 p = parse_power(p, q, &entry->vcc);
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +02001089 if (p == NULL)
1090 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 } else
1092 entry->vcc.present = 0;
1093 if ((features & 3) > 1) {
1094 p = parse_power(p, q, &entry->vpp1);
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +02001095 if (p == NULL)
1096 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097 } else
1098 entry->vpp1.present = 0;
1099 if ((features & 3) > 2) {
1100 p = parse_power(p, q, &entry->vpp2);
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +02001101 if (p == NULL)
1102 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 } else
1104 entry->vpp2.present = 0;
1105
1106 /* Timing options */
1107 if (features & 0x04) {
1108 p = parse_timing(p, q, &entry->timing);
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +02001109 if (p == NULL)
1110 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 } else {
1112 entry->timing.wait = 0;
1113 entry->timing.ready = 0;
1114 entry->timing.reserved = 0;
1115 }
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001116
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 /* I/O window options */
1118 if (features & 0x08) {
1119 p = parse_io(p, q, &entry->io);
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +02001120 if (p == NULL)
1121 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 } else
1123 entry->io.nwin = 0;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001124
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 /* Interrupt options */
1126 if (features & 0x10) {
1127 p = parse_irq(p, q, &entry->irq);
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +02001128 if (p == NULL)
1129 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 } else
1131 entry->irq.IRQInfo1 = 0;
1132
1133 switch (features & 0x60) {
1134 case 0x00:
1135 entry->mem.nwin = 0;
1136 break;
1137 case 0x20:
1138 entry->mem.nwin = 1;
Harvey Harrison6b1e6f62008-04-29 01:03:39 -07001139 entry->mem.win[0].len = get_unaligned_le16(p) << 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 entry->mem.win[0].card_addr = 0;
1141 entry->mem.win[0].host_addr = 0;
1142 p += 2;
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +02001143 if (p > q)
1144 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 break;
1146 case 0x40:
1147 entry->mem.nwin = 1;
Harvey Harrison6b1e6f62008-04-29 01:03:39 -07001148 entry->mem.win[0].len = get_unaligned_le16(p) << 8;
1149 entry->mem.win[0].card_addr = get_unaligned_le16(p + 2) << 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 entry->mem.win[0].host_addr = 0;
1151 p += 4;
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +02001152 if (p > q)
1153 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 break;
1155 case 0x60:
1156 p = parse_mem(p, q, &entry->mem);
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +02001157 if (p == NULL)
1158 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 break;
1160 }
1161
1162 /* Misc features */
1163 if (features & 0x80) {
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +02001164 if (p == q)
1165 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 entry->flags |= (*p << 8);
1167 while (*p & 0x80)
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +02001168 if (++p == q)
1169 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 p++;
1171 }
1172
1173 entry->subtuples = q-p;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001174
Dominik Brodowski4c89e882008-08-03 10:07:45 +02001175 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176}
1177
1178/*====================================================================*/
1179
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180static int parse_device_geo(tuple_t *tuple, cistpl_device_geo_t *geo)
1181{
1182 u_char *p, *q;
1183 int n;
1184
1185 p = (u_char *)tuple->TupleData;
1186 q = p + tuple->TupleDataLen;
1187
1188 for (n = 0; n < CISTPL_MAX_DEVICES; n++) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001189 if (p > q-6)
1190 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191 geo->geo[n].buswidth = p[0];
1192 geo->geo[n].erase_block = 1 << (p[1]-1);
1193 geo->geo[n].read_block = 1 << (p[2]-1);
1194 geo->geo[n].write_block = 1 << (p[3]-1);
1195 geo->geo[n].partition = 1 << (p[4]-1);
1196 geo->geo[n].interleave = 1 << (p[5]-1);
1197 p += 6;
1198 }
1199 geo->ngeo = n;
Dominik Brodowski4c89e882008-08-03 10:07:45 +02001200 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201}
1202
1203/*====================================================================*/
1204
1205static int parse_vers_2(tuple_t *tuple, cistpl_vers_2_t *v2)
1206{
1207 u_char *p, *q;
1208
1209 if (tuple->TupleDataLen < 10)
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +02001210 return -EINVAL;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001211
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212 p = tuple->TupleData;
1213 q = p + tuple->TupleDataLen;
1214
1215 v2->vers = p[0];
1216 v2->comply = p[1];
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001217 v2->dindex = get_unaligned_le16(p + 2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 v2->vspec8 = p[6];
1219 v2->vspec9 = p[7];
1220 v2->nhdr = p[8];
1221 p += 9;
1222 return parse_strings(p, q, 2, v2->str, &v2->vendor, NULL);
1223}
1224
1225/*====================================================================*/
1226
1227static int parse_org(tuple_t *tuple, cistpl_org_t *org)
1228{
1229 u_char *p, *q;
1230 int i;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001231
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 p = tuple->TupleData;
1233 q = p + tuple->TupleDataLen;
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +02001234 if (p == q)
1235 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 org->data_org = *p;
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +02001237 if (++p == q)
1238 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 for (i = 0; i < 30; i++) {
1240 org->desc[i] = *p;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001241 if (*p == '\0')
1242 break;
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +02001243 if (++p == q)
1244 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 }
Dominik Brodowski4c89e882008-08-03 10:07:45 +02001246 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247}
1248
1249/*====================================================================*/
1250
1251static int parse_format(tuple_t *tuple, cistpl_format_t *fmt)
1252{
1253 u_char *p;
1254
1255 if (tuple->TupleDataLen < 10)
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +02001256 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257
1258 p = tuple->TupleData;
1259
1260 fmt->type = p[0];
1261 fmt->edc = p[1];
Harvey Harrison6b1e6f62008-04-29 01:03:39 -07001262 fmt->offset = get_unaligned_le32(p + 2);
1263 fmt->length = get_unaligned_le32(p + 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264
Dominik Brodowski4c89e882008-08-03 10:07:45 +02001265 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266}
1267
1268/*====================================================================*/
1269
Dominik Brodowski2f3061e2008-08-31 15:50:33 +02001270int pcmcia_parse_tuple(tuple_t *tuple, cisparse_t *parse)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271{
Dominik Brodowski4c89e882008-08-03 10:07:45 +02001272 int ret = 0;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001273
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 if (tuple->TupleDataLen > tuple->TupleDataMax)
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +02001275 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276 switch (tuple->TupleCode) {
1277 case CISTPL_DEVICE:
1278 case CISTPL_DEVICE_A:
1279 ret = parse_device(tuple, &parse->device);
1280 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001281 case CISTPL_CHECKSUM:
1282 ret = parse_checksum(tuple, &parse->checksum);
1283 break;
1284 case CISTPL_LONGLINK_A:
1285 case CISTPL_LONGLINK_C:
1286 ret = parse_longlink(tuple, &parse->longlink);
1287 break;
1288 case CISTPL_LONGLINK_MFC:
1289 ret = parse_longlink_mfc(tuple, &parse->longlink_mfc);
1290 break;
1291 case CISTPL_VERS_1:
1292 ret = parse_vers_1(tuple, &parse->version_1);
1293 break;
1294 case CISTPL_ALTSTR:
1295 ret = parse_altstr(tuple, &parse->altstr);
1296 break;
1297 case CISTPL_JEDEC_A:
1298 case CISTPL_JEDEC_C:
1299 ret = parse_jedec(tuple, &parse->jedec);
1300 break;
1301 case CISTPL_MANFID:
1302 ret = parse_manfid(tuple, &parse->manfid);
1303 break;
1304 case CISTPL_FUNCID:
1305 ret = parse_funcid(tuple, &parse->funcid);
1306 break;
1307 case CISTPL_FUNCE:
1308 ret = parse_funce(tuple, &parse->funce);
1309 break;
1310 case CISTPL_CONFIG:
1311 ret = parse_config(tuple, &parse->config);
1312 break;
1313 case CISTPL_CFTABLE_ENTRY:
1314 ret = parse_cftable_entry(tuple, &parse->cftable_entry);
1315 break;
1316 case CISTPL_DEVICE_GEO:
1317 case CISTPL_DEVICE_GEO_A:
1318 ret = parse_device_geo(tuple, &parse->device_geo);
1319 break;
1320 case CISTPL_VERS_2:
1321 ret = parse_vers_2(tuple, &parse->vers_2);
1322 break;
1323 case CISTPL_ORG:
1324 ret = parse_org(tuple, &parse->org);
1325 break;
1326 case CISTPL_FORMAT:
1327 case CISTPL_FORMAT_A:
1328 ret = parse_format(tuple, &parse->format);
1329 break;
1330 case CISTPL_NO_LINK:
1331 case CISTPL_LINKTARGET:
Dominik Brodowski4c89e882008-08-03 10:07:45 +02001332 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 break;
1334 default:
Dominik Brodowskide6405e2008-08-03 10:47:59 +02001335 ret = -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 break;
1337 }
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +02001338 if (ret)
Dominik Brodowskid50dbec2009-10-23 12:51:28 +02001339 pr_debug("parse_tuple failed %d\n", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001340 return ret;
1341}
Dominik Brodowski2f3061e2008-08-31 15:50:33 +02001342EXPORT_SYMBOL(pcmcia_parse_tuple);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001343
1344/*======================================================================
1345
1346 This is used internally by Card Services to look up CIS stuff.
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001347
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348======================================================================*/
1349
1350int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function, cisdata_t code, void *parse)
1351{
1352 tuple_t tuple;
1353 cisdata_t *buf;
1354 int ret;
1355
1356 buf = kmalloc(256, GFP_KERNEL);
Dominik Brodowski11683862008-08-03 10:22:47 +02001357 if (buf == NULL) {
1358 dev_printk(KERN_WARNING, &s->dev, "no memory to read tuple\n");
1359 return -ENOMEM;
1360 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001361 tuple.DesiredTuple = code;
Dominik Brodowski84897fc2009-10-18 23:51:09 +02001362 tuple.Attributes = 0;
1363 if (function == BIND_FN_ALL)
1364 tuple.Attributes = TUPLE_RETURN_COMMON;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365 ret = pccard_get_first_tuple(s, function, &tuple);
Dominik Brodowski4c89e882008-08-03 10:07:45 +02001366 if (ret != 0)
1367 goto done;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001368 tuple.TupleData = buf;
1369 tuple.TupleOffset = 0;
1370 tuple.TupleDataMax = 255;
1371 ret = pccard_get_tuple_data(s, &tuple);
Dominik Brodowski4c89e882008-08-03 10:07:45 +02001372 if (ret != 0)
1373 goto done;
Dominik Brodowski2f3061e2008-08-31 15:50:33 +02001374 ret = pcmcia_parse_tuple(&tuple, parse);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001375done:
1376 kfree(buf);
1377 return ret;
1378}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379
Dominik Brodowski91284222009-10-18 23:32:33 +02001380
1381/**
1382 * pccard_loop_tuple() - loop over tuples in the CIS
1383 * @s: the struct pcmcia_socket where the card is inserted
1384 * @function: the device function we loop for
1385 * @code: which CIS code shall we look for?
1386 * @parse: buffer where the tuple shall be parsed (or NULL, if no parse)
1387 * @priv_data: private data to be passed to the loop_tuple function.
1388 * @loop_tuple: function to call for each CIS entry of type @function. IT
1389 * gets passed the raw tuple, the paresed tuple (if @parse is
1390 * set) and @priv_data.
1391 *
1392 * pccard_loop_tuple() loops over all CIS entries of type @function, and
1393 * calls the @loop_tuple function for each entry. If the call to @loop_tuple
1394 * returns 0, the loop exits. Returns 0 on success or errorcode otherwise.
1395 */
1396int pccard_loop_tuple(struct pcmcia_socket *s, unsigned int function,
1397 cisdata_t code, cisparse_t *parse, void *priv_data,
1398 int (*loop_tuple) (tuple_t *tuple,
1399 cisparse_t *parse,
1400 void *priv_data))
1401{
1402 tuple_t tuple;
1403 cisdata_t *buf;
1404 int ret;
1405
1406 buf = kzalloc(256, GFP_KERNEL);
1407 if (buf == NULL) {
1408 dev_printk(KERN_WARNING, &s->dev, "no memory to read tuple\n");
1409 return -ENOMEM;
1410 }
1411
1412 tuple.TupleData = buf;
1413 tuple.TupleDataMax = 255;
1414 tuple.TupleOffset = 0;
1415 tuple.DesiredTuple = code;
1416 tuple.Attributes = 0;
1417
1418 ret = pccard_get_first_tuple(s, function, &tuple);
1419 while (!ret) {
1420 if (pccard_get_tuple_data(s, &tuple))
1421 goto next_entry;
1422
1423 if (parse)
1424 if (pcmcia_parse_tuple(&tuple, parse))
1425 goto next_entry;
1426
1427 ret = loop_tuple(&tuple, parse, priv_data);
1428 if (!ret)
1429 break;
1430
1431next_entry:
1432 ret = pccard_get_next_tuple(s, function, &tuple);
1433 }
1434
1435 kfree(buf);
1436 return ret;
1437}
Dominik Brodowski91284222009-10-18 23:32:33 +02001438
1439
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001440/**
1441 * pccard_validate_cis() - check whether card has a sensible CIS
1442 * @s: the struct pcmcia_socket we are to check
1443 * @info: returns the number of tuples in the (valid) CIS, or 0
1444 *
1445 * This tries to determine if a card has a sensible CIS. In @info, it
1446 * returns the number of tuples in the CIS, or 0 if the CIS looks bad. The
1447 * checks include making sure several critical tuples are present and
1448 * valid; seeing if the total number of tuples is reasonable; and
1449 * looking for tuples that use reserved codes.
1450 *
1451 * The function returns 0 on success.
1452 */
Dominik Brodowski84897fc2009-10-18 23:51:09 +02001453int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001454{
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001455 tuple_t *tuple;
1456 cisparse_t *p;
1457 unsigned int count = 0;
1458 int ret, reserved, dev_ok = 0, ident_ok = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001460 if (!s)
1461 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001463 /* We do not want to validate the CIS cache... */
1464 destroy_cis_cache(s);
Dominik Brodowski904e3772010-01-02 12:28:04 +01001465
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001466 tuple = kmalloc(sizeof(*tuple), GFP_KERNEL);
1467 if (tuple == NULL) {
1468 dev_warn(&s->dev, "no memory to validate CIS\n");
1469 return -ENOMEM;
1470 }
1471 p = kmalloc(sizeof(*p), GFP_KERNEL);
1472 if (p == NULL) {
1473 kfree(tuple);
1474 dev_warn(&s->dev, "no memory to validate CIS\n");
1475 return -ENOMEM;
1476 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001478 count = reserved = 0;
1479 tuple->DesiredTuple = RETURN_FIRST_TUPLE;
1480 tuple->Attributes = TUPLE_RETURN_COMMON;
1481 ret = pccard_get_first_tuple(s, BIND_FN_ALL, tuple);
Dominik Brodowski4c89e882008-08-03 10:07:45 +02001482 if (ret != 0)
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001483 goto done;
1484
1485 /* First tuple should be DEVICE; we should really have either that
1486 or a CFTABLE_ENTRY of some sort */
1487 if ((tuple->TupleCode == CISTPL_DEVICE) ||
1488 (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_CFTABLE_ENTRY, p)) ||
1489 (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_CFTABLE_ENTRY_CB, p)))
1490 dev_ok++;
1491
1492 /* All cards should have a MANFID tuple, and/or a VERS_1 or VERS_2
1493 tuple, for card identification. Certain old D-Link and Linksys
1494 cards have only a broken VERS_2 tuple; hence the bogus test. */
1495 if ((pccard_read_tuple(s, BIND_FN_ALL, CISTPL_MANFID, p) == 0) ||
1496 (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_VERS_1, p) == 0) ||
1497 (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_VERS_2, p) != -ENOSPC))
1498 ident_ok++;
1499
1500 if (!dev_ok && !ident_ok)
1501 goto done;
1502
1503 for (count = 1; count < MAX_TUPLES; count++) {
1504 ret = pccard_get_next_tuple(s, BIND_FN_ALL, tuple);
1505 if (ret != 0)
1506 break;
1507 if (((tuple->TupleCode > 0x23) && (tuple->TupleCode < 0x40)) ||
1508 ((tuple->TupleCode > 0x47) && (tuple->TupleCode < 0x80)) ||
1509 ((tuple->TupleCode > 0x90) && (tuple->TupleCode < 0xff)))
1510 reserved++;
1511 }
1512 if ((count == MAX_TUPLES) || (reserved > 5) ||
1513 ((!dev_ok || !ident_ok) && (count > 10)))
1514 count = 0;
1515
1516 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001517
1518done:
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001519 /* invalidate CIS cache on failure */
1520 if (!dev_ok || !ident_ok || !count) {
1521 destroy_cis_cache(s);
1522 ret = -EIO;
1523 }
Dominik Brodowski904e3772010-01-02 12:28:04 +01001524
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001525 if (info)
1526 *info = count;
1527 kfree(tuple);
1528 kfree(p);
1529 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530}
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001531
1532
1533#define to_socket(_dev) container_of(_dev, struct pcmcia_socket, dev)
1534
1535static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf,
1536 loff_t off, size_t count)
1537{
1538 tuple_t tuple;
1539 int status, i;
1540 loff_t pointer = 0;
1541 ssize_t ret = 0;
1542 u_char *tuplebuffer;
1543 u_char *tempbuffer;
1544
1545 tuplebuffer = kmalloc(sizeof(u_char) * 256, GFP_KERNEL);
1546 if (!tuplebuffer)
1547 return -ENOMEM;
1548
1549 tempbuffer = kmalloc(sizeof(u_char) * 258, GFP_KERNEL);
1550 if (!tempbuffer) {
1551 ret = -ENOMEM;
1552 goto free_tuple;
1553 }
1554
1555 memset(&tuple, 0, sizeof(tuple_t));
1556
1557 tuple.Attributes = TUPLE_RETURN_LINK | TUPLE_RETURN_COMMON;
1558 tuple.DesiredTuple = RETURN_FIRST_TUPLE;
1559 tuple.TupleOffset = 0;
1560
1561 status = pccard_get_first_tuple(s, BIND_FN_ALL, &tuple);
1562 while (!status) {
1563 tuple.TupleData = tuplebuffer;
1564 tuple.TupleDataMax = 255;
1565 memset(tuplebuffer, 0, sizeof(u_char) * 255);
1566
1567 status = pccard_get_tuple_data(s, &tuple);
1568 if (status)
1569 break;
1570
1571 if (off < (pointer + 2 + tuple.TupleDataLen)) {
1572 tempbuffer[0] = tuple.TupleCode & 0xff;
1573 tempbuffer[1] = tuple.TupleLink & 0xff;
1574 for (i = 0; i < tuple.TupleDataLen; i++)
1575 tempbuffer[i + 2] = tuplebuffer[i] & 0xff;
1576
1577 for (i = 0; i < (2 + tuple.TupleDataLen); i++) {
1578 if (((i + pointer) >= off) &&
1579 (i + pointer) < (off + count)) {
1580 buf[ret] = tempbuffer[i];
1581 ret++;
1582 }
1583 }
1584 }
1585
1586 pointer += 2 + tuple.TupleDataLen;
1587
1588 if (pointer >= (off + count))
1589 break;
1590
1591 if (tuple.TupleCode == CISTPL_END)
1592 break;
1593 status = pccard_get_next_tuple(s, BIND_FN_ALL, &tuple);
1594 }
1595
1596 kfree(tempbuffer);
1597 free_tuple:
1598 kfree(tuplebuffer);
1599
1600 return ret;
1601}
1602
1603
1604static ssize_t pccard_show_cis(struct kobject *kobj,
1605 struct bin_attribute *bin_attr,
1606 char *buf, loff_t off, size_t count)
1607{
1608 unsigned int size = 0x200;
1609
1610 if (off >= size)
1611 count = 0;
1612 else {
1613 struct pcmcia_socket *s;
1614 unsigned int chains;
1615
1616 if (off + count > size)
1617 count = size - off;
1618
1619 s = to_socket(container_of(kobj, struct device, kobj));
1620
1621 if (!(s->state & SOCKET_PRESENT))
1622 return -ENODEV;
1623 if (pccard_validate_cis(s, &chains))
1624 return -EIO;
1625 if (!chains)
1626 return -ENODATA;
1627
1628 count = pccard_extract_cis(s, buf, off, count);
1629 }
1630
1631 return count;
1632}
1633
1634
1635static ssize_t pccard_store_cis(struct kobject *kobj,
1636 struct bin_attribute *bin_attr,
1637 char *buf, loff_t off, size_t count)
1638{
1639 struct pcmcia_socket *s;
1640 int error;
1641
1642 s = to_socket(container_of(kobj, struct device, kobj));
1643
1644 if (off)
1645 return -EINVAL;
1646
1647 if (count >= CISTPL_MAX_CIS_SIZE)
1648 return -EINVAL;
1649
1650 if (!(s->state & SOCKET_PRESENT))
1651 return -ENODEV;
1652
1653 error = pcmcia_replace_cis(s, buf, count);
1654 if (error)
1655 return -EIO;
1656
1657 mutex_lock(&s->skt_mutex);
1658 if ((s->callback) && (s->state & SOCKET_PRESENT) &&
1659 !(s->state & SOCKET_CARDBUS)) {
1660 if (try_module_get(s->callback->owner)) {
1661 s->callback->requery(s, 1);
1662 module_put(s->callback->owner);
1663 }
1664 }
1665 mutex_unlock(&s->skt_mutex);
1666
1667 return count;
1668}
1669
1670
1671struct bin_attribute pccard_cis_attr = {
1672 .attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR },
1673 .size = 0x200,
1674 .read = pccard_show_cis,
1675 .write = pccard_store_cis,
1676};