blob: 39ae542d9d23bb704f595a7adf6f2a2674f26fbc [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) {
Joe Perchesf2e6cf72014-10-10 09:12:47 -070097 dev_notice(&s->dev, "cs: unable to map card memory!\n");
Dominik Brodowski2e5a3e72005-07-28 01:07:23 -070098 return NULL;
99 }
100 s->cis_virt = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 }
Dominik Brodowski2ad0a0a2005-06-27 16:28:58 -0700102
Dominik Brodowski2e5a3e72005-07-28 01:07:23 -0700103 if (!(s->features & SS_CAP_STATIC_MAP) && (!s->cis_virt))
104 s->cis_virt = ioremap(mem->res->start, s->map_size);
105
106 mem->card_start = card_offset;
107 mem->flags = flags;
108
109 ret = s->ops->set_mem_map(s, mem);
110 if (ret) {
111 iounmap(s->cis_virt);
112 s->cis_virt = NULL;
113 return NULL;
114 }
115
116 if (s->features & SS_CAP_STATIC_MAP) {
117 if (s->cis_virt)
118 iounmap(s->cis_virt);
119 s->cis_virt = ioremap(mem->static_start, s->map_size);
120 }
121
122 return s->cis_virt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123}
124
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125
126/* Bits in attr field */
127#define IS_ATTR 1
128#define IS_INDIRECT 8
129
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100130/**
131 * pcmcia_read_cis_mem() - low-level function to read CIS memory
Dominik Brodowski059f6672010-03-30 18:07:50 +0200132 *
133 * must be called with ops_mutex held
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100134 */
Dominik Brodowskie6ea0b9e2005-06-27 16:28:52 -0700135int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 u_int len, void *ptr)
137{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100138 void __iomem *sys, *end;
139 unsigned char *buf = ptr;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100140
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100141 dev_dbg(&s->dev, "pcmcia_read_cis_mem(%d, %#x, %u)\n", attr, addr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100143 if (attr & IS_INDIRECT) {
144 /* Indirect accesses use a bunch of special registers at fixed
145 locations in common memory */
146 u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN;
147 if (attr & IS_ATTR) {
148 addr *= 2;
149 flags = ICTRL0_AUTOINC;
150 }
151
152 sys = set_cis_map(s, 0, MAP_ACTIVE |
153 ((cis_width) ? MAP_16BIT : 0));
154 if (!sys) {
155 dev_dbg(&s->dev, "could not map memory\n");
156 memset(ptr, 0xff, len);
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100157 return -1;
158 }
159
160 writeb(flags, sys+CISREG_ICTRL0);
161 writeb(addr & 0xff, sys+CISREG_IADDR0);
162 writeb((addr>>8) & 0xff, sys+CISREG_IADDR1);
163 writeb((addr>>16) & 0xff, sys+CISREG_IADDR2);
164 writeb((addr>>24) & 0xff, sys+CISREG_IADDR3);
165 for ( ; len > 0; len--, buf++)
166 *buf = readb(sys+CISREG_IDATA0);
167 } else {
168 u_int inc = 1, card_offset, flags;
169
Alan Coxb38a4bd2014-12-10 15:06:10 +0000170 if (addr > CISTPL_MAX_CIS_SIZE) {
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100171 dev_dbg(&s->dev,
172 "attempt to read CIS mem at addr %#x", addr);
Alan Coxb38a4bd2014-12-10 15:06:10 +0000173 memset(ptr, 0xff, len);
174 return -1;
175 }
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100176
177 flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
178 if (attr) {
179 flags |= MAP_ATTRIB;
180 inc++;
181 addr *= 2;
182 }
183
184 card_offset = addr & ~(s->map_size-1);
185 while (len) {
186 sys = set_cis_map(s, card_offset, flags);
187 if (!sys) {
188 dev_dbg(&s->dev, "could not map memory\n");
189 memset(ptr, 0xff, len);
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100190 return -1;
191 }
192 end = sys + s->map_size;
193 sys = sys + (addr & (s->map_size-1));
194 for ( ; len > 0; len--, buf++, sys += inc) {
195 if (sys == end)
196 break;
197 *buf = readb(sys);
198 }
199 card_offset += s->map_size;
200 addr = 0;
201 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 }
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100203 dev_dbg(&s->dev, " %#2.2x %#2.2x %#2.2x %#2.2x ...\n",
204 *(u_char *)(ptr+0), *(u_char *)(ptr+1),
205 *(u_char *)(ptr+2), *(u_char *)(ptr+3));
206 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207}
Dominik Brodowski1a8d4662005-06-27 16:28:53 -0700208
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100210/**
211 * pcmcia_write_cis_mem() - low-level function to write CIS memory
212 *
Dominik Brodowski059f6672010-03-30 18:07:50 +0200213 * Probably only useful for writing one-byte registers. Must be called
214 * with ops_mutex held.
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100215 */
Dominik Brodowski1d5cc192010-07-24 12:23:21 +0200216int pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 u_int len, void *ptr)
218{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100219 void __iomem *sys, *end;
220 unsigned char *buf = ptr;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100221
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100222 dev_dbg(&s->dev,
223 "pcmcia_write_cis_mem(%d, %#x, %u)\n", attr, addr, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100225 if (attr & IS_INDIRECT) {
226 /* Indirect accesses use a bunch of special registers at fixed
227 locations in common memory */
228 u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN;
229 if (attr & IS_ATTR) {
230 addr *= 2;
231 flags = ICTRL0_AUTOINC;
232 }
233
234 sys = set_cis_map(s, 0, MAP_ACTIVE |
235 ((cis_width) ? MAP_16BIT : 0));
236 if (!sys) {
237 dev_dbg(&s->dev, "could not map memory\n");
Dominik Brodowski1d5cc192010-07-24 12:23:21 +0200238 return -EINVAL;
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100239 }
240
241 writeb(flags, sys+CISREG_ICTRL0);
242 writeb(addr & 0xff, sys+CISREG_IADDR0);
243 writeb((addr>>8) & 0xff, sys+CISREG_IADDR1);
244 writeb((addr>>16) & 0xff, sys+CISREG_IADDR2);
245 writeb((addr>>24) & 0xff, sys+CISREG_IADDR3);
246 for ( ; len > 0; len--, buf++)
247 writeb(*buf, sys+CISREG_IDATA0);
248 } else {
249 u_int inc = 1, card_offset, flags;
250
251 flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
252 if (attr & IS_ATTR) {
253 flags |= MAP_ATTRIB;
254 inc++;
255 addr *= 2;
256 }
257
258 card_offset = addr & ~(s->map_size-1);
259 while (len) {
260 sys = set_cis_map(s, card_offset, flags);
261 if (!sys) {
262 dev_dbg(&s->dev, "could not map memory\n");
Dominik Brodowski1d5cc192010-07-24 12:23:21 +0200263 return -EINVAL;
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100264 }
265
266 end = sys + s->map_size;
267 sys = sys + (addr & (s->map_size-1));
268 for ( ; len > 0; len--, buf++, sys += inc) {
269 if (sys == end)
270 break;
271 writeb(*buf, sys);
272 }
273 card_offset += s->map_size;
274 addr = 0;
275 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 }
Dominik Brodowski1d5cc192010-07-24 12:23:21 +0200277 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278}
Dominik Brodowski1a8d4662005-06-27 16:28:53 -0700279
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100281/**
282 * read_cis_cache() - read CIS memory or its associated cache
283 *
284 * This is a wrapper around read_cis_mem, with the same interface,
285 * but which caches information, for cards whose CIS may not be
286 * readable all the time.
287 */
Dominik Brodowskid7005182010-02-17 18:01:31 +0100288static int read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr,
289 size_t len, void *ptr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290{
Dominik Brodowski57197b92010-01-02 17:27:33 +0100291 struct cis_cache_entry *cis;
Dominik Brodowskid7005182010-02-17 18:01:31 +0100292 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
Dominik Brodowski57197b92010-01-02 17:27:33 +0100294 if (s->state & SOCKET_CARDBUS)
Dominik Brodowskid7005182010-02-17 18:01:31 +0100295 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
Dominik Brodowski8680c4b2010-01-12 22:05:36 +0100297 mutex_lock(&s->ops_mutex);
Dominik Brodowski57197b92010-01-02 17:27:33 +0100298 if (s->fake_cis) {
299 if (s->fake_cis_len >= addr+len)
300 memcpy(ptr, s->fake_cis+addr, len);
Dominik Brodowskid7005182010-02-17 18:01:31 +0100301 else {
Dominik Brodowski57197b92010-01-02 17:27:33 +0100302 memset(ptr, 0xff, len);
Dominik Brodowskid7005182010-02-17 18:01:31 +0100303 ret = -EINVAL;
304 }
Dominik Brodowski8680c4b2010-01-12 22:05:36 +0100305 mutex_unlock(&s->ops_mutex);
Dominik Brodowskid7005182010-02-17 18:01:31 +0100306 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
Dominik Brodowski57197b92010-01-02 17:27:33 +0100309 list_for_each_entry(cis, &s->cis_cache, node) {
310 if (cis->addr == addr && cis->len == len && cis->attr == attr) {
311 memcpy(ptr, cis->cache, len);
Dominik Brodowski8680c4b2010-01-12 22:05:36 +0100312 mutex_unlock(&s->ops_mutex);
Dominik Brodowskid7005182010-02-17 18:01:31 +0100313 return 0;
Dominik Brodowski57197b92010-01-02 17:27:33 +0100314 }
315 }
316
Dominik Brodowskie6ea0b9e2005-06-27 16:28:52 -0700317 ret = pcmcia_read_cis_mem(s, attr, addr, len, ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
319 if (ret == 0) {
320 /* Copy data into the cache */
321 cis = kmalloc(sizeof(struct cis_cache_entry) + len, GFP_KERNEL);
322 if (cis) {
323 cis->addr = addr;
324 cis->len = len;
325 cis->attr = attr;
326 memcpy(cis->cache, ptr, len);
327 list_add(&cis->node, &s->cis_cache);
328 }
329 }
Dominik Brodowski059f6672010-03-30 18:07:50 +0200330 mutex_unlock(&s->ops_mutex);
331
Dominik Brodowskid7005182010-02-17 18:01:31 +0100332 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333}
334
335static void
336remove_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, u_int len)
337{
338 struct cis_cache_entry *cis;
339
Dominik Brodowski8680c4b2010-01-12 22:05:36 +0100340 mutex_lock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 list_for_each_entry(cis, &s->cis_cache, node)
342 if (cis->addr == addr && cis->len == len && cis->attr == attr) {
343 list_del(&cis->node);
344 kfree(cis);
345 break;
346 }
Dominik Brodowski8680c4b2010-01-12 22:05:36 +0100347 mutex_unlock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348}
349
Dominik Brodowski904e3772010-01-02 12:28:04 +0100350/**
351 * destroy_cis_cache() - destroy the CIS cache
352 * @s: pcmcia_socket for which CIS cache shall be destroyed
353 *
Dominik Brodowski8680c4b2010-01-12 22:05:36 +0100354 * This destroys the CIS cache but keeps any fake CIS alive. Must be
355 * called with ops_mutex held.
Dominik Brodowski904e3772010-01-02 12:28:04 +0100356 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357void destroy_cis_cache(struct pcmcia_socket *s)
358{
359 struct list_head *l, *n;
Dominik Brodowski904e3772010-01-02 12:28:04 +0100360 struct cis_cache_entry *cis;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361
362 list_for_each_safe(l, n, &s->cis_cache) {
Dominik Brodowski904e3772010-01-02 12:28:04 +0100363 cis = list_entry(l, struct cis_cache_entry, node);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 list_del(&cis->node);
365 kfree(cis);
366 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100369/**
370 * verify_cis_cache() - does the CIS match what is in the CIS cache?
371 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372int verify_cis_cache(struct pcmcia_socket *s)
373{
374 struct cis_cache_entry *cis;
375 char *buf;
Dominik Brodowskid7005182010-02-17 18:01:31 +0100376 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377
Dominik Brodowski57197b92010-01-02 17:27:33 +0100378 if (s->state & SOCKET_CARDBUS)
379 return -EINVAL;
380
Linus Torvalds1da177e2005-04-16 15:20:36 -0700381 buf = kmalloc(256, GFP_KERNEL);
Dominik Brodowskie6895972008-11-02 19:55:45 +0100382 if (buf == NULL) {
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700383 dev_warn(&s->dev, "no memory for verifying CIS\n");
Dominik Brodowski11683862008-08-03 10:22:47 +0200384 return -ENOMEM;
Dominik Brodowskie6895972008-11-02 19:55:45 +0100385 }
Dominik Brodowski059f6672010-03-30 18:07:50 +0200386 mutex_lock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387 list_for_each_entry(cis, &s->cis_cache, node) {
388 int len = cis->len;
389
390 if (len > 256)
391 len = 256;
Dominik Brodowski57197b92010-01-02 17:27:33 +0100392
Dominik Brodowskid7005182010-02-17 18:01:31 +0100393 ret = pcmcia_read_cis_mem(s, cis->attr, cis->addr, len, buf);
394 if (ret || memcmp(buf, cis->cache, len) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 kfree(buf);
Dominik Brodowski059f6672010-03-30 18:07:50 +0200396 mutex_unlock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 return -1;
398 }
399 }
400 kfree(buf);
Dominik Brodowski059f6672010-03-30 18:07:50 +0200401 mutex_unlock(&s->ops_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 return 0;
403}
404
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100405/**
406 * pcmcia_replace_cis() - use a replacement CIS instead of the card's CIS
407 *
408 * For really bad cards, we provide a facility for uploading a
409 * replacement CIS.
410 */
Dominik Brodowski53efec92008-07-28 19:44:05 +0200411int pcmcia_replace_cis(struct pcmcia_socket *s,
412 const u8 *data, const size_t len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413{
Dominik Brodowski11683862008-08-03 10:22:47 +0200414 if (len > CISTPL_MAX_CIS_SIZE) {
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700415 dev_warn(&s->dev, "replacement CIS too big\n");
Dominik Brodowski11683862008-08-03 10:22:47 +0200416 return -EINVAL;
417 }
Dominik Brodowski8680c4b2010-01-12 22:05:36 +0100418 mutex_lock(&s->ops_mutex);
Dominik Brodowski11683862008-08-03 10:22:47 +0200419 kfree(s->fake_cis);
420 s->fake_cis = kmalloc(len, GFP_KERNEL);
421 if (s->fake_cis == NULL) {
Joe Perchesf2e6cf72014-10-10 09:12:47 -0700422 dev_warn(&s->dev, "no memory to replace CIS\n");
Dominik Brodowski8680c4b2010-01-12 22:05:36 +0100423 mutex_unlock(&s->ops_mutex);
Dominik Brodowski11683862008-08-03 10:22:47 +0200424 return -ENOMEM;
425 }
426 s->fake_cis_len = len;
427 memcpy(s->fake_cis, data, len);
Dominik Brodowskid7005182010-02-17 18:01:31 +0100428 dev_info(&s->dev, "Using replacement CIS\n");
Dominik Brodowski8680c4b2010-01-12 22:05:36 +0100429 mutex_unlock(&s->ops_mutex);
Dominik Brodowski11683862008-08-03 10:22:47 +0200430 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700431}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100433/* The high-level CIS tuple services */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434
Himangi Saraogi820dc842014-08-06 17:59:48 +0530435struct tuple_flags {
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100436 u_int link_space:4;
437 u_int has_link:1;
438 u_int mfc_fn:3;
439 u_int space:4;
Himangi Saraogi820dc842014-08-06 17:59:48 +0530440};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441
Himangi Saraogi820dc842014-08-06 17:59:48 +0530442#define LINK_SPACE(f) (((struct tuple_flags *)(&(f)))->link_space)
443#define HAS_LINK(f) (((struct tuple_flags *)(&(f)))->has_link)
444#define MFC_FN(f) (((struct tuple_flags *)(&(f)))->mfc_fn)
445#define SPACE(f) (((struct tuple_flags *)(&(f)))->space)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100447int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function,
448 tuple_t *tuple)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100450 if (!s)
451 return -EINVAL;
Dominik Brodowski57197b92010-01-02 17:27:33 +0100452
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100453 if (!(s->state & SOCKET_PRESENT) || (s->state & SOCKET_CARDBUS))
454 return -ENODEV;
455 tuple->TupleLink = tuple->Flags = 0;
Dominik Brodowski57197b92010-01-02 17:27:33 +0100456
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100457 /* Assume presence of a LONGLINK_C to address 0 */
458 tuple->CISOffset = tuple->LinkOffset = 0;
459 SPACE(tuple->Flags) = HAS_LINK(tuple->Flags) = 1;
Dominik Brodowski57197b92010-01-02 17:27:33 +0100460
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100461 if ((s->functions > 1) && !(tuple->Attributes & TUPLE_RETURN_COMMON)) {
462 cisdata_t req = tuple->DesiredTuple;
463 tuple->DesiredTuple = CISTPL_LONGLINK_MFC;
464 if (pccard_get_next_tuple(s, function, tuple) == 0) {
465 tuple->DesiredTuple = CISTPL_LINKTARGET;
466 if (pccard_get_next_tuple(s, function, tuple) != 0)
467 return -ENOSPC;
468 } else
469 tuple->CISOffset = tuple->TupleLink = 0;
470 tuple->DesiredTuple = req;
471 }
472 return pccard_get_next_tuple(s, function, tuple);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474
475static int follow_link(struct pcmcia_socket *s, tuple_t *tuple)
476{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100477 u_char link[5];
478 u_int ofs;
479 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100481 if (MFC_FN(tuple->Flags)) {
482 /* Get indirect link from the MFC tuple */
483 ret = read_cis_cache(s, LINK_SPACE(tuple->Flags),
484 tuple->LinkOffset, 5, link);
485 if (ret)
486 return -1;
487 ofs = get_unaligned_le32(link + 1);
488 SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR);
489 /* Move to the next indirect link */
490 tuple->LinkOffset += 5;
491 MFC_FN(tuple->Flags)--;
492 } else if (HAS_LINK(tuple->Flags)) {
493 ofs = tuple->LinkOffset;
494 SPACE(tuple->Flags) = LINK_SPACE(tuple->Flags);
495 HAS_LINK(tuple->Flags) = 0;
496 } else
Dominik Brodowskid7005182010-02-17 18:01:31 +0100497 return -1;
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100498
499 if (SPACE(tuple->Flags)) {
500 /* This is ugly, but a common CIS error is to code the long
501 link offset incorrectly, so we check the right spot... */
502 ret = read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link);
503 if (ret)
504 return -1;
505 if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) &&
506 (strncmp(link+2, "CIS", 3) == 0))
507 return ofs;
508 remove_cis_cache(s, SPACE(tuple->Flags), ofs, 5);
509 /* Then, we try the wrong spot... */
510 ofs = ofs >> 1;
511 }
Dominik Brodowskid7005182010-02-17 18:01:31 +0100512 ret = read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link);
513 if (ret)
514 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) &&
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100516 (strncmp(link+2, "CIS", 3) == 0))
517 return ofs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 remove_cis_cache(s, SPACE(tuple->Flags), ofs, 5);
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100519 return -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520}
521
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100522int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function,
523 tuple_t *tuple)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100525 u_char link[2], tmp;
526 int ofs, i, attr;
527 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100529 if (!s)
530 return -EINVAL;
531 if (!(s->state & SOCKET_PRESENT) || (s->state & SOCKET_CARDBUS))
532 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100534 link[1] = tuple->TupleLink;
535 ofs = tuple->CISOffset + tuple->TupleLink;
536 attr = SPACE(tuple->Flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100538 for (i = 0; i < MAX_TUPLES; i++) {
539 if (link[1] == 0xff)
540 link[0] = CISTPL_END;
541 else {
542 ret = read_cis_cache(s, attr, ofs, 2, link);
543 if (ret)
544 return -1;
545 if (link[0] == CISTPL_NULL) {
546 ofs++;
547 continue;
548 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 }
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100550
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100551 /* End of chain? Follow long link if possible */
552 if (link[0] == CISTPL_END) {
553 ofs = follow_link(s, tuple);
554 if (ofs < 0)
555 return -ENOSPC;
556 attr = SPACE(tuple->Flags);
557 ret = read_cis_cache(s, attr, ofs, 2, link);
558 if (ret)
559 return -1;
560 }
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100561
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100562 /* Is this a link tuple? Make a note of it */
563 if ((link[0] == CISTPL_LONGLINK_A) ||
564 (link[0] == CISTPL_LONGLINK_C) ||
565 (link[0] == CISTPL_LONGLINK_MFC) ||
566 (link[0] == CISTPL_LINKTARGET) ||
567 (link[0] == CISTPL_INDIRECT) ||
568 (link[0] == CISTPL_NO_LINK)) {
569 switch (link[0]) {
570 case CISTPL_LONGLINK_A:
571 HAS_LINK(tuple->Flags) = 1;
572 LINK_SPACE(tuple->Flags) = attr | IS_ATTR;
573 ret = read_cis_cache(s, attr, ofs+2, 4,
574 &tuple->LinkOffset);
575 if (ret)
576 return -1;
577 break;
578 case CISTPL_LONGLINK_C:
579 HAS_LINK(tuple->Flags) = 1;
580 LINK_SPACE(tuple->Flags) = attr & ~IS_ATTR;
581 ret = read_cis_cache(s, attr, ofs+2, 4,
582 &tuple->LinkOffset);
583 if (ret)
584 return -1;
585 break;
586 case CISTPL_INDIRECT:
587 HAS_LINK(tuple->Flags) = 1;
588 LINK_SPACE(tuple->Flags) = IS_ATTR |
589 IS_INDIRECT;
590 tuple->LinkOffset = 0;
591 break;
592 case CISTPL_LONGLINK_MFC:
593 tuple->LinkOffset = ofs + 3;
594 LINK_SPACE(tuple->Flags) = attr;
595 if (function == BIND_FN_ALL) {
596 /* Follow all the MFC links */
597 ret = read_cis_cache(s, attr, ofs+2,
598 1, &tmp);
599 if (ret)
600 return -1;
601 MFC_FN(tuple->Flags) = tmp;
602 } else {
603 /* Follow exactly one of the links */
604 MFC_FN(tuple->Flags) = 1;
605 tuple->LinkOffset += function * 5;
606 }
607 break;
608 case CISTPL_NO_LINK:
609 HAS_LINK(tuple->Flags) = 0;
610 break;
611 }
612 if ((tuple->Attributes & TUPLE_RETURN_LINK) &&
613 (tuple->DesiredTuple == RETURN_FIRST_TUPLE))
614 break;
615 } else
616 if (tuple->DesiredTuple == RETURN_FIRST_TUPLE)
617 break;
618
619 if (link[0] == tuple->DesiredTuple)
620 break;
621 ofs += link[1] + 2;
622 }
623 if (i == MAX_TUPLES) {
624 dev_dbg(&s->dev, "cs: overrun in pcmcia_get_next_tuple\n");
625 return -ENOSPC;
626 }
627
628 tuple->TupleCode = link[0];
629 tuple->TupleLink = link[1];
630 tuple->CISOffset = ofs + 2;
631 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700633
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple)
635{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100636 u_int len;
637 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700638
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100639 if (!s)
640 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100642 if (tuple->TupleLink < tuple->TupleOffset)
643 return -ENOSPC;
644 len = tuple->TupleLink - tuple->TupleOffset;
645 tuple->TupleDataLen = tuple->TupleLink;
646 if (len == 0)
647 return 0;
648 ret = read_cis_cache(s, SPACE(tuple->Flags),
649 tuple->CISOffset + tuple->TupleOffset,
650 min(len, (u_int) tuple->TupleDataMax),
651 tuple->TupleData);
652 if (ret)
653 return -1;
Dominik Brodowski4c89e882008-08-03 10:07:45 +0200654 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656
657
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100658/* Parsing routines for individual tuples */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
660static int parse_device(tuple_t *tuple, cistpl_device_t *device)
661{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100662 int i;
663 u_char scale;
664 u_char *p, *q;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100666 p = (u_char *)tuple->TupleData;
667 q = p + tuple->TupleDataLen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100669 device->ndev = 0;
670 for (i = 0; i < CISTPL_MAX_DEVICES; i++) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100671
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100672 if (*p == 0xff)
673 break;
674 device->dev[i].type = (*p >> 4);
675 device->dev[i].wp = (*p & 0x08) ? 1 : 0;
676 switch (*p & 0x07) {
677 case 0:
678 device->dev[i].speed = 0;
679 break;
680 case 1:
681 device->dev[i].speed = 250;
682 break;
683 case 2:
684 device->dev[i].speed = 200;
685 break;
686 case 3:
687 device->dev[i].speed = 150;
688 break;
689 case 4:
690 device->dev[i].speed = 100;
691 break;
692 case 7:
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100693 if (++p == q)
694 return -EINVAL;
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100695 device->dev[i].speed = SPEED_CVT(*p);
696 while (*p & 0x80)
697 if (++p == q)
698 return -EINVAL;
699 break;
700 default:
701 return -EINVAL;
702 }
703
704 if (++p == q)
705 return -EINVAL;
706 if (*p == 0xff)
707 break;
708 scale = *p & 7;
709 if (scale == 7)
710 return -EINVAL;
711 device->dev[i].size = ((*p >> 3) + 1) * (512 << (scale*2));
712 device->ndev++;
713 if (++p == q)
714 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715 }
716
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100717 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718}
719
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720
721static int parse_checksum(tuple_t *tuple, cistpl_checksum_t *csum)
722{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100723 u_char *p;
724 if (tuple->TupleDataLen < 5)
725 return -EINVAL;
726 p = (u_char *) tuple->TupleData;
727 csum->addr = tuple->CISOffset + get_unaligned_le16(p) - 2;
728 csum->len = get_unaligned_le16(p + 2);
729 csum->sum = *(p + 4);
730 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731}
732
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733
734static int parse_longlink(tuple_t *tuple, cistpl_longlink_t *link)
735{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100736 if (tuple->TupleDataLen < 4)
737 return -EINVAL;
738 link->addr = get_unaligned_le32(tuple->TupleData);
739 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740}
741
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100743static int parse_longlink_mfc(tuple_t *tuple, cistpl_longlink_mfc_t *link)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100745 u_char *p;
746 int i;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100747
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100748 p = (u_char *)tuple->TupleData;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100749
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100750 link->nfn = *p; p++;
751 if (tuple->TupleDataLen <= link->nfn*5)
752 return -EINVAL;
753 for (i = 0; i < link->nfn; i++) {
754 link->fn[i].space = *p; p++;
755 link->fn[i].addr = get_unaligned_le32(p);
756 p += 4;
757 }
758 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759}
760
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761
762static int parse_strings(u_char *p, u_char *q, int max,
763 char *s, u_char *ofs, u_char *found)
764{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100765 int i, j, ns;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100767 if (p == q)
768 return -EINVAL;
769 ns = 0; j = 0;
770 for (i = 0; i < max; i++) {
771 if (*p == 0xff)
772 break;
773 ofs[i] = j;
774 ns++;
775 for (;;) {
776 s[j++] = (*p == 0xff) ? '\0' : *p;
777 if ((*p == '\0') || (*p == 0xff))
778 break;
779 if (++p == q)
780 return -EINVAL;
781 }
782 if ((*p == 0xff) || (++p == q))
783 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 }
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100785 if (found) {
786 *found = ns;
787 return 0;
788 }
789
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +0200790 return (ns == max) ? 0 : -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791}
792
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793
794static int parse_vers_1(tuple_t *tuple, cistpl_vers_1_t *vers_1)
795{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100796 u_char *p, *q;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100797
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100798 p = (u_char *)tuple->TupleData;
799 q = p + tuple->TupleDataLen;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100800
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100801 vers_1->major = *p; p++;
802 vers_1->minor = *p; p++;
803 if (p >= q)
804 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100806 return parse_strings(p, q, CISTPL_VERS_1_MAX_PROD_STRINGS,
807 vers_1->str, vers_1->ofs, &vers_1->ns);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808}
809
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810
811static int parse_altstr(tuple_t *tuple, cistpl_altstr_t *altstr)
812{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100813 u_char *p, *q;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100814
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100815 p = (u_char *)tuple->TupleData;
816 q = p + tuple->TupleDataLen;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100817
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100818 return parse_strings(p, q, CISTPL_MAX_ALTSTR_STRINGS,
819 altstr->str, altstr->ofs, &altstr->ns);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820}
821
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822
823static int parse_jedec(tuple_t *tuple, cistpl_jedec_t *jedec)
824{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100825 u_char *p, *q;
826 int nid;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100828 p = (u_char *)tuple->TupleData;
829 q = p + tuple->TupleDataLen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100831 for (nid = 0; nid < CISTPL_MAX_DEVICES; nid++) {
832 if (p > q-2)
833 break;
834 jedec->id[nid].mfr = p[0];
835 jedec->id[nid].info = p[1];
836 p += 2;
837 }
838 jedec->nid = nid;
839 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840}
841
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842
843static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m)
844{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100845 if (tuple->TupleDataLen < 4)
846 return -EINVAL;
847 m->manf = get_unaligned_le16(tuple->TupleData);
848 m->card = get_unaligned_le16(tuple->TupleData + 2);
849 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850}
851
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852
853static int parse_funcid(tuple_t *tuple, cistpl_funcid_t *f)
854{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100855 u_char *p;
856 if (tuple->TupleDataLen < 2)
857 return -EINVAL;
858 p = (u_char *)tuple->TupleData;
859 f->func = p[0];
860 f->sysinit = p[1];
861 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862}
863
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864
865static int parse_funce(tuple_t *tuple, cistpl_funce_t *f)
866{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100867 u_char *p;
868 int i;
869 if (tuple->TupleDataLen < 1)
870 return -EINVAL;
871 p = (u_char *)tuple->TupleData;
872 f->type = p[0];
873 for (i = 1; i < tuple->TupleDataLen; i++)
874 f->data[i-1] = p[i];
875 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876}
877
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878
879static int parse_config(tuple_t *tuple, cistpl_config_t *config)
880{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100881 int rasz, rmsz, i;
882 u_char *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100884 p = (u_char *)tuple->TupleData;
885 rasz = *p & 0x03;
886 rmsz = (*p & 0x3c) >> 2;
887 if (tuple->TupleDataLen < rasz+rmsz+4)
888 return -EINVAL;
889 config->last_idx = *(++p);
890 p++;
891 config->base = 0;
892 for (i = 0; i <= rasz; i++)
893 config->base += p[i] << (8*i);
894 p += rasz+1;
895 for (i = 0; i < 4; i++)
896 config->rmask[i] = 0;
897 for (i = 0; i <= rmsz; i++)
898 config->rmask[i>>2] += p[i] << (8*(i%4));
899 config->subtuples = tuple->TupleDataLen - (rasz+rmsz+4);
900 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901}
902
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100903/* The following routines are all used to parse the nightmarish
904 * config table entries.
905 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100907static u_char *parse_power(u_char *p, u_char *q, cistpl_power_t *pwr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100909 int i;
910 u_int scale;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100912 if (p == q)
913 return NULL;
914 pwr->present = *p;
915 pwr->flags = 0;
916 p++;
917 for (i = 0; i < 7; i++)
918 if (pwr->present & (1<<i)) {
919 if (p == q)
920 return NULL;
921 pwr->param[i] = POWER_CVT(*p);
922 scale = POWER_SCALE(*p);
923 while (*p & 0x80) {
924 if (++p == q)
925 return NULL;
926 if ((*p & 0x7f) < 100)
927 pwr->param[i] +=
928 (*p & 0x7f) * scale / 100;
929 else if (*p == 0x7d)
930 pwr->flags |= CISTPL_POWER_HIGHZ_OK;
931 else if (*p == 0x7e)
932 pwr->param[i] = 0;
933 else if (*p == 0x7f)
934 pwr->flags |= CISTPL_POWER_HIGHZ_REQ;
935 else
936 return NULL;
937 }
938 p++;
939 }
940 return p;
941}
942
943
944static u_char *parse_timing(u_char *p, u_char *q, cistpl_timing_t *timing)
945{
946 u_char scale;
947
948 if (p == q)
949 return NULL;
950 scale = *p;
951 if ((scale & 3) != 3) {
Dominik Brodowski9fea84f2009-12-07 22:11:45 +0100952 if (++p == q)
953 return NULL;
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100954 timing->wait = SPEED_CVT(*p);
955 timing->waitscale = exponent[scale & 3];
956 } else
957 timing->wait = 0;
958 scale >>= 2;
959 if ((scale & 7) != 7) {
960 if (++p == q)
961 return NULL;
962 timing->ready = SPEED_CVT(*p);
963 timing->rdyscale = exponent[scale & 7];
964 } else
965 timing->ready = 0;
966 scale >>= 3;
967 if (scale != 7) {
968 if (++p == q)
969 return NULL;
970 timing->reserved = SPEED_CVT(*p);
971 timing->rsvscale = exponent[scale];
972 } else
973 timing->reserved = 0;
974 p++;
975 return p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976}
977
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978
979static u_char *parse_io(u_char *p, u_char *q, cistpl_io_t *io)
980{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100981 int i, j, bsz, lsz;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100983 if (p == q)
984 return NULL;
985 io->flags = *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100987 if (!(*p & 0x80)) {
988 io->nwin = 1;
989 io->win[0].base = 0;
990 io->win[0].len = (1 << (io->flags & CISTPL_IO_LINES_MASK));
991 return p+1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 }
Dominik Brodowski6e83ee02010-03-02 08:57:33 +0100993
994 if (++p == q)
995 return NULL;
996 io->nwin = (*p & 0x0f) + 1;
997 bsz = (*p & 0x30) >> 4;
998 if (bsz == 3)
999 bsz++;
1000 lsz = (*p & 0xc0) >> 6;
1001 if (lsz == 3)
1002 lsz++;
1003 p++;
1004
1005 for (i = 0; i < io->nwin; i++) {
1006 io->win[i].base = 0;
1007 io->win[i].len = 1;
1008 for (j = 0; j < bsz; j++, p++) {
1009 if (p == q)
1010 return NULL;
1011 io->win[i].base += *p << (j*8);
1012 }
1013 for (j = 0; j < lsz; j++, p++) {
1014 if (p == q)
1015 return NULL;
1016 io->win[i].len += *p << (j*8);
1017 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 }
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001019 return p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020}
1021
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022
1023static u_char *parse_mem(u_char *p, u_char *q, cistpl_mem_t *mem)
1024{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001025 int i, j, asz, lsz, has_ha;
1026 u_int len, ca, ha;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001028 if (p == q)
1029 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001031 mem->nwin = (*p & 0x07) + 1;
1032 lsz = (*p & 0x18) >> 3;
1033 asz = (*p & 0x60) >> 5;
1034 has_ha = (*p & 0x80);
1035 if (++p == q)
1036 return NULL;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001037
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001038 for (i = 0; i < mem->nwin; i++) {
1039 len = ca = ha = 0;
1040 for (j = 0; j < lsz; j++, p++) {
1041 if (p == q)
1042 return NULL;
1043 len += *p << (j*8);
1044 }
1045 for (j = 0; j < asz; j++, p++) {
1046 if (p == q)
1047 return NULL;
1048 ca += *p << (j*8);
1049 }
1050 if (has_ha)
1051 for (j = 0; j < asz; j++, p++) {
1052 if (p == q)
1053 return NULL;
1054 ha += *p << (j*8);
1055 }
1056 mem->win[i].len = len << 8;
1057 mem->win[i].card_addr = ca << 8;
1058 mem->win[i].host_addr = ha << 8;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 }
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001060 return p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061}
1062
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063
1064static u_char *parse_irq(u_char *p, u_char *q, cistpl_irq_t *irq)
1065{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001066 if (p == q)
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +02001067 return NULL;
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001068 irq->IRQInfo1 = *p; p++;
1069 if (irq->IRQInfo1 & IRQ_INFO2_VALID) {
1070 if (p+2 > q)
1071 return NULL;
1072 irq->IRQInfo2 = (p[1]<<8) + p[0];
1073 p += 2;
1074 }
1075 return p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076}
1077
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078
1079static int parse_cftable_entry(tuple_t *tuple,
1080 cistpl_cftable_entry_t *entry)
1081{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001082 u_char *p, *q, features;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001084 p = tuple->TupleData;
1085 q = p + tuple->TupleDataLen;
1086 entry->index = *p & 0x3f;
1087 entry->flags = 0;
1088 if (*p & 0x40)
1089 entry->flags |= CISTPL_CFTABLE_DEFAULT;
1090 if (*p & 0x80) {
1091 if (++p == q)
1092 return -EINVAL;
1093 if (*p & 0x10)
1094 entry->flags |= CISTPL_CFTABLE_BVDS;
1095 if (*p & 0x20)
1096 entry->flags |= CISTPL_CFTABLE_WP;
1097 if (*p & 0x40)
1098 entry->flags |= CISTPL_CFTABLE_RDYBSY;
1099 if (*p & 0x80)
1100 entry->flags |= CISTPL_CFTABLE_MWAIT;
1101 entry->interface = *p & 0x0f;
1102 } else
1103 entry->interface = 0;
1104
1105 /* Process optional features */
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +02001106 if (++p == q)
1107 return -EINVAL;
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001108 features = *p; p++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001110 /* Power options */
1111 if ((features & 3) > 0) {
1112 p = parse_power(p, q, &entry->vcc);
1113 if (p == NULL)
1114 return -EINVAL;
1115 } else
1116 entry->vcc.present = 0;
1117 if ((features & 3) > 1) {
1118 p = parse_power(p, q, &entry->vpp1);
1119 if (p == NULL)
1120 return -EINVAL;
1121 } else
1122 entry->vpp1.present = 0;
1123 if ((features & 3) > 2) {
1124 p = parse_power(p, q, &entry->vpp2);
1125 if (p == NULL)
1126 return -EINVAL;
1127 } else
1128 entry->vpp2.present = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001130 /* Timing options */
1131 if (features & 0x04) {
1132 p = parse_timing(p, q, &entry->timing);
1133 if (p == NULL)
1134 return -EINVAL;
1135 } else {
1136 entry->timing.wait = 0;
1137 entry->timing.ready = 0;
1138 entry->timing.reserved = 0;
1139 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001141 /* I/O window options */
1142 if (features & 0x08) {
1143 p = parse_io(p, q, &entry->io);
1144 if (p == NULL)
1145 return -EINVAL;
1146 } else
1147 entry->io.nwin = 0;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001148
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001149 /* Interrupt options */
1150 if (features & 0x10) {
1151 p = parse_irq(p, q, &entry->irq);
1152 if (p == NULL)
1153 return -EINVAL;
1154 } else
1155 entry->irq.IRQInfo1 = 0;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001156
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001157 switch (features & 0x60) {
1158 case 0x00:
1159 entry->mem.nwin = 0;
1160 break;
1161 case 0x20:
1162 entry->mem.nwin = 1;
1163 entry->mem.win[0].len = get_unaligned_le16(p) << 8;
1164 entry->mem.win[0].card_addr = 0;
1165 entry->mem.win[0].host_addr = 0;
1166 p += 2;
1167 if (p > q)
1168 return -EINVAL;
1169 break;
1170 case 0x40:
1171 entry->mem.nwin = 1;
1172 entry->mem.win[0].len = get_unaligned_le16(p) << 8;
1173 entry->mem.win[0].card_addr = get_unaligned_le16(p + 2) << 8;
1174 entry->mem.win[0].host_addr = 0;
1175 p += 4;
1176 if (p > q)
1177 return -EINVAL;
1178 break;
1179 case 0x60:
1180 p = parse_mem(p, q, &entry->mem);
1181 if (p == NULL)
1182 return -EINVAL;
1183 break;
1184 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001186 /* Misc features */
1187 if (features & 0x80) {
1188 if (p == q)
1189 return -EINVAL;
1190 entry->flags |= (*p << 8);
1191 while (*p & 0x80)
1192 if (++p == q)
1193 return -EINVAL;
1194 p++;
1195 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001197 entry->subtuples = q-p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001199 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200}
1201
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203static int parse_device_geo(tuple_t *tuple, cistpl_device_geo_t *geo)
1204{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001205 u_char *p, *q;
1206 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001208 p = (u_char *)tuple->TupleData;
1209 q = p + tuple->TupleDataLen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001211 for (n = 0; n < CISTPL_MAX_DEVICES; n++) {
1212 if (p > q-6)
1213 break;
1214 geo->geo[n].buswidth = p[0];
1215 geo->geo[n].erase_block = 1 << (p[1]-1);
1216 geo->geo[n].read_block = 1 << (p[2]-1);
1217 geo->geo[n].write_block = 1 << (p[3]-1);
1218 geo->geo[n].partition = 1 << (p[4]-1);
1219 geo->geo[n].interleave = 1 << (p[5]-1);
1220 p += 6;
1221 }
1222 geo->ngeo = n;
1223 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224}
1225
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226
1227static int parse_vers_2(tuple_t *tuple, cistpl_vers_2_t *v2)
1228{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001229 u_char *p, *q;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001231 if (tuple->TupleDataLen < 10)
1232 return -EINVAL;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001233
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001234 p = tuple->TupleData;
1235 q = p + tuple->TupleDataLen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001237 v2->vers = p[0];
1238 v2->comply = p[1];
1239 v2->dindex = get_unaligned_le16(p + 2);
1240 v2->vspec8 = p[6];
1241 v2->vspec9 = p[7];
1242 v2->nhdr = p[8];
1243 p += 9;
1244 return parse_strings(p, q, 2, v2->str, &v2->vendor, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245}
1246
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247
1248static int parse_org(tuple_t *tuple, cistpl_org_t *org)
1249{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001250 u_char *p, *q;
1251 int i;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001252
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001253 p = tuple->TupleData;
1254 q = p + tuple->TupleDataLen;
1255 if (p == q)
1256 return -EINVAL;
1257 org->data_org = *p;
Dominik Brodowski3f9c5f42008-08-03 12:22:40 +02001258 if (++p == q)
1259 return -EINVAL;
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001260 for (i = 0; i < 30; i++) {
1261 org->desc[i] = *p;
1262 if (*p == '\0')
1263 break;
1264 if (++p == q)
1265 return -EINVAL;
1266 }
1267 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001268}
1269
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270
1271static int parse_format(tuple_t *tuple, cistpl_format_t *fmt)
1272{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001273 u_char *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001275 if (tuple->TupleDataLen < 10)
1276 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001278 p = tuple->TupleData;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001280 fmt->type = p[0];
1281 fmt->edc = p[1];
1282 fmt->offset = get_unaligned_le32(p + 2);
1283 fmt->length = get_unaligned_le32(p + 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001284
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001285 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286}
1287
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288
Dominik Brodowski2f3061e2008-08-31 15:50:33 +02001289int pcmcia_parse_tuple(tuple_t *tuple, cisparse_t *parse)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001290{
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001291 int ret = 0;
Dominik Brodowski9fea84f2009-12-07 22:11:45 +01001292
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001293 if (tuple->TupleDataLen > tuple->TupleDataMax)
1294 return -EINVAL;
1295 switch (tuple->TupleCode) {
1296 case CISTPL_DEVICE:
1297 case CISTPL_DEVICE_A:
1298 ret = parse_device(tuple, &parse->device);
1299 break;
1300 case CISTPL_CHECKSUM:
1301 ret = parse_checksum(tuple, &parse->checksum);
1302 break;
1303 case CISTPL_LONGLINK_A:
1304 case CISTPL_LONGLINK_C:
1305 ret = parse_longlink(tuple, &parse->longlink);
1306 break;
1307 case CISTPL_LONGLINK_MFC:
1308 ret = parse_longlink_mfc(tuple, &parse->longlink_mfc);
1309 break;
1310 case CISTPL_VERS_1:
1311 ret = parse_vers_1(tuple, &parse->version_1);
1312 break;
1313 case CISTPL_ALTSTR:
1314 ret = parse_altstr(tuple, &parse->altstr);
1315 break;
1316 case CISTPL_JEDEC_A:
1317 case CISTPL_JEDEC_C:
1318 ret = parse_jedec(tuple, &parse->jedec);
1319 break;
1320 case CISTPL_MANFID:
1321 ret = parse_manfid(tuple, &parse->manfid);
1322 break;
1323 case CISTPL_FUNCID:
1324 ret = parse_funcid(tuple, &parse->funcid);
1325 break;
1326 case CISTPL_FUNCE:
1327 ret = parse_funce(tuple, &parse->funce);
1328 break;
1329 case CISTPL_CONFIG:
1330 ret = parse_config(tuple, &parse->config);
1331 break;
1332 case CISTPL_CFTABLE_ENTRY:
1333 ret = parse_cftable_entry(tuple, &parse->cftable_entry);
1334 break;
1335 case CISTPL_DEVICE_GEO:
1336 case CISTPL_DEVICE_GEO_A:
1337 ret = parse_device_geo(tuple, &parse->device_geo);
1338 break;
1339 case CISTPL_VERS_2:
1340 ret = parse_vers_2(tuple, &parse->vers_2);
1341 break;
1342 case CISTPL_ORG:
1343 ret = parse_org(tuple, &parse->org);
1344 break;
1345 case CISTPL_FORMAT:
1346 case CISTPL_FORMAT_A:
1347 ret = parse_format(tuple, &parse->format);
1348 break;
1349 case CISTPL_NO_LINK:
1350 case CISTPL_LINKTARGET:
1351 ret = 0;
1352 break;
1353 default:
1354 ret = -EINVAL;
1355 break;
1356 }
1357 if (ret)
1358 pr_debug("parse_tuple failed %d\n", ret);
1359 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360}
Dominik Brodowski2f3061e2008-08-31 15:50:33 +02001361EXPORT_SYMBOL(pcmcia_parse_tuple);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001362
Linus Torvalds1da177e2005-04-16 15:20:36 -07001363
Dominik Brodowski6e83ee02010-03-02 08:57:33 +01001364/**
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001365 * pccard_validate_cis() - check whether card has a sensible CIS
1366 * @s: the struct pcmcia_socket we are to check
1367 * @info: returns the number of tuples in the (valid) CIS, or 0
1368 *
1369 * This tries to determine if a card has a sensible CIS. In @info, it
1370 * returns the number of tuples in the CIS, or 0 if the CIS looks bad. The
1371 * checks include making sure several critical tuples are present and
1372 * valid; seeing if the total number of tuples is reasonable; and
1373 * looking for tuples that use reserved codes.
1374 *
1375 * The function returns 0 on success.
1376 */
Dominik Brodowski84897fc2009-10-18 23:51:09 +02001377int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378{
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001379 tuple_t *tuple;
1380 cisparse_t *p;
1381 unsigned int count = 0;
1382 int ret, reserved, dev_ok = 0, ident_ok = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001384 if (!s)
1385 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386
Alan Cox84026412014-12-10 15:06:40 +00001387 if (s->functions || !(s->state & SOCKET_PRESENT)) {
Dominik Brodowskia8408c12010-04-17 17:37:33 +02001388 WARN_ON(1);
1389 return -EINVAL;
1390 }
1391
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001392 /* We do not want to validate the CIS cache... */
Dominik Brodowski8680c4b2010-01-12 22:05:36 +01001393 mutex_lock(&s->ops_mutex);
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001394 destroy_cis_cache(s);
Dominik Brodowski8680c4b2010-01-12 22:05:36 +01001395 mutex_unlock(&s->ops_mutex);
Dominik Brodowski904e3772010-01-02 12:28:04 +01001396
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001397 tuple = kmalloc(sizeof(*tuple), GFP_KERNEL);
1398 if (tuple == NULL) {
1399 dev_warn(&s->dev, "no memory to validate CIS\n");
1400 return -ENOMEM;
1401 }
1402 p = kmalloc(sizeof(*p), GFP_KERNEL);
1403 if (p == NULL) {
1404 kfree(tuple);
1405 dev_warn(&s->dev, "no memory to validate CIS\n");
1406 return -ENOMEM;
1407 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001409 count = reserved = 0;
1410 tuple->DesiredTuple = RETURN_FIRST_TUPLE;
1411 tuple->Attributes = TUPLE_RETURN_COMMON;
1412 ret = pccard_get_first_tuple(s, BIND_FN_ALL, tuple);
Dominik Brodowski4c89e882008-08-03 10:07:45 +02001413 if (ret != 0)
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001414 goto done;
1415
1416 /* First tuple should be DEVICE; we should really have either that
1417 or a CFTABLE_ENTRY of some sort */
1418 if ((tuple->TupleCode == CISTPL_DEVICE) ||
1419 (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_CFTABLE_ENTRY, p)) ||
1420 (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_CFTABLE_ENTRY_CB, p)))
1421 dev_ok++;
1422
1423 /* All cards should have a MANFID tuple, and/or a VERS_1 or VERS_2
1424 tuple, for card identification. Certain old D-Link and Linksys
1425 cards have only a broken VERS_2 tuple; hence the bogus test. */
1426 if ((pccard_read_tuple(s, BIND_FN_ALL, CISTPL_MANFID, p) == 0) ||
1427 (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_VERS_1, p) == 0) ||
1428 (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_VERS_2, p) != -ENOSPC))
1429 ident_ok++;
1430
1431 if (!dev_ok && !ident_ok)
1432 goto done;
1433
1434 for (count = 1; count < MAX_TUPLES; count++) {
1435 ret = pccard_get_next_tuple(s, BIND_FN_ALL, tuple);
1436 if (ret != 0)
1437 break;
1438 if (((tuple->TupleCode > 0x23) && (tuple->TupleCode < 0x40)) ||
1439 ((tuple->TupleCode > 0x47) && (tuple->TupleCode < 0x80)) ||
1440 ((tuple->TupleCode > 0x90) && (tuple->TupleCode < 0xff)))
1441 reserved++;
1442 }
1443 if ((count == MAX_TUPLES) || (reserved > 5) ||
1444 ((!dev_ok || !ident_ok) && (count > 10)))
1445 count = 0;
1446
1447 ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448
1449done:
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001450 /* invalidate CIS cache on failure */
1451 if (!dev_ok || !ident_ok || !count) {
Alan Cox1c6c9b12014-12-10 15:07:14 +00001452#if defined(CONFIG_MTD_PCMCIA_ANONYMOUS)
1453 /* Set up as an anonymous card. If we don't have anonymous
1454 memory support then just error the card as there is no
1455 point trying to second guess.
1456
1457 Note: some cards have just a device entry, it may be
1458 worth extending support to cover these in future */
1459 if (!dev_ok || !ident_ok) {
1460 dev_info(&s->dev, "no CIS, assuming an anonymous memory card.\n");
1461 pcmcia_replace_cis(s, "\xFF", 1);
1462 count = 1;
1463 ret = 0;
1464 } else
1465#endif
1466 {
1467 mutex_lock(&s->ops_mutex);
1468 destroy_cis_cache(s);
1469 mutex_unlock(&s->ops_mutex);
1470 ret = -EIO;
1471 }
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001472 }
Dominik Brodowski904e3772010-01-02 12:28:04 +01001473
Dominik Brodowskif131ddc2010-01-02 12:58:10 +01001474 if (info)
1475 *info = count;
1476 kfree(tuple);
1477 kfree(p);
1478 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001479}
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001480
1481
1482#define to_socket(_dev) container_of(_dev, struct pcmcia_socket, dev)
1483
1484static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf,
1485 loff_t off, size_t count)
1486{
1487 tuple_t tuple;
1488 int status, i;
1489 loff_t pointer = 0;
1490 ssize_t ret = 0;
1491 u_char *tuplebuffer;
1492 u_char *tempbuffer;
1493
1494 tuplebuffer = kmalloc(sizeof(u_char) * 256, GFP_KERNEL);
1495 if (!tuplebuffer)
1496 return -ENOMEM;
1497
1498 tempbuffer = kmalloc(sizeof(u_char) * 258, GFP_KERNEL);
1499 if (!tempbuffer) {
1500 ret = -ENOMEM;
1501 goto free_tuple;
1502 }
1503
1504 memset(&tuple, 0, sizeof(tuple_t));
1505
1506 tuple.Attributes = TUPLE_RETURN_LINK | TUPLE_RETURN_COMMON;
1507 tuple.DesiredTuple = RETURN_FIRST_TUPLE;
1508 tuple.TupleOffset = 0;
1509
1510 status = pccard_get_first_tuple(s, BIND_FN_ALL, &tuple);
1511 while (!status) {
1512 tuple.TupleData = tuplebuffer;
1513 tuple.TupleDataMax = 255;
1514 memset(tuplebuffer, 0, sizeof(u_char) * 255);
1515
1516 status = pccard_get_tuple_data(s, &tuple);
1517 if (status)
1518 break;
1519
1520 if (off < (pointer + 2 + tuple.TupleDataLen)) {
1521 tempbuffer[0] = tuple.TupleCode & 0xff;
1522 tempbuffer[1] = tuple.TupleLink & 0xff;
1523 for (i = 0; i < tuple.TupleDataLen; i++)
1524 tempbuffer[i + 2] = tuplebuffer[i] & 0xff;
1525
1526 for (i = 0; i < (2 + tuple.TupleDataLen); i++) {
1527 if (((i + pointer) >= off) &&
1528 (i + pointer) < (off + count)) {
1529 buf[ret] = tempbuffer[i];
1530 ret++;
1531 }
1532 }
1533 }
1534
1535 pointer += 2 + tuple.TupleDataLen;
1536
1537 if (pointer >= (off + count))
1538 break;
1539
1540 if (tuple.TupleCode == CISTPL_END)
1541 break;
1542 status = pccard_get_next_tuple(s, BIND_FN_ALL, &tuple);
1543 }
1544
1545 kfree(tempbuffer);
1546 free_tuple:
1547 kfree(tuplebuffer);
1548
1549 return ret;
1550}
1551
1552
Chris Wright2c3c8be2010-05-12 18:28:57 -07001553static ssize_t pccard_show_cis(struct file *filp, struct kobject *kobj,
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001554 struct bin_attribute *bin_attr,
1555 char *buf, loff_t off, size_t count)
1556{
1557 unsigned int size = 0x200;
1558
1559 if (off >= size)
1560 count = 0;
1561 else {
1562 struct pcmcia_socket *s;
Dominik Brodowskia8408c12010-04-17 17:37:33 +02001563 unsigned int chains = 1;
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001564
1565 if (off + count > size)
1566 count = size - off;
1567
1568 s = to_socket(container_of(kobj, struct device, kobj));
1569
1570 if (!(s->state & SOCKET_PRESENT))
1571 return -ENODEV;
Dominik Brodowskia8408c12010-04-17 17:37:33 +02001572 if (!s->functions && pccard_validate_cis(s, &chains))
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001573 return -EIO;
1574 if (!chains)
1575 return -ENODATA;
1576
1577 count = pccard_extract_cis(s, buf, off, count);
1578 }
1579
1580 return count;
1581}
1582
1583
Chris Wright2c3c8be2010-05-12 18:28:57 -07001584static ssize_t pccard_store_cis(struct file *filp, struct kobject *kobj,
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001585 struct bin_attribute *bin_attr,
1586 char *buf, loff_t off, size_t count)
1587{
1588 struct pcmcia_socket *s;
1589 int error;
1590
1591 s = to_socket(container_of(kobj, struct device, kobj));
1592
1593 if (off)
1594 return -EINVAL;
1595
1596 if (count >= CISTPL_MAX_CIS_SIZE)
1597 return -EINVAL;
1598
1599 if (!(s->state & SOCKET_PRESENT))
1600 return -ENODEV;
1601
1602 error = pcmcia_replace_cis(s, buf, count);
1603 if (error)
1604 return -EIO;
1605
Dominik Brodowskiaf461fc2010-01-17 19:30:53 +01001606 pcmcia_parse_uevents(s, PCMCIA_UEVENT_REQUERY);
Dominik Brodowski6e7b51a2010-01-06 13:57:43 +01001607
1608 return count;
1609}
1610
1611
1612struct bin_attribute pccard_cis_attr = {
1613 .attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR },
1614 .size = 0x200,
1615 .read = pccard_show_cis,
1616 .write = pccard_store_cis,
1617};