Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cc4b9d39 authored by Dan Williams's avatar Dan Williams Committed by John W. Linville
Browse files

libertas: convert 11D_DOMAIN_INFO to a direct command

parent 9fb7663d
Loading
Loading
Loading
Loading
+5 −98
Original line number Diff line number Diff line
@@ -1979,113 +1979,20 @@ int lbs_cfg_register(struct lbs_private *priv)
	return ret;
}

/**
 *  @brief This function sets DOMAIN INFO to FW
 *  @param priv       pointer to struct lbs_private
 *  @return          0; -1
*/
static int lbs_11d_set_domain_info(struct lbs_private *priv)
{
	int ret;

	ret = lbs_prepare_and_send_command(priv, CMD_802_11D_DOMAIN_INFO,
			CMD_ACT_SET,
			CMD_OPTION_WAITFORRSP, 0, NULL);
	if (ret)
		lbs_deb_11d("fail to dnld domain info\n");

	return ret;
}

static void lbs_send_domain_info_cmd_fw(struct wiphy *wiphy,
int lbs_reg_notifier(struct wiphy *wiphy,
		struct regulatory_request *request)
{
	u8   no_of_triplet = 0;
	u8   no_of_parsed_chan = 0;
	u8   first_channel = 0, next_chan = 0, max_pwr = 0;
	u8   i, flag = 0;
	enum ieee80211_band band;
	struct ieee80211_supported_band *sband;
	struct ieee80211_channel *ch;
	struct lbs_private *priv = wiphy_priv(wiphy);
	struct lbs_802_11d_domain_reg *domain_info = &priv->domain_reg;
	int ret = 0;

	lbs_deb_enter(LBS_DEB_CFG80211);

	/* Set country code */
	domain_info->country_code[0] = request->alpha2[0];
	domain_info->country_code[1] = request->alpha2[1];
	domain_info->country_code[2] = ' ';

	for (band = 0; band < IEEE80211_NUM_BANDS ; band++) {

		if (!wiphy->bands[band])
			continue;

		sband = wiphy->bands[band];

		for (i = 0; i < sband->n_channels ; i++) {
			ch = &sband->channels[i];
			if (ch->flags & IEEE80211_CHAN_DISABLED)
				continue;

			if (!flag) {
				flag = 1;
				next_chan = first_channel = (u32) ch->hw_value;
				max_pwr = ch->max_power;
				no_of_parsed_chan = 1;
				continue;
			}

			if (ch->hw_value == next_chan + 1 &&
					ch->max_power == max_pwr) {
				next_chan++;
				no_of_parsed_chan++;
			} else {
				domain_info->triplet[no_of_triplet]
					.chans.first_channel = first_channel;
				domain_info->triplet[no_of_triplet]
					.chans.num_channels = no_of_parsed_chan;
				domain_info->triplet[no_of_triplet]
					.chans.max_power = max_pwr;
				no_of_triplet++;
				flag = 0;
			}
		}
		if (flag) {
			domain_info->triplet[no_of_triplet]
				.chans.first_channel = first_channel;
			domain_info->triplet[no_of_triplet]
				.chans.num_channels = no_of_parsed_chan;
			domain_info->triplet[no_of_triplet]
				.chans.max_power = max_pwr;
			no_of_triplet++;
		}
	}

	domain_info->no_triplet = no_of_triplet;

	/* Set domain info */
	ret = lbs_11d_set_domain_info(priv);
	if (ret)
		lbs_pr_err("11D: error setting domain info in FW\n");

	lbs_deb_leave(LBS_DEB_CFG80211);
}
	int ret;

int lbs_reg_notifier(struct wiphy *wiphy,
		struct regulatory_request *request)
{
	lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain "
			"callback for domain %c%c\n", request->alpha2[0],
			request->alpha2[1]);

	lbs_send_domain_info_cmd_fw(wiphy, request);
	ret = lbs_set_11d_domain_info(priv, request, wiphy->bands);

	lbs_deb_leave(LBS_DEB_CFG80211);

	return 0;
	return ret;
}

void lbs_scan_deinit(struct lbs_private *priv)
+123 −65
Original line number Diff line number Diff line
@@ -725,6 +725,129 @@ int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf)
	return ret;
}

/**
 *  @brief Send regulatory and 802.11d domain information to the firmware
 *
 *  @param priv		pointer to struct lbs_private
 *  @param request	cfg80211 regulatory request structure
 *  @param bands	the device's supported bands and channels
 *
 *  @return		0 on success, error code on failure
*/
int lbs_set_11d_domain_info(struct lbs_private *priv,
			    struct regulatory_request *request,
			    struct ieee80211_supported_band **bands)
{
	struct cmd_ds_802_11d_domain_info cmd;
	struct mrvl_ie_domain_param_set *domain = &cmd.domain;
	struct ieee80211_country_ie_triplet *t;
	enum ieee80211_band band;
	struct ieee80211_channel *ch;
	u8 num_triplet = 0;
	u8 num_parsed_chan = 0;
	u8 first_channel = 0, next_chan = 0, max_pwr = 0;
	u8 i, flag = 0;
	size_t triplet_size;
	int ret;

