diff options
Diffstat (limited to 'drivers/pcmcia/cistpl.c')
-rw-r--r-- | drivers/pcmcia/cistpl.c | 606 |
1 files changed, 337 insertions, 269 deletions
diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 25b1cd219e37..2f3622dd4b69 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c | |||
@@ -64,6 +64,7 @@ module_param(cis_width, int, 0444); | |||
64 | 64 | ||
65 | void release_cis_mem(struct pcmcia_socket *s) | 65 | void release_cis_mem(struct pcmcia_socket *s) |
66 | { | 66 | { |
67 | mutex_lock(&s->ops_mutex); | ||
67 | if (s->cis_mem.flags & MAP_ACTIVE) { | 68 | if (s->cis_mem.flags & MAP_ACTIVE) { |
68 | s->cis_mem.flags &= ~MAP_ACTIVE; | 69 | s->cis_mem.flags &= ~MAP_ACTIVE; |
69 | s->ops->set_mem_map(s, &s->cis_mem); | 70 | s->ops->set_mem_map(s, &s->cis_mem); |
@@ -75,13 +76,15 @@ void release_cis_mem(struct pcmcia_socket *s) | |||
75 | iounmap(s->cis_virt); | 76 | iounmap(s->cis_virt); |
76 | s->cis_virt = NULL; | 77 | s->cis_virt = NULL; |
77 | } | 78 | } |
79 | mutex_unlock(&s->ops_mutex); | ||
78 | } | 80 | } |
79 | EXPORT_SYMBOL(release_cis_mem); | ||
80 | 81 | ||
81 | /* | 82 | /* |
82 | * Map the card memory at "card_offset" into virtual space. | 83 | * Map the card memory at "card_offset" into virtual space. |
83 | * If flags & MAP_ATTRIB, map the attribute space, otherwise | 84 | * If flags & MAP_ATTRIB, map the attribute space, otherwise |
84 | * map the memory space. | 85 | * map the memory space. |
86 | * | ||
87 | * Must be called with ops_mutex held. | ||
85 | */ | 88 | */ |
86 | static void __iomem * | 89 | static void __iomem * |
87 | set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flags) | 90 | set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flags) |
@@ -140,6 +143,7 @@ int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, | |||
140 | 143 | ||
141 | dev_dbg(&s->dev, "pcmcia_read_cis_mem(%d, %#x, %u)\n", attr, addr, len); | 144 | dev_dbg(&s->dev, "pcmcia_read_cis_mem(%d, %#x, %u)\n", attr, addr, len); |
142 | 145 | ||
146 | mutex_lock(&s->ops_mutex); | ||
143 | if (attr & IS_INDIRECT) { | 147 | if (attr & IS_INDIRECT) { |
144 | /* Indirect accesses use a bunch of special registers at fixed | 148 | /* Indirect accesses use a bunch of special registers at fixed |
145 | locations in common memory */ | 149 | locations in common memory */ |
@@ -151,7 +155,9 @@ int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, | |||
151 | 155 | ||
152 | sys = set_cis_map(s, 0, MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0)); | 156 | sys = set_cis_map(s, 0, MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0)); |
153 | if (!sys) { | 157 | if (!sys) { |
158 | dev_dbg(&s->dev, "could not map memory\n"); | ||
154 | memset(ptr, 0xff, len); | 159 | memset(ptr, 0xff, len); |
160 | mutex_unlock(&s->ops_mutex); | ||
155 | return -1; | 161 | return -1; |
156 | } | 162 | } |
157 | 163 | ||
@@ -165,6 +171,9 @@ int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, | |||
165 | } else { | 171 | } else { |
166 | u_int inc = 1, card_offset, flags; | 172 | u_int inc = 1, card_offset, flags; |
167 | 173 | ||
174 | if (addr > CISTPL_MAX_CIS_SIZE) | ||
175 | dev_dbg(&s->dev, "attempt to read CIS mem at addr %#x", addr); | ||
176 | |||
168 | flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0); | 177 | flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0); |
169 | if (attr) { | 178 | if (attr) { |
170 | flags |= MAP_ATTRIB; | 179 | flags |= MAP_ATTRIB; |
@@ -176,7 +185,9 @@ int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, | |||
176 | while (len) { | 185 | while (len) { |
177 | sys = set_cis_map(s, card_offset, flags); | 186 | sys = set_cis_map(s, card_offset, flags); |
178 | if (!sys) { | 187 | if (!sys) { |
188 | dev_dbg(&s->dev, "could not map memory\n"); | ||
179 | memset(ptr, 0xff, len); | 189 | memset(ptr, 0xff, len); |
190 | mutex_unlock(&s->ops_mutex); | ||
180 | return -1; | 191 | return -1; |
181 | } | 192 | } |
182 | end = sys + s->map_size; | 193 | end = sys + s->map_size; |
@@ -190,12 +201,12 @@ int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, | |||
190 | addr = 0; | 201 | addr = 0; |
191 | } | 202 | } |
192 | } | 203 | } |
204 | mutex_unlock(&s->ops_mutex); | ||
193 | dev_dbg(&s->dev, " %#2.2x %#2.2x %#2.2x %#2.2x ...\n", | 205 | dev_dbg(&s->dev, " %#2.2x %#2.2x %#2.2x %#2.2x ...\n", |
194 | *(u_char *)(ptr+0), *(u_char *)(ptr+1), | 206 | *(u_char *)(ptr+0), *(u_char *)(ptr+1), |
195 | *(u_char *)(ptr+2), *(u_char *)(ptr+3)); | 207 | *(u_char *)(ptr+2), *(u_char *)(ptr+3)); |
196 | return 0; | 208 | return 0; |
197 | } | 209 | } |
198 | EXPORT_SYMBOL(pcmcia_read_cis_mem); | ||
199 | 210 | ||
200 | 211 | ||
201 | void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, | 212 | void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, |
@@ -206,6 +217,7 @@ void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, | |||
206 | 217 | ||
207 | dev_dbg(&s->dev, "pcmcia_write_cis_mem(%d, %#x, %u)\n", attr, addr, len); | 218 | dev_dbg(&s->dev, "pcmcia_write_cis_mem(%d, %#x, %u)\n", attr, addr, len); |
208 | 219 | ||
220 | mutex_lock(&s->ops_mutex); | ||
209 | if (attr & IS_INDIRECT) { | 221 | if (attr & IS_INDIRECT) { |
210 | /* Indirect accesses use a bunch of special registers at fixed | 222 | /* Indirect accesses use a bunch of special registers at fixed |
211 | locations in common memory */ | 223 | locations in common memory */ |
@@ -216,8 +228,11 @@ void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, | |||
216 | } | 228 | } |
217 | 229 | ||
218 | sys = set_cis_map(s, 0, MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0)); | 230 | sys = set_cis_map(s, 0, MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0)); |
219 | if (!sys) | 231 | if (!sys) { |
232 | dev_dbg(&s->dev, "could not map memory\n"); | ||
233 | mutex_unlock(&s->ops_mutex); | ||
220 | return; /* FIXME: Error */ | 234 | return; /* FIXME: Error */ |
235 | } | ||
221 | 236 | ||
222 | writeb(flags, sys+CISREG_ICTRL0); | 237 | writeb(flags, sys+CISREG_ICTRL0); |
223 | writeb(addr & 0xff, sys+CISREG_IADDR0); | 238 | writeb(addr & 0xff, sys+CISREG_IADDR0); |
@@ -239,8 +254,11 @@ void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, | |||
239 | card_offset = addr & ~(s->map_size-1); | 254 | card_offset = addr & ~(s->map_size-1); |
240 | while (len) { | 255 | while (len) { |
241 | sys = set_cis_map(s, card_offset, flags); | 256 | sys = set_cis_map(s, card_offset, flags); |
242 | if (!sys) | 257 | if (!sys) { |
258 | dev_dbg(&s->dev, "could not map memory\n"); | ||
259 | mutex_unlock(&s->ops_mutex); | ||
243 | return; /* FIXME: error */ | 260 | return; /* FIXME: error */ |
261 | } | ||
244 | 262 | ||
245 | end = sys + s->map_size; | 263 | end = sys + s->map_size; |
246 | sys = sys + (addr & (s->map_size-1)); | 264 | sys = sys + (addr & (s->map_size-1)); |
@@ -253,8 +271,8 @@ void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, | |||
253 | addr = 0; | 271 | addr = 0; |
254 | } | 272 | } |
255 | } | 273 | } |
274 | mutex_unlock(&s->ops_mutex); | ||
256 | } | 275 | } |
257 | EXPORT_SYMBOL(pcmcia_write_cis_mem); | ||
258 | 276 | ||
259 | 277 | ||
260 | /*====================================================================== | 278 | /*====================================================================== |
@@ -265,32 +283,36 @@ EXPORT_SYMBOL(pcmcia_write_cis_mem); | |||
265 | 283 | ||
266 | ======================================================================*/ | 284 | ======================================================================*/ |
267 | 285 | ||
268 | static void read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, | 286 | static int read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, |
269 | size_t len, void *ptr) | 287 | size_t len, void *ptr) |
270 | { | 288 | { |
271 | struct cis_cache_entry *cis; | 289 | struct cis_cache_entry *cis; |
272 | int ret; | 290 | int ret = 0; |
273 | 291 | ||
274 | if (s->fake_cis) { | 292 | if (s->state & SOCKET_CARDBUS) |
275 | if (s->fake_cis_len >= addr+len) | 293 | return -EINVAL; |
276 | memcpy(ptr, s->fake_cis+addr, len); | ||
277 | else | ||
278 | memset(ptr, 0xff, len); | ||
279 | return; | ||
280 | } | ||
281 | 294 | ||
282 | list_for_each_entry(cis, &s->cis_cache, node) { | 295 | mutex_lock(&s->ops_mutex); |
283 | if (cis->addr == addr && cis->len == len && cis->attr == attr) { | 296 | if (s->fake_cis) { |
284 | memcpy(ptr, cis->cache, len); | 297 | if (s->fake_cis_len >= addr+len) |
285 | return; | 298 | memcpy(ptr, s->fake_cis+addr, len); |
299 | else { | ||
300 | memset(ptr, 0xff, len); | ||
301 | ret = -EINVAL; | ||
302 | } | ||
303 | mutex_unlock(&s->ops_mutex); | ||
304 | return ret; | ||
286 | } | 305 | } |
287 | } | ||
288 | 306 | ||
289 | #ifdef CONFIG_CARDBUS | 307 | list_for_each_entry(cis, &s->cis_cache, node) { |
290 | if (s->state & SOCKET_CARDBUS) | 308 | if (cis->addr == addr && cis->len == len && cis->attr == attr) { |
291 | ret = read_cb_mem(s, attr, addr, len, ptr); | 309 | memcpy(ptr, cis->cache, len); |
292 | else | 310 | mutex_unlock(&s->ops_mutex); |
293 | #endif | 311 | return 0; |
312 | } | ||
313 | } | ||
314 | mutex_unlock(&s->ops_mutex); | ||
315 | |||
294 | ret = pcmcia_read_cis_mem(s, attr, addr, len, ptr); | 316 | ret = pcmcia_read_cis_mem(s, attr, addr, len, ptr); |
295 | 317 | ||
296 | if (ret == 0) { | 318 | if (ret == 0) { |
@@ -301,9 +323,12 @@ static void read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, | |||
301 | cis->len = len; | 323 | cis->len = len; |
302 | cis->attr = attr; | 324 | cis->attr = attr; |
303 | memcpy(cis->cache, ptr, len); | 325 | memcpy(cis->cache, ptr, len); |
326 | mutex_lock(&s->ops_mutex); | ||
304 | list_add(&cis->node, &s->cis_cache); | 327 | list_add(&cis->node, &s->cis_cache); |
328 | mutex_unlock(&s->ops_mutex); | ||
305 | } | 329 | } |
306 | } | 330 | } |
331 | return ret; | ||
307 | } | 332 | } |
308 | 333 | ||
309 | static void | 334 | static void |
@@ -311,32 +336,35 @@ remove_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, u_int len) | |||
311 | { | 336 | { |
312 | struct cis_cache_entry *cis; | 337 | struct cis_cache_entry *cis; |
313 | 338 | ||
339 | mutex_lock(&s->ops_mutex); | ||
314 | list_for_each_entry(cis, &s->cis_cache, node) | 340 | list_for_each_entry(cis, &s->cis_cache, node) |
315 | if (cis->addr == addr && cis->len == len && cis->attr == attr) { | 341 | if (cis->addr == addr && cis->len == len && cis->attr == attr) { |
316 | list_del(&cis->node); | 342 | list_del(&cis->node); |
317 | kfree(cis); | 343 | kfree(cis); |
318 | break; | 344 | break; |
319 | } | 345 | } |
346 | mutex_unlock(&s->ops_mutex); | ||
320 | } | 347 | } |
321 | 348 | ||
349 | /** | ||
350 | * destroy_cis_cache() - destroy the CIS cache | ||
351 | * @s: pcmcia_socket for which CIS cache shall be destroyed | ||
352 | * | ||
353 | * This destroys the CIS cache but keeps any fake CIS alive. Must be | ||
354 | * called with ops_mutex held. | ||
355 | */ | ||
356 | |||
322 | void destroy_cis_cache(struct pcmcia_socket *s) | 357 | void destroy_cis_cache(struct pcmcia_socket *s) |
323 | { | 358 | { |
324 | struct list_head *l, *n; | 359 | struct list_head *l, *n; |
360 | struct cis_cache_entry *cis; | ||
325 | 361 | ||
326 | list_for_each_safe(l, n, &s->cis_cache) { | 362 | list_for_each_safe(l, n, &s->cis_cache) { |
327 | struct cis_cache_entry *cis = list_entry(l, struct cis_cache_entry, node); | 363 | cis = list_entry(l, struct cis_cache_entry, node); |
328 | |||
329 | list_del(&cis->node); | 364 | list_del(&cis->node); |
330 | kfree(cis); | 365 | kfree(cis); |
331 | } | 366 | } |
332 | |||
333 | /* | ||
334 | * If there was a fake CIS, destroy that as well. | ||
335 | */ | ||
336 | kfree(s->fake_cis); | ||
337 | s->fake_cis = NULL; | ||
338 | } | 367 | } |
339 | EXPORT_SYMBOL(destroy_cis_cache); | ||
340 | 368 | ||
341 | /*====================================================================== | 369 | /*====================================================================== |
342 | 370 | ||
@@ -349,6 +377,10 @@ int verify_cis_cache(struct pcmcia_socket *s) | |||
349 | { | 377 | { |
350 | struct cis_cache_entry *cis; | 378 | struct cis_cache_entry *cis; |
351 | char *buf; | 379 | char *buf; |
380 | int ret; | ||
381 | |||
382 | if (s->state & SOCKET_CARDBUS) | ||
383 | return -EINVAL; | ||
352 | 384 | ||
353 | buf = kmalloc(256, GFP_KERNEL); | 385 | buf = kmalloc(256, GFP_KERNEL); |
354 | if (buf == NULL) { | 386 | if (buf == NULL) { |
@@ -361,14 +393,9 @@ int verify_cis_cache(struct pcmcia_socket *s) | |||
361 | 393 | ||
362 | if (len > 256) | 394 | if (len > 256) |
363 | len = 256; | 395 | len = 256; |
364 | #ifdef CONFIG_CARDBUS | ||
365 | if (s->state & SOCKET_CARDBUS) | ||
366 | read_cb_mem(s, cis->attr, cis->addr, len, buf); | ||
367 | else | ||
368 | #endif | ||
369 | pcmcia_read_cis_mem(s, cis->attr, cis->addr, len, buf); | ||
370 | 396 | ||
371 | if (memcmp(buf, cis->cache, len) != 0) { | 397 | ret = pcmcia_read_cis_mem(s, cis->attr, cis->addr, len, buf); |
398 | if (ret || memcmp(buf, cis->cache, len) != 0) { | ||
372 | kfree(buf); | 399 | kfree(buf); |
373 | return -1; | 400 | return -1; |
374 | } | 401 | } |
@@ -391,17 +418,20 @@ int pcmcia_replace_cis(struct pcmcia_socket *s, | |||
391 | dev_printk(KERN_WARNING, &s->dev, "replacement CIS too big\n"); | 418 | dev_printk(KERN_WARNING, &s->dev, "replacement CIS too big\n"); |
392 | return -EINVAL; | 419 | return -EINVAL; |
393 | } | 420 | } |
421 | mutex_lock(&s->ops_mutex); | ||
394 | kfree(s->fake_cis); | 422 | kfree(s->fake_cis); |
395 | s->fake_cis = kmalloc(len, GFP_KERNEL); | 423 | s->fake_cis = kmalloc(len, GFP_KERNEL); |
396 | if (s->fake_cis == NULL) { | 424 | if (s->fake_cis == NULL) { |
397 | dev_printk(KERN_WARNING, &s->dev, "no memory to replace CIS\n"); | 425 | dev_printk(KERN_WARNING, &s->dev, "no memory to replace CIS\n"); |
426 | mutex_unlock(&s->ops_mutex); | ||
398 | return -ENOMEM; | 427 | return -ENOMEM; |
399 | } | 428 | } |
400 | s->fake_cis_len = len; | 429 | s->fake_cis_len = len; |
401 | memcpy(s->fake_cis, data, len); | 430 | memcpy(s->fake_cis, data, len); |
431 | dev_info(&s->dev, "Using replacement CIS\n"); | ||
432 | mutex_unlock(&s->ops_mutex); | ||
402 | return 0; | 433 | return 0; |
403 | } | 434 | } |
404 | EXPORT_SYMBOL(pcmcia_replace_cis); | ||
405 | 435 | ||
406 | /*====================================================================== | 436 | /*====================================================================== |
407 | 437 | ||
@@ -425,25 +455,16 @@ int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function, tuple | |||
425 | { | 455 | { |
426 | if (!s) | 456 | if (!s) |
427 | return -EINVAL; | 457 | return -EINVAL; |
428 | if (!(s->state & SOCKET_PRESENT)) | 458 | |
459 | if (!(s->state & SOCKET_PRESENT) || (s->state & SOCKET_CARDBUS)) | ||
429 | return -ENODEV; | 460 | return -ENODEV; |
430 | tuple->TupleLink = tuple->Flags = 0; | 461 | tuple->TupleLink = tuple->Flags = 0; |
431 | #ifdef CONFIG_CARDBUS | 462 | |
432 | if (s->state & SOCKET_CARDBUS) { | 463 | /* Assume presence of a LONGLINK_C to address 0 */ |
433 | struct pci_dev *dev = s->cb_dev; | 464 | tuple->CISOffset = tuple->LinkOffset = 0; |
434 | u_int ptr; | 465 | SPACE(tuple->Flags) = HAS_LINK(tuple->Flags) = 1; |
435 | pci_bus_read_config_dword(dev->subordinate, 0, PCI_CARDBUS_CIS, &ptr); | 466 | |
436 | tuple->CISOffset = ptr & ~7; | 467 | if ((s->functions > 1) && !(tuple->Attributes & TUPLE_RETURN_COMMON)) { |
437 | SPACE(tuple->Flags) = (ptr & 7); | ||
438 | } else | ||
439 | #endif | ||
440 | { | ||
441 | /* Assume presence of a LONGLINK_C to address 0 */ | ||
442 | tuple->CISOffset = tuple->LinkOffset = 0; | ||
443 | SPACE(tuple->Flags) = HAS_LINK(tuple->Flags) = 1; | ||
444 | } | ||
445 | if (!(s->state & SOCKET_CARDBUS) && (s->functions > 1) && | ||
446 | !(tuple->Attributes & TUPLE_RETURN_COMMON)) { | ||
447 | cisdata_t req = tuple->DesiredTuple; | 468 | cisdata_t req = tuple->DesiredTuple; |
448 | tuple->DesiredTuple = CISTPL_LONGLINK_MFC; | 469 | tuple->DesiredTuple = CISTPL_LONGLINK_MFC; |
449 | if (pccard_get_next_tuple(s, function, tuple) == 0) { | 470 | if (pccard_get_next_tuple(s, function, tuple) == 0) { |
@@ -456,17 +477,19 @@ int pccard_get_first_tuple(struct pcmcia_socket *s, unsigned int function, tuple | |||
456 | } | 477 | } |
457 | return pccard_get_next_tuple(s, function, tuple); | 478 | return pccard_get_next_tuple(s, function, tuple); |
458 | } | 479 | } |
459 | EXPORT_SYMBOL(pccard_get_first_tuple); | ||
460 | 480 | ||
461 | static int follow_link(struct pcmcia_socket *s, tuple_t *tuple) | 481 | static int follow_link(struct pcmcia_socket *s, tuple_t *tuple) |
462 | { | 482 | { |
463 | u_char link[5]; | 483 | u_char link[5]; |
464 | u_int ofs; | 484 | u_int ofs; |
485 | int ret; | ||
465 | 486 | ||
466 | if (MFC_FN(tuple->Flags)) { | 487 | if (MFC_FN(tuple->Flags)) { |
467 | /* Get indirect link from the MFC tuple */ | 488 | /* Get indirect link from the MFC tuple */ |
468 | read_cis_cache(s, LINK_SPACE(tuple->Flags), | 489 | ret = read_cis_cache(s, LINK_SPACE(tuple->Flags), |
469 | tuple->LinkOffset, 5, link); | 490 | tuple->LinkOffset, 5, link); |
491 | if (ret) | ||
492 | return -1; | ||
470 | ofs = get_unaligned_le32(link + 1); | 493 | ofs = get_unaligned_le32(link + 1); |
471 | SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR); | 494 | SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR); |
472 | /* Move to the next indirect link */ | 495 | /* Move to the next indirect link */ |
@@ -479,10 +502,12 @@ static int follow_link(struct pcmcia_socket *s, tuple_t *tuple) | |||
479 | } else { | 502 | } else { |
480 | return -1; | 503 | return -1; |
481 | } | 504 | } |
482 | if (!(s->state & SOCKET_CARDBUS) && SPACE(tuple->Flags)) { | 505 | if (SPACE(tuple->Flags)) { |
483 | /* This is ugly, but a common CIS error is to code the long | 506 | /* This is ugly, but a common CIS error is to code the long |
484 | link offset incorrectly, so we check the right spot... */ | 507 | link offset incorrectly, so we check the right spot... */ |
485 | read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link); | 508 | ret = read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link); |
509 | if (ret) | ||
510 | return -1; | ||
486 | if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) && | 511 | if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) && |
487 | (strncmp(link+2, "CIS", 3) == 0)) | 512 | (strncmp(link+2, "CIS", 3) == 0)) |
488 | return ofs; | 513 | return ofs; |
@@ -490,7 +515,9 @@ static int follow_link(struct pcmcia_socket *s, tuple_t *tuple) | |||
490 | /* Then, we try the wrong spot... */ | 515 | /* Then, we try the wrong spot... */ |
491 | ofs = ofs >> 1; | 516 | ofs = ofs >> 1; |
492 | } | 517 | } |
493 | read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link); | 518 | ret = read_cis_cache(s, SPACE(tuple->Flags), ofs, 5, link); |
519 | if (ret) | ||
520 | return -1; | ||
494 | if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) && | 521 | if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) && |
495 | (strncmp(link+2, "CIS", 3) == 0)) | 522 | (strncmp(link+2, "CIS", 3) == 0)) |
496 | return ofs; | 523 | return ofs; |
@@ -502,10 +529,11 @@ int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, tuple_ | |||
502 | { | 529 | { |
503 | u_char link[2], tmp; | 530 | u_char link[2], tmp; |
504 | int ofs, i, attr; | 531 | int ofs, i, attr; |
532 | int ret; | ||
505 | 533 | ||
506 | if (!s) | 534 | if (!s) |
507 | return -EINVAL; | 535 | return -EINVAL; |
508 | if (!(s->state & SOCKET_PRESENT)) | 536 | if (!(s->state & SOCKET_PRESENT) || (s->state & SOCKET_CARDBUS)) |
509 | return -ENODEV; | 537 | return -ENODEV; |
510 | 538 | ||
511 | link[1] = tuple->TupleLink; | 539 | link[1] = tuple->TupleLink; |
@@ -516,7 +544,9 @@ int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, tuple_ | |||
516 | if (link[1] == 0xff) { | 544 | if (link[1] == 0xff) { |
517 | link[0] = CISTPL_END; | 545 | link[0] = CISTPL_END; |
518 | } else { | 546 | } else { |
519 | read_cis_cache(s, attr, ofs, 2, link); | 547 | ret = read_cis_cache(s, attr, ofs, 2, link); |
548 | if (ret) | ||
549 | return -1; | ||
520 | if (link[0] == CISTPL_NULL) { | 550 | if (link[0] == CISTPL_NULL) { |
521 | ofs++; continue; | 551 | ofs++; continue; |
522 | } | 552 | } |
@@ -528,7 +558,9 @@ int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, tuple_ | |||
528 | if (ofs < 0) | 558 | if (ofs < 0) |
529 | return -ENOSPC; | 559 | return -ENOSPC; |
530 | attr = SPACE(tuple->Flags); | 560 | attr = SPACE(tuple->Flags); |
531 | read_cis_cache(s, attr, ofs, 2, link); | 561 | ret = read_cis_cache(s, attr, ofs, 2, link); |
562 | if (ret) | ||
563 | return -1; | ||
532 | } | 564 | } |
533 | 565 | ||
534 | /* Is this a link tuple? Make a note of it */ | 566 | /* Is this a link tuple? Make a note of it */ |
@@ -542,12 +574,16 @@ int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, tuple_ | |||
542 | case CISTPL_LONGLINK_A: | 574 | case CISTPL_LONGLINK_A: |
543 | HAS_LINK(tuple->Flags) = 1; | 575 | HAS_LINK(tuple->Flags) = 1; |
544 | LINK_SPACE(tuple->Flags) = attr | IS_ATTR; | 576 | LINK_SPACE(tuple->Flags) = attr | IS_ATTR; |
545 | read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset); | 577 | ret = read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset); |
578 | if (ret) | ||
579 | return -1; | ||
546 | break; | 580 | break; |
547 | case CISTPL_LONGLINK_C: | 581 | case CISTPL_LONGLINK_C: |
548 | HAS_LINK(tuple->Flags) = 1; | 582 | HAS_LINK(tuple->Flags) = 1; |
549 | LINK_SPACE(tuple->Flags) = attr & ~IS_ATTR; | 583 | LINK_SPACE(tuple->Flags) = attr & ~IS_ATTR; |
550 | read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset); | 584 | ret = read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset); |
585 | if (ret) | ||
586 | return -1; | ||
551 | break; | 587 | break; |
552 | case CISTPL_INDIRECT: | 588 | case CISTPL_INDIRECT: |
553 | HAS_LINK(tuple->Flags) = 1; | 589 | HAS_LINK(tuple->Flags) = 1; |
@@ -559,7 +595,9 @@ int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, tuple_ | |||
559 | LINK_SPACE(tuple->Flags) = attr; | 595 | LINK_SPACE(tuple->Flags) = attr; |
560 | if (function == BIND_FN_ALL) { | 596 | if (function == BIND_FN_ALL) { |
561 | /* Follow all the MFC links */ | 597 | /* Follow all the MFC links */ |
562 | read_cis_cache(s, attr, ofs+2, 1, &tmp); | 598 | ret = read_cis_cache(s, attr, ofs+2, 1, &tmp); |
599 | if (ret) | ||
600 | return -1; | ||
563 | MFC_FN(tuple->Flags) = tmp; | 601 | MFC_FN(tuple->Flags) = tmp; |
564 | } else { | 602 | } else { |
565 | /* Follow exactly one of the links */ | 603 | /* Follow exactly one of the links */ |
@@ -592,7 +630,6 @@ int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, tuple_ | |||
592 | tuple->CISOffset = ofs + 2; | 630 | tuple->CISOffset = ofs + 2; |
593 | return 0; | 631 | return 0; |
594 | } | 632 | } |
595 | EXPORT_SYMBOL(pccard_get_next_tuple); | ||
596 | 633 | ||
597 | /*====================================================================*/ | 634 | /*====================================================================*/ |
598 | 635 | ||
@@ -601,6 +638,7 @@ EXPORT_SYMBOL(pccard_get_next_tuple); | |||
601 | int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple) | 638 | int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple) |
602 | { | 639 | { |
603 | u_int len; | 640 | u_int len; |
641 | int ret; | ||
604 | 642 | ||
605 | if (!s) | 643 | if (!s) |
606 | return -EINVAL; | 644 | return -EINVAL; |
@@ -611,12 +649,13 @@ int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple) | |||
611 | tuple->TupleDataLen = tuple->TupleLink; | 649 | tuple->TupleDataLen = tuple->TupleLink; |
612 | if (len == 0) | 650 | if (len == 0) |
613 | return 0; | 651 | return 0; |
614 | read_cis_cache(s, SPACE(tuple->Flags), | 652 | ret = read_cis_cache(s, SPACE(tuple->Flags), |
615 | tuple->CISOffset + tuple->TupleOffset, | 653 | tuple->CISOffset + tuple->TupleOffset, |
616 | _MIN(len, tuple->TupleDataMax), tuple->TupleData); | 654 | _MIN(len, tuple->TupleDataMax), tuple->TupleData); |
655 | if (ret) | ||
656 | return -1; | ||
617 | return 0; | 657 | return 0; |
618 | } | 658 | } |
619 | EXPORT_SYMBOL(pccard_get_tuple_data); | ||
620 | 659 | ||
621 | 660 | ||
622 | /*====================================================================== | 661 | /*====================================================================== |
@@ -1190,119 +1229,6 @@ static int parse_cftable_entry(tuple_t *tuple, | |||
1190 | 1229 | ||
1191 | /*====================================================================*/ | 1230 | /*====================================================================*/ |
1192 | 1231 | ||
1193 | #ifdef CONFIG_CARDBUS | ||
1194 | |||
1195 | static int parse_bar(tuple_t *tuple, cistpl_bar_t *bar) | ||
1196 | { | ||
1197 | u_char *p; | ||
1198 | if (tuple->TupleDataLen < 6) | ||
1199 | return -EINVAL; | ||
1200 | p = (u_char *)tuple->TupleData; | ||
1201 | bar->attr = *p; | ||
1202 | p += 2; | ||
1203 | bar->size = get_unaligned_le32(p); | ||
1204 | return 0; | ||
1205 | } | ||
1206 | |||
1207 | static int parse_config_cb(tuple_t *tuple, cistpl_config_t *config) | ||
1208 | { | ||
1209 | u_char *p; | ||
1210 | |||
1211 | p = (u_char *)tuple->TupleData; | ||
1212 | if ((*p != 3) || (tuple->TupleDataLen < 6)) | ||
1213 | return -EINVAL; | ||
1214 | config->last_idx = *(++p); | ||
1215 | p++; | ||
1216 | config->base = get_unaligned_le32(p); | ||
1217 | config->subtuples = tuple->TupleDataLen - 6; | ||
1218 | return 0; | ||
1219 | } | ||
1220 | |||
1221 | static int parse_cftable_entry_cb(tuple_t *tuple, | ||
1222 | cistpl_cftable_entry_cb_t *entry) | ||
1223 | { | ||
1224 | u_char *p, *q, features; | ||
1225 | |||
1226 | p = tuple->TupleData; | ||
1227 | q = p + tuple->TupleDataLen; | ||
1228 | entry->index = *p & 0x3f; | ||
1229 | entry->flags = 0; | ||
1230 | if (*p & 0x40) | ||
1231 | entry->flags |= CISTPL_CFTABLE_DEFAULT; | ||
1232 | |||
1233 | /* Process optional features */ | ||
1234 | if (++p == q) | ||
1235 | return -EINVAL; | ||
1236 | features = *p; p++; | ||
1237 | |||
1238 | /* Power options */ | ||
1239 | if ((features & 3) > 0) { | ||
1240 | p = parse_power(p, q, &entry->vcc); | ||
1241 | if (p == NULL) | ||
1242 | return -EINVAL; | ||
1243 | } else | ||
1244 | entry->vcc.present = 0; | ||
1245 | if ((features & 3) > 1) { | ||
1246 | p = parse_power(p, q, &entry->vpp1); | ||
1247 | if (p == NULL) | ||
1248 | return -EINVAL; | ||
1249 | } else | ||
1250 | entry->vpp1.present = 0; | ||
1251 | if ((features & 3) > 2) { | ||
1252 | p = parse_power(p, q, &entry->vpp2); | ||
1253 | if (p == NULL) | ||
1254 | return -EINVAL; | ||
1255 | } else | ||
1256 | entry->vpp2.present = 0; | ||
1257 | |||
1258 | /* I/O window options */ | ||
1259 | if (features & 0x08) { | ||
1260 | if (p == q) | ||
1261 | return -EINVAL; | ||
1262 | entry->io = *p; p++; | ||
1263 | } else | ||
1264 | entry->io = 0; | ||
1265 | |||
1266 | /* Interrupt options */ | ||
1267 | if (features & 0x10) { | ||
1268 | p = parse_irq(p, q, &entry->irq); | ||
1269 | if (p == NULL) | ||
1270 | return -EINVAL; | ||
1271 | } else | ||
1272 | entry->irq.IRQInfo1 = 0; | ||
1273 | |||
1274 | if (features & 0x20) { | ||
1275 | if (p == q) | ||
1276 | return -EINVAL; | ||
1277 | entry->mem = *p; p++; | ||
1278 | } else | ||
1279 | entry->mem = 0; | ||
1280 | |||
1281 | /* Misc features */ | ||
1282 | if (features & 0x80) { | ||
1283 | if (p == q) | ||
1284 | return -EINVAL; | ||
1285 | entry->flags |= (*p << 8); | ||
1286 | if (*p & 0x80) { | ||
1287 | if (++p == q) | ||
1288 | return -EINVAL; | ||
1289 | entry->flags |= (*p << 16); | ||
1290 | } | ||
1291 | while (*p & 0x80) | ||
1292 | if (++p == q) | ||
1293 | return -EINVAL; | ||
1294 | p++; | ||
1295 | } | ||
1296 | |||
1297 | entry->subtuples = q-p; | ||
1298 | |||
1299 | return 0; | ||
1300 | } | ||
1301 | |||
1302 | #endif | ||
1303 | |||
1304 | /*====================================================================*/ | ||
1305 | |||
1306 | static int parse_device_geo(tuple_t *tuple, cistpl_device_geo_t *geo) | 1232 | static int parse_device_geo(tuple_t *tuple, cistpl_device_geo_t *geo) |
1307 | { | 1233 | { |
1308 | u_char *p, *q; | 1234 | u_char *p, *q; |
@@ -1404,17 +1330,6 @@ int pcmcia_parse_tuple(tuple_t *tuple, cisparse_t *parse) | |||
1404 | case CISTPL_DEVICE_A: | 1330 | case CISTPL_DEVICE_A: |
1405 | ret = parse_device(tuple, &parse->device); | 1331 | ret = parse_device(tuple, &parse->device); |
1406 | break; | 1332 | break; |
1407 | #ifdef CONFIG_CARDBUS | ||
1408 | case CISTPL_BAR: | ||
1409 | ret = parse_bar(tuple, &parse->bar); | ||
1410 | break; | ||
1411 | case CISTPL_CONFIG_CB: | ||
1412 | ret = parse_config_cb(tuple, &parse->config); | ||
1413 | break; | ||
1414 | case CISTPL_CFTABLE_ENTRY_CB: | ||
1415 | ret = parse_cftable_entry_cb(tuple, &parse->cftable_entry_cb); | ||
1416 | break; | ||
1417 | #endif | ||
1418 | case CISTPL_CHECKSUM: | 1333 | case CISTPL_CHECKSUM: |
1419 | ret = parse_checksum(tuple, &parse->checksum); | 1334 | ret = parse_checksum(tuple, &parse->checksum); |
1420 | break; | 1335 | break; |
@@ -1513,7 +1428,6 @@ done: | |||
1513 | kfree(buf); | 1428 | kfree(buf); |
1514 | return ret; | 1429 | return ret; |
1515 | } | 1430 | } |
1516 | EXPORT_SYMBOL(pccard_read_tuple); | ||
1517 | 1431 | ||
1518 | 1432 | ||
1519 | /** | 1433 | /** |
@@ -1573,84 +1487,238 @@ next_entry: | |||
1573 | kfree(buf); | 1487 | kfree(buf); |
1574 | return ret; | 1488 | return ret; |
1575 | } | 1489 | } |
1576 | EXPORT_SYMBOL(pccard_loop_tuple); | ||
1577 | 1490 | ||
1578 | 1491 | ||
1579 | /*====================================================================== | 1492 | /** |
1580 | 1493 | * pccard_validate_cis() - check whether card has a sensible CIS | |
1581 | This tries to determine if a card has a sensible CIS. It returns | 1494 | * @s: the struct pcmcia_socket we are to check |
1582 | the number of tuples in the CIS, or 0 if the CIS looks bad. The | 1495 | * @info: returns the number of tuples in the (valid) CIS, or 0 |
1583 | checks include making sure several critical tuples are present and | 1496 | * |
1584 | valid; seeing if the total number of tuples is reasonable; and | 1497 | * This tries to determine if a card has a sensible CIS. In @info, it |
1585 | looking for tuples that use reserved codes. | 1498 | * returns the number of tuples in the CIS, or 0 if the CIS looks bad. The |
1586 | 1499 | * checks include making sure several critical tuples are present and | |
1587 | ======================================================================*/ | 1500 | * valid; seeing if the total number of tuples is reasonable; and |
1588 | 1501 | * looking for tuples that use reserved codes. | |
1502 | * | ||
1503 | * The function returns 0 on success. | ||
1504 | */ | ||
1589 | int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *info) | 1505 | int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *info) |
1590 | { | 1506 | { |
1591 | tuple_t *tuple; | 1507 | tuple_t *tuple; |
1592 | cisparse_t *p; | 1508 | cisparse_t *p; |
1593 | unsigned int count = 0; | 1509 | unsigned int count = 0; |
1594 | int ret, reserved, dev_ok = 0, ident_ok = 0; | 1510 | int ret, reserved, dev_ok = 0, ident_ok = 0; |
1595 | 1511 | ||
1596 | if (!s) | 1512 | if (!s) |
1597 | return -EINVAL; | 1513 | return -EINVAL; |
1598 | 1514 | ||
1599 | tuple = kmalloc(sizeof(*tuple), GFP_KERNEL); | 1515 | /* We do not want to validate the CIS cache... */ |
1600 | if (tuple == NULL) { | 1516 | mutex_lock(&s->ops_mutex); |
1601 | dev_printk(KERN_WARNING, &s->dev, "no memory to validate CIS\n"); | 1517 | destroy_cis_cache(s); |
1602 | return -ENOMEM; | 1518 | mutex_unlock(&s->ops_mutex); |
1603 | } | ||
1604 | p = kmalloc(sizeof(*p), GFP_KERNEL); | ||
1605 | if (p == NULL) { | ||
1606 | kfree(tuple); | ||
1607 | dev_printk(KERN_WARNING, &s->dev, "no memory to validate CIS\n"); | ||
1608 | return -ENOMEM; | ||
1609 | } | ||
1610 | 1519 | ||
1611 | count = reserved = 0; | 1520 | tuple = kmalloc(sizeof(*tuple), GFP_KERNEL); |
1612 | tuple->DesiredTuple = RETURN_FIRST_TUPLE; | 1521 | if (tuple == NULL) { |
1613 | tuple->Attributes = TUPLE_RETURN_COMMON; | 1522 | dev_warn(&s->dev, "no memory to validate CIS\n"); |
1614 | ret = pccard_get_first_tuple(s, BIND_FN_ALL, tuple); | 1523 | return -ENOMEM; |
1615 | if (ret != 0) | 1524 | } |
1616 | goto done; | 1525 | p = kmalloc(sizeof(*p), GFP_KERNEL); |
1617 | 1526 | if (p == NULL) { | |
1618 | /* First tuple should be DEVICE; we should really have either that | 1527 | kfree(tuple); |
1619 | or a CFTABLE_ENTRY of some sort */ | 1528 | dev_warn(&s->dev, "no memory to validate CIS\n"); |
1620 | if ((tuple->TupleCode == CISTPL_DEVICE) || | 1529 | return -ENOMEM; |
1621 | (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_CFTABLE_ENTRY, p) == 0) || | 1530 | } |
1622 | (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_CFTABLE_ENTRY_CB, p) == 0)) | 1531 | |
1623 | dev_ok++; | 1532 | count = reserved = 0; |
1624 | 1533 | tuple->DesiredTuple = RETURN_FIRST_TUPLE; | |
1625 | /* All cards should have a MANFID tuple, and/or a VERS_1 or VERS_2 | 1534 | tuple->Attributes = TUPLE_RETURN_COMMON; |
1626 | tuple, for card identification. Certain old D-Link and Linksys | 1535 | ret = pccard_get_first_tuple(s, BIND_FN_ALL, tuple); |
1627 | cards have only a broken VERS_2 tuple; hence the bogus test. */ | ||
1628 | if ((pccard_read_tuple(s, BIND_FN_ALL, CISTPL_MANFID, p) == 0) || | ||
1629 | (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_VERS_1, p) == 0) || | ||
1630 | (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_VERS_2, p) != -ENOSPC)) | ||
1631 | ident_ok++; | ||
1632 | |||
1633 | if (!dev_ok && !ident_ok) | ||
1634 | goto done; | ||
1635 | |||
1636 | for (count = 1; count < MAX_TUPLES; count++) { | ||
1637 | ret = pccard_get_next_tuple(s, BIND_FN_ALL, tuple); | ||
1638 | if (ret != 0) | 1536 | if (ret != 0) |
1639 | break; | 1537 | goto done; |
1640 | if (((tuple->TupleCode > 0x23) && (tuple->TupleCode < 0x40)) || | 1538 | |
1641 | ((tuple->TupleCode > 0x47) && (tuple->TupleCode < 0x80)) || | 1539 | /* First tuple should be DEVICE; we should really have either that |
1642 | ((tuple->TupleCode > 0x90) && (tuple->TupleCode < 0xff))) | 1540 | or a CFTABLE_ENTRY of some sort */ |
1643 | reserved++; | 1541 | if ((tuple->TupleCode == CISTPL_DEVICE) || |
1644 | } | 1542 | (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_CFTABLE_ENTRY, p)) || |
1645 | if ((count == MAX_TUPLES) || (reserved > 5) || | 1543 | (!pccard_read_tuple(s, BIND_FN_ALL, CISTPL_CFTABLE_ENTRY_CB, p))) |
1646 | ((!dev_ok || !ident_ok) && (count > 10))) | 1544 | dev_ok++; |
1647 | count = 0; | 1545 | |
1546 | /* All cards should have a MANFID tuple, and/or a VERS_1 or VERS_2 | ||
1547 | tuple, for card identification. Certain old D-Link and Linksys | ||
1548 | cards have only a broken VERS_2 tuple; hence the bogus test. */ | ||
1549 | if ((pccard_read_tuple(s, BIND_FN_ALL, CISTPL_MANFID, p) == 0) || | ||
1550 | (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_VERS_1, p) == 0) || | ||
1551 | (pccard_read_tuple(s, BIND_FN_ALL, CISTPL_VERS_2, p) != -ENOSPC)) | ||
1552 | ident_ok++; | ||
1553 | |||
1554 | if (!dev_ok && !ident_ok) | ||
1555 | goto done; | ||
1556 | |||
1557 | for (count = 1; count < MAX_TUPLES; count++) { | ||
1558 | ret = pccard_get_next_tuple(s, BIND_FN_ALL, tuple); | ||
1559 | if (ret != 0) | ||
1560 | break; | ||
1561 | if (((tuple->TupleCode > 0x23) && (tuple->TupleCode < 0x40)) || | ||
1562 | ((tuple->TupleCode > 0x47) && (tuple->TupleCode < 0x80)) || | ||
1563 | ((tuple->TupleCode > 0x90) && (tuple->TupleCode < 0xff))) | ||
1564 | reserved++; | ||
1565 | } | ||
1566 | if ((count == MAX_TUPLES) || (reserved > 5) || | ||
1567 | ((!dev_ok || !ident_ok) && (count > 10))) | ||
1568 | count = 0; | ||
1569 | |||
1570 | ret = 0; | ||
1648 | 1571 | ||
1649 | done: | 1572 | done: |
1650 | if (info) | 1573 | /* invalidate CIS cache on failure */ |
1651 | *info = count; | 1574 | if (!dev_ok || !ident_ok || !count) { |
1652 | kfree(tuple); | 1575 | mutex_lock(&s->ops_mutex); |
1653 | kfree(p); | 1576 | destroy_cis_cache(s); |
1654 | return 0; | 1577 | mutex_unlock(&s->ops_mutex); |
1578 | ret = -EIO; | ||
1579 | } | ||
1580 | |||
1581 | if (info) | ||
1582 | *info = count; | ||
1583 | kfree(tuple); | ||
1584 | kfree(p); | ||
1585 | return ret; | ||
1655 | } | 1586 | } |
1656 | EXPORT_SYMBOL(pccard_validate_cis); | 1587 | |
1588 | |||
1589 | #define to_socket(_dev) container_of(_dev, struct pcmcia_socket, dev) | ||
1590 | |||
1591 | static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf, | ||
1592 | loff_t off, size_t count) | ||
1593 | { | ||
1594 | tuple_t tuple; | ||
1595 | int status, i; | ||
1596 | loff_t pointer = 0; | ||
1597 | ssize_t ret = 0; | ||
1598 | u_char *tuplebuffer; | ||
1599 | u_char *tempbuffer; | ||
1600 | |||
1601 | tuplebuffer = kmalloc(sizeof(u_char) * 256, GFP_KERNEL); | ||
1602 | if (!tuplebuffer) | ||
1603 | return -ENOMEM; | ||
1604 | |||
1605 | tempbuffer = kmalloc(sizeof(u_char) * 258, GFP_KERNEL); | ||
1606 | if (!tempbuffer) { | ||
1607 | ret = -ENOMEM; | ||
1608 | goto free_tuple; | ||
1609 | } | ||
1610 | |||
1611 | memset(&tuple, 0, sizeof(tuple_t)); | ||
1612 | |||
1613 | tuple.Attributes = TUPLE_RETURN_LINK | TUPLE_RETURN_COMMON; | ||
1614 | tuple.DesiredTuple = RETURN_FIRST_TUPLE; | ||
1615 | tuple.TupleOffset = 0; | ||
1616 | |||
1617 | status = pccard_get_first_tuple(s, BIND_FN_ALL, &tuple); | ||
1618 | while (!status) { | ||
1619 | tuple.TupleData = tuplebuffer; | ||
1620 | tuple.TupleDataMax = 255; | ||
1621 | memset(tuplebuffer, 0, sizeof(u_char) * 255); | ||
1622 | |||
1623 | status = pccard_get_tuple_data(s, &tuple); | ||
1624 | if (status) | ||
1625 | break; | ||
1626 | |||
1627 | if (off < (pointer + 2 + tuple.TupleDataLen)) { | ||
1628 | tempbuffer[0] = tuple.TupleCode & 0xff; | ||
1629 | tempbuffer[1] = tuple.TupleLink & 0xff; | ||
1630 | for (i = 0; i < tuple.TupleDataLen; i++) | ||
1631 | tempbuffer[i + 2] = tuplebuffer[i] & 0xff; | ||
1632 | |||
1633 | for (i = 0; i < (2 + tuple.TupleDataLen); i++) { | ||
1634 | if (((i + pointer) >= off) && | ||
1635 | (i + pointer) < (off + count)) { | ||
1636 | buf[ret] = tempbuffer[i]; | ||
1637 | ret++; | ||
1638 | } | ||
1639 | } | ||
1640 | } | ||
1641 | |||
1642 | pointer += 2 + tuple.TupleDataLen; | ||
1643 | |||
1644 | if (pointer >= (off + count)) | ||
1645 | break; | ||
1646 | |||
1647 | if (tuple.TupleCode == CISTPL_END) | ||
1648 | break; | ||
1649 | status = pccard_get_next_tuple(s, BIND_FN_ALL, &tuple); | ||
1650 | } | ||
1651 | |||
1652 | kfree(tempbuffer); | ||
1653 | free_tuple: | ||
1654 | kfree(tuplebuffer); | ||
1655 | |||
1656 | return ret; | ||
1657 | } | ||
1658 | |||
1659 | |||
1660 | static ssize_t pccard_show_cis(struct kobject *kobj, | ||
1661 | struct bin_attribute *bin_attr, | ||
1662 | char *buf, loff_t off, size_t count) | ||
1663 | { | ||
1664 | unsigned int size = 0x200; | ||
1665 | |||
1666 | if (off >= size) | ||
1667 | count = 0; | ||
1668 | else { | ||
1669 | struct pcmcia_socket *s; | ||
1670 | unsigned int chains; | ||
1671 | |||
1672 | if (off + count > size) | ||
1673 | count = size - off; | ||
1674 | |||
1675 | s = to_socket(container_of(kobj, struct device, kobj)); | ||
1676 | |||
1677 | if (!(s->state & SOCKET_PRESENT)) | ||
1678 | return -ENODEV; | ||
1679 | if (pccard_validate_cis(s, &chains)) | ||
1680 | return -EIO; | ||
1681 | if (!chains) | ||
1682 | return -ENODATA; | ||
1683 | |||
1684 | count = pccard_extract_cis(s, buf, off, count); | ||
1685 | } | ||
1686 | |||
1687 | return count; | ||
1688 | } | ||
1689 | |||
1690 | |||
1691 | static ssize_t pccard_store_cis(struct kobject *kobj, | ||
1692 | struct bin_attribute *bin_attr, | ||
1693 | char *buf, loff_t off, size_t count) | ||
1694 | { | ||
1695 | struct pcmcia_socket *s; | ||
1696 | int error; | ||
1697 | |||
1698 | s = to_socket(container_of(kobj, struct device, kobj)); | ||
1699 | |||
1700 | if (off) | ||
1701 | return -EINVAL; | ||
1702 | |||
1703 | if (count >= CISTPL_MAX_CIS_SIZE) | ||
1704 | return -EINVAL; | ||
1705 | |||
1706 | if (!(s->state & SOCKET_PRESENT)) | ||
1707 | return -ENODEV; | ||
1708 | |||
1709 | error = pcmcia_replace_cis(s, buf, count); | ||
1710 | if (error) | ||
1711 | return -EIO; | ||
1712 | |||
1713 | pcmcia_parse_uevents(s, PCMCIA_UEVENT_REQUERY); | ||
1714 | |||
1715 | return count; | ||
1716 | } | ||
1717 | |||
1718 | |||
1719 | struct bin_attribute pccard_cis_attr = { | ||
1720 | .attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR }, | ||
1721 | .size = 0x200, | ||
1722 | .read = pccard_show_cis, | ||
1723 | .write = pccard_store_cis, | ||
1724 | }; | ||