⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 iwl4965-base.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* These twh conditions has the same outcome but keep them separate	  since they have different meaning */	if (unlikely(index == IWL_INVALID_STATION)) {		spin_unlock_irqrestore(&priv->sta_lock, flags_spin);		return index;	}	if (priv->stations[index].used &&	    !compare_ether_addr(priv->stations[index].sta.sta.addr, addr)) {		spin_unlock_irqrestore(&priv->sta_lock, flags_spin);		return index;	}	IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr));	station = &priv->stations[index];	station->used = 1;	priv->num_stations++;	memset(&station->sta, 0, sizeof(struct iwl_addsta_cmd));	memcpy(station->sta.sta.addr, addr, ETH_ALEN);	station->sta.mode = 0;	station->sta.sta.sta_id = index;	station->sta.station_flags = 0;#ifdef CONFIG_IWLWIFI_HT	/* BCAST station and IBSS stations do not work in HT mode */	if (index != priv->hw_setting.bcast_sta_id &&	    priv->iw_mode != IEEE80211_IF_TYPE_IBSS)		iwl4965_set_ht_add_station(priv, index);#endif /*CONFIG_IWLWIFI_HT*/	spin_unlock_irqrestore(&priv->sta_lock, flags_spin);	iwl_send_add_station(priv, &station->sta, flags);	return index;}/*************** DRIVER STATUS FUNCTIONS   *****/static inline int iwl_is_ready(struct iwl_priv *priv){	/* The adapter is 'ready' if READY and GEO_CONFIGURED bits are	 * set but EXIT_PENDING is not */	return test_bit(STATUS_READY, &priv->status) &&	       test_bit(STATUS_GEO_CONFIGURED, &priv->status) &&	       !test_bit(STATUS_EXIT_PENDING, &priv->status);}static inline int iwl_is_alive(struct iwl_priv *priv){	return test_bit(STATUS_ALIVE, &priv->status);}static inline int iwl_is_init(struct iwl_priv *priv){	return test_bit(STATUS_INIT, &priv->status);}static inline int iwl_is_rfkill(struct iwl_priv *priv){	return test_bit(STATUS_RF_KILL_HW, &priv->status) ||	       test_bit(STATUS_RF_KILL_SW, &priv->status);}static inline int iwl_is_ready_rf(struct iwl_priv *priv){	if (iwl_is_rfkill(priv))		return 0;	return iwl_is_ready(priv);}/*************** HOST COMMAND QUEUE FUNCTIONS   *****/#define IWL_CMD(x) case x : return #xstatic const char *get_cmd_string(u8 cmd){	switch (cmd) {		IWL_CMD(REPLY_ALIVE);		IWL_CMD(REPLY_ERROR);		IWL_CMD(REPLY_RXON);		IWL_CMD(REPLY_RXON_ASSOC);		IWL_CMD(REPLY_QOS_PARAM);		IWL_CMD(REPLY_RXON_TIMING);		IWL_CMD(REPLY_ADD_STA);		IWL_CMD(REPLY_REMOVE_STA);		IWL_CMD(REPLY_REMOVE_ALL_STA);		IWL_CMD(REPLY_TX);		IWL_CMD(REPLY_RATE_SCALE);		IWL_CMD(REPLY_LEDS_CMD);		IWL_CMD(REPLY_TX_LINK_QUALITY_CMD);		IWL_CMD(RADAR_NOTIFICATION);		IWL_CMD(REPLY_QUIET_CMD);		IWL_CMD(REPLY_CHANNEL_SWITCH);		IWL_CMD(CHANNEL_SWITCH_NOTIFICATION);		IWL_CMD(REPLY_SPECTRUM_MEASUREMENT_CMD);		IWL_CMD(SPECTRUM_MEASURE_NOTIFICATION);		IWL_CMD(POWER_TABLE_CMD);		IWL_CMD(PM_SLEEP_NOTIFICATION);		IWL_CMD(PM_DEBUG_STATISTIC_NOTIFIC);		IWL_CMD(REPLY_SCAN_CMD);		IWL_CMD(REPLY_SCAN_ABORT_CMD);		IWL_CMD(SCAN_START_NOTIFICATION);		IWL_CMD(SCAN_RESULTS_NOTIFICATION);		IWL_CMD(SCAN_COMPLETE_NOTIFICATION);		IWL_CMD(BEACON_NOTIFICATION);		IWL_CMD(REPLY_TX_BEACON);		IWL_CMD(WHO_IS_AWAKE_NOTIFICATION);		IWL_CMD(QUIET_NOTIFICATION);		IWL_CMD(REPLY_TX_PWR_TABLE_CMD);		IWL_CMD(MEASURE_ABORT_NOTIFICATION);		IWL_CMD(REPLY_BT_CONFIG);		IWL_CMD(REPLY_STATISTICS_CMD);		IWL_CMD(STATISTICS_NOTIFICATION);		IWL_CMD(REPLY_CARD_STATE_CMD);		IWL_CMD(CARD_STATE_NOTIFICATION);		IWL_CMD(MISSED_BEACONS_NOTIFICATION);		IWL_CMD(REPLY_CT_KILL_CONFIG_CMD);		IWL_CMD(SENSITIVITY_CMD);		IWL_CMD(REPLY_PHY_CALIBRATION_CMD);		IWL_CMD(REPLY_RX_PHY_CMD);		IWL_CMD(REPLY_RX_MPDU_CMD);		IWL_CMD(REPLY_4965_RX);		IWL_CMD(REPLY_COMPRESSED_BA);	default:		return "UNKNOWN";	}}#define HOST_COMPLETE_TIMEOUT (HZ / 2)/** * iwl_enqueue_hcmd - enqueue a uCode command * @priv: device private data point * @cmd: a point to the ucode command structure * * The function returns < 0 values to indicate the operation is * failed. On success, it turns the index (> 0) of command in the * command queue. */static int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd){	struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];	struct iwl_queue *q = &txq->q;	struct iwl_tfd_frame *tfd;	u32 *control_flags;	struct iwl_cmd *out_cmd;	u32 idx;	u16 fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr));	dma_addr_t phys_addr;	int ret;	unsigned long flags;	/* If any of the command structures end up being larger than	 * the TFD_MAX_PAYLOAD_SIZE, and it sent as a 'small' command then	 * we will need to increase the size of the TFD entries */	BUG_ON((fix_size > TFD_MAX_PAYLOAD_SIZE) &&	       !(cmd->meta.flags & CMD_SIZE_HUGE));	if (iwl_queue_space(q) < ((cmd->meta.flags & CMD_ASYNC) ? 2 : 1)) {		IWL_ERROR("No space for Tx\n");		return -ENOSPC;	}	spin_lock_irqsave(&priv->hcmd_lock, flags);	tfd = &txq->bd[q->first_empty];	memset(tfd, 0, sizeof(*tfd));	control_flags = (u32 *) tfd;	idx = get_cmd_index(q, q->first_empty, cmd->meta.flags & CMD_SIZE_HUGE);	out_cmd = &txq->cmd[idx];	out_cmd->hdr.cmd = cmd->id;	memcpy(&out_cmd->meta, &cmd->meta, sizeof(cmd->meta));	memcpy(&out_cmd->cmd.payload, cmd->data, cmd->len);	/* At this point, the out_cmd now has all of the incoming cmd	 * information */	out_cmd->hdr.flags = 0;	out_cmd->hdr.sequence = cpu_to_le16(QUEUE_TO_SEQ(IWL_CMD_QUEUE_NUM) |			INDEX_TO_SEQ(q->first_empty));	if (out_cmd->meta.flags & CMD_SIZE_HUGE)		out_cmd->hdr.sequence |= cpu_to_le16(SEQ_HUGE_FRAME);	phys_addr = txq->dma_addr_cmd + sizeof(txq->cmd[0]) * idx +			offsetof(struct iwl_cmd, hdr);	iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size);	IWL_DEBUG_HC("Sending command %s (#%x), seq: 0x%04X, "		     "%d bytes at %d[%d]:%d\n",		     get_cmd_string(out_cmd->hdr.cmd),		     out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence),		     fix_size, q->first_empty, idx, IWL_CMD_QUEUE_NUM);	txq->need_update = 1;	ret = iwl4965_tx_queue_update_wr_ptr(priv, txq, 0);	q->first_empty = iwl_queue_inc_wrap(q->first_empty, q->n_bd);	iwl_tx_queue_update_write_ptr(priv, txq);	spin_unlock_irqrestore(&priv->hcmd_lock, flags);	return ret ? ret : idx;}int iwl_send_cmd_async(struct iwl_priv *priv, struct iwl_host_cmd *cmd){	int ret;	BUG_ON(!(cmd->meta.flags & CMD_ASYNC));	/* An asynchronous command can not expect an SKB to be set. */	BUG_ON(cmd->meta.flags & CMD_WANT_SKB);	/* An asynchronous command MUST have a callback. */	BUG_ON(!cmd->meta.u.callback);	if (test_bit(STATUS_EXIT_PENDING, &priv->status))		return -EBUSY;	ret = iwl_enqueue_hcmd(priv, cmd);	if (ret < 0) {		IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n",			  get_cmd_string(cmd->id), ret);		return ret;	}	return 0;}int iwl_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd){	int cmd_idx;	int ret;	static atomic_t entry = ATOMIC_INIT(0); /* reentrance protection */	BUG_ON(cmd->meta.flags & CMD_ASYNC);	 /* A synchronous command can not have a callback set. */	BUG_ON(cmd->meta.u.callback != NULL);	if (atomic_xchg(&entry, 1)) {		IWL_ERROR("Error sending %s: Already sending a host command\n",			  get_cmd_string(cmd->id));		return -EBUSY;	}	set_bit(STATUS_HCMD_ACTIVE, &priv->status);	if (cmd->meta.flags & CMD_WANT_SKB)		cmd->meta.source = &cmd->meta;	cmd_idx = iwl_enqueue_hcmd(priv, cmd);	if (cmd_idx < 0) {		ret = cmd_idx;		IWL_ERROR("Error sending %s: iwl_enqueue_hcmd failed: %d\n",			  get_cmd_string(cmd->id), ret);		goto out;	}	ret = wait_event_interruptible_timeout(priv->wait_command_queue,			!test_bit(STATUS_HCMD_ACTIVE, &priv->status),			HOST_COMPLETE_TIMEOUT);	if (!ret) {		if (test_bit(STATUS_HCMD_ACTIVE, &priv->status)) {			IWL_ERROR("Error sending %s: time out after %dms.\n",				  get_cmd_string(cmd->id),				  jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));			clear_bit(STATUS_HCMD_ACTIVE, &priv->status);			ret = -ETIMEDOUT;			goto cancel;		}	}	if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {		IWL_DEBUG_INFO("Command %s aborted: RF KILL Switch\n",			       get_cmd_string(cmd->id));		ret = -ECANCELED;		goto fail;	}	if (test_bit(STATUS_FW_ERROR, &priv->status)) {		IWL_DEBUG_INFO("Command %s failed: FW Error\n",			       get_cmd_string(cmd->id));		ret = -EIO;		goto fail;	}	if ((cmd->meta.flags & CMD_WANT_SKB) && !cmd->meta.u.skb) {		IWL_ERROR("Error: Response NULL in '%s'\n",			  get_cmd_string(cmd->id));		ret = -EIO;		goto out;	}	ret = 0;	goto out;cancel:	if (cmd->meta.flags & CMD_WANT_SKB) {		struct iwl_cmd *qcmd;		/* Cancel the CMD_WANT_SKB flag for the cmd in the		 * TX cmd queue. Otherwise in case the cmd comes		 * in later, it will possibly set an invalid		 * address (cmd->meta.source). */		qcmd = &priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_idx];		qcmd->meta.flags &= ~CMD_WANT_SKB;	}fail:	if (cmd->meta.u.skb) {		dev_kfree_skb_any(cmd->meta.u.skb);		cmd->meta.u.skb = NULL;	}out:	atomic_set(&entry, 0);	return ret;}int iwl_send_cmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd){	/* A command can not be asynchronous AND expect an SKB to be set. */	BUG_ON((cmd->meta.flags & CMD_ASYNC) &&	       (cmd->meta.flags & CMD_WANT_SKB));	if (cmd->meta.flags & CMD_ASYNC)		return iwl_send_cmd_async(priv, cmd);	return iwl_send_cmd_sync(priv, cmd);}int iwl_send_cmd_pdu(struct iwl_priv *priv, u8 id, u16 len, const void *data){	struct iwl_host_cmd cmd = {		.id = id,		.len = len,		.data = data,	};	return iwl_send_cmd_sync(priv, &cmd);}static int __must_check iwl_send_cmd_u32(struct iwl_priv *priv, u8 id, u32 val){	struct iwl_host_cmd cmd = {		.id = id,		.len = sizeof(val),		.data = &val,	};	return iwl_send_cmd_sync(priv, &cmd);}int iwl_send_statistics_request(struct iwl_priv *priv){	return iwl_send_cmd_u32(priv, REPLY_STATISTICS_CMD, 0);}/** * iwl_rxon_add_station - add station into station table. * * there is only one AP station with id= IWL_AP_ID * NOTE: mutex must be held before calling the this fnction*/static int iwl_rxon_add_station(struct iwl_priv *priv,				const u8 *addr, int is_ap){	u8 sta_id;	sta_id = iwl_add_station(priv, addr, is_ap, 0);	iwl4965_add_station(priv, addr, is_ap);	return sta_id;}/** * iwl_set_rxon_channel - Set the phymode and channel values in staging RXON * @phymode: MODE_IEEE80211A sets to 5.2GHz; all else set to 2.4GHz * @channel: Any channel valid for the requested phymode * In addition to setting the staging RXON, priv->phymode is also set. * * NOTE:  Does not commit to the hardware; it sets appropriate bit fields * in the staging RXON flag structure based on the phymode */static int iwl_set_rxon_channel(struct iwl_priv *priv, u8 phymode, u16 channel){	if (!iwl_get_channel_info(priv, phymode, channel)) {		IWL_DEBUG_INFO("Could not set channel to %d [%d]\n",			       channel, phymode);		return -EINVAL;	}	if ((le16_to_cpu(priv->staging_rxon.channel) == channel) &&	    (priv->phymode == phymode))		return 0;	priv->staging_rxon.channel = cpu_to_le16(channel);	if (phymode == MODE_IEEE80211A)		priv->staging_rxon.flags &= ~RXON_FLG_BAND_24G_MSK;	else		priv->staging_rxon.flags |= RXON_FLG_BAND_24G_MSK;	priv->phymode = phymode;	IWL_DEBUG_INFO("Staging channel set to %d [%d]\n", channel, phymode);	return 0;}/** * iwl_check_rxon_cmd - validate RXON structure is valid * * NOTE:  This is really only useful during development and can eventually * be #ifdef'd out once the driver is stable and folks aren't actively * making changes */static int iwl_check_rxon_cmd(struct iwl_rxon_cmd *rxon){	int error = 0;	int counter = 1;	if (rxon->flags & RXON_FLG_BAND_24G_MSK) {		error |= le32_to_cpu(rxon->flags &				(RXON_FLG_TGJ_NARROW_BAND_MSK |				 RXON_FLG_RADAR_DETECT_MSK));		if (error)			IWL_WARNING("check 24G fields %d | %d\n",				    counter++, error);	} else {		error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ?				0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK);		if (error)			IWL_WARNING("check 52 fields %d | %d\n",				    counter++, error);		error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK);		if (error)			IWL_WARNING("check 52 CCK %d | %d\n",				    counter++, error);	}	error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1;	if (error)		IWL_WARNING("check mac addr %d | %d\n", counter++, error);	/* make sure basic rates 6Mbps and 1Mbps are supported */	error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) &&		  ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0));	if (error)		IWL_WARNING("check basic rate %d | %d\n", counter++, error);	error |= (le16_to_cpu(rxon->assoc_id) > 2007);	if (error)		IWL_WARNING("check assoc id %d | %d\n", counter++, error);	error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK))			== (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK));	if (error)		IWL_WARNING("check CCK and short slot %d | %d\n",			    counter++, error);	error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK))			== (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK));	if (error)		IWL_WARNING("check CCK & auto detect %d | %d\n",			    counter++, error);	error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK |			RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK);	if (error)		IWL_WARNING("check TGG and auto detect %d | %d\n",			    counter++, error);	if (error)		IWL_WARNING("Tuning to channel %d\n",			    le16_to_cpu(rxon->channel));	if (error) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -