diff options
Diffstat (limited to 'drivers/char/pcmcia/synclink_cs.c')
-rw-r--r-- | drivers/char/pcmcia/synclink_cs.c | 132 |
1 files changed, 40 insertions, 92 deletions
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index 2c326ea53421..cf45b100eff1 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c | |||
@@ -486,13 +486,7 @@ static void mgslpc_wait_until_sent(struct tty_struct *tty, int timeout); | |||
486 | 486 | ||
487 | static void mgslpc_config(dev_link_t *link); | 487 | static void mgslpc_config(dev_link_t *link); |
488 | static void mgslpc_release(u_long arg); | 488 | static void mgslpc_release(u_long arg); |
489 | static int mgslpc_event(event_t event, int priority, | 489 | static void mgslpc_detach(struct pcmcia_device *p_dev); |
490 | event_callback_args_t *args); | ||
491 | static dev_link_t *mgslpc_attach(void); | ||
492 | static void mgslpc_detach(dev_link_t *); | ||
493 | |||
494 | static dev_info_t dev_info = "synclink_cs"; | ||
495 | static dev_link_t *dev_list = NULL; | ||
496 | 490 | ||
497 | /* | 491 | /* |
498 | * 1st function defined in .text section. Calling this function in | 492 | * 1st function defined in .text section. Calling this function in |
@@ -539,12 +533,10 @@ static void ldisc_receive_buf(struct tty_struct *tty, | |||
539 | } | 533 | } |
540 | } | 534 | } |
541 | 535 | ||
542 | static dev_link_t *mgslpc_attach(void) | 536 | static int mgslpc_attach(struct pcmcia_device *p_dev) |
543 | { | 537 | { |
544 | MGSLPC_INFO *info; | 538 | MGSLPC_INFO *info; |
545 | dev_link_t *link; | 539 | dev_link_t *link; |
546 | client_reg_t client_reg; | ||
547 | int ret; | ||
548 | 540 | ||
549 | if (debug_level >= DEBUG_LEVEL_INFO) | 541 | if (debug_level >= DEBUG_LEVEL_INFO) |
550 | printk("mgslpc_attach\n"); | 542 | printk("mgslpc_attach\n"); |
@@ -552,7 +544,7 @@ static dev_link_t *mgslpc_attach(void) | |||
552 | info = (MGSLPC_INFO *)kmalloc(sizeof(MGSLPC_INFO), GFP_KERNEL); | 544 | info = (MGSLPC_INFO *)kmalloc(sizeof(MGSLPC_INFO), GFP_KERNEL); |
553 | if (!info) { | 545 | if (!info) { |
554 | printk("Error can't allocate device instance data\n"); | 546 | printk("Error can't allocate device instance data\n"); |
555 | return NULL; | 547 | return -ENOMEM; |
556 | } | 548 | } |
557 | 549 | ||
558 | memset(info, 0, sizeof(MGSLPC_INFO)); | 550 | memset(info, 0, sizeof(MGSLPC_INFO)); |
@@ -587,24 +579,15 @@ static dev_link_t *mgslpc_attach(void) | |||
587 | link->conf.Vcc = 50; | 579 | link->conf.Vcc = 50; |
588 | link->conf.IntType = INT_MEMORY_AND_IO; | 580 | link->conf.IntType = INT_MEMORY_AND_IO; |
589 | 581 | ||
590 | /* Register with Card Services */ | 582 | link->handle = p_dev; |
591 | link->next = dev_list; | 583 | p_dev->instance = link; |
592 | dev_list = link; | ||
593 | |||
594 | client_reg.dev_info = &dev_info; | ||
595 | client_reg.Version = 0x0210; | ||
596 | client_reg.event_callback_args.client_data = link; | ||
597 | 584 | ||
598 | ret = pcmcia_register_client(&link->handle, &client_reg); | 585 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
599 | if (ret != CS_SUCCESS) { | 586 | mgslpc_config(link); |
600 | cs_error(link->handle, RegisterClient, ret); | ||
601 | mgslpc_detach(link); | ||
602 | return NULL; | ||
603 | } | ||
604 | 587 | ||
605 | mgslpc_add_device(info); | 588 | mgslpc_add_device(info); |
606 | 589 | ||
607 | return link; | 590 | return 0; |
608 | } | 591 | } |
609 | 592 | ||
610 | /* Card has been inserted. | 593 | /* Card has been inserted. |
@@ -736,85 +719,50 @@ static void mgslpc_release(u_long arg) | |||
736 | pcmcia_release_io(link->handle, &link->io); | 719 | pcmcia_release_io(link->handle, &link->io); |
737 | if (link->irq.AssignedIRQ) | 720 | if (link->irq.AssignedIRQ) |
738 | pcmcia_release_irq(link->handle, &link->irq); | 721 | pcmcia_release_irq(link->handle, &link->irq); |
739 | if (link->state & DEV_STALE_LINK) | ||
740 | mgslpc_detach(link); | ||
741 | } | 722 | } |
742 | 723 | ||
743 | static void mgslpc_detach(dev_link_t *link) | 724 | static void mgslpc_detach(struct pcmcia_device *p_dev) |
744 | { | 725 | { |
745 | dev_link_t **linkp; | 726 | dev_link_t *link = dev_to_instance(p_dev); |
746 | 727 | ||
747 | if (debug_level >= DEBUG_LEVEL_INFO) | 728 | if (debug_level >= DEBUG_LEVEL_INFO) |
748 | printk("mgslpc_detach(0x%p)\n", link); | 729 | printk("mgslpc_detach(0x%p)\n", link); |
749 | |||
750 | /* find device */ | ||
751 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
752 | if (*linkp == link) break; | ||
753 | if (*linkp == NULL) | ||
754 | return; | ||
755 | 730 | ||
756 | if (link->state & DEV_CONFIG) { | 731 | if (link->state & DEV_CONFIG) { |
757 | /* device is configured/active, mark it so when | 732 | ((MGSLPC_INFO *)link->priv)->stop = 1; |
758 | * release() is called a proper detach() occurs. | 733 | mgslpc_release((u_long)link); |
759 | */ | ||
760 | if (debug_level >= DEBUG_LEVEL_INFO) | ||
761 | printk(KERN_DEBUG "synclinkpc: detach postponed, '%s' " | ||
762 | "still locked\n", link->dev->dev_name); | ||
763 | link->state |= DEV_STALE_LINK; | ||
764 | return; | ||
765 | } | 734 | } |
766 | 735 | ||
767 | /* Break the link with Card Services */ | ||
768 | if (link->handle) | ||
769 | pcmcia_deregister_client(link->handle); | ||
770 | |||
771 | /* Unlink device structure, and free it */ | ||
772 | *linkp = link->next; | ||
773 | mgslpc_remove_device((MGSLPC_INFO *)link->priv); | 736 | mgslpc_remove_device((MGSLPC_INFO *)link->priv); |
774 | } | 737 | } |
775 | 738 | ||
776 | static int mgslpc_event(event_t event, int priority, | 739 | static int mgslpc_suspend(struct pcmcia_device *dev) |
777 | event_callback_args_t *args) | ||
778 | { | 740 | { |
779 | dev_link_t *link = args->client_data; | 741 | dev_link_t *link = dev_to_instance(dev); |
780 | MGSLPC_INFO *info = link->priv; | 742 | MGSLPC_INFO *info = link->priv; |
781 | 743 | ||
782 | if (debug_level >= DEBUG_LEVEL_INFO) | 744 | link->state |= DEV_SUSPEND; |
783 | printk("mgslpc_event(0x%06x)\n", event); | 745 | info->stop = 1; |
784 | 746 | if (link->state & DEV_CONFIG) | |
785 | switch (event) { | 747 | pcmcia_release_configuration(link->handle); |
786 | case CS_EVENT_CARD_REMOVAL: | 748 | |
787 | link->state &= ~DEV_PRESENT; | 749 | return 0; |
788 | if (link->state & DEV_CONFIG) { | ||
789 | ((MGSLPC_INFO *)link->priv)->stop = 1; | ||
790 | mgslpc_release((u_long)link); | ||
791 | } | ||
792 | break; | ||
793 | case CS_EVENT_CARD_INSERTION: | ||
794 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
795 | mgslpc_config(link); | ||
796 | break; | ||
797 | case CS_EVENT_PM_SUSPEND: | ||
798 | link->state |= DEV_SUSPEND; | ||
799 | /* Fall through... */ | ||
800 | case CS_EVENT_RESET_PHYSICAL: | ||
801 | /* Mark the device as stopped, to block IO until later */ | ||
802 | info->stop = 1; | ||
803 | if (link->state & DEV_CONFIG) | ||
804 | pcmcia_release_configuration(link->handle); | ||
805 | break; | ||
806 | case CS_EVENT_PM_RESUME: | ||
807 | link->state &= ~DEV_SUSPEND; | ||
808 | /* Fall through... */ | ||
809 | case CS_EVENT_CARD_RESET: | ||
810 | if (link->state & DEV_CONFIG) | ||
811 | pcmcia_request_configuration(link->handle, &link->conf); | ||
812 | info->stop = 0; | ||
813 | break; | ||
814 | } | ||
815 | return 0; | ||
816 | } | 750 | } |
817 | 751 | ||
752 | static int mgslpc_resume(struct pcmcia_device *dev) | ||
753 | { | ||
754 | dev_link_t *link = dev_to_instance(dev); | ||
755 | MGSLPC_INFO *info = link->priv; | ||
756 | |||
757 | link->state &= ~DEV_SUSPEND; | ||
758 | if (link->state & DEV_CONFIG) | ||
759 | pcmcia_request_configuration(link->handle, &link->conf); | ||
760 | info->stop = 0; | ||
761 | |||
762 | return 0; | ||
763 | } | ||
764 | |||
765 | |||
818 | static inline int mgslpc_paranoia_check(MGSLPC_INFO *info, | 766 | static inline int mgslpc_paranoia_check(MGSLPC_INFO *info, |
819 | char *name, const char *routine) | 767 | char *name, const char *routine) |
820 | { | 768 | { |
@@ -3091,10 +3039,11 @@ static struct pcmcia_driver mgslpc_driver = { | |||
3091 | .drv = { | 3039 | .drv = { |
3092 | .name = "synclink_cs", | 3040 | .name = "synclink_cs", |
3093 | }, | 3041 | }, |
3094 | .attach = mgslpc_attach, | 3042 | .probe = mgslpc_attach, |
3095 | .event = mgslpc_event, | 3043 | .remove = mgslpc_detach, |
3096 | .detach = mgslpc_detach, | ||
3097 | .id_table = mgslpc_ids, | 3044 | .id_table = mgslpc_ids, |
3045 | .suspend = mgslpc_suspend, | ||
3046 | .resume = mgslpc_resume, | ||
3098 | }; | 3047 | }; |
3099 | 3048 | ||
3100 | static struct tty_operations mgslpc_ops = { | 3049 | static struct tty_operations mgslpc_ops = { |
@@ -3138,7 +3087,6 @@ static void synclink_cs_cleanup(void) | |||
3138 | } | 3087 | } |
3139 | 3088 | ||
3140 | pcmcia_unregister_driver(&mgslpc_driver); | 3089 | pcmcia_unregister_driver(&mgslpc_driver); |
3141 | BUG_ON(dev_list != NULL); | ||
3142 | } | 3090 | } |
3143 | 3091 | ||
3144 | static int __init synclink_cs_init(void) | 3092 | static int __init synclink_cs_init(void) |