diff options
Diffstat (limited to 'drivers/net/wireless/rndis_wlan.c')
-rw-r--r-- | drivers/net/wireless/rndis_wlan.c | 206 |
1 files changed, 183 insertions, 23 deletions
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 71b5971da597..19f3d568f700 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 | ||
@@ -810,7 +817,8 @@ exit_unlock: | |||
810 | return ret; | 817 | return ret; |
811 | } | 818 | } |
812 | 819 | ||
813 | static int rndis_set_oid(struct usbnet *dev, __le32 oid, void *data, int len) | 820 | static int rndis_set_oid(struct usbnet *dev, __le32 oid, const void *data, |
821 | int len) | ||
814 | { | 822 | { |
815 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev); | 823 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(dev); |
816 | union { | 824 | union { |
@@ -994,7 +1002,18 @@ static int level_to_qual(int level) | |||
994 | */ | 1002 | */ |
995 | static int set_infra_mode(struct usbnet *usbdev, int mode); | 1003 | static int set_infra_mode(struct usbnet *usbdev, int mode); |
996 | static void restore_keys(struct usbnet *usbdev); | 1004 | static void restore_keys(struct usbnet *usbdev); |
997 | static int rndis_check_bssid_list(struct usbnet *usbdev); | 1005 | static int rndis_check_bssid_list(struct usbnet *usbdev, u8 *match_bssid, |
1006 | bool *matched); | ||
1007 | |||
1008 | static int rndis_start_bssid_list_scan(struct usbnet *usbdev) | ||
1009 | { | ||
1010 | __le32 tmp; | ||
1011 | |||
1012 | /* Note: OID_802_11_BSSID_LIST_SCAN clears internal BSS list. */ | ||
1013 | tmp = cpu_to_le32(1); | ||
1014 | return rndis_set_oid(usbdev, OID_802_11_BSSID_LIST_SCAN, &tmp, | ||
1015 | sizeof(tmp)); | ||
1016 | } | ||
998 | 1017 | ||
999 | static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) | 1018 | static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) |
1000 | { | 1019 | { |
@@ -1015,7 +1034,7 @@ static int set_essid(struct usbnet *usbdev, struct ndis_80211_ssid *ssid) | |||
1015 | return ret; | 1034 | return ret; |
1016 | } | 1035 | } |
1017 | 1036 | ||
1018 | static int set_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN]) | 1037 | static int set_bssid(struct usbnet *usbdev, const u8 *bssid) |
1019 | { | 1038 | { |
1020 | int ret; | 1039 | int ret; |
1021 | 1040 | ||
@@ -1031,7 +1050,9 @@ static int set_bssid(struct usbnet *usbdev, u8 bssid[ETH_ALEN]) | |||
1031 | 1050 | ||
1032 | static int clear_bssid(struct usbnet *usbdev) | 1051 | static int clear_bssid(struct usbnet *usbdev) |
1033 | { | 1052 | { |
1034 | u8 broadcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | 1053 | static const u8 broadcast_mac[ETH_ALEN] = { |
1054 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff | ||
1055 | }; | ||
1035 | 1056 | ||
1036 | return set_bssid(usbdev, broadcast_mac); | 1057 | return set_bssid(usbdev, broadcast_mac); |
1037 | } | 1058 | } |
@@ -1904,14 +1925,14 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, | |||
1904 | struct usbnet *usbdev = netdev_priv(dev); | 1925 | struct usbnet *usbdev = netdev_priv(dev); |
1905 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); | 1926 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); |
1906 | int ret; | 1927 | int ret; |
1907 | __le32 tmp; | 1928 | int delay = SCAN_DELAY_JIFFIES; |
1908 | 1929 | ||
1909 | netdev_dbg(usbdev->net, "cfg80211.scan\n"); | 1930 | netdev_dbg(usbdev->net, "cfg80211.scan\n"); |
1910 | 1931 | ||
1911 | /* Get current bssid list from device before new scan, as new scan | 1932 | /* Get current bssid list from device before new scan, as new scan |
1912 | * clears internal bssid list. | 1933 | * clears internal bssid list. |
1913 | */ | 1934 | */ |
1914 | rndis_check_bssid_list(usbdev); | 1935 | rndis_check_bssid_list(usbdev, NULL, NULL); |
1915 | 1936 | ||
1916 | if (!request) | 1937 | if (!request) |
1917 | return -EINVAL; | 1938 | return -EINVAL; |
@@ -1921,13 +1942,13 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, | |||
1921 | 1942 | ||
1922 | priv->scan_request = request; | 1943 | priv->scan_request = request; |
1923 | 1944 | ||
1924 | tmp = cpu_to_le32(1); | 1945 | ret = rndis_start_bssid_list_scan(usbdev); |
1925 | ret = rndis_set_oid(usbdev, OID_802_11_BSSID_LIST_SCAN, &tmp, | ||
1926 | sizeof(tmp)); | ||
1927 | if (ret == 0) { | 1946 | if (ret == 0) { |
1947 | if (priv->device_type == RNDIS_BCM4320A) | ||
1948 | delay = HZ; | ||
1949 | |||
1928 | /* Wait before retrieving scan results from device */ | 1950 | /* Wait before retrieving scan results from device */ |
1929 | queue_delayed_work(priv->workqueue, &priv->scan_work, | 1951 | queue_delayed_work(priv->workqueue, &priv->scan_work, delay); |
1930 | SCAN_DELAY_JIFFIES); | ||
1931 | } | 1952 | } |
1932 | 1953 | ||
1933 | return ret; | 1954 | return ret; |
@@ -1981,7 +2002,8 @@ static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev, | |||
1981 | GFP_KERNEL); | 2002 | GFP_KERNEL); |
1982 | } | 2003 | } |
1983 | 2004 | ||
1984 | static int rndis_check_bssid_list(struct usbnet *usbdev) | 2005 | static int rndis_check_bssid_list(struct usbnet *usbdev, u8 *match_bssid, |
2006 | bool *matched) | ||
1985 | { | 2007 | { |
1986 | void *buf = NULL; | 2008 | void *buf = NULL; |
1987 | struct ndis_80211_bssid_list_ex *bssid_list; | 2009 | struct ndis_80211_bssid_list_ex *bssid_list; |
@@ -2017,7 +2039,11 @@ resize_buf: | |||
2017 | count, len); | 2039 | count, len); |
2018 | 2040 | ||
2019 | while (count && ((void *)bssid + bssid_len) <= (buf + len)) { | 2041 | while (count && ((void *)bssid + bssid_len) <= (buf + len)) { |
2020 | rndis_bss_info_update(usbdev, bssid); | 2042 | if (rndis_bss_info_update(usbdev, bssid) && match_bssid && |
2043 | matched) { | ||
2044 | if (compare_ether_addr(bssid->mac, match_bssid)) | ||
2045 | *matched = true; | ||
2046 | } | ||
2021 | 2047 | ||
2022 | bssid = (void *)bssid + bssid_len; | 2048 | bssid = (void *)bssid + bssid_len; |
2023 | bssid_len = le32_to_cpu(bssid->length); | 2049 | bssid_len = le32_to_cpu(bssid->length); |
@@ -2041,7 +2067,7 @@ static void rndis_get_scan_results(struct work_struct *work) | |||
2041 | if (!priv->scan_request) | 2067 | if (!priv->scan_request) |
2042 | return; | 2068 | return; |
2043 | 2069 | ||
2044 | ret = rndis_check_bssid_list(usbdev); | 2070 | ret = rndis_check_bssid_list(usbdev, NULL, NULL); |
2045 | 2071 | ||
2046 | cfg80211_scan_done(priv->scan_request, ret < 0); | 2072 | cfg80211_scan_done(priv->scan_request, ret < 0); |
2047 | 2073 | ||
@@ -2495,6 +2521,91 @@ static int rndis_flush_pmksa(struct wiphy *wiphy, struct net_device *netdev) | |||
2495 | return rndis_set_oid(usbdev, OID_802_11_PMKID, &pmkid, sizeof(pmkid)); | 2521 | return rndis_set_oid(usbdev, OID_802_11_PMKID, &pmkid, sizeof(pmkid)); |
2496 | } | 2522 | } |
2497 | 2523 | ||
2524 | static void rndis_wlan_craft_connected_bss(struct usbnet *usbdev, u8 *bssid, | ||
2525 | struct ndis_80211_assoc_info *info) | ||
2526 | { | ||
2527 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); | ||
2528 | struct ieee80211_channel *channel; | ||
2529 | struct ndis_80211_conf config; | ||
2530 | struct ndis_80211_ssid ssid; | ||
2531 | s32 signal; | ||
2532 | u64 timestamp; | ||
2533 | u16 capability; | ||
2534 | u16 beacon_interval; | ||
2535 | __le32 rssi; | ||
2536 | u8 ie_buf[34]; | ||
2537 | int len, ret, ie_len; | ||
2538 | |||
2539 | /* Get signal quality, in case of error use rssi=0 and ignore error. */ | ||
2540 | len = sizeof(rssi); | ||
2541 | rssi = 0; | ||
2542 | ret = rndis_query_oid(usbdev, OID_802_11_RSSI, &rssi, &len); | ||
2543 | signal = level_to_qual(le32_to_cpu(rssi)); | ||
2544 | |||
2545 | netdev_dbg(usbdev->net, "%s(): OID_802_11_RSSI -> %d, " | ||
2546 | "rssi:%d, qual: %d\n", __func__, ret, le32_to_cpu(rssi), | ||
2547 | level_to_qual(le32_to_cpu(rssi))); | ||
2548 | |||
2549 | /* Get AP capabilities */ | ||
2550 | if (info) { | ||
2551 | capability = le16_to_cpu(info->resp_ie.capa); | ||
2552 | } else { | ||
2553 | /* Set atleast ESS/IBSS capability */ | ||
2554 | capability = (priv->infra_mode == NDIS_80211_INFRA_INFRA) ? | ||
2555 | WLAN_CAPABILITY_ESS : WLAN_CAPABILITY_IBSS; | ||
2556 | } | ||
2557 | |||
2558 | /* Get channel and beacon interval */ | ||
2559 | len = sizeof(config); | ||
2560 | ret = rndis_query_oid(usbdev, OID_802_11_CONFIGURATION, &config, &len); | ||
2561 | netdev_dbg(usbdev->net, "%s(): OID_802_11_CONFIGURATION -> %d\n", | ||
2562 | __func__, ret); | ||
2563 | if (ret >= 0) { | ||
2564 | beacon_interval = le16_to_cpu(config.beacon_period); | ||
2565 | channel = ieee80211_get_channel(priv->wdev.wiphy, | ||
2566 | KHZ_TO_MHZ(le32_to_cpu(config.ds_config))); | ||
2567 | if (!channel) { | ||
2568 | netdev_warn(usbdev->net, "%s(): could not get channel." | ||
2569 | "\n", __func__); | ||
2570 | return; | ||
2571 | } | ||
2572 | } else { | ||
2573 | netdev_warn(usbdev->net, "%s(): could not get configuration.\n", | ||
2574 | __func__); | ||
2575 | return; | ||
2576 | } | ||
2577 | |||
2578 | /* Get SSID, in case of error, use zero length SSID and ignore error. */ | ||
2579 | len = sizeof(ssid); | ||
2580 | memset(&ssid, 0, sizeof(ssid)); | ||
2581 | ret = rndis_query_oid(usbdev, OID_802_11_SSID, &ssid, &len); | ||
2582 | netdev_dbg(usbdev->net, "%s(): OID_802_11_SSID -> %d, len: %d, ssid: " | ||
2583 | "'%.32s'\n", __func__, ret, | ||
2584 | le32_to_cpu(ssid.length), ssid.essid); | ||
2585 | |||
2586 | if (le32_to_cpu(ssid.length) > 32) | ||
2587 | ssid.length = cpu_to_le32(32); | ||
2588 | |||
2589 | ie_buf[0] = WLAN_EID_SSID; | ||
2590 | ie_buf[1] = le32_to_cpu(ssid.length); | ||
2591 | memcpy(&ie_buf[2], ssid.essid, le32_to_cpu(ssid.length)); | ||
2592 | |||
2593 | ie_len = le32_to_cpu(ssid.length) + 2; | ||
2594 | |||
2595 | /* no tsf */ | ||
2596 | timestamp = 0; | ||
2597 | |||
2598 | netdev_dbg(usbdev->net, "%s(): channel:%d(freq), bssid:[%pM], tsf:%d, " | ||
2599 | "capa:%x, beacon int:%d, resp_ie(len:%d, essid:'%.32s'), " | ||
2600 | "signal:%d\n", __func__, (channel ? channel->center_freq : -1), | ||
2601 | bssid, (u32)timestamp, capability, beacon_interval, ie_len, | ||
2602 | ssid.essid, signal); | ||
2603 | |||
2604 | cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid, | ||
2605 | timestamp, capability, beacon_interval, ie_buf, ie_len, | ||
2606 | signal, GFP_KERNEL); | ||
2607 | } | ||
2608 | |||
2498 | /* | 2609 | /* |
2499 | * workers, indication handlers, device poller | 2610 | * workers, indication handlers, device poller |
2500 | */ | 2611 | */ |
@@ -2507,6 +2618,7 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) | |||
2507 | u8 *req_ie, *resp_ie; | 2618 | u8 *req_ie, *resp_ie; |
2508 | int ret, offset; | 2619 | int ret, offset; |
2509 | bool roamed = false; | 2620 | bool roamed = false; |
2621 | bool match_bss; | ||
2510 | 2622 | ||
2511 | if (priv->infra_mode == NDIS_80211_INFRA_INFRA && priv->connected) { | 2623 | if (priv->infra_mode == NDIS_80211_INFRA_INFRA && priv->connected) { |
2512 | /* received media connect indication while connected, either | 2624 | /* received media connect indication while connected, either |
@@ -2558,6 +2670,13 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) | |||
2558 | resp_ie_len = | 2670 | resp_ie_len = |
2559 | CONTROL_BUFFER_SIZE - offset; | 2671 | CONTROL_BUFFER_SIZE - offset; |
2560 | } | 2672 | } |
2673 | } else { | ||
2674 | /* Since rndis_wlan_craft_connected_bss() might use info | ||
2675 | * later and expects info to contain valid data if | ||
2676 | * non-null, free info and set NULL here. | ||
2677 | */ | ||
2678 | kfree(info); | ||
2679 | info = NULL; | ||
2561 | } | 2680 | } |
2562 | } else if (WARN_ON(priv->infra_mode != NDIS_80211_INFRA_ADHOC)) | 2681 | } else if (WARN_ON(priv->infra_mode != NDIS_80211_INFRA_ADHOC)) |
2563 | return; | 2682 | return; |
@@ -2569,13 +2688,26 @@ static void rndis_wlan_do_link_up_work(struct usbnet *usbdev) | |||
2569 | netdev_dbg(usbdev->net, "link up work: [%pM]%s\n", | 2688 | netdev_dbg(usbdev->net, "link up work: [%pM]%s\n", |
2570 | bssid, roamed ? " roamed" : ""); | 2689 | bssid, roamed ? " roamed" : ""); |
2571 | 2690 | ||
2572 | /* Internal bss list in device always contains at least the currently | 2691 | /* Internal bss list in device should contain at least the currently |
2573 | * connected bss and we can get it to cfg80211 with | 2692 | * connected bss and we can get it to cfg80211 with |
2574 | * rndis_check_bssid_list(). | 2693 | * rndis_check_bssid_list(). |
2575 | * NOTE: This is true for Broadcom chip, but not mentioned in RNDIS | 2694 | * |
2576 | * spec. | 2695 | * NDIS spec says: "If the device is associated, but the associated |
2696 | * BSSID is not in its BSSID scan list, then the driver must add an | ||
2697 | * entry for the BSSID at the end of the data that it returns in | ||
2698 | * response to query of OID_802_11_BSSID_LIST." | ||
2699 | * | ||
2700 | * NOTE: Seems to be true for BCM4320b variant, but not BCM4320a. | ||
2577 | */ | 2701 | */ |
2578 | rndis_check_bssid_list(usbdev); | 2702 | match_bss = false; |
2703 | rndis_check_bssid_list(usbdev, bssid, &match_bss); | ||
2704 | |||
2705 | if (!is_zero_ether_addr(bssid) && !match_bss) { | ||
2706 | /* Couldn't get bss from device, we need to manually craft bss | ||
2707 | * for cfg80211. | ||
2708 | */ | ||
2709 | rndis_wlan_craft_connected_bss(usbdev, bssid, info); | ||
2710 | } | ||
2579 | 2711 | ||
2580 | if (priv->infra_mode == NDIS_80211_INFRA_INFRA) { | 2712 | if (priv->infra_mode == NDIS_80211_INFRA_INFRA) { |
2581 | if (!roamed) | 2713 | if (!roamed) |
@@ -2934,8 +3066,21 @@ static void rndis_device_poller(struct work_struct *work) | |||
2934 | * also polls device with rndis_command() and catches for media link | 3066 | * also polls device with rndis_command() and catches for media link |
2935 | * indications. | 3067 | * indications. |
2936 | */ | 3068 | */ |
2937 | if (!is_associated(usbdev)) | 3069 | if (!is_associated(usbdev)) { |
3070 | /* Workaround bad scanning in BCM4320a devices with active | ||
3071 | * background scanning when not associated. | ||
3072 | */ | ||
3073 | if (priv->device_type == RNDIS_BCM4320A && priv->radio_on && | ||
3074 | !priv->scan_request) { | ||
3075 | /* Get previous scan results */ | ||
3076 | rndis_check_bssid_list(usbdev, NULL, NULL); | ||
3077 | |||
3078 | /* Initiate new scan */ | ||
3079 | rndis_start_bssid_list_scan(usbdev); | ||
3080 | } | ||
3081 | |||
2938 | goto end; | 3082 | goto end; |
3083 | } | ||
2939 | 3084 | ||
2940 | len = sizeof(rssi); | 3085 | len = sizeof(rssi); |
2941 | ret = rndis_query_oid(usbdev, OID_802_11_RSSI, &rssi, &len); | 3086 | ret = rndis_query_oid(usbdev, OID_802_11_RSSI, &rssi, &len); |
@@ -2992,10 +3137,12 @@ end: | |||
2992 | /* | 3137 | /* |
2993 | * driver/device initialization | 3138 | * driver/device initialization |
2994 | */ | 3139 | */ |
2995 | static void rndis_copy_module_params(struct usbnet *usbdev) | 3140 | static void rndis_copy_module_params(struct usbnet *usbdev, int device_type) |
2996 | { | 3141 | { |
2997 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); | 3142 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); |
2998 | 3143 | ||
3144 | priv->device_type = device_type; | ||
3145 | |||
2999 | priv->param_country[0] = modparam_country[0]; | 3146 | priv->param_country[0] = modparam_country[0]; |
3000 | priv->param_country[1] = modparam_country[1]; | 3147 | priv->param_country[1] = modparam_country[1]; |
3001 | priv->param_country[2] = 0; | 3148 | priv->param_country[2] = 0; |
@@ -3038,12 +3185,25 @@ static void rndis_copy_module_params(struct usbnet *usbdev) | |||
3038 | priv->param_workaround_interval = modparam_workaround_interval; | 3185 | priv->param_workaround_interval = modparam_workaround_interval; |
3039 | } | 3186 | } |
3040 | 3187 | ||
3188 | static int unknown_early_init(struct usbnet *usbdev) | ||
3189 | { | ||
3190 | /* copy module parameters for unknown so that iwconfig reports txpower | ||
3191 | * and workaround parameter is copied to private structure correctly. | ||
3192 | */ | ||
3193 | rndis_copy_module_params(usbdev, RNDIS_UNKNOWN); | ||
3194 | |||
3195 | /* This is unknown device, so do not try set configuration parameters. | ||
3196 | */ | ||
3197 | |||
3198 | return 0; | ||
3199 | } | ||
3200 | |||
3041 | static int bcm4320a_early_init(struct usbnet *usbdev) | 3201 | static int bcm4320a_early_init(struct usbnet *usbdev) |
3042 | { | 3202 | { |
3043 | /* copy module parameters for bcm4320a so that iwconfig reports txpower | 3203 | /* copy module parameters for bcm4320a so that iwconfig reports txpower |
3044 | * and workaround parameter is copied to private structure correctly. | 3204 | * and workaround parameter is copied to private structure correctly. |
3045 | */ | 3205 | */ |
3046 | rndis_copy_module_params(usbdev); | 3206 | rndis_copy_module_params(usbdev, RNDIS_BCM4320A); |
3047 | 3207 | ||
3048 | /* bcm4320a doesn't handle configuration parameters well. Try | 3208 | /* bcm4320a doesn't handle configuration parameters well. Try |
3049 | * set any and you get partially zeroed mac and broken device. | 3209 | * set any and you get partially zeroed mac and broken device. |
@@ -3057,7 +3217,7 @@ static int bcm4320b_early_init(struct usbnet *usbdev) | |||
3057 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); | 3217 | struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); |
3058 | char buf[8]; | 3218 | char buf[8]; |
3059 | 3219 | ||
3060 | rndis_copy_module_params(usbdev); | 3220 | rndis_copy_module_params(usbdev, RNDIS_BCM4320B); |
3061 | 3221 | ||
3062 | /* Early initialization settings, setting these won't have effect | 3222 | /* Early initialization settings, setting these won't have effect |
3063 | * if called after generic_rndis_bind(). | 3223 | * if called after generic_rndis_bind(). |
@@ -3320,7 +3480,7 @@ static const struct driver_info rndis_wlan_info = { | |||
3320 | .tx_fixup = rndis_tx_fixup, | 3480 | .tx_fixup = rndis_tx_fixup, |
3321 | .reset = rndis_wlan_reset, | 3481 | .reset = rndis_wlan_reset, |
3322 | .stop = rndis_wlan_stop, | 3482 | .stop = rndis_wlan_stop, |
3323 | .early_init = bcm4320a_early_init, | 3483 | .early_init = unknown_early_init, |
3324 | .indication = rndis_wlan_indication, | 3484 | .indication = rndis_wlan_indication, |
3325 | }; | 3485 | }; |
3326 | 3486 | ||