diff options
-rw-r--r-- | drivers/net/wireless/rndis_wlan.c | 67 |
1 files changed, 56 insertions, 11 deletions
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 0a423c49aab..8a77ff68590 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c | |||
@@ -156,6 +156,12 @@ MODULE_PARM_DESC(workaround_interval, | |||
156 | #define RNDIS_STATUS_ADAPTER_NOT_OPEN cpu_to_le32(0xc0010012) | 156 | #define RNDIS_STATUS_ADAPTER_NOT_OPEN cpu_to_le32(0xc0010012) |
157 | 157 | ||
158 | 158 | ||
159 | /* Known device types */ | ||
160 | #define RNDIS_UNKNOWN 0 | ||
161 | #define RNDIS_BCM4320A 1 | ||
162 | #define RNDIS_BCM4320B 2 | ||
163 | |||
164 | |||
159 | /* NDIS data structures. Taken from wpa_supplicant driver_ndis.c | 165 | /* NDIS data structures. Taken from wpa_supplicant driver_ndis.c |
160 | * slightly modified for datatype endianess, etc | 166 | * slightly modified for datatype endianess, etc |
161 | */ | 167 | */ |
@@ -478,6 +484,7 @@ struct rndis_wlan_private { | |||
478 | struct ieee80211_rate rates[ARRAY_SIZE(rndis_rates)]; | 484 | struct ieee80211_rate rates[ARRAY_SIZE(rndis_rates)]; |
479 | u32 cipher_suites[ARRAY_SIZE(rndis_cipher_suites)]; | 485 | u32 cipher_suites[ARRAY_SIZE(rndis_cipher_suites)]; |
480 | 486 | ||
487 | int device_type; | ||
481 | int caps; | 488 | int caps; |
482 | int multicast_size; | 489 | int multicast_size; |
483 | 490 | ||
@@ -997,6 +1004,16 @@ static void restore_keys(struct usbnet *usbdev); | |||
997 | static int rndis_check_bssid_list(struct usbnet *usbdev, u8 *match_bssid, | 1004 | static int rndis_check_bssid_list(struct usbnet *usbdev, u8 *match_bssid, |
998 | bool *matched); | 1005 | bool *matched); |
999 | 1006 | ||
1007 | static int rndis_start_bssid_list_scan(struct usbnet *usbdev) | ||
1008 | { | ||
1009 | __le32 tmp; | ||
1010 | |||
1011 | /* Note: OID_802_11_BSSID_LIST_SCAN clears internal BSS list. */ | ||
1012 | tmp = cpu_to_le32(1); | ||
1013 | return rndis_set_oid(usbdev, OID_802_11_BSSID_LIST_SCAN, &tmp, | ||
1014 | sizeof(tmp)); | ||
1015 | } | ||
1016 | |||
1000 | static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) | 1017 | static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) |
1001 | { | 1018 | { |
1002 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); | 1019 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); |
@@ -1905,7 +1922,7 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, | |||
1905 | struct usbnet *usbdev = netdev_priv(dev); | 1922 | struct usbnet *usbdev = netdev_priv(dev); |
1906 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); | 1923 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); |
1907 | int ret; | 1924 | int ret; |
1908 | __le32 tmp; | 1925 | int delay = SCAN_DELAY_JIFFIES; |
1909 | 1926 | ||
1910 | netdev_dbg(usbdev->net, "cfg80211.scan\n"); | 1927 | netdev_dbg(usbdev->net, "cfg80211.scan\n"); |
1911 | 1928 | ||
@@ -1922,13 +1939,13 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, | |||
1922 | 1939 | ||
1923 | priv->scan_request = request; | 1940 | priv->scan_request = request; |
1924 | 1941 | ||
1925 | tmp = cpu_to_le32(1); | 1942 | ret = rndis_start_bssid_list_scan(usbdev); |
1926 | ret = rndis_set_oid(usbdev, OID_802_11_BSSID_LIST_SCAN, &tmp, | ||
1927 | sizeof(tmp)); | ||
1928 | if (ret == 0) { | 1943 | if (ret == 0) { |
1944 | if (priv->device_type == RNDIS_BCM4320A) | ||
1945 | delay = HZ; | ||
1946 | |||
1929 | /* Wait before retrieving scan results from device */ | 1947 | /* Wait before retrieving scan results from device */ |
1930 | queue_delayed_work(priv->workqueue, &priv->scan_work, | 1948 | queue_delayed_work(priv->workqueue, &priv->scan_work, delay); |
1931 | SCAN_DELAY_JIFFIES); | ||
1932 | } | 1949 | } |
1933 | 1950 | ||
1934 | return ret; | 1951 | return ret; |
@@ -3046,8 +3063,21 @@ static void rndis_device_poller(struct work_struct *work) | |||
3046 | * also polls device with rndis_command() and catches for media link | 3063 | * also polls device with rndis_command() and catches for media link |
3047 | * indications. | 3064 | * indications. |
3048 | */ | 3065 | */ |
3049 | if (!is_associated(usbdev)) | 3066 | if (!is_associated(usbdev)) { |
3067 | /* Workaround bad scanning in BCM4320a devices with active | ||
3068 | * background scanning when not associated. | ||
3069 | */ | ||
3070 | if (priv->device_type == RNDIS_BCM4320A && priv->radio_on && | ||
3071 | !priv->scan_request) { | ||
3072 | /* Get previous scan results */ | ||
3073 | rndis_check_bssid_list(usbdev, NULL, NULL); | ||
3074 | |||
3075 | /* Initiate new scan */ | ||
3076 | rndis_start_bssid_list_scan(usbdev); | ||
3077 | } | ||
3078 | |||
3050 | goto end; | 3079 | goto end; |
3080 | } | ||
3051 | 3081 | ||
3052 | len = sizeof(rssi); | 3082 | len = sizeof(rssi); |
3053 | ret = rndis_query_oid(usbdev, OID_802_11_RSSI, &rssi, &len); | 3083 | ret = rndis_query_oid(usbdev, OID_802_11_RSSI, &rssi, &len); |
@@ -3104,10 +3134,12 @@ end: | |||
3104 | /* | 3134 | /* |
3105 | * driver/device initialization | 3135 | * driver/device initialization |
3106 | */ | 3136 | */ |
3107 | static void rndis_copy_module_params(struct usbnet *usbdev) | 3137 | static void rndis_copy_module_params(struct usbnet *usbdev, int device_type) |
3108 | { | 3138 | { |
3109 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); | 3139 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); |
3110 | 3140 | ||
3141 | priv->device_type = device_type; | ||
3142 | |||
3111 | priv->param_country[0] = modparam_country[0]; | 3143 | priv->param_country[0] = modparam_country[0]; |
3112 | priv->param_country[1] = modparam_country[1]; | 3144 | priv->param_country[1] = modparam_country[1]; |
3113 | priv->param_country[2] = 0; | 3145 | priv->param_country[2] = 0; |
@@ -3150,12 +3182,25 @@ static void rndis_copy_module_params(struct usbnet *usbdev) | |||
3150 | priv->param_workaround_interval = modparam_workaround_interval; | 3182 | priv->param_workaround_interval = modparam_workaround_interval; |
3151 | } | 3183 | } |
3152 | 3184 | ||
3185 | static int unknown_early_init(struct usbnet *usbdev) | ||
3186 | { | ||
3187 | /* copy module parameters for unknown so that iwconfig reports txpower | ||
3188 | * and workaround parameter is copied to private structure correctly. | ||
3189 | */ | ||
3190 | rndis_copy_module_params(usbdev, RNDIS_UNKNOWN); | ||
3191 | |||
3192 | /* This is unknown device, so do not try set configuration parameters. | ||
3193 | */ | ||
3194 | |||
3195 | return 0; | ||
3196 | } | ||
3197 | |||
3153 | static int bcm4320a_early_init(struct usbnet *usbdev) | 3198 | static int bcm4320a_early_init(struct usbnet *usbdev) |
3154 | { | 3199 | { |
3155 | /* copy module parameters for bcm4320a so that iwconfig reports txpower | 3200 | /* copy module parameters for bcm4320a so that iwconfig reports txpower |
3156 | * and workaround parameter is copied to private structure correctly. | 3201 | * and workaround parameter is copied to private structure correctly. |
3157 | */ | 3202 | */ |
3158 | rndis_copy_module_params(usbdev); | 3203 | rndis_copy_module_params(usbdev, RNDIS_BCM4320A); |
3159 | 3204 | ||
3160 | /* bcm4320a doesn't handle configuration parameters well. Try | 3205 | /* bcm4320a doesn't handle configuration parameters well. Try |
3161 | * set any and you get partially zeroed mac and broken device. | 3206 | * set any and you get partially zeroed mac and broken device. |
@@ -3169,7 +3214,7 @@ static int bcm4320b_early_init(struct usbnet *usbdev) | |||
3169 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); | 3214 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); |
3170 | char buf[8]; | 3215 | char buf[8]; |
3171 | 3216 | ||
3172 | rndis_copy_module_params(usbdev); | 3217 | rndis_copy_module_params(usbdev, RNDIS_BCM4320B); |
3173 | 3218 | ||
3174 | /* Early initialization settings, setting these won't have effect | 3219 | /* Early initialization settings, setting these won't have effect |
3175 | * if called after generic_rndis_bind(). | 3220 | * if called after generic_rndis_bind(). |
@@ -3432,7 +3477,7 @@ static const struct driver_info rndis_wlan_info = { | |||
3432 | .tx_fixup = rndis_tx_fixup, | 3477 | .tx_fixup = rndis_tx_fixup, |
3433 | .reset = rndis_wlan_reset, | 3478 | .reset = rndis_wlan_reset, |
3434 | .stop = rndis_wlan_stop, | 3479 | .stop = rndis_wlan_stop, |
3435 | .early_init = bcm4320a_early_init, | 3480 | .early_init = unknown_early_init, |
3436 | .indication = rndis_wlan_indication, | 3481 | .indication = rndis_wlan_indication, |
3437 | }; | 3482 | }; |
3438 | 3483 | ||