Signed-off-by: Daniel Golle <[email protected]> create mode 100644 package/mac80211/patches/580-cfg80211-antenna-configuration-profiles.patch create mode 100644 package/mac80211/patches/581-mac80211-antenna-configuration-ops.patch create mode 100644 package/mac80211/patches/582-ath9k-antenna-switch-profile-support-for-ar9285.patch
diff --git a/package/mac80211/patches/580-cfg80211-antenna-configuration-profiles.patch b/package/mac80211/patches/580-cfg80211-antenna-configuration-profiles.patch new file mode 100644 index 0000000..e3429c5 --- /dev/null +++ b/package/mac80211/patches/580-cfg80211-antenna-configuration-profiles.patch @@ -0,0 +1,247 @@ +From bb2d00ec0ccd141170c61fb66639ab9234a69915 Mon Sep 17 00:00:00 2001 +From: Daniel Golle <[email protected]> +Date: Tue, 13 Dec 2011 17:31:52 +0200 +Subject: [PATCH 1/3] cfg80211: add support for antenna configuration profiles + +This patch adds support for antenna configuration profiles to +cfg80211/nl80211. It provides an infrastructure to allow the user +to select from pre-defined configartion profiles such as +vertical/horizontal polarization or built-in/external antenna. + +Cc: Adrian Chadd <[email protected]> +Cc: Johannes Berg <[email protected]> +Signed-off-by: Daniel Golle <[email protected]> +--- + include/linux/nl80211.h | 47 ++++++++++++++++++++++++++++++++++++++++ + include/net/cfg80211.h | 27 +++++++++++++++++++++++ + net/wireless/nl80211.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 131 insertions(+) + +--- a/include/linux/nl80211.h ++++ b/include/linux/nl80211.h +@@ -1245,6 +1245,12 @@ enum nl80211_commands { + * @NL80211_ATTR_BG_SCAN_PERIOD: Background scan period in seconds + * or 0 to disable background scan. + * ++ * @NL80211_ATTR_WIPHY_EXTANT: External antenna switch profiles. This nested ++ * structure contains a list of available profiles as well as the current ++ * profile selection status. ++ * ++ * @NL80211_ATTR_WIPHY_EXTANT_SELECT: Select extant profile. ++ * + * @NL80211_ATTR_MAX: highest attribute number currently defined + * @__NL80211_ATTR_AFTER_LAST: internal use + */ +@@ -1498,6 +1504,9 @@ enum nl80211_attrs { + + NL80211_ATTR_WDEV, + ++ NL80211_ATTR_WIPHY_EXTANT, ++ NL80211_ATTR_WIPHY_EXTANT_SELECT, ++ + /* add attributes here, update the policy in nl80211.c */ + + __NL80211_ATTR_AFTER_LAST, +@@ -1819,6 +1828,44 @@ enum nl80211_mpath_info { + NL80211_MPATH_INFO_MAX = __NL80211_MPATH_INFO_AFTER_LAST - 1 + }; + ++ ++ ++/** ++ * enum nl80211_extant_attr - external antenna switch ++ * @__NL80211_EXTANT_ATTR_INVALID: attribute number 0 is reserved ++ * @NL80211_EXTANT_ATTR_STATE: currently selected profile ++ * @NL80211_EXTANT_ATTR_PROFILES: highest profile attribute currently defined ++ * @NL80211_EXTANT_ATTR_MAX: highest profile attribute currently defined ++ * @__NL80211_EXTANT_ATTR_AFTER_LAST: internal use ++ */ ++enum nl80211_extant_attr { ++ __NL80211_EXTANT_ATTR_INVALID, ++ NL80211_EXTANT_ATTR_STATE, ++ NL80211_EXTANT_ATTR_PROFILES, ++ /* keep last */ ++ __NL80211_EXTANT_ATTR_AFTER_LAST, ++ NL80211_EXTANT_ATTR_MAX = __NL80211_EXTANT_ATTR_AFTER_LAST - 1 ++}; ++ ++/** ++ * enum nl80211_easp_attr - external antenna switch configuration profile ++ * @__NL80211_EASP_ATTR_INVALID: attribute number 0 is reserved ++ * @NL80211_EASP_ATTR_ID: unique identifier ++ * @NL80211_EASP_ATTR_NAME: human-readable name of the configuration profile ++ * @NL80211_EASP_ATTR_DESC: human-readable description of the configuration profile ++ * @NL80211_EASP_ATTR_MAX: highest profile attribute currently defined ++ * @__NL80211_EASP_ATTR_AFTER_LAST: internal use ++ */ ++enum nl80211_easp_attr { ++ __NL80211_EASP_ATTR_INVALID, ++ NL80211_EASP_ATTR_ID, ++ NL80211_EASP_ATTR_NAME, ++ NL80211_EASP_ATTR_DESC, ++ /* keep last */ ++ __NL80211_EASP_ATTR_AFTER_LAST, ++ NL80211_EASP_ATTR_MAX = __NL80211_EASP_ATTR_AFTER_LAST - 1 ++}; ++ + /** + * enum nl80211_band_attr - band attributes + * @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved +--- a/include/net/cfg80211.h ++++ b/include/net/cfg80211.h +@@ -1601,6 +1601,9 @@ struct cfg80211_gtk_rekey_data { + * + * @get_antenna: Get current antenna configuration from device (tx_ant, rx_ant). + * ++ * @set_extant: Select the external antenna switch configuration profile. ++ * @get_extant: Get currently selected antenna switch profile. ++ * + * @set_ringparam: Set tx and rx ring sizes. + * + * @get_ringparam: Get tx and rx ring current and maximum sizes. +@@ -1802,6 +1805,9 @@ struct cfg80211_ops { + int (*set_antenna)(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant); + int (*get_antenna)(struct wiphy *wiphy, u32 *tx_ant, u32 *rx_ant); + ++ int (*set_extant)(struct wiphy *wiphy, u32 extant); ++ int (*get_extant)(struct wiphy *wiphy, u32 *extant); ++ + int (*set_ringparam)(struct wiphy *wiphy, u32 tx, u32 rx); + void (*get_ringparam)(struct wiphy *wiphy, + u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max); +@@ -1925,6 +1931,7 @@ enum wiphy_flags { + WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD = BIT(19), + WIPHY_FLAG_OFFCHAN_TX = BIT(20), + WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL = BIT(21), ++ WIPHY_FLAG_HAS_EXTANT_SWITCH = BIT(22), + }; + + /** +@@ -2052,6 +2059,21 @@ struct wiphy_wowlan_support { + }; + + /** ++ * struct wiphy_extant_profile - User-parsable external antenna switch info ++ * ++ * This structure is used to provide the available switch configurations. ++ * @id: unique identifier of the profile ++ * @name: profile name (a short string) ++ * @description: user-parsable description of the profile ++ */ ++struct wiphy_extant_profile { ++ int id; ++ char *name; ++ char *desc; ++}; ++ ++ ++/** + * struct wiphy - wireless hardware description + * @reg_notifier: the driver's regulatory notification callback, + * note that if your driver uses wiphy_apply_custom_regulatory() +@@ -2137,6 +2159,8 @@ struct wiphy_wowlan_support { + * See &enum nl80211_probe_resp_offload_support_attr. Only valid + * when the wiphy flag @WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD is set. + * ++ * @extant: struct holding the available antenna switch configuration profiles. ++ * + * @max_remain_on_channel_duration: Maximum time a remain-on-channel operation + * may request, if implemented. + * +@@ -2212,6 +2236,9 @@ struct wiphy { + */ + u32 probe_resp_offload; + ++ u8 num_extant_profiles; ++ struct wiphy_extant_profile *extant; ++ + /* If multiple wiphys are registered and you're handed e.g. + * a regular netdev with assigned ieee80211_ptr, you won't + * know whether it points to a wiphy your driver has registered +--- a/net/wireless/nl80211.c ++++ b/net/wireless/nl80211.c +@@ -354,6 +354,8 @@ static const struct nla_policy nl80211_p + [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 }, + [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 }, + [NL80211_ATTR_WDEV] = { .type = NLA_U64 }, ++ [NL80211_ATTR_WIPHY_EXTANT] = { .type = NLA_NESTED }, ++ [NL80211_ATTR_WIPHY_EXTANT_SELECT] = { .type = NLA_U32 }, + }; + + /* policy for the key attributes */ +@@ -857,6 +859,8 @@ static int nl80211_send_wiphy(struct sk_ + struct nlattr *nl_bands, *nl_band; + struct nlattr *nl_freqs, *nl_freq; + struct nlattr *nl_rates, *nl_rate; ++ struct nlattr *nl_easps, *nl_easp; ++ struct nlattr *nl_extant; + struct nlattr *nl_cmds; + enum ieee80211_band band; + struct ieee80211_channel *chan; +@@ -952,6 +956,45 @@ static int nl80211_send_wiphy(struct sk_ + } + } + ++ /* ++ * antenna switch configuration profile support ++ */ ++ if (dev->wiphy.flags & WIPHY_FLAG_HAS_EXTANT_SWITCH) { ++ nl_extant = nla_nest_start(msg, NL80211_ATTR_WIPHY_EXTANT); ++ if (!nl_extant) ++ goto nla_put_failure; ++ ++ /* currently selected configuration profile */ ++ if (dev->ops->get_extant) { ++ u32 extant; ++ int res; ++ res = dev->ops->get_extant(&dev->wiphy, &extant); ++ if (!res) ++ NLA_PUT_U32(msg, ++ NL80211_EXTANT_ATTR_STATE, ++ extant); ++ } ++ ++ /* available profiles */ ++ nl_easps = nla_nest_start(msg, NL80211_EXTANT_ATTR_PROFILES); ++ for (i=0; i < dev->wiphy.num_extant_profiles; i++) { ++ nl_easp = nla_nest_start(msg, i); ++ if (!nl_easp) ++ goto nla_put_failure; ++ NLA_PUT_U32(msg, NL80211_EASP_ATTR_ID, ++ dev->wiphy.extant[i].id); ++ NLA_PUT(msg, NL80211_EASP_ATTR_NAME, ++ strlen(dev->wiphy.extant[i].name), ++ dev->wiphy.extant[i].name); ++ NLA_PUT(msg, NL80211_EASP_ATTR_DESC, ++ strlen(dev->wiphy.extant[i].desc), ++ dev->wiphy.extant[i].desc); ++ nla_nest_end(msg, nl_easp); ++ } ++ nla_nest_end(msg, nl_easps); ++ nla_nest_end(msg, nl_extant); ++ } ++ + if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES, + dev->wiphy.interface_modes)) + goto nla_put_failure; +@@ -1630,6 +1673,20 @@ static int nl80211_set_wiphy(struct sk_b + if (result) + goto bad_res; + } ++ ++ if (info->attrs[NL80211_ATTR_WIPHY_EXTANT_SELECT]) { ++ u32 extant; ++ if (!rdev->ops->set_extant) { ++ result = -EOPNOTSUPP; ++ goto bad_res; ++ } ++ ++ extant = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_EXTANT_SELECT]); ++ ++ result = rdev->ops->set_extant(&rdev->wiphy, extant); ++ if (result) ++ goto bad_res; ++ } + + changed = 0; + diff --git a/package/mac80211/patches/581-mac80211-antenna-configuration-ops.patch b/package/mac80211/patches/581-mac80211-antenna-configuration-ops.patch new file mode 100644 index 0000000..df8ccfb --- /dev/null +++ b/package/mac80211/patches/581-mac80211-antenna-configuration-ops.patch @@ -0,0 +1,92 @@ +From cd01191c9d7386ffb99b9087d4665f740d1be725 Mon Sep 17 00:00:00 2001 +From: Daniel Golle <[email protected]> +Date: Tue, 13 Dec 2011 17:37:33 +0200 +Subject: [PATCH 2/3] mac80211: add operations for antenna configuration + profiles + +This adds get_extant and set_extant operations to mac80211 thus +allowing mac80211 drivers to expose those operations to the user. + +Cc: Adrian Chadd <[email protected]> +Cc: Johannes Berg <[email protected]> +Signed-off-by: Daniel Golle <[email protected]> +--- + include/net/mac80211.h | 3 +++ + net/mac80211/cfg.c | 19 +++++++++++++++++++ + net/mac80211/driver-ops.h | 20 ++++++++++++++++++++ + 4 files changed, 88 insertions(+) + +--- a/include/net/mac80211.h ++++ b/include/net/mac80211.h +@@ -2376,6 +2376,9 @@ struct ieee80211_ops { + int (*set_antenna)(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant); + int (*get_antenna)(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant); + ++ int (*set_extant)(struct ieee80211_hw *hw, u32 extant); ++ int (*get_extant)(struct ieee80211_hw *hw, u32 *extant); ++ + int (*remain_on_channel)(struct ieee80211_hw *hw, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type, +--- a/net/mac80211/cfg.c ++++ b/net/mac80211/cfg.c +@@ -2593,6 +2593,23 @@ static int ieee80211_get_antenna(struct + return drv_get_antenna(local, tx_ant, rx_ant); + } + ++static int ieee80211_set_extant(struct wiphy *wiphy, u32 extant) ++{ ++ struct ieee80211_local *local = wiphy_priv(wiphy); ++ ++ if (local->started) ++ return -EOPNOTSUPP; ++ ++ return drv_set_extant(local, extant); ++} ++ ++static int ieee80211_get_extant(struct wiphy *wiphy, u32 *extant) ++{ ++ struct ieee80211_local *local = wiphy_priv(wiphy); ++ ++ return drv_get_extant(local, extant); ++} ++ + static int ieee80211_set_ringparam(struct wiphy *wiphy, u32 tx, u32 rx) + { + struct ieee80211_local *local = wiphy_priv(wiphy); +@@ -3082,6 +3099,8 @@ struct cfg80211_ops mac80211_config_ops + .mgmt_frame_register = ieee80211_mgmt_frame_register, + .set_antenna = ieee80211_set_antenna, + .get_antenna = ieee80211_get_antenna, ++ .set_extant = ieee80211_set_extant, ++ .get_extant = ieee80211_get_extant, + .set_ringparam = ieee80211_set_ringparam, + .get_ringparam = ieee80211_get_ringparam, + .set_rekey_data = ieee80211_set_rekey_data, +--- a/net/mac80211/driver-ops.h ++++ b/net/mac80211/driver-ops.h +@@ -712,6 +712,24 @@ static inline int drv_get_antenna(struct + return ret; + } + ++static inline int drv_set_extant(struct ieee80211_local *local, u32 extant) ++{ ++ int ret = -EOPNOTSUPP; ++ might_sleep(); ++ if (local->ops->set_extant) ++ ret = local->ops->set_extant(&local->hw, extant); ++ return ret; ++} ++ ++static inline int drv_get_extant(struct ieee80211_local *local, u32 *extant) ++{ ++ int ret = -EOPNOTSUPP; ++ might_sleep(); ++ if (local->ops->get_extant) ++ ret = local->ops->get_extant(&local->hw, extant); ++ return ret; ++} ++ + static inline int drv_remain_on_channel(struct ieee80211_local *local, + struct ieee80211_channel *chan, + enum nl80211_channel_type chantype, diff --git a/package/mac80211/patches/582-ath9k-antenna-switch-profile-support-for-ar9285.patch b/package/mac80211/patches/582-ath9k-antenna-switch-profile-support-for-ar9285.patch new file mode 100644 index 0000000..d2e040e --- /dev/null +++ b/package/mac80211/patches/582-ath9k-antenna-switch-profile-support-for-ar9285.patch @@ -0,0 +1,448 @@ +From 564b3c4c8cf0ea10dbb090f2dc818d282a795cbd Mon Sep 17 00:00:00 2001 +From: Daniel Golle <[email protected]> +Date: Tue, 13 Dec 2011 17:53:31 +0200 +Subject: [PATCH 3/3] ath9k: antenna switch profile support for ar9285 + +This implements support for antenna configuration profiles for +devices based on Ar9285 using the AR_PHY_SWITCH_COM register, such +as the Allnet ALL0258N, Senao/EnGenius ENH200 and maybe others. + +Cc: Adrian Chadd <[email protected]> +Cc: Johannes Berg <[email protected]> +Signed-off-by: Daniel Golle <[email protected]> +--- + drivers/net/wireless/ath/ath9k/ar9002_phy.c | 13 ++++ + drivers/net/wireless/ath/ath9k/ar9003_eeprom.c | 8 ++- + drivers/net/wireless/ath/ath9k/eeprom.h | 1 + + drivers/net/wireless/ath/ath9k/eeprom_4k.c | 29 +++++++- + drivers/net/wireless/ath/ath9k/eeprom_9287.c | 8 ++- + drivers/net/wireless/ath/ath9k/eeprom_def.c | 8 ++- + drivers/net/wireless/ath/ath9k/hw.h | 28 ++++++++ + drivers/net/wireless/ath/ath9k/init.c | 92 ++++++++++++++++++++++++++ + drivers/net/wireless/ath/ath9k/main.c | 36 ++++++++++ + include/linux/ath9k_platform.h | 6 ++ + 10 files changed, 224 insertions(+), 5 deletions(-) + +--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c ++++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c +@@ -555,6 +555,16 @@ static void ar9002_hw_antdiv_comb_conf_s + REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regval); + } + ++static void ar9002_hw_extant_switchcom_set(struct ath_hw *ah, u32 switch_com_value) ++{ ++ REG_WRITE(ah, AR_PHY_SWITCH_COM, switch_com_value); ++} ++ ++static u32 ar9002_hw_extant_switchcom_get(struct ath_hw *ah) ++{ ++ return REG_READ(ah, AR_PHY_SWITCH_COM); ++} ++ + void ar9002_hw_attach_phy_ops(struct ath_hw *ah) + { + struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah); +@@ -572,5 +582,8 @@ void ar9002_hw_attach_phy_ops(struct ath + ops->antdiv_comb_conf_get = ar9002_hw_antdiv_comb_conf_get; + ops->antdiv_comb_conf_set = ar9002_hw_antdiv_comb_conf_set; + ++ ops->extant_switchcom_set = ar9002_hw_extant_switchcom_set; ++ ops->extant_switchcom_get = ar9002_hw_extant_switchcom_get; ++ + ar9002_hw_set_nf_limits(ah); + } +--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c ++++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +@@ -5153,6 +5153,11 @@ unsigned int ar9003_get_paprd_scale_fact + } + } + ++static u32 ath9k_hw_ar9300_get_switch_com(struct ath_hw *ah) ++{ ++ return 0; ++} ++ + const struct eeprom_ops eep_ar9300_ops = { + .check_eeprom = ath9k_hw_ar9300_check_eeprom, + .get_eeprom = ath9k_hw_ar9300_get_eeprom, +@@ -5163,5 +5168,6 @@ const struct eeprom_ops eep_ar9300_ops = + .set_board_values = ath9k_hw_ar9300_set_board_values, + .set_addac = ath9k_hw_ar9300_set_addac, + .set_txpower = ath9k_hw_ar9300_set_txpower, +- .get_spur_channel = ath9k_hw_ar9300_get_spur_channel ++ .get_spur_channel = ath9k_hw_ar9300_get_spur_channel, ++ .get_switch_com = ath9k_hw_ar9300_get_switch_com + }; +--- a/drivers/net/wireless/ath/ath9k/eeprom.h ++++ b/drivers/net/wireless/ath/ath9k/eeprom.h +@@ -652,6 +652,7 @@ struct eeprom_ops { + u16 cfgCtl, u8 twiceAntennaReduction, + u8 powerLimit, bool test); + u16 (*get_spur_channel)(struct ath_hw *ah, u16 i, bool is2GHz); ++ u32 (*get_switch_com)(struct ath_hw *ah); + }; + + void ath9k_hw_analog_shift_regwrite(struct ath_hw *ah, u32 reg, u32 val); +--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c ++++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c +@@ -811,6 +811,30 @@ static void ath9k_hw_4k_set_gain(struct + } + + /* ++ * Get common antenna configuration bits ++ */ ++static u32 ath9k_hw_4k_get_switch_com(struct ath_hw *ah) ++{ ++ struct ath_hw_switch_com_profile *easp; ++ struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k; ++ struct modal_eep_4k_header *pModal = &eep->modalHeader; ++ ++ /* return value from eeprom if there are no profiles */ ++ if (!ah->switch_com_profiles) ++ return pModal->antCtrlCommon; ++ ++ /* find matching value for profile id */ ++ for(easp = ah->switch_com_profiles;easp->id >= 0; easp++) { ++ if ( easp->id == ah->selected_extant_profile ) ++ return easp->switch_com_value; ++ } ++ ++ /* invalid profile selected, return an error */ ++ return 1; ++} ++ ++ ++/* + * Read EEPROM header info and program the device for correct operation + * given the channel value. + */ +@@ -829,7 +853,7 @@ static void ath9k_hw_4k_set_board_values + pModal = &eep->modalHeader; + txRxAttenLocal = 23; + +- REG_WRITE(ah, AR_PHY_SWITCH_COM, pModal->antCtrlCommon); ++ REG_WRITE(ah, AR_PHY_SWITCH_COM, ath9k_hw_4k_get_switch_com(ah)); + + /* Single chain for 4K EEPROM*/ + ath9k_hw_4k_set_gain(ah, pModal, eep, txRxAttenLocal); +@@ -1107,5 +1131,6 @@ const struct eeprom_ops eep_4k_ops = { + .get_eeprom_rev = ath9k_hw_4k_get_eeprom_rev, + .set_board_values = ath9k_hw_4k_set_board_values, + .set_txpower = ath9k_hw_4k_set_txpower, +- .get_spur_channel = ath9k_hw_4k_get_spur_channel ++ .get_spur_channel = ath9k_hw_4k_get_spur_channel, ++ .get_switch_com = ath9k_hw_4k_get_switch_com + }; +--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c ++++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c +@@ -1036,6 +1036,11 @@ static u16 ath9k_hw_ar9287_get_spur_chan + #undef EEP_MAP9287_SPURCHAN + } + ++static u32 ath9k_hw_ar9287_get_switch_com(struct ath_hw *ah) ++{ ++ return 0; ++} ++ + const struct eeprom_ops eep_ar9287_ops = { + .check_eeprom = ath9k_hw_ar9287_check_eeprom, + .get_eeprom = ath9k_hw_ar9287_get_eeprom, +@@ -1045,5 +1050,6 @@ const struct eeprom_ops eep_ar9287_ops = + .get_eeprom_rev = ath9k_hw_ar9287_get_eeprom_rev, + .set_board_values = ath9k_hw_ar9287_set_board_values, + .set_txpower = ath9k_hw_ar9287_set_txpower, +- .get_spur_channel = ath9k_hw_ar9287_get_spur_channel ++ .get_spur_channel = ath9k_hw_ar9287_get_spur_channel, ++ .get_switch_com = ath9k_hw_ar9287_get_switch_com + }; +--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c ++++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c +@@ -1369,6 +1369,11 @@ static u16 ath9k_hw_def_get_spur_channel + #undef EEP_DEF_SPURCHAN + } + ++static u32 ath9k_hw_def_get_switch_com(struct ath_hw *ah) ++{ ++ return 0; ++} ++ + const struct eeprom_ops eep_def_ops = { + .check_eeprom = ath9k_hw_def_check_eeprom, + .get_eeprom = ath9k_hw_def_get_eeprom, +@@ -1379,5 +1384,6 @@ const struct eeprom_ops eep_def_ops = { + .set_board_values = ath9k_hw_def_set_board_values, + .set_addac = ath9k_hw_def_set_addac, + .set_txpower = ath9k_hw_def_set_txpower, +- .get_spur_channel = ath9k_hw_def_get_spur_channel ++ .get_spur_channel = ath9k_hw_def_get_spur_channel, ++ .get_switch_com = ath9k_hw_def_get_switch_com + }; +--- a/drivers/net/wireless/ath/ath9k/hw.h ++++ b/drivers/net/wireless/ath/ath9k/hw.h +@@ -587,6 +587,25 @@ struct ath_hw_radar_conf { + bool ext_channel; + }; + ++ ++/** ++ * struct ath_hw_switch_com_profile - external antenna switch settings ++ * ++ * This structure holds a platform_data-supplied alternative value ++ * of AR_PHY_SWITCH_COM. ++ * ++ * @id: unique identifier ++ * @switch_com_value: bit-field to be set in register AR_PHY_SWITCH_COM ++ * @name: profile name ++ * @desc: profile description ++ */ ++struct ath_hw_switch_com_profile { ++ int id; ++ u32 switch_com_value; ++ char *name; ++ char *desc; ++}; ++ + /** + * struct ath_hw_private_ops - callbacks used internally by hardware code + * +@@ -685,6 +704,9 @@ struct ath_hw_ops { + void (*antdiv_comb_conf_set)(struct ath_hw *ah, + struct ath_hw_antcomb_conf *antconf); + ++ u32 (*extant_switchcom_get)(struct ath_hw *ah); ++ void (*extant_switchcom_set)(struct ath_hw *ah, ++ u32 switch_com_value); + }; + + struct ath_nf_limits { +@@ -918,6 +940,12 @@ struct ath_hw { + bool is_clk_25mhz; + int (*get_mac_revision)(void); + int (*external_reset)(void); ++ ++ /* ++ * External antenna switch configuration profiles ++ */ ++ struct ath_hw_switch_com_profile *switch_com_profiles; ++ u32 selected_extant_profile; + }; + + struct ath_bus_ops { +--- a/drivers/net/wireless/ath/ath9k/init.c ++++ b/drivers/net/wireless/ath/ath9k/init.c +@@ -504,6 +504,43 @@ static void ath9k_init_misc(struct ath_s + sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT; + } + ++static int ath9k_init_switch_com_profiles(struct ath_softc *sc, struct ath_hw *ah) ++{ ++ struct ath9k_platform_data *pdata = sc->dev->platform_data; ++ int i,j; ++ ++ /* count valid profiles in platform data */ ++ j=0; ++ for(i=0;i<ATH9K_PLAT_MAX_SWITCH_COM_PROFILES;i++) { ++ if ( pdata->switch_com_profiles[i].name ) ++ j++; ++ } ++ /* ++ * allocate space for the j profiles found + 1 for termination ++ */ ++ if ( j>0 && ! ah->switch_com_profiles ) { ++ ah->switch_com_profiles = kcalloc(j + 1, ++ sizeof(struct ath_hw_switch_com_profile), ++ GFP_KERNEL); ++ if ( ! ah->switch_com_profiles ) ++ return -ENOMEM; ++ } ++ /* populate the space from platform_data */ ++ j=0; ++ for(i=0;i<ATH9K_PLAT_MAX_SWITCH_COM_PROFILES;i++) { ++ if ( pdata->switch_com_profiles[i].name ) { ++ ah->switch_com_profiles[j].id = j; ++ ah->switch_com_profiles[j].switch_com_value = pdata->switch_com_profiles[i].val; ++ ah->switch_com_profiles[j].name = pdata->switch_com_profiles[i].name; ++ ah->switch_com_profiles[j].desc = pdata->switch_com_profiles[i].desc; ++ j++; ++ } ++ } ++ if ( j>0 ) ++ ah->switch_com_profiles[j].id = -1; ++ return 0; ++} ++ + static int ath9k_init_softc(u16 devid, struct ath_softc *sc, + const struct ath_bus_ops *bus_ops) + { +@@ -599,6 +636,10 @@ static int ath9k_init_softc(u16 devid, s + if (ret) + goto err_btcoex; + ++ ret = ath9k_init_switch_com_profiles(sc, ah); ++ if (ret) ++ goto err_btcoex; ++ + ath9k_cmn_init_crypto(sc->sc_ah); + ath9k_init_misc(sc); + +@@ -615,6 +656,8 @@ err_queues: + ath9k_hw_deinit(ah); + err_hw: + ++ if ( ah->switch_com_profiles ) ++ kfree(ah->switch_com_profiles); + kfree(ah); + sc->sc_ah = NULL; + +@@ -771,6 +814,47 @@ void ath9k_set_hw_capab(struct ath_softc + SET_IEEE80211_PERM_ADDR(hw, common->macaddr); + } + ++int ath9k_set_extant_profiles(struct ath_hw *ah, struct ieee80211_hw *hw) ++{ ++ struct ath_common *common = ath9k_hw_common(ah); ++ int i; ++ /* nothing to do if there are no profiles */ ++ if (! ah->switch_com_profiles) ++ return 0; ++ ++ ath_dbg(common, CONFIG, ++ "Device got extant support.\n"); ++ hw->wiphy->flags |= WIPHY_FLAG_HAS_EXTANT_SWITCH; ++ ++ /* allocate profile structure in wiphy for all available profiles + 1 */ ++ for (i=0; ah->switch_com_profiles[i].id >= 0; i++); ++ hw->wiphy->extant = kcalloc(i, sizeof(struct wiphy_extant_profile), GFP_KERNEL); ++ if ( ! hw->wiphy->extant ) ++ return -ENOMEM; ++ ++ ath_dbg(common, CONFIG, ++ "Detected %d antenna configuration profiles:\n", i); ++ hw->wiphy->num_extant_profiles = i; ++ /* populate wiphy->exant structure */ ++ for (i=0; ah->switch_com_profiles[i].id >= 0; i++) { ++ hw->wiphy->extant[i].id = ah->switch_com_profiles[i].id; ++ hw->wiphy->extant[i].name = ah->switch_com_profiles[i].name; ++ hw->wiphy->extant[i].desc = ah->switch_com_profiles[i].desc; ++ ath_dbg(common, CONFIG, ++ "\t%d \"%s\" (%s)\n", ++ hw->wiphy->extant[i].id, ++ hw->wiphy->extant[i].name, ++ hw->wiphy->extant[i].desc); ++ } ++ return 0; ++} ++ ++void ath9k_free_extant_profiles(struct ieee80211_hw *hw) ++{ ++ if (hw->wiphy->extant) ++ kfree(hw->wiphy->extant); ++} ++ + int ath9k_init_device(u16 devid, struct ath_softc *sc, + const struct ath_bus_ops *bus_ops) + { +@@ -789,6 +873,11 @@ int ath9k_init_device(u16 devid, struct + common = ath9k_hw_common(ah); + ath9k_set_hw_capab(sc, hw); + ++ /* Initialize extant profiles */ ++ error = ath9k_set_extant_profiles(ah, hw); ++ if (error != 0) ++ goto error_extant; ++ + /* Initialize regulatory */ + error = ath_regd_init(&common->regulatory, sc->hw->wiphy, + ath9k_reg_notifier); +@@ -848,6 +937,8 @@ error_rx: + error_tx: + /* Nothing */ + error_regd: ++ ath9k_free_extant_profiles(hw); ++error_extant: + ath9k_deinit_softc(sc); + error_init: + return error; +@@ -895,6 +986,7 @@ void ath9k_deinit_device(struct ath_soft + ieee80211_unregister_hw(hw); + ath_rx_cleanup(sc); + ath_tx_cleanup(sc); ++ ath9k_free_extant_profiles(hw); + ath9k_deinit_softc(sc); + } + +--- a/drivers/net/wireless/ath/ath9k/main.c ++++ b/drivers/net/wireless/ath/ath9k/main.c +@@ -2390,6 +2390,40 @@ static void ath9k_set_wakeup(struct ieee + + #endif + ++static int ath9k_set_extant(struct ieee80211_hw *hw, u32 extant) ++{ ++ struct ath_softc *sc = hw->priv; ++ struct ath_hw *ah = sc->sc_ah; ++ struct ath_common *common = ath9k_hw_common(ah); ++ u32 backup_extant = ah->selected_extant_profile; ++ u32 switch_com_value = 0; ++ ++ ath_dbg(common, CONFIG, "entering set_extant(%d)\n", extant); ++ ++ ah->selected_extant_profile = extant; ++ switch_com_value = ah->eep_ops->get_switch_com(ah); ++ if (switch_com_value & 0xf) ++ goto invalid_profile; ++ ++ ath_dbg(common, CONFIG, "switch_com: %08x\n", switch_com_value); ++ return 0; ++ ++invalid_profile: ++ ath_dbg(common, CONFIG, "invalid profile (%08x)\n", switch_com_value); ++ ah->selected_extant_profile = backup_extant; ++ return -EINVAL; ++} ++ ++static int ath9k_get_extant(struct ieee80211_hw *hw, u32 *extant) ++{ ++ struct ath_softc *sc = hw->priv; ++ struct ath_hw *ah = sc->sc_ah; ++ if (!ah->switch_com_profiles) ++ return -EINVAL; ++ *extant = ah->selected_extant_profile; ++ return 0; ++} ++ + struct ieee80211_ops ath9k_ops = { + .tx = ath9k_tx, + .start = ath9k_start, +@@ -2418,6 +2452,8 @@ struct ieee80211_ops ath9k_ops = { + .get_stats = ath9k_get_stats, + .set_antenna = ath9k_set_antenna, + .get_antenna = ath9k_get_antenna, ++ .set_extant = ath9k_set_extant, ++ .get_extant = ath9k_get_extant, + + #ifdef CONFIG_PM_SLEEP + .suspend = ath9k_suspend, +--- a/include/linux/ath9k_platform.h ++++ b/include/linux/ath9k_platform.h +@@ -20,6 +20,7 @@ + #define _LINUX_ATH9K_PLATFORM_H + + #define ATH9K_PLAT_EEP_MAX_WORDS 2048 ++#define ATH9K_PLAT_MAX_SWITCH_COM_PROFILES 4 + + struct ath9k_platform_data { + u16 eeprom_data[ATH9K_PLAT_EEP_MAX_WORDS]; +@@ -36,6 +37,12 @@ struct ath9k_platform_data { + + int num_leds; + const struct gpio_led *leds; ++ ++ struct { ++ u32 val; ++ char *name; ++ char *desc; ++ } switch_com_profiles[ATH9K_PLAT_MAX_SWITCH_COM_PROFILES]; + }; + + #endif /* _LINUX_ATH9K_PLATFORM_H */ -- 1.7.11.3
pgpM6EA5SuClH.pgp
Description: PGP signature
_______________________________________________ openwrt-devel mailing list [email protected] https://lists.openwrt.org/mailman/listinfo/openwrt-devel
