diff options
| -rw-r--r-- | drivers/pcmcia/cistpl.c | 63 |
1 files changed, 44 insertions, 19 deletions
diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 602f574898dc..2f3622dd4b69 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c | |||
| @@ -283,30 +283,32 @@ void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr, | |||
| 283 | 283 | ||
| 284 | ======================================================================*/ | 284 | ======================================================================*/ |
| 285 | 285 | ||
| 286 | 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, |
| 287 | size_t len, void *ptr) | 287 | size_t len, void *ptr) |
| 288 | { | 288 | { |
| 289 | struct cis_cache_entry *cis; | 289 | struct cis_cache_entry *cis; |
| 290 | int ret; | 290 | int ret = 0; |
| 291 | 291 | ||
| 292 | if (s->state & SOCKET_CARDBUS) | 292 | if (s->state & SOCKET_CARDBUS) |
| 293 | return; | 293 | return -EINVAL; |
| 294 | 294 | ||
| 295 | mutex_lock(&s->ops_mutex); | 295 | mutex_lock(&s->ops_mutex); |
| 296 | if (s->fake_cis) { | 296 | if (s->fake_cis) { |
| 297 | if (s->fake_cis_len >= addr+len) | 297 | if (s->fake_cis_len >= addr+len) |
| 298 | memcpy(ptr, s->fake_cis+addr, len); | 298 | memcpy(ptr, s->fake_cis+addr, len); |
| 299 | else | 299 | else { |
| 300 | memset(ptr, 0xff, len); | 300 | memset(ptr, 0xff, len); |
| 301 | ret = -EINVAL; | ||
| 302 | } | ||
| 301 | mutex_unlock(&s->ops_mutex); | 303 | mutex_unlock(&s->ops_mutex); |
| 302 | return; | 304 | return ret; |
| 303 | } | 305 | } |
| 304 | 306 | ||
| 305 | list_for_each_entry(cis, &s->cis_cache, node) { | 307 | list_for_each_entry(cis, &s->cis_cache, node) { |
| 306 | if (cis->addr == addr && cis->len == len && cis->attr == attr) { | 308 | if (cis->addr == addr && cis->len == len && cis->attr == attr) { |
| 307 | memcpy(ptr, cis->cache, len); | 309 | memcpy(ptr, cis->cache, len); |
| 308 | mutex_unlock(&s->ops_mutex); | 310 | mutex_unlock(&s->ops_mutex); |
| 309 | return; | 311 | return 0; |
| 310 | } | 312 | } |
| 311 | } | 313 | } |
| 312 | mutex_unlock(&s->ops_mutex); | 314 | mutex_unlock(&s->ops_mutex); |
| @@ -326,6 +328,7 @@ static void read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr, | |||
| 326 | mutex_unlock(&s->ops_mutex); | 328 | mutex_unlock(&s->ops_mutex); |
| 327 | } | 329 | } |
| 328 | } | 330 | } |
| 331 | return ret; | ||
| 329 | } | 332 | } |
| 330 | 333 | ||
| 331 | static void | 334 | static void |
| @@ -374,6 +377,7 @@ int verify_cis_cache(struct pcmcia_socket *s) | |||
| 374 | { | 377 | { |
| 375 | struct cis_cache_entry *cis; | 378 | struct cis_cache_entry *cis; |
| 376 | char *buf; | 379 | char *buf; |
| 380 | int ret; | ||
| 377 | 381 | ||
| 378 | if (s->state & SOCKET_CARDBUS) | 382 | if (s->state & SOCKET_CARDBUS) |
| 379 | return -EINVAL; | 383 | return -EINVAL; |
| @@ -390,9 +394,8 @@ int verify_cis_cache(struct pcmcia_socket *s) | |||
| 390 | if (len > 256) | 394 | if (len > 256) |
| 391 | len = 256; | 395 | len = 256; |
| 392 | 396 | ||
| 393 | pcmcia_read_cis_mem(s, cis->attr, cis->addr, len, buf); | 397 | ret = pcmcia_read_cis_mem(s, cis->attr, cis->addr, len, buf); |
| 394 | 398 | if (ret || memcmp(buf, cis->cache, len) != 0) { | |
| 395 | if (memcmp(buf, cis->cache, len) != 0) { | ||
| 396 | kfree(buf); | 399 | kfree(buf); |
| 397 | return -1; | 400 | return -1; |
| 398 | } | 401 | } |
| @@ -425,6 +428,7 @@ int pcmcia_replace_cis(struct pcmcia_socket *s, | |||
| 425 | } | 428 | } |
| 426 | s->fake_cis_len = len; | 429 | s->fake_cis_len = len; |
| 427 | memcpy(s->fake_cis, data, len); | 430 | memcpy(s->fake_cis, data, len); |
| 431 | dev_info(&s->dev, "Using replacement CIS\n"); | ||
| 428 | mutex_unlock(&s->ops_mutex); | 432 | mutex_unlock(&s->ops_mutex); |
| 429 | return 0; | 433 | return 0; |
| 430 | } | 434 | } |
| @@ -478,11 +482,14 @@ static int follow_link(struct pcmcia_socket *s, tuple_t *tuple) | |||
| 478 | { | 482 | { |
| 479 | u_char link[5]; | 483 | u_char link[5]; |
| 480 | u_int ofs; | 484 | u_int ofs; |
| 485 | int ret; | ||
| 481 | 486 | ||
| 482 | if (MFC_FN(tuple->Flags)) { | 487 | if (MFC_FN(tuple->Flags)) { |
| 483 | /* Get indirect link from the MFC tuple */ | 488 | /* Get indirect link from the MFC tuple */ |
| 484 | read_cis_cache(s, LINK_SPACE(tuple->Flags), | 489 | ret = read_cis_cache(s, LINK_SPACE(tuple->Flags), |
| 485 | tuple->LinkOffset, 5, link); | 490 | tuple->LinkOffset, 5, link); |
| 491 | if (ret) | ||
| 492 | return -1; | ||
| 486 | ofs = get_unaligned_le32(link + 1); | 493 | ofs = get_unaligned_le32(link + 1); |
| 487 | SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR); | 494 | SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR); |
| 488 | /* Move to the next indirect link */ | 495 | /* Move to the next indirect link */ |
| @@ -498,7 +505,9 @@ static int follow_link(struct pcmcia_socket *s, tuple_t *tuple) | |||
| 498 | if (SPACE(tuple->Flags)) { | 505 | if (SPACE(tuple->Flags)) { |
| 499 | /* 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 |
| 500 | link offset incorrectly, so we check the right spot... */ | 507 | link offset incorrectly, so we check the right spot... */ |
| 501 | 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; | ||
| 502 | if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) && | 511 | if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) && |
| 503 | (strncmp(link+2, "CIS", 3) == 0)) | 512 | (strncmp(link+2, "CIS", 3) == 0)) |
| 504 | return ofs; | 513 | return ofs; |
| @@ -506,7 +515,9 @@ static int follow_link(struct pcmcia_socket *s, tuple_t *tuple) | |||
| 506 | /* Then, we try the wrong spot... */ | 515 | /* Then, we try the wrong spot... */ |
| 507 | ofs = ofs >> 1; | 516 | ofs = ofs >> 1; |
| 508 | } | 517 | } |
| 509 | 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; | ||
| 510 | if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) && | 521 | if ((link[0] == CISTPL_LINKTARGET) && (link[1] >= 3) && |
| 511 | (strncmp(link+2, "CIS", 3) == 0)) | 522 | (strncmp(link+2, "CIS", 3) == 0)) |
| 512 | return ofs; | 523 | return ofs; |
| @@ -518,6 +529,7 @@ int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, tuple_ | |||
| 518 | { | 529 | { |
| 519 | u_char link[2], tmp; | 530 | u_char link[2], tmp; |
| 520 | int ofs, i, attr; | 531 | int ofs, i, attr; |
| 532 | int ret; | ||
| 521 | 533 | ||
| 522 | if (!s) | 534 | if (!s) |
| 523 | return -EINVAL; | 535 | return -EINVAL; |
| @@ -532,7 +544,9 @@ int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, tuple_ | |||
| 532 | if (link[1] == 0xff) { | 544 | if (link[1] == 0xff) { |
| 533 | link[0] = CISTPL_END; | 545 | link[0] = CISTPL_END; |
| 534 | } else { | 546 | } else { |
| 535 | read_cis_cache(s, attr, ofs, 2, link); | 547 | ret = read_cis_cache(s, attr, ofs, 2, link); |
| 548 | if (ret) | ||
| 549 | return -1; | ||
| 536 | if (link[0] == CISTPL_NULL) { | 550 | if (link[0] == CISTPL_NULL) { |
| 537 | ofs++; continue; | 551 | ofs++; continue; |
| 538 | } | 552 | } |
| @@ -544,7 +558,9 @@ int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, tuple_ | |||
| 544 | if (ofs < 0) | 558 | if (ofs < 0) |
| 545 | return -ENOSPC; | 559 | return -ENOSPC; |
| 546 | attr = SPACE(tuple->Flags); | 560 | attr = SPACE(tuple->Flags); |
| 547 | read_cis_cache(s, attr, ofs, 2, link); | 561 | ret = read_cis_cache(s, attr, ofs, 2, link); |
| 562 | if (ret) | ||
| 563 | return -1; | ||
| 548 | } | 564 | } |
| 549 | 565 | ||
| 550 | /* Is this a link tuple? Make a note of it */ | 566 | /* Is this a link tuple? Make a note of it */ |
| @@ -558,12 +574,16 @@ int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, tuple_ | |||
| 558 | case CISTPL_LONGLINK_A: | 574 | case CISTPL_LONGLINK_A: |
| 559 | HAS_LINK(tuple->Flags) = 1; | 575 | HAS_LINK(tuple->Flags) = 1; |
| 560 | LINK_SPACE(tuple->Flags) = attr | IS_ATTR; | 576 | LINK_SPACE(tuple->Flags) = attr | IS_ATTR; |
| 561 | 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; | ||
| 562 | break; | 580 | break; |
| 563 | case CISTPL_LONGLINK_C: | 581 | case CISTPL_LONGLINK_C: |
| 564 | HAS_LINK(tuple->Flags) = 1; | 582 | HAS_LINK(tuple->Flags) = 1; |
| 565 | LINK_SPACE(tuple->Flags) = attr & ~IS_ATTR; | 583 | LINK_SPACE(tuple->Flags) = attr & ~IS_ATTR; |
| 566 | 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; | ||
| 567 | break; | 587 | break; |
| 568 | case CISTPL_INDIRECT: | 588 | case CISTPL_INDIRECT: |
| 569 | HAS_LINK(tuple->Flags) = 1; | 589 | HAS_LINK(tuple->Flags) = 1; |
| @@ -575,7 +595,9 @@ int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, tuple_ | |||
| 575 | LINK_SPACE(tuple->Flags) = attr; | 595 | LINK_SPACE(tuple->Flags) = attr; |
| 576 | if (function == BIND_FN_ALL) { | 596 | if (function == BIND_FN_ALL) { |
| 577 | /* Follow all the MFC links */ | 597 | /* Follow all the MFC links */ |
| 578 | 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; | ||
| 579 | MFC_FN(tuple->Flags) = tmp; | 601 | MFC_FN(tuple->Flags) = tmp; |
| 580 | } else { | 602 | } else { |
| 581 | /* Follow exactly one of the links */ | 603 | /* Follow exactly one of the links */ |
| @@ -616,6 +638,7 @@ int pccard_get_next_tuple(struct pcmcia_socket *s, unsigned int function, tuple_ | |||
| 616 | 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) |
| 617 | { | 639 | { |
| 618 | u_int len; | 640 | u_int len; |
| 641 | int ret; | ||
| 619 | 642 | ||
| 620 | if (!s) | 643 | if (!s) |
| 621 | return -EINVAL; | 644 | return -EINVAL; |
| @@ -626,9 +649,11 @@ int pccard_get_tuple_data(struct pcmcia_socket *s, tuple_t *tuple) | |||
| 626 | tuple->TupleDataLen = tuple->TupleLink; | 649 | tuple->TupleDataLen = tuple->TupleLink; |
| 627 | if (len == 0) | 650 | if (len == 0) |
| 628 | return 0; | 651 | return 0; |
| 629 | read_cis_cache(s, SPACE(tuple->Flags), | 652 | ret = read_cis_cache(s, SPACE(tuple->Flags), |
| 630 | tuple->CISOffset + tuple->TupleOffset, | 653 | tuple->CISOffset + tuple->TupleOffset, |
| 631 | _MIN(len, tuple->TupleDataMax), tuple->TupleData); | 654 | _MIN(len, tuple->TupleDataMax), tuple->TupleData); |
| 655 | if (ret) | ||
| 656 | return -1; | ||
| 632 | return 0; | 657 | return 0; |
| 633 | } | 658 | } |
| 634 | 659 | ||
