diff options
Diffstat (limited to 'drivers/pcmcia/ds.c')
-rw-r--r-- | drivers/pcmcia/ds.c | 249 |
1 files changed, 163 insertions, 86 deletions
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index bb96ce1db08c..ae10d1eed65e 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c | |||
@@ -10,10 +10,9 @@ | |||
10 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. | 10 | * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. |
11 | * | 11 | * |
12 | * (C) 1999 David A. Hinds | 12 | * (C) 1999 David A. Hinds |
13 | * (C) 2003 - 2005 Dominik Brodowski | 13 | * (C) 2003 - 2006 Dominik Brodowski |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/config.h> | ||
17 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
18 | #include <linux/module.h> | 17 | #include <linux/module.h> |
19 | #include <linux/init.h> | 18 | #include <linux/init.h> |
@@ -23,6 +22,7 @@ | |||
23 | #include <linux/workqueue.h> | 22 | #include <linux/workqueue.h> |
24 | #include <linux/crc32.h> | 23 | #include <linux/crc32.h> |
25 | #include <linux/firmware.h> | 24 | #include <linux/firmware.h> |
25 | #include <linux/kref.h> | ||
26 | 26 | ||
27 | #define IN_CARD_SERVICES | 27 | #define IN_CARD_SERVICES |
28 | #include <pcmcia/cs_types.h> | 28 | #include <pcmcia/cs_types.h> |
@@ -343,12 +343,19 @@ void pcmcia_put_dev(struct pcmcia_device *p_dev) | |||
343 | put_device(&p_dev->dev); | 343 | put_device(&p_dev->dev); |
344 | } | 344 | } |
345 | 345 | ||
346 | static void pcmcia_release_function(struct kref *ref) | ||
347 | { | ||
348 | struct config_t *c = container_of(ref, struct config_t, ref); | ||
349 | kfree(c); | ||
350 | } | ||
351 | |||
346 | static void pcmcia_release_dev(struct device *dev) | 352 | static void pcmcia_release_dev(struct device *dev) |
347 | { | 353 | { |
348 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | 354 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); |
349 | ds_dbg(1, "releasing dev %p\n", p_dev); | 355 | ds_dbg(1, "releasing dev %p\n", p_dev); |
350 | pcmcia_put_socket(p_dev->socket); | 356 | pcmcia_put_socket(p_dev->socket); |
351 | kfree(p_dev->devname); | 357 | kfree(p_dev->devname); |
358 | kref_put(&p_dev->function_config->ref, pcmcia_release_function); | ||
352 | kfree(p_dev); | 359 | kfree(p_dev); |
353 | } | 360 | } |
354 | 361 | ||
@@ -377,29 +384,12 @@ static int pcmcia_device_probe(struct device * dev) | |||
377 | p_drv = to_pcmcia_drv(dev->driver); | 384 | p_drv = to_pcmcia_drv(dev->driver); |
378 | s = p_dev->socket; | 385 | s = p_dev->socket; |
379 | 386 | ||
380 | if ((!p_drv->probe) || (!try_module_get(p_drv->owner))) { | 387 | if ((!p_drv->probe) || (!p_dev->function_config) || |
388 | (!try_module_get(p_drv->owner))) { | ||
381 | ret = -EINVAL; | 389 | ret = -EINVAL; |
382 | goto put_dev; | 390 | goto put_dev; |
383 | } | 391 | } |
384 | 392 | ||
385 | p_dev->state &= ~CLIENT_UNBOUND; | ||
386 | |||
387 | /* set up the device configuration, if it hasn't been done before */ | ||
388 | if (!s->functions) { | ||
389 | cistpl_longlink_mfc_t mfc; | ||
390 | if (pccard_read_tuple(s, p_dev->func, CISTPL_LONGLINK_MFC, | ||
391 | &mfc) == CS_SUCCESS) | ||
392 | s->functions = mfc.nfn; | ||
393 | else | ||
394 | s->functions = 1; | ||
395 | s->config = kzalloc(sizeof(config_t) * s->functions, | ||
396 | GFP_KERNEL); | ||
397 | if (!s->config) { | ||
398 | ret = -ENOMEM; | ||
399 | goto put_module; | ||
400 | } | ||
401 | } | ||
402 | |||
403 | ret = p_drv->probe(p_dev); | 393 | ret = p_drv->probe(p_dev); |
404 | if (ret) | 394 | if (ret) |
405 | goto put_module; | 395 | goto put_module; |
@@ -425,15 +415,61 @@ static int pcmcia_device_probe(struct device * dev) | |||
425 | } | 415 | } |
426 | 416 | ||
427 | 417 | ||
418 | /* | ||
419 | * Removes a PCMCIA card from the device tree and socket list. | ||
420 | */ | ||
421 | static void pcmcia_card_remove(struct pcmcia_socket *s, struct pcmcia_device *leftover) | ||
422 | { | ||
423 | struct pcmcia_device *p_dev; | ||
424 | struct pcmcia_device *tmp; | ||
425 | unsigned long flags; | ||
426 | |||
427 | ds_dbg(2, "unbind_request(%d)\n", s->sock); | ||
428 | |||
429 | |||
430 | if (!leftover) | ||
431 | s->device_count = 0; | ||
432 | else | ||
433 | s->device_count = 1; | ||
434 | |||
435 | /* unregister all pcmcia_devices registered with this socket, except leftover */ | ||
436 | list_for_each_entry_safe(p_dev, tmp, &s->devices_list, socket_device_list) { | ||
437 | if (p_dev == leftover) | ||
438 | continue; | ||
439 | |||
440 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | ||
441 | list_del(&p_dev->socket_device_list); | ||
442 | p_dev->_removed=1; | ||
443 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
444 | |||
445 | device_unregister(&p_dev->dev); | ||
446 | } | ||
447 | |||
448 | return; | ||
449 | } | ||
450 | |||
451 | |||
428 | static int pcmcia_device_remove(struct device * dev) | 452 | static int pcmcia_device_remove(struct device * dev) |
429 | { | 453 | { |
430 | struct pcmcia_device *p_dev; | 454 | struct pcmcia_device *p_dev; |
431 | struct pcmcia_driver *p_drv; | 455 | struct pcmcia_driver *p_drv; |
456 | struct pcmcia_device_id *did; | ||
432 | int i; | 457 | int i; |
433 | 458 | ||
434 | /* detach the "instance" */ | ||
435 | p_dev = to_pcmcia_dev(dev); | 459 | p_dev = to_pcmcia_dev(dev); |
436 | p_drv = to_pcmcia_drv(dev->driver); | 460 | p_drv = to_pcmcia_drv(dev->driver); |
461 | |||
462 | /* If we're removing the primary module driving a | ||
463 | * pseudo multi-function card, we need to unbind | ||
464 | * all devices | ||
465 | */ | ||
466 | did = (struct pcmcia_device_id *) p_dev->dev.driver_data; | ||
467 | if (did && (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) && | ||
468 | (p_dev->socket->device_count != 0) && | ||
469 | (p_dev->device_no == 0)) | ||
470 | pcmcia_card_remove(p_dev->socket, p_dev); | ||
471 | |||
472 | /* detach the "instance" */ | ||
437 | if (!p_drv) | 473 | if (!p_drv) |
438 | return 0; | 474 | return 0; |
439 | 475 | ||
@@ -441,17 +477,16 @@ static int pcmcia_device_remove(struct device * dev) | |||
441 | p_drv->remove(p_dev); | 477 | p_drv->remove(p_dev); |
442 | 478 | ||
443 | /* check for proper unloading */ | 479 | /* check for proper unloading */ |
444 | if (p_dev->state & (CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED)) | 480 | if (p_dev->_irq || p_dev->_io || p_dev->_locked) |
445 | printk(KERN_INFO "pcmcia: driver %s did not release config properly\n", | 481 | printk(KERN_INFO "pcmcia: driver %s did not release config properly\n", |
446 | p_drv->drv.name); | 482 | p_drv->drv.name); |
447 | 483 | ||
448 | for (i = 0; i < MAX_WIN; i++) | 484 | for (i = 0; i < MAX_WIN; i++) |
449 | if (p_dev->state & CLIENT_WIN_REQ(i)) | 485 | if (p_dev->_win & CLIENT_WIN_REQ(i)) |
450 | printk(KERN_INFO "pcmcia: driver %s did not release windows properly\n", | 486 | printk(KERN_INFO "pcmcia: driver %s did not release windows properly\n", |
451 | p_drv->drv.name); | 487 | p_drv->drv.name); |
452 | 488 | ||
453 | /* references from pcmcia_probe_device */ | 489 | /* references from pcmcia_probe_device */ |
454 | p_dev->state = CLIENT_UNBOUND; | ||
455 | pcmcia_put_dev(p_dev); | 490 | pcmcia_put_dev(p_dev); |
456 | module_put(p_drv->owner); | 491 | module_put(p_drv->owner); |
457 | 492 | ||
@@ -460,37 +495,6 @@ static int pcmcia_device_remove(struct device * dev) | |||
460 | 495 | ||
461 | 496 | ||
462 | /* | 497 | /* |
463 | * Removes a PCMCIA card from the device tree and socket list. | ||
464 | */ | ||
465 | static void pcmcia_card_remove(struct pcmcia_socket *s) | ||
466 | { | ||
467 | struct pcmcia_device *p_dev; | ||
468 | unsigned long flags; | ||
469 | |||
470 | ds_dbg(2, "unbind_request(%d)\n", s->sock); | ||
471 | |||
472 | s->device_count = 0; | ||
473 | |||
474 | for (;;) { | ||
475 | /* unregister all pcmcia_devices registered with this socket*/ | ||
476 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | ||
477 | if (list_empty(&s->devices_list)) { | ||
478 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
479 | return; | ||
480 | } | ||
481 | p_dev = list_entry((&s->devices_list)->next, struct pcmcia_device, socket_device_list); | ||
482 | list_del(&p_dev->socket_device_list); | ||
483 | p_dev->state |= CLIENT_STALE; | ||
484 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
485 | |||
486 | device_unregister(&p_dev->dev); | ||
487 | } | ||
488 | |||
489 | return; | ||
490 | } /* unbind_request */ | ||
491 | |||
492 | |||
493 | /* | ||
494 | * pcmcia_device_query -- determine information about a pcmcia device | 498 | * pcmcia_device_query -- determine information about a pcmcia device |
495 | */ | 499 | */ |
496 | static int pcmcia_device_query(struct pcmcia_device *p_dev) | 500 | static int pcmcia_device_query(struct pcmcia_device *p_dev) |
@@ -546,7 +550,7 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev) | |||
546 | tmp = vers1->str + vers1->ofs[i]; | 550 | tmp = vers1->str + vers1->ofs[i]; |
547 | 551 | ||
548 | length = strlen(tmp) + 1; | 552 | length = strlen(tmp) + 1; |
549 | if ((length < 3) || (length > 255)) | 553 | if ((length < 2) || (length > 255)) |
550 | continue; | 554 | continue; |
551 | 555 | ||
552 | p_dev->prod_id[i] = kmalloc(sizeof(char) * length, | 556 | p_dev->prod_id[i] = kmalloc(sizeof(char) * length, |
@@ -571,11 +575,11 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev) | |||
571 | * won't work, this doesn't matter much at the moment: the driver core doesn't | 575 | * won't work, this doesn't matter much at the moment: the driver core doesn't |
572 | * support it either. | 576 | * support it either. |
573 | */ | 577 | */ |
574 | static DECLARE_MUTEX(device_add_lock); | 578 | static DEFINE_MUTEX(device_add_lock); |
575 | 579 | ||
576 | struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int function) | 580 | struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int function) |
577 | { | 581 | { |
578 | struct pcmcia_device *p_dev; | 582 | struct pcmcia_device *p_dev, *tmp_dev; |
579 | unsigned long flags; | 583 | unsigned long flags; |
580 | int bus_id_len; | 584 | int bus_id_len; |
581 | 585 | ||
@@ -583,7 +587,7 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f | |||
583 | if (!s) | 587 | if (!s) |
584 | return NULL; | 588 | return NULL; |
585 | 589 | ||
586 | down(&device_add_lock); | 590 | mutex_lock(&device_add_lock); |
587 | 591 | ||
588 | /* max of 2 devices per card */ | 592 | /* max of 2 devices per card */ |
589 | if (s->device_count == 2) | 593 | if (s->device_count == 2) |
@@ -596,6 +600,8 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f | |||
596 | p_dev->socket = s; | 600 | p_dev->socket = s; |
597 | p_dev->device_no = (s->device_count++); | 601 | p_dev->device_no = (s->device_count++); |
598 | p_dev->func = function; | 602 | p_dev->func = function; |
603 | if (s->functions <= function) | ||
604 | s->functions = function + 1; | ||
599 | 605 | ||
600 | p_dev->dev.bus = &pcmcia_bus_type; | 606 | p_dev->dev.bus = &pcmcia_bus_type; |
601 | p_dev->dev.parent = s->dev.dev; | 607 | p_dev->dev.parent = s->dev.dev; |
@@ -608,36 +614,55 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f | |||
608 | sprintf (p_dev->devname, "pcmcia%s", p_dev->dev.bus_id); | 614 | sprintf (p_dev->devname, "pcmcia%s", p_dev->dev.bus_id); |
609 | 615 | ||
610 | /* compat */ | 616 | /* compat */ |
611 | p_dev->state = CLIENT_UNBOUND; | 617 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); |
618 | |||
619 | /* | ||
620 | * p_dev->function_config must be the same for all card functions. | ||
621 | * Note that this is serialized by the device_add_lock, so that | ||
622 | * only one such struct will be created. | ||
623 | */ | ||
624 | list_for_each_entry(tmp_dev, &s->devices_list, socket_device_list) | ||
625 | if (p_dev->func == tmp_dev->func) { | ||
626 | p_dev->function_config = tmp_dev->function_config; | ||
627 | kref_get(&p_dev->function_config->ref); | ||
628 | } | ||
612 | 629 | ||
613 | /* Add to the list in pcmcia_bus_socket */ | 630 | /* Add to the list in pcmcia_bus_socket */ |
614 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | ||
615 | list_add_tail(&p_dev->socket_device_list, &s->devices_list); | 631 | list_add_tail(&p_dev->socket_device_list, &s->devices_list); |
632 | |||
616 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | 633 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); |
617 | 634 | ||
635 | if (!p_dev->function_config) { | ||
636 | p_dev->function_config = kzalloc(sizeof(struct config_t), | ||
637 | GFP_KERNEL); | ||
638 | if (!p_dev->function_config) | ||
639 | goto err_unreg; | ||
640 | kref_init(&p_dev->function_config->ref); | ||
641 | } | ||
642 | |||
618 | printk(KERN_NOTICE "pcmcia: registering new device %s\n", | 643 | printk(KERN_NOTICE "pcmcia: registering new device %s\n", |
619 | p_dev->devname); | 644 | p_dev->devname); |
620 | 645 | ||
621 | pcmcia_device_query(p_dev); | 646 | pcmcia_device_query(p_dev); |
622 | 647 | ||
623 | if (device_register(&p_dev->dev)) { | 648 | if (device_register(&p_dev->dev)) |
624 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | 649 | goto err_unreg; |
625 | list_del(&p_dev->socket_device_list); | ||
626 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
627 | |||
628 | goto err_free; | ||
629 | } | ||
630 | 650 | ||
631 | up(&device_add_lock); | 651 | mutex_unlock(&device_add_lock); |
632 | 652 | ||
633 | return p_dev; | 653 | return p_dev; |
634 | 654 | ||
655 | err_unreg: | ||
656 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | ||
657 | list_del(&p_dev->socket_device_list); | ||
658 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
659 | |||
635 | err_free: | 660 | err_free: |
636 | kfree(p_dev->devname); | 661 | kfree(p_dev->devname); |
637 | kfree(p_dev); | 662 | kfree(p_dev); |
638 | s->device_count--; | 663 | s->device_count--; |
639 | err_put: | 664 | err_put: |
640 | up(&device_add_lock); | 665 | mutex_unlock(&device_add_lock); |
641 | pcmcia_put_socket(s); | 666 | pcmcia_put_socket(s); |
642 | 667 | ||
643 | return NULL; | 668 | return NULL; |
@@ -696,7 +721,7 @@ static void pcmcia_bus_rescan(struct pcmcia_socket *skt) | |||
696 | int no_devices=0; | 721 | int no_devices=0; |
697 | unsigned long flags; | 722 | unsigned long flags; |
698 | 723 | ||
699 | /* must be called with skt_sem held */ | 724 | /* must be called with skt_mutex held */ |
700 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | 725 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); |
701 | if (list_empty(&skt->devices_list)) | 726 | if (list_empty(&skt->devices_list)) |
702 | no_devices=1; | 727 | no_devices=1; |
@@ -819,9 +844,11 @@ static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) { | |||
819 | struct pcmcia_driver * p_drv = to_pcmcia_drv(drv); | 844 | struct pcmcia_driver * p_drv = to_pcmcia_drv(drv); |
820 | struct pcmcia_device_id *did = p_drv->id_table; | 845 | struct pcmcia_device_id *did = p_drv->id_table; |
821 | 846 | ||
847 | #ifdef CONFIG_PCMCIA_IOCTL | ||
822 | /* matching by cardmgr */ | 848 | /* matching by cardmgr */ |
823 | if (p_dev->cardmgr == p_drv) | 849 | if (p_dev->cardmgr == p_drv) |
824 | return 1; | 850 | return 1; |
851 | #endif | ||
825 | 852 | ||
826 | while (did && did->match_flags) { | 853 | while (did && did->match_flags) { |
827 | if (pcmcia_devmatch(p_dev, did)) | 854 | if (pcmcia_devmatch(p_dev, did)) |
@@ -927,7 +954,7 @@ static ssize_t pcmcia_show_pm_state(struct device *dev, struct device_attribute | |||
927 | { | 954 | { |
928 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | 955 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); |
929 | 956 | ||
930 | if (p_dev->dev.power.power_state.event != PM_EVENT_ON) | 957 | if (p_dev->suspended) |
931 | return sprintf(buf, "off\n"); | 958 | return sprintf(buf, "off\n"); |
932 | else | 959 | else |
933 | return sprintf(buf, "on\n"); | 960 | return sprintf(buf, "on\n"); |
@@ -942,11 +969,9 @@ static ssize_t pcmcia_store_pm_state(struct device *dev, struct device_attribute | |||
942 | if (!count) | 969 | if (!count) |
943 | return -EINVAL; | 970 | return -EINVAL; |
944 | 971 | ||
945 | if ((p_dev->dev.power.power_state.event == PM_EVENT_ON) && | 972 | if ((!p_dev->suspended) && !strncmp(buf, "off", 3)) |
946 | (!strncmp(buf, "off", 3))) | ||
947 | ret = dpm_runtime_suspend(dev, PMSG_SUSPEND); | 973 | ret = dpm_runtime_suspend(dev, PMSG_SUSPEND); |
948 | else if ((p_dev->dev.power.power_state.event != PM_EVENT_ON) && | 974 | else if (p_dev->suspended && !strncmp(buf, "on", 2)) |
949 | (!strncmp(buf, "on", 2))) | ||
950 | dpm_runtime_resume(dev); | 975 | dpm_runtime_resume(dev); |
951 | 976 | ||
952 | return ret ? ret : count; | 977 | return ret ? ret : count; |
@@ -982,9 +1007,9 @@ static ssize_t pcmcia_store_allow_func_id_match(struct device *dev, | |||
982 | if (!count) | 1007 | if (!count) |
983 | return -EINVAL; | 1008 | return -EINVAL; |
984 | 1009 | ||
985 | down(&p_dev->socket->skt_sem); | 1010 | mutex_lock(&p_dev->socket->skt_mutex); |
986 | p_dev->allow_func_id_match = 1; | 1011 | p_dev->allow_func_id_match = 1; |
987 | up(&p_dev->socket->skt_sem); | 1012 | mutex_unlock(&p_dev->socket->skt_mutex); |
988 | 1013 | ||
989 | bus_rescan_devices(&pcmcia_bus_type); | 1014 | bus_rescan_devices(&pcmcia_bus_type); |
990 | 1015 | ||
@@ -1012,14 +1037,27 @@ static int pcmcia_dev_suspend(struct device * dev, pm_message_t state) | |||
1012 | { | 1037 | { |
1013 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | 1038 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); |
1014 | struct pcmcia_driver *p_drv = NULL; | 1039 | struct pcmcia_driver *p_drv = NULL; |
1040 | int ret = 0; | ||
1015 | 1041 | ||
1016 | if (dev->driver) | 1042 | if (dev->driver) |
1017 | p_drv = to_pcmcia_drv(dev->driver); | 1043 | p_drv = to_pcmcia_drv(dev->driver); |
1018 | 1044 | ||
1019 | if (p_drv && p_drv->suspend) | 1045 | if (!p_drv) |
1020 | return p_drv->suspend(p_dev); | 1046 | goto out; |
1021 | 1047 | ||
1022 | return 0; | 1048 | if (p_drv->suspend) { |
1049 | ret = p_drv->suspend(p_dev); | ||
1050 | if (ret) | ||
1051 | goto out; | ||
1052 | } | ||
1053 | |||
1054 | if (p_dev->device_no == p_dev->func) | ||
1055 | pcmcia_release_configuration(p_dev); | ||
1056 | |||
1057 | out: | ||
1058 | if (!ret) | ||
1059 | p_dev->suspended = 1; | ||
1060 | return ret; | ||
1023 | } | 1061 | } |
1024 | 1062 | ||
1025 | 1063 | ||
@@ -1027,14 +1065,27 @@ static int pcmcia_dev_resume(struct device * dev) | |||
1027 | { | 1065 | { |
1028 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | 1066 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); |
1029 | struct pcmcia_driver *p_drv = NULL; | 1067 | struct pcmcia_driver *p_drv = NULL; |
1068 | int ret = 0; | ||
1030 | 1069 | ||
1031 | if (dev->driver) | 1070 | if (dev->driver) |
1032 | p_drv = to_pcmcia_drv(dev->driver); | 1071 | p_drv = to_pcmcia_drv(dev->driver); |
1033 | 1072 | ||
1034 | if (p_drv && p_drv->resume) | 1073 | if (!p_drv) |
1035 | return p_drv->resume(p_dev); | 1074 | goto out; |
1036 | 1075 | ||
1037 | return 0; | 1076 | if (p_dev->device_no == p_dev->func) { |
1077 | ret = pcmcia_request_configuration(p_dev, &p_dev->conf); | ||
1078 | if (ret) | ||
1079 | goto out; | ||
1080 | } | ||
1081 | |||
1082 | if (p_drv->resume) | ||
1083 | ret = p_drv->resume(p_dev); | ||
1084 | |||
1085 | out: | ||
1086 | if (!ret) | ||
1087 | p_dev->suspended = 0; | ||
1088 | return ret; | ||
1038 | } | 1089 | } |
1039 | 1090 | ||
1040 | 1091 | ||
@@ -1100,7 +1151,7 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) | |||
1100 | switch (event) { | 1151 | switch (event) { |
1101 | case CS_EVENT_CARD_REMOVAL: | 1152 | case CS_EVENT_CARD_REMOVAL: |
1102 | s->pcmcia_state.present = 0; | 1153 | s->pcmcia_state.present = 0; |
1103 | pcmcia_card_remove(skt); | 1154 | pcmcia_card_remove(skt, NULL); |
1104 | handle_event(skt, event); | 1155 | handle_event(skt, event); |
1105 | break; | 1156 | break; |
1106 | 1157 | ||
@@ -1128,6 +1179,32 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) | |||
1128 | } /* ds_event */ | 1179 | } /* ds_event */ |
1129 | 1180 | ||
1130 | 1181 | ||
1182 | struct pcmcia_device * pcmcia_dev_present(struct pcmcia_device *_p_dev) | ||
1183 | { | ||
1184 | struct pcmcia_device *p_dev; | ||
1185 | struct pcmcia_device *ret = NULL; | ||
1186 | |||
1187 | p_dev = pcmcia_get_dev(_p_dev); | ||
1188 | if (!p_dev) | ||
1189 | return NULL; | ||
1190 | |||
1191 | if (!p_dev->socket->pcmcia_state.present) | ||
1192 | goto out; | ||
1193 | |||
1194 | if (p_dev->_removed) | ||
1195 | goto out; | ||
1196 | |||
1197 | if (p_dev->suspended) | ||
1198 | goto out; | ||
1199 | |||
1200 | ret = p_dev; | ||
1201 | out: | ||
1202 | pcmcia_put_dev(p_dev); | ||
1203 | return ret; | ||
1204 | } | ||
1205 | EXPORT_SYMBOL(pcmcia_dev_present); | ||
1206 | |||
1207 | |||
1131 | static struct pcmcia_callback pcmcia_bus_callback = { | 1208 | static struct pcmcia_callback pcmcia_bus_callback = { |
1132 | .owner = THIS_MODULE, | 1209 | .owner = THIS_MODULE, |
1133 | .event = ds_event, | 1210 | .event = ds_event, |