cmd.c revision 95dac04f881322b510c45e5ae83f0dbee4f823a2
1f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/*
2f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * This file is part of wl1271
3f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho *
42f826f55404ca43efced94d548356182820e764fLuciano Coelho * Copyright (C) 2009-2010 Nokia Corporation
5f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho *
6f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * Contact: Luciano Coelho <luciano.coelho@nokia.com>
7f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho *
8f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * This program is free software; you can redistribute it and/or
9f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * modify it under the terms of the GNU General Public License
10f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * version 2 as published by the Free Software Foundation.
11f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho *
12f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * This program is distributed in the hope that it will be useful, but
13f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * WITHOUT ANY WARRANTY; without even the implied warranty of
14f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * General Public License for more details.
16f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho *
17f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * You should have received a copy of the GNU General Public License
18f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * along with this program; if not, write to the Free Software
19f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * 02110-1301 USA
21f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho *
22f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */
23f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
24f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho#include <linux/module.h>
25f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho#include <linux/platform_device.h>
26f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho#include <linux/spi/spi.h>
27f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho#include <linux/etherdevice.h>
28023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo#include <linux/ieee80211.h>
295a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
30f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
3100d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "wl12xx.h"
3200d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "reg.h"
3300d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "io.h"
3400d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "acx.h"
35f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho#include "wl12xx_80211.h"
3600d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "cmd.h"
3700d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "event.h"
3898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov#include "tx.h"
39f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
4016092b5cccd6f3a8d1957ca004c97947e07018dbJuuso Oikarinen#define WL1271_CMD_FAST_POLL_COUNT       50
41f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
42f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/*
43f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * send command to firmware
44f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho *
45f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @wl: wl struct
46f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @id: command id
47f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @buf: buffer containing the command, must work with dma
48f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @len: length of the buffer
49f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */
50fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinenint wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
51fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen		    size_t res_len)
52f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
53f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct wl1271_cmd_header *cmd;
54f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	unsigned long timeout;
55f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	u32 intr;
56f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret = 0;
57ad150e966e987edcf737e1871d9e44a30d1aa58dJuuso Oikarinen	u16 status;
58bc0f03ea579d78f845a44a0c611806da64057b03Saravanan Dhanabal	u16 poll_count = 0;
59f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
60f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd = buf;
61d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	cmd->id = cpu_to_le16(id);
62f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->status = 0;
63f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
64f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	WARN_ON(len % 4 != 0);
6524225b37bd78d3e2edaa1a39316c54786adaa465Arik Nemtsov	WARN_ON(test_bit(WL1271_FLAG_IN_ELP, &wl->flags));
66f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
677b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi	wl1271_write(wl, wl->cmd_box_addr, buf, len, false);
68f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
697b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi	wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
70f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
71f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT);
72f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
737b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi	intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
74f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) {
75f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		if (time_after(jiffies, timeout)) {
76f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho			wl1271_error("command complete timeout");
77f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho			ret = -ETIMEDOUT;
78f482b76202f4ac0f62a77b0e55ac1a1cfe480e2bArik Nemtsov			goto fail;
79f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		}
80f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
81bc0f03ea579d78f845a44a0c611806da64057b03Saravanan Dhanabal		poll_count++;
8216092b5cccd6f3a8d1957ca004c97947e07018dbJuuso Oikarinen		if (poll_count < WL1271_CMD_FAST_POLL_COUNT)
8316092b5cccd6f3a8d1957ca004c97947e07018dbJuuso Oikarinen			udelay(10);
8416092b5cccd6f3a8d1957ca004c97947e07018dbJuuso Oikarinen		else
8516092b5cccd6f3a8d1957ca004c97947e07018dbJuuso Oikarinen			msleep(1);
86f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
877b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi		intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
88f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
89f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
903b775b4b27818130291e7716f3ce1e24664004c9Juuso Oikarinen	/* read back the status code of the command */
91fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	if (res_len == 0)
92fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen		res_len = sizeof(struct wl1271_cmd_header);
937b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi	wl1271_read(wl, wl->cmd_box_addr, cmd, res_len, false);
943b775b4b27818130291e7716f3ce1e24664004c9Juuso Oikarinen
95ad150e966e987edcf737e1871d9e44a30d1aa58dJuuso Oikarinen	status = le16_to_cpu(cmd->status);
96ad150e966e987edcf737e1871d9e44a30d1aa58dJuuso Oikarinen	if (status != CMD_STATUS_SUCCESS) {
97ad150e966e987edcf737e1871d9e44a30d1aa58dJuuso Oikarinen		wl1271_error("command execute failure %d", status);
983b775b4b27818130291e7716f3ce1e24664004c9Juuso Oikarinen		ret = -EIO;
99f482b76202f4ac0f62a77b0e55ac1a1cfe480e2bArik Nemtsov		goto fail;
1003b775b4b27818130291e7716f3ce1e24664004c9Juuso Oikarinen	}
1013b775b4b27818130291e7716f3ce1e24664004c9Juuso Oikarinen
1027b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi	wl1271_write32(wl, ACX_REG_INTERRUPT_ACK,
1037b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi		       WL1271_ACX_INTR_CMD_COMPLETE);
104f482b76202f4ac0f62a77b0e55ac1a1cfe480e2bArik Nemtsov	return 0;
105f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
106f482b76202f4ac0f62a77b0e55ac1a1cfe480e2bArik Nemtsovfail:
107f482b76202f4ac0f62a77b0e55ac1a1cfe480e2bArik Nemtsov	WARN_ON(1);
108baacb9aed020b890ddf6a57837a169092a25fc9bIdo Yariv	wl12xx_queue_recovery_work(wl);
109f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
110f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
111f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
11298b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelhoint wl1271_cmd_general_parms(struct wl1271 *wl)
11398b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho{
11498b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	struct wl1271_general_parms_cmd *gen_parms;
11549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	struct wl1271_ini_general_params *gp =
11649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		&((struct wl1271_nvs_file *)wl->nvs)->general_params;
11749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	bool answer = false;
11849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	int ret;
11949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
12049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	if (!wl->nvs)
12149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		return -ENODEV;
12249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
12349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
12449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	if (!gen_parms)
12549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		return -ENOMEM;
12649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
12749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM;
12849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
12949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	memcpy(&gen_parms->general_params, gp, sizeof(*gp));
13049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
13149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	if (gp->tx_bip_fem_auto_detect)
13249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		answer = true;
13349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
134b03acadea4f46884aa3c3e4d3a6ce03d283525e6Shahar Levi	/* Override the REF CLK from the NVS with the one from platform data */
135b03acadea4f46884aa3c3e4d3a6ce03d283525e6Shahar Levi	gen_parms->general_params.ref_clock = wl->ref_clock;
136b03acadea4f46884aa3c3e4d3a6ce03d283525e6Shahar Levi
1370c005048aa3cd3ac7bfdd3c6fcc20ea4f0ab667dShahar Levi	/* LPD mode enable (bits 6-7) in WL1271 AP mode only */
1380c005048aa3cd3ac7bfdd3c6fcc20ea4f0ab667dShahar Levi	if (wl->quirks & WL12XX_QUIRK_LPD_MODE)
1390c005048aa3cd3ac7bfdd3c6fcc20ea4f0ab667dShahar Levi		gen_parms->general_params.general_settings |=
1400c005048aa3cd3ac7bfdd3c6fcc20ea4f0ab667dShahar Levi			GENERAL_SETTINGS_DRPW_LPD;
1410c005048aa3cd3ac7bfdd3c6fcc20ea4f0ab667dShahar Levi
14249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
14349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	if (ret < 0) {
14449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
14549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		goto out;
14649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	}
14749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
14849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	gp->tx_bip_fem_manufacturer =
14949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		gen_parms->general_params.tx_bip_fem_manufacturer;
15049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
15149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n",
15249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		     answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer);
15349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
15449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Leviout:
15549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	kfree(gen_parms);
15649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	return ret;
15749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi}
15849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
15949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Leviint wl128x_cmd_general_parms(struct wl1271 *wl)
16049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi{
16149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	struct wl128x_general_parms_cmd *gen_parms;
16249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	struct wl128x_ini_general_params *gp =
16349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		&((struct wl128x_nvs_file *)wl->nvs)->general_params;
1644b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	bool answer = false;
16598b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	int ret;
16698b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
167152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen	if (!wl->nvs)
168152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen		return -ENODEV;
169152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen
17098b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
17198b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	if (!gen_parms)
17298b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho		return -ENOMEM;
17398b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
17498b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM;
17598b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
1764b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	memcpy(&gen_parms->general_params, gp, sizeof(*gp));
1774b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen
1784b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	if (gp->tx_bip_fem_auto_detect)
1794b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen		answer = true;
18076c0f8d396bd306111d349cfe770e1c4fcf70248Luciano Coelho
181b03acadea4f46884aa3c3e4d3a6ce03d283525e6Shahar Levi	/* Replace REF and TCXO CLKs with the ones from platform data */
182b03acadea4f46884aa3c3e4d3a6ce03d283525e6Shahar Levi	gen_parms->general_params.ref_clock = wl->ref_clock;
183b03acadea4f46884aa3c3e4d3a6ce03d283525e6Shahar Levi	gen_parms->general_params.tcxo_ref_clock = wl->tcxo_clock;
184b03acadea4f46884aa3c3e4d3a6ce03d283525e6Shahar Levi
1854b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
1864b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	if (ret < 0) {
18798b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho		wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
1884b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen		goto out;
1894b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	}
19098b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
1914b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	gp->tx_bip_fem_manufacturer =
1924b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen		gen_parms->general_params.tx_bip_fem_manufacturer;
1934b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen
1944b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n",
1954b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen		     answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer);
1964b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen
1974b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinenout:
19898b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	kfree(gen_parms);
19998b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	return ret;
20098b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho}
20198b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
20298b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelhoint wl1271_cmd_radio_parms(struct wl1271 *wl)
20398b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho{
204bc765bf3b9a095b3e41c8cda80643901884c3dd4Shahar Levi	struct wl1271_nvs_file *nvs = (struct wl1271_nvs_file *)wl->nvs;
20598b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	struct wl1271_radio_parms_cmd *radio_parms;
206bc765bf3b9a095b3e41c8cda80643901884c3dd4Shahar Levi	struct wl1271_ini_general_params *gp = &nvs->general_params;
207152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen	int ret;
208152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen
209152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen	if (!wl->nvs)
210152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen		return -ENODEV;
21198b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
21298b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL);
21398b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	if (!radio_parms)
21498b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho		return -ENOMEM;
21598b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
21698b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
21798b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
218a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen	/* 2.4GHz parameters */
219bc765bf3b9a095b3e41c8cda80643901884c3dd4Shahar Levi	memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2,
220eb70eb723b489dd4e233e22e47d993f59858cdd8Juuso Oikarinen	       sizeof(struct wl1271_ini_band_params_2));
221eb70eb723b489dd4e233e22e47d993f59858cdd8Juuso Oikarinen	memcpy(&radio_parms->dyn_params_2,
222bc765bf3b9a095b3e41c8cda80643901884c3dd4Shahar Levi	       &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params,
223eb70eb723b489dd4e233e22e47d993f59858cdd8Juuso Oikarinen	       sizeof(struct wl1271_ini_fem_params_2));
224152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen
225a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen	/* 5GHz parameters */
226a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen	memcpy(&radio_parms->static_params_5,
227bc765bf3b9a095b3e41c8cda80643901884c3dd4Shahar Levi	       &nvs->stat_radio_params_5,
228a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen	       sizeof(struct wl1271_ini_band_params_5));
229a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen	memcpy(&radio_parms->dyn_params_5,
230bc765bf3b9a095b3e41c8cda80643901884c3dd4Shahar Levi	       &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params,
231a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen	       sizeof(struct wl1271_ini_fem_params_5));
23298b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
23398b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
23498b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho		    radio_parms, sizeof(*radio_parms));
23598b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
23698b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0);
23798b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	if (ret < 0)
23898b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho		wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed");
23998b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
24098b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	kfree(radio_parms);
24198b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	return ret;
24298b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho}
24398b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
24449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Leviint wl128x_cmd_radio_parms(struct wl1271 *wl)
24549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi{
24649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs;
24749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	struct wl128x_radio_parms_cmd *radio_parms;
24849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	struct wl128x_ini_general_params *gp = &nvs->general_params;
24949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	int ret;
25049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
25149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	if (!wl->nvs)
25249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		return -ENODEV;
25349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
25449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL);
25549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	if (!radio_parms)
25649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		return -ENOMEM;
25749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
25849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
25949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
26049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	/* 2.4GHz parameters */
26149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2,
26249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	       sizeof(struct wl128x_ini_band_params_2));
26349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	memcpy(&radio_parms->dyn_params_2,
26449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	       &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params,
26549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	       sizeof(struct wl128x_ini_fem_params_2));
26649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
26749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	/* 5GHz parameters */
26849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	memcpy(&radio_parms->static_params_5,
26949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	       &nvs->stat_radio_params_5,
27049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	       sizeof(struct wl128x_ini_band_params_5));
27149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	memcpy(&radio_parms->dyn_params_5,
27249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	       &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params,
27349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	       sizeof(struct wl128x_ini_fem_params_5));
27449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
27549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	radio_parms->fem_vendor_and_options = nvs->fem_vendor_and_options;
27649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
27749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
27849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		    radio_parms, sizeof(*radio_parms));
27949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
28049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0);
28198b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	if (ret < 0)
28298b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho		wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed");
28398b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
28498b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	kfree(radio_parms);
28598b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	return ret;
28698b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho}
28798b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
288644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinenint wl1271_cmd_ext_radio_parms(struct wl1271 *wl)
289644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen{
290644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	struct wl1271_ext_radio_parms_cmd *ext_radio_parms;
291644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	struct conf_rf_settings *rf = &wl->conf.rf;
292644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	int ret;
293644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
294644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	if (!wl->nvs)
295644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen		return -ENODEV;
296644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
297644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	ext_radio_parms = kzalloc(sizeof(*ext_radio_parms), GFP_KERNEL);
298644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	if (!ext_radio_parms)
299644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen		return -ENOMEM;
300644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
301644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	ext_radio_parms->test.id = TEST_CMD_INI_FILE_RF_EXTENDED_PARAM;
302644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
303644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	memcpy(ext_radio_parms->tx_per_channel_power_compensation_2,
304644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	       rf->tx_per_channel_power_compensation_2,
305644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	       CONF_TX_PWR_COMPENSATION_LEN_2);
306644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	memcpy(ext_radio_parms->tx_per_channel_power_compensation_5,
307644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	       rf->tx_per_channel_power_compensation_5,
308644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	       CONF_TX_PWR_COMPENSATION_LEN_5);
309644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
310644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_EXT_RADIO_PARAM: ",
311644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen		    ext_radio_parms, sizeof(*ext_radio_parms));
312644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
313644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	ret = wl1271_cmd_test(wl, ext_radio_parms, sizeof(*ext_radio_parms), 0);
314644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	if (ret < 0)
315644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen		wl1271_warning("TEST_CMD_INI_FILE_RF_EXTENDED_PARAM failed");
316644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
317644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	kfree(ext_radio_parms);
318644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	return ret;
319644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen}
320644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
32199d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho/*
32299d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho * Poll the mailbox event field until any of the bits in the mask is set or a
32399d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho * timeout occurs (WL1271_EVENT_TIMEOUT in msecs)
32499d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho */
32505285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsovstatic int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask)
32699d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho{
32799d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	u32 events_vector, event;
32899d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	unsigned long timeout;
32999d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho
33099d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT);
33199d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho
33299d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	do {
33352b0e7a61fd4b67fe8efe295297d8549f052f786Juuso Oikarinen		if (time_after(jiffies, timeout)) {
33405285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov			wl1271_debug(DEBUG_CMD, "timeout waiting for event %d",
33505285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov				     (int)mask);
33699d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho			return -ETIMEDOUT;
33752b0e7a61fd4b67fe8efe295297d8549f052f786Juuso Oikarinen		}
33899d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho
33999d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho		msleep(1);
34099d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho
34199d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho		/* read from both event fields */
34299d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho		wl1271_read(wl, wl->mbox_ptr[0], &events_vector,
34399d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho			    sizeof(events_vector), false);
34499d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho		event = events_vector & mask;
34599d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho		wl1271_read(wl, wl->mbox_ptr[1], &events_vector,
34699d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho			    sizeof(events_vector), false);
34799d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho		event |= events_vector & mask;
34899d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	} while (!event);
34999d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho
35099d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	return 0;
35199d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho}
35299d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho
35305285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsovstatic int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
35405285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov{
35505285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	int ret;
35605285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov
35705285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask);
35805285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	if (ret != 0) {
359baacb9aed020b890ddf6a57837a169092a25fc9bIdo Yariv		wl12xx_queue_recovery_work(wl);
36005285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov		return ret;
36105285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	}
36205285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov
36305285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	return 0;
36405285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov}
36505285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov
36615305498a443c181c8fb5deafb94eae585fe3ad5Juuso Oikarinenint wl1271_cmd_join(struct wl1271 *wl, u8 bss_type)
367f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
368f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct wl1271_cmd_join *join;
369f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret, i;
370f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	u8 *bssid;
371f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
372f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	join = kzalloc(sizeof(*join), GFP_KERNEL);
373f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (!join) {
374f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		ret = -ENOMEM;
375f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
376f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
377f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
378f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd join");
379f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
380f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	/* Reverse order BSSID */
381f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	bssid = (u8 *) &join->bssid_lsb;
382f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	for (i = 0; i < ETH_ALEN; i++)
383f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		bssid[i] = wl->bssid[ETH_ALEN - i - 1];
384f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
385d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	join->rx_config_options = cpu_to_le32(wl->rx_config);
386d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	join->rx_filter_options = cpu_to_le32(wl->rx_filter);
38715305498a443c181c8fb5deafb94eae585fe3ad5Juuso Oikarinen	join->bss_type = bss_type;
38823a7a51c5a35b30aa3edcc31a6a57b01c523b4cdLuciano Coelho	join->basic_rate_set = cpu_to_le32(wl->basic_rate_set);
38972c2d9e511846a4f2759389b38ed8a5553579eb3Eliad Peller	join->supported_rate_set = cpu_to_le32(wl->rate_set);
390f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
391ebba60c66b3aa321a84c9a90a343c91fde972066Juuso Oikarinen	if (wl->band == IEEE80211_BAND_5GHZ)
392a410264553447ff90bf13e3662684e794e5ff83eTeemu Paasikivi		join->bss_type |= WL1271_JOIN_CMD_BSS_TYPE_5GHZ;
393f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
39460e84c2ebb7b04361cf1ba0d325cc93366bd04a6Juuso Oikarinen	join->beacon_interval = cpu_to_le16(wl->beacon_int);
395ae751bab9f55c3152ebf713c89a4fb6f439c2575Luciano Coelho	join->dtim_interval = WL1271_DEFAULT_DTIM_PERIOD;
396a410264553447ff90bf13e3662684e794e5ff83eTeemu Paasikivi
397f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	join->channel = wl->channel;
398f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	join->ssid_len = wl->ssid_len;
399f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	memcpy(join->ssid, wl->ssid, wl->ssid_len);
400f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
401f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET;
402f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
403ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen	/* reset TX security counters */
404ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen	wl->tx_security_last_seq = 0;
40504e36fc5f1ff4e349ea21de8d15e4e1844d04197Juuso Oikarinen	wl->tx_security_seq = 0;
406f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
40772c2d9e511846a4f2759389b38ed8a5553579eb3Eliad Peller	wl1271_debug(DEBUG_CMD, "cmd join: basic_rate_set=0x%x, rate_set=0x%x",
40872c2d9e511846a4f2759389b38ed8a5553579eb3Eliad Peller		join->basic_rate_set, join->supported_rate_set);
40972c2d9e511846a4f2759389b38ed8a5553579eb3Eliad Peller
410fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join), 0);
411f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
412f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_error("failed to initiate cmd join");
413f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out_free;
414f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
415f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
41699d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	ret = wl1271_cmd_wait_for_event(wl, JOIN_EVENT_COMPLETE_ID);
41799d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	if (ret < 0)
41899d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho		wl1271_error("cmd join event completion error");
419f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
420f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout_free:
421f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	kfree(join);
422f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
423f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout:
424f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
425f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
426f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
427f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/**
428f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * send test command to firmware
429f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho *
430f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @wl: wl struct
431f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @buf: buffer containing the command, with all headers, must work with dma
432f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @len: length of the buffer
433f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @answer: is answer needed
434f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */
435f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer)
436f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
437f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret;
438fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	size_t res_len = 0;
439f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
440f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd test");
441f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
442fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	if (answer)
443fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen		res_len = buf_len;
444fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen
445fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_TEST, buf, buf_len, res_len);
446f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
447f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
448f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_warning("TEST command failed");
449f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		return ret;
450f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
451f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
452fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	return ret;
453f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
454f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
455f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/**
456f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * read acx from firmware
457f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho *
458f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @wl: wl struct
459f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @id: acx id
460f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @buf: buffer for the response, including all headers, must work with dma
46125985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * @len: length of buf
462f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */
463f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len)
464f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
465f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct acx_header *acx = buf;
466f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret;
467f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
468f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd interrogate");
469f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
470d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	acx->id = cpu_to_le16(id);
471f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
472f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	/* payload length, does not include any headers */
473d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	acx->len = cpu_to_le16(len - sizeof(*acx));
474f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
475fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx), len);
476fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	if (ret < 0)
477f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_error("INTERROGATE command failed");
478f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
479f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
480f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
481f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
482f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/**
483f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * write acx value to firmware
484f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho *
485f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @wl: wl struct
486f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @id: acx id
487f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @buf: buffer containing acx, including all headers, must work with dma
488f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @len: length of buf
489f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */
490f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len)
491f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
492f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct acx_header *acx = buf;
493f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret;
494f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
495f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd configure");
496f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
497d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	acx->id = cpu_to_le16(id);
498f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
499f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	/* payload length, does not include any headers */
500d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	acx->len = cpu_to_le16(len - sizeof(*acx));
501f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
502fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len, 0);
503f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
504f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_warning("CONFIGURE command NOK");
505f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		return ret;
506f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
507f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
508f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return 0;
509f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
510f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
51194210897e2b7df8446fdecd360342149e5b4a400Luciano Coelhoint wl1271_cmd_data_path(struct wl1271 *wl, bool enable)
512f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
513f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct cmd_enabledisable_path *cmd;
514f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret;
515f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	u16 cmd_rx, cmd_tx;
516f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
517f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd data path");
518f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
519f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
520f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (!cmd) {
521f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		ret = -ENOMEM;
522f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
523f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
524f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
52594210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho	/* the channel here is only used for calibration, so hardcoded to 1 */
52694210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho	cmd->channel = 1;
527f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
528f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (enable) {
529f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		cmd_rx = CMD_ENABLE_RX;
530f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		cmd_tx = CMD_ENABLE_TX;
531f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	} else {
532f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		cmd_rx = CMD_DISABLE_RX;
533f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		cmd_tx = CMD_DISABLE_TX;
534f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
535f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
536fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd), 0);
537f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
538f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_error("rx %s cmd for channel %d failed",
53994210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho			     enable ? "start" : "stop", cmd->channel);
540f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
541f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
542f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
543f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d",
54494210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho		     enable ? "start" : "stop", cmd->channel);
545f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
546fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd), 0);
547f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
548f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_error("tx %s cmd for channel %d failed",
54994210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho			     enable ? "start" : "stop", cmd->channel);
5501b00f2b560028a68cdbc57a0352163afd79822ddJuuso Oikarinen		goto out;
551f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
552f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
553f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d",
55494210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho		     enable ? "start" : "stop", cmd->channel);
555f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
556f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout:
557f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	kfree(cmd);
558f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
559f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
560f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
561c8bde243421d759844264cf11e4248e7862c2722Eliad Pellerint wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode)
562f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
563f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct wl1271_cmd_ps_params *ps_params = NULL;
564f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret = 0;
565f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
566f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd set ps mode");
567f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
568f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL);
569f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (!ps_params) {
570f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		ret = -ENOMEM;
571f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
572f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
573f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
574f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	ps_params->ps_mode = ps_mode;
575f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
576f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
577fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen			      sizeof(*ps_params), 0);
578f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
579f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_error("cmd set_ps_mode failed");
580f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
581f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
582f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
583f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout:
584f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	kfree(ps_params);
585f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
586f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
587f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
588f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
589606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen			    void *buf, size_t buf_len, int index, u32 rates)
590f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
591f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct wl1271_cmd_template_set *cmd;
592f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret = 0;
593f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
594f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd template_set %d", template_id);
595f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
596f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	WARN_ON(buf_len > WL1271_CMD_TEMPL_MAX_SIZE);
597f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	buf_len = min_t(size_t, buf_len, WL1271_CMD_TEMPL_MAX_SIZE);
598f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
599f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
600f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (!cmd) {
601f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		ret = -ENOMEM;
602f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
603f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
604f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
605f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->len = cpu_to_le16(buf_len);
606f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->template_type = template_id;
607606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen	cmd->enabled_rates = cpu_to_le32(rates);
6081e05a81888318752e9a6d2158a95ddd6442ae117Arik Nemtsov	cmd->short_retry_limit = wl->conf.tx.tmpl_short_retry_limit;
6091e05a81888318752e9a6d2158a95ddd6442ae117Arik Nemtsov	cmd->long_retry_limit = wl->conf.tx.tmpl_long_retry_limit;
610bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	cmd->index = index;
611f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
612f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (buf)
613f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		memcpy(cmd->template_data, buf, buf_len);
614f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
615fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_SET_TEMPLATE, cmd, sizeof(*cmd), 0);
616f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
617f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_warning("cmd set_template failed: %d", ret);
618f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out_free;
619f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
620f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
621f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout_free:
622f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	kfree(cmd);
623f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
624f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout:
625f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
626f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
627f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
628f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_build_null_data(struct wl1271 *wl)
629f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
630a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	struct sk_buff *skb = NULL;
631a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	int size;
632a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	void *ptr;
633a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	int ret = -ENOMEM;
634f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
635f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
636a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	if (wl->bss_type == BSS_TYPE_IBSS) {
637a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen		size = sizeof(struct wl12xx_null_data_template);
638a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen		ptr = NULL;
639a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	} else {
640a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen		skb = ieee80211_nullfunc_get(wl->hw, wl->vif);
641a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen		if (!skb)
642a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen			goto out;
643a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen		size = skb->len;
644a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen		ptr = skb->data;
645a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	}
646a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen
647606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, ptr, size, 0,
6488eab7b4708b5ef4701ecbe5d659f99743b77b668Juuso Oikarinen				      wl->basic_rate);
649f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
650899e6e65c39990a76c17940625dbe6001f618734Kalle Valoout:
651899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	dev_kfree_skb(skb);
652a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	if (ret)
653a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen		wl1271_warning("cmd buld null data failed %d", ret);
654a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen
655899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	return ret;
656f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
657f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
658f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
659bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinenint wl1271_cmd_build_klv_null_data(struct wl1271 *wl)
660bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen{
661bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	struct sk_buff *skb = NULL;
662bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	int ret = -ENOMEM;
663bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen
664bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	skb = ieee80211_nullfunc_get(wl->hw, wl->vif);
665bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	if (!skb)
666bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen		goto out;
667bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen
668bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV,
669bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen				      skb->data, skb->len,
670606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen				      CMD_TEMPL_KLV_IDX_NULL_DATA,
6718eab7b4708b5ef4701ecbe5d659f99743b77b668Juuso Oikarinen				      wl->basic_rate);
672bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen
673bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinenout:
674bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	dev_kfree_skb(skb);
675bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	if (ret)
676bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen		wl1271_warning("cmd build klv null data failed %d", ret);
677bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen
678bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	return ret;
679bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen
680bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen}
681bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen
682f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid)
683f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
684899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	struct sk_buff *skb;
685899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	int ret = 0;
686c3fea1994ac34dafa3ebb40d4f95354b2782af31Juuso Oikarinen
687899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	skb = ieee80211_pspoll_get(wl->hw, wl->vif);
688899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	if (!skb)
689899e6e65c39990a76c17940625dbe6001f618734Kalle Valo		goto out;
690f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
691899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, skb->data,
692849923f43ca681cc86a401178db31acb60e79f3bJuuso Oikarinen				      skb->len, 0, wl->basic_rate_set);
693f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
694899e6e65c39990a76c17940625dbe6001f618734Kalle Valoout:
695899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	dev_kfree_skb(skb);
696899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	return ret;
697f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
698f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
699818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valoint wl1271_cmd_build_probe_req(struct wl1271 *wl,
700818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo			       const u8 *ssid, size_t ssid_len,
701818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo			       const u8 *ie, size_t ie_len, u8 band)
702f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
703818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo	struct sk_buff *skb;
704abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi	int ret;
705f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
706818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo	skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len,
707818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo				     ie, ie_len);
708818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo	if (!skb) {
709818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo		ret = -ENOMEM;
710818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo		goto out;
711818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo	}
712818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo
713818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo	wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len);
714f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
715abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi	if (band == IEEE80211_BAND_2GHZ)
716abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi		ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
717606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen					      skb->data, skb->len, 0,
718606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen					      wl->conf.tx.basic_rate);
719abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi	else
720abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi		ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
721606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen					      skb->data, skb->len, 0,
722606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen					      wl->conf.tx.basic_rate_5);
723818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo
724818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valoout:
725818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo	dev_kfree_skb(skb);
726abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi	return ret;
727f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
728f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
7292f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinenstruct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
7302f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen					      struct sk_buff *skb)
7312f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen{
7322f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	int ret;
7332f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen
7342f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	if (!skb)
7352f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen		skb = ieee80211_ap_probereq_get(wl->hw, wl->vif);
7362f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	if (!skb)
7372f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen		goto out;
7382f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen
7392f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	wl1271_dump(DEBUG_SCAN, "AP PROBE REQ: ", skb->data, skb->len);
7402f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen
7412f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	if (wl->band == IEEE80211_BAND_2GHZ)
7422f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen		ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
7432f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen					      skb->data, skb->len, 0,
7442f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen					      wl->conf.tx.basic_rate);
7452f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	else
7462f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen		ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
7472f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen					      skb->data, skb->len, 0,
7482f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen					      wl->conf.tx.basic_rate_5);
7492f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen
7502f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	if (ret < 0)
7512f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen		wl1271_error("Unable to set ap probe request template.");
7522f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen
7532f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinenout:
7542f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	return skb;
7552f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen}
7562f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen
757c5312772156bb5f9b2e95e4c91526d578426a069Eliad Pellerint wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr)
758c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller{
759c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	int ret;
760c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	struct wl12xx_arp_rsp_template tmpl;
761c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	struct ieee80211_hdr_3addr *hdr;
762c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	struct arphdr *arp_hdr;
763c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
764c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	memset(&tmpl, 0, sizeof(tmpl));
765c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
766c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	/* mac80211 header */
767c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	hdr = &tmpl.hdr;
768c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
769c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller					 IEEE80211_STYPE_DATA |
770c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller					 IEEE80211_FCTL_TODS);
771c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	memcpy(hdr->addr1, wl->vif->bss_conf.bssid, ETH_ALEN);
772c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	memcpy(hdr->addr2, wl->vif->addr, ETH_ALEN);
773c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	memset(hdr->addr3, 0xff, ETH_ALEN);
774c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
775c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	/* llc layer */
776c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	memcpy(tmpl.llc_hdr, rfc1042_header, sizeof(rfc1042_header));
7776177eaea277527e48753d050723cd138494c98a8Eliad Peller	tmpl.llc_type = cpu_to_be16(ETH_P_ARP);
778c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
779c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	/* arp header */
780c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	arp_hdr = &tmpl.arp_hdr;
7816177eaea277527e48753d050723cd138494c98a8Eliad Peller	arp_hdr->ar_hrd = cpu_to_be16(ARPHRD_ETHER);
7826177eaea277527e48753d050723cd138494c98a8Eliad Peller	arp_hdr->ar_pro = cpu_to_be16(ETH_P_IP);
783c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	arp_hdr->ar_hln = ETH_ALEN;
784c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	arp_hdr->ar_pln = 4;
7856177eaea277527e48753d050723cd138494c98a8Eliad Peller	arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY);
786c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
787c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	/* arp payload */
788c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	memcpy(tmpl.sender_hw, wl->vif->addr, ETH_ALEN);
789c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	tmpl.sender_ip = ip_addr;
790c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
791c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP,
792c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller				      &tmpl, sizeof(tmpl), 0,
793c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller				      wl->basic_rate);
794c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
795c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	return ret;
796c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller}
797c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
798023e082609ba3225dbd5c33933a90156d2201d7fKalle Valoint wl1271_build_qos_null_data(struct wl1271 *wl)
799023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo{
800023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	struct ieee80211_qos_hdr template;
801023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo
802023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	memset(&template, 0, sizeof(template));
803023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo
804023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	memcpy(template.addr1, wl->bssid, ETH_ALEN);
805023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	memcpy(template.addr2, wl->mac_addr, ETH_ALEN);
806023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	memcpy(template.addr3, wl->bssid, ETH_ALEN);
807023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo
808023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	template.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
809023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo					     IEEE80211_STYPE_QOS_NULLFUNC |
810023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo					     IEEE80211_FCTL_TODS);
811023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo
812023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	/* FIXME: not sure what priority to use here */
813023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	template.qos_ctrl = cpu_to_le16(0);
814023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo
815023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	return wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, &template,
816606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen				       sizeof(template), 0,
8178eab7b4708b5ef4701ecbe5d659f99743b77b668Juuso Oikarinen				       wl->basic_rate);
818023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo}
819023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo
82098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovint wl1271_cmd_set_sta_default_wep_key(struct wl1271 *wl, u8 id)
821f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
82298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	struct wl1271_cmd_set_sta_keys *cmd;
823f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret = 0;
824f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
825f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id);
826f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
827f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
828f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (!cmd) {
829f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		ret = -ENOMEM;
830f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
831f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
832f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
833f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->id = id;
834d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	cmd->key_action = cpu_to_le16(KEY_SET_ID);
835f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->key_type = KEY_WEP;
836f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
837fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0);
838f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
839f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_warning("cmd set_default_wep_key failed: %d", ret);
840f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
841f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
842f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
843f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout:
844f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	kfree(cmd);
845f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
846f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
847f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
848f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
84998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovint wl1271_cmd_set_ap_default_wep_key(struct wl1271 *wl, u8 id)
85098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov{
85198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	struct wl1271_cmd_set_ap_keys *cmd;
85298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	int ret = 0;
85398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
85498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	wl1271_debug(DEBUG_CMD, "cmd set_ap_default_wep_key %d", id);
85598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
85698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
85798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (!cmd) {
85898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		ret = -ENOMEM;
85998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out;
86098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
86198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
86298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->hlid = WL1271_AP_BROADCAST_HLID;
86398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->key_id = id;
86498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->lid_key_type = WEP_DEFAULT_LID_TYPE;
86598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->key_action = cpu_to_le16(KEY_SET_ID);
86698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->key_type = KEY_WEP;
86798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
86898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0);
86998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (ret < 0) {
87098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		wl1271_warning("cmd set_ap_default_wep_key failed: %d", ret);
87198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out;
87298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
87398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
87498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout:
87598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	kfree(cmd);
87698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
87798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	return ret;
87898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov}
87998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
88098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovint wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
881ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen		       u8 key_size, const u8 *key, const u8 *addr,
882ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen		       u32 tx_seq_32, u16 tx_seq_16)
883f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
88498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	struct wl1271_cmd_set_sta_keys *cmd;
885f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret = 0;
886f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
887f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
888f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (!cmd) {
889f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		ret = -ENOMEM;
890f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
891f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
892f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
893f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (key_type != KEY_WEP)
894f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		memcpy(cmd->addr, addr, ETH_ALEN);
895f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
896d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	cmd->key_action = cpu_to_le16(action);
897f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->key_size = key_size;
898f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->key_type = key_type;
899f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
900d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16);
901d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32);
902ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen
903f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	/* we have only one SSID profile */
904f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->ssid_profile = 0;
905f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
906f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->id = id;
907f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
908f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (key_type == KEY_TKIP) {
909f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		/*
910f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		 * We get the key in the following form:
911f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		 * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes)
912f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		 * but the target is expecting:
913f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		 * TKIP - RX MIC - TX MIC
914f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		 */
915f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		memcpy(cmd->key, key, 16);
916f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		memcpy(cmd->key + 16, key + 24, 8);
917f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		memcpy(cmd->key + 24, key + 16, 8);
918f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
919f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	} else {
920f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		memcpy(cmd->key, key, key_size);
921f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
922f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
923f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_dump(DEBUG_CRYPT, "TARGET KEY: ", cmd, sizeof(*cmd));
924f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
925fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0);
926f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
927f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_warning("could not set keys");
928152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen	goto out;
929f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
930f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
931f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout:
932f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	kfree(cmd);
933f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
934f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
935f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
93625a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho
93798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovint wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
93898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov			u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
93998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov			u16 tx_seq_16)
94098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov{
94198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	struct wl1271_cmd_set_ap_keys *cmd;
94298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	int ret = 0;
94398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	u8 lid_type;
94498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
94598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
94698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (!cmd)
94798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		return -ENOMEM;
94898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
94998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (hlid == WL1271_AP_BROADCAST_HLID) {
95098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		if (key_type == KEY_WEP)
95198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov			lid_type = WEP_DEFAULT_LID_TYPE;
95298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		else
95398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov			lid_type = BROADCAST_LID_TYPE;
95498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	} else {
95598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		lid_type = UNICAST_LID_TYPE;
95698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
95798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
95898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	wl1271_debug(DEBUG_CRYPT, "ap key action: %d id: %d lid: %d type: %d"
95998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		     " hlid: %d", (int)action, (int)id, (int)lid_type,
96098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		     (int)key_type, (int)hlid);
96198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
96298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->lid_key_type = lid_type;
96398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->hlid = hlid;
96498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->key_action = cpu_to_le16(action);
96598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->key_size = key_size;
96698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->key_type = key_type;
96798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->key_id = id;
96898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16);
96998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32);
97098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
97198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (key_type == KEY_TKIP) {
97298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		/*
97398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		 * We get the key in the following form:
97498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		 * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes)
97598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		 * but the target is expecting:
97698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		 * TKIP - RX MIC - TX MIC
97798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		 */
97898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		memcpy(cmd->key, key, 16);
97998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		memcpy(cmd->key + 16, key + 24, 8);
98098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		memcpy(cmd->key + 24, key + 16, 8);
98198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	} else {
98298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		memcpy(cmd->key, key, key_size);
98398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
98498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
98598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	wl1271_dump(DEBUG_CRYPT, "TARGET AP KEY: ", cmd, sizeof(*cmd));
98698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
98798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0);
98898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (ret < 0) {
98998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		wl1271_warning("could not set ap keys");
99098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out;
99198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
99298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
99398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout:
99498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	kfree(cmd);
99598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	return ret;
99698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov}
99798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
99825a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelhoint wl1271_cmd_disconnect(struct wl1271 *wl)
99925a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho{
100025a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	struct wl1271_cmd_disconnect *cmd;
100125a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	int ret = 0;
100225a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho
100325a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd disconnect");
100425a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho
100525a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
100625a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	if (!cmd) {
100725a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho		ret = -ENOMEM;
100825a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho		goto out;
100925a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	}
101025a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho
1011d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	cmd->rx_config_options = cpu_to_le32(wl->rx_config);
1012d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	cmd->rx_filter_options = cpu_to_le32(wl->rx_filter);
101325a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	/* disconnect reason is not used in immediate disconnections */
101425a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	cmd->type = DISCONNECT_IMMEDIATE;
101525a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho
1016fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_DISCONNECT, cmd, sizeof(*cmd), 0);
101725a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	if (ret < 0) {
101825a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho		wl1271_error("failed to send disconnect command");
101925a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho		goto out_free;
102025a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	}
102125a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho
10222f826f55404ca43efced94d548356182820e764fLuciano Coelho	ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID);
10232f826f55404ca43efced94d548356182820e764fLuciano Coelho	if (ret < 0)
10242f826f55404ca43efced94d548356182820e764fLuciano Coelho		wl1271_error("cmd disconnect event completion error");
10252f826f55404ca43efced94d548356182820e764fLuciano Coelho
102625a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelhoout_free:
102725a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	kfree(cmd);
102825a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho
102925a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelhoout:
103025a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	return ret;
103125a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho}
1032be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen
1033be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinenint wl1271_cmd_set_sta_state(struct wl1271 *wl)
1034be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen{
1035be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	struct wl1271_cmd_set_sta_state *cmd;
1036be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	int ret = 0;
1037be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen
1038be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	wl1271_debug(DEBUG_CMD, "cmd set sta state");
1039be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen
1040be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1041be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	if (!cmd) {
1042be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen		ret = -ENOMEM;
1043be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen		goto out;
1044be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	}
1045be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen
1046be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	cmd->state = WL1271_CMD_STA_STATE_CONNECTED;
1047be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen
1048be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_SET_STA_STATE, cmd, sizeof(*cmd), 0);
1049be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	if (ret < 0) {
1050be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen		wl1271_error("failed to send set STA state command");
1051be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen		goto out_free;
1052be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	}
1053be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen
1054be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinenout_free:
1055be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	kfree(cmd);
1056be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen
1057be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinenout:
1058be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	return ret;
1059be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen}
106098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
106198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovint wl1271_cmd_start_bss(struct wl1271 *wl)
106298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov{
106398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	struct wl1271_cmd_bss_start *cmd;
106498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
106598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	int ret;
106698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
106798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	wl1271_debug(DEBUG_CMD, "cmd start bss");
106898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
106998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	/*
107098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	 * FIXME: We currently do not support hidden SSID. The real SSID
107198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	 * should be fetched from mac80211 first.
107298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	 */
107398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (wl->ssid_len == 0) {
107498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		wl1271_warning("Hidden SSID currently not supported for AP");
107598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		ret = -EINVAL;
107698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out;
107798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
107898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
107998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
108098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (!cmd) {
108198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		ret = -ENOMEM;
108298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out;
108398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
108498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
108598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	memcpy(cmd->bssid, bss_conf->bssid, ETH_ALEN);
108698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
108725eaea30cd7b009ba2ca693708330d2f395cbc4dLuciano Coelho	cmd->aging_period = cpu_to_le16(WL1271_AP_DEF_INACTIV_SEC);
108898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->bss_index = WL1271_AP_BSS_INDEX;
108998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->global_hlid = WL1271_AP_GLOBAL_HLID;
109098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->broadcast_hlid = WL1271_AP_BROADCAST_HLID;
109198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->basic_rate_set = cpu_to_le32(wl->basic_rate_set);
109298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->beacon_interval = cpu_to_le16(wl->beacon_int);
109398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->dtim_interval = bss_conf->dtim_period;
109498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->beacon_expiry = WL1271_AP_DEF_BEACON_EXP;
109598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->channel = wl->channel;
109698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->ssid_len = wl->ssid_len;
109798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->ssid_type = SSID_TYPE_PUBLIC;
109898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	memcpy(cmd->ssid, wl->ssid, wl->ssid_len);
109998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
110098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	switch (wl->band) {
110198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	case IEEE80211_BAND_2GHZ:
110298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		cmd->band = RADIO_BAND_2_4GHZ;
110398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		break;
110498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	case IEEE80211_BAND_5GHZ:
110598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		cmd->band = RADIO_BAND_5GHZ;
110698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		break;
110798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	default:
110898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		wl1271_warning("bss start - unknown band: %d", (int)wl->band);
110998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		cmd->band = RADIO_BAND_2_4GHZ;
111098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		break;
111198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
111298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
111398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	ret = wl1271_cmd_send(wl, CMD_BSS_START, cmd, sizeof(*cmd), 0);
111498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (ret < 0) {
111598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		wl1271_error("failed to initiate cmd start bss");
111698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out_free;
111798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
111898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
111998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout_free:
112098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	kfree(cmd);
112198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
112298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout:
112398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	return ret;
112498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov}
112598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
112698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovint wl1271_cmd_stop_bss(struct wl1271 *wl)
112798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov{
112898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	struct wl1271_cmd_bss_start *cmd;
112998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	int ret;
113098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
113198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	wl1271_debug(DEBUG_CMD, "cmd stop bss");
113298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
113398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
113498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (!cmd) {
113598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		ret = -ENOMEM;
113698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out;
113798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
113898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
113998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->bss_index = WL1271_AP_BSS_INDEX;
114098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
114198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	ret = wl1271_cmd_send(wl, CMD_BSS_STOP, cmd, sizeof(*cmd), 0);
114298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (ret < 0) {
114398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		wl1271_error("failed to initiate cmd stop bss");
114498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out_free;
114598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
114698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
114798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout_free:
114898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	kfree(cmd);
114998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
115098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout:
115198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	return ret;
115298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov}
115398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
115498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovint wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid)
115598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov{
115698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	struct wl1271_cmd_add_sta *cmd;
115798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	int ret;
115898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
115998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	wl1271_debug(DEBUG_CMD, "cmd add sta %d", (int)hlid);
116098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
116198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
116298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (!cmd) {
116398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		ret = -ENOMEM;
116498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out;
116598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
116698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
116798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	/* currently we don't support UAPSD */
116898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->sp_len = 0;
116998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
117098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	memcpy(cmd->addr, sta->addr, ETH_ALEN);
117198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->bss_index = WL1271_AP_BSS_INDEX;
117298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->aid = sta->aid;
117398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->hlid = hlid;
117498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
117598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	/*
117698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	 * FIXME: Does STA support QOS? We need to propagate this info from
117798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	 * hostapd. Currently not that important since this is only used for
117898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	 * sending the correct flavor of null-data packet in response to a
117998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	 * trigger.
118098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	 */
118198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->wmm = 0;
118298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
118398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->supported_rates = cpu_to_le32(wl1271_tx_enabled_rates_get(wl,
118498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov						sta->supp_rates[wl->band]));
118598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
118698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	wl1271_debug(DEBUG_CMD, "new sta rates: 0x%x", cmd->supported_rates);
118798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
118898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	ret = wl1271_cmd_send(wl, CMD_ADD_STA, cmd, sizeof(*cmd), 0);
118998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (ret < 0) {
119098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		wl1271_error("failed to initiate cmd add sta");
119198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out_free;
119298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
119398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
119498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout_free:
119598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	kfree(cmd);
119698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
119798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout:
119898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	return ret;
119998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov}
120098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
120198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovint wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid)
120298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov{
120398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	struct wl1271_cmd_remove_sta *cmd;
120498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	int ret;
120598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
120698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	wl1271_debug(DEBUG_CMD, "cmd remove sta %d", (int)hlid);
120798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
120898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
120998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (!cmd) {
121098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		ret = -ENOMEM;
121198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out;
121298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
121398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
121498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->hlid = hlid;
121598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	/* We never send a deauth, mac80211 is in charge of this */
121698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->reason_opcode = 0;
121798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->send_deauth_flag = 0;
121898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
121998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	ret = wl1271_cmd_send(wl, CMD_REMOVE_STA, cmd, sizeof(*cmd), 0);
122098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (ret < 0) {
122198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		wl1271_error("failed to initiate cmd remove sta");
122298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out_free;
122398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
122498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
122505285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	/*
122605285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	 * We are ok with a timeout here. The event is sometimes not sent
122705285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	 * due to a firmware bug.
122805285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	 */
122905285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	wl1271_cmd_wait_for_event_or_timeout(wl, STA_REMOVE_COMPLETE_EVENT_ID);
123098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
123198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout_free:
123298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	kfree(cmd);
123398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
123498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout:
123598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	return ret;
123698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov}
123795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
123895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivint wl12xx_cmd_config_fwlog(struct wl1271 *wl)
123995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv{
124095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	struct wl12xx_cmd_config_fwlog *cmd;
124195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	int ret = 0;
124295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
124395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	wl1271_debug(DEBUG_CMD, "cmd config firmware logger");
124495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
124595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
124695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	if (!cmd) {
124795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv		ret = -ENOMEM;
124895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv		goto out;
124995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	}
125095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
125195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	cmd->logger_mode = wl->conf.fwlog.mode;
125295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	cmd->log_severity = wl->conf.fwlog.severity;
125395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	cmd->timestamp = wl->conf.fwlog.timestamp;
125495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	cmd->output = wl->conf.fwlog.output;
125595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	cmd->threshold = wl->conf.fwlog.threshold;
125695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
125795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	ret = wl1271_cmd_send(wl, CMD_CONFIG_FWLOGGER, cmd, sizeof(*cmd), 0);
125895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	if (ret < 0) {
125995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv		wl1271_error("failed to send config firmware logger command");
126095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv		goto out_free;
126195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	}
126295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
126395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivout_free:
126495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	kfree(cmd);
126595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
126695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivout:
126795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	return ret;
126895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv}
126995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
127095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivint wl12xx_cmd_start_fwlog(struct wl1271 *wl)
127195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv{
127295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	struct wl12xx_cmd_start_fwlog *cmd;
127395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	int ret = 0;
127495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
127595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	wl1271_debug(DEBUG_CMD, "cmd start firmware logger");
127695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
127795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
127895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	if (!cmd) {
127995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv		ret = -ENOMEM;
128095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv		goto out;
128195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	}
128295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
128395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	ret = wl1271_cmd_send(wl, CMD_START_FWLOGGER, cmd, sizeof(*cmd), 0);
128495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	if (ret < 0) {
128595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv		wl1271_error("failed to send start firmware logger command");
128695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv		goto out_free;
128795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	}
128895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
128995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivout_free:
129095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	kfree(cmd);
129195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
129295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivout:
129395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	return ret;
129495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv}
129595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
129695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivint wl12xx_cmd_stop_fwlog(struct wl1271 *wl)
129795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv{
129895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	struct wl12xx_cmd_stop_fwlog *cmd;
129995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	int ret = 0;
130095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
130195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	wl1271_debug(DEBUG_CMD, "cmd stop firmware logger");
130295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
130395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
130495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	if (!cmd) {
130595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv		ret = -ENOMEM;
130695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv		goto out;
130795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	}
130895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
130995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	ret = wl1271_cmd_send(wl, CMD_STOP_FWLOGGER, cmd, sizeof(*cmd), 0);
131095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	if (ret < 0) {
131195dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv		wl1271_error("failed to send stop firmware logger command");
131295dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv		goto out_free;
131395dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	}
131495dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
131595dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivout_free:
131695dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	kfree(cmd);
131795dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv
131895dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yarivout:
131995dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv	return ret;
132095dac04f881322b510c45e5ae83f0dbee4f823a2Ido Yariv}
1321