diff options
Diffstat (limited to 'drivers/net/wireless/spectrum_cs.c')
-rw-r--r-- | drivers/net/wireless/spectrum_cs.c | 175 |
1 files changed, 53 insertions, 122 deletions
diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c index b1bbc8e8e91f..fee4be1ce810 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/spectrum_cs.c | |||
@@ -57,17 +57,6 @@ module_param(ignore_cis_vcc, int, 0); | |||
57 | MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket"); | 57 | MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket"); |
58 | 58 | ||
59 | /********************************************************************/ | 59 | /********************************************************************/ |
60 | /* Magic constants */ | ||
61 | /********************************************************************/ | ||
62 | |||
63 | /* | ||
64 | * The dev_info variable is the "key" that is used to match up this | ||
65 | * device driver with appropriate cards, through the card | ||
66 | * configuration database. | ||
67 | */ | ||
68 | static dev_info_t dev_info = DRIVER_NAME; | ||
69 | |||
70 | /********************************************************************/ | ||
71 | /* Data structures */ | 60 | /* Data structures */ |
72 | /********************************************************************/ | 61 | /********************************************************************/ |
73 | 62 | ||
@@ -78,19 +67,12 @@ struct orinoco_pccard { | |||
78 | dev_node_t node; | 67 | dev_node_t node; |
79 | }; | 68 | }; |
80 | 69 | ||
81 | /* | ||
82 | * A linked list of "instances" of the device. Each actual PCMCIA | ||
83 | * card corresponds to one device instance, and is described by one | ||
84 | * dev_link_t structure (defined in ds.h). | ||
85 | */ | ||
86 | static dev_link_t *dev_list; /* = NULL */ | ||
87 | |||
88 | /********************************************************************/ | 70 | /********************************************************************/ |
89 | /* Function prototypes */ | 71 | /* Function prototypes */ |
90 | /********************************************************************/ | 72 | /********************************************************************/ |
91 | 73 | ||
74 | static void spectrum_cs_config(dev_link_t *link); | ||
92 | static void spectrum_cs_release(dev_link_t *link); | 75 | static void spectrum_cs_release(dev_link_t *link); |
93 | static void spectrum_cs_detach(dev_link_t *link); | ||
94 | 76 | ||
95 | /********************************************************************/ | 77 | /********************************************************************/ |
96 | /* Firmware downloader */ | 78 | /* Firmware downloader */ |
@@ -601,19 +583,17 @@ spectrum_cs_hard_reset(struct orinoco_private *priv) | |||
601 | * The dev_link structure is initialized, but we don't actually | 583 | * The dev_link structure is initialized, but we don't actually |
602 | * configure the card at this point -- we wait until we receive a card | 584 | * configure the card at this point -- we wait until we receive a card |
603 | * insertion event. */ | 585 | * insertion event. */ |
604 | static dev_link_t * | 586 | static int |
605 | spectrum_cs_attach(void) | 587 | spectrum_cs_attach(struct pcmcia_device *p_dev) |
606 | { | 588 | { |
607 | struct net_device *dev; | 589 | struct net_device *dev; |
608 | struct orinoco_private *priv; | 590 | struct orinoco_private *priv; |
609 | struct orinoco_pccard *card; | 591 | struct orinoco_pccard *card; |
610 | dev_link_t *link; | 592 | dev_link_t *link; |
611 | client_reg_t client_reg; | ||
612 | int ret; | ||
613 | 593 | ||
614 | dev = alloc_orinocodev(sizeof(*card), spectrum_cs_hard_reset); | 594 | dev = alloc_orinocodev(sizeof(*card), spectrum_cs_hard_reset); |
615 | if (! dev) | 595 | if (! dev) |
616 | return NULL; | 596 | return -ENOMEM; |
617 | priv = netdev_priv(dev); | 597 | priv = netdev_priv(dev); |
618 | card = priv->card; | 598 | card = priv->card; |
619 | 599 | ||
@@ -635,23 +615,13 @@ spectrum_cs_attach(void) | |||
635 | link->conf.Attributes = 0; | 615 | link->conf.Attributes = 0; |
636 | link->conf.IntType = INT_MEMORY_AND_IO; | 616 | link->conf.IntType = INT_MEMORY_AND_IO; |
637 | 617 | ||
638 | /* Register with Card Services */ | 618 | link->handle = p_dev; |
639 | /* FIXME: need a lock? */ | 619 | p_dev->instance = link; |
640 | link->next = dev_list; | ||
641 | dev_list = link; | ||
642 | 620 | ||
643 | client_reg.dev_info = &dev_info; | 621 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
644 | client_reg.Version = 0x0210; /* FIXME: what does this mean? */ | 622 | spectrum_cs_config(link); |
645 | client_reg.event_callback_args.client_data = link; | ||
646 | 623 | ||
647 | ret = pcmcia_register_client(&link->handle, &client_reg); | 624 | return 0; |
648 | if (ret != CS_SUCCESS) { | ||
649 | cs_error(link->handle, RegisterClient, ret); | ||
650 | spectrum_cs_detach(link); | ||
651 | return NULL; | ||
652 | } | ||
653 | |||
654 | return link; | ||
655 | } /* spectrum_cs_attach */ | 625 | } /* spectrum_cs_attach */ |
656 | 626 | ||
657 | /* | 627 | /* |
@@ -660,27 +630,14 @@ spectrum_cs_attach(void) | |||
660 | * are freed. Otherwise, the structures will be freed when the device | 630 | * are freed. Otherwise, the structures will be freed when the device |
661 | * is released. | 631 | * is released. |
662 | */ | 632 | */ |
663 | static void spectrum_cs_detach(dev_link_t *link) | 633 | static void spectrum_cs_detach(struct pcmcia_device *p_dev) |
664 | { | 634 | { |
665 | dev_link_t **linkp; | 635 | dev_link_t *link = dev_to_instance(p_dev); |
666 | struct net_device *dev = link->priv; | 636 | struct net_device *dev = link->priv; |
667 | 637 | ||
668 | /* Locate device structure */ | ||
669 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
670 | if (*linkp == link) | ||
671 | break; | ||
672 | |||
673 | BUG_ON(*linkp == NULL); | ||
674 | |||
675 | if (link->state & DEV_CONFIG) | 638 | if (link->state & DEV_CONFIG) |
676 | spectrum_cs_release(link); | 639 | spectrum_cs_release(link); |
677 | 640 | ||
678 | /* Break the link with Card Services */ | ||
679 | if (link->handle) | ||
680 | pcmcia_deregister_client(link->handle); | ||
681 | |||
682 | /* Unlink device structure, and free it */ | ||
683 | *linkp = link->next; | ||
684 | DEBUG(0, PFX "detach: link=%p link->dev=%p\n", link, link->dev); | 641 | DEBUG(0, PFX "detach: link=%p link->dev=%p\n", link, link->dev); |
685 | if (link->dev) { | 642 | if (link->dev) { |
686 | DEBUG(0, PFX "About to unregister net device %p\n", | 643 | DEBUG(0, PFX "About to unregister net device %p\n", |
@@ -948,82 +905,56 @@ spectrum_cs_release(dev_link_t *link) | |||
948 | ioport_unmap(priv->hw.iobase); | 905 | ioport_unmap(priv->hw.iobase); |
949 | } /* spectrum_cs_release */ | 906 | } /* spectrum_cs_release */ |
950 | 907 | ||
951 | /* | 908 | |
952 | * The card status event handler. Mostly, this schedules other stuff | ||
953 | * to run after an event is received. | ||
954 | */ | ||
955 | static int | 909 | static int |
956 | spectrum_cs_event(event_t event, int priority, | 910 | spectrum_cs_suspend(struct pcmcia_device *p_dev) |
957 | event_callback_args_t * args) | ||
958 | { | 911 | { |
959 | dev_link_t *link = args->client_data; | 912 | dev_link_t *link = dev_to_instance(p_dev); |
960 | struct net_device *dev = link->priv; | 913 | struct net_device *dev = link->priv; |
961 | struct orinoco_private *priv = netdev_priv(dev); | 914 | struct orinoco_private *priv = netdev_priv(dev); |
962 | int err = 0; | ||
963 | unsigned long flags; | 915 | unsigned long flags; |
916 | int err = 0; | ||
964 | 917 | ||
965 | switch (event) { | 918 | link->state |= DEV_SUSPEND; |
966 | case CS_EVENT_CARD_REMOVAL: | 919 | /* Mark the device as stopped, to block IO until later */ |
967 | link->state &= ~DEV_PRESENT; | 920 | if (link->state & DEV_CONFIG) { |
968 | if (link->state & DEV_CONFIG) { | 921 | spin_lock_irqsave(&priv->lock, flags); |
969 | unsigned long flags; | ||
970 | 922 | ||
971 | spin_lock_irqsave(&priv->lock, flags); | 923 | err = __orinoco_down(dev); |
972 | netif_device_detach(dev); | 924 | if (err) |
973 | priv->hw_unavailable++; | 925 | printk(KERN_WARNING "%s: Error %d downing interface\n", |
974 | spin_unlock_irqrestore(&priv->lock, flags); | 926 | dev->name, err); |
975 | } | ||
976 | break; | ||
977 | 927 | ||
978 | case CS_EVENT_CARD_INSERTION: | 928 | netif_device_detach(dev); |
979 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | 929 | priv->hw_unavailable++; |
980 | spectrum_cs_config(link); | ||
981 | break; | ||
982 | 930 | ||
983 | case CS_EVENT_PM_SUSPEND: | 931 | spin_unlock_irqrestore(&priv->lock, flags); |
984 | link->state |= DEV_SUSPEND; | ||
985 | /* Fall through... */ | ||
986 | case CS_EVENT_RESET_PHYSICAL: | ||
987 | /* Mark the device as stopped, to block IO until later */ | ||
988 | if (link->state & DEV_CONFIG) { | ||
989 | /* This is probably racy, but I can't think of | ||
990 | a better way, short of rewriting the PCMCIA | ||
991 | layer to not suck :-( */ | ||
992 | spin_lock_irqsave(&priv->lock, flags); | ||
993 | |||
994 | err = __orinoco_down(dev); | ||
995 | if (err) | ||
996 | printk(KERN_WARNING "%s: %s: Error %d downing interface\n", | ||
997 | dev->name, | ||
998 | event == CS_EVENT_PM_SUSPEND ? "SUSPEND" : "RESET_PHYSICAL", | ||
999 | err); | ||
1000 | |||
1001 | netif_device_detach(dev); | ||
1002 | priv->hw_unavailable++; | ||
1003 | |||
1004 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1005 | |||
1006 | pcmcia_release_configuration(link->handle); | ||
1007 | } | ||
1008 | break; | ||
1009 | 932 | ||
1010 | case CS_EVENT_PM_RESUME: | 933 | pcmcia_release_configuration(link->handle); |
1011 | link->state &= ~DEV_SUSPEND; | 934 | } |
1012 | /* Fall through... */ | 935 | |
1013 | case CS_EVENT_CARD_RESET: | 936 | return 0; |
1014 | if (link->state & DEV_CONFIG) { | 937 | } |
1015 | /* FIXME: should we double check that this is | 938 | |
1016 | * the same card as we had before */ | 939 | static int |
1017 | pcmcia_request_configuration(link->handle, &link->conf); | 940 | spectrum_cs_resume(struct pcmcia_device *p_dev) |
1018 | netif_device_attach(dev); | 941 | { |
1019 | priv->hw_unavailable--; | 942 | dev_link_t *link = dev_to_instance(p_dev); |
1020 | schedule_work(&priv->reset_work); | 943 | struct net_device *dev = link->priv; |
1021 | } | 944 | struct orinoco_private *priv = netdev_priv(dev); |
1022 | break; | 945 | |
946 | link->state &= ~DEV_SUSPEND; | ||
947 | if (link->state & DEV_CONFIG) { | ||
948 | /* FIXME: should we double check that this is | ||
949 | * the same card as we had before */ | ||
950 | pcmcia_request_configuration(link->handle, &link->conf); | ||
951 | netif_device_attach(dev); | ||
952 | priv->hw_unavailable--; | ||
953 | schedule_work(&priv->reset_work); | ||
1023 | } | 954 | } |
955 | return 0; | ||
956 | } | ||
1024 | 957 | ||
1025 | return err; | ||
1026 | } /* spectrum_cs_event */ | ||
1027 | 958 | ||
1028 | /********************************************************************/ | 959 | /********************************************************************/ |
1029 | /* Module initialization */ | 960 | /* Module initialization */ |
@@ -1048,9 +979,10 @@ static struct pcmcia_driver orinoco_driver = { | |||
1048 | .drv = { | 979 | .drv = { |
1049 | .name = DRIVER_NAME, | 980 | .name = DRIVER_NAME, |
1050 | }, | 981 | }, |
1051 | .attach = spectrum_cs_attach, | 982 | .probe = spectrum_cs_attach, |
1052 | .detach = spectrum_cs_detach, | 983 | .remove = spectrum_cs_detach, |
1053 | .event = spectrum_cs_event, | 984 | .suspend = spectrum_cs_suspend, |
985 | .resume = spectrum_cs_resume, | ||
1054 | .id_table = spectrum_cs_ids, | 986 | .id_table = spectrum_cs_ids, |
1055 | }; | 987 | }; |
1056 | 988 | ||
@@ -1066,7 +998,6 @@ static void __exit | |||
1066 | exit_spectrum_cs(void) | 998 | exit_spectrum_cs(void) |
1067 | { | 999 | { |
1068 | pcmcia_unregister_driver(&orinoco_driver); | 1000 | pcmcia_unregister_driver(&orinoco_driver); |
1069 | BUG_ON(dev_list != NULL); | ||
1070 | } | 1001 | } |
1071 | 1002 | ||
1072 | module_init(init_spectrum_cs); | 1003 | module_init(init_spectrum_cs); |