diff options
Diffstat (limited to 'drivers/pcmcia')
-rw-r--r-- | drivers/pcmcia/cs_internal.h | 2 | ||||
-rw-r--r-- | drivers/pcmcia/ds.c | 4 | ||||
-rw-r--r-- | drivers/pcmcia/rsrc_mgr.c | 6 | ||||
-rw-r--r-- | drivers/pcmcia/rsrc_nonstatic.c | 123 |
4 files changed, 74 insertions, 61 deletions
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 55867bc7f199..634426b78f2c 100644 --- a/drivers/pcmcia/cs_internal.h +++ b/drivers/pcmcia/cs_internal.h | |||
@@ -117,7 +117,7 @@ int verify_cis_cache(struct pcmcia_socket *s); | |||
117 | int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function, cisdata_t code, void *parse); | 117 | int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function, cisdata_t code, void *parse); |
118 | 118 | ||
119 | /* In rsrc_mgr */ | 119 | /* In rsrc_mgr */ |
120 | void pcmcia_validate_mem(struct pcmcia_socket *s); | 120 | int pcmcia_validate_mem(struct pcmcia_socket *s); |
121 | struct resource *pcmcia_find_io_region(unsigned long base, int num, unsigned long align, | 121 | struct resource *pcmcia_find_io_region(unsigned long base, int num, unsigned long align, |
122 | struct pcmcia_socket *s); | 122 | struct pcmcia_socket *s); |
123 | int pcmcia_adjust_io_region(struct resource *res, unsigned long r_start, | 123 | int pcmcia_adjust_io_region(struct resource *res, unsigned long r_start, |
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 6fb76399547e..b120794c03a9 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c | |||
@@ -583,7 +583,9 @@ static int pcmcia_card_add(struct pcmcia_socket *s) | |||
583 | if (!(s->resource_setup_done)) | 583 | if (!(s->resource_setup_done)) |
584 | return -EAGAIN; /* try again, but later... */ | 584 | return -EAGAIN; /* try again, but later... */ |
585 | 585 | ||
586 | pcmcia_validate_mem(s); | 586 | if (pcmcia_validate_mem(s)) |
587 | return -EAGAIN; /* try again, but later... */ | ||
588 | |||
587 | ret = pccard_validate_cis(s, BIND_FN_ALL, &cisinfo); | 589 | ret = pccard_validate_cis(s, BIND_FN_ALL, &cisinfo); |
588 | if (ret || !cisinfo.Chains) { | 590 | if (ret || !cisinfo.Chains) { |
589 | ds_dbg(0, "invalid CIS or invalid resources\n"); | 591 | ds_dbg(0, "invalid CIS or invalid resources\n"); |
diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index 0668384ebc8b..b02598a5a912 100644 --- a/drivers/pcmcia/rsrc_mgr.c +++ b/drivers/pcmcia/rsrc_mgr.c | |||
@@ -98,10 +98,12 @@ int pcmcia_adjust_resource_info(adjust_t *adj) | |||
98 | } | 98 | } |
99 | EXPORT_SYMBOL(pcmcia_adjust_resource_info); | 99 | EXPORT_SYMBOL(pcmcia_adjust_resource_info); |
100 | 100 | ||
101 | void pcmcia_validate_mem(struct pcmcia_socket *s) | 101 | int pcmcia_validate_mem(struct pcmcia_socket *s) |
102 | { | 102 | { |
103 | if (s->resource_ops->validate_mem) | 103 | if (s->resource_ops->validate_mem) |
104 | s->resource_ops->validate_mem(s); | 104 | return s->resource_ops->validate_mem(s); |
105 | /* if there is no callback, we can assume that everything is OK */ | ||
106 | return 0; | ||
105 | } | 107 | } |
106 | EXPORT_SYMBOL(pcmcia_validate_mem); | 108 | EXPORT_SYMBOL(pcmcia_validate_mem); |
107 | 109 | ||
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index 00960a379b9c..ebfcab5df9ea 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c | |||
@@ -407,56 +407,62 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s) | |||
407 | 407 | ||
408 | static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s) | 408 | static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s) |
409 | { | 409 | { |
410 | struct socket_data *s_data = s->resource_data; | 410 | struct socket_data *s_data = s->resource_data; |
411 | u_long ok; | 411 | u_long ok; |
412 | if (m == &s_data->mem_db) | 412 | if (m == &s_data->mem_db) |
413 | return 0; | 413 | return 0; |
414 | ok = inv_probe(m->next, s); | 414 | ok = inv_probe(m->next, s); |
415 | if (ok) { | 415 | if (ok) { |
416 | if (m->base >= 0x100000) | 416 | if (m->base >= 0x100000) |
417 | sub_interval(&s_data->mem_db, m->base, m->num); | 417 | sub_interval(&s_data->mem_db, m->base, m->num); |
418 | return ok; | 418 | return ok; |
419 | } | 419 | } |
420 | if (m->base < 0x100000) | 420 | if (m->base < 0x100000) |
421 | return 0; | 421 | return 0; |
422 | return do_mem_probe(m->base, m->num, s); | 422 | return do_mem_probe(m->base, m->num, s); |
423 | } | 423 | } |
424 | 424 | ||
425 | static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) | 425 | static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) |
426 | { | 426 | { |
427 | struct resource_map *m, mm; | 427 | struct resource_map *m, mm; |
428 | static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 }; | 428 | static unsigned char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 }; |
429 | u_long b, i, ok = 0; | 429 | unsigned long b, i, ok = 0; |
430 | struct socket_data *s_data = s->resource_data; | 430 | struct socket_data *s_data = s->resource_data; |
431 | 431 | ||
432 | /* We do up to four passes through the list */ | 432 | /* We do up to four passes through the list */ |
433 | if (probe_mask & MEM_PROBE_HIGH) { | 433 | if (probe_mask & MEM_PROBE_HIGH) { |
434 | if (inv_probe(s_data->mem_db.next, s) > 0) | 434 | if (inv_probe(s_data->mem_db.next, s) > 0) |
435 | return; | 435 | return 0; |
436 | printk(KERN_NOTICE "cs: warning: no high memory space " | 436 | printk(KERN_NOTICE "cs: warning: no high memory space " |
437 | "available!\n"); | 437 | "available!\n"); |
438 | } | 438 | return -ENODEV; |
439 | if ((probe_mask & MEM_PROBE_LOW) == 0) | ||
440 | return; | ||
441 | for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) { | ||
442 | mm = *m; | ||
443 | /* Only probe < 1 MB */ | ||
444 | if (mm.base >= 0x100000) continue; | ||
445 | if ((mm.base | mm.num) & 0xffff) { | ||
446 | ok += do_mem_probe(mm.base, mm.num, s); | ||
447 | continue; | ||
448 | } | 439 | } |
449 | /* Special probe for 64K-aligned block */ | 440 | |
450 | for (i = 0; i < 4; i++) { | 441 | for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) { |
451 | b = order[i] << 12; | 442 | mm = *m; |
452 | if ((b >= mm.base) && (b+0x10000 <= mm.base+mm.num)) { | 443 | /* Only probe < 1 MB */ |
453 | if (ok >= mem_limit) | 444 | if (mm.base >= 0x100000) |
454 | sub_interval(&s_data->mem_db, b, 0x10000); | 445 | continue; |
455 | else | 446 | if ((mm.base | mm.num) & 0xffff) { |
456 | ok += do_mem_probe(b, 0x10000, s); | 447 | ok += do_mem_probe(mm.base, mm.num, s); |
457 | } | 448 | continue; |
449 | } | ||
450 | /* Special probe for 64K-aligned block */ | ||
451 | for (i = 0; i < 4; i++) { | ||
452 | b = order[i] << 12; | ||
453 | if ((b >= mm.base) && (b+0x10000 <= mm.base+mm.num)) { | ||
454 | if (ok >= mem_limit) | ||
455 | sub_interval(&s_data->mem_db, b, 0x10000); | ||
456 | else | ||
457 | ok += do_mem_probe(b, 0x10000, s); | ||
458 | } | ||
459 | } | ||
458 | } | 460 | } |
459 | } | 461 | |
462 | if (ok > 0) | ||
463 | return 0; | ||
464 | |||
465 | return -ENODEV; | ||
460 | } | 466 | } |
461 | 467 | ||
462 | #else /* CONFIG_PCMCIA_PROBE */ | 468 | #else /* CONFIG_PCMCIA_PROBE */ |
@@ -478,27 +484,30 @@ static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) | |||
478 | /* | 484 | /* |
479 | * Locking note: Must be called with skt_sem held! | 485 | * Locking note: Must be called with skt_sem held! |
480 | */ | 486 | */ |
481 | static void pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s) | 487 | static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s) |
482 | { | 488 | { |
483 | struct socket_data *s_data = s->resource_data; | 489 | struct socket_data *s_data = s->resource_data; |
484 | if (probe_mem) { | 490 | unsigned int probe_mask = MEM_PROBE_LOW; |
485 | unsigned int probe_mask; | 491 | int ret = 0; |
486 | 492 | ||
487 | down(&rsrc_sem); | 493 | if (!probe_mem) |
494 | return 0; | ||
488 | 495 | ||
489 | probe_mask = MEM_PROBE_LOW; | 496 | down(&rsrc_sem); |
490 | if (s->features & SS_CAP_PAGE_REGS) | ||
491 | probe_mask = MEM_PROBE_HIGH; | ||
492 | 497 | ||
493 | if (probe_mask & ~s_data->rsrc_mem_probe) { | 498 | if (s->features & SS_CAP_PAGE_REGS) |
499 | probe_mask = MEM_PROBE_HIGH; | ||
500 | |||
501 | if (probe_mask & ~s_data->rsrc_mem_probe) { | ||
502 | if (s->state & SOCKET_PRESENT) | ||
503 | ret = validate_mem(s, probe_mask); | ||
504 | if (!ret) | ||
494 | s_data->rsrc_mem_probe |= probe_mask; | 505 | s_data->rsrc_mem_probe |= probe_mask; |
506 | } | ||
495 | 507 | ||
496 | if (s->state & SOCKET_PRESENT) | 508 | up(&rsrc_sem); |
497 | validate_mem(s, probe_mask); | ||
498 | } | ||
499 | 509 | ||
500 | up(&rsrc_sem); | 510 | return ret; |
501 | } | ||
502 | } | 511 | } |
503 | 512 | ||
504 | struct pcmcia_align_data { | 513 | struct pcmcia_align_data { |