cmd.c revision 25985edcedea6396277003854657b5f3cb31a628
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/crc7.h>
27f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho#include <linux/spi/spi.h>
28f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho#include <linux/etherdevice.h>
29023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo#include <linux/ieee80211.h>
305a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
31f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
3200d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "wl12xx.h"
3300d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "reg.h"
3400d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "io.h"
3500d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "acx.h"
36f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho#include "wl12xx_80211.h"
3700d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "cmd.h"
3800d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "event.h"
3998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov#include "tx.h"
40f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
4116092b5cccd6f3a8d1957ca004c97947e07018dbJuuso Oikarinen#define WL1271_CMD_FAST_POLL_COUNT       50
42f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
43f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/*
44f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * send command to firmware
45f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho *
46f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @wl: wl struct
47f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @id: command id
48f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @buf: buffer containing the command, must work with dma
49f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @len: length of the buffer
50f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */
51fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinenint wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len,
52fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen		    size_t res_len)
53f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
54f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct wl1271_cmd_header *cmd;
55f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	unsigned long timeout;
56f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	u32 intr;
57f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret = 0;
58ad150e966e987edcf737e1871d9e44a30d1aa58dJuuso Oikarinen	u16 status;
59bc0f03ea579d78f845a44a0c611806da64057b03Saravanan Dhanabal	u16 poll_count = 0;
60f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
61f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd = buf;
62d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	cmd->id = cpu_to_le16(id);
63f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->status = 0;
64f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
65f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	WARN_ON(len % 4 != 0);
6624225b37bd78d3e2edaa1a39316c54786adaa465Arik Nemtsov	WARN_ON(test_bit(WL1271_FLAG_IN_ELP, &wl->flags));
67f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
687b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi	wl1271_write(wl, wl->cmd_box_addr, buf, len, false);
69f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
707b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi	wl1271_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD);
71f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
72f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT);
73f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
747b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi	intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
75f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) {
76f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		if (time_after(jiffies, timeout)) {
77f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho			wl1271_error("command complete timeout");
78f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho			ret = -ETIMEDOUT;
79f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho			goto out;
80f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		}
81f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
82bc0f03ea579d78f845a44a0c611806da64057b03Saravanan Dhanabal		poll_count++;
8316092b5cccd6f3a8d1957ca004c97947e07018dbJuuso Oikarinen		if (poll_count < WL1271_CMD_FAST_POLL_COUNT)
8416092b5cccd6f3a8d1957ca004c97947e07018dbJuuso Oikarinen			udelay(10);
8516092b5cccd6f3a8d1957ca004c97947e07018dbJuuso Oikarinen		else
8616092b5cccd6f3a8d1957ca004c97947e07018dbJuuso Oikarinen			msleep(1);
87f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
887b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi		intr = wl1271_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR);
89f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
90f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
913b775b4b27818130291e7716f3ce1e24664004c9Juuso Oikarinen	/* read back the status code of the command */
92fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	if (res_len == 0)
93fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen		res_len = sizeof(struct wl1271_cmd_header);
947b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi	wl1271_read(wl, wl->cmd_box_addr, cmd, res_len, false);
953b775b4b27818130291e7716f3ce1e24664004c9Juuso Oikarinen
96ad150e966e987edcf737e1871d9e44a30d1aa58dJuuso Oikarinen	status = le16_to_cpu(cmd->status);
97ad150e966e987edcf737e1871d9e44a30d1aa58dJuuso Oikarinen	if (status != CMD_STATUS_SUCCESS) {
98ad150e966e987edcf737e1871d9e44a30d1aa58dJuuso Oikarinen		wl1271_error("command execute failure %d", status);
9952b0e7a61fd4b67fe8efe295297d8549f052f786Juuso Oikarinen		ieee80211_queue_work(wl->hw, &wl->recovery_work);
1003b775b4b27818130291e7716f3ce1e24664004c9Juuso Oikarinen		ret = -EIO;
1013b775b4b27818130291e7716f3ce1e24664004c9Juuso Oikarinen	}
1023b775b4b27818130291e7716f3ce1e24664004c9Juuso Oikarinen
1037b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi	wl1271_write32(wl, ACX_REG_INTERRUPT_ACK,
1047b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi		       WL1271_ACX_INTR_CMD_COMPLETE);
105f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
106f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout:
107f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
108f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
109f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
11098b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelhoint wl1271_cmd_general_parms(struct wl1271 *wl)
11198b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho{
11298b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	struct wl1271_general_parms_cmd *gen_parms;
1134b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	struct wl1271_ini_general_params *gp = &wl->nvs->general_params;
1144b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	bool answer = false;
11598b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	int ret;
11698b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
117152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen	if (!wl->nvs)
118152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen		return -ENODEV;
119152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen
12098b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
12198b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	if (!gen_parms)
12298b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho		return -ENOMEM;
12398b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
12498b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM;
12598b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
1264b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	memcpy(&gen_parms->general_params, gp, sizeof(*gp));
1274b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen
1284b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	if (gp->tx_bip_fem_auto_detect)
1294b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen		answer = true;
13076c0f8d396bd306111d349cfe770e1c4fcf70248Luciano Coelho
1314b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
1324b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	if (ret < 0) {
13398b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho		wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
1344b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen		goto out;
1354b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	}
13698b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
1374b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	gp->tx_bip_fem_manufacturer =
1384b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen		gen_parms->general_params.tx_bip_fem_manufacturer;
1394b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen
1404b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n",
1414b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen		     answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer);
1424b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen
1434b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinenout:
14498b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	kfree(gen_parms);
14598b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	return ret;
14698b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho}
14798b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
14898b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelhoint wl1271_cmd_radio_parms(struct wl1271 *wl)
14998b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho{
15098b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	struct wl1271_radio_parms_cmd *radio_parms;
151e6b190ff3c2f4e4859502c41fa17b5c595e82000Luciano Coelho	struct wl1271_ini_general_params *gp = &wl->nvs->general_params;
152152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen	int ret;
153152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen
154152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen	if (!wl->nvs)
155152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen		return -ENODEV;
15698b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
15798b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL);
15898b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	if (!radio_parms)
15998b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho		return -ENOMEM;
16098b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
16198b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
16298b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
163a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen	/* 2.4GHz parameters */
164eb70eb723b489dd4e233e22e47d993f59858cdd8Juuso Oikarinen	memcpy(&radio_parms->static_params_2, &wl->nvs->stat_radio_params_2,
165eb70eb723b489dd4e233e22e47d993f59858cdd8Juuso Oikarinen	       sizeof(struct wl1271_ini_band_params_2));
166eb70eb723b489dd4e233e22e47d993f59858cdd8Juuso Oikarinen	memcpy(&radio_parms->dyn_params_2,
167e6b190ff3c2f4e4859502c41fa17b5c595e82000Luciano Coelho	       &wl->nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params,
168eb70eb723b489dd4e233e22e47d993f59858cdd8Juuso Oikarinen	       sizeof(struct wl1271_ini_fem_params_2));
169152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen
170a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen	/* 5GHz parameters */
171a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen	memcpy(&radio_parms->static_params_5,
172a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen	       &wl->nvs->stat_radio_params_5,
173a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen	       sizeof(struct wl1271_ini_band_params_5));
174a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen	memcpy(&radio_parms->dyn_params_5,
175e6b190ff3c2f4e4859502c41fa17b5c595e82000Luciano Coelho	       &wl->nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params,
176a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen	       sizeof(struct wl1271_ini_fem_params_5));
17798b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
17898b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
17998b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho		    radio_parms, sizeof(*radio_parms));
18098b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
18198b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0);
18298b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	if (ret < 0)
18398b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho		wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed");
18498b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
18598b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	kfree(radio_parms);
18698b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	return ret;
18798b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho}
18898b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
189644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinenint wl1271_cmd_ext_radio_parms(struct wl1271 *wl)
190644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen{
191644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	struct wl1271_ext_radio_parms_cmd *ext_radio_parms;
192644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	struct conf_rf_settings *rf = &wl->conf.rf;
193644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	int ret;
194644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
195644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	if (!wl->nvs)
196644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen		return -ENODEV;
197644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
198644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	ext_radio_parms = kzalloc(sizeof(*ext_radio_parms), GFP_KERNEL);
199644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	if (!ext_radio_parms)
200644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen		return -ENOMEM;
201644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
202644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	ext_radio_parms->test.id = TEST_CMD_INI_FILE_RF_EXTENDED_PARAM;
203644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
204644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	memcpy(ext_radio_parms->tx_per_channel_power_compensation_2,
205644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	       rf->tx_per_channel_power_compensation_2,
206644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	       CONF_TX_PWR_COMPENSATION_LEN_2);
207644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	memcpy(ext_radio_parms->tx_per_channel_power_compensation_5,
208644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	       rf->tx_per_channel_power_compensation_5,
209644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	       CONF_TX_PWR_COMPENSATION_LEN_5);
210644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
211644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_EXT_RADIO_PARAM: ",
212644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen		    ext_radio_parms, sizeof(*ext_radio_parms));
213644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
214644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	ret = wl1271_cmd_test(wl, ext_radio_parms, sizeof(*ext_radio_parms), 0);
215644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	if (ret < 0)
216644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen		wl1271_warning("TEST_CMD_INI_FILE_RF_EXTENDED_PARAM failed");
217644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
218644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	kfree(ext_radio_parms);
219644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	return ret;
220644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen}
221644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
22299d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho/*
22399d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho * Poll the mailbox event field until any of the bits in the mask is set or a
22499d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho * timeout occurs (WL1271_EVENT_TIMEOUT in msecs)
22599d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho */
22605285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsovstatic int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask)
22799d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho{
22899d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	u32 events_vector, event;
22999d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	unsigned long timeout;
23099d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho
23199d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT);
23299d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho
23399d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	do {
23452b0e7a61fd4b67fe8efe295297d8549f052f786Juuso Oikarinen		if (time_after(jiffies, timeout)) {
23505285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov			wl1271_debug(DEBUG_CMD, "timeout waiting for event %d",
23605285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov				     (int)mask);
23799d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho			return -ETIMEDOUT;
23852b0e7a61fd4b67fe8efe295297d8549f052f786Juuso Oikarinen		}
23999d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho
24099d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho		msleep(1);
24199d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho
24299d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho		/* read from both event fields */
24399d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho		wl1271_read(wl, wl->mbox_ptr[0], &events_vector,
24499d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho			    sizeof(events_vector), false);
24599d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho		event = events_vector & mask;
24699d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho		wl1271_read(wl, wl->mbox_ptr[1], &events_vector,
24799d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho			    sizeof(events_vector), false);
24899d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho		event |= events_vector & mask;
24999d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	} while (!event);
25099d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho
25199d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	return 0;
25299d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho}
25399d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho
25405285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsovstatic int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
25505285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov{
25605285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	int ret;
25705285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov
25805285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask);
25905285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	if (ret != 0) {
26005285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov		ieee80211_queue_work(wl->hw, &wl->recovery_work);
26105285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov		return ret;
26205285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	}
26305285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov
26405285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	return 0;
26505285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov}
26605285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov
26715305498a443c181c8fb5deafb94eae585fe3ad5Juuso Oikarinenint wl1271_cmd_join(struct wl1271 *wl, u8 bss_type)
268f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
269f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct wl1271_cmd_join *join;
270f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret, i;
271f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	u8 *bssid;
272f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
273f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	join = kzalloc(sizeof(*join), GFP_KERNEL);
274f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (!join) {
275f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		ret = -ENOMEM;
276f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
277f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
278f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
279f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd join");
280f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
281f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	/* Reverse order BSSID */
282f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	bssid = (u8 *) &join->bssid_lsb;
283f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	for (i = 0; i < ETH_ALEN; i++)
284f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		bssid[i] = wl->bssid[ETH_ALEN - i - 1];
285f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
286d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	join->rx_config_options = cpu_to_le32(wl->rx_config);
287d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	join->rx_filter_options = cpu_to_le32(wl->rx_filter);
28815305498a443c181c8fb5deafb94eae585fe3ad5Juuso Oikarinen	join->bss_type = bss_type;
28923a7a51c5a35b30aa3edcc31a6a57b01c523b4cdLuciano Coelho	join->basic_rate_set = cpu_to_le32(wl->basic_rate_set);
29072c2d9e511846a4f2759389b38ed8a5553579eb3Eliad Peller	join->supported_rate_set = cpu_to_le32(wl->rate_set);
291f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
292ebba60c66b3aa321a84c9a90a343c91fde972066Juuso Oikarinen	if (wl->band == IEEE80211_BAND_5GHZ)
293a410264553447ff90bf13e3662684e794e5ff83eTeemu Paasikivi		join->bss_type |= WL1271_JOIN_CMD_BSS_TYPE_5GHZ;
294f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
29560e84c2ebb7b04361cf1ba0d325cc93366bd04a6Juuso Oikarinen	join->beacon_interval = cpu_to_le16(wl->beacon_int);
296ae751bab9f55c3152ebf713c89a4fb6f439c2575Luciano Coelho	join->dtim_interval = WL1271_DEFAULT_DTIM_PERIOD;
297a410264553447ff90bf13e3662684e794e5ff83eTeemu Paasikivi
298f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	join->channel = wl->channel;
299f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	join->ssid_len = wl->ssid_len;
300f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	memcpy(join->ssid, wl->ssid, wl->ssid_len);
301f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
302f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET;
303f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
304ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen	/* reset TX security counters */
305ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen	wl->tx_security_last_seq = 0;
30604e36fc5f1ff4e349ea21de8d15e4e1844d04197Juuso Oikarinen	wl->tx_security_seq = 0;
307f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
30872c2d9e511846a4f2759389b38ed8a5553579eb3Eliad Peller	wl1271_debug(DEBUG_CMD, "cmd join: basic_rate_set=0x%x, rate_set=0x%x",
30972c2d9e511846a4f2759389b38ed8a5553579eb3Eliad Peller		join->basic_rate_set, join->supported_rate_set);
31072c2d9e511846a4f2759389b38ed8a5553579eb3Eliad Peller
311fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join), 0);
312f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
313f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_error("failed to initiate cmd join");
314f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out_free;
315f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
316f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
31799d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	ret = wl1271_cmd_wait_for_event(wl, JOIN_EVENT_COMPLETE_ID);
31899d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	if (ret < 0)
31999d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho		wl1271_error("cmd join event completion error");
320f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
321f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout_free:
322f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	kfree(join);
323f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
324f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout:
325f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
326f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
327f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
328f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/**
329f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * send test command to firmware
330f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho *
331f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @wl: wl struct
332f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @buf: buffer containing the command, with all headers, must work with dma
333f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @len: length of the buffer
334f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @answer: is answer needed
335f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */
336f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer)
337f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
338f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret;
339fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	size_t res_len = 0;
340f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
341f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd test");
342f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
343fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	if (answer)
344fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen		res_len = buf_len;
345fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen
346fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_TEST, buf, buf_len, res_len);
347f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
348f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
349f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_warning("TEST command failed");
350f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		return ret;
351f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
352f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
353fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	return ret;
354f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
355f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
356f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/**
357f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * read acx from firmware
358f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho *
359f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @wl: wl struct
360f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @id: acx id
361f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @buf: buffer for the response, including all headers, must work with dma
36225985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * @len: length of buf
363f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */
364f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len)
365f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
366f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct acx_header *acx = buf;
367f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret;
368f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
369f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd interrogate");
370f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
371d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	acx->id = cpu_to_le16(id);
372f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
373f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	/* payload length, does not include any headers */
374d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	acx->len = cpu_to_le16(len - sizeof(*acx));
375f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
376fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx), len);
377fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	if (ret < 0)
378f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_error("INTERROGATE command failed");
379f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
380f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
381f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
382f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
383f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/**
384f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * write acx value to firmware
385f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho *
386f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @wl: wl struct
387f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @id: acx id
388f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @buf: buffer containing acx, including all headers, must work with dma
389f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @len: length of buf
390f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */
391f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len)
392f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
393f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct acx_header *acx = buf;
394f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret;
395f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
396f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd configure");
397f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
398d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	acx->id = cpu_to_le16(id);
399f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
400f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	/* payload length, does not include any headers */
401d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	acx->len = cpu_to_le16(len - sizeof(*acx));
402f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
403fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len, 0);
404f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
405f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_warning("CONFIGURE command NOK");
406f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		return ret;
407f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
408f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
409f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return 0;
410f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
411f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
41294210897e2b7df8446fdecd360342149e5b4a400Luciano Coelhoint wl1271_cmd_data_path(struct wl1271 *wl, bool enable)
413f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
414f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct cmd_enabledisable_path *cmd;
415f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret;
416f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	u16 cmd_rx, cmd_tx;
417f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
418f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd data path");
419f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
420f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
421f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (!cmd) {
422f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		ret = -ENOMEM;
423f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
424f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
425f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
42694210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho	/* the channel here is only used for calibration, so hardcoded to 1 */
42794210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho	cmd->channel = 1;
428f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
429f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (enable) {
430f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		cmd_rx = CMD_ENABLE_RX;
431f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		cmd_tx = CMD_ENABLE_TX;
432f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	} else {
433f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		cmd_rx = CMD_DISABLE_RX;
434f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		cmd_tx = CMD_DISABLE_TX;
435f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
436f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
437fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd), 0);
438f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
439f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_error("rx %s cmd for channel %d failed",
44094210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho			     enable ? "start" : "stop", cmd->channel);
441f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
442f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
443f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
444f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d",
44594210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho		     enable ? "start" : "stop", cmd->channel);
446f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
447fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd), 0);
448f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
449f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_error("tx %s cmd for channel %d failed",
45094210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho			     enable ? "start" : "stop", cmd->channel);
4511b00f2b560028a68cdbc57a0352163afd79822ddJuuso Oikarinen		goto out;
452f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
453f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
454f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d",
45594210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho		     enable ? "start" : "stop", cmd->channel);
456f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
457f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout:
458f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	kfree(cmd);
459f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
460f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
461f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
462c8bde243421d759844264cf11e4248e7862c2722Eliad Pellerint wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode)
463f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
464f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct wl1271_cmd_ps_params *ps_params = NULL;
465f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret = 0;
466f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
467f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd set ps mode");
468f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
469f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL);
470f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (!ps_params) {
471f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		ret = -ENOMEM;
472f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
473f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
474f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
475f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	ps_params->ps_mode = ps_mode;
476f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
477f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
478fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen			      sizeof(*ps_params), 0);
479f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
480f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_error("cmd set_ps_mode failed");
481f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
482f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
483f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
484f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout:
485f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	kfree(ps_params);
486f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
487f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
488f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
489f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
490606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen			    void *buf, size_t buf_len, int index, u32 rates)
491f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
492f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct wl1271_cmd_template_set *cmd;
493f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret = 0;
494f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
495f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd template_set %d", template_id);
496f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
497f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	WARN_ON(buf_len > WL1271_CMD_TEMPL_MAX_SIZE);
498f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	buf_len = min_t(size_t, buf_len, WL1271_CMD_TEMPL_MAX_SIZE);
499f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
500f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
501f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (!cmd) {
502f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		ret = -ENOMEM;
503f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
504f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
505f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
506f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->len = cpu_to_le16(buf_len);
507f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->template_type = template_id;
508606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen	cmd->enabled_rates = cpu_to_le32(rates);
5091e05a81888318752e9a6d2158a95ddd6442ae117Arik Nemtsov	cmd->short_retry_limit = wl->conf.tx.tmpl_short_retry_limit;
5101e05a81888318752e9a6d2158a95ddd6442ae117Arik Nemtsov	cmd->long_retry_limit = wl->conf.tx.tmpl_long_retry_limit;
511bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	cmd->index = index;
512f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
513f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (buf)
514f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		memcpy(cmd->template_data, buf, buf_len);
515f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
516fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_SET_TEMPLATE, cmd, sizeof(*cmd), 0);
517f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
518f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_warning("cmd set_template failed: %d", ret);
519f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out_free;
520f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
521f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
522f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout_free:
523f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	kfree(cmd);
524f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
525f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout:
526f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
527f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
528f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
529f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_build_null_data(struct wl1271 *wl)
530f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
531a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	struct sk_buff *skb = NULL;
532a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	int size;
533a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	void *ptr;
534a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	int ret = -ENOMEM;
535f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
536f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
537a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	if (wl->bss_type == BSS_TYPE_IBSS) {
538a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen		size = sizeof(struct wl12xx_null_data_template);
539a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen		ptr = NULL;
540a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	} else {
541a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen		skb = ieee80211_nullfunc_get(wl->hw, wl->vif);
542a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen		if (!skb)
543a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen			goto out;
544a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen		size = skb->len;
545a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen		ptr = skb->data;
546a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	}
547a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen
548606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, ptr, size, 0,
5498eab7b4708b5ef4701ecbe5d659f99743b77b668Juuso Oikarinen				      wl->basic_rate);
550f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
551899e6e65c39990a76c17940625dbe6001f618734Kalle Valoout:
552899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	dev_kfree_skb(skb);
553a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	if (ret)
554a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen		wl1271_warning("cmd buld null data failed %d", ret);
555a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen
556899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	return ret;
557f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
558f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
559f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
560bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinenint wl1271_cmd_build_klv_null_data(struct wl1271 *wl)
561bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen{
562bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	struct sk_buff *skb = NULL;
563bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	int ret = -ENOMEM;
564bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen
565bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	skb = ieee80211_nullfunc_get(wl->hw, wl->vif);
566bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	if (!skb)
567bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen		goto out;
568bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen
569bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV,
570bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen				      skb->data, skb->len,
571606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen				      CMD_TEMPL_KLV_IDX_NULL_DATA,
5728eab7b4708b5ef4701ecbe5d659f99743b77b668Juuso Oikarinen				      wl->basic_rate);
573bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen
574bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinenout:
575bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	dev_kfree_skb(skb);
576bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	if (ret)
577bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen		wl1271_warning("cmd build klv null data failed %d", ret);
578bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen
579bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	return ret;
580bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen
581bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen}
582bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen
583f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid)
584f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
585899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	struct sk_buff *skb;
586899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	int ret = 0;
587c3fea1994ac34dafa3ebb40d4f95354b2782af31Juuso Oikarinen
588899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	skb = ieee80211_pspoll_get(wl->hw, wl->vif);
589899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	if (!skb)
590899e6e65c39990a76c17940625dbe6001f618734Kalle Valo		goto out;
591f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
592899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, skb->data,
593849923f43ca681cc86a401178db31acb60e79f3bJuuso Oikarinen				      skb->len, 0, wl->basic_rate_set);
594f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
595899e6e65c39990a76c17940625dbe6001f618734Kalle Valoout:
596899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	dev_kfree_skb(skb);
597899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	return ret;
598f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
599f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
600818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valoint wl1271_cmd_build_probe_req(struct wl1271 *wl,
601818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo			       const u8 *ssid, size_t ssid_len,
602818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo			       const u8 *ie, size_t ie_len, u8 band)
603f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
604818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo	struct sk_buff *skb;
605abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi	int ret;
606f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
607818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo	skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len,
608818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo				     ie, ie_len);
609818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo	if (!skb) {
610818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo		ret = -ENOMEM;
611818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo		goto out;
612818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo	}
613818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo
614818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo	wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len);
615f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
616abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi	if (band == IEEE80211_BAND_2GHZ)
617abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi		ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
618606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen					      skb->data, skb->len, 0,
619606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen					      wl->conf.tx.basic_rate);
620abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi	else
621abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi		ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
622606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen					      skb->data, skb->len, 0,
623606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen					      wl->conf.tx.basic_rate_5);
624818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo
625818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valoout:
626818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo	dev_kfree_skb(skb);
627abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi	return ret;
628f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
629f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
6302f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinenstruct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
6312f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen					      struct sk_buff *skb)
6322f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen{
6332f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	int ret;
6342f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen
6352f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	if (!skb)
6362f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen		skb = ieee80211_ap_probereq_get(wl->hw, wl->vif);
6372f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	if (!skb)
6382f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen		goto out;
6392f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen
6402f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	wl1271_dump(DEBUG_SCAN, "AP PROBE REQ: ", skb->data, skb->len);
6412f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen
6422f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	if (wl->band == IEEE80211_BAND_2GHZ)
6432f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen		ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
6442f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen					      skb->data, skb->len, 0,
6452f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen					      wl->conf.tx.basic_rate);
6462f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	else
6472f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen		ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
6482f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen					      skb->data, skb->len, 0,
6492f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen					      wl->conf.tx.basic_rate_5);
6502f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen
6512f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	if (ret < 0)
6522f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen		wl1271_error("Unable to set ap probe request template.");
6532f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen
6542f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinenout:
6552f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	return skb;
6562f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen}
6572f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen
658c5312772156bb5f9b2e95e4c91526d578426a069Eliad Pellerint wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr)
659c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller{
660c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	int ret;
661c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	struct wl12xx_arp_rsp_template tmpl;
662c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	struct ieee80211_hdr_3addr *hdr;
663c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	struct arphdr *arp_hdr;
664c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
665c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	memset(&tmpl, 0, sizeof(tmpl));
666c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
667c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	/* mac80211 header */
668c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	hdr = &tmpl.hdr;
669c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
670c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller					 IEEE80211_STYPE_DATA |
671c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller					 IEEE80211_FCTL_TODS);
672c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	memcpy(hdr->addr1, wl->vif->bss_conf.bssid, ETH_ALEN);
673c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	memcpy(hdr->addr2, wl->vif->addr, ETH_ALEN);
674c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	memset(hdr->addr3, 0xff, ETH_ALEN);
675c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
676c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	/* llc layer */
677c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	memcpy(tmpl.llc_hdr, rfc1042_header, sizeof(rfc1042_header));
6786177eaea277527e48753d050723cd138494c98a8Eliad Peller	tmpl.llc_type = cpu_to_be16(ETH_P_ARP);
679c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
680c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	/* arp header */
681c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	arp_hdr = &tmpl.arp_hdr;
6826177eaea277527e48753d050723cd138494c98a8Eliad Peller	arp_hdr->ar_hrd = cpu_to_be16(ARPHRD_ETHER);
6836177eaea277527e48753d050723cd138494c98a8Eliad Peller	arp_hdr->ar_pro = cpu_to_be16(ETH_P_IP);
684c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	arp_hdr->ar_hln = ETH_ALEN;
685c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	arp_hdr->ar_pln = 4;
6866177eaea277527e48753d050723cd138494c98a8Eliad Peller	arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY);
687c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
688c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	/* arp payload */
689c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	memcpy(tmpl.sender_hw, wl->vif->addr, ETH_ALEN);
690c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	tmpl.sender_ip = ip_addr;
691c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
692c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP,
693c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller				      &tmpl, sizeof(tmpl), 0,
694c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller				      wl->basic_rate);
695c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
696c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	return ret;
697c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller}
698c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
699023e082609ba3225dbd5c33933a90156d2201d7fKalle Valoint wl1271_build_qos_null_data(struct wl1271 *wl)
700023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo{
701023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	struct ieee80211_qos_hdr template;
702023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo
703023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	memset(&template, 0, sizeof(template));
704023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo
705023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	memcpy(template.addr1, wl->bssid, ETH_ALEN);
706023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	memcpy(template.addr2, wl->mac_addr, ETH_ALEN);
707023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	memcpy(template.addr3, wl->bssid, ETH_ALEN);
708023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo
709023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	template.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
710023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo					     IEEE80211_STYPE_QOS_NULLFUNC |
711023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo					     IEEE80211_FCTL_TODS);
712023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo
713023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	/* FIXME: not sure what priority to use here */
714023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	template.qos_ctrl = cpu_to_le16(0);
715023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo
716023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	return wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, &template,
717606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen				       sizeof(template), 0,
7188eab7b4708b5ef4701ecbe5d659f99743b77b668Juuso Oikarinen				       wl->basic_rate);
719023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo}
720023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo
72198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovint wl1271_cmd_set_sta_default_wep_key(struct wl1271 *wl, u8 id)
722f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
72398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	struct wl1271_cmd_set_sta_keys *cmd;
724f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret = 0;
725f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
726f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id);
727f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
728f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
729f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (!cmd) {
730f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		ret = -ENOMEM;
731f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
732f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
733f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
734f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->id = id;
735d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	cmd->key_action = cpu_to_le16(KEY_SET_ID);
736f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->key_type = KEY_WEP;
737f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
738fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0);
739f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
740f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_warning("cmd set_default_wep_key failed: %d", ret);
741f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
742f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
743f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
744f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout:
745f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	kfree(cmd);
746f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
747f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
748f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
749f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
75098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovint wl1271_cmd_set_ap_default_wep_key(struct wl1271 *wl, u8 id)
75198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov{
75298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	struct wl1271_cmd_set_ap_keys *cmd;
75398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	int ret = 0;
75498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
75598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	wl1271_debug(DEBUG_CMD, "cmd set_ap_default_wep_key %d", id);
75698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
75798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
75898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (!cmd) {
75998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		ret = -ENOMEM;
76098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out;
76198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
76298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
76398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->hlid = WL1271_AP_BROADCAST_HLID;
76498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->key_id = id;
76598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->lid_key_type = WEP_DEFAULT_LID_TYPE;
76698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->key_action = cpu_to_le16(KEY_SET_ID);
76798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->key_type = KEY_WEP;
76898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
76998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0);
77098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (ret < 0) {
77198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		wl1271_warning("cmd set_ap_default_wep_key failed: %d", ret);
77298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out;
77398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
77498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
77598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout:
77698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	kfree(cmd);
77798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
77898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	return ret;
77998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov}
78098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
78198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovint wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
782ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen		       u8 key_size, const u8 *key, const u8 *addr,
783ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen		       u32 tx_seq_32, u16 tx_seq_16)
784f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
78598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	struct wl1271_cmd_set_sta_keys *cmd;
786f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret = 0;
787f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
788f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
789f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (!cmd) {
790f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		ret = -ENOMEM;
791f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
792f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
793f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
794f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (key_type != KEY_WEP)
795f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		memcpy(cmd->addr, addr, ETH_ALEN);
796f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
797d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	cmd->key_action = cpu_to_le16(action);
798f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->key_size = key_size;
799f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->key_type = key_type;
800f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
801d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16);
802d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32);
803ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen
804f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	/* we have only one SSID profile */
805f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->ssid_profile = 0;
806f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
807f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->id = id;
808f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
809f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (key_type == KEY_TKIP) {
810f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		/*
811f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		 * We get the key in the following form:
812f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		 * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes)
813f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		 * but the target is expecting:
814f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		 * TKIP - RX MIC - TX MIC
815f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		 */
816f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		memcpy(cmd->key, key, 16);
817f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		memcpy(cmd->key + 16, key + 24, 8);
818f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		memcpy(cmd->key + 24, key + 16, 8);
819f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
820f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	} else {
821f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		memcpy(cmd->key, key, key_size);
822f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
823f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
824f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_dump(DEBUG_CRYPT, "TARGET KEY: ", cmd, sizeof(*cmd));
825f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
826fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0);
827f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
828f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_warning("could not set keys");
829152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen	goto out;
830f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
831f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
832f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout:
833f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	kfree(cmd);
834f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
835f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
836f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
83725a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho
83898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovint wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
83998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov			u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
84098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov			u16 tx_seq_16)
84198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov{
84298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	struct wl1271_cmd_set_ap_keys *cmd;
84398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	int ret = 0;
84498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	u8 lid_type;
84598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
84698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
84798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (!cmd)
84898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		return -ENOMEM;
84998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
85098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (hlid == WL1271_AP_BROADCAST_HLID) {
85198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		if (key_type == KEY_WEP)
85298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov			lid_type = WEP_DEFAULT_LID_TYPE;
85398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		else
85498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov			lid_type = BROADCAST_LID_TYPE;
85598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	} else {
85698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		lid_type = UNICAST_LID_TYPE;
85798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
85898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
85998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	wl1271_debug(DEBUG_CRYPT, "ap key action: %d id: %d lid: %d type: %d"
86098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		     " hlid: %d", (int)action, (int)id, (int)lid_type,
86198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		     (int)key_type, (int)hlid);
86298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
86398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->lid_key_type = lid_type;
86498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->hlid = hlid;
86598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->key_action = cpu_to_le16(action);
86698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->key_size = key_size;
86798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->key_type = key_type;
86898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->key_id = id;
86998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16);
87098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32);
87198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
87298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (key_type == KEY_TKIP) {
87398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		/*
87498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		 * We get the key in the following form:
87598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		 * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes)
87698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		 * but the target is expecting:
87798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		 * TKIP - RX MIC - TX MIC
87898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		 */
87998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		memcpy(cmd->key, key, 16);
88098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		memcpy(cmd->key + 16, key + 24, 8);
88198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		memcpy(cmd->key + 24, key + 16, 8);
88298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	} else {
88398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		memcpy(cmd->key, key, key_size);
88498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
88598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
88698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	wl1271_dump(DEBUG_CRYPT, "TARGET AP KEY: ", cmd, sizeof(*cmd));
88798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
88898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0);
88998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (ret < 0) {
89098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		wl1271_warning("could not set ap keys");
89198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out;
89298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
89398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
89498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout:
89598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	kfree(cmd);
89698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	return ret;
89798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov}
89898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
89925a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelhoint wl1271_cmd_disconnect(struct wl1271 *wl)
90025a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho{
90125a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	struct wl1271_cmd_disconnect *cmd;
90225a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	int ret = 0;
90325a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho
90425a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd disconnect");
90525a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho
90625a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
90725a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	if (!cmd) {
90825a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho		ret = -ENOMEM;
90925a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho		goto out;
91025a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	}
91125a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho
912d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	cmd->rx_config_options = cpu_to_le32(wl->rx_config);
913d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	cmd->rx_filter_options = cpu_to_le32(wl->rx_filter);
91425a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	/* disconnect reason is not used in immediate disconnections */
91525a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	cmd->type = DISCONNECT_IMMEDIATE;
91625a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho
917fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_DISCONNECT, cmd, sizeof(*cmd), 0);
91825a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	if (ret < 0) {
91925a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho		wl1271_error("failed to send disconnect command");
92025a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho		goto out_free;
92125a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	}
92225a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho
9232f826f55404ca43efced94d548356182820e764fLuciano Coelho	ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID);
9242f826f55404ca43efced94d548356182820e764fLuciano Coelho	if (ret < 0)
9252f826f55404ca43efced94d548356182820e764fLuciano Coelho		wl1271_error("cmd disconnect event completion error");
9262f826f55404ca43efced94d548356182820e764fLuciano Coelho
92725a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelhoout_free:
92825a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	kfree(cmd);
92925a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho
93025a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelhoout:
93125a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	return ret;
93225a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho}
933be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen
934be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinenint wl1271_cmd_set_sta_state(struct wl1271 *wl)
935be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen{
936be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	struct wl1271_cmd_set_sta_state *cmd;
937be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	int ret = 0;
938be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen
939be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	wl1271_debug(DEBUG_CMD, "cmd set sta state");
940be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen
941be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
942be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	if (!cmd) {
943be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen		ret = -ENOMEM;
944be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen		goto out;
945be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	}
946be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen
947be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	cmd->state = WL1271_CMD_STA_STATE_CONNECTED;
948be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen
949be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_SET_STA_STATE, cmd, sizeof(*cmd), 0);
950be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	if (ret < 0) {
951be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen		wl1271_error("failed to send set STA state command");
952be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen		goto out_free;
953be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	}
954be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen
955be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinenout_free:
956be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	kfree(cmd);
957be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen
958be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinenout:
959be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	return ret;
960be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen}
96198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
96298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovint wl1271_cmd_start_bss(struct wl1271 *wl)
96398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov{
96498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	struct wl1271_cmd_bss_start *cmd;
96598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
96698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	int ret;
96798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
96898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	wl1271_debug(DEBUG_CMD, "cmd start bss");
96998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
97098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	/*
97198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	 * FIXME: We currently do not support hidden SSID. The real SSID
97298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	 * should be fetched from mac80211 first.
97398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	 */
97498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (wl->ssid_len == 0) {
97598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		wl1271_warning("Hidden SSID currently not supported for AP");
97698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		ret = -EINVAL;
97798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out;
97898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
97998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
98098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
98198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (!cmd) {
98298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		ret = -ENOMEM;
98398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out;
98498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
98598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
98698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	memcpy(cmd->bssid, bss_conf->bssid, ETH_ALEN);
98798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
9881d4801f2689dc2618fdb5e83d4cb7743747491edEliad Peller	cmd->aging_period = cpu_to_le16(WL1271_AP_DEF_INACTIV_SEC);
98998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->bss_index = WL1271_AP_BSS_INDEX;
99098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->global_hlid = WL1271_AP_GLOBAL_HLID;
99198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->broadcast_hlid = WL1271_AP_BROADCAST_HLID;
99298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->basic_rate_set = cpu_to_le32(wl->basic_rate_set);
99398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->beacon_interval = cpu_to_le16(wl->beacon_int);
99498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->dtim_interval = bss_conf->dtim_period;
99598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->beacon_expiry = WL1271_AP_DEF_BEACON_EXP;
99698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->channel = wl->channel;
99798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->ssid_len = wl->ssid_len;
99898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->ssid_type = SSID_TYPE_PUBLIC;
99998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	memcpy(cmd->ssid, wl->ssid, wl->ssid_len);
100098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
100198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	switch (wl->band) {
100298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	case IEEE80211_BAND_2GHZ:
100398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		cmd->band = RADIO_BAND_2_4GHZ;
100498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		break;
100598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	case IEEE80211_BAND_5GHZ:
100698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		cmd->band = RADIO_BAND_5GHZ;
100798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		break;
100898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	default:
100998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		wl1271_warning("bss start - unknown band: %d", (int)wl->band);
101098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		cmd->band = RADIO_BAND_2_4GHZ;
101198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		break;
101298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
101398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
101498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	ret = wl1271_cmd_send(wl, CMD_BSS_START, cmd, sizeof(*cmd), 0);
101598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (ret < 0) {
101698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		wl1271_error("failed to initiate cmd start bss");
101798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out_free;
101898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
101998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
102098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout_free:
102198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	kfree(cmd);
102298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
102398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout:
102498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	return ret;
102598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov}
102698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
102798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovint wl1271_cmd_stop_bss(struct wl1271 *wl)
102898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov{
102998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	struct wl1271_cmd_bss_start *cmd;
103098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	int ret;
103198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
103298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	wl1271_debug(DEBUG_CMD, "cmd stop bss");
103398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
103498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
103598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (!cmd) {
103698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		ret = -ENOMEM;
103798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out;
103898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
103998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
104098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->bss_index = WL1271_AP_BSS_INDEX;
104198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
104298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	ret = wl1271_cmd_send(wl, CMD_BSS_STOP, cmd, sizeof(*cmd), 0);
104398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (ret < 0) {
104498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		wl1271_error("failed to initiate cmd stop bss");
104598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out_free;
104698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
104798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
104898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout_free:
104998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	kfree(cmd);
105098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
105198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout:
105298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	return ret;
105398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov}
105498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
105598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovint wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid)
105698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov{
105798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	struct wl1271_cmd_add_sta *cmd;
105898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	int ret;
105998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
106098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	wl1271_debug(DEBUG_CMD, "cmd add sta %d", (int)hlid);
106198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
106298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
106398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (!cmd) {
106498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		ret = -ENOMEM;
106598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out;
106698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
106798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
106898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	/* currently we don't support UAPSD */
106998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->sp_len = 0;
107098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
107198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	memcpy(cmd->addr, sta->addr, ETH_ALEN);
107298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->bss_index = WL1271_AP_BSS_INDEX;
107398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->aid = sta->aid;
107498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->hlid = hlid;
107598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
107698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	/*
107798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	 * FIXME: Does STA support QOS? We need to propagate this info from
107898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	 * hostapd. Currently not that important since this is only used for
107998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	 * sending the correct flavor of null-data packet in response to a
108098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	 * trigger.
108198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	 */
108298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->wmm = 0;
108398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
108498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->supported_rates = cpu_to_le32(wl1271_tx_enabled_rates_get(wl,
108598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov						sta->supp_rates[wl->band]));
108698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
108798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	wl1271_debug(DEBUG_CMD, "new sta rates: 0x%x", cmd->supported_rates);
108898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
108998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	ret = wl1271_cmd_send(wl, CMD_ADD_STA, cmd, sizeof(*cmd), 0);
109098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (ret < 0) {
109198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		wl1271_error("failed to initiate cmd add sta");
109298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out_free;
109398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
109498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
109598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout_free:
109698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	kfree(cmd);
109798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
109898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout:
109998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	return ret;
110098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov}
110198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
110298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovint wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid)
110398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov{
110498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	struct wl1271_cmd_remove_sta *cmd;
110598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	int ret;
110698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
110798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	wl1271_debug(DEBUG_CMD, "cmd remove sta %d", (int)hlid);
110898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
110998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
111098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (!cmd) {
111198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		ret = -ENOMEM;
111298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out;
111398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
111498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
111598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->hlid = hlid;
111698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	/* We never send a deauth, mac80211 is in charge of this */
111798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->reason_opcode = 0;
111898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->send_deauth_flag = 0;
111998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
112098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	ret = wl1271_cmd_send(wl, CMD_REMOVE_STA, cmd, sizeof(*cmd), 0);
112198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (ret < 0) {
112298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		wl1271_error("failed to initiate cmd remove sta");
112398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out_free;
112498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
112598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
112605285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	/*
112705285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	 * We are ok with a timeout here. The event is sometimes not sent
112805285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	 * due to a firmware bug.
112905285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	 */
113005285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	wl1271_cmd_wait_for_event_or_timeout(wl, STA_REMOVE_COMPLETE_EVENT_ID);
113198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
113298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout_free:
113398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	kfree(cmd);
113498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
113598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout:
113698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	return ret;
113798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov}
1138