Beispiel #1
0
/*
 * This function handles the user application commands for driver.
 *
 * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the
 * handlers respectively.
 *
 * If it's an unknown commdn ID, -ENOSYS is replied; otherwise, the returned
 * value of the actual command execution is replied to the user application.
 *
 * If there's any message responding to the user space, IWL_TM_ATTR_SYNC_RSP
 * is used for carry the message while IWL_TM_ATTR_COMMAND must set to
 * IWL_TM_CMD_DEV2APP_SYNC_RSP.
 *
 * @hw: ieee80211_hw object that represents the device
 * @tb: gnl message fields from the user space
 */
static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
{
	struct iwl_priv *priv = hw->priv;
	struct iwl_trans *trans = trans(priv);
	struct sk_buff *skb;
	unsigned char *rsp_data_ptr = NULL;
	int status = 0, rsp_data_len = 0;
	u32 devid;

	switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
	case IWL_TM_CMD_APP2DEV_GET_DEVICENAME:
		rsp_data_ptr = (unsigned char *)cfg(priv)->name;
		rsp_data_len = strlen(cfg(priv)->name);
		skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
							rsp_data_len + 20);
		if (!skb) {
			IWL_DEBUG_INFO(priv,
				       "Error allocating memory\n");
			return -ENOMEM;
		}
		NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND,
			    IWL_TM_CMD_DEV2APP_SYNC_RSP);
		NLA_PUT(skb, IWL_TM_ATTR_SYNC_RSP,
			rsp_data_len, rsp_data_ptr);
		status = cfg80211_testmode_reply(skb);
		if (status < 0)
			IWL_DEBUG_INFO(priv, "Error sending msg : %d\n",
				       status);
		break;

	case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
		status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_INIT);
		if (status)
			IWL_DEBUG_INFO(priv,
				"Error loading init ucode: %d\n", status);
		break;

	case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
		iwl_testmode_cfg_init_calib(priv);
		iwl_trans_stop_device(trans);
		break;

	case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
		status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_REGULAR);
		if (status) {
			IWL_DEBUG_INFO(priv,
				"Error loading runtime ucode: %d\n", status);
			break;
		}
		status = iwl_alive_start(priv);
		if (status)
			IWL_DEBUG_INFO(priv,
				"Error starting the device: %d\n", status);
		break;

	case IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW:
		iwl_scan_cancel_timeout(priv, 200);
		iwl_trans_stop_device(trans);
		status = iwl_load_ucode_wait_alive(trans, IWL_UCODE_WOWLAN);
		if (status) {
			IWL_DEBUG_INFO(priv,
				"Error loading WOWLAN ucode: %d\n", status);
			break;
		}
		status = iwl_alive_start(priv);
		if (status)
			IWL_DEBUG_INFO(priv,
				"Error starting the device: %d\n", status);
		break;

	case IWL_TM_CMD_APP2DEV_GET_EEPROM:
		if (priv->shrd->eeprom) {
			skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
				cfg(priv)->base_params->eeprom_size + 20);
			if (!skb) {
				IWL_DEBUG_INFO(priv,
				       "Error allocating memory\n");
				return -ENOMEM;
			}
			NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND,
				IWL_TM_CMD_DEV2APP_EEPROM_RSP);
			NLA_PUT(skb, IWL_TM_ATTR_EEPROM,
				cfg(priv)->base_params->eeprom_size,
				priv->shrd->eeprom);
			status = cfg80211_testmode_reply(skb);
			if (status < 0)
				IWL_DEBUG_INFO(priv,
					       "Error sending msg : %d\n",
					       status);
		} else
			return -EFAULT;
		break;

	case IWL_TM_CMD_APP2DEV_FIXRATE_REQ:
		if (!tb[IWL_TM_ATTR_FIXRATE]) {
			IWL_DEBUG_INFO(priv,
				       "Error finding fixrate setting\n");
			return -ENOMSG;
		}
		priv->tm_fixed_rate = nla_get_u32(tb[IWL_TM_ATTR_FIXRATE]);
		break;

	case IWL_TM_CMD_APP2DEV_GET_FW_VERSION:
		IWL_INFO(priv, "uCode version raw: 0x%x\n", priv->ucode_ver);

		skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
		if (!skb) {
			IWL_DEBUG_INFO(priv, "Error allocating memory\n");
			return -ENOMEM;
		}
		NLA_PUT_U32(skb, IWL_TM_ATTR_FW_VERSION, priv->ucode_ver);
		status = cfg80211_testmode_reply(skb);
		if (status < 0)
			IWL_DEBUG_INFO(priv,
					"Error sending msg : %d\n", status);
		break;

	case IWL_TM_CMD_APP2DEV_GET_DEVICE_ID:
		devid = bus_get_hw_id(bus(priv));
		IWL_INFO(priv, "hw version: 0x%x\n", devid);

		skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
		if (!skb) {
			IWL_DEBUG_INFO(priv, "Error allocating memory\n");
			return -ENOMEM;
		}
		NLA_PUT_U32(skb, IWL_TM_ATTR_DEVICE_ID, devid);
		status = cfg80211_testmode_reply(skb);
		if (status < 0)
			IWL_DEBUG_INFO(priv,
					"Error sending msg : %d\n", status);
		break;

	default:
		IWL_DEBUG_INFO(priv, "Unknown testmode driver command ID\n");
		return -ENOSYS;
	}
	return status;

