diff options
author | Jody McIntyre <scjody@modernduck.com> | 2006-01-05 22:22:50 -0500 |
---|---|---|
committer | Jody McIntyre <scjody@modernduck.com> | 2006-01-05 22:22:50 -0500 |
commit | 52cab57873c25d3c8324ee3e4d463db6e8e73fd7 (patch) | |
tree | 826cb36827afa363944e6478d19512e669446c64 | |
parent | 0a75c23a009ff65f651532cecc16675d05f4de37 (diff) | |
parent | 46f25dffbaba48c571d75f5f574f31978287b8d2 (diff) |
Merge with http://kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
128 files changed, 5045 insertions, 5709 deletions
diff --git a/Documentation/pcmcia/driver-changes.txt b/Documentation/pcmcia/driver-changes.txt index 403e7b4dcdd4..97420f08c786 100644 --- a/Documentation/pcmcia/driver-changes.txt +++ b/Documentation/pcmcia/driver-changes.txt | |||
@@ -1,5 +1,16 @@ | |||
1 | This file details changes in 2.6 which affect PCMCIA card driver authors: | 1 | This file details changes in 2.6 which affect PCMCIA card driver authors: |
2 | 2 | ||
3 | * Unify detach and REMOVAL event code, as well as attach and INSERTION | ||
4 | code (as of 2.6.16) | ||
5 | void (*remove) (struct pcmcia_device *dev); | ||
6 | int (*probe) (struct pcmcia_device *dev); | ||
7 | |||
8 | * Move suspend, resume and reset out of event handler (as of 2.6.16) | ||
9 | int (*suspend) (struct pcmcia_device *dev); | ||
10 | int (*resume) (struct pcmcia_device *dev); | ||
11 | should be initialized in struct pcmcia_driver, and handle | ||
12 | (SUSPEND == RESET_PHYSICAL) and (RESUME == CARD_RESET) events | ||
13 | |||
3 | * event handler initialization in struct pcmcia_driver (as of 2.6.13) | 14 | * event handler initialization in struct pcmcia_driver (as of 2.6.13) |
4 | The event handler is notified of all events, and must be initialized | 15 | The event handler is notified of all events, and must be initialized |
5 | as the event() callback in the driver's struct pcmcia_driver. | 16 | as the event() callback in the driver's struct pcmcia_driver. |
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c index 088e5dded8dc..c33305d8e5eb 100644 --- a/arch/ia64/kernel/setup.c +++ b/arch/ia64/kernel/setup.c | |||
@@ -518,7 +518,7 @@ show_cpuinfo (struct seq_file *m, void *v) | |||
518 | char family[32], features[128], *cp, sep; | 518 | char family[32], features[128], *cp, sep; |
519 | struct cpuinfo_ia64 *c = v; | 519 | struct cpuinfo_ia64 *c = v; |
520 | unsigned long mask; | 520 | unsigned long mask; |
521 | unsigned int proc_freq; | 521 | unsigned long proc_freq; |
522 | int i; | 522 | int i; |
523 | 523 | ||
524 | mask = c->features; | 524 | mask = c->features; |
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index 20d76fae24e8..30dbc98bf0b3 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c | |||
@@ -700,7 +700,7 @@ int ia64_pci_legacy_read(struct pci_bus *bus, u16 port, u32 *val, u8 size) | |||
700 | */ | 700 | */ |
701 | int ia64_pci_legacy_write(struct pci_dev *bus, u16 port, u32 val, u8 size) | 701 | int ia64_pci_legacy_write(struct pci_dev *bus, u16 port, u32 val, u8 size) |
702 | { | 702 | { |
703 | int ret = 0; | 703 | int ret = size; |
704 | 704 | ||
705 | switch (size) { | 705 | switch (size) { |
706 | case 1: | 706 | case 1: |
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 4bafef83e79f..96370ec1d673 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c | |||
@@ -62,6 +62,7 @@ int dpm_runtime_suspend(struct device * dev, pm_message_t state) | |||
62 | up(&dpm_sem); | 62 | up(&dpm_sem); |
63 | return error; | 63 | return error; |
64 | } | 64 | } |
65 | EXPORT_SYMBOL(dpm_runtime_suspend); | ||
65 | 66 | ||
66 | 67 | ||
67 | #if 0 | 68 | #if 0 |
diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index f36c563d72c4..9888bc151755 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c | |||
@@ -87,14 +87,8 @@ typedef struct bluecard_info_t { | |||
87 | 87 | ||
88 | static void bluecard_config(dev_link_t *link); | 88 | static void bluecard_config(dev_link_t *link); |
89 | static void bluecard_release(dev_link_t *link); | 89 | static void bluecard_release(dev_link_t *link); |
90 | static int bluecard_event(event_t event, int priority, event_callback_args_t *args); | ||
91 | 90 | ||
92 | static dev_info_t dev_info = "bluecard_cs"; | 91 | static void bluecard_detach(struct pcmcia_device *p_dev); |
93 | |||
94 | static dev_link_t *bluecard_attach(void); | ||
95 | static void bluecard_detach(dev_link_t *); | ||
96 | |||
97 | static dev_link_t *dev_list = NULL; | ||
98 | 92 | ||
99 | 93 | ||
100 | /* Default baud rate: 57600, 115200, 230400 or 460800 */ | 94 | /* Default baud rate: 57600, 115200, 230400 or 460800 */ |
@@ -862,17 +856,15 @@ static int bluecard_close(bluecard_info_t *info) | |||
862 | return 0; | 856 | return 0; |
863 | } | 857 | } |
864 | 858 | ||
865 | static dev_link_t *bluecard_attach(void) | 859 | static int bluecard_attach(struct pcmcia_device *p_dev) |
866 | { | 860 | { |
867 | bluecard_info_t *info; | 861 | bluecard_info_t *info; |
868 | client_reg_t client_reg; | ||
869 | dev_link_t *link; | 862 | dev_link_t *link; |
870 | int ret; | ||
871 | 863 | ||
872 | /* Create new info device */ | 864 | /* Create new info device */ |
873 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 865 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
874 | if (!info) | 866 | if (!info) |
875 | return NULL; | 867 | return -ENOMEM; |
876 | 868 | ||
877 | link = &info->link; | 869 | link = &info->link; |
878 | link->priv = info; | 870 | link->priv = info; |
@@ -889,50 +881,24 @@ static dev_link_t *bluecard_attach(void) | |||
889 | link->conf.Vcc = 50; | 881 | link->conf.Vcc = 50; |
890 | link->conf.IntType = INT_MEMORY_AND_IO; | 882 | link->conf.IntType = INT_MEMORY_AND_IO; |
891 | 883 | ||
892 | /* Register with Card Services */ | 884 | link->handle = p_dev; |
893 | link->next = dev_list; | 885 | p_dev->instance = link; |
894 | dev_list = link; | ||
895 | client_reg.dev_info = &dev_info; | ||
896 | client_reg.Version = 0x0210; | ||
897 | client_reg.event_callback_args.client_data = link; | ||
898 | |||
899 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
900 | if (ret != CS_SUCCESS) { | ||
901 | cs_error(link->handle, RegisterClient, ret); | ||
902 | bluecard_detach(link); | ||
903 | return NULL; | ||
904 | } | ||
905 | 886 | ||
906 | return link; | 887 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
888 | bluecard_config(link); | ||
889 | |||
890 | return 0; | ||
907 | } | 891 | } |
908 | 892 | ||
909 | 893 | ||
910 | static void bluecard_detach(dev_link_t *link) | 894 | static void bluecard_detach(struct pcmcia_device *p_dev) |
911 | { | 895 | { |
896 | dev_link_t *link = dev_to_instance(p_dev); | ||
912 | bluecard_info_t *info = link->priv; | 897 | bluecard_info_t *info = link->priv; |
913 | dev_link_t **linkp; | ||
914 | int ret; | ||
915 | |||
916 | /* Locate device structure */ | ||
917 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
918 | if (*linkp == link) | ||
919 | break; | ||
920 | |||
921 | if (*linkp == NULL) | ||
922 | return; | ||
923 | 898 | ||
924 | if (link->state & DEV_CONFIG) | 899 | if (link->state & DEV_CONFIG) |
925 | bluecard_release(link); | 900 | bluecard_release(link); |
926 | 901 | ||
927 | if (link->handle) { | ||
928 | ret = pcmcia_deregister_client(link->handle); | ||
929 | if (ret != CS_SUCCESS) | ||
930 | cs_error(link->handle, DeregisterClient, ret); | ||
931 | } | ||
932 | |||
933 | /* Unlink device structure, free bits */ | ||
934 | *linkp = link->next; | ||
935 | |||
936 | kfree(info); | 902 | kfree(info); |
937 | } | 903 | } |
938 | 904 | ||
@@ -1045,39 +1011,24 @@ static void bluecard_release(dev_link_t *link) | |||
1045 | link->state &= ~DEV_CONFIG; | 1011 | link->state &= ~DEV_CONFIG; |
1046 | } | 1012 | } |
1047 | 1013 | ||
1014 | static int bluecard_suspend(struct pcmcia_device *dev) | ||
1015 | { | ||
1016 | dev_link_t *link = dev_to_instance(dev); | ||
1017 | |||
1018 | link->state |= DEV_SUSPEND; | ||
1019 | if (link->state & DEV_CONFIG) | ||
1020 | pcmcia_release_configuration(link->handle); | ||
1048 | 1021 | ||
1049 | static int bluecard_event(event_t event, int priority, event_callback_args_t *args) | 1022 | return 0; |
1023 | } | ||
1024 | |||
1025 | static int bluecard_resume(struct pcmcia_device *dev) | ||
1050 | { | 1026 | { |
1051 | dev_link_t *link = args->client_data; | 1027 | dev_link_t *link = dev_to_instance(dev); |
1052 | bluecard_info_t *info = link->priv; | ||
1053 | 1028 | ||
1054 | switch (event) { | 1029 | link->state &= ~DEV_SUSPEND; |
1055 | case CS_EVENT_CARD_REMOVAL: | 1030 | if (DEV_OK(link)) |
1056 | link->state &= ~DEV_PRESENT; | 1031 | pcmcia_request_configuration(link->handle, &link->conf); |
1057 | if (link->state & DEV_CONFIG) { | ||
1058 | bluecard_close(info); | ||
1059 | bluecard_release(link); | ||
1060 | } | ||
1061 | break; | ||
1062 | case CS_EVENT_CARD_INSERTION: | ||
1063 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
1064 | bluecard_config(link); | ||
1065 | break; | ||
1066 | case CS_EVENT_PM_SUSPEND: | ||
1067 | link->state |= DEV_SUSPEND; | ||
1068 | /* Fall through... */ | ||
1069 | case CS_EVENT_RESET_PHYSICAL: | ||
1070 | if (link->state & DEV_CONFIG) | ||
1071 | pcmcia_release_configuration(link->handle); | ||
1072 | break; | ||
1073 | case CS_EVENT_PM_RESUME: | ||
1074 | link->state &= ~DEV_SUSPEND; | ||
1075 | /* Fall through... */ | ||
1076 | case CS_EVENT_CARD_RESET: | ||
1077 | if (DEV_OK(link)) | ||
1078 | pcmcia_request_configuration(link->handle, &link->conf); | ||
1079 | break; | ||
1080 | } | ||
1081 | 1032 | ||
1082 | return 0; | 1033 | return 0; |
1083 | } | 1034 | } |
@@ -1095,10 +1046,11 @@ static struct pcmcia_driver bluecard_driver = { | |||
1095 | .drv = { | 1046 | .drv = { |
1096 | .name = "bluecard_cs", | 1047 | .name = "bluecard_cs", |
1097 | }, | 1048 | }, |
1098 | .attach = bluecard_attach, | 1049 | .probe = bluecard_attach, |
1099 | .event = bluecard_event, | 1050 | .remove = bluecard_detach, |
1100 | .detach = bluecard_detach, | ||
1101 | .id_table = bluecard_ids, | 1051 | .id_table = bluecard_ids, |
1052 | .suspend = bluecard_suspend, | ||
1053 | .resume = bluecard_resume, | ||
1102 | }; | 1054 | }; |
1103 | 1055 | ||
1104 | static int __init init_bluecard_cs(void) | 1056 | static int __init init_bluecard_cs(void) |
@@ -1110,7 +1062,6 @@ static int __init init_bluecard_cs(void) | |||
1110 | static void __exit exit_bluecard_cs(void) | 1062 | static void __exit exit_bluecard_cs(void) |
1111 | { | 1063 | { |
1112 | pcmcia_unregister_driver(&bluecard_driver); | 1064 | pcmcia_unregister_driver(&bluecard_driver); |
1113 | BUG_ON(dev_list != NULL); | ||
1114 | } | 1065 | } |
1115 | 1066 | ||
1116 | module_init(init_bluecard_cs); | 1067 | module_init(init_bluecard_cs); |
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index d2a0add19cc8..e522d19ad886 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c | |||
@@ -90,14 +90,8 @@ typedef struct bt3c_info_t { | |||
90 | 90 | ||
91 | static void bt3c_config(dev_link_t *link); | 91 | static void bt3c_config(dev_link_t *link); |
92 | static void bt3c_release(dev_link_t *link); | 92 | static void bt3c_release(dev_link_t *link); |
93 | static int bt3c_event(event_t event, int priority, event_callback_args_t *args); | ||
94 | 93 | ||
95 | static dev_info_t dev_info = "bt3c_cs"; | 94 | static void bt3c_detach(struct pcmcia_device *p_dev); |
96 | |||
97 | static dev_link_t *bt3c_attach(void); | ||
98 | static void bt3c_detach(dev_link_t *); | ||
99 | |||
100 | static dev_link_t *dev_list = NULL; | ||
101 | 95 | ||
102 | 96 | ||
103 | /* Transmit states */ | 97 | /* Transmit states */ |
@@ -663,17 +657,15 @@ static int bt3c_close(bt3c_info_t *info) | |||
663 | return 0; | 657 | return 0; |
664 | } | 658 | } |
665 | 659 | ||
666 | static dev_link_t *bt3c_attach(void) | 660 | static int bt3c_attach(struct pcmcia_device *p_dev) |
667 | { | 661 | { |
668 | bt3c_info_t *info; | 662 | bt3c_info_t *info; |
669 | client_reg_t client_reg; | ||
670 | dev_link_t *link; | 663 | dev_link_t *link; |
671 | int ret; | ||
672 | 664 | ||
673 | /* Create new info device */ | 665 | /* Create new info device */ |
674 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 666 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
675 | if (!info) | 667 | if (!info) |
676 | return NULL; | 668 | return -ENOMEM; |
677 | 669 | ||
678 | link = &info->link; | 670 | link = &info->link; |
679 | link->priv = info; | 671 | link->priv = info; |
@@ -690,50 +682,24 @@ static dev_link_t *bt3c_attach(void) | |||
690 | link->conf.Vcc = 50; | 682 | link->conf.Vcc = 50; |
691 | link->conf.IntType = INT_MEMORY_AND_IO; | 683 | link->conf.IntType = INT_MEMORY_AND_IO; |
692 | 684 | ||
693 | /* Register with Card Services */ | 685 | link->handle = p_dev; |
694 | link->next = dev_list; | 686 | p_dev->instance = link; |
695 | dev_list = link; | ||
696 | client_reg.dev_info = &dev_info; | ||
697 | client_reg.Version = 0x0210; | ||
698 | client_reg.event_callback_args.client_data = link; | ||
699 | |||
700 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
701 | if (ret != CS_SUCCESS) { | ||
702 | cs_error(link->handle, RegisterClient, ret); | ||
703 | bt3c_detach(link); | ||
704 | return NULL; | ||
705 | } | ||
706 | 687 | ||
707 | return link; | 688 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
689 | bt3c_config(link); | ||
690 | |||
691 | return 0; | ||
708 | } | 692 | } |
709 | 693 | ||
710 | 694 | ||
711 | static void bt3c_detach(dev_link_t *link) | 695 | static void bt3c_detach(struct pcmcia_device *p_dev) |
712 | { | 696 | { |
697 | dev_link_t *link = dev_to_instance(p_dev); | ||
713 | bt3c_info_t *info = link->priv; | 698 | bt3c_info_t *info = link->priv; |
714 | dev_link_t **linkp; | ||
715 | int ret; | ||
716 | |||
717 | /* Locate device structure */ | ||
718 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
719 | if (*linkp == link) | ||
720 | break; | ||
721 | |||
722 | if (*linkp == NULL) | ||
723 | return; | ||
724 | 699 | ||
725 | if (link->state & DEV_CONFIG) | 700 | if (link->state & DEV_CONFIG) |
726 | bt3c_release(link); | 701 | bt3c_release(link); |
727 | 702 | ||
728 | if (link->handle) { | ||
729 | ret = pcmcia_deregister_client(link->handle); | ||
730 | if (ret != CS_SUCCESS) | ||
731 | cs_error(link->handle, DeregisterClient, ret); | ||
732 | } | ||
733 | |||
734 | /* Unlink device structure, free bits */ | ||
735 | *linkp = link->next; | ||
736 | |||
737 | kfree(info); | 703 | kfree(info); |
738 | } | 704 | } |
739 | 705 | ||
@@ -891,43 +857,29 @@ static void bt3c_release(dev_link_t *link) | |||
891 | link->state &= ~DEV_CONFIG; | 857 | link->state &= ~DEV_CONFIG; |
892 | } | 858 | } |
893 | 859 | ||
860 | static int bt3c_suspend(struct pcmcia_device *dev) | ||
861 | { | ||
862 | dev_link_t *link = dev_to_instance(dev); | ||
894 | 863 | ||
895 | static int bt3c_event(event_t event, int priority, event_callback_args_t *args) | 864 | link->state |= DEV_SUSPEND; |
865 | if (link->state & DEV_CONFIG) | ||
866 | pcmcia_release_configuration(link->handle); | ||
867 | |||
868 | return 0; | ||
869 | } | ||
870 | |||
871 | static int bt3c_resume(struct pcmcia_device *dev) | ||
896 | { | 872 | { |
897 | dev_link_t *link = args->client_data; | 873 | dev_link_t *link = dev_to_instance(dev); |
898 | bt3c_info_t *info = link->priv; | ||
899 | 874 | ||
900 | switch (event) { | 875 | link->state &= ~DEV_SUSPEND; |
901 | case CS_EVENT_CARD_REMOVAL: | 876 | if (DEV_OK(link)) |
902 | link->state &= ~DEV_PRESENT; | 877 | pcmcia_request_configuration(link->handle, &link->conf); |
903 | if (link->state & DEV_CONFIG) { | ||
904 | bt3c_close(info); | ||
905 | bt3c_release(link); | ||
906 | } | ||
907 | break; | ||
908 | case CS_EVENT_CARD_INSERTION: | ||
909 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
910 | bt3c_config(link); | ||
911 | break; | ||
912 | case CS_EVENT_PM_SUSPEND: | ||
913 | link->state |= DEV_SUSPEND; | ||
914 | /* Fall through... */ | ||
915 | case CS_EVENT_RESET_PHYSICAL: | ||
916 | if (link->state & DEV_CONFIG) | ||
917 | pcmcia_release_configuration(link->handle); | ||
918 | break; | ||
919 | case CS_EVENT_PM_RESUME: | ||
920 | link->state &= ~DEV_SUSPEND; | ||
921 | /* Fall through... */ | ||
922 | case CS_EVENT_CARD_RESET: | ||
923 | if (DEV_OK(link)) | ||
924 | pcmcia_request_configuration(link->handle, &link->conf); | ||
925 | break; | ||
926 | } | ||
927 | 878 | ||
928 | return 0; | 879 | return 0; |
929 | } | 880 | } |
930 | 881 | ||
882 | |||
931 | static struct pcmcia_device_id bt3c_ids[] = { | 883 | static struct pcmcia_device_id bt3c_ids[] = { |
932 | PCMCIA_DEVICE_PROD_ID13("3COM", "Bluetooth PC Card", 0xefce0a31, 0xd4ce9b02), | 884 | PCMCIA_DEVICE_PROD_ID13("3COM", "Bluetooth PC Card", 0xefce0a31, 0xd4ce9b02), |
933 | PCMCIA_DEVICE_NULL | 885 | PCMCIA_DEVICE_NULL |
@@ -939,10 +891,11 @@ static struct pcmcia_driver bt3c_driver = { | |||
939 | .drv = { | 891 | .drv = { |
940 | .name = "bt3c_cs", | 892 | .name = "bt3c_cs", |
941 | }, | 893 | }, |
942 | .attach = bt3c_attach, | 894 | .probe = bt3c_attach, |
943 | .event = bt3c_event, | 895 | .remove = bt3c_detach, |
944 | .detach = bt3c_detach, | ||
945 | .id_table = bt3c_ids, | 896 | .id_table = bt3c_ids, |
897 | .suspend = bt3c_suspend, | ||
898 | .resume = bt3c_resume, | ||
946 | }; | 899 | }; |
947 | 900 | ||
948 | static int __init init_bt3c_cs(void) | 901 | static int __init init_bt3c_cs(void) |
@@ -954,7 +907,6 @@ static int __init init_bt3c_cs(void) | |||
954 | static void __exit exit_bt3c_cs(void) | 907 | static void __exit exit_bt3c_cs(void) |
955 | { | 908 | { |
956 | pcmcia_unregister_driver(&bt3c_driver); | 909 | pcmcia_unregister_driver(&bt3c_driver); |
957 | BUG_ON(dev_list != NULL); | ||
958 | } | 910 | } |
959 | 911 | ||
960 | module_init(init_bt3c_cs); | 912 | module_init(init_bt3c_cs); |
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index 529a28a3209d..7b4bff4cfa2d 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c | |||
@@ -86,14 +86,8 @@ typedef struct btuart_info_t { | |||
86 | 86 | ||
87 | static void btuart_config(dev_link_t *link); | 87 | static void btuart_config(dev_link_t *link); |
88 | static void btuart_release(dev_link_t *link); | 88 | static void btuart_release(dev_link_t *link); |
89 | static int btuart_event(event_t event, int priority, event_callback_args_t *args); | ||
90 | 89 | ||
91 | static dev_info_t dev_info = "btuart_cs"; | 90 | static void btuart_detach(struct pcmcia_device *p_dev); |
92 | |||
93 | static dev_link_t *btuart_attach(void); | ||
94 | static void btuart_detach(dev_link_t *); | ||
95 | |||
96 | static dev_link_t *dev_list = NULL; | ||
97 | 91 | ||
98 | 92 | ||
99 | /* Maximum baud rate */ | 93 | /* Maximum baud rate */ |
@@ -582,17 +576,15 @@ static int btuart_close(btuart_info_t *info) | |||
582 | return 0; | 576 | return 0; |
583 | } | 577 | } |
584 | 578 | ||
585 | static dev_link_t *btuart_attach(void) | 579 | static int btuart_attach(struct pcmcia_device *p_dev) |
586 | { | 580 | { |
587 | btuart_info_t *info; | 581 | btuart_info_t *info; |
588 | client_reg_t client_reg; | ||
589 | dev_link_t *link; | 582 | dev_link_t *link; |
590 | int ret; | ||
591 | 583 | ||
592 | /* Create new info device */ | 584 | /* Create new info device */ |
593 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 585 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
594 | if (!info) | 586 | if (!info) |
595 | return NULL; | 587 | return -ENOMEM; |
596 | 588 | ||
597 | link = &info->link; | 589 | link = &info->link; |
598 | link->priv = info; | 590 | link->priv = info; |
@@ -609,50 +601,24 @@ static dev_link_t *btuart_attach(void) | |||
609 | link->conf.Vcc = 50; | 601 | link->conf.Vcc = 50; |
610 | link->conf.IntType = INT_MEMORY_AND_IO; | 602 | link->conf.IntType = INT_MEMORY_AND_IO; |
611 | 603 | ||
612 | /* Register with Card Services */ | 604 | link->handle = p_dev; |
613 | link->next = dev_list; | 605 | p_dev->instance = link; |
614 | dev_list = link; | ||
615 | client_reg.dev_info = &dev_info; | ||
616 | client_reg.Version = 0x0210; | ||
617 | client_reg.event_callback_args.client_data = link; | ||
618 | |||
619 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
620 | if (ret != CS_SUCCESS) { | ||
621 | cs_error(link->handle, RegisterClient, ret); | ||
622 | btuart_detach(link); | ||
623 | return NULL; | ||
624 | } | ||
625 | 606 | ||
626 | return link; | 607 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
608 | btuart_config(link); | ||
609 | |||
610 | return 0; | ||
627 | } | 611 | } |
628 | 612 | ||
629 | 613 | ||
630 | static void btuart_detach(dev_link_t *link) | 614 | static void btuart_detach(struct pcmcia_device *p_dev) |
631 | { | 615 | { |
616 | dev_link_t *link = dev_to_instance(p_dev); | ||
632 | btuart_info_t *info = link->priv; | 617 | btuart_info_t *info = link->priv; |
633 | dev_link_t **linkp; | ||
634 | int ret; | ||
635 | |||
636 | /* Locate device structure */ | ||
637 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
638 | if (*linkp == link) | ||
639 | break; | ||
640 | |||
641 | if (*linkp == NULL) | ||
642 | return; | ||
643 | 618 | ||
644 | if (link->state & DEV_CONFIG) | 619 | if (link->state & DEV_CONFIG) |
645 | btuart_release(link); | 620 | btuart_release(link); |
646 | 621 | ||
647 | if (link->handle) { | ||
648 | ret = pcmcia_deregister_client(link->handle); | ||
649 | if (ret != CS_SUCCESS) | ||
650 | cs_error(link->handle, DeregisterClient, ret); | ||
651 | } | ||
652 | |||
653 | /* Unlink device structure, free bits */ | ||
654 | *linkp = link->next; | ||
655 | |||
656 | kfree(info); | 622 | kfree(info); |
657 | } | 623 | } |
658 | 624 | ||
@@ -811,43 +777,29 @@ static void btuart_release(dev_link_t *link) | |||
811 | link->state &= ~DEV_CONFIG; | 777 | link->state &= ~DEV_CONFIG; |
812 | } | 778 | } |
813 | 779 | ||
780 | static int btuart_suspend(struct pcmcia_device *dev) | ||
781 | { | ||
782 | dev_link_t *link = dev_to_instance(dev); | ||
814 | 783 | ||
815 | static int btuart_event(event_t event, int priority, event_callback_args_t *args) | 784 | link->state |= DEV_SUSPEND; |
785 | if (link->state & DEV_CONFIG) | ||
786 | pcmcia_release_configuration(link->handle); | ||
787 | |||
788 | return 0; | ||
789 | } | ||
790 | |||
791 | static int btuart_resume(struct pcmcia_device *dev) | ||
816 | { | 792 | { |
817 | dev_link_t *link = args->client_data; | 793 | dev_link_t *link = dev_to_instance(dev); |
818 | btuart_info_t *info = link->priv; | ||
819 | 794 | ||
820 | switch (event) { | 795 | link->state &= ~DEV_SUSPEND; |
821 | case CS_EVENT_CARD_REMOVAL: | 796 | if (DEV_OK(link)) |
822 | link->state &= ~DEV_PRESENT; | 797 | pcmcia_request_configuration(link->handle, &link->conf); |
823 | if (link->state & DEV_CONFIG) { | ||
824 | btuart_close(info); | ||
825 | btuart_release(link); | ||
826 | } | ||
827 | break; | ||
828 | case CS_EVENT_CARD_INSERTION: | ||
829 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
830 | btuart_config(link); | ||
831 | break; | ||
832 | case CS_EVENT_PM_SUSPEND: | ||
833 | link->state |= DEV_SUSPEND; | ||
834 | /* Fall through... */ | ||
835 | case CS_EVENT_RESET_PHYSICAL: | ||
836 | if (link->state & DEV_CONFIG) | ||
837 | pcmcia_release_configuration(link->handle); | ||
838 | break; | ||
839 | case CS_EVENT_PM_RESUME: | ||
840 | link->state &= ~DEV_SUSPEND; | ||
841 | /* Fall through... */ | ||
842 | case CS_EVENT_CARD_RESET: | ||
843 | if (DEV_OK(link)) | ||
844 | pcmcia_request_configuration(link->handle, &link->conf); | ||
845 | break; | ||
846 | } | ||
847 | 798 | ||
848 | return 0; | 799 | return 0; |
849 | } | 800 | } |
850 | 801 | ||
802 | |||
851 | static struct pcmcia_device_id btuart_ids[] = { | 803 | static struct pcmcia_device_id btuart_ids[] = { |
852 | /* don't use this driver. Use serial_cs + hci_uart instead */ | 804 | /* don't use this driver. Use serial_cs + hci_uart instead */ |
853 | PCMCIA_DEVICE_NULL | 805 | PCMCIA_DEVICE_NULL |
@@ -859,10 +811,11 @@ static struct pcmcia_driver btuart_driver = { | |||
859 | .drv = { | 811 | .drv = { |
860 | .name = "btuart_cs", | 812 | .name = "btuart_cs", |
861 | }, | 813 | }, |
862 | .attach = btuart_attach, | 814 | .probe = btuart_attach, |
863 | .event = btuart_event, | 815 | .remove = btuart_detach, |
864 | .detach = btuart_detach, | ||
865 | .id_table = btuart_ids, | 816 | .id_table = btuart_ids, |
817 | .suspend = btuart_suspend, | ||
818 | .resume = btuart_resume, | ||
866 | }; | 819 | }; |
867 | 820 | ||
868 | static int __init init_btuart_cs(void) | 821 | static int __init init_btuart_cs(void) |
@@ -874,7 +827,6 @@ static int __init init_btuart_cs(void) | |||
874 | static void __exit exit_btuart_cs(void) | 827 | static void __exit exit_btuart_cs(void) |
875 | { | 828 | { |
876 | pcmcia_unregister_driver(&btuart_driver); | 829 | pcmcia_unregister_driver(&btuart_driver); |
877 | BUG_ON(dev_list != NULL); | ||
878 | } | 830 | } |
879 | 831 | ||
880 | module_init(init_btuart_cs); | 832 | module_init(init_btuart_cs); |
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index dec5980a1cd6..0449bc45ae5e 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c | |||
@@ -89,14 +89,8 @@ typedef struct dtl1_info_t { | |||
89 | 89 | ||
90 | static void dtl1_config(dev_link_t *link); | 90 | static void dtl1_config(dev_link_t *link); |
91 | static void dtl1_release(dev_link_t *link); | 91 | static void dtl1_release(dev_link_t *link); |
92 | static int dtl1_event(event_t event, int priority, event_callback_args_t *args); | ||
93 | 92 | ||
94 | static dev_info_t dev_info = "dtl1_cs"; | 93 | static void dtl1_detach(struct pcmcia_device *p_dev); |
95 | |||
96 | static dev_link_t *dtl1_attach(void); | ||
97 | static void dtl1_detach(dev_link_t *); | ||
98 | |||
99 | static dev_link_t *dev_list = NULL; | ||
100 | 94 | ||
101 | 95 | ||
102 | /* Transmit states */ | 96 | /* Transmit states */ |
@@ -561,17 +555,15 @@ static int dtl1_close(dtl1_info_t *info) | |||
561 | return 0; | 555 | return 0; |
562 | } | 556 | } |
563 | 557 | ||
564 | static dev_link_t *dtl1_attach(void) | 558 | static int dtl1_attach(struct pcmcia_device *p_dev) |
565 | { | 559 | { |
566 | dtl1_info_t *info; | 560 | dtl1_info_t *info; |
567 | client_reg_t client_reg; | ||
568 | dev_link_t *link; | 561 | dev_link_t *link; |
569 | int ret; | ||
570 | 562 | ||
571 | /* Create new info device */ | 563 | /* Create new info device */ |
572 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 564 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
573 | if (!info) | 565 | if (!info) |
574 | return NULL; | 566 | return -ENOMEM; |
575 | 567 | ||
576 | link = &info->link; | 568 | link = &info->link; |
577 | link->priv = info; | 569 | link->priv = info; |
@@ -588,50 +580,24 @@ static dev_link_t *dtl1_attach(void) | |||
588 | link->conf.Vcc = 50; | 580 | link->conf.Vcc = 50; |
589 | link->conf.IntType = INT_MEMORY_AND_IO; | 581 | link->conf.IntType = INT_MEMORY_AND_IO; |
590 | 582 | ||
591 | /* Register with Card Services */ | 583 | link->handle = p_dev; |
592 | link->next = dev_list; | 584 | p_dev->instance = link; |
593 | dev_list = link; | ||
594 | client_reg.dev_info = &dev_info; | ||
595 | client_reg.Version = 0x0210; | ||
596 | client_reg.event_callback_args.client_data = link; | ||
597 | |||
598 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
599 | if (ret != CS_SUCCESS) { | ||
600 | cs_error(link->handle, RegisterClient, ret); | ||
601 | dtl1_detach(link); | ||
602 | return NULL; | ||
603 | } | ||
604 | 585 | ||
605 | return link; | 586 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
587 | dtl1_config(link); | ||
588 | |||
589 | return 0; | ||
606 | } | 590 | } |
607 | 591 | ||
608 | 592 | ||
609 | static void dtl1_detach(dev_link_t *link) | 593 | static void dtl1_detach(struct pcmcia_device *p_dev) |
610 | { | 594 | { |
595 | dev_link_t *link = dev_to_instance(p_dev); | ||
611 | dtl1_info_t *info = link->priv; | 596 | dtl1_info_t *info = link->priv; |
612 | dev_link_t **linkp; | ||
613 | int ret; | ||
614 | |||
615 | /* Locate device structure */ | ||
616 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
617 | if (*linkp == link) | ||
618 | break; | ||
619 | |||
620 | if (*linkp == NULL) | ||
621 | return; | ||
622 | 597 | ||
623 | if (link->state & DEV_CONFIG) | 598 | if (link->state & DEV_CONFIG) |
624 | dtl1_release(link); | 599 | dtl1_release(link); |
625 | 600 | ||
626 | if (link->handle) { | ||
627 | ret = pcmcia_deregister_client(link->handle); | ||
628 | if (ret != CS_SUCCESS) | ||
629 | cs_error(link->handle, DeregisterClient, ret); | ||
630 | } | ||
631 | |||
632 | /* Unlink device structure, free bits */ | ||
633 | *linkp = link->next; | ||
634 | |||
635 | kfree(info); | 601 | kfree(info); |
636 | } | 602 | } |
637 | 603 | ||
@@ -763,46 +729,33 @@ static void dtl1_release(dev_link_t *link) | |||
763 | link->state &= ~DEV_CONFIG; | 729 | link->state &= ~DEV_CONFIG; |
764 | } | 730 | } |
765 | 731 | ||
732 | static int dtl1_suspend(struct pcmcia_device *dev) | ||
733 | { | ||
734 | dev_link_t *link = dev_to_instance(dev); | ||
766 | 735 | ||
767 | static int dtl1_event(event_t event, int priority, event_callback_args_t *args) | 736 | link->state |= DEV_SUSPEND; |
737 | if (link->state & DEV_CONFIG) | ||
738 | pcmcia_release_configuration(link->handle); | ||
739 | |||
740 | return 0; | ||
741 | } | ||
742 | |||
743 | static int dtl1_resume(struct pcmcia_device *dev) | ||
768 | { | 744 | { |
769 | dev_link_t *link = args->client_data; | 745 | dev_link_t *link = dev_to_instance(dev); |
770 | dtl1_info_t *info = link->priv; | ||
771 | 746 | ||
772 | switch (event) { | 747 | link->state &= ~DEV_SUSPEND; |
773 | case CS_EVENT_CARD_REMOVAL: | 748 | if (DEV_OK(link)) |
774 | link->state &= ~DEV_PRESENT; | 749 | pcmcia_request_configuration(link->handle, &link->conf); |
775 | if (link->state & DEV_CONFIG) { | ||
776 | dtl1_close(info); | ||
777 | dtl1_release(link); | ||
778 | } | ||
779 | break; | ||
780 | case CS_EVENT_CARD_INSERTION: | ||
781 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
782 | dtl1_config(link); | ||
783 | break; | ||
784 | case CS_EVENT_PM_SUSPEND: | ||
785 | link->state |= DEV_SUSPEND; | ||
786 | /* Fall through... */ | ||
787 | case CS_EVENT_RESET_PHYSICAL: | ||
788 | if (link->state & DEV_CONFIG) | ||
789 | pcmcia_release_configuration(link->handle); | ||
790 | break; | ||
791 | case CS_EVENT_PM_RESUME: | ||
792 | link->state &= ~DEV_SUSPEND; | ||
793 | /* Fall through... */ | ||
794 | case CS_EVENT_CARD_RESET: | ||
795 | if (DEV_OK(link)) | ||
796 | pcmcia_request_configuration(link->handle, &link->conf); | ||
797 | break; | ||
798 | } | ||
799 | 750 | ||
800 | return 0; | 751 | return 0; |
801 | } | 752 | } |
802 | 753 | ||
754 | |||
803 | static struct pcmcia_device_id dtl1_ids[] = { | 755 | static struct pcmcia_device_id dtl1_ids[] = { |
804 | PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-1", 0xe1bfdd64, 0xe168480d), | 756 | PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-1", 0xe1bfdd64, 0xe168480d), |
805 | PCMCIA_DEVICE_PROD_ID12("Socket", "CF", 0xb38bcc2e, 0x44ebf863), | 757 | PCMCIA_DEVICE_PROD_ID12("Socket", "CF", 0xb38bcc2e, 0x44ebf863), |
758 | PCMCIA_DEVICE_PROD_ID12("Socket", "CF+ Personal Network Card", 0xb38bcc2e, 0xe732bae3), | ||
806 | PCMCIA_DEVICE_NULL | 759 | PCMCIA_DEVICE_NULL |
807 | }; | 760 | }; |
808 | MODULE_DEVICE_TABLE(pcmcia, dtl1_ids); | 761 | MODULE_DEVICE_TABLE(pcmcia, dtl1_ids); |
@@ -812,10 +765,11 @@ static struct pcmcia_driver dtl1_driver = { | |||
812 | .drv = { | 765 | .drv = { |
813 | .name = "dtl1_cs", | 766 | .name = "dtl1_cs", |
814 | }, | 767 | }, |
815 | .attach = dtl1_attach, | 768 | .probe = dtl1_attach, |
816 | .event = dtl1_event, | 769 | .remove = dtl1_detach, |
817 | .detach = dtl1_detach, | ||
818 | .id_table = dtl1_ids, | 770 | .id_table = dtl1_ids, |
771 | .suspend = dtl1_suspend, | ||
772 | .resume = dtl1_resume, | ||
819 | }; | 773 | }; |
820 | 774 | ||
821 | static int __init init_dtl1_cs(void) | 775 | static int __init init_dtl1_cs(void) |
@@ -827,7 +781,6 @@ static int __init init_dtl1_cs(void) | |||
827 | static void __exit exit_dtl1_cs(void) | 781 | static void __exit exit_dtl1_cs(void) |
828 | { | 782 | { |
829 | pcmcia_unregister_driver(&dtl1_driver); | 783 | pcmcia_unregister_driver(&dtl1_driver); |
830 | BUG_ON(dev_list != NULL); | ||
831 | } | 784 | } |
832 | 785 | ||
833 | module_init(init_dtl1_cs); | 786 | module_init(init_dtl1_cs); |
diff --git a/drivers/char/pcmcia/cm4000_cs.c b/drivers/char/pcmcia/cm4000_cs.c index 61681c9f3f72..649677b5dc36 100644 --- a/drivers/char/pcmcia/cm4000_cs.c +++ b/drivers/char/pcmcia/cm4000_cs.c | |||
@@ -66,7 +66,6 @@ static char *version = "cm4000_cs.c v2.4.0gm5 - All bugs added by Harald Welte"; | |||
66 | #define T_100MSEC msecs_to_jiffies(100) | 66 | #define T_100MSEC msecs_to_jiffies(100) |
67 | #define T_500MSEC msecs_to_jiffies(500) | 67 | #define T_500MSEC msecs_to_jiffies(500) |
68 | 68 | ||
69 | static void cm4000_detach(dev_link_t *link); | ||
70 | static void cm4000_release(dev_link_t *link); | 69 | static void cm4000_release(dev_link_t *link); |
71 | 70 | ||
72 | static int major; /* major number we get from the kernel */ | 71 | static int major; /* major number we get from the kernel */ |
@@ -156,7 +155,6 @@ struct cm4000_dev { | |||
156 | /*sbuf*/ 512*sizeof(char) - \ | 155 | /*sbuf*/ 512*sizeof(char) - \ |
157 | /*queue*/ 4*sizeof(wait_queue_head_t)) | 156 | /*queue*/ 4*sizeof(wait_queue_head_t)) |
158 | 157 | ||
159 | static dev_info_t dev_info = MODULE_NAME; | ||
160 | static dev_link_t *dev_table[CM4000_MAX_DEV]; | 158 | static dev_link_t *dev_table[CM4000_MAX_DEV]; |
161 | 159 | ||
162 | /* This table doesn't use spaces after the comma between fields and thus | 160 | /* This table doesn't use spaces after the comma between fields and thus |
@@ -1864,68 +1862,36 @@ cs_release: | |||
1864 | link->state &= ~DEV_CONFIG_PENDING; | 1862 | link->state &= ~DEV_CONFIG_PENDING; |
1865 | } | 1863 | } |
1866 | 1864 | ||
1867 | static int cm4000_event(event_t event, int priority, | 1865 | static int cm4000_suspend(struct pcmcia_device *p_dev) |
1868 | event_callback_args_t *args) | ||
1869 | { | 1866 | { |
1870 | dev_link_t *link; | 1867 | dev_link_t *link = dev_to_instance(p_dev); |
1871 | struct cm4000_dev *dev; | 1868 | struct cm4000_dev *dev; |
1872 | int devno; | ||
1873 | 1869 | ||
1874 | link = args->client_data; | ||
1875 | dev = link->priv; | 1870 | dev = link->priv; |
1876 | 1871 | ||
1877 | DEBUGP(3, dev, "-> cm4000_event\n"); | 1872 | link->state |= DEV_SUSPEND; |
1878 | for (devno = 0; devno < CM4000_MAX_DEV; devno++) | 1873 | if (link->state & DEV_CONFIG) |
1879 | if (dev_table[devno] == link) | 1874 | pcmcia_release_configuration(link->handle); |
1880 | break; | 1875 | stop_monitor(dev); |
1881 | 1876 | ||
1882 | if (devno == CM4000_MAX_DEV) | 1877 | return 0; |
1883 | return CS_BAD_ADAPTER; | 1878 | } |
1884 | 1879 | ||
1885 | switch (event) { | 1880 | static int cm4000_resume(struct pcmcia_device *p_dev) |
1886 | case CS_EVENT_CARD_INSERTION: | 1881 | { |
1887 | DEBUGP(5, dev, "CS_EVENT_CARD_INSERTION\n"); | 1882 | dev_link_t *link = dev_to_instance(p_dev); |
1888 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | 1883 | struct cm4000_dev *dev; |
1889 | cm4000_config(link, devno); | 1884 | |
1890 | break; | 1885 | dev = link->priv; |
1891 | case CS_EVENT_CARD_REMOVAL: | 1886 | |
1892 | DEBUGP(5, dev, "CS_EVENT_CARD_REMOVAL\n"); | 1887 | link->state &= ~DEV_SUSPEND; |
1893 | link->state &= ~DEV_PRESENT; | 1888 | if (link->state & DEV_CONFIG) |
1894 | stop_monitor(dev); | 1889 | pcmcia_request_configuration(link->handle, &link->conf); |
1895 | break; | 1890 | |
1896 | case CS_EVENT_PM_SUSPEND: | 1891 | if (link->open) |
1897 | DEBUGP(5, dev, "CS_EVENT_PM_SUSPEND " | 1892 | start_monitor(dev); |
1898 | "(fall-through to CS_EVENT_RESET_PHYSICAL)\n"); | 1893 | |
1899 | link->state |= DEV_SUSPEND; | 1894 | return 0; |
1900 | /* fall-through */ | ||
1901 | case CS_EVENT_RESET_PHYSICAL: | ||
1902 | DEBUGP(5, dev, "CS_EVENT_RESET_PHYSICAL\n"); | ||
1903 | if (link->state & DEV_CONFIG) { | ||
1904 | DEBUGP(5, dev, "ReleaseConfiguration\n"); | ||
1905 | pcmcia_release_configuration(link->handle); | ||
1906 | } | ||
1907 | stop_monitor(dev); | ||
1908 | break; | ||
1909 | case CS_EVENT_PM_RESUME: | ||
1910 | DEBUGP(5, dev, "CS_EVENT_PM_RESUME " | ||
1911 | "(fall-through to CS_EVENT_CARD_RESET)\n"); | ||
1912 | link->state &= ~DEV_SUSPEND; | ||
1913 | /* fall-through */ | ||
1914 | case CS_EVENT_CARD_RESET: | ||
1915 | DEBUGP(5, dev, "CS_EVENT_CARD_RESET\n"); | ||
1916 | if ((link->state & DEV_CONFIG)) { | ||
1917 | DEBUGP(5, dev, "RequestConfiguration\n"); | ||
1918 | pcmcia_request_configuration(link->handle, &link->conf); | ||
1919 | } | ||
1920 | if (link->open) | ||
1921 | start_monitor(dev); | ||
1922 | break; | ||
1923 | default: | ||
1924 | DEBUGP(5, dev, "unknown event %.2x\n", event); | ||
1925 | break; | ||
1926 | } | ||
1927 | DEBUGP(3, dev, "<- cm4000_event\n"); | ||
1928 | return CS_SUCCESS; | ||
1929 | } | 1895 | } |
1930 | 1896 | ||
1931 | static void cm4000_release(dev_link_t *link) | 1897 | static void cm4000_release(dev_link_t *link) |
@@ -1935,11 +1901,10 @@ static void cm4000_release(dev_link_t *link) | |||
1935 | pcmcia_release_io(link->handle, &link->io); | 1901 | pcmcia_release_io(link->handle, &link->io); |
1936 | } | 1902 | } |
1937 | 1903 | ||
1938 | static dev_link_t *cm4000_attach(void) | 1904 | static int cm4000_attach(struct pcmcia_device *p_dev) |
1939 | { | 1905 | { |
1940 | struct cm4000_dev *dev; | 1906 | struct cm4000_dev *dev; |
1941 | dev_link_t *link; | 1907 | dev_link_t *link; |
1942 | client_reg_t client_reg; | ||
1943 | int i; | 1908 | int i; |
1944 | 1909 | ||
1945 | for (i = 0; i < CM4000_MAX_DEV; i++) | 1910 | for (i = 0; i < CM4000_MAX_DEV; i++) |
@@ -1948,76 +1913,55 @@ static dev_link_t *cm4000_attach(void) | |||
1948 | 1913 | ||
1949 | if (i == CM4000_MAX_DEV) { | 1914 | if (i == CM4000_MAX_DEV) { |
1950 | printk(KERN_NOTICE MODULE_NAME ": all devices in use\n"); | 1915 | printk(KERN_NOTICE MODULE_NAME ": all devices in use\n"); |
1951 | return NULL; | 1916 | return -ENODEV; |
1952 | } | 1917 | } |
1953 | 1918 | ||
1954 | /* create a new cm4000_cs device */ | 1919 | /* create a new cm4000_cs device */ |
1955 | dev = kzalloc(sizeof(struct cm4000_dev), GFP_KERNEL); | 1920 | dev = kzalloc(sizeof(struct cm4000_dev), GFP_KERNEL); |
1956 | if (dev == NULL) | 1921 | if (dev == NULL) |
1957 | return NULL; | 1922 | return -ENOMEM; |
1958 | 1923 | ||
1959 | link = &dev->link; | 1924 | link = &dev->link; |
1960 | link->priv = dev; | 1925 | link->priv = dev; |
1961 | link->conf.IntType = INT_MEMORY_AND_IO; | 1926 | link->conf.IntType = INT_MEMORY_AND_IO; |
1962 | dev_table[i] = link; | 1927 | dev_table[i] = link; |
1963 | 1928 | ||
1964 | /* register with card services */ | ||
1965 | client_reg.dev_info = &dev_info; | ||
1966 | client_reg.EventMask = | ||
1967 | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | | ||
1968 | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | | ||
1969 | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; | ||
1970 | client_reg.Version = 0x0210; | ||
1971 | client_reg.event_callback_args.client_data = link; | ||
1972 | |||
1973 | i = pcmcia_register_client(&link->handle, &client_reg); | ||
1974 | if (i) { | ||
1975 | cs_error(link->handle, RegisterClient, i); | ||
1976 | cm4000_detach(link); | ||
1977 | return NULL; | ||
1978 | } | ||
1979 | |||
1980 | init_waitqueue_head(&dev->devq); | 1929 | init_waitqueue_head(&dev->devq); |
1981 | init_waitqueue_head(&dev->ioq); | 1930 | init_waitqueue_head(&dev->ioq); |
1982 | init_waitqueue_head(&dev->atrq); | 1931 | init_waitqueue_head(&dev->atrq); |
1983 | init_waitqueue_head(&dev->readq); | 1932 | init_waitqueue_head(&dev->readq); |
1984 | 1933 | ||
1985 | return link; | 1934 | link->handle = p_dev; |
1986 | } | 1935 | p_dev->instance = link; |
1987 | |||
1988 | static void cm4000_detach_by_devno(int devno, dev_link_t * link) | ||
1989 | { | ||
1990 | struct cm4000_dev *dev = link->priv; | ||
1991 | |||
1992 | DEBUGP(3, dev, "-> detach_by_devno(devno=%d)\n", devno); | ||
1993 | |||
1994 | if (link->state & DEV_CONFIG) { | ||
1995 | DEBUGP(5, dev, "device still configured (try to release it)\n"); | ||
1996 | cm4000_release(link); | ||
1997 | } | ||
1998 | 1936 | ||
1999 | if (link->handle) { | 1937 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
2000 | pcmcia_deregister_client(link->handle); | 1938 | cm4000_config(link, i); |
2001 | } | ||
2002 | 1939 | ||
2003 | dev_table[devno] = NULL; | 1940 | return 0; |
2004 | kfree(dev); | ||
2005 | return; | ||
2006 | } | 1941 | } |
2007 | 1942 | ||
2008 | static void cm4000_detach(dev_link_t * link) | 1943 | static void cm4000_detach(struct pcmcia_device *p_dev) |
2009 | { | 1944 | { |
2010 | int i; | 1945 | dev_link_t *link = dev_to_instance(p_dev); |
1946 | struct cm4000_dev *dev = link->priv; | ||
1947 | int devno; | ||
2011 | 1948 | ||
2012 | /* find device */ | 1949 | /* find device */ |
2013 | for (i = 0; i < CM4000_MAX_DEV; i++) | 1950 | for (devno = 0; devno < CM4000_MAX_DEV; devno++) |
2014 | if (dev_table[i] == link) | 1951 | if (dev_table[devno] == link) |
2015 | break; | 1952 | break; |
2016 | 1953 | if (devno == CM4000_MAX_DEV) | |
2017 | if (i == CM4000_MAX_DEV) | ||
2018 | return; | 1954 | return; |
2019 | 1955 | ||
2020 | cm4000_detach_by_devno(i, link); | 1956 | link->state &= ~DEV_PRESENT; |
1957 | stop_monitor(dev); | ||
1958 | |||
1959 | if (link->state & DEV_CONFIG) | ||
1960 | cm4000_release(link); | ||
1961 | |||
1962 | dev_table[devno] = NULL; | ||
1963 | kfree(dev); | ||
1964 | |||
2021 | return; | 1965 | return; |
2022 | } | 1966 | } |
2023 | 1967 | ||
@@ -2042,9 +1986,10 @@ static struct pcmcia_driver cm4000_driver = { | |||
2042 | .drv = { | 1986 | .drv = { |
2043 | .name = "cm4000_cs", | 1987 | .name = "cm4000_cs", |
2044 | }, | 1988 | }, |
2045 | .attach = cm4000_attach, | 1989 | .probe = cm4000_attach, |
2046 | .detach = cm4000_detach, | 1990 | .remove = cm4000_detach, |
2047 | .event = cm4000_event, | 1991 | .suspend = cm4000_suspend, |
1992 | .resume = cm4000_resume, | ||
2048 | .id_table = cm4000_ids, | 1993 | .id_table = cm4000_ids, |
2049 | }; | 1994 | }; |
2050 | 1995 | ||
@@ -2064,13 +2009,8 @@ static int __init cmm_init(void) | |||
2064 | 2009 | ||
2065 | static void __exit cmm_exit(void) | 2010 | static void __exit cmm_exit(void) |
2066 | { | 2011 | { |
2067 | int i; | ||
2068 | |||
2069 | printk(KERN_INFO MODULE_NAME ": unloading\n"); | 2012 | printk(KERN_INFO MODULE_NAME ": unloading\n"); |
2070 | pcmcia_unregister_driver(&cm4000_driver); | 2013 | pcmcia_unregister_driver(&cm4000_driver); |
2071 | for (i = 0; i < CM4000_MAX_DEV; i++) | ||
2072 | if (dev_table[i]) | ||
2073 | cm4000_detach_by_devno(i, dev_table[i]); | ||
2074 | unregister_chrdev(major, DEVICE_NAME); | 2014 | unregister_chrdev(major, DEVICE_NAME); |
2075 | }; | 2015 | }; |
2076 | 2016 | ||
diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index 4c698d908ffa..46eb371bf17e 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c | |||
@@ -65,7 +65,6 @@ static char *version = | |||
65 | #define POLL_PERIOD msecs_to_jiffies(10) | 65 | #define POLL_PERIOD msecs_to_jiffies(10) |
66 | 66 | ||
67 | static void reader_release(dev_link_t *link); | 67 | static void reader_release(dev_link_t *link); |
68 | static void reader_detach(dev_link_t *link); | ||
69 | 68 | ||
70 | static int major; | 69 | static int major; |
71 | 70 | ||
@@ -86,7 +85,6 @@ struct reader_dev { | |||
86 | struct timer_list poll_timer; | 85 | struct timer_list poll_timer; |
87 | }; | 86 | }; |
88 | 87 | ||
89 | static dev_info_t dev_info = MODULE_NAME; | ||
90 | static dev_link_t *dev_table[CM_MAX_DEV]; | 88 | static dev_link_t *dev_table[CM_MAX_DEV]; |
91 | 89 | ||
92 | #ifndef PCMCIA_DEBUG | 90 | #ifndef PCMCIA_DEBUG |
@@ -629,65 +627,26 @@ cs_release: | |||
629 | link->state &= ~DEV_CONFIG_PENDING; | 627 | link->state &= ~DEV_CONFIG_PENDING; |
630 | } | 628 | } |
631 | 629 | ||
632 | static int reader_event(event_t event, int priority, | 630 | static int reader_suspend(struct pcmcia_device *p_dev) |
633 | event_callback_args_t *args) | ||
634 | { | 631 | { |
635 | dev_link_t *link; | 632 | dev_link_t *link = dev_to_instance(p_dev); |
636 | struct reader_dev *dev; | ||
637 | int devno; | ||
638 | 633 | ||
639 | link = args->client_data; | 634 | link->state |= DEV_SUSPEND; |
640 | dev = link->priv; | 635 | if (link->state & DEV_CONFIG) |
641 | DEBUGP(3, dev, "-> reader_event\n"); | 636 | pcmcia_release_configuration(link->handle); |
642 | for (devno = 0; devno < CM_MAX_DEV; devno++) { | ||
643 | if (dev_table[devno] == link) | ||
644 | break; | ||
645 | } | ||
646 | if (devno == CM_MAX_DEV) | ||
647 | return CS_BAD_ADAPTER; | ||
648 | 637 | ||
649 | switch (event) { | 638 | return 0; |
650 | case CS_EVENT_CARD_INSERTION: | 639 | } |
651 | DEBUGP(5, dev, "CS_EVENT_CARD_INSERTION\n"); | 640 | |
652 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | 641 | static int reader_resume(struct pcmcia_device *p_dev) |
653 | reader_config(link, devno); | 642 | { |
654 | break; | 643 | dev_link_t *link = dev_to_instance(p_dev); |
655 | case CS_EVENT_CARD_REMOVAL: | 644 | |
656 | DEBUGP(5, dev, "CS_EVENT_CARD_REMOVAL\n"); | 645 | link->state &= ~DEV_SUSPEND; |
657 | link->state &= ~DEV_PRESENT; | 646 | if (link->state & DEV_CONFIG) |
658 | break; | 647 | pcmcia_request_configuration(link->handle, &link->conf); |
659 | case CS_EVENT_PM_SUSPEND: | 648 | |
660 | DEBUGP(5, dev, "CS_EVENT_PM_SUSPEND " | 649 | return 0; |
661 | "(fall-through to CS_EVENT_RESET_PHYSICAL)\n"); | ||
662 | link->state |= DEV_SUSPEND; | ||
663 | |||
664 | case CS_EVENT_RESET_PHYSICAL: | ||
665 | DEBUGP(5, dev, "CS_EVENT_RESET_PHYSICAL\n"); | ||
666 | if (link->state & DEV_CONFIG) { | ||
667 | DEBUGP(5, dev, "ReleaseConfiguration\n"); | ||
668 | pcmcia_release_configuration(link->handle); | ||
669 | } | ||
670 | break; | ||
671 | case CS_EVENT_PM_RESUME: | ||
672 | DEBUGP(5, dev, "CS_EVENT_PM_RESUME " | ||
673 | "(fall-through to CS_EVENT_CARD_RESET)\n"); | ||
674 | link->state &= ~DEV_SUSPEND; | ||
675 | |||
676 | case CS_EVENT_CARD_RESET: | ||
677 | DEBUGP(5, dev, "CS_EVENT_CARD_RESET\n"); | ||
678 | if ((link->state & DEV_CONFIG)) { | ||
679 | DEBUGP(5, dev, "RequestConfiguration\n"); | ||
680 | pcmcia_request_configuration(link->handle, | ||
681 | &link->conf); | ||
682 | } | ||
683 | break; | ||
684 | default: | ||
685 | DEBUGP(5, dev, "reader_event: unknown event %.2x\n", | ||
686 | event); | ||
687 | break; | ||
688 | } | ||
689 | DEBUGP(3, dev, "<- reader_event\n"); | ||
690 | return CS_SUCCESS; | ||
691 | } | 650 | } |
692 | 651 | ||
693 | static void reader_release(dev_link_t *link) | 652 | static void reader_release(dev_link_t *link) |
@@ -697,11 +656,10 @@ static void reader_release(dev_link_t *link) | |||
697 | pcmcia_release_io(link->handle, &link->io); | 656 | pcmcia_release_io(link->handle, &link->io); |
698 | } | 657 | } |
699 | 658 | ||
700 | static dev_link_t *reader_attach(void) | 659 | static int reader_attach(struct pcmcia_device *p_dev) |
701 | { | 660 | { |
702 | struct reader_dev *dev; | 661 | struct reader_dev *dev; |
703 | dev_link_t *link; | 662 | dev_link_t *link; |
704 | client_reg_t client_reg; | ||
705 | int i; | 663 | int i; |
706 | 664 | ||
707 | for (i = 0; i < CM_MAX_DEV; i++) { | 665 | for (i = 0; i < CM_MAX_DEV; i++) { |
@@ -710,11 +668,11 @@ static dev_link_t *reader_attach(void) | |||
710 | } | 668 | } |
711 | 669 | ||
712 | if (i == CM_MAX_DEV) | 670 | if (i == CM_MAX_DEV) |
713 | return NULL; | 671 | return -ENODEV; |
714 | 672 | ||
715 | dev = kzalloc(sizeof(struct reader_dev), GFP_KERNEL); | 673 | dev = kzalloc(sizeof(struct reader_dev), GFP_KERNEL); |
716 | if (dev == NULL) | 674 | if (dev == NULL) |
717 | return NULL; | 675 | return -ENOMEM; |
718 | 676 | ||
719 | dev->timeout = CCID_DRIVER_MINIMUM_TIMEOUT; | 677 | dev->timeout = CCID_DRIVER_MINIMUM_TIMEOUT; |
720 | dev->buffer_status = 0; | 678 | dev->buffer_status = 0; |
@@ -725,20 +683,6 @@ static dev_link_t *reader_attach(void) | |||
725 | link->conf.IntType = INT_MEMORY_AND_IO; | 683 | link->conf.IntType = INT_MEMORY_AND_IO; |
726 | dev_table[i] = link; | 684 | dev_table[i] = link; |
727 | 685 | ||
728 | client_reg.dev_info = &dev_info; | ||
729 | client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; | ||
730 | client_reg.EventMask= | ||
731 | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | | ||
732 | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | | ||
733 | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; | ||
734 | client_reg.Version = 0x0210; | ||
735 | client_reg.event_callback_args.client_data = link; | ||
736 | i = pcmcia_register_client(&link->handle, &client_reg); | ||
737 | if (i) { | ||
738 | cs_error(link->handle, RegisterClient, i); | ||
739 | reader_detach(link); | ||
740 | return NULL; | ||
741 | } | ||
742 | init_waitqueue_head(&dev->devq); | 686 | init_waitqueue_head(&dev->devq); |
743 | init_waitqueue_head(&dev->poll_wait); | 687 | init_waitqueue_head(&dev->poll_wait); |
744 | init_waitqueue_head(&dev->read_wait); | 688 | init_waitqueue_head(&dev->read_wait); |
@@ -746,39 +690,37 @@ static dev_link_t *reader_attach(void) | |||
746 | init_timer(&dev->poll_timer); | 690 | init_timer(&dev->poll_timer); |
747 | dev->poll_timer.function = &cm4040_do_poll; | 691 | dev->poll_timer.function = &cm4040_do_poll; |
748 | 692 | ||
749 | return link; | 693 | link->handle = p_dev; |
750 | } | 694 | p_dev->instance = link; |
751 | |||
752 | static void reader_detach_by_devno(int devno, dev_link_t *link) | ||
753 | { | ||
754 | struct reader_dev *dev = link->priv; | ||
755 | 695 | ||
756 | if (link->state & DEV_CONFIG) { | 696 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
757 | DEBUGP(5, dev, "device still configured (try to release it)\n"); | 697 | reader_config(link, i); |
758 | reader_release(link); | ||
759 | } | ||
760 | 698 | ||
761 | pcmcia_deregister_client(link->handle); | 699 | return 0; |
762 | dev_table[devno] = NULL; | ||
763 | DEBUGP(5, dev, "freeing dev=%p\n", dev); | ||
764 | cm4040_stop_poll(dev); | ||
765 | kfree(dev); | ||
766 | return; | ||
767 | } | 700 | } |
768 | 701 | ||
769 | static void reader_detach(dev_link_t *link) | 702 | static void reader_detach(struct pcmcia_device *p_dev) |
770 | { | 703 | { |
771 | int i; | 704 | dev_link_t *link = dev_to_instance(p_dev); |
705 | struct reader_dev *dev = link->priv; | ||
706 | int devno; | ||
772 | 707 | ||
773 | /* find device */ | 708 | /* find device */ |
774 | for (i = 0; i < CM_MAX_DEV; i++) { | 709 | for (devno = 0; devno < CM_MAX_DEV; devno++) { |
775 | if (dev_table[i] == link) | 710 | if (dev_table[devno] == link) |
776 | break; | 711 | break; |
777 | } | 712 | } |
778 | if (i == CM_MAX_DEV) | 713 | if (devno == CM_MAX_DEV) |
779 | return; | 714 | return; |
780 | 715 | ||
781 | reader_detach_by_devno(i, link); | 716 | link->state &= ~DEV_PRESENT; |
717 | |||
718 | if (link->state & DEV_CONFIG) | ||
719 | reader_release(link); | ||
720 | |||
721 | dev_table[devno] = NULL; | ||
722 | kfree(dev); | ||
723 | |||
782 | return; | 724 | return; |
783 | } | 725 | } |
784 | 726 | ||
@@ -804,9 +746,10 @@ static struct pcmcia_driver reader_driver = { | |||
804 | .drv = { | 746 | .drv = { |
805 | .name = "cm4040_cs", | 747 | .name = "cm4040_cs", |
806 | }, | 748 | }, |
807 | .attach = reader_attach, | 749 | .probe = reader_attach, |
808 | .detach = reader_detach, | 750 | .remove = reader_detach, |
809 | .event = reader_event, | 751 | .suspend = reader_suspend, |
752 | .resume = reader_resume, | ||
810 | .id_table = cm4040_ids, | 753 | .id_table = cm4040_ids, |
811 | }; | 754 | }; |
812 | 755 | ||
@@ -825,14 +768,8 @@ static int __init cm4040_init(void) | |||
825 | 768 | ||
826 | static void __exit cm4040_exit(void) | 769 | static void __exit cm4040_exit(void) |
827 | { | 770 | { |
828 | int i; | ||
829 | |||
830 | printk(KERN_INFO MODULE_NAME ": unloading\n"); | 771 | printk(KERN_INFO MODULE_NAME ": unloading\n"); |
831 | pcmcia_unregister_driver(&reader_driver); | 772 | pcmcia_unregister_driver(&reader_driver); |
832 | for (i = 0; i < CM_MAX_DEV; i++) { | ||
833 | if (dev_table[i]) | ||
834 | reader_detach_by_devno(i, dev_table[i]); | ||
835 | } | ||
836 | unregister_chrdev(major, DEVICE_NAME); | 773 | unregister_chrdev(major, DEVICE_NAME); |
837 | } | 774 | } |
838 | 775 | ||
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) |
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c index ef79805218e4..4c2af9020905 100644 --- a/drivers/ide/legacy/ide-cs.c +++ b/drivers/ide/legacy/ide-cs.c | |||
@@ -88,15 +88,12 @@ typedef struct ide_info_t { | |||
88 | } ide_info_t; | 88 | } ide_info_t; |
89 | 89 | ||
90 | static void ide_release(dev_link_t *); | 90 | static void ide_release(dev_link_t *); |
91 | static int ide_event(event_t event, int priority, | 91 | static void ide_config(dev_link_t *); |
92 | event_callback_args_t *args); | 92 | |
93 | static void ide_detach(struct pcmcia_device *p_dev); | ||
93 | 94 | ||
94 | static dev_info_t dev_info = "ide-cs"; | ||
95 | 95 | ||
96 | static dev_link_t *ide_attach(void); | ||
97 | static void ide_detach(dev_link_t *); | ||
98 | 96 | ||
99 | static dev_link_t *dev_list = NULL; | ||
100 | 97 | ||
101 | /*====================================================================== | 98 | /*====================================================================== |
102 | 99 | ||
@@ -106,18 +103,17 @@ static dev_link_t *dev_list = NULL; | |||
106 | 103 | ||
107 | ======================================================================*/ | 104 | ======================================================================*/ |
108 | 105 | ||
109 | static dev_link_t *ide_attach(void) | 106 | static int ide_attach(struct pcmcia_device *p_dev) |
110 | { | 107 | { |
111 | ide_info_t *info; | 108 | ide_info_t *info; |
112 | dev_link_t *link; | 109 | dev_link_t *link; |
113 | client_reg_t client_reg; | 110 | |
114 | int ret; | ||
115 | |||
116 | DEBUG(0, "ide_attach()\n"); | 111 | DEBUG(0, "ide_attach()\n"); |
117 | 112 | ||
118 | /* Create new ide device */ | 113 | /* Create new ide device */ |
119 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 114 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
120 | if (!info) return NULL; | 115 | if (!info) |
116 | return -ENOMEM; | ||
121 | link = &info->link; link->priv = info; | 117 | link = &info->link; link->priv = info; |
122 | 118 | ||
123 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; | 119 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; |
@@ -128,21 +124,14 @@ static dev_link_t *ide_attach(void) | |||
128 | link->conf.Attributes = CONF_ENABLE_IRQ; | 124 | link->conf.Attributes = CONF_ENABLE_IRQ; |
129 | link->conf.Vcc = 50; | 125 | link->conf.Vcc = 50; |
130 | link->conf.IntType = INT_MEMORY_AND_IO; | 126 | link->conf.IntType = INT_MEMORY_AND_IO; |
131 | 127 | ||
132 | /* Register with Card Services */ | 128 | link->handle = p_dev; |
133 | link->next = dev_list; | 129 | p_dev->instance = link; |
134 | dev_list = link; | 130 | |
135 | client_reg.dev_info = &dev_info; | 131 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
136 | client_reg.Version = 0x0210; | 132 | ide_config(link); |
137 | client_reg.event_callback_args.client_data = link; | 133 | |
138 | ret = pcmcia_register_client(&link->handle, &client_reg); | 134 | return 0; |
139 | if (ret != CS_SUCCESS) { | ||
140 | cs_error(link->handle, RegisterClient, ret); | ||
141 | ide_detach(link); | ||
142 | return NULL; | ||
143 | } | ||
144 | |||
145 | return link; | ||
146 | } /* ide_attach */ | 135 | } /* ide_attach */ |
147 | 136 | ||
148 | /*====================================================================== | 137 | /*====================================================================== |
@@ -154,32 +143,16 @@ static dev_link_t *ide_attach(void) | |||
154 | 143 | ||
155 | ======================================================================*/ | 144 | ======================================================================*/ |
156 | 145 | ||
157 | static void ide_detach(dev_link_t *link) | 146 | static void ide_detach(struct pcmcia_device *p_dev) |
158 | { | 147 | { |
159 | dev_link_t **linkp; | 148 | dev_link_t *link = dev_to_instance(p_dev); |
160 | int ret; | ||
161 | 149 | ||
162 | DEBUG(0, "ide_detach(0x%p)\n", link); | 150 | DEBUG(0, "ide_detach(0x%p)\n", link); |
163 | |||
164 | /* Locate device structure */ | ||
165 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
166 | if (*linkp == link) break; | ||
167 | if (*linkp == NULL) | ||
168 | return; | ||
169 | 151 | ||
170 | if (link->state & DEV_CONFIG) | 152 | if (link->state & DEV_CONFIG) |
171 | ide_release(link); | 153 | ide_release(link); |
172 | 154 | ||
173 | if (link->handle) { | ||
174 | ret = pcmcia_deregister_client(link->handle); | ||
175 | if (ret != CS_SUCCESS) | ||
176 | cs_error(link->handle, DeregisterClient, ret); | ||
177 | } | ||
178 | |||
179 | /* Unlink, free device structure */ | ||
180 | *linkp = link->next; | ||
181 | kfree(link->priv); | 155 | kfree(link->priv); |
182 | |||
183 | } /* ide_detach */ | 156 | } /* ide_detach */ |
184 | 157 | ||
185 | static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq, struct pcmcia_device *handle) | 158 | static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq, struct pcmcia_device *handle) |
@@ -406,6 +379,28 @@ void ide_release(dev_link_t *link) | |||
406 | 379 | ||
407 | } /* ide_release */ | 380 | } /* ide_release */ |
408 | 381 | ||
382 | static int ide_suspend(struct pcmcia_device *dev) | ||
383 | { | ||
384 | dev_link_t *link = dev_to_instance(dev); | ||
385 | |||
386 | link->state |= DEV_SUSPEND; | ||
387 | if (link->state & DEV_CONFIG) | ||
388 | pcmcia_release_configuration(link->handle); | ||
389 | |||
390 | return 0; | ||
391 | } | ||
392 | |||
393 | static int ide_resume(struct pcmcia_device *dev) | ||
394 | { | ||
395 | dev_link_t *link = dev_to_instance(dev); | ||
396 | |||
397 | link->state &= ~DEV_SUSPEND; | ||
398 | if (DEV_OK(link)) | ||
399 | pcmcia_request_configuration(link->handle, &link->conf); | ||
400 | |||
401 | return 0; | ||
402 | } | ||
403 | |||
409 | /*====================================================================== | 404 | /*====================================================================== |
410 | 405 | ||
411 | The card status event handler. Mostly, this schedules other | 406 | The card status event handler. Mostly, this schedules other |
@@ -415,48 +410,15 @@ void ide_release(dev_link_t *link) | |||
415 | 410 | ||
416 | ======================================================================*/ | 411 | ======================================================================*/ |
417 | 412 | ||
418 | int ide_event(event_t event, int priority, | ||
419 | event_callback_args_t *args) | ||
420 | { | ||
421 | dev_link_t *link = args->client_data; | ||
422 | |||
423 | DEBUG(1, "ide_event(0x%06x)\n", event); | ||
424 | |||
425 | switch (event) { | ||
426 | case CS_EVENT_CARD_REMOVAL: | ||
427 | link->state &= ~DEV_PRESENT; | ||
428 | if (link->state & DEV_CONFIG) | ||
429 | ide_release(link); | ||
430 | break; | ||
431 | case CS_EVENT_CARD_INSERTION: | ||
432 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
433 | ide_config(link); | ||
434 | break; | ||
435 | case CS_EVENT_PM_SUSPEND: | ||
436 | link->state |= DEV_SUSPEND; | ||
437 | /* Fall through... */ | ||
438 | case CS_EVENT_RESET_PHYSICAL: | ||
439 | if (link->state & DEV_CONFIG) | ||
440 | pcmcia_release_configuration(link->handle); | ||
441 | break; | ||
442 | case CS_EVENT_PM_RESUME: | ||
443 | link->state &= ~DEV_SUSPEND; | ||
444 | /* Fall through... */ | ||
445 | case CS_EVENT_CARD_RESET: | ||
446 | if (DEV_OK(link)) | ||
447 | pcmcia_request_configuration(link->handle, &link->conf); | ||
448 | break; | ||
449 | } | ||
450 | return 0; | ||
451 | } /* ide_event */ | ||
452 | |||
453 | static struct pcmcia_device_id ide_ids[] = { | 413 | static struct pcmcia_device_id ide_ids[] = { |
454 | PCMCIA_DEVICE_FUNC_ID(4), | 414 | PCMCIA_DEVICE_FUNC_ID(4), |
415 | PCMCIA_DEVICE_MANF_CARD(0x0007, 0x0000), /* Hitachi */ | ||
455 | PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704), | 416 | PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704), |
456 | PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401), | 417 | PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401), |
457 | PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000), /* Toshiba */ | 418 | PCMCIA_DEVICE_MANF_CARD(0x0098, 0x0000), /* Toshiba */ |
458 | PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d), | 419 | PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d), |
459 | PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000), /* Samsung */ | 420 | PCMCIA_DEVICE_MANF_CARD(0x00ce, 0x0000), /* Samsung */ |
421 | PCMCIA_DEVICE_MANF_CARD(0x0319, 0x0000), /* Hitachi */ | ||
460 | PCMCIA_DEVICE_MANF_CARD(0x2080, 0x0001), | 422 | PCMCIA_DEVICE_MANF_CARD(0x2080, 0x0001), |
461 | PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0200), /* Lexar */ | 423 | PCMCIA_DEVICE_MANF_CARD(0x4e01, 0x0200), /* Lexar */ |
462 | PCMCIA_DEVICE_PROD_ID123("Caravelle", "PSC-IDE ", "PSC000", 0x8c36137c, 0xd0693ab8, 0x2768a9f0), | 424 | PCMCIA_DEVICE_PROD_ID123("Caravelle", "PSC-IDE ", "PSC000", 0x8c36137c, 0xd0693ab8, 0x2768a9f0), |
@@ -471,6 +433,8 @@ static struct pcmcia_device_id ide_ids[] = { | |||
471 | PCMCIA_DEVICE_PROD_ID12("EXP ", "CD-ROM", 0x0a5c52fd, 0x66536591), | 433 | PCMCIA_DEVICE_PROD_ID12("EXP ", "CD-ROM", 0x0a5c52fd, 0x66536591), |
472 | PCMCIA_DEVICE_PROD_ID12("EXP ", "PnPIDE", 0x0a5c52fd, 0x0c694728), | 434 | PCMCIA_DEVICE_PROD_ID12("EXP ", "PnPIDE", 0x0a5c52fd, 0x0c694728), |
473 | PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e), | 435 | PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e), |
436 | PCMCIA_DEVICE_PROD_ID12("HITACHI", "FLASH", 0xf4f43949, 0x9eb86aae), | ||
437 | PCMCIA_DEVICE_PROD_ID12("HITACHI", "microdrive", 0xf4f43949, 0xa6d76178), | ||
474 | PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753), | 438 | PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753), |
475 | PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2 ", 0x547e66dc, 0x8671043b), | 439 | PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2 ", 0x547e66dc, 0x8671043b), |
476 | PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149), | 440 | PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149), |
@@ -494,10 +458,11 @@ static struct pcmcia_driver ide_cs_driver = { | |||
494 | .drv = { | 458 | .drv = { |
495 | .name = "ide-cs", | 459 | .name = "ide-cs", |
496 | }, | 460 | }, |
497 | .attach = ide_attach, | 461 | .probe = ide_attach, |
498 | .event = ide_event, | 462 | .remove = ide_detach, |
499 | .detach = ide_detach, | ||
500 | .id_table = ide_ids, | 463 | .id_table = ide_ids, |
464 | .suspend = ide_suspend, | ||
465 | .resume = ide_resume, | ||
501 | }; | 466 | }; |
502 | 467 | ||
503 | static int __init init_ide_cs(void) | 468 | static int __init init_ide_cs(void) |
@@ -508,7 +473,6 @@ static int __init init_ide_cs(void) | |||
508 | static void __exit exit_ide_cs(void) | 473 | static void __exit exit_ide_cs(void) |
509 | { | 474 | { |
510 | pcmcia_unregister_driver(&ide_cs_driver); | 475 | pcmcia_unregister_driver(&ide_cs_driver); |
511 | BUG_ON(dev_list != NULL); | ||
512 | } | 476 | } |
513 | 477 | ||
514 | late_initcall(init_ide_cs); | 478 | late_initcall(init_ide_cs); |
diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c index 27391c32f3eb..2a2b03ff096b 100644 --- a/drivers/isdn/hardware/avm/avm_cs.c +++ b/drivers/isdn/hardware/avm/avm_cs.c | |||
@@ -53,8 +53,6 @@ MODULE_LICENSE("GPL"); | |||
53 | 53 | ||
54 | static void avmcs_config(dev_link_t *link); | 54 | static void avmcs_config(dev_link_t *link); |
55 | static void avmcs_release(dev_link_t *link); | 55 | static void avmcs_release(dev_link_t *link); |
56 | static int avmcs_event(event_t event, int priority, | ||
57 | event_callback_args_t *args); | ||
58 | 56 | ||
59 | /* | 57 | /* |
60 | The attach() and detach() entry points are used to create and destroy | 58 | The attach() and detach() entry points are used to create and destroy |
@@ -62,16 +60,7 @@ static int avmcs_event(event_t event, int priority, | |||
62 | needed to manage one actual PCMCIA card. | 60 | needed to manage one actual PCMCIA card. |
63 | */ | 61 | */ |
64 | 62 | ||
65 | static dev_link_t *avmcs_attach(void); | 63 | static void avmcs_detach(struct pcmcia_device *p_dev); |
66 | static void avmcs_detach(dev_link_t *); | ||
67 | |||
68 | /* | ||
69 | The dev_info variable is the "key" that is used to match up this | ||
70 | device driver with appropriate cards, through the card configuration | ||
71 | database. | ||
72 | */ | ||
73 | |||
74 | static dev_info_t dev_info = "avm_cs"; | ||
75 | 64 | ||
76 | /* | 65 | /* |
77 | A linked list of "instances" of the skeleton device. Each actual | 66 | A linked list of "instances" of the skeleton device. Each actual |
@@ -83,15 +72,7 @@ static dev_info_t dev_info = "avm_cs"; | |||
83 | device numbers are used to derive the corresponding array index. | 72 | device numbers are used to derive the corresponding array index. |
84 | */ | 73 | */ |
85 | 74 | ||
86 | static dev_link_t *dev_list = NULL; | ||
87 | |||
88 | /* | 75 | /* |
89 | A dev_link_t structure has fields for most things that are needed | ||
90 | to keep track of a socket, but there will usually be some device | ||
91 | specific information that also needs to be kept track of. The | ||
92 | 'priv' pointer in a dev_link_t structure can be used to point to | ||
93 | a device-specific private data structure, like this. | ||
94 | |||
95 | A driver needs to provide a dev_node_t structure for each device | 76 | A driver needs to provide a dev_node_t structure for each device |
96 | on a card. In some cases, there is only one device per card (for | 77 | on a card. In some cases, there is only one device per card (for |
97 | example, ethernet cards, modems). In other cases, there may be | 78 | example, ethernet cards, modems). In other cases, there may be |
@@ -118,13 +99,11 @@ typedef struct local_info_t { | |||
118 | 99 | ||
119 | ======================================================================*/ | 100 | ======================================================================*/ |
120 | 101 | ||
121 | static dev_link_t *avmcs_attach(void) | 102 | static int avmcs_attach(struct pcmcia_device *p_dev) |
122 | { | 103 | { |
123 | client_reg_t client_reg; | ||
124 | dev_link_t *link; | 104 | dev_link_t *link; |
125 | local_info_t *local; | 105 | local_info_t *local; |
126 | int ret; | 106 | |
127 | |||
128 | /* Initialize the dev_link_t structure */ | 107 | /* Initialize the dev_link_t structure */ |
129 | link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); | 108 | link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); |
130 | if (!link) | 109 | if (!link) |
@@ -155,25 +134,19 @@ static dev_link_t *avmcs_attach(void) | |||
155 | goto err_kfree; | 134 | goto err_kfree; |
156 | memset(local, 0, sizeof(local_info_t)); | 135 | memset(local, 0, sizeof(local_info_t)); |
157 | link->priv = local; | 136 | link->priv = local; |
158 | 137 | ||
159 | /* Register with Card Services */ | 138 | link->handle = p_dev; |
160 | link->next = dev_list; | 139 | p_dev->instance = link; |
161 | dev_list = link; | 140 | |
162 | client_reg.dev_info = &dev_info; | 141 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
163 | client_reg.Version = 0x0210; | 142 | avmcs_config(link); |
164 | client_reg.event_callback_args.client_data = link; | 143 | |
165 | ret = pcmcia_register_client(&link->handle, &client_reg); | 144 | return 0; |
166 | if (ret != 0) { | ||
167 | cs_error(link->handle, RegisterClient, ret); | ||
168 | avmcs_detach(link); | ||
169 | goto err; | ||
170 | } | ||
171 | return link; | ||
172 | 145 | ||
173 | err_kfree: | 146 | err_kfree: |
174 | kfree(link); | 147 | kfree(link); |
175 | err: | 148 | err: |
176 | return NULL; | 149 | return -EINVAL; |
177 | } /* avmcs_attach */ | 150 | } /* avmcs_attach */ |
178 | 151 | ||
179 | /*====================================================================== | 152 | /*====================================================================== |
@@ -185,33 +158,13 @@ static dev_link_t *avmcs_attach(void) | |||
185 | 158 | ||
186 | ======================================================================*/ | 159 | ======================================================================*/ |
187 | 160 | ||
188 | static void avmcs_detach(dev_link_t *link) | 161 | static void avmcs_detach(struct pcmcia_device *p_dev) |
189 | { | 162 | { |
190 | dev_link_t **linkp; | 163 | dev_link_t *link = dev_to_instance(p_dev); |
191 | |||
192 | /* Locate device structure */ | ||
193 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
194 | if (*linkp == link) break; | ||
195 | if (*linkp == NULL) | ||
196 | return; | ||
197 | 164 | ||
198 | /* | 165 | if (link->state & DEV_CONFIG) |
199 | If the device is currently configured and active, we won't | 166 | avmcs_release(link); |
200 | actually delete it yet. Instead, it is marked so that when | ||
201 | the release() function is called, that will trigger a proper | ||
202 | detach(). | ||
203 | */ | ||
204 | if (link->state & DEV_CONFIG) { | ||
205 | link->state |= DEV_STALE_LINK; | ||
206 | return; | ||
207 | } | ||
208 | 167 | ||
209 | /* Break the link with Card Services */ | ||
210 | if (link->handle) | ||
211 | pcmcia_deregister_client(link->handle); | ||
212 | |||
213 | /* Unlink device structure, free pieces */ | ||
214 | *linkp = link->next; | ||
215 | kfree(link->priv); | 168 | kfree(link->priv); |
216 | kfree(link); | 169 | kfree(link); |
217 | } /* avmcs_detach */ | 170 | } /* avmcs_detach */ |
@@ -424,12 +377,30 @@ static void avmcs_release(dev_link_t *link) | |||
424 | pcmcia_release_io(link->handle, &link->io); | 377 | pcmcia_release_io(link->handle, &link->io); |
425 | pcmcia_release_irq(link->handle, &link->irq); | 378 | pcmcia_release_irq(link->handle, &link->irq); |
426 | link->state &= ~DEV_CONFIG; | 379 | link->state &= ~DEV_CONFIG; |
427 | |||
428 | if (link->state & DEV_STALE_LINK) | ||
429 | avmcs_detach(link); | ||
430 | |||
431 | } /* avmcs_release */ | 380 | } /* avmcs_release */ |
432 | 381 | ||
382 | static int avmcs_suspend(struct pcmcia_device *dev) | ||
383 | { | ||
384 | dev_link_t *link = dev_to_instance(dev); | ||
385 | |||
386 | link->state |= DEV_SUSPEND; | ||
387 | if (link->state & DEV_CONFIG) | ||
388 | pcmcia_release_configuration(link->handle); | ||
389 | |||
390 | return 0; | ||
391 | } | ||
392 | |||
393 | static int avmcs_resume(struct pcmcia_device *dev) | ||
394 | { | ||
395 | dev_link_t *link = dev_to_instance(dev); | ||
396 | |||
397 | link->state &= ~DEV_SUSPEND; | ||
398 | if (link->state & DEV_CONFIG) | ||
399 | pcmcia_request_configuration(link->handle, &link->conf); | ||
400 | |||
401 | return 0; | ||
402 | } | ||
403 | |||
433 | /*====================================================================== | 404 | /*====================================================================== |
434 | 405 | ||
435 | The card status event handler. Mostly, this schedules other | 406 | The card status event handler. Mostly, this schedules other |
@@ -444,38 +415,6 @@ static void avmcs_release(dev_link_t *link) | |||
444 | 415 | ||
445 | ======================================================================*/ | 416 | ======================================================================*/ |
446 | 417 | ||
447 | static int avmcs_event(event_t event, int priority, | ||
448 | event_callback_args_t *args) | ||
449 | { | ||
450 | dev_link_t *link = args->client_data; | ||
451 | |||
452 | switch (event) { | ||
453 | case CS_EVENT_CARD_REMOVAL: | ||
454 | link->state &= ~DEV_PRESENT; | ||
455 | if (link->state & DEV_CONFIG) | ||
456 | avmcs_release(link); | ||
457 | break; | ||
458 | case CS_EVENT_CARD_INSERTION: | ||
459 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
460 | avmcs_config(link); | ||
461 | break; | ||
462 | case CS_EVENT_PM_SUSPEND: | ||
463 | link->state |= DEV_SUSPEND; | ||
464 | /* Fall through... */ | ||
465 | case CS_EVENT_RESET_PHYSICAL: | ||
466 | if (link->state & DEV_CONFIG) | ||
467 | pcmcia_release_configuration(link->handle); | ||
468 | break; | ||
469 | case CS_EVENT_PM_RESUME: | ||
470 | link->state &= ~DEV_SUSPEND; | ||
471 | /* Fall through... */ | ||
472 | case CS_EVENT_CARD_RESET: | ||
473 | if (link->state & DEV_CONFIG) | ||
474 | pcmcia_request_configuration(link->handle, &link->conf); | ||
475 | break; | ||
476 | } | ||
477 | return 0; | ||
478 | } /* avmcs_event */ | ||
479 | 418 | ||
480 | static struct pcmcia_device_id avmcs_ids[] = { | 419 | static struct pcmcia_device_id avmcs_ids[] = { |
481 | PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN-Controller B1", 0x95d42008, 0x845dc335), | 420 | PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN-Controller B1", 0x95d42008, 0x845dc335), |
@@ -490,10 +429,11 @@ static struct pcmcia_driver avmcs_driver = { | |||
490 | .drv = { | 429 | .drv = { |
491 | .name = "avm_cs", | 430 | .name = "avm_cs", |
492 | }, | 431 | }, |
493 | .attach = avmcs_attach, | 432 | .probe = avmcs_attach, |
494 | .event = avmcs_event, | 433 | .remove = avmcs_detach, |
495 | .detach = avmcs_detach, | ||
496 | .id_table = avmcs_ids, | 434 | .id_table = avmcs_ids, |
435 | .suspend= avmcs_suspend, | ||
436 | .resume = avmcs_resume, | ||
497 | }; | 437 | }; |
498 | 438 | ||
499 | static int __init avmcs_init(void) | 439 | static int __init avmcs_init(void) |
@@ -504,7 +444,6 @@ static int __init avmcs_init(void) | |||
504 | static void __exit avmcs_exit(void) | 444 | static void __exit avmcs_exit(void) |
505 | { | 445 | { |
506 | pcmcia_unregister_driver(&avmcs_driver); | 446 | pcmcia_unregister_driver(&avmcs_driver); |
507 | BUG_ON(dev_list != NULL); | ||
508 | } | 447 | } |
509 | 448 | ||
510 | module_init(avmcs_init); | 449 | module_init(avmcs_init); |
diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c index 5f5a5ae740d2..969da40c4248 100644 --- a/drivers/isdn/hisax/avma1_cs.c +++ b/drivers/isdn/hisax/avma1_cs.c | |||
@@ -69,8 +69,6 @@ module_param(isdnprot, int, 0); | |||
69 | 69 | ||
70 | static void avma1cs_config(dev_link_t *link); | 70 | static void avma1cs_config(dev_link_t *link); |
71 | static void avma1cs_release(dev_link_t *link); | 71 | static void avma1cs_release(dev_link_t *link); |
72 | static int avma1cs_event(event_t event, int priority, | ||
73 | event_callback_args_t *args); | ||
74 | 72 | ||
75 | /* | 73 | /* |
76 | The attach() and detach() entry points are used to create and destroy | 74 | The attach() and detach() entry points are used to create and destroy |
@@ -78,16 +76,8 @@ static int avma1cs_event(event_t event, int priority, | |||
78 | needed to manage one actual PCMCIA card. | 76 | needed to manage one actual PCMCIA card. |
79 | */ | 77 | */ |
80 | 78 | ||
81 | static dev_link_t *avma1cs_attach(void); | 79 | static void avma1cs_detach(struct pcmcia_device *p_dev); |
82 | static void avma1cs_detach(dev_link_t *); | ||
83 | 80 | ||
84 | /* | ||
85 | The dev_info variable is the "key" that is used to match up this | ||
86 | device driver with appropriate cards, through the card configuration | ||
87 | database. | ||
88 | */ | ||
89 | |||
90 | static dev_info_t dev_info = "avma1_cs"; | ||
91 | 81 | ||
92 | /* | 82 | /* |
93 | A linked list of "instances" of the skeleton device. Each actual | 83 | A linked list of "instances" of the skeleton device. Each actual |
@@ -99,15 +89,7 @@ static dev_info_t dev_info = "avma1_cs"; | |||
99 | device numbers are used to derive the corresponding array index. | 89 | device numbers are used to derive the corresponding array index. |
100 | */ | 90 | */ |
101 | 91 | ||
102 | static dev_link_t *dev_list = NULL; | ||
103 | |||
104 | /* | 92 | /* |
105 | A dev_link_t structure has fields for most things that are needed | ||
106 | to keep track of a socket, but there will usually be some device | ||
107 | specific information that also needs to be kept track of. The | ||
108 | 'priv' pointer in a dev_link_t structure can be used to point to | ||
109 | a device-specific private data structure, like this. | ||
110 | |||
111 | A driver needs to provide a dev_node_t structure for each device | 93 | A driver needs to provide a dev_node_t structure for each device |
112 | on a card. In some cases, there is only one device per card (for | 94 | on a card. In some cases, there is only one device per card (for |
113 | example, ethernet cards, modems). In other cases, there may be | 95 | example, ethernet cards, modems). In other cases, there may be |
@@ -134,26 +116,24 @@ typedef struct local_info_t { | |||
134 | 116 | ||
135 | ======================================================================*/ | 117 | ======================================================================*/ |
136 | 118 | ||
137 | static dev_link_t *avma1cs_attach(void) | 119 | static int avma1cs_attach(struct pcmcia_device *p_dev) |
138 | { | 120 | { |
139 | client_reg_t client_reg; | ||
140 | dev_link_t *link; | 121 | dev_link_t *link; |
141 | local_info_t *local; | 122 | local_info_t *local; |
142 | int ret; | 123 | |
143 | |||
144 | DEBUG(0, "avma1cs_attach()\n"); | 124 | DEBUG(0, "avma1cs_attach()\n"); |
145 | 125 | ||
146 | /* Initialize the dev_link_t structure */ | 126 | /* Initialize the dev_link_t structure */ |
147 | link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); | 127 | link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); |
148 | if (!link) | 128 | if (!link) |
149 | return NULL; | 129 | return -ENOMEM; |
150 | memset(link, 0, sizeof(struct dev_link_t)); | 130 | memset(link, 0, sizeof(struct dev_link_t)); |
151 | 131 | ||
152 | /* Allocate space for private device-specific data */ | 132 | /* Allocate space for private device-specific data */ |
153 | local = kmalloc(sizeof(local_info_t), GFP_KERNEL); | 133 | local = kmalloc(sizeof(local_info_t), GFP_KERNEL); |
154 | if (!local) { | 134 | if (!local) { |
155 | kfree(link); | 135 | kfree(link); |
156 | return NULL; | 136 | return -ENOMEM; |
157 | } | 137 | } |
158 | memset(local, 0, sizeof(local_info_t)); | 138 | memset(local, 0, sizeof(local_info_t)); |
159 | link->priv = local; | 139 | link->priv = local; |
@@ -178,20 +158,13 @@ static dev_link_t *avma1cs_attach(void) | |||
178 | link->conf.ConfigIndex = 1; | 158 | link->conf.ConfigIndex = 1; |
179 | link->conf.Present = PRESENT_OPTION; | 159 | link->conf.Present = PRESENT_OPTION; |
180 | 160 | ||
181 | /* Register with Card Services */ | 161 | link->handle = p_dev; |
182 | link->next = dev_list; | 162 | p_dev->instance = link; |
183 | dev_list = link; | ||
184 | client_reg.dev_info = &dev_info; | ||
185 | client_reg.Version = 0x0210; | ||
186 | client_reg.event_callback_args.client_data = link; | ||
187 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
188 | if (ret != 0) { | ||
189 | cs_error(link->handle, RegisterClient, ret); | ||
190 | avma1cs_detach(link); | ||
191 | return NULL; | ||
192 | } | ||
193 | 163 | ||
194 | return link; | 164 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
165 | avma1cs_config(link); | ||
166 | |||
167 | return 0; | ||
195 | } /* avma1cs_attach */ | 168 | } /* avma1cs_attach */ |
196 | 169 | ||
197 | /*====================================================================== | 170 | /*====================================================================== |
@@ -203,42 +176,17 @@ static dev_link_t *avma1cs_attach(void) | |||
203 | 176 | ||
204 | ======================================================================*/ | 177 | ======================================================================*/ |
205 | 178 | ||
206 | static void avma1cs_detach(dev_link_t *link) | 179 | static void avma1cs_detach(struct pcmcia_device *p_dev) |
207 | { | 180 | { |
208 | dev_link_t **linkp; | 181 | dev_link_t *link = dev_to_instance(p_dev); |
209 | 182 | ||
210 | DEBUG(0, "avma1cs_detach(0x%p)\n", link); | 183 | DEBUG(0, "avma1cs_detach(0x%p)\n", link); |
211 | |||
212 | /* Locate device structure */ | ||
213 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
214 | if (*linkp == link) break; | ||
215 | if (*linkp == NULL) | ||
216 | return; | ||
217 | 184 | ||
218 | /* | 185 | if (link->state & DEV_CONFIG) |
219 | If the device is currently configured and active, we won't | 186 | avma1cs_release(link); |
220 | actually delete it yet. Instead, it is marked so that when | ||
221 | the release() function is called, that will trigger a proper | ||
222 | detach(). | ||
223 | */ | ||
224 | if (link->state & DEV_CONFIG) { | ||
225 | #ifdef PCMCIA_DEBUG | ||
226 | printk(KERN_DEBUG "avma1_cs: detach postponed, '%s' " | ||
227 | "still locked\n", link->dev->dev_name); | ||
228 | #endif | ||
229 | link->state |= DEV_STALE_LINK; | ||
230 | return; | ||
231 | } | ||
232 | 187 | ||
233 | /* Break the link with Card Services */ | ||
234 | if (link->handle) | ||
235 | pcmcia_deregister_client(link->handle); | ||
236 | |||
237 | /* Unlink device structure, free pieces */ | ||
238 | *linkp = link->next; | ||
239 | kfree(link->priv); | 188 | kfree(link->priv); |
240 | kfree(link); | 189 | kfree(link); |
241 | |||
242 | } /* avma1cs_detach */ | 190 | } /* avma1cs_detach */ |
243 | 191 | ||
244 | /*====================================================================== | 192 | /*====================================================================== |
@@ -440,58 +388,30 @@ static void avma1cs_release(dev_link_t *link) | |||
440 | pcmcia_release_io(link->handle, &link->io); | 388 | pcmcia_release_io(link->handle, &link->io); |
441 | pcmcia_release_irq(link->handle, &link->irq); | 389 | pcmcia_release_irq(link->handle, &link->irq); |
442 | link->state &= ~DEV_CONFIG; | 390 | link->state &= ~DEV_CONFIG; |
443 | |||
444 | if (link->state & DEV_STALE_LINK) | ||
445 | avma1cs_detach(link); | ||
446 | } /* avma1cs_release */ | 391 | } /* avma1cs_release */ |
447 | 392 | ||
448 | /*====================================================================== | 393 | static int avma1cs_suspend(struct pcmcia_device *dev) |
394 | { | ||
395 | dev_link_t *link = dev_to_instance(dev); | ||
449 | 396 | ||
450 | The card status event handler. Mostly, this schedules other | 397 | link->state |= DEV_SUSPEND; |
451 | stuff to run after an event is received. A CARD_REMOVAL event | 398 | if (link->state & DEV_CONFIG) |
452 | also sets some flags to discourage the net drivers from trying | 399 | pcmcia_release_configuration(link->handle); |
453 | to talk to the card any more. | ||
454 | 400 | ||
455 | When a CARD_REMOVAL event is received, we immediately set a flag | 401 | return 0; |
456 | to block future accesses to this device. All the functions that | 402 | } |
457 | actually access the device should check this flag to make sure | ||
458 | the card is still present. | ||
459 | |||
460 | ======================================================================*/ | ||
461 | 403 | ||
462 | static int avma1cs_event(event_t event, int priority, | 404 | static int avma1cs_resume(struct pcmcia_device *dev) |
463 | event_callback_args_t *args) | ||
464 | { | 405 | { |
465 | dev_link_t *link = args->client_data; | 406 | dev_link_t *link = dev_to_instance(dev); |
466 | 407 | ||
467 | DEBUG(1, "avma1cs_event(0x%06x)\n", event); | 408 | link->state &= ~DEV_SUSPEND; |
468 | 409 | if (link->state & DEV_CONFIG) | |
469 | switch (event) { | ||
470 | case CS_EVENT_CARD_REMOVAL: | ||
471 | if (link->state & DEV_CONFIG) | ||
472 | avma1cs_release(link); | ||
473 | break; | ||
474 | case CS_EVENT_CARD_INSERTION: | ||
475 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
476 | avma1cs_config(link); | ||
477 | break; | ||
478 | case CS_EVENT_PM_SUSPEND: | ||
479 | link->state |= DEV_SUSPEND; | ||
480 | /* Fall through... */ | ||
481 | case CS_EVENT_RESET_PHYSICAL: | ||
482 | if (link->state & DEV_CONFIG) | ||
483 | pcmcia_release_configuration(link->handle); | ||
484 | break; | ||
485 | case CS_EVENT_PM_RESUME: | ||
486 | link->state &= ~DEV_SUSPEND; | ||
487 | /* Fall through... */ | ||
488 | case CS_EVENT_CARD_RESET: | ||
489 | if (link->state & DEV_CONFIG) | ||
490 | pcmcia_request_configuration(link->handle, &link->conf); | 410 | pcmcia_request_configuration(link->handle, &link->conf); |
491 | break; | 411 | |
492 | } | 412 | return 0; |
493 | return 0; | 413 | } |
494 | } /* avma1cs_event */ | 414 | |
495 | 415 | ||
496 | static struct pcmcia_device_id avma1cs_ids[] = { | 416 | static struct pcmcia_device_id avma1cs_ids[] = { |
497 | PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb), | 417 | PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb), |
@@ -505,10 +425,11 @@ static struct pcmcia_driver avma1cs_driver = { | |||
505 | .drv = { | 425 | .drv = { |
506 | .name = "avma1_cs", | 426 | .name = "avma1_cs", |
507 | }, | 427 | }, |
508 | .attach = avma1cs_attach, | 428 | .probe = avma1cs_attach, |
509 | .event = avma1cs_event, | 429 | .remove = avma1cs_detach, |
510 | .detach = avma1cs_detach, | ||
511 | .id_table = avma1cs_ids, | 430 | .id_table = avma1cs_ids, |
431 | .suspend = avma1cs_suspend, | ||
432 | .resume = avma1cs_resume, | ||
512 | }; | 433 | }; |
513 | 434 | ||
514 | /*====================================================================*/ | 435 | /*====================================================================*/ |
@@ -521,7 +442,6 @@ static int __init init_avma1_cs(void) | |||
521 | static void __exit exit_avma1_cs(void) | 442 | static void __exit exit_avma1_cs(void) |
522 | { | 443 | { |
523 | pcmcia_unregister_driver(&avma1cs_driver); | 444 | pcmcia_unregister_driver(&avma1cs_driver); |
524 | BUG_ON(dev_list != NULL); | ||
525 | } | 445 | } |
526 | 446 | ||
527 | module_init(init_avma1_cs); | 447 | module_init(init_avma1_cs); |
diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c index 6fc6868de0b0..062fb8f0739f 100644 --- a/drivers/isdn/hisax/elsa_cs.c +++ b/drivers/isdn/hisax/elsa_cs.c | |||
@@ -96,8 +96,6 @@ module_param(protocol, int, 0); | |||
96 | 96 | ||
97 | static void elsa_cs_config(dev_link_t *link); | 97 | static void elsa_cs_config(dev_link_t *link); |
98 | static void elsa_cs_release(dev_link_t *link); | 98 | static void elsa_cs_release(dev_link_t *link); |
99 | static int elsa_cs_event(event_t event, int priority, | ||
100 | event_callback_args_t *args); | ||
101 | 99 | ||
102 | /* | 100 | /* |
103 | The attach() and detach() entry points are used to create and destroy | 101 | The attach() and detach() entry points are used to create and destroy |
@@ -105,39 +103,9 @@ static int elsa_cs_event(event_t event, int priority, | |||
105 | needed to manage one actual PCMCIA card. | 103 | needed to manage one actual PCMCIA card. |
106 | */ | 104 | */ |
107 | 105 | ||
108 | static dev_link_t *elsa_cs_attach(void); | 106 | static void elsa_cs_detach(struct pcmcia_device *p_dev); |
109 | static void elsa_cs_detach(dev_link_t *); | ||
110 | 107 | ||
111 | /* | 108 | /* |
112 | The dev_info variable is the "key" that is used to match up this | ||
113 | device driver with appropriate cards, through the card configuration | ||
114 | database. | ||
115 | */ | ||
116 | |||
117 | static dev_info_t dev_info = "elsa_cs"; | ||
118 | |||
119 | /* | ||
120 | A linked list of "instances" of the elsa_cs device. Each actual | ||
121 | PCMCIA card corresponds to one device instance, and is described | ||
122 | by one dev_link_t structure (defined in ds.h). | ||
123 | |||
124 | You may not want to use a linked list for this -- for example, the | ||
125 | memory card driver uses an array of dev_link_t pointers, where minor | ||
126 | device numbers are used to derive the corresponding array index. | ||
127 | */ | ||
128 | |||
129 | static dev_link_t *dev_list = NULL; | ||
130 | |||
131 | /* | ||
132 | A dev_link_t structure has fields for most things that are needed | ||
133 | to keep track of a socket, but there will usually be some device | ||
134 | specific information that also needs to be kept track of. The | ||
135 | 'priv' pointer in a dev_link_t structure can be used to point to | ||
136 | a device-specific private data structure, like this. | ||
137 | |||
138 | To simplify the data structure handling, we actually include the | ||
139 | dev_link_t structure in the device's private data structure. | ||
140 | |||
141 | A driver needs to provide a dev_node_t structure for each device | 109 | A driver needs to provide a dev_node_t structure for each device |
142 | on a card. In some cases, there is only one device per card (for | 110 | on a card. In some cases, there is only one device per card (for |
143 | example, ethernet cards, modems). In other cases, there may be | 111 | example, ethernet cards, modems). In other cases, there may be |
@@ -171,18 +139,16 @@ typedef struct local_info_t { | |||
171 | 139 | ||
172 | ======================================================================*/ | 140 | ======================================================================*/ |
173 | 141 | ||
174 | static dev_link_t *elsa_cs_attach(void) | 142 | static int elsa_cs_attach(struct pcmcia_device *p_dev) |
175 | { | 143 | { |
176 | client_reg_t client_reg; | ||
177 | dev_link_t *link; | 144 | dev_link_t *link; |
178 | local_info_t *local; | 145 | local_info_t *local; |
179 | int ret; | ||
180 | 146 | ||
181 | DEBUG(0, "elsa_cs_attach()\n"); | 147 | DEBUG(0, "elsa_cs_attach()\n"); |
182 | 148 | ||
183 | /* Allocate space for private device-specific data */ | 149 | /* Allocate space for private device-specific data */ |
184 | local = kmalloc(sizeof(local_info_t), GFP_KERNEL); | 150 | local = kmalloc(sizeof(local_info_t), GFP_KERNEL); |
185 | if (!local) return NULL; | 151 | if (!local) return -ENOMEM; |
186 | memset(local, 0, sizeof(local_info_t)); | 152 | memset(local, 0, sizeof(local_info_t)); |
187 | local->cardnr = -1; | 153 | local->cardnr = -1; |
188 | link = &local->link; link->priv = local; | 154 | link = &local->link; link->priv = local; |
@@ -207,20 +173,13 @@ static dev_link_t *elsa_cs_attach(void) | |||
207 | link->conf.Vcc = 50; | 173 | link->conf.Vcc = 50; |
208 | link->conf.IntType = INT_MEMORY_AND_IO; | 174 | link->conf.IntType = INT_MEMORY_AND_IO; |
209 | 175 | ||
210 | /* Register with Card Services */ | 176 | link->handle = p_dev; |
211 | link->next = dev_list; | 177 | p_dev->instance = link; |
212 | dev_list = link; | ||
213 | client_reg.dev_info = &dev_info; | ||
214 | client_reg.Version = 0x0210; | ||
215 | client_reg.event_callback_args.client_data = link; | ||
216 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
217 | if (ret != CS_SUCCESS) { | ||
218 | cs_error(link->handle, RegisterClient, ret); | ||
219 | elsa_cs_detach(link); | ||
220 | return NULL; | ||
221 | } | ||
222 | 178 | ||
223 | return link; | 179 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
180 | elsa_cs_config(link); | ||
181 | |||
182 | return 0; | ||
224 | } /* elsa_cs_attach */ | 183 | } /* elsa_cs_attach */ |
225 | 184 | ||
226 | /*====================================================================== | 185 | /*====================================================================== |
@@ -232,32 +191,18 @@ static dev_link_t *elsa_cs_attach(void) | |||
232 | 191 | ||
233 | ======================================================================*/ | 192 | ======================================================================*/ |
234 | 193 | ||
235 | static void elsa_cs_detach(dev_link_t *link) | 194 | static void elsa_cs_detach(struct pcmcia_device *p_dev) |
236 | { | 195 | { |
237 | dev_link_t **linkp; | 196 | dev_link_t *link = dev_to_instance(p_dev); |
238 | local_info_t *info = link->priv; | 197 | local_info_t *info = link->priv; |
239 | int ret; | ||
240 | 198 | ||
241 | DEBUG(0, "elsa_cs_detach(0x%p)\n", link); | 199 | DEBUG(0, "elsa_cs_detach(0x%p)\n", link); |
242 | 200 | ||
243 | /* Locate device structure */ | 201 | if (link->state & DEV_CONFIG) { |
244 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | 202 | info->busy = 1; |
245 | if (*linkp == link) break; | 203 | elsa_cs_release(link); |
246 | if (*linkp == NULL) | ||
247 | return; | ||
248 | |||
249 | if (link->state & DEV_CONFIG) | ||
250 | elsa_cs_release(link); | ||
251 | |||
252 | /* Break the link with Card Services */ | ||
253 | if (link->handle) { | ||
254 | ret = pcmcia_deregister_client(link->handle); | ||
255 | if (ret != CS_SUCCESS) | ||
256 | cs_error(link->handle, DeregisterClient, ret); | ||
257 | } | 204 | } |
258 | 205 | ||
259 | /* Unlink device structure and free it */ | ||
260 | *linkp = link->next; | ||
261 | kfree(info); | 206 | kfree(info); |
262 | 207 | ||
263 | } /* elsa_cs_detach */ | 208 | } /* elsa_cs_detach */ |
@@ -447,60 +392,31 @@ static void elsa_cs_release(dev_link_t *link) | |||
447 | link->state &= ~DEV_CONFIG; | 392 | link->state &= ~DEV_CONFIG; |
448 | } /* elsa_cs_release */ | 393 | } /* elsa_cs_release */ |
449 | 394 | ||
450 | /*====================================================================== | 395 | static int elsa_suspend(struct pcmcia_device *p_dev) |
451 | 396 | { | |
452 | The card status event handler. Mostly, this schedules other | 397 | dev_link_t *link = dev_to_instance(p_dev); |
453 | stuff to run after an event is received. A CARD_REMOVAL event | 398 | local_info_t *dev = link->priv; |
454 | also sets some flags to discourage the net drivers from trying | ||
455 | to talk to the card any more. | ||
456 | 399 | ||
457 | When a CARD_REMOVAL event is received, we immediately set a flag | 400 | link->state |= DEV_SUSPEND; |
458 | to block future accesses to this device. All the functions that | 401 | dev->busy = 1; |
459 | actually access the device should check this flag to make sure | 402 | if (link->state & DEV_CONFIG) |
460 | the card is still present. | 403 | pcmcia_release_configuration(link->handle); |
461 | 404 | ||
462 | ======================================================================*/ | 405 | return 0; |
406 | } | ||
463 | 407 | ||
464 | static int elsa_cs_event(event_t event, int priority, | 408 | static int elsa_resume(struct pcmcia_device *p_dev) |
465 | event_callback_args_t *args) | ||
466 | { | 409 | { |
467 | dev_link_t *link = args->client_data; | 410 | dev_link_t *link = dev_to_instance(p_dev); |
468 | local_info_t *dev = link->priv; | 411 | local_info_t *dev = link->priv; |
469 | |||
470 | DEBUG(1, "elsa_cs_event(%d)\n", event); | ||
471 | 412 | ||
472 | switch (event) { | 413 | link->state &= ~DEV_SUSPEND; |
473 | case CS_EVENT_CARD_REMOVAL: | 414 | if (link->state & DEV_CONFIG) |
474 | link->state &= ~DEV_PRESENT; | 415 | pcmcia_request_configuration(link->handle, &link->conf); |
475 | if (link->state & DEV_CONFIG) { | ||
476 | ((local_info_t*)link->priv)->busy = 1; | ||
477 | elsa_cs_release(link); | ||
478 | } | ||
479 | break; | ||
480 | case CS_EVENT_CARD_INSERTION: | ||
481 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
482 | elsa_cs_config(link); | ||
483 | break; | ||
484 | case CS_EVENT_PM_SUSPEND: | ||
485 | link->state |= DEV_SUSPEND; | ||
486 | /* Fall through... */ | ||
487 | case CS_EVENT_RESET_PHYSICAL: | ||
488 | /* Mark the device as stopped, to block IO until later */ | ||
489 | dev->busy = 1; | ||
490 | if (link->state & DEV_CONFIG) | ||
491 | pcmcia_release_configuration(link->handle); | ||
492 | break; | ||
493 | case CS_EVENT_PM_RESUME: | ||
494 | link->state &= ~DEV_SUSPEND; | ||
495 | /* Fall through... */ | ||
496 | case CS_EVENT_CARD_RESET: | ||
497 | if (link->state & DEV_CONFIG) | ||
498 | pcmcia_request_configuration(link->handle, &link->conf); | ||
499 | dev->busy = 0; | 416 | dev->busy = 0; |
500 | break; | 417 | |
501 | } | 418 | return 0; |
502 | return 0; | 419 | } |
503 | } /* elsa_cs_event */ | ||
504 | 420 | ||
505 | static struct pcmcia_device_id elsa_ids[] = { | 421 | static struct pcmcia_device_id elsa_ids[] = { |
506 | PCMCIA_DEVICE_PROD_ID12("ELSA AG (Aachen, Germany)", "MicroLink ISDN/MC ", 0x983de2c4, 0x333ba257), | 422 | PCMCIA_DEVICE_PROD_ID12("ELSA AG (Aachen, Germany)", "MicroLink ISDN/MC ", 0x983de2c4, 0x333ba257), |
@@ -514,10 +430,11 @@ static struct pcmcia_driver elsa_cs_driver = { | |||
514 | .drv = { | 430 | .drv = { |
515 | .name = "elsa_cs", | 431 | .name = "elsa_cs", |
516 | }, | 432 | }, |
517 | .attach = elsa_cs_attach, | 433 | .probe = elsa_cs_attach, |
518 | .event = elsa_cs_event, | 434 | .remove = elsa_cs_detach, |
519 | .detach = elsa_cs_detach, | ||
520 | .id_table = elsa_ids, | 435 | .id_table = elsa_ids, |
436 | .suspend = elsa_suspend, | ||
437 | .resume = elsa_resume, | ||
521 | }; | 438 | }; |
522 | 439 | ||
523 | static int __init init_elsa_cs(void) | 440 | static int __init init_elsa_cs(void) |
@@ -528,7 +445,6 @@ static int __init init_elsa_cs(void) | |||
528 | static void __exit exit_elsa_cs(void) | 445 | static void __exit exit_elsa_cs(void) |
529 | { | 446 | { |
530 | pcmcia_unregister_driver(&elsa_cs_driver); | 447 | pcmcia_unregister_driver(&elsa_cs_driver); |
531 | BUG_ON(dev_list != NULL); | ||
532 | } | 448 | } |
533 | 449 | ||
534 | module_init(init_elsa_cs); | 450 | module_init(init_elsa_cs); |
diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c index dc334aab433e..6f5213a18a8d 100644 --- a/drivers/isdn/hisax/sedlbauer_cs.c +++ b/drivers/isdn/hisax/sedlbauer_cs.c | |||
@@ -97,8 +97,6 @@ module_param(protocol, int, 0); | |||
97 | 97 | ||
98 | static void sedlbauer_config(dev_link_t *link); | 98 | static void sedlbauer_config(dev_link_t *link); |
99 | static void sedlbauer_release(dev_link_t *link); | 99 | static void sedlbauer_release(dev_link_t *link); |
100 | static int sedlbauer_event(event_t event, int priority, | ||
101 | event_callback_args_t *args); | ||
102 | 100 | ||
103 | /* | 101 | /* |
104 | The attach() and detach() entry points are used to create and destroy | 102 | The attach() and detach() entry points are used to create and destroy |
@@ -106,8 +104,7 @@ static int sedlbauer_event(event_t event, int priority, | |||
106 | needed to manage one actual PCMCIA card. | 104 | needed to manage one actual PCMCIA card. |
107 | */ | 105 | */ |
108 | 106 | ||
109 | static dev_link_t *sedlbauer_attach(void); | 107 | static void sedlbauer_detach(struct pcmcia_device *p_dev); |
110 | static void sedlbauer_detach(dev_link_t *); | ||
111 | 108 | ||
112 | /* | 109 | /* |
113 | You'll also need to prototype all the functions that will actually | 110 | You'll also need to prototype all the functions that will actually |
@@ -117,35 +114,6 @@ static void sedlbauer_detach(dev_link_t *); | |||
117 | */ | 114 | */ |
118 | 115 | ||
119 | /* | 116 | /* |
120 | The dev_info variable is the "key" that is used to match up this | ||
121 | device driver with appropriate cards, through the card configuration | ||
122 | database. | ||
123 | */ | ||
124 | |||
125 | static dev_info_t dev_info = "sedlbauer_cs"; | ||
126 | |||
127 | /* | ||
128 | A linked list of "instances" of the sedlbauer device. Each actual | ||
129 | PCMCIA card corresponds to one device instance, and is described | ||
130 | by one dev_link_t structure (defined in ds.h). | ||
131 | |||
132 | You may not want to use a linked list for this -- for example, the | ||
133 | memory card driver uses an array of dev_link_t pointers, where minor | ||
134 | device numbers are used to derive the corresponding array index. | ||
135 | */ | ||
136 | |||
137 | static dev_link_t *dev_list = NULL; | ||
138 | |||
139 | /* | ||
140 | A dev_link_t structure has fields for most things that are needed | ||
141 | to keep track of a socket, but there will usually be some device | ||
142 | specific information that also needs to be kept track of. The | ||
143 | 'priv' pointer in a dev_link_t structure can be used to point to | ||
144 | a device-specific private data structure, like this. | ||
145 | |||
146 | To simplify the data structure handling, we actually include the | ||
147 | dev_link_t structure in the device's private data structure. | ||
148 | |||
149 | A driver needs to provide a dev_node_t structure for each device | 117 | A driver needs to provide a dev_node_t structure for each device |
150 | on a card. In some cases, there is only one device per card (for | 118 | on a card. In some cases, there is only one device per card (for |
151 | example, ethernet cards, modems). In other cases, there may be | 119 | example, ethernet cards, modems). In other cases, there may be |
@@ -180,18 +148,16 @@ typedef struct local_info_t { | |||
180 | 148 | ||
181 | ======================================================================*/ | 149 | ======================================================================*/ |
182 | 150 | ||
183 | static dev_link_t *sedlbauer_attach(void) | 151 | static int sedlbauer_attach(struct pcmcia_device *p_dev) |
184 | { | 152 | { |
185 | local_info_t *local; | 153 | local_info_t *local; |
186 | dev_link_t *link; | 154 | dev_link_t *link; |
187 | client_reg_t client_reg; | ||
188 | int ret; | ||
189 | 155 | ||
190 | DEBUG(0, "sedlbauer_attach()\n"); | 156 | DEBUG(0, "sedlbauer_attach()\n"); |
191 | 157 | ||
192 | /* Allocate space for private device-specific data */ | 158 | /* Allocate space for private device-specific data */ |
193 | local = kmalloc(sizeof(local_info_t), GFP_KERNEL); | 159 | local = kmalloc(sizeof(local_info_t), GFP_KERNEL); |
194 | if (!local) return NULL; | 160 | if (!local) return -ENOMEM; |
195 | memset(local, 0, sizeof(local_info_t)); | 161 | memset(local, 0, sizeof(local_info_t)); |
196 | local->cardnr = -1; | 162 | local->cardnr = -1; |
197 | link = &local->link; link->priv = local; | 163 | link = &local->link; link->priv = local; |
@@ -221,20 +187,13 @@ static dev_link_t *sedlbauer_attach(void) | |||
221 | link->conf.Vcc = 50; | 187 | link->conf.Vcc = 50; |
222 | link->conf.IntType = INT_MEMORY_AND_IO; | 188 | link->conf.IntType = INT_MEMORY_AND_IO; |
223 | 189 | ||
224 | /* Register with Card Services */ | 190 | link->handle = p_dev; |
225 | link->next = dev_list; | 191 | p_dev->instance = link; |
226 | dev_list = link; | 192 | |
227 | client_reg.dev_info = &dev_info; | 193 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
228 | client_reg.Version = 0x0210; | 194 | sedlbauer_config(link); |
229 | client_reg.event_callback_args.client_data = link; | ||
230 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
231 | if (ret != CS_SUCCESS) { | ||
232 | cs_error(link->handle, RegisterClient, ret); | ||
233 | sedlbauer_detach(link); | ||
234 | return NULL; | ||
235 | } | ||
236 | 195 | ||
237 | return link; | 196 | return 0; |
238 | } /* sedlbauer_attach */ | 197 | } /* sedlbauer_attach */ |
239 | 198 | ||
240 | /*====================================================================== | 199 | /*====================================================================== |
@@ -246,39 +205,17 @@ static dev_link_t *sedlbauer_attach(void) | |||
246 | 205 | ||
247 | ======================================================================*/ | 206 | ======================================================================*/ |
248 | 207 | ||
249 | static void sedlbauer_detach(dev_link_t *link) | 208 | static void sedlbauer_detach(struct pcmcia_device *p_dev) |
250 | { | 209 | { |
251 | dev_link_t **linkp; | 210 | dev_link_t *link = dev_to_instance(p_dev); |
252 | 211 | ||
253 | DEBUG(0, "sedlbauer_detach(0x%p)\n", link); | 212 | DEBUG(0, "sedlbauer_detach(0x%p)\n", link); |
254 | |||
255 | /* Locate device structure */ | ||
256 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
257 | if (*linkp == link) break; | ||
258 | if (*linkp == NULL) | ||
259 | return; | ||
260 | 213 | ||
261 | /* | ||
262 | If the device is currently configured and active, we won't | ||
263 | actually delete it yet. Instead, it is marked so that when | ||
264 | the release() function is called, that will trigger a proper | ||
265 | detach(). | ||
266 | */ | ||
267 | if (link->state & DEV_CONFIG) { | 214 | if (link->state & DEV_CONFIG) { |
268 | #ifdef PCMCIA_DEBUG | 215 | ((local_info_t *)link->priv)->stop = 1; |
269 | printk(KERN_DEBUG "sedlbauer_cs: detach postponed, '%s' " | 216 | sedlbauer_release(link); |
270 | "still locked\n", link->dev->dev_name); | ||
271 | #endif | ||
272 | link->state |= DEV_STALE_LINK; | ||
273 | return; | ||
274 | } | 217 | } |
275 | 218 | ||
276 | /* Break the link with Card Services */ | ||
277 | if (link->handle) | ||
278 | pcmcia_deregister_client(link->handle); | ||
279 | |||
280 | /* Unlink device structure, and free it */ | ||
281 | *linkp = link->next; | ||
282 | /* This points to the parent local_info_t struct */ | 219 | /* This points to the parent local_info_t struct */ |
283 | kfree(link->priv); | 220 | kfree(link->priv); |
284 | } /* sedlbauer_detach */ | 221 | } /* sedlbauer_detach */ |
@@ -547,68 +484,34 @@ static void sedlbauer_release(dev_link_t *link) | |||
547 | if (link->irq.AssignedIRQ) | 484 | if (link->irq.AssignedIRQ) |
548 | pcmcia_release_irq(link->handle, &link->irq); | 485 | pcmcia_release_irq(link->handle, &link->irq); |
549 | link->state &= ~DEV_CONFIG; | 486 | link->state &= ~DEV_CONFIG; |
550 | |||
551 | if (link->state & DEV_STALE_LINK) | ||
552 | sedlbauer_detach(link); | ||
553 | |||
554 | } /* sedlbauer_release */ | 487 | } /* sedlbauer_release */ |
555 | 488 | ||
556 | /*====================================================================== | 489 | static int sedlbauer_suspend(struct pcmcia_device *p_dev) |
557 | |||
558 | The card status event handler. Mostly, this schedules other | ||
559 | stuff to run after an event is received. | ||
560 | |||
561 | When a CARD_REMOVAL event is received, we immediately set a | ||
562 | private flag to block future accesses to this device. All the | ||
563 | functions that actually access the device should check this flag | ||
564 | to make sure the card is still present. | ||
565 | |||
566 | ======================================================================*/ | ||
567 | |||
568 | static int sedlbauer_event(event_t event, int priority, | ||
569 | event_callback_args_t *args) | ||
570 | { | 490 | { |
571 | dev_link_t *link = args->client_data; | 491 | dev_link_t *link = dev_to_instance(p_dev); |
572 | local_info_t *dev = link->priv; | 492 | local_info_t *dev = link->priv; |
573 | 493 | ||
574 | DEBUG(1, "sedlbauer_event(0x%06x)\n", event); | ||
575 | |||
576 | switch (event) { | ||
577 | case CS_EVENT_CARD_REMOVAL: | ||
578 | link->state &= ~DEV_PRESENT; | ||
579 | if (link->state & DEV_CONFIG) { | ||
580 | ((local_info_t *)link->priv)->stop = 1; | ||
581 | sedlbauer_release(link); | ||
582 | } | ||
583 | break; | ||
584 | case CS_EVENT_CARD_INSERTION: | ||
585 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
586 | sedlbauer_config(link); | ||
587 | break; | ||
588 | case CS_EVENT_PM_SUSPEND: | ||
589 | link->state |= DEV_SUSPEND; | 494 | link->state |= DEV_SUSPEND; |
590 | /* Fall through... */ | ||
591 | case CS_EVENT_RESET_PHYSICAL: | ||
592 | /* Mark the device as stopped, to block IO until later */ | ||
593 | dev->stop = 1; | 495 | dev->stop = 1; |
594 | if (link->state & DEV_CONFIG) | 496 | if (link->state & DEV_CONFIG) |
595 | pcmcia_release_configuration(link->handle); | 497 | pcmcia_release_configuration(link->handle); |
596 | break; | 498 | |
597 | case CS_EVENT_PM_RESUME: | 499 | return 0; |
500 | } | ||
501 | |||
502 | static int sedlbauer_resume(struct pcmcia_device *p_dev) | ||
503 | { | ||
504 | dev_link_t *link = dev_to_instance(p_dev); | ||
505 | local_info_t *dev = link->priv; | ||
506 | |||
598 | link->state &= ~DEV_SUSPEND; | 507 | link->state &= ~DEV_SUSPEND; |
599 | /* Fall through... */ | ||
600 | case CS_EVENT_CARD_RESET: | ||
601 | if (link->state & DEV_CONFIG) | 508 | if (link->state & DEV_CONFIG) |
602 | pcmcia_request_configuration(link->handle, &link->conf); | 509 | pcmcia_request_configuration(link->handle, &link->conf); |
603 | dev->stop = 0; | 510 | dev->stop = 0; |
604 | /* | 511 | |
605 | In a normal driver, additional code may go here to restore | 512 | return 0; |
606 | the device state and restart IO. | 513 | } |
607 | */ | 514 | |
608 | break; | ||
609 | } | ||
610 | return 0; | ||
611 | } /* sedlbauer_event */ | ||
612 | 515 | ||
613 | static struct pcmcia_device_id sedlbauer_ids[] = { | 516 | static struct pcmcia_device_id sedlbauer_ids[] = { |
614 | PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "speed star II", "V 3.1", 0x81fb79f5, 0xf3612e1d, 0x6b95c78a), | 517 | PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "speed star II", "V 3.1", 0x81fb79f5, 0xf3612e1d, 0x6b95c78a), |
@@ -627,10 +530,11 @@ static struct pcmcia_driver sedlbauer_driver = { | |||
627 | .drv = { | 530 | .drv = { |
628 | .name = "sedlbauer_cs", | 531 | .name = "sedlbauer_cs", |
629 | }, | 532 | }, |
630 | .attach = sedlbauer_attach, | 533 | .probe = sedlbauer_attach, |
631 | .event = sedlbauer_event, | 534 | .remove = sedlbauer_detach, |
632 | .detach = sedlbauer_detach, | ||
633 | .id_table = sedlbauer_ids, | 535 | .id_table = sedlbauer_ids, |
536 | .suspend = sedlbauer_suspend, | ||
537 | .resume = sedlbauer_resume, | ||
634 | }; | 538 | }; |
635 | 539 | ||
636 | static int __init init_sedlbauer_cs(void) | 540 | static int __init init_sedlbauer_cs(void) |
@@ -641,7 +545,6 @@ static int __init init_sedlbauer_cs(void) | |||
641 | static void __exit exit_sedlbauer_cs(void) | 545 | static void __exit exit_sedlbauer_cs(void) |
642 | { | 546 | { |
643 | pcmcia_unregister_driver(&sedlbauer_driver); | 547 | pcmcia_unregister_driver(&sedlbauer_driver); |
644 | BUG_ON(dev_list != NULL); | ||
645 | } | 548 | } |
646 | 549 | ||
647 | module_init(init_sedlbauer_cs); | 550 | module_init(init_sedlbauer_cs); |
diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c index 0ddef1bf778b..4e5c14c7240e 100644 --- a/drivers/isdn/hisax/teles_cs.c +++ b/drivers/isdn/hisax/teles_cs.c | |||
@@ -77,8 +77,6 @@ module_param(protocol, int, 0); | |||
77 | 77 | ||
78 | static void teles_cs_config(dev_link_t *link); | 78 | static void teles_cs_config(dev_link_t *link); |
79 | static void teles_cs_release(dev_link_t *link); | 79 | static void teles_cs_release(dev_link_t *link); |
80 | static int teles_cs_event(event_t event, int priority, | ||
81 | event_callback_args_t *args); | ||
82 | 80 | ||
83 | /* | 81 | /* |
84 | The attach() and detach() entry points are used to create and destroy | 82 | The attach() and detach() entry points are used to create and destroy |
@@ -86,16 +84,7 @@ static int teles_cs_event(event_t event, int priority, | |||
86 | needed to manage one actual PCMCIA card. | 84 | needed to manage one actual PCMCIA card. |
87 | */ | 85 | */ |
88 | 86 | ||
89 | static dev_link_t *teles_attach(void); | 87 | static void teles_detach(struct pcmcia_device *p_dev); |
90 | static void teles_detach(dev_link_t *); | ||
91 | |||
92 | /* | ||
93 | The dev_info variable is the "key" that is used to match up this | ||
94 | device driver with appropriate cards, through the card configuration | ||
95 | database. | ||
96 | */ | ||
97 | |||
98 | static dev_info_t dev_info = "teles_cs"; | ||
99 | 88 | ||
100 | /* | 89 | /* |
101 | A linked list of "instances" of the teles_cs device. Each actual | 90 | A linked list of "instances" of the teles_cs device. Each actual |
@@ -107,18 +96,7 @@ static dev_info_t dev_info = "teles_cs"; | |||
107 | device numbers are used to derive the corresponding array index. | 96 | device numbers are used to derive the corresponding array index. |
108 | */ | 97 | */ |
109 | 98 | ||
110 | static dev_link_t *dev_list = NULL; | ||
111 | |||
112 | /* | 99 | /* |
113 | A dev_link_t structure has fields for most things that are needed | ||
114 | to keep track of a socket, but there will usually be some device | ||
115 | specific information that also needs to be kept track of. The | ||
116 | 'priv' pointer in a dev_link_t structure can be used to point to | ||
117 | a device-specific private data structure, like this. | ||
118 | |||
119 | To simplify the data structure handling, we actually include the | ||
120 | dev_link_t structure in the device's private data structure. | ||
121 | |||
122 | A driver needs to provide a dev_node_t structure for each device | 100 | A driver needs to provide a dev_node_t structure for each device |
123 | on a card. In some cases, there is only one device per card (for | 101 | on a card. In some cases, there is only one device per card (for |
124 | example, ethernet cards, modems). In other cases, there may be | 102 | example, ethernet cards, modems). In other cases, there may be |
@@ -152,18 +130,16 @@ typedef struct local_info_t { | |||
152 | 130 | ||
153 | ======================================================================*/ | 131 | ======================================================================*/ |
154 | 132 | ||
155 | static dev_link_t *teles_attach(void) | 133 | static int teles_attach(struct pcmcia_device *p_dev) |
156 | { | 134 | { |
157 | client_reg_t client_reg; | ||
158 | dev_link_t *link; | 135 | dev_link_t *link; |
159 | local_info_t *local; | 136 | local_info_t *local; |
160 | int ret; | ||
161 | 137 | ||
162 | DEBUG(0, "teles_attach()\n"); | 138 | DEBUG(0, "teles_attach()\n"); |
163 | 139 | ||
164 | /* Allocate space for private device-specific data */ | 140 | /* Allocate space for private device-specific data */ |
165 | local = kmalloc(sizeof(local_info_t), GFP_KERNEL); | 141 | local = kmalloc(sizeof(local_info_t), GFP_KERNEL); |
166 | if (!local) return NULL; | 142 | if (!local) return -ENOMEM; |
167 | memset(local, 0, sizeof(local_info_t)); | 143 | memset(local, 0, sizeof(local_info_t)); |
168 | local->cardnr = -1; | 144 | local->cardnr = -1; |
169 | link = &local->link; link->priv = local; | 145 | link = &local->link; link->priv = local; |
@@ -188,20 +164,13 @@ static dev_link_t *teles_attach(void) | |||
188 | link->conf.Vcc = 50; | 164 | link->conf.Vcc = 50; |
189 | link->conf.IntType = INT_MEMORY_AND_IO; | 165 | link->conf.IntType = INT_MEMORY_AND_IO; |
190 | 166 | ||
191 | /* Register with Card Services */ | 167 | link->handle = p_dev; |
192 | link->next = dev_list; | 168 | p_dev->instance = link; |
193 | dev_list = link; | 169 | |
194 | client_reg.dev_info = &dev_info; | 170 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
195 | client_reg.Version = 0x0210; | 171 | teles_cs_config(link); |
196 | client_reg.event_callback_args.client_data = link; | ||
197 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
198 | if (ret != CS_SUCCESS) { | ||
199 | cs_error(link->handle, RegisterClient, ret); | ||
200 | teles_detach(link); | ||
201 | return NULL; | ||
202 | } | ||
203 | 172 | ||
204 | return link; | 173 | return 0; |
205 | } /* teles_attach */ | 174 | } /* teles_attach */ |
206 | 175 | ||
207 | /*====================================================================== | 176 | /*====================================================================== |
@@ -213,32 +182,18 @@ static dev_link_t *teles_attach(void) | |||
213 | 182 | ||
214 | ======================================================================*/ | 183 | ======================================================================*/ |
215 | 184 | ||
216 | static void teles_detach(dev_link_t *link) | 185 | static void teles_detach(struct pcmcia_device *p_dev) |
217 | { | 186 | { |
218 | dev_link_t **linkp; | 187 | dev_link_t *link = dev_to_instance(p_dev); |
219 | local_info_t *info = link->priv; | 188 | local_info_t *info = link->priv; |
220 | int ret; | ||
221 | 189 | ||
222 | DEBUG(0, "teles_detach(0x%p)\n", link); | 190 | DEBUG(0, "teles_detach(0x%p)\n", link); |
223 | 191 | ||
224 | /* Locate device structure */ | 192 | if (link->state & DEV_CONFIG) { |
225 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | 193 | info->busy = 1; |
226 | if (*linkp == link) break; | 194 | teles_cs_release(link); |
227 | if (*linkp == NULL) | ||
228 | return; | ||
229 | |||
230 | if (link->state & DEV_CONFIG) | ||
231 | teles_cs_release(link); | ||
232 | |||
233 | /* Break the link with Card Services */ | ||
234 | if (link->handle) { | ||
235 | ret = pcmcia_deregister_client(link->handle); | ||
236 | if (ret != CS_SUCCESS) | ||
237 | cs_error(link->handle, DeregisterClient, ret); | ||
238 | } | 195 | } |
239 | 196 | ||
240 | /* Unlink device structure and free it */ | ||
241 | *linkp = link->next; | ||
242 | kfree(info); | 197 | kfree(info); |
243 | 198 | ||
244 | } /* teles_detach */ | 199 | } /* teles_detach */ |
@@ -428,60 +383,32 @@ static void teles_cs_release(dev_link_t *link) | |||
428 | link->state &= ~DEV_CONFIG; | 383 | link->state &= ~DEV_CONFIG; |
429 | } /* teles_cs_release */ | 384 | } /* teles_cs_release */ |
430 | 385 | ||
431 | /*====================================================================== | 386 | static int teles_suspend(struct pcmcia_device *p_dev) |
432 | 387 | { | |
433 | The card status event handler. Mostly, this schedules other | 388 | dev_link_t *link = dev_to_instance(p_dev); |
434 | stuff to run after an event is received. A CARD_REMOVAL event | 389 | local_info_t *dev = link->priv; |
435 | also sets some flags to discourage the net drivers from trying | ||
436 | to talk to the card any more. | ||
437 | 390 | ||
438 | When a CARD_REMOVAL event is received, we immediately set a flag | 391 | link->state |= DEV_SUSPEND; |
439 | to block future accesses to this device. All the functions that | 392 | dev->busy = 1; |
440 | actually access the device should check this flag to make sure | 393 | if (link->state & DEV_CONFIG) |
441 | the card is still present. | 394 | pcmcia_release_configuration(link->handle); |
442 | 395 | ||
443 | ======================================================================*/ | 396 | return 0; |
397 | } | ||
444 | 398 | ||
445 | static int teles_cs_event(event_t event, int priority, | 399 | static int teles_resume(struct pcmcia_device *p_dev) |
446 | event_callback_args_t *args) | ||
447 | { | 400 | { |
448 | dev_link_t *link = args->client_data; | 401 | dev_link_t *link = dev_to_instance(p_dev); |
449 | local_info_t *dev = link->priv; | 402 | local_info_t *dev = link->priv; |
450 | |||
451 | DEBUG(1, "teles_cs_event(%d)\n", event); | ||
452 | 403 | ||
453 | switch (event) { | 404 | link->state &= ~DEV_SUSPEND; |
454 | case CS_EVENT_CARD_REMOVAL: | 405 | if (link->state & DEV_CONFIG) |
455 | link->state &= ~DEV_PRESENT; | 406 | pcmcia_request_configuration(link->handle, &link->conf); |
456 | if (link->state & DEV_CONFIG) { | ||
457 | ((local_info_t*)link->priv)->busy = 1; | ||
458 | teles_cs_release(link); | ||
459 | } | ||
460 | break; | ||
461 | case CS_EVENT_CARD_INSERTION: | ||
462 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
463 | teles_cs_config(link); | ||
464 | break; | ||
465 | case CS_EVENT_PM_SUSPEND: | ||
466 | link->state |= DEV_SUSPEND; | ||
467 | /* Fall through... */ | ||
468 | case CS_EVENT_RESET_PHYSICAL: | ||
469 | /* Mark the device as stopped, to block IO until later */ | ||
470 | dev->busy = 1; | ||
471 | if (link->state & DEV_CONFIG) | ||
472 | pcmcia_release_configuration(link->handle); | ||
473 | break; | ||
474 | case CS_EVENT_PM_RESUME: | ||
475 | link->state &= ~DEV_SUSPEND; | ||
476 | /* Fall through... */ | ||
477 | case CS_EVENT_CARD_RESET: | ||
478 | if (link->state & DEV_CONFIG) | ||
479 | pcmcia_request_configuration(link->handle, &link->conf); | ||
480 | dev->busy = 0; | 407 | dev->busy = 0; |
481 | break; | 408 | |
482 | } | 409 | return 0; |
483 | return 0; | 410 | } |
484 | } /* teles_cs_event */ | 411 | |
485 | 412 | ||
486 | static struct pcmcia_device_id teles_ids[] = { | 413 | static struct pcmcia_device_id teles_ids[] = { |
487 | PCMCIA_DEVICE_PROD_ID12("TELES", "S0/PC", 0x67b50eae, 0xe9e70119), | 414 | PCMCIA_DEVICE_PROD_ID12("TELES", "S0/PC", 0x67b50eae, 0xe9e70119), |
@@ -494,10 +421,11 @@ static struct pcmcia_driver teles_cs_driver = { | |||
494 | .drv = { | 421 | .drv = { |
495 | .name = "teles_cs", | 422 | .name = "teles_cs", |
496 | }, | 423 | }, |
497 | .attach = teles_attach, | 424 | .probe = teles_attach, |
498 | .event = teles_cs_event, | 425 | .remove = teles_detach, |
499 | .detach = teles_detach, | ||
500 | .id_table = teles_ids, | 426 | .id_table = teles_ids, |
427 | .suspend = teles_suspend, | ||
428 | .resume = teles_resume, | ||
501 | }; | 429 | }; |
502 | 430 | ||
503 | static int __init init_teles_cs(void) | 431 | static int __init init_teles_cs(void) |
@@ -508,7 +436,6 @@ static int __init init_teles_cs(void) | |||
508 | static void __exit exit_teles_cs(void) | 436 | static void __exit exit_teles_cs(void) |
509 | { | 437 | { |
510 | pcmcia_unregister_driver(&teles_cs_driver); | 438 | pcmcia_unregister_driver(&teles_cs_driver); |
511 | BUG_ON(dev_list != NULL); | ||
512 | } | 439 | } |
513 | 440 | ||
514 | module_init(init_teles_cs); | 441 | module_init(init_teles_cs); |
diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c index af24216a0626..f0f8916da7ad 100644 --- a/drivers/mtd/maps/pcmciamtd.c +++ b/drivers/mtd/maps/pcmciamtd.c | |||
@@ -66,9 +66,6 @@ struct pcmciamtd_dev { | |||
66 | }; | 66 | }; |
67 | 67 | ||
68 | 68 | ||
69 | static dev_info_t dev_info = "pcmciamtd"; | ||
70 | static dev_link_t *dev_list; | ||
71 | |||
72 | /* Module parameters */ | 69 | /* Module parameters */ |
73 | 70 | ||
74 | /* 2 = do 16-bit transfers, 1 = do 8-bit transfers */ | 71 | /* 2 = do 16-bit transfers, 1 = do 8-bit transfers */ |
@@ -691,55 +688,21 @@ static void pcmciamtd_config(dev_link_t *link) | |||
691 | } | 688 | } |
692 | 689 | ||
693 | 690 | ||
694 | /* The card status event handler. Mostly, this schedules other | 691 | static int pcmciamtd_suspend(struct pcmcia_device *dev) |
695 | * stuff to run after an event is received. A CARD_REMOVAL event | 692 | { |
696 | * also sets some flags to discourage the driver from trying | 693 | DEBUG(2, "EVENT_PM_RESUME"); |
697 | * to talk to the card any more. | 694 | |
698 | */ | 695 | /* get_lock(link); */ |
696 | |||
697 | return 0; | ||
698 | } | ||
699 | 699 | ||
700 | static int pcmciamtd_event(event_t event, int priority, | 700 | static int pcmciamtd_resume(struct pcmcia_device *dev) |
701 | event_callback_args_t *args) | ||
702 | { | 701 | { |
703 | dev_link_t *link = args->client_data; | 702 | DEBUG(2, "EVENT_PM_SUSPEND"); |
704 | 703 | ||
705 | DEBUG(1, "event=0x%06x", event); | 704 | /* free_lock(link); */ |
706 | switch (event) { | 705 | |
707 | case CS_EVENT_CARD_REMOVAL: | ||
708 | DEBUG(2, "EVENT_CARD_REMOVAL"); | ||
709 | link->state &= ~DEV_PRESENT; | ||
710 | if (link->state & DEV_CONFIG) { | ||
711 | struct pcmciamtd_dev *dev = link->priv; | ||
712 | if(dev->mtd_info) { | ||
713 | del_mtd_device(dev->mtd_info); | ||
714 | info("mtd%d: Removed", dev->mtd_info->index); | ||
715 | } | ||
716 | pcmciamtd_release(link); | ||
717 | } | ||
718 | break; | ||
719 | case CS_EVENT_CARD_INSERTION: | ||
720 | DEBUG(2, "EVENT_CARD_INSERTION"); | ||
721 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
722 | pcmciamtd_config(link); | ||
723 | break; | ||
724 | case CS_EVENT_PM_SUSPEND: | ||
725 | DEBUG(2, "EVENT_PM_SUSPEND"); | ||
726 | link->state |= DEV_SUSPEND; | ||
727 | /* Fall through... */ | ||
728 | case CS_EVENT_RESET_PHYSICAL: | ||
729 | DEBUG(2, "EVENT_RESET_PHYSICAL"); | ||
730 | /* get_lock(link); */ | ||
731 | break; | ||
732 | case CS_EVENT_PM_RESUME: | ||
733 | DEBUG(2, "EVENT_PM_RESUME"); | ||
734 | link->state &= ~DEV_SUSPEND; | ||
735 | /* Fall through... */ | ||
736 | case CS_EVENT_CARD_RESET: | ||
737 | DEBUG(2, "EVENT_CARD_RESET"); | ||
738 | /* free_lock(link); */ | ||
739 | break; | ||
740 | default: | ||
741 | DEBUG(2, "Unknown event %d", event); | ||
742 | } | ||
743 | return 0; | 706 | return 0; |
744 | } | 707 | } |
745 | 708 | ||
@@ -750,23 +713,21 @@ static int pcmciamtd_event(event_t event, int priority, | |||
750 | * when the device is released. | 713 | * when the device is released. |
751 | */ | 714 | */ |
752 | 715 | ||
753 | static void pcmciamtd_detach(dev_link_t *link) | 716 | static void pcmciamtd_detach(struct pcmcia_device *p_dev) |
754 | { | 717 | { |
718 | dev_link_t *link = dev_to_instance(p_dev); | ||
719 | |||
755 | DEBUG(3, "link=0x%p", link); | 720 | DEBUG(3, "link=0x%p", link); |
756 | 721 | ||
757 | if(link->state & DEV_CONFIG) { | 722 | if(link->state & DEV_CONFIG) { |
758 | pcmciamtd_release(link); | 723 | struct pcmciamtd_dev *dev = link->priv; |
759 | } | 724 | if(dev->mtd_info) { |
725 | del_mtd_device(dev->mtd_info); | ||
726 | info("mtd%d: Removed", dev->mtd_info->index); | ||
727 | } | ||
760 | 728 | ||
761 | if (link->handle) { | 729 | pcmciamtd_release(link); |
762 | int ret; | ||
763 | DEBUG(2, "Deregistering with card services"); | ||
764 | ret = pcmcia_deregister_client(link->handle); | ||
765 | if (ret != CS_SUCCESS) | ||
766 | cs_error(link->handle, DeregisterClient, ret); | ||
767 | } | 730 | } |
768 | |||
769 | link->state |= DEV_STALE_LINK; | ||
770 | } | 731 | } |
771 | 732 | ||
772 | 733 | ||
@@ -775,16 +736,14 @@ static void pcmciamtd_detach(dev_link_t *link) | |||
775 | * with Card Services. | 736 | * with Card Services. |
776 | */ | 737 | */ |
777 | 738 | ||
778 | static dev_link_t *pcmciamtd_attach(void) | 739 | static int pcmciamtd_attach(struct pcmcia_device *p_dev) |
779 | { | 740 | { |
780 | struct pcmciamtd_dev *dev; | 741 | struct pcmciamtd_dev *dev; |
781 | dev_link_t *link; | 742 | dev_link_t *link; |
782 | client_reg_t client_reg; | ||
783 | int ret; | ||
784 | 743 | ||
785 | /* Create new memory card device */ | 744 | /* Create new memory card device */ |
786 | dev = kmalloc(sizeof(*dev), GFP_KERNEL); | 745 | dev = kmalloc(sizeof(*dev), GFP_KERNEL); |
787 | if (!dev) return NULL; | 746 | if (!dev) return -ENOMEM; |
788 | DEBUG(1, "dev=0x%p", dev); | 747 | DEBUG(1, "dev=0x%p", dev); |
789 | 748 | ||
790 | memset(dev, 0, sizeof(*dev)); | 749 | memset(dev, 0, sizeof(*dev)); |
@@ -794,22 +753,14 @@ static dev_link_t *pcmciamtd_attach(void) | |||
794 | link->conf.Attributes = 0; | 753 | link->conf.Attributes = 0; |
795 | link->conf.IntType = INT_MEMORY; | 754 | link->conf.IntType = INT_MEMORY; |
796 | 755 | ||
797 | link->next = dev_list; | 756 | link->next = NULL; |
798 | dev_list = link; | 757 | link->handle = p_dev; |
799 | 758 | p_dev->instance = link; | |
800 | /* Register with Card Services */ | 759 | |
801 | client_reg.dev_info = &dev_info; | 760 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
802 | client_reg.Version = 0x0210; | 761 | pcmciamtd_config(link); |
803 | client_reg.event_callback_args.client_data = link; | 762 | |
804 | DEBUG(2, "Calling RegisterClient"); | 763 | return 0; |
805 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
806 | if (ret != 0) { | ||
807 | cs_error(link->handle, RegisterClient, ret); | ||
808 | pcmciamtd_detach(link); | ||
809 | return NULL; | ||
810 | } | ||
811 | DEBUG(2, "link = %p", link); | ||
812 | return link; | ||
813 | } | 764 | } |
814 | 765 | ||
815 | static struct pcmcia_device_id pcmciamtd_ids[] = { | 766 | static struct pcmcia_device_id pcmciamtd_ids[] = { |
@@ -843,11 +794,12 @@ static struct pcmcia_driver pcmciamtd_driver = { | |||
843 | .drv = { | 794 | .drv = { |
844 | .name = "pcmciamtd" | 795 | .name = "pcmciamtd" |
845 | }, | 796 | }, |
846 | .attach = pcmciamtd_attach, | 797 | .probe = pcmciamtd_attach, |
847 | .event = pcmciamtd_event, | 798 | .remove = pcmciamtd_detach, |
848 | .detach = pcmciamtd_detach, | ||
849 | .owner = THIS_MODULE, | 799 | .owner = THIS_MODULE, |
850 | .id_table = pcmciamtd_ids, | 800 | .id_table = pcmciamtd_ids, |
801 | .suspend = pcmciamtd_suspend, | ||
802 | .resume = pcmciamtd_resume, | ||
851 | }; | 803 | }; |
852 | 804 | ||
853 | 805 | ||
@@ -875,7 +827,6 @@ static void __exit exit_pcmciamtd(void) | |||
875 | { | 827 | { |
876 | DEBUG(1, DRIVER_DESC " unloading"); | 828 | DEBUG(1, DRIVER_DESC " unloading"); |
877 | pcmcia_unregister_driver(&pcmciamtd_driver); | 829 | pcmcia_unregister_driver(&pcmciamtd_driver); |
878 | BUG_ON(dev_list != NULL); | ||
879 | } | 830 | } |
880 | 831 | ||
881 | module_init(init_pcmciamtd); | 832 | module_init(init_pcmciamtd); |
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 71fd41122c91..48774efeec71 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c | |||
@@ -227,8 +227,6 @@ static char mii_preamble_required = 0; | |||
227 | 227 | ||
228 | static void tc574_config(dev_link_t *link); | 228 | static void tc574_config(dev_link_t *link); |
229 | static void tc574_release(dev_link_t *link); | 229 | static void tc574_release(dev_link_t *link); |
230 | static int tc574_event(event_t event, int priority, | ||
231 | event_callback_args_t *args); | ||
232 | 230 | ||
233 | static void mdio_sync(kio_addr_t ioaddr, int bits); | 231 | static void mdio_sync(kio_addr_t ioaddr, int bits); |
234 | static int mdio_read(kio_addr_t ioaddr, int phy_id, int location); | 232 | static int mdio_read(kio_addr_t ioaddr, int phy_id, int location); |
@@ -250,12 +248,7 @@ static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); | |||
250 | static struct ethtool_ops netdev_ethtool_ops; | 248 | static struct ethtool_ops netdev_ethtool_ops; |
251 | static void set_rx_mode(struct net_device *dev); | 249 | static void set_rx_mode(struct net_device *dev); |
252 | 250 | ||
253 | static dev_info_t dev_info = "3c574_cs"; | 251 | static void tc574_detach(struct pcmcia_device *p_dev); |
254 | |||
255 | static dev_link_t *tc574_attach(void); | ||
256 | static void tc574_detach(dev_link_t *); | ||
257 | |||
258 | static dev_link_t *dev_list; | ||
259 | 252 | ||
260 | /* | 253 | /* |
261 | tc574_attach() creates an "instance" of the driver, allocating | 254 | tc574_attach() creates an "instance" of the driver, allocating |
@@ -263,20 +256,18 @@ static dev_link_t *dev_list; | |||
263 | with Card Services. | 256 | with Card Services. |
264 | */ | 257 | */ |
265 | 258 | ||
266 | static dev_link_t *tc574_attach(void) | 259 | static int tc574_attach(struct pcmcia_device *p_dev) |
267 | { | 260 | { |
268 | struct el3_private *lp; | 261 | struct el3_private *lp; |
269 | client_reg_t client_reg; | ||
270 | dev_link_t *link; | 262 | dev_link_t *link; |
271 | struct net_device *dev; | 263 | struct net_device *dev; |
272 | int ret; | ||
273 | 264 | ||
274 | DEBUG(0, "3c574_attach()\n"); | 265 | DEBUG(0, "3c574_attach()\n"); |
275 | 266 | ||
276 | /* Create the PC card device object. */ | 267 | /* Create the PC card device object. */ |
277 | dev = alloc_etherdev(sizeof(struct el3_private)); | 268 | dev = alloc_etherdev(sizeof(struct el3_private)); |
278 | if (!dev) | 269 | if (!dev) |
279 | return NULL; | 270 | return -ENOMEM; |
280 | lp = netdev_priv(dev); | 271 | lp = netdev_priv(dev); |
281 | link = &lp->link; | 272 | link = &lp->link; |
282 | link->priv = dev; | 273 | link->priv = dev; |
@@ -307,20 +298,13 @@ static dev_link_t *tc574_attach(void) | |||
307 | dev->watchdog_timeo = TX_TIMEOUT; | 298 | dev->watchdog_timeo = TX_TIMEOUT; |
308 | #endif | 299 | #endif |
309 | 300 | ||
310 | /* Register with Card Services */ | 301 | link->handle = p_dev; |
311 | link->next = dev_list; | 302 | p_dev->instance = link; |
312 | dev_list = link; | ||
313 | client_reg.dev_info = &dev_info; | ||
314 | client_reg.Version = 0x0210; | ||
315 | client_reg.event_callback_args.client_data = link; | ||
316 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
317 | if (ret != 0) { | ||
318 | cs_error(link->handle, RegisterClient, ret); | ||
319 | tc574_detach(link); | ||
320 | return NULL; | ||
321 | } | ||
322 | 303 | ||
323 | return link; | 304 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
305 | tc574_config(link); | ||
306 | |||
307 | return 0; | ||
324 | } /* tc574_attach */ | 308 | } /* tc574_attach */ |
325 | 309 | ||
326 | /* | 310 | /* |
@@ -332,30 +316,19 @@ static dev_link_t *tc574_attach(void) | |||
332 | 316 | ||
333 | */ | 317 | */ |
334 | 318 | ||
335 | static void tc574_detach(dev_link_t *link) | 319 | static void tc574_detach(struct pcmcia_device *p_dev) |
336 | { | 320 | { |
321 | dev_link_t *link = dev_to_instance(p_dev); | ||
337 | struct net_device *dev = link->priv; | 322 | struct net_device *dev = link->priv; |
338 | dev_link_t **linkp; | ||
339 | 323 | ||
340 | DEBUG(0, "3c574_detach(0x%p)\n", link); | 324 | DEBUG(0, "3c574_detach(0x%p)\n", link); |
341 | 325 | ||
342 | /* Locate device structure */ | ||
343 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
344 | if (*linkp == link) break; | ||
345 | if (*linkp == NULL) | ||
346 | return; | ||
347 | |||
348 | if (link->dev) | 326 | if (link->dev) |
349 | unregister_netdev(dev); | 327 | unregister_netdev(dev); |
350 | 328 | ||
351 | if (link->state & DEV_CONFIG) | 329 | if (link->state & DEV_CONFIG) |
352 | tc574_release(link); | 330 | tc574_release(link); |
353 | 331 | ||
354 | if (link->handle) | ||
355 | pcmcia_deregister_client(link->handle); | ||
356 | |||
357 | /* Unlink device structure, free bits */ | ||
358 | *linkp = link->next; | ||
359 | free_netdev(dev); | 332 | free_netdev(dev); |
360 | } /* tc574_detach */ | 333 | } /* tc574_detach */ |
361 | 334 | ||
@@ -547,56 +520,37 @@ static void tc574_release(dev_link_t *link) | |||
547 | link->state &= ~DEV_CONFIG; | 520 | link->state &= ~DEV_CONFIG; |
548 | } | 521 | } |
549 | 522 | ||
550 | /* | 523 | static int tc574_suspend(struct pcmcia_device *p_dev) |
551 | The card status event handler. Mostly, this schedules other | ||
552 | stuff to run after an event is received. A CARD_REMOVAL event | ||
553 | also sets some flags to discourage the net drivers from trying | ||
554 | to talk to the card any more. | ||
555 | */ | ||
556 | |||
557 | static int tc574_event(event_t event, int priority, | ||
558 | event_callback_args_t *args) | ||
559 | { | 524 | { |
560 | dev_link_t *link = args->client_data; | 525 | dev_link_t *link = dev_to_instance(p_dev); |
561 | struct net_device *dev = link->priv; | 526 | struct net_device *dev = link->priv; |
562 | 527 | ||
563 | DEBUG(1, "3c574_event(0x%06x)\n", event); | 528 | link->state |= DEV_SUSPEND; |
564 | 529 | if (link->state & DEV_CONFIG) { | |
565 | switch (event) { | 530 | if (link->open) |
566 | case CS_EVENT_CARD_REMOVAL: | ||
567 | link->state &= ~DEV_PRESENT; | ||
568 | if (link->state & DEV_CONFIG) | ||
569 | netif_device_detach(dev); | 531 | netif_device_detach(dev); |
570 | break; | 532 | pcmcia_release_configuration(link->handle); |
571 | case CS_EVENT_CARD_INSERTION: | 533 | } |
572 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | 534 | |
573 | tc574_config(link); | 535 | return 0; |
574 | break; | 536 | } |
575 | case CS_EVENT_PM_SUSPEND: | 537 | |
576 | link->state |= DEV_SUSPEND; | 538 | static int tc574_resume(struct pcmcia_device *p_dev) |
577 | /* Fall through... */ | 539 | { |
578 | case CS_EVENT_RESET_PHYSICAL: | 540 | dev_link_t *link = dev_to_instance(p_dev); |
579 | if (link->state & DEV_CONFIG) { | 541 | struct net_device *dev = link->priv; |
580 | if (link->open) | 542 | |
581 | netif_device_detach(dev); | 543 | link->state &= ~DEV_SUSPEND; |
582 | pcmcia_release_configuration(link->handle); | 544 | if (link->state & DEV_CONFIG) { |
583 | } | 545 | pcmcia_request_configuration(link->handle, &link->conf); |
584 | break; | 546 | if (link->open) { |
585 | case CS_EVENT_PM_RESUME: | 547 | tc574_reset(dev); |
586 | link->state &= ~DEV_SUSPEND; | 548 | netif_device_attach(dev); |
587 | /* Fall through... */ | ||
588 | case CS_EVENT_CARD_RESET: | ||
589 | if (link->state & DEV_CONFIG) { | ||
590 | pcmcia_request_configuration(link->handle, &link->conf); | ||
591 | if (link->open) { | ||
592 | tc574_reset(dev); | ||
593 | netif_device_attach(dev); | ||
594 | } | ||
595 | } | 549 | } |
596 | break; | ||
597 | } | 550 | } |
551 | |||
598 | return 0; | 552 | return 0; |
599 | } /* tc574_event */ | 553 | } |
600 | 554 | ||
601 | static void dump_status(struct net_device *dev) | 555 | static void dump_status(struct net_device *dev) |
602 | { | 556 | { |
@@ -1292,10 +1246,11 @@ static struct pcmcia_driver tc574_driver = { | |||
1292 | .drv = { | 1246 | .drv = { |
1293 | .name = "3c574_cs", | 1247 | .name = "3c574_cs", |
1294 | }, | 1248 | }, |
1295 | .attach = tc574_attach, | 1249 | .probe = tc574_attach, |
1296 | .event = tc574_event, | 1250 | .remove = tc574_detach, |
1297 | .detach = tc574_detach, | ||
1298 | .id_table = tc574_ids, | 1251 | .id_table = tc574_ids, |
1252 | .suspend = tc574_suspend, | ||
1253 | .resume = tc574_resume, | ||
1299 | }; | 1254 | }; |
1300 | 1255 | ||
1301 | static int __init init_tc574(void) | 1256 | static int __init init_tc574(void) |
@@ -1306,7 +1261,6 @@ static int __init init_tc574(void) | |||
1306 | static void __exit exit_tc574(void) | 1261 | static void __exit exit_tc574(void) |
1307 | { | 1262 | { |
1308 | pcmcia_unregister_driver(&tc574_driver); | 1263 | pcmcia_unregister_driver(&tc574_driver); |
1309 | BUG_ON(dev_list != NULL); | ||
1310 | } | 1264 | } |
1311 | 1265 | ||
1312 | module_init(init_tc574); | 1266 | module_init(init_tc574); |
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index d83fdd8c1943..1c3c9c666f74 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c | |||
@@ -143,8 +143,6 @@ DRV_NAME ".c " DRV_VERSION " 2001/10/13 00:08:50 (David Hinds)"; | |||
143 | 143 | ||
144 | static void tc589_config(dev_link_t *link); | 144 | static void tc589_config(dev_link_t *link); |
145 | static void tc589_release(dev_link_t *link); | 145 | static void tc589_release(dev_link_t *link); |
146 | static int tc589_event(event_t event, int priority, | ||
147 | event_callback_args_t *args); | ||
148 | 146 | ||
149 | static u16 read_eeprom(kio_addr_t ioaddr, int index); | 147 | static u16 read_eeprom(kio_addr_t ioaddr, int index); |
150 | static void tc589_reset(struct net_device *dev); | 148 | static void tc589_reset(struct net_device *dev); |
@@ -161,12 +159,7 @@ static void el3_tx_timeout(struct net_device *dev); | |||
161 | static void set_multicast_list(struct net_device *dev); | 159 | static void set_multicast_list(struct net_device *dev); |
162 | static struct ethtool_ops netdev_ethtool_ops; | 160 | static struct ethtool_ops netdev_ethtool_ops; |
163 | 161 | ||
164 | static dev_info_t dev_info = "3c589_cs"; | 162 | static void tc589_detach(struct pcmcia_device *p_dev); |
165 | |||
166 | static dev_link_t *tc589_attach(void); | ||
167 | static void tc589_detach(dev_link_t *); | ||
168 | |||
169 | static dev_link_t *dev_list; | ||
170 | 163 | ||
171 | /*====================================================================== | 164 | /*====================================================================== |
172 | 165 | ||
@@ -176,20 +169,18 @@ static dev_link_t *dev_list; | |||
176 | 169 | ||
177 | ======================================================================*/ | 170 | ======================================================================*/ |
178 | 171 | ||
179 | static dev_link_t *tc589_attach(void) | 172 | static int tc589_attach(struct pcmcia_device *p_dev) |
180 | { | 173 | { |
181 | struct el3_private *lp; | 174 | struct el3_private *lp; |
182 | client_reg_t client_reg; | ||
183 | dev_link_t *link; | 175 | dev_link_t *link; |
184 | struct net_device *dev; | 176 | struct net_device *dev; |
185 | int ret; | ||
186 | 177 | ||
187 | DEBUG(0, "3c589_attach()\n"); | 178 | DEBUG(0, "3c589_attach()\n"); |
188 | 179 | ||
189 | /* Create new ethernet device */ | 180 | /* Create new ethernet device */ |
190 | dev = alloc_etherdev(sizeof(struct el3_private)); | 181 | dev = alloc_etherdev(sizeof(struct el3_private)); |
191 | if (!dev) | 182 | if (!dev) |
192 | return NULL; | 183 | return -ENOMEM; |
193 | lp = netdev_priv(dev); | 184 | lp = netdev_priv(dev); |
194 | link = &lp->link; | 185 | link = &lp->link; |
195 | link->priv = dev; | 186 | link->priv = dev; |
@@ -206,7 +197,7 @@ static dev_link_t *tc589_attach(void) | |||
206 | link->conf.IntType = INT_MEMORY_AND_IO; | 197 | link->conf.IntType = INT_MEMORY_AND_IO; |
207 | link->conf.ConfigIndex = 1; | 198 | link->conf.ConfigIndex = 1; |
208 | link->conf.Present = PRESENT_OPTION; | 199 | link->conf.Present = PRESENT_OPTION; |
209 | 200 | ||
210 | /* The EL3-specific entries in the device structure. */ | 201 | /* The EL3-specific entries in the device structure. */ |
211 | SET_MODULE_OWNER(dev); | 202 | SET_MODULE_OWNER(dev); |
212 | dev->hard_start_xmit = &el3_start_xmit; | 203 | dev->hard_start_xmit = &el3_start_xmit; |
@@ -221,20 +212,13 @@ static dev_link_t *tc589_attach(void) | |||
221 | #endif | 212 | #endif |
222 | SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); | 213 | SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); |
223 | 214 | ||
224 | /* Register with Card Services */ | 215 | link->handle = p_dev; |
225 | link->next = dev_list; | 216 | p_dev->instance = link; |
226 | dev_list = link; | 217 | |
227 | client_reg.dev_info = &dev_info; | 218 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
228 | client_reg.Version = 0x0210; | 219 | tc589_config(link); |
229 | client_reg.event_callback_args.client_data = link; | 220 | |
230 | ret = pcmcia_register_client(&link->handle, &client_reg); | 221 | return 0; |
231 | if (ret != 0) { | ||
232 | cs_error(link->handle, RegisterClient, ret); | ||
233 | tc589_detach(link); | ||
234 | return NULL; | ||
235 | } | ||
236 | |||
237 | return link; | ||
238 | } /* tc589_attach */ | 222 | } /* tc589_attach */ |
239 | 223 | ||
240 | /*====================================================================== | 224 | /*====================================================================== |
@@ -246,30 +230,19 @@ static dev_link_t *tc589_attach(void) | |||
246 | 230 | ||
247 | ======================================================================*/ | 231 | ======================================================================*/ |
248 | 232 | ||
249 | static void tc589_detach(dev_link_t *link) | 233 | static void tc589_detach(struct pcmcia_device *p_dev) |
250 | { | 234 | { |
235 | dev_link_t *link = dev_to_instance(p_dev); | ||
251 | struct net_device *dev = link->priv; | 236 | struct net_device *dev = link->priv; |
252 | dev_link_t **linkp; | 237 | |
253 | |||
254 | DEBUG(0, "3c589_detach(0x%p)\n", link); | 238 | DEBUG(0, "3c589_detach(0x%p)\n", link); |
255 | |||
256 | /* Locate device structure */ | ||
257 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
258 | if (*linkp == link) break; | ||
259 | if (*linkp == NULL) | ||
260 | return; | ||
261 | 239 | ||
262 | if (link->dev) | 240 | if (link->dev) |
263 | unregister_netdev(dev); | 241 | unregister_netdev(dev); |
264 | 242 | ||
265 | if (link->state & DEV_CONFIG) | 243 | if (link->state & DEV_CONFIG) |
266 | tc589_release(link); | 244 | tc589_release(link); |
267 | 245 | ||
268 | if (link->handle) | ||
269 | pcmcia_deregister_client(link->handle); | ||
270 | |||
271 | /* Unlink device structure, free bits */ | ||
272 | *linkp = link->next; | ||
273 | free_netdev(dev); | 246 | free_netdev(dev); |
274 | } /* tc589_detach */ | 247 | } /* tc589_detach */ |
275 | 248 | ||
@@ -421,58 +394,37 @@ static void tc589_release(dev_link_t *link) | |||
421 | link->state &= ~DEV_CONFIG; | 394 | link->state &= ~DEV_CONFIG; |
422 | } | 395 | } |
423 | 396 | ||
424 | /*====================================================================== | 397 | static int tc589_suspend(struct pcmcia_device *p_dev) |
425 | |||
426 | The card status event handler. Mostly, this schedules other | ||
427 | stuff to run after an event is received. A CARD_REMOVAL event | ||
428 | also sets some flags to discourage the net drivers from trying | ||
429 | to talk to the card any more. | ||
430 | |||
431 | ======================================================================*/ | ||
432 | |||
433 | static int tc589_event(event_t event, int priority, | ||
434 | event_callback_args_t *args) | ||
435 | { | 398 | { |
436 | dev_link_t *link = args->client_data; | 399 | dev_link_t *link = dev_to_instance(p_dev); |
437 | struct net_device *dev = link->priv; | 400 | struct net_device *dev = link->priv; |
438 | 401 | ||
439 | DEBUG(1, "3c589_event(0x%06x)\n", event); | ||
440 | |||
441 | switch (event) { | ||
442 | case CS_EVENT_CARD_REMOVAL: | ||
443 | link->state &= ~DEV_PRESENT; | ||
444 | if (link->state & DEV_CONFIG) | ||
445 | netif_device_detach(dev); | ||
446 | break; | ||
447 | case CS_EVENT_CARD_INSERTION: | ||
448 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
449 | tc589_config(link); | ||
450 | break; | ||
451 | case CS_EVENT_PM_SUSPEND: | ||
452 | link->state |= DEV_SUSPEND; | 402 | link->state |= DEV_SUSPEND; |
453 | /* Fall through... */ | ||
454 | case CS_EVENT_RESET_PHYSICAL: | ||
455 | if (link->state & DEV_CONFIG) { | 403 | if (link->state & DEV_CONFIG) { |
456 | if (link->open) | 404 | if (link->open) |
457 | netif_device_detach(dev); | 405 | netif_device_detach(dev); |
458 | pcmcia_release_configuration(link->handle); | 406 | pcmcia_release_configuration(link->handle); |
459 | } | 407 | } |
460 | break; | 408 | |
461 | case CS_EVENT_PM_RESUME: | 409 | return 0; |
410 | } | ||
411 | |||
412 | static int tc589_resume(struct pcmcia_device *p_dev) | ||
413 | { | ||
414 | dev_link_t *link = dev_to_instance(p_dev); | ||
415 | struct net_device *dev = link->priv; | ||
416 | |||
462 | link->state &= ~DEV_SUSPEND; | 417 | link->state &= ~DEV_SUSPEND; |
463 | /* Fall through... */ | ||
464 | case CS_EVENT_CARD_RESET: | ||
465 | if (link->state & DEV_CONFIG) { | 418 | if (link->state & DEV_CONFIG) { |
466 | pcmcia_request_configuration(link->handle, &link->conf); | 419 | pcmcia_request_configuration(link->handle, &link->conf); |
467 | if (link->open) { | 420 | if (link->open) { |
468 | tc589_reset(dev); | 421 | tc589_reset(dev); |
469 | netif_device_attach(dev); | 422 | netif_device_attach(dev); |
470 | } | 423 | } |
471 | } | 424 | } |
472 | break; | 425 | |
473 | } | 426 | return 0; |
474 | return 0; | 427 | } |
475 | } /* tc589_event */ | ||
476 | 428 | ||
477 | /*====================================================================*/ | 429 | /*====================================================================*/ |
478 | 430 | ||
@@ -1067,10 +1019,11 @@ static struct pcmcia_driver tc589_driver = { | |||
1067 | .drv = { | 1019 | .drv = { |
1068 | .name = "3c589_cs", | 1020 | .name = "3c589_cs", |
1069 | }, | 1021 | }, |
1070 | .attach = tc589_attach, | 1022 | .probe = tc589_attach, |
1071 | .event = tc589_event, | 1023 | .remove = tc589_detach, |
1072 | .detach = tc589_detach, | ||
1073 | .id_table = tc589_ids, | 1024 | .id_table = tc589_ids, |
1025 | .suspend = tc589_suspend, | ||
1026 | .resume = tc589_resume, | ||
1074 | }; | 1027 | }; |
1075 | 1028 | ||
1076 | static int __init init_tc589(void) | 1029 | static int __init init_tc589(void) |
@@ -1081,7 +1034,6 @@ static int __init init_tc589(void) | |||
1081 | static void __exit exit_tc589(void) | 1034 | static void __exit exit_tc589(void) |
1082 | { | 1035 | { |
1083 | pcmcia_unregister_driver(&tc589_driver); | 1036 | pcmcia_unregister_driver(&tc589_driver); |
1084 | BUG_ON(dev_list != NULL); | ||
1085 | } | 1037 | } |
1086 | 1038 | ||
1087 | module_init(init_tc589); | 1039 | module_init(init_tc589); |
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 8bb4e85689ea..01ddfc8cce3f 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c | |||
@@ -87,8 +87,6 @@ static char *version = | |||
87 | 87 | ||
88 | static void axnet_config(dev_link_t *link); | 88 | static void axnet_config(dev_link_t *link); |
89 | static void axnet_release(dev_link_t *link); | 89 | static void axnet_release(dev_link_t *link); |
90 | static int axnet_event(event_t event, int priority, | ||
91 | event_callback_args_t *args); | ||
92 | static int axnet_open(struct net_device *dev); | 90 | static int axnet_open(struct net_device *dev); |
93 | static int axnet_close(struct net_device *dev); | 91 | static int axnet_close(struct net_device *dev); |
94 | static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); | 92 | static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); |
@@ -107,11 +105,7 @@ static void block_input(struct net_device *dev, int count, | |||
107 | static void block_output(struct net_device *dev, int count, | 105 | static void block_output(struct net_device *dev, int count, |
108 | const u_char *buf, const int start_page); | 106 | const u_char *buf, const int start_page); |
109 | 107 | ||
110 | static dev_link_t *axnet_attach(void); | 108 | static void axnet_detach(struct pcmcia_device *p_dev); |
111 | static void axnet_detach(dev_link_t *); | ||
112 | |||
113 | static dev_info_t dev_info = "axnet_cs"; | ||
114 | static dev_link_t *dev_list; | ||
115 | 109 | ||
116 | static void axdev_setup(struct net_device *dev); | 110 | static void axdev_setup(struct net_device *dev); |
117 | static void AX88190_init(struct net_device *dev, int startp); | 111 | static void AX88190_init(struct net_device *dev, int startp); |
@@ -147,13 +141,11 @@ static inline axnet_dev_t *PRIV(struct net_device *dev) | |||
147 | 141 | ||
148 | ======================================================================*/ | 142 | ======================================================================*/ |
149 | 143 | ||
150 | static dev_link_t *axnet_attach(void) | 144 | static int axnet_attach(struct pcmcia_device *p_dev) |
151 | { | 145 | { |
152 | axnet_dev_t *info; | 146 | axnet_dev_t *info; |
153 | dev_link_t *link; | 147 | dev_link_t *link; |
154 | struct net_device *dev; | 148 | struct net_device *dev; |
155 | client_reg_t client_reg; | ||
156 | int ret; | ||
157 | 149 | ||
158 | DEBUG(0, "axnet_attach()\n"); | 150 | DEBUG(0, "axnet_attach()\n"); |
159 | 151 | ||
@@ -161,7 +153,7 @@ static dev_link_t *axnet_attach(void) | |||
161 | "eth%d", axdev_setup); | 153 | "eth%d", axdev_setup); |
162 | 154 | ||
163 | if (!dev) | 155 | if (!dev) |
164 | return NULL; | 156 | return -ENOMEM; |
165 | 157 | ||
166 | info = PRIV(dev); | 158 | info = PRIV(dev); |
167 | link = &info->link; | 159 | link = &info->link; |
@@ -176,20 +168,13 @@ static dev_link_t *axnet_attach(void) | |||
176 | dev->do_ioctl = &axnet_ioctl; | 168 | dev->do_ioctl = &axnet_ioctl; |
177 | SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); | 169 | SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); |
178 | 170 | ||
179 | /* Register with Card Services */ | 171 | link->handle = p_dev; |
180 | link->next = dev_list; | 172 | p_dev->instance = link; |
181 | dev_list = link; | ||
182 | client_reg.dev_info = &dev_info; | ||
183 | client_reg.Version = 0x0210; | ||
184 | client_reg.event_callback_args.client_data = link; | ||
185 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
186 | if (ret != CS_SUCCESS) { | ||
187 | cs_error(link->handle, RegisterClient, ret); | ||
188 | axnet_detach(link); | ||
189 | return NULL; | ||
190 | } | ||
191 | 173 | ||
192 | return link; | 174 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
175 | axnet_config(link); | ||
176 | |||
177 | return 0; | ||
193 | } /* axnet_attach */ | 178 | } /* axnet_attach */ |
194 | 179 | ||
195 | /*====================================================================== | 180 | /*====================================================================== |
@@ -201,30 +186,19 @@ static dev_link_t *axnet_attach(void) | |||
201 | 186 | ||
202 | ======================================================================*/ | 187 | ======================================================================*/ |
203 | 188 | ||
204 | static void axnet_detach(dev_link_t *link) | 189 | static void axnet_detach(struct pcmcia_device *p_dev) |
205 | { | 190 | { |
191 | dev_link_t *link = dev_to_instance(p_dev); | ||
206 | struct net_device *dev = link->priv; | 192 | struct net_device *dev = link->priv; |
207 | dev_link_t **linkp; | ||
208 | 193 | ||
209 | DEBUG(0, "axnet_detach(0x%p)\n", link); | 194 | DEBUG(0, "axnet_detach(0x%p)\n", link); |
210 | 195 | ||
211 | /* Locate device structure */ | ||
212 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
213 | if (*linkp == link) break; | ||
214 | if (*linkp == NULL) | ||
215 | return; | ||
216 | |||
217 | if (link->dev) | 196 | if (link->dev) |
218 | unregister_netdev(dev); | 197 | unregister_netdev(dev); |
219 | 198 | ||
220 | if (link->state & DEV_CONFIG) | 199 | if (link->state & DEV_CONFIG) |
221 | axnet_release(link); | 200 | axnet_release(link); |
222 | 201 | ||
223 | if (link->handle) | ||
224 | pcmcia_deregister_client(link->handle); | ||
225 | |||
226 | /* Unlink device structure, free bits */ | ||
227 | *linkp = link->next; | ||
228 | free_netdev(dev); | 202 | free_netdev(dev); |
229 | } /* axnet_detach */ | 203 | } /* axnet_detach */ |
230 | 204 | ||
@@ -490,59 +464,39 @@ static void axnet_release(dev_link_t *link) | |||
490 | link->state &= ~DEV_CONFIG; | 464 | link->state &= ~DEV_CONFIG; |
491 | } | 465 | } |
492 | 466 | ||
493 | /*====================================================================== | 467 | static int axnet_suspend(struct pcmcia_device *p_dev) |
494 | |||
495 | The card status event handler. Mostly, this schedules other | ||
496 | stuff to run after an event is received. A CARD_REMOVAL event | ||
497 | also sets some flags to discourage the net drivers from trying | ||
498 | to talk to the card any more. | ||
499 | |||
500 | ======================================================================*/ | ||
501 | |||
502 | static int axnet_event(event_t event, int priority, | ||
503 | event_callback_args_t *args) | ||
504 | { | 468 | { |
505 | dev_link_t *link = args->client_data; | 469 | dev_link_t *link = dev_to_instance(p_dev); |
506 | struct net_device *dev = link->priv; | 470 | struct net_device *dev = link->priv; |
507 | 471 | ||
508 | DEBUG(2, "axnet_event(0x%06x)\n", event); | ||
509 | |||
510 | switch (event) { | ||
511 | case CS_EVENT_CARD_REMOVAL: | ||
512 | link->state &= ~DEV_PRESENT; | ||
513 | if (link->state & DEV_CONFIG) | ||
514 | netif_device_detach(dev); | ||
515 | break; | ||
516 | case CS_EVENT_CARD_INSERTION: | ||
517 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
518 | axnet_config(link); | ||
519 | break; | ||
520 | case CS_EVENT_PM_SUSPEND: | ||
521 | link->state |= DEV_SUSPEND; | 472 | link->state |= DEV_SUSPEND; |
522 | /* Fall through... */ | ||
523 | case CS_EVENT_RESET_PHYSICAL: | ||
524 | if (link->state & DEV_CONFIG) { | 473 | if (link->state & DEV_CONFIG) { |
525 | if (link->open) | 474 | if (link->open) |
526 | netif_device_detach(dev); | 475 | netif_device_detach(dev); |
527 | pcmcia_release_configuration(link->handle); | 476 | pcmcia_release_configuration(link->handle); |
528 | } | 477 | } |
529 | break; | 478 | |
530 | case CS_EVENT_PM_RESUME: | 479 | return 0; |
480 | } | ||
481 | |||
482 | static int axnet_resume(struct pcmcia_device *p_dev) | ||
483 | { | ||
484 | dev_link_t *link = dev_to_instance(p_dev); | ||
485 | struct net_device *dev = link->priv; | ||
486 | |||
531 | link->state &= ~DEV_SUSPEND; | 487 | link->state &= ~DEV_SUSPEND; |
532 | /* Fall through... */ | ||
533 | case CS_EVENT_CARD_RESET: | ||
534 | if (link->state & DEV_CONFIG) { | 488 | if (link->state & DEV_CONFIG) { |
535 | pcmcia_request_configuration(link->handle, &link->conf); | 489 | pcmcia_request_configuration(link->handle, &link->conf); |
536 | if (link->open) { | 490 | if (link->open) { |
537 | axnet_reset_8390(dev); | 491 | axnet_reset_8390(dev); |
538 | AX88190_init(dev, 1); | 492 | AX88190_init(dev, 1); |
539 | netif_device_attach(dev); | 493 | netif_device_attach(dev); |
540 | } | 494 | } |
541 | } | 495 | } |
542 | break; | 496 | |
543 | } | 497 | return 0; |
544 | return 0; | 498 | } |
545 | } /* axnet_event */ | 499 | |
546 | 500 | ||
547 | /*====================================================================== | 501 | /*====================================================================== |
548 | 502 | ||
@@ -616,7 +570,7 @@ static int axnet_open(struct net_device *dev) | |||
616 | 570 | ||
617 | link->open++; | 571 | link->open++; |
618 | 572 | ||
619 | request_irq(dev->irq, ei_irq_wrapper, SA_SHIRQ, dev_info, dev); | 573 | request_irq(dev->irq, ei_irq_wrapper, SA_SHIRQ, "axnet_cs", dev); |
620 | 574 | ||
621 | info->link_status = 0x00; | 575 | info->link_status = 0x00; |
622 | init_timer(&info->watchdog); | 576 | init_timer(&info->watchdog); |
@@ -877,10 +831,11 @@ static struct pcmcia_driver axnet_cs_driver = { | |||
877 | .drv = { | 831 | .drv = { |
878 | .name = "axnet_cs", | 832 | .name = "axnet_cs", |
879 | }, | 833 | }, |
880 | .attach = axnet_attach, | 834 | .probe = axnet_attach, |
881 | .event = axnet_event, | 835 | .remove = axnet_detach, |
882 | .detach = axnet_detach, | ||
883 | .id_table = axnet_ids, | 836 | .id_table = axnet_ids, |
837 | .suspend = axnet_suspend, | ||
838 | .resume = axnet_resume, | ||
884 | }; | 839 | }; |
885 | 840 | ||
886 | static int __init init_axnet_cs(void) | 841 | static int __init init_axnet_cs(void) |
@@ -891,7 +846,6 @@ static int __init init_axnet_cs(void) | |||
891 | static void __exit exit_axnet_cs(void) | 846 | static void __exit exit_axnet_cs(void) |
892 | { | 847 | { |
893 | pcmcia_unregister_driver(&axnet_cs_driver); | 848 | pcmcia_unregister_driver(&axnet_cs_driver); |
894 | BUG_ON(dev_list != NULL); | ||
895 | } | 849 | } |
896 | 850 | ||
897 | module_init(init_axnet_cs); | 851 | module_init(init_axnet_cs); |
diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c index b9355d9498a3..2827a48ea37c 100644 --- a/drivers/net/pcmcia/com20020_cs.c +++ b/drivers/net/pcmcia/com20020_cs.c | |||
@@ -120,15 +120,8 @@ MODULE_LICENSE("GPL"); | |||
120 | 120 | ||
121 | static void com20020_config(dev_link_t *link); | 121 | static void com20020_config(dev_link_t *link); |
122 | static void com20020_release(dev_link_t *link); | 122 | static void com20020_release(dev_link_t *link); |
123 | static int com20020_event(event_t event, int priority, | ||
124 | event_callback_args_t *args); | ||
125 | 123 | ||
126 | static dev_info_t dev_info = "com20020_cs"; | 124 | static void com20020_detach(struct pcmcia_device *p_dev); |
127 | |||
128 | static dev_link_t *com20020_attach(void); | ||
129 | static void com20020_detach(dev_link_t *); | ||
130 | |||
131 | static dev_link_t *dev_list; | ||
132 | 125 | ||
133 | /*====================================================================*/ | 126 | /*====================================================================*/ |
134 | 127 | ||
@@ -145,21 +138,19 @@ typedef struct com20020_dev_t { | |||
145 | 138 | ||
146 | ======================================================================*/ | 139 | ======================================================================*/ |
147 | 140 | ||
148 | static dev_link_t *com20020_attach(void) | 141 | static int com20020_attach(struct pcmcia_device *p_dev) |
149 | { | 142 | { |
150 | client_reg_t client_reg; | ||
151 | dev_link_t *link; | 143 | dev_link_t *link; |
152 | com20020_dev_t *info; | 144 | com20020_dev_t *info; |
153 | struct net_device *dev; | 145 | struct net_device *dev; |
154 | int ret; | ||
155 | struct arcnet_local *lp; | 146 | struct arcnet_local *lp; |
156 | 147 | ||
157 | DEBUG(0, "com20020_attach()\n"); | 148 | DEBUG(0, "com20020_attach()\n"); |
158 | 149 | ||
159 | /* Create new network device */ | 150 | /* Create new network device */ |
160 | link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); | 151 | link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); |
161 | if (!link) | 152 | if (!link) |
162 | return NULL; | 153 | return -ENOMEM; |
163 | 154 | ||
164 | info = kmalloc(sizeof(struct com20020_dev_t), GFP_KERNEL); | 155 | info = kmalloc(sizeof(struct com20020_dev_t), GFP_KERNEL); |
165 | if (!info) | 156 | if (!info) |
@@ -191,30 +182,19 @@ static dev_link_t *com20020_attach(void) | |||
191 | link->conf.IntType = INT_MEMORY_AND_IO; | 182 | link->conf.IntType = INT_MEMORY_AND_IO; |
192 | link->conf.Present = PRESENT_OPTION; | 183 | link->conf.Present = PRESENT_OPTION; |
193 | 184 | ||
194 | |||
195 | link->irq.Instance = info->dev = dev; | 185 | link->irq.Instance = info->dev = dev; |
196 | link->priv = info; | 186 | link->priv = info; |
197 | 187 | ||
198 | /* Register with Card Services */ | 188 | link->state |= DEV_PRESENT; |
199 | link->next = dev_list; | 189 | com20020_config(link); |
200 | dev_list = link; | ||
201 | client_reg.dev_info = &dev_info; | ||
202 | client_reg.Version = 0x0210; | ||
203 | client_reg.event_callback_args.client_data = link; | ||
204 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
205 | if (ret != 0) { | ||
206 | cs_error(link->handle, RegisterClient, ret); | ||
207 | com20020_detach(link); | ||
208 | return NULL; | ||
209 | } | ||
210 | 190 | ||
211 | return link; | 191 | return 0; |
212 | 192 | ||
213 | fail_alloc_dev: | 193 | fail_alloc_dev: |
214 | kfree(info); | 194 | kfree(info); |
215 | fail_alloc_info: | 195 | fail_alloc_info: |
216 | kfree(link); | 196 | kfree(link); |
217 | return NULL; | 197 | return -ENOMEM; |
218 | } /* com20020_attach */ | 198 | } /* com20020_attach */ |
219 | 199 | ||
220 | /*====================================================================== | 200 | /*====================================================================== |
@@ -226,29 +206,21 @@ fail_alloc_info: | |||
226 | 206 | ||
227 | ======================================================================*/ | 207 | ======================================================================*/ |
228 | 208 | ||
229 | static void com20020_detach(dev_link_t *link) | 209 | static void com20020_detach(struct pcmcia_device *p_dev) |
230 | { | 210 | { |
211 | dev_link_t *link = dev_to_instance(p_dev); | ||
231 | struct com20020_dev_t *info = link->priv; | 212 | struct com20020_dev_t *info = link->priv; |
232 | dev_link_t **linkp; | 213 | struct net_device *dev = info->dev; |
233 | struct net_device *dev; | 214 | |
234 | |||
235 | DEBUG(1,"detach...\n"); | 215 | DEBUG(1,"detach...\n"); |
236 | 216 | ||
237 | DEBUG(0, "com20020_detach(0x%p)\n", link); | 217 | DEBUG(0, "com20020_detach(0x%p)\n", link); |
238 | 218 | ||
239 | /* Locate device structure */ | ||
240 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
241 | if (*linkp == link) break; | ||
242 | if (*linkp == NULL) | ||
243 | return; | ||
244 | |||
245 | dev = info->dev; | ||
246 | |||
247 | if (link->dev) { | 219 | if (link->dev) { |
248 | DEBUG(1,"unregister...\n"); | 220 | DEBUG(1,"unregister...\n"); |
249 | 221 | ||
250 | unregister_netdev(dev); | 222 | unregister_netdev(dev); |
251 | 223 | ||
252 | /* | 224 | /* |
253 | * this is necessary because we register our IRQ separately | 225 | * this is necessary because we register our IRQ separately |
254 | * from card services. | 226 | * from card services. |
@@ -260,12 +232,8 @@ static void com20020_detach(dev_link_t *link) | |||
260 | if (link->state & DEV_CONFIG) | 232 | if (link->state & DEV_CONFIG) |
261 | com20020_release(link); | 233 | com20020_release(link); |
262 | 234 | ||
263 | if (link->handle) | ||
264 | pcmcia_deregister_client(link->handle); | ||
265 | |||
266 | /* Unlink device structure, free bits */ | 235 | /* Unlink device structure, free bits */ |
267 | DEBUG(1,"unlinking...\n"); | 236 | DEBUG(1,"unlinking...\n"); |
268 | *linkp = link->next; | ||
269 | if (link->priv) | 237 | if (link->priv) |
270 | { | 238 | { |
271 | dev = info->dev; | 239 | dev = info->dev; |
@@ -421,61 +389,41 @@ static void com20020_release(dev_link_t *link) | |||
421 | link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING); | 389 | link->state &= ~(DEV_CONFIG | DEV_RELEASE_PENDING); |
422 | } | 390 | } |
423 | 391 | ||
424 | /*====================================================================== | 392 | static int com20020_suspend(struct pcmcia_device *p_dev) |
393 | { | ||
394 | dev_link_t *link = dev_to_instance(p_dev); | ||
395 | com20020_dev_t *info = link->priv; | ||
396 | struct net_device *dev = info->dev; | ||
425 | 397 | ||
426 | The card status event handler. Mostly, this schedules other | 398 | link->state |= DEV_SUSPEND; |
427 | stuff to run after an event is received. A CARD_REMOVAL event | 399 | if (link->state & DEV_CONFIG) { |
428 | also sets some flags to discourage the net drivers from trying | 400 | if (link->open) { |
429 | to talk to the card any more. | 401 | netif_device_detach(dev); |
402 | } | ||
403 | pcmcia_release_configuration(link->handle); | ||
404 | } | ||
430 | 405 | ||
431 | ======================================================================*/ | 406 | return 0; |
407 | } | ||
432 | 408 | ||
433 | static int com20020_event(event_t event, int priority, | 409 | static int com20020_resume(struct pcmcia_device *p_dev) |
434 | event_callback_args_t *args) | ||
435 | { | 410 | { |
436 | dev_link_t *link = args->client_data; | 411 | dev_link_t *link = dev_to_instance(p_dev); |
437 | com20020_dev_t *info = link->priv; | 412 | com20020_dev_t *info = link->priv; |
438 | struct net_device *dev = info->dev; | 413 | struct net_device *dev = info->dev; |
439 | 414 | ||
440 | DEBUG(1, "com20020_event(0x%06x)\n", event); | 415 | link->state &= ~DEV_SUSPEND; |
441 | |||
442 | switch (event) { | ||
443 | case CS_EVENT_CARD_REMOVAL: | ||
444 | link->state &= ~DEV_PRESENT; | ||
445 | if (link->state & DEV_CONFIG) | ||
446 | netif_device_detach(dev); | ||
447 | break; | ||
448 | case CS_EVENT_CARD_INSERTION: | ||
449 | link->state |= DEV_PRESENT; | ||
450 | com20020_config(link); | ||
451 | break; | ||
452 | case CS_EVENT_PM_SUSPEND: | ||
453 | link->state |= DEV_SUSPEND; | ||
454 | /* Fall through... */ | ||
455 | case CS_EVENT_RESET_PHYSICAL: | ||
456 | if (link->state & DEV_CONFIG) { | ||
457 | if (link->open) { | ||
458 | netif_device_detach(dev); | ||
459 | } | ||
460 | pcmcia_release_configuration(link->handle); | ||
461 | } | ||
462 | break; | ||
463 | case CS_EVENT_PM_RESUME: | ||
464 | link->state &= ~DEV_SUSPEND; | ||
465 | /* Fall through... */ | ||
466 | case CS_EVENT_CARD_RESET: | ||
467 | if (link->state & DEV_CONFIG) { | 416 | if (link->state & DEV_CONFIG) { |
468 | pcmcia_request_configuration(link->handle, &link->conf); | 417 | pcmcia_request_configuration(link->handle, &link->conf); |
469 | if (link->open) { | 418 | if (link->open) { |
470 | int ioaddr = dev->base_addr; | 419 | int ioaddr = dev->base_addr; |
471 | struct arcnet_local *lp = dev->priv; | 420 | struct arcnet_local *lp = dev->priv; |
472 | ARCRESET; | 421 | ARCRESET; |
473 | } | 422 | } |
474 | } | 423 | } |
475 | break; | 424 | |
476 | } | 425 | return 0; |
477 | return 0; | 426 | } |
478 | } /* com20020_event */ | ||
479 | 427 | ||
480 | static struct pcmcia_device_id com20020_ids[] = { | 428 | static struct pcmcia_device_id com20020_ids[] = { |
481 | PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.", "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf), | 429 | PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.", "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf), |
@@ -488,10 +436,11 @@ static struct pcmcia_driver com20020_cs_driver = { | |||
488 | .drv = { | 436 | .drv = { |
489 | .name = "com20020_cs", | 437 | .name = "com20020_cs", |
490 | }, | 438 | }, |
491 | .attach = com20020_attach, | 439 | .probe = com20020_attach, |
492 | .event = com20020_event, | 440 | .remove = com20020_detach, |
493 | .detach = com20020_detach, | ||
494 | .id_table = com20020_ids, | 441 | .id_table = com20020_ids, |
442 | .suspend = com20020_suspend, | ||
443 | .resume = com20020_resume, | ||
495 | }; | 444 | }; |
496 | 445 | ||
497 | static int __init init_com20020_cs(void) | 446 | static int __init init_com20020_cs(void) |
@@ -502,7 +451,6 @@ static int __init init_com20020_cs(void) | |||
502 | static void __exit exit_com20020_cs(void) | 451 | static void __exit exit_com20020_cs(void) |
503 | { | 452 | { |
504 | pcmcia_unregister_driver(&com20020_cs_driver); | 453 | pcmcia_unregister_driver(&com20020_cs_driver); |
505 | BUG_ON(dev_list != NULL); | ||
506 | } | 454 | } |
507 | 455 | ||
508 | module_init(init_com20020_cs); | 456 | module_init(init_com20020_cs); |
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 356f50909222..28fe2fb4d6c0 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c | |||
@@ -88,10 +88,7 @@ static void fmvj18x_config(dev_link_t *link); | |||
88 | static int fmvj18x_get_hwinfo(dev_link_t *link, u_char *node_id); | 88 | static int fmvj18x_get_hwinfo(dev_link_t *link, u_char *node_id); |
89 | static int fmvj18x_setup_mfc(dev_link_t *link); | 89 | static int fmvj18x_setup_mfc(dev_link_t *link); |
90 | static void fmvj18x_release(dev_link_t *link); | 90 | static void fmvj18x_release(dev_link_t *link); |
91 | static int fmvj18x_event(event_t event, int priority, | 91 | static void fmvj18x_detach(struct pcmcia_device *p_dev); |
92 | event_callback_args_t *args); | ||
93 | static dev_link_t *fmvj18x_attach(void); | ||
94 | static void fmvj18x_detach(dev_link_t *); | ||
95 | 92 | ||
96 | /* | 93 | /* |
97 | LAN controller(MBH86960A) specific routines | 94 | LAN controller(MBH86960A) specific routines |
@@ -108,9 +105,6 @@ static void set_rx_mode(struct net_device *dev); | |||
108 | static void fjn_tx_timeout(struct net_device *dev); | 105 | static void fjn_tx_timeout(struct net_device *dev); |
109 | static struct ethtool_ops netdev_ethtool_ops; | 106 | static struct ethtool_ops netdev_ethtool_ops; |
110 | 107 | ||
111 | static dev_info_t dev_info = "fmvj18x_cs"; | ||
112 | static dev_link_t *dev_list; | ||
113 | |||
114 | /* | 108 | /* |
115 | card type | 109 | card type |
116 | */ | 110 | */ |
@@ -234,20 +228,18 @@ typedef struct local_info_t { | |||
234 | #define BANK_1U 0x24 /* bank 1 (CONFIG_1) */ | 228 | #define BANK_1U 0x24 /* bank 1 (CONFIG_1) */ |
235 | #define BANK_2U 0x28 /* bank 2 (CONFIG_1) */ | 229 | #define BANK_2U 0x28 /* bank 2 (CONFIG_1) */ |
236 | 230 | ||
237 | static dev_link_t *fmvj18x_attach(void) | 231 | static int fmvj18x_attach(struct pcmcia_device *p_dev) |
238 | { | 232 | { |
239 | local_info_t *lp; | 233 | local_info_t *lp; |
240 | dev_link_t *link; | 234 | dev_link_t *link; |
241 | struct net_device *dev; | 235 | struct net_device *dev; |
242 | client_reg_t client_reg; | 236 | |
243 | int ret; | ||
244 | |||
245 | DEBUG(0, "fmvj18x_attach()\n"); | 237 | DEBUG(0, "fmvj18x_attach()\n"); |
246 | 238 | ||
247 | /* Make up a FMVJ18x specific data structure */ | 239 | /* Make up a FMVJ18x specific data structure */ |
248 | dev = alloc_etherdev(sizeof(local_info_t)); | 240 | dev = alloc_etherdev(sizeof(local_info_t)); |
249 | if (!dev) | 241 | if (!dev) |
250 | return NULL; | 242 | return -ENOMEM; |
251 | lp = netdev_priv(dev); | 243 | lp = netdev_priv(dev); |
252 | link = &lp->link; | 244 | link = &lp->link; |
253 | link->priv = dev; | 245 | link->priv = dev; |
@@ -262,7 +254,7 @@ static dev_link_t *fmvj18x_attach(void) | |||
262 | link->irq.IRQInfo1 = IRQ_LEVEL_ID; | 254 | link->irq.IRQInfo1 = IRQ_LEVEL_ID; |
263 | link->irq.Handler = &fjn_interrupt; | 255 | link->irq.Handler = &fjn_interrupt; |
264 | link->irq.Instance = dev; | 256 | link->irq.Instance = dev; |
265 | 257 | ||
266 | /* General socket configuration */ | 258 | /* General socket configuration */ |
267 | link->conf.Attributes = CONF_ENABLE_IRQ; | 259 | link->conf.Attributes = CONF_ENABLE_IRQ; |
268 | link->conf.Vcc = 50; | 260 | link->conf.Vcc = 50; |
@@ -281,37 +273,24 @@ static dev_link_t *fmvj18x_attach(void) | |||
281 | dev->watchdog_timeo = TX_TIMEOUT; | 273 | dev->watchdog_timeo = TX_TIMEOUT; |
282 | #endif | 274 | #endif |
283 | SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); | 275 | SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); |
284 | |||
285 | /* Register with Card Services */ | ||
286 | link->next = dev_list; | ||
287 | dev_list = link; | ||
288 | client_reg.dev_info = &dev_info; | ||
289 | client_reg.Version = 0x0210; | ||
290 | client_reg.event_callback_args.client_data = link; | ||
291 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
292 | if (ret != 0) { | ||
293 | cs_error(link->handle, RegisterClient, ret); | ||
294 | fmvj18x_detach(link); | ||
295 | return NULL; | ||
296 | } | ||
297 | 276 | ||
298 | return link; | 277 | link->handle = p_dev; |
278 | p_dev->instance = link; | ||
279 | |||
280 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
281 | fmvj18x_config(link); | ||
282 | |||
283 | return 0; | ||
299 | } /* fmvj18x_attach */ | 284 | } /* fmvj18x_attach */ |
300 | 285 | ||
301 | /*====================================================================*/ | 286 | /*====================================================================*/ |
302 | 287 | ||
303 | static void fmvj18x_detach(dev_link_t *link) | 288 | static void fmvj18x_detach(struct pcmcia_device *p_dev) |
304 | { | 289 | { |
290 | dev_link_t *link = dev_to_instance(p_dev); | ||
305 | struct net_device *dev = link->priv; | 291 | struct net_device *dev = link->priv; |
306 | dev_link_t **linkp; | 292 | |
307 | |||
308 | DEBUG(0, "fmvj18x_detach(0x%p)\n", link); | 293 | DEBUG(0, "fmvj18x_detach(0x%p)\n", link); |
309 | |||
310 | /* Locate device structure */ | ||
311 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
312 | if (*linkp == link) break; | ||
313 | if (*linkp == NULL) | ||
314 | return; | ||
315 | 294 | ||
316 | if (link->dev) | 295 | if (link->dev) |
317 | unregister_netdev(dev); | 296 | unregister_netdev(dev); |
@@ -319,12 +298,6 @@ static void fmvj18x_detach(dev_link_t *link) | |||
319 | if (link->state & DEV_CONFIG) | 298 | if (link->state & DEV_CONFIG) |
320 | fmvj18x_release(link); | 299 | fmvj18x_release(link); |
321 | 300 | ||
322 | /* Break the link with Card Services */ | ||
323 | if (link->handle) | ||
324 | pcmcia_deregister_client(link->handle); | ||
325 | |||
326 | /* Unlink device structure, free pieces */ | ||
327 | *linkp = link->next; | ||
328 | free_netdev(dev); | 301 | free_netdev(dev); |
329 | } /* fmvj18x_detach */ | 302 | } /* fmvj18x_detach */ |
330 | 303 | ||
@@ -713,51 +686,40 @@ static void fmvj18x_release(dev_link_t *link) | |||
713 | link->state &= ~DEV_CONFIG; | 686 | link->state &= ~DEV_CONFIG; |
714 | } | 687 | } |
715 | 688 | ||
716 | /*====================================================================*/ | 689 | static int fmvj18x_suspend(struct pcmcia_device *p_dev) |
717 | |||
718 | static int fmvj18x_event(event_t event, int priority, | ||
719 | event_callback_args_t *args) | ||
720 | { | 690 | { |
721 | dev_link_t *link = args->client_data; | 691 | dev_link_t *link = dev_to_instance(p_dev); |
722 | struct net_device *dev = link->priv; | 692 | struct net_device *dev = link->priv; |
723 | 693 | ||
724 | DEBUG(1, "fmvj18x_event(0x%06x)\n", event); | ||
725 | |||
726 | switch (event) { | ||
727 | case CS_EVENT_CARD_REMOVAL: | ||
728 | link->state &= ~DEV_PRESENT; | ||
729 | if (link->state & DEV_CONFIG) | ||
730 | netif_device_detach(dev); | ||
731 | break; | ||
732 | case CS_EVENT_CARD_INSERTION: | ||
733 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
734 | fmvj18x_config(link); | ||
735 | break; | ||
736 | case CS_EVENT_PM_SUSPEND: | ||
737 | link->state |= DEV_SUSPEND; | 694 | link->state |= DEV_SUSPEND; |
738 | /* Fall through... */ | ||
739 | case CS_EVENT_RESET_PHYSICAL: | ||
740 | if (link->state & DEV_CONFIG) { | 695 | if (link->state & DEV_CONFIG) { |
741 | if (link->open) | 696 | if (link->open) |
742 | netif_device_detach(dev); | 697 | netif_device_detach(dev); |
743 | pcmcia_release_configuration(link->handle); | 698 | pcmcia_release_configuration(link->handle); |
744 | } | 699 | } |
745 | break; | 700 | |
746 | case CS_EVENT_PM_RESUME: | 701 | |
702 | return 0; | ||
703 | } | ||
704 | |||
705 | static int fmvj18x_resume(struct pcmcia_device *p_dev) | ||
706 | { | ||
707 | dev_link_t *link = dev_to_instance(p_dev); | ||
708 | struct net_device *dev = link->priv; | ||
709 | |||
747 | link->state &= ~DEV_SUSPEND; | 710 | link->state &= ~DEV_SUSPEND; |
748 | /* Fall through... */ | ||
749 | case CS_EVENT_CARD_RESET: | ||
750 | if (link->state & DEV_CONFIG) { | 711 | if (link->state & DEV_CONFIG) { |
751 | pcmcia_request_configuration(link->handle, &link->conf); | 712 | pcmcia_request_configuration(link->handle, &link->conf); |
752 | if (link->open) { | 713 | if (link->open) { |
753 | fjn_reset(dev); | 714 | fjn_reset(dev); |
754 | netif_device_attach(dev); | 715 | netif_device_attach(dev); |
755 | } | 716 | } |
756 | } | 717 | } |
757 | break; | 718 | |
758 | } | 719 | return 0; |
759 | return 0; | 720 | } |
760 | } /* fmvj18x_event */ | 721 | |
722 | /*====================================================================*/ | ||
761 | 723 | ||
762 | static struct pcmcia_device_id fmvj18x_ids[] = { | 724 | static struct pcmcia_device_id fmvj18x_ids[] = { |
763 | PCMCIA_DEVICE_MANF_CARD(0x0004, 0x0004), | 725 | PCMCIA_DEVICE_MANF_CARD(0x0004, 0x0004), |
@@ -789,10 +751,11 @@ static struct pcmcia_driver fmvj18x_cs_driver = { | |||
789 | .drv = { | 751 | .drv = { |
790 | .name = "fmvj18x_cs", | 752 | .name = "fmvj18x_cs", |
791 | }, | 753 | }, |
792 | .attach = fmvj18x_attach, | 754 | .probe = fmvj18x_attach, |
793 | .event = fmvj18x_event, | 755 | .remove = fmvj18x_detach, |
794 | .detach = fmvj18x_detach, | ||
795 | .id_table = fmvj18x_ids, | 756 | .id_table = fmvj18x_ids, |
757 | .suspend = fmvj18x_suspend, | ||
758 | .resume = fmvj18x_resume, | ||
796 | }; | 759 | }; |
797 | 760 | ||
798 | static int __init init_fmvj18x_cs(void) | 761 | static int __init init_fmvj18x_cs(void) |
@@ -803,7 +766,6 @@ static int __init init_fmvj18x_cs(void) | |||
803 | static void __exit exit_fmvj18x_cs(void) | 766 | static void __exit exit_fmvj18x_cs(void) |
804 | { | 767 | { |
805 | pcmcia_unregister_driver(&fmvj18x_cs_driver); | 768 | pcmcia_unregister_driver(&fmvj18x_cs_driver); |
806 | BUG_ON(dev_list != NULL); | ||
807 | } | 769 | } |
808 | 770 | ||
809 | module_init(init_fmvj18x_cs); | 771 | module_init(init_fmvj18x_cs); |
diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c index b6c140eb9799..b9c7e39576f5 100644 --- a/drivers/net/pcmcia/ibmtr_cs.c +++ b/drivers/net/pcmcia/ibmtr_cs.c | |||
@@ -108,15 +108,7 @@ MODULE_LICENSE("GPL"); | |||
108 | static void ibmtr_config(dev_link_t *link); | 108 | static void ibmtr_config(dev_link_t *link); |
109 | static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase); | 109 | static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase); |
110 | static void ibmtr_release(dev_link_t *link); | 110 | static void ibmtr_release(dev_link_t *link); |
111 | static int ibmtr_event(event_t event, int priority, | 111 | static void ibmtr_detach(struct pcmcia_device *p_dev); |
112 | event_callback_args_t *args); | ||
113 | |||
114 | static dev_info_t dev_info = "ibmtr_cs"; | ||
115 | |||
116 | static dev_link_t *ibmtr_attach(void); | ||
117 | static void ibmtr_detach(dev_link_t *); | ||
118 | |||
119 | static dev_link_t *dev_list; | ||
120 | 112 | ||
121 | /*====================================================================*/ | 113 | /*====================================================================*/ |
122 | 114 | ||
@@ -146,25 +138,23 @@ static struct ethtool_ops netdev_ethtool_ops = { | |||
146 | 138 | ||
147 | ======================================================================*/ | 139 | ======================================================================*/ |
148 | 140 | ||
149 | static dev_link_t *ibmtr_attach(void) | 141 | static int ibmtr_attach(struct pcmcia_device *p_dev) |
150 | { | 142 | { |
151 | ibmtr_dev_t *info; | 143 | ibmtr_dev_t *info; |
152 | dev_link_t *link; | 144 | dev_link_t *link; |
153 | struct net_device *dev; | 145 | struct net_device *dev; |
154 | client_reg_t client_reg; | ||
155 | int ret; | ||
156 | 146 | ||
157 | DEBUG(0, "ibmtr_attach()\n"); | 147 | DEBUG(0, "ibmtr_attach()\n"); |
158 | 148 | ||
159 | /* Create new token-ring device */ | 149 | /* Create new token-ring device */ |
160 | info = kmalloc(sizeof(*info), GFP_KERNEL); | 150 | info = kmalloc(sizeof(*info), GFP_KERNEL); |
161 | if (!info) return NULL; | 151 | if (!info) return -ENOMEM; |
162 | memset(info,0,sizeof(*info)); | 152 | memset(info,0,sizeof(*info)); |
163 | dev = alloc_trdev(sizeof(struct tok_info)); | 153 | dev = alloc_trdev(sizeof(struct tok_info)); |
164 | if (!dev) { | 154 | if (!dev) { |
165 | kfree(info); | 155 | kfree(info); |
166 | return NULL; | 156 | return -ENOMEM; |
167 | } | 157 | } |
168 | 158 | ||
169 | link = &info->link; | 159 | link = &info->link; |
170 | link->priv = info; | 160 | link->priv = info; |
@@ -185,25 +175,13 @@ static dev_link_t *ibmtr_attach(void) | |||
185 | 175 | ||
186 | SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); | 176 | SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); |
187 | 177 | ||
188 | /* Register with Card Services */ | 178 | link->handle = p_dev; |
189 | link->next = dev_list; | 179 | p_dev->instance = link; |
190 | dev_list = link; | ||
191 | client_reg.dev_info = &dev_info; | ||
192 | client_reg.Version = 0x0210; | ||
193 | client_reg.event_callback_args.client_data = link; | ||
194 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
195 | if (ret != 0) { | ||
196 | cs_error(link->handle, RegisterClient, ret); | ||
197 | goto out_detach; | ||
198 | } | ||
199 | 180 | ||
200 | out: | 181 | link->state |= DEV_PRESENT; |
201 | return link; | 182 | ibmtr_config(link); |
202 | 183 | ||
203 | out_detach: | 184 | return 0; |
204 | ibmtr_detach(link); | ||
205 | link = NULL; | ||
206 | goto out; | ||
207 | } /* ibmtr_attach */ | 185 | } /* ibmtr_attach */ |
208 | 186 | ||
209 | /*====================================================================== | 187 | /*====================================================================== |
@@ -215,22 +193,14 @@ out_detach: | |||
215 | 193 | ||
216 | ======================================================================*/ | 194 | ======================================================================*/ |
217 | 195 | ||
218 | static void ibmtr_detach(dev_link_t *link) | 196 | static void ibmtr_detach(struct pcmcia_device *p_dev) |
219 | { | 197 | { |
198 | dev_link_t *link = dev_to_instance(p_dev); | ||
220 | struct ibmtr_dev_t *info = link->priv; | 199 | struct ibmtr_dev_t *info = link->priv; |
221 | dev_link_t **linkp; | 200 | struct net_device *dev = info->dev; |
222 | struct net_device *dev; | ||
223 | 201 | ||
224 | DEBUG(0, "ibmtr_detach(0x%p)\n", link); | 202 | DEBUG(0, "ibmtr_detach(0x%p)\n", link); |
225 | 203 | ||
226 | /* Locate device structure */ | ||
227 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
228 | if (*linkp == link) break; | ||
229 | if (*linkp == NULL) | ||
230 | return; | ||
231 | |||
232 | dev = info->dev; | ||
233 | |||
234 | if (link->dev) | 204 | if (link->dev) |
235 | unregister_netdev(dev); | 205 | unregister_netdev(dev); |
236 | 206 | ||
@@ -241,13 +211,8 @@ static void ibmtr_detach(dev_link_t *link) | |||
241 | if (link->state & DEV_CONFIG) | 211 | if (link->state & DEV_CONFIG) |
242 | ibmtr_release(link); | 212 | ibmtr_release(link); |
243 | 213 | ||
244 | if (link->handle) | ||
245 | pcmcia_deregister_client(link->handle); | ||
246 | |||
247 | /* Unlink device structure, free bits */ | ||
248 | *linkp = link->next; | ||
249 | free_netdev(dev); | 214 | free_netdev(dev); |
250 | kfree(info); | 215 | kfree(info); |
251 | } /* ibmtr_detach */ | 216 | } /* ibmtr_detach */ |
252 | 217 | ||
253 | /*====================================================================== | 218 | /*====================================================================== |
@@ -401,63 +366,40 @@ static void ibmtr_release(dev_link_t *link) | |||
401 | link->state &= ~DEV_CONFIG; | 366 | link->state &= ~DEV_CONFIG; |
402 | } | 367 | } |
403 | 368 | ||
404 | /*====================================================================== | 369 | static int ibmtr_suspend(struct pcmcia_device *p_dev) |
370 | { | ||
371 | dev_link_t *link = dev_to_instance(p_dev); | ||
372 | ibmtr_dev_t *info = link->priv; | ||
373 | struct net_device *dev = info->dev; | ||
405 | 374 | ||
406 | The card status event handler. Mostly, this schedules other | 375 | link->state |= DEV_SUSPEND; |
407 | stuff to run after an event is received. A CARD_REMOVAL event | 376 | if (link->state & DEV_CONFIG) { |
408 | also sets some flags to discourage the net drivers from trying | 377 | if (link->open) |
409 | to talk to the card any more. | 378 | netif_device_detach(dev); |
379 | pcmcia_release_configuration(link->handle); | ||
380 | } | ||
410 | 381 | ||
411 | ======================================================================*/ | 382 | return 0; |
383 | } | ||
412 | 384 | ||
413 | static int ibmtr_event(event_t event, int priority, | 385 | static int ibmtr_resume(struct pcmcia_device *p_dev) |
414 | event_callback_args_t *args) | ||
415 | { | 386 | { |
416 | dev_link_t *link = args->client_data; | 387 | dev_link_t *link = dev_to_instance(p_dev); |
417 | ibmtr_dev_t *info = link->priv; | 388 | ibmtr_dev_t *info = link->priv; |
418 | struct net_device *dev = info->dev; | 389 | struct net_device *dev = info->dev; |
419 | 390 | ||
420 | DEBUG(1, "ibmtr_event(0x%06x)\n", event); | 391 | link->state &= ~DEV_SUSPEND; |
421 | |||
422 | switch (event) { | ||
423 | case CS_EVENT_CARD_REMOVAL: | ||
424 | link->state &= ~DEV_PRESENT; | ||
425 | if (link->state & DEV_CONFIG) { | ||
426 | /* set flag to bypass normal interrupt code */ | ||
427 | struct tok_info *priv = netdev_priv(dev); | ||
428 | priv->sram_phys |= 1; | ||
429 | netif_device_detach(dev); | ||
430 | } | ||
431 | break; | ||
432 | case CS_EVENT_CARD_INSERTION: | ||
433 | link->state |= DEV_PRESENT; | ||
434 | ibmtr_config(link); | ||
435 | break; | ||
436 | case CS_EVENT_PM_SUSPEND: | ||
437 | link->state |= DEV_SUSPEND; | ||
438 | /* Fall through... */ | ||
439 | case CS_EVENT_RESET_PHYSICAL: | ||
440 | if (link->state & DEV_CONFIG) { | 392 | if (link->state & DEV_CONFIG) { |
441 | if (link->open) | 393 | pcmcia_request_configuration(link->handle, &link->conf); |
442 | netif_device_detach(dev); | 394 | if (link->open) { |
443 | pcmcia_release_configuration(link->handle); | 395 | ibmtr_probe(dev); /* really? */ |
396 | netif_device_attach(dev); | ||
397 | } | ||
444 | } | 398 | } |
445 | break; | 399 | |
446 | case CS_EVENT_PM_RESUME: | 400 | return 0; |
447 | link->state &= ~DEV_SUSPEND; | 401 | } |
448 | /* Fall through... */ | 402 | |
449 | case CS_EVENT_CARD_RESET: | ||
450 | if (link->state & DEV_CONFIG) { | ||
451 | pcmcia_request_configuration(link->handle, &link->conf); | ||
452 | if (link->open) { | ||
453 | ibmtr_probe(dev); /* really? */ | ||
454 | netif_device_attach(dev); | ||
455 | } | ||
456 | } | ||
457 | break; | ||
458 | } | ||
459 | return 0; | ||
460 | } /* ibmtr_event */ | ||
461 | 403 | ||
462 | /*====================================================================*/ | 404 | /*====================================================================*/ |
463 | 405 | ||
@@ -514,10 +456,11 @@ static struct pcmcia_driver ibmtr_cs_driver = { | |||
514 | .drv = { | 456 | .drv = { |
515 | .name = "ibmtr_cs", | 457 | .name = "ibmtr_cs", |
516 | }, | 458 | }, |
517 | .attach = ibmtr_attach, | 459 | .probe = ibmtr_attach, |
518 | .event = ibmtr_event, | 460 | .remove = ibmtr_detach, |
519 | .detach = ibmtr_detach, | ||
520 | .id_table = ibmtr_ids, | 461 | .id_table = ibmtr_ids, |
462 | .suspend = ibmtr_suspend, | ||
463 | .resume = ibmtr_resume, | ||
521 | }; | 464 | }; |
522 | 465 | ||
523 | static int __init init_ibmtr_cs(void) | 466 | static int __init init_ibmtr_cs(void) |
@@ -528,7 +471,6 @@ static int __init init_ibmtr_cs(void) | |||
528 | static void __exit exit_ibmtr_cs(void) | 471 | static void __exit exit_ibmtr_cs(void) |
529 | { | 472 | { |
530 | pcmcia_unregister_driver(&ibmtr_cs_driver); | 473 | pcmcia_unregister_driver(&ibmtr_cs_driver); |
531 | BUG_ON(dev_list != NULL); | ||
532 | } | 474 | } |
533 | 475 | ||
534 | module_init(init_ibmtr_cs); | 476 | module_init(init_ibmtr_cs); |
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index 980d7e5d66cb..4a232254a497 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c | |||
@@ -388,9 +388,6 @@ static char *version = | |||
388 | DRV_NAME " " DRV_VERSION " (Roger C. Pao)"; | 388 | DRV_NAME " " DRV_VERSION " (Roger C. Pao)"; |
389 | #endif | 389 | #endif |
390 | 390 | ||
391 | static dev_info_t dev_info="nmclan_cs"; | ||
392 | static dev_link_t *dev_list; | ||
393 | |||
394 | static char *if_names[]={ | 391 | static char *if_names[]={ |
395 | "Auto", "10baseT", "BNC", | 392 | "Auto", "10baseT", "BNC", |
396 | }; | 393 | }; |
@@ -422,8 +419,6 @@ Function Prototypes | |||
422 | 419 | ||
423 | static void nmclan_config(dev_link_t *link); | 420 | static void nmclan_config(dev_link_t *link); |
424 | static void nmclan_release(dev_link_t *link); | 421 | static void nmclan_release(dev_link_t *link); |
425 | static int nmclan_event(event_t event, int priority, | ||
426 | event_callback_args_t *args); | ||
427 | 422 | ||
428 | static void nmclan_reset(struct net_device *dev); | 423 | static void nmclan_reset(struct net_device *dev); |
429 | static int mace_config(struct net_device *dev, struct ifmap *map); | 424 | static int mace_config(struct net_device *dev, struct ifmap *map); |
@@ -439,8 +434,7 @@ static void set_multicast_list(struct net_device *dev); | |||
439 | static struct ethtool_ops netdev_ethtool_ops; | 434 | static struct ethtool_ops netdev_ethtool_ops; |
440 | 435 | ||
441 | 436 | ||
442 | static dev_link_t *nmclan_attach(void); | 437 | static void nmclan_detach(struct pcmcia_device *p_dev); |
443 | static void nmclan_detach(dev_link_t *); | ||
444 | 438 | ||
445 | /* ---------------------------------------------------------------------------- | 439 | /* ---------------------------------------------------------------------------- |
446 | nmclan_attach | 440 | nmclan_attach |
@@ -449,13 +443,11 @@ nmclan_attach | |||
449 | Services. | 443 | Services. |
450 | ---------------------------------------------------------------------------- */ | 444 | ---------------------------------------------------------------------------- */ |
451 | 445 | ||
452 | static dev_link_t *nmclan_attach(void) | 446 | static int nmclan_attach(struct pcmcia_device *p_dev) |
453 | { | 447 | { |
454 | mace_private *lp; | 448 | mace_private *lp; |
455 | dev_link_t *link; | 449 | dev_link_t *link; |
456 | struct net_device *dev; | 450 | struct net_device *dev; |
457 | client_reg_t client_reg; | ||
458 | int ret; | ||
459 | 451 | ||
460 | DEBUG(0, "nmclan_attach()\n"); | 452 | DEBUG(0, "nmclan_attach()\n"); |
461 | DEBUG(1, "%s\n", rcsid); | 453 | DEBUG(1, "%s\n", rcsid); |
@@ -463,7 +455,7 @@ static dev_link_t *nmclan_attach(void) | |||
463 | /* Create new ethernet device */ | 455 | /* Create new ethernet device */ |
464 | dev = alloc_etherdev(sizeof(mace_private)); | 456 | dev = alloc_etherdev(sizeof(mace_private)); |
465 | if (!dev) | 457 | if (!dev) |
466 | return NULL; | 458 | return -ENOMEM; |
467 | lp = netdev_priv(dev); | 459 | lp = netdev_priv(dev); |
468 | link = &lp->link; | 460 | link = &lp->link; |
469 | link->priv = dev; | 461 | link->priv = dev; |
@@ -497,20 +489,13 @@ static dev_link_t *nmclan_attach(void) | |||
497 | dev->watchdog_timeo = TX_TIMEOUT; | 489 | dev->watchdog_timeo = TX_TIMEOUT; |
498 | #endif | 490 | #endif |
499 | 491 | ||
500 | /* Register with Card Services */ | 492 | link->handle = p_dev; |
501 | link->next = dev_list; | 493 | p_dev->instance = link; |
502 | dev_list = link; | 494 | |
503 | client_reg.dev_info = &dev_info; | 495 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
504 | client_reg.Version = 0x0210; | 496 | nmclan_config(link); |
505 | client_reg.event_callback_args.client_data = link; | ||
506 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
507 | if (ret != 0) { | ||
508 | cs_error(link->handle, RegisterClient, ret); | ||
509 | nmclan_detach(link); | ||
510 | return NULL; | ||
511 | } | ||
512 | 497 | ||
513 | return link; | 498 | return 0; |
514 | } /* nmclan_attach */ | 499 | } /* nmclan_attach */ |
515 | 500 | ||
516 | /* ---------------------------------------------------------------------------- | 501 | /* ---------------------------------------------------------------------------- |
@@ -521,30 +506,19 @@ nmclan_detach | |||
521 | when the device is released. | 506 | when the device is released. |
522 | ---------------------------------------------------------------------------- */ | 507 | ---------------------------------------------------------------------------- */ |
523 | 508 | ||
524 | static void nmclan_detach(dev_link_t *link) | 509 | static void nmclan_detach(struct pcmcia_device *p_dev) |
525 | { | 510 | { |
511 | dev_link_t *link = dev_to_instance(p_dev); | ||
526 | struct net_device *dev = link->priv; | 512 | struct net_device *dev = link->priv; |
527 | dev_link_t **linkp; | ||
528 | 513 | ||
529 | DEBUG(0, "nmclan_detach(0x%p)\n", link); | 514 | DEBUG(0, "nmclan_detach(0x%p)\n", link); |
530 | 515 | ||
531 | /* Locate device structure */ | ||
532 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
533 | if (*linkp == link) break; | ||
534 | if (*linkp == NULL) | ||
535 | return; | ||
536 | |||
537 | if (link->dev) | 516 | if (link->dev) |
538 | unregister_netdev(dev); | 517 | unregister_netdev(dev); |
539 | 518 | ||
540 | if (link->state & DEV_CONFIG) | 519 | if (link->state & DEV_CONFIG) |
541 | nmclan_release(link); | 520 | nmclan_release(link); |
542 | 521 | ||
543 | if (link->handle) | ||
544 | pcmcia_deregister_client(link->handle); | ||
545 | |||
546 | /* Unlink device structure, free bits */ | ||
547 | *linkp = link->next; | ||
548 | free_netdev(dev); | 522 | free_netdev(dev); |
549 | } /* nmclan_detach */ | 523 | } /* nmclan_detach */ |
550 | 524 | ||
@@ -801,59 +775,39 @@ static void nmclan_release(dev_link_t *link) | |||
801 | link->state &= ~DEV_CONFIG; | 775 | link->state &= ~DEV_CONFIG; |
802 | } | 776 | } |
803 | 777 | ||
804 | /* ---------------------------------------------------------------------------- | 778 | static int nmclan_suspend(struct pcmcia_device *p_dev) |
805 | nmclan_event | ||
806 | The card status event handler. Mostly, this schedules other | ||
807 | stuff to run after an event is received. A CARD_REMOVAL event | ||
808 | also sets some flags to discourage the net drivers from trying | ||
809 | to talk to the card any more. | ||
810 | ---------------------------------------------------------------------------- */ | ||
811 | static int nmclan_event(event_t event, int priority, | ||
812 | event_callback_args_t *args) | ||
813 | { | 779 | { |
814 | dev_link_t *link = args->client_data; | 780 | dev_link_t *link = dev_to_instance(p_dev); |
815 | struct net_device *dev = link->priv; | 781 | struct net_device *dev = link->priv; |
782 | |||
783 | link->state |= DEV_SUSPEND; | ||
784 | if (link->state & DEV_CONFIG) { | ||
785 | if (link->open) | ||
786 | netif_device_detach(dev); | ||
787 | pcmcia_release_configuration(link->handle); | ||
788 | } | ||
816 | 789 | ||
817 | DEBUG(1, "nmclan_event(0x%06x)\n", event); | ||
818 | 790 | ||
819 | switch (event) { | 791 | return 0; |
820 | case CS_EVENT_CARD_REMOVAL: | 792 | } |
821 | link->state &= ~DEV_PRESENT; | 793 | |
822 | if (link->state & DEV_CONFIG) | 794 | static int nmclan_resume(struct pcmcia_device *p_dev) |
823 | netif_device_detach(dev); | 795 | { |
824 | break; | 796 | dev_link_t *link = dev_to_instance(p_dev); |
825 | case CS_EVENT_CARD_INSERTION: | 797 | struct net_device *dev = link->priv; |
826 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | 798 | |
827 | nmclan_config(link); | 799 | link->state &= ~DEV_SUSPEND; |
828 | break; | 800 | if (link->state & DEV_CONFIG) { |
829 | case CS_EVENT_PM_SUSPEND: | 801 | pcmcia_request_configuration(link->handle, &link->conf); |
830 | link->state |= DEV_SUSPEND; | 802 | if (link->open) { |
831 | /* Fall through... */ | 803 | nmclan_reset(dev); |
832 | case CS_EVENT_RESET_PHYSICAL: | 804 | netif_device_attach(dev); |
833 | if (link->state & DEV_CONFIG) { | 805 | } |
834 | if (link->open) | ||
835 | netif_device_detach(dev); | ||
836 | pcmcia_release_configuration(link->handle); | ||
837 | } | ||
838 | break; | ||
839 | case CS_EVENT_PM_RESUME: | ||
840 | link->state &= ~DEV_SUSPEND; | ||
841 | /* Fall through... */ | ||
842 | case CS_EVENT_CARD_RESET: | ||
843 | if (link->state & DEV_CONFIG) { | ||
844 | pcmcia_request_configuration(link->handle, &link->conf); | ||
845 | if (link->open) { | ||
846 | nmclan_reset(dev); | ||
847 | netif_device_attach(dev); | ||
848 | } | 806 | } |
849 | } | 807 | |
850 | break; | 808 | return 0; |
851 | case CS_EVENT_RESET_REQUEST: | 809 | } |
852 | return 1; | 810 | |
853 | break; | ||
854 | } | ||
855 | return 0; | ||
856 | } /* nmclan_event */ | ||
857 | 811 | ||
858 | /* ---------------------------------------------------------------------------- | 812 | /* ---------------------------------------------------------------------------- |
859 | nmclan_reset | 813 | nmclan_reset |
@@ -1681,10 +1635,11 @@ static struct pcmcia_driver nmclan_cs_driver = { | |||
1681 | .drv = { | 1635 | .drv = { |
1682 | .name = "nmclan_cs", | 1636 | .name = "nmclan_cs", |
1683 | }, | 1637 | }, |
1684 | .attach = nmclan_attach, | 1638 | .probe = nmclan_attach, |
1685 | .event = nmclan_event, | 1639 | .remove = nmclan_detach, |
1686 | .detach = nmclan_detach, | ||
1687 | .id_table = nmclan_ids, | 1640 | .id_table = nmclan_ids, |
1641 | .suspend = nmclan_suspend, | ||
1642 | .resume = nmclan_resume, | ||
1688 | }; | 1643 | }; |
1689 | 1644 | ||
1690 | static int __init init_nmclan_cs(void) | 1645 | static int __init init_nmclan_cs(void) |
@@ -1695,7 +1650,6 @@ static int __init init_nmclan_cs(void) | |||
1695 | static void __exit exit_nmclan_cs(void) | 1650 | static void __exit exit_nmclan_cs(void) |
1696 | { | 1651 | { |
1697 | pcmcia_unregister_driver(&nmclan_cs_driver); | 1652 | pcmcia_unregister_driver(&nmclan_cs_driver); |
1698 | BUG_ON(dev_list != NULL); | ||
1699 | } | 1653 | } |
1700 | 1654 | ||
1701 | module_init(init_nmclan_cs); | 1655 | module_init(init_nmclan_cs); |
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index 818c185d6438..d85b758f3efa 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c | |||
@@ -105,8 +105,6 @@ module_param_array(hw_addr, int, NULL, 0); | |||
105 | static void mii_phy_probe(struct net_device *dev); | 105 | static void mii_phy_probe(struct net_device *dev); |
106 | static void pcnet_config(dev_link_t *link); | 106 | static void pcnet_config(dev_link_t *link); |
107 | static void pcnet_release(dev_link_t *link); | 107 | static void pcnet_release(dev_link_t *link); |
108 | static int pcnet_event(event_t event, int priority, | ||
109 | event_callback_args_t *args); | ||
110 | static int pcnet_open(struct net_device *dev); | 108 | static int pcnet_open(struct net_device *dev); |
111 | static int pcnet_close(struct net_device *dev); | 109 | static int pcnet_close(struct net_device *dev); |
112 | static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); | 110 | static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); |
@@ -120,11 +118,9 @@ static int setup_shmem_window(dev_link_t *link, int start_pg, | |||
120 | static int setup_dma_config(dev_link_t *link, int start_pg, | 118 | static int setup_dma_config(dev_link_t *link, int start_pg, |
121 | int stop_pg); | 119 | int stop_pg); |
122 | 120 | ||
123 | static dev_link_t *pcnet_attach(void); | 121 | static void pcnet_detach(struct pcmcia_device *p_dev); |
124 | static void pcnet_detach(dev_link_t *); | ||
125 | 122 | ||
126 | static dev_info_t dev_info = "pcnet_cs"; | 123 | static dev_info_t dev_info = "pcnet_cs"; |
127 | static dev_link_t *dev_list; | ||
128 | 124 | ||
129 | /*====================================================================*/ | 125 | /*====================================================================*/ |
130 | 126 | ||
@@ -244,19 +240,17 @@ static inline pcnet_dev_t *PRIV(struct net_device *dev) | |||
244 | 240 | ||
245 | ======================================================================*/ | 241 | ======================================================================*/ |
246 | 242 | ||
247 | static dev_link_t *pcnet_attach(void) | 243 | static int pcnet_probe(struct pcmcia_device *p_dev) |
248 | { | 244 | { |
249 | pcnet_dev_t *info; | 245 | pcnet_dev_t *info; |
250 | dev_link_t *link; | 246 | dev_link_t *link; |
251 | struct net_device *dev; | 247 | struct net_device *dev; |
252 | client_reg_t client_reg; | ||
253 | int ret; | ||
254 | 248 | ||
255 | DEBUG(0, "pcnet_attach()\n"); | 249 | DEBUG(0, "pcnet_attach()\n"); |
256 | 250 | ||
257 | /* Create new ethernet device */ | 251 | /* Create new ethernet device */ |
258 | dev = __alloc_ei_netdev(sizeof(pcnet_dev_t)); | 252 | dev = __alloc_ei_netdev(sizeof(pcnet_dev_t)); |
259 | if (!dev) return NULL; | 253 | if (!dev) return -ENOMEM; |
260 | info = PRIV(dev); | 254 | info = PRIV(dev); |
261 | link = &info->link; | 255 | link = &info->link; |
262 | link->priv = dev; | 256 | link->priv = dev; |
@@ -271,20 +265,13 @@ static dev_link_t *pcnet_attach(void) | |||
271 | dev->stop = &pcnet_close; | 265 | dev->stop = &pcnet_close; |
272 | dev->set_config = &set_config; | 266 | dev->set_config = &set_config; |
273 | 267 | ||
274 | /* Register with Card Services */ | 268 | link->handle = p_dev; |
275 | link->next = dev_list; | 269 | p_dev->instance = link; |
276 | dev_list = link; | ||
277 | client_reg.dev_info = &dev_info; | ||
278 | client_reg.Version = 0x0210; | ||
279 | client_reg.event_callback_args.client_data = link; | ||
280 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
281 | if (ret != CS_SUCCESS) { | ||
282 | cs_error(link->handle, RegisterClient, ret); | ||
283 | pcnet_detach(link); | ||
284 | return NULL; | ||
285 | } | ||
286 | 270 | ||
287 | return link; | 271 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
272 | pcnet_config(link); | ||
273 | |||
274 | return 0; | ||
288 | } /* pcnet_attach */ | 275 | } /* pcnet_attach */ |
289 | 276 | ||
290 | /*====================================================================== | 277 | /*====================================================================== |
@@ -296,31 +283,20 @@ static dev_link_t *pcnet_attach(void) | |||
296 | 283 | ||
297 | ======================================================================*/ | 284 | ======================================================================*/ |
298 | 285 | ||
299 | static void pcnet_detach(dev_link_t *link) | 286 | static void pcnet_detach(struct pcmcia_device *p_dev) |
300 | { | 287 | { |
301 | struct net_device *dev = link->priv; | 288 | dev_link_t *link = dev_to_instance(p_dev); |
302 | dev_link_t **linkp; | 289 | struct net_device *dev = link->priv; |
303 | |||
304 | DEBUG(0, "pcnet_detach(0x%p)\n", link); | ||
305 | 290 | ||
306 | /* Locate device structure */ | 291 | DEBUG(0, "pcnet_detach(0x%p)\n", link); |
307 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
308 | if (*linkp == link) break; | ||
309 | if (*linkp == NULL) | ||
310 | return; | ||
311 | 292 | ||
312 | if (link->dev) | 293 | if (link->dev) |
313 | unregister_netdev(dev); | 294 | unregister_netdev(dev); |
314 | 295 | ||
315 | if (link->state & DEV_CONFIG) | 296 | if (link->state & DEV_CONFIG) |
316 | pcnet_release(link); | 297 | pcnet_release(link); |
317 | |||
318 | if (link->handle) | ||
319 | pcmcia_deregister_client(link->handle); | ||
320 | 298 | ||
321 | /* Unlink device structure, free bits */ | 299 | free_netdev(dev); |
322 | *linkp = link->next; | ||
323 | free_netdev(dev); | ||
324 | } /* pcnet_detach */ | 300 | } /* pcnet_detach */ |
325 | 301 | ||
326 | /*====================================================================== | 302 | /*====================================================================== |
@@ -780,50 +756,39 @@ static void pcnet_release(dev_link_t *link) | |||
780 | 756 | ||
781 | ======================================================================*/ | 757 | ======================================================================*/ |
782 | 758 | ||
783 | static int pcnet_event(event_t event, int priority, | 759 | static int pcnet_suspend(struct pcmcia_device *p_dev) |
784 | event_callback_args_t *args) | ||
785 | { | 760 | { |
786 | dev_link_t *link = args->client_data; | 761 | dev_link_t *link = dev_to_instance(p_dev); |
787 | struct net_device *dev = link->priv; | 762 | struct net_device *dev = link->priv; |
788 | 763 | ||
789 | DEBUG(2, "pcnet_event(0x%06x)\n", event); | ||
790 | |||
791 | switch (event) { | ||
792 | case CS_EVENT_CARD_REMOVAL: | ||
793 | link->state &= ~DEV_PRESENT; | ||
794 | if (link->state & DEV_CONFIG) | ||
795 | netif_device_detach(dev); | ||
796 | break; | ||
797 | case CS_EVENT_CARD_INSERTION: | ||
798 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
799 | pcnet_config(link); | ||
800 | break; | ||
801 | case CS_EVENT_PM_SUSPEND: | ||
802 | link->state |= DEV_SUSPEND; | 764 | link->state |= DEV_SUSPEND; |
803 | /* Fall through... */ | ||
804 | case CS_EVENT_RESET_PHYSICAL: | ||
805 | if (link->state & DEV_CONFIG) { | 765 | if (link->state & DEV_CONFIG) { |
806 | if (link->open) | 766 | if (link->open) |
807 | netif_device_detach(dev); | 767 | netif_device_detach(dev); |
808 | pcmcia_release_configuration(link->handle); | 768 | pcmcia_release_configuration(link->handle); |
809 | } | 769 | } |
810 | break; | 770 | |
811 | case CS_EVENT_PM_RESUME: | 771 | return 0; |
772 | } | ||
773 | |||
774 | static int pcnet_resume(struct pcmcia_device *p_dev) | ||
775 | { | ||
776 | dev_link_t *link = dev_to_instance(p_dev); | ||
777 | struct net_device *dev = link->priv; | ||
778 | |||
812 | link->state &= ~DEV_SUSPEND; | 779 | link->state &= ~DEV_SUSPEND; |
813 | /* Fall through... */ | ||
814 | case CS_EVENT_CARD_RESET: | ||
815 | if (link->state & DEV_CONFIG) { | 780 | if (link->state & DEV_CONFIG) { |
816 | pcmcia_request_configuration(link->handle, &link->conf); | 781 | pcmcia_request_configuration(link->handle, &link->conf); |
817 | if (link->open) { | 782 | if (link->open) { |
818 | pcnet_reset_8390(dev); | 783 | pcnet_reset_8390(dev); |
819 | NS8390_init(dev, 1); | 784 | NS8390_init(dev, 1); |
820 | netif_device_attach(dev); | 785 | netif_device_attach(dev); |
821 | } | 786 | } |
822 | } | 787 | } |
823 | break; | 788 | |
824 | } | 789 | return 0; |
825 | return 0; | 790 | } |
826 | } /* pcnet_event */ | 791 | |
827 | 792 | ||
828 | /*====================================================================== | 793 | /*====================================================================== |
829 | 794 | ||
@@ -1844,11 +1809,12 @@ static struct pcmcia_driver pcnet_driver = { | |||
1844 | .drv = { | 1809 | .drv = { |
1845 | .name = "pcnet_cs", | 1810 | .name = "pcnet_cs", |
1846 | }, | 1811 | }, |
1847 | .attach = pcnet_attach, | 1812 | .probe = pcnet_probe, |
1848 | .event = pcnet_event, | 1813 | .remove = pcnet_detach, |
1849 | .detach = pcnet_detach, | ||
1850 | .owner = THIS_MODULE, | 1814 | .owner = THIS_MODULE, |
1851 | .id_table = pcnet_ids, | 1815 | .id_table = pcnet_ids, |
1816 | .suspend = pcnet_suspend, | ||
1817 | .resume = pcnet_resume, | ||
1852 | }; | 1818 | }; |
1853 | 1819 | ||
1854 | static int __init init_pcnet_cs(void) | 1820 | static int __init init_pcnet_cs(void) |
@@ -1860,7 +1826,6 @@ static void __exit exit_pcnet_cs(void) | |||
1860 | { | 1826 | { |
1861 | DEBUG(0, "pcnet_cs: unloading\n"); | 1827 | DEBUG(0, "pcnet_cs: unloading\n"); |
1862 | pcmcia_unregister_driver(&pcnet_driver); | 1828 | pcmcia_unregister_driver(&pcnet_driver); |
1863 | BUG_ON(dev_list != NULL); | ||
1864 | } | 1829 | } |
1865 | 1830 | ||
1866 | module_init(init_pcnet_cs); | 1831 | module_init(init_pcnet_cs); |
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index c7cca842e5ee..0122415dfeef 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c | |||
@@ -102,10 +102,6 @@ static const char *version = | |||
102 | currently have room for another Tx packet. */ | 102 | currently have room for another Tx packet. */ |
103 | #define MEMORY_WAIT_TIME 8 | 103 | #define MEMORY_WAIT_TIME 8 |
104 | 104 | ||
105 | static dev_info_t dev_info = "smc91c92_cs"; | ||
106 | |||
107 | static dev_link_t *dev_list; | ||
108 | |||
109 | struct smc_private { | 105 | struct smc_private { |
110 | dev_link_t link; | 106 | dev_link_t link; |
111 | spinlock_t lock; | 107 | spinlock_t lock; |
@@ -281,12 +277,9 @@ enum RxCfg { RxAllMulti = 0x0004, RxPromisc = 0x0002, | |||
281 | 277 | ||
282 | /*====================================================================*/ | 278 | /*====================================================================*/ |
283 | 279 | ||
284 | static dev_link_t *smc91c92_attach(void); | 280 | static void smc91c92_detach(struct pcmcia_device *p_dev); |
285 | static void smc91c92_detach(dev_link_t *); | ||
286 | static void smc91c92_config(dev_link_t *link); | 281 | static void smc91c92_config(dev_link_t *link); |
287 | static void smc91c92_release(dev_link_t *link); | 282 | static void smc91c92_release(dev_link_t *link); |
288 | static int smc91c92_event(event_t event, int priority, | ||
289 | event_callback_args_t *args); | ||
290 | 283 | ||
291 | static int smc_open(struct net_device *dev); | 284 | static int smc_open(struct net_device *dev); |
292 | static int smc_close(struct net_device *dev); | 285 | static int smc_close(struct net_device *dev); |
@@ -315,20 +308,18 @@ static struct ethtool_ops ethtool_ops; | |||
315 | 308 | ||
316 | ======================================================================*/ | 309 | ======================================================================*/ |
317 | 310 | ||
318 | static dev_link_t *smc91c92_attach(void) | 311 | static int smc91c92_attach(struct pcmcia_device *p_dev) |
319 | { | 312 | { |
320 | client_reg_t client_reg; | ||
321 | struct smc_private *smc; | 313 | struct smc_private *smc; |
322 | dev_link_t *link; | 314 | dev_link_t *link; |
323 | struct net_device *dev; | 315 | struct net_device *dev; |
324 | int ret; | ||
325 | 316 | ||
326 | DEBUG(0, "smc91c92_attach()\n"); | 317 | DEBUG(0, "smc91c92_attach()\n"); |
327 | 318 | ||
328 | /* Create new ethernet device */ | 319 | /* Create new ethernet device */ |
329 | dev = alloc_etherdev(sizeof(struct smc_private)); | 320 | dev = alloc_etherdev(sizeof(struct smc_private)); |
330 | if (!dev) | 321 | if (!dev) |
331 | return NULL; | 322 | return -ENOMEM; |
332 | smc = netdev_priv(dev); | 323 | smc = netdev_priv(dev); |
333 | link = &smc->link; | 324 | link = &smc->link; |
334 | link->priv = dev; | 325 | link->priv = dev; |
@@ -366,20 +357,13 @@ static dev_link_t *smc91c92_attach(void) | |||
366 | smc->mii_if.phy_id_mask = 0x1f; | 357 | smc->mii_if.phy_id_mask = 0x1f; |
367 | smc->mii_if.reg_num_mask = 0x1f; | 358 | smc->mii_if.reg_num_mask = 0x1f; |
368 | 359 | ||
369 | /* Register with Card Services */ | 360 | link->handle = p_dev; |
370 | link->next = dev_list; | 361 | p_dev->instance = link; |
371 | dev_list = link; | 362 | |
372 | client_reg.dev_info = &dev_info; | 363 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
373 | client_reg.Version = 0x0210; | 364 | smc91c92_config(link); |
374 | client_reg.event_callback_args.client_data = link; | ||
375 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
376 | if (ret != 0) { | ||
377 | cs_error(link->handle, RegisterClient, ret); | ||
378 | smc91c92_detach(link); | ||
379 | return NULL; | ||
380 | } | ||
381 | 365 | ||
382 | return link; | 366 | return 0; |
383 | } /* smc91c92_attach */ | 367 | } /* smc91c92_attach */ |
384 | 368 | ||
385 | /*====================================================================== | 369 | /*====================================================================== |
@@ -391,30 +375,19 @@ static dev_link_t *smc91c92_attach(void) | |||
391 | 375 | ||
392 | ======================================================================*/ | 376 | ======================================================================*/ |
393 | 377 | ||
394 | static void smc91c92_detach(dev_link_t *link) | 378 | static void smc91c92_detach(struct pcmcia_device *p_dev) |
395 | { | 379 | { |
380 | dev_link_t *link = dev_to_instance(p_dev); | ||
396 | struct net_device *dev = link->priv; | 381 | struct net_device *dev = link->priv; |
397 | dev_link_t **linkp; | ||
398 | 382 | ||
399 | DEBUG(0, "smc91c92_detach(0x%p)\n", link); | 383 | DEBUG(0, "smc91c92_detach(0x%p)\n", link); |
400 | 384 | ||
401 | /* Locate device structure */ | ||
402 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
403 | if (*linkp == link) break; | ||
404 | if (*linkp == NULL) | ||
405 | return; | ||
406 | |||
407 | if (link->dev) | 385 | if (link->dev) |
408 | unregister_netdev(dev); | 386 | unregister_netdev(dev); |
409 | 387 | ||
410 | if (link->state & DEV_CONFIG) | 388 | if (link->state & DEV_CONFIG) |
411 | smc91c92_release(link); | 389 | smc91c92_release(link); |
412 | 390 | ||
413 | if (link->handle) | ||
414 | pcmcia_deregister_client(link->handle); | ||
415 | |||
416 | /* Unlink device structure, free bits */ | ||
417 | *linkp = link->next; | ||
418 | free_netdev(dev); | 391 | free_netdev(dev); |
419 | } /* smc91c92_detach */ | 392 | } /* smc91c92_detach */ |
420 | 393 | ||
@@ -895,6 +868,62 @@ free_cfg_mem: | |||
895 | return rc; | 868 | return rc; |
896 | } | 869 | } |
897 | 870 | ||
871 | static int smc91c92_suspend(struct pcmcia_device *p_dev) | ||
872 | { | ||
873 | dev_link_t *link = dev_to_instance(p_dev); | ||
874 | struct net_device *dev = link->priv; | ||
875 | |||
876 | link->state |= DEV_SUSPEND; | ||
877 | if (link->state & DEV_CONFIG) { | ||
878 | if (link->open) | ||
879 | netif_device_detach(dev); | ||
880 | pcmcia_release_configuration(link->handle); | ||
881 | } | ||
882 | |||
883 | return 0; | ||
884 | } | ||
885 | |||
886 | static int smc91c92_resume(struct pcmcia_device *p_dev) | ||
887 | { | ||
888 | dev_link_t *link = dev_to_instance(p_dev); | ||
889 | struct net_device *dev = link->priv; | ||
890 | struct smc_private *smc = netdev_priv(dev); | ||
891 | int i; | ||
892 | |||
893 | link->state &= ~DEV_SUSPEND; | ||
894 | if (link->state & DEV_CONFIG) { | ||
895 | if ((smc->manfid == MANFID_MEGAHERTZ) && | ||
896 | (smc->cardid == PRODID_MEGAHERTZ_EM3288)) | ||
897 | mhz_3288_power(link); | ||
898 | pcmcia_request_configuration(link->handle, &link->conf); | ||
899 | if (smc->manfid == MANFID_MOTOROLA) | ||
900 | mot_config(link); | ||
901 | if ((smc->manfid == MANFID_OSITECH) && | ||
902 | (smc->cardid != PRODID_OSITECH_SEVEN)) { | ||
903 | /* Power up the card and enable interrupts */ | ||
904 | set_bits(0x0300, dev->base_addr-0x10+OSITECH_AUI_PWR); | ||
905 | set_bits(0x0300, dev->base_addr-0x10+OSITECH_RESET_ISR); | ||
906 | } | ||
907 | if (((smc->manfid == MANFID_OSITECH) && | ||
908 | (smc->cardid == PRODID_OSITECH_SEVEN)) || | ||
909 | ((smc->manfid == MANFID_PSION) && | ||
910 | (smc->cardid == PRODID_PSION_NET100))) { | ||
911 | /* Download the Seven of Diamonds firmware */ | ||
912 | for (i = 0; i < sizeof(__Xilinx7OD); i++) { | ||
913 | outb(__Xilinx7OD[i], link->io.BasePort1+2); | ||
914 | udelay(50); | ||
915 | } | ||
916 | } | ||
917 | if (link->open) { | ||
918 | smc_reset(dev); | ||
919 | netif_device_attach(dev); | ||
920 | } | ||
921 | } | ||
922 | |||
923 | return 0; | ||
924 | } | ||
925 | |||
926 | |||
898 | /*====================================================================== | 927 | /*====================================================================== |
899 | 928 | ||
900 | This verifies that the chip is some SMC91cXX variant, and returns | 929 | This verifies that the chip is some SMC91cXX variant, and returns |
@@ -935,14 +964,12 @@ static int check_sig(dev_link_t *link) | |||
935 | } | 964 | } |
936 | 965 | ||
937 | if (width) { | 966 | if (width) { |
938 | event_callback_args_t args; | ||
939 | printk(KERN_INFO "smc91c92_cs: using 8-bit IO window.\n"); | 967 | printk(KERN_INFO "smc91c92_cs: using 8-bit IO window.\n"); |
940 | args.client_data = link; | 968 | smc91c92_suspend(link->handle); |
941 | smc91c92_event(CS_EVENT_RESET_PHYSICAL, 0, &args); | ||
942 | pcmcia_release_io(link->handle, &link->io); | 969 | pcmcia_release_io(link->handle, &link->io); |
943 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | 970 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; |
944 | pcmcia_request_io(link->handle, &link->io); | 971 | pcmcia_request_io(link->handle, &link->io); |
945 | smc91c92_event(CS_EVENT_CARD_RESET, 0, &args); | 972 | smc91c92_resume(link->handle); |
946 | return check_sig(link); | 973 | return check_sig(link); |
947 | } | 974 | } |
948 | return -ENODEV; | 975 | return -ENODEV; |
@@ -1172,82 +1199,6 @@ static void smc91c92_release(dev_link_t *link) | |||
1172 | 1199 | ||
1173 | /*====================================================================== | 1200 | /*====================================================================== |
1174 | 1201 | ||
1175 | The card status event handler. Mostly, this schedules other | ||
1176 | stuff to run after an event is received. A CARD_REMOVAL event | ||
1177 | also sets some flags to discourage the net drivers from trying | ||
1178 | to talk to the card any more. | ||
1179 | |||
1180 | ======================================================================*/ | ||
1181 | |||
1182 | static int smc91c92_event(event_t event, int priority, | ||
1183 | event_callback_args_t *args) | ||
1184 | { | ||
1185 | dev_link_t *link = args->client_data; | ||
1186 | struct net_device *dev = link->priv; | ||
1187 | struct smc_private *smc = netdev_priv(dev); | ||
1188 | int i; | ||
1189 | |||
1190 | DEBUG(1, "smc91c92_event(0x%06x)\n", event); | ||
1191 | |||
1192 | switch (event) { | ||
1193 | case CS_EVENT_CARD_REMOVAL: | ||
1194 | link->state &= ~DEV_PRESENT; | ||
1195 | if (link->state & DEV_CONFIG) | ||
1196 | netif_device_detach(dev); | ||
1197 | break; | ||
1198 | case CS_EVENT_CARD_INSERTION: | ||
1199 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
1200 | smc91c92_config(link); | ||
1201 | break; | ||
1202 | case CS_EVENT_PM_SUSPEND: | ||
1203 | link->state |= DEV_SUSPEND; | ||
1204 | /* Fall through... */ | ||
1205 | case CS_EVENT_RESET_PHYSICAL: | ||
1206 | if (link->state & DEV_CONFIG) { | ||
1207 | if (link->open) | ||
1208 | netif_device_detach(dev); | ||
1209 | pcmcia_release_configuration(link->handle); | ||
1210 | } | ||
1211 | break; | ||
1212 | case CS_EVENT_PM_RESUME: | ||
1213 | link->state &= ~DEV_SUSPEND; | ||
1214 | /* Fall through... */ | ||
1215 | case CS_EVENT_CARD_RESET: | ||
1216 | if (link->state & DEV_CONFIG) { | ||
1217 | if ((smc->manfid == MANFID_MEGAHERTZ) && | ||
1218 | (smc->cardid == PRODID_MEGAHERTZ_EM3288)) | ||
1219 | mhz_3288_power(link); | ||
1220 | pcmcia_request_configuration(link->handle, &link->conf); | ||
1221 | if (smc->manfid == MANFID_MOTOROLA) | ||
1222 | mot_config(link); | ||
1223 | if ((smc->manfid == MANFID_OSITECH) && | ||
1224 | (smc->cardid != PRODID_OSITECH_SEVEN)) { | ||
1225 | /* Power up the card and enable interrupts */ | ||
1226 | set_bits(0x0300, dev->base_addr-0x10+OSITECH_AUI_PWR); | ||
1227 | set_bits(0x0300, dev->base_addr-0x10+OSITECH_RESET_ISR); | ||
1228 | } | ||
1229 | if (((smc->manfid == MANFID_OSITECH) && | ||
1230 | (smc->cardid == PRODID_OSITECH_SEVEN)) || | ||
1231 | ((smc->manfid == MANFID_PSION) && | ||
1232 | (smc->cardid == PRODID_PSION_NET100))) { | ||
1233 | /* Download the Seven of Diamonds firmware */ | ||
1234 | for (i = 0; i < sizeof(__Xilinx7OD); i++) { | ||
1235 | outb(__Xilinx7OD[i], link->io.BasePort1+2); | ||
1236 | udelay(50); | ||
1237 | } | ||
1238 | } | ||
1239 | if (link->open) { | ||
1240 | smc_reset(dev); | ||
1241 | netif_device_attach(dev); | ||
1242 | } | ||
1243 | } | ||
1244 | break; | ||
1245 | } | ||
1246 | return 0; | ||
1247 | } /* smc91c92_event */ | ||
1248 | |||
1249 | /*====================================================================== | ||
1250 | |||
1251 | MII interface support for SMC91cXX based cards | 1202 | MII interface support for SMC91cXX based cards |
1252 | ======================================================================*/ | 1203 | ======================================================================*/ |
1253 | 1204 | ||
@@ -2360,10 +2311,11 @@ static struct pcmcia_driver smc91c92_cs_driver = { | |||
2360 | .drv = { | 2311 | .drv = { |
2361 | .name = "smc91c92_cs", | 2312 | .name = "smc91c92_cs", |
2362 | }, | 2313 | }, |
2363 | .attach = smc91c92_attach, | 2314 | .probe = smc91c92_attach, |
2364 | .event = smc91c92_event, | 2315 | .remove = smc91c92_detach, |
2365 | .detach = smc91c92_detach, | ||
2366 | .id_table = smc91c92_ids, | 2316 | .id_table = smc91c92_ids, |
2317 | .suspend = smc91c92_suspend, | ||
2318 | .resume = smc91c92_resume, | ||
2367 | }; | 2319 | }; |
2368 | 2320 | ||
2369 | static int __init init_smc91c92_cs(void) | 2321 | static int __init init_smc91c92_cs(void) |
@@ -2374,7 +2326,6 @@ static int __init init_smc91c92_cs(void) | |||
2374 | static void __exit exit_smc91c92_cs(void) | 2326 | static void __exit exit_smc91c92_cs(void) |
2375 | { | 2327 | { |
2376 | pcmcia_unregister_driver(&smc91c92_cs_driver); | 2328 | pcmcia_unregister_driver(&smc91c92_cs_driver); |
2377 | BUG_ON(dev_list != NULL); | ||
2378 | } | 2329 | } |
2379 | 2330 | ||
2380 | module_init(init_smc91c92_cs); | 2331 | module_init(init_smc91c92_cs); |
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index ce143f08638a..049c34b37067 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c | |||
@@ -292,8 +292,6 @@ static void mii_wr(kio_addr_t ioaddr, u_char phyaddr, u_char phyreg, | |||
292 | static int has_ce2_string(dev_link_t * link); | 292 | static int has_ce2_string(dev_link_t * link); |
293 | static void xirc2ps_config(dev_link_t * link); | 293 | static void xirc2ps_config(dev_link_t * link); |
294 | static void xirc2ps_release(dev_link_t * link); | 294 | static void xirc2ps_release(dev_link_t * link); |
295 | static int xirc2ps_event(event_t event, int priority, | ||
296 | event_callback_args_t * args); | ||
297 | 295 | ||
298 | /**************** | 296 | /**************** |
299 | * The attach() and detach() entry points are used to create and destroy | 297 | * The attach() and detach() entry points are used to create and destroy |
@@ -301,8 +299,7 @@ static int xirc2ps_event(event_t event, int priority, | |||
301 | * needed to manage one actual PCMCIA card. | 299 | * needed to manage one actual PCMCIA card. |
302 | */ | 300 | */ |
303 | 301 | ||
304 | static dev_link_t *xirc2ps_attach(void); | 302 | static void xirc2ps_detach(struct pcmcia_device *p_dev); |
305 | static void xirc2ps_detach(dev_link_t *); | ||
306 | 303 | ||
307 | /**************** | 304 | /**************** |
308 | * You'll also need to prototype all the functions that will actually | 305 | * You'll also need to prototype all the functions that will actually |
@@ -313,14 +310,6 @@ static void xirc2ps_detach(dev_link_t *); | |||
313 | 310 | ||
314 | static irqreturn_t xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs); | 311 | static irqreturn_t xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs); |
315 | 312 | ||
316 | /* | ||
317 | * The dev_info variable is the "key" that is used to match up this | ||
318 | * device driver with appropriate cards, through the card configuration | ||
319 | * database. | ||
320 | */ | ||
321 | |||
322 | static dev_info_t dev_info = "xirc2ps_cs"; | ||
323 | |||
324 | /**************** | 313 | /**************** |
325 | * A linked list of "instances" of the device. Each actual | 314 | * A linked list of "instances" of the device. Each actual |
326 | * PCMCIA card corresponds to one device instance, and is described | 315 | * PCMCIA card corresponds to one device instance, and is described |
@@ -331,15 +320,7 @@ static dev_info_t dev_info = "xirc2ps_cs"; | |||
331 | * device numbers are used to derive the corresponding array index. | 320 | * device numbers are used to derive the corresponding array index. |
332 | */ | 321 | */ |
333 | 322 | ||
334 | static dev_link_t *dev_list; | ||
335 | |||
336 | /**************** | 323 | /**************** |
337 | * A dev_link_t structure has fields for most things that are needed | ||
338 | * to keep track of a socket, but there will usually be some device | ||
339 | * specific information that also needs to be kept track of. The | ||
340 | * 'priv' pointer in a dev_link_t structure can be used to point to | ||
341 | * a device-specific private data structure, like this. | ||
342 | * | ||
343 | * A driver needs to provide a dev_node_t structure for each device | 324 | * A driver needs to provide a dev_node_t structure for each device |
344 | * on a card. In some cases, there is only one device per card (for | 325 | * on a card. In some cases, there is only one device per card (for |
345 | * example, ethernet cards, modems). In other cases, there may be | 326 | * example, ethernet cards, modems). In other cases, there may be |
@@ -571,21 +552,19 @@ mii_wr(kio_addr_t ioaddr, u_char phyaddr, u_char phyreg, unsigned data, int len) | |||
571 | * card insertion event. | 552 | * card insertion event. |
572 | */ | 553 | */ |
573 | 554 | ||
574 | static dev_link_t * | 555 | static int |
575 | xirc2ps_attach(void) | 556 | xirc2ps_attach(struct pcmcia_device *p_dev) |
576 | { | 557 | { |
577 | client_reg_t client_reg; | ||
578 | dev_link_t *link; | 558 | dev_link_t *link; |
579 | struct net_device *dev; | 559 | struct net_device *dev; |
580 | local_info_t *local; | 560 | local_info_t *local; |
581 | int err; | ||
582 | 561 | ||
583 | DEBUG(0, "attach()\n"); | 562 | DEBUG(0, "attach()\n"); |
584 | 563 | ||
585 | /* Allocate the device structure */ | 564 | /* Allocate the device structure */ |
586 | dev = alloc_etherdev(sizeof(local_info_t)); | 565 | dev = alloc_etherdev(sizeof(local_info_t)); |
587 | if (!dev) | 566 | if (!dev) |
588 | return NULL; | 567 | return -ENOMEM; |
589 | local = netdev_priv(dev); | 568 | local = netdev_priv(dev); |
590 | link = &local->link; | 569 | link = &local->link; |
591 | link->priv = dev; | 570 | link->priv = dev; |
@@ -614,19 +593,13 @@ xirc2ps_attach(void) | |||
614 | dev->watchdog_timeo = TX_TIMEOUT; | 593 | dev->watchdog_timeo = TX_TIMEOUT; |
615 | #endif | 594 | #endif |
616 | 595 | ||
617 | /* Register with Card Services */ | 596 | link->handle = p_dev; |
618 | link->next = dev_list; | 597 | p_dev->instance = link; |
619 | dev_list = link; | 598 | |
620 | client_reg.dev_info = &dev_info; | 599 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
621 | client_reg.Version = 0x0210; | 600 | xirc2ps_config(link); |
622 | client_reg.event_callback_args.client_data = link; | ||
623 | if ((err = pcmcia_register_client(&link->handle, &client_reg))) { | ||
624 | cs_error(link->handle, RegisterClient, err); | ||
625 | xirc2ps_detach(link); | ||
626 | return NULL; | ||
627 | } | ||
628 | 601 | ||
629 | return link; | 602 | return 0; |
630 | } /* xirc2ps_attach */ | 603 | } /* xirc2ps_attach */ |
631 | 604 | ||
632 | /**************** | 605 | /**************** |
@@ -637,40 +610,19 @@ xirc2ps_attach(void) | |||
637 | */ | 610 | */ |
638 | 611 | ||
639 | static void | 612 | static void |
640 | xirc2ps_detach(dev_link_t * link) | 613 | xirc2ps_detach(struct pcmcia_device *p_dev) |
641 | { | 614 | { |
615 | dev_link_t *link = dev_to_instance(p_dev); | ||
642 | struct net_device *dev = link->priv; | 616 | struct net_device *dev = link->priv; |
643 | dev_link_t **linkp; | ||
644 | 617 | ||
645 | DEBUG(0, "detach(0x%p)\n", link); | 618 | DEBUG(0, "detach(0x%p)\n", link); |
646 | 619 | ||
647 | /* Locate device structure */ | ||
648 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
649 | if (*linkp == link) | ||
650 | break; | ||
651 | if (!*linkp) { | ||
652 | DEBUG(0, "detach(0x%p): dev_link lost\n", link); | ||
653 | return; | ||
654 | } | ||
655 | |||
656 | if (link->dev) | 620 | if (link->dev) |
657 | unregister_netdev(dev); | 621 | unregister_netdev(dev); |
658 | 622 | ||
659 | /* | ||
660 | * If the device is currently configured and active, we won't | ||
661 | * actually delete it yet. Instead, it is marked so that when | ||
662 | * the release() function is called, that will trigger a proper | ||
663 | * detach(). | ||
664 | */ | ||
665 | if (link->state & DEV_CONFIG) | 623 | if (link->state & DEV_CONFIG) |
666 | xirc2ps_release(link); | 624 | xirc2ps_release(link); |
667 | 625 | ||
668 | /* Break the link with Card Services */ | ||
669 | if (link->handle) | ||
670 | pcmcia_deregister_client(link->handle); | ||
671 | |||
672 | /* Unlink device structure, free it */ | ||
673 | *linkp = link->next; | ||
674 | free_netdev(dev); | 626 | free_netdev(dev); |
675 | } /* xirc2ps_detach */ | 627 | } /* xirc2ps_detach */ |
676 | 628 | ||
@@ -1157,67 +1109,41 @@ xirc2ps_release(dev_link_t *link) | |||
1157 | 1109 | ||
1158 | /*====================================================================*/ | 1110 | /*====================================================================*/ |
1159 | 1111 | ||
1160 | /**************** | ||
1161 | * The card status event handler. Mostly, this schedules other | ||
1162 | * stuff to run after an event is received. A CARD_REMOVAL event | ||
1163 | * also sets some flags to discourage the net drivers from trying | ||
1164 | * to talk to the card any more. | ||
1165 | * | ||
1166 | * When a CARD_REMOVAL event is received, we immediately set a flag | ||
1167 | * to block future accesses to this device. All the functions that | ||
1168 | * actually access the device should check this flag to make sure | ||
1169 | * the card is still present. | ||
1170 | */ | ||
1171 | 1112 | ||
1172 | static int | 1113 | static int xirc2ps_suspend(struct pcmcia_device *p_dev) |
1173 | xirc2ps_event(event_t event, int priority, | ||
1174 | event_callback_args_t * args) | ||
1175 | { | 1114 | { |
1176 | dev_link_t *link = args->client_data; | 1115 | dev_link_t *link = dev_to_instance(p_dev); |
1177 | struct net_device *dev = link->priv; | 1116 | struct net_device *dev = link->priv; |
1178 | |||
1179 | DEBUG(0, "event(%d)\n", (int)event); | ||
1180 | 1117 | ||
1181 | switch (event) { | ||
1182 | case CS_EVENT_REGISTRATION_COMPLETE: | ||
1183 | DEBUG(0, "registration complete\n"); | ||
1184 | break; | ||
1185 | case CS_EVENT_CARD_REMOVAL: | ||
1186 | link->state &= ~DEV_PRESENT; | ||
1187 | if (link->state & DEV_CONFIG) | ||
1188 | netif_device_detach(dev); | ||
1189 | break; | ||
1190 | case CS_EVENT_CARD_INSERTION: | ||
1191 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
1192 | xirc2ps_config(link); | ||
1193 | break; | ||
1194 | case CS_EVENT_PM_SUSPEND: | ||
1195 | link->state |= DEV_SUSPEND; | 1118 | link->state |= DEV_SUSPEND; |
1196 | /* Fall through... */ | ||
1197 | case CS_EVENT_RESET_PHYSICAL: | ||
1198 | if (link->state & DEV_CONFIG) { | 1119 | if (link->state & DEV_CONFIG) { |
1199 | if (link->open) { | 1120 | if (link->open) { |
1200 | netif_device_detach(dev); | 1121 | netif_device_detach(dev); |
1201 | do_powerdown(dev); | 1122 | do_powerdown(dev); |
1202 | } | 1123 | } |
1203 | pcmcia_release_configuration(link->handle); | 1124 | pcmcia_release_configuration(link->handle); |
1204 | } | 1125 | } |
1205 | break; | 1126 | |
1206 | case CS_EVENT_PM_RESUME: | 1127 | return 0; |
1128 | } | ||
1129 | |||
1130 | static int xirc2ps_resume(struct pcmcia_device *p_dev) | ||
1131 | { | ||
1132 | dev_link_t *link = dev_to_instance(p_dev); | ||
1133 | struct net_device *dev = link->priv; | ||
1134 | |||
1207 | link->state &= ~DEV_SUSPEND; | 1135 | link->state &= ~DEV_SUSPEND; |
1208 | /* Fall through... */ | ||
1209 | case CS_EVENT_CARD_RESET: | ||
1210 | if (link->state & DEV_CONFIG) { | 1136 | if (link->state & DEV_CONFIG) { |
1211 | pcmcia_request_configuration(link->handle, &link->conf); | 1137 | pcmcia_request_configuration(link->handle, &link->conf); |
1212 | if (link->open) { | 1138 | if (link->open) { |
1213 | do_reset(dev,1); | 1139 | do_reset(dev,1); |
1214 | netif_device_attach(dev); | 1140 | netif_device_attach(dev); |
1215 | } | 1141 | } |
1216 | } | 1142 | } |
1217 | break; | 1143 | |
1218 | } | 1144 | return 0; |
1219 | return 0; | 1145 | } |
1220 | } /* xirc2ps_event */ | 1146 | |
1221 | 1147 | ||
1222 | /*====================================================================*/ | 1148 | /*====================================================================*/ |
1223 | 1149 | ||
@@ -2009,10 +1935,11 @@ static struct pcmcia_driver xirc2ps_cs_driver = { | |||
2009 | .drv = { | 1935 | .drv = { |
2010 | .name = "xirc2ps_cs", | 1936 | .name = "xirc2ps_cs", |
2011 | }, | 1937 | }, |
2012 | .attach = xirc2ps_attach, | 1938 | .probe = xirc2ps_attach, |
2013 | .event = xirc2ps_event, | 1939 | .remove = xirc2ps_detach, |
2014 | .detach = xirc2ps_detach, | ||
2015 | .id_table = xirc2ps_ids, | 1940 | .id_table = xirc2ps_ids, |
1941 | .suspend = xirc2ps_suspend, | ||
1942 | .resume = xirc2ps_resume, | ||
2016 | }; | 1943 | }; |
2017 | 1944 | ||
2018 | static int __init | 1945 | static int __init |
@@ -2025,7 +1952,6 @@ static void __exit | |||
2025 | exit_xirc2ps_cs(void) | 1952 | exit_xirc2ps_cs(void) |
2026 | { | 1953 | { |
2027 | pcmcia_unregister_driver(&xirc2ps_cs_driver); | 1954 | pcmcia_unregister_driver(&xirc2ps_cs_driver); |
2028 | BUG_ON(dev_list != NULL); | ||
2029 | } | 1955 | } |
2030 | 1956 | ||
2031 | module_init(init_xirc2ps_cs); | 1957 | module_init(init_xirc2ps_cs); |
diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index e328547599dc..a496460ce224 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c | |||
@@ -82,8 +82,6 @@ MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340 PCMCIA cards"); | |||
82 | 82 | ||
83 | static void airo_config(dev_link_t *link); | 83 | static void airo_config(dev_link_t *link); |
84 | static void airo_release(dev_link_t *link); | 84 | static void airo_release(dev_link_t *link); |
85 | static int airo_event(event_t event, int priority, | ||
86 | event_callback_args_t *args); | ||
87 | 85 | ||
88 | /* | 86 | /* |
89 | The attach() and detach() entry points are used to create and destroy | 87 | The attach() and detach() entry points are used to create and destroy |
@@ -91,8 +89,7 @@ static int airo_event(event_t event, int priority, | |||
91 | needed to manage one actual PCMCIA card. | 89 | needed to manage one actual PCMCIA card. |
92 | */ | 90 | */ |
93 | 91 | ||
94 | static dev_link_t *airo_attach(void); | 92 | static void airo_detach(struct pcmcia_device *p_dev); |
95 | static void airo_detach(dev_link_t *); | ||
96 | 93 | ||
97 | /* | 94 | /* |
98 | You'll also need to prototype all the functions that will actually | 95 | You'll also need to prototype all the functions that will actually |
@@ -102,14 +99,6 @@ static void airo_detach(dev_link_t *); | |||
102 | */ | 99 | */ |
103 | 100 | ||
104 | /* | 101 | /* |
105 | The dev_info variable is the "key" that is used to match up this | ||
106 | device driver with appropriate cards, through the card configuration | ||
107 | database. | ||
108 | */ | ||
109 | |||
110 | static dev_info_t dev_info = "airo_cs"; | ||
111 | |||
112 | /* | ||
113 | A linked list of "instances" of the aironet device. Each actual | 102 | A linked list of "instances" of the aironet device. Each actual |
114 | PCMCIA card corresponds to one device instance, and is described | 103 | PCMCIA card corresponds to one device instance, and is described |
115 | by one dev_link_t structure (defined in ds.h). | 104 | by one dev_link_t structure (defined in ds.h). |
@@ -119,15 +108,7 @@ static dev_info_t dev_info = "airo_cs"; | |||
119 | device numbers are used to derive the corresponding array index. | 108 | device numbers are used to derive the corresponding array index. |
120 | */ | 109 | */ |
121 | 110 | ||
122 | static dev_link_t *dev_list = NULL; | ||
123 | |||
124 | /* | 111 | /* |
125 | A dev_link_t structure has fields for most things that are needed | ||
126 | to keep track of a socket, but there will usually be some device | ||
127 | specific information that also needs to be kept track of. The | ||
128 | 'priv' pointer in a dev_link_t structure can be used to point to | ||
129 | a device-specific private data structure, like this. | ||
130 | |||
131 | A driver needs to provide a dev_node_t structure for each device | 112 | A driver needs to provide a dev_node_t structure for each device |
132 | on a card. In some cases, there is only one device per card (for | 113 | on a card. In some cases, there is only one device per card (for |
133 | example, ethernet cards, modems). In other cases, there may be | 114 | example, ethernet cards, modems). In other cases, there may be |
@@ -160,20 +141,18 @@ typedef struct local_info_t { | |||
160 | 141 | ||
161 | ======================================================================*/ | 142 | ======================================================================*/ |
162 | 143 | ||
163 | static dev_link_t *airo_attach(void) | 144 | static int airo_attach(struct pcmcia_device *p_dev) |
164 | { | 145 | { |
165 | client_reg_t client_reg; | ||
166 | dev_link_t *link; | 146 | dev_link_t *link; |
167 | local_info_t *local; | 147 | local_info_t *local; |
168 | int ret; | 148 | |
169 | |||
170 | DEBUG(0, "airo_attach()\n"); | 149 | DEBUG(0, "airo_attach()\n"); |
171 | 150 | ||
172 | /* Initialize the dev_link_t structure */ | 151 | /* Initialize the dev_link_t structure */ |
173 | link = kzalloc(sizeof(struct dev_link_t), GFP_KERNEL); | 152 | link = kzalloc(sizeof(struct dev_link_t), GFP_KERNEL); |
174 | if (!link) { | 153 | if (!link) { |
175 | printk(KERN_ERR "airo_cs: no memory for new device\n"); | 154 | printk(KERN_ERR "airo_cs: no memory for new device\n"); |
176 | return NULL; | 155 | return -ENOMEM; |
177 | } | 156 | } |
178 | 157 | ||
179 | /* Interrupt setup */ | 158 | /* Interrupt setup */ |
@@ -197,24 +176,17 @@ static dev_link_t *airo_attach(void) | |||
197 | if (!local) { | 176 | if (!local) { |
198 | printk(KERN_ERR "airo_cs: no memory for new device\n"); | 177 | printk(KERN_ERR "airo_cs: no memory for new device\n"); |
199 | kfree (link); | 178 | kfree (link); |
200 | return NULL; | 179 | return -ENOMEM; |
201 | } | 180 | } |
202 | link->priv = local; | 181 | link->priv = local; |
203 | 182 | ||
204 | /* Register with Card Services */ | 183 | link->handle = p_dev; |
205 | link->next = dev_list; | 184 | p_dev->instance = link; |
206 | dev_list = link; | 185 | |
207 | client_reg.dev_info = &dev_info; | 186 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
208 | client_reg.Version = 0x0210; | 187 | airo_config(link); |
209 | client_reg.event_callback_args.client_data = link; | 188 | |
210 | ret = pcmcia_register_client(&link->handle, &client_reg); | 189 | return 0; |
211 | if (ret != 0) { | ||
212 | cs_error(link->handle, RegisterClient, ret); | ||
213 | airo_detach(link); | ||
214 | return NULL; | ||
215 | } | ||
216 | |||
217 | return link; | ||
218 | } /* airo_attach */ | 190 | } /* airo_attach */ |
219 | 191 | ||
220 | /*====================================================================== | 192 | /*====================================================================== |
@@ -226,37 +198,22 @@ static dev_link_t *airo_attach(void) | |||
226 | 198 | ||
227 | ======================================================================*/ | 199 | ======================================================================*/ |
228 | 200 | ||
229 | static void airo_detach(dev_link_t *link) | 201 | static void airo_detach(struct pcmcia_device *p_dev) |
230 | { | 202 | { |
231 | dev_link_t **linkp; | 203 | dev_link_t *link = dev_to_instance(p_dev); |
232 | 204 | ||
233 | DEBUG(0, "airo_detach(0x%p)\n", link); | 205 | DEBUG(0, "airo_detach(0x%p)\n", link); |
234 | 206 | ||
235 | /* Locate device structure */ | ||
236 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
237 | if (*linkp == link) break; | ||
238 | if (*linkp == NULL) | ||
239 | return; | ||
240 | |||
241 | if (link->state & DEV_CONFIG) | 207 | if (link->state & DEV_CONFIG) |
242 | airo_release(link); | 208 | airo_release(link); |
243 | 209 | ||
244 | if ( ((local_info_t*)link->priv)->eth_dev ) { | 210 | if ( ((local_info_t*)link->priv)->eth_dev ) { |
245 | stop_airo_card( ((local_info_t*)link->priv)->eth_dev, 0 ); | 211 | stop_airo_card( ((local_info_t*)link->priv)->eth_dev, 0 ); |
246 | } | 212 | } |
247 | ((local_info_t*)link->priv)->eth_dev = NULL; | 213 | ((local_info_t*)link->priv)->eth_dev = NULL; |
248 | 214 | ||
249 | /* Break the link with Card Services */ | ||
250 | if (link->handle) | ||
251 | pcmcia_deregister_client(link->handle); | ||
252 | |||
253 | |||
254 | |||
255 | /* Unlink device structure, free pieces */ | ||
256 | *linkp = link->next; | ||
257 | kfree(link->priv); | 215 | kfree(link->priv); |
258 | kfree(link); | 216 | kfree(link); |
259 | |||
260 | } /* airo_detach */ | 217 | } /* airo_detach */ |
261 | 218 | ||
262 | /*====================================================================== | 219 | /*====================================================================== |
@@ -492,60 +449,34 @@ static void airo_release(dev_link_t *link) | |||
492 | link->state &= ~DEV_CONFIG; | 449 | link->state &= ~DEV_CONFIG; |
493 | } | 450 | } |
494 | 451 | ||
495 | /*====================================================================== | 452 | static int airo_suspend(struct pcmcia_device *p_dev) |
496 | 453 | { | |
497 | The card status event handler. Mostly, this schedules other | 454 | dev_link_t *link = dev_to_instance(p_dev); |
498 | stuff to run after an event is received. | 455 | local_info_t *local = link->priv; |
499 | 456 | ||
500 | When a CARD_REMOVAL event is received, we immediately set a | 457 | link->state |= DEV_SUSPEND; |
501 | private flag to block future accesses to this device. All the | 458 | if (link->state & DEV_CONFIG) { |
502 | functions that actually access the device should check this flag | 459 | netif_device_detach(local->eth_dev); |
503 | to make sure the card is still present. | 460 | pcmcia_release_configuration(link->handle); |
504 | 461 | } | |
505 | ======================================================================*/ | 462 | |
463 | return 0; | ||
464 | } | ||
506 | 465 | ||
507 | static int airo_event(event_t event, int priority, | 466 | static int airo_resume(struct pcmcia_device *p_dev) |
508 | event_callback_args_t *args) | ||
509 | { | 467 | { |
510 | dev_link_t *link = args->client_data; | 468 | dev_link_t *link = dev_to_instance(p_dev); |
511 | local_info_t *local = link->priv; | 469 | local_info_t *local = link->priv; |
512 | 470 | ||
513 | DEBUG(1, "airo_event(0x%06x)\n", event); | 471 | link->state &= ~DEV_SUSPEND; |
514 | 472 | if (link->state & DEV_CONFIG) { | |
515 | switch (event) { | 473 | pcmcia_request_configuration(link->handle, &link->conf); |
516 | case CS_EVENT_CARD_REMOVAL: | 474 | reset_airo_card(local->eth_dev); |
517 | link->state &= ~DEV_PRESENT; | 475 | netif_device_attach(local->eth_dev); |
518 | if (link->state & DEV_CONFIG) { | ||
519 | netif_device_detach(local->eth_dev); | ||
520 | airo_release(link); | ||
521 | } | ||
522 | break; | ||
523 | case CS_EVENT_CARD_INSERTION: | ||
524 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
525 | airo_config(link); | ||
526 | break; | ||
527 | case CS_EVENT_PM_SUSPEND: | ||
528 | link->state |= DEV_SUSPEND; | ||
529 | /* Fall through... */ | ||
530 | case CS_EVENT_RESET_PHYSICAL: | ||
531 | if (link->state & DEV_CONFIG) { | ||
532 | netif_device_detach(local->eth_dev); | ||
533 | pcmcia_release_configuration(link->handle); | ||
534 | } | ||
535 | break; | ||
536 | case CS_EVENT_PM_RESUME: | ||
537 | link->state &= ~DEV_SUSPEND; | ||
538 | /* Fall through... */ | ||
539 | case CS_EVENT_CARD_RESET: | ||
540 | if (link->state & DEV_CONFIG) { | ||
541 | pcmcia_request_configuration(link->handle, &link->conf); | ||
542 | reset_airo_card(local->eth_dev); | ||
543 | netif_device_attach(local->eth_dev); | ||
544 | } | ||
545 | break; | ||
546 | } | 476 | } |
477 | |||
547 | return 0; | 478 | return 0; |
548 | } /* airo_event */ | 479 | } |
549 | 480 | ||
550 | static struct pcmcia_device_id airo_ids[] = { | 481 | static struct pcmcia_device_id airo_ids[] = { |
551 | PCMCIA_DEVICE_MANF_CARD(0x015f, 0x000a), | 482 | PCMCIA_DEVICE_MANF_CARD(0x015f, 0x000a), |
@@ -561,10 +492,11 @@ static struct pcmcia_driver airo_driver = { | |||
561 | .drv = { | 492 | .drv = { |
562 | .name = "airo_cs", | 493 | .name = "airo_cs", |
563 | }, | 494 | }, |
564 | .attach = airo_attach, | 495 | .probe = airo_attach, |
565 | .event = airo_event, | 496 | .remove = airo_detach, |
566 | .detach = airo_detach, | ||
567 | .id_table = airo_ids, | 497 | .id_table = airo_ids, |
498 | .suspend = airo_suspend, | ||
499 | .resume = airo_resume, | ||
568 | }; | 500 | }; |
569 | 501 | ||
570 | static int airo_cs_init(void) | 502 | static int airo_cs_init(void) |
@@ -575,7 +507,6 @@ static int airo_cs_init(void) | |||
575 | static void airo_cs_cleanup(void) | 507 | static void airo_cs_cleanup(void) |
576 | { | 508 | { |
577 | pcmcia_unregister_driver(&airo_driver); | 509 | pcmcia_unregister_driver(&airo_driver); |
578 | BUG_ON(dev_list != NULL); | ||
579 | } | 510 | } |
580 | 511 | ||
581 | /* | 512 | /* |
diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index 17d1fd90f832..d6f4a5a3e55a 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c | |||
@@ -93,8 +93,6 @@ MODULE_SUPPORTED_DEVICE("Atmel at76c50x PCMCIA cards"); | |||
93 | 93 | ||
94 | static void atmel_config(dev_link_t *link); | 94 | static void atmel_config(dev_link_t *link); |
95 | static void atmel_release(dev_link_t *link); | 95 | static void atmel_release(dev_link_t *link); |
96 | static int atmel_event(event_t event, int priority, | ||
97 | event_callback_args_t *args); | ||
98 | 96 | ||
99 | /* | 97 | /* |
100 | The attach() and detach() entry points are used to create and destroy | 98 | The attach() and detach() entry points are used to create and destroy |
@@ -102,8 +100,7 @@ static int atmel_event(event_t event, int priority, | |||
102 | needed to manage one actual PCMCIA card. | 100 | needed to manage one actual PCMCIA card. |
103 | */ | 101 | */ |
104 | 102 | ||
105 | static dev_link_t *atmel_attach(void); | 103 | static void atmel_detach(struct pcmcia_device *p_dev); |
106 | static void atmel_detach(dev_link_t *); | ||
107 | 104 | ||
108 | /* | 105 | /* |
109 | You'll also need to prototype all the functions that will actually | 106 | You'll also need to prototype all the functions that will actually |
@@ -113,14 +110,6 @@ static void atmel_detach(dev_link_t *); | |||
113 | */ | 110 | */ |
114 | 111 | ||
115 | /* | 112 | /* |
116 | The dev_info variable is the "key" that is used to match up this | ||
117 | device driver with appropriate cards, through the card configuration | ||
118 | database. | ||
119 | */ | ||
120 | |||
121 | static dev_info_t dev_info = "atmel_cs"; | ||
122 | |||
123 | /* | ||
124 | A linked list of "instances" of the atmelnet device. Each actual | 113 | A linked list of "instances" of the atmelnet device. Each actual |
125 | PCMCIA card corresponds to one device instance, and is described | 114 | PCMCIA card corresponds to one device instance, and is described |
126 | by one dev_link_t structure (defined in ds.h). | 115 | by one dev_link_t structure (defined in ds.h). |
@@ -130,15 +119,7 @@ static dev_info_t dev_info = "atmel_cs"; | |||
130 | device numbers are used to derive the corresponding array index. | 119 | device numbers are used to derive the corresponding array index. |
131 | */ | 120 | */ |
132 | 121 | ||
133 | static dev_link_t *dev_list = NULL; | ||
134 | |||
135 | /* | 122 | /* |
136 | A dev_link_t structure has fields for most things that are needed | ||
137 | to keep track of a socket, but there will usually be some device | ||
138 | specific information that also needs to be kept track of. The | ||
139 | 'priv' pointer in a dev_link_t structure can be used to point to | ||
140 | a device-specific private data structure, like this. | ||
141 | |||
142 | A driver needs to provide a dev_node_t structure for each device | 123 | A driver needs to provide a dev_node_t structure for each device |
143 | on a card. In some cases, there is only one device per card (for | 124 | on a card. In some cases, there is only one device per card (for |
144 | example, ethernet cards, modems). In other cases, there may be | 125 | example, ethernet cards, modems). In other cases, there may be |
@@ -171,27 +152,25 @@ typedef struct local_info_t { | |||
171 | 152 | ||
172 | ======================================================================*/ | 153 | ======================================================================*/ |
173 | 154 | ||
174 | static dev_link_t *atmel_attach(void) | 155 | static int atmel_attach(struct pcmcia_device *p_dev) |
175 | { | 156 | { |
176 | client_reg_t client_reg; | ||
177 | dev_link_t *link; | 157 | dev_link_t *link; |
178 | local_info_t *local; | 158 | local_info_t *local; |
179 | int ret; | 159 | |
180 | |||
181 | DEBUG(0, "atmel_attach()\n"); | 160 | DEBUG(0, "atmel_attach()\n"); |
182 | 161 | ||
183 | /* Initialize the dev_link_t structure */ | 162 | /* Initialize the dev_link_t structure */ |
184 | link = kzalloc(sizeof(struct dev_link_t), GFP_KERNEL); | 163 | link = kzalloc(sizeof(struct dev_link_t), GFP_KERNEL); |
185 | if (!link) { | 164 | if (!link) { |
186 | printk(KERN_ERR "atmel_cs: no memory for new device\n"); | 165 | printk(KERN_ERR "atmel_cs: no memory for new device\n"); |
187 | return NULL; | 166 | return -ENOMEM; |
188 | } | 167 | } |
189 | 168 | ||
190 | /* Interrupt setup */ | 169 | /* Interrupt setup */ |
191 | link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; | 170 | link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; |
192 | link->irq.IRQInfo1 = IRQ_LEVEL_ID; | 171 | link->irq.IRQInfo1 = IRQ_LEVEL_ID; |
193 | link->irq.Handler = NULL; | 172 | link->irq.Handler = NULL; |
194 | 173 | ||
195 | /* | 174 | /* |
196 | General socket configuration defaults can go here. In this | 175 | General socket configuration defaults can go here. In this |
197 | client, we assume very little, and rely on the CIS for almost | 176 | client, we assume very little, and rely on the CIS for almost |
@@ -202,30 +181,23 @@ static dev_link_t *atmel_attach(void) | |||
202 | link->conf.Attributes = 0; | 181 | link->conf.Attributes = 0; |
203 | link->conf.Vcc = 50; | 182 | link->conf.Vcc = 50; |
204 | link->conf.IntType = INT_MEMORY_AND_IO; | 183 | link->conf.IntType = INT_MEMORY_AND_IO; |
205 | 184 | ||
206 | /* Allocate space for private device-specific data */ | 185 | /* Allocate space for private device-specific data */ |
207 | local = kzalloc(sizeof(local_info_t), GFP_KERNEL); | 186 | local = kzalloc(sizeof(local_info_t), GFP_KERNEL); |
208 | if (!local) { | 187 | if (!local) { |
209 | printk(KERN_ERR "atmel_cs: no memory for new device\n"); | 188 | printk(KERN_ERR "atmel_cs: no memory for new device\n"); |
210 | kfree (link); | 189 | kfree (link); |
211 | return NULL; | 190 | return -ENOMEM; |
212 | } | 191 | } |
213 | link->priv = local; | 192 | link->priv = local; |
214 | 193 | ||
215 | /* Register with Card Services */ | 194 | link->handle = p_dev; |
216 | link->next = dev_list; | 195 | p_dev->instance = link; |
217 | dev_list = link; | 196 | |
218 | client_reg.dev_info = &dev_info; | 197 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
219 | client_reg.Version = 0x0210; | 198 | atmel_config(link); |
220 | client_reg.event_callback_args.client_data = link; | 199 | |
221 | ret = pcmcia_register_client(&link->handle, &client_reg); | 200 | return 0; |
222 | if (ret != 0) { | ||
223 | cs_error(link->handle, RegisterClient, ret); | ||
224 | atmel_detach(link); | ||
225 | return NULL; | ||
226 | } | ||
227 | |||
228 | return link; | ||
229 | } /* atmel_attach */ | 201 | } /* atmel_attach */ |
230 | 202 | ||
231 | /*====================================================================== | 203 | /*====================================================================== |
@@ -237,27 +209,15 @@ static dev_link_t *atmel_attach(void) | |||
237 | 209 | ||
238 | ======================================================================*/ | 210 | ======================================================================*/ |
239 | 211 | ||
240 | static void atmel_detach(dev_link_t *link) | 212 | static void atmel_detach(struct pcmcia_device *p_dev) |
241 | { | 213 | { |
242 | dev_link_t **linkp; | 214 | dev_link_t *link = dev_to_instance(p_dev); |
243 | 215 | ||
244 | DEBUG(0, "atmel_detach(0x%p)\n", link); | 216 | DEBUG(0, "atmel_detach(0x%p)\n", link); |
245 | |||
246 | /* Locate device structure */ | ||
247 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
248 | if (*linkp == link) break; | ||
249 | if (*linkp == NULL) | ||
250 | return; | ||
251 | 217 | ||
252 | if (link->state & DEV_CONFIG) | 218 | if (link->state & DEV_CONFIG) |
253 | atmel_release(link); | 219 | atmel_release(link); |
254 | |||
255 | /* Break the link with Card Services */ | ||
256 | if (link->handle) | ||
257 | pcmcia_deregister_client(link->handle); | ||
258 | 220 | ||
259 | /* Unlink device structure, free pieces */ | ||
260 | *linkp = link->next; | ||
261 | kfree(link->priv); | 221 | kfree(link->priv); |
262 | kfree(link); | 222 | kfree(link); |
263 | } | 223 | } |
@@ -477,60 +437,34 @@ static void atmel_release(dev_link_t *link) | |||
477 | link->state &= ~DEV_CONFIG; | 437 | link->state &= ~DEV_CONFIG; |
478 | } | 438 | } |
479 | 439 | ||
480 | /*====================================================================== | 440 | static int atmel_suspend(struct pcmcia_device *dev) |
481 | 441 | { | |
482 | The card status event handler. Mostly, this schedules other | 442 | dev_link_t *link = dev_to_instance(dev); |
483 | stuff to run after an event is received. | 443 | local_info_t *local = link->priv; |
484 | 444 | ||
485 | When a CARD_REMOVAL event is received, we immediately set a | 445 | link->state |= DEV_SUSPEND; |
486 | private flag to block future accesses to this device. All the | 446 | if (link->state & DEV_CONFIG) { |
487 | functions that actually access the device should check this flag | 447 | netif_device_detach(local->eth_dev); |
488 | to make sure the card is still present. | 448 | pcmcia_release_configuration(link->handle); |
489 | 449 | } | |
490 | ======================================================================*/ | 450 | |
451 | return 0; | ||
452 | } | ||
491 | 453 | ||
492 | static int atmel_event(event_t event, int priority, | 454 | static int atmel_resume(struct pcmcia_device *dev) |
493 | event_callback_args_t *args) | ||
494 | { | 455 | { |
495 | dev_link_t *link = args->client_data; | 456 | dev_link_t *link = dev_to_instance(dev); |
496 | local_info_t *local = link->priv; | 457 | local_info_t *local = link->priv; |
497 | 458 | ||
498 | DEBUG(1, "atmel_event(0x%06x)\n", event); | 459 | link->state &= ~DEV_SUSPEND; |
499 | 460 | if (link->state & DEV_CONFIG) { | |
500 | switch (event) { | 461 | pcmcia_request_configuration(link->handle, &link->conf); |
501 | case CS_EVENT_CARD_REMOVAL: | 462 | atmel_open(local->eth_dev); |
502 | link->state &= ~DEV_PRESENT; | 463 | netif_device_attach(local->eth_dev); |
503 | if (link->state & DEV_CONFIG) { | ||
504 | netif_device_detach(local->eth_dev); | ||
505 | atmel_release(link); | ||
506 | } | ||
507 | break; | ||
508 | case CS_EVENT_CARD_INSERTION: | ||
509 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
510 | atmel_config(link); | ||
511 | break; | ||
512 | case CS_EVENT_PM_SUSPEND: | ||
513 | link->state |= DEV_SUSPEND; | ||
514 | /* Fall through... */ | ||
515 | case CS_EVENT_RESET_PHYSICAL: | ||
516 | if (link->state & DEV_CONFIG) { | ||
517 | netif_device_detach(local->eth_dev); | ||
518 | pcmcia_release_configuration(link->handle); | ||
519 | } | ||
520 | break; | ||
521 | case CS_EVENT_PM_RESUME: | ||
522 | link->state &= ~DEV_SUSPEND; | ||
523 | /* Fall through... */ | ||
524 | case CS_EVENT_CARD_RESET: | ||
525 | if (link->state & DEV_CONFIG) { | ||
526 | pcmcia_request_configuration(link->handle, &link->conf); | ||
527 | atmel_open(local->eth_dev); | ||
528 | netif_device_attach(local->eth_dev); | ||
529 | } | ||
530 | break; | ||
531 | } | 464 | } |
465 | |||
532 | return 0; | 466 | return 0; |
533 | } /* atmel_event */ | 467 | } |
534 | 468 | ||
535 | /*====================================================================*/ | 469 | /*====================================================================*/ |
536 | /* We use the driver_info field to store the correct firmware type for a card. */ | 470 | /* We use the driver_info field to store the correct firmware type for a card. */ |
@@ -581,10 +515,11 @@ static struct pcmcia_driver atmel_driver = { | |||
581 | .drv = { | 515 | .drv = { |
582 | .name = "atmel_cs", | 516 | .name = "atmel_cs", |
583 | }, | 517 | }, |
584 | .attach = atmel_attach, | 518 | .probe = atmel_attach, |
585 | .event = atmel_event, | 519 | .remove = atmel_detach, |
586 | .detach = atmel_detach, | ||
587 | .id_table = atmel_ids, | 520 | .id_table = atmel_ids, |
521 | .suspend = atmel_suspend, | ||
522 | .resume = atmel_resume, | ||
588 | }; | 523 | }; |
589 | 524 | ||
590 | static int atmel_cs_init(void) | 525 | static int atmel_cs_init(void) |
@@ -595,7 +530,6 @@ static int atmel_cs_init(void) | |||
595 | static void atmel_cs_cleanup(void) | 530 | static void atmel_cs_cleanup(void) |
596 | { | 531 | { |
597 | pcmcia_unregister_driver(&atmel_driver); | 532 | pcmcia_unregister_driver(&atmel_driver); |
598 | BUG_ON(dev_list != NULL); | ||
599 | } | 533 | } |
600 | 534 | ||
601 | /* | 535 | /* |
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index 2643976a6677..8bc0b528548f 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c | |||
@@ -25,7 +25,6 @@ | |||
25 | 25 | ||
26 | static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)"; | 26 | static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)"; |
27 | static dev_info_t dev_info = "hostap_cs"; | 27 | static dev_info_t dev_info = "hostap_cs"; |
28 | static dev_link_t *dev_list = NULL; | ||
29 | 28 | ||
30 | MODULE_AUTHOR("Jouni Malinen"); | 29 | MODULE_AUTHOR("Jouni Malinen"); |
31 | MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN " | 30 | MODULE_DESCRIPTION("Support for Intersil Prism2-based 802.11 wireless LAN " |
@@ -203,10 +202,9 @@ static int hfa384x_to_bap(struct net_device *dev, u16 bap, void *buf, int len) | |||
203 | 202 | ||
204 | 203 | ||
205 | 204 | ||
206 | static void prism2_detach(dev_link_t *link); | 205 | static void prism2_detach(struct pcmcia_device *p_dev); |
207 | static void prism2_release(u_long arg); | 206 | static void prism2_release(u_long arg); |
208 | static int prism2_event(event_t event, int priority, | 207 | static int prism2_config(dev_link_t *link); |
209 | event_callback_args_t *args); | ||
210 | 208 | ||
211 | 209 | ||
212 | static int prism2_pccard_card_present(local_info_t *local) | 210 | static int prism2_pccard_card_present(local_info_t *local) |
@@ -503,15 +501,13 @@ static struct prism2_helper_functions prism2_pccard_funcs = | |||
503 | 501 | ||
504 | /* allocate local data and register with CardServices | 502 | /* allocate local data and register with CardServices |
505 | * initialize dev_link structure, but do not configure the card yet */ | 503 | * initialize dev_link structure, but do not configure the card yet */ |
506 | static dev_link_t *prism2_attach(void) | 504 | static int prism2_attach(struct pcmcia_device *p_dev) |
507 | { | 505 | { |
508 | dev_link_t *link; | 506 | dev_link_t *link; |
509 | client_reg_t client_reg; | ||
510 | int ret; | ||
511 | 507 | ||
512 | link = kmalloc(sizeof(dev_link_t), GFP_KERNEL); | 508 | link = kmalloc(sizeof(dev_link_t), GFP_KERNEL); |
513 | if (link == NULL) | 509 | if (link == NULL) |
514 | return NULL; | 510 | return -ENOMEM; |
515 | 511 | ||
516 | memset(link, 0, sizeof(dev_link_t)); | 512 | memset(link, 0, sizeof(dev_link_t)); |
517 | 513 | ||
@@ -519,50 +515,27 @@ static dev_link_t *prism2_attach(void) | |||
519 | link->conf.Vcc = 33; | 515 | link->conf.Vcc = 33; |
520 | link->conf.IntType = INT_MEMORY_AND_IO; | 516 | link->conf.IntType = INT_MEMORY_AND_IO; |
521 | 517 | ||
522 | /* register with CardServices */ | 518 | link->handle = p_dev; |
523 | link->next = dev_list; | 519 | p_dev->instance = link; |
524 | dev_list = link; | 520 | |
525 | client_reg.dev_info = &dev_info; | 521 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
526 | client_reg.Version = 0x0210; | 522 | if (prism2_config(link)) |
527 | client_reg.event_callback_args.client_data = link; | 523 | PDEBUG(DEBUG_EXTRA, "prism2_config() failed\n"); |
528 | ret = pcmcia_register_client(&link->handle, &client_reg); | 524 | |
529 | if (ret != CS_SUCCESS) { | 525 | return 0; |
530 | cs_error(link->handle, RegisterClient, ret); | ||
531 | prism2_detach(link); | ||
532 | return NULL; | ||
533 | } | ||
534 | return link; | ||
535 | } | 526 | } |
536 | 527 | ||
537 | 528 | ||
538 | static void prism2_detach(dev_link_t *link) | 529 | static void prism2_detach(struct pcmcia_device *p_dev) |
539 | { | 530 | { |
540 | dev_link_t **linkp; | 531 | dev_link_t *link = dev_to_instance(p_dev); |
541 | 532 | ||
542 | PDEBUG(DEBUG_FLOW, "prism2_detach\n"); | 533 | PDEBUG(DEBUG_FLOW, "prism2_detach\n"); |
543 | 534 | ||
544 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
545 | if (*linkp == link) | ||
546 | break; | ||
547 | if (*linkp == NULL) { | ||
548 | printk(KERN_WARNING "%s: Attempt to detach non-existing " | ||
549 | "PCMCIA client\n", dev_info); | ||
550 | return; | ||
551 | } | ||
552 | |||
553 | if (link->state & DEV_CONFIG) { | 535 | if (link->state & DEV_CONFIG) { |
554 | prism2_release((u_long)link); | 536 | prism2_release((u_long)link); |
555 | } | 537 | } |
556 | 538 | ||
557 | if (link->handle) { | ||
558 | int res = pcmcia_deregister_client(link->handle); | ||
559 | if (res) { | ||
560 | printk("CardService(DeregisterClient) => %d\n", res); | ||
561 | cs_error(link->handle, DeregisterClient, res); | ||
562 | } | ||
563 | } | ||
564 | |||
565 | *linkp = link->next; | ||
566 | /* release net devices */ | 539 | /* release net devices */ |
567 | if (link->priv) { | 540 | if (link->priv) { |
568 | struct hostap_cs_priv *hw_priv; | 541 | struct hostap_cs_priv *hw_priv; |
@@ -846,84 +819,58 @@ static void prism2_release(u_long arg) | |||
846 | PDEBUG(DEBUG_FLOW, "release - done\n"); | 819 | PDEBUG(DEBUG_FLOW, "release - done\n"); |
847 | } | 820 | } |
848 | 821 | ||
849 | 822 | static int hostap_cs_suspend(struct pcmcia_device *p_dev) | |
850 | static int prism2_event(event_t event, int priority, | ||
851 | event_callback_args_t *args) | ||
852 | { | 823 | { |
853 | dev_link_t *link = args->client_data; | 824 | dev_link_t *link = dev_to_instance(p_dev); |
854 | struct net_device *dev = (struct net_device *) link->priv; | 825 | struct net_device *dev = (struct net_device *) link->priv; |
855 | int dev_open = 0; | 826 | int dev_open = 0; |
856 | 827 | ||
828 | PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_SUSPEND\n", dev_info); | ||
829 | |||
830 | link->state |= DEV_SUSPEND; | ||
831 | |||
857 | if (link->state & DEV_CONFIG) { | 832 | if (link->state & DEV_CONFIG) { |
858 | struct hostap_interface *iface = netdev_priv(dev); | 833 | struct hostap_interface *iface = netdev_priv(dev); |
859 | if (iface && iface->local) | 834 | if (iface && iface->local) |
860 | dev_open = iface->local->num_dev_open > 0; | 835 | dev_open = iface->local->num_dev_open > 0; |
861 | } | 836 | if (dev_open) { |
862 | |||
863 | switch (event) { | ||
864 | case CS_EVENT_CARD_INSERTION: | ||
865 | PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_CARD_INSERTION\n", dev_info); | ||
866 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
867 | if (prism2_config(link)) { | ||
868 | PDEBUG(DEBUG_EXTRA, "prism2_config() failed\n"); | ||
869 | } | ||
870 | break; | ||
871 | |||
872 | case CS_EVENT_CARD_REMOVAL: | ||
873 | PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_CARD_REMOVAL\n", dev_info); | ||
874 | link->state &= ~DEV_PRESENT; | ||
875 | if (link->state & DEV_CONFIG) { | ||
876 | netif_stop_queue(dev); | 837 | netif_stop_queue(dev); |
877 | netif_device_detach(dev); | 838 | netif_device_detach(dev); |
878 | prism2_release((u_long) link); | ||
879 | } | 839 | } |
880 | break; | 840 | prism2_suspend(dev); |
841 | pcmcia_release_configuration(link->handle); | ||
842 | } | ||
881 | 843 | ||
882 | case CS_EVENT_PM_SUSPEND: | 844 | return 0; |
883 | PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_SUSPEND\n", dev_info); | 845 | } |
884 | link->state |= DEV_SUSPEND; | ||
885 | /* fall through */ | ||
886 | |||
887 | case CS_EVENT_RESET_PHYSICAL: | ||
888 | PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_RESET_PHYSICAL\n", dev_info); | ||
889 | if (link->state & DEV_CONFIG) { | ||
890 | if (dev_open) { | ||
891 | netif_stop_queue(dev); | ||
892 | netif_device_detach(dev); | ||
893 | } | ||
894 | prism2_suspend(dev); | ||
895 | pcmcia_release_configuration(link->handle); | ||
896 | } | ||
897 | break; | ||
898 | 846 | ||
899 | case CS_EVENT_PM_RESUME: | 847 | static int hostap_cs_resume(struct pcmcia_device *p_dev) |
900 | PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_RESUME\n", dev_info); | 848 | { |
901 | link->state &= ~DEV_SUSPEND; | 849 | dev_link_t *link = dev_to_instance(p_dev); |
902 | /* fall through */ | 850 | struct net_device *dev = (struct net_device *) link->priv; |
903 | 851 | int dev_open = 0; | |
904 | case CS_EVENT_CARD_RESET: | ||
905 | PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_CARD_RESET\n", dev_info); | ||
906 | if (link->state & DEV_CONFIG) { | ||
907 | pcmcia_request_configuration(link->handle, | ||
908 | &link->conf); | ||
909 | prism2_hw_shutdown(dev, 1); | ||
910 | prism2_hw_config(dev, dev_open ? 0 : 1); | ||
911 | if (dev_open) { | ||
912 | netif_device_attach(dev); | ||
913 | netif_start_queue(dev); | ||
914 | } | ||
915 | } | ||
916 | break; | ||
917 | 852 | ||
918 | default: | 853 | PDEBUG(DEBUG_EXTRA, "%s: CS_EVENT_PM_RESUME\n", dev_info); |
919 | PDEBUG(DEBUG_EXTRA, "%s: prism2_event() - unknown event %d\n", | 854 | |
920 | dev_info, event); | 855 | link->state &= ~DEV_SUSPEND; |
921 | break; | 856 | if (link->state & DEV_CONFIG) { |
857 | struct hostap_interface *iface = netdev_priv(dev); | ||
858 | if (iface && iface->local) | ||
859 | dev_open = iface->local->num_dev_open > 0; | ||
860 | |||
861 | pcmcia_request_configuration(link->handle, &link->conf); | ||
862 | |||
863 | prism2_hw_shutdown(dev, 1); | ||
864 | prism2_hw_config(dev, dev_open ? 0 : 1); | ||
865 | if (dev_open) { | ||
866 | netif_device_attach(dev); | ||
867 | netif_start_queue(dev); | ||
868 | } | ||
922 | } | 869 | } |
870 | |||
923 | return 0; | 871 | return 0; |
924 | } | 872 | } |
925 | 873 | ||
926 | |||
927 | static struct pcmcia_device_id hostap_cs_ids[] = { | 874 | static struct pcmcia_device_id hostap_cs_ids[] = { |
928 | PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), | 875 | PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7100), |
929 | PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), | 876 | PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), |
@@ -982,11 +929,12 @@ static struct pcmcia_driver hostap_driver = { | |||
982 | .drv = { | 929 | .drv = { |
983 | .name = "hostap_cs", | 930 | .name = "hostap_cs", |
984 | }, | 931 | }, |
985 | .attach = prism2_attach, | 932 | .probe = prism2_attach, |
986 | .detach = prism2_detach, | 933 | .remove = prism2_detach, |
987 | .owner = THIS_MODULE, | 934 | .owner = THIS_MODULE, |
988 | .event = prism2_event, | ||
989 | .id_table = hostap_cs_ids, | 935 | .id_table = hostap_cs_ids, |
936 | .suspend = hostap_cs_suspend, | ||
937 | .resume = hostap_cs_resume, | ||
990 | }; | 938 | }; |
991 | 939 | ||
992 | static int __init init_prism2_pccard(void) | 940 | static int __init init_prism2_pccard(void) |
diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index 92793b958e32..bf6271ee387a 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c | |||
@@ -166,8 +166,6 @@ static char *version = | |||
166 | #define DEBUG(n, args...) | 166 | #define DEBUG(n, args...) |
167 | #endif | 167 | #endif |
168 | 168 | ||
169 | static dev_info_t dev_info = "netwave_cs"; | ||
170 | |||
171 | /*====================================================================*/ | 169 | /*====================================================================*/ |
172 | 170 | ||
173 | /* Parameters that can be set with 'insmod' */ | 171 | /* Parameters that can be set with 'insmod' */ |
@@ -195,12 +193,9 @@ module_param(mem_speed, int, 0); | |||
195 | 193 | ||
196 | /* PCMCIA (Card Services) related functions */ | 194 | /* PCMCIA (Card Services) related functions */ |
197 | static void netwave_release(dev_link_t *link); /* Card removal */ | 195 | static void netwave_release(dev_link_t *link); /* Card removal */ |
198 | static int netwave_event(event_t event, int priority, | ||
199 | event_callback_args_t *args); | ||
200 | static void netwave_pcmcia_config(dev_link_t *arg); /* Runs after card | 196 | static void netwave_pcmcia_config(dev_link_t *arg); /* Runs after card |
201 | insertion */ | 197 | insertion */ |
202 | static dev_link_t *netwave_attach(void); /* Create instance */ | 198 | static void netwave_detach(struct pcmcia_device *p_dev); /* Destroy instance */ |
203 | static void netwave_detach(dev_link_t *); /* Destroy instance */ | ||
204 | 199 | ||
205 | /* Hardware configuration */ | 200 | /* Hardware configuration */ |
206 | static void netwave_doreset(kio_addr_t iobase, u_char __iomem *ramBase); | 201 | static void netwave_doreset(kio_addr_t iobase, u_char __iomem *ramBase); |
@@ -228,17 +223,6 @@ static struct iw_statistics* netwave_get_wireless_stats(struct net_device *dev); | |||
228 | static void set_multicast_list(struct net_device *dev); | 223 | static void set_multicast_list(struct net_device *dev); |
229 | 224 | ||
230 | /* | 225 | /* |
231 | A linked list of "instances" of the skeleton device. Each actual | ||
232 | PCMCIA card corresponds to one device instance, and is described | ||
233 | by one dev_link_t structure (defined in ds.h). | ||
234 | |||
235 | You may not want to use a linked list for this -- for example, the | ||
236 | memory card driver uses an array of dev_link_t pointers, where minor | ||
237 | device numbers are used to derive the corresponding array index. | ||
238 | */ | ||
239 | static dev_link_t *dev_list; | ||
240 | |||
241 | /* | ||
242 | A dev_link_t structure has fields for most things that are needed | 226 | A dev_link_t structure has fields for most things that are needed |
243 | to keep track of a socket, but there will usually be some device | 227 | to keep track of a socket, but there will usually be some device |
244 | specific information that also needs to be kept track of. The | 228 | specific information that also needs to be kept track of. The |
@@ -394,20 +378,18 @@ static struct iw_statistics *netwave_get_wireless_stats(struct net_device *dev) | |||
394 | * configure the card at this point -- we wait until we receive a | 378 | * configure the card at this point -- we wait until we receive a |
395 | * card insertion event. | 379 | * card insertion event. |
396 | */ | 380 | */ |
397 | static dev_link_t *netwave_attach(void) | 381 | static int netwave_attach(struct pcmcia_device *p_dev) |
398 | { | 382 | { |
399 | client_reg_t client_reg; | ||
400 | dev_link_t *link; | 383 | dev_link_t *link; |
401 | struct net_device *dev; | 384 | struct net_device *dev; |
402 | netwave_private *priv; | 385 | netwave_private *priv; |
403 | int ret; | 386 | |
404 | |||
405 | DEBUG(0, "netwave_attach()\n"); | 387 | DEBUG(0, "netwave_attach()\n"); |
406 | 388 | ||
407 | /* Initialize the dev_link_t structure */ | 389 | /* Initialize the dev_link_t structure */ |
408 | dev = alloc_etherdev(sizeof(netwave_private)); | 390 | dev = alloc_etherdev(sizeof(netwave_private)); |
409 | if (!dev) | 391 | if (!dev) |
410 | return NULL; | 392 | return -ENOMEM; |
411 | priv = netdev_priv(dev); | 393 | priv = netdev_priv(dev); |
412 | link = &priv->link; | 394 | link = &priv->link; |
413 | link->priv = dev; | 395 | link->priv = dev; |
@@ -449,21 +431,14 @@ static dev_link_t *netwave_attach(void) | |||
449 | dev->open = &netwave_open; | 431 | dev->open = &netwave_open; |
450 | dev->stop = &netwave_close; | 432 | dev->stop = &netwave_close; |
451 | link->irq.Instance = dev; | 433 | link->irq.Instance = dev; |
452 | |||
453 | /* Register with Card Services */ | ||
454 | link->next = dev_list; | ||
455 | dev_list = link; | ||
456 | client_reg.dev_info = &dev_info; | ||
457 | client_reg.Version = 0x0210; | ||
458 | client_reg.event_callback_args.client_data = link; | ||
459 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
460 | if (ret != 0) { | ||
461 | cs_error(link->handle, RegisterClient, ret); | ||
462 | netwave_detach(link); | ||
463 | return NULL; | ||
464 | } | ||
465 | 434 | ||
466 | return link; | 435 | link->handle = p_dev; |
436 | p_dev->instance = link; | ||
437 | |||
438 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
439 | netwave_pcmcia_config( link); | ||
440 | |||
441 | return 0; | ||
467 | } /* netwave_attach */ | 442 | } /* netwave_attach */ |
468 | 443 | ||
469 | /* | 444 | /* |
@@ -474,42 +449,20 @@ static dev_link_t *netwave_attach(void) | |||
474 | * structures are freed. Otherwise, the structures will be freed | 449 | * structures are freed. Otherwise, the structures will be freed |
475 | * when the device is released. | 450 | * when the device is released. |
476 | */ | 451 | */ |
477 | static void netwave_detach(dev_link_t *link) | 452 | static void netwave_detach(struct pcmcia_device *p_dev) |
478 | { | 453 | { |
479 | struct net_device *dev = link->priv; | 454 | dev_link_t *link = dev_to_instance(p_dev); |
480 | dev_link_t **linkp; | 455 | struct net_device *dev = link->priv; |
481 | 456 | ||
482 | DEBUG(0, "netwave_detach(0x%p)\n", link); | 457 | DEBUG(0, "netwave_detach(0x%p)\n", link); |
483 | 458 | ||
484 | /* | 459 | if (link->state & DEV_CONFIG) |
485 | If the device is currently configured and active, we won't | 460 | netwave_release(link); |
486 | actually delete it yet. Instead, it is marked so that when | 461 | |
487 | the release() function is called, that will trigger a proper | 462 | if (link->dev) |
488 | detach(). | 463 | unregister_netdev(dev); |
489 | */ | 464 | |
490 | if (link->state & DEV_CONFIG) | 465 | free_netdev(dev); |
491 | netwave_release(link); | ||
492 | |||
493 | /* Break the link with Card Services */ | ||
494 | if (link->handle) | ||
495 | pcmcia_deregister_client(link->handle); | ||
496 | |||
497 | /* Locate device structure */ | ||
498 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
499 | if (*linkp == link) break; | ||
500 | if (*linkp == NULL) | ||
501 | { | ||
502 | DEBUG(1, "netwave_cs: detach fail, '%s' not in list\n", | ||
503 | link->dev->dev_name); | ||
504 | return; | ||
505 | } | ||
506 | |||
507 | /* Unlink device structure, free pieces */ | ||
508 | *linkp = link->next; | ||
509 | if (link->dev) | ||
510 | unregister_netdev(dev); | ||
511 | free_netdev(dev); | ||
512 | |||
513 | } /* netwave_detach */ | 466 | } /* netwave_detach */ |
514 | 467 | ||
515 | /* | 468 | /* |
@@ -935,69 +888,38 @@ static void netwave_release(dev_link_t *link) | |||
935 | link->state &= ~DEV_CONFIG; | 888 | link->state &= ~DEV_CONFIG; |
936 | } | 889 | } |
937 | 890 | ||
938 | /* | 891 | static int netwave_suspend(struct pcmcia_device *p_dev) |
939 | * Function netwave_event (event, priority, args) | ||
940 | * | ||
941 | * The card status event handler. Mostly, this schedules other | ||
942 | * stuff to run after an event is received. A CARD_REMOVAL event | ||
943 | * also sets some flags to discourage the net drivers from trying | ||
944 | * to talk to the card any more. | ||
945 | * | ||
946 | * When a CARD_REMOVAL event is received, we immediately set a flag | ||
947 | * to block future accesses to this device. All the functions that | ||
948 | * actually access the device should check this flag to make sure | ||
949 | * the card is still present. | ||
950 | * | ||
951 | */ | ||
952 | static int netwave_event(event_t event, int priority, | ||
953 | event_callback_args_t *args) | ||
954 | { | 892 | { |
955 | dev_link_t *link = args->client_data; | 893 | dev_link_t *link = dev_to_instance(p_dev); |
956 | struct net_device *dev = link->priv; | 894 | struct net_device *dev = link->priv; |
957 | 895 | ||
958 | DEBUG(1, "netwave_event(0x%06x)\n", event); | ||
959 | |||
960 | switch (event) { | ||
961 | case CS_EVENT_REGISTRATION_COMPLETE: | ||
962 | DEBUG(0, "netwave_cs: registration complete\n"); | ||
963 | break; | ||
964 | |||
965 | case CS_EVENT_CARD_REMOVAL: | ||
966 | link->state &= ~DEV_PRESENT; | ||
967 | if (link->state & DEV_CONFIG) { | ||
968 | netif_device_detach(dev); | ||
969 | netwave_release(link); | ||
970 | } | ||
971 | break; | ||
972 | case CS_EVENT_CARD_INSERTION: | ||
973 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
974 | netwave_pcmcia_config( link); | ||
975 | break; | ||
976 | case CS_EVENT_PM_SUSPEND: | ||
977 | link->state |= DEV_SUSPEND; | 896 | link->state |= DEV_SUSPEND; |
978 | /* Fall through... */ | ||
979 | case CS_EVENT_RESET_PHYSICAL: | ||
980 | if (link->state & DEV_CONFIG) { | 897 | if (link->state & DEV_CONFIG) { |
981 | if (link->open) | 898 | if (link->open) |
982 | netif_device_detach(dev); | 899 | netif_device_detach(dev); |
983 | pcmcia_release_configuration(link->handle); | 900 | pcmcia_release_configuration(link->handle); |
984 | } | 901 | } |
985 | break; | 902 | |
986 | case CS_EVENT_PM_RESUME: | 903 | return 0; |
904 | } | ||
905 | |||
906 | static int netwave_resume(struct pcmcia_device *p_dev) | ||
907 | { | ||
908 | dev_link_t *link = dev_to_instance(p_dev); | ||
909 | struct net_device *dev = link->priv; | ||
910 | |||
987 | link->state &= ~DEV_SUSPEND; | 911 | link->state &= ~DEV_SUSPEND; |
988 | /* Fall through... */ | ||
989 | case CS_EVENT_CARD_RESET: | ||
990 | if (link->state & DEV_CONFIG) { | 912 | if (link->state & DEV_CONFIG) { |
991 | pcmcia_request_configuration(link->handle, &link->conf); | 913 | pcmcia_request_configuration(link->handle, &link->conf); |
992 | if (link->open) { | 914 | if (link->open) { |
993 | netwave_reset(dev); | 915 | netwave_reset(dev); |
994 | netif_device_attach(dev); | 916 | netif_device_attach(dev); |
995 | } | 917 | } |
996 | } | 918 | } |
997 | break; | 919 | |
998 | } | 920 | return 0; |
999 | return 0; | 921 | } |
1000 | } /* netwave_event */ | 922 | |
1001 | 923 | ||
1002 | /* | 924 | /* |
1003 | * Function netwave_doreset (ioBase, ramBase) | 925 | * Function netwave_doreset (ioBase, ramBase) |
@@ -1491,10 +1413,11 @@ static struct pcmcia_driver netwave_driver = { | |||
1491 | .drv = { | 1413 | .drv = { |
1492 | .name = "netwave_cs", | 1414 | .name = "netwave_cs", |
1493 | }, | 1415 | }, |
1494 | .attach = netwave_attach, | 1416 | .probe = netwave_attach, |
1495 | .event = netwave_event, | 1417 | .remove = netwave_detach, |
1496 | .detach = netwave_detach, | ||
1497 | .id_table = netwave_ids, | 1418 | .id_table = netwave_ids, |
1419 | .suspend = netwave_suspend, | ||
1420 | .resume = netwave_resume, | ||
1498 | }; | 1421 | }; |
1499 | 1422 | ||
1500 | static int __init init_netwave_cs(void) | 1423 | static int __init init_netwave_cs(void) |
@@ -1505,7 +1428,6 @@ static int __init init_netwave_cs(void) | |||
1505 | static void __exit exit_netwave_cs(void) | 1428 | static void __exit exit_netwave_cs(void) |
1506 | { | 1429 | { |
1507 | pcmcia_unregister_driver(&netwave_driver); | 1430 | pcmcia_unregister_driver(&netwave_driver); |
1508 | BUG_ON(dev_list != NULL); | ||
1509 | } | 1431 | } |
1510 | 1432 | ||
1511 | module_init(init_netwave_cs); | 1433 | module_init(init_netwave_cs); |
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index dc1128a00971..b664708481cc 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c | |||
@@ -43,17 +43,6 @@ module_param(ignore_cis_vcc, int, 0); | |||
43 | MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket"); | 43 | MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket"); |
44 | 44 | ||
45 | /********************************************************************/ | 45 | /********************************************************************/ |
46 | /* Magic constants */ | ||
47 | /********************************************************************/ | ||
48 | |||
49 | /* | ||
50 | * The dev_info variable is the "key" that is used to match up this | ||
51 | * device driver with appropriate cards, through the card | ||
52 | * configuration database. | ||
53 | */ | ||
54 | static dev_info_t dev_info = DRIVER_NAME; | ||
55 | |||
56 | /********************************************************************/ | ||
57 | /* Data structures */ | 46 | /* Data structures */ |
58 | /********************************************************************/ | 47 | /********************************************************************/ |
59 | 48 | ||
@@ -69,19 +58,14 @@ struct orinoco_pccard { | |||
69 | unsigned long hard_reset_in_progress; | 58 | unsigned long hard_reset_in_progress; |
70 | }; | 59 | }; |
71 | 60 | ||
72 | /* | ||
73 | * A linked list of "instances" of the device. Each actual PCMCIA | ||
74 | * card corresponds to one device instance, and is described by one | ||
75 | * dev_link_t structure (defined in ds.h). | ||
76 | */ | ||
77 | static dev_link_t *dev_list; /* = NULL */ | ||
78 | 61 | ||
79 | /********************************************************************/ | 62 | /********************************************************************/ |
80 | /* Function prototypes */ | 63 | /* Function prototypes */ |
81 | /********************************************************************/ | 64 | /********************************************************************/ |
82 | 65 | ||
66 | static void orinoco_cs_config(dev_link_t *link); | ||
83 | static void orinoco_cs_release(dev_link_t *link); | 67 | static void orinoco_cs_release(dev_link_t *link); |
84 | static void orinoco_cs_detach(dev_link_t *link); | 68 | static void orinoco_cs_detach(struct pcmcia_device *p_dev); |
85 | 69 | ||
86 | /********************************************************************/ | 70 | /********************************************************************/ |
87 | /* Device methods */ | 71 | /* Device methods */ |
@@ -119,19 +103,17 @@ orinoco_cs_hard_reset(struct orinoco_private *priv) | |||
119 | * The dev_link structure is initialized, but we don't actually | 103 | * The dev_link structure is initialized, but we don't actually |
120 | * configure the card at this point -- we wait until we receive a card | 104 | * configure the card at this point -- we wait until we receive a card |
121 | * insertion event. */ | 105 | * insertion event. */ |
122 | static dev_link_t * | 106 | static int |
123 | orinoco_cs_attach(void) | 107 | orinoco_cs_attach(struct pcmcia_device *p_dev) |
124 | { | 108 | { |
125 | struct net_device *dev; | 109 | struct net_device *dev; |
126 | struct orinoco_private *priv; | 110 | struct orinoco_private *priv; |
127 | struct orinoco_pccard *card; | 111 | struct orinoco_pccard *card; |
128 | dev_link_t *link; | 112 | dev_link_t *link; |
129 | client_reg_t client_reg; | ||
130 | int ret; | ||
131 | 113 | ||
132 | dev = alloc_orinocodev(sizeof(*card), orinoco_cs_hard_reset); | 114 | dev = alloc_orinocodev(sizeof(*card), orinoco_cs_hard_reset); |
133 | if (! dev) | 115 | if (! dev) |
134 | return NULL; | 116 | return -ENOMEM; |
135 | priv = netdev_priv(dev); | 117 | priv = netdev_priv(dev); |
136 | card = priv->card; | 118 | card = priv->card; |
137 | 119 | ||
@@ -154,22 +136,15 @@ orinoco_cs_attach(void) | |||
154 | link->conf.IntType = INT_MEMORY_AND_IO; | 136 | link->conf.IntType = INT_MEMORY_AND_IO; |
155 | 137 | ||
156 | /* Register with Card Services */ | 138 | /* Register with Card Services */ |
157 | /* FIXME: need a lock? */ | 139 | link->next = NULL; |
158 | link->next = dev_list; | 140 | |
159 | dev_list = link; | 141 | link->handle = p_dev; |
160 | 142 | p_dev->instance = link; | |
161 | client_reg.dev_info = &dev_info; | 143 | |
162 | client_reg.Version = 0x0210; /* FIXME: what does this mean? */ | 144 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
163 | client_reg.event_callback_args.client_data = link; | 145 | orinoco_cs_config(link); |
164 | |||
165 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
166 | if (ret != CS_SUCCESS) { | ||
167 | cs_error(link->handle, RegisterClient, ret); | ||
168 | orinoco_cs_detach(link); | ||
169 | return NULL; | ||
170 | } | ||
171 | 146 | ||
172 | return link; | 147 | return 0; |
173 | } /* orinoco_cs_attach */ | 148 | } /* orinoco_cs_attach */ |
174 | 149 | ||
175 | /* | 150 | /* |
@@ -178,27 +153,14 @@ orinoco_cs_attach(void) | |||
178 | * are freed. Otherwise, the structures will be freed when the device | 153 | * are freed. Otherwise, the structures will be freed when the device |
179 | * is released. | 154 | * is released. |
180 | */ | 155 | */ |
181 | static void orinoco_cs_detach(dev_link_t *link) | 156 | static void orinoco_cs_detach(struct pcmcia_device *p_dev) |
182 | { | 157 | { |
183 | dev_link_t **linkp; | 158 | dev_link_t *link = dev_to_instance(p_dev); |
184 | struct net_device *dev = link->priv; | 159 | struct net_device *dev = link->priv; |
185 | 160 | ||
186 | /* Locate device structure */ | ||
187 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
188 | if (*linkp == link) | ||
189 | break; | ||
190 | |||
191 | BUG_ON(*linkp == NULL); | ||
192 | |||
193 | if (link->state & DEV_CONFIG) | 161 | if (link->state & DEV_CONFIG) |
194 | orinoco_cs_release(link); | 162 | orinoco_cs_release(link); |
195 | 163 | ||
196 | /* Break the link with Card Services */ | ||
197 | if (link->handle) | ||
198 | pcmcia_deregister_client(link->handle); | ||
199 | |||
200 | /* Unlink device structure, and free it */ | ||
201 | *linkp = link->next; | ||
202 | DEBUG(0, PFX "detach: link=%p link->dev=%p\n", link, link->dev); | 164 | DEBUG(0, PFX "detach: link=%p link->dev=%p\n", link, link->dev); |
203 | if (link->dev) { | 165 | if (link->dev) { |
204 | DEBUG(0, PFX "About to unregister net device %p\n", | 166 | DEBUG(0, PFX "About to unregister net device %p\n", |
@@ -465,106 +427,82 @@ orinoco_cs_release(dev_link_t *link) | |||
465 | ioport_unmap(priv->hw.iobase); | 427 | ioport_unmap(priv->hw.iobase); |
466 | } /* orinoco_cs_release */ | 428 | } /* orinoco_cs_release */ |
467 | 429 | ||
468 | /* | 430 | static int orinoco_cs_suspend(struct pcmcia_device *p_dev) |
469 | * The card status event handler. Mostly, this schedules other stuff | ||
470 | * to run after an event is received. | ||
471 | */ | ||
472 | static int | ||
473 | orinoco_cs_event(event_t event, int priority, | ||
474 | event_callback_args_t * args) | ||
475 | { | 431 | { |
476 | dev_link_t *link = args->client_data; | 432 | dev_link_t *link = dev_to_instance(p_dev); |
477 | struct net_device *dev = link->priv; | 433 | struct net_device *dev = link->priv; |
478 | struct orinoco_private *priv = netdev_priv(dev); | 434 | struct orinoco_private *priv = netdev_priv(dev); |
479 | struct orinoco_pccard *card = priv->card; | 435 | struct orinoco_pccard *card = priv->card; |
480 | int err = 0; | 436 | int err = 0; |
481 | unsigned long flags; | 437 | unsigned long flags; |
482 | 438 | ||
483 | switch (event) { | 439 | link->state |= DEV_SUSPEND; |
484 | case CS_EVENT_CARD_REMOVAL: | 440 | if (link->state & DEV_CONFIG) { |
485 | link->state &= ~DEV_PRESENT; | 441 | /* This is probably racy, but I can't think of |
486 | if (link->state & DEV_CONFIG) { | 442 | a better way, short of rewriting the PCMCIA |
487 | unsigned long flags; | 443 | layer to not suck :-( */ |
488 | 444 | if (! test_bit(0, &card->hard_reset_in_progress)) { | |
489 | spin_lock_irqsave(&priv->lock, flags); | 445 | spin_lock_irqsave(&priv->lock, flags); |
446 | |||
447 | err = __orinoco_down(dev); | ||
448 | if (err) | ||
449 | printk(KERN_WARNING "%s: Error %d downing interface\n", | ||
450 | dev->name, err); | ||
451 | |||
490 | netif_device_detach(dev); | 452 | netif_device_detach(dev); |
491 | priv->hw_unavailable++; | 453 | priv->hw_unavailable++; |
454 | |||
492 | spin_unlock_irqrestore(&priv->lock, flags); | 455 | spin_unlock_irqrestore(&priv->lock, flags); |
493 | } | 456 | } |
494 | break; | ||
495 | 457 | ||
496 | case CS_EVENT_CARD_INSERTION: | 458 | pcmcia_release_configuration(link->handle); |
497 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | 459 | } |
498 | orinoco_cs_config(link); | ||
499 | break; | ||
500 | 460 | ||
501 | case CS_EVENT_PM_SUSPEND: | 461 | return 0; |
502 | link->state |= DEV_SUSPEND; | 462 | } |
503 | /* Fall through... */ | 463 | |
504 | case CS_EVENT_RESET_PHYSICAL: | 464 | static int orinoco_cs_resume(struct pcmcia_device *p_dev) |
505 | /* Mark the device as stopped, to block IO until later */ | 465 | { |
506 | if (link->state & DEV_CONFIG) { | 466 | dev_link_t *link = dev_to_instance(p_dev); |
507 | /* This is probably racy, but I can't think of | 467 | struct net_device *dev = link->priv; |
508 | a better way, short of rewriting the PCMCIA | 468 | struct orinoco_private *priv = netdev_priv(dev); |
509 | layer to not suck :-( */ | 469 | struct orinoco_pccard *card = priv->card; |
510 | if (! test_bit(0, &card->hard_reset_in_progress)) { | 470 | int err = 0; |
511 | spin_lock_irqsave(&priv->lock, flags); | 471 | unsigned long flags; |
512 | 472 | ||
513 | err = __orinoco_down(dev); | 473 | link->state &= ~DEV_SUSPEND; |
514 | if (err) | 474 | if (link->state & DEV_CONFIG) { |
515 | printk(KERN_WARNING "%s: %s: Error %d downing interface\n", | 475 | /* FIXME: should we double check that this is |
516 | dev->name, | 476 | * the same card as we had before */ |
517 | event == CS_EVENT_PM_SUSPEND ? "SUSPEND" : "RESET_PHYSICAL", | 477 | pcmcia_request_configuration(link->handle, &link->conf); |
518 | err); | 478 | |
519 | 479 | if (! test_bit(0, &card->hard_reset_in_progress)) { | |
520 | netif_device_detach(dev); | 480 | err = orinoco_reinit_firmware(dev); |
521 | priv->hw_unavailable++; | 481 | if (err) { |
522 | 482 | printk(KERN_ERR "%s: Error %d re-initializing firmware\n", | |
523 | spin_unlock_irqrestore(&priv->lock, flags); | 483 | dev->name, err); |
484 | return -EIO; | ||
524 | } | 485 | } |
525 | 486 | ||
526 | pcmcia_release_configuration(link->handle); | 487 | spin_lock_irqsave(&priv->lock, flags); |
527 | } | 488 | |
528 | break; | 489 | netif_device_attach(dev); |
490 | priv->hw_unavailable--; | ||
529 | 491 | ||
530 | case CS_EVENT_PM_RESUME: | 492 | if (priv->open && ! priv->hw_unavailable) { |
531 | link->state &= ~DEV_SUSPEND; | 493 | err = __orinoco_up(dev); |
532 | /* Fall through... */ | 494 | if (err) |
533 | case CS_EVENT_CARD_RESET: | 495 | printk(KERN_ERR "%s: Error %d restarting card\n", |
534 | if (link->state & DEV_CONFIG) { | ||
535 | /* FIXME: should we double check that this is | ||
536 | * the same card as we had before */ | ||
537 | pcmcia_request_configuration(link->handle, &link->conf); | ||
538 | |||
539 | if (! test_bit(0, &card->hard_reset_in_progress)) { | ||
540 | err = orinoco_reinit_firmware(dev); | ||
541 | if (err) { | ||
542 | printk(KERN_ERR "%s: Error %d re-initializing firmware\n", | ||
543 | dev->name, err); | 496 | dev->name, err); |
544 | break; | ||
545 | } | ||
546 | |||
547 | spin_lock_irqsave(&priv->lock, flags); | ||
548 | |||
549 | netif_device_attach(dev); | ||
550 | priv->hw_unavailable--; | ||
551 | |||
552 | if (priv->open && ! priv->hw_unavailable) { | ||
553 | err = __orinoco_up(dev); | ||
554 | if (err) | ||
555 | printk(KERN_ERR "%s: Error %d restarting card\n", | ||
556 | dev->name, err); | ||
557 | |||
558 | } | ||
559 | |||
560 | spin_unlock_irqrestore(&priv->lock, flags); | ||
561 | } | 497 | } |
498 | |||
499 | spin_unlock_irqrestore(&priv->lock, flags); | ||
562 | } | 500 | } |
563 | break; | ||
564 | } | 501 | } |
565 | 502 | ||
566 | return err; | 503 | return 0; |
567 | } /* orinoco_cs_event */ | 504 | } |
505 | |||
568 | 506 | ||
569 | /********************************************************************/ | 507 | /********************************************************************/ |
570 | /* Module initialization */ | 508 | /* Module initialization */ |
@@ -665,10 +603,11 @@ static struct pcmcia_driver orinoco_driver = { | |||
665 | .drv = { | 603 | .drv = { |
666 | .name = DRIVER_NAME, | 604 | .name = DRIVER_NAME, |
667 | }, | 605 | }, |
668 | .attach = orinoco_cs_attach, | 606 | .probe = orinoco_cs_attach, |
669 | .detach = orinoco_cs_detach, | 607 | .remove = orinoco_cs_detach, |
670 | .event = orinoco_cs_event, | ||
671 | .id_table = orinoco_cs_ids, | 608 | .id_table = orinoco_cs_ids, |
609 | .suspend = orinoco_cs_suspend, | ||
610 | .resume = orinoco_cs_resume, | ||
672 | }; | 611 | }; |
673 | 612 | ||
674 | static int __init | 613 | static int __init |
@@ -683,7 +622,6 @@ static void __exit | |||
683 | exit_orinoco_cs(void) | 622 | exit_orinoco_cs(void) |
684 | { | 623 | { |
685 | pcmcia_unregister_driver(&orinoco_driver); | 624 | pcmcia_unregister_driver(&orinoco_driver); |
686 | BUG_ON(dev_list != NULL); | ||
687 | } | 625 | } |
688 | 626 | ||
689 | module_init(init_orinoco_cs); | 627 | module_init(init_orinoco_cs); |
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 70fd6fd8feb9..319180ca7e71 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c | |||
@@ -92,9 +92,7 @@ module_param(pc_debug, int, 0); | |||
92 | /** Prototypes based on PCMCIA skeleton driver *******************************/ | 92 | /** Prototypes based on PCMCIA skeleton driver *******************************/ |
93 | static void ray_config(dev_link_t *link); | 93 | static void ray_config(dev_link_t *link); |
94 | static void ray_release(dev_link_t *link); | 94 | static void ray_release(dev_link_t *link); |
95 | static int ray_event(event_t event, int priority, event_callback_args_t *args); | 95 | static void ray_detach(struct pcmcia_device *p_dev); |
96 | static dev_link_t *ray_attach(void); | ||
97 | static void ray_detach(dev_link_t *); | ||
98 | 96 | ||
99 | /***** Prototypes indicated by device structure ******************************/ | 97 | /***** Prototypes indicated by device structure ******************************/ |
100 | static int ray_dev_close(struct net_device *dev); | 98 | static int ray_dev_close(struct net_device *dev); |
@@ -192,12 +190,6 @@ static int bc; | |||
192 | static char *phy_addr = NULL; | 190 | static char *phy_addr = NULL; |
193 | 191 | ||
194 | 192 | ||
195 | /* The dev_info variable is the "key" that is used to match up this | ||
196 | device driver with appropriate cards, through the card configuration | ||
197 | database. | ||
198 | */ | ||
199 | static dev_info_t dev_info = "ray_cs"; | ||
200 | |||
201 | /* A linked list of "instances" of the ray device. Each actual | 193 | /* A linked list of "instances" of the ray device. Each actual |
202 | PCMCIA card corresponds to one device instance, and is described | 194 | PCMCIA card corresponds to one device instance, and is described |
203 | by one dev_link_t structure (defined in ds.h). | 195 | by one dev_link_t structure (defined in ds.h). |
@@ -314,12 +306,10 @@ static char rcsid[] = "Raylink/WebGear wireless LAN - Corey <Thomas corey@world. | |||
314 | configure the card at this point -- we wait until we receive a | 306 | configure the card at this point -- we wait until we receive a |
315 | card insertion event. | 307 | card insertion event. |
316 | =============================================================================*/ | 308 | =============================================================================*/ |
317 | static dev_link_t *ray_attach(void) | 309 | static int ray_attach(struct pcmcia_device *p_dev) |
318 | { | 310 | { |
319 | client_reg_t client_reg; | ||
320 | dev_link_t *link; | 311 | dev_link_t *link; |
321 | ray_dev_t *local; | 312 | ray_dev_t *local; |
322 | int ret; | ||
323 | struct net_device *dev; | 313 | struct net_device *dev; |
324 | 314 | ||
325 | DEBUG(1, "ray_attach()\n"); | 315 | DEBUG(1, "ray_attach()\n"); |
@@ -328,7 +318,7 @@ static dev_link_t *ray_attach(void) | |||
328 | link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); | 318 | link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); |
329 | 319 | ||
330 | if (!link) | 320 | if (!link) |
331 | return NULL; | 321 | return -ENOMEM; |
332 | 322 | ||
333 | /* Allocate space for private device-specific data */ | 323 | /* Allocate space for private device-specific data */ |
334 | dev = alloc_etherdev(sizeof(ray_dev_t)); | 324 | dev = alloc_etherdev(sizeof(ray_dev_t)); |
@@ -387,30 +377,19 @@ static dev_link_t *ray_attach(void) | |||
387 | dev->stop = &ray_dev_close; | 377 | dev->stop = &ray_dev_close; |
388 | netif_stop_queue(dev); | 378 | netif_stop_queue(dev); |
389 | 379 | ||
390 | /* Register with Card Services */ | 380 | init_timer(&local->timer); |
391 | link->next = dev_list; | ||
392 | dev_list = link; | ||
393 | client_reg.dev_info = &dev_info; | ||
394 | client_reg.Version = 0x0210; | ||
395 | client_reg.event_callback_args.client_data = link; | ||
396 | 381 | ||
397 | DEBUG(2,"ray_cs ray_attach calling pcmcia_register_client(...)\n"); | 382 | link->handle = p_dev; |
383 | p_dev->instance = link; | ||
398 | 384 | ||
399 | init_timer(&local->timer); | 385 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
386 | ray_config(link); | ||
400 | 387 | ||
401 | ret = pcmcia_register_client(&link->handle, &client_reg); | 388 | return 0; |
402 | if (ret != 0) { | ||
403 | printk("ray_cs ray_attach RegisterClient unhappy - detaching\n"); | ||
404 | cs_error(link->handle, RegisterClient, ret); | ||
405 | ray_detach(link); | ||
406 | return NULL; | ||
407 | } | ||
408 | DEBUG(2,"ray_cs ray_attach ending\n"); | ||
409 | return link; | ||
410 | 389 | ||
411 | fail_alloc_dev: | 390 | fail_alloc_dev: |
412 | kfree(link); | 391 | kfree(link); |
413 | return NULL; | 392 | return -ENOMEM; |
414 | } /* ray_attach */ | 393 | } /* ray_attach */ |
415 | /*============================================================================= | 394 | /*============================================================================= |
416 | This deletes a driver "instance". The device is de-registered | 395 | This deletes a driver "instance". The device is de-registered |
@@ -418,9 +397,12 @@ fail_alloc_dev: | |||
418 | structures are freed. Otherwise, the structures will be freed | 397 | structures are freed. Otherwise, the structures will be freed |
419 | when the device is released. | 398 | when the device is released. |
420 | =============================================================================*/ | 399 | =============================================================================*/ |
421 | static void ray_detach(dev_link_t *link) | 400 | static void ray_detach(struct pcmcia_device *p_dev) |
422 | { | 401 | { |
402 | dev_link_t *link = dev_to_instance(p_dev); | ||
423 | dev_link_t **linkp; | 403 | dev_link_t **linkp; |
404 | struct net_device *dev; | ||
405 | ray_dev_t *local; | ||
424 | 406 | ||
425 | DEBUG(1, "ray_detach(0x%p)\n", link); | 407 | DEBUG(1, "ray_detach(0x%p)\n", link); |
426 | 408 | ||
@@ -430,22 +412,18 @@ static void ray_detach(dev_link_t *link) | |||
430 | if (*linkp == NULL) | 412 | if (*linkp == NULL) |
431 | return; | 413 | return; |
432 | 414 | ||
433 | /* If the device is currently configured and active, we won't | 415 | dev = link->priv; |
434 | actually delete it yet. Instead, it is marked so that when | 416 | |
435 | the release() function is called, that will trigger a proper | 417 | if (link->state & DEV_CONFIG) { |
436 | detach(). | 418 | ray_release(link); |
437 | */ | 419 | |
438 | if (link->state & DEV_CONFIG) | 420 | local = (ray_dev_t *)dev->priv; |
439 | ray_release(link); | 421 | del_timer(&local->timer); |
422 | } | ||
440 | 423 | ||
441 | /* Break the link with Card Services */ | ||
442 | if (link->handle) | ||
443 | pcmcia_deregister_client(link->handle); | ||
444 | |||
445 | /* Unlink device structure, free pieces */ | 424 | /* Unlink device structure, free pieces */ |
446 | *linkp = link->next; | 425 | *linkp = link->next; |
447 | if (link->priv) { | 426 | if (link->priv) { |
448 | struct net_device *dev = link->priv; | ||
449 | if (link->dev) unregister_netdev(dev); | 427 | if (link->dev) unregister_netdev(dev); |
450 | free_netdev(dev); | 428 | free_netdev(dev); |
451 | } | 429 | } |
@@ -891,65 +869,40 @@ static void ray_release(dev_link_t *link) | |||
891 | DEBUG(2,"ray_release ending\n"); | 869 | DEBUG(2,"ray_release ending\n"); |
892 | } | 870 | } |
893 | 871 | ||
894 | /*============================================================================= | 872 | static int ray_suspend(struct pcmcia_device *p_dev) |
895 | The card status event handler. Mostly, this schedules other | ||
896 | stuff to run after an event is received. A CARD_REMOVAL event | ||
897 | also sets some flags to discourage the net drivers from trying | ||
898 | to talk to the card any more. | ||
899 | |||
900 | When a CARD_REMOVAL event is received, we immediately set a flag | ||
901 | to block future accesses to this device. All the functions that | ||
902 | actually access the device should check this flag to make sure | ||
903 | the card is still present. | ||
904 | =============================================================================*/ | ||
905 | static int ray_event(event_t event, int priority, | ||
906 | event_callback_args_t *args) | ||
907 | { | 873 | { |
908 | dev_link_t *link = args->client_data; | 874 | dev_link_t *link = dev_to_instance(p_dev); |
909 | struct net_device *dev = link->priv; | 875 | struct net_device *dev = link->priv; |
910 | ray_dev_t *local = (ray_dev_t *)dev->priv; | 876 | |
911 | DEBUG(1, "ray_event(0x%06x)\n", event); | 877 | link->state |= DEV_SUSPEND; |
912 | |||
913 | switch (event) { | ||
914 | case CS_EVENT_CARD_REMOVAL: | ||
915 | link->state &= ~DEV_PRESENT; | ||
916 | netif_device_detach(dev); | ||
917 | if (link->state & DEV_CONFIG) { | ||
918 | ray_release(link); | ||
919 | del_timer(&local->timer); | ||
920 | } | ||
921 | break; | ||
922 | case CS_EVENT_CARD_INSERTION: | ||
923 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
924 | ray_config(link); | ||
925 | break; | ||
926 | case CS_EVENT_PM_SUSPEND: | ||
927 | link->state |= DEV_SUSPEND; | ||
928 | /* Fall through... */ | ||
929 | case CS_EVENT_RESET_PHYSICAL: | ||
930 | if (link->state & DEV_CONFIG) { | 878 | if (link->state & DEV_CONFIG) { |
931 | if (link->open) | 879 | if (link->open) |
932 | netif_device_detach(dev); | 880 | netif_device_detach(dev); |
933 | 881 | ||
934 | pcmcia_release_configuration(link->handle); | 882 | pcmcia_release_configuration(link->handle); |
935 | } | 883 | } |
936 | break; | 884 | |
937 | case CS_EVENT_PM_RESUME: | 885 | |
938 | link->state &= ~DEV_SUSPEND; | 886 | return 0; |
939 | /* Fall through... */ | 887 | } |
940 | case CS_EVENT_CARD_RESET: | 888 | |
889 | static int ray_resume(struct pcmcia_device *p_dev) | ||
890 | { | ||
891 | dev_link_t *link = dev_to_instance(p_dev); | ||
892 | struct net_device *dev = link->priv; | ||
893 | |||
894 | link->state &= ~DEV_SUSPEND; | ||
941 | if (link->state & DEV_CONFIG) { | 895 | if (link->state & DEV_CONFIG) { |
942 | pcmcia_request_configuration(link->handle, &link->conf); | 896 | pcmcia_request_configuration(link->handle, &link->conf); |
943 | if (link->open) { | 897 | if (link->open) { |
944 | ray_reset(dev); | 898 | ray_reset(dev); |
945 | netif_device_attach(dev); | 899 | netif_device_attach(dev); |
946 | } | 900 | } |
947 | } | 901 | } |
948 | break; | 902 | |
949 | } | 903 | return 0; |
950 | return 0; | 904 | } |
951 | DEBUG(2,"ray_event ending\n"); | 905 | |
952 | } /* ray_event */ | ||
953 | /*===========================================================================*/ | 906 | /*===========================================================================*/ |
954 | int ray_dev_init(struct net_device *dev) | 907 | int ray_dev_init(struct net_device *dev) |
955 | { | 908 | { |
@@ -2945,10 +2898,11 @@ static struct pcmcia_driver ray_driver = { | |||
2945 | .drv = { | 2898 | .drv = { |
2946 | .name = "ray_cs", | 2899 | .name = "ray_cs", |
2947 | }, | 2900 | }, |
2948 | .attach = ray_attach, | 2901 | .probe = ray_attach, |
2949 | .event = ray_event, | 2902 | .remove = ray_detach, |
2950 | .detach = ray_detach, | ||
2951 | .id_table = ray_ids, | 2903 | .id_table = ray_ids, |
2904 | .suspend = ray_suspend, | ||
2905 | .resume = ray_resume, | ||
2952 | }; | 2906 | }; |
2953 | 2907 | ||
2954 | static int __init init_ray_cs(void) | 2908 | static int __init init_ray_cs(void) |
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); |
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index c822cad3333f..7e2039f52c49 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c | |||
@@ -4594,14 +4594,12 @@ wavelan_close(struct net_device * dev) | |||
4594 | * configure the card at this point -- we wait until we receive a | 4594 | * configure the card at this point -- we wait until we receive a |
4595 | * card insertion event. | 4595 | * card insertion event. |
4596 | */ | 4596 | */ |
4597 | static dev_link_t * | 4597 | static int |
4598 | wavelan_attach(void) | 4598 | wavelan_attach(struct pcmcia_device *p_dev) |
4599 | { | 4599 | { |
4600 | client_reg_t client_reg; /* Register with cardmgr */ | ||
4601 | dev_link_t * link; /* Info for cardmgr */ | 4600 | dev_link_t * link; /* Info for cardmgr */ |
4602 | struct net_device * dev; /* Interface generic data */ | 4601 | struct net_device * dev; /* Interface generic data */ |
4603 | net_local * lp; /* Interface specific data */ | 4602 | net_local * lp; /* Interface specific data */ |
4604 | int ret; | ||
4605 | 4603 | ||
4606 | #ifdef DEBUG_CALLBACK_TRACE | 4604 | #ifdef DEBUG_CALLBACK_TRACE |
4607 | printk(KERN_DEBUG "-> wavelan_attach()\n"); | 4605 | printk(KERN_DEBUG "-> wavelan_attach()\n"); |
@@ -4609,7 +4607,7 @@ wavelan_attach(void) | |||
4609 | 4607 | ||
4610 | /* Initialize the dev_link_t structure */ | 4608 | /* Initialize the dev_link_t structure */ |
4611 | link = kzalloc(sizeof(struct dev_link_t), GFP_KERNEL); | 4609 | link = kzalloc(sizeof(struct dev_link_t), GFP_KERNEL); |
4612 | if (!link) return NULL; | 4610 | if (!link) return -ENOMEM; |
4613 | 4611 | ||
4614 | /* The io structure describes IO port mapping */ | 4612 | /* The io structure describes IO port mapping */ |
4615 | link->io.NumPorts1 = 8; | 4613 | link->io.NumPorts1 = 8; |
@@ -4627,14 +4625,13 @@ wavelan_attach(void) | |||
4627 | link->conf.IntType = INT_MEMORY_AND_IO; | 4625 | link->conf.IntType = INT_MEMORY_AND_IO; |
4628 | 4626 | ||
4629 | /* Chain drivers */ | 4627 | /* Chain drivers */ |
4630 | link->next = dev_list; | 4628 | link->next = NULL; |
4631 | dev_list = link; | ||
4632 | 4629 | ||
4633 | /* Allocate the generic data structure */ | 4630 | /* Allocate the generic data structure */ |
4634 | dev = alloc_etherdev(sizeof(net_local)); | 4631 | dev = alloc_etherdev(sizeof(net_local)); |
4635 | if (!dev) { | 4632 | if (!dev) { |
4636 | kfree(link); | 4633 | kfree(link); |
4637 | return NULL; | 4634 | return -ENOMEM; |
4638 | } | 4635 | } |
4639 | link->priv = link->irq.Instance = dev; | 4636 | link->priv = link->irq.Instance = dev; |
4640 | 4637 | ||
@@ -4679,28 +4676,21 @@ wavelan_attach(void) | |||
4679 | /* Other specific data */ | 4676 | /* Other specific data */ |
4680 | dev->mtu = WAVELAN_MTU; | 4677 | dev->mtu = WAVELAN_MTU; |
4681 | 4678 | ||
4682 | /* Register with Card Services */ | 4679 | link->handle = p_dev; |
4683 | client_reg.dev_info = &dev_info; | 4680 | p_dev->instance = link; |
4684 | client_reg.Version = 0x0210; | ||
4685 | client_reg.event_callback_args.client_data = link; | ||
4686 | 4681 | ||
4687 | #ifdef DEBUG_CONFIG_INFO | 4682 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
4688 | printk(KERN_DEBUG "wavelan_attach(): almost done, calling pcmcia_register_client\n"); | 4683 | if(wv_pcmcia_config(link) && |
4689 | #endif | 4684 | wv_hw_config(dev)) |
4690 | 4685 | wv_init_info(dev); | |
4691 | ret = pcmcia_register_client(&link->handle, &client_reg); | 4686 | else |
4692 | if(ret != 0) | 4687 | dev->irq = 0; |
4693 | { | ||
4694 | cs_error(link->handle, RegisterClient, ret); | ||
4695 | wavelan_detach(link); | ||
4696 | return NULL; | ||
4697 | } | ||
4698 | 4688 | ||
4699 | #ifdef DEBUG_CALLBACK_TRACE | 4689 | #ifdef DEBUG_CALLBACK_TRACE |
4700 | printk(KERN_DEBUG "<- wavelan_attach()\n"); | 4690 | printk(KERN_DEBUG "<- wavelan_attach()\n"); |
4701 | #endif | 4691 | #endif |
4702 | 4692 | ||
4703 | return link; | 4693 | return 0; |
4704 | } | 4694 | } |
4705 | 4695 | ||
4706 | /*------------------------------------------------------------------*/ | 4696 | /*------------------------------------------------------------------*/ |
@@ -4711,8 +4701,10 @@ wavelan_attach(void) | |||
4711 | * is released. | 4701 | * is released. |
4712 | */ | 4702 | */ |
4713 | static void | 4703 | static void |
4714 | wavelan_detach(dev_link_t * link) | 4704 | wavelan_detach(struct pcmcia_device *p_dev) |
4715 | { | 4705 | { |
4706 | dev_link_t *link = dev_to_instance(p_dev); | ||
4707 | |||
4716 | #ifdef DEBUG_CALLBACK_TRACE | 4708 | #ifdef DEBUG_CALLBACK_TRACE |
4717 | printk(KERN_DEBUG "-> wavelan_detach(0x%p)\n", link); | 4709 | printk(KERN_DEBUG "-> wavelan_detach(0x%p)\n", link); |
4718 | #endif | 4710 | #endif |
@@ -4729,31 +4721,6 @@ wavelan_detach(dev_link_t * link) | |||
4729 | wv_pcmcia_release(link); | 4721 | wv_pcmcia_release(link); |
4730 | } | 4722 | } |
4731 | 4723 | ||
4732 | /* Break the link with Card Services */ | ||
4733 | if(link->handle) | ||
4734 | pcmcia_deregister_client(link->handle); | ||
4735 | |||
4736 | /* Remove the interface data from the linked list */ | ||
4737 | if(dev_list == link) | ||
4738 | dev_list = link->next; | ||
4739 | else | ||
4740 | { | ||
4741 | dev_link_t * prev = dev_list; | ||
4742 | |||
4743 | while((prev != (dev_link_t *) NULL) && (prev->next != link)) | ||
4744 | prev = prev->next; | ||
4745 | |||
4746 | if(prev == (dev_link_t *) NULL) | ||
4747 | { | ||
4748 | #ifdef DEBUG_CONFIG_ERRORS | ||
4749 | printk(KERN_WARNING "wavelan_detach : Attempting to remove a nonexistent device.\n"); | ||
4750 | #endif | ||
4751 | return; | ||
4752 | } | ||
4753 | |||
4754 | prev->next = link->next; | ||
4755 | } | ||
4756 | |||
4757 | /* Free pieces */ | 4724 | /* Free pieces */ |
4758 | if(link->priv) | 4725 | if(link->priv) |
4759 | { | 4726 | { |
@@ -4775,65 +4742,11 @@ wavelan_detach(dev_link_t * link) | |||
4775 | #endif | 4742 | #endif |
4776 | } | 4743 | } |
4777 | 4744 | ||
4778 | /*------------------------------------------------------------------*/ | 4745 | static int wavelan_suspend(struct pcmcia_device *p_dev) |
4779 | /* | ||
4780 | * The card status event handler. Mostly, this schedules other stuff | ||
4781 | * to run after an event is received. A CARD_REMOVAL event also sets | ||
4782 | * some flags to discourage the net drivers from trying to talk to the | ||
4783 | * card any more. | ||
4784 | */ | ||
4785 | static int | ||
4786 | wavelan_event(event_t event, /* The event received */ | ||
4787 | int priority, | ||
4788 | event_callback_args_t * args) | ||
4789 | { | 4746 | { |
4790 | dev_link_t * link = (dev_link_t *) args->client_data; | 4747 | dev_link_t *link = dev_to_instance(p_dev); |
4791 | struct net_device * dev = (struct net_device *) link->priv; | 4748 | struct net_device * dev = (struct net_device *) link->priv; |
4792 | |||
4793 | #ifdef DEBUG_CALLBACK_TRACE | ||
4794 | printk(KERN_DEBUG "->wavelan_event(): %s\n", | ||
4795 | ((event == CS_EVENT_REGISTRATION_COMPLETE)?"registration complete" : | ||
4796 | ((event == CS_EVENT_CARD_REMOVAL) ? "card removal" : | ||
4797 | ((event == CS_EVENT_CARD_INSERTION) ? "card insertion" : | ||
4798 | ((event == CS_EVENT_PM_SUSPEND) ? "pm suspend" : | ||
4799 | ((event == CS_EVENT_RESET_PHYSICAL) ? "physical reset" : | ||
4800 | ((event == CS_EVENT_PM_RESUME) ? "pm resume" : | ||
4801 | ((event == CS_EVENT_CARD_RESET) ? "card reset" : | ||
4802 | "unknown")))))))); | ||
4803 | #endif | ||
4804 | |||
4805 | switch(event) | ||
4806 | { | ||
4807 | case CS_EVENT_REGISTRATION_COMPLETE: | ||
4808 | #ifdef DEBUG_CONFIG_INFO | ||
4809 | printk(KERN_DEBUG "wavelan_cs: registration complete\n"); | ||
4810 | #endif | ||
4811 | break; | ||
4812 | 4749 | ||
4813 | case CS_EVENT_CARD_REMOVAL: | ||
4814 | /* Oups ! The card is no more there */ | ||
4815 | link->state &= ~DEV_PRESENT; | ||
4816 | if(link->state & DEV_CONFIG) | ||
4817 | { | ||
4818 | /* Accept no more transmissions */ | ||
4819 | netif_device_detach(dev); | ||
4820 | |||
4821 | /* Release the card */ | ||
4822 | wv_pcmcia_release(link); | ||
4823 | } | ||
4824 | break; | ||
4825 | |||
4826 | case CS_EVENT_CARD_INSERTION: | ||
4827 | /* Reset and configure the card */ | ||
4828 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
4829 | if(wv_pcmcia_config(link) && | ||
4830 | wv_hw_config(dev)) | ||
4831 | wv_init_info(dev); | ||
4832 | else | ||
4833 | dev->irq = 0; | ||
4834 | break; | ||
4835 | |||
4836 | case CS_EVENT_PM_SUSPEND: | ||
4837 | /* NB: wavelan_close will be called, but too late, so we are | 4750 | /* NB: wavelan_close will be called, but too late, so we are |
4838 | * obliged to close nicely the wavelan here. David, could you | 4751 | * obliged to close nicely the wavelan here. David, could you |
4839 | * close the device before suspending them ? And, by the way, | 4752 | * close the device before suspending them ? And, by the way, |
@@ -4848,38 +4761,37 @@ wavelan_event(event_t event, /* The event received */ | |||
4848 | 4761 | ||
4849 | /* The card is now suspended */ | 4762 | /* The card is now suspended */ |
4850 | link->state |= DEV_SUSPEND; | 4763 | link->state |= DEV_SUSPEND; |
4851 | /* Fall through... */ | 4764 | |
4852 | case CS_EVENT_RESET_PHYSICAL: | ||
4853 | if(link->state & DEV_CONFIG) | 4765 | if(link->state & DEV_CONFIG) |
4854 | { | 4766 | { |
4855 | if(link->open) | 4767 | if(link->open) |
4856 | netif_device_detach(dev); | 4768 | netif_device_detach(dev); |
4857 | pcmcia_release_configuration(link->handle); | 4769 | pcmcia_release_configuration(link->handle); |
4858 | } | 4770 | } |
4859 | break; | 4771 | |
4772 | return 0; | ||
4773 | } | ||
4774 | |||
4775 | static int wavelan_resume(struct pcmcia_device *p_dev) | ||
4776 | { | ||
4777 | dev_link_t *link = dev_to_instance(p_dev); | ||
4778 | struct net_device * dev = (struct net_device *) link->priv; | ||
4860 | 4779 | ||
4861 | case CS_EVENT_PM_RESUME: | ||
4862 | link->state &= ~DEV_SUSPEND; | 4780 | link->state &= ~DEV_SUSPEND; |
4863 | /* Fall through... */ | ||
4864 | case CS_EVENT_CARD_RESET: | ||
4865 | if(link->state & DEV_CONFIG) | 4781 | if(link->state & DEV_CONFIG) |
4866 | { | 4782 | { |
4867 | pcmcia_request_configuration(link->handle, &link->conf); | 4783 | pcmcia_request_configuration(link->handle, &link->conf); |
4868 | if(link->open) /* If RESET -> True, If RESUME -> False ? */ | 4784 | if(link->open) /* If RESET -> True, If RESUME -> False ? */ |
4869 | { | 4785 | { |
4870 | wv_hw_reset(dev); | 4786 | wv_hw_reset(dev); |
4871 | netif_device_attach(dev); | 4787 | netif_device_attach(dev); |
4872 | } | 4788 | } |
4873 | } | 4789 | } |
4874 | break; | ||
4875 | } | ||
4876 | 4790 | ||
4877 | #ifdef DEBUG_CALLBACK_TRACE | 4791 | return 0; |
4878 | printk(KERN_DEBUG "<-wavelan_event()\n"); | ||
4879 | #endif | ||
4880 | return 0; | ||
4881 | } | 4792 | } |
4882 | 4793 | ||
4794 | |||
4883 | static struct pcmcia_device_id wavelan_ids[] = { | 4795 | static struct pcmcia_device_id wavelan_ids[] = { |
4884 | PCMCIA_DEVICE_PROD_ID12("AT&T","WaveLAN/PCMCIA", 0xe7c5affd, 0x1bc50975), | 4796 | PCMCIA_DEVICE_PROD_ID12("AT&T","WaveLAN/PCMCIA", 0xe7c5affd, 0x1bc50975), |
4885 | PCMCIA_DEVICE_PROD_ID12("Digital", "RoamAbout/DS", 0x9999ab35, 0x00d05e06), | 4797 | PCMCIA_DEVICE_PROD_ID12("Digital", "RoamAbout/DS", 0x9999ab35, 0x00d05e06), |
@@ -4894,10 +4806,11 @@ static struct pcmcia_driver wavelan_driver = { | |||
4894 | .drv = { | 4806 | .drv = { |
4895 | .name = "wavelan_cs", | 4807 | .name = "wavelan_cs", |
4896 | }, | 4808 | }, |
4897 | .attach = wavelan_attach, | 4809 | .probe = wavelan_attach, |
4898 | .event = wavelan_event, | 4810 | .remove = wavelan_detach, |
4899 | .detach = wavelan_detach, | ||
4900 | .id_table = wavelan_ids, | 4811 | .id_table = wavelan_ids, |
4812 | .suspend = wavelan_suspend, | ||
4813 | .resume = wavelan_resume, | ||
4901 | }; | 4814 | }; |
4902 | 4815 | ||
4903 | static int __init | 4816 | static int __init |
diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h index 724a715089c9..f2d597568151 100644 --- a/drivers/net/wireless/wavelan_cs.p.h +++ b/drivers/net/wireless/wavelan_cs.p.h | |||
@@ -754,20 +754,11 @@ static void | |||
754 | static int | 754 | static int |
755 | wavelan_open(struct net_device *), /* Open the device */ | 755 | wavelan_open(struct net_device *), /* Open the device */ |
756 | wavelan_close(struct net_device *); /* Close the device */ | 756 | wavelan_close(struct net_device *); /* Close the device */ |
757 | static dev_link_t * | ||
758 | wavelan_attach(void); /* Create a new device */ | ||
759 | static void | 757 | static void |
760 | wavelan_detach(dev_link_t *); /* Destroy a removed device */ | 758 | wavelan_detach(struct pcmcia_device *p_dev); /* Destroy a removed device */ |
761 | static int | ||
762 | wavelan_event(event_t, /* Manage pcmcia events */ | ||
763 | int, | ||
764 | event_callback_args_t *); | ||
765 | 759 | ||
766 | /**************************** VARIABLES ****************************/ | 760 | /**************************** VARIABLES ****************************/ |
767 | 761 | ||
768 | static dev_info_t dev_info = "wavelan_cs"; | ||
769 | static dev_link_t *dev_list = NULL; /* Linked list of devices */ | ||
770 | |||
771 | /* | 762 | /* |
772 | * Parameters that can be set with 'insmod' | 763 | * Parameters that can be set with 'insmod' |
773 | * The exact syntax is 'insmod wavelan_cs.o <var>=<value>' | 764 | * The exact syntax is 'insmod wavelan_cs.o <var>=<value>' |
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 978fdc606781..48e10b0c7e74 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c | |||
@@ -105,7 +105,6 @@ module_param(pc_debug, int, 0); | |||
105 | */ | 105 | */ |
106 | static void wl3501_config(dev_link_t *link); | 106 | static void wl3501_config(dev_link_t *link); |
107 | static void wl3501_release(dev_link_t *link); | 107 | static void wl3501_release(dev_link_t *link); |
108 | static int wl3501_event(event_t event, int pri, event_callback_args_t *args); | ||
109 | 108 | ||
110 | /* | 109 | /* |
111 | * The dev_info variable is the "key" that is used to match up this | 110 | * The dev_info variable is the "key" that is used to match up this |
@@ -1498,9 +1497,11 @@ static struct ethtool_ops ops = { | |||
1498 | * Services. If it has been released, all local data structures are freed. | 1497 | * Services. If it has been released, all local data structures are freed. |
1499 | * Otherwise, the structures will be freed when the device is released. | 1498 | * Otherwise, the structures will be freed when the device is released. |
1500 | */ | 1499 | */ |
1501 | static void wl3501_detach(dev_link_t *link) | 1500 | static void wl3501_detach(struct pcmcia_device *p_dev) |
1502 | { | 1501 | { |
1502 | dev_link_t *link = dev_to_instance(p_dev); | ||
1503 | dev_link_t **linkp; | 1503 | dev_link_t **linkp; |
1504 | struct net_device *dev = link->priv; | ||
1504 | 1505 | ||
1505 | /* Locate device structure */ | 1506 | /* Locate device structure */ |
1506 | for (linkp = &wl3501_dev_list; *linkp; linkp = &(*linkp)->next) | 1507 | for (linkp = &wl3501_dev_list; *linkp; linkp = &(*linkp)->next) |
@@ -1514,16 +1515,12 @@ static void wl3501_detach(dev_link_t *link) | |||
1514 | * function is called, that will trigger a proper detach(). */ | 1515 | * function is called, that will trigger a proper detach(). */ |
1515 | 1516 | ||
1516 | if (link->state & DEV_CONFIG) { | 1517 | if (link->state & DEV_CONFIG) { |
1517 | #ifdef PCMCIA_DEBUG | 1518 | while (link->open > 0) |
1518 | printk(KERN_DEBUG "wl3501_cs: detach postponed, '%s' " | 1519 | wl3501_close(dev); |
1519 | "still locked\n", link->dev->dev_name); | ||
1520 | #endif | ||
1521 | goto out; | ||
1522 | } | ||
1523 | 1520 | ||
1524 | /* Break the link with Card Services */ | 1521 | netif_device_detach(dev); |
1525 | if (link->handle) | 1522 | wl3501_release(link); |
1526 | pcmcia_deregister_client(link->handle); | 1523 | } |
1527 | 1524 | ||
1528 | /* Unlink device structure, free pieces */ | 1525 | /* Unlink device structure, free pieces */ |
1529 | *linkp = link->next; | 1526 | *linkp = link->next; |
@@ -1956,18 +1953,16 @@ static const struct iw_handler_def wl3501_handler_def = { | |||
1956 | * The dev_link structure is initialized, but we don't actually configure the | 1953 | * The dev_link structure is initialized, but we don't actually configure the |
1957 | * card at this point -- we wait until we receive a card insertion event. | 1954 | * card at this point -- we wait until we receive a card insertion event. |
1958 | */ | 1955 | */ |
1959 | static dev_link_t *wl3501_attach(void) | 1956 | static int wl3501_attach(struct pcmcia_device *p_dev) |
1960 | { | 1957 | { |
1961 | client_reg_t client_reg; | ||
1962 | dev_link_t *link; | 1958 | dev_link_t *link; |
1963 | struct net_device *dev; | 1959 | struct net_device *dev; |
1964 | struct wl3501_card *this; | 1960 | struct wl3501_card *this; |
1965 | int ret; | ||
1966 | 1961 | ||
1967 | /* Initialize the dev_link_t structure */ | 1962 | /* Initialize the dev_link_t structure */ |
1968 | link = kzalloc(sizeof(*link), GFP_KERNEL); | 1963 | link = kzalloc(sizeof(*link), GFP_KERNEL); |
1969 | if (!link) | 1964 | if (!link) |
1970 | goto out; | 1965 | return -ENOMEM; |
1971 | 1966 | ||
1972 | /* The io structure describes IO port mapping */ | 1967 | /* The io structure describes IO port mapping */ |
1973 | link->io.NumPorts1 = 16; | 1968 | link->io.NumPorts1 = 16; |
@@ -2003,24 +1998,17 @@ static dev_link_t *wl3501_attach(void) | |||
2003 | netif_stop_queue(dev); | 1998 | netif_stop_queue(dev); |
2004 | link->priv = link->irq.Instance = dev; | 1999 | link->priv = link->irq.Instance = dev; |
2005 | 2000 | ||
2006 | /* Register with Card Services */ | 2001 | link->handle = p_dev; |
2007 | link->next = wl3501_dev_list; | 2002 | p_dev->instance = link; |
2008 | wl3501_dev_list = link; | 2003 | |
2009 | client_reg.dev_info = &wl3501_dev_info; | 2004 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
2010 | client_reg.Version = 0x0210; | 2005 | wl3501_config(link); |
2011 | client_reg.event_callback_args.client_data = link; | 2006 | |
2012 | ret = pcmcia_register_client(&link->handle, &client_reg); | 2007 | return 0; |
2013 | if (ret) { | ||
2014 | cs_error(link->handle, RegisterClient, ret); | ||
2015 | wl3501_detach(link); | ||
2016 | link = NULL; | ||
2017 | } | ||
2018 | out: | ||
2019 | return link; | ||
2020 | out_link: | 2008 | out_link: |
2021 | kfree(link); | 2009 | kfree(link); |
2022 | link = NULL; | 2010 | link = NULL; |
2023 | goto out; | 2011 | return -ENOMEM; |
2024 | } | 2012 | } |
2025 | 2013 | ||
2026 | #define CS_CHECK(fn, ret) \ | 2014 | #define CS_CHECK(fn, ret) \ |
@@ -2173,67 +2161,41 @@ static void wl3501_release(dev_link_t *link) | |||
2173 | link->state &= ~DEV_CONFIG; | 2161 | link->state &= ~DEV_CONFIG; |
2174 | } | 2162 | } |
2175 | 2163 | ||
2176 | /** | 2164 | static int wl3501_suspend(struct pcmcia_device *p_dev) |
2177 | * wl3501_event - The card status event handler | ||
2178 | * @event - event | ||
2179 | * @pri - priority | ||
2180 | * @args - arguments for this event | ||
2181 | * | ||
2182 | * The card status event handler. Mostly, this schedules other stuff to run | ||
2183 | * after an event is received. A CARD_REMOVAL event also sets some flags to | ||
2184 | * discourage the net drivers from trying to talk to the card any more. | ||
2185 | * | ||
2186 | * When a CARD_REMOVAL event is received, we immediately set a flag to block | ||
2187 | * future accesses to this device. All the functions that actually access the | ||
2188 | * device should check this flag to make sure the card is still present. | ||
2189 | */ | ||
2190 | static int wl3501_event(event_t event, int pri, event_callback_args_t *args) | ||
2191 | { | 2165 | { |
2192 | dev_link_t *link = args->client_data; | 2166 | dev_link_t *link = dev_to_instance(p_dev); |
2193 | struct net_device *dev = link->priv; | 2167 | struct net_device *dev = link->priv; |
2194 | 2168 | ||
2195 | switch (event) { | 2169 | link->state |= DEV_SUSPEND; |
2196 | case CS_EVENT_CARD_REMOVAL: | 2170 | |
2197 | link->state &= ~DEV_PRESENT; | 2171 | wl3501_pwr_mgmt(dev->priv, WL3501_SUSPEND); |
2198 | if (link->state & DEV_CONFIG) { | 2172 | if (link->state & DEV_CONFIG) { |
2199 | while (link->open > 0) | 2173 | if (link->open) |
2200 | wl3501_close(dev); | ||
2201 | netif_device_detach(dev); | 2174 | netif_device_detach(dev); |
2202 | wl3501_release(link); | 2175 | pcmcia_release_configuration(link->handle); |
2203 | } | 2176 | } |
2204 | break; | 2177 | |
2205 | case CS_EVENT_CARD_INSERTION: | 2178 | return 0; |
2206 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | 2179 | } |
2207 | wl3501_config(link); | 2180 | |
2208 | break; | 2181 | static int wl3501_resume(struct pcmcia_device *p_dev) |
2209 | case CS_EVENT_PM_SUSPEND: | 2182 | { |
2210 | link->state |= DEV_SUSPEND; | 2183 | dev_link_t *link = dev_to_instance(p_dev); |
2211 | wl3501_pwr_mgmt(dev->priv, WL3501_SUSPEND); | 2184 | struct net_device *dev = link->priv; |
2212 | /* Fall through... */ | 2185 | |
2213 | case CS_EVENT_RESET_PHYSICAL: | 2186 | wl3501_pwr_mgmt(dev->priv, WL3501_RESUME); |
2214 | if (link->state & DEV_CONFIG) { | 2187 | if (link->state & DEV_CONFIG) { |
2215 | if (link->open) | 2188 | pcmcia_request_configuration(link->handle, &link->conf); |
2216 | netif_device_detach(dev); | 2189 | if (link->open) { |
2217 | pcmcia_release_configuration(link->handle); | 2190 | wl3501_reset(dev); |
2218 | } | 2191 | netif_device_attach(dev); |
2219 | break; | ||
2220 | case CS_EVENT_PM_RESUME: | ||
2221 | link->state &= ~DEV_SUSPEND; | ||
2222 | wl3501_pwr_mgmt(dev->priv, WL3501_RESUME); | ||
2223 | /* Fall through... */ | ||
2224 | case CS_EVENT_CARD_RESET: | ||
2225 | if (link->state & DEV_CONFIG) { | ||
2226 | pcmcia_request_configuration(link->handle, &link->conf); | ||
2227 | if (link->open) { | ||
2228 | wl3501_reset(dev); | ||
2229 | netif_device_attach(dev); | ||
2230 | } | ||
2231 | } | 2192 | } |
2232 | break; | ||
2233 | } | 2193 | } |
2194 | |||
2234 | return 0; | 2195 | return 0; |
2235 | } | 2196 | } |
2236 | 2197 | ||
2198 | |||
2237 | static struct pcmcia_device_id wl3501_ids[] = { | 2199 | static struct pcmcia_device_id wl3501_ids[] = { |
2238 | PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0001), | 2200 | PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0001), |
2239 | PCMCIA_DEVICE_NULL | 2201 | PCMCIA_DEVICE_NULL |
@@ -2245,10 +2207,11 @@ static struct pcmcia_driver wl3501_driver = { | |||
2245 | .drv = { | 2207 | .drv = { |
2246 | .name = "wl3501_cs", | 2208 | .name = "wl3501_cs", |
2247 | }, | 2209 | }, |
2248 | .attach = wl3501_attach, | 2210 | .probe = wl3501_attach, |
2249 | .event = wl3501_event, | 2211 | .remove = wl3501_detach, |
2250 | .detach = wl3501_detach, | ||
2251 | .id_table = wl3501_ids, | 2212 | .id_table = wl3501_ids, |
2213 | .suspend = wl3501_suspend, | ||
2214 | .resume = wl3501_resume, | ||
2252 | }; | 2215 | }; |
2253 | 2216 | ||
2254 | static int __init wl3501_init_module(void) | 2217 | static int __init wl3501_init_module(void) |
diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c index 24e6aacddb74..158d92563259 100644 --- a/drivers/parport/parport_cs.c +++ b/drivers/parport/parport_cs.c | |||
@@ -87,15 +87,9 @@ typedef struct parport_info_t { | |||
87 | struct parport *port; | 87 | struct parport *port; |
88 | } parport_info_t; | 88 | } parport_info_t; |
89 | 89 | ||
90 | static dev_link_t *parport_attach(void); | 90 | static void parport_detach(struct pcmcia_device *p_dev); |
91 | static void parport_detach(dev_link_t *); | ||
92 | static void parport_config(dev_link_t *link); | 91 | static void parport_config(dev_link_t *link); |
93 | static void parport_cs_release(dev_link_t *); | 92 | static void parport_cs_release(dev_link_t *); |
94 | static int parport_event(event_t event, int priority, | ||
95 | event_callback_args_t *args); | ||
96 | |||
97 | static dev_info_t dev_info = "parport_cs"; | ||
98 | static dev_link_t *dev_list = NULL; | ||
99 | 93 | ||
100 | /*====================================================================== | 94 | /*====================================================================== |
101 | 95 | ||
@@ -105,18 +99,16 @@ static dev_link_t *dev_list = NULL; | |||
105 | 99 | ||
106 | ======================================================================*/ | 100 | ======================================================================*/ |
107 | 101 | ||
108 | static dev_link_t *parport_attach(void) | 102 | static int parport_attach(struct pcmcia_device *p_dev) |
109 | { | 103 | { |
110 | parport_info_t *info; | 104 | parport_info_t *info; |
111 | dev_link_t *link; | 105 | dev_link_t *link; |
112 | client_reg_t client_reg; | 106 | |
113 | int ret; | ||
114 | |||
115 | DEBUG(0, "parport_attach()\n"); | 107 | DEBUG(0, "parport_attach()\n"); |
116 | 108 | ||
117 | /* Create new parport device */ | 109 | /* Create new parport device */ |
118 | info = kmalloc(sizeof(*info), GFP_KERNEL); | 110 | info = kmalloc(sizeof(*info), GFP_KERNEL); |
119 | if (!info) return NULL; | 111 | if (!info) return -ENOMEM; |
120 | memset(info, 0, sizeof(*info)); | 112 | memset(info, 0, sizeof(*info)); |
121 | link = &info->link; link->priv = info; | 113 | link = &info->link; link->priv = info; |
122 | 114 | ||
@@ -127,21 +119,14 @@ static dev_link_t *parport_attach(void) | |||
127 | link->conf.Attributes = CONF_ENABLE_IRQ; | 119 | link->conf.Attributes = CONF_ENABLE_IRQ; |
128 | link->conf.Vcc = 50; | 120 | link->conf.Vcc = 50; |
129 | link->conf.IntType = INT_MEMORY_AND_IO; | 121 | link->conf.IntType = INT_MEMORY_AND_IO; |
130 | 122 | ||
131 | /* Register with Card Services */ | 123 | link->handle = p_dev; |
132 | link->next = dev_list; | 124 | p_dev->instance = link; |
133 | dev_list = link; | 125 | |
134 | client_reg.dev_info = &dev_info; | 126 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
135 | client_reg.Version = 0x0210; | 127 | parport_config(link); |
136 | client_reg.event_callback_args.client_data = link; | 128 | |
137 | ret = pcmcia_register_client(&link->handle, &client_reg); | 129 | return 0; |
138 | if (ret != CS_SUCCESS) { | ||
139 | cs_error(link->handle, RegisterClient, ret); | ||
140 | parport_detach(link); | ||
141 | return NULL; | ||
142 | } | ||
143 | |||
144 | return link; | ||
145 | } /* parport_attach */ | 130 | } /* parport_attach */ |
146 | 131 | ||
147 | /*====================================================================== | 132 | /*====================================================================== |
@@ -153,32 +138,16 @@ static dev_link_t *parport_attach(void) | |||
153 | 138 | ||
154 | ======================================================================*/ | 139 | ======================================================================*/ |
155 | 140 | ||
156 | static void parport_detach(dev_link_t *link) | 141 | static void parport_detach(struct pcmcia_device *p_dev) |
157 | { | 142 | { |
158 | dev_link_t **linkp; | 143 | dev_link_t *link = dev_to_instance(p_dev); |
159 | int ret; | ||
160 | 144 | ||
161 | DEBUG(0, "parport_detach(0x%p)\n", link); | 145 | DEBUG(0, "parport_detach(0x%p)\n", link); |
162 | |||
163 | /* Locate device structure */ | ||
164 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
165 | if (*linkp == link) break; | ||
166 | if (*linkp == NULL) | ||
167 | return; | ||
168 | 146 | ||
169 | if (link->state & DEV_CONFIG) | 147 | if (link->state & DEV_CONFIG) |
170 | parport_cs_release(link); | 148 | parport_cs_release(link); |
171 | 149 | ||
172 | if (link->handle) { | ||
173 | ret = pcmcia_deregister_client(link->handle); | ||
174 | if (ret != CS_SUCCESS) | ||
175 | cs_error(link->handle, DeregisterClient, ret); | ||
176 | } | ||
177 | |||
178 | /* Unlink, free device structure */ | ||
179 | *linkp = link->next; | ||
180 | kfree(link->priv); | 150 | kfree(link->priv); |
181 | |||
182 | } /* parport_detach */ | 151 | } /* parport_detach */ |
183 | 152 | ||
184 | /*====================================================================== | 153 | /*====================================================================== |
@@ -325,47 +294,27 @@ void parport_cs_release(dev_link_t *link) | |||
325 | 294 | ||
326 | } /* parport_cs_release */ | 295 | } /* parport_cs_release */ |
327 | 296 | ||
328 | /*====================================================================== | 297 | static int parport_suspend(struct pcmcia_device *dev) |
329 | |||
330 | The card status event handler. Mostly, this schedules other | ||
331 | stuff to run after an event is received. | ||
332 | |||
333 | ======================================================================*/ | ||
334 | |||
335 | int parport_event(event_t event, int priority, | ||
336 | event_callback_args_t *args) | ||
337 | { | 298 | { |
338 | dev_link_t *link = args->client_data; | 299 | dev_link_t *link = dev_to_instance(dev); |
339 | 300 | ||
340 | DEBUG(1, "parport_event(0x%06x)\n", event); | ||
341 | |||
342 | switch (event) { | ||
343 | case CS_EVENT_CARD_REMOVAL: | ||
344 | link->state &= ~DEV_PRESENT; | ||
345 | if (link->state & DEV_CONFIG) | ||
346 | parport_cs_release(link); | ||
347 | break; | ||
348 | case CS_EVENT_CARD_INSERTION: | ||
349 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
350 | parport_config(link); | ||
351 | break; | ||
352 | case CS_EVENT_PM_SUSPEND: | ||
353 | link->state |= DEV_SUSPEND; | 301 | link->state |= DEV_SUSPEND; |
354 | /* Fall through... */ | ||
355 | case CS_EVENT_RESET_PHYSICAL: | ||
356 | if (link->state & DEV_CONFIG) | 302 | if (link->state & DEV_CONFIG) |
357 | pcmcia_release_configuration(link->handle); | 303 | pcmcia_release_configuration(link->handle); |
358 | break; | 304 | |
359 | case CS_EVENT_PM_RESUME: | 305 | return 0; |
306 | } | ||
307 | |||
308 | static int parport_resume(struct pcmcia_device *dev) | ||
309 | { | ||
310 | dev_link_t *link = dev_to_instance(dev); | ||
311 | |||
360 | link->state &= ~DEV_SUSPEND; | 312 | link->state &= ~DEV_SUSPEND; |
361 | /* Fall through... */ | ||
362 | case CS_EVENT_CARD_RESET: | ||
363 | if (DEV_OK(link)) | 313 | if (DEV_OK(link)) |
364 | pcmcia_request_configuration(link->handle, &link->conf); | 314 | pcmcia_request_configuration(link->handle, &link->conf); |
365 | break; | 315 | |
366 | } | 316 | return 0; |
367 | return 0; | 317 | } |
368 | } /* parport_event */ | ||
369 | 318 | ||
370 | static struct pcmcia_device_id parport_ids[] = { | 319 | static struct pcmcia_device_id parport_ids[] = { |
371 | PCMCIA_DEVICE_FUNC_ID(3), | 320 | PCMCIA_DEVICE_FUNC_ID(3), |
@@ -379,11 +328,11 @@ static struct pcmcia_driver parport_cs_driver = { | |||
379 | .drv = { | 328 | .drv = { |
380 | .name = "parport_cs", | 329 | .name = "parport_cs", |
381 | }, | 330 | }, |
382 | .attach = parport_attach, | 331 | .probe = parport_attach, |
383 | .event = parport_event, | 332 | .remove = parport_detach, |
384 | .detach = parport_detach, | ||
385 | .id_table = parport_ids, | 333 | .id_table = parport_ids, |
386 | 334 | .suspend = parport_suspend, | |
335 | .resume = parport_resume, | ||
387 | }; | 336 | }; |
388 | 337 | ||
389 | static int __init init_parport_cs(void) | 338 | static int __init init_parport_cs(void) |
@@ -394,7 +343,6 @@ static int __init init_parport_cs(void) | |||
394 | static void __exit exit_parport_cs(void) | 343 | static void __exit exit_parport_cs(void) |
395 | { | 344 | { |
396 | pcmcia_unregister_driver(&parport_cs_driver); | 345 | pcmcia_unregister_driver(&parport_cs_driver); |
397 | BUG_ON(dev_list != NULL); | ||
398 | } | 346 | } |
399 | 347 | ||
400 | module_init(init_parport_cs); | 348 | module_init(init_parport_cs); |
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index 309eb557f9a3..1f4ad0e7836e 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig | |||
@@ -116,6 +116,31 @@ config YENTA | |||
116 | 116 | ||
117 | If unsure, say Y. | 117 | If unsure, say Y. |
118 | 118 | ||
119 | config YENTA_O2 | ||
120 | default y | ||
121 | bool "Special initialization for O2Micro bridges" if EMBEDDED | ||
122 | depends on YENTA | ||
123 | |||
124 | config YENTA_RICOH | ||
125 | default y | ||
126 | bool "Special initialization for Ricoh bridges" if EMBEDDED | ||
127 | depends on YENTA | ||
128 | |||
129 | config YENTA_TI | ||
130 | default y | ||
131 | bool "Special initialization for TI and EnE bridges" if EMBEDDED | ||
132 | depends on YENTA | ||
133 | |||
134 | config YENTA_ENE_TUNE | ||
135 | default y | ||
136 | bool "Auto-tune EnE bridges for CB cards" if EMBEDDED | ||
137 | depends on YENTA_TI && CARDBUS | ||
138 | |||
139 | config YENTA_TOSHIBA | ||
140 | default y | ||
141 | bool "Special initialization for Toshiba ToPIC bridges" if EMBEDDED | ||
142 | depends on YENTA | ||
143 | |||
119 | config PD6729 | 144 | config PD6729 |
120 | tristate "Cirrus PD6729 compatible bridge support" | 145 | tristate "Cirrus PD6729 compatible bridge support" |
121 | depends on PCMCIA && PCI | 146 | depends on PCMCIA && PCI |
@@ -157,7 +182,7 @@ config TCIC | |||
157 | config PCMCIA_M8XX | 182 | config PCMCIA_M8XX |
158 | tristate "MPC8xx PCMCIA support" | 183 | tristate "MPC8xx PCMCIA support" |
159 | depends on PCMCIA && PPC && 8xx | 184 | depends on PCMCIA && PPC && 8xx |
160 | select PCCARD_NONSTATIC | 185 | select PCCARD_IODYN |
161 | help | 186 | help |
162 | Say Y here to include support for PowerPC 8xx series PCMCIA | 187 | Say Y here to include support for PowerPC 8xx series PCMCIA |
163 | controller. | 188 | controller. |
@@ -200,7 +225,7 @@ config PCMCIA_PXA2XX | |||
200 | 225 | ||
201 | config PCMCIA_PROBE | 226 | config PCMCIA_PROBE |
202 | bool | 227 | bool |
203 | default y if ISA && !ARCH_SA1100 && !ARCH_CLPS711X | 228 | default y if ISA && !ARCH_SA1100 && !ARCH_CLPS711X && !PARISC |
204 | 229 | ||
205 | config M32R_PCC | 230 | config M32R_PCC |
206 | bool "M32R PCMCIA I/F" | 231 | bool "M32R PCMCIA I/F" |
@@ -241,6 +266,9 @@ config OMAP_CF | |||
241 | config PCCARD_NONSTATIC | 266 | config PCCARD_NONSTATIC |
242 | tristate | 267 | tristate |
243 | 268 | ||
269 | config PCCARD_IODYN | ||
270 | bool | ||
271 | |||
244 | endif # PCCARD | 272 | endif # PCCARD |
245 | 273 | ||
246 | endmenu | 274 | endmenu |
diff --git a/drivers/pcmcia/au1000_generic.c b/drivers/pcmcia/au1000_generic.c index 87302c548c24..971a35281649 100644 --- a/drivers/pcmcia/au1000_generic.c +++ b/drivers/pcmcia/au1000_generic.c | |||
@@ -241,23 +241,6 @@ au1x00_pcmcia_get_status(struct pcmcia_socket *sock, unsigned int *status) | |||
241 | return 0; | 241 | return 0; |
242 | } | 242 | } |
243 | 243 | ||
244 | /* au1x00_pcmcia_get_socket() | ||
245 | * Implements the get_socket() operation for the in-kernel PCMCIA | ||
246 | * service (formerly SS_GetSocket in Card Services). Not a very | ||
247 | * exciting routine. | ||
248 | * | ||
249 | * Returns: 0 | ||
250 | */ | ||
251 | static int | ||
252 | au1x00_pcmcia_get_socket(struct pcmcia_socket *sock, socket_state_t *state) | ||
253 | { | ||
254 | struct au1000_pcmcia_socket *skt = to_au1000_socket(sock); | ||
255 | |||
256 | debug("for sock %u\n", skt->nr); | ||
257 | *state = skt->cs_state; | ||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | /* au1x00_pcmcia_set_socket() | 244 | /* au1x00_pcmcia_set_socket() |
262 | * Implements the set_socket() operation for the in-kernel PCMCIA | 245 | * Implements the set_socket() operation for the in-kernel PCMCIA |
263 | * service (formerly SS_SetSocket in Card Services). We more or | 246 | * service (formerly SS_SetSocket in Card Services). We more or |
@@ -352,7 +335,6 @@ static struct pccard_operations au1x00_pcmcia_operations = { | |||
352 | .init = au1x00_pcmcia_sock_init, | 335 | .init = au1x00_pcmcia_sock_init, |
353 | .suspend = au1x00_pcmcia_suspend, | 336 | .suspend = au1x00_pcmcia_suspend, |
354 | .get_status = au1x00_pcmcia_get_status, | 337 | .get_status = au1x00_pcmcia_get_status, |
355 | .get_socket = au1x00_pcmcia_get_socket, | ||
356 | .set_socket = au1x00_pcmcia_set_socket, | 338 | .set_socket = au1x00_pcmcia_set_socket, |
357 | .set_io_map = au1x00_pcmcia_set_io_map, | 339 | .set_io_map = au1x00_pcmcia_set_io_map, |
358 | .set_mem_map = au1x00_pcmcia_set_mem_map, | 340 | .set_mem_map = au1x00_pcmcia_set_mem_map, |
@@ -372,13 +354,12 @@ int au1x00_pcmcia_socket_probe(struct device *dev, struct pcmcia_low_level *ops, | |||
372 | struct skt_dev_info *sinfo; | 354 | struct skt_dev_info *sinfo; |
373 | int ret, i; | 355 | int ret, i; |
374 | 356 | ||
375 | sinfo = kmalloc(sizeof(struct skt_dev_info), GFP_KERNEL); | 357 | sinfo = kzalloc(sizeof(struct skt_dev_info), GFP_KERNEL); |
376 | if (!sinfo) { | 358 | if (!sinfo) { |
377 | ret = -ENOMEM; | 359 | ret = -ENOMEM; |
378 | goto out; | 360 | goto out; |
379 | } | 361 | } |
380 | 362 | ||
381 | memset(sinfo, 0, sizeof(struct skt_dev_info)); | ||
382 | sinfo->nskt = nr; | 363 | sinfo->nskt = nr; |
383 | 364 | ||
384 | /* | 365 | /* |
diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c index 2dc3e611a9a3..120fa8da6392 100644 --- a/drivers/pcmcia/cistpl.c +++ b/drivers/pcmcia/cistpl.c | |||
@@ -60,9 +60,9 @@ static const u_int exponent[] = { | |||
60 | 60 | ||
61 | /* Parameters that can be set with 'insmod' */ | 61 | /* Parameters that can be set with 'insmod' */ |
62 | 62 | ||
63 | #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444) | 63 | /* 16-bit CIS? */ |
64 | 64 | static int cis_width; | |
65 | INT_MODULE_PARM(cis_width, 0); /* 16-bit CIS? */ | 65 | module_param(cis_width, int, 0444); |
66 | 66 | ||
67 | void release_cis_mem(struct pcmcia_socket *s) | 67 | void release_cis_mem(struct pcmcia_socket *s) |
68 | { | 68 | { |
@@ -463,7 +463,7 @@ static int follow_link(struct pcmcia_socket *s, tuple_t *tuple) | |||
463 | /* Get indirect link from the MFC tuple */ | 463 | /* Get indirect link from the MFC tuple */ |
464 | read_cis_cache(s, LINK_SPACE(tuple->Flags), | 464 | read_cis_cache(s, LINK_SPACE(tuple->Flags), |
465 | tuple->LinkOffset, 5, link); | 465 | tuple->LinkOffset, 5, link); |
466 | ofs = le32_to_cpu(*(u_int *)(link+1)); | 466 | ofs = le32_to_cpu(*(__le32 *)(link+1)); |
467 | SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR); | 467 | SPACE(tuple->Flags) = (link[0] == CISTPL_MFC_ATTR); |
468 | /* Move to the next indirect link */ | 468 | /* Move to the next indirect link */ |
469 | tuple->LinkOffset += 5; | 469 | tuple->LinkOffset += 5; |
@@ -671,8 +671,8 @@ static int parse_checksum(tuple_t *tuple, cistpl_checksum_t *csum) | |||
671 | if (tuple->TupleDataLen < 5) | 671 | if (tuple->TupleDataLen < 5) |
672 | return CS_BAD_TUPLE; | 672 | return CS_BAD_TUPLE; |
673 | p = (u_char *)tuple->TupleData; | 673 | p = (u_char *)tuple->TupleData; |
674 | csum->addr = tuple->CISOffset+(short)le16_to_cpu(*(u_short *)p)-2; | 674 | csum->addr = tuple->CISOffset+(short)le16_to_cpu(*(__le16 *)p)-2; |
675 | csum->len = le16_to_cpu(*(u_short *)(p + 2)); | 675 | csum->len = le16_to_cpu(*(__le16 *)(p + 2)); |
676 | csum->sum = *(p+4); | 676 | csum->sum = *(p+4); |
677 | return CS_SUCCESS; | 677 | return CS_SUCCESS; |
678 | } | 678 | } |
@@ -683,7 +683,7 @@ static int parse_longlink(tuple_t *tuple, cistpl_longlink_t *link) | |||
683 | { | 683 | { |
684 | if (tuple->TupleDataLen < 4) | 684 | if (tuple->TupleDataLen < 4) |
685 | return CS_BAD_TUPLE; | 685 | return CS_BAD_TUPLE; |
686 | link->addr = le32_to_cpu(*(u_int *)tuple->TupleData); | 686 | link->addr = le32_to_cpu(*(__le32 *)tuple->TupleData); |
687 | return CS_SUCCESS; | 687 | return CS_SUCCESS; |
688 | } | 688 | } |
689 | 689 | ||
@@ -702,7 +702,7 @@ static int parse_longlink_mfc(tuple_t *tuple, | |||
702 | return CS_BAD_TUPLE; | 702 | return CS_BAD_TUPLE; |
703 | for (i = 0; i < link->nfn; i++) { | 703 | for (i = 0; i < link->nfn; i++) { |
704 | link->fn[i].space = *p; p++; | 704 | link->fn[i].space = *p; p++; |
705 | link->fn[i].addr = le32_to_cpu(*(u_int *)p); p += 4; | 705 | link->fn[i].addr = le32_to_cpu(*(__le32 *)p); p += 4; |
706 | } | 706 | } |
707 | return CS_SUCCESS; | 707 | return CS_SUCCESS; |
708 | } | 708 | } |
@@ -789,10 +789,10 @@ static int parse_jedec(tuple_t *tuple, cistpl_jedec_t *jedec) | |||
789 | 789 | ||
790 | static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m) | 790 | static int parse_manfid(tuple_t *tuple, cistpl_manfid_t *m) |
791 | { | 791 | { |
792 | u_short *p; | 792 | __le16 *p; |
793 | if (tuple->TupleDataLen < 4) | 793 | if (tuple->TupleDataLen < 4) |
794 | return CS_BAD_TUPLE; | 794 | return CS_BAD_TUPLE; |
795 | p = (u_short *)tuple->TupleData; | 795 | p = (__le16 *)tuple->TupleData; |
796 | m->manf = le16_to_cpu(p[0]); | 796 | m->manf = le16_to_cpu(p[0]); |
797 | m->card = le16_to_cpu(p[1]); | 797 | m->card = le16_to_cpu(p[1]); |
798 | return CS_SUCCESS; | 798 | return CS_SUCCESS; |
@@ -1093,7 +1093,7 @@ static int parse_cftable_entry(tuple_t *tuple, | |||
1093 | break; | 1093 | break; |
1094 | case 0x20: | 1094 | case 0x20: |
1095 | entry->mem.nwin = 1; | 1095 | entry->mem.nwin = 1; |
1096 | entry->mem.win[0].len = le16_to_cpu(*(u_short *)p) << 8; | 1096 | entry->mem.win[0].len = le16_to_cpu(*(__le16 *)p) << 8; |
1097 | entry->mem.win[0].card_addr = 0; | 1097 | entry->mem.win[0].card_addr = 0; |
1098 | entry->mem.win[0].host_addr = 0; | 1098 | entry->mem.win[0].host_addr = 0; |
1099 | p += 2; | 1099 | p += 2; |
@@ -1101,9 +1101,9 @@ static int parse_cftable_entry(tuple_t *tuple, | |||
1101 | break; | 1101 | break; |
1102 | case 0x40: | 1102 | case 0x40: |
1103 | entry->mem.nwin = 1; | 1103 | entry->mem.nwin = 1; |
1104 | entry->mem.win[0].len = le16_to_cpu(*(u_short *)p) << 8; | 1104 | entry->mem.win[0].len = le16_to_cpu(*(__le16 *)p) << 8; |
1105 | entry->mem.win[0].card_addr = | 1105 | entry->mem.win[0].card_addr = |
1106 | le16_to_cpu(*(u_short *)(p+2)) << 8; | 1106 | le16_to_cpu(*(__le16 *)(p+2)) << 8; |
1107 | entry->mem.win[0].host_addr = 0; | 1107 | entry->mem.win[0].host_addr = 0; |
1108 | p += 4; | 1108 | p += 4; |
1109 | if (p > q) return CS_BAD_TUPLE; | 1109 | if (p > q) return CS_BAD_TUPLE; |
@@ -1140,7 +1140,7 @@ static int parse_bar(tuple_t *tuple, cistpl_bar_t *bar) | |||
1140 | p = (u_char *)tuple->TupleData; | 1140 | p = (u_char *)tuple->TupleData; |
1141 | bar->attr = *p; | 1141 | bar->attr = *p; |
1142 | p += 2; | 1142 | p += 2; |
1143 | bar->size = le32_to_cpu(*(u_int *)p); | 1143 | bar->size = le32_to_cpu(*(__le32 *)p); |
1144 | return CS_SUCCESS; | 1144 | return CS_SUCCESS; |
1145 | } | 1145 | } |
1146 | 1146 | ||
@@ -1153,7 +1153,7 @@ static int parse_config_cb(tuple_t *tuple, cistpl_config_t *config) | |||
1153 | return CS_BAD_TUPLE; | 1153 | return CS_BAD_TUPLE; |
1154 | config->last_idx = *(++p); | 1154 | config->last_idx = *(++p); |
1155 | p++; | 1155 | p++; |
1156 | config->base = le32_to_cpu(*(u_int *)p); | 1156 | config->base = le32_to_cpu(*(__le32 *)p); |
1157 | config->subtuples = tuple->TupleDataLen - 6; | 1157 | config->subtuples = tuple->TupleDataLen - 6; |
1158 | return CS_SUCCESS; | 1158 | return CS_SUCCESS; |
1159 | } | 1159 | } |
@@ -1269,7 +1269,7 @@ static int parse_vers_2(tuple_t *tuple, cistpl_vers_2_t *v2) | |||
1269 | 1269 | ||
1270 | v2->vers = p[0]; | 1270 | v2->vers = p[0]; |
1271 | v2->comply = p[1]; | 1271 | v2->comply = p[1]; |
1272 | v2->dindex = le16_to_cpu(*(u_short *)(p+2)); | 1272 | v2->dindex = le16_to_cpu(*(__le16 *)(p+2)); |
1273 | v2->vspec8 = p[6]; | 1273 | v2->vspec8 = p[6]; |
1274 | v2->vspec9 = p[7]; | 1274 | v2->vspec9 = p[7]; |
1275 | v2->nhdr = p[8]; | 1275 | v2->nhdr = p[8]; |
@@ -1310,8 +1310,8 @@ static int parse_format(tuple_t *tuple, cistpl_format_t *fmt) | |||
1310 | 1310 | ||
1311 | fmt->type = p[0]; | 1311 | fmt->type = p[0]; |
1312 | fmt->edc = p[1]; | 1312 | fmt->edc = p[1]; |
1313 | fmt->offset = le32_to_cpu(*(u_int *)(p+2)); | 1313 | fmt->offset = le32_to_cpu(*(__le32 *)(p+2)); |
1314 | fmt->length = le32_to_cpu(*(u_int *)(p+6)); | 1314 | fmt->length = le32_to_cpu(*(__le32 *)(p+6)); |
1315 | 1315 | ||
1316 | return CS_SUCCESS; | 1316 | return CS_SUCCESS; |
1317 | } | 1317 | } |
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 7cf09084ef61..613f2f1fbfdd 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c | |||
@@ -309,41 +309,6 @@ struct pcmcia_socket * pcmcia_get_socket_by_nr(unsigned int nr) | |||
309 | } | 309 | } |
310 | EXPORT_SYMBOL(pcmcia_get_socket_by_nr); | 310 | EXPORT_SYMBOL(pcmcia_get_socket_by_nr); |
311 | 311 | ||
312 | |||
313 | /** | ||
314 | * socket_setup() and shutdown_socket() are called by the main event | ||
315 | * handler when card insertion and removal events are received. | ||
316 | * socket_setup() turns on socket power and resets the socket, in two stages. | ||
317 | * shutdown_socket() unconfigures a socket and turns off socket power. | ||
318 | */ | ||
319 | static void shutdown_socket(struct pcmcia_socket *s) | ||
320 | { | ||
321 | cs_dbg(s, 1, "shutdown_socket\n"); | ||
322 | |||
323 | /* Blank out the socket state */ | ||
324 | s->socket = dead_socket; | ||
325 | s->ops->init(s); | ||
326 | s->ops->set_socket(s, &s->socket); | ||
327 | s->irq.AssignedIRQ = s->irq.Config = 0; | ||
328 | s->lock_count = 0; | ||
329 | destroy_cis_cache(s); | ||
330 | #ifdef CONFIG_CARDBUS | ||
331 | cb_free(s); | ||
332 | #endif | ||
333 | s->functions = 0; | ||
334 | kfree(s->config); | ||
335 | s->config = NULL; | ||
336 | |||
337 | { | ||
338 | int status; | ||
339 | s->ops->get_status(s, &status); | ||
340 | if (status & SS_POWERON) { | ||
341 | printk(KERN_ERR "PCMCIA: socket %p: *** DANGER *** unable to remove socket power\n", s); | ||
342 | } | ||
343 | } | ||
344 | } /* shutdown_socket */ | ||
345 | |||
346 | |||
347 | /** | 312 | /** |
348 | * The central event handler. Send_event() sends an event to the | 313 | * The central event handler. Send_event() sends an event to the |
349 | * 16-bit subsystem, which then calls the relevant device drivers. | 314 | * 16-bit subsystem, which then calls the relevant device drivers. |
@@ -383,17 +348,6 @@ static void socket_remove_drivers(struct pcmcia_socket *skt) | |||
383 | send_event(skt, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH); | 348 | send_event(skt, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH); |
384 | } | 349 | } |
385 | 350 | ||
386 | static void socket_shutdown(struct pcmcia_socket *skt) | ||
387 | { | ||
388 | cs_dbg(skt, 4, "shutdown\n"); | ||
389 | |||
390 | socket_remove_drivers(skt); | ||
391 | skt->state &= SOCKET_INUSE|SOCKET_PRESENT; | ||
392 | msleep(shutdown_delay * 10); | ||
393 | skt->state &= SOCKET_INUSE; | ||
394 | shutdown_socket(skt); | ||
395 | } | ||
396 | |||
397 | static int socket_reset(struct pcmcia_socket *skt) | 351 | static int socket_reset(struct pcmcia_socket *skt) |
398 | { | 352 | { |
399 | int status, i; | 353 | int status, i; |
@@ -424,6 +378,45 @@ static int socket_reset(struct pcmcia_socket *skt) | |||
424 | return CS_GENERAL_FAILURE; | 378 | return CS_GENERAL_FAILURE; |
425 | } | 379 | } |
426 | 380 | ||
381 | /** | ||
382 | * socket_setup() and socket_shutdown() are called by the main event handler | ||
383 | * when card insertion and removal events are received. | ||
384 | * socket_setup() turns on socket power and resets the socket, in two stages. | ||
385 | * socket_shutdown() unconfigures a socket and turns off socket power. | ||
386 | */ | ||
387 | static void socket_shutdown(struct pcmcia_socket *s) | ||
388 | { | ||
389 | int status; | ||
390 | |||
391 | cs_dbg(s, 4, "shutdown\n"); | ||
392 | |||
393 | socket_remove_drivers(s); | ||
394 | s->state &= SOCKET_INUSE | SOCKET_PRESENT; | ||
395 | msleep(shutdown_delay * 10); | ||
396 | s->state &= SOCKET_INUSE; | ||
397 | |||
398 | /* Blank out the socket state */ | ||
399 | s->socket = dead_socket; | ||
400 | s->ops->init(s); | ||
401 | s->ops->set_socket(s, &s->socket); | ||
402 | s->irq.AssignedIRQ = s->irq.Config = 0; | ||
403 | s->lock_count = 0; | ||
404 | destroy_cis_cache(s); | ||
405 | #ifdef CONFIG_CARDBUS | ||
406 | cb_free(s); | ||
407 | #endif | ||
408 | s->functions = 0; | ||
409 | kfree(s->config); | ||
410 | s->config = NULL; | ||
411 | |||
412 | s->ops->get_status(s, &status); | ||
413 | if (status & SS_POWERON) { | ||
414 | printk(KERN_ERR "PCMCIA: socket %p: *** DANGER *** unable to remove socket power\n", s); | ||
415 | } | ||
416 | |||
417 | cs_socket_put(s); | ||
418 | } | ||
419 | |||
427 | static int socket_setup(struct pcmcia_socket *skt, int initial_delay) | 420 | static int socket_setup(struct pcmcia_socket *skt, int initial_delay) |
428 | { | 421 | { |
429 | int status, i; | 422 | int status, i; |
@@ -529,7 +522,6 @@ static int socket_insert(struct pcmcia_socket *skt) | |||
529 | send_event(skt, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW); | 522 | send_event(skt, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW); |
530 | } else { | 523 | } else { |
531 | socket_shutdown(skt); | 524 | socket_shutdown(skt); |
532 | cs_socket_put(skt); | ||
533 | } | 525 | } |
534 | 526 | ||
535 | return ret; | 527 | return ret; |
@@ -593,7 +585,6 @@ static int socket_resume(struct pcmcia_socket *skt) | |||
593 | } | 585 | } |
594 | } else { | 586 | } else { |
595 | socket_shutdown(skt); | 587 | socket_shutdown(skt); |
596 | cs_socket_put(skt); | ||
597 | } | 588 | } |
598 | 589 | ||
599 | skt->state &= ~SOCKET_SUSPEND; | 590 | skt->state &= ~SOCKET_SUSPEND; |
@@ -605,7 +596,6 @@ static void socket_remove(struct pcmcia_socket *skt) | |||
605 | { | 596 | { |
606 | printk(KERN_NOTICE "pccard: card ejected from slot %d\n", skt->sock); | 597 | printk(KERN_NOTICE "pccard: card ejected from slot %d\n", skt->sock); |
607 | socket_shutdown(skt); | 598 | socket_shutdown(skt); |
608 | cs_socket_put(skt); | ||
609 | } | 599 | } |
610 | 600 | ||
611 | /* | 601 | /* |
@@ -780,8 +770,13 @@ int pccard_reset_card(struct pcmcia_socket *skt) | |||
780 | ret = send_event(skt, CS_EVENT_RESET_REQUEST, CS_EVENT_PRI_LOW); | 770 | ret = send_event(skt, CS_EVENT_RESET_REQUEST, CS_EVENT_PRI_LOW); |
781 | if (ret == 0) { | 771 | if (ret == 0) { |
782 | send_event(skt, CS_EVENT_RESET_PHYSICAL, CS_EVENT_PRI_LOW); | 772 | send_event(skt, CS_EVENT_RESET_PHYSICAL, CS_EVENT_PRI_LOW); |
783 | if (socket_reset(skt) == CS_SUCCESS) | 773 | if (skt->callback) |
774 | skt->callback->suspend(skt); | ||
775 | if (socket_reset(skt) == CS_SUCCESS) { | ||
784 | send_event(skt, CS_EVENT_CARD_RESET, CS_EVENT_PRI_LOW); | 776 | send_event(skt, CS_EVENT_CARD_RESET, CS_EVENT_PRI_LOW); |
777 | if (skt->callback) | ||
778 | skt->callback->resume(skt); | ||
779 | } | ||
785 | } | 780 | } |
786 | 781 | ||
787 | ret = CS_SUCCESS; | 782 | ret = CS_SUCCESS; |
@@ -812,6 +807,11 @@ int pcmcia_suspend_card(struct pcmcia_socket *skt) | |||
812 | ret = CS_UNSUPPORTED_FUNCTION; | 807 | ret = CS_UNSUPPORTED_FUNCTION; |
813 | break; | 808 | break; |
814 | } | 809 | } |
810 | if (skt->callback) { | ||
811 | ret = skt->callback->suspend(skt); | ||
812 | if (ret) | ||
813 | break; | ||
814 | } | ||
815 | ret = socket_suspend(skt); | 815 | ret = socket_suspend(skt); |
816 | } while (0); | 816 | } while (0); |
817 | up(&skt->skt_sem); | 817 | up(&skt->skt_sem); |
@@ -838,6 +838,8 @@ int pcmcia_resume_card(struct pcmcia_socket *skt) | |||
838 | break; | 838 | break; |
839 | } | 839 | } |
840 | ret = socket_resume(skt); | 840 | ret = socket_resume(skt); |
841 | if (!ret && skt->callback) | ||
842 | skt->callback->resume(skt); | ||
841 | } while (0); | 843 | } while (0); |
842 | up(&skt->skt_sem); | 844 | up(&skt->skt_sem); |
843 | 845 | ||
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h index 55867bc7f199..7b37eba35bf1 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, |
@@ -143,6 +143,8 @@ struct pcmcia_callback{ | |||
143 | struct module *owner; | 143 | struct module *owner; |
144 | int (*event) (struct pcmcia_socket *s, event_t event, int priority); | 144 | int (*event) (struct pcmcia_socket *s, event_t event, int priority); |
145 | void (*requery) (struct pcmcia_socket *s); | 145 | void (*requery) (struct pcmcia_socket *s); |
146 | int (*suspend) (struct pcmcia_socket *s); | ||
147 | int (*resume) (struct pcmcia_socket *s); | ||
146 | }; | 148 | }; |
147 | 149 | ||
148 | int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c); | 150 | int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c); |
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c index 6fb76399547e..0252582b91cd 100644 --- a/drivers/pcmcia/ds.c +++ b/drivers/pcmcia/ds.c | |||
@@ -57,8 +57,6 @@ module_param_named(pc_debug, ds_pc_debug, int, 0644); | |||
57 | 57 | ||
58 | spinlock_t pcmcia_dev_list_lock; | 58 | spinlock_t pcmcia_dev_list_lock; |
59 | 59 | ||
60 | static int unbind_request(struct pcmcia_socket *s); | ||
61 | |||
62 | /*====================================================================*/ | 60 | /*====================================================================*/ |
63 | 61 | ||
64 | /* code which was in cs.c before */ | 62 | /* code which was in cs.c before */ |
@@ -205,7 +203,7 @@ static void pcmcia_check_driver(struct pcmcia_driver *p_drv) | |||
205 | unsigned int i; | 203 | unsigned int i; |
206 | u32 hash; | 204 | u32 hash; |
207 | 205 | ||
208 | if (!p_drv->attach || !p_drv->event || !p_drv->detach) | 206 | if (!p_drv->probe || !p_drv->remove) |
209 | printk(KERN_DEBUG "pcmcia: %s lacks a requisite callback " | 207 | printk(KERN_DEBUG "pcmcia: %s lacks a requisite callback " |
210 | "function\n", p_drv->drv.name); | 208 | "function\n", p_drv->drv.name); |
211 | 209 | ||
@@ -266,12 +264,10 @@ static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename) | |||
266 | if (fw->size >= CISTPL_MAX_CIS_SIZE) | 264 | if (fw->size >= CISTPL_MAX_CIS_SIZE) |
267 | goto release; | 265 | goto release; |
268 | 266 | ||
269 | cis = kmalloc(sizeof(cisdump_t), GFP_KERNEL); | 267 | cis = kzalloc(sizeof(cisdump_t), GFP_KERNEL); |
270 | if (!cis) | 268 | if (!cis) |
271 | goto release; | 269 | goto release; |
272 | 270 | ||
273 | memset(cis, 0, sizeof(cisdump_t)); | ||
274 | |||
275 | cis->Length = fw->size + 1; | 271 | cis->Length = fw->size + 1; |
276 | memcpy(cis->Data, fw->data, fw->size); | 272 | memcpy(cis->Data, fw->data, fw->size); |
277 | 273 | ||
@@ -363,6 +359,7 @@ static int pcmcia_device_probe(struct device * dev) | |||
363 | { | 359 | { |
364 | struct pcmcia_device *p_dev; | 360 | struct pcmcia_device *p_dev; |
365 | struct pcmcia_driver *p_drv; | 361 | struct pcmcia_driver *p_drv; |
362 | struct pcmcia_socket *s; | ||
366 | int ret = 0; | 363 | int ret = 0; |
367 | 364 | ||
368 | dev = get_device(dev); | 365 | dev = get_device(dev); |
@@ -371,25 +368,38 @@ static int pcmcia_device_probe(struct device * dev) | |||
371 | 368 | ||
372 | p_dev = to_pcmcia_dev(dev); | 369 | p_dev = to_pcmcia_dev(dev); |
373 | p_drv = to_pcmcia_drv(dev->driver); | 370 | p_drv = to_pcmcia_drv(dev->driver); |
371 | s = p_dev->socket; | ||
374 | 372 | ||
375 | if (!try_module_get(p_drv->owner)) { | 373 | if ((!p_drv->probe) || (!try_module_get(p_drv->owner))) { |
376 | ret = -EINVAL; | 374 | ret = -EINVAL; |
377 | goto put_dev; | 375 | goto put_dev; |
378 | } | 376 | } |
379 | 377 | ||
380 | if (p_drv->attach) { | 378 | p_dev->state &= ~CLIENT_UNBOUND; |
381 | p_dev->instance = p_drv->attach(); | 379 | |
382 | if ((!p_dev->instance) || (p_dev->state & CLIENT_UNBOUND)) { | 380 | /* set up the device configuration, if it hasn't been done before */ |
383 | printk(KERN_NOTICE "ds: unable to create instance " | 381 | if (!s->functions) { |
384 | "of '%s'!\n", p_drv->drv.name); | 382 | cistpl_longlink_mfc_t mfc; |
385 | ret = -EINVAL; | 383 | if (pccard_read_tuple(s, p_dev->func, CISTPL_LONGLINK_MFC, |
384 | &mfc) == CS_SUCCESS) | ||
385 | s->functions = mfc.nfn; | ||
386 | else | ||
387 | s->functions = 1; | ||
388 | s->config = kzalloc(sizeof(config_t) * s->functions, | ||
389 | GFP_KERNEL); | ||
390 | if (!s->config) { | ||
391 | ret = -ENOMEM; | ||
392 | goto put_module; | ||
386 | } | 393 | } |
387 | } | 394 | } |
388 | 395 | ||
396 | ret = p_drv->probe(p_dev); | ||
397 | |||
398 | put_module: | ||
389 | if (ret) | 399 | if (ret) |
390 | module_put(p_drv->owner); | 400 | module_put(p_drv->owner); |
391 | put_dev: | 401 | put_dev: |
392 | if ((ret) || !(p_drv->attach)) | 402 | if (ret) |
393 | put_device(dev); | 403 | put_device(dev); |
394 | return (ret); | 404 | return (ret); |
395 | } | 405 | } |
@@ -399,24 +409,66 @@ static int pcmcia_device_remove(struct device * dev) | |||
399 | { | 409 | { |
400 | struct pcmcia_device *p_dev; | 410 | struct pcmcia_device *p_dev; |
401 | struct pcmcia_driver *p_drv; | 411 | struct pcmcia_driver *p_drv; |
412 | int i; | ||
402 | 413 | ||
403 | /* detach the "instance" */ | 414 | /* detach the "instance" */ |
404 | p_dev = to_pcmcia_dev(dev); | 415 | p_dev = to_pcmcia_dev(dev); |
405 | p_drv = to_pcmcia_drv(dev->driver); | 416 | p_drv = to_pcmcia_drv(dev->driver); |
417 | if (!p_drv) | ||
418 | return 0; | ||
406 | 419 | ||
407 | if (p_drv) { | 420 | if (p_drv->remove) |
408 | if ((p_drv->detach) && (p_dev->instance)) { | 421 | p_drv->remove(p_dev); |
409 | p_drv->detach(p_dev->instance); | 422 | |
410 | /* from pcmcia_probe_device */ | 423 | /* check for proper unloading */ |
411 | put_device(&p_dev->dev); | 424 | if (p_dev->state & (CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED)) |
412 | } | 425 | printk(KERN_INFO "pcmcia: driver %s did not release config properly\n", |
413 | module_put(p_drv->owner); | 426 | p_drv->drv.name); |
414 | } | 427 | |
428 | for (i = 0; i < MAX_WIN; i++) | ||
429 | if (p_dev->state & CLIENT_WIN_REQ(i)) | ||
430 | printk(KERN_INFO "pcmcia: driver %s did not release windows properly\n", | ||
431 | p_drv->drv.name); | ||
432 | |||
433 | /* references from pcmcia_probe_device */ | ||
434 | p_dev->state = CLIENT_UNBOUND; | ||
435 | pcmcia_put_dev(p_dev); | ||
436 | module_put(p_drv->owner); | ||
415 | 437 | ||
416 | return 0; | 438 | return 0; |
417 | } | 439 | } |
418 | 440 | ||
419 | 441 | ||
442 | /* | ||
443 | * Removes a PCMCIA card from the device tree and socket list. | ||
444 | */ | ||
445 | static void pcmcia_card_remove(struct pcmcia_socket *s) | ||
446 | { | ||
447 | struct pcmcia_device *p_dev; | ||
448 | unsigned long flags; | ||
449 | |||
450 | ds_dbg(2, "unbind_request(%d)\n", s->sock); | ||
451 | |||
452 | s->device_count = 0; | ||
453 | |||
454 | for (;;) { | ||
455 | /* unregister all pcmcia_devices registered with this socket*/ | ||
456 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | ||
457 | if (list_empty(&s->devices_list)) { | ||
458 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
459 | return; | ||
460 | } | ||
461 | p_dev = list_entry((&s->devices_list)->next, struct pcmcia_device, socket_device_list); | ||
462 | list_del(&p_dev->socket_device_list); | ||
463 | p_dev->state |= CLIENT_STALE; | ||
464 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
465 | |||
466 | device_unregister(&p_dev->dev); | ||
467 | } | ||
468 | |||
469 | return; | ||
470 | } /* unbind_request */ | ||
471 | |||
420 | 472 | ||
421 | /* | 473 | /* |
422 | * pcmcia_device_query -- determine information about a pcmcia device | 474 | * pcmcia_device_query -- determine information about a pcmcia device |
@@ -517,10 +569,9 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f | |||
517 | if (s->device_count == 2) | 569 | if (s->device_count == 2) |
518 | goto err_put; | 570 | goto err_put; |
519 | 571 | ||
520 | p_dev = kmalloc(sizeof(struct pcmcia_device), GFP_KERNEL); | 572 | p_dev = kzalloc(sizeof(struct pcmcia_device), GFP_KERNEL); |
521 | if (!p_dev) | 573 | if (!p_dev) |
522 | goto err_put; | 574 | goto err_put; |
523 | memset(p_dev, 0, sizeof(struct pcmcia_device)); | ||
524 | 575 | ||
525 | p_dev->socket = s; | 576 | p_dev->socket = s; |
526 | p_dev->device_no = (s->device_count++); | 577 | p_dev->device_no = (s->device_count++); |
@@ -583,7 +634,9 @@ static int pcmcia_card_add(struct pcmcia_socket *s) | |||
583 | if (!(s->resource_setup_done)) | 634 | if (!(s->resource_setup_done)) |
584 | return -EAGAIN; /* try again, but later... */ | 635 | return -EAGAIN; /* try again, but later... */ |
585 | 636 | ||
586 | pcmcia_validate_mem(s); | 637 | if (pcmcia_validate_mem(s)) |
638 | return -EAGAIN; /* try again, but later... */ | ||
639 | |||
587 | ret = pccard_validate_cis(s, BIND_FN_ALL, &cisinfo); | 640 | ret = pccard_validate_cis(s, BIND_FN_ALL, &cisinfo); |
588 | if (ret || !cisinfo.Chains) { | 641 | if (ret || !cisinfo.Chains) { |
589 | ds_dbg(0, "invalid CIS or invalid resources\n"); | 642 | ds_dbg(0, "invalid CIS or invalid resources\n"); |
@@ -918,55 +971,84 @@ static struct device_attribute pcmcia_dev_attrs[] = { | |||
918 | __ATTR_NULL, | 971 | __ATTR_NULL, |
919 | }; | 972 | }; |
920 | 973 | ||
974 | /* PM support, also needed for reset */ | ||
921 | 975 | ||
922 | /*====================================================================== | 976 | static int pcmcia_dev_suspend(struct device * dev, pm_message_t state) |
977 | { | ||
978 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | ||
979 | struct pcmcia_driver *p_drv = NULL; | ||
923 | 980 | ||
924 | The card status event handler. | 981 | if (dev->driver) |
925 | 982 | p_drv = to_pcmcia_drv(dev->driver); | |
926 | ======================================================================*/ | ||
927 | 983 | ||
928 | struct send_event_data { | 984 | if (p_drv && p_drv->suspend) |
929 | struct pcmcia_socket *skt; | 985 | return p_drv->suspend(p_dev); |
930 | event_t event; | 986 | |
931 | int priority; | 987 | return 0; |
932 | }; | 988 | } |
933 | 989 | ||
934 | static int send_event_callback(struct device *dev, void * _data) | 990 | |
991 | static int pcmcia_dev_resume(struct device * dev) | ||
935 | { | 992 | { |
936 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | 993 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); |
937 | struct pcmcia_driver *p_drv; | 994 | struct pcmcia_driver *p_drv = NULL; |
938 | struct send_event_data *data = _data; | ||
939 | 995 | ||
940 | /* we get called for all sockets, but may only pass the event | 996 | if (dev->driver) |
941 | * for drivers _on the affected socket_ */ | 997 | p_drv = to_pcmcia_drv(dev->driver); |
942 | if (p_dev->socket != data->skt) | ||
943 | return 0; | ||
944 | 998 | ||
945 | p_drv = to_pcmcia_drv(p_dev->dev.driver); | 999 | if (p_drv && p_drv->resume) |
946 | if (!p_drv) | 1000 | return p_drv->resume(p_dev); |
1001 | |||
1002 | return 0; | ||
1003 | } | ||
1004 | |||
1005 | |||
1006 | static int pcmcia_bus_suspend_callback(struct device *dev, void * _data) | ||
1007 | { | ||
1008 | struct pcmcia_socket *skt = _data; | ||
1009 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | ||
1010 | |||
1011 | if (p_dev->socket != skt) | ||
947 | return 0; | 1012 | return 0; |
948 | 1013 | ||
949 | if (p_dev->state & (CLIENT_UNBOUND|CLIENT_STALE)) | 1014 | return dpm_runtime_suspend(dev, PMSG_SUSPEND); |
1015 | } | ||
1016 | |||
1017 | static int pcmcia_bus_resume_callback(struct device *dev, void * _data) | ||
1018 | { | ||
1019 | struct pcmcia_socket *skt = _data; | ||
1020 | struct pcmcia_device *p_dev = to_pcmcia_dev(dev); | ||
1021 | |||
1022 | if (p_dev->socket != skt) | ||
950 | return 0; | 1023 | return 0; |
951 | 1024 | ||
952 | if (p_drv->event) | 1025 | dpm_runtime_resume(dev); |
953 | return p_drv->event(data->event, data->priority, | ||
954 | &p_dev->event_callback_args); | ||
955 | 1026 | ||
956 | return 0; | 1027 | return 0; |
957 | } | 1028 | } |
958 | 1029 | ||
959 | static int send_event(struct pcmcia_socket *s, event_t event, int priority) | 1030 | static int pcmcia_bus_resume(struct pcmcia_socket *skt) |
960 | { | 1031 | { |
961 | struct send_event_data private; | 1032 | bus_for_each_dev(&pcmcia_bus_type, NULL, skt, pcmcia_bus_resume_callback); |
1033 | return 0; | ||
1034 | } | ||
1035 | |||
1036 | static int pcmcia_bus_suspend(struct pcmcia_socket *skt) | ||
1037 | { | ||
1038 | if (bus_for_each_dev(&pcmcia_bus_type, NULL, skt, | ||
1039 | pcmcia_bus_suspend_callback)) { | ||
1040 | pcmcia_bus_resume(skt); | ||
1041 | return -EIO; | ||
1042 | } | ||
1043 | return 0; | ||
1044 | } | ||
962 | 1045 | ||
963 | private.skt = s; | ||
964 | private.event = event; | ||
965 | private.priority = priority; | ||
966 | 1046 | ||
967 | return bus_for_each_dev(&pcmcia_bus_type, NULL, &private, send_event_callback); | 1047 | /*====================================================================== |
968 | } /* send_event */ | ||
969 | 1048 | ||
1049 | The card status event handler. | ||
1050 | |||
1051 | ======================================================================*/ | ||
970 | 1052 | ||
971 | /* Normally, the event is passed to individual drivers after | 1053 | /* Normally, the event is passed to individual drivers after |
972 | * informing userspace. Only for CS_EVENT_CARD_REMOVAL this | 1054 | * informing userspace. Only for CS_EVENT_CARD_REMOVAL this |
@@ -976,20 +1058,17 @@ static int send_event(struct pcmcia_socket *s, event_t event, int priority) | |||
976 | static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) | 1058 | static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) |
977 | { | 1059 | { |
978 | struct pcmcia_socket *s = pcmcia_get_socket(skt); | 1060 | struct pcmcia_socket *s = pcmcia_get_socket(skt); |
979 | int ret = 0; | ||
980 | 1061 | ||
981 | ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n", | 1062 | ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n", |
982 | event, priority, skt); | 1063 | event, priority, skt); |
983 | |||
984 | switch (event) { | ||
985 | 1064 | ||
1065 | switch (event) { | ||
986 | case CS_EVENT_CARD_REMOVAL: | 1066 | case CS_EVENT_CARD_REMOVAL: |
987 | s->pcmcia_state.present = 0; | 1067 | s->pcmcia_state.present = 0; |
988 | send_event(skt, event, priority); | 1068 | pcmcia_card_remove(skt); |
989 | unbind_request(skt); | ||
990 | handle_event(skt, event); | 1069 | handle_event(skt, event); |
991 | break; | 1070 | break; |
992 | 1071 | ||
993 | case CS_EVENT_CARD_INSERTION: | 1072 | case CS_EVENT_CARD_INSERTION: |
994 | s->pcmcia_state.present = 1; | 1073 | s->pcmcia_state.present = 1; |
995 | pcmcia_card_add(skt); | 1074 | pcmcia_card_add(skt); |
@@ -997,12 +1076,14 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) | |||
997 | break; | 1076 | break; |
998 | 1077 | ||
999 | case CS_EVENT_EJECTION_REQUEST: | 1078 | case CS_EVENT_EJECTION_REQUEST: |
1000 | ret = send_event(skt, event, priority); | ||
1001 | break; | 1079 | break; |
1002 | 1080 | ||
1081 | case CS_EVENT_PM_SUSPEND: | ||
1082 | case CS_EVENT_PM_RESUME: | ||
1083 | case CS_EVENT_RESET_PHYSICAL: | ||
1084 | case CS_EVENT_CARD_RESET: | ||
1003 | default: | 1085 | default: |
1004 | handle_event(skt, event); | 1086 | handle_event(skt, event); |
1005 | send_event(skt, event, priority); | ||
1006 | break; | 1087 | break; |
1007 | } | 1088 | } |
1008 | 1089 | ||
@@ -1012,152 +1093,12 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority) | |||
1012 | } /* ds_event */ | 1093 | } /* ds_event */ |
1013 | 1094 | ||
1014 | 1095 | ||
1015 | |||
1016 | int pcmcia_register_client(struct pcmcia_device **handle, client_reg_t *req) | ||
1017 | { | ||
1018 | struct pcmcia_socket *s = NULL; | ||
1019 | struct pcmcia_device *p_dev = NULL; | ||
1020 | struct pcmcia_driver *p_drv = NULL; | ||
1021 | |||
1022 | /* Look for unbound client with matching dev_info */ | ||
1023 | down_read(&pcmcia_socket_list_rwsem); | ||
1024 | list_for_each_entry(s, &pcmcia_socket_list, socket_list) { | ||
1025 | unsigned long flags; | ||
1026 | |||
1027 | if (s->state & SOCKET_CARDBUS) | ||
1028 | continue; | ||
1029 | |||
1030 | s = pcmcia_get_socket(s); | ||
1031 | if (!s) | ||
1032 | continue; | ||
1033 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | ||
1034 | list_for_each_entry(p_dev, &s->devices_list, socket_device_list) { | ||
1035 | p_dev = pcmcia_get_dev(p_dev); | ||
1036 | if (!p_dev) | ||
1037 | continue; | ||
1038 | if (!(p_dev->state & CLIENT_UNBOUND) || | ||
1039 | (!p_dev->dev.driver)) { | ||
1040 | pcmcia_put_dev(p_dev); | ||
1041 | continue; | ||
1042 | } | ||
1043 | p_drv = to_pcmcia_drv(p_dev->dev.driver); | ||
1044 | if (!strncmp(p_drv->drv.name, (char *)req->dev_info, DEV_NAME_LEN)) { | ||
1045 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
1046 | goto found; | ||
1047 | } | ||
1048 | pcmcia_put_dev(p_dev); | ||
1049 | } | ||
1050 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
1051 | pcmcia_put_socket(s); | ||
1052 | } | ||
1053 | found: | ||
1054 | up_read(&pcmcia_socket_list_rwsem); | ||
1055 | if (!p_dev) | ||
1056 | return -ENODEV; | ||
1057 | |||
1058 | pcmcia_put_socket(s); /* safe, as we already hold a reference from bind_device */ | ||
1059 | |||
1060 | *handle = p_dev; | ||
1061 | p_dev->state &= ~CLIENT_UNBOUND; | ||
1062 | p_dev->event_callback_args = req->event_callback_args; | ||
1063 | p_dev->event_callback_args.client_handle = p_dev; | ||
1064 | |||
1065 | |||
1066 | if (!s->functions) { | ||
1067 | cistpl_longlink_mfc_t mfc; | ||
1068 | if (pccard_read_tuple(s, p_dev->func, CISTPL_LONGLINK_MFC, &mfc) | ||
1069 | == CS_SUCCESS) | ||
1070 | s->functions = mfc.nfn; | ||
1071 | else | ||
1072 | s->functions = 1; | ||
1073 | s->config = kmalloc(sizeof(config_t) * s->functions, | ||
1074 | GFP_KERNEL); | ||
1075 | if (!s->config) | ||
1076 | goto out_no_resource; | ||
1077 | memset(s->config, 0, sizeof(config_t) * s->functions); | ||
1078 | } | ||
1079 | |||
1080 | ds_dbg(1, "register_client(): client 0x%p, dev %s\n", | ||
1081 | p_dev, p_dev->dev.bus_id); | ||
1082 | |||
1083 | if ((s->state & (SOCKET_PRESENT|SOCKET_CARDBUS)) == SOCKET_PRESENT) { | ||
1084 | if (p_drv->event) | ||
1085 | p_drv->event(CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW, | ||
1086 | &p_dev->event_callback_args); | ||
1087 | |||
1088 | } | ||
1089 | |||
1090 | return CS_SUCCESS; | ||
1091 | |||
1092 | out_no_resource: | ||
1093 | pcmcia_put_dev(p_dev); | ||
1094 | return CS_OUT_OF_RESOURCE; | ||
1095 | } /* register_client */ | ||
1096 | EXPORT_SYMBOL(pcmcia_register_client); | ||
1097 | |||
1098 | |||
1099 | /* unbind _all_ devices attached to a given pcmcia_bus_socket. The | ||
1100 | * drivers have been called with EVENT_CARD_REMOVAL before. | ||
1101 | */ | ||
1102 | static int unbind_request(struct pcmcia_socket *s) | ||
1103 | { | ||
1104 | struct pcmcia_device *p_dev; | ||
1105 | unsigned long flags; | ||
1106 | |||
1107 | ds_dbg(2, "unbind_request(%d)\n", s->sock); | ||
1108 | |||
1109 | s->device_count = 0; | ||
1110 | |||
1111 | for (;;) { | ||
1112 | /* unregister all pcmcia_devices registered with this socket*/ | ||
1113 | spin_lock_irqsave(&pcmcia_dev_list_lock, flags); | ||
1114 | if (list_empty(&s->devices_list)) { | ||
1115 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
1116 | return 0; | ||
1117 | } | ||
1118 | p_dev = list_entry((&s->devices_list)->next, struct pcmcia_device, socket_device_list); | ||
1119 | list_del(&p_dev->socket_device_list); | ||
1120 | p_dev->state |= CLIENT_STALE; | ||
1121 | spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags); | ||
1122 | |||
1123 | device_unregister(&p_dev->dev); | ||
1124 | } | ||
1125 | |||
1126 | return 0; | ||
1127 | } /* unbind_request */ | ||
1128 | |||
1129 | int pcmcia_deregister_client(struct pcmcia_device *p_dev) | ||
1130 | { | ||
1131 | struct pcmcia_socket *s; | ||
1132 | int i; | ||
1133 | |||
1134 | s = p_dev->socket; | ||
1135 | ds_dbg(1, "deregister_client(%p)\n", p_dev); | ||
1136 | |||
1137 | if (p_dev->state & (CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED)) | ||
1138 | goto warn_out; | ||
1139 | for (i = 0; i < MAX_WIN; i++) | ||
1140 | if (p_dev->state & CLIENT_WIN_REQ(i)) | ||
1141 | goto warn_out; | ||
1142 | |||
1143 | if (p_dev->state & CLIENT_STALE) { | ||
1144 | p_dev->state &= ~CLIENT_STALE; | ||
1145 | pcmcia_put_dev(p_dev); | ||
1146 | } else { | ||
1147 | p_dev->state = CLIENT_UNBOUND; | ||
1148 | } | ||
1149 | |||
1150 | return CS_SUCCESS; | ||
1151 | warn_out: | ||
1152 | printk(KERN_WARNING "ds: deregister_client was called too early.\n"); | ||
1153 | return CS_IN_USE; | ||
1154 | } /* deregister_client */ | ||
1155 | EXPORT_SYMBOL(pcmcia_deregister_client); | ||
1156 | |||
1157 | static struct pcmcia_callback pcmcia_bus_callback = { | 1096 | static struct pcmcia_callback pcmcia_bus_callback = { |
1158 | .owner = THIS_MODULE, | 1097 | .owner = THIS_MODULE, |
1159 | .event = ds_event, | 1098 | .event = ds_event, |
1160 | .requery = pcmcia_bus_rescan, | 1099 | .requery = pcmcia_bus_rescan, |
1100 | .suspend = pcmcia_bus_suspend, | ||
1101 | .resume = pcmcia_bus_resume, | ||
1161 | }; | 1102 | }; |
1162 | 1103 | ||
1163 | static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev, | 1104 | static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev, |
@@ -1226,6 +1167,8 @@ struct bus_type pcmcia_bus_type = { | |||
1226 | .uevent = pcmcia_bus_uevent, | 1167 | .uevent = pcmcia_bus_uevent, |
1227 | .match = pcmcia_bus_match, | 1168 | .match = pcmcia_bus_match, |
1228 | .dev_attrs = pcmcia_dev_attrs, | 1169 | .dev_attrs = pcmcia_dev_attrs, |
1170 | .suspend = pcmcia_dev_suspend, | ||
1171 | .resume = pcmcia_dev_resume, | ||
1229 | }; | 1172 | }; |
1230 | 1173 | ||
1231 | 1174 | ||
diff --git a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c index 561706ba4499..b39435bbfaeb 100644 --- a/drivers/pcmcia/hd64465_ss.c +++ b/drivers/pcmcia/hd64465_ss.c | |||
@@ -417,18 +417,6 @@ static int hs_get_status(struct pcmcia_socket *s, u_int *value) | |||
417 | 417 | ||
418 | /*============================================================*/ | 418 | /*============================================================*/ |
419 | 419 | ||
420 | static int hs_get_socket(struct pcmcia_socket *s, socket_state_t *state) | ||
421 | { | ||
422 | hs_socket_t *sp = container_of(s, struct hs_socket_t, socket); | ||
423 | |||
424 | DPRINTK("hs_get_socket(%d)\n", sock); | ||
425 | |||
426 | *state = sp->state; | ||
427 | return 0; | ||
428 | } | ||
429 | |||
430 | /*============================================================*/ | ||
431 | |||
432 | static int hs_set_socket(struct pcmcia_socket *s, socket_state_t *state) | 420 | static int hs_set_socket(struct pcmcia_socket *s, socket_state_t *state) |
433 | { | 421 | { |
434 | hs_socket_t *sp = container_of(s, struct hs_socket_t, socket); | 422 | hs_socket_t *sp = container_of(s, struct hs_socket_t, socket); |
@@ -749,7 +737,6 @@ static irqreturn_t hs_interrupt(int irq, void *dev, struct pt_regs *regs) | |||
749 | static struct pccard_operations hs_operations = { | 737 | static struct pccard_operations hs_operations = { |
750 | .init = hs_init, | 738 | .init = hs_init, |
751 | .get_status = hs_get_status, | 739 | .get_status = hs_get_status, |
752 | .get_socket = hs_get_socket, | ||
753 | .set_socket = hs_set_socket, | 740 | .set_socket = hs_set_socket, |
754 | .set_io_map = hs_set_io_map, | 741 | .set_io_map = hs_set_io_map, |
755 | .set_mem_map = hs_set_mem_map, | 742 | .set_mem_map = hs_set_mem_map, |
diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c index f3fdc748659d..7979c85df3dc 100644 --- a/drivers/pcmcia/i82092.c +++ b/drivers/pcmcia/i82092.c | |||
@@ -66,7 +66,6 @@ static struct pci_driver i82092aa_pci_drv = { | |||
66 | static struct pccard_operations i82092aa_operations = { | 66 | static struct pccard_operations i82092aa_operations = { |
67 | .init = i82092aa_init, | 67 | .init = i82092aa_init, |
68 | .get_status = i82092aa_get_status, | 68 | .get_status = i82092aa_get_status, |
69 | .get_socket = i82092aa_get_socket, | ||
70 | .set_socket = i82092aa_set_socket, | 69 | .set_socket = i82092aa_set_socket, |
71 | .set_io_map = i82092aa_set_io_map, | 70 | .set_io_map = i82092aa_set_io_map, |
72 | .set_mem_map = i82092aa_set_mem_map, | 71 | .set_mem_map = i82092aa_set_mem_map, |
@@ -482,78 +481,6 @@ static int i82092aa_get_status(struct pcmcia_socket *socket, u_int *value) | |||
482 | } | 481 | } |
483 | 482 | ||
484 | 483 | ||
485 | static int i82092aa_get_socket(struct pcmcia_socket *socket, socket_state_t *state) | ||
486 | { | ||
487 | unsigned int sock = container_of(socket, struct socket_info, socket)->number; | ||
488 | unsigned char reg,vcc,vpp; | ||
489 | |||
490 | enter("i82092aa_get_socket"); | ||
491 | state->flags = 0; | ||
492 | state->Vcc = 0; | ||
493 | state->Vpp = 0; | ||
494 | state->io_irq = 0; | ||
495 | state->csc_mask = 0; | ||
496 | |||
497 | /* First the power status of the socket */ | ||
498 | reg = indirect_read(sock,I365_POWER); /* PCTRL - Power Control Register */ | ||
499 | |||
500 | if (reg & I365_PWR_AUTO) | ||
501 | state->flags |= SS_PWR_AUTO; /* Automatic Power Switch */ | ||
502 | |||
503 | if (reg & I365_PWR_OUT) | ||
504 | state->flags |= SS_OUTPUT_ENA; /* Output signals are enabled */ | ||
505 | |||
506 | vcc = reg & I365_VCC_MASK; vpp = reg & I365_VPP1_MASK; | ||
507 | |||
508 | if (reg & I365_VCC_5V) { /* Can still be 3.3V, in this case the Vcc value will be overwritten later */ | ||
509 | state->Vcc = 50; | ||
510 | |||
511 | if (vpp == I365_VPP1_5V) | ||
512 | state->Vpp = 50; | ||
513 | if (vpp == I365_VPP1_12V) | ||
514 | state->Vpp = 120; | ||
515 | |||
516 | } | ||
517 | |||
518 | if ((reg & I365_VCC_3V)==I365_VCC_3V) | ||
519 | state->Vcc = 33; | ||
520 | |||
521 | |||
522 | /* Now the IO card, RESET flags and IO interrupt */ | ||
523 | |||
524 | reg = indirect_read(sock, I365_INTCTL); /* IGENC, Interrupt and General Control */ | ||
525 | |||
526 | if ((reg & I365_PC_RESET)==0) | ||
527 | state->flags |= SS_RESET; | ||
528 | if (reg & I365_PC_IOCARD) | ||
529 | state->flags |= SS_IOCARD; /* This is an IO card */ | ||
530 | |||
531 | /* Set the IRQ number */ | ||
532 | if (sockets[sock].dev!=NULL) | ||
533 | state->io_irq = sockets[sock].dev->irq; | ||
534 | |||
535 | /* Card status change */ | ||
536 | reg = indirect_read(sock, I365_CSCINT); /* CSCICR, Card Status Change Interrupt Configuration */ | ||
537 | |||
538 | if (reg & I365_CSC_DETECT) | ||
539 | state->csc_mask |= SS_DETECT; /* Card detect is enabled */ | ||
540 | |||
541 | if (state->flags & SS_IOCARD) {/* IO Cards behave different */ | ||
542 | if (reg & I365_CSC_STSCHG) | ||
543 | state->csc_mask |= SS_STSCHG; | ||
544 | } else { | ||
545 | if (reg & I365_CSC_BVD1) | ||
546 | state->csc_mask |= SS_BATDEAD; | ||
547 | if (reg & I365_CSC_BVD2) | ||
548 | state->csc_mask |= SS_BATWARN; | ||
549 | if (reg & I365_CSC_READY) | ||
550 | state->csc_mask |= SS_READY; | ||
551 | } | ||
552 | |||
553 | leave("i82092aa_get_socket"); | ||
554 | return 0; | ||
555 | } | ||
556 | |||
557 | static int i82092aa_set_socket(struct pcmcia_socket *socket, socket_state_t *state) | 484 | static int i82092aa_set_socket(struct pcmcia_socket *socket, socket_state_t *state) |
558 | { | 485 | { |
559 | unsigned int sock = container_of(socket, struct socket_info, socket)->number; | 486 | unsigned int sock = container_of(socket, struct socket_info, socket)->number; |
diff --git a/drivers/pcmcia/i82092aa.h b/drivers/pcmcia/i82092aa.h index b98cac7bda9f..9c14599d0673 100644 --- a/drivers/pcmcia/i82092aa.h +++ b/drivers/pcmcia/i82092aa.h | |||
@@ -29,7 +29,6 @@ static irqreturn_t i82092aa_interrupt(int irq, void *dev, struct pt_regs *regs); | |||
29 | 29 | ||
30 | 30 | ||
31 | static int i82092aa_get_status(struct pcmcia_socket *socket, u_int *value); | 31 | static int i82092aa_get_status(struct pcmcia_socket *socket, u_int *value); |
32 | static int i82092aa_get_socket(struct pcmcia_socket *socket, socket_state_t *state); | ||
33 | static int i82092aa_set_socket(struct pcmcia_socket *socket, socket_state_t *state); | 32 | static int i82092aa_set_socket(struct pcmcia_socket *socket, socket_state_t *state); |
34 | static int i82092aa_set_io_map(struct pcmcia_socket *socket, struct pccard_io_map *io); | 33 | static int i82092aa_set_io_map(struct pcmcia_socket *socket, struct pccard_io_map *io); |
35 | static int i82092aa_set_mem_map(struct pcmcia_socket *socket, struct pccard_mem_map *mem); | 34 | static int i82092aa_set_mem_map(struct pcmcia_socket *socket, struct pccard_mem_map *mem); |
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c index 4d56bc9926d6..35a92d1e4945 100644 --- a/drivers/pcmcia/i82365.c +++ b/drivers/pcmcia/i82365.c | |||
@@ -940,78 +940,6 @@ static int i365_get_status(u_short sock, u_int *value) | |||
940 | 940 | ||
941 | /*====================================================================*/ | 941 | /*====================================================================*/ |
942 | 942 | ||
943 | static int i365_get_socket(u_short sock, socket_state_t *state) | ||
944 | { | ||
945 | struct i82365_socket *t = &socket[sock]; | ||
946 | u_char reg, vcc, vpp; | ||
947 | |||
948 | reg = i365_get(sock, I365_POWER); | ||
949 | state->flags = (reg & I365_PWR_AUTO) ? SS_PWR_AUTO : 0; | ||
950 | state->flags |= (reg & I365_PWR_OUT) ? SS_OUTPUT_ENA : 0; | ||
951 | vcc = reg & I365_VCC_MASK; vpp = reg & I365_VPP1_MASK; | ||
952 | state->Vcc = state->Vpp = 0; | ||
953 | if (t->flags & IS_CIRRUS) { | ||
954 | if (i365_get(sock, PD67_MISC_CTL_1) & PD67_MC1_VCC_3V) { | ||
955 | if (reg & I365_VCC_5V) state->Vcc = 33; | ||
956 | if (vpp == I365_VPP1_5V) state->Vpp = 33; | ||
957 | } else { | ||
958 | if (reg & I365_VCC_5V) state->Vcc = 50; | ||
959 | if (vpp == I365_VPP1_5V) state->Vpp = 50; | ||
960 | } | ||
961 | if (vpp == I365_VPP1_12V) state->Vpp = 120; | ||
962 | } else if (t->flags & IS_VG_PWR) { | ||
963 | if (i365_get(sock, VG469_VSELECT) & VG469_VSEL_VCC) { | ||
964 | if (reg & I365_VCC_5V) state->Vcc = 33; | ||
965 | if (vpp == I365_VPP1_5V) state->Vpp = 33; | ||
966 | } else { | ||
967 | if (reg & I365_VCC_5V) state->Vcc = 50; | ||
968 | if (vpp == I365_VPP1_5V) state->Vpp = 50; | ||
969 | } | ||
970 | if (vpp == I365_VPP1_12V) state->Vpp = 120; | ||
971 | } else if (t->flags & IS_DF_PWR) { | ||
972 | if (vcc == I365_VCC_3V) state->Vcc = 33; | ||
973 | if (vcc == I365_VCC_5V) state->Vcc = 50; | ||
974 | if (vpp == I365_VPP1_5V) state->Vpp = 50; | ||
975 | if (vpp == I365_VPP1_12V) state->Vpp = 120; | ||
976 | } else { | ||
977 | if (reg & I365_VCC_5V) { | ||
978 | state->Vcc = 50; | ||
979 | if (vpp == I365_VPP1_5V) state->Vpp = 50; | ||
980 | if (vpp == I365_VPP1_12V) state->Vpp = 120; | ||
981 | } | ||
982 | } | ||
983 | |||
984 | /* IO card, RESET flags, IO interrupt */ | ||
985 | reg = i365_get(sock, I365_INTCTL); | ||
986 | state->flags |= (reg & I365_PC_RESET) ? 0 : SS_RESET; | ||
987 | if (reg & I365_PC_IOCARD) state->flags |= SS_IOCARD; | ||
988 | state->io_irq = reg & I365_IRQ_MASK; | ||
989 | |||
990 | /* speaker control */ | ||
991 | if (t->flags & IS_CIRRUS) { | ||
992 | if (i365_get(sock, PD67_MISC_CTL_1) & PD67_MC1_SPKR_ENA) | ||
993 | state->flags |= SS_SPKR_ENA; | ||
994 | } | ||
995 | |||
996 | /* Card status change mask */ | ||
997 | reg = i365_get(sock, I365_CSCINT); | ||
998 | state->csc_mask = (reg & I365_CSC_DETECT) ? SS_DETECT : 0; | ||
999 | if (state->flags & SS_IOCARD) | ||
1000 | state->csc_mask |= (reg & I365_CSC_STSCHG) ? SS_STSCHG : 0; | ||
1001 | else { | ||
1002 | state->csc_mask |= (reg & I365_CSC_BVD1) ? SS_BATDEAD : 0; | ||
1003 | state->csc_mask |= (reg & I365_CSC_BVD2) ? SS_BATWARN : 0; | ||
1004 | state->csc_mask |= (reg & I365_CSC_READY) ? SS_READY : 0; | ||
1005 | } | ||
1006 | |||
1007 | debug(1, "GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, " | ||
1008 | "io_irq %d, csc_mask %#2.2x\n", sock, state->flags, | ||
1009 | state->Vcc, state->Vpp, state->io_irq, state->csc_mask); | ||
1010 | return 0; | ||
1011 | } /* i365_get_socket */ | ||
1012 | |||
1013 | /*====================================================================*/ | ||
1014 | |||
1015 | static int i365_set_socket(u_short sock, socket_state_t *state) | 943 | static int i365_set_socket(u_short sock, socket_state_t *state) |
1016 | { | 944 | { |
1017 | struct i82365_socket *t = &socket[sock]; | 945 | struct i82365_socket *t = &socket[sock]; |
@@ -1265,16 +1193,6 @@ static int pcic_get_status(struct pcmcia_socket *s, u_int *value) | |||
1265 | LOCKED(i365_get_status(sock, value)); | 1193 | LOCKED(i365_get_status(sock, value)); |
1266 | } | 1194 | } |
1267 | 1195 | ||
1268 | static int pcic_get_socket(struct pcmcia_socket *s, socket_state_t *state) | ||
1269 | { | ||
1270 | unsigned int sock = container_of(s, struct i82365_socket, socket)->number; | ||
1271 | |||
1272 | if (socket[sock].flags & IS_ALIVE) | ||
1273 | return -EINVAL; | ||
1274 | |||
1275 | LOCKED(i365_get_socket(sock, state)); | ||
1276 | } | ||
1277 | |||
1278 | static int pcic_set_socket(struct pcmcia_socket *s, socket_state_t *state) | 1196 | static int pcic_set_socket(struct pcmcia_socket *s, socket_state_t *state) |
1279 | { | 1197 | { |
1280 | unsigned int sock = container_of(s, struct i82365_socket, socket)->number; | 1198 | unsigned int sock = container_of(s, struct i82365_socket, socket)->number; |
@@ -1324,7 +1242,6 @@ static int pcic_init(struct pcmcia_socket *s) | |||
1324 | static struct pccard_operations pcic_operations = { | 1242 | static struct pccard_operations pcic_operations = { |
1325 | .init = pcic_init, | 1243 | .init = pcic_init, |
1326 | .get_status = pcic_get_status, | 1244 | .get_status = pcic_get_status, |
1327 | .get_socket = pcic_get_socket, | ||
1328 | .set_socket = pcic_set_socket, | 1245 | .set_socket = pcic_set_socket, |
1329 | .set_io_map = pcic_set_io_map, | 1246 | .set_io_map = pcic_set_io_map, |
1330 | .set_mem_map = pcic_set_mem_map, | 1247 | .set_mem_map = pcic_set_mem_map, |
diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c index 078579ae6359..071cf485e1a3 100644 --- a/drivers/pcmcia/m32r_cfc.c +++ b/drivers/pcmcia/m32r_cfc.c | |||
@@ -480,25 +480,6 @@ static int _pcc_get_status(u_short sock, u_int *value) | |||
480 | 480 | ||
481 | /*====================================================================*/ | 481 | /*====================================================================*/ |
482 | 482 | ||
483 | static int _pcc_get_socket(u_short sock, socket_state_t *state) | ||
484 | { | ||
485 | // pcc_socket_t *t = &socket[sock]; | ||
486 | |||
487 | state->flags = 0; | ||
488 | state->csc_mask = SS_DETECT; | ||
489 | state->csc_mask |= SS_READY; | ||
490 | state->io_irq = 0; | ||
491 | state->Vcc = 33; /* 3.3V fixed */ | ||
492 | state->Vpp = 33; | ||
493 | |||
494 | debug(3, "m32r_cfc: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, " | ||
495 | "io_irq %d, csc_mask %#2.2x\n", sock, state->flags, | ||
496 | state->Vcc, state->Vpp, state->io_irq, state->csc_mask); | ||
497 | return 0; | ||
498 | } /* _get_socket */ | ||
499 | |||
500 | /*====================================================================*/ | ||
501 | |||
502 | static int _pcc_set_socket(u_short sock, socket_state_t *state) | 483 | static int _pcc_set_socket(u_short sock, socket_state_t *state) |
503 | { | 484 | { |
504 | debug(3, "m32r_cfc: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " | 485 | debug(3, "m32r_cfc: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, " |
@@ -667,18 +648,6 @@ static int pcc_get_status(struct pcmcia_socket *s, u_int *value) | |||
667 | LOCKED(_pcc_get_status(sock, value)); | 648 | LOCKED(_pcc_get_status(sock, value)); |
668 | } | 649 | } |
669 | 650 | ||
670 | static int pcc_get_socket(struct pcmcia_socket *s, socket_state_t *state) | ||
671 | { | ||
672 | unsigned int sock = container_of(s, struct pcc_socket, socket)->number; | ||
673 | |||
674 | if (socket[sock].flags & IS_ALIVE) { | ||
675 | debug(3, "m32r_cfc: pcc_get_socket: sock(%d) -EINVAL\n", sock); | ||
676 | return -EINVAL; | ||
677 | } | ||
678 | debug(3, "m32r_cfc: pcc_get_socket: sock(%d)\n", sock); | ||
679 | LOCKED(_pcc_get_socket(sock, state)); | ||
680 | } | ||
681 | |||
682 | static int pcc_set_socket(struct pcmcia_socket *s, socket_state_t *state) | 651 | static int pcc_set_socket(struct pcmcia_socket *s, socket_state_t *state) |
683 | { | 652 | { |
684 | unsigned int sock = container_of(s, struct pcc_socket, socket)->number; | 653 | unsigned int sock = container_of(s, struct pcc_socket, socket)->number; |
@@ -724,7 +693,6 @@ static int pcc_init(struct pcmcia_socket *s) | |||
724 | static struct pccard_operations pcc_operations = { | 693 | static struct pccard_operations pcc_operations = { |
725 | .init = pcc_init, | 694 | .init = pcc_init, |
726 | .get_status = pcc_get_status, | 695 | .get_status = pcc_get_status, |
727 | .get_socket = pcc_get_socket, | ||
728 | .set_socket = pcc_set_socket, | 696 | .set_socket = pcc_set_socket, |
729 | .set_io_map = pcc_set_io_map, | 697 | .set_io_map = pcc_set_io_map, |
730 | .set_mem_map = pcc_set_mem_map, | 698 | .set_mem_map = pcc_set_mem_map, |
diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c index 356a6fb416a1..70d5f0748d55 100644 --- a/drivers/pcmcia/m32r_pcc.c +++ b/drivers/pcmcia/m32r_pcc.c | |||
@@ -429,16 +429,6 @@ static int _pcc_get_status(u_short sock, u_int *value) | |||
429 | 429 | ||
430 | /*====================================================================*/ | 430 | /*====================================================================*/ |
431 | 431 | ||
432 | static int _pcc_get_socket(u_short sock, socket_state_t *state) | ||
433 | { | ||
434 | debug(3, "m32r-pcc: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, " | ||
435 | "io_irq %d, csc_mask %#2.2x\n", sock, state->flags, | ||
436 | state->Vcc, state->Vpp, state->io_irq, state->csc_mask); | ||
437 | return 0; | ||
438 | } /* _get_socket */ | ||
439 | |||
440 | /*====================================================================*/ | ||
441 | |||
442 | static int _pcc_set_socket(u_short sock, socket_state_t *state) | 432 | static int _pcc_set_socket(u_short sock, socket_state_t *state) |
443 | { | 433 | { |
444 | u_long reg = 0; | 434 | u_long reg = 0; |
@@ -641,15 +631,6 @@ static int pcc_get_status(struct pcmcia_socket *s, u_int *value) | |||
641 | LOCKED(_pcc_get_status(sock, value)); | 631 | LOCKED(_pcc_get_status(sock, value)); |
642 | } | 632 | } |
643 | 633 | ||
644 | static int pcc_get_socket(struct pcmcia_socket *s, socket_state_t *state) | ||
645 | { | ||
646 | unsigned int sock = container_of(s, struct pcc_socket, socket)->number; | ||
647 | |||
648 | if (socket[sock].flags & IS_ALIVE) | ||
649 | return -EINVAL; | ||
650 | LOCKED(_pcc_get_socket(sock, state)); | ||
651 | } | ||
652 | |||
653 | static int pcc_set_socket(struct pcmcia_socket *s, socket_state_t *state) | 634 | static int pcc_set_socket(struct pcmcia_socket *s, socket_state_t *state) |
654 | { | 635 | { |
655 | unsigned int sock = container_of(s, struct pcc_socket, socket)->number; | 636 | unsigned int sock = container_of(s, struct pcc_socket, socket)->number; |
@@ -687,7 +668,6 @@ static int pcc_init(struct pcmcia_socket *s) | |||
687 | static struct pccard_operations pcc_operations = { | 668 | static struct pccard_operations pcc_operations = { |
688 | .init = pcc_init, | 669 | .init = pcc_init, |
689 | .get_status = pcc_get_status, | 670 | .get_status = pcc_get_status, |
690 | .get_socket = pcc_get_socket, | ||
691 | .set_socket = pcc_set_socket, | 671 | .set_socket = pcc_set_socket, |
692 | .set_io_map = pcc_set_io_map, | 672 | .set_io_map = pcc_set_io_map, |
693 | .set_mem_map = pcc_set_mem_map, | 673 | .set_mem_map = pcc_set_mem_map, |
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c index 6d9f71cfcb34..0e07d9535116 100644 --- a/drivers/pcmcia/m8xx_pcmcia.c +++ b/drivers/pcmcia/m8xx_pcmcia.c | |||
@@ -9,6 +9,9 @@ | |||
9 | * <oliver.kurth@cyclades.de> | 9 | * <oliver.kurth@cyclades.de> |
10 | * Further fixes, v2.6 kernel port | 10 | * Further fixes, v2.6 kernel port |
11 | * <marcelo.tosatti@cyclades.com> | 11 | * <marcelo.tosatti@cyclades.com> |
12 | * | ||
13 | * Some fixes, additions (C) 2005 Montavista Software, Inc. | ||
14 | * <vbordug@ru.mvista.com> | ||
12 | * | 15 | * |
13 | * "The ExCA standard specifies that socket controllers should provide | 16 | * "The ExCA standard specifies that socket controllers should provide |
14 | * two IO and five memory windows per socket, which can be independently | 17 | * two IO and five memory windows per socket, which can be independently |
@@ -97,6 +100,11 @@ MODULE_LICENSE("Dual MPL/GPL"); | |||
97 | #endif | 100 | #endif |
98 | #endif | 101 | #endif |
99 | 102 | ||
103 | #if defined(CONFIG_MPC885ADS) | ||
104 | #define CONFIG_PCMCIA_SLOT_A | ||
105 | #define PCMCIA_GLITCHY_CD | ||
106 | #endif | ||
107 | |||
100 | /* Cyclades ACS uses both slots */ | 108 | /* Cyclades ACS uses both slots */ |
101 | #ifdef CONFIG_PRxK | 109 | #ifdef CONFIG_PRxK |
102 | #define CONFIG_PCMCIA_SLOT_A | 110 | #define CONFIG_PCMCIA_SLOT_A |
@@ -374,10 +382,10 @@ static int voltage_set(int slot, int vcc, int vpp) | |||
374 | } | 382 | } |
375 | 383 | ||
376 | /* first, turn off all power */ | 384 | /* first, turn off all power */ |
377 | out_be32(&((u32 *)BCSR1), in_be32(&((u32 *)BCSR1)) & ~(BCSR1_PCCVCC_MASK | BCSR1_PCCVPP_MASK)); | 385 | out_be32((u32 *)BCSR1, in_be32((u32 *)BCSR1) & ~(BCSR1_PCCVCC_MASK | BCSR1_PCCVPP_MASK)); |
378 | 386 | ||
379 | /* enable new powersettings */ | 387 | /* enable new powersettings */ |
380 | out_be32(&((u32 *)BCSR1), in_be32(&((u32 *)BCSR1)) | reg); | 388 | out_be32((u32 *)BCSR1, in_be32((u32 *)BCSR1) | reg); |
381 | 389 | ||
382 | return 0; | 390 | return 0; |
383 | } | 391 | } |
@@ -386,12 +394,89 @@ static int voltage_set(int slot, int vcc, int vpp) | |||
386 | 394 | ||
387 | static void hardware_enable(int slot) | 395 | static void hardware_enable(int slot) |
388 | { | 396 | { |
389 | out_be32(&((u32 *)BCSR1), in_be32(&((u32 *)BCSR1)) & ~BCSR1_PCCEN); | 397 | out_be32((u32 *)BCSR1, in_be32((u32 *)BCSR1) & ~BCSR1_PCCEN); |
390 | } | 398 | } |
391 | 399 | ||
392 | static void hardware_disable(int slot) | 400 | static void hardware_disable(int slot) |
393 | { | 401 | { |
394 | out_be32(&((u32 *)BCSR1), in_be32(&((u32 *)BCSR1)) | BCSR1_PCCEN); | 402 | out_be32((u32 *)BCSR1, in_be32((u32 *)BCSR1) | BCSR1_PCCEN); |
403 | } | ||
404 | |||
405 | #endif | ||
406 | |||
407 | /* MPC885ADS Boards */ | ||
408 | |||
409 | #if defined(CONFIG_MPC885ADS) | ||
410 | |||
411 | #define PCMCIA_BOARD_MSG "MPC885ADS" | ||
412 | |||
413 | static int voltage_set(int slot, int vcc, int vpp) | ||
414 | { | ||
415 | u32 reg = 0; | ||
416 | unsigned *bcsr_io; | ||
417 | |||
418 | bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); | ||
419 | |||
420 | switch(vcc) { | ||
421 | case 0: | ||
422 | break; | ||
423 | case 33: | ||
424 | reg |= BCSR1_PCCVCC0; | ||
425 | break; | ||
426 | case 50: | ||
427 | reg |= BCSR1_PCCVCC1; | ||
428 | break; | ||
429 | default: | ||
430 | return 1; | ||
431 | } | ||
432 | |||
433 | switch(vpp) { | ||
434 | case 0: | ||
435 | break; | ||
436 | case 33: | ||
437 | case 50: | ||
438 | if(vcc == vpp) | ||
439 | reg |= BCSR1_PCCVPP1; | ||
440 | else | ||
441 | return 1; | ||
442 | break; | ||
443 | case 120: | ||
444 | if ((vcc == 33) || (vcc == 50)) | ||
445 | reg |= BCSR1_PCCVPP0; | ||
446 | else | ||
447 | return 1; | ||
448 | default: | ||
449 | return 1; | ||
450 | } | ||
451 | |||
452 | /* first, turn off all power */ | ||
453 | out_be32(bcsr_io, in_be32(bcsr_io) & ~(BCSR1_PCCVCC_MASK | BCSR1_PCCVPP_MASK)); | ||
454 | |||
455 | /* enable new powersettings */ | ||
456 | out_be32(bcsr_io, in_be32(bcsr_io) | reg); | ||
457 | |||
458 | iounmap(bcsr_io); | ||
459 | return 0; | ||
460 | } | ||
461 | |||
462 | #define socket_get(_slot_) PCMCIA_SOCKET_KEY_5V | ||
463 | |||
464 | static void hardware_enable(int slot) | ||
465 | { | ||
466 | unsigned *bcsr_io; | ||
467 | |||
468 | bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); | ||
469 | out_be32(bcsr_io, in_be32(bcsr_io) & ~BCSR1_PCCEN); | ||
470 | iounmap(bcsr_io); | ||
471 | } | ||
472 | |||
473 | static void hardware_disable(int slot) | ||
474 | { | ||
475 | unsigned *bcsr_io; | ||
476 | |||
477 | bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); | ||
478 | out_be32(bcsr_io, in_be32(bcsr_io) | BCSR1_PCCEN); | ||
479 | iounmap(bcsr_io); | ||
395 | } | 480 | } |
396 | 481 | ||
397 | #endif | 482 | #endif |
@@ -440,10 +525,10 @@ static int voltage_set(int slot, int vcc, int vpp) | |||
440 | } | 525 | } |
441 | 526 | ||
442 | /* first, turn off all power */ | 527 | /* first, turn off all power */ |
443 | out_8(&((u8 *)MBX_CSR2_ADDR), in_8(&((u8 *)MBX_CSR2_ADDR)) & ~(CSR2_VCC_MASK | CSR2_VPP_MASK)); | 528 | out_8((u8 *)MBX_CSR2_ADDR, in_8((u8 *)MBX_CSR2_ADDR) & ~(CSR2_VCC_MASK | CSR2_VPP_MASK)); |
444 | 529 | ||
445 | /* enable new powersettings */ | 530 | /* enable new powersettings */ |
446 | out_8(&((u8 *)MBX_CSR2_ADDR), in_8(&((u8 *)MBX_CSR2_ADDR)) | reg); | 531 | out_8((u8 *)MBX_CSR2_ADDR, in_8((u8 *)MBX_CSR2_ADDR) | reg); |
447 | 532 | ||
448 | return 0; | 533 | return 0; |
449 | } | 534 | } |
@@ -823,17 +908,6 @@ static int m8xx_get_status(struct pcmcia_socket *sock, unsigned int *value) | |||
823 | return 0; | 908 | return 0; |
824 | } | 909 | } |
825 | 910 | ||
826 | static int m8xx_get_socket(struct pcmcia_socket *sock, socket_state_t *state) | ||
827 | { | ||
828 | int lsock = container_of(sock, struct socket_info, socket)->slot; | ||
829 | *state = socket[lsock].state; /* copy the whole structure */ | ||
830 | |||
831 | dprintk("GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, " | ||
832 | "io_irq %d, csc_mask %#2.2x\n", lsock, state->flags, | ||
833 | state->Vcc, state->Vpp, state->io_irq, state->csc_mask); | ||
834 | return 0; | ||
835 | } | ||
836 | |||
837 | static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state) | 911 | static int m8xx_set_socket(struct pcmcia_socket *sock, socket_state_t *state) |
838 | { | 912 | { |
839 | int lsock = container_of(sock, struct socket_info, socket)->slot; | 913 | int lsock = container_of(sock, struct socket_info, socket)->slot; |
@@ -1023,8 +1097,7 @@ static int m8xx_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io) | |||
1023 | if(io->flags & MAP_WRPROT) | 1097 | if(io->flags & MAP_WRPROT) |
1024 | reg |= M8XX_PCMCIA_POR_WRPROT; | 1098 | reg |= M8XX_PCMCIA_POR_WRPROT; |
1025 | 1099 | ||
1026 | /*if(io->flags & (MAP_16BIT | MAP_AUTOSZ))*/ | 1100 | if(io->flags & (MAP_16BIT | MAP_AUTOSZ)) |
1027 | if(io->flags & MAP_16BIT) | ||
1028 | reg |= M8XX_PCMCIA_POR_16BIT; | 1101 | reg |= M8XX_PCMCIA_POR_16BIT; |
1029 | 1102 | ||
1030 | if(io->flags & MAP_ACTIVE) | 1103 | if(io->flags & MAP_ACTIVE) |
@@ -1169,7 +1242,6 @@ static struct pccard_operations m8xx_services = { | |||
1169 | .init = m8xx_sock_init, | 1242 | .init = m8xx_sock_init, |
1170 | .suspend = m8xx_suspend, | 1243 | .suspend = m8xx_suspend, |
1171 | .get_status = m8xx_get_status, | 1244 | .get_status = m8xx_get_status, |
1172 | .get_socket = m8xx_get_socket, | ||
1173 | .set_socket = m8xx_set_socket, | 1245 | .set_socket = m8xx_set_socket, |
1174 | .set_io_map = m8xx_set_io_map, | 1246 | .set_io_map = m8xx_set_io_map, |
1175 | .set_mem_map = m8xx_set_mem_map, | 1247 | .set_mem_map = m8xx_set_mem_map, |
@@ -1244,7 +1316,7 @@ static int __init m8xx_init(void) | |||
1244 | socket[i].socket.io_offset = 0; | 1316 | socket[i].socket.io_offset = 0; |
1245 | socket[i].socket.pci_irq = i ? 7 : 9; | 1317 | socket[i].socket.pci_irq = i ? 7 : 9; |
1246 | socket[i].socket.ops = &m8xx_services; | 1318 | socket[i].socket.ops = &m8xx_services; |
1247 | socket[i].socket.resource_ops = &pccard_nonstatic_ops; | 1319 | socket[i].socket.resource_ops = &pccard_iodyn_ops; |
1248 | socket[i].socket.cb_dev = NULL; | 1320 | socket[i].socket.cb_dev = NULL; |
1249 | socket[i].socket.dev.dev = &m8xx_device.dev; | 1321 | socket[i].socket.dev.dev = &m8xx_device.dev; |
1250 | } | 1322 | } |
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c index 20642f0e7bfe..f2789afb22b2 100644 --- a/drivers/pcmcia/pd6729.c +++ b/drivers/pcmcia/pd6729.c | |||
@@ -304,75 +304,6 @@ static int pd6729_get_status(struct pcmcia_socket *sock, u_int *value) | |||
304 | } | 304 | } |
305 | 305 | ||
306 | 306 | ||
307 | static int pd6729_get_socket(struct pcmcia_socket *sock, socket_state_t *state) | ||
308 | { | ||
309 | struct pd6729_socket *socket | ||
310 | = container_of(sock, struct pd6729_socket, socket); | ||
311 | unsigned char reg, vcc, vpp; | ||
312 | |||
313 | state->flags = 0; | ||
314 | state->Vcc = 0; | ||
315 | state->Vpp = 0; | ||
316 | state->io_irq = 0; | ||
317 | state->csc_mask = 0; | ||
318 | |||
319 | /* First the power status of the socket */ | ||
320 | reg = indirect_read(socket, I365_POWER); | ||
321 | |||
322 | if (reg & I365_PWR_AUTO) | ||
323 | state->flags |= SS_PWR_AUTO; /* Automatic Power Switch */ | ||
324 | |||
325 | if (reg & I365_PWR_OUT) | ||
326 | state->flags |= SS_OUTPUT_ENA; /* Output signals are enabled */ | ||
327 | |||
328 | vcc = reg & I365_VCC_MASK; vpp = reg & I365_VPP1_MASK; | ||
329 | |||
330 | if (reg & I365_VCC_5V) { | ||
331 | state->Vcc = (indirect_read(socket, PD67_MISC_CTL_1) & | ||
332 | PD67_MC1_VCC_3V) ? 33 : 50; | ||
333 | |||
334 | if (vpp == I365_VPP1_5V) { | ||
335 | if (state->Vcc == 50) | ||
336 | state->Vpp = 50; | ||
337 | else | ||
338 | state->Vpp = 33; | ||
339 | } | ||
340 | if (vpp == I365_VPP1_12V) | ||
341 | state->Vpp = 120; | ||
342 | } | ||
343 | |||
344 | /* Now the IO card, RESET flags and IO interrupt */ | ||
345 | reg = indirect_read(socket, I365_INTCTL); | ||
346 | |||
347 | if ((reg & I365_PC_RESET) == 0) | ||
348 | state->flags |= SS_RESET; | ||
349 | if (reg & I365_PC_IOCARD) | ||
350 | state->flags |= SS_IOCARD; /* This is an IO card */ | ||
351 | |||
352 | /* Set the IRQ number */ | ||
353 | state->io_irq = socket->card_irq; | ||
354 | |||
355 | /* Card status change */ | ||
356 | reg = indirect_read(socket, I365_CSCINT); | ||
357 | |||
358 | if (reg & I365_CSC_DETECT) | ||
359 | state->csc_mask |= SS_DETECT; /* Card detect is enabled */ | ||
360 | |||
361 | if (state->flags & SS_IOCARD) {/* IO Cards behave different */ | ||
362 | if (reg & I365_CSC_STSCHG) | ||
363 | state->csc_mask |= SS_STSCHG; | ||
364 | } else { | ||
365 | if (reg & I365_CSC_BVD1) | ||
366 | state->csc_mask |= SS_BATDEAD; | ||
367 | if (reg & I365_CSC_BVD2) | ||
368 | state->csc_mask |= SS_BATWARN; | ||
369 | if (reg & I365_CSC_READY) | ||
370 | state->csc_mask |= SS_READY; | ||
371 | } | ||
372 | |||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | static int pd6729_set_socket(struct pcmcia_socket *sock, socket_state_t *state) | 307 | static int pd6729_set_socket(struct pcmcia_socket *sock, socket_state_t *state) |
377 | { | 308 | { |
378 | struct pd6729_socket *socket | 309 | struct pd6729_socket *socket |
@@ -640,7 +571,6 @@ static int pd6729_init(struct pcmcia_socket *sock) | |||
640 | static struct pccard_operations pd6729_operations = { | 571 | static struct pccard_operations pd6729_operations = { |
641 | .init = pd6729_init, | 572 | .init = pd6729_init, |
642 | .get_status = pd6729_get_status, | 573 | .get_status = pd6729_get_status, |
643 | .get_socket = pd6729_get_socket, | ||
644 | .set_socket = pd6729_set_socket, | 574 | .set_socket = pd6729_set_socket, |
645 | .set_io_map = pd6729_set_io_map, | 575 | .set_io_map = pd6729_set_io_map, |
646 | .set_mem_map = pd6729_set_mem_map, | 576 | .set_mem_map = pd6729_set_mem_map, |
@@ -704,13 +634,11 @@ static int __devinit pd6729_pci_probe(struct pci_dev *dev, | |||
704 | char configbyte; | 634 | char configbyte; |
705 | struct pd6729_socket *socket; | 635 | struct pd6729_socket *socket; |
706 | 636 | ||
707 | socket = kmalloc(sizeof(struct pd6729_socket) * MAX_SOCKETS, | 637 | socket = kzalloc(sizeof(struct pd6729_socket) * MAX_SOCKETS, |
708 | GFP_KERNEL); | 638 | GFP_KERNEL); |
709 | if (!socket) | 639 | if (!socket) |
710 | return -ENOMEM; | 640 | return -ENOMEM; |
711 | 641 | ||
712 | memset(socket, 0, sizeof(struct pd6729_socket) * MAX_SOCKETS); | ||
713 | |||
714 | if ((ret = pci_enable_device(dev))) | 642 | if ((ret = pci_enable_device(dev))) |
715 | goto err_out_free_mem; | 643 | goto err_out_free_mem; |
716 | 644 | ||
diff --git a/drivers/pcmcia/pxa2xx_mainstone.c b/drivers/pcmcia/pxa2xx_mainstone.c index 5209d8c7764f..5d957dfe23d9 100644 --- a/drivers/pcmcia/pxa2xx_mainstone.c +++ b/drivers/pcmcia/pxa2xx_mainstone.c | |||
@@ -171,10 +171,9 @@ static int __init mst_pcmcia_init(void) | |||
171 | { | 171 | { |
172 | int ret; | 172 | int ret; |
173 | 173 | ||
174 | mst_pcmcia_device = kmalloc(sizeof(*mst_pcmcia_device), GFP_KERNEL); | 174 | mst_pcmcia_device = kzalloc(sizeof(*mst_pcmcia_device), GFP_KERNEL); |
175 | if (!mst_pcmcia_device) | 175 | if (!mst_pcmcia_device) |
176 | return -ENOMEM; | 176 | return -ENOMEM; |
177 | memset(mst_pcmcia_device, 0, sizeof(*mst_pcmcia_device)); | ||
178 | mst_pcmcia_device->name = "pxa2xx-pcmcia"; | 177 | mst_pcmcia_device->name = "pxa2xx-pcmcia"; |
179 | mst_pcmcia_device->dev.platform_data = &mst_pcmcia_ops; | 178 | mst_pcmcia_device->dev.platform_data = &mst_pcmcia_ops; |
180 | 179 | ||
diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c index 56c58831e80e..b5fdeec20b15 100644 --- a/drivers/pcmcia/pxa2xx_sharpsl.c +++ b/drivers/pcmcia/pxa2xx_sharpsl.c | |||
@@ -264,11 +264,10 @@ static int __init sharpsl_pcmcia_init(void) | |||
264 | int ret; | 264 | int ret; |
265 | 265 | ||
266 | sharpsl_pcmcia_ops.nr=platform_scoop_config->num_devs; | 266 | sharpsl_pcmcia_ops.nr=platform_scoop_config->num_devs; |
267 | sharpsl_pcmcia_device = kmalloc(sizeof(*sharpsl_pcmcia_device), GFP_KERNEL); | 267 | sharpsl_pcmcia_device = kzalloc(sizeof(*sharpsl_pcmcia_device), GFP_KERNEL); |
268 | if (!sharpsl_pcmcia_device) | 268 | if (!sharpsl_pcmcia_device) |
269 | return -ENOMEM; | 269 | return -ENOMEM; |
270 | 270 | ||
271 | memset(sharpsl_pcmcia_device, 0, sizeof(*sharpsl_pcmcia_device)); | ||
272 | sharpsl_pcmcia_device->name = "pxa2xx-pcmcia"; | 271 | sharpsl_pcmcia_device->name = "pxa2xx-pcmcia"; |
273 | sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops; | 272 | sharpsl_pcmcia_device->dev.platform_data = &sharpsl_pcmcia_ops; |
274 | sharpsl_pcmcia_device->dev.parent=platform_scoop_config->devs[0].dev; | 273 | sharpsl_pcmcia_device->dev.parent=platform_scoop_config->devs[0].dev; |
diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c index 0668384ebc8b..514609369836 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 | ||
@@ -164,3 +166,105 @@ struct pccard_resource_ops pccard_static_ops = { | |||
164 | .exit = NULL, | 166 | .exit = NULL, |
165 | }; | 167 | }; |
166 | EXPORT_SYMBOL(pccard_static_ops); | 168 | EXPORT_SYMBOL(pccard_static_ops); |
169 | |||
170 | |||
171 | #ifdef CONFIG_PCCARD_IODYN | ||
172 | |||
173 | static struct resource * | ||
174 | make_resource(unsigned long b, unsigned long n, int flags, char *name) | ||
175 | { | ||
176 | struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL); | ||
177 | |||
178 | if (res) { | ||
179 | res->name = name; | ||
180 | res->start = b; | ||
181 | res->end = b + n - 1; | ||
182 | res->flags = flags; | ||
183 | } | ||
184 | return res; | ||
185 | } | ||
186 | |||
187 | struct pcmcia_align_data { | ||
188 | unsigned long mask; | ||
189 | unsigned long offset; | ||
190 | }; | ||
191 | |||
192 | static void pcmcia_align(void *align_data, struct resource *res, | ||
193 | unsigned long size, unsigned long align) | ||
194 | { | ||
195 | struct pcmcia_align_data *data = align_data; | ||
196 | unsigned long start; | ||
197 | |||
198 | start = (res->start & ~data->mask) + data->offset; | ||
199 | if (start < res->start) | ||
200 | start += data->mask + 1; | ||
201 | res->start = start; | ||
202 | |||
203 | #ifdef CONFIG_X86 | ||
204 | if (res->flags & IORESOURCE_IO) { | ||
205 | if (start & 0x300) { | ||
206 | start = (start + 0x3ff) & ~0x3ff; | ||
207 | res->start = start; | ||
208 | } | ||
209 | } | ||
210 | #endif | ||
211 | |||
212 | #ifdef CONFIG_M68K | ||
213 | if (res->flags & IORESOURCE_IO) { | ||
214 | if ((res->start + size - 1) >= 1024) | ||
215 | res->start = res->end; | ||
216 | } | ||
217 | #endif | ||
218 | } | ||
219 | |||
220 | |||
221 | static int iodyn_adjust_io_region(struct resource *res, unsigned long r_start, | ||
222 | unsigned long r_end, struct pcmcia_socket *s) | ||
223 | { | ||
224 | return adjust_resource(res, r_start, r_end - r_start + 1); | ||
225 | } | ||
226 | |||
227 | |||
228 | static struct resource *iodyn_find_io_region(unsigned long base, int num, | ||
229 | unsigned long align, struct pcmcia_socket *s) | ||
230 | { | ||
231 | struct resource *res = make_resource(0, num, IORESOURCE_IO, | ||
232 | s->dev.class_id); | ||
233 | struct pcmcia_align_data data; | ||
234 | unsigned long min = base; | ||
235 | int ret; | ||
236 | |||
237 | if (align == 0) | ||
238 | align = 0x10000; | ||
239 | |||
240 | data.mask = align - 1; | ||
241 | data.offset = base & data.mask; | ||
242 | |||
243 | #ifdef CONFIG_PCI | ||
244 | if (s->cb_dev) { | ||
245 | ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1, | ||
246 | min, 0, pcmcia_align, &data); | ||
247 | } else | ||
248 | #endif | ||
249 | ret = allocate_resource(&ioport_resource, res, num, min, ~0UL, | ||
250 | 1, pcmcia_align, &data); | ||
251 | |||
252 | if (ret != 0) { | ||
253 | kfree(res); | ||
254 | res = NULL; | ||
255 | } | ||
256 | return res; | ||
257 | } | ||
258 | |||
259 | struct pccard_resource_ops pccard_iodyn_ops = { | ||
260 | .validate_mem = NULL, | ||
261 | .adjust_io_region = iodyn_adjust_io_region, | ||
262 | .find_io = iodyn_find_io_region, | ||
263 | .find_mem = NULL, | ||
264 | .adjust_resource = NULL, | ||
265 | .init = static_init, | ||
266 | .exit = NULL, | ||
267 | }; | ||
268 | EXPORT_SYMBOL(pccard_iodyn_ops); | ||
269 | |||
270 | #endif /* CONFIG_PCCARD_IODYN */ | ||
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c index 00960a379b9c..5301ac60358f 100644 --- a/drivers/pcmcia/rsrc_nonstatic.c +++ b/drivers/pcmcia/rsrc_nonstatic.c | |||
@@ -75,10 +75,9 @@ static DECLARE_MUTEX(rsrc_sem); | |||
75 | static struct resource * | 75 | static struct resource * |
76 | make_resource(unsigned long b, unsigned long n, int flags, char *name) | 76 | make_resource(unsigned long b, unsigned long n, int flags, char *name) |
77 | { | 77 | { |
78 | struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL); | 78 | struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL); |
79 | 79 | ||
80 | if (res) { | 80 | if (res) { |
81 | memset(res, 0, sizeof(*res)); | ||
82 | res->name = name; | 81 | res->name = name; |
83 | res->start = b; | 82 | res->start = b; |
84 | res->end = b + n - 1; | 83 | res->end = b + n - 1; |
@@ -200,12 +199,11 @@ static void do_io_probe(struct pcmcia_socket *s, kio_addr_t base, kio_addr_t num | |||
200 | base, base+num-1); | 199 | base, base+num-1); |
201 | 200 | ||
202 | /* First, what does a floating port look like? */ | 201 | /* First, what does a floating port look like? */ |
203 | b = kmalloc(256, GFP_KERNEL); | 202 | b = kzalloc(256, GFP_KERNEL); |
204 | if (!b) { | 203 | if (!b) { |
205 | printk(KERN_ERR "do_io_probe: unable to kmalloc 256 bytes"); | 204 | printk(KERN_ERR "do_io_probe: unable to kmalloc 256 bytes"); |
206 | return; | 205 | return; |
207 | } | 206 | } |
208 | memset(b, 0, 256); | ||
209 | for (i = base, most = 0; i < base+num; i += 8) { | 207 | for (i = base, most = 0; i < base+num; i += 8) { |
210 | res = claim_region(NULL, i, 8, IORESOURCE_IO, "PCMCIA IO probe"); | 208 | res = claim_region(NULL, i, 8, IORESOURCE_IO, "PCMCIA IO probe"); |
211 | if (!res) | 209 | if (!res) |
@@ -407,69 +405,79 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s) | |||
407 | 405 | ||
408 | static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s) | 406 | static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s) |
409 | { | 407 | { |
410 | struct socket_data *s_data = s->resource_data; | 408 | struct socket_data *s_data = s->resource_data; |
411 | u_long ok; | 409 | u_long ok; |
412 | if (m == &s_data->mem_db) | 410 | if (m == &s_data->mem_db) |
413 | return 0; | 411 | return 0; |
414 | ok = inv_probe(m->next, s); | 412 | ok = inv_probe(m->next, s); |
415 | if (ok) { | 413 | if (ok) { |
416 | if (m->base >= 0x100000) | 414 | if (m->base >= 0x100000) |
417 | sub_interval(&s_data->mem_db, m->base, m->num); | 415 | sub_interval(&s_data->mem_db, m->base, m->num); |
418 | return ok; | 416 | return ok; |
419 | } | 417 | } |
420 | if (m->base < 0x100000) | 418 | if (m->base < 0x100000) |
421 | return 0; | 419 | return 0; |
422 | return do_mem_probe(m->base, m->num, s); | 420 | return do_mem_probe(m->base, m->num, s); |
423 | } | 421 | } |
424 | 422 | ||
425 | static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) | 423 | static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) |
426 | { | 424 | { |
427 | struct resource_map *m, mm; | 425 | struct resource_map *m, mm; |
428 | static u_char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 }; | 426 | static unsigned char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 }; |
429 | u_long b, i, ok = 0; | 427 | unsigned long b, i, ok = 0; |
430 | struct socket_data *s_data = s->resource_data; | 428 | struct socket_data *s_data = s->resource_data; |
431 | 429 | ||
432 | /* We do up to four passes through the list */ | 430 | /* We do up to four passes through the list */ |
433 | if (probe_mask & MEM_PROBE_HIGH) { | 431 | if (probe_mask & MEM_PROBE_HIGH) { |
434 | if (inv_probe(s_data->mem_db.next, s) > 0) | 432 | if (inv_probe(s_data->mem_db.next, s) > 0) |
435 | return; | 433 | return 0; |
436 | printk(KERN_NOTICE "cs: warning: no high memory space " | 434 | printk(KERN_NOTICE "cs: warning: no high memory space " |
437 | "available!\n"); | 435 | "available!\n"); |
438 | } | 436 | 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 | } | 437 | } |
449 | /* Special probe for 64K-aligned block */ | 438 | |
450 | for (i = 0; i < 4; i++) { | 439 | for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) { |
451 | b = order[i] << 12; | 440 | mm = *m; |
452 | if ((b >= mm.base) && (b+0x10000 <= mm.base+mm.num)) { | 441 | /* Only probe < 1 MB */ |
453 | if (ok >= mem_limit) | 442 | if (mm.base >= 0x100000) |
454 | sub_interval(&s_data->mem_db, b, 0x10000); | 443 | continue; |
455 | else | 444 | if ((mm.base | mm.num) & 0xffff) { |
456 | ok += do_mem_probe(b, 0x10000, s); | 445 | ok += do_mem_probe(mm.base, mm.num, s); |
457 | } | 446 | continue; |
447 | } | ||
448 | /* Special probe for 64K-aligned block */ | ||
449 | for (i = 0; i < 4; i++) { | ||
450 | b = order[i] << 12; | ||
451 | if ((b >= mm.base) && (b+0x10000 <= mm.base+mm.num)) { | ||
452 | if (ok >= mem_limit) | ||
453 | sub_interval(&s_data->mem_db, b, 0x10000); | ||
454 | else | ||
455 | ok += do_mem_probe(b, 0x10000, s); | ||
456 | } | ||
457 | } | ||
458 | } | 458 | } |
459 | } | 459 | |
460 | if (ok > 0) | ||
461 | return 0; | ||
462 | |||
463 | return -ENODEV; | ||
460 | } | 464 | } |
461 | 465 | ||
462 | #else /* CONFIG_PCMCIA_PROBE */ | 466 | #else /* CONFIG_PCMCIA_PROBE */ |
463 | 467 | ||
464 | static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) | 468 | static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) |
465 | { | 469 | { |
466 | struct resource_map *m, mm; | 470 | struct resource_map *m, mm; |
467 | struct socket_data *s_data = s->resource_data; | 471 | struct socket_data *s_data = s->resource_data; |
472 | unsigned long ok = 0; | ||
468 | 473 | ||
469 | for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) { | 474 | for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) { |
470 | mm = *m; | 475 | mm = *m; |
471 | do_mem_probe(mm.base, mm.num, s); | 476 | ok += do_mem_probe(mm.base, mm.num, s); |
472 | } | 477 | } |
478 | if (ok > 0) | ||
479 | return 0; | ||
480 | return -ENODEV; | ||
473 | } | 481 | } |
474 | 482 | ||
475 | #endif /* CONFIG_PCMCIA_PROBE */ | 483 | #endif /* CONFIG_PCMCIA_PROBE */ |
@@ -478,27 +486,30 @@ static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask) | |||
478 | /* | 486 | /* |
479 | * Locking note: Must be called with skt_sem held! | 487 | * Locking note: Must be called with skt_sem held! |
480 | */ | 488 | */ |
481 | static void pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s) | 489 | static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s) |
482 | { | 490 | { |
483 | struct socket_data *s_data = s->resource_data; | 491 | struct socket_data *s_data = s->resource_data; |
484 | if (probe_mem) { | 492 | unsigned int probe_mask = MEM_PROBE_LOW; |
485 | unsigned int probe_mask; | 493 | int ret = 0; |
486 | 494 | ||
487 | down(&rsrc_sem); | 495 | if (!probe_mem) |
496 | return 0; | ||
488 | 497 | ||
489 | probe_mask = MEM_PROBE_LOW; | 498 | down(&rsrc_sem); |
490 | if (s->features & SS_CAP_PAGE_REGS) | ||
491 | probe_mask = MEM_PROBE_HIGH; | ||
492 | 499 | ||
493 | if (probe_mask & ~s_data->rsrc_mem_probe) { | 500 | if (s->features & SS_CAP_PAGE_REGS) |
501 | probe_mask = MEM_PROBE_HIGH; | ||
502 | |||
503 | if (probe_mask & ~s_data->rsrc_mem_probe) { | ||
504 | if (s->state & SOCKET_PRESENT) | ||
505 | ret = validate_mem(s, probe_mask); | ||
506 | if (!ret) | ||
494 | s_data->rsrc_mem_probe |= probe_mask; | 507 | s_data->rsrc_mem_probe |= probe_mask; |
508 | } | ||
495 | 509 | ||
496 | if (s->state & SOCKET_PRESENT) | 510 | up(&rsrc_sem); |
497 | validate_mem(s, probe_mask); | ||
498 | } | ||
499 | 511 | ||
500 | up(&rsrc_sem); | 512 | return ret; |
501 | } | ||
502 | } | 513 | } |
503 | 514 | ||
504 | struct pcmcia_align_data { | 515 | struct pcmcia_align_data { |
@@ -837,10 +848,9 @@ static int nonstatic_init(struct pcmcia_socket *s) | |||
837 | { | 848 | { |
838 | struct socket_data *data; | 849 | struct socket_data *data; |
839 | 850 | ||
840 | data = kmalloc(sizeof(struct socket_data), GFP_KERNEL); | 851 | data = kzalloc(sizeof(struct socket_data), GFP_KERNEL); |
841 | if (!data) | 852 | if (!data) |
842 | return -ENOMEM; | 853 | return -ENOMEM; |
843 | memset(data, 0, sizeof(struct socket_data)); | ||
844 | 854 | ||
845 | data->mem_db.next = &data->mem_db; | 855 | data->mem_db.next = &data->mem_db; |
846 | data->io_db.next = &data->io_db; | 856 | data->io_db.next = &data->io_db; |
diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c index 9e7ccd8a4321..ea7d9ca160b2 100644 --- a/drivers/pcmcia/soc_common.c +++ b/drivers/pcmcia/soc_common.c | |||
@@ -297,25 +297,6 @@ soc_common_pcmcia_get_status(struct pcmcia_socket *sock, unsigned int *status) | |||
297 | 297 | ||
298 | 298 | ||
299 | /* | 299 | /* |
300 | * Implements the get_socket() operation for the in-kernel PCMCIA | ||
301 | * service (formerly SS_GetSocket in Card Services). Not a very | ||
302 | * exciting routine. | ||
303 | * | ||
304 | * Returns: 0 | ||
305 | */ | ||
306 | static int | ||
307 | soc_common_pcmcia_get_socket(struct pcmcia_socket *sock, socket_state_t *state) | ||
308 | { | ||
309 | struct soc_pcmcia_socket *skt = to_soc_pcmcia_socket(sock); | ||
310 | |||
311 | debug(skt, 2, "\n"); | ||
312 | |||
313 | *state = skt->cs_state; | ||
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | /* | ||
319 | * Implements the set_socket() operation for the in-kernel PCMCIA | 300 | * Implements the set_socket() operation for the in-kernel PCMCIA |
320 | * service (formerly SS_SetSocket in Card Services). We more or | 301 | * service (formerly SS_SetSocket in Card Services). We more or |
321 | * less punt all of this work and let the kernel handle the details | 302 | * less punt all of this work and let the kernel handle the details |
@@ -528,7 +509,6 @@ static struct pccard_operations soc_common_pcmcia_operations = { | |||
528 | .init = soc_common_pcmcia_sock_init, | 509 | .init = soc_common_pcmcia_sock_init, |
529 | .suspend = soc_common_pcmcia_suspend, | 510 | .suspend = soc_common_pcmcia_suspend, |
530 | .get_status = soc_common_pcmcia_get_status, | 511 | .get_status = soc_common_pcmcia_get_status, |
531 | .get_socket = soc_common_pcmcia_get_socket, | ||
532 | .set_socket = soc_common_pcmcia_set_socket, | 512 | .set_socket = soc_common_pcmcia_set_socket, |
533 | .set_io_map = soc_common_pcmcia_set_io_map, | 513 | .set_io_map = soc_common_pcmcia_set_io_map, |
534 | .set_mem_map = soc_common_pcmcia_set_mem_map, | 514 | .set_mem_map = soc_common_pcmcia_set_mem_map, |
@@ -665,13 +645,12 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops | |||
665 | 645 | ||
666 | down(&soc_pcmcia_sockets_lock); | 646 | down(&soc_pcmcia_sockets_lock); |
667 | 647 | ||
668 | sinfo = kmalloc(SKT_DEV_INFO_SIZE(nr), GFP_KERNEL); | 648 | sinfo = kzalloc(SKT_DEV_INFO_SIZE(nr), GFP_KERNEL); |
669 | if (!sinfo) { | 649 | if (!sinfo) { |
670 | ret = -ENOMEM; | 650 | ret = -ENOMEM; |
671 | goto out; | 651 | goto out; |
672 | } | 652 | } |
673 | 653 | ||
674 | memset(sinfo, 0, SKT_DEV_INFO_SIZE(nr)); | ||
675 | sinfo->nskt = nr; | 654 | sinfo->nskt = nr; |
676 | 655 | ||
677 | /* | 656 | /* |
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c index 4a3150a7854c..7a7744662d54 100644 --- a/drivers/pcmcia/socket_sysfs.c +++ b/drivers/pcmcia/socket_sysfs.c | |||
@@ -42,35 +42,28 @@ | |||
42 | 42 | ||
43 | static ssize_t pccard_show_type(struct class_device *dev, char *buf) | 43 | static ssize_t pccard_show_type(struct class_device *dev, char *buf) |
44 | { | 44 | { |
45 | int val; | ||
46 | struct pcmcia_socket *s = to_socket(dev); | 45 | struct pcmcia_socket *s = to_socket(dev); |
47 | 46 | ||
48 | if (!(s->state & SOCKET_PRESENT)) | 47 | if (!(s->state & SOCKET_PRESENT)) |
49 | return -ENODEV; | 48 | return -ENODEV; |
50 | s->ops->get_status(s, &val); | 49 | if (s->state & SOCKET_CARDBUS) |
51 | if (val & SS_CARDBUS) | ||
52 | return sprintf(buf, "32-bit\n"); | 50 | return sprintf(buf, "32-bit\n"); |
53 | if (val & SS_DETECT) | 51 | return sprintf(buf, "16-bit\n"); |
54 | return sprintf(buf, "16-bit\n"); | ||
55 | return sprintf(buf, "invalid\n"); | ||
56 | } | 52 | } |
57 | static CLASS_DEVICE_ATTR(card_type, 0400, pccard_show_type, NULL); | 53 | static CLASS_DEVICE_ATTR(card_type, 0444, pccard_show_type, NULL); |
58 | 54 | ||
59 | static ssize_t pccard_show_voltage(struct class_device *dev, char *buf) | 55 | static ssize_t pccard_show_voltage(struct class_device *dev, char *buf) |
60 | { | 56 | { |
61 | int val; | ||
62 | struct pcmcia_socket *s = to_socket(dev); | 57 | struct pcmcia_socket *s = to_socket(dev); |
63 | 58 | ||
64 | if (!(s->state & SOCKET_PRESENT)) | 59 | if (!(s->state & SOCKET_PRESENT)) |
65 | return -ENODEV; | 60 | return -ENODEV; |
66 | s->ops->get_status(s, &val); | 61 | if (s->socket.Vcc) |
67 | if (val & SS_3VCARD) | 62 | return sprintf(buf, "%d.%dV\n", s->socket.Vcc / 10, |
68 | return sprintf(buf, "3.3V\n"); | 63 | s->socket.Vcc % 10); |
69 | if (val & SS_XVCARD) | 64 | return sprintf(buf, "X.XV\n"); |
70 | return sprintf(buf, "X.XV\n"); | ||
71 | return sprintf(buf, "5.0V\n"); | ||
72 | } | 65 | } |
73 | static CLASS_DEVICE_ATTR(card_voltage, 0400, pccard_show_voltage, NULL); | 66 | static CLASS_DEVICE_ATTR(card_voltage, 0444, pccard_show_voltage, NULL); |
74 | 67 | ||
75 | static ssize_t pccard_show_vpp(struct class_device *dev, char *buf) | 68 | static ssize_t pccard_show_vpp(struct class_device *dev, char *buf) |
76 | { | 69 | { |
@@ -79,7 +72,7 @@ static ssize_t pccard_show_vpp(struct class_device *dev, char *buf) | |||
79 | return -ENODEV; | 72 | return -ENODEV; |
80 | return sprintf(buf, "%d.%dV\n", s->socket.Vpp / 10, s->socket.Vpp % 10); | 73 | return sprintf(buf, "%d.%dV\n", s->socket.Vpp / 10, s->socket.Vpp % 10); |
81 | } | 74 | } |
82 | static CLASS_DEVICE_ATTR(card_vpp, 0400, pccard_show_vpp, NULL); | 75 | static CLASS_DEVICE_ATTR(card_vpp, 0444, pccard_show_vpp, NULL); |
83 | 76 | ||
84 | static ssize_t pccard_show_vcc(struct class_device *dev, char *buf) | 77 | static ssize_t pccard_show_vcc(struct class_device *dev, char *buf) |
85 | { | 78 | { |
@@ -88,7 +81,7 @@ static ssize_t pccard_show_vcc(struct class_device *dev, char *buf) | |||
88 | return -ENODEV; | 81 | return -ENODEV; |
89 | return sprintf(buf, "%d.%dV\n", s->socket.Vcc / 10, s->socket.Vcc % 10); | 82 | return sprintf(buf, "%d.%dV\n", s->socket.Vcc / 10, s->socket.Vcc % 10); |
90 | } | 83 | } |
91 | static CLASS_DEVICE_ATTR(card_vcc, 0400, pccard_show_vcc, NULL); | 84 | static CLASS_DEVICE_ATTR(card_vcc, 0444, pccard_show_vcc, NULL); |
92 | 85 | ||
93 | 86 | ||
94 | static ssize_t pccard_store_insert(struct class_device *dev, const char *buf, size_t count) | 87 | static ssize_t pccard_store_insert(struct class_device *dev, const char *buf, size_t count) |
@@ -292,10 +285,9 @@ static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, siz | |||
292 | if (!(s->state & SOCKET_PRESENT)) | 285 | if (!(s->state & SOCKET_PRESENT)) |
293 | return -ENODEV; | 286 | return -ENODEV; |
294 | 287 | ||
295 | cis = kmalloc(sizeof(cisdump_t), GFP_KERNEL); | 288 | cis = kzalloc(sizeof(cisdump_t), GFP_KERNEL); |
296 | if (!cis) | 289 | if (!cis) |
297 | return -ENOMEM; | 290 | return -ENOMEM; |
298 | memset(cis, 0, sizeof(cisdump_t)); | ||
299 | 291 | ||
300 | cis->Length = count + 1; | 292 | cis->Length = count + 1; |
301 | memcpy(cis->Data, buf, count); | 293 | memcpy(cis->Data, buf, count); |
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c index e31263864377..73bad1d5cb23 100644 --- a/drivers/pcmcia/tcic.c +++ b/drivers/pcmcia/tcic.c | |||
@@ -181,13 +181,6 @@ static void tcic_setl(u_char reg, u_int data) | |||
181 | outw(data >> 16, tcic_base+reg+2); | 181 | outw(data >> 16, tcic_base+reg+2); |
182 | } | 182 | } |
183 | 183 | ||
184 | static u_char tcic_aux_getb(u_short reg) | ||
185 | { | ||
186 | u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg; | ||
187 | tcic_setb(TCIC_MODE, mode); | ||
188 | return tcic_getb(TCIC_AUX); | ||
189 | } | ||
190 | |||
191 | static void tcic_aux_setb(u_short reg, u_char data) | 184 | static void tcic_aux_setb(u_short reg, u_char data) |
192 | { | 185 | { |
193 | u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg; | 186 | u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg; |
@@ -641,59 +634,6 @@ static int tcic_get_status(struct pcmcia_socket *sock, u_int *value) | |||
641 | debug(1, "GetStatus(%d) = %#2.2x\n", psock, *value); | 634 | debug(1, "GetStatus(%d) = %#2.2x\n", psock, *value); |
642 | return 0; | 635 | return 0; |
643 | } /* tcic_get_status */ | 636 | } /* tcic_get_status */ |
644 | |||
645 | /*====================================================================*/ | ||
646 | |||
647 | static int tcic_get_socket(struct pcmcia_socket *sock, socket_state_t *state) | ||
648 | { | ||
649 | u_short psock = container_of(sock, struct tcic_socket, socket)->psock; | ||
650 | u_char reg; | ||
651 | u_short scf1, scf2; | ||
652 | |||
653 | tcic_setl(TCIC_ADDR, (psock << TCIC_ADDR_SS_SHFT) | ||
654 | | TCIC_ADDR_INDREG | TCIC_SCF1(psock)); | ||
655 | scf1 = tcic_getw(TCIC_DATA); | ||
656 | state->flags = (scf1 & TCIC_SCF1_IOSTS) ? SS_IOCARD : 0; | ||
657 | state->flags |= (scf1 & TCIC_SCF1_DMA_MASK) ? SS_DMA_MODE : 0; | ||
658 | state->flags |= (scf1 & TCIC_SCF1_SPKR) ? SS_SPKR_ENA : 0; | ||
659 | if (tcic_getb(TCIC_SCTRL) & TCIC_SCTRL_ENA) | ||
660 | state->flags |= SS_OUTPUT_ENA; | ||
661 | state->io_irq = scf1 & TCIC_SCF1_IRQ_MASK; | ||
662 | if (state->io_irq == 1) state->io_irq = 11; | ||
663 | |||
664 | reg = tcic_getb(TCIC_PWR); | ||
665 | state->Vcc = state->Vpp = 0; | ||
666 | if (reg & TCIC_PWR_VCC(psock)) { | ||
667 | if (reg & TCIC_PWR_VPP(psock)) | ||
668 | state->Vcc = 50; | ||
669 | else | ||
670 | state->Vcc = state->Vpp = 50; | ||
671 | } else { | ||
672 | if (reg & TCIC_PWR_VPP(psock)) { | ||
673 | state->Vcc = 50; | ||
674 | state->Vpp = 120; | ||
675 | } | ||
676 | } | ||
677 | reg = tcic_aux_getb(TCIC_AUX_ILOCK); | ||
678 | state->flags |= (reg & TCIC_ILOCK_CRESET) ? SS_RESET : 0; | ||
679 | |||
680 | /* Card status change interrupt mask */ | ||
681 | tcic_setw(TCIC_ADDR, TCIC_SCF2(psock)); | ||
682 | scf2 = tcic_getw(TCIC_DATA); | ||
683 | state->csc_mask = (scf2 & TCIC_SCF2_MCD) ? 0 : SS_DETECT; | ||
684 | if (state->flags & SS_IOCARD) { | ||
685 | state->csc_mask |= (scf2 & TCIC_SCF2_MLBAT1) ? 0 : SS_STSCHG; | ||
686 | } else { | ||
687 | state->csc_mask |= (scf2 & TCIC_SCF2_MLBAT1) ? 0 : SS_BATDEAD; | ||
688 | state->csc_mask |= (scf2 & TCIC_SCF2_MLBAT2) ? 0 : SS_BATWARN; | ||
689 | state->csc_mask |= (scf2 & TCIC_SCF2_MRDY) ? 0 : SS_READY; | ||
690 | } | ||
691 | |||
692 | debug(1, "GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, " | ||
693 | "io_irq %d, csc_mask %#2.2x\n", psock, state->flags, | ||
694 | state->Vcc, state->Vpp, state->io_irq, state->csc_mask); | ||
695 | return 0; | ||
696 | } /* tcic_get_socket */ | ||
697 | 637 | ||
698 | /*====================================================================*/ | 638 | /*====================================================================*/ |
699 | 639 | ||
@@ -874,7 +814,6 @@ static int tcic_init(struct pcmcia_socket *s) | |||
874 | static struct pccard_operations tcic_operations = { | 814 | static struct pccard_operations tcic_operations = { |
875 | .init = tcic_init, | 815 | .init = tcic_init, |
876 | .get_status = tcic_get_status, | 816 | .get_status = tcic_get_status, |
877 | .get_socket = tcic_get_socket, | ||
878 | .set_socket = tcic_set_socket, | 817 | .set_socket = tcic_set_socket, |
879 | .set_io_map = tcic_set_io_map, | 818 | .set_io_map = tcic_set_io_map, |
880 | .set_mem_map = tcic_set_mem_map, | 819 | .set_mem_map = tcic_set_mem_map, |
diff --git a/drivers/pcmcia/ti113x.h b/drivers/pcmcia/ti113x.h index 539b5cd1a598..d5b4ff74462e 100644 --- a/drivers/pcmcia/ti113x.h +++ b/drivers/pcmcia/ti113x.h | |||
@@ -873,7 +873,7 @@ static int ti1250_override(struct yenta_socket *socket) | |||
873 | * Some fixup code to make everybody happy (TM). | 873 | * Some fixup code to make everybody happy (TM). |
874 | */ | 874 | */ |
875 | 875 | ||
876 | #ifdef CONFIG_CARDBUS | 876 | #ifdef CONFIG_YENTA_ENE_TUNE |
877 | /** | 877 | /** |
878 | * set/clear various test bits: | 878 | * set/clear various test bits: |
879 | * Defaults to clear the bit. | 879 | * Defaults to clear the bit. |
@@ -937,7 +937,7 @@ static int ene_override(struct yenta_socket *socket) | |||
937 | } | 937 | } |
938 | #else | 938 | #else |
939 | # define ene_override ti1250_override | 939 | # define ene_override ti1250_override |
940 | #endif | 940 | #endif /* !CONFIG_YENTA_ENE_TUNE */ |
941 | 941 | ||
942 | #endif /* _LINUX_TI113X_H */ | 942 | #endif /* _LINUX_TI113X_H */ |
943 | 943 | ||
diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c index 38a028c725d4..24c547ef512b 100644 --- a/drivers/pcmcia/vrc4171_card.c +++ b/drivers/pcmcia/vrc4171_card.c | |||
@@ -301,75 +301,6 @@ static int pccard_get_status(struct pcmcia_socket *sock, u_int *value) | |||
301 | return 0; | 301 | return 0; |
302 | } | 302 | } |
303 | 303 | ||
304 | static inline u_char get_Vcc_value(uint8_t voltage) | ||
305 | { | ||
306 | switch (voltage) { | ||
307 | case VCC_STATUS_3V: | ||
308 | return 33; | ||
309 | case VCC_STATUS_5V: | ||
310 | return 50; | ||
311 | default: | ||
312 | break; | ||
313 | } | ||
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static inline u_char get_Vpp_value(uint8_t power, u_char Vcc) | ||
319 | { | ||
320 | if ((power & 0x03) == 0x01 || (power & 0x03) == 0x02) | ||
321 | return Vcc; | ||
322 | |||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | static int pccard_get_socket(struct pcmcia_socket *sock, socket_state_t *state) | ||
327 | { | ||
328 | unsigned int slot; | ||
329 | uint8_t power, voltage, control, cscint; | ||
330 | |||
331 | if (sock == NULL || sock->sock >= CARD_MAX_SLOTS || state == NULL) | ||
332 | return -EINVAL; | ||
333 | |||
334 | slot = sock->sock; | ||
335 | |||
336 | power = exca_read_byte(slot, I365_POWER); | ||
337 | voltage = exca_read_byte(slot, CARD_VOLTAGE_SELECT); | ||
338 | |||
339 | state->Vcc = get_Vcc_value(voltage); | ||
340 | state->Vpp = get_Vpp_value(power, state->Vcc); | ||
341 | |||
342 | state->flags = 0; | ||
343 | if (power & POWER_ENABLE) | ||
344 | state->flags |= SS_PWR_AUTO; | ||
345 | if (power & I365_PWR_OUT) | ||
346 | state->flags |= SS_OUTPUT_ENA; | ||
347 | |||
348 | control = exca_read_byte(slot, I365_INTCTL); | ||
349 | if (control & I365_PC_IOCARD) | ||
350 | state->flags |= SS_IOCARD; | ||
351 | if (!(control & I365_PC_RESET)) | ||
352 | state->flags |= SS_RESET; | ||
353 | |||
354 | cscint = exca_read_byte(slot, I365_CSCINT); | ||
355 | state->csc_mask = 0; | ||
356 | if (state->flags & SS_IOCARD) { | ||
357 | if (cscint & I365_CSC_STSCHG) | ||
358 | state->flags |= SS_STSCHG; | ||
359 | } else { | ||
360 | if (cscint & I365_CSC_BVD1) | ||
361 | state->csc_mask |= SS_BATDEAD; | ||
362 | if (cscint & I365_CSC_BVD2) | ||
363 | state->csc_mask |= SS_BATWARN; | ||
364 | } | ||
365 | if (cscint & I365_CSC_READY) | ||
366 | state->csc_mask |= SS_READY; | ||
367 | if (cscint & I365_CSC_DETECT) | ||
368 | state->csc_mask |= SS_DETECT; | ||
369 | |||
370 | return 0; | ||
371 | } | ||
372 | |||
373 | static inline uint8_t set_Vcc_value(u_char Vcc) | 304 | static inline uint8_t set_Vcc_value(u_char Vcc) |
374 | { | 305 | { |
375 | switch (Vcc) { | 306 | switch (Vcc) { |
@@ -551,7 +482,6 @@ static int pccard_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map | |||
551 | static struct pccard_operations vrc4171_pccard_operations = { | 482 | static struct pccard_operations vrc4171_pccard_operations = { |
552 | .init = pccard_init, | 483 | .init = pccard_init, |
553 | .get_status = pccard_get_status, | 484 | .get_status = pccard_get_status, |
554 | .get_socket = pccard_get_socket, | ||
555 | .set_socket = pccard_set_socket, | 485 | .set_socket = pccard_set_socket, |
556 | .set_io_map = pccard_set_io_map, | 486 | .set_io_map = pccard_set_io_map, |
557 | .set_mem_map = pccard_set_mem_map, | 487 | .set_mem_map = pccard_set_mem_map, |
diff --git a/drivers/pcmcia/vrc4173_cardu.c b/drivers/pcmcia/vrc4173_cardu.c index db91259dc50e..1b277d2c1c96 100644 --- a/drivers/pcmcia/vrc4173_cardu.c +++ b/drivers/pcmcia/vrc4173_cardu.c | |||
@@ -198,48 +198,6 @@ static int cardu_get_status(unsigned int sock, u_int *value) | |||
198 | return 0; | 198 | return 0; |
199 | } | 199 | } |
200 | 200 | ||
201 | static inline u_char get_Vcc_value(uint8_t val) | ||
202 | { | ||
203 | switch (val & VCC_MASK) { | ||
204 | case VCC_3V: | ||
205 | return 33; | ||
206 | case VCC_5V: | ||
207 | return 50; | ||
208 | } | ||
209 | |||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | static inline u_char get_Vpp_value(uint8_t val) | ||
214 | { | ||
215 | switch (val & VPP_MASK) { | ||
216 | case VPP_12V: | ||
217 | return 120; | ||
218 | case VPP_VCC: | ||
219 | return get_Vcc_value(val); | ||
220 | } | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static int cardu_get_socket(unsigned int sock, socket_state_t *state) | ||
226 | { | ||
227 | vrc4173_socket_t *socket = &cardu_sockets[sock]; | ||
228 | uint8_t val; | ||
229 | |||
230 | val = exca_readb(socket, PWR_CNT); | ||
231 | state->Vcc = get_Vcc_value(val); | ||
232 | state->Vpp = get_Vpp_value(val); | ||
233 | state->flags = 0; | ||
234 | if (val & CARD_OUT_EN) state->flags |= SS_OUTPUT_ENA; | ||
235 | |||
236 | val = exca_readb(socket, INT_GEN_CNT); | ||
237 | if (!(val & CARD_REST0)) state->flags |= SS_RESET; | ||
238 | if (val & CARD_TYPE_IO) state->flags |= SS_IOCARD; | ||
239 | |||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static inline uint8_t set_Vcc_value(u_char Vcc) | 201 | static inline uint8_t set_Vcc_value(u_char Vcc) |
244 | { | 202 | { |
245 | switch (Vcc) { | 203 | switch (Vcc) { |
@@ -431,7 +389,6 @@ static struct pccard_operations cardu_operations = { | |||
431 | .register_callback = cardu_register_callback, | 389 | .register_callback = cardu_register_callback, |
432 | .inquire_socket = cardu_inquire_socket, | 390 | .inquire_socket = cardu_inquire_socket, |
433 | .get_status = cardu_get_status, | 391 | .get_status = cardu_get_status, |
434 | .get_socket = cardu_get_socket, | ||
435 | .set_socket = cardu_set_socket, | 392 | .set_socket = cardu_set_socket, |
436 | .get_io_map = cardu_get_io_map, | 393 | .get_io_map = cardu_get_io_map, |
437 | .set_io_map = cardu_set_io_map, | 394 | .set_io_map = cardu_set_io_map, |
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index ec6ab65f0872..4145eb83b9b6 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c | |||
@@ -49,7 +49,13 @@ MODULE_PARM_DESC(pwr_irqs_off, "Force IRQs off during power-on of slot. Use only | |||
49 | #define to_cycles(ns) ((ns)/120) | 49 | #define to_cycles(ns) ((ns)/120) |
50 | #define to_ns(cycles) ((cycles)*120) | 50 | #define to_ns(cycles) ((cycles)*120) |
51 | 51 | ||
52 | /** | ||
53 | * yenta PCI irq probing. | ||
54 | * currently only used in the TI/EnE initialization code | ||
55 | */ | ||
56 | #ifdef CONFIG_YENTA_TI | ||
52 | static int yenta_probe_cb_irq(struct yenta_socket *socket); | 57 | static int yenta_probe_cb_irq(struct yenta_socket *socket); |
58 | #endif | ||
53 | 59 | ||
54 | 60 | ||
55 | static unsigned int override_bios; | 61 | static unsigned int override_bios; |
@@ -224,95 +230,6 @@ static int yenta_get_status(struct pcmcia_socket *sock, unsigned int *value) | |||
224 | return 0; | 230 | return 0; |
225 | } | 231 | } |
226 | 232 | ||
227 | static void yenta_get_power(struct yenta_socket *socket, socket_state_t *state) | ||
228 | { | ||
229 | if (!(cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) && | ||
230 | (socket->flags & YENTA_16BIT_POWER_EXCA)) { | ||
231 | u8 reg, vcc, vpp; | ||
232 | |||
233 | reg = exca_readb(socket, I365_POWER); | ||
234 | vcc = reg & I365_VCC_MASK; | ||
235 | vpp = reg & I365_VPP1_MASK; | ||
236 | state->Vcc = state->Vpp = 0; | ||
237 | |||
238 | if (socket->flags & YENTA_16BIT_POWER_DF) { | ||
239 | if (vcc == I365_VCC_3V) | ||
240 | state->Vcc = 33; | ||
241 | if (vcc == I365_VCC_5V) | ||
242 | state->Vcc = 50; | ||
243 | if (vpp == I365_VPP1_5V) | ||
244 | state->Vpp = state->Vcc; | ||
245 | if (vpp == I365_VPP1_12V) | ||
246 | state->Vpp = 120; | ||
247 | } else { | ||
248 | if (reg & I365_VCC_5V) { | ||
249 | state->Vcc = 50; | ||
250 | if (vpp == I365_VPP1_5V) | ||
251 | state->Vpp = 50; | ||
252 | if (vpp == I365_VPP1_12V) | ||
253 | state->Vpp = 120; | ||
254 | } | ||
255 | } | ||
256 | } else { | ||
257 | u32 control; | ||
258 | |||
259 | control = cb_readl(socket, CB_SOCKET_CONTROL); | ||
260 | |||
261 | switch (control & CB_SC_VCC_MASK) { | ||
262 | case CB_SC_VCC_5V: state->Vcc = 50; break; | ||
263 | case CB_SC_VCC_3V: state->Vcc = 33; break; | ||
264 | default: state->Vcc = 0; | ||
265 | } | ||
266 | |||
267 | switch (control & CB_SC_VPP_MASK) { | ||
268 | case CB_SC_VPP_12V: state->Vpp = 120; break; | ||
269 | case CB_SC_VPP_5V: state->Vpp = 50; break; | ||
270 | case CB_SC_VPP_3V: state->Vpp = 33; break; | ||
271 | default: state->Vpp = 0; | ||
272 | } | ||
273 | } | ||
274 | } | ||
275 | |||
276 | static int yenta_get_socket(struct pcmcia_socket *sock, socket_state_t *state) | ||
277 | { | ||
278 | struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); | ||
279 | u8 reg; | ||
280 | u32 control; | ||
281 | |||
282 | control = cb_readl(socket, CB_SOCKET_CONTROL); | ||
283 | |||
284 | yenta_get_power(socket, state); | ||
285 | state->io_irq = socket->io_irq; | ||
286 | |||
287 | if (cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) { | ||
288 | u16 bridge = config_readw(socket, CB_BRIDGE_CONTROL); | ||
289 | if (bridge & CB_BRIDGE_CRST) | ||
290 | state->flags |= SS_RESET; | ||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | /* 16-bit card state.. */ | ||
295 | reg = exca_readb(socket, I365_POWER); | ||
296 | state->flags = (reg & I365_PWR_AUTO) ? SS_PWR_AUTO : 0; | ||
297 | state->flags |= (reg & I365_PWR_OUT) ? SS_OUTPUT_ENA : 0; | ||
298 | |||
299 | reg = exca_readb(socket, I365_INTCTL); | ||
300 | state->flags |= (reg & I365_PC_RESET) ? 0 : SS_RESET; | ||
301 | state->flags |= (reg & I365_PC_IOCARD) ? SS_IOCARD : 0; | ||
302 | |||
303 | reg = exca_readb(socket, I365_CSCINT); | ||
304 | state->csc_mask = (reg & I365_CSC_DETECT) ? SS_DETECT : 0; | ||
305 | if (state->flags & SS_IOCARD) { | ||
306 | state->csc_mask |= (reg & I365_CSC_STSCHG) ? SS_STSCHG : 0; | ||
307 | } else { | ||
308 | state->csc_mask |= (reg & I365_CSC_BVD1) ? SS_BATDEAD : 0; | ||
309 | state->csc_mask |= (reg & I365_CSC_BVD2) ? SS_BATWARN : 0; | ||
310 | state->csc_mask |= (reg & I365_CSC_READY) ? SS_READY : 0; | ||
311 | } | ||
312 | |||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | static void yenta_set_power(struct yenta_socket *socket, socket_state_t *state) | 233 | static void yenta_set_power(struct yenta_socket *socket, socket_state_t *state) |
317 | { | 234 | { |
318 | /* some birdges require to use the ExCA registers to power 16bit cards */ | 235 | /* some birdges require to use the ExCA registers to power 16bit cards */ |
@@ -531,6 +448,9 @@ static irqreturn_t yenta_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
531 | 448 | ||
532 | csc = exca_readb(socket, I365_CSC); | 449 | csc = exca_readb(socket, I365_CSC); |
533 | 450 | ||
451 | if (!(cb_event || csc)) | ||
452 | return IRQ_NONE; | ||
453 | |||
534 | events = (cb_event & (CB_CD1EVENT | CB_CD2EVENT)) ? SS_DETECT : 0 ; | 454 | events = (cb_event & (CB_CD1EVENT | CB_CD2EVENT)) ? SS_DETECT : 0 ; |
535 | events |= (csc & I365_CSC_DETECT) ? SS_DETECT : 0; | 455 | events |= (csc & I365_CSC_DETECT) ? SS_DETECT : 0; |
536 | if (exca_readb(socket, I365_INTCTL) & I365_PC_IOCARD) { | 456 | if (exca_readb(socket, I365_INTCTL) & I365_PC_IOCARD) { |
@@ -544,10 +464,7 @@ static irqreturn_t yenta_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
544 | if (events) | 464 | if (events) |
545 | pcmcia_parse_events(&socket->socket, events); | 465 | pcmcia_parse_events(&socket->socket, events); |
546 | 466 | ||
547 | if (cb_event || csc) | 467 | return IRQ_HANDLED; |
548 | return IRQ_HANDLED; | ||
549 | |||
550 | return IRQ_NONE; | ||
551 | } | 468 | } |
552 | 469 | ||
553 | static void yenta_interrupt_wrapper(unsigned long data) | 470 | static void yenta_interrupt_wrapper(unsigned long data) |
@@ -828,17 +745,24 @@ static struct pccard_operations yenta_socket_operations = { | |||
828 | .init = yenta_sock_init, | 745 | .init = yenta_sock_init, |
829 | .suspend = yenta_sock_suspend, | 746 | .suspend = yenta_sock_suspend, |
830 | .get_status = yenta_get_status, | 747 | .get_status = yenta_get_status, |
831 | .get_socket = yenta_get_socket, | ||
832 | .set_socket = yenta_set_socket, | 748 | .set_socket = yenta_set_socket, |
833 | .set_io_map = yenta_set_io_map, | 749 | .set_io_map = yenta_set_io_map, |
834 | .set_mem_map = yenta_set_mem_map, | 750 | .set_mem_map = yenta_set_mem_map, |
835 | }; | 751 | }; |
836 | 752 | ||
837 | 753 | ||
754 | #ifdef CONFIG_YENTA_TI | ||
838 | #include "ti113x.h" | 755 | #include "ti113x.h" |
756 | #endif | ||
757 | #ifdef CONFIG_YENTA_RICOH | ||
839 | #include "ricoh.h" | 758 | #include "ricoh.h" |
759 | #endif | ||
760 | #ifdef CONFIG_YENTA_TOSHIBA | ||
840 | #include "topic.h" | 761 | #include "topic.h" |
762 | #endif | ||
763 | #ifdef CONFIG_YENTA_O2 | ||
841 | #include "o2micro.h" | 764 | #include "o2micro.h" |
765 | #endif | ||
842 | 766 | ||
843 | enum { | 767 | enum { |
844 | CARDBUS_TYPE_DEFAULT = -1, | 768 | CARDBUS_TYPE_DEFAULT = -1, |
@@ -858,6 +782,7 @@ enum { | |||
858 | * initialization sequences etc details. List them here.. | 782 | * initialization sequences etc details. List them here.. |
859 | */ | 783 | */ |
860 | static struct cardbus_type cardbus_type[] = { | 784 | static struct cardbus_type cardbus_type[] = { |
785 | #ifdef CONFIG_YENTA_TI | ||
861 | [CARDBUS_TYPE_TI] = { | 786 | [CARDBUS_TYPE_TI] = { |
862 | .override = ti_override, | 787 | .override = ti_override, |
863 | .save_state = ti_save_state, | 788 | .save_state = ti_save_state, |
@@ -882,27 +807,36 @@ static struct cardbus_type cardbus_type[] = { | |||
882 | .restore_state = ti_restore_state, | 807 | .restore_state = ti_restore_state, |
883 | .sock_init = ti_init, | 808 | .sock_init = ti_init, |
884 | }, | 809 | }, |
810 | #endif | ||
811 | #ifdef CONFIG_YENTA_RICOH | ||
885 | [CARDBUS_TYPE_RICOH] = { | 812 | [CARDBUS_TYPE_RICOH] = { |
886 | .override = ricoh_override, | 813 | .override = ricoh_override, |
887 | .save_state = ricoh_save_state, | 814 | .save_state = ricoh_save_state, |
888 | .restore_state = ricoh_restore_state, | 815 | .restore_state = ricoh_restore_state, |
889 | }, | 816 | }, |
817 | #endif | ||
818 | #ifdef CONFIG_YENTA_TOSHIBA | ||
890 | [CARDBUS_TYPE_TOPIC95] = { | 819 | [CARDBUS_TYPE_TOPIC95] = { |
891 | .override = topic95_override, | 820 | .override = topic95_override, |
892 | }, | 821 | }, |
893 | [CARDBUS_TYPE_TOPIC97] = { | 822 | [CARDBUS_TYPE_TOPIC97] = { |
894 | .override = topic97_override, | 823 | .override = topic97_override, |
895 | }, | 824 | }, |
825 | #endif | ||
826 | #ifdef CONFIG_YENTA_O2 | ||
896 | [CARDBUS_TYPE_O2MICRO] = { | 827 | [CARDBUS_TYPE_O2MICRO] = { |
897 | .override = o2micro_override, | 828 | .override = o2micro_override, |
898 | .restore_state = o2micro_restore_state, | 829 | .restore_state = o2micro_restore_state, |
899 | }, | 830 | }, |
831 | #endif | ||
832 | #ifdef CONFIG_YENTA_TI | ||
900 | [CARDBUS_TYPE_ENE] = { | 833 | [CARDBUS_TYPE_ENE] = { |
901 | .override = ene_override, | 834 | .override = ene_override, |
902 | .save_state = ti_save_state, | 835 | .save_state = ti_save_state, |
903 | .restore_state = ti_restore_state, | 836 | .restore_state = ti_restore_state, |
904 | .sock_init = ti_init, | 837 | .sock_init = ti_init, |
905 | }, | 838 | }, |
839 | #endif | ||
906 | }; | 840 | }; |
907 | 841 | ||
908 | 842 | ||
@@ -948,6 +882,12 @@ static unsigned int yenta_probe_irq(struct yenta_socket *socket, u32 isa_irq_mas | |||
948 | } | 882 | } |
949 | 883 | ||
950 | 884 | ||
885 | /** | ||
886 | * yenta PCI irq probing. | ||
887 | * currently only used in the TI/EnE initialization code | ||
888 | */ | ||
889 | #ifdef CONFIG_YENTA_TI | ||
890 | |||
951 | /* interrupt handler, only used during probing */ | 891 | /* interrupt handler, only used during probing */ |
952 | static irqreturn_t yenta_probe_handler(int irq, void *dev_id, struct pt_regs *regs) | 892 | static irqreturn_t yenta_probe_handler(int irq, void *dev_id, struct pt_regs *regs) |
953 | { | 893 | { |
@@ -1000,6 +940,7 @@ static int yenta_probe_cb_irq(struct yenta_socket *socket) | |||
1000 | return (int) socket->probe_status; | 940 | return (int) socket->probe_status; |
1001 | } | 941 | } |
1002 | 942 | ||
943 | #endif /* CONFIG_YENTA_TI */ | ||
1003 | 944 | ||
1004 | 945 | ||
1005 | /* | 946 | /* |
@@ -1078,10 +1019,9 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i | |||
1078 | return -ENODEV; | 1019 | return -ENODEV; |
1079 | } | 1020 | } |
1080 | 1021 | ||
1081 | socket = kmalloc(sizeof(struct yenta_socket), GFP_KERNEL); | 1022 | socket = kzalloc(sizeof(struct yenta_socket), GFP_KERNEL); |
1082 | if (!socket) | 1023 | if (!socket) |
1083 | return -ENOMEM; | 1024 | return -ENOMEM; |
1084 | memset(socket, 0, sizeof(*socket)); | ||
1085 | 1025 | ||
1086 | /* prepare pcmcia_socket */ | 1026 | /* prepare pcmcia_socket */ |
1087 | socket->socket.ops = ¥ta_socket_operations; | 1027 | socket->socket.ops = ¥ta_socket_operations; |
@@ -1263,6 +1203,7 @@ static struct pci_device_id yenta_table [] = { | |||
1263 | * advanced overrides instead. (I can't get the | 1203 | * advanced overrides instead. (I can't get the |
1264 | * data sheets for these devices. --rmk) | 1204 | * data sheets for these devices. --rmk) |
1265 | */ | 1205 | */ |
1206 | #ifdef CONFIG_YENTA_TI | ||
1266 | CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1210, TI), | 1207 | CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1210, TI), |
1267 | 1208 | ||
1268 | CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1130, TI113X), | 1209 | CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1130, TI113X), |
@@ -1305,18 +1246,25 @@ static struct pci_device_id yenta_table [] = { | |||
1305 | CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1225, ENE), | 1246 | CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1225, ENE), |
1306 | CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1410, ENE), | 1247 | CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1410, ENE), |
1307 | CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1420, ENE), | 1248 | CB_ID(PCI_VENDOR_ID_ENE, PCI_DEVICE_ID_ENE_1420, ENE), |
1249 | #endif /* CONFIG_YENTA_TI */ | ||
1308 | 1250 | ||
1251 | #ifdef CONFIG_YENTA_RICOH | ||
1309 | CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C465, RICOH), | 1252 | CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C465, RICOH), |
1310 | CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C466, RICOH), | 1253 | CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C466, RICOH), |
1311 | CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C475, RICOH), | 1254 | CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C475, RICOH), |
1312 | CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, RICOH), | 1255 | CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C476, RICOH), |
1313 | CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C478, RICOH), | 1256 | CB_ID(PCI_VENDOR_ID_RICOH, PCI_DEVICE_ID_RICOH_RL5C478, RICOH), |
1257 | #endif | ||
1314 | 1258 | ||
1259 | #ifdef CONFIG_YENTA_TOSHIBA | ||
1315 | CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC95, TOPIC95), | 1260 | CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC95, TOPIC95), |
1316 | CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC97, TOPIC97), | 1261 | CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC97, TOPIC97), |
1317 | CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC100, TOPIC97), | 1262 | CB_ID(PCI_VENDOR_ID_TOSHIBA, PCI_DEVICE_ID_TOSHIBA_TOPIC100, TOPIC97), |
1263 | #endif | ||
1318 | 1264 | ||
1265 | #ifdef CONFIG_YENTA_O2 | ||
1319 | CB_ID(PCI_VENDOR_ID_O2, PCI_ANY_ID, O2MICRO), | 1266 | CB_ID(PCI_VENDOR_ID_O2, PCI_ANY_ID, O2MICRO), |
1267 | #endif | ||
1320 | 1268 | ||
1321 | /* match any cardbus bridge */ | 1269 | /* match any cardbus bridge */ |
1322 | CB_ID(PCI_ANY_ID, PCI_ANY_ID, DEFAULT), | 1270 | CB_ID(PCI_ANY_ID, PCI_ANY_ID, DEFAULT), |
diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c index 7c5306499832..0c9edb7051f4 100644 --- a/drivers/scsi/pcmcia/aha152x_stub.c +++ b/drivers/scsi/pcmcia/aha152x_stub.c | |||
@@ -95,27 +95,21 @@ typedef struct scsi_info_t { | |||
95 | } scsi_info_t; | 95 | } scsi_info_t; |
96 | 96 | ||
97 | static void aha152x_release_cs(dev_link_t *link); | 97 | static void aha152x_release_cs(dev_link_t *link); |
98 | static int aha152x_event(event_t event, int priority, | 98 | static void aha152x_detach(struct pcmcia_device *p_dev); |
99 | event_callback_args_t *args); | 99 | static void aha152x_config_cs(dev_link_t *link); |
100 | |||
101 | static dev_link_t *aha152x_attach(void); | ||
102 | static void aha152x_detach(dev_link_t *); | ||
103 | 100 | ||
104 | static dev_link_t *dev_list; | 101 | static dev_link_t *dev_list; |
105 | static dev_info_t dev_info = "aha152x_cs"; | ||
106 | 102 | ||
107 | static dev_link_t *aha152x_attach(void) | 103 | static int aha152x_attach(struct pcmcia_device *p_dev) |
108 | { | 104 | { |
109 | scsi_info_t *info; | 105 | scsi_info_t *info; |
110 | client_reg_t client_reg; | ||
111 | dev_link_t *link; | 106 | dev_link_t *link; |
112 | int ret; | ||
113 | 107 | ||
114 | DEBUG(0, "aha152x_attach()\n"); | 108 | DEBUG(0, "aha152x_attach()\n"); |
115 | 109 | ||
116 | /* Create new SCSI device */ | 110 | /* Create new SCSI device */ |
117 | info = kmalloc(sizeof(*info), GFP_KERNEL); | 111 | info = kmalloc(sizeof(*info), GFP_KERNEL); |
118 | if (!info) return NULL; | 112 | if (!info) return -ENOMEM; |
119 | memset(info, 0, sizeof(*info)); | 113 | memset(info, 0, sizeof(*info)); |
120 | link = &info->link; link->priv = info; | 114 | link = &info->link; link->priv = info; |
121 | 115 | ||
@@ -129,26 +123,20 @@ static dev_link_t *aha152x_attach(void) | |||
129 | link->conf.IntType = INT_MEMORY_AND_IO; | 123 | link->conf.IntType = INT_MEMORY_AND_IO; |
130 | link->conf.Present = PRESENT_OPTION; | 124 | link->conf.Present = PRESENT_OPTION; |
131 | 125 | ||
132 | /* Register with Card Services */ | 126 | link->handle = p_dev; |
133 | link->next = dev_list; | 127 | p_dev->instance = link; |
134 | dev_list = link; | 128 | |
135 | client_reg.dev_info = &dev_info; | 129 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
136 | client_reg.Version = 0x0210; | 130 | aha152x_config_cs(link); |
137 | client_reg.event_callback_args.client_data = link; | 131 | |
138 | ret = pcmcia_register_client(&link->handle, &client_reg); | 132 | return 0; |
139 | if (ret != 0) { | ||
140 | cs_error(link->handle, RegisterClient, ret); | ||
141 | aha152x_detach(link); | ||
142 | return NULL; | ||
143 | } | ||
144 | |||
145 | return link; | ||
146 | } /* aha152x_attach */ | 133 | } /* aha152x_attach */ |
147 | 134 | ||
148 | /*====================================================================*/ | 135 | /*====================================================================*/ |
149 | 136 | ||
150 | static void aha152x_detach(dev_link_t *link) | 137 | static void aha152x_detach(struct pcmcia_device *p_dev) |
151 | { | 138 | { |
139 | dev_link_t *link = dev_to_instance(p_dev); | ||
152 | dev_link_t **linkp; | 140 | dev_link_t **linkp; |
153 | 141 | ||
154 | DEBUG(0, "aha152x_detach(0x%p)\n", link); | 142 | DEBUG(0, "aha152x_detach(0x%p)\n", link); |
@@ -162,9 +150,6 @@ static void aha152x_detach(dev_link_t *link) | |||
162 | if (link->state & DEV_CONFIG) | 150 | if (link->state & DEV_CONFIG) |
163 | aha152x_release_cs(link); | 151 | aha152x_release_cs(link); |
164 | 152 | ||
165 | if (link->handle) | ||
166 | pcmcia_deregister_client(link->handle); | ||
167 | |||
168 | /* Unlink device structure, free bits */ | 153 | /* Unlink device structure, free bits */ |
169 | *linkp = link->next; | 154 | *linkp = link->next; |
170 | kfree(link->priv); | 155 | kfree(link->priv); |
@@ -272,44 +257,31 @@ static void aha152x_release_cs(dev_link_t *link) | |||
272 | link->state &= ~DEV_CONFIG; | 257 | link->state &= ~DEV_CONFIG; |
273 | } | 258 | } |
274 | 259 | ||
275 | static int aha152x_event(event_t event, int priority, | 260 | static int aha152x_suspend(struct pcmcia_device *dev) |
276 | event_callback_args_t *args) | ||
277 | { | 261 | { |
278 | dev_link_t *link = args->client_data; | 262 | dev_link_t *link = dev_to_instance(dev); |
279 | scsi_info_t *info = link->priv; | 263 | |
280 | |||
281 | DEBUG(0, "aha152x_event(0x%06x)\n", event); | ||
282 | |||
283 | switch (event) { | ||
284 | case CS_EVENT_CARD_REMOVAL: | ||
285 | link->state &= ~DEV_PRESENT; | ||
286 | if (link->state & DEV_CONFIG) | ||
287 | aha152x_release_cs(link); | ||
288 | break; | ||
289 | case CS_EVENT_CARD_INSERTION: | ||
290 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
291 | aha152x_config_cs(link); | ||
292 | break; | ||
293 | case CS_EVENT_PM_SUSPEND: | ||
294 | link->state |= DEV_SUSPEND; | 264 | link->state |= DEV_SUSPEND; |
295 | /* Fall through... */ | ||
296 | case CS_EVENT_RESET_PHYSICAL: | ||
297 | if (link->state & DEV_CONFIG) | 265 | if (link->state & DEV_CONFIG) |
298 | pcmcia_release_configuration(link->handle); | 266 | pcmcia_release_configuration(link->handle); |
299 | break; | 267 | |
300 | case CS_EVENT_PM_RESUME: | 268 | return 0; |
269 | } | ||
270 | |||
271 | static int aha152x_resume(struct pcmcia_device *dev) | ||
272 | { | ||
273 | dev_link_t *link = dev_to_instance(dev); | ||
274 | scsi_info_t *info = link->priv; | ||
275 | |||
301 | link->state &= ~DEV_SUSPEND; | 276 | link->state &= ~DEV_SUSPEND; |
302 | /* Fall through... */ | ||
303 | case CS_EVENT_CARD_RESET: | ||
304 | if (link->state & DEV_CONFIG) { | 277 | if (link->state & DEV_CONFIG) { |
305 | Scsi_Cmnd tmp; | 278 | Scsi_Cmnd tmp; |
306 | pcmcia_request_configuration(link->handle, &link->conf); | 279 | pcmcia_request_configuration(link->handle, &link->conf); |
307 | tmp.device->host = info->host; | 280 | tmp.device->host = info->host; |
308 | aha152x_host_reset(&tmp); | 281 | aha152x_host_reset(&tmp); |
309 | } | 282 | } |
310 | break; | 283 | |
311 | } | 284 | return 0; |
312 | return 0; | ||
313 | } | 285 | } |
314 | 286 | ||
315 | static struct pcmcia_device_id aha152x_ids[] = { | 287 | static struct pcmcia_device_id aha152x_ids[] = { |
@@ -327,10 +299,11 @@ static struct pcmcia_driver aha152x_cs_driver = { | |||
327 | .drv = { | 299 | .drv = { |
328 | .name = "aha152x_cs", | 300 | .name = "aha152x_cs", |
329 | }, | 301 | }, |
330 | .attach = aha152x_attach, | 302 | .probe = aha152x_attach, |
331 | .event = aha152x_event, | 303 | .remove = aha152x_detach, |
332 | .detach = aha152x_detach, | ||
333 | .id_table = aha152x_ids, | 304 | .id_table = aha152x_ids, |
305 | .suspend = aha152x_suspend, | ||
306 | .resume = aha152x_resume, | ||
334 | }; | 307 | }; |
335 | 308 | ||
336 | static int __init init_aha152x_cs(void) | 309 | static int __init init_aha152x_cs(void) |
diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c index db8f5cd85ffe..788c58d805f3 100644 --- a/drivers/scsi/pcmcia/fdomain_stub.c +++ b/drivers/scsi/pcmcia/fdomain_stub.c | |||
@@ -80,29 +80,19 @@ typedef struct scsi_info_t { | |||
80 | 80 | ||
81 | 81 | ||
82 | static void fdomain_release(dev_link_t *link); | 82 | static void fdomain_release(dev_link_t *link); |
83 | static int fdomain_event(event_t event, int priority, | 83 | static void fdomain_detach(struct pcmcia_device *p_dev); |
84 | event_callback_args_t *args); | 84 | static void fdomain_config(dev_link_t *link); |
85 | 85 | ||
86 | static dev_link_t *fdomain_attach(void); | 86 | static int fdomain_attach(struct pcmcia_device *p_dev) |
87 | static void fdomain_detach(dev_link_t *); | ||
88 | |||
89 | |||
90 | static dev_link_t *dev_list = NULL; | ||
91 | |||
92 | static dev_info_t dev_info = "fdomain_cs"; | ||
93 | |||
94 | static dev_link_t *fdomain_attach(void) | ||
95 | { | 87 | { |
96 | scsi_info_t *info; | 88 | scsi_info_t *info; |
97 | client_reg_t client_reg; | ||
98 | dev_link_t *link; | 89 | dev_link_t *link; |
99 | int ret; | 90 | |
100 | |||
101 | DEBUG(0, "fdomain_attach()\n"); | 91 | DEBUG(0, "fdomain_attach()\n"); |
102 | 92 | ||
103 | /* Create new SCSI device */ | 93 | /* Create new SCSI device */ |
104 | info = kmalloc(sizeof(*info), GFP_KERNEL); | 94 | info = kmalloc(sizeof(*info), GFP_KERNEL); |
105 | if (!info) return NULL; | 95 | if (!info) return -ENOMEM; |
106 | memset(info, 0, sizeof(*info)); | 96 | memset(info, 0, sizeof(*info)); |
107 | link = &info->link; link->priv = info; | 97 | link = &info->link; link->priv = info; |
108 | link->io.NumPorts1 = 0x10; | 98 | link->io.NumPorts1 = 0x10; |
@@ -115,46 +105,27 @@ static dev_link_t *fdomain_attach(void) | |||
115 | link->conf.IntType = INT_MEMORY_AND_IO; | 105 | link->conf.IntType = INT_MEMORY_AND_IO; |
116 | link->conf.Present = PRESENT_OPTION; | 106 | link->conf.Present = PRESENT_OPTION; |
117 | 107 | ||
118 | /* Register with Card Services */ | 108 | link->handle = p_dev; |
119 | link->next = dev_list; | 109 | p_dev->instance = link; |
120 | dev_list = link; | 110 | |
121 | client_reg.dev_info = &dev_info; | 111 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
122 | client_reg.Version = 0x0210; | 112 | fdomain_config(link); |
123 | client_reg.event_callback_args.client_data = link; | 113 | |
124 | ret = pcmcia_register_client(&link->handle, &client_reg); | 114 | return 0; |
125 | if (ret != 0) { | ||
126 | cs_error(link->handle, RegisterClient, ret); | ||
127 | fdomain_detach(link); | ||
128 | return NULL; | ||
129 | } | ||
130 | |||
131 | return link; | ||
132 | } /* fdomain_attach */ | 115 | } /* fdomain_attach */ |
133 | 116 | ||
134 | /*====================================================================*/ | 117 | /*====================================================================*/ |
135 | 118 | ||
136 | static void fdomain_detach(dev_link_t *link) | 119 | static void fdomain_detach(struct pcmcia_device *p_dev) |
137 | { | 120 | { |
138 | dev_link_t **linkp; | 121 | dev_link_t *link = dev_to_instance(p_dev); |
139 | 122 | ||
140 | DEBUG(0, "fdomain_detach(0x%p)\n", link); | 123 | DEBUG(0, "fdomain_detach(0x%p)\n", link); |
141 | |||
142 | /* Locate device structure */ | ||
143 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
144 | if (*linkp == link) break; | ||
145 | if (*linkp == NULL) | ||
146 | return; | ||
147 | 124 | ||
148 | if (link->state & DEV_CONFIG) | 125 | if (link->state & DEV_CONFIG) |
149 | fdomain_release(link); | 126 | fdomain_release(link); |
150 | 127 | ||
151 | if (link->handle) | 128 | kfree(link->priv); |
152 | pcmcia_deregister_client(link->handle); | ||
153 | |||
154 | /* Unlink device structure, free bits */ | ||
155 | *linkp = link->next; | ||
156 | kfree(link->priv); | ||
157 | |||
158 | } /* fdomain_detach */ | 129 | } /* fdomain_detach */ |
159 | 130 | ||
160 | /*====================================================================*/ | 131 | /*====================================================================*/ |
@@ -256,43 +227,29 @@ static void fdomain_release(dev_link_t *link) | |||
256 | 227 | ||
257 | /*====================================================================*/ | 228 | /*====================================================================*/ |
258 | 229 | ||
259 | static int fdomain_event(event_t event, int priority, | 230 | static int fdomain_suspend(struct pcmcia_device *dev) |
260 | event_callback_args_t *args) | ||
261 | { | 231 | { |
262 | dev_link_t *link = args->client_data; | 232 | dev_link_t *link = dev_to_instance(dev); |
263 | 233 | ||
264 | DEBUG(1, "fdomain_event(0x%06x)\n", event); | ||
265 | |||
266 | switch (event) { | ||
267 | case CS_EVENT_CARD_REMOVAL: | ||
268 | link->state &= ~DEV_PRESENT; | ||
269 | if (link->state & DEV_CONFIG) | ||
270 | fdomain_release(link); | ||
271 | break; | ||
272 | case CS_EVENT_CARD_INSERTION: | ||
273 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
274 | fdomain_config(link); | ||
275 | break; | ||
276 | case CS_EVENT_PM_SUSPEND: | ||
277 | link->state |= DEV_SUSPEND; | 234 | link->state |= DEV_SUSPEND; |
278 | /* Fall through... */ | ||
279 | case CS_EVENT_RESET_PHYSICAL: | ||
280 | if (link->state & DEV_CONFIG) | 235 | if (link->state & DEV_CONFIG) |
281 | pcmcia_release_configuration(link->handle); | 236 | pcmcia_release_configuration(link->handle); |
282 | break; | 237 | |
283 | case CS_EVENT_PM_RESUME: | 238 | return 0; |
239 | } | ||
240 | |||
241 | static int fdomain_resume(struct pcmcia_device *dev) | ||
242 | { | ||
243 | dev_link_t *link = dev_to_instance(dev); | ||
244 | |||
284 | link->state &= ~DEV_SUSPEND; | 245 | link->state &= ~DEV_SUSPEND; |
285 | /* Fall through... */ | ||
286 | case CS_EVENT_CARD_RESET: | ||
287 | if (link->state & DEV_CONFIG) { | 246 | if (link->state & DEV_CONFIG) { |
288 | pcmcia_request_configuration(link->handle, &link->conf); | 247 | pcmcia_request_configuration(link->handle, &link->conf); |
289 | fdomain_16x0_bus_reset(NULL); | 248 | fdomain_16x0_bus_reset(NULL); |
290 | } | 249 | } |
291 | break; | ||
292 | } | ||
293 | return 0; | ||
294 | } /* fdomain_event */ | ||
295 | 250 | ||
251 | return 0; | ||
252 | } | ||
296 | 253 | ||
297 | static struct pcmcia_device_id fdomain_ids[] = { | 254 | static struct pcmcia_device_id fdomain_ids[] = { |
298 | PCMCIA_DEVICE_PROD_ID12("IBM Corp.", "SCSI PCMCIA Card", 0xe3736c88, 0x859cad20), | 255 | PCMCIA_DEVICE_PROD_ID12("IBM Corp.", "SCSI PCMCIA Card", 0xe3736c88, 0x859cad20), |
@@ -307,10 +264,11 @@ static struct pcmcia_driver fdomain_cs_driver = { | |||
307 | .drv = { | 264 | .drv = { |
308 | .name = "fdomain_cs", | 265 | .name = "fdomain_cs", |
309 | }, | 266 | }, |
310 | .attach = fdomain_attach, | 267 | .probe = fdomain_attach, |
311 | .event = fdomain_event, | 268 | .remove = fdomain_detach, |
312 | .detach = fdomain_detach, | ||
313 | .id_table = fdomain_ids, | 269 | .id_table = fdomain_ids, |
270 | .suspend = fdomain_suspend, | ||
271 | .resume = fdomain_resume, | ||
314 | }; | 272 | }; |
315 | 273 | ||
316 | static int __init init_fdomain_cs(void) | 274 | static int __init init_fdomain_cs(void) |
@@ -321,7 +279,6 @@ static int __init init_fdomain_cs(void) | |||
321 | static void __exit exit_fdomain_cs(void) | 279 | static void __exit exit_fdomain_cs(void) |
322 | { | 280 | { |
323 | pcmcia_unregister_driver(&fdomain_cs_driver); | 281 | pcmcia_unregister_driver(&fdomain_cs_driver); |
324 | BUG_ON(dev_list != NULL); | ||
325 | } | 282 | } |
326 | 283 | ||
327 | module_init(init_fdomain_cs); | 284 | module_init(init_fdomain_cs); |
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index 050ea13ff80b..9e3ab3fd5355 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c | |||
@@ -104,9 +104,6 @@ static struct scsi_host_template nsp_driver_template = { | |||
104 | #endif | 104 | #endif |
105 | }; | 105 | }; |
106 | 106 | ||
107 | static dev_link_t *dev_list = NULL; | ||
108 | static dev_info_t dev_info = {"nsp_cs"}; | ||
109 | |||
110 | static nsp_hw_data nsp_data_base; /* attach <-> detect glue */ | 107 | static nsp_hw_data nsp_data_base; /* attach <-> detect glue */ |
111 | 108 | ||
112 | 109 | ||
@@ -1596,19 +1593,17 @@ static int nsp_eh_host_reset(Scsi_Cmnd *SCpnt) | |||
1596 | configure the card at this point -- we wait until we receive a | 1593 | configure the card at this point -- we wait until we receive a |
1597 | card insertion event. | 1594 | card insertion event. |
1598 | ======================================================================*/ | 1595 | ======================================================================*/ |
1599 | static dev_link_t *nsp_cs_attach(void) | 1596 | static int nsp_cs_attach(struct pcmcia_device *p_dev) |
1600 | { | 1597 | { |
1601 | scsi_info_t *info; | 1598 | scsi_info_t *info; |
1602 | client_reg_t client_reg; | ||
1603 | dev_link_t *link; | 1599 | dev_link_t *link; |
1604 | int ret; | ||
1605 | nsp_hw_data *data = &nsp_data_base; | 1600 | nsp_hw_data *data = &nsp_data_base; |
1606 | 1601 | ||
1607 | nsp_dbg(NSP_DEBUG_INIT, "in"); | 1602 | nsp_dbg(NSP_DEBUG_INIT, "in"); |
1608 | 1603 | ||
1609 | /* Create new SCSI device */ | 1604 | /* Create new SCSI device */ |
1610 | info = kmalloc(sizeof(*info), GFP_KERNEL); | 1605 | info = kmalloc(sizeof(*info), GFP_KERNEL); |
1611 | if (info == NULL) { return NULL; } | 1606 | if (info == NULL) { return -ENOMEM; } |
1612 | memset(info, 0, sizeof(*info)); | 1607 | memset(info, 0, sizeof(*info)); |
1613 | link = &info->link; | 1608 | link = &info->link; |
1614 | link->priv = info; | 1609 | link->priv = info; |
@@ -1636,23 +1631,14 @@ static dev_link_t *nsp_cs_attach(void) | |||
1636 | link->conf.IntType = INT_MEMORY_AND_IO; | 1631 | link->conf.IntType = INT_MEMORY_AND_IO; |
1637 | link->conf.Present = PRESENT_OPTION; | 1632 | link->conf.Present = PRESENT_OPTION; |
1638 | 1633 | ||
1634 | link->handle = p_dev; | ||
1635 | p_dev->instance = link; | ||
1639 | 1636 | ||
1640 | /* Register with Card Services */ | 1637 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
1641 | link->next = dev_list; | 1638 | nsp_cs_config(link); |
1642 | dev_list = link; | ||
1643 | client_reg.dev_info = &dev_info; | ||
1644 | client_reg.Version = 0x0210; | ||
1645 | client_reg.event_callback_args.client_data = link; | ||
1646 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
1647 | if (ret != CS_SUCCESS) { | ||
1648 | cs_error(link->handle, RegisterClient, ret); | ||
1649 | nsp_cs_detach(link); | ||
1650 | return NULL; | ||
1651 | } | ||
1652 | |||
1653 | 1639 | ||
1654 | nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link); | 1640 | nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link); |
1655 | return link; | 1641 | return 0; |
1656 | } /* nsp_cs_attach */ | 1642 | } /* nsp_cs_attach */ |
1657 | 1643 | ||
1658 | 1644 | ||
@@ -1662,35 +1648,19 @@ static dev_link_t *nsp_cs_attach(void) | |||
1662 | structures are freed. Otherwise, the structures will be freed | 1648 | structures are freed. Otherwise, the structures will be freed |
1663 | when the device is released. | 1649 | when the device is released. |
1664 | ======================================================================*/ | 1650 | ======================================================================*/ |
1665 | static void nsp_cs_detach(dev_link_t *link) | 1651 | static void nsp_cs_detach(struct pcmcia_device *p_dev) |
1666 | { | 1652 | { |
1667 | dev_link_t **linkp; | 1653 | dev_link_t *link = dev_to_instance(p_dev); |
1668 | 1654 | ||
1669 | nsp_dbg(NSP_DEBUG_INIT, "in, link=0x%p", link); | 1655 | nsp_dbg(NSP_DEBUG_INIT, "in, link=0x%p", link); |
1670 | 1656 | ||
1671 | /* Locate device structure */ | 1657 | if (link->state & DEV_CONFIG) { |
1672 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) { | 1658 | ((scsi_info_t *)link->priv)->stop = 1; |
1673 | if (*linkp == link) { | ||
1674 | break; | ||
1675 | } | ||
1676 | } | ||
1677 | if (*linkp == NULL) { | ||
1678 | return; | ||
1679 | } | ||
1680 | |||
1681 | if (link->state & DEV_CONFIG) | ||
1682 | nsp_cs_release(link); | 1659 | nsp_cs_release(link); |
1683 | |||
1684 | /* Break the link with Card Services */ | ||
1685 | if (link->handle) { | ||
1686 | pcmcia_deregister_client(link->handle); | ||
1687 | } | 1660 | } |
1688 | 1661 | ||
1689 | /* Unlink device structure, free bits */ | ||
1690 | *linkp = link->next; | ||
1691 | kfree(link->priv); | 1662 | kfree(link->priv); |
1692 | link->priv = NULL; | 1663 | link->priv = NULL; |
1693 | |||
1694 | } /* nsp_cs_detach */ | 1664 | } /* nsp_cs_detach */ |
1695 | 1665 | ||
1696 | 1666 | ||
@@ -2021,99 +1991,58 @@ static void nsp_cs_release(dev_link_t *link) | |||
2021 | #endif | 1991 | #endif |
2022 | } /* nsp_cs_release */ | 1992 | } /* nsp_cs_release */ |
2023 | 1993 | ||
2024 | /*====================================================================== | 1994 | static int nsp_cs_suspend(struct pcmcia_device *dev) |
2025 | |||
2026 | The card status event handler. Mostly, this schedules other | ||
2027 | stuff to run after an event is received. A CARD_REMOVAL event | ||
2028 | also sets some flags to discourage the net drivers from trying | ||
2029 | to talk to the card any more. | ||
2030 | |||
2031 | When a CARD_REMOVAL event is received, we immediately set a flag | ||
2032 | to block future accesses to this device. All the functions that | ||
2033 | actually access the device should check this flag to make sure | ||
2034 | the card is still present. | ||
2035 | |||
2036 | ======================================================================*/ | ||
2037 | static int nsp_cs_event(event_t event, | ||
2038 | int priority, | ||
2039 | event_callback_args_t *args) | ||
2040 | { | 1995 | { |
2041 | dev_link_t *link = args->client_data; | 1996 | dev_link_t *link = dev_to_instance(dev); |
2042 | scsi_info_t *info = link->priv; | 1997 | scsi_info_t *info = link->priv; |
2043 | nsp_hw_data *data; | 1998 | nsp_hw_data *data; |
2044 | 1999 | ||
2045 | nsp_dbg(NSP_DEBUG_INIT, "in, event=0x%08x", event); | 2000 | link->state |= DEV_SUSPEND; |
2046 | 2001 | ||
2047 | switch (event) { | 2002 | nsp_dbg(NSP_DEBUG_INIT, "event: suspend"); |
2048 | case CS_EVENT_CARD_REMOVAL: | ||
2049 | nsp_dbg(NSP_DEBUG_INIT, "event: remove"); | ||
2050 | link->state &= ~DEV_PRESENT; | ||
2051 | if (link->state & DEV_CONFIG) { | ||
2052 | ((scsi_info_t *)link->priv)->stop = 1; | ||
2053 | nsp_cs_release(link); | ||
2054 | } | ||
2055 | break; | ||
2056 | 2003 | ||
2057 | case CS_EVENT_CARD_INSERTION: | 2004 | if (info->host != NULL) { |
2058 | nsp_dbg(NSP_DEBUG_INIT, "event: insert"); | 2005 | nsp_msg(KERN_INFO, "clear SDTR status"); |
2059 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
2060 | #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,68)) | ||
2061 | info->bus = args->bus; | ||
2062 | #endif | ||
2063 | nsp_cs_config(link); | ||
2064 | break; | ||
2065 | 2006 | ||
2066 | case CS_EVENT_PM_SUSPEND: | 2007 | data = (nsp_hw_data *)info->host->hostdata; |
2067 | nsp_dbg(NSP_DEBUG_INIT, "event: suspend"); | ||
2068 | link->state |= DEV_SUSPEND; | ||
2069 | /* Fall through... */ | ||
2070 | case CS_EVENT_RESET_PHYSICAL: | ||
2071 | /* Mark the device as stopped, to block IO until later */ | ||
2072 | nsp_dbg(NSP_DEBUG_INIT, "event: reset physical"); | ||
2073 | 2008 | ||
2074 | if (info->host != NULL) { | 2009 | nsphw_init_sync(data); |
2075 | nsp_msg(KERN_INFO, "clear SDTR status"); | 2010 | } |
2076 | 2011 | ||
2077 | data = (nsp_hw_data *)info->host->hostdata; | 2012 | info->stop = 1; |
2078 | 2013 | ||
2079 | nsphw_init_sync(data); | 2014 | if (link->state & DEV_CONFIG) |
2080 | } | 2015 | pcmcia_release_configuration(link->handle); |
2081 | 2016 | ||
2082 | info->stop = 1; | 2017 | return 0; |
2083 | if (link->state & DEV_CONFIG) { | 2018 | } |
2084 | pcmcia_release_configuration(link->handle); | ||
2085 | } | ||
2086 | break; | ||
2087 | 2019 | ||
2088 | case CS_EVENT_PM_RESUME: | 2020 | static int nsp_cs_resume(struct pcmcia_device *dev) |
2089 | nsp_dbg(NSP_DEBUG_INIT, "event: resume"); | 2021 | { |
2090 | link->state &= ~DEV_SUSPEND; | 2022 | dev_link_t *link = dev_to_instance(dev); |
2091 | /* Fall through... */ | 2023 | scsi_info_t *info = link->priv; |
2092 | case CS_EVENT_CARD_RESET: | 2024 | nsp_hw_data *data; |
2093 | nsp_dbg(NSP_DEBUG_INIT, "event: reset"); | ||
2094 | if (link->state & DEV_CONFIG) { | ||
2095 | pcmcia_request_configuration(link->handle, &link->conf); | ||
2096 | } | ||
2097 | info->stop = 0; | ||
2098 | 2025 | ||
2099 | if (info->host != NULL) { | 2026 | nsp_dbg(NSP_DEBUG_INIT, "event: resume"); |
2100 | nsp_msg(KERN_INFO, "reset host and bus"); | ||
2101 | 2027 | ||
2102 | data = (nsp_hw_data *)info->host->hostdata; | 2028 | link->state &= ~DEV_SUSPEND; |
2103 | 2029 | ||
2104 | nsphw_init (data); | 2030 | if (link->state & DEV_CONFIG) |
2105 | nsp_bus_reset(data); | 2031 | pcmcia_request_configuration(link->handle, &link->conf); |
2106 | } | ||
2107 | 2032 | ||
2108 | break; | 2033 | info->stop = 0; |
2109 | 2034 | ||
2110 | default: | 2035 | if (info->host != NULL) { |
2111 | nsp_dbg(NSP_DEBUG_INIT, "event: unknown"); | 2036 | nsp_msg(KERN_INFO, "reset host and bus"); |
2112 | break; | 2037 | |
2038 | data = (nsp_hw_data *)info->host->hostdata; | ||
2039 | |||
2040 | nsphw_init (data); | ||
2041 | nsp_bus_reset(data); | ||
2113 | } | 2042 | } |
2114 | nsp_dbg(NSP_DEBUG_INIT, "end"); | 2043 | |
2115 | return 0; | 2044 | return 0; |
2116 | } /* nsp_cs_event */ | 2045 | } |
2117 | 2046 | ||
2118 | /*======================================================================* | 2047 | /*======================================================================* |
2119 | * module entry point | 2048 | * module entry point |
@@ -2136,10 +2065,11 @@ static struct pcmcia_driver nsp_driver = { | |||
2136 | .drv = { | 2065 | .drv = { |
2137 | .name = "nsp_cs", | 2066 | .name = "nsp_cs", |
2138 | }, | 2067 | }, |
2139 | .attach = nsp_cs_attach, | 2068 | .probe = nsp_cs_attach, |
2140 | .event = nsp_cs_event, | 2069 | .remove = nsp_cs_detach, |
2141 | .detach = nsp_cs_detach, | ||
2142 | .id_table = nsp_cs_ids, | 2070 | .id_table = nsp_cs_ids, |
2071 | .suspend = nsp_cs_suspend, | ||
2072 | .resume = nsp_cs_resume, | ||
2143 | }; | 2073 | }; |
2144 | #endif | 2074 | #endif |
2145 | 2075 | ||
@@ -2171,7 +2101,6 @@ static void __exit nsp_cs_exit(void) | |||
2171 | 2101 | ||
2172 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68)) | 2102 | #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68)) |
2173 | pcmcia_unregister_driver(&nsp_driver); | 2103 | pcmcia_unregister_driver(&nsp_driver); |
2174 | BUG_ON(dev_list != NULL); | ||
2175 | #else | 2104 | #else |
2176 | unregister_pcmcia_driver(&dev_info); | 2105 | unregister_pcmcia_driver(&dev_info); |
2177 | /* XXX: this really needs to move into generic code.. */ | 2106 | /* XXX: this really needs to move into generic code.. */ |
diff --git a/drivers/scsi/pcmcia/nsp_cs.h b/drivers/scsi/pcmcia/nsp_cs.h index f8b943082717..b66b140a745e 100644 --- a/drivers/scsi/pcmcia/nsp_cs.h +++ b/drivers/scsi/pcmcia/nsp_cs.h | |||
@@ -296,11 +296,9 @@ typedef struct _nsp_hw_data { | |||
296 | */ | 296 | */ |
297 | 297 | ||
298 | /* Card service functions */ | 298 | /* Card service functions */ |
299 | static dev_link_t *nsp_cs_attach (void); | 299 | static void nsp_cs_detach (struct pcmcia_device *p_dev); |
300 | static void nsp_cs_detach (dev_link_t *link); | ||
301 | static void nsp_cs_release(dev_link_t *link); | 300 | static void nsp_cs_release(dev_link_t *link); |
302 | static void nsp_cs_config (dev_link_t *link); | 301 | static void nsp_cs_config (dev_link_t *link); |
303 | static int nsp_cs_event (event_t event, int priority, event_callback_args_t *args); | ||
304 | 302 | ||
305 | /* Linux SCSI subsystem specific functions */ | 303 | /* Linux SCSI subsystem specific functions */ |
306 | static struct Scsi_Host *nsp_detect (struct scsi_host_template *sht); | 304 | static struct Scsi_Host *nsp_detect (struct scsi_host_template *sht); |
diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c index bb091a45a880..dce7e687fd4a 100644 --- a/drivers/scsi/pcmcia/qlogic_stub.c +++ b/drivers/scsi/pcmcia/qlogic_stub.c | |||
@@ -98,15 +98,8 @@ typedef struct scsi_info_t { | |||
98 | } scsi_info_t; | 98 | } scsi_info_t; |
99 | 99 | ||
100 | static void qlogic_release(dev_link_t *link); | 100 | static void qlogic_release(dev_link_t *link); |
101 | static int qlogic_event(event_t event, int priority, event_callback_args_t * args); | 101 | static void qlogic_detach(struct pcmcia_device *p_dev); |
102 | 102 | static void qlogic_config(dev_link_t * link); | |
103 | static dev_link_t *qlogic_attach(void); | ||
104 | static void qlogic_detach(dev_link_t *); | ||
105 | |||
106 | |||
107 | static dev_link_t *dev_list = NULL; | ||
108 | |||
109 | static dev_info_t dev_info = "qlogic_cs"; | ||
110 | 103 | ||
111 | static struct Scsi_Host *qlogic_detect(struct scsi_host_template *host, | 104 | static struct Scsi_Host *qlogic_detect(struct scsi_host_template *host, |
112 | dev_link_t *link, int qbase, int qlirq) | 105 | dev_link_t *link, int qbase, int qlirq) |
@@ -163,19 +156,17 @@ free_scsi_host: | |||
163 | err: | 156 | err: |
164 | return NULL; | 157 | return NULL; |
165 | } | 158 | } |
166 | static dev_link_t *qlogic_attach(void) | 159 | static int qlogic_attach(struct pcmcia_device *p_dev) |
167 | { | 160 | { |
168 | scsi_info_t *info; | 161 | scsi_info_t *info; |
169 | client_reg_t client_reg; | ||
170 | dev_link_t *link; | 162 | dev_link_t *link; |
171 | int ret; | ||
172 | 163 | ||
173 | DEBUG(0, "qlogic_attach()\n"); | 164 | DEBUG(0, "qlogic_attach()\n"); |
174 | 165 | ||
175 | /* Create new SCSI device */ | 166 | /* Create new SCSI device */ |
176 | info = kmalloc(sizeof(*info), GFP_KERNEL); | 167 | info = kmalloc(sizeof(*info), GFP_KERNEL); |
177 | if (!info) | 168 | if (!info) |
178 | return NULL; | 169 | return -ENOMEM; |
179 | memset(info, 0, sizeof(*info)); | 170 | memset(info, 0, sizeof(*info)); |
180 | link = &info->link; | 171 | link = &info->link; |
181 | link->priv = info; | 172 | link->priv = info; |
@@ -189,45 +180,26 @@ static dev_link_t *qlogic_attach(void) | |||
189 | link->conf.IntType = INT_MEMORY_AND_IO; | 180 | link->conf.IntType = INT_MEMORY_AND_IO; |
190 | link->conf.Present = PRESENT_OPTION; | 181 | link->conf.Present = PRESENT_OPTION; |
191 | 182 | ||
192 | /* Register with Card Services */ | 183 | link->handle = p_dev; |
193 | link->next = dev_list; | 184 | p_dev->instance = link; |
194 | dev_list = link; | ||
195 | client_reg.dev_info = &dev_info; | ||
196 | client_reg.Version = 0x0210; | ||
197 | client_reg.event_callback_args.client_data = link; | ||
198 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
199 | if (ret != 0) { | ||
200 | cs_error(link->handle, RegisterClient, ret); | ||
201 | qlogic_detach(link); | ||
202 | return NULL; | ||
203 | } | ||
204 | 185 | ||
205 | return link; | 186 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
187 | qlogic_config(link); | ||
188 | |||
189 | return 0; | ||
206 | } /* qlogic_attach */ | 190 | } /* qlogic_attach */ |
207 | 191 | ||
208 | /*====================================================================*/ | 192 | /*====================================================================*/ |
209 | 193 | ||
210 | static void qlogic_detach(dev_link_t * link) | 194 | static void qlogic_detach(struct pcmcia_device *p_dev) |
211 | { | 195 | { |
212 | dev_link_t **linkp; | 196 | dev_link_t *link = dev_to_instance(p_dev); |
213 | 197 | ||
214 | DEBUG(0, "qlogic_detach(0x%p)\n", link); | 198 | DEBUG(0, "qlogic_detach(0x%p)\n", link); |
215 | 199 | ||
216 | /* Locate device structure */ | ||
217 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
218 | if (*linkp == link) | ||
219 | break; | ||
220 | if (*linkp == NULL) | ||
221 | return; | ||
222 | |||
223 | if (link->state & DEV_CONFIG) | 200 | if (link->state & DEV_CONFIG) |
224 | qlogic_release(link); | 201 | qlogic_release(link); |
225 | 202 | ||
226 | if (link->handle) | ||
227 | pcmcia_deregister_client(link->handle); | ||
228 | |||
229 | /* Unlink device structure, free bits */ | ||
230 | *linkp = link->next; | ||
231 | kfree(link->priv); | 203 | kfree(link->priv); |
232 | 204 | ||
233 | } /* qlogic_detach */ | 205 | } /* qlogic_detach */ |
@@ -349,48 +321,39 @@ static void qlogic_release(dev_link_t *link) | |||
349 | 321 | ||
350 | /*====================================================================*/ | 322 | /*====================================================================*/ |
351 | 323 | ||
352 | static int qlogic_event(event_t event, int priority, event_callback_args_t * args) | 324 | static int qlogic_suspend(struct pcmcia_device *dev) |
353 | { | 325 | { |
354 | dev_link_t *link = args->client_data; | 326 | dev_link_t *link = dev_to_instance(dev); |
355 | 327 | ||
356 | DEBUG(1, "qlogic_event(0x%06x)\n", event); | 328 | link->state |= DEV_SUSPEND; |
357 | 329 | if (link->state & DEV_CONFIG) | |
358 | switch (event) { | 330 | pcmcia_release_configuration(link->handle); |
359 | case CS_EVENT_CARD_REMOVAL: | 331 | |
360 | link->state &= ~DEV_PRESENT; | 332 | return 0; |
361 | if (link->state & DEV_CONFIG) | 333 | } |
362 | qlogic_release(link); | 334 | |
363 | break; | 335 | static int qlogic_resume(struct pcmcia_device *dev) |
364 | case CS_EVENT_CARD_INSERTION: | 336 | { |
365 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | 337 | dev_link_t *link = dev_to_instance(dev); |
366 | qlogic_config(link); | 338 | |
367 | break; | 339 | link->state &= ~DEV_SUSPEND; |
368 | case CS_EVENT_PM_SUSPEND: | 340 | if (link->state & DEV_CONFIG) { |
369 | link->state |= DEV_SUSPEND; | 341 | scsi_info_t *info = link->priv; |
370 | /* Fall through... */ | 342 | |
371 | case CS_EVENT_RESET_PHYSICAL: | 343 | pcmcia_request_configuration(link->handle, &link->conf); |
372 | if (link->state & DEV_CONFIG) | 344 | if ((info->manf_id == MANFID_MACNICA) || |
373 | pcmcia_release_configuration(link->handle); | 345 | (info->manf_id == MANFID_PIONEER) || |
374 | break; | 346 | (info->manf_id == 0x0098)) { |
375 | case CS_EVENT_PM_RESUME: | 347 | outb(0x80, link->io.BasePort1 + 0xd); |
376 | link->state &= ~DEV_SUSPEND; | 348 | outb(0x24, link->io.BasePort1 + 0x9); |
377 | /* Fall through... */ | 349 | outb(0x04, link->io.BasePort1 + 0xd); |
378 | case CS_EVENT_CARD_RESET: | ||
379 | if (link->state & DEV_CONFIG) { | ||
380 | scsi_info_t *info = link->priv; | ||
381 | pcmcia_request_configuration(link->handle, &link->conf); | ||
382 | if ((info->manf_id == MANFID_MACNICA) || (info->manf_id == MANFID_PIONEER) || (info->manf_id == 0x0098)) { | ||
383 | outb(0x80, link->io.BasePort1 + 0xd); | ||
384 | outb(0x24, link->io.BasePort1 + 0x9); | ||
385 | outb(0x04, link->io.BasePort1 + 0xd); | ||
386 | } | ||
387 | /* Ugggglllyyyy!!! */ | ||
388 | qlogicfas408_bus_reset(NULL); | ||
389 | } | 350 | } |
390 | break; | 351 | /* Ugggglllyyyy!!! */ |
352 | qlogicfas408_bus_reset(NULL); | ||
391 | } | 353 | } |
354 | |||
392 | return 0; | 355 | return 0; |
393 | } /* qlogic_event */ | 356 | } |
394 | 357 | ||
395 | static struct pcmcia_device_id qlogic_ids[] = { | 358 | static struct pcmcia_device_id qlogic_ids[] = { |
396 | PCMCIA_DEVICE_PROD_ID12("EIger Labs", "PCMCIA-to-SCSI Adapter", 0x88395fa7, 0x33b7a5e6), | 359 | PCMCIA_DEVICE_PROD_ID12("EIger Labs", "PCMCIA-to-SCSI Adapter", 0x88395fa7, 0x33b7a5e6), |
@@ -419,10 +382,11 @@ static struct pcmcia_driver qlogic_cs_driver = { | |||
419 | .drv = { | 382 | .drv = { |
420 | .name = "qlogic_cs", | 383 | .name = "qlogic_cs", |
421 | }, | 384 | }, |
422 | .attach = qlogic_attach, | 385 | .probe = qlogic_attach, |
423 | .event = qlogic_event, | 386 | .remove = qlogic_detach, |
424 | .detach = qlogic_detach, | ||
425 | .id_table = qlogic_ids, | 387 | .id_table = qlogic_ids, |
388 | .suspend = qlogic_suspend, | ||
389 | .resume = qlogic_resume, | ||
426 | }; | 390 | }; |
427 | 391 | ||
428 | static int __init init_qlogic_cs(void) | 392 | static int __init init_qlogic_cs(void) |
@@ -433,7 +397,6 @@ static int __init init_qlogic_cs(void) | |||
433 | static void __exit exit_qlogic_cs(void) | 397 | static void __exit exit_qlogic_cs(void) |
434 | { | 398 | { |
435 | pcmcia_unregister_driver(&qlogic_cs_driver); | 399 | pcmcia_unregister_driver(&qlogic_cs_driver); |
436 | BUG_ON(dev_list != NULL); | ||
437 | } | 400 | } |
438 | 401 | ||
439 | MODULE_AUTHOR("Tom Zerucha, Michael Griffith"); | 402 | MODULE_AUTHOR("Tom Zerucha, Michael Griffith"); |
diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c index 98b64b2aa8ee..3a4dd6f5b81f 100644 --- a/drivers/scsi/pcmcia/sym53c500_cs.c +++ b/drivers/scsi/pcmcia/sym53c500_cs.c | |||
@@ -228,15 +228,6 @@ enum Phase { | |||
228 | 228 | ||
229 | /* ================================================================== */ | 229 | /* ================================================================== */ |
230 | 230 | ||
231 | /* | ||
232 | * Global (within this module) variables other than | ||
233 | * sym53c500_driver_template (the scsi_host_template). | ||
234 | */ | ||
235 | static dev_link_t *dev_list; | ||
236 | static dev_info_t dev_info = "sym53c500_cs"; | ||
237 | |||
238 | /* ================================================================== */ | ||
239 | |||
240 | static void | 231 | static void |
241 | chip_init(int io_port) | 232 | chip_init(int io_port) |
242 | { | 233 | { |
@@ -872,96 +863,70 @@ cs_failed: | |||
872 | return; | 863 | return; |
873 | } /* SYM53C500_config */ | 864 | } /* SYM53C500_config */ |
874 | 865 | ||
875 | static int | 866 | static int sym53c500_suspend(struct pcmcia_device *dev) |
876 | SYM53C500_event(event_t event, int priority, event_callback_args_t *args) | ||
877 | { | 867 | { |
878 | dev_link_t *link = args->client_data; | 868 | dev_link_t *link = dev_to_instance(dev); |
879 | struct scsi_info_t *info = link->priv; | ||
880 | 869 | ||
881 | DEBUG(1, "SYM53C500_event(0x%06x)\n", event); | 870 | link->state |= DEV_SUSPEND; |
871 | if (link->state & DEV_CONFIG) | ||
872 | pcmcia_release_configuration(link->handle); | ||
882 | 873 | ||
883 | switch (event) { | 874 | return 0; |
884 | case CS_EVENT_CARD_REMOVAL: | 875 | } |
885 | link->state &= ~DEV_PRESENT; | 876 | |
886 | if (link->state & DEV_CONFIG) | 877 | static int sym53c500_resume(struct pcmcia_device *dev) |
887 | SYM53C500_release(link); | 878 | { |
888 | break; | 879 | dev_link_t *link = dev_to_instance(dev); |
889 | case CS_EVENT_CARD_INSERTION: | 880 | struct scsi_info_t *info = link->priv; |
890 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | 881 | |
891 | SYM53C500_config(link); | 882 | link->state &= ~DEV_SUSPEND; |
892 | break; | 883 | if (link->state & DEV_CONFIG) { |
893 | case CS_EVENT_PM_SUSPEND: | 884 | pcmcia_request_configuration(link->handle, &link->conf); |
894 | link->state |= DEV_SUSPEND; | 885 | |
895 | /* Fall through... */ | 886 | /* See earlier comment about manufacturer IDs. */ |
896 | case CS_EVENT_RESET_PHYSICAL: | 887 | if ((info->manf_id == MANFID_MACNICA) || |
897 | if (link->state & DEV_CONFIG) | 888 | (info->manf_id == MANFID_PIONEER) || |
898 | pcmcia_release_configuration(link->handle); | 889 | (info->manf_id == 0x0098)) { |
899 | break; | 890 | outb(0x80, link->io.BasePort1 + 0xd); |
900 | case CS_EVENT_PM_RESUME: | 891 | outb(0x24, link->io.BasePort1 + 0x9); |
901 | link->state &= ~DEV_SUSPEND; | 892 | outb(0x04, link->io.BasePort1 + 0xd); |
902 | /* Fall through... */ | ||
903 | case CS_EVENT_CARD_RESET: | ||
904 | if (link->state & DEV_CONFIG) { | ||
905 | pcmcia_request_configuration(link->handle, &link->conf); | ||
906 | /* See earlier comment about manufacturer IDs. */ | ||
907 | if ((info->manf_id == MANFID_MACNICA) || | ||
908 | (info->manf_id == MANFID_PIONEER) || | ||
909 | (info->manf_id == 0x0098)) { | ||
910 | outb(0x80, link->io.BasePort1 + 0xd); | ||
911 | outb(0x24, link->io.BasePort1 + 0x9); | ||
912 | outb(0x04, link->io.BasePort1 + 0xd); | ||
913 | } | ||
914 | /* | ||
915 | * If things don't work after a "resume", | ||
916 | * this is a good place to start looking. | ||
917 | */ | ||
918 | SYM53C500_int_host_reset(link->io.BasePort1); | ||
919 | } | 893 | } |
920 | break; | 894 | /* |
895 | * If things don't work after a "resume", | ||
896 | * this is a good place to start looking. | ||
897 | */ | ||
898 | SYM53C500_int_host_reset(link->io.BasePort1); | ||
921 | } | 899 | } |
900 | |||
922 | return 0; | 901 | return 0; |
923 | } /* SYM53C500_event */ | 902 | } |
924 | 903 | ||
925 | static void | 904 | static void |
926 | SYM53C500_detach(dev_link_t *link) | 905 | SYM53C500_detach(struct pcmcia_device *p_dev) |
927 | { | 906 | { |
928 | dev_link_t **linkp; | 907 | dev_link_t *link = dev_to_instance(p_dev); |
929 | 908 | ||
930 | DEBUG(0, "SYM53C500_detach(0x%p)\n", link); | 909 | DEBUG(0, "SYM53C500_detach(0x%p)\n", link); |
931 | 910 | ||
932 | /* Locate device structure */ | ||
933 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
934 | if (*linkp == link) | ||
935 | break; | ||
936 | if (*linkp == NULL) | ||
937 | return; | ||
938 | |||
939 | if (link->state & DEV_CONFIG) | 911 | if (link->state & DEV_CONFIG) |
940 | SYM53C500_release(link); | 912 | SYM53C500_release(link); |
941 | 913 | ||
942 | if (link->handle) | ||
943 | pcmcia_deregister_client(link->handle); | ||
944 | |||
945 | /* Unlink device structure, free bits. */ | ||
946 | *linkp = link->next; | ||
947 | kfree(link->priv); | 914 | kfree(link->priv); |
948 | link->priv = NULL; | 915 | link->priv = NULL; |
949 | } /* SYM53C500_detach */ | 916 | } /* SYM53C500_detach */ |
950 | 917 | ||
951 | static dev_link_t * | 918 | static int |
952 | SYM53C500_attach(void) | 919 | SYM53C500_attach(struct pcmcia_device *p_dev) |
953 | { | 920 | { |
954 | struct scsi_info_t *info; | 921 | struct scsi_info_t *info; |
955 | client_reg_t client_reg; | ||
956 | dev_link_t *link; | 922 | dev_link_t *link; |
957 | int ret; | ||
958 | 923 | ||
959 | DEBUG(0, "SYM53C500_attach()\n"); | 924 | DEBUG(0, "SYM53C500_attach()\n"); |
960 | 925 | ||
961 | /* Create new SCSI device */ | 926 | /* Create new SCSI device */ |
962 | info = kmalloc(sizeof(*info), GFP_KERNEL); | 927 | info = kmalloc(sizeof(*info), GFP_KERNEL); |
963 | if (!info) | 928 | if (!info) |
964 | return NULL; | 929 | return -ENOMEM; |
965 | memset(info, 0, sizeof(*info)); | 930 | memset(info, 0, sizeof(*info)); |
966 | link = &info->link; | 931 | link = &info->link; |
967 | link->priv = info; | 932 | link->priv = info; |
@@ -975,20 +940,13 @@ SYM53C500_attach(void) | |||
975 | link->conf.IntType = INT_MEMORY_AND_IO; | 940 | link->conf.IntType = INT_MEMORY_AND_IO; |
976 | link->conf.Present = PRESENT_OPTION; | 941 | link->conf.Present = PRESENT_OPTION; |
977 | 942 | ||
978 | /* Register with Card Services */ | 943 | link->handle = p_dev; |
979 | link->next = dev_list; | 944 | p_dev->instance = link; |
980 | dev_list = link; | 945 | |
981 | client_reg.dev_info = &dev_info; | 946 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
982 | client_reg.Version = 0x0210; | 947 | SYM53C500_config(link); |
983 | client_reg.event_callback_args.client_data = link; | ||
984 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
985 | if (ret != 0) { | ||
986 | cs_error(link->handle, RegisterClient, ret); | ||
987 | SYM53C500_detach(link); | ||
988 | return NULL; | ||
989 | } | ||
990 | 948 | ||
991 | return link; | 949 | return 0; |
992 | } /* SYM53C500_attach */ | 950 | } /* SYM53C500_attach */ |
993 | 951 | ||
994 | MODULE_AUTHOR("Bob Tracy <rct@frus.com>"); | 952 | MODULE_AUTHOR("Bob Tracy <rct@frus.com>"); |
@@ -1008,10 +966,11 @@ static struct pcmcia_driver sym53c500_cs_driver = { | |||
1008 | .drv = { | 966 | .drv = { |
1009 | .name = "sym53c500_cs", | 967 | .name = "sym53c500_cs", |
1010 | }, | 968 | }, |
1011 | .attach = SYM53C500_attach, | 969 | .probe = SYM53C500_attach, |
1012 | .event = SYM53C500_event, | 970 | .remove = SYM53C500_detach, |
1013 | .detach = SYM53C500_detach, | ||
1014 | .id_table = sym53c500_ids, | 971 | .id_table = sym53c500_ids, |
972 | .suspend = sym53c500_suspend, | ||
973 | .resume = sym53c500_resume, | ||
1015 | }; | 974 | }; |
1016 | 975 | ||
1017 | static int __init | 976 | static int __init |
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c index 7ce0c7e66d37..96969cb960a9 100644 --- a/drivers/serial/serial_cs.c +++ b/drivers/serial/serial_cs.c | |||
@@ -114,15 +114,7 @@ struct serial_cfg_mem { | |||
114 | 114 | ||
115 | 115 | ||
116 | static void serial_config(dev_link_t * link); | 116 | static void serial_config(dev_link_t * link); |
117 | static int serial_event(event_t event, int priority, | ||
118 | event_callback_args_t * args); | ||
119 | 117 | ||
120 | static dev_info_t dev_info = "serial_cs"; | ||
121 | |||
122 | static dev_link_t *serial_attach(void); | ||
123 | static void serial_detach(dev_link_t *); | ||
124 | |||
125 | static dev_link_t *dev_list = NULL; | ||
126 | 118 | ||
127 | /*====================================================================== | 119 | /*====================================================================== |
128 | 120 | ||
@@ -159,8 +151,9 @@ static void serial_remove(dev_link_t *link) | |||
159 | } | 151 | } |
160 | } | 152 | } |
161 | 153 | ||
162 | static void serial_suspend(dev_link_t *link) | 154 | static int serial_suspend(struct pcmcia_device *dev) |
163 | { | 155 | { |
156 | dev_link_t *link = dev_to_instance(dev); | ||
164 | link->state |= DEV_SUSPEND; | 157 | link->state |= DEV_SUSPEND; |
165 | 158 | ||
166 | if (link->state & DEV_CONFIG) { | 159 | if (link->state & DEV_CONFIG) { |
@@ -173,10 +166,13 @@ static void serial_suspend(dev_link_t *link) | |||
173 | if (!info->slave) | 166 | if (!info->slave) |
174 | pcmcia_release_configuration(link->handle); | 167 | pcmcia_release_configuration(link->handle); |
175 | } | 168 | } |
169 | |||
170 | return 0; | ||
176 | } | 171 | } |
177 | 172 | ||
178 | static void serial_resume(dev_link_t *link) | 173 | static int serial_resume(struct pcmcia_device *dev) |
179 | { | 174 | { |
175 | dev_link_t *link = dev_to_instance(dev); | ||
180 | link->state &= ~DEV_SUSPEND; | 176 | link->state &= ~DEV_SUSPEND; |
181 | 177 | ||
182 | if (DEV_OK(link)) { | 178 | if (DEV_OK(link)) { |
@@ -189,6 +185,8 @@ static void serial_resume(dev_link_t *link) | |||
189 | for (i = 0; i < info->ndev; i++) | 185 | for (i = 0; i < info->ndev; i++) |
190 | serial8250_resume_port(info->line[i]); | 186 | serial8250_resume_port(info->line[i]); |
191 | } | 187 | } |
188 | |||
189 | return 0; | ||
192 | } | 190 | } |
193 | 191 | ||
194 | /*====================================================================== | 192 | /*====================================================================== |
@@ -199,19 +197,17 @@ static void serial_resume(dev_link_t *link) | |||
199 | 197 | ||
200 | ======================================================================*/ | 198 | ======================================================================*/ |
201 | 199 | ||
202 | static dev_link_t *serial_attach(void) | 200 | static int serial_probe(struct pcmcia_device *p_dev) |
203 | { | 201 | { |
204 | struct serial_info *info; | 202 | struct serial_info *info; |
205 | client_reg_t client_reg; | ||
206 | dev_link_t *link; | 203 | dev_link_t *link; |
207 | int ret; | ||
208 | 204 | ||
209 | DEBUG(0, "serial_attach()\n"); | 205 | DEBUG(0, "serial_attach()\n"); |
210 | 206 | ||
211 | /* Create new serial device */ | 207 | /* Create new serial device */ |
212 | info = kmalloc(sizeof (*info), GFP_KERNEL); | 208 | info = kmalloc(sizeof (*info), GFP_KERNEL); |
213 | if (!info) | 209 | if (!info) |
214 | return NULL; | 210 | return -ENOMEM; |
215 | memset(info, 0, sizeof (*info)); | 211 | memset(info, 0, sizeof (*info)); |
216 | link = &info->link; | 212 | link = &info->link; |
217 | link->priv = info; | 213 | link->priv = info; |
@@ -227,20 +223,12 @@ static dev_link_t *serial_attach(void) | |||
227 | } | 223 | } |
228 | link->conf.IntType = INT_MEMORY_AND_IO; | 224 | link->conf.IntType = INT_MEMORY_AND_IO; |
229 | 225 | ||
230 | /* Register with Card Services */ | 226 | link->handle = p_dev; |
231 | link->next = dev_list; | 227 | p_dev->instance = link; |
232 | dev_list = link; | 228 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
233 | client_reg.dev_info = &dev_info; | 229 | serial_config(link); |
234 | client_reg.Version = 0x0210; | ||
235 | client_reg.event_callback_args.client_data = link; | ||
236 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
237 | if (ret != CS_SUCCESS) { | ||
238 | cs_error(link->handle, RegisterClient, ret); | ||
239 | serial_detach(link); | ||
240 | return NULL; | ||
241 | } | ||
242 | 230 | ||
243 | return link; | 231 | return 0; |
244 | } | 232 | } |
245 | 233 | ||
246 | /*====================================================================== | 234 | /*====================================================================== |
@@ -252,21 +240,13 @@ static dev_link_t *serial_attach(void) | |||
252 | 240 | ||
253 | ======================================================================*/ | 241 | ======================================================================*/ |
254 | 242 | ||
255 | static void serial_detach(dev_link_t * link) | 243 | static void serial_detach(struct pcmcia_device *p_dev) |
256 | { | 244 | { |
245 | dev_link_t *link = dev_to_instance(p_dev); | ||
257 | struct serial_info *info = link->priv; | 246 | struct serial_info *info = link->priv; |
258 | dev_link_t **linkp; | ||
259 | int ret; | ||
260 | 247 | ||
261 | DEBUG(0, "serial_detach(0x%p)\n", link); | 248 | DEBUG(0, "serial_detach(0x%p)\n", link); |
262 | 249 | ||
263 | /* Locate device structure */ | ||
264 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
265 | if (*linkp == link) | ||
266 | break; | ||
267 | if (*linkp == NULL) | ||
268 | return; | ||
269 | |||
270 | /* | 250 | /* |
271 | * Ensure any outstanding scheduled tasks are completed. | 251 | * Ensure any outstanding scheduled tasks are completed. |
272 | */ | 252 | */ |
@@ -277,14 +257,7 @@ static void serial_detach(dev_link_t * link) | |||
277 | */ | 257 | */ |
278 | serial_remove(link); | 258 | serial_remove(link); |
279 | 259 | ||
280 | if (link->handle) { | 260 | /* free bits */ |
281 | ret = pcmcia_deregister_client(link->handle); | ||
282 | if (ret != CS_SUCCESS) | ||
283 | cs_error(link->handle, DeregisterClient, ret); | ||
284 | } | ||
285 | |||
286 | /* Unlink device structure, free bits */ | ||
287 | *linkp = link->next; | ||
288 | kfree(info); | 261 | kfree(info); |
289 | } | 262 | } |
290 | 263 | ||
@@ -718,54 +691,6 @@ void serial_config(dev_link_t * link) | |||
718 | kfree(cfg_mem); | 691 | kfree(cfg_mem); |
719 | } | 692 | } |
720 | 693 | ||
721 | /*====================================================================== | ||
722 | |||
723 | The card status event handler. Mostly, this schedules other | ||
724 | stuff to run after an event is received. A CARD_REMOVAL event | ||
725 | also sets some flags to discourage the serial drivers from | ||
726 | talking to the ports. | ||
727 | |||
728 | ======================================================================*/ | ||
729 | |||
730 | static int | ||
731 | serial_event(event_t event, int priority, event_callback_args_t * args) | ||
732 | { | ||
733 | dev_link_t *link = args->client_data; | ||
734 | struct serial_info *info = link->priv; | ||
735 | |||
736 | DEBUG(1, "serial_event(0x%06x)\n", event); | ||
737 | |||
738 | switch (event) { | ||
739 | case CS_EVENT_CARD_REMOVAL: | ||
740 | serial_remove(link); | ||
741 | break; | ||
742 | |||
743 | case CS_EVENT_CARD_INSERTION: | ||
744 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
745 | serial_config(link); | ||
746 | break; | ||
747 | |||
748 | case CS_EVENT_PM_SUSPEND: | ||
749 | serial_suspend(link); | ||
750 | break; | ||
751 | |||
752 | case CS_EVENT_RESET_PHYSICAL: | ||
753 | if ((link->state & DEV_CONFIG) && !info->slave) | ||
754 | pcmcia_release_configuration(link->handle); | ||
755 | break; | ||
756 | |||
757 | case CS_EVENT_PM_RESUME: | ||
758 | serial_resume(link); | ||
759 | break; | ||
760 | |||
761 | case CS_EVENT_CARD_RESET: | ||
762 | if (DEV_OK(link) && !info->slave) | ||
763 | pcmcia_request_configuration(link->handle, &link->conf); | ||
764 | break; | ||
765 | } | ||
766 | return 0; | ||
767 | } | ||
768 | |||
769 | static struct pcmcia_device_id serial_ids[] = { | 694 | static struct pcmcia_device_id serial_ids[] = { |
770 | PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0057, 0x0021), | 695 | PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0057, 0x0021), |
771 | PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0089, 0x110a), | 696 | PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0089, 0x110a), |
@@ -877,10 +802,11 @@ static struct pcmcia_driver serial_cs_driver = { | |||
877 | .drv = { | 802 | .drv = { |
878 | .name = "serial_cs", | 803 | .name = "serial_cs", |
879 | }, | 804 | }, |
880 | .attach = serial_attach, | 805 | .probe = serial_probe, |
881 | .event = serial_event, | 806 | .remove = serial_detach, |
882 | .detach = serial_detach, | ||
883 | .id_table = serial_ids, | 807 | .id_table = serial_ids, |
808 | .suspend = serial_suspend, | ||
809 | .resume = serial_resume, | ||
884 | }; | 810 | }; |
885 | 811 | ||
886 | static int __init init_serial_cs(void) | 812 | static int __init init_serial_cs(void) |
@@ -891,7 +817,6 @@ static int __init init_serial_cs(void) | |||
891 | static void __exit exit_serial_cs(void) | 817 | static void __exit exit_serial_cs(void) |
892 | { | 818 | { |
893 | pcmcia_unregister_driver(&serial_cs_driver); | 819 | pcmcia_unregister_driver(&serial_cs_driver); |
894 | BUG_ON(dev_list != NULL); | ||
895 | } | 820 | } |
896 | 821 | ||
897 | module_init(init_serial_cs); | 822 | module_init(init_serial_cs); |
diff --git a/drivers/telephony/ixj_pcmcia.c b/drivers/telephony/ixj_pcmcia.c index 57c0c6e3fbed..d3a7b0c3d38b 100644 --- a/drivers/telephony/ixj_pcmcia.c +++ b/drivers/telephony/ixj_pcmcia.c | |||
@@ -34,24 +34,19 @@ typedef struct ixj_info_t { | |||
34 | struct ixj *port; | 34 | struct ixj *port; |
35 | } ixj_info_t; | 35 | } ixj_info_t; |
36 | 36 | ||
37 | static dev_link_t *ixj_attach(void); | 37 | static void ixj_detach(struct pcmcia_device *p_dev); |
38 | static void ixj_detach(dev_link_t *); | ||
39 | static void ixj_config(dev_link_t * link); | 38 | static void ixj_config(dev_link_t * link); |
40 | static void ixj_cs_release(dev_link_t * link); | 39 | static void ixj_cs_release(dev_link_t * link); |
41 | static int ixj_event(event_t event, int priority, event_callback_args_t * args); | ||
42 | static dev_info_t dev_info = "ixj_cs"; | ||
43 | static dev_link_t *dev_list = NULL; | ||
44 | 40 | ||
45 | static dev_link_t *ixj_attach(void) | 41 | static int ixj_attach(struct pcmcia_device *p_dev) |
46 | { | 42 | { |
47 | client_reg_t client_reg; | ||
48 | dev_link_t *link; | 43 | dev_link_t *link; |
49 | int ret; | 44 | |
50 | DEBUG(0, "ixj_attach()\n"); | 45 | DEBUG(0, "ixj_attach()\n"); |
51 | /* Create new ixj device */ | 46 | /* Create new ixj device */ |
52 | link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); | 47 | link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); |
53 | if (!link) | 48 | if (!link) |
54 | return NULL; | 49 | return -ENOMEM; |
55 | memset(link, 0, sizeof(struct dev_link_t)); | 50 | memset(link, 0, sizeof(struct dev_link_t)); |
56 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; | 51 | link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; |
57 | link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; | 52 | link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; |
@@ -61,44 +56,29 @@ static dev_link_t *ixj_attach(void) | |||
61 | link->priv = kmalloc(sizeof(struct ixj_info_t), GFP_KERNEL); | 56 | link->priv = kmalloc(sizeof(struct ixj_info_t), GFP_KERNEL); |
62 | if (!link->priv) { | 57 | if (!link->priv) { |
63 | kfree(link); | 58 | kfree(link); |
64 | return NULL; | 59 | return -ENOMEM; |
65 | } | 60 | } |
66 | memset(link->priv, 0, sizeof(struct ixj_info_t)); | 61 | memset(link->priv, 0, sizeof(struct ixj_info_t)); |
67 | /* Register with Card Services */ | 62 | |
68 | link->next = dev_list; | 63 | link->handle = p_dev; |
69 | dev_list = link; | 64 | p_dev->instance = link; |
70 | client_reg.dev_info = &dev_info; | 65 | |
71 | client_reg.Version = 0x0210; | 66 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
72 | client_reg.event_callback_args.client_data = link; | 67 | ixj_config(link); |
73 | ret = pcmcia_register_client(&link->handle, &client_reg); | 68 | |
74 | if (ret != CS_SUCCESS) { | 69 | return 0; |
75 | cs_error(link->handle, RegisterClient, ret); | ||
76 | ixj_detach(link); | ||
77 | return NULL; | ||
78 | } | ||
79 | return link; | ||
80 | } | 70 | } |
81 | 71 | ||
82 | static void ixj_detach(dev_link_t * link) | 72 | static void ixj_detach(struct pcmcia_device *p_dev) |
83 | { | 73 | { |
84 | dev_link_t **linkp; | 74 | dev_link_t *link = dev_to_instance(p_dev); |
85 | int ret; | 75 | |
86 | DEBUG(0, "ixj_detach(0x%p)\n", link); | 76 | DEBUG(0, "ixj_detach(0x%p)\n", link); |
87 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | 77 | |
88 | if (*linkp == link) | ||
89 | break; | ||
90 | if (*linkp == NULL) | ||
91 | return; | ||
92 | link->state &= ~DEV_RELEASE_PENDING; | 78 | link->state &= ~DEV_RELEASE_PENDING; |
93 | if (link->state & DEV_CONFIG) | 79 | if (link->state & DEV_CONFIG) |
94 | ixj_cs_release(link); | 80 | ixj_cs_release(link); |
95 | if (link->handle) { | 81 | |
96 | ret = pcmcia_deregister_client(link->handle); | ||
97 | if (ret != CS_SUCCESS) | ||
98 | cs_error(link->handle, DeregisterClient, ret); | ||
99 | } | ||
100 | /* Unlink device structure, free bits */ | ||
101 | *linkp = link->next; | ||
102 | kfree(link->priv); | 82 | kfree(link->priv); |
103 | kfree(link); | 83 | kfree(link); |
104 | } | 84 | } |
@@ -255,37 +235,25 @@ static void ixj_cs_release(dev_link_t *link) | |||
255 | link->state &= ~DEV_CONFIG; | 235 | link->state &= ~DEV_CONFIG; |
256 | } | 236 | } |
257 | 237 | ||
258 | static int ixj_event(event_t event, int priority, event_callback_args_t * args) | 238 | static int ixj_suspend(struct pcmcia_device *dev) |
259 | { | 239 | { |
260 | dev_link_t *link = args->client_data; | 240 | dev_link_t *link = dev_to_instance(dev); |
261 | DEBUG(1, "ixj_event(0x%06x)\n", event); | 241 | |
262 | switch (event) { | 242 | link->state |= DEV_SUSPEND; |
263 | case CS_EVENT_CARD_REMOVAL: | 243 | if (link->state & DEV_CONFIG) |
264 | link->state &= ~DEV_PRESENT; | 244 | pcmcia_release_configuration(link->handle); |
265 | if (link->state & DEV_CONFIG) { | 245 | |
266 | link->state |= DEV_RELEASE_PENDING; | 246 | return 0; |
267 | ixj_cs_release(link); | 247 | } |
268 | } | 248 | |
269 | break; | 249 | static int ixj_resume(struct pcmcia_device *dev) |
270 | case CS_EVENT_CARD_INSERTION: | 250 | { |
271 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | 251 | dev_link_t *link = dev_to_instance(dev); |
272 | ixj_config(link); | 252 | |
273 | break; | 253 | link->state &= ~DEV_SUSPEND; |
274 | case CS_EVENT_PM_SUSPEND: | 254 | if (DEV_OK(link)) |
275 | link->state |= DEV_SUSPEND; | 255 | pcmcia_request_configuration(link->handle, &link->conf); |
276 | /* Fall through... */ | 256 | |
277 | case CS_EVENT_RESET_PHYSICAL: | ||
278 | if (link->state & DEV_CONFIG) | ||
279 | pcmcia_release_configuration(link->handle); | ||
280 | break; | ||
281 | case CS_EVENT_PM_RESUME: | ||
282 | link->state &= ~DEV_SUSPEND; | ||
283 | /* Fall through... */ | ||
284 | case CS_EVENT_CARD_RESET: | ||
285 | if (DEV_OK(link)) | ||
286 | pcmcia_request_configuration(link->handle, &link->conf); | ||
287 | break; | ||
288 | } | ||
289 | return 0; | 257 | return 0; |
290 | } | 258 | } |
291 | 259 | ||
@@ -300,10 +268,11 @@ static struct pcmcia_driver ixj_driver = { | |||
300 | .drv = { | 268 | .drv = { |
301 | .name = "ixj_cs", | 269 | .name = "ixj_cs", |
302 | }, | 270 | }, |
303 | .attach = ixj_attach, | 271 | .probe = ixj_attach, |
304 | .event = ixj_event, | 272 | .remove = ixj_detach, |
305 | .detach = ixj_detach, | ||
306 | .id_table = ixj_ids, | 273 | .id_table = ixj_ids, |
274 | .suspend = ixj_suspend, | ||
275 | .resume = ixj_resume, | ||
307 | }; | 276 | }; |
308 | 277 | ||
309 | static int __init ixj_pcmcia_init(void) | 278 | static int __init ixj_pcmcia_init(void) |
@@ -314,7 +283,6 @@ static int __init ixj_pcmcia_init(void) | |||
314 | static void ixj_pcmcia_exit(void) | 283 | static void ixj_pcmcia_exit(void) |
315 | { | 284 | { |
316 | pcmcia_unregister_driver(&ixj_driver); | 285 | pcmcia_unregister_driver(&ixj_driver); |
317 | BUG_ON(dev_list != NULL); | ||
318 | } | 286 | } |
319 | 287 | ||
320 | module_init(ixj_pcmcia_init); | 288 | module_init(ixj_pcmcia_init); |
diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c index 5056b7459994..466384d7c79f 100644 --- a/drivers/usb/host/sl811_cs.c +++ b/drivers/usb/host/sl811_cs.c | |||
@@ -66,13 +66,13 @@ module_param(pc_debug, int, 0644); | |||
66 | 66 | ||
67 | static const char driver_name[DEV_NAME_LEN] = "sl811_cs"; | 67 | static const char driver_name[DEV_NAME_LEN] = "sl811_cs"; |
68 | 68 | ||
69 | static dev_link_t *dev_list = NULL; | ||
70 | |||
71 | typedef struct local_info_t { | 69 | typedef struct local_info_t { |
72 | dev_link_t link; | 70 | dev_link_t link; |
73 | dev_node_t node; | 71 | dev_node_t node; |
74 | } local_info_t; | 72 | } local_info_t; |
75 | 73 | ||
74 | static void sl811_cs_release(dev_link_t * link); | ||
75 | |||
76 | /*====================================================================*/ | 76 | /*====================================================================*/ |
77 | 77 | ||
78 | static void release_platform_dev(struct device * dev) | 78 | static void release_platform_dev(struct device * dev) |
@@ -138,26 +138,16 @@ static int sl811_hc_init(struct device *parent, ioaddr_t base_addr, int irq) | |||
138 | 138 | ||
139 | /*====================================================================*/ | 139 | /*====================================================================*/ |
140 | 140 | ||
141 | static void sl811_cs_detach(dev_link_t *link) | 141 | static void sl811_cs_detach(struct pcmcia_device *p_dev) |
142 | { | 142 | { |
143 | dev_link_t **linkp; | 143 | dev_link_t *link = dev_to_instance(p_dev); |
144 | 144 | ||
145 | DBG(0, "sl811_cs_detach(0x%p)\n", link); | 145 | DBG(0, "sl811_cs_detach(0x%p)\n", link); |
146 | 146 | ||
147 | /* Locate device structure */ | 147 | link->state &= ~DEV_PRESENT; |
148 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) { | 148 | if (link->state & DEV_CONFIG) |
149 | if (*linkp == link) | 149 | sl811_cs_release(link); |
150 | break; | ||
151 | } | ||
152 | if (*linkp == NULL) | ||
153 | return; | ||
154 | |||
155 | /* Break the link with Card Services */ | ||
156 | if (link->handle) | ||
157 | pcmcia_deregister_client(link->handle); | ||
158 | 150 | ||
159 | /* Unlink device structure, and free it */ | ||
160 | *linkp = link->next; | ||
161 | /* This points to the parent local_info_t struct */ | 151 | /* This points to the parent local_info_t struct */ |
162 | kfree(link->priv); | 152 | kfree(link->priv); |
163 | } | 153 | } |
@@ -167,13 +157,6 @@ static void sl811_cs_release(dev_link_t * link) | |||
167 | 157 | ||
168 | DBG(0, "sl811_cs_release(0x%p)\n", link); | 158 | DBG(0, "sl811_cs_release(0x%p)\n", link); |
169 | 159 | ||
170 | if (link->open) { | ||
171 | DBG(1, "sl811_cs: release postponed, '%s' still open\n", | ||
172 | link->dev->dev_name); | ||
173 | link->state |= DEV_STALE_CONFIG; | ||
174 | return; | ||
175 | } | ||
176 | |||
177 | /* Unlink the device chain */ | 160 | /* Unlink the device chain */ |
178 | link->dev = NULL; | 161 | link->dev = NULL; |
179 | 162 | ||
@@ -184,9 +167,6 @@ static void sl811_cs_release(dev_link_t * link) | |||
184 | if (link->irq.AssignedIRQ) | 167 | if (link->irq.AssignedIRQ) |
185 | pcmcia_release_irq(link->handle, &link->irq); | 168 | pcmcia_release_irq(link->handle, &link->irq); |
186 | link->state &= ~DEV_CONFIG; | 169 | link->state &= ~DEV_CONFIG; |
187 | |||
188 | if (link->state & DEV_STALE_LINK) | ||
189 | sl811_cs_detach(link); | ||
190 | } | 170 | } |
191 | 171 | ||
192 | static void sl811_cs_config(dev_link_t *link) | 172 | static void sl811_cs_config(dev_link_t *link) |
@@ -323,55 +303,36 @@ cs_failed: | |||
323 | } | 303 | } |
324 | } | 304 | } |
325 | 305 | ||
326 | static int | 306 | static int sl811_suspend(struct pcmcia_device *dev) |
327 | sl811_cs_event(event_t event, int priority, event_callback_args_t *args) | ||
328 | { | 307 | { |
329 | dev_link_t *link = args->client_data; | 308 | dev_link_t *link = dev_to_instance(dev); |
330 | 309 | ||
331 | DBG(1, "sl811_cs_event(0x%06x)\n", event); | 310 | link->state |= DEV_SUSPEND; |
311 | if (link->state & DEV_CONFIG) | ||
312 | pcmcia_release_configuration(link->handle); | ||
332 | 313 | ||
333 | switch (event) { | 314 | return 0; |
334 | case CS_EVENT_CARD_REMOVAL: | 315 | } |
335 | link->state &= ~DEV_PRESENT; | ||
336 | if (link->state & DEV_CONFIG) | ||
337 | sl811_cs_release(link); | ||
338 | break; | ||
339 | 316 | ||
340 | case CS_EVENT_CARD_INSERTION: | 317 | static int sl811_resume(struct pcmcia_device *dev) |
341 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | 318 | { |
342 | sl811_cs_config(link); | 319 | dev_link_t *link = dev_to_instance(dev); |
343 | break; | ||
344 | 320 | ||
345 | case CS_EVENT_PM_SUSPEND: | 321 | link->state &= ~DEV_SUSPEND; |
346 | link->state |= DEV_SUSPEND; | 322 | if (link->state & DEV_CONFIG) |
347 | /* Fall through... */ | 323 | pcmcia_request_configuration(link->handle, &link->conf); |
348 | case CS_EVENT_RESET_PHYSICAL: | ||
349 | if (link->state & DEV_CONFIG) | ||
350 | pcmcia_release_configuration(link->handle); | ||
351 | break; | ||
352 | 324 | ||
353 | case CS_EVENT_PM_RESUME: | ||
354 | link->state &= ~DEV_SUSPEND; | ||
355 | /* Fall through... */ | ||
356 | case CS_EVENT_CARD_RESET: | ||
357 | if (link->state & DEV_CONFIG) | ||
358 | pcmcia_request_configuration(link->handle, &link->conf); | ||
359 | DBG(0, "reset sl811-hcd here?\n"); | ||
360 | break; | ||
361 | } | ||
362 | return 0; | 325 | return 0; |
363 | } | 326 | } |
364 | 327 | ||
365 | static dev_link_t *sl811_cs_attach(void) | 328 | static int sl811_cs_attach(struct pcmcia_device *p_dev) |
366 | { | 329 | { |
367 | local_info_t *local; | 330 | local_info_t *local; |
368 | dev_link_t *link; | 331 | dev_link_t *link; |
369 | client_reg_t client_reg; | ||
370 | int ret; | ||
371 | 332 | ||
372 | local = kmalloc(sizeof(local_info_t), GFP_KERNEL); | 333 | local = kmalloc(sizeof(local_info_t), GFP_KERNEL); |
373 | if (!local) | 334 | if (!local) |
374 | return NULL; | 335 | return -ENOMEM; |
375 | memset(local, 0, sizeof(local_info_t)); | 336 | memset(local, 0, sizeof(local_info_t)); |
376 | link = &local->link; | 337 | link = &local->link; |
377 | link->priv = local; | 338 | link->priv = local; |
@@ -385,21 +346,13 @@ static dev_link_t *sl811_cs_attach(void) | |||
385 | link->conf.Vcc = 33; | 346 | link->conf.Vcc = 33; |
386 | link->conf.IntType = INT_MEMORY_AND_IO; | 347 | link->conf.IntType = INT_MEMORY_AND_IO; |
387 | 348 | ||
388 | /* Register with Card Services */ | 349 | link->handle = p_dev; |
389 | link->next = dev_list; | 350 | p_dev->instance = link; |
390 | dev_list = link; | ||
391 | client_reg.dev_info = (dev_info_t *) &driver_name; | ||
392 | client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; | ||
393 | client_reg.Version = 0x0210; | ||
394 | client_reg.event_callback_args.client_data = link; | ||
395 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
396 | if (ret != CS_SUCCESS) { | ||
397 | cs_error(link->handle, RegisterClient, ret); | ||
398 | sl811_cs_detach(link); | ||
399 | return NULL; | ||
400 | } | ||
401 | 351 | ||
402 | return link; | 352 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; |
353 | sl811_cs_config(link); | ||
354 | |||
355 | return 0; | ||
403 | } | 356 | } |
404 | 357 | ||
405 | static struct pcmcia_device_id sl811_ids[] = { | 358 | static struct pcmcia_device_id sl811_ids[] = { |
@@ -413,10 +366,11 @@ static struct pcmcia_driver sl811_cs_driver = { | |||
413 | .drv = { | 366 | .drv = { |
414 | .name = (char *)driver_name, | 367 | .name = (char *)driver_name, |
415 | }, | 368 | }, |
416 | .attach = sl811_cs_attach, | 369 | .probe = sl811_cs_attach, |
417 | .event = sl811_cs_event, | 370 | .remove = sl811_cs_detach, |
418 | .detach = sl811_cs_detach, | ||
419 | .id_table = sl811_ids, | 371 | .id_table = sl811_ids, |
372 | .suspend = sl811_suspend, | ||
373 | .resume = sl811_resume, | ||
420 | }; | 374 | }; |
421 | 375 | ||
422 | /*====================================================================*/ | 376 | /*====================================================================*/ |
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c index 08edbfcfca58..3fefdb0cbf07 100644 --- a/drivers/video/aty/atyfb_base.c +++ b/drivers/video/aty/atyfb_base.c | |||
@@ -403,7 +403,7 @@ static struct { | |||
403 | { PCI_CHIP_MACH64GM, "3D RAGE XL (Mach64 GM, AGP)", 230, 83, 63, ATI_CHIP_264XL }, | 403 | { PCI_CHIP_MACH64GM, "3D RAGE XL (Mach64 GM, AGP)", 230, 83, 63, ATI_CHIP_264XL }, |
404 | { PCI_CHIP_MACH64GN, "3D RAGE XL (Mach64 GN, AGP)", 230, 83, 63, ATI_CHIP_264XL }, | 404 | { PCI_CHIP_MACH64GN, "3D RAGE XL (Mach64 GN, AGP)", 230, 83, 63, ATI_CHIP_264XL }, |
405 | { PCI_CHIP_MACH64GO, "3D RAGE XL (Mach64 GO, PCI-66/BGA)", 230, 83, 63, ATI_CHIP_264XL }, | 405 | { PCI_CHIP_MACH64GO, "3D RAGE XL (Mach64 GO, PCI-66/BGA)", 230, 83, 63, ATI_CHIP_264XL }, |
406 | { PCI_CHIP_MACH64GR, "3D RAGE XL (Mach64 GR, PCI-33MHz)", 230, 83, 63, ATI_CHIP_264XL }, | 406 | { PCI_CHIP_MACH64GR, "3D RAGE XL (Mach64 GR, PCI-33MHz)", 235, 83, 63, ATI_CHIP_264XL | M64F_SDRAM_MAGIC_PLL }, |
407 | { PCI_CHIP_MACH64GL, "3D RAGE XL (Mach64 GL, PCI)", 230, 83, 63, ATI_CHIP_264XL }, | 407 | { PCI_CHIP_MACH64GL, "3D RAGE XL (Mach64 GL, PCI)", 230, 83, 63, ATI_CHIP_264XL }, |
408 | { PCI_CHIP_MACH64GS, "3D RAGE XL (Mach64 GS, PCI)", 230, 83, 63, ATI_CHIP_264XL }, | 408 | { PCI_CHIP_MACH64GS, "3D RAGE XL (Mach64 GS, PCI)", 230, 83, 63, ATI_CHIP_264XL }, |
409 | 409 | ||
diff --git a/include/linux/netfilter/nfnetlink_conntrack.h b/include/linux/netfilter/nfnetlink_conntrack.h index 116fcaced909..668ec946c8e2 100644 --- a/include/linux/netfilter/nfnetlink_conntrack.h +++ b/include/linux/netfilter/nfnetlink_conntrack.h | |||
@@ -64,6 +64,9 @@ enum ctattr_l4proto { | |||
64 | CTA_PROTO_ICMP_ID, | 64 | CTA_PROTO_ICMP_ID, |
65 | CTA_PROTO_ICMP_TYPE, | 65 | CTA_PROTO_ICMP_TYPE, |
66 | CTA_PROTO_ICMP_CODE, | 66 | CTA_PROTO_ICMP_CODE, |
67 | CTA_PROTO_ICMPV6_ID, | ||
68 | CTA_PROTO_ICMPV6_TYPE, | ||
69 | CTA_PROTO_ICMPV6_CODE, | ||
67 | __CTA_PROTO_MAX | 70 | __CTA_PROTO_MAX |
68 | }; | 71 | }; |
69 | #define CTA_PROTO_MAX (__CTA_PROTO_MAX - 1) | 72 | #define CTA_PROTO_MAX (__CTA_PROTO_MAX - 1) |
@@ -128,6 +131,4 @@ enum ctattr_help { | |||
128 | }; | 131 | }; |
129 | #define CTA_HELP_MAX (__CTA_HELP_MAX - 1) | 132 | #define CTA_HELP_MAX (__CTA_HELP_MAX - 1) |
130 | 133 | ||
131 | #define CTA_HELP_MAXNAMESIZE 32 | ||
132 | |||
133 | #endif /* _IPCONNTRACK_NETLINK_H */ | 134 | #endif /* _IPCONNTRACK_NETLINK_H */ |
diff --git a/include/linux/netfilter_ipv6/ip6_tables.h b/include/linux/netfilter_ipv6/ip6_tables.h index 2efc046d9e94..c163ba31aab7 100644 --- a/include/linux/netfilter_ipv6/ip6_tables.h +++ b/include/linux/netfilter_ipv6/ip6_tables.h | |||
@@ -474,7 +474,11 @@ extern unsigned int ip6t_do_table(struct sk_buff **pskb, | |||
474 | extern int ip6t_ext_hdr(u8 nexthdr); | 474 | extern int ip6t_ext_hdr(u8 nexthdr); |
475 | /* find specified header and get offset to it */ | 475 | /* find specified header and get offset to it */ |
476 | extern int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, | 476 | extern int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, |
477 | u8 target); | 477 | int target, unsigned short *fragoff); |
478 | |||
479 | extern int ip6_masked_addrcmp(const struct in6_addr *addr1, | ||
480 | const struct in6_addr *mask, | ||
481 | const struct in6_addr *addr2); | ||
478 | 482 | ||
479 | #define IP6T_ALIGN(s) (((s) + (__alignof__(struct ip6t_entry)-1)) & ~(__alignof__(struct ip6t_entry)-1)) | 483 | #define IP6T_ALIGN(s) (((s) + (__alignof__(struct ip6t_entry)-1)) & ~(__alignof__(struct ip6t_entry)-1)) |
480 | 484 | ||
diff --git a/include/net/ip.h b/include/net/ip.h index f7e7fd728b67..7bb5804847f2 100644 --- a/include/net/ip.h +++ b/include/net/ip.h | |||
@@ -317,7 +317,6 @@ enum ip_defrag_users | |||
317 | IP_DEFRAG_CALL_RA_CHAIN, | 317 | IP_DEFRAG_CALL_RA_CHAIN, |
318 | IP_DEFRAG_CONNTRACK_IN, | 318 | IP_DEFRAG_CONNTRACK_IN, |
319 | IP_DEFRAG_CONNTRACK_OUT, | 319 | IP_DEFRAG_CONNTRACK_OUT, |
320 | IP_DEFRAG_NAT_OUT, | ||
321 | IP_DEFRAG_VS_IN, | 320 | IP_DEFRAG_VS_IN, |
322 | IP_DEFRAG_VS_OUT, | 321 | IP_DEFRAG_VS_OUT, |
323 | IP_DEFRAG_VS_FWD | 322 | IP_DEFRAG_VS_FWD |
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index cc4825610795..64b82b74a650 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h | |||
@@ -94,6 +94,9 @@ struct nf_conn | |||
94 | /* Current number of expected connections */ | 94 | /* Current number of expected connections */ |
95 | unsigned int expecting; | 95 | unsigned int expecting; |
96 | 96 | ||
97 | /* Unique ID that identifies this conntrack*/ | ||
98 | unsigned int id; | ||
99 | |||
97 | /* Helper. if any */ | 100 | /* Helper. if any */ |
98 | struct nf_conntrack_helper *helper; | 101 | struct nf_conntrack_helper *helper; |
99 | 102 | ||
@@ -140,6 +143,9 @@ struct nf_conntrack_expect | |||
140 | /* Usage count. */ | 143 | /* Usage count. */ |
141 | atomic_t use; | 144 | atomic_t use; |
142 | 145 | ||
146 | /* Unique ID */ | ||
147 | unsigned int id; | ||
148 | |||
143 | /* Flags */ | 149 | /* Flags */ |
144 | unsigned int flags; | 150 | unsigned int flags; |
145 | 151 | ||
@@ -190,6 +196,31 @@ static inline void nf_ct_put(struct nf_conn *ct) | |||
190 | nf_conntrack_put(&ct->ct_general); | 196 | nf_conntrack_put(&ct->ct_general); |
191 | } | 197 | } |
192 | 198 | ||
199 | extern struct nf_conntrack_tuple_hash * | ||
200 | __nf_conntrack_find(const struct nf_conntrack_tuple *tuple, | ||
201 | const struct nf_conn *ignored_conntrack); | ||
202 | |||
203 | extern void nf_conntrack_hash_insert(struct nf_conn *ct); | ||
204 | |||
205 | extern struct nf_conntrack_expect * | ||
206 | __nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple); | ||
207 | |||
208 | extern struct nf_conntrack_expect * | ||
209 | nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple); | ||
210 | |||
211 | extern void nf_ct_unlink_expect(struct nf_conntrack_expect *exp); | ||
212 | |||
213 | extern void nf_ct_remove_expectations(struct nf_conn *ct); | ||
214 | |||
215 | extern void nf_conntrack_flush(void); | ||
216 | |||
217 | extern struct nf_conntrack_helper * | ||
218 | nf_ct_helper_find_get( const struct nf_conntrack_tuple *tuple); | ||
219 | extern void nf_ct_helper_put(struct nf_conntrack_helper *helper); | ||
220 | |||
221 | extern struct nf_conntrack_helper * | ||
222 | __nf_conntrack_helper_find_byname(const char *name); | ||
223 | |||
193 | /* call to create an explicit dependency on nf_conntrack. */ | 224 | /* call to create an explicit dependency on nf_conntrack. */ |
194 | extern void need_nf_conntrack(void); | 225 | extern void need_nf_conntrack(void); |
195 | 226 | ||
diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h index 5a66b2a3a623..86ec8174ad02 100644 --- a/include/net/netfilter/nf_conntrack_helper.h +++ b/include/net/netfilter/nf_conntrack_helper.h | |||
@@ -33,6 +33,8 @@ struct nf_conntrack_helper | |||
33 | unsigned int protoff, | 33 | unsigned int protoff, |
34 | struct nf_conn *ct, | 34 | struct nf_conn *ct, |
35 | enum ip_conntrack_info conntrackinfo); | 35 | enum ip_conntrack_info conntrackinfo); |
36 | |||
37 | int (*to_nfattr)(struct sk_buff *skb, const struct nf_conn *ct); | ||
36 | }; | 38 | }; |
37 | 39 | ||
38 | extern int nf_conntrack_helper_register(struct nf_conntrack_helper *); | 40 | extern int nf_conntrack_helper_register(struct nf_conntrack_helper *); |
diff --git a/include/net/netfilter/nf_conntrack_l3proto.h b/include/net/netfilter/nf_conntrack_l3proto.h index 01663e5b33df..67856eb93b43 100644 --- a/include/net/netfilter/nf_conntrack_l3proto.h +++ b/include/net/netfilter/nf_conntrack_l3proto.h | |||
@@ -14,6 +14,8 @@ | |||
14 | #include <linux/seq_file.h> | 14 | #include <linux/seq_file.h> |
15 | #include <net/netfilter/nf_conntrack.h> | 15 | #include <net/netfilter/nf_conntrack.h> |
16 | 16 | ||
17 | struct nfattr; | ||
18 | |||
17 | struct nf_conntrack_l3proto | 19 | struct nf_conntrack_l3proto |
18 | { | 20 | { |
19 | /* Next pointer. */ | 21 | /* Next pointer. */ |
@@ -70,6 +72,12 @@ struct nf_conntrack_l3proto | |||
70 | 72 | ||
71 | u_int32_t (*get_features)(const struct nf_conntrack_tuple *tuple); | 73 | u_int32_t (*get_features)(const struct nf_conntrack_tuple *tuple); |
72 | 74 | ||
75 | int (*tuple_to_nfattr)(struct sk_buff *skb, | ||
76 | const struct nf_conntrack_tuple *t); | ||
77 | |||
78 | int (*nfattr_to_tuple)(struct nfattr *tb[], | ||
79 | struct nf_conntrack_tuple *t); | ||
80 | |||
73 | /* Module (if any) which this is connected to. */ | 81 | /* Module (if any) which this is connected to. */ |
74 | struct module *me; | 82 | struct module *me; |
75 | }; | 83 | }; |
@@ -81,11 +89,16 @@ extern int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto); | |||
81 | extern void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto); | 89 | extern void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto); |
82 | 90 | ||
83 | static inline struct nf_conntrack_l3proto * | 91 | static inline struct nf_conntrack_l3proto * |
84 | nf_ct_find_l3proto(u_int16_t l3proto) | 92 | __nf_ct_l3proto_find(u_int16_t l3proto) |
85 | { | 93 | { |
86 | return nf_ct_l3protos[l3proto]; | 94 | return nf_ct_l3protos[l3proto]; |
87 | } | 95 | } |
88 | 96 | ||
97 | extern struct nf_conntrack_l3proto * | ||
98 | nf_ct_l3proto_find_get(u_int16_t l3proto); | ||
99 | |||
100 | extern void nf_ct_l3proto_put(struct nf_conntrack_l3proto *p); | ||
101 | |||
89 | /* Existing built-in protocols */ | 102 | /* Existing built-in protocols */ |
90 | extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4; | 103 | extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4; |
91 | extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6; | 104 | extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6; |
diff --git a/include/net/netfilter/nf_conntrack_protocol.h b/include/net/netfilter/nf_conntrack_protocol.h index b3afda35397a..1f33737fcea5 100644 --- a/include/net/netfilter/nf_conntrack_protocol.h +++ b/include/net/netfilter/nf_conntrack_protocol.h | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <net/netfilter/nf_conntrack.h> | 12 | #include <net/netfilter/nf_conntrack.h> |
13 | 13 | ||
14 | struct seq_file; | 14 | struct seq_file; |
15 | struct nfattr; | ||
15 | 16 | ||
16 | struct nf_conntrack_protocol | 17 | struct nf_conntrack_protocol |
17 | { | 18 | { |
@@ -66,6 +67,18 @@ struct nf_conntrack_protocol | |||
66 | enum ip_conntrack_info *ctinfo, | 67 | enum ip_conntrack_info *ctinfo, |
67 | int pf, unsigned int hooknum); | 68 | int pf, unsigned int hooknum); |
68 | 69 | ||
70 | /* convert protoinfo to nfnetink attributes */ | ||
71 | int (*to_nfattr)(struct sk_buff *skb, struct nfattr *nfa, | ||
72 | const struct nf_conn *ct); | ||
73 | |||
74 | /* convert nfnetlink attributes to protoinfo */ | ||
75 | int (*from_nfattr)(struct nfattr *tb[], struct nf_conn *ct); | ||
76 | |||
77 | int (*tuple_to_nfattr)(struct sk_buff *skb, | ||
78 | const struct nf_conntrack_tuple *t); | ||
79 | int (*nfattr_to_tuple)(struct nfattr *tb[], | ||
80 | struct nf_conntrack_tuple *t); | ||
81 | |||
69 | /* Module (if any) which this is connected to. */ | 82 | /* Module (if any) which this is connected to. */ |
70 | struct module *me; | 83 | struct module *me; |
71 | }; | 84 | }; |
@@ -80,12 +93,23 @@ extern struct nf_conntrack_protocol nf_conntrack_generic_protocol; | |||
80 | extern struct nf_conntrack_protocol **nf_ct_protos[PF_MAX]; | 93 | extern struct nf_conntrack_protocol **nf_ct_protos[PF_MAX]; |
81 | 94 | ||
82 | extern struct nf_conntrack_protocol * | 95 | extern struct nf_conntrack_protocol * |
83 | nf_ct_find_proto(u_int16_t l3proto, u_int8_t protocol); | 96 | __nf_ct_proto_find(u_int16_t l3proto, u_int8_t protocol); |
97 | |||
98 | extern struct nf_conntrack_protocol * | ||
99 | nf_ct_proto_find_get(u_int16_t l3proto, u_int8_t protocol); | ||
100 | |||
101 | extern void nf_ct_proto_put(struct nf_conntrack_protocol *p); | ||
84 | 102 | ||
85 | /* Protocol registration. */ | 103 | /* Protocol registration. */ |
86 | extern int nf_conntrack_protocol_register(struct nf_conntrack_protocol *proto); | 104 | extern int nf_conntrack_protocol_register(struct nf_conntrack_protocol *proto); |
87 | extern void nf_conntrack_protocol_unregister(struct nf_conntrack_protocol *proto); | 105 | extern void nf_conntrack_protocol_unregister(struct nf_conntrack_protocol *proto); |
88 | 106 | ||
107 | /* Generic netlink helpers */ | ||
108 | extern int nf_ct_port_tuple_to_nfattr(struct sk_buff *skb, | ||
109 | const struct nf_conntrack_tuple *tuple); | ||
110 | extern int nf_ct_port_nfattr_to_tuple(struct nfattr *tb[], | ||
111 | struct nf_conntrack_tuple *t); | ||
112 | |||
89 | /* Log invalid packets */ | 113 | /* Log invalid packets */ |
90 | extern unsigned int nf_ct_log_invalid; | 114 | extern unsigned int nf_ct_log_invalid; |
91 | 115 | ||
diff --git a/include/pcmcia/cs.h b/include/pcmcia/cs.h index 2cab39f49eb2..52660f32663d 100644 --- a/include/pcmcia/cs.h +++ b/include/pcmcia/cs.h | |||
@@ -382,7 +382,6 @@ enum service { | |||
382 | struct pcmcia_socket; | 382 | struct pcmcia_socket; |
383 | 383 | ||
384 | int pcmcia_access_configuration_register(struct pcmcia_device *p_dev, conf_reg_t *reg); | 384 | int pcmcia_access_configuration_register(struct pcmcia_device *p_dev, conf_reg_t *reg); |
385 | int pcmcia_deregister_client(struct pcmcia_device *p_dev); | ||
386 | int pcmcia_get_configuration_info(struct pcmcia_device *p_dev, config_info_t *config); | 385 | int pcmcia_get_configuration_info(struct pcmcia_device *p_dev, config_info_t *config); |
387 | int pcmcia_get_first_window(window_handle_t *win, win_req_t *req); | 386 | int pcmcia_get_first_window(window_handle_t *win, win_req_t *req); |
388 | int pcmcia_get_next_window(window_handle_t *win, win_req_t *req); | 387 | int pcmcia_get_next_window(window_handle_t *win, win_req_t *req); |
@@ -390,7 +389,6 @@ int pcmcia_get_status(struct pcmcia_device *p_dev, cs_status_t *status); | |||
390 | int pcmcia_get_mem_page(window_handle_t win, memreq_t *req); | 389 | int pcmcia_get_mem_page(window_handle_t win, memreq_t *req); |
391 | int pcmcia_map_mem_page(window_handle_t win, memreq_t *req); | 390 | int pcmcia_map_mem_page(window_handle_t win, memreq_t *req); |
392 | int pcmcia_modify_configuration(struct pcmcia_device *p_dev, modconf_t *mod); | 391 | int pcmcia_modify_configuration(struct pcmcia_device *p_dev, modconf_t *mod); |
393 | int pcmcia_register_client(client_handle_t *handle, client_reg_t *req); | ||
394 | int pcmcia_release_configuration(struct pcmcia_device *p_dev); | 392 | int pcmcia_release_configuration(struct pcmcia_device *p_dev); |
395 | int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req); | 393 | int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req); |
396 | int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req); | 394 | int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req); |
diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h index cb8b6e6ce66c..8e2a96396478 100644 --- a/include/pcmcia/ds.h +++ b/include/pcmcia/ds.h | |||
@@ -133,10 +133,12 @@ typedef struct dev_link_t { | |||
133 | struct pcmcia_socket; | 133 | struct pcmcia_socket; |
134 | 134 | ||
135 | struct pcmcia_driver { | 135 | struct pcmcia_driver { |
136 | dev_link_t *(*attach)(void); | 136 | int (*probe) (struct pcmcia_device *dev); |
137 | int (*event) (event_t event, int priority, | 137 | void (*remove) (struct pcmcia_device *dev); |
138 | event_callback_args_t *); | 138 | |
139 | void (*detach)(dev_link_t *); | 139 | int (*suspend) (struct pcmcia_device *dev); |
140 | int (*resume) (struct pcmcia_device *dev); | ||
141 | |||
140 | struct module *owner; | 142 | struct module *owner; |
141 | struct pcmcia_device_id *id_table; | 143 | struct pcmcia_device_id *id_table; |
142 | struct device_driver drv; | 144 | struct device_driver drv; |
@@ -164,7 +166,6 @@ struct pcmcia_device { | |||
164 | /* deprecated, a cleaned up version will be moved into this | 166 | /* deprecated, a cleaned up version will be moved into this |
165 | struct soon */ | 167 | struct soon */ |
166 | dev_link_t *instance; | 168 | dev_link_t *instance; |
167 | event_callback_args_t event_callback_args; | ||
168 | u_int state; | 169 | u_int state; |
169 | 170 | ||
170 | /* information about this device */ | 171 | /* information about this device */ |
@@ -193,6 +194,8 @@ struct pcmcia_device { | |||
193 | #define handle_to_pdev(handle) (handle) | 194 | #define handle_to_pdev(handle) (handle) |
194 | #define handle_to_dev(handle) (handle->dev) | 195 | #define handle_to_dev(handle) (handle->dev) |
195 | 196 | ||
197 | #define dev_to_instance(dev) (dev->instance) | ||
198 | |||
196 | /* error reporting */ | 199 | /* error reporting */ |
197 | void cs_error(client_handle_t handle, int func, int ret); | 200 | void cs_error(client_handle_t handle, int func, int ret); |
198 | 201 | ||
diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h index e788bbc5657d..2889a69a7a8f 100644 --- a/include/pcmcia/ss.h +++ b/include/pcmcia/ss.h | |||
@@ -118,16 +118,14 @@ struct pcmcia_socket; | |||
118 | struct pccard_operations { | 118 | struct pccard_operations { |
119 | int (*init)(struct pcmcia_socket *sock); | 119 | int (*init)(struct pcmcia_socket *sock); |
120 | int (*suspend)(struct pcmcia_socket *sock); | 120 | int (*suspend)(struct pcmcia_socket *sock); |
121 | int (*register_callback)(struct pcmcia_socket *sock, void (*handler)(void *, unsigned int), void * info); | ||
122 | int (*get_status)(struct pcmcia_socket *sock, u_int *value); | 121 | int (*get_status)(struct pcmcia_socket *sock, u_int *value); |
123 | int (*get_socket)(struct pcmcia_socket *sock, socket_state_t *state); | ||
124 | int (*set_socket)(struct pcmcia_socket *sock, socket_state_t *state); | 122 | int (*set_socket)(struct pcmcia_socket *sock, socket_state_t *state); |
125 | int (*set_io_map)(struct pcmcia_socket *sock, struct pccard_io_map *io); | 123 | int (*set_io_map)(struct pcmcia_socket *sock, struct pccard_io_map *io); |
126 | int (*set_mem_map)(struct pcmcia_socket *sock, struct pccard_mem_map *mem); | 124 | int (*set_mem_map)(struct pcmcia_socket *sock, struct pccard_mem_map *mem); |
127 | }; | 125 | }; |
128 | 126 | ||
129 | struct pccard_resource_ops { | 127 | struct pccard_resource_ops { |
130 | void (*validate_mem) (struct pcmcia_socket *s); | 128 | int (*validate_mem) (struct pcmcia_socket *s); |
131 | int (*adjust_io_region) (struct resource *res, | 129 | int (*adjust_io_region) (struct resource *res, |
132 | unsigned long r_start, | 130 | unsigned long r_start, |
133 | unsigned long r_end, | 131 | unsigned long r_end, |
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 11321197338e..ba442883e877 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/rtnetlink.h> | 22 | #include <linux/rtnetlink.h> |
23 | #include <linux/if_ether.h> | ||
23 | #include <net/sock.h> | 24 | #include <net/sock.h> |
24 | 25 | ||
25 | #include "br_private.h" | 26 | #include "br_private.h" |
@@ -323,7 +324,7 @@ int br_del_bridge(const char *name) | |||
323 | return ret; | 324 | return ret; |
324 | } | 325 | } |
325 | 326 | ||
326 | /* Mtu of the bridge pseudo-device 1500 or the minimum of the ports */ | 327 | /* MTU of the bridge pseudo-device: ETH_DATA_LEN or the minimum of the ports */ |
327 | int br_min_mtu(const struct net_bridge *br) | 328 | int br_min_mtu(const struct net_bridge *br) |
328 | { | 329 | { |
329 | const struct net_bridge_port *p; | 330 | const struct net_bridge_port *p; |
@@ -332,7 +333,7 @@ int br_min_mtu(const struct net_bridge *br) | |||
332 | ASSERT_RTNL(); | 333 | ASSERT_RTNL(); |
333 | 334 | ||
334 | if (list_empty(&br->port_list)) | 335 | if (list_empty(&br->port_list)) |
335 | mtu = 1500; | 336 | mtu = ETH_DATA_LEN; |
336 | else { | 337 | else { |
337 | list_for_each_entry(p, &br->port_list, list) { | 338 | list_for_each_entry(p, &br->port_list, list) { |
338 | if (!mtu || p->dev->mtu < mtu) | 339 | if (!mtu || p->dev->mtu < mtu) |
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index e24577367274..9f4dbeb59315 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c | |||
@@ -53,6 +53,7 @@ | |||
53 | #include <linux/errno.h> | 53 | #include <linux/errno.h> |
54 | #include <linux/config.h> | 54 | #include <linux/config.h> |
55 | #include <linux/init.h> | 55 | #include <linux/init.h> |
56 | #include <linux/if_ether.h> | ||
56 | #include <net/dst.h> | 57 | #include <net/dst.h> |
57 | #include <net/arp.h> | 58 | #include <net/arp.h> |
58 | #include <net/sock.h> | 59 | #include <net/sock.h> |
@@ -251,7 +252,7 @@ static int eth_mac_addr(struct net_device *dev, void *p) | |||
251 | 252 | ||
252 | static int eth_change_mtu(struct net_device *dev, int new_mtu) | 253 | static int eth_change_mtu(struct net_device *dev, int new_mtu) |
253 | { | 254 | { |
254 | if ((new_mtu < 68) || (new_mtu > 1500)) | 255 | if (new_mtu < 68 || new_mtu > ETH_DATA_LEN) |
255 | return -EINVAL; | 256 | return -EINVAL; |
256 | dev->mtu = new_mtu; | 257 | dev->mtu = new_mtu; |
257 | return 0; | 258 | return 0; |
@@ -272,7 +273,7 @@ void ether_setup(struct net_device *dev) | |||
272 | 273 | ||
273 | dev->type = ARPHRD_ETHER; | 274 | dev->type = ARPHRD_ETHER; |
274 | dev->hard_header_len = ETH_HLEN; | 275 | dev->hard_header_len = ETH_HLEN; |
275 | dev->mtu = 1500; /* eth_mtu */ | 276 | dev->mtu = ETH_DATA_LEN; |
276 | dev->addr_len = ETH_ALEN; | 277 | dev->addr_len = ETH_ALEN; |
277 | dev->tx_queue_len = 1000; /* Ethernet wants good queues */ | 278 | dev->tx_queue_len = 1000; /* Ethernet wants good queues */ |
278 | dev->flags = IFF_BROADCAST|IFF_MULTICAST; | 279 | dev->flags = IFF_BROADCAST|IFF_MULTICAST; |
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 46f9d9cf7a5f..912c42f57c79 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/inetdevice.h> | 28 | #include <linux/inetdevice.h> |
29 | #include <linux/igmp.h> | 29 | #include <linux/igmp.h> |
30 | #include <linux/netfilter_ipv4.h> | 30 | #include <linux/netfilter_ipv4.h> |
31 | #include <linux/if_ether.h> | ||
31 | 32 | ||
32 | #include <net/sock.h> | 33 | #include <net/sock.h> |
33 | #include <net/ip.h> | 34 | #include <net/ip.h> |
@@ -1140,7 +1141,7 @@ static void ipgre_tunnel_setup(struct net_device *dev) | |||
1140 | 1141 | ||
1141 | dev->type = ARPHRD_IPGRE; | 1142 | dev->type = ARPHRD_IPGRE; |
1142 | dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr) + 4; | 1143 | dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr) + 4; |
1143 | dev->mtu = 1500 - sizeof(struct iphdr) - 4; | 1144 | dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr) - 4; |
1144 | dev->flags = IFF_NOARP; | 1145 | dev->flags = IFF_NOARP; |
1145 | dev->iflink = 0; | 1146 | dev->iflink = 0; |
1146 | dev->addr_len = 4; | 1147 | dev->addr_len = 4; |
@@ -1152,7 +1153,7 @@ static int ipgre_tunnel_init(struct net_device *dev) | |||
1152 | struct ip_tunnel *tunnel; | 1153 | struct ip_tunnel *tunnel; |
1153 | struct iphdr *iph; | 1154 | struct iphdr *iph; |
1154 | int hlen = LL_MAX_HEADER; | 1155 | int hlen = LL_MAX_HEADER; |
1155 | int mtu = 1500; | 1156 | int mtu = ETH_DATA_LEN; |
1156 | int addend = sizeof(struct iphdr) + 4; | 1157 | int addend = sizeof(struct iphdr) + 4; |
1157 | 1158 | ||
1158 | tunnel = (struct ip_tunnel*)dev->priv; | 1159 | tunnel = (struct ip_tunnel*)dev->priv; |
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 2a830de3a699..71da31818cfc 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c | |||
@@ -202,13 +202,11 @@ static inline int ip_finish_output2(struct sk_buff *skb) | |||
202 | 202 | ||
203 | static inline int ip_finish_output(struct sk_buff *skb) | 203 | static inline int ip_finish_output(struct sk_buff *skb) |
204 | { | 204 | { |
205 | struct net_device *dev = skb->dst->dev; | 205 | if (skb->len > dst_mtu(skb->dst) && |
206 | 206 | !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size)) | |
207 | skb->dev = dev; | 207 | return ip_fragment(skb, ip_finish_output2); |
208 | skb->protocol = htons(ETH_P_IP); | 208 | else |
209 | 209 | return ip_finish_output2(skb); | |
210 | return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev, | ||
211 | ip_finish_output2); | ||
212 | } | 210 | } |
213 | 211 | ||
214 | int ip_mc_output(struct sk_buff *skb) | 212 | int ip_mc_output(struct sk_buff *skb) |
@@ -265,21 +263,21 @@ int ip_mc_output(struct sk_buff *skb) | |||
265 | newskb->dev, ip_dev_loopback_xmit); | 263 | newskb->dev, ip_dev_loopback_xmit); |
266 | } | 264 | } |
267 | 265 | ||
268 | if (skb->len > dst_mtu(&rt->u.dst)) | 266 | return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, skb->dev, |
269 | return ip_fragment(skb, ip_finish_output); | 267 | ip_finish_output); |
270 | else | ||
271 | return ip_finish_output(skb); | ||
272 | } | 268 | } |
273 | 269 | ||
274 | int ip_output(struct sk_buff *skb) | 270 | int ip_output(struct sk_buff *skb) |
275 | { | 271 | { |
272 | struct net_device *dev = skb->dst->dev; | ||
273 | |||
276 | IP_INC_STATS(IPSTATS_MIB_OUTREQUESTS); | 274 | IP_INC_STATS(IPSTATS_MIB_OUTREQUESTS); |
277 | 275 | ||
278 | if (skb->len > dst_mtu(skb->dst) && | 276 | skb->dev = dev; |
279 | !(skb_shinfo(skb)->ufo_size || skb_shinfo(skb)->tso_size)) | 277 | skb->protocol = htons(ETH_P_IP); |
280 | return ip_fragment(skb, ip_finish_output); | 278 | |
281 | else | 279 | return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev, |
282 | return ip_finish_output(skb); | 280 | ip_finish_output); |
283 | } | 281 | } |
284 | 282 | ||
285 | int ip_queue_xmit(struct sk_buff *skb, int ipfragok) | 283 | int ip_queue_xmit(struct sk_buff *skb, int ipfragok) |
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index c05c1df0bb04..35571cff81c6 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c | |||
@@ -108,6 +108,7 @@ | |||
108 | #include <linux/mroute.h> | 108 | #include <linux/mroute.h> |
109 | #include <linux/init.h> | 109 | #include <linux/init.h> |
110 | #include <linux/netfilter_ipv4.h> | 110 | #include <linux/netfilter_ipv4.h> |
111 | #include <linux/if_ether.h> | ||
111 | 112 | ||
112 | #include <net/sock.h> | 113 | #include <net/sock.h> |
113 | #include <net/ip.h> | 114 | #include <net/ip.h> |
@@ -786,7 +787,7 @@ static void ipip_tunnel_setup(struct net_device *dev) | |||
786 | 787 | ||
787 | dev->type = ARPHRD_TUNNEL; | 788 | dev->type = ARPHRD_TUNNEL; |
788 | dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr); | 789 | dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr); |
789 | dev->mtu = 1500 - sizeof(struct iphdr); | 790 | dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr); |
790 | dev->flags = IFF_NOARP; | 791 | dev->flags = IFF_NOARP; |
791 | dev->iflink = 0; | 792 | dev->iflink = 0; |
792 | dev->addr_len = 4; | 793 | dev->addr_len = 4; |
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index caa3b7d2e48a..9a5c0ce7ff35 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c | |||
@@ -49,6 +49,7 @@ | |||
49 | #include <linux/seq_file.h> | 49 | #include <linux/seq_file.h> |
50 | #include <linux/mroute.h> | 50 | #include <linux/mroute.h> |
51 | #include <linux/init.h> | 51 | #include <linux/init.h> |
52 | #include <linux/if_ether.h> | ||
52 | #include <net/ip.h> | 53 | #include <net/ip.h> |
53 | #include <net/protocol.h> | 54 | #include <net/protocol.h> |
54 | #include <linux/skbuff.h> | 55 | #include <linux/skbuff.h> |
@@ -193,7 +194,7 @@ static struct net_device_stats *reg_vif_get_stats(struct net_device *dev) | |||
193 | static void reg_vif_setup(struct net_device *dev) | 194 | static void reg_vif_setup(struct net_device *dev) |
194 | { | 195 | { |
195 | dev->type = ARPHRD_PIMREG; | 196 | dev->type = ARPHRD_PIMREG; |
196 | dev->mtu = 1500 - sizeof(struct iphdr) - 8; | 197 | dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr) - 8; |
197 | dev->flags = IFF_NOARP; | 198 | dev->flags = IFF_NOARP; |
198 | dev->hard_start_xmit = reg_vif_xmit; | 199 | dev->hard_start_xmit = reg_vif_xmit; |
199 | dev->get_stats = reg_vif_get_stats; | 200 | dev->get_stats = reg_vif_get_stats; |
diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c index 81d90354c928..87b83813cf2c 100644 --- a/net/ipv4/ipvs/ip_vs_conn.c +++ b/net/ipv4/ipvs/ip_vs_conn.c | |||
@@ -24,6 +24,7 @@ | |||
24 | * | 24 | * |
25 | */ | 25 | */ |
26 | 26 | ||
27 | #include <linux/interrupt.h> | ||
27 | #include <linux/in.h> | 28 | #include <linux/in.h> |
28 | #include <linux/net.h> | 29 | #include <linux/net.h> |
29 | #include <linux/kernel.h> | 30 | #include <linux/kernel.h> |
diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c index 1aca94a9fd8b..3f47ad8e1cad 100644 --- a/net/ipv4/ipvs/ip_vs_core.c +++ b/net/ipv4/ipvs/ip_vs_core.c | |||
@@ -532,11 +532,8 @@ static unsigned int ip_vs_post_routing(unsigned int hooknum, | |||
532 | { | 532 | { |
533 | if (!((*pskb)->ipvs_property)) | 533 | if (!((*pskb)->ipvs_property)) |
534 | return NF_ACCEPT; | 534 | return NF_ACCEPT; |
535 | |||
536 | /* The packet was sent from IPVS, exit this chain */ | 535 | /* The packet was sent from IPVS, exit this chain */ |
537 | (*okfn)(*pskb); | 536 | return NF_STOP; |
538 | |||
539 | return NF_STOLEN; | ||
540 | } | 537 | } |
541 | 538 | ||
542 | u16 ip_vs_checksum_complete(struct sk_buff *skb, int offset) | 539 | u16 ip_vs_checksum_complete(struct sk_buff *skb, int offset) |
diff --git a/net/ipv4/ipvs/ip_vs_est.c b/net/ipv4/ipvs/ip_vs_est.c index e7004741ac73..c453e1e57f4b 100644 --- a/net/ipv4/ipvs/ip_vs_est.c +++ b/net/ipv4/ipvs/ip_vs_est.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/jiffies.h> | 18 | #include <linux/jiffies.h> |
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | #include <linux/types.h> | 20 | #include <linux/types.h> |
21 | #include <linux/interrupt.h> | ||
21 | 22 | ||
22 | #include <net/ip_vs.h> | 23 | #include <net/ip_vs.h> |
23 | 24 | ||
diff --git a/net/ipv4/ipvs/ip_vs_sched.c b/net/ipv4/ipvs/ip_vs_sched.c index 0f7c56a225bd..8bc42b76223d 100644 --- a/net/ipv4/ipvs/ip_vs_sched.c +++ b/net/ipv4/ipvs/ip_vs_sched.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/module.h> | 22 | #include <linux/module.h> |
23 | #include <linux/sched.h> | 23 | #include <linux/sched.h> |
24 | #include <linux/spinlock.h> | 24 | #include <linux/spinlock.h> |
25 | #include <linux/interrupt.h> | ||
25 | #include <asm/string.h> | 26 | #include <asm/string.h> |
26 | #include <linux/kmod.h> | 27 | #include <linux/kmod.h> |
27 | 28 | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_amanda.c b/net/ipv4/netfilter/ip_conntrack_amanda.c index 0366eedb4d70..84e4f79b7ffa 100644 --- a/net/ipv4/netfilter/ip_conntrack_amanda.c +++ b/net/ipv4/netfilter/ip_conntrack_amanda.c | |||
@@ -36,7 +36,7 @@ static unsigned int master_timeout = 300; | |||
36 | MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>"); | 36 | MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>"); |
37 | MODULE_DESCRIPTION("Amanda connection tracking module"); | 37 | MODULE_DESCRIPTION("Amanda connection tracking module"); |
38 | MODULE_LICENSE("GPL"); | 38 | MODULE_LICENSE("GPL"); |
39 | module_param(master_timeout, int, 0600); | 39 | module_param(master_timeout, uint, 0600); |
40 | MODULE_PARM_DESC(master_timeout, "timeout for the master connection"); | 40 | MODULE_PARM_DESC(master_timeout, "timeout for the master connection"); |
41 | 41 | ||
42 | static const char *conns[] = { "DATA ", "MESG ", "INDEX " }; | 42 | static const char *conns[] = { "DATA ", "MESG ", "INDEX " }; |
diff --git a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c index 68b173bcda60..e627e5856172 100644 --- a/net/ipv4/netfilter/ip_conntrack_ftp.c +++ b/net/ipv4/netfilter/ip_conntrack_ftp.c | |||
@@ -34,7 +34,7 @@ static int ports_c; | |||
34 | module_param_array(ports, ushort, &ports_c, 0400); | 34 | module_param_array(ports, ushort, &ports_c, 0400); |
35 | 35 | ||
36 | static int loose; | 36 | static int loose; |
37 | module_param(loose, int, 0600); | 37 | module_param(loose, bool, 0600); |
38 | 38 | ||
39 | unsigned int (*ip_nat_ftp_hook)(struct sk_buff **pskb, | 39 | unsigned int (*ip_nat_ftp_hook)(struct sk_buff **pskb, |
40 | enum ip_conntrack_info ctinfo, | 40 | enum ip_conntrack_info ctinfo, |
diff --git a/net/ipv4/netfilter/ip_conntrack_irc.c b/net/ipv4/netfilter/ip_conntrack_irc.c index d7c40421d0d1..c51a2cf71b4b 100644 --- a/net/ipv4/netfilter/ip_conntrack_irc.c +++ b/net/ipv4/netfilter/ip_conntrack_irc.c | |||
@@ -36,7 +36,7 @@ | |||
36 | #define MAX_PORTS 8 | 36 | #define MAX_PORTS 8 |
37 | static unsigned short ports[MAX_PORTS]; | 37 | static unsigned short ports[MAX_PORTS]; |
38 | static int ports_c; | 38 | static int ports_c; |
39 | static int max_dcc_channels = 8; | 39 | static unsigned int max_dcc_channels = 8; |
40 | static unsigned int dcc_timeout = 300; | 40 | static unsigned int dcc_timeout = 300; |
41 | /* This is slow, but it's simple. --RR */ | 41 | /* This is slow, but it's simple. --RR */ |
42 | static char *irc_buffer; | 42 | static char *irc_buffer; |
@@ -54,9 +54,9 @@ MODULE_DESCRIPTION("IRC (DCC) connection tracking helper"); | |||
54 | MODULE_LICENSE("GPL"); | 54 | MODULE_LICENSE("GPL"); |
55 | module_param_array(ports, ushort, &ports_c, 0400); | 55 | module_param_array(ports, ushort, &ports_c, 0400); |
56 | MODULE_PARM_DESC(ports, "port numbers of IRC servers"); | 56 | MODULE_PARM_DESC(ports, "port numbers of IRC servers"); |
57 | module_param(max_dcc_channels, int, 0400); | 57 | module_param(max_dcc_channels, uint, 0400); |
58 | MODULE_PARM_DESC(max_dcc_channels, "max number of expected DCC channels per IRC session"); | 58 | MODULE_PARM_DESC(max_dcc_channels, "max number of expected DCC channels per IRC session"); |
59 | module_param(dcc_timeout, int, 0400); | 59 | module_param(dcc_timeout, uint, 0400); |
60 | MODULE_PARM_DESC(dcc_timeout, "timeout on for unestablished DCC channels"); | 60 | MODULE_PARM_DESC(dcc_timeout, "timeout on for unestablished DCC channels"); |
61 | 61 | ||
62 | static const char *dccprotos[] = { "SEND ", "CHAT ", "MOVE ", "TSEND ", "SCHAT " }; | 62 | static const char *dccprotos[] = { "SEND ", "CHAT ", "MOVE ", "TSEND ", "SCHAT " }; |
@@ -254,10 +254,6 @@ static int __init init(void) | |||
254 | printk("ip_conntrack_irc: max_dcc_channels must be a positive integer\n"); | 254 | printk("ip_conntrack_irc: max_dcc_channels must be a positive integer\n"); |
255 | return -EBUSY; | 255 | return -EBUSY; |
256 | } | 256 | } |
257 | if (dcc_timeout < 0) { | ||
258 | printk("ip_conntrack_irc: dcc_timeout must be a positive integer\n"); | ||
259 | return -EBUSY; | ||
260 | } | ||
261 | 257 | ||
262 | irc_buffer = kmalloc(65536, GFP_KERNEL); | 258 | irc_buffer = kmalloc(65536, GFP_KERNEL); |
263 | if (!irc_buffer) | 259 | if (!irc_buffer) |
diff --git a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c index 186646eb249f..4e68e16a2612 100644 --- a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c +++ b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c | |||
@@ -37,7 +37,7 @@ MODULE_DESCRIPTION("NetBIOS name service broadcast connection tracking helper"); | |||
37 | MODULE_LICENSE("GPL"); | 37 | MODULE_LICENSE("GPL"); |
38 | 38 | ||
39 | static unsigned int timeout = 3; | 39 | static unsigned int timeout = 3; |
40 | module_param(timeout, int, 0600); | 40 | module_param(timeout, uint, 0400); |
41 | MODULE_PARM_DESC(timeout, "timeout for master connection/replies in seconds"); | 41 | MODULE_PARM_DESC(timeout, "timeout for master connection/replies in seconds"); |
42 | 42 | ||
43 | static int help(struct sk_buff **pskb, | 43 | static int help(struct sk_buff **pskb, |
diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c index 91fe8f2e38ff..c9ebbe0d2d9c 100644 --- a/net/ipv4/netfilter/ip_conntrack_netlink.c +++ b/net/ipv4/netfilter/ip_conntrack_netlink.c | |||
@@ -79,6 +79,7 @@ ctnetlink_dump_tuples(struct sk_buff *skb, | |||
79 | const struct ip_conntrack_tuple *tuple) | 79 | const struct ip_conntrack_tuple *tuple) |
80 | { | 80 | { |
81 | struct nfattr *nest_parms; | 81 | struct nfattr *nest_parms; |
82 | int ret; | ||
82 | 83 | ||
83 | nest_parms = NFA_NEST(skb, CTA_TUPLE_IP); | 84 | nest_parms = NFA_NEST(skb, CTA_TUPLE_IP); |
84 | NFA_PUT(skb, CTA_IP_V4_SRC, sizeof(u_int32_t), &tuple->src.ip); | 85 | NFA_PUT(skb, CTA_IP_V4_SRC, sizeof(u_int32_t), &tuple->src.ip); |
@@ -86,10 +87,10 @@ ctnetlink_dump_tuples(struct sk_buff *skb, | |||
86 | NFA_NEST_END(skb, nest_parms); | 87 | NFA_NEST_END(skb, nest_parms); |
87 | 88 | ||
88 | nest_parms = NFA_NEST(skb, CTA_TUPLE_PROTO); | 89 | nest_parms = NFA_NEST(skb, CTA_TUPLE_PROTO); |
89 | ctnetlink_dump_tuples_proto(skb, tuple); | 90 | ret = ctnetlink_dump_tuples_proto(skb, tuple); |
90 | NFA_NEST_END(skb, nest_parms); | 91 | NFA_NEST_END(skb, nest_parms); |
91 | 92 | ||
92 | return 0; | 93 | return ret; |
93 | 94 | ||
94 | nfattr_failure: | 95 | nfattr_failure: |
95 | return -1; | 96 | return -1; |
@@ -160,7 +161,7 @@ ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct ip_conntrack *ct) | |||
160 | return 0; | 161 | return 0; |
161 | 162 | ||
162 | nest_helper = NFA_NEST(skb, CTA_HELP); | 163 | nest_helper = NFA_NEST(skb, CTA_HELP); |
163 | NFA_PUT(skb, CTA_HELP_NAME, CTA_HELP_MAXNAMESIZE, &ct->helper->name); | 164 | NFA_PUT(skb, CTA_HELP_NAME, strlen(ct->helper->name), ct->helper->name); |
164 | 165 | ||
165 | if (ct->helper->to_nfattr) | 166 | if (ct->helper->to_nfattr) |
166 | ct->helper->to_nfattr(skb, ct); | 167 | ct->helper->to_nfattr(skb, ct); |
@@ -229,7 +230,7 @@ nfattr_failure: | |||
229 | static inline int | 230 | static inline int |
230 | ctnetlink_dump_use(struct sk_buff *skb, const struct ip_conntrack *ct) | 231 | ctnetlink_dump_use(struct sk_buff *skb, const struct ip_conntrack *ct) |
231 | { | 232 | { |
232 | unsigned int use = htonl(atomic_read(&ct->ct_general.use)); | 233 | u_int32_t use = htonl(atomic_read(&ct->ct_general.use)); |
233 | 234 | ||
234 | NFA_PUT(skb, CTA_USE, sizeof(u_int32_t), &use); | 235 | NFA_PUT(skb, CTA_USE, sizeof(u_int32_t), &use); |
235 | return 0; | 236 | return 0; |
@@ -311,29 +312,22 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, | |||
311 | if (events & IPCT_DESTROY) { | 312 | if (events & IPCT_DESTROY) { |
312 | type = IPCTNL_MSG_CT_DELETE; | 313 | type = IPCTNL_MSG_CT_DELETE; |
313 | group = NFNLGRP_CONNTRACK_DESTROY; | 314 | group = NFNLGRP_CONNTRACK_DESTROY; |
314 | goto alloc_skb; | 315 | } else if (events & (IPCT_NEW | IPCT_RELATED)) { |
315 | } | ||
316 | if (events & (IPCT_NEW | IPCT_RELATED)) { | ||
317 | type = IPCTNL_MSG_CT_NEW; | 316 | type = IPCTNL_MSG_CT_NEW; |
318 | flags = NLM_F_CREATE|NLM_F_EXCL; | 317 | flags = NLM_F_CREATE|NLM_F_EXCL; |
319 | /* dump everything */ | 318 | /* dump everything */ |
320 | events = ~0UL; | 319 | events = ~0UL; |
321 | group = NFNLGRP_CONNTRACK_NEW; | 320 | group = NFNLGRP_CONNTRACK_NEW; |
322 | goto alloc_skb; | 321 | } else if (events & (IPCT_STATUS | |
323 | } | ||
324 | if (events & (IPCT_STATUS | | ||
325 | IPCT_PROTOINFO | | 322 | IPCT_PROTOINFO | |
326 | IPCT_HELPER | | 323 | IPCT_HELPER | |
327 | IPCT_HELPINFO | | 324 | IPCT_HELPINFO | |
328 | IPCT_NATINFO)) { | 325 | IPCT_NATINFO)) { |
329 | type = IPCTNL_MSG_CT_NEW; | 326 | type = IPCTNL_MSG_CT_NEW; |
330 | group = NFNLGRP_CONNTRACK_UPDATE; | 327 | group = NFNLGRP_CONNTRACK_UPDATE; |
331 | goto alloc_skb; | 328 | } else |
332 | } | 329 | return NOTIFY_DONE; |
333 | 330 | ||
334 | return NOTIFY_DONE; | ||
335 | |||
336 | alloc_skb: | ||
337 | /* FIXME: Check if there are any listeners before, don't hurt performance */ | 331 | /* FIXME: Check if there are any listeners before, don't hurt performance */ |
338 | 332 | ||
339 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); | 333 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); |
@@ -1037,6 +1031,11 @@ ctnetlink_create_conntrack(struct nfattr *cda[], | |||
1037 | return err; | 1031 | return err; |
1038 | } | 1032 | } |
1039 | 1033 | ||
1034 | #if defined(CONFIG_IP_NF_CONNTRACK_MARK) | ||
1035 | if (cda[CTA_MARK-1]) | ||
1036 | ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1])); | ||
1037 | #endif | ||
1038 | |||
1040 | ct->helper = ip_conntrack_helper_find_get(rtuple); | 1039 | ct->helper = ip_conntrack_helper_find_get(rtuple); |
1041 | 1040 | ||
1042 | add_timer(&ct->timeout); | 1041 | add_timer(&ct->timeout); |
@@ -1045,11 +1044,6 @@ ctnetlink_create_conntrack(struct nfattr *cda[], | |||
1045 | if (ct->helper) | 1044 | if (ct->helper) |
1046 | ip_conntrack_helper_put(ct->helper); | 1045 | ip_conntrack_helper_put(ct->helper); |
1047 | 1046 | ||
1048 | #if defined(CONFIG_IP_NF_CONNTRACK_MARK) | ||
1049 | if (cda[CTA_MARK-1]) | ||
1050 | ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1])); | ||
1051 | #endif | ||
1052 | |||
1053 | DEBUGP("conntrack with id %u inserted\n", ct->id); | 1047 | DEBUGP("conntrack with id %u inserted\n", ct->id); |
1054 | return 0; | 1048 | return 0; |
1055 | 1049 | ||
@@ -1209,7 +1203,6 @@ static int ctnetlink_expect_event(struct notifier_block *this, | |||
1209 | unsigned int type; | 1203 | unsigned int type; |
1210 | unsigned char *b; | 1204 | unsigned char *b; |
1211 | int flags = 0; | 1205 | int flags = 0; |
1212 | u16 proto; | ||
1213 | 1206 | ||
1214 | if (events & IPEXP_NEW) { | 1207 | if (events & IPEXP_NEW) { |
1215 | type = IPCTNL_MSG_EXP_NEW; | 1208 | type = IPCTNL_MSG_EXP_NEW; |
@@ -1236,7 +1229,6 @@ static int ctnetlink_expect_event(struct notifier_block *this, | |||
1236 | goto nfattr_failure; | 1229 | goto nfattr_failure; |
1237 | 1230 | ||
1238 | nlh->nlmsg_len = skb->tail - b; | 1231 | nlh->nlmsg_len = skb->tail - b; |
1239 | proto = exp->tuple.dst.protonum; | ||
1240 | nfnetlink_send(skb, 0, NFNLGRP_CONNTRACK_EXP_NEW, 0); | 1232 | nfnetlink_send(skb, 0, NFNLGRP_CONNTRACK_EXP_NEW, 0); |
1241 | return NOTIFY_DONE; | 1233 | return NOTIFY_DONE; |
1242 | 1234 | ||
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c index 5f9925db608e..30fc21d6165a 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c | |||
@@ -47,20 +47,21 @@ static int icmp_pkt_to_tuple(const struct sk_buff *skb, | |||
47 | return 1; | 47 | return 1; |
48 | } | 48 | } |
49 | 49 | ||
50 | /* Add 1; spaces filled with 0. */ | ||
51 | static const u_int8_t invmap[] = { | ||
52 | [ICMP_ECHO] = ICMP_ECHOREPLY + 1, | ||
53 | [ICMP_ECHOREPLY] = ICMP_ECHO + 1, | ||
54 | [ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1, | ||
55 | [ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1, | ||
56 | [ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1, | ||
57 | [ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1, | ||
58 | [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1, | ||
59 | [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1 | ||
60 | }; | ||
61 | |||
50 | static int icmp_invert_tuple(struct ip_conntrack_tuple *tuple, | 62 | static int icmp_invert_tuple(struct ip_conntrack_tuple *tuple, |
51 | const struct ip_conntrack_tuple *orig) | 63 | const struct ip_conntrack_tuple *orig) |
52 | { | 64 | { |
53 | /* Add 1; spaces filled with 0. */ | ||
54 | static const u_int8_t invmap[] | ||
55 | = { [ICMP_ECHO] = ICMP_ECHOREPLY + 1, | ||
56 | [ICMP_ECHOREPLY] = ICMP_ECHO + 1, | ||
57 | [ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1, | ||
58 | [ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1, | ||
59 | [ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1, | ||
60 | [ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1, | ||
61 | [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1, | ||
62 | [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1}; | ||
63 | |||
64 | if (orig->dst.u.icmp.type >= sizeof(invmap) | 65 | if (orig->dst.u.icmp.type >= sizeof(invmap) |
65 | || !invmap[orig->dst.u.icmp.type]) | 66 | || !invmap[orig->dst.u.icmp.type]) |
66 | return 0; | 67 | return 0; |
@@ -110,17 +111,17 @@ static int icmp_packet(struct ip_conntrack *ct, | |||
110 | return NF_ACCEPT; | 111 | return NF_ACCEPT; |
111 | } | 112 | } |
112 | 113 | ||
113 | static const u_int8_t valid_new[] = { | ||
114 | [ICMP_ECHO] = 1, | ||
115 | [ICMP_TIMESTAMP] = 1, | ||
116 | [ICMP_INFO_REQUEST] = 1, | ||
117 | [ICMP_ADDRESS] = 1 | ||
118 | }; | ||
119 | |||
120 | /* Called when a new connection for this protocol found. */ | 114 | /* Called when a new connection for this protocol found. */ |
121 | static int icmp_new(struct ip_conntrack *conntrack, | 115 | static int icmp_new(struct ip_conntrack *conntrack, |
122 | const struct sk_buff *skb) | 116 | const struct sk_buff *skb) |
123 | { | 117 | { |
118 | static const u_int8_t valid_new[] = { | ||
119 | [ICMP_ECHO] = 1, | ||
120 | [ICMP_TIMESTAMP] = 1, | ||
121 | [ICMP_INFO_REQUEST] = 1, | ||
122 | [ICMP_ADDRESS] = 1 | ||
123 | }; | ||
124 | |||
124 | if (conntrack->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new) | 125 | if (conntrack->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new) |
125 | || !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type]) { | 126 | || !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type]) { |
126 | /* Can't create a new ICMP `conn' with this. */ | 127 | /* Can't create a new ICMP `conn' with this. */ |
@@ -279,10 +280,6 @@ static int icmp_tuple_to_nfattr(struct sk_buff *skb, | |||
279 | NFA_PUT(skb, CTA_PROTO_ICMP_CODE, sizeof(u_int8_t), | 280 | NFA_PUT(skb, CTA_PROTO_ICMP_CODE, sizeof(u_int8_t), |
280 | &t->dst.u.icmp.code); | 281 | &t->dst.u.icmp.code); |
281 | 282 | ||
282 | if (t->dst.u.icmp.type >= sizeof(valid_new) | ||
283 | || !valid_new[t->dst.u.icmp.type]) | ||
284 | return -EINVAL; | ||
285 | |||
286 | return 0; | 283 | return 0; |
287 | 284 | ||
288 | nfattr_failure: | 285 | nfattr_failure: |
@@ -295,7 +292,7 @@ static int icmp_nfattr_to_tuple(struct nfattr *tb[], | |||
295 | if (!tb[CTA_PROTO_ICMP_TYPE-1] | 292 | if (!tb[CTA_PROTO_ICMP_TYPE-1] |
296 | || !tb[CTA_PROTO_ICMP_CODE-1] | 293 | || !tb[CTA_PROTO_ICMP_CODE-1] |
297 | || !tb[CTA_PROTO_ICMP_ID-1]) | 294 | || !tb[CTA_PROTO_ICMP_ID-1]) |
298 | return -1; | 295 | return -EINVAL; |
299 | 296 | ||
300 | tuple->dst.u.icmp.type = | 297 | tuple->dst.u.icmp.type = |
301 | *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_TYPE-1]); | 298 | *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_TYPE-1]); |
@@ -304,6 +301,10 @@ static int icmp_nfattr_to_tuple(struct nfattr *tb[], | |||
304 | tuple->src.u.icmp.id = | 301 | tuple->src.u.icmp.id = |
305 | *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]); | 302 | *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]); |
306 | 303 | ||
304 | if (tuple->dst.u.icmp.type >= sizeof(invmap) | ||
305 | || !invmap[tuple->dst.u.icmp.type]) | ||
306 | return -EINVAL; | ||
307 | |||
307 | return 0; | 308 | return 0; |
308 | } | 309 | } |
309 | #endif | 310 | #endif |
diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index a88bcc551244..7ba97783e741 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c | |||
@@ -451,30 +451,6 @@ static unsigned int ip_conntrack_defrag(unsigned int hooknum, | |||
451 | return NF_ACCEPT; | 451 | return NF_ACCEPT; |
452 | } | 452 | } |
453 | 453 | ||
454 | static unsigned int ip_refrag(unsigned int hooknum, | ||
455 | struct sk_buff **pskb, | ||
456 | const struct net_device *in, | ||
457 | const struct net_device *out, | ||
458 | int (*okfn)(struct sk_buff *)) | ||
459 | { | ||
460 | struct rtable *rt = (struct rtable *)(*pskb)->dst; | ||
461 | |||
462 | /* We've seen it coming out the other side: confirm */ | ||
463 | if (ip_confirm(hooknum, pskb, in, out, okfn) != NF_ACCEPT) | ||
464 | return NF_DROP; | ||
465 | |||
466 | /* Local packets are never produced too large for their | ||
467 | interface. We degfragment them at LOCAL_OUT, however, | ||
468 | so we have to refragment them here. */ | ||
469 | if ((*pskb)->len > dst_mtu(&rt->u.dst) && | ||
470 | !skb_shinfo(*pskb)->tso_size) { | ||
471 | /* No hook can be after us, so this should be OK. */ | ||
472 | ip_fragment(*pskb, okfn); | ||
473 | return NF_STOLEN; | ||
474 | } | ||
475 | return NF_ACCEPT; | ||
476 | } | ||
477 | |||
478 | static unsigned int ip_conntrack_local(unsigned int hooknum, | 454 | static unsigned int ip_conntrack_local(unsigned int hooknum, |
479 | struct sk_buff **pskb, | 455 | struct sk_buff **pskb, |
480 | const struct net_device *in, | 456 | const struct net_device *in, |
@@ -544,7 +520,7 @@ static struct nf_hook_ops ip_conntrack_helper_in_ops = { | |||
544 | 520 | ||
545 | /* Refragmenter; last chance. */ | 521 | /* Refragmenter; last chance. */ |
546 | static struct nf_hook_ops ip_conntrack_out_ops = { | 522 | static struct nf_hook_ops ip_conntrack_out_ops = { |
547 | .hook = ip_refrag, | 523 | .hook = ip_confirm, |
548 | .owner = THIS_MODULE, | 524 | .owner = THIS_MODULE, |
549 | .pf = PF_INET, | 525 | .pf = PF_INET, |
550 | .hooknum = NF_IP_POST_ROUTING, | 526 | .hooknum = NF_IP_POST_ROUTING, |
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c index 30cd4e18c129..f04111f74e09 100644 --- a/net/ipv4/netfilter/ip_nat_standalone.c +++ b/net/ipv4/netfilter/ip_nat_standalone.c | |||
@@ -190,23 +190,6 @@ ip_nat_out(unsigned int hooknum, | |||
190 | || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) | 190 | || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr)) |
191 | return NF_ACCEPT; | 191 | return NF_ACCEPT; |
192 | 192 | ||
193 | /* We can hit fragment here; forwarded packets get | ||
194 | defragmented by connection tracking coming in, then | ||
195 | fragmented (grr) by the forward code. | ||
196 | |||
197 | In future: If we have nfct != NULL, AND we have NAT | ||
198 | initialized, AND there is no helper, then we can do full | ||
199 | NAPT on the head, and IP-address-only NAT on the rest. | ||
200 | |||
201 | I'm starting to have nightmares about fragments. */ | ||
202 | |||
203 | if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) { | ||
204 | *pskb = ip_ct_gather_frags(*pskb, IP_DEFRAG_NAT_OUT); | ||
205 | |||
206 | if (!*pskb) | ||
207 | return NF_STOLEN; | ||
208 | } | ||
209 | |||
210 | return ip_nat_fn(hooknum, pskb, in, out, okfn); | 193 | return ip_nat_fn(hooknum, pskb, in, out, okfn); |
211 | } | 194 | } |
212 | 195 | ||
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index f057025a719e..6693526ae128 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c | |||
@@ -203,7 +203,7 @@ static void send_reset(struct sk_buff *oldskb, int hook) | |||
203 | sizeof(struct tcphdr), 0)); | 203 | sizeof(struct tcphdr), 0)); |
204 | 204 | ||
205 | /* Adjust IP TTL, DF */ | 205 | /* Adjust IP TTL, DF */ |
206 | nskb->nh.iph->ttl = MAXTTL; | 206 | nskb->nh.iph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT); |
207 | /* Set DF, id = 0 */ | 207 | /* Set DF, id = 0 */ |
208 | nskb->nh.iph->frag_off = htons(IP_DF); | 208 | nskb->nh.iph->frag_off = htons(IP_DF); |
209 | nskb->nh.iph->id = 0; | 209 | nskb->nh.iph->id = 0; |
diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c index 2883ccd8a91d..38641cd06123 100644 --- a/net/ipv4/netfilter/ipt_ULOG.c +++ b/net/ipv4/netfilter/ipt_ULOG.c | |||
@@ -77,15 +77,15 @@ MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NFLOG); | |||
77 | #define PRINTR(format, args...) do { if (net_ratelimit()) printk(format , ## args); } while (0) | 77 | #define PRINTR(format, args...) do { if (net_ratelimit()) printk(format , ## args); } while (0) |
78 | 78 | ||
79 | static unsigned int nlbufsiz = 4096; | 79 | static unsigned int nlbufsiz = 4096; |
80 | module_param(nlbufsiz, uint, 0600); /* FIXME: Check size < 128k --RR */ | 80 | module_param(nlbufsiz, uint, 0400); |
81 | MODULE_PARM_DESC(nlbufsiz, "netlink buffer size"); | 81 | MODULE_PARM_DESC(nlbufsiz, "netlink buffer size"); |
82 | 82 | ||
83 | static unsigned int flushtimeout = 10; | 83 | static unsigned int flushtimeout = 10; |
84 | module_param(flushtimeout, int, 0600); | 84 | module_param(flushtimeout, uint, 0600); |
85 | MODULE_PARM_DESC(flushtimeout, "buffer flush timeout (hundredths of a second)"); | 85 | MODULE_PARM_DESC(flushtimeout, "buffer flush timeout (hundredths of a second)"); |
86 | 86 | ||
87 | static unsigned int nflog = 1; | 87 | static int nflog = 1; |
88 | module_param(nflog, int, 0400); | 88 | module_param(nflog, bool, 0400); |
89 | MODULE_PARM_DESC(nflog, "register as internal netfilter logging module"); | 89 | MODULE_PARM_DESC(nflog, "register as internal netfilter logging module"); |
90 | 90 | ||
91 | /* global data structures */ | 91 | /* global data structures */ |
@@ -376,7 +376,7 @@ static int __init init(void) | |||
376 | 376 | ||
377 | DEBUGP("ipt_ULOG: init module\n"); | 377 | DEBUGP("ipt_ULOG: init module\n"); |
378 | 378 | ||
379 | if (nlbufsiz >= 128*1024) { | 379 | if (nlbufsiz > 128*1024) { |
380 | printk("Netlink buffer has to be <= 128kB\n"); | 380 | printk("Netlink buffer has to be <= 128kB\n"); |
381 | return -EINVAL; | 381 | return -EINVAL; |
382 | } | 382 | } |
diff --git a/net/ipv4/netfilter/ipt_recent.c b/net/ipv4/netfilter/ipt_recent.c index 261cbb4d4c49..5ddccb18c65e 100644 --- a/net/ipv4/netfilter/ipt_recent.c +++ b/net/ipv4/netfilter/ipt_recent.c | |||
@@ -24,10 +24,10 @@ | |||
24 | #define HASH_LOG 9 | 24 | #define HASH_LOG 9 |
25 | 25 | ||
26 | /* Defaults, these can be overridden on the module command-line. */ | 26 | /* Defaults, these can be overridden on the module command-line. */ |
27 | static int ip_list_tot = 100; | 27 | static unsigned int ip_list_tot = 100; |
28 | static int ip_pkt_list_tot = 20; | 28 | static unsigned int ip_pkt_list_tot = 20; |
29 | static int ip_list_hash_size = 0; | 29 | static unsigned int ip_list_hash_size = 0; |
30 | static int ip_list_perms = 0644; | 30 | static unsigned int ip_list_perms = 0644; |
31 | #ifdef DEBUG | 31 | #ifdef DEBUG |
32 | static int debug = 1; | 32 | static int debug = 1; |
33 | #endif | 33 | #endif |
@@ -38,13 +38,13 @@ KERN_INFO RECENT_NAME " " RECENT_VER ": Stephen Frost <sfrost@snowman.net>. htt | |||
38 | MODULE_AUTHOR("Stephen Frost <sfrost@snowman.net>"); | 38 | MODULE_AUTHOR("Stephen Frost <sfrost@snowman.net>"); |
39 | MODULE_DESCRIPTION("IP tables recently seen matching module " RECENT_VER); | 39 | MODULE_DESCRIPTION("IP tables recently seen matching module " RECENT_VER); |
40 | MODULE_LICENSE("GPL"); | 40 | MODULE_LICENSE("GPL"); |
41 | module_param(ip_list_tot, int, 0400); | 41 | module_param(ip_list_tot, uint, 0400); |
42 | module_param(ip_pkt_list_tot, int, 0400); | 42 | module_param(ip_pkt_list_tot, uint, 0400); |
43 | module_param(ip_list_hash_size, int, 0400); | 43 | module_param(ip_list_hash_size, uint, 0400); |
44 | module_param(ip_list_perms, int, 0400); | 44 | module_param(ip_list_perms, uint, 0400); |
45 | #ifdef DEBUG | 45 | #ifdef DEBUG |
46 | module_param(debug, int, 0600); | 46 | module_param(debug, bool, 0600); |
47 | MODULE_PARM_DESC(debug,"debugging level, defaults to 1"); | 47 | MODULE_PARM_DESC(debug,"enable debugging output"); |
48 | #endif | 48 | #endif |
49 | MODULE_PARM_DESC(ip_list_tot,"number of IPs to remember per list"); | 49 | MODULE_PARM_DESC(ip_list_tot,"number of IPs to remember per list"); |
50 | MODULE_PARM_DESC(ip_pkt_list_tot,"number of packets per IP to remember"); | 50 | MODULE_PARM_DESC(ip_pkt_list_tot,"number of packets per IP to remember"); |
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 8202c1c0afad..9bdbb7793971 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/skbuff.h> | 22 | #include <linux/skbuff.h> |
23 | #include <linux/icmp.h> | 23 | #include <linux/icmp.h> |
24 | #include <linux/sysctl.h> | 24 | #include <linux/sysctl.h> |
25 | #include <net/route.h> | ||
25 | #include <net/ip.h> | 26 | #include <net/ip.h> |
26 | 27 | ||
27 | #include <linux/netfilter_ipv4.h> | 28 | #include <linux/netfilter_ipv4.h> |
@@ -180,30 +181,6 @@ static unsigned int ipv4_conntrack_defrag(unsigned int hooknum, | |||
180 | return NF_ACCEPT; | 181 | return NF_ACCEPT; |
181 | } | 182 | } |
182 | 183 | ||
183 | static unsigned int ipv4_refrag(unsigned int hooknum, | ||
184 | struct sk_buff **pskb, | ||
185 | const struct net_device *in, | ||
186 | const struct net_device *out, | ||
187 | int (*okfn)(struct sk_buff *)) | ||
188 | { | ||
189 | struct rtable *rt = (struct rtable *)(*pskb)->dst; | ||
190 | |||
191 | /* We've seen it coming out the other side: confirm */ | ||
192 | if (ipv4_confirm(hooknum, pskb, in, out, okfn) != NF_ACCEPT) | ||
193 | return NF_DROP; | ||
194 | |||
195 | /* Local packets are never produced too large for their | ||
196 | interface. We degfragment them at LOCAL_OUT, however, | ||
197 | so we have to refragment them here. */ | ||
198 | if ((*pskb)->len > dst_mtu(&rt->u.dst) && | ||
199 | !skb_shinfo(*pskb)->tso_size) { | ||
200 | /* No hook can be after us, so this should be OK. */ | ||
201 | ip_fragment(*pskb, okfn); | ||
202 | return NF_STOLEN; | ||
203 | } | ||
204 | return NF_ACCEPT; | ||
205 | } | ||
206 | |||
207 | static unsigned int ipv4_conntrack_in(unsigned int hooknum, | 184 | static unsigned int ipv4_conntrack_in(unsigned int hooknum, |
208 | struct sk_buff **pskb, | 185 | struct sk_buff **pskb, |
209 | const struct net_device *in, | 186 | const struct net_device *in, |
@@ -283,7 +260,7 @@ static struct nf_hook_ops ipv4_conntrack_helper_in_ops = { | |||
283 | 260 | ||
284 | /* Refragmenter; last chance. */ | 261 | /* Refragmenter; last chance. */ |
285 | static struct nf_hook_ops ipv4_conntrack_out_ops = { | 262 | static struct nf_hook_ops ipv4_conntrack_out_ops = { |
286 | .hook = ipv4_refrag, | 263 | .hook = ipv4_confirm, |
287 | .owner = THIS_MODULE, | 264 | .owner = THIS_MODULE, |
288 | .pf = PF_INET, | 265 | .pf = PF_INET, |
289 | .hooknum = NF_IP_POST_ROUTING, | 266 | .hooknum = NF_IP_POST_ROUTING, |
@@ -392,6 +369,48 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len) | |||
392 | return -ENOENT; | 369 | return -ENOENT; |
393 | } | 370 | } |
394 | 371 | ||
372 | #if defined(CONFIG_NF_CT_NETLINK) || \ | ||
373 | defined(CONFIG_NF_CT_NETLINK_MODULE) | ||
374 | |||
375 | #include <linux/netfilter/nfnetlink.h> | ||
376 | #include <linux/netfilter/nfnetlink_conntrack.h> | ||
377 | |||
378 | static int ipv4_tuple_to_nfattr(struct sk_buff *skb, | ||
379 | const struct nf_conntrack_tuple *tuple) | ||
380 | { | ||
381 | NFA_PUT(skb, CTA_IP_V4_SRC, sizeof(u_int32_t), | ||
382 | &tuple->src.u3.ip); | ||
383 | NFA_PUT(skb, CTA_IP_V4_DST, sizeof(u_int32_t), | ||
384 | &tuple->dst.u3.ip); | ||
385 | return 0; | ||
386 | |||
387 | nfattr_failure: | ||
388 | return -1; | ||
389 | } | ||
390 | |||
391 | static const size_t cta_min_ip[CTA_IP_MAX] = { | ||
392 | [CTA_IP_V4_SRC-1] = sizeof(u_int32_t), | ||
393 | [CTA_IP_V4_DST-1] = sizeof(u_int32_t), | ||
394 | }; | ||
395 | |||
396 | static int ipv4_nfattr_to_tuple(struct nfattr *tb[], | ||
397 | struct nf_conntrack_tuple *t) | ||
398 | { | ||
399 | if (!tb[CTA_IP_V4_SRC-1] || !tb[CTA_IP_V4_DST-1]) | ||
400 | return -EINVAL; | ||
401 | |||
402 | if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip)) | ||
403 | return -EINVAL; | ||
404 | |||
405 | t->src.u3.ip = | ||
406 | *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_SRC-1]); | ||
407 | t->dst.u3.ip = | ||
408 | *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_DST-1]); | ||
409 | |||
410 | return 0; | ||
411 | } | ||
412 | #endif | ||
413 | |||
395 | static struct nf_sockopt_ops so_getorigdst = { | 414 | static struct nf_sockopt_ops so_getorigdst = { |
396 | .pf = PF_INET, | 415 | .pf = PF_INET, |
397 | .get_optmin = SO_ORIGINAL_DST, | 416 | .get_optmin = SO_ORIGINAL_DST, |
@@ -408,6 +427,11 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 = { | |||
408 | .print_conntrack = ipv4_print_conntrack, | 427 | .print_conntrack = ipv4_print_conntrack, |
409 | .prepare = ipv4_prepare, | 428 | .prepare = ipv4_prepare, |
410 | .get_features = ipv4_get_features, | 429 | .get_features = ipv4_get_features, |
430 | #if defined(CONFIG_NF_CT_NETLINK) || \ | ||
431 | defined(CONFIG_NF_CT_NETLINK_MODULE) | ||
432 | .tuple_to_nfattr = ipv4_tuple_to_nfattr, | ||
433 | .nfattr_to_tuple = ipv4_nfattr_to_tuple, | ||
434 | #endif | ||
411 | .me = THIS_MODULE, | 435 | .me = THIS_MODULE, |
412 | }; | 436 | }; |
413 | 437 | ||
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index 7ddb5c08f7b8..52dc175be39a 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c | |||
@@ -50,20 +50,21 @@ static int icmp_pkt_to_tuple(const struct sk_buff *skb, | |||
50 | return 1; | 50 | return 1; |
51 | } | 51 | } |
52 | 52 | ||
53 | /* Add 1; spaces filled with 0. */ | ||
54 | static const u_int8_t invmap[] = { | ||
55 | [ICMP_ECHO] = ICMP_ECHOREPLY + 1, | ||
56 | [ICMP_ECHOREPLY] = ICMP_ECHO + 1, | ||
57 | [ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1, | ||
58 | [ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1, | ||
59 | [ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1, | ||
60 | [ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1, | ||
61 | [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1, | ||
62 | [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1 | ||
63 | }; | ||
64 | |||
53 | static int icmp_invert_tuple(struct nf_conntrack_tuple *tuple, | 65 | static int icmp_invert_tuple(struct nf_conntrack_tuple *tuple, |
54 | const struct nf_conntrack_tuple *orig) | 66 | const struct nf_conntrack_tuple *orig) |
55 | { | 67 | { |
56 | /* Add 1; spaces filled with 0. */ | ||
57 | static u_int8_t invmap[] | ||
58 | = { [ICMP_ECHO] = ICMP_ECHOREPLY + 1, | ||
59 | [ICMP_ECHOREPLY] = ICMP_ECHO + 1, | ||
60 | [ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1, | ||
61 | [ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1, | ||
62 | [ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1, | ||
63 | [ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1, | ||
64 | [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1, | ||
65 | [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1}; | ||
66 | |||
67 | if (orig->dst.u.icmp.type >= sizeof(invmap) | 68 | if (orig->dst.u.icmp.type >= sizeof(invmap) |
68 | || !invmap[orig->dst.u.icmp.type]) | 69 | || !invmap[orig->dst.u.icmp.type]) |
69 | return 0; | 70 | return 0; |
@@ -120,11 +121,12 @@ static int icmp_packet(struct nf_conn *ct, | |||
120 | static int icmp_new(struct nf_conn *conntrack, | 121 | static int icmp_new(struct nf_conn *conntrack, |
121 | const struct sk_buff *skb, unsigned int dataoff) | 122 | const struct sk_buff *skb, unsigned int dataoff) |
122 | { | 123 | { |
123 | static u_int8_t valid_new[] | 124 | static const u_int8_t valid_new[] = { |
124 | = { [ICMP_ECHO] = 1, | 125 | [ICMP_ECHO] = 1, |
125 | [ICMP_TIMESTAMP] = 1, | 126 | [ICMP_TIMESTAMP] = 1, |
126 | [ICMP_INFO_REQUEST] = 1, | 127 | [ICMP_INFO_REQUEST] = 1, |
127 | [ICMP_ADDRESS] = 1 }; | 128 | [ICMP_ADDRESS] = 1 |
129 | }; | ||
128 | 130 | ||
129 | if (conntrack->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new) | 131 | if (conntrack->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new) |
130 | || !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type]) { | 132 | || !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type]) { |
@@ -168,7 +170,7 @@ icmp_error_message(struct sk_buff *skb, | |||
168 | return -NF_ACCEPT; | 170 | return -NF_ACCEPT; |
169 | } | 171 | } |
170 | 172 | ||
171 | innerproto = nf_ct_find_proto(PF_INET, inside->ip.protocol); | 173 | innerproto = __nf_ct_proto_find(PF_INET, inside->ip.protocol); |
172 | dataoff = skb->nh.iph->ihl*4 + sizeof(inside->icmp); | 174 | dataoff = skb->nh.iph->ihl*4 + sizeof(inside->icmp); |
173 | /* Are they talking about one of our connections? */ | 175 | /* Are they talking about one of our connections? */ |
174 | if (!nf_ct_get_tuple(skb, dataoff, dataoff + inside->ip.ihl*4, PF_INET, | 176 | if (!nf_ct_get_tuple(skb, dataoff, dataoff + inside->ip.ihl*4, PF_INET, |
@@ -281,6 +283,60 @@ checksum_skipped: | |||
281 | return icmp_error_message(skb, ctinfo, hooknum); | 283 | return icmp_error_message(skb, ctinfo, hooknum); |
282 | } | 284 | } |
283 | 285 | ||
286 | #if defined(CONFIG_NF_CT_NETLINK) || \ | ||
287 | defined(CONFIG_NF_CT_NETLINK_MODULE) | ||
288 | |||
289 | #include <linux/netfilter/nfnetlink.h> | ||
290 | #include <linux/netfilter/nfnetlink_conntrack.h> | ||
291 | |||
292 | static int icmp_tuple_to_nfattr(struct sk_buff *skb, | ||
293 | const struct nf_conntrack_tuple *t) | ||
294 | { | ||
295 | NFA_PUT(skb, CTA_PROTO_ICMP_ID, sizeof(u_int16_t), | ||
296 | &t->src.u.icmp.id); | ||
297 | NFA_PUT(skb, CTA_PROTO_ICMP_TYPE, sizeof(u_int8_t), | ||
298 | &t->dst.u.icmp.type); | ||
299 | NFA_PUT(skb, CTA_PROTO_ICMP_CODE, sizeof(u_int8_t), | ||
300 | &t->dst.u.icmp.code); | ||
301 | |||
302 | return 0; | ||
303 | |||
304 | nfattr_failure: | ||
305 | return -1; | ||
306 | } | ||
307 | |||
308 | static const size_t cta_min_proto[CTA_PROTO_MAX] = { | ||
309 | [CTA_PROTO_ICMP_TYPE-1] = sizeof(u_int8_t), | ||
310 | [CTA_PROTO_ICMP_CODE-1] = sizeof(u_int8_t), | ||
311 | [CTA_PROTO_ICMP_ID-1] = sizeof(u_int16_t) | ||
312 | }; | ||
313 | |||
314 | static int icmp_nfattr_to_tuple(struct nfattr *tb[], | ||
315 | struct nf_conntrack_tuple *tuple) | ||
316 | { | ||
317 | if (!tb[CTA_PROTO_ICMP_TYPE-1] | ||
318 | || !tb[CTA_PROTO_ICMP_CODE-1] | ||
319 | || !tb[CTA_PROTO_ICMP_ID-1]) | ||
320 | return -EINVAL; | ||
321 | |||
322 | if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto)) | ||
323 | return -EINVAL; | ||
324 | |||
325 | tuple->dst.u.icmp.type = | ||
326 | *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_TYPE-1]); | ||
327 | tuple->dst.u.icmp.code = | ||
328 | *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_CODE-1]); | ||
329 | tuple->src.u.icmp.id = | ||
330 | *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]); | ||
331 | |||
332 | if (tuple->dst.u.icmp.type >= sizeof(invmap) | ||
333 | || !invmap[tuple->dst.u.icmp.type]) | ||
334 | return -EINVAL; | ||
335 | |||
336 | return 0; | ||
337 | } | ||
338 | #endif | ||
339 | |||
284 | struct nf_conntrack_protocol nf_conntrack_protocol_icmp = | 340 | struct nf_conntrack_protocol nf_conntrack_protocol_icmp = |
285 | { | 341 | { |
286 | .list = { NULL, NULL }, | 342 | .list = { NULL, NULL }, |
@@ -295,7 +351,12 @@ struct nf_conntrack_protocol nf_conntrack_protocol_icmp = | |||
295 | .new = icmp_new, | 351 | .new = icmp_new, |
296 | .error = icmp_error, | 352 | .error = icmp_error, |
297 | .destroy = NULL, | 353 | .destroy = NULL, |
298 | .me = NULL | 354 | .me = NULL, |
355 | #if defined(CONFIG_NF_CT_NETLINK) || \ | ||
356 | defined(CONFIG_NF_CT_NETLINK_MODULE) | ||
357 | .tuple_to_nfattr = icmp_tuple_to_nfattr, | ||
358 | .nfattr_to_tuple = icmp_nfattr_to_tuple, | ||
359 | #endif | ||
299 | }; | 360 | }; |
300 | 361 | ||
301 | EXPORT_SYMBOL(nf_conntrack_protocol_icmp); | 362 | EXPORT_SYMBOL(nf_conntrack_protocol_icmp); |
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index ea43ef1d94a7..925b42d48347 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c | |||
@@ -119,13 +119,14 @@ static LIST_HEAD(ip6t_tables); | |||
119 | #define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0) | 119 | #define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0) |
120 | #endif | 120 | #endif |
121 | 121 | ||
122 | static int ip6_masked_addrcmp(struct in6_addr addr1, struct in6_addr mask, | 122 | int |
123 | struct in6_addr addr2) | 123 | ip6_masked_addrcmp(const struct in6_addr *addr1, const struct in6_addr *mask, |
124 | const struct in6_addr *addr2) | ||
124 | { | 125 | { |
125 | int i; | 126 | int i; |
126 | for( i = 0; i < 16; i++){ | 127 | for( i = 0; i < 16; i++){ |
127 | if((addr1.s6_addr[i] & mask.s6_addr[i]) != | 128 | if((addr1->s6_addr[i] & mask->s6_addr[i]) != |
128 | (addr2.s6_addr[i] & mask.s6_addr[i])) | 129 | (addr2->s6_addr[i] & mask->s6_addr[i])) |
129 | return 1; | 130 | return 1; |
130 | } | 131 | } |
131 | return 0; | 132 | return 0; |
@@ -159,10 +160,10 @@ ip6_packet_match(const struct sk_buff *skb, | |||
159 | 160 | ||
160 | #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg)) | 161 | #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg)) |
161 | 162 | ||
162 | if (FWINV(ip6_masked_addrcmp(ipv6->saddr,ip6info->smsk,ip6info->src), | 163 | if (FWINV(ip6_masked_addrcmp(&ipv6->saddr, &ip6info->smsk, |
163 | IP6T_INV_SRCIP) | 164 | &ip6info->src), IP6T_INV_SRCIP) |
164 | || FWINV(ip6_masked_addrcmp(ipv6->daddr,ip6info->dmsk,ip6info->dst), | 165 | || FWINV(ip6_masked_addrcmp(&ipv6->daddr, &ip6info->dmsk, |
165 | IP6T_INV_DSTIP)) { | 166 | &ip6info->dst), IP6T_INV_DSTIP)) { |
166 | dprintf("Source or dest mismatch.\n"); | 167 | dprintf("Source or dest mismatch.\n"); |
167 | /* | 168 | /* |
168 | dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr, | 169 | dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr, |
@@ -205,69 +206,21 @@ ip6_packet_match(const struct sk_buff *skb, | |||
205 | 206 | ||
206 | /* look for the desired protocol header */ | 207 | /* look for the desired protocol header */ |
207 | if((ip6info->flags & IP6T_F_PROTO)) { | 208 | if((ip6info->flags & IP6T_F_PROTO)) { |
208 | u_int8_t currenthdr = ipv6->nexthdr; | 209 | int protohdr; |
209 | struct ipv6_opt_hdr _hdr, *hp; | 210 | unsigned short _frag_off; |
210 | u_int16_t ptr; /* Header offset in skb */ | ||
211 | u_int16_t hdrlen; /* Header */ | ||
212 | u_int16_t _fragoff = 0, *fp = NULL; | ||
213 | |||
214 | ptr = IPV6_HDR_LEN; | ||
215 | |||
216 | while (ip6t_ext_hdr(currenthdr)) { | ||
217 | /* Is there enough space for the next ext header? */ | ||
218 | if (skb->len - ptr < IPV6_OPTHDR_LEN) | ||
219 | return 0; | ||
220 | |||
221 | /* NONE or ESP: there isn't protocol part */ | ||
222 | /* If we want to count these packets in '-p all', | ||
223 | * we will change the return 0 to 1*/ | ||
224 | if ((currenthdr == IPPROTO_NONE) || | ||
225 | (currenthdr == IPPROTO_ESP)) | ||
226 | break; | ||
227 | 211 | ||
228 | hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr); | 212 | protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off); |
229 | BUG_ON(hp == NULL); | 213 | if (protohdr < 0) |
230 | 214 | return 0; | |
231 | /* Size calculation */ | ||
232 | if (currenthdr == IPPROTO_FRAGMENT) { | ||
233 | fp = skb_header_pointer(skb, | ||
234 | ptr+offsetof(struct frag_hdr, | ||
235 | frag_off), | ||
236 | sizeof(_fragoff), | ||
237 | &_fragoff); | ||
238 | if (fp == NULL) | ||
239 | return 0; | ||
240 | |||
241 | _fragoff = ntohs(*fp) & ~0x7; | ||
242 | hdrlen = 8; | ||
243 | } else if (currenthdr == IPPROTO_AH) | ||
244 | hdrlen = (hp->hdrlen+2)<<2; | ||
245 | else | ||
246 | hdrlen = ipv6_optlen(hp); | ||
247 | |||
248 | currenthdr = hp->nexthdr; | ||
249 | ptr += hdrlen; | ||
250 | /* ptr is too large */ | ||
251 | if ( ptr > skb->len ) | ||
252 | return 0; | ||
253 | if (_fragoff) { | ||
254 | if (ip6t_ext_hdr(currenthdr)) | ||
255 | return 0; | ||
256 | break; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | *protoff = ptr; | ||
261 | *fragoff = _fragoff; | ||
262 | 215 | ||
263 | /* currenthdr contains the protocol header */ | 216 | *fragoff = _frag_off; |
264 | 217 | ||
265 | dprintf("Packet protocol %hi ?= %s%hi.\n", | 218 | dprintf("Packet protocol %hi ?= %s%hi.\n", |
266 | currenthdr, | 219 | protohdr, |
267 | ip6info->invflags & IP6T_INV_PROTO ? "!":"", | 220 | ip6info->invflags & IP6T_INV_PROTO ? "!":"", |
268 | ip6info->proto); | 221 | ip6info->proto); |
269 | 222 | ||
270 | if (ip6info->proto == currenthdr) { | 223 | if (ip6info->proto == protohdr) { |
271 | if(ip6info->invflags & IP6T_INV_PROTO) { | 224 | if(ip6info->invflags & IP6T_INV_PROTO) { |
272 | return 0; | 225 | return 0; |
273 | } | 226 | } |
@@ -2098,26 +2051,39 @@ static void __exit fini(void) | |||
2098 | } | 2051 | } |
2099 | 2052 | ||
2100 | /* | 2053 | /* |
2101 | * find specified header up to transport protocol header. | 2054 | * find the offset to specified header or the protocol number of last header |
2102 | * If found target header, the offset to the header is set to *offset | 2055 | * if target < 0. "last header" is transport protocol header, ESP, or |
2103 | * and return 0. otherwise, return -1. | 2056 | * "No next header". |
2057 | * | ||
2058 | * If target header is found, its offset is set in *offset and return protocol | ||
2059 | * number. Otherwise, return -1. | ||
2060 | * | ||
2061 | * Note that non-1st fragment is special case that "the protocol number | ||
2062 | * of last header" is "next header" field in Fragment header. In this case, | ||
2063 | * *offset is meaningless and fragment offset is stored in *fragoff if fragoff | ||
2064 | * isn't NULL. | ||
2104 | * | 2065 | * |
2105 | * Notes: - non-1st Fragment Header isn't skipped. | ||
2106 | * - ESP header isn't skipped. | ||
2107 | * - The target header may be trancated. | ||
2108 | */ | 2066 | */ |
2109 | int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, u8 target) | 2067 | int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, |
2068 | int target, unsigned short *fragoff) | ||
2110 | { | 2069 | { |
2111 | unsigned int start = (u8*)(skb->nh.ipv6h + 1) - skb->data; | 2070 | unsigned int start = (u8*)(skb->nh.ipv6h + 1) - skb->data; |
2112 | u8 nexthdr = skb->nh.ipv6h->nexthdr; | 2071 | u8 nexthdr = skb->nh.ipv6h->nexthdr; |
2113 | unsigned int len = skb->len - start; | 2072 | unsigned int len = skb->len - start; |
2114 | 2073 | ||
2074 | if (fragoff) | ||
2075 | *fragoff = 0; | ||
2076 | |||
2115 | while (nexthdr != target) { | 2077 | while (nexthdr != target) { |
2116 | struct ipv6_opt_hdr _hdr, *hp; | 2078 | struct ipv6_opt_hdr _hdr, *hp; |
2117 | unsigned int hdrlen; | 2079 | unsigned int hdrlen; |
2118 | 2080 | ||
2119 | if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) | 2081 | if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) { |
2082 | if (target < 0) | ||
2083 | break; | ||
2120 | return -1; | 2084 | return -1; |
2085 | } | ||
2086 | |||
2121 | hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr); | 2087 | hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr); |
2122 | if (hp == NULL) | 2088 | if (hp == NULL) |
2123 | return -1; | 2089 | return -1; |
@@ -2131,8 +2097,17 @@ int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, u8 target) | |||
2131 | if (fp == NULL) | 2097 | if (fp == NULL) |
2132 | return -1; | 2098 | return -1; |
2133 | 2099 | ||
2134 | if (ntohs(*fp) & ~0x7) | 2100 | _frag_off = ntohs(*fp) & ~0x7; |
2101 | if (_frag_off) { | ||
2102 | if (target < 0 && | ||
2103 | ((!ipv6_ext_hdr(hp->nexthdr)) || | ||
2104 | nexthdr == NEXTHDR_NONE)) { | ||
2105 | if (fragoff) | ||
2106 | *fragoff = _frag_off; | ||
2107 | return hp->nexthdr; | ||
2108 | } | ||
2135 | return -1; | 2109 | return -1; |
2110 | } | ||
2136 | hdrlen = 8; | 2111 | hdrlen = 8; |
2137 | } else if (nexthdr == NEXTHDR_AUTH) | 2112 | } else if (nexthdr == NEXTHDR_AUTH) |
2138 | hdrlen = (hp->hdrlen + 2) << 2; | 2113 | hdrlen = (hp->hdrlen + 2) << 2; |
@@ -2145,7 +2120,7 @@ int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, u8 target) | |||
2145 | } | 2120 | } |
2146 | 2121 | ||
2147 | *offset = start; | 2122 | *offset = start; |
2148 | return 0; | 2123 | return nexthdr; |
2149 | } | 2124 | } |
2150 | 2125 | ||
2151 | EXPORT_SYMBOL(ip6t_register_table); | 2126 | EXPORT_SYMBOL(ip6t_register_table); |
@@ -2157,6 +2132,7 @@ EXPORT_SYMBOL(ip6t_register_target); | |||
2157 | EXPORT_SYMBOL(ip6t_unregister_target); | 2132 | EXPORT_SYMBOL(ip6t_unregister_target); |
2158 | EXPORT_SYMBOL(ip6t_ext_hdr); | 2133 | EXPORT_SYMBOL(ip6t_ext_hdr); |
2159 | EXPORT_SYMBOL(ipv6_find_hdr); | 2134 | EXPORT_SYMBOL(ipv6_find_hdr); |
2135 | EXPORT_SYMBOL(ip6_masked_addrcmp); | ||
2160 | 2136 | ||
2161 | module_init(init); | 2137 | module_init(init); |
2162 | module_exit(fini); | 2138 | module_exit(fini); |
diff --git a/net/ipv6/netfilter/ip6t_ah.c b/net/ipv6/netfilter/ip6t_ah.c index 268918d5deea..f5c1a7ff4a1f 100644 --- a/net/ipv6/netfilter/ip6t_ah.c +++ b/net/ipv6/netfilter/ip6t_ah.c | |||
@@ -54,7 +54,7 @@ match(const struct sk_buff *skb, | |||
54 | unsigned int ptr; | 54 | unsigned int ptr; |
55 | unsigned int hdrlen = 0; | 55 | unsigned int hdrlen = 0; |
56 | 56 | ||
57 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_AUTH) < 0) | 57 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_AUTH, NULL) < 0) |
58 | return 0; | 58 | return 0; |
59 | 59 | ||
60 | ah = skb_header_pointer(skb, ptr, sizeof(_ah), &_ah); | 60 | ah = skb_header_pointer(skb, ptr, sizeof(_ah), &_ah); |
diff --git a/net/ipv6/netfilter/ip6t_dst.c b/net/ipv6/netfilter/ip6t_dst.c index c450a635e54b..48cf5f9efc95 100644 --- a/net/ipv6/netfilter/ip6t_dst.c +++ b/net/ipv6/netfilter/ip6t_dst.c | |||
@@ -71,9 +71,9 @@ match(const struct sk_buff *skb, | |||
71 | unsigned int optlen; | 71 | unsigned int optlen; |
72 | 72 | ||
73 | #if HOPBYHOP | 73 | #if HOPBYHOP |
74 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP) < 0) | 74 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP, NULL) < 0) |
75 | #else | 75 | #else |
76 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST) < 0) | 76 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST, NULL) < 0) |
77 | #endif | 77 | #endif |
78 | return 0; | 78 | return 0; |
79 | 79 | ||
diff --git a/net/ipv6/netfilter/ip6t_esp.c b/net/ipv6/netfilter/ip6t_esp.c index 65937de1b58c..e1828f6d0a40 100644 --- a/net/ipv6/netfilter/ip6t_esp.c +++ b/net/ipv6/netfilter/ip6t_esp.c | |||
@@ -56,7 +56,7 @@ match(const struct sk_buff *skb, | |||
56 | /* Make sure this isn't an evil packet */ | 56 | /* Make sure this isn't an evil packet */ |
57 | /*DEBUGP("ipv6_esp entered \n");*/ | 57 | /*DEBUGP("ipv6_esp entered \n");*/ |
58 | 58 | ||
59 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_ESP) < 0) | 59 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_ESP, NULL) < 0) |
60 | return 0; | 60 | return 0; |
61 | 61 | ||
62 | eh = skb_header_pointer(skb, ptr, sizeof(_esp), &_esp); | 62 | eh = skb_header_pointer(skb, ptr, sizeof(_esp), &_esp); |
diff --git a/net/ipv6/netfilter/ip6t_frag.c b/net/ipv6/netfilter/ip6t_frag.c index 085d5f8eea29..d1549b268669 100644 --- a/net/ipv6/netfilter/ip6t_frag.c +++ b/net/ipv6/netfilter/ip6t_frag.c | |||
@@ -52,7 +52,7 @@ match(const struct sk_buff *skb, | |||
52 | const struct ip6t_frag *fraginfo = matchinfo; | 52 | const struct ip6t_frag *fraginfo = matchinfo; |
53 | unsigned int ptr; | 53 | unsigned int ptr; |
54 | 54 | ||
55 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT) < 0) | 55 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_FRAGMENT, NULL) < 0) |
56 | return 0; | 56 | return 0; |
57 | 57 | ||
58 | fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag); | 58 | fh = skb_header_pointer(skb, ptr, sizeof(_frag), &_frag); |
diff --git a/net/ipv6/netfilter/ip6t_hbh.c b/net/ipv6/netfilter/ip6t_hbh.c index 1d09485111d0..e3bc8e2700e7 100644 --- a/net/ipv6/netfilter/ip6t_hbh.c +++ b/net/ipv6/netfilter/ip6t_hbh.c | |||
@@ -71,9 +71,9 @@ match(const struct sk_buff *skb, | |||
71 | unsigned int optlen; | 71 | unsigned int optlen; |
72 | 72 | ||
73 | #if HOPBYHOP | 73 | #if HOPBYHOP |
74 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP) < 0) | 74 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_HOP, NULL) < 0) |
75 | #else | 75 | #else |
76 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST) < 0) | 76 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_DEST, NULL) < 0) |
77 | #endif | 77 | #endif |
78 | return 0; | 78 | return 0; |
79 | 79 | ||
diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c index beb2fd5cebbb..c1e770e45543 100644 --- a/net/ipv6/netfilter/ip6t_rt.c +++ b/net/ipv6/netfilter/ip6t_rt.c | |||
@@ -58,7 +58,7 @@ match(const struct sk_buff *skb, | |||
58 | unsigned int ret = 0; | 58 | unsigned int ret = 0; |
59 | struct in6_addr *ap, _addr; | 59 | struct in6_addr *ap, _addr; |
60 | 60 | ||
61 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING) < 0) | 61 | if (ipv6_find_hdr(skb, &ptr, NEXTHDR_ROUTING, NULL) < 0) |
62 | return 0; | 62 | return 0; |
63 | 63 | ||
64 | rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route); | 64 | rh = skb_header_pointer(skb, ptr, sizeof(_route), &_route); |
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index 753a3ae8502b..704fbbe74874 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | |||
@@ -401,6 +401,48 @@ static ctl_table nf_ct_net_table[] = { | |||
401 | }; | 401 | }; |
402 | #endif | 402 | #endif |
403 | 403 | ||
404 | #if defined(CONFIG_NF_CT_NETLINK) || \ | ||
405 | defined(CONFIG_NF_CT_NETLINK_MODULE) | ||
406 | |||
407 | #include <linux/netfilter/nfnetlink.h> | ||
408 | #include <linux/netfilter/nfnetlink_conntrack.h> | ||
409 | |||
410 | static int ipv6_tuple_to_nfattr(struct sk_buff *skb, | ||
411 | const struct nf_conntrack_tuple *tuple) | ||
412 | { | ||
413 | NFA_PUT(skb, CTA_IP_V6_SRC, sizeof(u_int32_t) * 4, | ||
414 | &tuple->src.u3.ip6); | ||
415 | NFA_PUT(skb, CTA_IP_V6_DST, sizeof(u_int32_t) * 4, | ||
416 | &tuple->dst.u3.ip6); | ||
417 | return 0; | ||
418 | |||
419 | nfattr_failure: | ||
420 | return -1; | ||
421 | } | ||
422 | |||
423 | static const size_t cta_min_ip[CTA_IP_MAX] = { | ||
424 | [CTA_IP_V6_SRC-1] = sizeof(u_int32_t)*4, | ||
425 | [CTA_IP_V6_DST-1] = sizeof(u_int32_t)*4, | ||
426 | }; | ||
427 | |||
428 | static int ipv6_nfattr_to_tuple(struct nfattr *tb[], | ||
429 | struct nf_conntrack_tuple *t) | ||
430 | { | ||
431 | if (!tb[CTA_IP_V6_SRC-1] || !tb[CTA_IP_V6_DST-1]) | ||
432 | return -EINVAL; | ||
433 | |||
434 | if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip)) | ||
435 | return -EINVAL; | ||
436 | |||
437 | memcpy(&t->src.u3.ip6, NFA_DATA(tb[CTA_IP_V6_SRC-1]), | ||
438 | sizeof(u_int32_t) * 4); | ||
439 | memcpy(&t->dst.u3.ip6, NFA_DATA(tb[CTA_IP_V6_DST-1]), | ||
440 | sizeof(u_int32_t) * 4); | ||
441 | |||
442 | return 0; | ||
443 | } | ||
444 | #endif | ||
445 | |||
404 | struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 = { | 446 | struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 = { |
405 | .l3proto = PF_INET6, | 447 | .l3proto = PF_INET6, |
406 | .name = "ipv6", | 448 | .name = "ipv6", |
@@ -409,6 +451,11 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 = { | |||
409 | .print_tuple = ipv6_print_tuple, | 451 | .print_tuple = ipv6_print_tuple, |
410 | .print_conntrack = ipv6_print_conntrack, | 452 | .print_conntrack = ipv6_print_conntrack, |
411 | .prepare = ipv6_prepare, | 453 | .prepare = ipv6_prepare, |
454 | #if defined(CONFIG_NF_CT_NETLINK) || \ | ||
455 | defined(CONFIG_NF_CT_NETLINK_MODULE) | ||
456 | .tuple_to_nfattr = ipv6_tuple_to_nfattr, | ||
457 | .nfattr_to_tuple = ipv6_nfattr_to_tuple, | ||
458 | #endif | ||
412 | .get_features = ipv6_get_features, | 459 | .get_features = ipv6_get_features, |
413 | .me = THIS_MODULE, | 460 | .me = THIS_MODULE, |
414 | }; | 461 | }; |
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index a7e03cfacd06..09945c333055 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c | |||
@@ -57,17 +57,17 @@ static int icmpv6_pkt_to_tuple(const struct sk_buff *skb, | |||
57 | return 1; | 57 | return 1; |
58 | } | 58 | } |
59 | 59 | ||
60 | /* Add 1; spaces filled with 0. */ | ||
61 | static u_int8_t invmap[] = { | ||
62 | [ICMPV6_ECHO_REQUEST - 128] = ICMPV6_ECHO_REPLY + 1, | ||
63 | [ICMPV6_ECHO_REPLY - 128] = ICMPV6_ECHO_REQUEST + 1, | ||
64 | [ICMPV6_NI_QUERY - 128] = ICMPV6_NI_QUERY + 1, | ||
65 | [ICMPV6_NI_REPLY - 128] = ICMPV6_NI_REPLY +1 | ||
66 | }; | ||
67 | |||
60 | static int icmpv6_invert_tuple(struct nf_conntrack_tuple *tuple, | 68 | static int icmpv6_invert_tuple(struct nf_conntrack_tuple *tuple, |
61 | const struct nf_conntrack_tuple *orig) | 69 | const struct nf_conntrack_tuple *orig) |
62 | { | 70 | { |
63 | /* Add 1; spaces filled with 0. */ | ||
64 | static u_int8_t invmap[] = { | ||
65 | [ICMPV6_ECHO_REQUEST - 128] = ICMPV6_ECHO_REPLY + 1, | ||
66 | [ICMPV6_ECHO_REPLY - 128] = ICMPV6_ECHO_REQUEST + 1, | ||
67 | [ICMPV6_NI_QUERY - 128] = ICMPV6_NI_QUERY + 1, | ||
68 | [ICMPV6_NI_REPLY - 128] = ICMPV6_NI_REPLY +1 | ||
69 | }; | ||
70 | |||
71 | int type = orig->dst.u.icmp.type - 128; | 71 | int type = orig->dst.u.icmp.type - 128; |
72 | if (type < 0 || type >= sizeof(invmap) || !invmap[type]) | 72 | if (type < 0 || type >= sizeof(invmap) || !invmap[type]) |
73 | return 0; | 73 | return 0; |
@@ -185,7 +185,7 @@ icmpv6_error_message(struct sk_buff *skb, | |||
185 | return -NF_ACCEPT; | 185 | return -NF_ACCEPT; |
186 | } | 186 | } |
187 | 187 | ||
188 | inproto = nf_ct_find_proto(PF_INET6, inprotonum); | 188 | inproto = __nf_ct_proto_find(PF_INET6, inprotonum); |
189 | 189 | ||
190 | /* Are they talking about one of our connections? */ | 190 | /* Are they talking about one of our connections? */ |
191 | if (!nf_ct_get_tuple(skb, inip6off, inprotoff, PF_INET6, inprotonum, | 191 | if (!nf_ct_get_tuple(skb, inip6off, inprotoff, PF_INET6, inprotonum, |
@@ -255,6 +255,60 @@ skipped: | |||
255 | return icmpv6_error_message(skb, dataoff, ctinfo, hooknum); | 255 | return icmpv6_error_message(skb, dataoff, ctinfo, hooknum); |
256 | } | 256 | } |
257 | 257 | ||
258 | #if defined(CONFIG_NF_CT_NETLINK) || \ | ||
259 | defined(CONFIG_NF_CT_NETLINK_MODULE) | ||
260 | |||
261 | #include <linux/netfilter/nfnetlink.h> | ||
262 | #include <linux/netfilter/nfnetlink_conntrack.h> | ||
263 | static int icmpv6_tuple_to_nfattr(struct sk_buff *skb, | ||
264 | const struct nf_conntrack_tuple *t) | ||
265 | { | ||
266 | NFA_PUT(skb, CTA_PROTO_ICMPV6_ID, sizeof(u_int16_t), | ||
267 | &t->src.u.icmp.id); | ||
268 | NFA_PUT(skb, CTA_PROTO_ICMPV6_TYPE, sizeof(u_int8_t), | ||
269 | &t->dst.u.icmp.type); | ||
270 | NFA_PUT(skb, CTA_PROTO_ICMPV6_CODE, sizeof(u_int8_t), | ||
271 | &t->dst.u.icmp.code); | ||
272 | |||
273 | return 0; | ||
274 | |||
275 | nfattr_failure: | ||
276 | return -1; | ||
277 | } | ||
278 | |||
279 | static const size_t cta_min_proto[CTA_PROTO_MAX] = { | ||
280 | [CTA_PROTO_ICMPV6_TYPE-1] = sizeof(u_int8_t), | ||
281 | [CTA_PROTO_ICMPV6_CODE-1] = sizeof(u_int8_t), | ||
282 | [CTA_PROTO_ICMPV6_ID-1] = sizeof(u_int16_t) | ||
283 | }; | ||
284 | |||
285 | static int icmpv6_nfattr_to_tuple(struct nfattr *tb[], | ||
286 | struct nf_conntrack_tuple *tuple) | ||
287 | { | ||
288 | if (!tb[CTA_PROTO_ICMPV6_TYPE-1] | ||
289 | || !tb[CTA_PROTO_ICMPV6_CODE-1] | ||
290 | || !tb[CTA_PROTO_ICMPV6_ID-1]) | ||
291 | return -EINVAL; | ||
292 | |||
293 | if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto)) | ||
294 | return -EINVAL; | ||
295 | |||
296 | tuple->dst.u.icmp.type = | ||
297 | *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMPV6_TYPE-1]); | ||
298 | tuple->dst.u.icmp.code = | ||
299 | *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMPV6_CODE-1]); | ||
300 | tuple->src.u.icmp.id = | ||
301 | *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_ICMPV6_ID-1]); | ||
302 | |||
303 | if (tuple->dst.u.icmp.type < 128 | ||
304 | || tuple->dst.u.icmp.type - 128 >= sizeof(invmap) | ||
305 | || !invmap[tuple->dst.u.icmp.type - 128]) | ||
306 | return -EINVAL; | ||
307 | |||
308 | return 0; | ||
309 | } | ||
310 | #endif | ||
311 | |||
258 | struct nf_conntrack_protocol nf_conntrack_protocol_icmpv6 = | 312 | struct nf_conntrack_protocol nf_conntrack_protocol_icmpv6 = |
259 | { | 313 | { |
260 | .l3proto = PF_INET6, | 314 | .l3proto = PF_INET6, |
@@ -267,6 +321,11 @@ struct nf_conntrack_protocol nf_conntrack_protocol_icmpv6 = | |||
267 | .packet = icmpv6_packet, | 321 | .packet = icmpv6_packet, |
268 | .new = icmpv6_new, | 322 | .new = icmpv6_new, |
269 | .error = icmpv6_error, | 323 | .error = icmpv6_error, |
324 | #if defined(CONFIG_NF_CT_NETLINK) || \ | ||
325 | defined(CONFIG_NF_CT_NETLINK_MODULE) | ||
326 | .tuple_to_nfattr = icmpv6_tuple_to_nfattr, | ||
327 | .nfattr_to_tuple = icmpv6_nfattr_to_tuple, | ||
328 | #endif | ||
270 | }; | 329 | }; |
271 | 330 | ||
272 | EXPORT_SYMBOL(nf_conntrack_protocol_icmpv6); | 331 | EXPORT_SYMBOL(nf_conntrack_protocol_icmpv6); |
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index c3123c9e1a8e..577d49732b0f 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <asm/uaccess.h> | 33 | #include <asm/uaccess.h> |
34 | #include <linux/init.h> | 34 | #include <linux/init.h> |
35 | #include <linux/netfilter_ipv4.h> | 35 | #include <linux/netfilter_ipv4.h> |
36 | #include <linux/if_ether.h> | ||
36 | 37 | ||
37 | #include <net/sock.h> | 38 | #include <net/sock.h> |
38 | #include <net/snmp.h> | 39 | #include <net/snmp.h> |
@@ -720,7 +721,7 @@ static void ipip6_tunnel_setup(struct net_device *dev) | |||
720 | 721 | ||
721 | dev->type = ARPHRD_SIT; | 722 | dev->type = ARPHRD_SIT; |
722 | dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr); | 723 | dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr); |
723 | dev->mtu = 1500 - sizeof(struct iphdr); | 724 | dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr); |
724 | dev->flags = IFF_NOARP; | 725 | dev->flags = IFF_NOARP; |
725 | dev->iflink = 0; | 726 | dev->iflink = 0; |
726 | dev->addr_len = 4; | 727 | dev->addr_len = 4; |
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 794c41d19b28..7d55f9cbd853 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig | |||
@@ -95,4 +95,11 @@ config NF_CONNTRACK_FTP | |||
95 | 95 | ||
96 | To compile it as a module, choose M here. If unsure, say N. | 96 | To compile it as a module, choose M here. If unsure, say N. |
97 | 97 | ||
98 | config NF_CT_NETLINK | ||
99 | tristate 'Connection tracking netlink interface (EXPERIMENTAL)' | ||
100 | depends on EXPERIMENTAL && NF_CONNTRACK && NETFILTER_NETLINK | ||
101 | depends on NF_CONNTRACK!=y || NETFILTER_NETLINK!=m | ||
102 | help | ||
103 | This option enables support for a netlink-based userspace interface | ||
104 | |||
98 | endmenu | 105 | endmenu |
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile index 55f019ad2c08..cb2183145c37 100644 --- a/net/netfilter/Makefile +++ b/net/netfilter/Makefile | |||
@@ -13,3 +13,6 @@ obj-$(CONFIG_NF_CONNTRACK_FTP) += nf_conntrack_ftp.o | |||
13 | 13 | ||
14 | # SCTP protocol connection tracking | 14 | # SCTP protocol connection tracking |
15 | obj-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o | 15 | obj-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o |
16 | |||
17 | # netlink interface for nf_conntrack | ||
18 | obj-$(CONFIG_NF_CT_NETLINK) += nf_conntrack_netlink.o | ||
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index a7c7b490cf22..62bb509f05d4 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c | |||
@@ -82,6 +82,8 @@ unsigned int nf_ct_log_invalid; | |||
82 | static LIST_HEAD(unconfirmed); | 82 | static LIST_HEAD(unconfirmed); |
83 | static int nf_conntrack_vmalloc; | 83 | static int nf_conntrack_vmalloc; |
84 | 84 | ||
85 | static unsigned int nf_conntrack_next_id = 1; | ||
86 | static unsigned int nf_conntrack_expect_next_id = 1; | ||
85 | #ifdef CONFIG_NF_CONNTRACK_EVENTS | 87 | #ifdef CONFIG_NF_CONNTRACK_EVENTS |
86 | struct notifier_block *nf_conntrack_chain; | 88 | struct notifier_block *nf_conntrack_chain; |
87 | struct notifier_block *nf_conntrack_expect_chain; | 89 | struct notifier_block *nf_conntrack_expect_chain; |
@@ -184,7 +186,7 @@ DECLARE_MUTEX(nf_ct_cache_mutex); | |||
184 | 186 | ||
185 | extern struct nf_conntrack_protocol nf_conntrack_generic_protocol; | 187 | extern struct nf_conntrack_protocol nf_conntrack_generic_protocol; |
186 | struct nf_conntrack_protocol * | 188 | struct nf_conntrack_protocol * |
187 | nf_ct_find_proto(u_int16_t l3proto, u_int8_t protocol) | 189 | __nf_ct_proto_find(u_int16_t l3proto, u_int8_t protocol) |
188 | { | 190 | { |
189 | if (unlikely(nf_ct_protos[l3proto] == NULL)) | 191 | if (unlikely(nf_ct_protos[l3proto] == NULL)) |
190 | return &nf_conntrack_generic_protocol; | 192 | return &nf_conntrack_generic_protocol; |
@@ -192,6 +194,50 @@ nf_ct_find_proto(u_int16_t l3proto, u_int8_t protocol) | |||
192 | return nf_ct_protos[l3proto][protocol]; | 194 | return nf_ct_protos[l3proto][protocol]; |
193 | } | 195 | } |
194 | 196 | ||
197 | /* this is guaranteed to always return a valid protocol helper, since | ||
198 | * it falls back to generic_protocol */ | ||
199 | struct nf_conntrack_protocol * | ||
200 | nf_ct_proto_find_get(u_int16_t l3proto, u_int8_t protocol) | ||
201 | { | ||
202 | struct nf_conntrack_protocol *p; | ||
203 | |||
204 | preempt_disable(); | ||
205 | p = __nf_ct_proto_find(l3proto, protocol); | ||
206 | if (p) { | ||
207 | if (!try_module_get(p->me)) | ||
208 | p = &nf_conntrack_generic_protocol; | ||
209 | } | ||
210 | preempt_enable(); | ||
211 | |||
212 | return p; | ||
213 | } | ||
214 | |||
215 | void nf_ct_proto_put(struct nf_conntrack_protocol *p) | ||
216 | { | ||
217 | module_put(p->me); | ||
218 | } | ||
219 | |||
220 | struct nf_conntrack_l3proto * | ||
221 | nf_ct_l3proto_find_get(u_int16_t l3proto) | ||
222 | { | ||
223 | struct nf_conntrack_l3proto *p; | ||
224 | |||
225 | preempt_disable(); | ||
226 | p = __nf_ct_l3proto_find(l3proto); | ||
227 | if (p) { | ||
228 | if (!try_module_get(p->me)) | ||
229 | p = &nf_conntrack_generic_l3proto; | ||
230 | } | ||
231 | preempt_enable(); | ||
232 | |||
233 | return p; | ||
234 | } | ||
235 | |||
236 | void nf_ct_l3proto_put(struct nf_conntrack_l3proto *p) | ||
237 | { | ||
238 | module_put(p->me); | ||
239 | } | ||
240 | |||
195 | static int nf_conntrack_hash_rnd_initted; | 241 | static int nf_conntrack_hash_rnd_initted; |
196 | static unsigned int nf_conntrack_hash_rnd; | 242 | static unsigned int nf_conntrack_hash_rnd; |
197 | 243 | ||
@@ -384,7 +430,7 @@ nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse, | |||
384 | } | 430 | } |
385 | 431 | ||
386 | /* nf_conntrack_expect helper functions */ | 432 | /* nf_conntrack_expect helper functions */ |
387 | static void nf_ct_unlink_expect(struct nf_conntrack_expect *exp) | 433 | void nf_ct_unlink_expect(struct nf_conntrack_expect *exp) |
388 | { | 434 | { |
389 | ASSERT_WRITE_LOCK(&nf_conntrack_lock); | 435 | ASSERT_WRITE_LOCK(&nf_conntrack_lock); |
390 | NF_CT_ASSERT(!timer_pending(&exp->timeout)); | 436 | NF_CT_ASSERT(!timer_pending(&exp->timeout)); |
@@ -404,6 +450,33 @@ static void expectation_timed_out(unsigned long ul_expect) | |||
404 | nf_conntrack_expect_put(exp); | 450 | nf_conntrack_expect_put(exp); |
405 | } | 451 | } |
406 | 452 | ||
453 | struct nf_conntrack_expect * | ||
454 | __nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple) | ||
455 | { | ||
456 | struct nf_conntrack_expect *i; | ||
457 | |||
458 | list_for_each_entry(i, &nf_conntrack_expect_list, list) { | ||
459 | if (nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)) { | ||
460 | atomic_inc(&i->use); | ||
461 | return i; | ||
462 | } | ||
463 | } | ||
464 | return NULL; | ||
465 | } | ||
466 | |||
467 | /* Just find a expectation corresponding to a tuple. */ | ||
468 | struct nf_conntrack_expect * | ||
469 | nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple) | ||
470 | { | ||
471 | struct nf_conntrack_expect *i; | ||
472 | |||
473 | read_lock_bh(&nf_conntrack_lock); | ||
474 | i = __nf_conntrack_expect_find(tuple); | ||
475 | read_unlock_bh(&nf_conntrack_lock); | ||
476 | |||
477 | return i; | ||
478 | } | ||
479 | |||
407 | /* If an expectation for this connection is found, it gets delete from | 480 | /* If an expectation for this connection is found, it gets delete from |
408 | * global list then returned. */ | 481 | * global list then returned. */ |
409 | static struct nf_conntrack_expect * | 482 | static struct nf_conntrack_expect * |
@@ -432,7 +505,7 @@ find_expectation(const struct nf_conntrack_tuple *tuple) | |||
432 | } | 505 | } |
433 | 506 | ||
434 | /* delete all expectations for this conntrack */ | 507 | /* delete all expectations for this conntrack */ |
435 | static void remove_expectations(struct nf_conn *ct) | 508 | void nf_ct_remove_expectations(struct nf_conn *ct) |
436 | { | 509 | { |
437 | struct nf_conntrack_expect *i, *tmp; | 510 | struct nf_conntrack_expect *i, *tmp; |
438 | 511 | ||
@@ -462,7 +535,7 @@ clean_from_lists(struct nf_conn *ct) | |||
462 | LIST_DELETE(&nf_conntrack_hash[hr], &ct->tuplehash[IP_CT_DIR_REPLY]); | 535 | LIST_DELETE(&nf_conntrack_hash[hr], &ct->tuplehash[IP_CT_DIR_REPLY]); |
463 | 536 | ||
464 | /* Destroy all pending expectations */ | 537 | /* Destroy all pending expectations */ |
465 | remove_expectations(ct); | 538 | nf_ct_remove_expectations(ct); |
466 | } | 539 | } |
467 | 540 | ||
468 | static void | 541 | static void |
@@ -482,12 +555,11 @@ destroy_conntrack(struct nf_conntrack *nfct) | |||
482 | /* To make sure we don't get any weird locking issues here: | 555 | /* To make sure we don't get any weird locking issues here: |
483 | * destroy_conntrack() MUST NOT be called with a write lock | 556 | * destroy_conntrack() MUST NOT be called with a write lock |
484 | * to nf_conntrack_lock!!! -HW */ | 557 | * to nf_conntrack_lock!!! -HW */ |
485 | l3proto = nf_ct_find_l3proto(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num); | 558 | l3proto = __nf_ct_l3proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num); |
486 | if (l3proto && l3proto->destroy) | 559 | if (l3proto && l3proto->destroy) |
487 | l3proto->destroy(ct); | 560 | l3proto->destroy(ct); |
488 | 561 | ||
489 | proto = nf_ct_find_proto(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num, | 562 | proto = __nf_ct_proto_find(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.l3num, ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum); |
490 | ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.protonum); | ||
491 | if (proto && proto->destroy) | 563 | if (proto && proto->destroy) |
492 | proto->destroy(ct); | 564 | proto->destroy(ct); |
493 | 565 | ||
@@ -499,7 +571,7 @@ destroy_conntrack(struct nf_conntrack *nfct) | |||
499 | * except TFTP can create an expectation on the first packet, | 571 | * except TFTP can create an expectation on the first packet, |
500 | * before connection is in the list, so we need to clean here, | 572 | * before connection is in the list, so we need to clean here, |
501 | * too. */ | 573 | * too. */ |
502 | remove_expectations(ct); | 574 | nf_ct_remove_expectations(ct); |
503 | 575 | ||
504 | /* We overload first tuple to link into unconfirmed list. */ | 576 | /* We overload first tuple to link into unconfirmed list. */ |
505 | if (!nf_ct_is_confirmed(ct)) { | 577 | if (!nf_ct_is_confirmed(ct)) { |
@@ -540,7 +612,7 @@ conntrack_tuple_cmp(const struct nf_conntrack_tuple_hash *i, | |||
540 | && nf_ct_tuple_equal(tuple, &i->tuple); | 612 | && nf_ct_tuple_equal(tuple, &i->tuple); |
541 | } | 613 | } |
542 | 614 | ||
543 | static struct nf_conntrack_tuple_hash * | 615 | struct nf_conntrack_tuple_hash * |
544 | __nf_conntrack_find(const struct nf_conntrack_tuple *tuple, | 616 | __nf_conntrack_find(const struct nf_conntrack_tuple *tuple, |
545 | const struct nf_conn *ignored_conntrack) | 617 | const struct nf_conn *ignored_conntrack) |
546 | { | 618 | { |
@@ -575,6 +647,29 @@ nf_conntrack_find_get(const struct nf_conntrack_tuple *tuple, | |||
575 | return h; | 647 | return h; |
576 | } | 648 | } |
577 | 649 | ||
650 | static void __nf_conntrack_hash_insert(struct nf_conn *ct, | ||
651 | unsigned int hash, | ||
652 | unsigned int repl_hash) | ||
653 | { | ||
654 | ct->id = ++nf_conntrack_next_id; | ||
655 | list_prepend(&nf_conntrack_hash[hash], | ||
656 | &ct->tuplehash[IP_CT_DIR_ORIGINAL].list); | ||
657 | list_prepend(&nf_conntrack_hash[repl_hash], | ||
658 | &ct->tuplehash[IP_CT_DIR_REPLY].list); | ||
659 | } | ||
660 | |||
661 | void nf_conntrack_hash_insert(struct nf_conn *ct) | ||
662 | { | ||
663 | unsigned int hash, repl_hash; | ||
664 | |||
665 | hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); | ||
666 | repl_hash = hash_conntrack(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); | ||
667 | |||
668 | write_lock_bh(&nf_conntrack_lock); | ||
669 | __nf_conntrack_hash_insert(ct, hash, repl_hash); | ||
670 | write_unlock_bh(&nf_conntrack_lock); | ||
671 | } | ||
672 | |||
578 | /* Confirm a connection given skb; places it in hash table */ | 673 | /* Confirm a connection given skb; places it in hash table */ |
579 | int | 674 | int |
580 | __nf_conntrack_confirm(struct sk_buff **pskb) | 675 | __nf_conntrack_confirm(struct sk_buff **pskb) |
@@ -621,10 +716,7 @@ __nf_conntrack_confirm(struct sk_buff **pskb) | |||
621 | /* Remove from unconfirmed list */ | 716 | /* Remove from unconfirmed list */ |
622 | list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list); | 717 | list_del(&ct->tuplehash[IP_CT_DIR_ORIGINAL].list); |
623 | 718 | ||
624 | list_prepend(&nf_conntrack_hash[hash], | 719 | __nf_conntrack_hash_insert(ct, hash, repl_hash); |
625 | &ct->tuplehash[IP_CT_DIR_ORIGINAL]); | ||
626 | list_prepend(&nf_conntrack_hash[repl_hash], | ||
627 | &ct->tuplehash[IP_CT_DIR_REPLY]); | ||
628 | /* Timer relative to confirmation time, not original | 720 | /* Timer relative to confirmation time, not original |
629 | setting time, otherwise we'd get timer wrap in | 721 | setting time, otherwise we'd get timer wrap in |
630 | weird delay cases. */ | 722 | weird delay cases. */ |
@@ -708,13 +800,41 @@ static inline int helper_cmp(const struct nf_conntrack_helper *i, | |||
708 | } | 800 | } |
709 | 801 | ||
710 | static struct nf_conntrack_helper * | 802 | static struct nf_conntrack_helper * |
711 | nf_ct_find_helper(const struct nf_conntrack_tuple *tuple) | 803 | __nf_ct_helper_find(const struct nf_conntrack_tuple *tuple) |
712 | { | 804 | { |
713 | return LIST_FIND(&helpers, helper_cmp, | 805 | return LIST_FIND(&helpers, helper_cmp, |
714 | struct nf_conntrack_helper *, | 806 | struct nf_conntrack_helper *, |
715 | tuple); | 807 | tuple); |
716 | } | 808 | } |
717 | 809 | ||
810 | struct nf_conntrack_helper * | ||
811 | nf_ct_helper_find_get( const struct nf_conntrack_tuple *tuple) | ||
812 | { | ||
813 | struct nf_conntrack_helper *helper; | ||
814 | |||
815 | /* need nf_conntrack_lock to assure that helper exists until | ||
816 | * try_module_get() is called */ | ||
817 | read_lock_bh(&nf_conntrack_lock); | ||
818 | |||
819 | helper = __nf_ct_helper_find(tuple); | ||
820 | if (helper) { | ||
821 | /* need to increase module usage count to assure helper will | ||
822 | * not go away while the caller is e.g. busy putting a | ||
823 | * conntrack in the hash that uses the helper */ | ||
824 | if (!try_module_get(helper->me)) | ||
825 | helper = NULL; | ||
826 | } | ||
827 | |||
828 | read_unlock_bh(&nf_conntrack_lock); | ||
829 | |||
830 | return helper; | ||
831 | } | ||
832 | |||
833 | void nf_ct_helper_put(struct nf_conntrack_helper *helper) | ||
834 | { | ||
835 | module_put(helper->me); | ||
836 | } | ||
837 | |||
718 | static struct nf_conn * | 838 | static struct nf_conn * |
719 | __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig, | 839 | __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig, |
720 | const struct nf_conntrack_tuple *repl, | 840 | const struct nf_conntrack_tuple *repl, |
@@ -744,7 +864,7 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig, | |||
744 | /* find features needed by this conntrack. */ | 864 | /* find features needed by this conntrack. */ |
745 | features = l3proto->get_features(orig); | 865 | features = l3proto->get_features(orig); |
746 | read_lock_bh(&nf_conntrack_lock); | 866 | read_lock_bh(&nf_conntrack_lock); |
747 | if (nf_ct_find_helper(repl) != NULL) | 867 | if (__nf_ct_helper_find(repl) != NULL) |
748 | features |= NF_CT_F_HELP; | 868 | features |= NF_CT_F_HELP; |
749 | read_unlock_bh(&nf_conntrack_lock); | 869 | read_unlock_bh(&nf_conntrack_lock); |
750 | 870 | ||
@@ -794,7 +914,7 @@ struct nf_conn *nf_conntrack_alloc(const struct nf_conntrack_tuple *orig, | |||
794 | { | 914 | { |
795 | struct nf_conntrack_l3proto *l3proto; | 915 | struct nf_conntrack_l3proto *l3proto; |
796 | 916 | ||
797 | l3proto = nf_ct_find_l3proto(orig->src.l3num); | 917 | l3proto = __nf_ct_l3proto_find(orig->src.l3num); |
798 | return __nf_conntrack_alloc(orig, repl, l3proto); | 918 | return __nf_conntrack_alloc(orig, repl, l3proto); |
799 | } | 919 | } |
800 | 920 | ||
@@ -853,7 +973,7 @@ init_conntrack(const struct nf_conntrack_tuple *tuple, | |||
853 | nf_conntrack_get(&conntrack->master->ct_general); | 973 | nf_conntrack_get(&conntrack->master->ct_general); |
854 | NF_CT_STAT_INC(expect_new); | 974 | NF_CT_STAT_INC(expect_new); |
855 | } else { | 975 | } else { |
856 | conntrack->helper = nf_ct_find_helper(&repl_tuple); | 976 | conntrack->helper = __nf_ct_helper_find(&repl_tuple); |
857 | 977 | ||
858 | NF_CT_STAT_INC(new); | 978 | NF_CT_STAT_INC(new); |
859 | } | 979 | } |
@@ -947,13 +1067,13 @@ nf_conntrack_in(int pf, unsigned int hooknum, struct sk_buff **pskb) | |||
947 | return NF_ACCEPT; | 1067 | return NF_ACCEPT; |
948 | } | 1068 | } |
949 | 1069 | ||
950 | l3proto = nf_ct_find_l3proto((u_int16_t)pf); | 1070 | l3proto = __nf_ct_l3proto_find((u_int16_t)pf); |
951 | if ((ret = l3proto->prepare(pskb, hooknum, &dataoff, &protonum)) <= 0) { | 1071 | if ((ret = l3proto->prepare(pskb, hooknum, &dataoff, &protonum)) <= 0) { |
952 | DEBUGP("not prepared to track yet or error occured\n"); | 1072 | DEBUGP("not prepared to track yet or error occured\n"); |
953 | return -ret; | 1073 | return -ret; |
954 | } | 1074 | } |
955 | 1075 | ||
956 | proto = nf_ct_find_proto((u_int16_t)pf, protonum); | 1076 | proto = __nf_ct_proto_find((u_int16_t)pf, protonum); |
957 | 1077 | ||
958 | /* It may be an special packet, error, unclean... | 1078 | /* It may be an special packet, error, unclean... |
959 | * inverse of the return code tells to the netfilter | 1079 | * inverse of the return code tells to the netfilter |
@@ -1002,9 +1122,9 @@ int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse, | |||
1002 | const struct nf_conntrack_tuple *orig) | 1122 | const struct nf_conntrack_tuple *orig) |
1003 | { | 1123 | { |
1004 | return nf_ct_invert_tuple(inverse, orig, | 1124 | return nf_ct_invert_tuple(inverse, orig, |
1005 | nf_ct_find_l3proto(orig->src.l3num), | 1125 | __nf_ct_l3proto_find(orig->src.l3num), |
1006 | nf_ct_find_proto(orig->src.l3num, | 1126 | __nf_ct_proto_find(orig->src.l3num, |
1007 | orig->dst.protonum)); | 1127 | orig->dst.protonum)); |
1008 | } | 1128 | } |
1009 | 1129 | ||
1010 | /* Would two expected things clash? */ | 1130 | /* Would two expected things clash? */ |
@@ -1096,6 +1216,7 @@ static void nf_conntrack_expect_insert(struct nf_conntrack_expect *exp) | |||
1096 | exp->timeout.expires = jiffies + exp->master->helper->timeout * HZ; | 1216 | exp->timeout.expires = jiffies + exp->master->helper->timeout * HZ; |
1097 | add_timer(&exp->timeout); | 1217 | add_timer(&exp->timeout); |
1098 | 1218 | ||
1219 | exp->id = ++nf_conntrack_expect_next_id; | ||
1099 | atomic_inc(&exp->use); | 1220 | atomic_inc(&exp->use); |
1100 | NF_CT_STAT_INC(expect_create); | 1221 | NF_CT_STAT_INC(expect_create); |
1101 | } | 1222 | } |
@@ -1129,6 +1250,7 @@ static inline int refresh_timer(struct nf_conntrack_expect *i) | |||
1129 | int nf_conntrack_expect_related(struct nf_conntrack_expect *expect) | 1250 | int nf_conntrack_expect_related(struct nf_conntrack_expect *expect) |
1130 | { | 1251 | { |
1131 | struct nf_conntrack_expect *i; | 1252 | struct nf_conntrack_expect *i; |
1253 | struct nf_conn *master = expect->master; | ||
1132 | int ret; | 1254 | int ret; |
1133 | 1255 | ||
1134 | DEBUGP("nf_conntrack_expect_related %p\n", related_to); | 1256 | DEBUGP("nf_conntrack_expect_related %p\n", related_to); |
@@ -1149,9 +1271,9 @@ int nf_conntrack_expect_related(struct nf_conntrack_expect *expect) | |||
1149 | } | 1271 | } |
1150 | } | 1272 | } |
1151 | /* Will be over limit? */ | 1273 | /* Will be over limit? */ |
1152 | if (expect->master->helper->max_expected && | 1274 | if (master->helper->max_expected && |
1153 | expect->master->expecting >= expect->master->helper->max_expected) | 1275 | master->expecting >= master->helper->max_expected) |
1154 | evict_oldest_expect(expect->master); | 1276 | evict_oldest_expect(master); |
1155 | 1277 | ||
1156 | nf_conntrack_expect_insert(expect); | 1278 | nf_conntrack_expect_insert(expect); |
1157 | nf_conntrack_expect_event(IPEXP_NEW, expect); | 1279 | nf_conntrack_expect_event(IPEXP_NEW, expect); |
@@ -1175,7 +1297,7 @@ void nf_conntrack_alter_reply(struct nf_conn *conntrack, | |||
1175 | 1297 | ||
1176 | conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply; | 1298 | conntrack->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply; |
1177 | if (!conntrack->master && conntrack->expecting == 0) | 1299 | if (!conntrack->master && conntrack->expecting == 0) |
1178 | conntrack->helper = nf_ct_find_helper(newreply); | 1300 | conntrack->helper = __nf_ct_helper_find(newreply); |
1179 | write_unlock_bh(&nf_conntrack_lock); | 1301 | write_unlock_bh(&nf_conntrack_lock); |
1180 | } | 1302 | } |
1181 | 1303 | ||
@@ -1200,6 +1322,19 @@ int nf_conntrack_helper_register(struct nf_conntrack_helper *me) | |||
1200 | return 0; | 1322 | return 0; |
1201 | } | 1323 | } |
1202 | 1324 | ||
1325 | struct nf_conntrack_helper * | ||
1326 | __nf_conntrack_helper_find_byname(const char *name) | ||
1327 | { | ||
1328 | struct nf_conntrack_helper *h; | ||
1329 | |||
1330 | list_for_each_entry(h, &helpers, list) { | ||
1331 | if (!strcmp(h->name, name)) | ||
1332 | return h; | ||
1333 | } | ||
1334 | |||
1335 | return NULL; | ||
1336 | } | ||
1337 | |||
1203 | static inline int unhelp(struct nf_conntrack_tuple_hash *i, | 1338 | static inline int unhelp(struct nf_conntrack_tuple_hash *i, |
1204 | const struct nf_conntrack_helper *me) | 1339 | const struct nf_conntrack_helper *me) |
1205 | { | 1340 | { |
@@ -1283,6 +1418,51 @@ void __nf_ct_refresh_acct(struct nf_conn *ct, | |||
1283 | nf_conntrack_event_cache(event, skb); | 1418 | nf_conntrack_event_cache(event, skb); |
1284 | } | 1419 | } |
1285 | 1420 | ||
1421 | #if defined(CONFIG_NF_CT_NETLINK) || \ | ||
1422 | defined(CONFIG_NF_CT_NETLINK_MODULE) | ||
1423 | |||
1424 | #include <linux/netfilter/nfnetlink.h> | ||
1425 | #include <linux/netfilter/nfnetlink_conntrack.h> | ||
1426 | |||
1427 | /* Generic function for tcp/udp/sctp/dccp and alike. This needs to be | ||
1428 | * in ip_conntrack_core, since we don't want the protocols to autoload | ||
1429 | * or depend on ctnetlink */ | ||
1430 | int nf_ct_port_tuple_to_nfattr(struct sk_buff *skb, | ||
1431 | const struct nf_conntrack_tuple *tuple) | ||
1432 | { | ||
1433 | NFA_PUT(skb, CTA_PROTO_SRC_PORT, sizeof(u_int16_t), | ||
1434 | &tuple->src.u.tcp.port); | ||
1435 | NFA_PUT(skb, CTA_PROTO_DST_PORT, sizeof(u_int16_t), | ||
1436 | &tuple->dst.u.tcp.port); | ||
1437 | return 0; | ||
1438 | |||
1439 | nfattr_failure: | ||
1440 | return -1; | ||
1441 | } | ||
1442 | |||
1443 | static const size_t cta_min_proto[CTA_PROTO_MAX] = { | ||
1444 | [CTA_PROTO_SRC_PORT-1] = sizeof(u_int16_t), | ||
1445 | [CTA_PROTO_DST_PORT-1] = sizeof(u_int16_t) | ||
1446 | }; | ||
1447 | |||
1448 | int nf_ct_port_nfattr_to_tuple(struct nfattr *tb[], | ||
1449 | struct nf_conntrack_tuple *t) | ||
1450 | { | ||
1451 | if (!tb[CTA_PROTO_SRC_PORT-1] || !tb[CTA_PROTO_DST_PORT-1]) | ||
1452 | return -EINVAL; | ||
1453 | |||
1454 | if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto)) | ||
1455 | return -EINVAL; | ||
1456 | |||
1457 | t->src.u.tcp.port = | ||
1458 | *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_SRC_PORT-1]); | ||
1459 | t->dst.u.tcp.port = | ||
1460 | *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_DST_PORT-1]); | ||
1461 | |||
1462 | return 0; | ||
1463 | } | ||
1464 | #endif | ||
1465 | |||
1286 | /* Used by ipt_REJECT and ip6t_REJECT. */ | 1466 | /* Used by ipt_REJECT and ip6t_REJECT. */ |
1287 | void __nf_conntrack_attach(struct sk_buff *nskb, struct sk_buff *skb) | 1467 | void __nf_conntrack_attach(struct sk_buff *nskb, struct sk_buff *skb) |
1288 | { | 1468 | { |
@@ -1365,6 +1545,11 @@ static void free_conntrack_hash(struct list_head *hash, int vmalloced, int size) | |||
1365 | get_order(sizeof(struct list_head) * size)); | 1545 | get_order(sizeof(struct list_head) * size)); |
1366 | } | 1546 | } |
1367 | 1547 | ||
1548 | void nf_conntrack_flush() | ||
1549 | { | ||
1550 | nf_ct_iterate_cleanup(kill_all, NULL); | ||
1551 | } | ||
1552 | |||
1368 | /* Mishearing the voices in his head, our hero wonders how he's | 1553 | /* Mishearing the voices in his head, our hero wonders how he's |
1369 | supposed to kill the mall. */ | 1554 | supposed to kill the mall. */ |
1370 | void nf_conntrack_cleanup(void) | 1555 | void nf_conntrack_cleanup(void) |
@@ -1378,7 +1563,7 @@ void nf_conntrack_cleanup(void) | |||
1378 | 1563 | ||
1379 | nf_ct_event_cache_flush(); | 1564 | nf_ct_event_cache_flush(); |
1380 | i_see_dead_people: | 1565 | i_see_dead_people: |
1381 | nf_ct_iterate_cleanup(kill_all, NULL); | 1566 | nf_conntrack_flush(); |
1382 | if (atomic_read(&nf_conntrack_count) != 0) { | 1567 | if (atomic_read(&nf_conntrack_count) != 0) { |
1383 | schedule(); | 1568 | schedule(); |
1384 | goto i_see_dead_people; | 1569 | goto i_see_dead_people; |
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c index 65080e269f27..d5a6eaf4a1de 100644 --- a/net/netfilter/nf_conntrack_ftp.c +++ b/net/netfilter/nf_conntrack_ftp.c | |||
@@ -44,7 +44,7 @@ static unsigned int ports_c; | |||
44 | module_param_array(ports, ushort, &ports_c, 0400); | 44 | module_param_array(ports, ushort, &ports_c, 0400); |
45 | 45 | ||
46 | static int loose; | 46 | static int loose; |
47 | module_param(loose, int, 0600); | 47 | module_param(loose, bool, 0600); |
48 | 48 | ||
49 | unsigned int (*nf_nat_ftp_hook)(struct sk_buff **pskb, | 49 | unsigned int (*nf_nat_ftp_hook)(struct sk_buff **pskb, |
50 | enum ip_conntrack_info ctinfo, | 50 | enum ip_conntrack_info ctinfo, |
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c new file mode 100644 index 000000000000..73ab16bc7d40 --- /dev/null +++ b/net/netfilter/nf_conntrack_netlink.c | |||
@@ -0,0 +1,1653 @@ | |||
1 | /* Connection tracking via netlink socket. Allows for user space | ||
2 | * protocol helpers and general trouble making from userspace. | ||
3 | * | ||
4 | * (C) 2001 by Jay Schulist <jschlst@samba.org> | ||
5 | * (C) 2002-2005 by Harald Welte <laforge@gnumonks.org> | ||
6 | * (C) 2003 by Patrick Mchardy <kaber@trash.net> | ||
7 | * (C) 2005 by Pablo Neira Ayuso <pablo@eurodev.net> | ||
8 | * | ||
9 | * I've reworked this stuff to use attributes instead of conntrack | ||
10 | * structures. 5.44 am. I need more tea. --pablo 05/07/11. | ||
11 | * | ||
12 | * Initial connection tracking via netlink development funded and | ||
13 | * generally made possible by Network Robots, Inc. (www.networkrobots.com) | ||
14 | * | ||
15 | * Further development of this code funded by Astaro AG (http://www.astaro.com) | ||
16 | * | ||
17 | * This software may be used and distributed according to the terms | ||
18 | * of the GNU General Public License, incorporated herein by reference. | ||
19 | * | ||
20 | * Derived from ip_conntrack_netlink.c: Port by Pablo Neira Ayuso (05/11/14) | ||
21 | */ | ||
22 | |||
23 | #include <linux/init.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/types.h> | ||
27 | #include <linux/timer.h> | ||
28 | #include <linux/skbuff.h> | ||
29 | #include <linux/errno.h> | ||
30 | #include <linux/netlink.h> | ||
31 | #include <linux/spinlock.h> | ||
32 | #include <linux/notifier.h> | ||
33 | |||
34 | #include <linux/netfilter.h> | ||
35 | #include <net/netfilter/nf_conntrack.h> | ||
36 | #include <net/netfilter/nf_conntrack_core.h> | ||
37 | #include <net/netfilter/nf_conntrack_helper.h> | ||
38 | #include <net/netfilter/nf_conntrack_l3proto.h> | ||
39 | #include <net/netfilter/nf_conntrack_protocol.h> | ||
40 | #include <linux/netfilter_ipv4/ip_nat_protocol.h> | ||
41 | |||
42 | #include <linux/netfilter/nfnetlink.h> | ||
43 | #include <linux/netfilter/nfnetlink_conntrack.h> | ||
44 | |||
45 | MODULE_LICENSE("GPL"); | ||
46 | |||
47 | static char __initdata version[] = "0.92"; | ||
48 | |||
49 | #if 0 | ||
50 | #define DEBUGP printk | ||
51 | #else | ||
52 | #define DEBUGP(format, args...) | ||
53 | #endif | ||
54 | |||
55 | |||
56 | static inline int | ||
57 | ctnetlink_dump_tuples_proto(struct sk_buff *skb, | ||
58 | const struct nf_conntrack_tuple *tuple) | ||
59 | { | ||
60 | struct nf_conntrack_protocol *proto; | ||
61 | int ret = 0; | ||
62 | |||
63 | NFA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum); | ||
64 | |||
65 | /* If no protocol helper is found, this function will return the | ||
66 | * generic protocol helper, so proto won't *ever* be NULL */ | ||
67 | proto = nf_ct_proto_find_get(tuple->src.l3num, tuple->dst.protonum); | ||
68 | if (likely(proto->tuple_to_nfattr)) | ||
69 | ret = proto->tuple_to_nfattr(skb, tuple); | ||
70 | |||
71 | nf_ct_proto_put(proto); | ||
72 | |||
73 | return ret; | ||
74 | |||
75 | nfattr_failure: | ||
76 | return -1; | ||
77 | } | ||
78 | |||
79 | static inline int | ||
80 | ctnetlink_dump_tuples(struct sk_buff *skb, | ||
81 | const struct nf_conntrack_tuple *tuple) | ||
82 | { | ||
83 | struct nfattr *nest_parms; | ||
84 | struct nf_conntrack_l3proto *l3proto; | ||
85 | int ret = 0; | ||
86 | |||
87 | l3proto = nf_ct_l3proto_find_get(tuple->src.l3num); | ||
88 | |||
89 | nest_parms = NFA_NEST(skb, CTA_TUPLE_IP); | ||
90 | if (likely(l3proto->tuple_to_nfattr)) | ||
91 | ret = l3proto->tuple_to_nfattr(skb, tuple); | ||
92 | NFA_NEST_END(skb, nest_parms); | ||
93 | |||
94 | nf_ct_l3proto_put(l3proto); | ||
95 | |||
96 | if (unlikely(ret < 0)) | ||
97 | return ret; | ||
98 | |||
99 | nest_parms = NFA_NEST(skb, CTA_TUPLE_PROTO); | ||
100 | ret = ctnetlink_dump_tuples_proto(skb, tuple); | ||
101 | NFA_NEST_END(skb, nest_parms); | ||
102 | |||
103 | return ret; | ||
104 | |||
105 | nfattr_failure: | ||
106 | return -1; | ||
107 | } | ||
108 | |||
109 | static inline int | ||
110 | ctnetlink_dump_status(struct sk_buff *skb, const struct nf_conn *ct) | ||
111 | { | ||
112 | u_int32_t status = htonl((u_int32_t) ct->status); | ||
113 | NFA_PUT(skb, CTA_STATUS, sizeof(status), &status); | ||
114 | return 0; | ||
115 | |||
116 | nfattr_failure: | ||
117 | return -1; | ||
118 | } | ||
119 | |||
120 | static inline int | ||
121 | ctnetlink_dump_timeout(struct sk_buff *skb, const struct nf_conn *ct) | ||
122 | { | ||
123 | long timeout_l = ct->timeout.expires - jiffies; | ||
124 | u_int32_t timeout; | ||
125 | |||
126 | if (timeout_l < 0) | ||
127 | timeout = 0; | ||
128 | else | ||
129 | timeout = htonl(timeout_l / HZ); | ||
130 | |||
131 | NFA_PUT(skb, CTA_TIMEOUT, sizeof(timeout), &timeout); | ||
132 | return 0; | ||
133 | |||
134 | nfattr_failure: | ||
135 | return -1; | ||
136 | } | ||
137 | |||
138 | static inline int | ||
139 | ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct nf_conn *ct) | ||
140 | { | ||
141 | struct nf_conntrack_protocol *proto = nf_ct_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num, ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); | ||
142 | struct nfattr *nest_proto; | ||
143 | int ret; | ||
144 | |||
145 | if (!proto->to_nfattr) { | ||
146 | nf_ct_proto_put(proto); | ||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | nest_proto = NFA_NEST(skb, CTA_PROTOINFO); | ||
151 | |||
152 | ret = proto->to_nfattr(skb, nest_proto, ct); | ||
153 | |||
154 | nf_ct_proto_put(proto); | ||
155 | |||
156 | NFA_NEST_END(skb, nest_proto); | ||
157 | |||
158 | return ret; | ||
159 | |||
160 | nfattr_failure: | ||
161 | return -1; | ||
162 | } | ||
163 | |||
164 | static inline int | ||
165 | ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct) | ||
166 | { | ||
167 | struct nfattr *nest_helper; | ||
168 | |||
169 | if (!ct->helper) | ||
170 | return 0; | ||
171 | |||
172 | nest_helper = NFA_NEST(skb, CTA_HELP); | ||
173 | NFA_PUT(skb, CTA_HELP_NAME, strlen(ct->helper->name), ct->helper->name); | ||
174 | |||
175 | if (ct->helper->to_nfattr) | ||
176 | ct->helper->to_nfattr(skb, ct); | ||
177 | |||
178 | NFA_NEST_END(skb, nest_helper); | ||
179 | |||
180 | return 0; | ||
181 | |||
182 | nfattr_failure: | ||
183 | return -1; | ||
184 | } | ||
185 | |||
186 | #ifdef CONFIG_NF_CT_ACCT | ||
187 | static inline int | ||
188 | ctnetlink_dump_counters(struct sk_buff *skb, const struct nf_conn *ct, | ||
189 | enum ip_conntrack_dir dir) | ||
190 | { | ||
191 | enum ctattr_type type = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG; | ||
192 | struct nfattr *nest_count = NFA_NEST(skb, type); | ||
193 | u_int32_t tmp; | ||
194 | |||
195 | tmp = htonl(ct->counters[dir].packets); | ||
196 | NFA_PUT(skb, CTA_COUNTERS32_PACKETS, sizeof(u_int32_t), &tmp); | ||
197 | |||
198 | tmp = htonl(ct->counters[dir].bytes); | ||
199 | NFA_PUT(skb, CTA_COUNTERS32_BYTES, sizeof(u_int32_t), &tmp); | ||
200 | |||
201 | NFA_NEST_END(skb, nest_count); | ||
202 | |||
203 | return 0; | ||
204 | |||
205 | nfattr_failure: | ||
206 | return -1; | ||
207 | } | ||
208 | #else | ||
209 | #define ctnetlink_dump_counters(a, b, c) (0) | ||
210 | #endif | ||
211 | |||
212 | #ifdef CONFIG_NF_CONNTRACK_MARK | ||
213 | static inline int | ||
214 | ctnetlink_dump_mark(struct sk_buff *skb, const struct nf_conn *ct) | ||
215 | { | ||
216 | u_int32_t mark = htonl(ct->mark); | ||
217 | |||
218 | NFA_PUT(skb, CTA_MARK, sizeof(u_int32_t), &mark); | ||
219 | return 0; | ||
220 | |||
221 | nfattr_failure: | ||
222 | return -1; | ||
223 | } | ||
224 | #else | ||
225 | #define ctnetlink_dump_mark(a, b) (0) | ||
226 | #endif | ||
227 | |||
228 | static inline int | ||
229 | ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct) | ||
230 | { | ||
231 | u_int32_t id = htonl(ct->id); | ||
232 | NFA_PUT(skb, CTA_ID, sizeof(u_int32_t), &id); | ||
233 | return 0; | ||
234 | |||
235 | nfattr_failure: | ||
236 | return -1; | ||
237 | } | ||
238 | |||
239 | static inline int | ||
240 | ctnetlink_dump_use(struct sk_buff *skb, const struct nf_conn *ct) | ||
241 | { | ||
242 | u_int32_t use = htonl(atomic_read(&ct->ct_general.use)); | ||
243 | |||
244 | NFA_PUT(skb, CTA_USE, sizeof(u_int32_t), &use); | ||
245 | return 0; | ||
246 | |||
247 | nfattr_failure: | ||
248 | return -1; | ||
249 | } | ||
250 | |||
251 | #define tuple(ct, dir) (&(ct)->tuplehash[dir].tuple) | ||
252 | |||
253 | static int | ||
254 | ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq, | ||
255 | int event, int nowait, | ||
256 | const struct nf_conn *ct) | ||
257 | { | ||
258 | struct nlmsghdr *nlh; | ||
259 | struct nfgenmsg *nfmsg; | ||
260 | struct nfattr *nest_parms; | ||
261 | unsigned char *b; | ||
262 | |||
263 | b = skb->tail; | ||
264 | |||
265 | event |= NFNL_SUBSYS_CTNETLINK << 8; | ||
266 | nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg)); | ||
267 | nfmsg = NLMSG_DATA(nlh); | ||
268 | |||
269 | nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0; | ||
270 | nfmsg->nfgen_family = | ||
271 | ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; | ||
272 | nfmsg->version = NFNETLINK_V0; | ||
273 | nfmsg->res_id = 0; | ||
274 | |||
275 | nest_parms = NFA_NEST(skb, CTA_TUPLE_ORIG); | ||
276 | if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0) | ||
277 | goto nfattr_failure; | ||
278 | NFA_NEST_END(skb, nest_parms); | ||
279 | |||
280 | nest_parms = NFA_NEST(skb, CTA_TUPLE_REPLY); | ||
281 | if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0) | ||
282 | goto nfattr_failure; | ||
283 | NFA_NEST_END(skb, nest_parms); | ||
284 | |||
285 | if (ctnetlink_dump_status(skb, ct) < 0 || | ||
286 | ctnetlink_dump_timeout(skb, ct) < 0 || | ||
287 | ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || | ||
288 | ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0 || | ||
289 | ctnetlink_dump_protoinfo(skb, ct) < 0 || | ||
290 | ctnetlink_dump_helpinfo(skb, ct) < 0 || | ||
291 | ctnetlink_dump_mark(skb, ct) < 0 || | ||
292 | ctnetlink_dump_id(skb, ct) < 0 || | ||
293 | ctnetlink_dump_use(skb, ct) < 0) | ||
294 | goto nfattr_failure; | ||
295 | |||
296 | nlh->nlmsg_len = skb->tail - b; | ||
297 | return skb->len; | ||
298 | |||
299 | nlmsg_failure: | ||
300 | nfattr_failure: | ||
301 | skb_trim(skb, b - skb->data); | ||
302 | return -1; | ||
303 | } | ||
304 | |||
305 | #ifdef CONFIG_NF_CONNTRACK_EVENTS | ||
306 | static int ctnetlink_conntrack_event(struct notifier_block *this, | ||
307 | unsigned long events, void *ptr) | ||
308 | { | ||
309 | struct nlmsghdr *nlh; | ||
310 | struct nfgenmsg *nfmsg; | ||
311 | struct nfattr *nest_parms; | ||
312 | struct nf_conn *ct = (struct nf_conn *)ptr; | ||
313 | struct sk_buff *skb; | ||
314 | unsigned int type; | ||
315 | unsigned char *b; | ||
316 | unsigned int flags = 0, group; | ||
317 | |||
318 | /* ignore our fake conntrack entry */ | ||
319 | if (ct == &nf_conntrack_untracked) | ||
320 | return NOTIFY_DONE; | ||
321 | |||
322 | if (events & IPCT_DESTROY) { | ||
323 | type = IPCTNL_MSG_CT_DELETE; | ||
324 | group = NFNLGRP_CONNTRACK_DESTROY; | ||
325 | } else if (events & (IPCT_NEW | IPCT_RELATED)) { | ||
326 | type = IPCTNL_MSG_CT_NEW; | ||
327 | flags = NLM_F_CREATE|NLM_F_EXCL; | ||
328 | /* dump everything */ | ||
329 | events = ~0UL; | ||
330 | group = NFNLGRP_CONNTRACK_NEW; | ||
331 | } else if (events & (IPCT_STATUS | | ||
332 | IPCT_PROTOINFO | | ||
333 | IPCT_HELPER | | ||
334 | IPCT_HELPINFO | | ||
335 | IPCT_NATINFO)) { | ||
336 | type = IPCTNL_MSG_CT_NEW; | ||
337 | group = NFNLGRP_CONNTRACK_UPDATE; | ||
338 | } else | ||
339 | return NOTIFY_DONE; | ||
340 | |||
341 | /* FIXME: Check if there are any listeners before, don't hurt performance */ | ||
342 | |||
343 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); | ||
344 | if (!skb) | ||
345 | return NOTIFY_DONE; | ||
346 | |||
347 | b = skb->tail; | ||
348 | |||
349 | type |= NFNL_SUBSYS_CTNETLINK << 8; | ||
350 | nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg)); | ||
351 | nfmsg = NLMSG_DATA(nlh); | ||
352 | |||
353 | nlh->nlmsg_flags = flags; | ||
354 | nfmsg->nfgen_family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; | ||
355 | nfmsg->version = NFNETLINK_V0; | ||
356 | nfmsg->res_id = 0; | ||
357 | |||
358 | nest_parms = NFA_NEST(skb, CTA_TUPLE_ORIG); | ||
359 | if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_ORIGINAL)) < 0) | ||
360 | goto nfattr_failure; | ||
361 | NFA_NEST_END(skb, nest_parms); | ||
362 | |||
363 | nest_parms = NFA_NEST(skb, CTA_TUPLE_REPLY); | ||
364 | if (ctnetlink_dump_tuples(skb, tuple(ct, IP_CT_DIR_REPLY)) < 0) | ||
365 | goto nfattr_failure; | ||
366 | NFA_NEST_END(skb, nest_parms); | ||
367 | |||
368 | /* NAT stuff is now a status flag */ | ||
369 | if ((events & IPCT_STATUS || events & IPCT_NATINFO) | ||
370 | && ctnetlink_dump_status(skb, ct) < 0) | ||
371 | goto nfattr_failure; | ||
372 | if (events & IPCT_REFRESH | ||
373 | && ctnetlink_dump_timeout(skb, ct) < 0) | ||
374 | goto nfattr_failure; | ||
375 | if (events & IPCT_PROTOINFO | ||
376 | && ctnetlink_dump_protoinfo(skb, ct) < 0) | ||
377 | goto nfattr_failure; | ||
378 | if (events & IPCT_HELPINFO | ||
379 | && ctnetlink_dump_helpinfo(skb, ct) < 0) | ||
380 | goto nfattr_failure; | ||
381 | |||
382 | if (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || | ||
383 | ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0) | ||
384 | goto nfattr_failure; | ||
385 | |||
386 | nlh->nlmsg_len = skb->tail - b; | ||
387 | nfnetlink_send(skb, 0, group, 0); | ||
388 | return NOTIFY_DONE; | ||
389 | |||
390 | nlmsg_failure: | ||
391 | nfattr_failure: | ||
392 | kfree_skb(skb); | ||
393 | return NOTIFY_DONE; | ||
394 | } | ||
395 | #endif /* CONFIG_NF_CONNTRACK_EVENTS */ | ||
396 | |||
397 | static int ctnetlink_done(struct netlink_callback *cb) | ||
398 | { | ||
399 | DEBUGP("entered %s\n", __FUNCTION__); | ||
400 | return 0; | ||
401 | } | ||
402 | |||
403 | #define L3PROTO(ct) ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num | ||
404 | |||
405 | static int | ||
406 | ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) | ||
407 | { | ||
408 | struct nf_conn *ct = NULL; | ||
409 | struct nf_conntrack_tuple_hash *h; | ||
410 | struct list_head *i; | ||
411 | u_int32_t *id = (u_int32_t *) &cb->args[1]; | ||
412 | struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh); | ||
413 | u_int8_t l3proto = nfmsg->nfgen_family; | ||
414 | |||
415 | DEBUGP("entered %s, last bucket=%lu id=%u\n", __FUNCTION__, | ||
416 | cb->args[0], *id); | ||
417 | |||
418 | read_lock_bh(&nf_conntrack_lock); | ||
419 | for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++, *id = 0) { | ||
420 | list_for_each_prev(i, &nf_conntrack_hash[cb->args[0]]) { | ||
421 | h = (struct nf_conntrack_tuple_hash *) i; | ||
422 | if (DIRECTION(h) != IP_CT_DIR_ORIGINAL) | ||
423 | continue; | ||
424 | ct = nf_ct_tuplehash_to_ctrack(h); | ||
425 | /* Dump entries of a given L3 protocol number. | ||
426 | * If it is not specified, ie. l3proto == 0, | ||
427 | * then dump everything. */ | ||
428 | if (l3proto && L3PROTO(ct) != l3proto) | ||
429 | continue; | ||
430 | if (ct->id <= *id) | ||
431 | continue; | ||
432 | if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, | ||
433 | cb->nlh->nlmsg_seq, | ||
434 | IPCTNL_MSG_CT_NEW, | ||
435 | 1, ct) < 0) | ||
436 | goto out; | ||
437 | *id = ct->id; | ||
438 | } | ||
439 | } | ||
440 | out: | ||
441 | read_unlock_bh(&nf_conntrack_lock); | ||
442 | |||
443 | DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id); | ||
444 | |||
445 | return skb->len; | ||
446 | } | ||
447 | |||
448 | #ifdef CONFIG_NF_CT_ACCT | ||
449 | static int | ||
450 | ctnetlink_dump_table_w(struct sk_buff *skb, struct netlink_callback *cb) | ||
451 | { | ||
452 | struct nf_conn *ct = NULL; | ||
453 | struct nf_conntrack_tuple_hash *h; | ||
454 | struct list_head *i; | ||
455 | u_int32_t *id = (u_int32_t *) &cb->args[1]; | ||
456 | struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh); | ||
457 | u_int8_t l3proto = nfmsg->nfgen_family; | ||
458 | |||
459 | DEBUGP("entered %s, last bucket=%u id=%u\n", __FUNCTION__, | ||
460 | cb->args[0], *id); | ||
461 | |||
462 | write_lock_bh(&nf_conntrack_lock); | ||
463 | for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++, *id = 0) { | ||
464 | list_for_each_prev(i, &nf_conntrack_hash[cb->args[0]]) { | ||
465 | h = (struct nf_conntrack_tuple_hash *) i; | ||
466 | if (DIRECTION(h) != IP_CT_DIR_ORIGINAL) | ||
467 | continue; | ||
468 | ct = nf_ct_tuplehash_to_ctrack(h); | ||
469 | if (l3proto && L3PROTO(ct) != l3proto) | ||
470 | continue; | ||
471 | if (ct->id <= *id) | ||
472 | continue; | ||
473 | if (ctnetlink_fill_info(skb, NETLINK_CB(cb->skb).pid, | ||
474 | cb->nlh->nlmsg_seq, | ||
475 | IPCTNL_MSG_CT_NEW, | ||
476 | 1, ct) < 0) | ||
477 | goto out; | ||
478 | *id = ct->id; | ||
479 | |||
480 | memset(&ct->counters, 0, sizeof(ct->counters)); | ||
481 | } | ||
482 | } | ||
483 | out: | ||
484 | write_unlock_bh(&nf_conntrack_lock); | ||
485 | |||
486 | DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id); | ||
487 | |||
488 | return skb->len; | ||
489 | } | ||
490 | #endif | ||
491 | |||
492 | static inline int | ||
493 | ctnetlink_parse_tuple_ip(struct nfattr *attr, struct nf_conntrack_tuple *tuple) | ||
494 | { | ||
495 | struct nfattr *tb[CTA_IP_MAX]; | ||
496 | struct nf_conntrack_l3proto *l3proto; | ||
497 | int ret = 0; | ||
498 | |||
499 | DEBUGP("entered %s\n", __FUNCTION__); | ||
500 | |||
501 | nfattr_parse_nested(tb, CTA_IP_MAX, attr); | ||
502 | |||
503 | l3proto = nf_ct_l3proto_find_get(tuple->src.l3num); | ||
504 | |||
505 | if (likely(l3proto->nfattr_to_tuple)) | ||
506 | ret = l3proto->nfattr_to_tuple(tb, tuple); | ||
507 | |||
508 | nf_ct_l3proto_put(l3proto); | ||
509 | |||
510 | DEBUGP("leaving\n"); | ||
511 | |||
512 | return ret; | ||
513 | } | ||
514 | |||
515 | static const size_t cta_min_proto[CTA_PROTO_MAX] = { | ||
516 | [CTA_PROTO_NUM-1] = sizeof(u_int8_t), | ||
517 | }; | ||
518 | |||
519 | static inline int | ||
520 | ctnetlink_parse_tuple_proto(struct nfattr *attr, | ||
521 | struct nf_conntrack_tuple *tuple) | ||
522 | { | ||
523 | struct nfattr *tb[CTA_PROTO_MAX]; | ||
524 | struct nf_conntrack_protocol *proto; | ||
525 | int ret = 0; | ||
526 | |||
527 | DEBUGP("entered %s\n", __FUNCTION__); | ||
528 | |||
529 | nfattr_parse_nested(tb, CTA_PROTO_MAX, attr); | ||
530 | |||
531 | if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto)) | ||
532 | return -EINVAL; | ||
533 | |||
534 | if (!tb[CTA_PROTO_NUM-1]) | ||
535 | return -EINVAL; | ||
536 | tuple->dst.protonum = *(u_int8_t *)NFA_DATA(tb[CTA_PROTO_NUM-1]); | ||
537 | |||
538 | proto = nf_ct_proto_find_get(tuple->src.l3num, tuple->dst.protonum); | ||
539 | |||
540 | if (likely(proto->nfattr_to_tuple)) | ||
541 | ret = proto->nfattr_to_tuple(tb, tuple); | ||
542 | |||
543 | nf_ct_proto_put(proto); | ||
544 | |||
545 | return ret; | ||
546 | } | ||
547 | |||
548 | static inline int | ||
549 | ctnetlink_parse_tuple(struct nfattr *cda[], struct nf_conntrack_tuple *tuple, | ||
550 | enum ctattr_tuple type, u_int8_t l3num) | ||
551 | { | ||
552 | struct nfattr *tb[CTA_TUPLE_MAX]; | ||
553 | int err; | ||
554 | |||
555 | DEBUGP("entered %s\n", __FUNCTION__); | ||
556 | |||
557 | memset(tuple, 0, sizeof(*tuple)); | ||
558 | |||
559 | nfattr_parse_nested(tb, CTA_TUPLE_MAX, cda[type-1]); | ||
560 | |||
561 | if (!tb[CTA_TUPLE_IP-1]) | ||
562 | return -EINVAL; | ||
563 | |||
564 | tuple->src.l3num = l3num; | ||
565 | |||
566 | err = ctnetlink_parse_tuple_ip(tb[CTA_TUPLE_IP-1], tuple); | ||
567 | if (err < 0) | ||
568 | return err; | ||
569 | |||
570 | if (!tb[CTA_TUPLE_PROTO-1]) | ||
571 | return -EINVAL; | ||
572 | |||
573 | err = ctnetlink_parse_tuple_proto(tb[CTA_TUPLE_PROTO-1], tuple); | ||
574 | if (err < 0) | ||
575 | return err; | ||
576 | |||
577 | /* orig and expect tuples get DIR_ORIGINAL */ | ||
578 | if (type == CTA_TUPLE_REPLY) | ||
579 | tuple->dst.dir = IP_CT_DIR_REPLY; | ||
580 | else | ||
581 | tuple->dst.dir = IP_CT_DIR_ORIGINAL; | ||
582 | |||
583 | NF_CT_DUMP_TUPLE(tuple); | ||
584 | |||
585 | DEBUGP("leaving\n"); | ||
586 | |||
587 | return 0; | ||
588 | } | ||
589 | |||
590 | #ifdef CONFIG_IP_NF_NAT_NEEDED | ||
591 | static const size_t cta_min_protonat[CTA_PROTONAT_MAX] = { | ||
592 | [CTA_PROTONAT_PORT_MIN-1] = sizeof(u_int16_t), | ||
593 | [CTA_PROTONAT_PORT_MAX-1] = sizeof(u_int16_t), | ||
594 | }; | ||
595 | |||
596 | static int ctnetlink_parse_nat_proto(struct nfattr *attr, | ||
597 | const struct nf_conn *ct, | ||
598 | struct ip_nat_range *range) | ||
599 | { | ||
600 | struct nfattr *tb[CTA_PROTONAT_MAX]; | ||
601 | struct ip_nat_protocol *npt; | ||
602 | |||
603 | DEBUGP("entered %s\n", __FUNCTION__); | ||
604 | |||
605 | nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr); | ||
606 | |||
607 | if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat)) | ||
608 | return -EINVAL; | ||
609 | |||
610 | npt = ip_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum); | ||
611 | |||
612 | if (!npt->nfattr_to_range) { | ||
613 | ip_nat_proto_put(npt); | ||
614 | return 0; | ||
615 | } | ||
616 | |||
617 | /* nfattr_to_range returns 1 if it parsed, 0 if not, neg. on error */ | ||
618 | if (npt->nfattr_to_range(tb, range) > 0) | ||
619 | range->flags |= IP_NAT_RANGE_PROTO_SPECIFIED; | ||
620 | |||
621 | ip_nat_proto_put(npt); | ||
622 | |||
623 | DEBUGP("leaving\n"); | ||
624 | return 0; | ||
625 | } | ||
626 | |||
627 | static const size_t cta_min_nat[CTA_NAT_MAX] = { | ||
628 | [CTA_NAT_MINIP-1] = sizeof(u_int32_t), | ||
629 | [CTA_NAT_MAXIP-1] = sizeof(u_int32_t), | ||
630 | }; | ||
631 | |||
632 | static inline int | ||
633 | ctnetlink_parse_nat(struct nfattr *cda[], | ||
634 | const struct nf_conn *ct, struct ip_nat_range *range) | ||
635 | { | ||
636 | struct nfattr *tb[CTA_NAT_MAX]; | ||
637 | int err; | ||
638 | |||
639 | DEBUGP("entered %s\n", __FUNCTION__); | ||
640 | |||
641 | memset(range, 0, sizeof(*range)); | ||
642 | |||
643 | nfattr_parse_nested(tb, CTA_NAT_MAX, cda[CTA_NAT-1]); | ||
644 | |||
645 | if (nfattr_bad_size(tb, CTA_NAT_MAX, cta_min_nat)) | ||
646 | return -EINVAL; | ||
647 | |||
648 | if (tb[CTA_NAT_MINIP-1]) | ||
649 | range->min_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MINIP-1]); | ||
650 | |||
651 | if (!tb[CTA_NAT_MAXIP-1]) | ||
652 | range->max_ip = range->min_ip; | ||
653 | else | ||
654 | range->max_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MAXIP-1]); | ||
655 | |||
656 | if (range->min_ip) | ||
657 | range->flags |= IP_NAT_RANGE_MAP_IPS; | ||
658 | |||
659 | if (!tb[CTA_NAT_PROTO-1]) | ||
660 | return 0; | ||
661 | |||
662 | err = ctnetlink_parse_nat_proto(tb[CTA_NAT_PROTO-1], ct, range); | ||
663 | if (err < 0) | ||
664 | return err; | ||
665 | |||
666 | DEBUGP("leaving\n"); | ||
667 | return 0; | ||
668 | } | ||
669 | #endif | ||
670 | |||
671 | static inline int | ||
672 | ctnetlink_parse_help(struct nfattr *attr, char **helper_name) | ||
673 | { | ||
674 | struct nfattr *tb[CTA_HELP_MAX]; | ||
675 | |||
676 | DEBUGP("entered %s\n", __FUNCTION__); | ||
677 | |||
678 | nfattr_parse_nested(tb, CTA_HELP_MAX, attr); | ||
679 | |||
680 | if (!tb[CTA_HELP_NAME-1]) | ||
681 | return -EINVAL; | ||
682 | |||
683 | *helper_name = NFA_DATA(tb[CTA_HELP_NAME-1]); | ||
684 | |||
685 | return 0; | ||
686 | } | ||
687 | |||
688 | static const size_t cta_min[CTA_MAX] = { | ||
689 | [CTA_STATUS-1] = sizeof(u_int32_t), | ||
690 | [CTA_TIMEOUT-1] = sizeof(u_int32_t), | ||
691 | [CTA_MARK-1] = sizeof(u_int32_t), | ||
692 | [CTA_USE-1] = sizeof(u_int32_t), | ||
693 | [CTA_ID-1] = sizeof(u_int32_t) | ||
694 | }; | ||
695 | |||
696 | static int | ||
697 | ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, | ||
698 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | ||
699 | { | ||
700 | struct nf_conntrack_tuple_hash *h; | ||
701 | struct nf_conntrack_tuple tuple; | ||
702 | struct nf_conn *ct; | ||
703 | struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); | ||
704 | u_int8_t u3 = nfmsg->nfgen_family; | ||
705 | int err = 0; | ||
706 | |||
707 | DEBUGP("entered %s\n", __FUNCTION__); | ||
708 | |||
709 | if (nfattr_bad_size(cda, CTA_MAX, cta_min)) | ||
710 | return -EINVAL; | ||
711 | |||
712 | if (cda[CTA_TUPLE_ORIG-1]) | ||
713 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG, u3); | ||
714 | else if (cda[CTA_TUPLE_REPLY-1]) | ||
715 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY, u3); | ||
716 | else { | ||
717 | /* Flush the whole table */ | ||
718 | nf_conntrack_flush(); | ||
719 | return 0; | ||
720 | } | ||
721 | |||
722 | if (err < 0) | ||
723 | return err; | ||
724 | |||
725 | h = nf_conntrack_find_get(&tuple, NULL); | ||
726 | if (!h) { | ||
727 | DEBUGP("tuple not found in conntrack hash\n"); | ||
728 | return -ENOENT; | ||
729 | } | ||
730 | |||
731 | ct = nf_ct_tuplehash_to_ctrack(h); | ||
732 | |||
733 | if (cda[CTA_ID-1]) { | ||
734 | u_int32_t id = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_ID-1])); | ||
735 | if (ct->id != id) { | ||
736 | nf_ct_put(ct); | ||
737 | return -ENOENT; | ||
738 | } | ||
739 | } | ||
740 | if (del_timer(&ct->timeout)) | ||
741 | ct->timeout.function((unsigned long)ct); | ||
742 | |||
743 | nf_ct_put(ct); | ||
744 | DEBUGP("leaving\n"); | ||
745 | |||
746 | return 0; | ||
747 | } | ||
748 | |||
749 | static int | ||
750 | ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, | ||
751 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | ||
752 | { | ||
753 | struct nf_conntrack_tuple_hash *h; | ||
754 | struct nf_conntrack_tuple tuple; | ||
755 | struct nf_conn *ct; | ||
756 | struct sk_buff *skb2 = NULL; | ||
757 | struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); | ||
758 | u_int8_t u3 = nfmsg->nfgen_family; | ||
759 | int err = 0; | ||
760 | |||
761 | DEBUGP("entered %s\n", __FUNCTION__); | ||
762 | |||
763 | if (nlh->nlmsg_flags & NLM_F_DUMP) { | ||
764 | u32 rlen; | ||
765 | |||
766 | if (NFNL_MSG_TYPE(nlh->nlmsg_type) == | ||
767 | IPCTNL_MSG_CT_GET_CTRZERO) { | ||
768 | #ifdef CONFIG_NF_CT_ACCT | ||
769 | if ((*errp = netlink_dump_start(ctnl, skb, nlh, | ||
770 | ctnetlink_dump_table_w, | ||
771 | ctnetlink_done)) != 0) | ||
772 | return -EINVAL; | ||
773 | #else | ||
774 | return -ENOTSUPP; | ||
775 | #endif | ||
776 | } else { | ||
777 | if ((*errp = netlink_dump_start(ctnl, skb, nlh, | ||
778 | ctnetlink_dump_table, | ||
779 | ctnetlink_done)) != 0) | ||
780 | return -EINVAL; | ||
781 | } | ||
782 | |||
783 | rlen = NLMSG_ALIGN(nlh->nlmsg_len); | ||
784 | if (rlen > skb->len) | ||
785 | rlen = skb->len; | ||
786 | skb_pull(skb, rlen); | ||
787 | return 0; | ||
788 | } | ||
789 | |||
790 | if (nfattr_bad_size(cda, CTA_MAX, cta_min)) | ||
791 | return -EINVAL; | ||
792 | |||
793 | if (cda[CTA_TUPLE_ORIG-1]) | ||
794 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_ORIG, u3); | ||
795 | else if (cda[CTA_TUPLE_REPLY-1]) | ||
796 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY, u3); | ||
797 | else | ||
798 | return -EINVAL; | ||
799 | |||
800 | if (err < 0) | ||
801 | return err; | ||
802 | |||
803 | h = nf_conntrack_find_get(&tuple, NULL); | ||
804 | if (!h) { | ||
805 | DEBUGP("tuple not found in conntrack hash"); | ||
806 | return -ENOENT; | ||
807 | } | ||
808 | DEBUGP("tuple found\n"); | ||
809 | ct = nf_ct_tuplehash_to_ctrack(h); | ||
810 | |||
811 | err = -ENOMEM; | ||
812 | skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | ||
813 | if (!skb2) { | ||
814 | nf_ct_put(ct); | ||
815 | return -ENOMEM; | ||
816 | } | ||
817 | NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid; | ||
818 | |||
819 | err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, | ||
820 | IPCTNL_MSG_CT_NEW, 1, ct); | ||
821 | nf_ct_put(ct); | ||
822 | if (err <= 0) | ||
823 | goto free; | ||
824 | |||
825 | err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); | ||
826 | if (err < 0) | ||
827 | goto out; | ||
828 | |||
829 | DEBUGP("leaving\n"); | ||
830 | return 0; | ||
831 | |||
832 | free: | ||
833 | kfree_skb(skb2); | ||
834 | out: | ||
835 | return err; | ||
836 | } | ||
837 | |||
838 | static inline int | ||
839 | ctnetlink_change_status(struct nf_conn *ct, struct nfattr *cda[]) | ||
840 | { | ||
841 | unsigned long d; | ||
842 | unsigned status = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_STATUS-1])); | ||
843 | d = ct->status ^ status; | ||
844 | |||
845 | if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING)) | ||
846 | /* unchangeable */ | ||
847 | return -EINVAL; | ||
848 | |||
849 | if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY)) | ||
850 | /* SEEN_REPLY bit can only be set */ | ||
851 | return -EINVAL; | ||
852 | |||
853 | |||
854 | if (d & IPS_ASSURED && !(status & IPS_ASSURED)) | ||
855 | /* ASSURED bit can only be set */ | ||
856 | return -EINVAL; | ||
857 | |||
858 | if (cda[CTA_NAT-1]) { | ||
859 | #ifndef CONFIG_IP_NF_NAT_NEEDED | ||
860 | return -EINVAL; | ||
861 | #else | ||
862 | unsigned int hooknum; | ||
863 | struct ip_nat_range range; | ||
864 | |||
865 | if (ctnetlink_parse_nat(cda, ct, &range) < 0) | ||
866 | return -EINVAL; | ||
867 | |||
868 | DEBUGP("NAT: %u.%u.%u.%u-%u.%u.%u.%u:%u-%u\n", | ||
869 | NIPQUAD(range.min_ip), NIPQUAD(range.max_ip), | ||
870 | htons(range.min.all), htons(range.max.all)); | ||
871 | |||
872 | /* This is tricky but it works. ip_nat_setup_info needs the | ||
873 | * hook number as parameter, so let's do the correct | ||
874 | * conversion and run away */ | ||
875 | if (status & IPS_SRC_NAT_DONE) | ||
876 | hooknum = NF_IP_POST_ROUTING; /* IP_NAT_MANIP_SRC */ | ||
877 | else if (status & IPS_DST_NAT_DONE) | ||
878 | hooknum = NF_IP_PRE_ROUTING; /* IP_NAT_MANIP_DST */ | ||
879 | else | ||
880 | return -EINVAL; /* Missing NAT flags */ | ||
881 | |||
882 | DEBUGP("NAT status: %lu\n", | ||
883 | status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK)); | ||
884 | |||
885 | if (ip_nat_initialized(ct, HOOK2MANIP(hooknum))) | ||
886 | return -EEXIST; | ||
887 | ip_nat_setup_info(ct, &range, hooknum); | ||
888 | |||
889 | DEBUGP("NAT status after setup_info: %lu\n", | ||
890 | ct->status & (IPS_NAT_MASK | IPS_NAT_DONE_MASK)); | ||
891 | #endif | ||
892 | } | ||
893 | |||
894 | /* Be careful here, modifying NAT bits can screw up things, | ||
895 | * so don't let users modify them directly if they don't pass | ||
896 | * ip_nat_range. */ | ||
897 | ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK); | ||
898 | return 0; | ||
899 | } | ||
900 | |||
901 | |||
902 | static inline int | ||
903 | ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[]) | ||
904 | { | ||
905 | struct nf_conntrack_helper *helper; | ||
906 | char *helpname; | ||
907 | int err; | ||
908 | |||
909 | DEBUGP("entered %s\n", __FUNCTION__); | ||
910 | |||
911 | /* don't change helper of sibling connections */ | ||
912 | if (ct->master) | ||
913 | return -EINVAL; | ||
914 | |||
915 | err = ctnetlink_parse_help(cda[CTA_HELP-1], &helpname); | ||
916 | if (err < 0) | ||
917 | return err; | ||
918 | |||
919 | helper = __nf_conntrack_helper_find_byname(helpname); | ||
920 | if (!helper) { | ||
921 | if (!strcmp(helpname, "")) | ||
922 | helper = NULL; | ||
923 | else | ||
924 | return -EINVAL; | ||
925 | } | ||
926 | |||
927 | if (ct->helper) { | ||
928 | if (!helper) { | ||
929 | /* we had a helper before ... */ | ||
930 | nf_ct_remove_expectations(ct); | ||
931 | ct->helper = NULL; | ||
932 | } else { | ||
933 | /* need to zero data of old helper */ | ||
934 | memset(&ct->help, 0, sizeof(ct->help)); | ||
935 | } | ||
936 | } | ||
937 | |||
938 | ct->helper = helper; | ||
939 | |||
940 | return 0; | ||
941 | } | ||
942 | |||
943 | static inline int | ||
944 | ctnetlink_change_timeout(struct nf_conn *ct, struct nfattr *cda[]) | ||
945 | { | ||
946 | u_int32_t timeout = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1])); | ||
947 | |||
948 | if (!del_timer(&ct->timeout)) | ||
949 | return -ETIME; | ||
950 | |||
951 | ct->timeout.expires = jiffies + timeout * HZ; | ||
952 | add_timer(&ct->timeout); | ||
953 | |||
954 | return 0; | ||
955 | } | ||
956 | |||
957 | static inline int | ||
958 | ctnetlink_change_protoinfo(struct nf_conn *ct, struct nfattr *cda[]) | ||
959 | { | ||
960 | struct nfattr *tb[CTA_PROTOINFO_MAX], *attr = cda[CTA_PROTOINFO-1]; | ||
961 | struct nf_conntrack_protocol *proto; | ||
962 | u_int16_t npt = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum; | ||
963 | u_int16_t l3num = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; | ||
964 | int err = 0; | ||
965 | |||
966 | nfattr_parse_nested(tb, CTA_PROTOINFO_MAX, attr); | ||
967 | |||
968 | proto = nf_ct_proto_find_get(l3num, npt); | ||
969 | |||
970 | if (proto->from_nfattr) | ||
971 | err = proto->from_nfattr(tb, ct); | ||
972 | nf_ct_proto_put(proto); | ||
973 | |||
974 | return err; | ||
975 | } | ||
976 | |||
977 | static int | ||
978 | ctnetlink_change_conntrack(struct nf_conn *ct, struct nfattr *cda[]) | ||
979 | { | ||
980 | int err; | ||
981 | |||
982 | DEBUGP("entered %s\n", __FUNCTION__); | ||
983 | |||
984 | if (cda[CTA_HELP-1]) { | ||
985 | err = ctnetlink_change_helper(ct, cda); | ||
986 | if (err < 0) | ||
987 | return err; | ||
988 | } | ||
989 | |||
990 | if (cda[CTA_TIMEOUT-1]) { | ||
991 | err = ctnetlink_change_timeout(ct, cda); | ||
992 | if (err < 0) | ||
993 | return err; | ||
994 | } | ||
995 | |||
996 | if (cda[CTA_STATUS-1]) { | ||
997 | err = ctnetlink_change_status(ct, cda); | ||
998 | if (err < 0) | ||
999 | return err; | ||
1000 | } | ||
1001 | |||
1002 | if (cda[CTA_PROTOINFO-1]) { | ||
1003 | err = ctnetlink_change_protoinfo(ct, cda); | ||
1004 | if (err < 0) | ||
1005 | return err; | ||
1006 | } | ||
1007 | |||
1008 | #if defined(CONFIG_IP_NF_CONNTRACK_MARK) | ||
1009 | if (cda[CTA_MARK-1]) | ||
1010 | ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1])); | ||
1011 | #endif | ||
1012 | |||
1013 | DEBUGP("all done\n"); | ||
1014 | return 0; | ||
1015 | } | ||
1016 | |||
1017 | static int | ||
1018 | ctnetlink_create_conntrack(struct nfattr *cda[], | ||
1019 | struct nf_conntrack_tuple *otuple, | ||
1020 | struct nf_conntrack_tuple *rtuple) | ||
1021 | { | ||
1022 | struct nf_conn *ct; | ||
1023 | int err = -EINVAL; | ||
1024 | |||
1025 | DEBUGP("entered %s\n", __FUNCTION__); | ||
1026 | |||
1027 | ct = nf_conntrack_alloc(otuple, rtuple); | ||
1028 | if (ct == NULL || IS_ERR(ct)) | ||
1029 | return -ENOMEM; | ||
1030 | |||
1031 | if (!cda[CTA_TIMEOUT-1]) | ||
1032 | goto err; | ||
1033 | ct->timeout.expires = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1])); | ||
1034 | |||
1035 | ct->timeout.expires = jiffies + ct->timeout.expires * HZ; | ||
1036 | ct->status |= IPS_CONFIRMED; | ||
1037 | |||
1038 | err = ctnetlink_change_status(ct, cda); | ||
1039 | if (err < 0) | ||
1040 | goto err; | ||
1041 | |||
1042 | if (cda[CTA_PROTOINFO-1]) { | ||
1043 | err = ctnetlink_change_protoinfo(ct, cda); | ||
1044 | if (err < 0) | ||
1045 | return err; | ||
1046 | } | ||
1047 | |||
1048 | #if defined(CONFIG_IP_NF_CONNTRACK_MARK) | ||
1049 | if (cda[CTA_MARK-1]) | ||
1050 | ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1])); | ||
1051 | #endif | ||
1052 | |||
1053 | ct->helper = nf_ct_helper_find_get(rtuple); | ||
1054 | |||
1055 | add_timer(&ct->timeout); | ||
1056 | nf_conntrack_hash_insert(ct); | ||
1057 | |||
1058 | if (ct->helper) | ||
1059 | nf_ct_helper_put(ct->helper); | ||
1060 | |||
1061 | DEBUGP("conntrack with id %u inserted\n", ct->id); | ||
1062 | return 0; | ||
1063 | |||
1064 | err: | ||
1065 | nf_conntrack_free(ct); | ||
1066 | return err; | ||
1067 | } | ||
1068 | |||
1069 | static int | ||
1070 | ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, | ||
1071 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | ||
1072 | { | ||
1073 | struct nf_conntrack_tuple otuple, rtuple; | ||
1074 | struct nf_conntrack_tuple_hash *h = NULL; | ||
1075 | struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); | ||
1076 | u_int8_t u3 = nfmsg->nfgen_family; | ||
1077 | int err = 0; | ||
1078 | |||
1079 | DEBUGP("entered %s\n", __FUNCTION__); | ||
1080 | |||
1081 | if (nfattr_bad_size(cda, CTA_MAX, cta_min)) | ||
1082 | return -EINVAL; | ||
1083 | |||
1084 | if (cda[CTA_TUPLE_ORIG-1]) { | ||
1085 | err = ctnetlink_parse_tuple(cda, &otuple, CTA_TUPLE_ORIG, u3); | ||
1086 | if (err < 0) | ||
1087 | return err; | ||
1088 | } | ||
1089 | |||
1090 | if (cda[CTA_TUPLE_REPLY-1]) { | ||
1091 | err = ctnetlink_parse_tuple(cda, &rtuple, CTA_TUPLE_REPLY, u3); | ||
1092 | if (err < 0) | ||
1093 | return err; | ||
1094 | } | ||
1095 | |||
1096 | write_lock_bh(&nf_conntrack_lock); | ||
1097 | if (cda[CTA_TUPLE_ORIG-1]) | ||
1098 | h = __nf_conntrack_find(&otuple, NULL); | ||
1099 | else if (cda[CTA_TUPLE_REPLY-1]) | ||
1100 | h = __nf_conntrack_find(&rtuple, NULL); | ||
1101 | |||
1102 | if (h == NULL) { | ||
1103 | write_unlock_bh(&nf_conntrack_lock); | ||
1104 | DEBUGP("no such conntrack, create new\n"); | ||
1105 | err = -ENOENT; | ||
1106 | if (nlh->nlmsg_flags & NLM_F_CREATE) | ||
1107 | err = ctnetlink_create_conntrack(cda, &otuple, &rtuple); | ||
1108 | return err; | ||
1109 | } | ||
1110 | /* implicit 'else' */ | ||
1111 | |||
1112 | /* we only allow nat config for new conntracks */ | ||
1113 | if (cda[CTA_NAT-1]) { | ||
1114 | err = -EINVAL; | ||
1115 | goto out_unlock; | ||
1116 | } | ||
1117 | |||
1118 | /* We manipulate the conntrack inside the global conntrack table lock, | ||
1119 | * so there's no need to increase the refcount */ | ||
1120 | DEBUGP("conntrack found\n"); | ||
1121 | err = -EEXIST; | ||
1122 | if (!(nlh->nlmsg_flags & NLM_F_EXCL)) | ||
1123 | err = ctnetlink_change_conntrack(nf_ct_tuplehash_to_ctrack(h), cda); | ||
1124 | |||
1125 | out_unlock: | ||
1126 | write_unlock_bh(&nf_conntrack_lock); | ||
1127 | return err; | ||
1128 | } | ||
1129 | |||
1130 | /*********************************************************************** | ||
1131 | * EXPECT | ||
1132 | ***********************************************************************/ | ||
1133 | |||
1134 | static inline int | ||
1135 | ctnetlink_exp_dump_tuple(struct sk_buff *skb, | ||
1136 | const struct nf_conntrack_tuple *tuple, | ||
1137 | enum ctattr_expect type) | ||
1138 | { | ||
1139 | struct nfattr *nest_parms = NFA_NEST(skb, type); | ||
1140 | |||
1141 | if (ctnetlink_dump_tuples(skb, tuple) < 0) | ||
1142 | goto nfattr_failure; | ||
1143 | |||
1144 | NFA_NEST_END(skb, nest_parms); | ||
1145 | |||
1146 | return 0; | ||
1147 | |||
1148 | nfattr_failure: | ||
1149 | return -1; | ||
1150 | } | ||
1151 | |||
1152 | static inline int | ||
1153 | ctnetlink_exp_dump_expect(struct sk_buff *skb, | ||
1154 | const struct nf_conntrack_expect *exp) | ||
1155 | { | ||
1156 | struct nf_conn *master = exp->master; | ||
1157 | u_int32_t timeout = htonl((exp->timeout.expires - jiffies) / HZ); | ||
1158 | u_int32_t id = htonl(exp->id); | ||
1159 | |||
1160 | if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0) | ||
1161 | goto nfattr_failure; | ||
1162 | if (ctnetlink_exp_dump_tuple(skb, &exp->mask, CTA_EXPECT_MASK) < 0) | ||
1163 | goto nfattr_failure; | ||
1164 | if (ctnetlink_exp_dump_tuple(skb, | ||
1165 | &master->tuplehash[IP_CT_DIR_ORIGINAL].tuple, | ||
1166 | CTA_EXPECT_MASTER) < 0) | ||
1167 | goto nfattr_failure; | ||
1168 | |||
1169 | NFA_PUT(skb, CTA_EXPECT_TIMEOUT, sizeof(timeout), &timeout); | ||
1170 | NFA_PUT(skb, CTA_EXPECT_ID, sizeof(u_int32_t), &id); | ||
1171 | |||
1172 | return 0; | ||
1173 | |||
1174 | nfattr_failure: | ||
1175 | return -1; | ||
1176 | } | ||
1177 | |||
1178 | static int | ||
1179 | ctnetlink_exp_fill_info(struct sk_buff *skb, u32 pid, u32 seq, | ||
1180 | int event, | ||
1181 | int nowait, | ||
1182 | const struct nf_conntrack_expect *exp) | ||
1183 | { | ||
1184 | struct nlmsghdr *nlh; | ||
1185 | struct nfgenmsg *nfmsg; | ||
1186 | unsigned char *b; | ||
1187 | |||
1188 | b = skb->tail; | ||
1189 | |||
1190 | event |= NFNL_SUBSYS_CTNETLINK_EXP << 8; | ||
1191 | nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(struct nfgenmsg)); | ||
1192 | nfmsg = NLMSG_DATA(nlh); | ||
1193 | |||
1194 | nlh->nlmsg_flags = (nowait && pid) ? NLM_F_MULTI : 0; | ||
1195 | nfmsg->nfgen_family = exp->tuple.src.l3num; | ||
1196 | nfmsg->version = NFNETLINK_V0; | ||
1197 | nfmsg->res_id = 0; | ||
1198 | |||
1199 | if (ctnetlink_exp_dump_expect(skb, exp) < 0) | ||
1200 | goto nfattr_failure; | ||
1201 | |||
1202 | nlh->nlmsg_len = skb->tail - b; | ||
1203 | return skb->len; | ||
1204 | |||
1205 | nlmsg_failure: | ||
1206 | nfattr_failure: | ||
1207 | skb_trim(skb, b - skb->data); | ||
1208 | return -1; | ||
1209 | } | ||
1210 | |||
1211 | #ifdef CONFIG_NF_CONNTRACK_EVENTS | ||
1212 | static int ctnetlink_expect_event(struct notifier_block *this, | ||
1213 | unsigned long events, void *ptr) | ||
1214 | { | ||
1215 | struct nlmsghdr *nlh; | ||
1216 | struct nfgenmsg *nfmsg; | ||
1217 | struct nf_conntrack_expect *exp = (struct nf_conntrack_expect *)ptr; | ||
1218 | struct sk_buff *skb; | ||
1219 | unsigned int type; | ||
1220 | unsigned char *b; | ||
1221 | int flags = 0; | ||
1222 | |||
1223 | if (events & IPEXP_NEW) { | ||
1224 | type = IPCTNL_MSG_EXP_NEW; | ||
1225 | flags = NLM_F_CREATE|NLM_F_EXCL; | ||
1226 | } else | ||
1227 | return NOTIFY_DONE; | ||
1228 | |||
1229 | skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC); | ||
1230 | if (!skb) | ||
1231 | return NOTIFY_DONE; | ||
1232 | |||
1233 | b = skb->tail; | ||
1234 | |||
1235 | type |= NFNL_SUBSYS_CTNETLINK << 8; | ||
1236 | nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg)); | ||
1237 | nfmsg = NLMSG_DATA(nlh); | ||
1238 | |||
1239 | nlh->nlmsg_flags = flags; | ||
1240 | nfmsg->nfgen_family = exp->tuple.src.l3num; | ||
1241 | nfmsg->version = NFNETLINK_V0; | ||
1242 | nfmsg->res_id = 0; | ||
1243 | |||
1244 | if (ctnetlink_exp_dump_expect(skb, exp) < 0) | ||
1245 | goto nfattr_failure; | ||
1246 | |||
1247 | nlh->nlmsg_len = skb->tail - b; | ||
1248 | nfnetlink_send(skb, 0, NFNLGRP_CONNTRACK_EXP_NEW, 0); | ||
1249 | return NOTIFY_DONE; | ||
1250 | |||
1251 | nlmsg_failure: | ||
1252 | nfattr_failure: | ||
1253 | kfree_skb(skb); | ||
1254 | return NOTIFY_DONE; | ||
1255 | } | ||
1256 | #endif | ||
1257 | |||
1258 | static int | ||
1259 | ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb) | ||
1260 | { | ||
1261 | struct nf_conntrack_expect *exp = NULL; | ||
1262 | struct list_head *i; | ||
1263 | u_int32_t *id = (u_int32_t *) &cb->args[0]; | ||
1264 | struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh); | ||
1265 | u_int8_t l3proto = nfmsg->nfgen_family; | ||
1266 | |||
1267 | DEBUGP("entered %s, last id=%llu\n", __FUNCTION__, *id); | ||
1268 | |||
1269 | read_lock_bh(&nf_conntrack_lock); | ||
1270 | list_for_each_prev(i, &nf_conntrack_expect_list) { | ||
1271 | exp = (struct nf_conntrack_expect *) i; | ||
1272 | if (l3proto && exp->tuple.src.l3num != l3proto) | ||
1273 | continue; | ||
1274 | if (exp->id <= *id) | ||
1275 | continue; | ||
1276 | if (ctnetlink_exp_fill_info(skb, NETLINK_CB(cb->skb).pid, | ||
1277 | cb->nlh->nlmsg_seq, | ||
1278 | IPCTNL_MSG_EXP_NEW, | ||
1279 | 1, exp) < 0) | ||
1280 | goto out; | ||
1281 | *id = exp->id; | ||
1282 | } | ||
1283 | out: | ||
1284 | read_unlock_bh(&nf_conntrack_lock); | ||
1285 | |||
1286 | DEBUGP("leaving, last id=%llu\n", *id); | ||
1287 | |||
1288 | return skb->len; | ||
1289 | } | ||
1290 | |||
1291 | static const size_t cta_min_exp[CTA_EXPECT_MAX] = { | ||
1292 | [CTA_EXPECT_TIMEOUT-1] = sizeof(u_int32_t), | ||
1293 | [CTA_EXPECT_ID-1] = sizeof(u_int32_t) | ||
1294 | }; | ||
1295 | |||
1296 | static int | ||
1297 | ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, | ||
1298 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | ||
1299 | { | ||
1300 | struct nf_conntrack_tuple tuple; | ||
1301 | struct nf_conntrack_expect *exp; | ||
1302 | struct sk_buff *skb2; | ||
1303 | struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); | ||
1304 | u_int8_t u3 = nfmsg->nfgen_family; | ||
1305 | int err = 0; | ||
1306 | |||
1307 | DEBUGP("entered %s\n", __FUNCTION__); | ||
1308 | |||
1309 | if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) | ||
1310 | return -EINVAL; | ||
1311 | |||
1312 | if (nlh->nlmsg_flags & NLM_F_DUMP) { | ||
1313 | u32 rlen; | ||
1314 | |||
1315 | if ((*errp = netlink_dump_start(ctnl, skb, nlh, | ||
1316 | ctnetlink_exp_dump_table, | ||
1317 | ctnetlink_done)) != 0) | ||
1318 | return -EINVAL; | ||
1319 | rlen = NLMSG_ALIGN(nlh->nlmsg_len); | ||
1320 | if (rlen > skb->len) | ||
1321 | rlen = skb->len; | ||
1322 | skb_pull(skb, rlen); | ||
1323 | return 0; | ||
1324 | } | ||
1325 | |||
1326 | if (cda[CTA_EXPECT_MASTER-1]) | ||
1327 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_MASTER, u3); | ||
1328 | else | ||
1329 | return -EINVAL; | ||
1330 | |||
1331 | if (err < 0) | ||
1332 | return err; | ||
1333 | |||
1334 | exp = nf_conntrack_expect_find(&tuple); | ||
1335 | if (!exp) | ||
1336 | return -ENOENT; | ||
1337 | |||
1338 | if (cda[CTA_EXPECT_ID-1]) { | ||
1339 | u_int32_t id = *(u_int32_t *)NFA_DATA(cda[CTA_EXPECT_ID-1]); | ||
1340 | if (exp->id != ntohl(id)) { | ||
1341 | nf_conntrack_expect_put(exp); | ||
1342 | return -ENOENT; | ||
1343 | } | ||
1344 | } | ||
1345 | |||
1346 | err = -ENOMEM; | ||
1347 | skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); | ||
1348 | if (!skb2) | ||
1349 | goto out; | ||
1350 | NETLINK_CB(skb2).dst_pid = NETLINK_CB(skb).pid; | ||
1351 | |||
1352 | err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid, | ||
1353 | nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, | ||
1354 | 1, exp); | ||
1355 | if (err <= 0) | ||
1356 | goto free; | ||
1357 | |||
1358 | nf_conntrack_expect_put(exp); | ||
1359 | |||
1360 | return netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT); | ||
1361 | |||
1362 | free: | ||
1363 | kfree_skb(skb2); | ||
1364 | out: | ||
1365 | nf_conntrack_expect_put(exp); | ||
1366 | return err; | ||
1367 | } | ||
1368 | |||
1369 | static int | ||
1370 | ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, | ||
1371 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | ||
1372 | { | ||
1373 | struct nf_conntrack_expect *exp, *tmp; | ||
1374 | struct nf_conntrack_tuple tuple; | ||
1375 | struct nf_conntrack_helper *h; | ||
1376 | struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); | ||
1377 | u_int8_t u3 = nfmsg->nfgen_family; | ||
1378 | int err; | ||
1379 | |||
1380 | if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) | ||
1381 | return -EINVAL; | ||
1382 | |||
1383 | if (cda[CTA_EXPECT_TUPLE-1]) { | ||
1384 | /* delete a single expect by tuple */ | ||
1385 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3); | ||
1386 | if (err < 0) | ||
1387 | return err; | ||
1388 | |||
1389 | /* bump usage count to 2 */ | ||
1390 | exp = nf_conntrack_expect_find(&tuple); | ||
1391 | if (!exp) | ||
1392 | return -ENOENT; | ||
1393 | |||
1394 | if (cda[CTA_EXPECT_ID-1]) { | ||
1395 | u_int32_t id = | ||
1396 | *(u_int32_t *)NFA_DATA(cda[CTA_EXPECT_ID-1]); | ||
1397 | if (exp->id != ntohl(id)) { | ||
1398 | nf_conntrack_expect_put(exp); | ||
1399 | return -ENOENT; | ||
1400 | } | ||
1401 | } | ||
1402 | |||
1403 | /* after list removal, usage count == 1 */ | ||
1404 | nf_conntrack_unexpect_related(exp); | ||
1405 | /* have to put what we 'get' above. | ||
1406 | * after this line usage count == 0 */ | ||
1407 | nf_conntrack_expect_put(exp); | ||
1408 | } else if (cda[CTA_EXPECT_HELP_NAME-1]) { | ||
1409 | char *name = NFA_DATA(cda[CTA_EXPECT_HELP_NAME-1]); | ||
1410 | |||
1411 | /* delete all expectations for this helper */ | ||
1412 | write_lock_bh(&nf_conntrack_lock); | ||
1413 | h = __nf_conntrack_helper_find_byname(name); | ||
1414 | if (!h) { | ||
1415 | write_unlock_bh(&nf_conntrack_lock); | ||
1416 | return -EINVAL; | ||
1417 | } | ||
1418 | list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list, | ||
1419 | list) { | ||
1420 | if (exp->master->helper == h | ||
1421 | && del_timer(&exp->timeout)) { | ||
1422 | nf_ct_unlink_expect(exp); | ||
1423 | nf_conntrack_expect_put(exp); | ||
1424 | } | ||
1425 | } | ||
1426 | write_unlock_bh(&nf_conntrack_lock); | ||
1427 | } else { | ||
1428 | /* This basically means we have to flush everything*/ | ||
1429 | write_lock_bh(&nf_conntrack_lock); | ||
1430 | list_for_each_entry_safe(exp, tmp, &nf_conntrack_expect_list, | ||
1431 | list) { | ||
1432 | if (del_timer(&exp->timeout)) { | ||
1433 | nf_ct_unlink_expect(exp); | ||
1434 | nf_conntrack_expect_put(exp); | ||
1435 | } | ||
1436 | } | ||
1437 | write_unlock_bh(&nf_conntrack_lock); | ||
1438 | } | ||
1439 | |||
1440 | return 0; | ||
1441 | } | ||
1442 | static int | ||
1443 | ctnetlink_change_expect(struct nf_conntrack_expect *x, struct nfattr *cda[]) | ||
1444 | { | ||
1445 | return -EOPNOTSUPP; | ||
1446 | } | ||
1447 | |||
1448 | static int | ||
1449 | ctnetlink_create_expect(struct nfattr *cda[], u_int8_t u3) | ||
1450 | { | ||
1451 | struct nf_conntrack_tuple tuple, mask, master_tuple; | ||
1452 | struct nf_conntrack_tuple_hash *h = NULL; | ||
1453 | struct nf_conntrack_expect *exp; | ||
1454 | struct nf_conn *ct; | ||
1455 | int err = 0; | ||
1456 | |||
1457 | DEBUGP("entered %s\n", __FUNCTION__); | ||
1458 | |||
1459 | /* caller guarantees that those three CTA_EXPECT_* exist */ | ||
1460 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3); | ||
1461 | if (err < 0) | ||
1462 | return err; | ||
1463 | err = ctnetlink_parse_tuple(cda, &mask, CTA_EXPECT_MASK, u3); | ||
1464 | if (err < 0) | ||
1465 | return err; | ||
1466 | err = ctnetlink_parse_tuple(cda, &master_tuple, CTA_EXPECT_MASTER, u3); | ||
1467 | if (err < 0) | ||
1468 | return err; | ||
1469 | |||
1470 | /* Look for master conntrack of this expectation */ | ||
1471 | h = nf_conntrack_find_get(&master_tuple, NULL); | ||
1472 | if (!h) | ||
1473 | return -ENOENT; | ||
1474 | ct = nf_ct_tuplehash_to_ctrack(h); | ||
1475 | |||
1476 | if (!ct->helper) { | ||
1477 | /* such conntrack hasn't got any helper, abort */ | ||
1478 | err = -EINVAL; | ||
1479 | goto out; | ||
1480 | } | ||
1481 | |||
1482 | exp = nf_conntrack_expect_alloc(ct); | ||
1483 | if (!exp) { | ||
1484 | err = -ENOMEM; | ||
1485 | goto out; | ||
1486 | } | ||
1487 | |||
1488 | exp->expectfn = NULL; | ||
1489 | exp->flags = 0; | ||
1490 | exp->master = ct; | ||
1491 | memcpy(&exp->tuple, &tuple, sizeof(struct nf_conntrack_tuple)); | ||
1492 | memcpy(&exp->mask, &mask, sizeof(struct nf_conntrack_tuple)); | ||
1493 | |||
1494 | err = nf_conntrack_expect_related(exp); | ||
1495 | nf_conntrack_expect_put(exp); | ||
1496 | |||
1497 | out: | ||
1498 | nf_ct_put(nf_ct_tuplehash_to_ctrack(h)); | ||
1499 | return err; | ||
1500 | } | ||
1501 | |||
1502 | static int | ||
1503 | ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, | ||
1504 | struct nlmsghdr *nlh, struct nfattr *cda[], int *errp) | ||
1505 | { | ||
1506 | struct nf_conntrack_tuple tuple; | ||
1507 | struct nf_conntrack_expect *exp; | ||
1508 | struct nfgenmsg *nfmsg = NLMSG_DATA(nlh); | ||
1509 | u_int8_t u3 = nfmsg->nfgen_family; | ||
1510 | int err = 0; | ||
1511 | |||
1512 | DEBUGP("entered %s\n", __FUNCTION__); | ||
1513 | |||
1514 | if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp)) | ||
1515 | return -EINVAL; | ||
1516 | |||
1517 | if (!cda[CTA_EXPECT_TUPLE-1] | ||
1518 | || !cda[CTA_EXPECT_MASK-1] | ||
1519 | || !cda[CTA_EXPECT_MASTER-1]) | ||
1520 | return -EINVAL; | ||
1521 | |||
1522 | err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3); | ||
1523 | if (err < 0) | ||
1524 | return err; | ||
1525 | |||
1526 | write_lock_bh(&nf_conntrack_lock); | ||
1527 | exp = __nf_conntrack_expect_find(&tuple); | ||
1528 | |||
1529 | if (!exp) { | ||
1530 | write_unlock_bh(&nf_conntrack_lock); | ||
1531 | err = -ENOENT; | ||
1532 | if (nlh->nlmsg_flags & NLM_F_CREATE) | ||
1533 | err = ctnetlink_create_expect(cda, u3); | ||
1534 | return err; | ||
1535 | } | ||
1536 | |||
1537 | err = -EEXIST; | ||
1538 | if (!(nlh->nlmsg_flags & NLM_F_EXCL)) | ||
1539 | err = ctnetlink_change_expect(exp, cda); | ||
1540 | write_unlock_bh(&nf_conntrack_lock); | ||
1541 | |||
1542 | DEBUGP("leaving\n"); | ||
1543 | |||
1544 | return err; | ||
1545 | } | ||
1546 | |||
1547 | #ifdef CONFIG_NF_CONNTRACK_EVENTS | ||
1548 | static struct notifier_block ctnl_notifier = { | ||
1549 | .notifier_call = ctnetlink_conntrack_event, | ||
1550 | }; | ||
1551 | |||
1552 | static struct notifier_block ctnl_notifier_exp = { | ||
1553 | .notifier_call = ctnetlink_expect_event, | ||
1554 | }; | ||
1555 | #endif | ||
1556 | |||
1557 | static struct nfnl_callback ctnl_cb[IPCTNL_MSG_MAX] = { | ||
1558 | [IPCTNL_MSG_CT_NEW] = { .call = ctnetlink_new_conntrack, | ||
1559 | .attr_count = CTA_MAX, }, | ||
1560 | [IPCTNL_MSG_CT_GET] = { .call = ctnetlink_get_conntrack, | ||
1561 | .attr_count = CTA_MAX, }, | ||
1562 | [IPCTNL_MSG_CT_DELETE] = { .call = ctnetlink_del_conntrack, | ||
1563 | .attr_count = CTA_MAX, }, | ||
1564 | [IPCTNL_MSG_CT_GET_CTRZERO] = { .call = ctnetlink_get_conntrack, | ||
1565 | .attr_count = CTA_MAX, }, | ||
1566 | }; | ||
1567 | |||
1568 | static struct nfnl_callback ctnl_exp_cb[IPCTNL_MSG_EXP_MAX] = { | ||
1569 | [IPCTNL_MSG_EXP_GET] = { .call = ctnetlink_get_expect, | ||
1570 | .attr_count = CTA_EXPECT_MAX, }, | ||
1571 | [IPCTNL_MSG_EXP_NEW] = { .call = ctnetlink_new_expect, | ||
1572 | .attr_count = CTA_EXPECT_MAX, }, | ||
1573 | [IPCTNL_MSG_EXP_DELETE] = { .call = ctnetlink_del_expect, | ||
1574 | .attr_count = CTA_EXPECT_MAX, }, | ||
1575 | }; | ||
1576 | |||
1577 | static struct nfnetlink_subsystem ctnl_subsys = { | ||
1578 | .name = "conntrack", | ||
1579 | .subsys_id = NFNL_SUBSYS_CTNETLINK, | ||
1580 | .cb_count = IPCTNL_MSG_MAX, | ||
1581 | .cb = ctnl_cb, | ||
1582 | }; | ||
1583 | |||
1584 | static struct nfnetlink_subsystem ctnl_exp_subsys = { | ||
1585 | .name = "conntrack_expect", | ||
1586 | .subsys_id = NFNL_SUBSYS_CTNETLINK_EXP, | ||
1587 | .cb_count = IPCTNL_MSG_EXP_MAX, | ||
1588 | .cb = ctnl_exp_cb, | ||
1589 | }; | ||
1590 | |||
1591 | MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK); | ||
1592 | |||
1593 | static int __init ctnetlink_init(void) | ||
1594 | { | ||
1595 | int ret; | ||
1596 | |||
1597 | printk("ctnetlink v%s: registering with nfnetlink.\n", version); | ||
1598 | ret = nfnetlink_subsys_register(&ctnl_subsys); | ||
1599 | if (ret < 0) { | ||
1600 | printk("ctnetlink_init: cannot register with nfnetlink.\n"); | ||
1601 | goto err_out; | ||
1602 | } | ||
1603 | |||
1604 | ret = nfnetlink_subsys_register(&ctnl_exp_subsys); | ||
1605 | if (ret < 0) { | ||
1606 | printk("ctnetlink_init: cannot register exp with nfnetlink.\n"); | ||
1607 | goto err_unreg_subsys; | ||
1608 | } | ||
1609 | |||
1610 | #ifdef CONFIG_NF_CONNTRACK_EVENTS | ||
1611 | ret = nf_conntrack_register_notifier(&ctnl_notifier); | ||
1612 | if (ret < 0) { | ||
1613 | printk("ctnetlink_init: cannot register notifier.\n"); | ||
1614 | goto err_unreg_exp_subsys; | ||
1615 | } | ||
1616 | |||
1617 | ret = nf_conntrack_expect_register_notifier(&ctnl_notifier_exp); | ||
1618 | if (ret < 0) { | ||
1619 | printk("ctnetlink_init: cannot expect register notifier.\n"); | ||
1620 | goto err_unreg_notifier; | ||
1621 | } | ||
1622 | #endif | ||
1623 | |||
1624 | return 0; | ||
1625 | |||
1626 | #ifdef CONFIG_NF_CONNTRACK_EVENTS | ||
1627 | err_unreg_notifier: | ||
1628 | nf_conntrack_unregister_notifier(&ctnl_notifier); | ||
1629 | err_unreg_exp_subsys: | ||
1630 | nfnetlink_subsys_unregister(&ctnl_exp_subsys); | ||
1631 | #endif | ||
1632 | err_unreg_subsys: | ||
1633 | nfnetlink_subsys_unregister(&ctnl_subsys); | ||
1634 | err_out: | ||
1635 | return ret; | ||
1636 | } | ||
1637 | |||
1638 | static void __exit ctnetlink_exit(void) | ||
1639 | { | ||
1640 | printk("ctnetlink: unregistering from nfnetlink.\n"); | ||
1641 | |||
1642 | #ifdef CONFIG_NF_CONNTRACK_EVENTS | ||
1643 | nf_conntrack_unregister_notifier(&ctnl_notifier_exp); | ||
1644 | nf_conntrack_unregister_notifier(&ctnl_notifier); | ||
1645 | #endif | ||
1646 | |||
1647 | nfnetlink_subsys_unregister(&ctnl_exp_subsys); | ||
1648 | nfnetlink_subsys_unregister(&ctnl_subsys); | ||
1649 | return; | ||
1650 | } | ||
1651 | |||
1652 | module_init(ctnetlink_init); | ||
1653 | module_exit(ctnetlink_exit); | ||
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 6035633d8225..6167137a5cb5 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c | |||
@@ -1147,6 +1147,63 @@ static int tcp_new(struct nf_conn *conntrack, | |||
1147 | receiver->td_scale); | 1147 | receiver->td_scale); |
1148 | return 1; | 1148 | return 1; |
1149 | } | 1149 | } |
1150 | |||
1151 | #if defined(CONFIG_NF_CT_NETLINK) || \ | ||
1152 | defined(CONFIG_NF_CT_NETLINK_MODULE) | ||
1153 | |||
1154 | #include <linux/netfilter/nfnetlink.h> | ||
1155 | #include <linux/netfilter/nfnetlink_conntrack.h> | ||
1156 | |||
1157 | static int tcp_to_nfattr(struct sk_buff *skb, struct nfattr *nfa, | ||
1158 | const struct nf_conn *ct) | ||
1159 | { | ||
1160 | struct nfattr *nest_parms; | ||
1161 | |||
1162 | read_lock_bh(&tcp_lock); | ||
1163 | nest_parms = NFA_NEST(skb, CTA_PROTOINFO_TCP); | ||
1164 | NFA_PUT(skb, CTA_PROTOINFO_TCP_STATE, sizeof(u_int8_t), | ||
1165 | &ct->proto.tcp.state); | ||
1166 | read_unlock_bh(&tcp_lock); | ||
1167 | |||
1168 | NFA_NEST_END(skb, nest_parms); | ||
1169 | |||
1170 | return 0; | ||
1171 | |||
1172 | nfattr_failure: | ||
1173 | read_unlock_bh(&tcp_lock); | ||
1174 | return -1; | ||
1175 | } | ||
1176 | |||
1177 | static const size_t cta_min_tcp[CTA_PROTOINFO_TCP_MAX] = { | ||
1178 | [CTA_PROTOINFO_TCP_STATE-1] = sizeof(u_int8_t), | ||
1179 | }; | ||
1180 | |||
1181 | static int nfattr_to_tcp(struct nfattr *cda[], struct nf_conn *ct) | ||
1182 | { | ||
1183 | struct nfattr *attr = cda[CTA_PROTOINFO_TCP-1]; | ||
1184 | struct nfattr *tb[CTA_PROTOINFO_TCP_MAX]; | ||
1185 | |||
1186 | /* updates could not contain anything about the private | ||
1187 | * protocol info, in that case skip the parsing */ | ||
1188 | if (!attr) | ||
1189 | return 0; | ||
1190 | |||
1191 | nfattr_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr); | ||
1192 | |||
1193 | if (nfattr_bad_size(tb, CTA_PROTOINFO_TCP_MAX, cta_min_tcp)) | ||
1194 | return -EINVAL; | ||
1195 | |||
1196 | if (!tb[CTA_PROTOINFO_TCP_STATE-1]) | ||
1197 | return -EINVAL; | ||
1198 | |||
1199 | write_lock_bh(&tcp_lock); | ||
1200 | ct->proto.tcp.state = | ||
1201 | *(u_int8_t *)NFA_DATA(tb[CTA_PROTOINFO_TCP_STATE-1]); | ||
1202 | write_unlock_bh(&tcp_lock); | ||
1203 | |||
1204 | return 0; | ||
1205 | } | ||
1206 | #endif | ||
1150 | 1207 | ||
1151 | struct nf_conntrack_protocol nf_conntrack_protocol_tcp4 = | 1208 | struct nf_conntrack_protocol nf_conntrack_protocol_tcp4 = |
1152 | { | 1209 | { |
@@ -1160,6 +1217,13 @@ struct nf_conntrack_protocol nf_conntrack_protocol_tcp4 = | |||
1160 | .packet = tcp_packet, | 1217 | .packet = tcp_packet, |
1161 | .new = tcp_new, | 1218 | .new = tcp_new, |
1162 | .error = tcp_error4, | 1219 | .error = tcp_error4, |
1220 | #if defined(CONFIG_NF_CT_NETLINK) || \ | ||
1221 | defined(CONFIG_NF_CT_NETLINK_MODULE) | ||
1222 | .to_nfattr = tcp_to_nfattr, | ||
1223 | .from_nfattr = nfattr_to_tcp, | ||
1224 | .tuple_to_nfattr = nf_ct_port_tuple_to_nfattr, | ||
1225 | .nfattr_to_tuple = nf_ct_port_nfattr_to_tuple, | ||
1226 | #endif | ||
1163 | }; | 1227 | }; |
1164 | 1228 | ||
1165 | struct nf_conntrack_protocol nf_conntrack_protocol_tcp6 = | 1229 | struct nf_conntrack_protocol nf_conntrack_protocol_tcp6 = |
@@ -1174,6 +1238,13 @@ struct nf_conntrack_protocol nf_conntrack_protocol_tcp6 = | |||
1174 | .packet = tcp_packet, | 1238 | .packet = tcp_packet, |
1175 | .new = tcp_new, | 1239 | .new = tcp_new, |
1176 | .error = tcp_error6, | 1240 | .error = tcp_error6, |
1241 | #if defined(CONFIG_NF_CT_NETLINK) || \ | ||
1242 | defined(CONFIG_NF_CT_NETLINK_MODULE) | ||
1243 | .to_nfattr = tcp_to_nfattr, | ||
1244 | .from_nfattr = nfattr_to_tcp, | ||
1245 | .tuple_to_nfattr = nf_ct_port_tuple_to_nfattr, | ||
1246 | .nfattr_to_tuple = nf_ct_port_nfattr_to_tuple, | ||
1247 | #endif | ||
1177 | }; | 1248 | }; |
1178 | 1249 | ||
1179 | EXPORT_SYMBOL(nf_conntrack_protocol_tcp4); | 1250 | EXPORT_SYMBOL(nf_conntrack_protocol_tcp4); |
diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c index 3cae7ce420dd..1a592a556182 100644 --- a/net/netfilter/nf_conntrack_proto_udp.c +++ b/net/netfilter/nf_conntrack_proto_udp.c | |||
@@ -196,6 +196,11 @@ struct nf_conntrack_protocol nf_conntrack_protocol_udp4 = | |||
196 | .packet = udp_packet, | 196 | .packet = udp_packet, |
197 | .new = udp_new, | 197 | .new = udp_new, |
198 | .error = udp_error4, | 198 | .error = udp_error4, |
199 | #if defined(CONFIG_NF_CT_NETLINK) || \ | ||
200 | defined(CONFIG_NF_CT_NETLINK_MODULE) | ||
201 | .tuple_to_nfattr = nf_ct_port_tuple_to_nfattr, | ||
202 | .nfattr_to_tuple = nf_ct_port_nfattr_to_tuple, | ||
203 | #endif | ||
199 | }; | 204 | }; |
200 | 205 | ||
201 | struct nf_conntrack_protocol nf_conntrack_protocol_udp6 = | 206 | struct nf_conntrack_protocol nf_conntrack_protocol_udp6 = |
@@ -210,6 +215,11 @@ struct nf_conntrack_protocol nf_conntrack_protocol_udp6 = | |||
210 | .packet = udp_packet, | 215 | .packet = udp_packet, |
211 | .new = udp_new, | 216 | .new = udp_new, |
212 | .error = udp_error6, | 217 | .error = udp_error6, |
218 | #if defined(CONFIG_NF_CT_NETLINK) || \ | ||
219 | defined(CONFIG_NF_CT_NETLINK_MODULE) | ||
220 | .tuple_to_nfattr = nf_ct_port_tuple_to_nfattr, | ||
221 | .nfattr_to_tuple = nf_ct_port_nfattr_to_tuple, | ||
222 | #endif | ||
213 | }; | 223 | }; |
214 | 224 | ||
215 | EXPORT_SYMBOL(nf_conntrack_protocol_udp4); | 225 | EXPORT_SYMBOL(nf_conntrack_protocol_udp4); |
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index 5af381f9fe3d..d17e42b28c79 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c | |||
@@ -161,14 +161,14 @@ static int ct_seq_show(struct seq_file *s, void *v) | |||
161 | if (NF_CT_DIRECTION(hash)) | 161 | if (NF_CT_DIRECTION(hash)) |
162 | return 0; | 162 | return 0; |
163 | 163 | ||
164 | l3proto = nf_ct_find_l3proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL] | 164 | l3proto = __nf_ct_l3proto_find(conntrack->tuplehash[IP_CT_DIR_ORIGINAL] |
165 | .tuple.src.l3num); | 165 | .tuple.src.l3num); |
166 | 166 | ||
167 | NF_CT_ASSERT(l3proto); | 167 | NF_CT_ASSERT(l3proto); |
168 | proto = nf_ct_find_proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL] | 168 | proto = __nf_ct_proto_find(conntrack->tuplehash[IP_CT_DIR_ORIGINAL] |
169 | .tuple.src.l3num, | 169 | .tuple.src.l3num, |
170 | conntrack->tuplehash[IP_CT_DIR_ORIGINAL] | 170 | conntrack->tuplehash[IP_CT_DIR_ORIGINAL] |
171 | .tuple.dst.protonum); | 171 | .tuple.dst.protonum); |
172 | NF_CT_ASSERT(proto); | 172 | NF_CT_ASSERT(proto); |
173 | 173 | ||
174 | if (seq_printf(s, "%-8s %u %-8s %u %ld ", | 174 | if (seq_printf(s, "%-8s %u %-8s %u %ld ", |
@@ -307,9 +307,9 @@ static int exp_seq_show(struct seq_file *s, void *v) | |||
307 | expect->tuple.src.l3num, | 307 | expect->tuple.src.l3num, |
308 | expect->tuple.dst.protonum); | 308 | expect->tuple.dst.protonum); |
309 | print_tuple(s, &expect->tuple, | 309 | print_tuple(s, &expect->tuple, |
310 | nf_ct_find_l3proto(expect->tuple.src.l3num), | 310 | __nf_ct_l3proto_find(expect->tuple.src.l3num), |
311 | nf_ct_find_proto(expect->tuple.src.l3num, | 311 | __nf_ct_proto_find(expect->tuple.src.l3num, |
312 | expect->tuple.dst.protonum)); | 312 | expect->tuple.dst.protonum)); |
313 | return seq_putc(s, '\n'); | 313 | return seq_putc(s, '\n'); |
314 | } | 314 | } |
315 | 315 | ||
@@ -847,7 +847,11 @@ EXPORT_SYMBOL(nf_conntrack_helper_unregister); | |||
847 | EXPORT_SYMBOL(nf_ct_iterate_cleanup); | 847 | EXPORT_SYMBOL(nf_ct_iterate_cleanup); |
848 | EXPORT_SYMBOL(__nf_ct_refresh_acct); | 848 | EXPORT_SYMBOL(__nf_ct_refresh_acct); |
849 | EXPORT_SYMBOL(nf_ct_protos); | 849 | EXPORT_SYMBOL(nf_ct_protos); |
850 | EXPORT_SYMBOL(nf_ct_find_proto); | 850 | EXPORT_SYMBOL(__nf_ct_proto_find); |
851 | EXPORT_SYMBOL(nf_ct_proto_find_get); | ||
852 | EXPORT_SYMBOL(nf_ct_proto_put); | ||
853 | EXPORT_SYMBOL(nf_ct_l3proto_find_get); | ||
854 | EXPORT_SYMBOL(nf_ct_l3proto_put); | ||
851 | EXPORT_SYMBOL(nf_ct_l3protos); | 855 | EXPORT_SYMBOL(nf_ct_l3protos); |
852 | EXPORT_SYMBOL(nf_conntrack_expect_alloc); | 856 | EXPORT_SYMBOL(nf_conntrack_expect_alloc); |
853 | EXPORT_SYMBOL(nf_conntrack_expect_put); | 857 | EXPORT_SYMBOL(nf_conntrack_expect_put); |
@@ -867,3 +871,21 @@ EXPORT_SYMBOL(nf_ct_get_tuple); | |||
867 | EXPORT_SYMBOL(nf_ct_invert_tuple); | 871 | EXPORT_SYMBOL(nf_ct_invert_tuple); |
868 | EXPORT_SYMBOL(nf_conntrack_in); | 872 | EXPORT_SYMBOL(nf_conntrack_in); |
869 | EXPORT_SYMBOL(__nf_conntrack_attach); | 873 | EXPORT_SYMBOL(__nf_conntrack_attach); |
874 | EXPORT_SYMBOL(nf_conntrack_alloc); | ||
875 | EXPORT_SYMBOL(nf_conntrack_free); | ||
876 | EXPORT_SYMBOL(nf_conntrack_flush); | ||
877 | EXPORT_SYMBOL(nf_ct_remove_expectations); | ||
878 | EXPORT_SYMBOL(nf_ct_helper_find_get); | ||
879 | EXPORT_SYMBOL(nf_ct_helper_put); | ||
880 | EXPORT_SYMBOL(__nf_conntrack_helper_find_byname); | ||
881 | EXPORT_SYMBOL(__nf_conntrack_find); | ||
882 | EXPORT_SYMBOL(nf_ct_unlink_expect); | ||
883 | EXPORT_SYMBOL(nf_conntrack_hash_insert); | ||
884 | EXPORT_SYMBOL(__nf_conntrack_expect_find); | ||
885 | EXPORT_SYMBOL(nf_conntrack_expect_find); | ||
886 | EXPORT_SYMBOL(nf_conntrack_expect_list); | ||
887 | #if defined(CONFIG_NF_CT_NETLINK) || \ | ||
888 | defined(CONFIG_NF_CT_NETLINK_MODULE) | ||
889 | EXPORT_SYMBOL(nf_ct_port_tuple_to_nfattr); | ||
890 | EXPORT_SYMBOL(nf_ct_port_nfattr_to_tuple); | ||
891 | #endif | ||
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 55afdda3d940..18ed9c5d209c 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c | |||
@@ -345,6 +345,10 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, | |||
345 | struct nfqnl_msg_packet_hdr pmsg; | 345 | struct nfqnl_msg_packet_hdr pmsg; |
346 | struct nlmsghdr *nlh; | 346 | struct nlmsghdr *nlh; |
347 | struct nfgenmsg *nfmsg; | 347 | struct nfgenmsg *nfmsg; |
348 | struct nf_info *entinf = entry->info; | ||
349 | struct sk_buff *entskb = entry->skb; | ||
350 | struct net_device *indev; | ||
351 | struct net_device *outdev; | ||
348 | unsigned int tmp_uint; | 352 | unsigned int tmp_uint; |
349 | 353 | ||
350 | QDEBUG("entered\n"); | 354 | QDEBUG("entered\n"); |
@@ -361,6 +365,8 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, | |||
361 | + NLMSG_SPACE(sizeof(struct nfqnl_msg_packet_hw)) | 365 | + NLMSG_SPACE(sizeof(struct nfqnl_msg_packet_hw)) |
362 | + NLMSG_SPACE(sizeof(struct nfqnl_msg_packet_timestamp)); | 366 | + NLMSG_SPACE(sizeof(struct nfqnl_msg_packet_timestamp)); |
363 | 367 | ||
368 | outdev = entinf->outdev; | ||
369 | |||
364 | spin_lock_bh(&queue->lock); | 370 | spin_lock_bh(&queue->lock); |
365 | 371 | ||
366 | switch (queue->copy_mode) { | 372 | switch (queue->copy_mode) { |
@@ -370,15 +376,15 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, | |||
370 | break; | 376 | break; |
371 | 377 | ||
372 | case NFQNL_COPY_PACKET: | 378 | case NFQNL_COPY_PACKET: |
373 | if (entry->skb->ip_summed == CHECKSUM_HW && | 379 | if (entskb->ip_summed == CHECKSUM_HW && |
374 | (*errp = skb_checksum_help(entry->skb, | 380 | (*errp = skb_checksum_help(entskb, |
375 | entry->info->outdev == NULL))) { | 381 | outdev == NULL))) { |
376 | spin_unlock_bh(&queue->lock); | 382 | spin_unlock_bh(&queue->lock); |
377 | return NULL; | 383 | return NULL; |
378 | } | 384 | } |
379 | if (queue->copy_range == 0 | 385 | if (queue->copy_range == 0 |
380 | || queue->copy_range > entry->skb->len) | 386 | || queue->copy_range > entskb->len) |
381 | data_len = entry->skb->len; | 387 | data_len = entskb->len; |
382 | else | 388 | else |
383 | data_len = queue->copy_range; | 389 | data_len = queue->copy_range; |
384 | 390 | ||
@@ -402,29 +408,30 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, | |||
402 | NFNL_SUBSYS_QUEUE << 8 | NFQNL_MSG_PACKET, | 408 | NFNL_SUBSYS_QUEUE << 8 | NFQNL_MSG_PACKET, |
403 | sizeof(struct nfgenmsg)); | 409 | sizeof(struct nfgenmsg)); |
404 | nfmsg = NLMSG_DATA(nlh); | 410 | nfmsg = NLMSG_DATA(nlh); |
405 | nfmsg->nfgen_family = entry->info->pf; | 411 | nfmsg->nfgen_family = entinf->pf; |
406 | nfmsg->version = NFNETLINK_V0; | 412 | nfmsg->version = NFNETLINK_V0; |
407 | nfmsg->res_id = htons(queue->queue_num); | 413 | nfmsg->res_id = htons(queue->queue_num); |
408 | 414 | ||
409 | pmsg.packet_id = htonl(entry->id); | 415 | pmsg.packet_id = htonl(entry->id); |
410 | pmsg.hw_protocol = htons(entry->skb->protocol); | 416 | pmsg.hw_protocol = htons(entskb->protocol); |
411 | pmsg.hook = entry->info->hook; | 417 | pmsg.hook = entinf->hook; |
412 | 418 | ||
413 | NFA_PUT(skb, NFQA_PACKET_HDR, sizeof(pmsg), &pmsg); | 419 | NFA_PUT(skb, NFQA_PACKET_HDR, sizeof(pmsg), &pmsg); |
414 | 420 | ||
415 | if (entry->info->indev) { | 421 | indev = entinf->indev; |
416 | tmp_uint = htonl(entry->info->indev->ifindex); | 422 | if (indev) { |
423 | tmp_uint = htonl(indev->ifindex); | ||
417 | #ifndef CONFIG_BRIDGE_NETFILTER | 424 | #ifndef CONFIG_BRIDGE_NETFILTER |
418 | NFA_PUT(skb, NFQA_IFINDEX_INDEV, sizeof(tmp_uint), &tmp_uint); | 425 | NFA_PUT(skb, NFQA_IFINDEX_INDEV, sizeof(tmp_uint), &tmp_uint); |
419 | #else | 426 | #else |
420 | if (entry->info->pf == PF_BRIDGE) { | 427 | if (entinf->pf == PF_BRIDGE) { |
421 | /* Case 1: indev is physical input device, we need to | 428 | /* Case 1: indev is physical input device, we need to |
422 | * look for bridge group (when called from | 429 | * look for bridge group (when called from |
423 | * netfilter_bridge) */ | 430 | * netfilter_bridge) */ |
424 | NFA_PUT(skb, NFQA_IFINDEX_PHYSINDEV, sizeof(tmp_uint), | 431 | NFA_PUT(skb, NFQA_IFINDEX_PHYSINDEV, sizeof(tmp_uint), |
425 | &tmp_uint); | 432 | &tmp_uint); |
426 | /* this is the bridge group "brX" */ | 433 | /* this is the bridge group "brX" */ |
427 | tmp_uint = htonl(entry->info->indev->br_port->br->dev->ifindex); | 434 | tmp_uint = htonl(indev->br_port->br->dev->ifindex); |
428 | NFA_PUT(skb, NFQA_IFINDEX_INDEV, sizeof(tmp_uint), | 435 | NFA_PUT(skb, NFQA_IFINDEX_INDEV, sizeof(tmp_uint), |
429 | &tmp_uint); | 436 | &tmp_uint); |
430 | } else { | 437 | } else { |
@@ -432,9 +439,9 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, | |||
432 | * physical device (when called from ipv4) */ | 439 | * physical device (when called from ipv4) */ |
433 | NFA_PUT(skb, NFQA_IFINDEX_INDEV, sizeof(tmp_uint), | 440 | NFA_PUT(skb, NFQA_IFINDEX_INDEV, sizeof(tmp_uint), |
434 | &tmp_uint); | 441 | &tmp_uint); |
435 | if (entry->skb->nf_bridge | 442 | if (entskb->nf_bridge |
436 | && entry->skb->nf_bridge->physindev) { | 443 | && entskb->nf_bridge->physindev) { |
437 | tmp_uint = htonl(entry->skb->nf_bridge->physindev->ifindex); | 444 | tmp_uint = htonl(entskb->nf_bridge->physindev->ifindex); |
438 | NFA_PUT(skb, NFQA_IFINDEX_PHYSINDEV, | 445 | NFA_PUT(skb, NFQA_IFINDEX_PHYSINDEV, |
439 | sizeof(tmp_uint), &tmp_uint); | 446 | sizeof(tmp_uint), &tmp_uint); |
440 | } | 447 | } |
@@ -442,19 +449,19 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, | |||
442 | #endif | 449 | #endif |
443 | } | 450 | } |
444 | 451 | ||
445 | if (entry->info->outdev) { | 452 | if (outdev) { |
446 | tmp_uint = htonl(entry->info->outdev->ifindex); | 453 | tmp_uint = htonl(outdev->ifindex); |
447 | #ifndef CONFIG_BRIDGE_NETFILTER | 454 | #ifndef CONFIG_BRIDGE_NETFILTER |
448 | NFA_PUT(skb, NFQA_IFINDEX_OUTDEV, sizeof(tmp_uint), &tmp_uint); | 455 | NFA_PUT(skb, NFQA_IFINDEX_OUTDEV, sizeof(tmp_uint), &tmp_uint); |
449 | #else | 456 | #else |
450 | if (entry->info->pf == PF_BRIDGE) { | 457 | if (entinf->pf == PF_BRIDGE) { |
451 | /* Case 1: outdev is physical output device, we need to | 458 | /* Case 1: outdev is physical output device, we need to |
452 | * look for bridge group (when called from | 459 | * look for bridge group (when called from |
453 | * netfilter_bridge) */ | 460 | * netfilter_bridge) */ |
454 | NFA_PUT(skb, NFQA_IFINDEX_PHYSOUTDEV, sizeof(tmp_uint), | 461 | NFA_PUT(skb, NFQA_IFINDEX_PHYSOUTDEV, sizeof(tmp_uint), |
455 | &tmp_uint); | 462 | &tmp_uint); |
456 | /* this is the bridge group "brX" */ | 463 | /* this is the bridge group "brX" */ |
457 | tmp_uint = htonl(entry->info->outdev->br_port->br->dev->ifindex); | 464 | tmp_uint = htonl(outdev->br_port->br->dev->ifindex); |
458 | NFA_PUT(skb, NFQA_IFINDEX_OUTDEV, sizeof(tmp_uint), | 465 | NFA_PUT(skb, NFQA_IFINDEX_OUTDEV, sizeof(tmp_uint), |
459 | &tmp_uint); | 466 | &tmp_uint); |
460 | } else { | 467 | } else { |
@@ -462,9 +469,9 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, | |||
462 | * physical output device (when called from ipv4) */ | 469 | * physical output device (when called from ipv4) */ |
463 | NFA_PUT(skb, NFQA_IFINDEX_OUTDEV, sizeof(tmp_uint), | 470 | NFA_PUT(skb, NFQA_IFINDEX_OUTDEV, sizeof(tmp_uint), |
464 | &tmp_uint); | 471 | &tmp_uint); |
465 | if (entry->skb->nf_bridge | 472 | if (entskb->nf_bridge |
466 | && entry->skb->nf_bridge->physoutdev) { | 473 | && entskb->nf_bridge->physoutdev) { |
467 | tmp_uint = htonl(entry->skb->nf_bridge->physoutdev->ifindex); | 474 | tmp_uint = htonl(entskb->nf_bridge->physoutdev->ifindex); |
468 | NFA_PUT(skb, NFQA_IFINDEX_PHYSOUTDEV, | 475 | NFA_PUT(skb, NFQA_IFINDEX_PHYSOUTDEV, |
469 | sizeof(tmp_uint), &tmp_uint); | 476 | sizeof(tmp_uint), &tmp_uint); |
470 | } | 477 | } |
@@ -472,27 +479,27 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, | |||
472 | #endif | 479 | #endif |
473 | } | 480 | } |
474 | 481 | ||
475 | if (entry->skb->nfmark) { | 482 | if (entskb->nfmark) { |
476 | tmp_uint = htonl(entry->skb->nfmark); | 483 | tmp_uint = htonl(entskb->nfmark); |
477 | NFA_PUT(skb, NFQA_MARK, sizeof(u_int32_t), &tmp_uint); | 484 | NFA_PUT(skb, NFQA_MARK, sizeof(u_int32_t), &tmp_uint); |
478 | } | 485 | } |
479 | 486 | ||
480 | if (entry->info->indev && entry->skb->dev | 487 | if (indev && entskb->dev |
481 | && entry->skb->dev->hard_header_parse) { | 488 | && entskb->dev->hard_header_parse) { |
482 | struct nfqnl_msg_packet_hw phw; | 489 | struct nfqnl_msg_packet_hw phw; |
483 | 490 | ||
484 | phw.hw_addrlen = | 491 | phw.hw_addrlen = |
485 | entry->skb->dev->hard_header_parse(entry->skb, | 492 | entskb->dev->hard_header_parse(entskb, |
486 | phw.hw_addr); | 493 | phw.hw_addr); |
487 | phw.hw_addrlen = htons(phw.hw_addrlen); | 494 | phw.hw_addrlen = htons(phw.hw_addrlen); |
488 | NFA_PUT(skb, NFQA_HWADDR, sizeof(phw), &phw); | 495 | NFA_PUT(skb, NFQA_HWADDR, sizeof(phw), &phw); |
489 | } | 496 | } |
490 | 497 | ||
491 | if (entry->skb->tstamp.off_sec) { | 498 | if (entskb->tstamp.off_sec) { |
492 | struct nfqnl_msg_packet_timestamp ts; | 499 | struct nfqnl_msg_packet_timestamp ts; |
493 | 500 | ||
494 | ts.sec = cpu_to_be64(entry->skb->tstamp.off_sec); | 501 | ts.sec = cpu_to_be64(entskb->tstamp.off_sec); |
495 | ts.usec = cpu_to_be64(entry->skb->tstamp.off_usec); | 502 | ts.usec = cpu_to_be64(entskb->tstamp.off_usec); |
496 | 503 | ||
497 | NFA_PUT(skb, NFQA_TIMESTAMP, sizeof(ts), &ts); | 504 | NFA_PUT(skb, NFQA_TIMESTAMP, sizeof(ts), &ts); |
498 | } | 505 | } |
@@ -510,7 +517,7 @@ nfqnl_build_packet_message(struct nfqnl_instance *queue, | |||
510 | nfa->nfa_type = NFQA_PAYLOAD; | 517 | nfa->nfa_type = NFQA_PAYLOAD; |
511 | nfa->nfa_len = size; | 518 | nfa->nfa_len = size; |
512 | 519 | ||
513 | if (skb_copy_bits(entry->skb, 0, NFA_DATA(nfa), data_len)) | 520 | if (skb_copy_bits(entskb, 0, NFA_DATA(nfa), data_len)) |
514 | BUG(); | 521 | BUG(); |
515 | } | 522 | } |
516 | 523 | ||
@@ -667,12 +674,14 @@ nfqnl_set_mode(struct nfqnl_instance *queue, | |||
667 | static int | 674 | static int |
668 | dev_cmp(struct nfqnl_queue_entry *entry, unsigned long ifindex) | 675 | dev_cmp(struct nfqnl_queue_entry *entry, unsigned long ifindex) |
669 | { | 676 | { |
670 | if (entry->info->indev) | 677 | struct nf_info *entinf = entry->info; |
671 | if (entry->info->indev->ifindex == ifindex) | 678 | |
679 | if (entinf->indev) | ||
680 | if (entinf->indev->ifindex == ifindex) | ||
672 | return 1; | 681 | return 1; |
673 | 682 | ||
674 | if (entry->info->outdev) | 683 | if (entinf->outdev) |
675 | if (entry->info->outdev->ifindex == ifindex) | 684 | if (entinf->outdev->ifindex == ifindex) |
676 | return 1; | 685 | return 1; |
677 | 686 | ||
678 | return 0; | 687 | return 0; |
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c index a7cd2d4df757..77caf43a3109 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c | |||
@@ -52,16 +52,13 @@ MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); | |||
52 | /* | 52 | /* |
53 | */ | 53 | */ |
54 | 54 | ||
55 | static dev_info_t dev_info = "snd-pdaudiocf"; | ||
56 | static struct snd_card *card_list[SNDRV_CARDS]; | 55 | static struct snd_card *card_list[SNDRV_CARDS]; |
57 | static dev_link_t *dev_list; | ||
58 | 56 | ||
59 | /* | 57 | /* |
60 | * prototypes | 58 | * prototypes |
61 | */ | 59 | */ |
62 | static void pdacf_config(dev_link_t *link); | 60 | static void pdacf_config(dev_link_t *link); |
63 | static int pdacf_event(event_t event, int priority, event_callback_args_t *args); | 61 | static void snd_pdacf_detach(struct pcmcia_device *p_dev); |
64 | static void snd_pdacf_detach(dev_link_t *link); | ||
65 | 62 | ||
66 | static void pdacf_release(dev_link_t *link) | 63 | static void pdacf_release(dev_link_t *link) |
67 | { | 64 | { |
@@ -83,10 +80,6 @@ static int snd_pdacf_free(struct snd_pdacf *pdacf) | |||
83 | 80 | ||
84 | pdacf_release(link); | 81 | pdacf_release(link); |
85 | 82 | ||
86 | /* Break the link with Card Services */ | ||
87 | if (link->handle) | ||
88 | pcmcia_deregister_client(link->handle); | ||
89 | |||
90 | card_list[pdacf->index] = NULL; | 83 | card_list[pdacf->index] = NULL; |
91 | pdacf->card = NULL; | 84 | pdacf->card = NULL; |
92 | 85 | ||
@@ -103,11 +96,10 @@ static int snd_pdacf_dev_free(struct snd_device *device) | |||
103 | /* | 96 | /* |
104 | * snd_pdacf_attach - attach callback for cs | 97 | * snd_pdacf_attach - attach callback for cs |
105 | */ | 98 | */ |
106 | static dev_link_t *snd_pdacf_attach(void) | 99 | static int snd_pdacf_attach(struct pcmcia_device *p_dev) |
107 | { | 100 | { |
108 | client_reg_t client_reg; /* Register with cardmgr */ | 101 | int i; |
109 | dev_link_t *link; /* Info for cardmgr */ | 102 | dev_link_t *link; /* Info for cardmgr */ |
110 | int i, ret; | ||
111 | struct snd_pdacf *pdacf; | 103 | struct snd_pdacf *pdacf; |
112 | struct snd_card *card; | 104 | struct snd_card *card; |
113 | static struct snd_device_ops ops = { | 105 | static struct snd_device_ops ops = { |
@@ -122,26 +114,26 @@ static dev_link_t *snd_pdacf_attach(void) | |||
122 | } | 114 | } |
123 | if (i >= SNDRV_CARDS) { | 115 | if (i >= SNDRV_CARDS) { |
124 | snd_printk(KERN_ERR "pdacf: too many cards found\n"); | 116 | snd_printk(KERN_ERR "pdacf: too many cards found\n"); |
125 | return NULL; | 117 | return -EINVAL; |
126 | } | 118 | } |
127 | if (! enable[i]) | 119 | if (! enable[i]) |
128 | return NULL; /* disabled explicitly */ | 120 | return -ENODEV; /* disabled explicitly */ |
129 | 121 | ||
130 | /* ok, create a card instance */ | 122 | /* ok, create a card instance */ |
131 | card = snd_card_new(index[i], id[i], THIS_MODULE, 0); | 123 | card = snd_card_new(index[i], id[i], THIS_MODULE, 0); |
132 | if (card == NULL) { | 124 | if (card == NULL) { |
133 | snd_printk(KERN_ERR "pdacf: cannot create a card instance\n"); | 125 | snd_printk(KERN_ERR "pdacf: cannot create a card instance\n"); |
134 | return NULL; | 126 | return -ENOMEM; |
135 | } | 127 | } |
136 | 128 | ||
137 | pdacf = snd_pdacf_create(card); | 129 | pdacf = snd_pdacf_create(card); |
138 | if (! pdacf) | 130 | if (! pdacf) |
139 | return NULL; | 131 | return -EIO; |
140 | 132 | ||
141 | if (snd_device_new(card, SNDRV_DEV_LOWLEVEL, pdacf, &ops) < 0) { | 133 | if (snd_device_new(card, SNDRV_DEV_LOWLEVEL, pdacf, &ops) < 0) { |
142 | kfree(pdacf); | 134 | kfree(pdacf); |
143 | snd_card_free(card); | 135 | snd_card_free(card); |
144 | return NULL; | 136 | return -ENODEV; |
145 | } | 137 | } |
146 | 138 | ||
147 | pdacf->index = i; | 139 | pdacf->index = i; |
@@ -165,22 +157,12 @@ static dev_link_t *snd_pdacf_attach(void) | |||
165 | link->conf.Present = PRESENT_OPTION; | 157 | link->conf.Present = PRESENT_OPTION; |
166 | 158 | ||
167 | /* Chain drivers */ | 159 | /* Chain drivers */ |
168 | link->next = dev_list; | 160 | link->next = NULL; |
169 | dev_list = link; | ||
170 | |||
171 | /* Register with Card Services */ | ||
172 | client_reg.dev_info = &dev_info; | ||
173 | client_reg.Version = 0x0210; | ||
174 | client_reg.event_callback_args.client_data = link; | ||
175 | |||
176 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
177 | if (ret != CS_SUCCESS) { | ||
178 | cs_error(link->handle, RegisterClient, ret); | ||
179 | snd_pdacf_detach(link); | ||
180 | return NULL; | ||
181 | } | ||
182 | 161 | ||
183 | return link; | 162 | link->handle = p_dev; |
163 | pdacf_config(link); | ||
164 | |||
165 | return 0; | ||
184 | } | 166 | } |
185 | 167 | ||
186 | 168 | ||
@@ -227,21 +209,13 @@ static int snd_pdacf_assign_resources(struct snd_pdacf *pdacf, int port, int irq | |||
227 | /* | 209 | /* |
228 | * snd_pdacf_detach - detach callback for cs | 210 | * snd_pdacf_detach - detach callback for cs |
229 | */ | 211 | */ |
230 | static void snd_pdacf_detach(dev_link_t *link) | 212 | static void snd_pdacf_detach(struct pcmcia_device *p_dev) |
231 | { | 213 | { |
214 | dev_link_t *link = dev_to_instance(p_dev); | ||
232 | struct snd_pdacf *chip = link->priv; | 215 | struct snd_pdacf *chip = link->priv; |
233 | 216 | ||
234 | snd_printdd(KERN_DEBUG "pdacf_detach called\n"); | 217 | snd_printdd(KERN_DEBUG "pdacf_detach called\n"); |
235 | /* Remove the interface data from the linked list */ | 218 | |
236 | { | ||
237 | dev_link_t **linkp; | ||
238 | /* Locate device structure */ | ||
239 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
240 | if (*linkp == link) | ||
241 | break; | ||
242 | if (*linkp) | ||
243 | *linkp = link->next; | ||
244 | } | ||
245 | if (chip->chip_status & PDAUDIOCF_STAT_IS_CONFIGURED) | 219 | if (chip->chip_status & PDAUDIOCF_STAT_IS_CONFIGURED) |
246 | snd_pdacf_powerdown(chip); | 220 | snd_pdacf_powerdown(chip); |
247 | chip->chip_status |= PDAUDIOCF_STAT_IS_STALE; /* to be sure */ | 221 | chip->chip_status |= PDAUDIOCF_STAT_IS_STALE; /* to be sure */ |
@@ -310,62 +284,51 @@ failed: | |||
310 | pcmcia_release_irq(link->handle, &link->irq); | 284 | pcmcia_release_irq(link->handle, &link->irq); |
311 | } | 285 | } |
312 | 286 | ||
313 | /* | 287 | #ifdef CONFIG_PM |
314 | * event callback | 288 | |
315 | */ | 289 | static int pdacf_suspend(struct pcmcia_device *dev) |
316 | static int pdacf_event(event_t event, int priority, event_callback_args_t *args) | ||
317 | { | 290 | { |
318 | dev_link_t *link = args->client_data; | 291 | dev_link_t *link = dev_to_instance(dev); |
319 | struct snd_pdacf *chip = link->priv; | 292 | struct snd_pdacf *chip = link->priv; |
320 | 293 | ||
321 | switch (event) { | 294 | snd_printdd(KERN_DEBUG "SUSPEND\n"); |
322 | case CS_EVENT_CARD_REMOVAL: | 295 | link->state |= DEV_SUSPEND; |
323 | snd_printdd(KERN_DEBUG "CARD_REMOVAL..\n"); | 296 | if (chip) { |
324 | link->state &= ~DEV_PRESENT; | 297 | snd_printdd(KERN_DEBUG "snd_pdacf_suspend calling\n"); |
325 | if (link->state & DEV_CONFIG) { | 298 | snd_pdacf_suspend(chip, PMSG_SUSPEND); |
326 | chip->chip_status |= PDAUDIOCF_STAT_IS_STALE; | 299 | } |
327 | } | 300 | |
328 | break; | 301 | snd_printdd(KERN_DEBUG "RESET_PHYSICAL\n"); |
329 | case CS_EVENT_CARD_INSERTION: | 302 | if (link->state & DEV_CONFIG) |
330 | snd_printdd(KERN_DEBUG "CARD_INSERTION..\n"); | 303 | pcmcia_release_configuration(link->handle); |
331 | link->state |= DEV_PRESENT; | 304 | |
332 | pdacf_config(link); | 305 | return 0; |
333 | break; | 306 | } |
334 | #ifdef CONFIG_PM | 307 | |
335 | case CS_EVENT_PM_SUSPEND: | 308 | static int pdacf_resume(struct pcmcia_device *dev) |
336 | snd_printdd(KERN_DEBUG "SUSPEND\n"); | 309 | { |
337 | link->state |= DEV_SUSPEND; | 310 | dev_link_t *link = dev_to_instance(dev); |
311 | struct snd_pdacf *chip = link->priv; | ||
312 | |||
313 | snd_printdd(KERN_DEBUG "RESUME\n"); | ||
314 | link->state &= ~DEV_SUSPEND; | ||
315 | |||
316 | snd_printdd(KERN_DEBUG "CARD_RESET\n"); | ||
317 | if (DEV_OK(link)) { | ||
318 | snd_printdd(KERN_DEBUG "requestconfig...\n"); | ||
319 | pcmcia_request_configuration(link->handle, &link->conf); | ||
338 | if (chip) { | 320 | if (chip) { |
339 | snd_printdd(KERN_DEBUG "snd_pdacf_suspend calling\n"); | 321 | snd_printdd(KERN_DEBUG "calling snd_pdacf_resume\n"); |
340 | snd_pdacf_suspend(chip, PMSG_SUSPEND); | 322 | snd_pdacf_resume(chip); |
341 | } | ||
342 | /* Fall through... */ | ||
343 | case CS_EVENT_RESET_PHYSICAL: | ||
344 | snd_printdd(KERN_DEBUG "RESET_PHYSICAL\n"); | ||
345 | if (link->state & DEV_CONFIG) | ||
346 | pcmcia_release_configuration(link->handle); | ||
347 | break; | ||
348 | case CS_EVENT_PM_RESUME: | ||
349 | snd_printdd(KERN_DEBUG "RESUME\n"); | ||
350 | link->state &= ~DEV_SUSPEND; | ||
351 | /* Fall through... */ | ||
352 | case CS_EVENT_CARD_RESET: | ||
353 | snd_printdd(KERN_DEBUG "CARD_RESET\n"); | ||
354 | if (DEV_OK(link)) { | ||
355 | snd_printdd(KERN_DEBUG "requestconfig...\n"); | ||
356 | pcmcia_request_configuration(link->handle, &link->conf); | ||
357 | if (chip) { | ||
358 | snd_printdd(KERN_DEBUG "calling snd_pdacf_resume\n"); | ||
359 | snd_pdacf_resume(chip); | ||
360 | } | ||
361 | } | 323 | } |
362 | snd_printdd(KERN_DEBUG "resume done!\n"); | ||
363 | break; | ||
364 | #endif | ||
365 | } | 324 | } |
325 | snd_printdd(KERN_DEBUG "resume done!\n"); | ||
326 | |||
366 | return 0; | 327 | return 0; |
367 | } | 328 | } |
368 | 329 | ||
330 | #endif | ||
331 | |||
369 | /* | 332 | /* |
370 | * Module entry points | 333 | * Module entry points |
371 | */ | 334 | */ |
@@ -380,10 +343,14 @@ static struct pcmcia_driver pdacf_cs_driver = { | |||
380 | .drv = { | 343 | .drv = { |
381 | .name = "snd-pdaudiocf", | 344 | .name = "snd-pdaudiocf", |
382 | }, | 345 | }, |
383 | .attach = snd_pdacf_attach, | 346 | .probe = snd_pdacf_attach, |
384 | .event = pdacf_event, | 347 | .remove = snd_pdacf_detach, |
385 | .detach = snd_pdacf_detach, | ||
386 | .id_table = snd_pdacf_ids, | 348 | .id_table = snd_pdacf_ids, |
349 | #ifdef CONFIG_PM | ||
350 | .suspend = pdacf_suspend, | ||
351 | .resume = pdacf_resume, | ||
352 | #endif | ||
353 | |||
387 | }; | 354 | }; |
388 | 355 | ||
389 | static int __init init_pdacf(void) | 356 | static int __init init_pdacf(void) |
@@ -394,7 +361,6 @@ static int __init init_pdacf(void) | |||
394 | static void __exit exit_pdacf(void) | 361 | static void __exit exit_pdacf(void) |
395 | { | 362 | { |
396 | pcmcia_unregister_driver(&pdacf_cs_driver); | 363 | pcmcia_unregister_driver(&pdacf_cs_driver); |
397 | BUG_ON(dev_list != NULL); | ||
398 | } | 364 | } |
399 | 365 | ||
400 | module_init(init_pdacf); | 366 | module_init(init_pdacf); |
diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index 5bb079d17959..66900d20a42f 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c | |||
@@ -55,11 +55,6 @@ MODULE_PARM_DESC(ibl, "Capture IBL size for VXPocket soundcard."); | |||
55 | */ | 55 | */ |
56 | 56 | ||
57 | static unsigned int card_alloc; | 57 | static unsigned int card_alloc; |
58 | static dev_link_t *dev_list; /* Linked list of devices */ | ||
59 | static dev_info_t dev_info = "snd-vxpocket"; | ||
60 | |||
61 | |||
62 | static int vxpocket_event(event_t event, int priority, event_callback_args_t *args); | ||
63 | 58 | ||
64 | 59 | ||
65 | /* | 60 | /* |
@@ -73,11 +68,6 @@ static void vxpocket_release(dev_link_t *link) | |||
73 | pcmcia_release_irq(link->handle, &link->irq); | 68 | pcmcia_release_irq(link->handle, &link->irq); |
74 | link->state &= ~DEV_CONFIG; | 69 | link->state &= ~DEV_CONFIG; |
75 | } | 70 | } |
76 | if (link->handle) { | ||
77 | /* Break the link with Card Services */ | ||
78 | pcmcia_deregister_client(link->handle); | ||
79 | link->handle = NULL; | ||
80 | } | ||
81 | } | 71 | } |
82 | 72 | ||
83 | /* | 73 | /* |
@@ -144,11 +134,9 @@ static struct snd_vx_hardware vxp440_hw = { | |||
144 | */ | 134 | */ |
145 | static struct snd_vxpocket *snd_vxpocket_new(struct snd_card *card, int ibl) | 135 | static struct snd_vxpocket *snd_vxpocket_new(struct snd_card *card, int ibl) |
146 | { | 136 | { |
147 | client_reg_t client_reg; /* Register with cardmgr */ | ||
148 | dev_link_t *link; /* Info for cardmgr */ | 137 | dev_link_t *link; /* Info for cardmgr */ |
149 | struct vx_core *chip; | 138 | struct vx_core *chip; |
150 | struct snd_vxpocket *vxp; | 139 | struct snd_vxpocket *vxp; |
151 | int ret; | ||
152 | static struct snd_device_ops ops = { | 140 | static struct snd_device_ops ops = { |
153 | .dev_free = snd_vxpocket_dev_free, | 141 | .dev_free = snd_vxpocket_dev_free, |
154 | }; | 142 | }; |
@@ -184,26 +172,6 @@ static struct snd_vxpocket *snd_vxpocket_new(struct snd_card *card, int ibl) | |||
184 | link->conf.ConfigIndex = 1; | 172 | link->conf.ConfigIndex = 1; |
185 | link->conf.Present = PRESENT_OPTION; | 173 | link->conf.Present = PRESENT_OPTION; |
186 | 174 | ||
187 | /* Register with Card Services */ | ||
188 | memset(&client_reg, 0, sizeof(client_reg)); | ||
189 | client_reg.dev_info = &dev_info; | ||
190 | client_reg.EventMask = | ||
191 | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | ||
192 | #ifdef CONFIG_PM | ||
193 | | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | ||
194 | | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME | ||
195 | #endif | ||
196 | ; | ||
197 | client_reg.event_handler = &vxpocket_event; | ||
198 | client_reg.Version = 0x0210; | ||
199 | client_reg.event_callback_args.client_data = link; | ||
200 | |||
201 | ret = pcmcia_register_client(&link->handle, &client_reg); | ||
202 | if (ret != CS_SUCCESS) { | ||
203 | cs_error(link->handle, RegisterClient, ret); | ||
204 | return NULL; | ||
205 | } | ||
206 | |||
207 | return vxp; | 175 | return vxp; |
208 | } | 176 | } |
209 | 177 | ||
@@ -317,67 +285,55 @@ failed: | |||
317 | kfree(parse); | 285 | kfree(parse); |
318 | } | 286 | } |
319 | 287 | ||
288 | #ifdef CONFIG_PM | ||
320 | 289 | ||
321 | /* | 290 | static int vxp_suspend(struct pcmcia_device *dev) |
322 | * event callback | ||
323 | */ | ||
324 | static int vxpocket_event(event_t event, int priority, event_callback_args_t *args) | ||
325 | { | 291 | { |
326 | dev_link_t *link = args->client_data; | 292 | dev_link_t *link = dev_to_instance(dev); |
327 | struct vx_core *chip = link->priv; | 293 | struct vx_core *chip = link->priv; |
328 | 294 | ||
329 | switch (event) { | 295 | snd_printdd(KERN_DEBUG "SUSPEND\n"); |
330 | case CS_EVENT_CARD_REMOVAL: | 296 | link->state |= DEV_SUSPEND; |
331 | snd_printdd(KERN_DEBUG "CARD_REMOVAL..\n"); | 297 | if (chip) { |
332 | link->state &= ~DEV_PRESENT; | 298 | snd_printdd(KERN_DEBUG "snd_vx_suspend calling\n"); |
333 | if (link->state & DEV_CONFIG) | 299 | snd_vx_suspend(chip, PMSG_SUSPEND); |
334 | chip->chip_status |= VX_STAT_IS_STALE; | 300 | } |
335 | break; | 301 | snd_printdd(KERN_DEBUG "RESET_PHYSICAL\n"); |
336 | case CS_EVENT_CARD_INSERTION: | 302 | if (link->state & DEV_CONFIG) |
337 | snd_printdd(KERN_DEBUG "CARD_INSERTION..\n"); | 303 | pcmcia_release_configuration(link->handle); |
338 | link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; | 304 | |
339 | vxpocket_config(link); | 305 | return 0; |
340 | break; | 306 | } |
341 | #ifdef CONFIG_PM | 307 | |
342 | case CS_EVENT_PM_SUSPEND: | 308 | static int vxp_resume(struct pcmcia_device *dev) |
343 | snd_printdd(KERN_DEBUG "SUSPEND\n"); | 309 | { |
344 | link->state |= DEV_SUSPEND; | 310 | dev_link_t *link = dev_to_instance(dev); |
311 | struct vx_core *chip = link->priv; | ||
312 | |||
313 | snd_printdd(KERN_DEBUG "RESUME\n"); | ||
314 | link->state &= ~DEV_SUSPEND; | ||
315 | |||
316 | snd_printdd(KERN_DEBUG "CARD_RESET\n"); | ||
317 | if (DEV_OK(link)) { | ||
318 | //struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip; | ||
319 | snd_printdd(KERN_DEBUG "requestconfig...\n"); | ||
320 | pcmcia_request_configuration(link->handle, &link->conf); | ||
345 | if (chip) { | 321 | if (chip) { |
346 | snd_printdd(KERN_DEBUG "snd_vx_suspend calling\n"); | 322 | snd_printdd(KERN_DEBUG "calling snd_vx_resume\n"); |
347 | snd_vx_suspend(chip, PMSG_SUSPEND); | 323 | snd_vx_resume(chip); |
348 | } | 324 | } |
349 | /* Fall through... */ | ||
350 | case CS_EVENT_RESET_PHYSICAL: | ||
351 | snd_printdd(KERN_DEBUG "RESET_PHYSICAL\n"); | ||
352 | if (link->state & DEV_CONFIG) | ||
353 | pcmcia_release_configuration(link->handle); | ||
354 | break; | ||
355 | case CS_EVENT_PM_RESUME: | ||
356 | snd_printdd(KERN_DEBUG "RESUME\n"); | ||
357 | link->state &= ~DEV_SUSPEND; | ||
358 | /* Fall through... */ | ||
359 | case CS_EVENT_CARD_RESET: | ||
360 | snd_printdd(KERN_DEBUG "CARD_RESET\n"); | ||
361 | if (DEV_OK(link)) { | ||
362 | //struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip; | ||
363 | snd_printdd(KERN_DEBUG "requestconfig...\n"); | ||
364 | pcmcia_request_configuration(link->handle, &link->conf); | ||
365 | if (chip) { | ||
366 | snd_printdd(KERN_DEBUG "calling snd_vx_resume\n"); | ||
367 | snd_vx_resume(chip); | ||
368 | } | ||
369 | } | ||
370 | snd_printdd(KERN_DEBUG "resume done!\n"); | ||
371 | break; | ||
372 | #endif | ||
373 | } | 325 | } |
326 | snd_printdd(KERN_DEBUG "resume done!\n"); | ||
327 | |||
374 | return 0; | 328 | return 0; |
375 | } | 329 | } |
376 | 330 | ||
331 | #endif | ||
332 | |||
377 | 333 | ||
378 | /* | 334 | /* |
379 | */ | 335 | */ |
380 | static dev_link_t *vxpocket_attach(void) | 336 | static int vxpocket_attach(struct pcmcia_device *p_dev) |
381 | { | 337 | { |
382 | struct snd_card *card; | 338 | struct snd_card *card; |
383 | struct snd_vxpocket *vxp; | 339 | struct snd_vxpocket *vxp; |
@@ -390,22 +346,22 @@ static dev_link_t *vxpocket_attach(void) | |||
390 | } | 346 | } |
391 | if (i >= SNDRV_CARDS) { | 347 | if (i >= SNDRV_CARDS) { |
392 | snd_printk(KERN_ERR "vxpocket: too many cards found\n"); | 348 | snd_printk(KERN_ERR "vxpocket: too many cards found\n"); |
393 | return NULL; | 349 | return -EINVAL; |
394 | } | 350 | } |
395 | if (! enable[i]) | 351 | if (! enable[i]) |
396 | return NULL; /* disabled explicitly */ | 352 | return -ENODEV; /* disabled explicitly */ |
397 | 353 | ||
398 | /* ok, create a card instance */ | 354 | /* ok, create a card instance */ |
399 | card = snd_card_new(index[i], id[i], THIS_MODULE, 0); | 355 | card = snd_card_new(index[i], id[i], THIS_MODULE, 0); |
400 | if (card == NULL) { | 356 | if (card == NULL) { |
401 | snd_printk(KERN_ERR "vxpocket: cannot create a card instance\n"); | 357 | snd_printk(KERN_ERR "vxpocket: cannot create a card instance\n"); |
402 | return NULL; | 358 | return -ENOMEM; |
403 | } | 359 | } |
404 | 360 | ||
405 | vxp = snd_vxpocket_new(card, ibl[i]); | 361 | vxp = snd_vxpocket_new(card, ibl[i]); |
406 | if (! vxp) { | 362 | if (! vxp) { |
407 | snd_card_free(card); | 363 | snd_card_free(card); |
408 | return NULL; | 364 | return -ENODEV; |
409 | } | 365 | } |
410 | card->private_data = vxp; | 366 | card->private_data = vxp; |
411 | 367 | ||
@@ -413,17 +369,21 @@ static dev_link_t *vxpocket_attach(void) | |||
413 | card_alloc |= 1 << i; | 369 | card_alloc |= 1 << i; |
414 | 370 | ||
415 | /* Chain drivers */ | 371 | /* Chain drivers */ |
416 | vxp->link.next = dev_list; | 372 | vxp->link.next = NULL; |
417 | dev_list = &vxp->link; | 373 | |
374 | vxp->link.handle = p_dev; | ||
375 | vxp->link.state |= DEV_PRESENT | DEV_CONFIG_PENDING; | ||
376 | p_dev->instance = &vxp->link; | ||
377 | vxpocket_config(&vxp->link); | ||
418 | 378 | ||
419 | return &vxp->link; | 379 | return 0; |
420 | } | 380 | } |
421 | 381 | ||
422 | static void vxpocket_detach(dev_link_t *link) | 382 | static void vxpocket_detach(struct pcmcia_device *p_dev) |
423 | { | 383 | { |
384 | dev_link_t *link = dev_to_instance(p_dev); | ||
424 | struct snd_vxpocket *vxp; | 385 | struct snd_vxpocket *vxp; |
425 | struct vx_core *chip; | 386 | struct vx_core *chip; |
426 | dev_link_t **linkp; | ||
427 | 387 | ||
428 | if (! link) | 388 | if (! link) |
429 | return; | 389 | return; |
@@ -432,13 +392,6 @@ static void vxpocket_detach(dev_link_t *link) | |||
432 | chip = (struct vx_core *)vxp; | 392 | chip = (struct vx_core *)vxp; |
433 | card_alloc &= ~(1 << vxp->index); | 393 | card_alloc &= ~(1 << vxp->index); |
434 | 394 | ||
435 | /* Remove the interface data from the linked list */ | ||
436 | for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) | ||
437 | if (*linkp == link) { | ||
438 | *linkp = link->next; | ||
439 | break; | ||
440 | } | ||
441 | |||
442 | chip->chip_status |= VX_STAT_IS_STALE; /* to be sure */ | 395 | chip->chip_status |= VX_STAT_IS_STALE; /* to be sure */ |
443 | snd_card_disconnect(chip->card); | 396 | snd_card_disconnect(chip->card); |
444 | vxpocket_release(link); | 397 | vxpocket_release(link); |
@@ -460,10 +413,13 @@ static struct pcmcia_driver vxp_cs_driver = { | |||
460 | .drv = { | 413 | .drv = { |
461 | .name = "snd-vxpocket", | 414 | .name = "snd-vxpocket", |
462 | }, | 415 | }, |
463 | .attach = vxpocket_attach, | 416 | .probe = vxpocket_attach, |
464 | .detach = vxpocket_detach, | 417 | .remove = vxpocket_detach, |
465 | .event = vxpocket_event, | ||
466 | .id_table = vxp_ids, | 418 | .id_table = vxp_ids, |
419 | #ifdef CONFIG_PM | ||
420 | .suspend = vxp_suspend, | ||
421 | .resume = vxp_resume, | ||
422 | #endif | ||
467 | }; | 423 | }; |
468 | 424 | ||
469 | static int __init init_vxpocket(void) | 425 | static int __init init_vxpocket(void) |
@@ -474,7 +430,6 @@ static int __init init_vxpocket(void) | |||
474 | static void __exit exit_vxpocket(void) | 430 | static void __exit exit_vxpocket(void) |
475 | { | 431 | { |
476 | pcmcia_unregister_driver(&vxp_cs_driver); | 432 | pcmcia_unregister_driver(&vxp_cs_driver); |
477 | BUG_ON(dev_list != NULL); | ||
478 | } | 433 | } |
479 | 434 | ||
480 | module_init(init_vxpocket); | 435 | module_init(init_vxpocket); |