	lbs_deb_enter(LBS_DEB_11D);

	memset(&cmd, 0, sizeof(cmd));
	cmd.action = cpu_to_le16(CMD_ACT_SET);

	lbs_deb_11d("Setting country code '%c%c'\n",
		    request->alpha2[0], request->alpha2[1]);

	domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);

	/* Set country code */
	domain->country_code[0] = request->alpha2[0];
	domain->country_code[1] = request->alpha2[1];
	domain->country_code[2] = ' ';

	/* Now set up the channel triplets; firmware is somewhat picky here
	 * and doesn't validate channel numbers and spans; hence it would
	 * interpret a triplet of (36, 4, 20) as channels 36, 37, 38, 39.  Since
	 * the last 3 aren't valid channels, the driver is responsible for
	 * splitting that up into 4 triplet pairs of (36, 1, 20) + (40, 1, 20)
	 * etc.
	 */
	for (band = 0;
	     (band < IEEE80211_NUM_BANDS) && (num_triplet < MAX_11D_TRIPLETS);
	     band++) {

		if (!bands[band])
			continue;

		for (i = 0;
		     (i < bands[band]->n_channels) && (num_triplet < MAX_11D_TRIPLETS);
		     i++) {
			ch = &bands[band]->channels[i];
			if (ch->flags & IEEE80211_CHAN_DISABLED)
				continue;

			if (!flag) {
				flag = 1;
				next_chan = first_channel = (u32) ch->hw_value;
				max_pwr = ch->max_power;
				num_parsed_chan = 1;
				continue;
			}

			if ((ch->hw_value == next_chan + 1) &&
					(ch->max_power == max_pwr)) {
				/* Consolidate adjacent channels */
				next_chan++;
				num_parsed_chan++;
			} else {
				/* Add this triplet */
				lbs_deb_11d("11D triplet (%d, %d, %d)\n",
					first_channel, num_parsed_chan,
					max_pwr);
				t = &domain->triplet[num_triplet];
				t->chans.first_channel = first_channel;
				t->chans.num_channels = num_parsed_chan;
				t->chans.max_power = max_pwr;
				num_triplet++;
				flag = 0;
			}
		}

		if (flag) {
			/* Add last triplet */
			lbs_deb_11d("11D triplet (%d, %d, %d)\n", first_channel,
				num_parsed_chan, max_pwr);
			t = &domain->triplet[num_triplet];
			t->chans.first_channel = first_channel;
			t->chans.num_channels = num_parsed_chan;
			t->chans.max_power = max_pwr;
			num_triplet++;
		}
	}

	lbs_deb_11d("# triplets %d\n", num_triplet);

	/* Set command header sizes */
	triplet_size = num_triplet * sizeof(struct ieee80211_country_ie_triplet);
	domain->header.len = cpu_to_le16(sizeof(domain->country_code) +
					triplet_size);

	lbs_deb_hex(LBS_DEB_11D, "802.11D domain param set",
			(u8 *) &cmd.domain.country_code,
			le16_to_cpu(domain->header.len));

	cmd.hdr.size = cpu_to_le16(sizeof(cmd.hdr) +
				   sizeof(cmd.action) +
				   sizeof(cmd.domain.header) +
				   sizeof(cmd.domain.country_code) +
				   triplet_size);

	ret = lbs_cmd_with_response(priv, CMD_802_11D_DOMAIN_INFO, &cmd);

	lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
	return ret;
}

static int lbs_cmd_reg_access(struct cmd_ds_command *cmdptr,
			       u8 cmd_action, void *pdata_buf)
{
@@ -1005,66 +1128,6 @@ void lbs_set_mac_control(struct lbs_private *priv)
	lbs_deb_leave(LBS_DEB_CMD);
}

/**
 *  @brief This function implements command CMD_802_11D_DOMAIN_INFO
 *  @param priv       pointer to struct lbs_private
 *  @param cmd        pointer to cmd buffer
 *  @param cmdno      cmd ID
 *  @param cmdOption  cmd action
 *  @return           0
*/
int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
				 struct cmd_ds_command *cmd,
				 u16 cmdoption)
{
	struct cmd_ds_802_11d_domain_info *pdomaininfo =
	    &cmd->params.domaininfo;
	struct mrvl_ie_domain_param_set *domain = &pdomaininfo->domain;
	u8 nr_triplet = priv->domain_reg.no_triplet;

	lbs_deb_enter(LBS_DEB_11D);

	lbs_deb_11d("nr_triplet=%x\n", nr_triplet);

	pdomaininfo->action = cpu_to_le16(cmdoption);
	if (cmdoption == CMD_ACT_GET) {
		cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
					sizeof(struct cmd_header));
		lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
			le16_to_cpu(cmd->size));
		goto done;
	}

	domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN);
	memcpy(domain->countrycode, priv->domain_reg.country_code,
	       sizeof(domain->countrycode));

	domain->header.len = cpu_to_le16(nr_triplet
				* sizeof(struct ieee80211_country_ie_triplet)
				+ sizeof(domain->countrycode));

	if (nr_triplet) {
		memcpy(domain->triplet, priv->domain_reg.triplet,
				nr_triplet *
				sizeof(struct ieee80211_country_ie_triplet));

		cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
					     le16_to_cpu(domain->header.len) +
					     sizeof(struct mrvl_ie_header) +
					     sizeof(struct cmd_header));
	} else {
		cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) +
					sizeof(struct cmd_header));
	}

	lbs_deb_hex(LBS_DEB_11D, "802_11D_DOMAIN_INFO", (u8 *) cmd,
			le16_to_cpu(cmd->size));