nla_put_failure:
	kfree_skb(skb);
	return -EMSGSIZE;
}
/*
 * This function handles the user application commands for driver.
 *
 * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the
 * handlers respectively.
 *
 * If it's an unknown commdn ID, -ENOSYS is replied; otherwise, the returned
 * value of the actual command execution is replied to the user application.
 *
 * If there's any message responding to the user space, IWL_TM_ATTR_SYNC_RSP
 * is used for carry the message while IWL_TM_ATTR_COMMAND must set to
 * IWL_TM_CMD_DEV2APP_SYNC_RSP.
 *
 * @hw: ieee80211_hw object that represents the device
 * @tb: gnl message fields from the user space
 */
static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
{
	struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
	struct iwl_trans *trans = trans(priv);
	struct sk_buff *skb;
	unsigned char *rsp_data_ptr = NULL;
	int status = 0, rsp_data_len = 0;
	u32 devid, inst_size = 0, data_size = 0;
	const struct fw_img *img;

	switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
	case IWL_TM_CMD_APP2DEV_GET_DEVICENAME:
		rsp_data_ptr = (unsigned char *)cfg(priv)->name;
		rsp_data_len = strlen(cfg(priv)->name);
		skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
							rsp_data_len + 20);
		if (!skb) {
			IWL_ERR(priv, "Memory allocation fail\n");
			return -ENOMEM;
		}
		NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND,
			    IWL_TM_CMD_DEV2APP_SYNC_RSP);
		NLA_PUT(skb, IWL_TM_ATTR_SYNC_RSP,
			rsp_data_len, rsp_data_ptr);
		status = cfg80211_testmode_reply(skb);
		if (status < 0)
			IWL_ERR(priv, "Error sending msg : %d\n", status);
		break;

	case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
		status = iwl_load_ucode_wait_alive(priv, IWL_UCODE_INIT);
		if (status)
			IWL_ERR(priv, "Error loading init ucode: %d\n", status);
		break;

	case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
		iwl_testmode_cfg_init_calib(priv);
		priv->ucode_loaded = false;
		iwl_trans_stop_device(trans);
		break;

	case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
		status = iwl_load_ucode_wait_alive(priv, IWL_UCODE_REGULAR);
		if (status) {
			IWL_ERR(priv,
				"Error loading runtime ucode: %d\n", status);
			break;
		}
		status = iwl_alive_start(priv);
		if (status)
			IWL_ERR(priv,
				"Error starting the device: %d\n", status);
		break;

	case IWL_TM_CMD_APP2DEV_LOAD_WOWLAN_FW:
		iwl_scan_cancel_timeout(priv, 200);
		priv->ucode_loaded = false;
		iwl_trans_stop_device(trans);
		status = iwl_load_ucode_wait_alive(priv, IWL_UCODE_WOWLAN);
		if (status) {
			IWL_ERR(priv,
				"Error loading WOWLAN ucode: %d\n", status);
			break;
		}
		status = iwl_alive_start(priv);
		if (status)
			IWL_ERR(priv,
				"Error starting the device: %d\n", status);
		break;

	case IWL_TM_CMD_APP2DEV_GET_EEPROM:
		if (priv->shrd->eeprom) {
			skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
				cfg(priv)->base_params->eeprom_size + 20);
			if (!skb) {
				IWL_ERR(priv, "Memory allocation fail\n");
				return -ENOMEM;
			}
			NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND,
				IWL_TM_CMD_DEV2APP_EEPROM_RSP);
			NLA_PUT(skb, IWL_TM_ATTR_EEPROM,
				cfg(priv)->base_params->eeprom_size,
				priv->shrd->eeprom);
			status = cfg80211_testmode_reply(skb);
			if (status < 0)
				IWL_ERR(priv, "Error sending msg : %d\n",
					status);
		} else
			return -EFAULT;
		break;

	case IWL_TM_CMD_APP2DEV_FIXRATE_REQ:
		if (!tb[IWL_TM_ATTR_FIXRATE]) {
			IWL_ERR(priv, "Missing fixrate setting\n");
			return -ENOMSG;
		}
		priv->tm_fixed_rate = nla_get_u32(tb[IWL_TM_ATTR_FIXRATE]);
		break;

	case IWL_TM_CMD_APP2DEV_GET_FW_VERSION:
		IWL_INFO(priv, "uCode version raw: 0x%x\n",
			 priv->fw->ucode_ver);

		skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
		if (!skb) {
			IWL_ERR(priv, "Memory allocation fail\n");
			return -ENOMEM;
		}
		NLA_PUT_U32(skb, IWL_TM_ATTR_FW_VERSION,
			    priv->fw->ucode_ver);
		status = cfg80211_testmode_reply(skb);
		if (status < 0)
			IWL_ERR(priv, "Error sending msg : %d\n", status);
		break;

	case IWL_TM_CMD_APP2DEV_GET_DEVICE_ID:
		devid = trans(priv)->hw_id;
		IWL_INFO(priv, "hw version: 0x%x\n", devid);

		skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
		if (!skb) {
			IWL_ERR(priv, "Memory allocation fail\n");
			return -ENOMEM;
		}
		NLA_PUT_U32(skb, IWL_TM_ATTR_DEVICE_ID, devid);
		status = cfg80211_testmode_reply(skb);
		if (status < 0)
			IWL_ERR(priv, "Error sending msg : %d\n", status);
		break;

	case IWL_TM_CMD_APP2DEV_GET_FW_INFO:
		skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20 + 8);
		if (!skb) {
			IWL_ERR(priv, "Memory allocation fail\n");
			return -ENOMEM;
		}
		if (!priv->ucode_loaded) {
			IWL_ERR(priv, "No uCode has not been loaded\n");
			return -EINVAL;
		} else {
			img = &priv->fw->img[priv->shrd->ucode_type];
			inst_size = img->sec[IWL_UCODE_SECTION_INST].len;
			data_size = img->sec[IWL_UCODE_SECTION_DATA].len;
		}
		NLA_PUT_U32(skb, IWL_TM_ATTR_FW_TYPE, priv->shrd->ucode_type);
		NLA_PUT_U32(skb, IWL_TM_ATTR_FW_INST_SIZE, inst_size);
		NLA_PUT_U32(skb, IWL_TM_ATTR_FW_DATA_SIZE, data_size);
		status = cfg80211_testmode_reply(skb);
		if (status < 0)
			IWL_ERR(priv, "Error sending msg : %d\n", status);
		break;

	default:
		IWL_ERR(priv, "Unknown testmode driver command ID\n");
		return -ENOSYS;
	}
	return status;

nla_put_failure:
	kfree_skb(skb);
	return -EMSGSIZE;
}