diff options
author | James Ketrenos <jketreno@linux.intel.com> | 2005-08-24 22:43:11 -0400 |
---|---|---|
committer | James Ketrenos <jketreno@linux.intel.com> | 2005-11-07 18:49:53 -0500 |
commit | a613bffd3aac89bb0a8c9b7afa72af9b0ae30f0a (patch) | |
tree | 982d4f3de285993749138b0e6e2f2d778b120407 | |
parent | ea2b26e0a0264650e13acac8e66d315bb818897c (diff) |
Catch ipw2200 up to equivelancy with v1.0.2
Removed unneeded parenthesis around numeric constant defines
Added support for iwspy
Put in fix for Ad-Hoc mode not passing through all packets (thanks to KKH)
Put in fix for fragmentation not working for fragment sizes between
441-464 bytes (thanks to Mohamed Abbas)
Fixed #592 problem of CONFIG_IEEE80211_WPA_MODULE not including WPA
support into the driver -- fixed as a result of no longer limiting WPAs
inclusion
Fixed #594 problem with user rates mask causing lack of association if
AP mandatory rate is masked out. We now add back in as a supported rate
any mandatory rate.
Fixed #597 kernel oops due to calling dev_kfree_skb on an skb multiple times.
Added code to control LEDs that can be controlled through the wireless
NIC (vs. non-wireless HW interfaces) -- this is currently disabled by
default due to reports by some users of it hanging their laptop.
Added some more debug messages around fragmentation logic
Added locking around STATUS_HCMD_ACTIVE to prevent re-entry race
conditions
Moved ipw_adapter_restart to only execute on the priv->workqueue to
keep keyboard errors from occuring during adapter restart
Added CFG_BACKGROUND_SCAN to easily allow people to play with
background scanning implementations
Modified WPA logic to send WPA IE if one is set (vs. being based on
wpa_enabled)
Modified scan result logic to report WPA and RSN IEs if set (vs. being
based on wpa_enabled)
Fixed issues with endianess compatability between the host and
wireless adapter (thanks to York Liu and Yi Zhu)
Fixed problem with Ad-Hoc network creation causing a firmware error if
a scan was actively running (thanks to Mohamed Abbas)
Signed-off-by: James Ketrenos <jketreno@linux.intel.com>
-rw-r--r-- | drivers/net/wireless/ipw2200.c | 962 | ||||
-rw-r--r-- | drivers/net/wireless/ipw2200.h | 73 |
2 files changed, 773 insertions, 262 deletions
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index ddbee3edcd8c..ea7a3dcf1daa 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c | |||
@@ -32,7 +32,7 @@ | |||
32 | 32 | ||
33 | #include "ipw2200.h" | 33 | #include "ipw2200.h" |
34 | 34 | ||
35 | #define IPW2200_VERSION "1.0.1" | 35 | #define IPW2200_VERSION "1.0.2" |
36 | #define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver" | 36 | #define DRV_DESCRIPTION "Intel(R) PRO/Wireless 2200/2915 Network Driver" |
37 | #define DRV_COPYRIGHT "Copyright(c) 2003-2004 Intel Corporation" | 37 | #define DRV_COPYRIGHT "Copyright(c) 2003-2004 Intel Corporation" |
38 | #define DRV_VERSION IPW2200_VERSION | 38 | #define DRV_VERSION IPW2200_VERSION |
@@ -49,6 +49,7 @@ static int mode = 0; | |||
49 | static u32 ipw_debug_level; | 49 | static u32 ipw_debug_level; |
50 | static int associate = 1; | 50 | static int associate = 1; |
51 | static int auto_create = 1; | 51 | static int auto_create = 1; |
52 | static int led = 0; | ||
52 | static int disable = 0; | 53 | static int disable = 0; |
53 | static const char ipw_modes[] = { | 54 | static const char ipw_modes[] = { |
54 | 'a', 'b', 'g', '?' | 55 | 'a', 'b', 'g', '?' |
@@ -637,6 +638,313 @@ static void ipw_init_ordinals(struct ipw_priv *priv) | |||
637 | 638 | ||
638 | } | 639 | } |
639 | 640 | ||
641 | u32 ipw_register_toggle(u32 reg) | ||
642 | { | ||
643 | reg &= ~CX2_START_STANDBY; | ||
644 | if (reg & CX2_GATE_ODMA) | ||
645 | reg &= ~CX2_GATE_ODMA; | ||
646 | if (reg & CX2_GATE_IDMA) | ||
647 | reg &= ~CX2_GATE_IDMA; | ||
648 | if (reg & CX2_GATE_ADMA) | ||
649 | reg &= ~CX2_GATE_ADMA; | ||
650 | return reg; | ||
651 | } | ||
652 | |||
653 | /* | ||
654 | * LED behavior: | ||
655 | * - On radio ON, turn on any LEDs that require to be on during start | ||
656 | * - On initialization, start unassociated blink | ||
657 | * - On association, disable unassociated blink | ||
658 | * - On disassociation, start unassociated blink | ||
659 | * - On radio OFF, turn off any LEDs started during radio on | ||
660 | * | ||
661 | */ | ||
662 | #define LD_TIME_LINK_ON 300 | ||
663 | #define LD_TIME_LINK_OFF 2700 | ||
664 | #define LD_TIME_ACT_ON 250 | ||
665 | |||
666 | void ipw_led_link_on(struct ipw_priv *priv) | ||
667 | { | ||
668 | unsigned long flags; | ||
669 | u32 led; | ||
670 | |||
671 | /* If configured to not use LEDs, or nic_type is 1, | ||
672 | * then we don't toggle a LINK led */ | ||
673 | if (priv->config & CFG_NO_LED || priv->nic_type == EEPROM_NIC_TYPE_1) | ||
674 | return; | ||
675 | |||
676 | spin_lock_irqsave(&priv->lock, flags); | ||
677 | |||
678 | if (!(priv->status & STATUS_RF_KILL_MASK) && | ||
679 | !(priv->status & STATUS_LED_LINK_ON)) { | ||
680 | IPW_DEBUG_LED("Link LED On\n"); | ||
681 | led = ipw_read_reg32(priv, CX2_EVENT_REG); | ||
682 | led |= priv->led_association_on; | ||
683 | |||
684 | led = ipw_register_toggle(led); | ||
685 | |||
686 | IPW_DEBUG_LED("Reg: 0x%08X\n", led); | ||
687 | ipw_write_reg32(priv, CX2_EVENT_REG, led); | ||
688 | |||
689 | priv->status |= STATUS_LED_LINK_ON; | ||
690 | |||
691 | /* If we aren't associated, schedule turning the LED off */ | ||
692 | if (!(priv->status & STATUS_ASSOCIATED)) | ||
693 | queue_delayed_work(priv->workqueue, | ||
694 | &priv->led_link_off, | ||
695 | LD_TIME_LINK_ON); | ||
696 | } | ||
697 | |||
698 | spin_unlock_irqrestore(&priv->lock, flags); | ||
699 | } | ||
700 | |||
701 | void ipw_led_link_off(struct ipw_priv *priv) | ||
702 | { | ||
703 | unsigned long flags; | ||
704 | u32 led; | ||
705 | |||
706 | /* If configured not to use LEDs, or nic type is 1, | ||
707 | * then we don't goggle the LINK led. */ | ||
708 | if (priv->config & CFG_NO_LED || priv->nic_type == EEPROM_NIC_TYPE_1) | ||
709 | return; | ||
710 | |||
711 | spin_lock_irqsave(&priv->lock, flags); | ||
712 | |||
713 | if (priv->status & STATUS_LED_LINK_ON) { | ||
714 | led = ipw_read_reg32(priv, CX2_EVENT_REG); | ||
715 | led &= priv->led_association_off; | ||
716 | led = ipw_register_toggle(led); | ||
717 | |||
718 | IPW_DEBUG_LED("Reg: 0x%08X\n", led); | ||
719 | ipw_write_reg32(priv, CX2_EVENT_REG, led); | ||
720 | |||
721 | IPW_DEBUG_LED("Link LED Off\n"); | ||
722 | |||
723 | priv->status &= ~STATUS_LED_LINK_ON; | ||
724 | |||
725 | /* If we aren't associated and the radio is on, schedule | ||
726 | * turning the LED on (blink while unassociated) */ | ||
727 | if (!(priv->status & STATUS_RF_KILL_MASK) && | ||
728 | !(priv->status & STATUS_ASSOCIATED)) | ||
729 | queue_delayed_work(priv->workqueue, &priv->led_link_on, | ||
730 | LD_TIME_LINK_OFF); | ||
731 | |||
732 | } | ||
733 | |||
734 | spin_unlock_irqrestore(&priv->lock, flags); | ||
735 | } | ||
736 | |||
737 | void ipw_led_activity_on(struct ipw_priv *priv) | ||
738 | { | ||
739 | unsigned long flags; | ||
740 | u32 led; | ||
741 | |||
742 | if (priv->config & CFG_NO_LED) | ||
743 | return; | ||
744 | |||
745 | spin_lock_irqsave(&priv->lock, flags); | ||
746 | |||
747 | if (priv->status & STATUS_RF_KILL_MASK) { | ||
748 | spin_unlock_irqrestore(&priv->lock, flags); | ||
749 | return; | ||
750 | } | ||
751 | |||
752 | if (!(priv->status & STATUS_LED_ACT_ON)) { | ||
753 | led = ipw_read_reg32(priv, CX2_EVENT_REG); | ||
754 | led |= priv->led_activity_on; | ||
755 | |||
756 | led = ipw_register_toggle(led); | ||
757 | |||
758 | IPW_DEBUG_LED("Reg: 0x%08X\n", led); | ||
759 | ipw_write_reg32(priv, CX2_EVENT_REG, led); | ||
760 | |||
761 | IPW_DEBUG_LED("Activity LED On\n"); | ||
762 | |||
763 | priv->status |= STATUS_LED_ACT_ON; | ||
764 | |||
765 | queue_delayed_work(priv->workqueue, &priv->led_act_off, | ||
766 | LD_TIME_ACT_ON); | ||
767 | } else { | ||
768 | /* Reschedule LED off for full time period */ | ||
769 | cancel_delayed_work(&priv->led_act_off); | ||
770 | queue_delayed_work(priv->workqueue, &priv->led_act_off, | ||
771 | LD_TIME_ACT_ON); | ||
772 | } | ||
773 | |||
774 | spin_unlock_irqrestore(&priv->lock, flags); | ||
775 | } | ||
776 | |||
777 | void ipw_led_activity_off(struct ipw_priv *priv) | ||
778 | { | ||
779 | unsigned long flags; | ||
780 | u32 led; | ||
781 | |||
782 | if (priv->config & CFG_NO_LED) | ||
783 | return; | ||
784 | |||
785 | spin_lock_irqsave(&priv->lock, flags); | ||
786 | |||
787 | if (priv->status & STATUS_LED_ACT_ON) { | ||
788 | led = ipw_read_reg32(priv, CX2_EVENT_REG); | ||
789 | led &= priv->led_activity_off; | ||
790 | |||
791 | led = ipw_register_toggle(led); | ||
792 | |||
793 | IPW_DEBUG_LED("Reg: 0x%08X\n", led); | ||
794 | ipw_write_reg32(priv, CX2_EVENT_REG, led); | ||
795 | |||
796 | IPW_DEBUG_LED("Activity LED Off\n"); | ||
797 | |||
798 | priv->status &= ~STATUS_LED_ACT_ON; | ||
799 | } | ||
800 | |||
801 | spin_unlock_irqrestore(&priv->lock, flags); | ||
802 | } | ||
803 | |||
804 | void ipw_led_band_on(struct ipw_priv *priv) | ||
805 | { | ||
806 | unsigned long flags; | ||
807 | u32 led; | ||
808 | |||
809 | /* Only nic type 1 supports mode LEDs */ | ||
810 | if (priv->config & CFG_NO_LED || priv->nic_type != EEPROM_NIC_TYPE_1) | ||
811 | return; | ||
812 | |||
813 | spin_lock_irqsave(&priv->lock, flags); | ||
814 | |||
815 | led = ipw_read_reg32(priv, CX2_EVENT_REG); | ||
816 | if (priv->assoc_network->mode == IEEE_A) { | ||
817 | led |= priv->led_ofdm_on; | ||
818 | led &= priv->led_association_off; | ||
819 | IPW_DEBUG_LED("Mode LED On: 802.11a\n"); | ||
820 | } else if (priv->assoc_network->mode == IEEE_G) { | ||
821 | led |= priv->led_ofdm_on; | ||
822 | led |= priv->led_association_on; | ||
823 | IPW_DEBUG_LED("Mode LED On: 802.11g\n"); | ||
824 | } else { | ||
825 | led &= priv->led_ofdm_off; | ||
826 | led |= priv->led_association_on; | ||
827 | IPW_DEBUG_LED("Mode LED On: 802.11b\n"); | ||
828 | } | ||
829 | |||
830 | led = ipw_register_toggle(led); | ||
831 | |||
832 | IPW_DEBUG_LED("Reg: 0x%08X\n", led); | ||
833 | ipw_write_reg32(priv, CX2_EVENT_REG, led); | ||
834 | |||
835 | spin_unlock_irqrestore(&priv->lock, flags); | ||
836 | } | ||
837 | |||
838 | void ipw_led_band_off(struct ipw_priv *priv) | ||
839 | { | ||
840 | unsigned long flags; | ||
841 | u32 led; | ||
842 | |||
843 | /* Only nic type 1 supports mode LEDs */ | ||
844 | if (priv->config & CFG_NO_LED || priv->nic_type != EEPROM_NIC_TYPE_1) | ||
845 | return; | ||
846 | |||
847 | spin_lock_irqsave(&priv->lock, flags); | ||
848 | |||
849 | led = ipw_read_reg32(priv, CX2_EVENT_REG); | ||
850 | led &= priv->led_ofdm_off; | ||
851 | led &= priv->led_association_off; | ||
852 | |||
853 | led = ipw_register_toggle(led); | ||
854 | |||
855 | IPW_DEBUG_LED("Reg: 0x%08X\n", led); | ||
856 | ipw_write_reg32(priv, CX2_EVENT_REG, led); | ||
857 | |||
858 | spin_unlock_irqrestore(&priv->lock, flags); | ||
859 | } | ||
860 | |||
861 | void ipw_led_radio_on(struct ipw_priv *priv) | ||
862 | { | ||
863 | ipw_led_link_on(priv); | ||
864 | } | ||
865 | |||
866 | void ipw_led_radio_off(struct ipw_priv *priv) | ||
867 | { | ||
868 | ipw_led_activity_off(priv); | ||
869 | ipw_led_link_off(priv); | ||
870 | } | ||
871 | |||
872 | void ipw_led_link_up(struct ipw_priv *priv) | ||
873 | { | ||
874 | /* Set the Link Led on for all nic types */ | ||
875 | ipw_led_link_on(priv); | ||
876 | } | ||
877 | |||
878 | void ipw_led_link_down(struct ipw_priv *priv) | ||
879 | { | ||
880 | ipw_led_activity_off(priv); | ||
881 | ipw_led_link_off(priv); | ||
882 | |||
883 | if (priv->status & STATUS_RF_KILL_MASK) | ||
884 | ipw_led_radio_off(priv); | ||
885 | } | ||
886 | |||
887 | void ipw_led_init(struct ipw_priv *priv) | ||
888 | { | ||
889 | priv->nic_type = priv->eeprom[EEPROM_NIC_TYPE]; | ||
890 | |||
891 | /* Set the default PINs for the link and activity leds */ | ||
892 | priv->led_activity_on = CX2_ACTIVITY_LED; | ||
893 | priv->led_activity_off = ~(CX2_ACTIVITY_LED); | ||
894 | |||
895 | priv->led_association_on = CX2_ASSOCIATED_LED; | ||
896 | priv->led_association_off = ~(CX2_ASSOCIATED_LED); | ||
897 | |||
898 | /* Set the default PINs for the OFDM leds */ | ||
899 | priv->led_ofdm_on = CX2_OFDM_LED; | ||
900 | priv->led_ofdm_off = ~(CX2_OFDM_LED); | ||
901 | |||
902 | switch (priv->nic_type) { | ||
903 | case EEPROM_NIC_TYPE_1: | ||
904 | /* In this NIC type, the LEDs are reversed.... */ | ||
905 | priv->led_activity_on = CX2_ASSOCIATED_LED; | ||
906 | priv->led_activity_off = ~(CX2_ASSOCIATED_LED); | ||
907 | priv->led_association_on = CX2_ACTIVITY_LED; | ||
908 | priv->led_association_off = ~(CX2_ACTIVITY_LED); | ||
909 | |||
910 | if (!(priv->config & CFG_NO_LED)) | ||
911 | ipw_led_band_on(priv); | ||
912 | |||
913 | /* And we don't blink link LEDs for this nic, so | ||
914 | * just return here */ | ||
915 | return; | ||
916 | |||
917 | case EEPROM_NIC_TYPE_3: | ||
918 | case EEPROM_NIC_TYPE_2: | ||
919 | case EEPROM_NIC_TYPE_4: | ||
920 | case EEPROM_NIC_TYPE_0: | ||
921 | break; | ||
922 | |||
923 | default: | ||
924 | IPW_DEBUG_INFO("Unknown NIC type from EEPROM: %d\n", | ||
925 | priv->nic_type); | ||
926 | priv->nic_type = EEPROM_NIC_TYPE_0; | ||
927 | break; | ||
928 | } | ||
929 | |||
930 | if (!(priv->config & CFG_NO_LED)) { | ||
931 | if (priv->status & STATUS_ASSOCIATED) | ||
932 | ipw_led_link_on(priv); | ||
933 | else | ||
934 | ipw_led_link_off(priv); | ||
935 | } | ||
936 | } | ||
937 | |||
938 | void ipw_led_shutdown(struct ipw_priv *priv) | ||
939 | { | ||
940 | cancel_delayed_work(&priv->led_link_on); | ||
941 | cancel_delayed_work(&priv->led_link_off); | ||
942 | cancel_delayed_work(&priv->led_act_off); | ||
943 | ipw_led_activity_off(priv); | ||
944 | ipw_led_link_off(priv); | ||
945 | ipw_led_band_off(priv); | ||
946 | } | ||
947 | |||
640 | /* | 948 | /* |
641 | * The following adds a new attribute to the sysfs representation | 949 | * The following adds a new attribute to the sysfs representation |
642 | * of this device driver (i.e. a new file in /sys/bus/pci/drivers/ipw/) | 950 | * of this device driver (i.e. a new file in /sys/bus/pci/drivers/ipw/) |
@@ -648,8 +956,9 @@ static ssize_t show_debug_level(struct device_driver *d, char *buf) | |||
648 | { | 956 | { |
649 | return sprintf(buf, "0x%08X\n", ipw_debug_level); | 957 | return sprintf(buf, "0x%08X\n", ipw_debug_level); |
650 | } | 958 | } |
651 | static ssize_t store_debug_level(struct device_driver *d, | 959 | |
652 | const char *buf, size_t count) | 960 | static ssize_t store_debug_level(struct device_driver *d, const char *buf, |
961 | size_t count) | ||
653 | { | 962 | { |
654 | char *p = (char *)buf; | 963 | char *p = (char *)buf; |
655 | u32 val; | 964 | u32 val; |
@@ -673,6 +982,82 @@ static ssize_t store_debug_level(struct device_driver *d, | |||
673 | static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, | 982 | static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO, |
674 | show_debug_level, store_debug_level); | 983 | show_debug_level, store_debug_level); |
675 | 984 | ||
985 | static ssize_t show_scan_age(struct device *d, struct device_attribute *attr, | ||
986 | char *buf) | ||
987 | { | ||
988 | struct ipw_priv *priv = dev_get_drvdata(d); | ||
989 | return sprintf(buf, "%d\n", priv->ieee->scan_age); | ||
990 | } | ||
991 | |||
992 | static ssize_t store_scan_age(struct device *d, struct device_attribute *attr, | ||
993 | const char *buf, size_t count) | ||
994 | { | ||
995 | struct ipw_priv *priv = dev_get_drvdata(d); | ||
996 | struct net_device *dev = priv->net_dev; | ||
997 | char buffer[] = "00000000"; | ||
998 | unsigned long len = | ||
999 | (sizeof(buffer) - 1) > count ? count : sizeof(buffer) - 1; | ||
1000 | unsigned long val; | ||
1001 | char *p = buffer; | ||
1002 | |||
1003 | IPW_DEBUG_INFO("enter\n"); | ||
1004 | |||
1005 | strncpy(buffer, buf, len); | ||
1006 | buffer[len] = 0; | ||
1007 | |||
1008 | if (p[1] == 'x' || p[1] == 'X' || p[0] == 'x' || p[0] == 'X') { | ||
1009 | p++; | ||
1010 | if (p[0] == 'x' || p[0] == 'X') | ||
1011 | p++; | ||
1012 | val = simple_strtoul(p, &p, 16); | ||
1013 | } else | ||
1014 | val = simple_strtoul(p, &p, 10); | ||
1015 | if (p == buffer) { | ||
1016 | IPW_DEBUG_INFO("%s: user supplied invalid value.\n", dev->name); | ||
1017 | } else { | ||
1018 | priv->ieee->scan_age = val; | ||
1019 | IPW_DEBUG_INFO("set scan_age = %u\n", priv->ieee->scan_age); | ||
1020 | } | ||
1021 | |||
1022 | IPW_DEBUG_INFO("exit\n"); | ||
1023 | return len; | ||
1024 | } | ||
1025 | |||
1026 | static DEVICE_ATTR(scan_age, S_IWUSR | S_IRUGO, show_scan_age, store_scan_age); | ||
1027 | |||
1028 | static ssize_t show_led(struct device *d, struct device_attribute *attr, | ||
1029 | char *buf) | ||
1030 | { | ||
1031 | struct ipw_priv *priv = dev_get_drvdata(d); | ||
1032 | return sprintf(buf, "%d\n", (priv->config & CFG_NO_LED) ? 0 : 1); | ||
1033 | } | ||
1034 | |||
1035 | static ssize_t store_led(struct device *d, struct device_attribute *attr, | ||
1036 | const char *buf, size_t count) | ||
1037 | { | ||
1038 | struct ipw_priv *priv = dev_get_drvdata(d); | ||
1039 | |||
1040 | IPW_DEBUG_INFO("enter\n"); | ||
1041 | |||
1042 | if (count == 0) | ||
1043 | return 0; | ||
1044 | |||
1045 | if (*buf == 0) { | ||
1046 | IPW_DEBUG_LED("Disabling LED control.\n"); | ||
1047 | priv->config |= CFG_NO_LED; | ||
1048 | ipw_led_shutdown(priv); | ||
1049 | } else { | ||
1050 | IPW_DEBUG_LED("Enabling LED control.\n"); | ||
1051 | priv->config &= ~CFG_NO_LED; | ||
1052 | ipw_led_init(priv); | ||
1053 | } | ||
1054 | |||
1055 | IPW_DEBUG_INFO("exit\n"); | ||
1056 | return count; | ||
1057 | } | ||
1058 | |||
1059 | static DEVICE_ATTR(led, S_IWUSR | S_IRUGO, show_led, store_led); | ||
1060 | |||
676 | static ssize_t show_status(struct device *d, | 1061 | static ssize_t show_status(struct device *d, |
677 | struct device_attribute *attr, char *buf) | 1062 | struct device_attribute *attr, char *buf) |
678 | { | 1063 | { |
@@ -694,23 +1079,8 @@ static DEVICE_ATTR(cfg, S_IRUGO, show_cfg, NULL); | |||
694 | static ssize_t show_nic_type(struct device *d, | 1079 | static ssize_t show_nic_type(struct device *d, |
695 | struct device_attribute *attr, char *buf) | 1080 | struct device_attribute *attr, char *buf) |
696 | { | 1081 | { |
697 | struct ipw_priv *p = d->driver_data; | 1082 | struct ipw_priv *priv = d->driver_data; |
698 | u8 type = p->eeprom[EEPROM_NIC_TYPE]; | 1083 | return sprintf(buf, "TYPE: %d\n", priv->nic_type); |
699 | |||
700 | switch (type) { | ||
701 | case EEPROM_NIC_TYPE_STANDARD: | ||
702 | return sprintf(buf, "STANDARD\n"); | ||
703 | case EEPROM_NIC_TYPE_DELL: | ||
704 | return sprintf(buf, "DELL\n"); | ||
705 | case EEPROM_NIC_TYPE_FUJITSU: | ||
706 | return sprintf(buf, "FUJITSU\n"); | ||
707 | case EEPROM_NIC_TYPE_IBM: | ||
708 | return sprintf(buf, "IBM\n"); | ||
709 | case EEPROM_NIC_TYPE_HP: | ||
710 | return sprintf(buf, "HP\n"); | ||
711 | } | ||
712 | |||
713 | return sprintf(buf, "UNKNOWN\n"); | ||
714 | } | 1084 | } |
715 | 1085 | ||
716 | static DEVICE_ATTR(nic_type, S_IRUGO, show_nic_type, NULL); | 1086 | static DEVICE_ATTR(nic_type, S_IRUGO, show_nic_type, NULL); |
@@ -955,9 +1325,8 @@ static int ipw_radio_kill_sw(struct ipw_priv *priv, int disable_radio) | |||
955 | if (disable_radio) { | 1325 | if (disable_radio) { |
956 | priv->status |= STATUS_RF_KILL_SW; | 1326 | priv->status |= STATUS_RF_KILL_SW; |
957 | 1327 | ||
958 | if (priv->workqueue) { | 1328 | if (priv->workqueue) |
959 | cancel_delayed_work(&priv->request_scan); | 1329 | cancel_delayed_work(&priv->request_scan); |
960 | } | ||
961 | wake_up_interruptible(&priv->wait_command_queue); | 1330 | wake_up_interruptible(&priv->wait_command_queue); |
962 | queue_work(priv->workqueue, &priv->down); | 1331 | queue_work(priv->workqueue, &priv->down); |
963 | } else { | 1332 | } else { |
@@ -1081,11 +1450,9 @@ static void ipw_irq_tasklet(struct ipw_priv *priv) | |||
1081 | IPW_DEBUG_RF_KILL("RF_KILL_DONE\n"); | 1450 | IPW_DEBUG_RF_KILL("RF_KILL_DONE\n"); |
1082 | priv->status |= STATUS_RF_KILL_HW; | 1451 | priv->status |= STATUS_RF_KILL_HW; |
1083 | wake_up_interruptible(&priv->wait_command_queue); | 1452 | wake_up_interruptible(&priv->wait_command_queue); |
1084 | netif_carrier_off(priv->net_dev); | ||
1085 | netif_stop_queue(priv->net_dev); | ||
1086 | priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); | 1453 | priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); |
1087 | notify_wx_assoc_event(priv); | ||
1088 | cancel_delayed_work(&priv->request_scan); | 1454 | cancel_delayed_work(&priv->request_scan); |
1455 | schedule_work(&priv->link_down); | ||
1089 | queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ); | 1456 | queue_delayed_work(priv->workqueue, &priv->rf_kill, 2 * HZ); |
1090 | handled |= CX2_INTA_BIT_RF_KILL_DONE; | 1457 | handled |= CX2_INTA_BIT_RF_KILL_DONE; |
1091 | } | 1458 | } |
@@ -1182,9 +1549,12 @@ static char *get_cmd_string(u8 cmd) | |||
1182 | static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) | 1549 | static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) |
1183 | { | 1550 | { |
1184 | int rc = 0; | 1551 | int rc = 0; |
1552 | unsigned long flags; | ||
1185 | 1553 | ||
1554 | spin_lock_irqsave(&priv->lock, flags); | ||
1186 | if (priv->status & STATUS_HCMD_ACTIVE) { | 1555 | if (priv->status & STATUS_HCMD_ACTIVE) { |
1187 | IPW_ERROR("Already sending a command\n"); | 1556 | IPW_ERROR("Already sending a command\n"); |
1557 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1188 | return -1; | 1558 | return -1; |
1189 | } | 1559 | } |
1190 | 1560 | ||
@@ -1195,19 +1565,30 @@ static int ipw_send_cmd(struct ipw_priv *priv, struct host_cmd *cmd) | |||
1195 | printk_buf(IPW_DL_HOST_COMMAND, (u8 *) cmd->param, cmd->len); | 1565 | printk_buf(IPW_DL_HOST_COMMAND, (u8 *) cmd->param, cmd->len); |
1196 | 1566 | ||
1197 | rc = ipw_queue_tx_hcmd(priv, cmd->cmd, &cmd->param, cmd->len, 0); | 1567 | rc = ipw_queue_tx_hcmd(priv, cmd->cmd, &cmd->param, cmd->len, 0); |
1198 | if (rc) | 1568 | if (rc) { |
1569 | priv->status &= ~STATUS_HCMD_ACTIVE; | ||
1570 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1199 | return rc; | 1571 | return rc; |
1572 | } | ||
1573 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1200 | 1574 | ||
1201 | rc = wait_event_interruptible_timeout(priv->wait_command_queue, | 1575 | rc = wait_event_interruptible_timeout(priv->wait_command_queue, |
1202 | !(priv-> | 1576 | !(priv-> |
1203 | status & STATUS_HCMD_ACTIVE), | 1577 | status & STATUS_HCMD_ACTIVE), |
1204 | HOST_COMPLETE_TIMEOUT); | 1578 | HOST_COMPLETE_TIMEOUT); |
1205 | if (rc == 0) { | 1579 | if (rc == 0) { |
1206 | IPW_DEBUG_INFO("Command completion failed out after %dms.\n", | 1580 | spin_lock_irqsave(&priv->lock, flags); |
1207 | jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); | 1581 | if (priv->status & STATUS_HCMD_ACTIVE) { |
1208 | priv->status &= ~STATUS_HCMD_ACTIVE; | 1582 | IPW_DEBUG_INFO("Command completion failed out after " |
1209 | return -EIO; | 1583 | "%dms.\n", |
1584 | 1000 * (HOST_COMPLETE_TIMEOUT / HZ)); | ||
1585 | priv->status &= ~STATUS_HCMD_ACTIVE; | ||
1586 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1587 | return -EIO; | ||
1588 | } | ||
1589 | spin_unlock_irqrestore(&priv->lock, flags); | ||
1210 | } | 1590 | } |
1591 | |||
1211 | if (priv->status & STATUS_RF_KILL_MASK) { | 1592 | if (priv->status & STATUS_RF_KILL_MASK) { |
1212 | IPW_DEBUG_INFO("Command aborted due to RF Kill Switch\n"); | 1593 | IPW_DEBUG_INFO("Command aborted due to RF Kill Switch\n"); |
1213 | return -EIO; | 1594 | return -EIO; |
@@ -1304,6 +1685,11 @@ static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac) | |||
1304 | return 0; | 1685 | return 0; |
1305 | } | 1686 | } |
1306 | 1687 | ||
1688 | /* | ||
1689 | * NOTE: This must be executed from our workqueue as it results in udelay | ||
1690 | * being called which may corrupt the keyboard if executed on default | ||
1691 | * workqueue | ||
1692 | */ | ||
1307 | static void ipw_adapter_restart(void *adapter) | 1693 | static void ipw_adapter_restart(void *adapter) |
1308 | { | 1694 | { |
1309 | struct ipw_priv *priv = adapter; | 1695 | struct ipw_priv *priv = adapter; |
@@ -1327,7 +1713,7 @@ static void ipw_scan_check(void *data) | |||
1327 | IPW_DEBUG_SCAN("Scan completion watchdog resetting " | 1713 | IPW_DEBUG_SCAN("Scan completion watchdog resetting " |
1328 | "adapter (%dms).\n", | 1714 | "adapter (%dms).\n", |
1329 | IPW_SCAN_CHECK_WATCHDOG / 100); | 1715 | IPW_SCAN_CHECK_WATCHDOG / 100); |
1330 | ipw_adapter_restart(priv); | 1716 | queue_work(priv->workqueue, &priv->adapter_restart); |
1331 | } | 1717 | } |
1332 | } | 1718 | } |
1333 | 1719 | ||
@@ -1400,12 +1786,25 @@ static int ipw_send_associate(struct ipw_priv *priv, | |||
1400 | .len = sizeof(*associate) | 1786 | .len = sizeof(*associate) |
1401 | }; | 1787 | }; |
1402 | 1788 | ||
1789 | struct ipw_associate tmp_associate; | ||
1790 | memcpy(&tmp_associate, associate, sizeof(*associate)); | ||
1791 | tmp_associate.policy_support = | ||
1792 | cpu_to_le16(tmp_associate.policy_support); | ||
1793 | tmp_associate.assoc_tsf_msw = cpu_to_le32(tmp_associate.assoc_tsf_msw); | ||
1794 | tmp_associate.assoc_tsf_lsw = cpu_to_le32(tmp_associate.assoc_tsf_lsw); | ||
1795 | tmp_associate.capability = cpu_to_le16(tmp_associate.capability); | ||
1796 | tmp_associate.listen_interval = | ||
1797 | cpu_to_le16(tmp_associate.listen_interval); | ||
1798 | tmp_associate.beacon_interval = | ||
1799 | cpu_to_le16(tmp_associate.beacon_interval); | ||
1800 | tmp_associate.atim_window = cpu_to_le16(tmp_associate.atim_window); | ||
1801 | |||
1403 | if (!priv || !associate) { | 1802 | if (!priv || !associate) { |
1404 | IPW_ERROR("Invalid args\n"); | 1803 | IPW_ERROR("Invalid args\n"); |
1405 | return -1; | 1804 | return -1; |
1406 | } | 1805 | } |
1407 | 1806 | ||
1408 | memcpy(&cmd.param, associate, sizeof(*associate)); | 1807 | memcpy(&cmd.param, &tmp_associate, sizeof(*associate)); |
1409 | if (ipw_send_cmd(priv, &cmd)) { | 1808 | if (ipw_send_cmd(priv, &cmd)) { |
1410 | IPW_ERROR("failed to send ASSOCIATE command\n"); | 1809 | IPW_ERROR("failed to send ASSOCIATE command\n"); |
1411 | return -1; | 1810 | return -1; |
@@ -1706,7 +2105,7 @@ static void ipw_eeprom_init_sram(struct ipw_priv *priv) | |||
1706 | 2105 | ||
1707 | /* read entire contents of eeprom into private buffer */ | 2106 | /* read entire contents of eeprom into private buffer */ |
1708 | for (i = 0; i < 128; i++) | 2107 | for (i = 0; i < 128; i++) |
1709 | eeprom[i] = eeprom_read_u16(priv, (u8) i); | 2108 | eeprom[i] = le16_to_cpu(eeprom_read_u16(priv, (u8) i)); |
1710 | 2109 | ||
1711 | /* | 2110 | /* |
1712 | If the data looks correct, then copy it to our private | 2111 | If the data looks correct, then copy it to our private |
@@ -2001,6 +2400,9 @@ static void ipw_remove_current_network(struct ipw_priv *priv) | |||
2001 | { | 2400 | { |
2002 | struct list_head *element, *safe; | 2401 | struct list_head *element, *safe; |
2003 | struct ieee80211_network *network = NULL; | 2402 | struct ieee80211_network *network = NULL; |
2403 | unsigned long flags; | ||
2404 | |||
2405 | spin_lock_irqsave(&priv->ieee->lock, flags); | ||
2004 | list_for_each_safe(element, safe, &priv->ieee->network_list) { | 2406 | list_for_each_safe(element, safe, &priv->ieee->network_list) { |
2005 | network = list_entry(element, struct ieee80211_network, list); | 2407 | network = list_entry(element, struct ieee80211_network, list); |
2006 | if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) { | 2408 | if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) { |
@@ -2009,6 +2411,7 @@ static void ipw_remove_current_network(struct ipw_priv *priv) | |||
2009 | &priv->ieee->network_free_list); | 2411 | &priv->ieee->network_free_list); |
2010 | } | 2412 | } |
2011 | } | 2413 | } |
2414 | spin_unlock_irqrestore(&priv->ieee->lock, flags); | ||
2012 | } | 2415 | } |
2013 | 2416 | ||
2014 | /** | 2417 | /** |
@@ -2158,7 +2561,8 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len) | |||
2158 | */ | 2561 | */ |
2159 | /* load new ipw uCode */ | 2562 | /* load new ipw uCode */ |
2160 | for (i = 0; i < len / 2; i++) | 2563 | for (i = 0; i < len / 2; i++) |
2161 | ipw_write_reg16(priv, CX2_BASEBAND_CONTROL_STORE, image[i]); | 2564 | ipw_write_reg16(priv, CX2_BASEBAND_CONTROL_STORE, |
2565 | cpu_to_le16(image[i])); | ||
2162 | 2566 | ||
2163 | /* enable DINO */ | 2567 | /* enable DINO */ |
2164 | ipw_write_reg8(priv, CX2_BASEBAND_CONTROL_STATUS, 0); | 2568 | ipw_write_reg8(priv, CX2_BASEBAND_CONTROL_STATUS, 0); |
@@ -2181,7 +2585,8 @@ static int ipw_load_ucode(struct ipw_priv *priv, u8 * data, size_t len) | |||
2181 | 2585 | ||
2182 | for (i = 0; i < ARRAY_SIZE(response_buffer); i++) | 2586 | for (i = 0; i < ARRAY_SIZE(response_buffer); i++) |
2183 | response_buffer[i] = | 2587 | response_buffer[i] = |
2184 | ipw_read_reg32(priv, CX2_BASEBAND_RX_FIFO_READ); | 2588 | le32_to_cpu(ipw_read_reg32(priv, |
2589 | CX2_BASEBAND_RX_FIFO_READ)); | ||
2185 | memcpy(&priv->dino_alive, response_buffer, | 2590 | memcpy(&priv->dino_alive, response_buffer, |
2186 | sizeof(priv->dino_alive)); | 2591 | sizeof(priv->dino_alive)); |
2187 | if (priv->dino_alive.alive_command == 1 | 2592 | if (priv->dino_alive.alive_command == 1 |
@@ -2250,13 +2655,14 @@ static int ipw_load_firmware(struct ipw_priv *priv, u8 * data, size_t len) | |||
2250 | * offeset*/ | 2655 | * offeset*/ |
2251 | /* Dma loading */ | 2656 | /* Dma loading */ |
2252 | rc = ipw_fw_dma_add_buffer(priv, shared_phys + offset, | 2657 | rc = ipw_fw_dma_add_buffer(priv, shared_phys + offset, |
2253 | chunk->address, chunk->length); | 2658 | le32_to_cpu(chunk->address), |
2659 | le32_to_cpu(chunk->length)); | ||
2254 | if (rc) { | 2660 | if (rc) { |
2255 | IPW_DEBUG_INFO("dmaAddBuffer Failed\n"); | 2661 | IPW_DEBUG_INFO("dmaAddBuffer Failed\n"); |
2256 | goto out; | 2662 | goto out; |
2257 | } | 2663 | } |
2258 | 2664 | ||
2259 | offset += chunk->length; | 2665 | offset += le32_to_cpu(chunk->length); |
2260 | } while (offset < len); | 2666 | } while (offset < len); |
2261 | 2667 | ||
2262 | /* Run the DMA and wait for the answer */ | 2668 | /* Run the DMA and wait for the answer */ |
@@ -2351,14 +2757,17 @@ static int ipw_init_nic(struct ipw_priv *priv) | |||
2351 | static int ipw_reset_nic(struct ipw_priv *priv) | 2757 | static int ipw_reset_nic(struct ipw_priv *priv) |
2352 | { | 2758 | { |
2353 | int rc = 0; | 2759 | int rc = 0; |
2760 | unsigned long flags; | ||
2354 | 2761 | ||
2355 | IPW_DEBUG_TRACE(">>\n"); | 2762 | IPW_DEBUG_TRACE(">>\n"); |
2356 | 2763 | ||
2357 | rc = ipw_init_nic(priv); | 2764 | rc = ipw_init_nic(priv); |
2358 | 2765 | ||
2766 | spin_lock_irqsave(&priv->lock, flags); | ||
2359 | /* Clear the 'host command active' bit... */ | 2767 | /* Clear the 'host command active' bit... */ |
2360 | priv->status &= ~STATUS_HCMD_ACTIVE; | 2768 | priv->status &= ~STATUS_HCMD_ACTIVE; |
2361 | wake_up_interruptible(&priv->wait_command_queue); | 2769 | wake_up_interruptible(&priv->wait_command_queue); |
2770 | spin_unlock_irqrestore(&priv->lock, flags); | ||
2362 | 2771 | ||
2363 | IPW_DEBUG_TRACE("<<\n"); | 2772 | IPW_DEBUG_TRACE("<<\n"); |
2364 | return rc; | 2773 | return rc; |
@@ -2378,17 +2787,18 @@ static int ipw_get_fw(struct ipw_priv *priv, | |||
2378 | } | 2787 | } |
2379 | 2788 | ||
2380 | header = (struct fw_header *)(*fw)->data; | 2789 | header = (struct fw_header *)(*fw)->data; |
2381 | if (IPW_FW_MAJOR(header->version) != IPW_FW_MAJOR_VERSION) { | 2790 | if (IPW_FW_MAJOR(le32_to_cpu(header->version)) != IPW_FW_MAJOR_VERSION) { |
2382 | IPW_ERROR("'%s' firmware version not compatible (%d != %d)\n", | 2791 | IPW_ERROR("'%s' firmware version not compatible (%d != %d)\n", |
2383 | name, | 2792 | name, |
2384 | IPW_FW_MAJOR(header->version), IPW_FW_MAJOR_VERSION); | 2793 | IPW_FW_MAJOR(le32_to_cpu(header->version)), |
2794 | IPW_FW_MAJOR_VERSION); | ||
2385 | return -EINVAL; | 2795 | return -EINVAL; |
2386 | } | 2796 | } |
2387 | 2797 | ||
2388 | IPW_DEBUG_INFO("Loading firmware '%s' file v%d.%d (%zd bytes)\n", | 2798 | IPW_DEBUG_INFO("Loading firmware '%s' file v%d.%d (%zd bytes)\n", |
2389 | name, | 2799 | name, |
2390 | IPW_FW_MAJOR(header->version), | 2800 | IPW_FW_MAJOR(le32_to_cpu(header->version)), |
2391 | IPW_FW_MINOR(header->version), | 2801 | IPW_FW_MINOR(le32_to_cpu(header->version)), |
2392 | (*fw)->size - sizeof(struct fw_header)); | 2802 | (*fw)->size - sizeof(struct fw_header)); |
2393 | return 0; | 2803 | return 0; |
2394 | } | 2804 | } |
@@ -2414,6 +2824,7 @@ static inline void ipw_rx_queue_reset(struct ipw_priv *priv, | |||
2414 | pci_unmap_single(priv->pci_dev, rxq->pool[i].dma_addr, | 2824 | pci_unmap_single(priv->pci_dev, rxq->pool[i].dma_addr, |
2415 | CX2_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); | 2825 | CX2_RX_BUF_SIZE, PCI_DMA_FROMDEVICE); |
2416 | dev_kfree_skb(rxq->pool[i].skb); | 2826 | dev_kfree_skb(rxq->pool[i].skb); |
2827 | rxq->pool[i].skb = NULL; | ||
2417 | } | 2828 | } |
2418 | list_add_tail(&rxq->pool[i].list, &rxq->rx_used); | 2829 | list_add_tail(&rxq->pool[i].list, &rxq->rx_used); |
2419 | } | 2830 | } |
@@ -2769,16 +3180,18 @@ static void ipw_queue_tx_free_tfd(struct ipw_priv *priv, | |||
2769 | return; | 3180 | return; |
2770 | 3181 | ||
2771 | /* sanity check */ | 3182 | /* sanity check */ |
2772 | if (bd->u.data.num_chunks > NUM_TFD_CHUNKS) { | 3183 | if (le32_to_cpu(bd->u.data.num_chunks) > NUM_TFD_CHUNKS) { |
2773 | IPW_ERROR("Too many chunks: %i\n", bd->u.data.num_chunks); | 3184 | IPW_ERROR("Too many chunks: %i\n", |
3185 | le32_to_cpu(bd->u.data.num_chunks)); | ||
2774 | /** @todo issue fatal error, it is quite serious situation */ | 3186 | /** @todo issue fatal error, it is quite serious situation */ |
2775 | return; | 3187 | return; |
2776 | } | 3188 | } |
2777 | 3189 | ||
2778 | /* unmap chunks if any */ | 3190 | /* unmap chunks if any */ |
2779 | for (i = 0; i < bd->u.data.num_chunks; i++) { | 3191 | for (i = 0; i < le32_to_cpu(bd->u.data.num_chunks); i++) { |
2780 | pci_unmap_single(dev, bd->u.data.chunk_ptr[i], | 3192 | pci_unmap_single(dev, le32_to_cpu(bd->u.data.chunk_ptr[i]), |
2781 | bd->u.data.chunk_len[i], PCI_DMA_TODEVICE); | 3193 | le16_to_cpu(bd->u.data.chunk_len[i]), |
3194 | PCI_DMA_TODEVICE); | ||
2782 | if (txq->txb[txq->q.last_used]) { | 3195 | if (txq->txb[txq->q.last_used]) { |
2783 | ieee80211_txb_free(txq->txb[txq->q.last_used]); | 3196 | ieee80211_txb_free(txq->txb[txq->q.last_used]); |
2784 | txq->txb[txq->q.last_used] = NULL; | 3197 | txq->txb[txq->q.last_used] = NULL; |
@@ -2841,9 +3254,8 @@ static void inline __maybe_wake_tx(struct ipw_priv *priv) | |||
2841 | switch (priv->port_type) { | 3254 | switch (priv->port_type) { |
2842 | case DCR_TYPE_MU_BSS: | 3255 | case DCR_TYPE_MU_BSS: |
2843 | case DCR_TYPE_MU_IBSS: | 3256 | case DCR_TYPE_MU_IBSS: |
2844 | if (!(priv->status & STATUS_ASSOCIATED)) { | 3257 | if (!(priv->status & STATUS_ASSOCIATED)) |
2845 | return; | 3258 | return; |
2846 | } | ||
2847 | } | 3259 | } |
2848 | netif_wake_queue(priv->net_dev); | 3260 | netif_wake_queue(priv->net_dev); |
2849 | } | 3261 | } |
@@ -3307,8 +3719,13 @@ static inline void ipw_handle_missed_beacon(struct ipw_priv *priv, | |||
3307 | IPW_DL_STATE, | 3719 | IPW_DL_STATE, |
3308 | "Missed beacon: %d - disassociate\n", missed_count); | 3720 | "Missed beacon: %d - disassociate\n", missed_count); |
3309 | priv->status &= ~STATUS_ROAMING; | 3721 | priv->status &= ~STATUS_ROAMING; |
3310 | if (priv->status & STATUS_SCANNING) | 3722 | if (priv->status & STATUS_SCANNING) { |
3723 | IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | | ||
3724 | IPW_DL_STATE, | ||
3725 | "Aborting scan with missed beacon.\n"); | ||
3311 | queue_work(priv->workqueue, &priv->abort_scan); | 3726 | queue_work(priv->workqueue, &priv->abort_scan); |
3727 | } | ||
3728 | |||
3312 | queue_work(priv->workqueue, &priv->disassociate); | 3729 | queue_work(priv->workqueue, &priv->disassociate); |
3313 | return; | 3730 | return; |
3314 | } | 3731 | } |
@@ -3342,6 +3759,8 @@ static inline void ipw_handle_missed_beacon(struct ipw_priv *priv, | |||
3342 | * stuck (only if we aren't roaming -- | 3759 | * stuck (only if we aren't roaming -- |
3343 | * otherwise we'll never scan more than 2 or 3 | 3760 | * otherwise we'll never scan more than 2 or 3 |
3344 | * channels..) */ | 3761 | * channels..) */ |
3762 | IPW_DEBUG(IPW_DL_INFO | IPW_DL_NOTIF | | ||
3763 | IPW_DL_STATE, "Aborting scan with missed beacon.\n"); | ||
3345 | queue_work(priv->workqueue, &priv->abort_scan); | 3764 | queue_work(priv->workqueue, &priv->abort_scan); |
3346 | } | 3765 | } |
3347 | 3766 | ||
@@ -3356,6 +3775,8 @@ static inline void ipw_handle_missed_beacon(struct ipw_priv *priv, | |||
3356 | static inline void ipw_rx_notification(struct ipw_priv *priv, | 3775 | static inline void ipw_rx_notification(struct ipw_priv *priv, |
3357 | struct ipw_rx_notification *notif) | 3776 | struct ipw_rx_notification *notif) |
3358 | { | 3777 | { |
3778 | notif->size = le16_to_cpu(notif->size); | ||
3779 | |||
3359 | IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, notif->size); | 3780 | IPW_DEBUG_NOTIF("type = %i (%d bytes)\n", notif->subtype, notif->size); |
3360 | 3781 | ||
3361 | switch (notif->subtype) { | 3782 | switch (notif->subtype) { |
@@ -3400,29 +3821,8 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, | |||
3400 | priv->status &= ~STATUS_ASSOCIATING; | 3821 | priv->status &= ~STATUS_ASSOCIATING; |
3401 | priv->status |= STATUS_ASSOCIATED; | 3822 | priv->status |= STATUS_ASSOCIATED; |
3402 | 3823 | ||
3403 | netif_carrier_on(priv->net_dev); | 3824 | schedule_work(&priv->link_up); |
3404 | if (netif_queue_stopped(priv->net_dev)) { | ||
3405 | IPW_DEBUG_NOTIF | ||
3406 | ("waking queue\n"); | ||
3407 | netif_wake_queue(priv->net_dev); | ||
3408 | } else { | ||
3409 | IPW_DEBUG_NOTIF | ||
3410 | ("starting queue\n"); | ||
3411 | netif_start_queue(priv-> | ||
3412 | net_dev); | ||
3413 | } | ||
3414 | 3825 | ||
3415 | ipw_reset_stats(priv); | ||
3416 | /* Ensure the rate is updated immediately */ | ||
3417 | priv->last_rate = | ||
3418 | ipw_get_current_rate(priv); | ||
3419 | schedule_work(&priv->gather_stats); | ||
3420 | notify_wx_assoc_event(priv); | ||
3421 | |||
3422 | /* queue_delayed_work(priv->workqueue, | ||
3423 | &priv->request_scan, | ||
3424 | SCAN_ASSOCIATED_INTERVAL); | ||
3425 | */ | ||
3426 | break; | 3826 | break; |
3427 | } | 3827 | } |
3428 | 3828 | ||
@@ -3455,12 +3855,7 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, | |||
3455 | STATUS_AUTH | | 3855 | STATUS_AUTH | |
3456 | STATUS_ASSOCIATED); | 3856 | STATUS_ASSOCIATED); |
3457 | 3857 | ||
3458 | netif_carrier_off(priv-> | 3858 | schedule_work(&priv->link_down); |
3459 | net_dev); | ||
3460 | netif_stop_queue(priv->net_dev); | ||
3461 | queue_work(priv->workqueue, | ||
3462 | &priv->request_scan); | ||
3463 | notify_wx_assoc_event(priv); | ||
3464 | break; | 3859 | break; |
3465 | } | 3860 | } |
3466 | 3861 | ||
@@ -3506,31 +3901,8 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, | |||
3506 | STATUS_ASSOCIATING | | 3901 | STATUS_ASSOCIATING | |
3507 | STATUS_ASSOCIATED | STATUS_AUTH); | 3902 | STATUS_ASSOCIATED | STATUS_AUTH); |
3508 | 3903 | ||
3509 | netif_stop_queue(priv->net_dev); | 3904 | schedule_work(&priv->link_down); |
3510 | if (!(priv->status & STATUS_ROAMING)) { | ||
3511 | netif_carrier_off(priv-> | ||
3512 | net_dev); | ||
3513 | notify_wx_assoc_event(priv); | ||
3514 | |||
3515 | /* Cancel any queued work ... */ | ||
3516 | cancel_delayed_work(&priv-> | ||
3517 | request_scan); | ||
3518 | cancel_delayed_work(&priv-> | ||
3519 | adhoc_check); | ||
3520 | |||
3521 | /* Queue up another scan... */ | ||
3522 | queue_work(priv->workqueue, | ||
3523 | &priv->request_scan); | ||
3524 | |||
3525 | cancel_delayed_work(&priv-> | ||
3526 | gather_stats); | ||
3527 | } else { | ||
3528 | priv->status |= STATUS_ROAMING; | ||
3529 | queue_work(priv->workqueue, | ||
3530 | &priv->request_scan); | ||
3531 | } | ||
3532 | 3905 | ||
3533 | ipw_reset_stats(priv); | ||
3534 | break; | 3906 | break; |
3535 | } | 3907 | } |
3536 | 3908 | ||
@@ -3576,11 +3948,7 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, | |||
3576 | STATUS_AUTH | | 3948 | STATUS_AUTH | |
3577 | STATUS_ASSOCIATED); | 3949 | STATUS_ASSOCIATED); |
3578 | 3950 | ||
3579 | netif_carrier_off(priv->net_dev); | 3951 | schedule_work(&priv->link_down); |
3580 | netif_stop_queue(priv->net_dev); | ||
3581 | queue_work(priv->workqueue, | ||
3582 | &priv->request_scan); | ||
3583 | notify_wx_assoc_event(priv); | ||
3584 | break; | 3952 | break; |
3585 | 3953 | ||
3586 | case CMAS_TX_AUTH_SEQ_1: | 3954 | case CMAS_TX_AUTH_SEQ_1: |
@@ -3682,6 +4050,10 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, | |||
3682 | } else if (priv->status & STATUS_SCAN_PENDING) | 4050 | } else if (priv->status & STATUS_SCAN_PENDING) |
3683 | queue_work(priv->workqueue, | 4051 | queue_work(priv->workqueue, |
3684 | &priv->request_scan); | 4052 | &priv->request_scan); |
4053 | else if (priv->config & CFG_BACKGROUND_SCAN | ||
4054 | && priv->status & STATUS_ASSOCIATED) | ||
4055 | queue_delayed_work(priv->workqueue, | ||
4056 | &priv->request_scan, HZ); | ||
3685 | 4057 | ||
3686 | priv->ieee->scans++; | 4058 | priv->ieee->scans++; |
3687 | break; | 4059 | break; |
@@ -3690,13 +4062,13 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, | |||
3690 | case HOST_NOTIFICATION_STATUS_FRAG_LENGTH:{ | 4062 | case HOST_NOTIFICATION_STATUS_FRAG_LENGTH:{ |
3691 | struct notif_frag_length *x = ¬if->u.frag_len; | 4063 | struct notif_frag_length *x = ¬if->u.frag_len; |
3692 | 4064 | ||
3693 | if (notif->size == sizeof(*x)) { | 4065 | if (notif->size == sizeof(*x)) |
3694 | IPW_ERROR("Frag length: %d\n", x->frag_length); | 4066 | IPW_ERROR("Frag length: %d\n", |
3695 | } else { | 4067 | le16_to_cpu(x->frag_length)); |
4068 | else | ||
3696 | IPW_ERROR("Frag length of wrong size %d " | 4069 | IPW_ERROR("Frag length of wrong size %d " |
3697 | "(should be %zd)\n", | 4070 | "(should be %zd)\n", |
3698 | notif->size, sizeof(*x)); | 4071 | notif->size, sizeof(*x)); |
3699 | } | ||
3700 | break; | 4072 | break; |
3701 | } | 4073 | } |
3702 | 4074 | ||
@@ -3722,11 +4094,9 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, | |||
3722 | case HOST_NOTIFICATION_DINO_CONFIG_RESPONSE:{ | 4094 | case HOST_NOTIFICATION_DINO_CONFIG_RESPONSE:{ |
3723 | IPW_ERROR("Dino config\n"); | 4095 | IPW_ERROR("Dino config\n"); |
3724 | if (priv->hcmd | 4096 | if (priv->hcmd |
3725 | && priv->hcmd->cmd == HOST_CMD_DINO_CONFIG) { | 4097 | && priv->hcmd->cmd != HOST_CMD_DINO_CONFIG) |
3726 | /* TODO: Do anything special? */ | ||
3727 | } else { | ||
3728 | IPW_ERROR("Unexpected DINO_CONFIG_RESPONSE\n"); | 4098 | IPW_ERROR("Unexpected DINO_CONFIG_RESPONSE\n"); |
3729 | } | 4099 | |
3730 | break; | 4100 | break; |
3731 | } | 4101 | } |
3732 | 4102 | ||
@@ -3739,8 +4109,11 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, | |||
3739 | break; | 4109 | break; |
3740 | } | 4110 | } |
3741 | 4111 | ||
3742 | if (x->state == HOST_NOTIFICATION_STATUS_BEACON_MISSING) | 4112 | if (le32_to_cpu(x->state) == |
3743 | ipw_handle_missed_beacon(priv, x->number); | 4113 | HOST_NOTIFICATION_STATUS_BEACON_MISSING) |
4114 | ipw_handle_missed_beacon(priv, | ||
4115 | le32_to_cpu(x-> | ||
4116 | number)); | ||
3744 | 4117 | ||
3745 | break; | 4118 | break; |
3746 | } | 4119 | } |
@@ -3779,7 +4152,8 @@ static inline void ipw_rx_notification(struct ipw_priv *priv, | |||
3779 | case HOST_NOTIFICATION_NOISE_STATS:{ | 4152 | case HOST_NOTIFICATION_NOISE_STATS:{ |
3780 | if (notif->size == sizeof(u32)) { | 4153 | if (notif->size == sizeof(u32)) { |
3781 | priv->last_noise = | 4154 | priv->last_noise = |
3782 | (u8) (notif->u.noise.value & 0xff); | 4155 | (u8) (le32_to_cpu(notif->u.noise.value) & |
4156 | 0xff); | ||
3783 | average_add(&priv->average_noise, | 4157 | average_add(&priv->average_noise, |
3784 | priv->last_noise); | 4158 | priv->last_noise); |
3785 | break; | 4159 | break; |
@@ -3896,9 +4270,8 @@ static int ipw_queue_tx_reclaim(struct ipw_priv *priv, | |||
3896 | priv->tx_packets++; | 4270 | priv->tx_packets++; |
3897 | } | 4271 | } |
3898 | done: | 4272 | done: |
3899 | if (ipw_queue_space(q) > q->low_mark && qindex >= 0) { | 4273 | if (ipw_queue_space(q) > q->low_mark && qindex >= 0) |
3900 | __maybe_wake_tx(priv); | 4274 | __maybe_wake_tx(priv); |
3901 | } | ||
3902 | used = q->first_empty - q->last_used; | 4275 | used = q->first_empty - q->last_used; |
3903 | if (used < 0) | 4276 | if (used < 0) |
3904 | used += q->n_bd; | 4277 | used += q->n_bd; |
@@ -4217,13 +4590,16 @@ static int ipw_compatible_rates(struct ipw_priv *priv, | |||
4217 | num_rates = min(network->rates_len, (u8) IPW_MAX_RATES); | 4590 | num_rates = min(network->rates_len, (u8) IPW_MAX_RATES); |
4218 | rates->num_rates = 0; | 4591 | rates->num_rates = 0; |
4219 | for (i = 0; i < num_rates; i++) { | 4592 | for (i = 0; i < num_rates; i++) { |
4220 | if (!ipw_is_rate_in_mask | 4593 | if (!ipw_is_rate_in_mask(priv, network->mode, |
4221 | (priv, network->mode, network->rates[i])) { | 4594 | network->rates[i])) { |
4595 | |||
4222 | if (network->rates[i] & IEEE80211_BASIC_RATE_MASK) { | 4596 | if (network->rates[i] & IEEE80211_BASIC_RATE_MASK) { |
4223 | IPW_DEBUG_SCAN | 4597 | IPW_DEBUG_SCAN("Adding masked mandatory " |
4224 | ("Basic rate %02X masked: 0x%08X\n", | 4598 | "rate %02X\n", |
4225 | network->rates[i], priv->rates_mask); | 4599 | network->rates[i]); |
4226 | return 0; | 4600 | rates->supported_rates[rates->num_rates++] = |
4601 | network->rates[i]; | ||
4602 | continue; | ||
4227 | } | 4603 | } |
4228 | 4604 | ||
4229 | IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n", | 4605 | IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n", |
@@ -4234,16 +4610,18 @@ static int ipw_compatible_rates(struct ipw_priv *priv, | |||
4234 | rates->supported_rates[rates->num_rates++] = network->rates[i]; | 4610 | rates->supported_rates[rates->num_rates++] = network->rates[i]; |
4235 | } | 4611 | } |
4236 | 4612 | ||
4237 | num_rates = | 4613 | num_rates = min(network->rates_ex_len, |
4238 | min(network->rates_ex_len, (u8) (IPW_MAX_RATES - num_rates)); | 4614 | (u8) (IPW_MAX_RATES - num_rates)); |
4239 | for (i = 0; i < num_rates; i++) { | 4615 | for (i = 0; i < num_rates; i++) { |
4240 | if (!ipw_is_rate_in_mask | 4616 | if (!ipw_is_rate_in_mask(priv, network->mode, |
4241 | (priv, network->mode, network->rates_ex[i])) { | 4617 | network->rates_ex[i])) { |
4242 | if (network->rates_ex[i] & IEEE80211_BASIC_RATE_MASK) { | 4618 | if (network->rates_ex[i] & IEEE80211_BASIC_RATE_MASK) { |
4243 | IPW_DEBUG_SCAN | 4619 | IPW_DEBUG_SCAN("Adding masked mandatory " |
4244 | ("Basic rate %02X masked: 0x%08X\n", | 4620 | "rate %02X\n", |
4245 | network->rates_ex[i], priv->rates_mask); | 4621 | network->rates_ex[i]); |
4246 | return 0; | 4622 | rates->supported_rates[rates->num_rates++] = |
4623 | network->rates[i]; | ||
4624 | continue; | ||
4247 | } | 4625 | } |
4248 | 4626 | ||
4249 | IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n", | 4627 | IPW_DEBUG_SCAN("Rate %02X masked : 0x%08X\n", |
@@ -4531,9 +4909,7 @@ static void ipw_adhoc_create(struct ipw_priv *priv, | |||
4531 | * FW fatal error. | 4909 | * FW fatal error. |
4532 | */ | 4910 | */ |
4533 | network->mode = is_valid_channel(priv->ieee->mode, priv->channel); | 4911 | network->mode = is_valid_channel(priv->ieee->mode, priv->channel); |
4534 | if (network->mode) { | 4912 | if (!network->mode) { |
4535 | network->channel = priv->channel; | ||
4536 | } else { | ||
4537 | IPW_WARNING("Overriding invalid channel\n"); | 4913 | IPW_WARNING("Overriding invalid channel\n"); |
4538 | if (priv->ieee->mode & IEEE_A) { | 4914 | if (priv->ieee->mode & IEEE_A) { |
4539 | network->mode = IEEE_A; | 4915 | network->mode = IEEE_A; |
@@ -4572,10 +4948,8 @@ static void ipw_adhoc_create(struct ipw_priv *priv, | |||
4572 | network->beacon_interval = 100; /* Default */ | 4948 | network->beacon_interval = 100; /* Default */ |
4573 | network->listen_interval = 10; /* Default */ | 4949 | network->listen_interval = 10; /* Default */ |
4574 | network->atim_window = 0; /* Default */ | 4950 | network->atim_window = 0; /* Default */ |
4575 | #ifdef CONFIG_IEEE80211_WPA | ||
4576 | network->wpa_ie_len = 0; | 4951 | network->wpa_ie_len = 0; |
4577 | network->rsn_ie_len = 0; | 4952 | network->rsn_ie_len = 0; |
4578 | #endif /* CONFIG_IEEE80211_WPA */ | ||
4579 | } | 4953 | } |
4580 | 4954 | ||
4581 | static void ipw_send_wep_keys(struct ipw_priv *priv) | 4955 | static void ipw_send_wep_keys(struct ipw_priv *priv) |
@@ -4593,9 +4967,9 @@ static void ipw_send_wep_keys(struct ipw_priv *priv) | |||
4593 | 4967 | ||
4594 | for (i = 0; i < 4; i++) { | 4968 | for (i = 0; i < 4; i++) { |
4595 | key->key_index = i; | 4969 | key->key_index = i; |
4596 | if (!(priv->sec.flags & (1 << i))) { | 4970 | if (!(priv->sec.flags & (1 << i))) |
4597 | key->key_size = 0; | 4971 | key->key_size = 0; |
4598 | } else { | 4972 | else { |
4599 | key->key_size = priv->sec.key_sizes[i]; | 4973 | key->key_size = priv->sec.key_sizes[i]; |
4600 | memcpy(key->key, priv->sec.keys[i], key->key_size); | 4974 | memcpy(key->key, priv->sec.keys[i], key->key_size); |
4601 | } | 4975 | } |
@@ -4752,9 +5126,10 @@ static int ipw_request_scan(struct ipw_priv *priv) | |||
4752 | } | 5126 | } |
4753 | 5127 | ||
4754 | if (priv->status & STATUS_SCANNING) { | 5128 | if (priv->status & STATUS_SCANNING) { |
4755 | IPW_DEBUG_HC("Concurrent scan requested. Aborting first.\n"); | 5129 | IPW_DEBUG_HC("Concurrent scan requested. Ignoring.\n"); |
5130 | // IPW_DEBUG_HC("Concurrent scan requested. Aborting first.\n"); | ||
4756 | priv->status |= STATUS_SCAN_PENDING; | 5131 | priv->status |= STATUS_SCAN_PENDING; |
4757 | ipw_abort_scan(priv); | 5132 | // ipw_abort_scan(priv); |
4758 | return 0; | 5133 | return 0; |
4759 | } | 5134 | } |
4760 | 5135 | ||
@@ -4772,11 +5147,12 @@ static int ipw_request_scan(struct ipw_priv *priv) | |||
4772 | 5147 | ||
4773 | memset(&scan, 0, sizeof(scan)); | 5148 | memset(&scan, 0, sizeof(scan)); |
4774 | 5149 | ||
4775 | scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = 20; | 5150 | scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = cpu_to_le16(20); |
4776 | scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] = 20; | 5151 | scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] = |
4777 | scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = 20; | 5152 | cpu_to_le16(20); |
5153 | scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(20); | ||
4778 | 5154 | ||
4779 | scan.full_scan_index = ieee80211_get_scans(priv->ieee); | 5155 | scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee)); |
4780 | 5156 | ||
4781 | #ifdef CONFIG_IPW_MONITOR | 5157 | #ifdef CONFIG_IPW_MONITOR |
4782 | if (priv->ieee->iw_mode == IW_MODE_MONITOR) { | 5158 | if (priv->ieee->iw_mode == IW_MODE_MONITOR) { |
@@ -4798,7 +5174,8 @@ static int ipw_request_scan(struct ipw_priv *priv) | |||
4798 | ipw_set_scan_type(&scan, channel_index, | 5174 | ipw_set_scan_type(&scan, channel_index, |
4799 | IPW_SCAN_PASSIVE_FULL_DWELL_SCAN); | 5175 | IPW_SCAN_PASSIVE_FULL_DWELL_SCAN); |
4800 | 5176 | ||
4801 | scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = 2000; | 5177 | scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = |
5178 | cpu_to_le16(2000); | ||
4802 | } else { | 5179 | } else { |
4803 | #endif /* CONFIG_IPW_MONITOR */ | 5180 | #endif /* CONFIG_IPW_MONITOR */ |
4804 | /* If we are roaming, then make this a directed scan for the current | 5181 | /* If we are roaming, then make this a directed scan for the current |
@@ -4807,7 +5184,7 @@ static int ipw_request_scan(struct ipw_priv *priv) | |||
4807 | if ((priv->status & STATUS_ROAMING) | 5184 | if ((priv->status & STATUS_ROAMING) |
4808 | || (!(priv->status & STATUS_ASSOCIATED) | 5185 | || (!(priv->status & STATUS_ASSOCIATED) |
4809 | && (priv->config & CFG_STATIC_ESSID) | 5186 | && (priv->config & CFG_STATIC_ESSID) |
4810 | && (scan.full_scan_index % 2))) { | 5187 | && (le32_to_cpu(scan.full_scan_index) % 2))) { |
4811 | err = ipw_send_ssid(priv, priv->essid, priv->essid_len); | 5188 | err = ipw_send_ssid(priv, priv->essid, priv->essid_len); |
4812 | if (err) { | 5189 | if (err) { |
4813 | IPW_DEBUG_HC | 5190 | IPW_DEBUG_HC |
@@ -4882,7 +5259,6 @@ static int ipw_request_scan(struct ipw_priv *priv) | |||
4882 | 5259 | ||
4883 | /* Support for wpa_supplicant. Will be replaced with WEXT once | 5260 | /* Support for wpa_supplicant. Will be replaced with WEXT once |
4884 | * they get WPA support. */ | 5261 | * they get WPA support. */ |
4885 | #ifdef CONFIG_IEEE80211_WPA | ||
4886 | 5262 | ||
4887 | /* following definitions must match definitions in driver_ipw.c */ | 5263 | /* following definitions must match definitions in driver_ipw.c */ |
4888 | 5264 | ||
@@ -4959,6 +5335,7 @@ static int ipw_wpa_enable(struct ipw_priv *priv, int value) | |||
4959 | } else { | 5335 | } else { |
4960 | sec.level = SEC_LEVEL_0; | 5336 | sec.level = SEC_LEVEL_0; |
4961 | sec.enabled = 0; | 5337 | sec.enabled = 0; |
5338 | ieee->wpa_ie_len = 0; | ||
4962 | } | 5339 | } |
4963 | 5340 | ||
4964 | if (ieee->set_security) | 5341 | if (ieee->set_security) |
@@ -4999,6 +5376,8 @@ static int ipw_wpa_set_auth_algs(struct ipw_priv *priv, int value) | |||
4999 | static int ipw_wpa_set_param(struct net_device *dev, u8 name, u32 value) | 5376 | static int ipw_wpa_set_param(struct net_device *dev, u8 name, u32 value) |
5000 | { | 5377 | { |
5001 | struct ipw_priv *priv = ieee80211_priv(dev); | 5378 | struct ipw_priv *priv = ieee80211_priv(dev); |
5379 | struct ieee80211_crypt_data *crypt; | ||
5380 | unsigned long flags; | ||
5002 | int ret = 0; | 5381 | int ret = 0; |
5003 | 5382 | ||
5004 | switch (name) { | 5383 | switch (name) { |
@@ -5007,7 +5386,22 @@ static int ipw_wpa_set_param(struct net_device *dev, u8 name, u32 value) | |||
5007 | break; | 5386 | break; |
5008 | 5387 | ||
5009 | case IPW_PARAM_TKIP_COUNTERMEASURES: | 5388 | case IPW_PARAM_TKIP_COUNTERMEASURES: |
5010 | priv->ieee->tkip_countermeasures = value; | 5389 | crypt = priv->ieee->crypt[priv->ieee->tx_keyidx]; |
5390 | if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags) { | ||
5391 | IPW_WARNING("Can't set TKIP countermeasures: " | ||
5392 | "crypt not set!\n"); | ||
5393 | break; | ||
5394 | } | ||
5395 | |||
5396 | flags = crypt->ops->get_flags(crypt->priv); | ||
5397 | |||
5398 | if (value) | ||
5399 | flags |= IEEE80211_CRYPTO_TKIP_COUNTERMEASURES; | ||
5400 | else | ||
5401 | flags &= ~IEEE80211_CRYPTO_TKIP_COUNTERMEASURES; | ||
5402 | |||
5403 | crypt->ops->set_flags(flags, crypt->priv); | ||
5404 | |||
5011 | break; | 5405 | break; |
5012 | 5406 | ||
5013 | case IPW_PARAM_DROP_UNENCRYPTED: | 5407 | case IPW_PARAM_DROP_UNENCRYPTED: |
@@ -5313,7 +5707,6 @@ static int ipw_wpa_supplicant(struct net_device *dev, struct iw_point *p) | |||
5313 | kfree(param); | 5707 | kfree(param); |
5314 | return ret; | 5708 | return ret; |
5315 | } | 5709 | } |
5316 | #endif /* CONFIG_IEEE80211_WPA */ | ||
5317 | 5710 | ||
5318 | static int ipw_associate_network(struct ipw_priv *priv, | 5711 | static int ipw_associate_network(struct ipw_priv *priv, |
5319 | struct ieee80211_network *network, | 5712 | struct ieee80211_network *network, |
@@ -5346,13 +5739,11 @@ static int ipw_associate_network(struct ipw_priv *priv, | |||
5346 | if (priv->capability & CAP_PRIVACY_ON) | 5739 | if (priv->capability & CAP_PRIVACY_ON) |
5347 | ipw_send_wep_keys(priv); | 5740 | ipw_send_wep_keys(priv); |
5348 | 5741 | ||
5349 | #ifdef CONFIG_IEEE80211_WPA | 5742 | if (priv->ieee->wpa_ie_len) { |
5350 | if (priv->ieee->wpa_enabled) { | ||
5351 | priv->assoc_request.policy_support = 0x02; /* RSN active */ | 5743 | priv->assoc_request.policy_support = 0x02; /* RSN active */ |
5352 | ipw_set_rsn_capa(priv, priv->ieee->wpa_ie, | 5744 | ipw_set_rsn_capa(priv, priv->ieee->wpa_ie, |
5353 | priv->ieee->wpa_ie_len); | 5745 | priv->ieee->wpa_ie_len); |
5354 | } | 5746 | } |
5355 | #endif | ||
5356 | 5747 | ||
5357 | /* | 5748 | /* |
5358 | * It is valid for our ieee device to support multiple modes, but | 5749 | * It is valid for our ieee device to support multiple modes, but |
@@ -5511,12 +5902,15 @@ static void ipw_roam(void *data) | |||
5511 | if (priv->status & STATUS_ASSOCIATED) { | 5902 | if (priv->status & STATUS_ASSOCIATED) { |
5512 | /* First pass through ROAM process -- look for a better | 5903 | /* First pass through ROAM process -- look for a better |
5513 | * network */ | 5904 | * network */ |
5905 | unsigned long flags; | ||
5514 | u8 rssi = priv->assoc_network->stats.rssi; | 5906 | u8 rssi = priv->assoc_network->stats.rssi; |
5515 | priv->assoc_network->stats.rssi = -128; | 5907 | priv->assoc_network->stats.rssi = -128; |
5908 | spin_lock_irqsave(&priv->ieee->lock, flags); | ||
5516 | list_for_each_entry(network, &priv->ieee->network_list, list) { | 5909 | list_for_each_entry(network, &priv->ieee->network_list, list) { |
5517 | if (network != priv->assoc_network) | 5910 | if (network != priv->assoc_network) |
5518 | ipw_best_network(priv, &match, network, 1); | 5911 | ipw_best_network(priv, &match, network, 1); |
5519 | } | 5912 | } |
5913 | spin_unlock_irqrestore(&priv->ieee->lock, flags); | ||
5520 | priv->assoc_network->stats.rssi = rssi; | 5914 | priv->assoc_network->stats.rssi = rssi; |
5521 | 5915 | ||
5522 | if (match.network == priv->assoc_network) { | 5916 | if (match.network == priv->assoc_network) { |
@@ -5549,6 +5943,7 @@ static void ipw_associate(void *data) | |||
5549 | }; | 5943 | }; |
5550 | struct ipw_supported_rates *rates; | 5944 | struct ipw_supported_rates *rates; |
5551 | struct list_head *element; | 5945 | struct list_head *element; |
5946 | unsigned long flags; | ||
5552 | 5947 | ||
5553 | if (!(priv->config & CFG_ASSOCIATE) && | 5948 | if (!(priv->config & CFG_ASSOCIATE) && |
5554 | !(priv->config & (CFG_STATIC_ESSID | | 5949 | !(priv->config & (CFG_STATIC_ESSID | |
@@ -5557,6 +5952,8 @@ static void ipw_associate(void *data) | |||
5557 | return; | 5952 | return; |
5558 | } | 5953 | } |
5559 | 5954 | ||
5955 | /* Protect our use of the network_list */ | ||
5956 | spin_lock_irqsave(&priv->ieee->lock, flags); | ||
5560 | list_for_each_entry(network, &priv->ieee->network_list, list) | 5957 | list_for_each_entry(network, &priv->ieee->network_list, list) |
5561 | ipw_best_network(priv, &match, network, 0); | 5958 | ipw_best_network(priv, &match, network, 0); |
5562 | 5959 | ||
@@ -5567,6 +5964,7 @@ static void ipw_associate(void *data) | |||
5567 | priv->ieee->iw_mode == IW_MODE_ADHOC && | 5964 | priv->ieee->iw_mode == IW_MODE_ADHOC && |
5568 | priv->config & CFG_ADHOC_CREATE && | 5965 | priv->config & CFG_ADHOC_CREATE && |
5569 | priv->config & CFG_STATIC_ESSID && | 5966 | priv->config & CFG_STATIC_ESSID && |
5967 | priv->config & CFG_STATIC_CHANNEL && | ||
5570 | !list_empty(&priv->ieee->network_free_list)) { | 5968 | !list_empty(&priv->ieee->network_free_list)) { |
5571 | element = priv->ieee->network_free_list.next; | 5969 | element = priv->ieee->network_free_list.next; |
5572 | network = list_entry(element, struct ieee80211_network, list); | 5970 | network = list_entry(element, struct ieee80211_network, list); |
@@ -5575,14 +5973,16 @@ static void ipw_associate(void *data) | |||
5575 | list_del(element); | 5973 | list_del(element); |
5576 | list_add_tail(&network->list, &priv->ieee->network_list); | 5974 | list_add_tail(&network->list, &priv->ieee->network_list); |
5577 | } | 5975 | } |
5976 | spin_unlock_irqrestore(&priv->ieee->lock, flags); | ||
5578 | 5977 | ||
5579 | /* If we reached the end of the list, then we don't have any valid | 5978 | /* If we reached the end of the list, then we don't have any valid |
5580 | * matching APs */ | 5979 | * matching APs */ |
5581 | if (!network) { | 5980 | if (!network) { |
5582 | ipw_debug_config(priv); | 5981 | ipw_debug_config(priv); |
5583 | 5982 | ||
5584 | queue_delayed_work(priv->workqueue, &priv->request_scan, | 5983 | if (!(priv->status & STATUS_SCANNING)) |
5585 | SCAN_INTERVAL); | 5984 | queue_delayed_work(priv->workqueue, &priv->request_scan, |
5985 | SCAN_INTERVAL); | ||
5586 | 5986 | ||
5587 | return; | 5987 | return; |
5588 | } | 5988 | } |
@@ -5601,7 +6001,7 @@ static inline void ipw_handle_data_packet(struct ipw_priv *priv, | |||
5601 | 6001 | ||
5602 | /* We only process data packets if the | 6002 | /* We only process data packets if the |
5603 | * interface is open */ | 6003 | * interface is open */ |
5604 | if (unlikely((pkt->u.frame.length + IPW_RX_FRAME_SIZE) > | 6004 | if (unlikely((le16_to_cpu(pkt->u.frame.length) + IPW_RX_FRAME_SIZE) > |
5605 | skb_tailroom(rxb->skb))) { | 6005 | skb_tailroom(rxb->skb))) { |
5606 | priv->ieee->stats.rx_errors++; | 6006 | priv->ieee->stats.rx_errors++; |
5607 | priv->wstats.discard.misc++; | 6007 | priv->wstats.discard.misc++; |
@@ -5618,14 +6018,16 @@ static inline void ipw_handle_data_packet(struct ipw_priv *priv, | |||
5618 | skb_reserve(rxb->skb, offsetof(struct ipw_rx_packet, u.frame.data)); | 6018 | skb_reserve(rxb->skb, offsetof(struct ipw_rx_packet, u.frame.data)); |
5619 | 6019 | ||
5620 | /* Set the size of the skb to the size of the frame */ | 6020 | /* Set the size of the skb to the size of the frame */ |
5621 | skb_put(rxb->skb, pkt->u.frame.length); | 6021 | skb_put(rxb->skb, le16_to_cpu(pkt->u.frame.length)); |
5622 | 6022 | ||
5623 | IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len); | 6023 | IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len); |
5624 | 6024 | ||
5625 | if (!ieee80211_rx(priv->ieee, rxb->skb, stats)) | 6025 | if (!ieee80211_rx(priv->ieee, rxb->skb, stats)) |
5626 | priv->ieee->stats.rx_errors++; | 6026 | priv->ieee->stats.rx_errors++; |
5627 | else /* ieee80211_rx succeeded, so it now owns the SKB */ | 6027 | else { /* ieee80211_rx succeeded, so it now owns the SKB */ |
5628 | rxb->skb = NULL; | 6028 | rxb->skb = NULL; |
6029 | ipw_led_activity_on(priv); | ||
6030 | } | ||
5629 | } | 6031 | } |
5630 | 6032 | ||
5631 | static inline int is_network_packet(struct ipw_priv *priv, | 6033 | static inline int is_network_packet(struct ipw_priv *priv, |
@@ -5634,23 +6036,29 @@ static inline int is_network_packet(struct ipw_priv *priv, | |||
5634 | /* Filter incoming packets to determine if they are targetted toward | 6036 | /* Filter incoming packets to determine if they are targetted toward |
5635 | * this network, discarding packets coming from ourselves */ | 6037 | * this network, discarding packets coming from ourselves */ |
5636 | switch (priv->ieee->iw_mode) { | 6038 | switch (priv->ieee->iw_mode) { |
5637 | case IW_MODE_ADHOC: | 6039 | case IW_MODE_ADHOC: /* Header: Dest. | Source | BSSID */ |
6040 | /* {broad,multi}cast packets to our IBSS go through */ | ||
5638 | if (is_broadcast_ether_addr(header->addr1) || | 6041 | if (is_broadcast_ether_addr(header->addr1) || |
5639 | is_multicast_ether_addr(header->addr1)) | 6042 | is_multicast_ether_addr(header->addr1)) |
5640 | return !memcmp(header->addr3, priv->bssid, ETH_ALEN); | 6043 | return !memcmp(header->addr3, priv->bssid, ETH_ALEN); |
5641 | else | 6044 | |
5642 | return memcmp(header->addr1, priv->net_dev->dev_addr, | 6045 | /* packets to our adapter go through */ |
5643 | ETH_ALEN); | 6046 | return !memcmp(header->addr1, priv->net_dev->dev_addr, |
6047 | ETH_ALEN); | ||
5644 | break; | 6048 | break; |
5645 | case IW_MODE_INFRA: | 6049 | |
5646 | if (is_broadcast_ether_addr(header->addr3) || | 6050 | case IW_MODE_INFRA: /* Header: Dest. | AP{BSSID} | Source */ |
5647 | is_multicast_ether_addr(header->addr3)) | 6051 | /* {broad,multi}cast packets to our IBSS go through */ |
5648 | return !memcmp(header->addr1, priv->bssid, ETH_ALEN); | 6052 | if (is_broadcast_ether_addr(header->addr1) || |
5649 | else | 6053 | is_multicast_ether_addr(header->addr1)) |
5650 | return memcmp(header->addr3, priv->net_dev->dev_addr, | 6054 | return !memcmp(header->addr2, priv->bssid, ETH_ALEN); |
5651 | ETH_ALEN); | 6055 | |
6056 | /* packets to our adapter go through */ | ||
6057 | return !memcmp(header->addr1, priv->net_dev->dev_addr, | ||
6058 | ETH_ALEN); | ||
5652 | break; | 6059 | break; |
5653 | } | 6060 | } |
6061 | |||
5654 | return 1; | 6062 | return 1; |
5655 | } | 6063 | } |
5656 | 6064 | ||
@@ -5695,7 +6103,7 @@ static void ipw_rx(struct ipw_priv *priv) | |||
5695 | struct ieee80211_rx_stats stats = { | 6103 | struct ieee80211_rx_stats stats = { |
5696 | .rssi = pkt->u.frame.rssi_dbm - | 6104 | .rssi = pkt->u.frame.rssi_dbm - |
5697 | IPW_RSSI_TO_DBM, | 6105 | IPW_RSSI_TO_DBM, |
5698 | .signal = pkt->u.frame.signal, | 6106 | /* .signal = le16_to_cpu(pkt->u.frame.signal), */ |
5699 | .rate = pkt->u.frame.rate, | 6107 | .rate = pkt->u.frame.rate, |
5700 | .mac_time = jiffies, | 6108 | .mac_time = jiffies, |
5701 | .received_channel = | 6109 | .received_channel = |
@@ -5705,7 +6113,7 @@ static void ipw_rx(struct ipw_priv *priv) | |||
5705 | control & (1 << 0)) ? | 6113 | control & (1 << 0)) ? |
5706 | IEEE80211_24GHZ_BAND : | 6114 | IEEE80211_24GHZ_BAND : |
5707 | IEEE80211_52GHZ_BAND, | 6115 | IEEE80211_52GHZ_BAND, |
5708 | .len = pkt->u.frame.length, | 6116 | .len = le16_to_cpu(pkt->u.frame.length), |
5709 | }; | 6117 | }; |
5710 | 6118 | ||
5711 | if (stats.rssi != 0) | 6119 | if (stats.rssi != 0) |
@@ -5746,9 +6154,10 @@ static void ipw_rx(struct ipw_priv *priv) | |||
5746 | } | 6154 | } |
5747 | 6155 | ||
5748 | IPW_DEBUG_RX("Frame: len=%u\n", | 6156 | IPW_DEBUG_RX("Frame: len=%u\n", |
5749 | pkt->u.frame.length); | 6157 | le16_to_cpu(pkt->u.frame.length)); |
5750 | 6158 | ||
5751 | if (pkt->u.frame.length < frame_hdr_len(header)) { | 6159 | if (le16_to_cpu(pkt->u.frame.length) < |
6160 | frame_hdr_len(header)) { | ||
5752 | IPW_DEBUG_DROP | 6161 | IPW_DEBUG_DROP |
5753 | ("Received packet is too small. " | 6162 | ("Received packet is too small. " |
5754 | "Dropping.\n"); | 6163 | "Dropping.\n"); |
@@ -5757,19 +6166,20 @@ static void ipw_rx(struct ipw_priv *priv) | |||
5757 | break; | 6166 | break; |
5758 | } | 6167 | } |
5759 | 6168 | ||
5760 | switch (WLAN_FC_GET_TYPE(header->frame_ctl)) { | 6169 | switch (WLAN_FC_GET_TYPE |
6170 | (le16_to_cpu(header->frame_ctl))) { | ||
5761 | case IEEE80211_FTYPE_MGMT: | 6171 | case IEEE80211_FTYPE_MGMT: |
5762 | ieee80211_rx_mgt(priv->ieee, header, | 6172 | ieee80211_rx_mgt(priv->ieee, header, |
5763 | &stats); | 6173 | &stats); |
5764 | if (priv->ieee->iw_mode == IW_MODE_ADHOC | 6174 | if (priv->ieee->iw_mode == IW_MODE_ADHOC |
5765 | && | 6175 | && |
5766 | ((WLAN_FC_GET_STYPE | 6176 | ((WLAN_FC_GET_STYPE |
5767 | (header->frame_ctl) == | 6177 | (le16_to_cpu(header->frame_ctl)) |
5768 | IEEE80211_STYPE_PROBE_RESP) | 6178 | == IEEE80211_STYPE_PROBE_RESP) |
5769 | || | 6179 | || |
5770 | (WLAN_FC_GET_STYPE | 6180 | (WLAN_FC_GET_STYPE |
5771 | (header->frame_ctl) == | 6181 | (le16_to_cpu(header->frame_ctl)) |
5772 | IEEE80211_STYPE_BEACON)) | 6182 | == IEEE80211_STYPE_BEACON)) |
5773 | && !memcmp(header->addr3, | 6183 | && !memcmp(header->addr3, |
5774 | priv->bssid, ETH_ALEN)) | 6184 | priv->bssid, ETH_ALEN)) |
5775 | ipw_add_station(priv, | 6185 | ipw_add_station(priv, |
@@ -5852,7 +6262,9 @@ static int ipw_wx_get_name(struct net_device *dev, | |||
5852 | union iwreq_data *wrqu, char *extra) | 6262 | union iwreq_data *wrqu, char *extra) |
5853 | { | 6263 | { |
5854 | struct ipw_priv *priv = ieee80211_priv(dev); | 6264 | struct ipw_priv *priv = ieee80211_priv(dev); |
5855 | if (!(priv->status & STATUS_ASSOCIATED)) | 6265 | if (priv->status & STATUS_RF_KILL_MASK) { |
6266 | strcpy(wrqu->name, "radio off"); | ||
6267 | } else if (!(priv->status & STATUS_ASSOCIATED)) | ||
5856 | strcpy(wrqu->name, "unassociated"); | 6268 | strcpy(wrqu->name, "unassociated"); |
5857 | else | 6269 | else |
5858 | snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11%c", | 6270 | snprintf(wrqu->name, IFNAMSIZ, "IEEE 802.11%c", |
@@ -5892,9 +6304,8 @@ static int ipw_set_channel(struct ipw_priv *priv, u8 channel) | |||
5892 | if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { | 6304 | if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { |
5893 | IPW_DEBUG_ASSOC("Disassociating due to channel change.\n"); | 6305 | IPW_DEBUG_ASSOC("Disassociating due to channel change.\n"); |
5894 | ipw_disassociate(priv); | 6306 | ipw_disassociate(priv); |
5895 | } else { | 6307 | } else if (!(priv->status & (STATUS_SCANNING))) |
5896 | ipw_associate(priv); | 6308 | ipw_associate(priv); |
5897 | } | ||
5898 | 6309 | ||
5899 | return 0; | 6310 | return 0; |
5900 | } | 6311 | } |
@@ -5986,9 +6397,8 @@ static int ipw_wx_set_mode(struct net_device *dev, | |||
5986 | #ifdef CONFIG_PM | 6397 | #ifdef CONFIG_PM |
5987 | /* Free the existing firmware and reset the fw_loaded | 6398 | /* Free the existing firmware and reset the fw_loaded |
5988 | * flag so ipw_load() will bring in the new firmawre */ | 6399 | * flag so ipw_load() will bring in the new firmawre */ |
5989 | if (fw_loaded) { | 6400 | if (fw_loaded) |
5990 | fw_loaded = 0; | 6401 | fw_loaded = 0; |
5991 | } | ||
5992 | 6402 | ||
5993 | release_firmware(bootfw); | 6403 | release_firmware(bootfw); |
5994 | release_firmware(ucode); | 6404 | release_firmware(ucode); |
@@ -5997,7 +6407,7 @@ static int ipw_wx_set_mode(struct net_device *dev, | |||
5997 | #endif | 6407 | #endif |
5998 | 6408 | ||
5999 | priv->ieee->iw_mode = wrqu->mode; | 6409 | priv->ieee->iw_mode = wrqu->mode; |
6000 | ipw_adapter_restart(priv); | 6410 | queue_work(priv->workqueue, &priv->adapter_restart); |
6001 | 6411 | ||
6002 | return err; | 6412 | return err; |
6003 | } | 6413 | } |
@@ -6149,9 +6559,8 @@ static int ipw_wx_set_wap(struct net_device *dev, | |||
6149 | if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { | 6559 | if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { |
6150 | IPW_DEBUG_ASSOC("Disassociating due to BSSID change.\n"); | 6560 | IPW_DEBUG_ASSOC("Disassociating due to BSSID change.\n"); |
6151 | ipw_disassociate(priv); | 6561 | ipw_disassociate(priv); |
6152 | } else { | 6562 | } else if (!(priv->status & (STATUS_SCANNING))) |
6153 | ipw_associate(priv); | 6563 | ipw_associate(priv); |
6154 | } | ||
6155 | 6564 | ||
6156 | return 0; | 6565 | return 0; |
6157 | } | 6566 | } |
@@ -6220,9 +6629,8 @@ static int ipw_wx_set_essid(struct net_device *dev, | |||
6220 | if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { | 6629 | if (priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { |
6221 | IPW_DEBUG_ASSOC("Disassociating due to ESSID change.\n"); | 6630 | IPW_DEBUG_ASSOC("Disassociating due to ESSID change.\n"); |
6222 | ipw_disassociate(priv); | 6631 | ipw_disassociate(priv); |
6223 | } else { | 6632 | } else if (!(priv->status & (STATUS_SCANNING))) |
6224 | ipw_associate(priv); | 6633 | ipw_associate(priv); |
6225 | } | ||
6226 | 6634 | ||
6227 | return 0; | 6635 | return 0; |
6228 | } | 6636 | } |
@@ -6383,10 +6791,10 @@ static int ipw_wx_set_rate(struct net_device *dev, | |||
6383 | if ((priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING))) { | 6791 | if ((priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING))) { |
6384 | IPW_DEBUG_ASSOC("Disassociating due to RATE change.\n"); | 6792 | IPW_DEBUG_ASSOC("Disassociating due to RATE change.\n"); |
6385 | ipw_disassociate(priv); | 6793 | ipw_disassociate(priv); |
6794 | } else if (!(priv->status & (STATUS_SCANNING))) { | ||
6795 | /* We are not yet associated, so kick one off... */ | ||
6796 | ipw_associate(priv); | ||
6386 | } | 6797 | } |
6387 | } else { | ||
6388 | /* We are not yet associated, so kick one off... */ | ||
6389 | ipw_associate(priv); | ||
6390 | } | 6798 | } |
6391 | 6799 | ||
6392 | return 0; | 6800 | return 0; |
@@ -6635,11 +7043,10 @@ static int ipw_wx_get_power(struct net_device *dev, | |||
6635 | { | 7043 | { |
6636 | struct ipw_priv *priv = ieee80211_priv(dev); | 7044 | struct ipw_priv *priv = ieee80211_priv(dev); |
6637 | 7045 | ||
6638 | if (!(priv->power_mode & IPW_POWER_ENABLED)) { | 7046 | if (!(priv->power_mode & IPW_POWER_ENABLED)) |
6639 | wrqu->power.disabled = 1; | 7047 | wrqu->power.disabled = 1; |
6640 | } else { | 7048 | else |
6641 | wrqu->power.disabled = 0; | 7049 | wrqu->power.disabled = 0; |
6642 | } | ||
6643 | 7050 | ||
6644 | IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode); | 7051 | IPW_DEBUG_WX("GET Power Management Mode -> %02X\n", priv->power_mode); |
6645 | 7052 | ||
@@ -6764,6 +7171,9 @@ static int ipw_wx_set_wireless_mode(struct net_device *dev, | |||
6764 | } else | 7171 | } else |
6765 | ipw_send_supported_rates(priv, &priv->rates); | 7172 | ipw_send_supported_rates(priv, &priv->rates); |
6766 | 7173 | ||
7174 | /* Update the band LEDs */ | ||
7175 | ipw_led_band_on(priv); | ||
7176 | |||
6767 | IPW_DEBUG_WX("PRIV SET MODE: %c%c%c\n", | 7177 | IPW_DEBUG_WX("PRIV SET MODE: %c%c%c\n", |
6768 | mode & IEEE_A ? 'a' : '.', | 7178 | mode & IEEE_A ? 'a' : '.', |
6769 | mode & IEEE_B ? 'b' : '.', mode & IEEE_G ? 'g' : '.'); | 7179 | mode & IEEE_B ? 'b' : '.', mode & IEEE_G ? 'g' : '.'); |
@@ -6870,7 +7280,7 @@ static int ipw_wx_set_monitor(struct net_device *dev, | |||
6870 | if (enable) { | 7280 | if (enable) { |
6871 | if (priv->ieee->iw_mode != IW_MODE_MONITOR) { | 7281 | if (priv->ieee->iw_mode != IW_MODE_MONITOR) { |
6872 | priv->net_dev->type = ARPHRD_IEEE80211; | 7282 | priv->net_dev->type = ARPHRD_IEEE80211; |
6873 | ipw_adapter_restart(priv); | 7283 | queue_work(priv->workqueue, &priv->adapter_restart); |
6874 | } | 7284 | } |
6875 | 7285 | ||
6876 | ipw_set_channel(priv, parms[1]); | 7286 | ipw_set_channel(priv, parms[1]); |
@@ -6878,7 +7288,7 @@ static int ipw_wx_set_monitor(struct net_device *dev, | |||
6878 | if (priv->ieee->iw_mode != IW_MODE_MONITOR) | 7288 | if (priv->ieee->iw_mode != IW_MODE_MONITOR) |
6879 | return 0; | 7289 | return 0; |
6880 | priv->net_dev->type = ARPHRD_ETHER; | 7290 | priv->net_dev->type = ARPHRD_ETHER; |
6881 | ipw_adapter_restart(priv); | 7291 | queue_work(priv->workqueue, &priv->adapter_restart); |
6882 | } | 7292 | } |
6883 | return 0; | 7293 | return 0; |
6884 | } | 7294 | } |
@@ -6889,7 +7299,7 @@ static int ipw_wx_reset(struct net_device *dev, | |||
6889 | { | 7299 | { |
6890 | struct ipw_priv *priv = ieee80211_priv(dev); | 7300 | struct ipw_priv *priv = ieee80211_priv(dev); |
6891 | IPW_DEBUG_WX("RESET\n"); | 7301 | IPW_DEBUG_WX("RESET\n"); |
6892 | ipw_adapter_restart(priv); | 7302 | queue_work(priv->workqueue, &priv->adapter_restart); |
6893 | return 0; | 7303 | return 0; |
6894 | } | 7304 | } |
6895 | #endif // CONFIG_IPW_MONITOR | 7305 | #endif // CONFIG_IPW_MONITOR |
@@ -6925,6 +7335,10 @@ static iw_handler ipw_wx_handlers[] = { | |||
6925 | IW_IOCTL(SIOCGIWENCODE) = ipw_wx_get_encode, | 7335 | IW_IOCTL(SIOCGIWENCODE) = ipw_wx_get_encode, |
6926 | IW_IOCTL(SIOCSIWPOWER) = ipw_wx_set_power, | 7336 | IW_IOCTL(SIOCSIWPOWER) = ipw_wx_set_power, |
6927 | IW_IOCTL(SIOCGIWPOWER) = ipw_wx_get_power, | 7337 | IW_IOCTL(SIOCGIWPOWER) = ipw_wx_get_power, |
7338 | IW_IOCTL(SIOCSIWSPY) = iw_handler_set_spy, | ||
7339 | IW_IOCTL(SIOCGIWSPY) = iw_handler_get_spy, | ||
7340 | IW_IOCTL(SIOCSIWTHRSPY) = iw_handler_set_thrspy, | ||
7341 | IW_IOCTL(SIOCGIWTHRSPY) = iw_handler_get_thrspy, | ||
6928 | }; | 7342 | }; |
6929 | 7343 | ||
6930 | #define IPW_PRIV_SET_POWER SIOCIWFIRSTPRIV | 7344 | #define IPW_PRIV_SET_POWER SIOCIWFIRSTPRIV |
@@ -6993,6 +7407,8 @@ static struct iw_handler_def ipw_wx_handler_def = { | |||
6993 | .private_args = ipw_priv_args, | 7407 | .private_args = ipw_priv_args, |
6994 | }; | 7408 | }; |
6995 | 7409 | ||
7410 | static struct iw_public_data ipw_wx_data; | ||
7411 | |||
6996 | /* | 7412 | /* |
6997 | * Get wireless statistics. | 7413 | * Get wireless statistics. |
6998 | * Called by /proc/net/wireless | 7414 | * Called by /proc/net/wireless |
@@ -7057,7 +7473,7 @@ static inline void init_sys_config(struct ipw_sys_config *sys_config) | |||
7057 | sys_config->dot11g_auto_detection = 0; | 7473 | sys_config->dot11g_auto_detection = 0; |
7058 | sys_config->enable_cts_to_self = 0; | 7474 | sys_config->enable_cts_to_self = 0; |
7059 | sys_config->bt_coexist_collision_thr = 0; | 7475 | sys_config->bt_coexist_collision_thr = 0; |
7060 | sys_config->pass_noise_stats_to_host = 1; | 7476 | sys_config->pass_noise_stats_to_host = 0; //1 -- fix for 256 |
7061 | } | 7477 | } |
7062 | 7478 | ||
7063 | static int ipw_net_open(struct net_device *dev) | 7479 | static int ipw_net_open(struct net_device *dev) |
@@ -7131,7 +7547,7 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb) | |||
7131 | tfd->control_flags.control_bits = TFD_NEED_IRQ_MASK; | 7547 | tfd->control_flags.control_bits = TFD_NEED_IRQ_MASK; |
7132 | 7548 | ||
7133 | tfd->u.data.cmd_id = DINO_CMD_TX; | 7549 | tfd->u.data.cmd_id = DINO_CMD_TX; |
7134 | tfd->u.data.len = txb->payload_size; | 7550 | tfd->u.data.len = cpu_to_le16(txb->payload_size); |
7135 | remaining_bytes = txb->payload_size; | 7551 | remaining_bytes = txb->payload_size; |
7136 | if (unlikely(!unicast)) | 7552 | if (unlikely(!unicast)) |
7137 | tfd->u.data.tx_flags = DCT_FLAG_NO_WEP; | 7553 | tfd->u.data.tx_flags = DCT_FLAG_NO_WEP; |
@@ -7149,8 +7565,14 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb) | |||
7149 | memcpy(&tfd->u.data.tfd.tfd_24.mchdr, hdr, hdr_len); | 7565 | memcpy(&tfd->u.data.tfd.tfd_24.mchdr, hdr, hdr_len); |
7150 | 7566 | ||
7151 | /* payload */ | 7567 | /* payload */ |
7152 | tfd->u.data.num_chunks = min((u8) (NUM_TFD_CHUNKS - 2), txb->nr_frags); | 7568 | tfd->u.data.num_chunks = cpu_to_le32(min((u8) (NUM_TFD_CHUNKS - 2), |
7153 | for (i = 0; i < tfd->u.data.num_chunks; i++) { | 7569 | txb->nr_frags)); |
7570 | IPW_DEBUG_FRAG("%i fragments being sent as %i chunks.\n", | ||
7571 | txb->nr_frags, le32_to_cpu(tfd->u.data.num_chunks)); | ||
7572 | for (i = 0; i < le32_to_cpu(tfd->u.data.num_chunks); i++) { | ||
7573 | IPW_DEBUG_FRAG("Adding fragment %i of %i (%d bytes).\n", | ||
7574 | i, le32_to_cpu(tfd->u.data.num_chunks), | ||
7575 | txb->fragments[i]->len - hdr_len); | ||
7154 | IPW_DEBUG_TX("Dumping TX packet frag %i of %i (%d bytes):\n", | 7576 | IPW_DEBUG_TX("Dumping TX packet frag %i of %i (%d bytes):\n", |
7155 | i, tfd->u.data.num_chunks, | 7577 | i, tfd->u.data.num_chunks, |
7156 | txb->fragments[i]->len - hdr_len); | 7578 | txb->fragments[i]->len - hdr_len); |
@@ -7158,11 +7580,13 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb) | |||
7158 | txb->fragments[i]->len - hdr_len); | 7580 | txb->fragments[i]->len - hdr_len); |
7159 | 7581 | ||
7160 | tfd->u.data.chunk_ptr[i] = | 7582 | tfd->u.data.chunk_ptr[i] = |
7161 | pci_map_single(priv->pci_dev, | 7583 | cpu_to_le32(pci_map_single |
7162 | txb->fragments[i]->data + hdr_len, | 7584 | (priv->pci_dev, |
7163 | txb->fragments[i]->len - hdr_len, | 7585 | txb->fragments[i]->data + hdr_len, |
7164 | PCI_DMA_TODEVICE); | 7586 | txb->fragments[i]->len - hdr_len, |
7165 | tfd->u.data.chunk_len[i] = txb->fragments[i]->len - hdr_len; | 7587 | PCI_DMA_TODEVICE)); |
7588 | tfd->u.data.chunk_len[i] = | ||
7589 | cpu_to_le16(txb->fragments[i]->len - hdr_len); | ||
7166 | } | 7590 | } |
7167 | 7591 | ||
7168 | if (i != txb->nr_frags) { | 7592 | if (i != txb->nr_frags) { |
@@ -7177,7 +7601,7 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb) | |||
7177 | remaining_bytes); | 7601 | remaining_bytes); |
7178 | skb = alloc_skb(remaining_bytes, GFP_ATOMIC); | 7602 | skb = alloc_skb(remaining_bytes, GFP_ATOMIC); |
7179 | if (skb != NULL) { | 7603 | if (skb != NULL) { |
7180 | tfd->u.data.chunk_len[i] = remaining_bytes; | 7604 | tfd->u.data.chunk_len[i] = cpu_to_le16(remaining_bytes); |
7181 | for (j = i; j < txb->nr_frags; j++) { | 7605 | for (j = i; j < txb->nr_frags; j++) { |
7182 | int size = txb->fragments[j]->len - hdr_len; | 7606 | int size = txb->fragments[j]->len - hdr_len; |
7183 | printk(KERN_INFO "Adding frag %d %d...\n", | 7607 | printk(KERN_INFO "Adding frag %d %d...\n", |
@@ -7188,10 +7612,14 @@ static inline void ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb) | |||
7188 | dev_kfree_skb_any(txb->fragments[i]); | 7612 | dev_kfree_skb_any(txb->fragments[i]); |
7189 | txb->fragments[i] = skb; | 7613 | txb->fragments[i] = skb; |
7190 | tfd->u.data.chunk_ptr[i] = | 7614 | tfd->u.data.chunk_ptr[i] = |
7191 | pci_map_single(priv->pci_dev, skb->data, | 7615 | cpu_to_le32(pci_map_single |
7192 | tfd->u.data.chunk_len[i], | 7616 | (priv->pci_dev, skb->data, |
7193 | PCI_DMA_TODEVICE); | 7617 | tfd->u.data.chunk_len[i], |
7194 | tfd->u.data.num_chunks++; | 7618 | PCI_DMA_TODEVICE)); |
7619 | |||
7620 | tfd->u.data.num_chunks = | ||
7621 | cpu_to_le32(le32_to_cpu(tfd->u.data.num_chunks) + | ||
7622 | 1); | ||
7195 | } | 7623 | } |
7196 | } | 7624 | } |
7197 | 7625 | ||
@@ -7227,6 +7655,7 @@ static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb, | |||
7227 | } | 7655 | } |
7228 | 7656 | ||
7229 | ipw_tx_skb(priv, txb); | 7657 | ipw_tx_skb(priv, txb); |
7658 | ipw_led_activity_on(priv); | ||
7230 | 7659 | ||
7231 | spin_unlock_irqrestore(&priv->lock, flags); | 7660 | spin_unlock_irqrestore(&priv->lock, flags); |
7232 | return 0; | 7661 | return 0; |
@@ -7260,7 +7689,7 @@ static int ipw_net_set_mac_address(struct net_device *dev, void *p) | |||
7260 | memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN); | 7689 | memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN); |
7261 | printk(KERN_INFO "%s: Setting MAC to " MAC_FMT "\n", | 7690 | printk(KERN_INFO "%s: Setting MAC to " MAC_FMT "\n", |
7262 | priv->net_dev->name, MAC_ARG(priv->mac_addr)); | 7691 | priv->net_dev->name, MAC_ARG(priv->mac_addr)); |
7263 | ipw_adapter_restart(priv); | 7692 | queue_work(priv->workqueue, &priv->adapter_restart); |
7264 | return 0; | 7693 | return 0; |
7265 | } | 7694 | } |
7266 | 7695 | ||
@@ -7414,6 +7843,46 @@ static void ipw_rf_kill(void *adapter) | |||
7414 | spin_unlock_irqrestore(&priv->lock, flags); | 7843 | spin_unlock_irqrestore(&priv->lock, flags); |
7415 | } | 7844 | } |
7416 | 7845 | ||
7846 | void ipw_link_up(struct ipw_priv *priv) | ||
7847 | { | ||
7848 | netif_carrier_on(priv->net_dev); | ||
7849 | if (netif_queue_stopped(priv->net_dev)) { | ||
7850 | IPW_DEBUG_NOTIF("waking queue\n"); | ||
7851 | netif_wake_queue(priv->net_dev); | ||
7852 | } else { | ||
7853 | IPW_DEBUG_NOTIF("starting queue\n"); | ||
7854 | netif_start_queue(priv->net_dev); | ||
7855 | } | ||
7856 | |||
7857 | ipw_reset_stats(priv); | ||
7858 | /* Ensure the rate is updated immediately */ | ||
7859 | priv->last_rate = ipw_get_current_rate(priv); | ||
7860 | ipw_gather_stats(priv); | ||
7861 | ipw_led_link_up(priv); | ||
7862 | notify_wx_assoc_event(priv); | ||
7863 | |||
7864 | if (priv->config & CFG_BACKGROUND_SCAN) | ||
7865 | queue_delayed_work(priv->workqueue, &priv->request_scan, HZ); | ||
7866 | } | ||
7867 | |||
7868 | void ipw_link_down(struct ipw_priv *priv) | ||
7869 | { | ||
7870 | ipw_led_link_down(priv); | ||
7871 | netif_carrier_off(priv->net_dev); | ||
7872 | netif_stop_queue(priv->net_dev); | ||
7873 | notify_wx_assoc_event(priv); | ||
7874 | |||
7875 | /* Cancel any queued work ... */ | ||
7876 | cancel_delayed_work(&priv->request_scan); | ||
7877 | cancel_delayed_work(&priv->adhoc_check); | ||
7878 | cancel_delayed_work(&priv->gather_stats); | ||
7879 | |||
7880 | ipw_reset_stats(priv); | ||
7881 | |||
7882 | /* Queue up another scan... */ | ||
7883 | queue_work(priv->workqueue, &priv->request_scan); | ||
7884 | } | ||
7885 | |||
7417 | static int ipw_setup_deferred_work(struct ipw_priv *priv) | 7886 | static int ipw_setup_deferred_work(struct ipw_priv *priv) |
7418 | { | 7887 | { |
7419 | int ret = 0; | 7888 | int ret = 0; |
@@ -7436,6 +7905,13 @@ static int ipw_setup_deferred_work(struct ipw_priv *priv) | |||
7436 | INIT_WORK(&priv->abort_scan, (void (*)(void *))ipw_abort_scan, priv); | 7905 | INIT_WORK(&priv->abort_scan, (void (*)(void *))ipw_abort_scan, priv); |
7437 | INIT_WORK(&priv->roam, ipw_roam, priv); | 7906 | INIT_WORK(&priv->roam, ipw_roam, priv); |
7438 | INIT_WORK(&priv->scan_check, ipw_scan_check, priv); | 7907 | INIT_WORK(&priv->scan_check, ipw_scan_check, priv); |
7908 | INIT_WORK(&priv->link_up, (void (*)(void *))ipw_link_up, priv); | ||
7909 | INIT_WORK(&priv->link_down, (void (*)(void *))ipw_link_down, priv); | ||
7910 | INIT_WORK(&priv->led_link_on, (void (*)(void *))ipw_led_link_on, priv); | ||
7911 | INIT_WORK(&priv->led_link_off, (void (*)(void *))ipw_led_link_off, | ||
7912 | priv); | ||
7913 | INIT_WORK(&priv->led_act_off, (void (*)(void *))ipw_led_activity_off, | ||
7914 | priv); | ||
7439 | 7915 | ||
7440 | tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) | 7916 | tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) |
7441 | ipw_irq_tasklet, (unsigned long)priv); | 7917 | ipw_irq_tasklet, (unsigned long)priv); |
@@ -7636,8 +8112,9 @@ static int ipw_up(struct ipw_priv *priv) | |||
7636 | rc = ipw_config(priv); | 8112 | rc = ipw_config(priv); |
7637 | if (!rc) { | 8113 | if (!rc) { |
7638 | IPW_DEBUG_INFO("Configured device on count %i\n", i); | 8114 | IPW_DEBUG_INFO("Configured device on count %i\n", i); |
8115 | ipw_led_init(priv); | ||
8116 | ipw_led_radio_on(priv); | ||
7639 | priv->notif_missed_beacons = 0; | 8117 | priv->notif_missed_beacons = 0; |
7640 | netif_start_queue(priv->net_dev); | ||
7641 | return 0; | 8118 | return 0; |
7642 | } else { | 8119 | } else { |
7643 | IPW_DEBUG_INFO("Device configuration failed: 0x%08X\n", | 8120 | IPW_DEBUG_INFO("Device configuration failed: 0x%08X\n", |
@@ -7675,11 +8152,12 @@ static void ipw_down(struct ipw_priv *priv) | |||
7675 | netif_stop_queue(priv->net_dev); | 8152 | netif_stop_queue(priv->net_dev); |
7676 | 8153 | ||
7677 | ipw_stop_nic(priv); | 8154 | ipw_stop_nic(priv); |
8155 | |||
8156 | ipw_led_radio_off(priv); | ||
7678 | } | 8157 | } |
7679 | 8158 | ||
7680 | static int ipw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | 8159 | static int ipw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) |
7681 | { | 8160 | { |
7682 | #ifdef CONFIG_IEEE80211_WPA | ||
7683 | struct iwreq *wrq = (struct iwreq *)rq; | 8161 | struct iwreq *wrq = (struct iwreq *)rq; |
7684 | int ret = -1; | 8162 | int ret = -1; |
7685 | switch (cmd) { | 8163 | switch (cmd) { |
@@ -7691,8 +8169,6 @@ static int ipw_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | |||
7691 | return -EOPNOTSUPP; | 8169 | return -EOPNOTSUPP; |
7692 | } | 8170 | } |
7693 | 8171 | ||
7694 | #endif /* CONFIG_IEEE80211_WPA */ | ||
7695 | |||
7696 | return -EOPNOTSUPP; | 8172 | return -EOPNOTSUPP; |
7697 | } | 8173 | } |
7698 | 8174 | ||
@@ -7739,7 +8215,7 @@ static struct pci_device_id card_ids[] = { | |||
7739 | {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2762, 0, 0, 0}, | 8215 | {PCI_VENDOR_ID_INTEL, 0x1043, 0x8086, 0x2762, 0, 0, 0}, |
7740 | {PCI_VENDOR_ID_INTEL, 0x104f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, | 8216 | {PCI_VENDOR_ID_INTEL, 0x104f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, |
7741 | {PCI_VENDOR_ID_INTEL, 0x4220, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* BG */ | 8217 | {PCI_VENDOR_ID_INTEL, 0x4220, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* BG */ |
7742 | {PCI_VENDOR_ID_INTEL, 0x4221, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* 2225BG */ | 8218 | {PCI_VENDOR_ID_INTEL, 0x4221, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* BG */ |
7743 | {PCI_VENDOR_ID_INTEL, 0x4223, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */ | 8219 | {PCI_VENDOR_ID_INTEL, 0x4223, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */ |
7744 | {PCI_VENDOR_ID_INTEL, 0x4224, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */ | 8220 | {PCI_VENDOR_ID_INTEL, 0x4224, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, /* ABG */ |
7745 | 8221 | ||
@@ -7764,6 +8240,8 @@ static struct attribute *ipw_sysfs_entries[] = { | |||
7764 | &dev_attr_eeprom_delay.attr, | 8240 | &dev_attr_eeprom_delay.attr, |
7765 | &dev_attr_ucode_version.attr, | 8241 | &dev_attr_ucode_version.attr, |
7766 | &dev_attr_rtc.attr, | 8242 | &dev_attr_rtc.attr, |
8243 | &dev_attr_scan_age.attr, | ||
8244 | &dev_attr_led.attr, | ||
7767 | NULL | 8245 | NULL |
7768 | }; | 8246 | }; |
7769 | 8247 | ||
@@ -7789,6 +8267,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
7789 | 8267 | ||
7790 | priv = ieee80211_priv(net_dev); | 8268 | priv = ieee80211_priv(net_dev); |
7791 | priv->ieee = netdev_priv(net_dev); | 8269 | priv->ieee = netdev_priv(net_dev); |
8270 | |||
7792 | priv->net_dev = net_dev; | 8271 | priv->net_dev = net_dev; |
7793 | priv->pci_dev = pdev; | 8272 | priv->pci_dev = pdev; |
7794 | #ifdef CONFIG_IPW_DEBUG | 8273 | #ifdef CONFIG_IPW_DEBUG |
@@ -7843,6 +8322,12 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
7843 | } | 8322 | } |
7844 | 8323 | ||
7845 | /* Initialize module parameter values here */ | 8324 | /* Initialize module parameter values here */ |
8325 | |||
8326 | /* We default to disabling the LED code as right now it causes | ||
8327 | * too many systems to lock up... */ | ||
8328 | if (!led) | ||
8329 | priv->config |= CFG_NO_LED; | ||
8330 | |||
7846 | if (associate) | 8331 | if (associate) |
7847 | priv->config |= CFG_ASSOCIATE; | 8332 | priv->config |= CFG_ASSOCIATE; |
7848 | else | 8333 | else |
@@ -7893,14 +8378,9 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
7893 | priv->adapter = IPW_2915ABG; | 8378 | priv->adapter = IPW_2915ABG; |
7894 | priv->ieee->mode = IEEE_A | IEEE_G | IEEE_B; | 8379 | priv->ieee->mode = IEEE_A | IEEE_G | IEEE_B; |
7895 | } else { | 8380 | } else { |
7896 | if (priv->pci_dev->device == 0x4221) | 8381 | printk(KERN_INFO DRV_NAME |
7897 | printk(KERN_INFO DRV_NAME | 8382 | ": Detected Intel PRO/Wireless 2200BG Network " |
7898 | ": Detected Intel PRO/Wireless 2225BG Network " | 8383 | "Connection\n"); |
7899 | "Connection\n"); | ||
7900 | else | ||
7901 | printk(KERN_INFO DRV_NAME | ||
7902 | ": Detected Intel PRO/Wireless 2200BG Network " | ||
7903 | "Connection\n"); | ||
7904 | 8384 | ||
7905 | priv->ieee->abg_true = 0; | 8385 | priv->ieee->abg_true = 0; |
7906 | band = IEEE80211_24GHZ_BAND; | 8386 | band = IEEE80211_24GHZ_BAND; |
@@ -7933,6 +8413,9 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
7933 | SET_MODULE_OWNER(net_dev); | 8413 | SET_MODULE_OWNER(net_dev); |
7934 | SET_NETDEV_DEV(net_dev, &pdev->dev); | 8414 | SET_NETDEV_DEV(net_dev, &pdev->dev); |
7935 | 8415 | ||
8416 | ipw_wx_data.spy_data = &priv->ieee->spy_data; | ||
8417 | ipw_wx_data.ieee80211 = priv->ieee; | ||
8418 | |||
7936 | priv->ieee->hard_start_xmit = ipw_net_hard_start_xmit; | 8419 | priv->ieee->hard_start_xmit = ipw_net_hard_start_xmit; |
7937 | priv->ieee->set_security = shim__set_security; | 8420 | priv->ieee->set_security = shim__set_security; |
7938 | 8421 | ||
@@ -7944,6 +8427,7 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
7944 | net_dev->set_multicast_list = ipw_net_set_multicast_list; | 8427 | net_dev->set_multicast_list = ipw_net_set_multicast_list; |
7945 | net_dev->set_mac_address = ipw_net_set_mac_address; | 8428 | net_dev->set_mac_address = ipw_net_set_mac_address; |
7946 | net_dev->get_wireless_stats = ipw_get_wireless_stats; | 8429 | net_dev->get_wireless_stats = ipw_get_wireless_stats; |
8430 | net_dev->wireless_data = &ipw_wx_data; | ||
7947 | net_dev->wireless_handlers = &ipw_wx_handler_def; | 8431 | net_dev->wireless_handlers = &ipw_wx_handler_def; |
7948 | net_dev->ethtool_ops = &ipw_ethtool_ops; | 8432 | net_dev->ethtool_ops = &ipw_ethtool_ops; |
7949 | net_dev->irq = pdev->irq; | 8433 | net_dev->irq = pdev->irq; |
@@ -7960,12 +8444,12 @@ static int ipw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
7960 | err = register_netdev(net_dev); | 8444 | err = register_netdev(net_dev); |
7961 | if (err) { | 8445 | if (err) { |
7962 | IPW_ERROR("failed to register network device\n"); | 8446 | IPW_ERROR("failed to register network device\n"); |
7963 | goto out_remove_group; | 8447 | goto out_remove_sysfs; |
7964 | } | 8448 | } |
7965 | 8449 | ||
7966 | return 0; | 8450 | return 0; |
7967 | 8451 | ||
7968 | out_remove_group: | 8452 | out_remove_sysfs: |
7969 | sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group); | 8453 | sysfs_remove_group(&pdev->dev.kobj, &ipw_attribute_group); |
7970 | out_release_irq: | 8454 | out_release_irq: |
7971 | free_irq(pdev->irq, priv); | 8455 | free_irq(pdev->irq, priv); |
@@ -8005,17 +8489,17 @@ static void ipw_pci_remove(struct pci_dev *pdev) | |||
8005 | } | 8489 | } |
8006 | ipw_tx_queue_free(priv); | 8490 | ipw_tx_queue_free(priv); |
8007 | 8491 | ||
8492 | ipw_led_shutdown(priv); | ||
8493 | |||
8008 | /* ipw_down will ensure that there is no more pending work | 8494 | /* ipw_down will ensure that there is no more pending work |
8009 | * in the workqueue's, so we can safely remove them now. */ | 8495 | * in the workqueue's, so we can safely remove them now. */ |
8010 | if (priv->workqueue) { | 8496 | cancel_delayed_work(&priv->adhoc_check); |
8011 | cancel_delayed_work(&priv->adhoc_check); | 8497 | cancel_delayed_work(&priv->gather_stats); |
8012 | cancel_delayed_work(&priv->gather_stats); | 8498 | cancel_delayed_work(&priv->request_scan); |
8013 | cancel_delayed_work(&priv->request_scan); | 8499 | cancel_delayed_work(&priv->rf_kill); |
8014 | cancel_delayed_work(&priv->rf_kill); | 8500 | cancel_delayed_work(&priv->scan_check); |
8015 | cancel_delayed_work(&priv->scan_check); | 8501 | destroy_workqueue(priv->workqueue); |
8016 | destroy_workqueue(priv->workqueue); | 8502 | priv->workqueue = NULL; |
8017 | priv->workqueue = NULL; | ||
8018 | } | ||
8019 | 8503 | ||
8020 | free_irq(pdev->irq, priv); | 8504 | free_irq(pdev->irq, priv); |
8021 | iounmap(priv->hw_base); | 8505 | iounmap(priv->hw_base); |
@@ -8138,6 +8622,10 @@ MODULE_PARM_DESC(associate, "auto associate when scanning (default on)"); | |||
8138 | module_param(auto_create, int, 0444); | 8622 | module_param(auto_create, int, 0444); |
8139 | MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)"); | 8623 | MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)"); |
8140 | 8624 | ||
8625 | module_param(led, int, 0444); | ||
8626 | MODULE_PARM_DESC(auto_create, | ||
8627 | "enable led control on some systems (default 0 off)\n"); | ||
8628 | |||
8141 | module_param(debug, int, 0444); | 8629 | module_param(debug, int, 0444); |
8142 | MODULE_PARM_DESC(debug, "debug output mask"); | 8630 | MODULE_PARM_DESC(debug, "debug output mask"); |
8143 | 8631 | ||
diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index 068027963181..1b339cb7a522 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h | |||
@@ -403,9 +403,9 @@ struct clx2_tx_queue { | |||
403 | #define RX_FREE_BUFFERS 32 | 403 | #define RX_FREE_BUFFERS 32 |
404 | #define RX_LOW_WATERMARK 8 | 404 | #define RX_LOW_WATERMARK 8 |
405 | 405 | ||
406 | #define SUP_RATE_11A_MAX_NUM_CHANNELS (8) | 406 | #define SUP_RATE_11A_MAX_NUM_CHANNELS 8 |
407 | #define SUP_RATE_11B_MAX_NUM_CHANNELS (4) | 407 | #define SUP_RATE_11B_MAX_NUM_CHANNELS 4 |
408 | #define SUP_RATE_11G_MAX_NUM_CHANNELS (12) | 408 | #define SUP_RATE_11G_MAX_NUM_CHANNELS 12 |
409 | 409 | ||
410 | // Used for passing to driver number of successes and failures per rate | 410 | // Used for passing to driver number of successes and failures per rate |
411 | struct rate_histogram { | 411 | struct rate_histogram { |
@@ -890,6 +890,9 @@ struct ipw_cmd { | |||
890 | #define STATUS_SCANNING (1<<21) | 890 | #define STATUS_SCANNING (1<<21) |
891 | #define STATUS_SCAN_ABORTING (1<<22) | 891 | #define STATUS_SCAN_ABORTING (1<<22) |
892 | 892 | ||
893 | #define STATUS_LED_LINK_ON (1<<24) | ||
894 | #define STATUS_LED_ACT_ON (1<<25) | ||
895 | |||
893 | #define STATUS_INDIRECT_BYTE (1<<28) /* sysfs entry configured for access */ | 896 | #define STATUS_INDIRECT_BYTE (1<<28) /* sysfs entry configured for access */ |
894 | #define STATUS_INDIRECT_DWORD (1<<29) /* sysfs entry configured for access */ | 897 | #define STATUS_INDIRECT_DWORD (1<<29) /* sysfs entry configured for access */ |
895 | #define STATUS_DIRECT_DWORD (1<<30) /* sysfs entry configured for access */ | 898 | #define STATUS_DIRECT_DWORD (1<<30) /* sysfs entry configured for access */ |
@@ -905,6 +908,8 @@ struct ipw_cmd { | |||
905 | #define CFG_ASSOCIATE (1<<6) | 908 | #define CFG_ASSOCIATE (1<<6) |
906 | #define CFG_FIXED_RATE (1<<7) | 909 | #define CFG_FIXED_RATE (1<<7) |
907 | #define CFG_ADHOC_CREATE (1<<8) | 910 | #define CFG_ADHOC_CREATE (1<<8) |
911 | #define CFG_NO_LED (1<<9) | ||
912 | #define CFG_BACKGROUND_SCAN (1<<10) | ||
908 | 913 | ||
909 | #define CAP_SHARED_KEY (1<<0) /* Off = OPEN */ | 914 | #define CAP_SHARED_KEY (1<<0) /* Off = OPEN */ |
910 | #define CAP_PRIVACY_ON (1<<1) /* Off = No privacy */ | 915 | #define CAP_PRIVACY_ON (1<<1) /* Off = No privacy */ |
@@ -1046,9 +1051,24 @@ struct ipw_priv { | |||
1046 | struct work_struct abort_scan; | 1051 | struct work_struct abort_scan; |
1047 | struct work_struct roam; | 1052 | struct work_struct roam; |
1048 | struct work_struct scan_check; | 1053 | struct work_struct scan_check; |
1054 | struct work_struct link_up; | ||
1055 | struct work_struct link_down; | ||
1049 | 1056 | ||
1050 | struct tasklet_struct irq_tasklet; | 1057 | struct tasklet_struct irq_tasklet; |
1051 | 1058 | ||
1059 | /* LED related variables and work_struct */ | ||
1060 | u8 nic_type; | ||
1061 | u32 led_activity_on; | ||
1062 | u32 led_activity_off; | ||
1063 | u32 led_association_on; | ||
1064 | u32 led_association_off; | ||
1065 | u32 led_ofdm_on; | ||
1066 | u32 led_ofdm_off; | ||
1067 | |||
1068 | struct work_struct led_link_on; | ||
1069 | struct work_struct led_link_off; | ||
1070 | struct work_struct led_act_off; | ||
1071 | |||
1052 | #define IPW_2200BG 1 | 1072 | #define IPW_2200BG 1 |
1053 | #define IPW_2915ABG 2 | 1073 | #define IPW_2915ABG 2 |
1054 | u8 adapter; | 1074 | u8 adapter; |
@@ -1126,6 +1146,8 @@ do { if (ipw_debug_level & (level)) \ | |||
1126 | #define IPW_DL_RF_KILL (1<<17) | 1146 | #define IPW_DL_RF_KILL (1<<17) |
1127 | #define IPW_DL_FW_ERRORS (1<<18) | 1147 | #define IPW_DL_FW_ERRORS (1<<18) |
1128 | 1148 | ||
1149 | #define IPW_DL_LED (1<<19) | ||
1150 | |||
1129 | #define IPW_DL_ORD (1<<20) | 1151 | #define IPW_DL_ORD (1<<20) |
1130 | 1152 | ||
1131 | #define IPW_DL_FRAG (1<<21) | 1153 | #define IPW_DL_FRAG (1<<21) |
@@ -1151,6 +1173,7 @@ do { if (ipw_debug_level & (level)) \ | |||
1151 | #define IPW_DEBUG_TX(f, a...) IPW_DEBUG(IPW_DL_TX, f, ## a) | 1173 | #define IPW_DEBUG_TX(f, a...) IPW_DEBUG(IPW_DL_TX, f, ## a) |
1152 | #define IPW_DEBUG_ISR(f, a...) IPW_DEBUG(IPW_DL_ISR, f, ## a) | 1174 | #define IPW_DEBUG_ISR(f, a...) IPW_DEBUG(IPW_DL_ISR, f, ## a) |
1153 | #define IPW_DEBUG_MANAGEMENT(f, a...) IPW_DEBUG(IPW_DL_MANAGE, f, ## a) | 1175 | #define IPW_DEBUG_MANAGEMENT(f, a...) IPW_DEBUG(IPW_DL_MANAGE, f, ## a) |
1176 | #define IPW_DEBUG_LED(f, a...) IPW_DEBUG(IPW_DL_LED, f, ## a) | ||
1154 | #define IPW_DEBUG_WEP(f, a...) IPW_DEBUG(IPW_DL_WEP, f, ## a) | 1177 | #define IPW_DEBUG_WEP(f, a...) IPW_DEBUG(IPW_DL_WEP, f, ## a) |
1155 | #define IPW_DEBUG_HC(f, a...) IPW_DEBUG(IPW_DL_HOST_COMMAND, f, ## a) | 1178 | #define IPW_DEBUG_HC(f, a...) IPW_DEBUG(IPW_DL_HOST_COMMAND, f, ## a) |
1156 | #define IPW_DEBUG_FRAG(f, a...) IPW_DEBUG(IPW_DL_FRAG, f, ## a) | 1179 | #define IPW_DEBUG_FRAG(f, a...) IPW_DEBUG(IPW_DL_FRAG, f, ## a) |
@@ -1268,25 +1291,25 @@ do { if (ipw_debug_level & (level)) \ | |||
1268 | #define CX2_DMA_I_DMA_CONTROL 0x003000A4 | 1291 | #define CX2_DMA_I_DMA_CONTROL 0x003000A4 |
1269 | #define CX2_DMA_I_CB_BASE 0x003000A0 | 1292 | #define CX2_DMA_I_CB_BASE 0x003000A0 |
1270 | 1293 | ||
1271 | #define CX2_TX_CMD_QUEUE_BD_BASE (0x00000200) | 1294 | #define CX2_TX_CMD_QUEUE_BD_BASE 0x00000200 |
1272 | #define CX2_TX_CMD_QUEUE_BD_SIZE (0x00000204) | 1295 | #define CX2_TX_CMD_QUEUE_BD_SIZE 0x00000204 |
1273 | #define CX2_TX_QUEUE_0_BD_BASE (0x00000208) | 1296 | #define CX2_TX_QUEUE_0_BD_BASE 0x00000208 |
1274 | #define CX2_TX_QUEUE_0_BD_SIZE (0x0000020C) | 1297 | #define CX2_TX_QUEUE_0_BD_SIZE (0x0000020C) |
1275 | #define CX2_TX_QUEUE_1_BD_BASE (0x00000210) | 1298 | #define CX2_TX_QUEUE_1_BD_BASE 0x00000210 |
1276 | #define CX2_TX_QUEUE_1_BD_SIZE (0x00000214) | 1299 | #define CX2_TX_QUEUE_1_BD_SIZE 0x00000214 |
1277 | #define CX2_TX_QUEUE_2_BD_BASE (0x00000218) | 1300 | #define CX2_TX_QUEUE_2_BD_BASE 0x00000218 |
1278 | #define CX2_TX_QUEUE_2_BD_SIZE (0x0000021C) | 1301 | #define CX2_TX_QUEUE_2_BD_SIZE (0x0000021C) |
1279 | #define CX2_TX_QUEUE_3_BD_BASE (0x00000220) | 1302 | #define CX2_TX_QUEUE_3_BD_BASE 0x00000220 |
1280 | #define CX2_TX_QUEUE_3_BD_SIZE (0x00000224) | 1303 | #define CX2_TX_QUEUE_3_BD_SIZE 0x00000224 |
1281 | #define CX2_RX_BD_BASE (0x00000240) | 1304 | #define CX2_RX_BD_BASE 0x00000240 |
1282 | #define CX2_RX_BD_SIZE (0x00000244) | 1305 | #define CX2_RX_BD_SIZE 0x00000244 |
1283 | #define CX2_RFDS_TABLE_LOWER (0x00000500) | 1306 | #define CX2_RFDS_TABLE_LOWER 0x00000500 |
1284 | 1307 | ||
1285 | #define CX2_TX_CMD_QUEUE_READ_INDEX (0x00000280) | 1308 | #define CX2_TX_CMD_QUEUE_READ_INDEX 0x00000280 |
1286 | #define CX2_TX_QUEUE_0_READ_INDEX (0x00000284) | 1309 | #define CX2_TX_QUEUE_0_READ_INDEX 0x00000284 |
1287 | #define CX2_TX_QUEUE_1_READ_INDEX (0x00000288) | 1310 | #define CX2_TX_QUEUE_1_READ_INDEX 0x00000288 |
1288 | #define CX2_TX_QUEUE_2_READ_INDEX (0x0000028C) | 1311 | #define CX2_TX_QUEUE_2_READ_INDEX (0x0000028C) |
1289 | #define CX2_TX_QUEUE_3_READ_INDEX (0x00000290) | 1312 | #define CX2_TX_QUEUE_3_READ_INDEX 0x00000290 |
1290 | #define CX2_RX_READ_INDEX (0x000002A0) | 1313 | #define CX2_RX_READ_INDEX (0x000002A0) |
1291 | 1314 | ||
1292 | #define CX2_TX_CMD_QUEUE_WRITE_INDEX (0x00000F80) | 1315 | #define CX2_TX_CMD_QUEUE_WRITE_INDEX (0x00000F80) |
@@ -1333,15 +1356,15 @@ do { if (ipw_debug_level & (level)) \ | |||
1333 | #define EEPROM_HW_VERSION (GET_EEPROM_ADDR(0x72,LSB)) /* 2 bytes */ | 1356 | #define EEPROM_HW_VERSION (GET_EEPROM_ADDR(0x72,LSB)) /* 2 bytes */ |
1334 | 1357 | ||
1335 | /* NIC type as found in the one byte EEPROM_NIC_TYPE offset*/ | 1358 | /* NIC type as found in the one byte EEPROM_NIC_TYPE offset*/ |
1336 | #define EEPROM_NIC_TYPE_STANDARD 0 | 1359 | #define EEPROM_NIC_TYPE_0 0 |
1337 | #define EEPROM_NIC_TYPE_DELL 1 | 1360 | #define EEPROM_NIC_TYPE_1 1 |
1338 | #define EEPROM_NIC_TYPE_FUJITSU 2 | 1361 | #define EEPROM_NIC_TYPE_2 2 |
1339 | #define EEPROM_NIC_TYPE_IBM 3 | 1362 | #define EEPROM_NIC_TYPE_3 3 |
1340 | #define EEPROM_NIC_TYPE_HP 4 | 1363 | #define EEPROM_NIC_TYPE_4 4 |
1341 | 1364 | ||
1342 | #define FW_MEM_REG_LOWER_BOUND 0x00300000 | 1365 | #define FW_MEM_REG_LOWER_BOUND 0x00300000 |
1343 | #define FW_MEM_REG_EEPROM_ACCESS (FW_MEM_REG_LOWER_BOUND + 0x40) | 1366 | #define FW_MEM_REG_EEPROM_ACCESS (FW_MEM_REG_LOWER_BOUND + 0x40) |
1344 | 1367 | #define CX2_EVENT_REG (FW_MEM_REG_LOWER_BOUND + 0x04) | |
1345 | #define EEPROM_BIT_SK (1<<0) | 1368 | #define EEPROM_BIT_SK (1<<0) |
1346 | #define EEPROM_BIT_CS (1<<1) | 1369 | #define EEPROM_BIT_CS (1<<1) |
1347 | #define EEPROM_BIT_DI (1<<2) | 1370 | #define EEPROM_BIT_DI (1<<2) |