done:
	lbs_deb_enter(LBS_DEB_11D);
	return 0;
}

/**
 *  @brief This function prepare the command before send to firmware.
 *
@@ -1154,11 +1217,6 @@ int lbs_prepare_and_send_command(struct lbs_private *priv,
		ret = 0;
		goto done;

	case CMD_802_11D_DOMAIN_INFO:
		cmdptr->command = cpu_to_le16(cmd_no);
		ret = lbs_cmd_802_11d_domain_info(priv, cmdptr, cmd_action);
		break;

	case CMD_802_11_TPC_CFG:
		cmdptr->command = cpu_to_le16(CMD_802_11_TPC_CFG);
		cmdptr->size =
+6 −0
Original line number Diff line number Diff line
@@ -3,6 +3,8 @@
#ifndef _LBS_CMD_H_
#define _LBS_CMD_H_

#include <net/cfg80211.h>

#include "host.h"
#include "dev.h"

@@ -133,4 +135,8 @@ int lbs_set_monitor_mode(struct lbs_private *priv, int enable);

int lbs_get_rssi(struct lbs_private *priv, s8 *snr, s8 *nf);

int lbs_set_11d_domain_info(struct lbs_private *priv,
			    struct regulatory_request *request,
			    struct ieee80211_supported_band **bands);

#endif /* _LBS_CMD_H */
+0 −51
Original line number Diff line number Diff line
@@ -96,53 +96,6 @@ static int lbs_ret_reg_access(struct lbs_private *priv,
	lbs_deb_leave_args(LBS_DEB_CMD, "ret %d", ret);
	return ret;
}

/**
 *  @brief This function parses countryinfo from AP and download country info to FW
 *  @param priv    pointer to struct lbs_private
 *  @param resp    pointer to command response buffer
 *  @return        0; -1
 */
static int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp)
{
	struct cmd_ds_802_11d_domain_info *domaininfo =
			&resp->params.domaininforesp;
	struct mrvl_ie_domain_param_set *domain = &domaininfo->domain;
	u16 action = le16_to_cpu(domaininfo->action);
	s16 ret = 0;
	u8 nr_triplet = 0;

	lbs_deb_enter(LBS_DEB_11D);

	lbs_deb_hex(LBS_DEB_11D, "domain info resp", (u8 *) resp,
			(int)le16_to_cpu(resp->size));

	nr_triplet = (le16_to_cpu(domain->header.len) - COUNTRY_CODE_LEN) /
		sizeof(struct ieee80211_country_ie_triplet);

	lbs_deb_11d("domain info resp: nr_triplet %d\n", nr_triplet);

	if (nr_triplet > MRVDRV_MAX_TRIPLET_802_11D) {
		lbs_deb_11d("invalid number of triplets returned!!\n");
		return -1;
	}

	switch (action) {
	case CMD_ACT_SET:	/*Proc set action */
		break;

	case CMD_ACT_GET:
		break;
	default:
		lbs_deb_11d("invalid action:%d\n", domaininfo->action);
		ret = -1;
		break;
	}

	lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret);
	return ret;
}

static inline int handle_cmd_response(struct lbs_private *priv,
				      struct cmd_header *cmd_response)
{
@@ -172,10 +125,6 @@ static inline int handle_cmd_response(struct lbs_private *priv,
	case CMD_RET(CMD_802_11_BEACON_STOP):
		break;

	case CMD_RET(CMD_802_11D_DOMAIN_INFO):
		ret = lbs_ret_802_11d_domain_info(resp);
		break;

	case CMD_RET(CMD_802_11_TPC_CFG):
		spin_lock_irqsave(&priv->driver_lock, flags);
		memmove((void *)priv->cur_cmd->callback_arg, &resp->params.tpccfg,
+0 −5
Original line number Diff line number Diff line
@@ -53,9 +53,4 @@ int lbs_exit_auto_deep_sleep(struct lbs_private *priv);
u32 lbs_fw_index_to_data_rate(u8 index);
u8 lbs_data_rate_to_fw_index(u32 rate);

int lbs_cmd_802_11d_domain_info(struct lbs_private *priv,
		struct cmd_ds_command *cmd, u16 cmdoption);

int lbs_ret_802_11d_domain_info(struct cmd_ds_command *resp);

#endif
Loading