cmd.c revision bc765bf3b9a095b3e41c8cda80643901884c3dd4
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;
11349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	struct wl1271_ini_general_params *gp =
11449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		&((struct wl1271_nvs_file *)wl->nvs)->general_params;
11549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	bool answer = false;
11649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	int ret;
11749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
11849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	if (!wl->nvs)
11949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		return -ENODEV;
12049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
12149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
12249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	if (!gen_parms)
12349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		return -ENOMEM;
12449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
12549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM;
12649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
12749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	memcpy(&gen_parms->general_params, gp, sizeof(*gp));
12849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
12949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	if (gp->tx_bip_fem_auto_detect)
13049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		answer = true;
13149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
13249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
13349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	if (ret < 0) {
13449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
13549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		goto out;
13649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	}
13749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
13849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	gp->tx_bip_fem_manufacturer =
13949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		gen_parms->general_params.tx_bip_fem_manufacturer;
14049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
14149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n",
14249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		     answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer);
14349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
14449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Leviout:
14549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	kfree(gen_parms);
14649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	return ret;
14749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi}
14849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
14949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Leviint wl128x_cmd_general_parms(struct wl1271 *wl)
15049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi{
15149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	struct wl128x_general_parms_cmd *gen_parms;
15249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	struct wl128x_ini_general_params *gp =
15349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		&((struct wl128x_nvs_file *)wl->nvs)->general_params;
1544b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	bool answer = false;
15598b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	int ret;
15698b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
157152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen	if (!wl->nvs)
158152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen		return -ENODEV;
159152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen
16098b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	gen_parms = kzalloc(sizeof(*gen_parms), GFP_KERNEL);
16198b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	if (!gen_parms)
16298b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho		return -ENOMEM;
16398b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
16498b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	gen_parms->test.id = TEST_CMD_INI_FILE_GENERAL_PARAM;
16598b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
1664b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	memcpy(&gen_parms->general_params, gp, sizeof(*gp));
1674b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen
1684b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	if (gp->tx_bip_fem_auto_detect)
1694b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen		answer = true;
17076c0f8d396bd306111d349cfe770e1c4fcf70248Luciano Coelho
1714b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
1724b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	if (ret < 0) {
17398b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho		wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
1744b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen		goto out;
1754b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	}
17698b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
1774b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	gp->tx_bip_fem_manufacturer =
1784b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen		gen_parms->general_params.tx_bip_fem_manufacturer;
1794b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen
1804b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen	wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n",
1814b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen		     answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer);
1824b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinen
1834b34d432b0fcff422304de4eb49d6da861fe335cJuuso Oikarinenout:
18498b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	kfree(gen_parms);
18598b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	return ret;
18698b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho}
18798b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
18898b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelhoint wl1271_cmd_radio_parms(struct wl1271 *wl)
18998b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho{
190bc765bf3b9a095b3e41c8cda80643901884c3dd4Shahar Levi	struct wl1271_nvs_file *nvs = (struct wl1271_nvs_file *)wl->nvs;
19198b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	struct wl1271_radio_parms_cmd *radio_parms;
192bc765bf3b9a095b3e41c8cda80643901884c3dd4Shahar Levi	struct wl1271_ini_general_params *gp = &nvs->general_params;
193152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen	int ret;
194152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen
195152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen	if (!wl->nvs)
196152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen		return -ENODEV;
19798b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
19898b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL);
19998b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	if (!radio_parms)
20098b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho		return -ENOMEM;
20198b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
20298b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
20398b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
204a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen	/* 2.4GHz parameters */
205bc765bf3b9a095b3e41c8cda80643901884c3dd4Shahar Levi	memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2,
206eb70eb723b489dd4e233e22e47d993f59858cdd8Juuso Oikarinen	       sizeof(struct wl1271_ini_band_params_2));
207eb70eb723b489dd4e233e22e47d993f59858cdd8Juuso Oikarinen	memcpy(&radio_parms->dyn_params_2,
208bc765bf3b9a095b3e41c8cda80643901884c3dd4Shahar Levi	       &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params,
209eb70eb723b489dd4e233e22e47d993f59858cdd8Juuso Oikarinen	       sizeof(struct wl1271_ini_fem_params_2));
210152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen
211a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen	/* 5GHz parameters */
212a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen	memcpy(&radio_parms->static_params_5,
213bc765bf3b9a095b3e41c8cda80643901884c3dd4Shahar Levi	       &nvs->stat_radio_params_5,
214a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen	       sizeof(struct wl1271_ini_band_params_5));
215a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen	memcpy(&radio_parms->dyn_params_5,
216bc765bf3b9a095b3e41c8cda80643901884c3dd4Shahar Levi	       &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params,
217a7da74fc88bff6f82f8255f2def49907f82f4c61Juuso Oikarinen	       sizeof(struct wl1271_ini_fem_params_5));
21898b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
21998b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
22098b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho		    radio_parms, sizeof(*radio_parms));
22198b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
22298b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0);
22349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	if (ret < 0)
22449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed");
22549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
22649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	kfree(radio_parms);
22749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	return ret;
22849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi}
22949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
23049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Leviint wl128x_cmd_radio_parms(struct wl1271 *wl)
23149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi{
23249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs;
23349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	struct wl128x_radio_parms_cmd *radio_parms;
23449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	struct wl128x_ini_general_params *gp = &nvs->general_params;
23549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	int ret;
23649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
23749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	if (!wl->nvs)
23849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		return -ENODEV;
23949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
24049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	radio_parms = kzalloc(sizeof(*radio_parms), GFP_KERNEL);
24149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	if (!radio_parms)
24249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		return -ENOMEM;
24349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
24449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM;
24549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
24649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	/* 2.4GHz parameters */
24749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2,
24849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	       sizeof(struct wl128x_ini_band_params_2));
24949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	memcpy(&radio_parms->dyn_params_2,
25049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	       &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params,
25149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	       sizeof(struct wl128x_ini_fem_params_2));
25249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
25349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	/* 5GHz parameters */
25449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	memcpy(&radio_parms->static_params_5,
25549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	       &nvs->stat_radio_params_5,
25649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	       sizeof(struct wl128x_ini_band_params_5));
25749d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	memcpy(&radio_parms->dyn_params_5,
25849d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	       &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params,
25949d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	       sizeof(struct wl128x_ini_fem_params_5));
26049d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
26149d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	radio_parms->fem_vendor_and_options = nvs->fem_vendor_and_options;
26249d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
26349d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ",
26449d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi		    radio_parms, sizeof(*radio_parms));
26549d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi
26649d750ca14cd49e76ab039b33b5a621e0a92b9fdShahar Levi	ret = wl1271_cmd_test(wl, radio_parms, sizeof(*radio_parms), 0);
26798b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	if (ret < 0)
26898b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho		wl1271_warning("CMD_INI_FILE_RADIO_PARAM failed");
26998b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
27098b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	kfree(radio_parms);
27198b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho	return ret;
27298b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho}
27398b5dd5ded8cb59b598b2c0c396100054779eda7Luciano Coelho
274644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinenint wl1271_cmd_ext_radio_parms(struct wl1271 *wl)
275644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen{
276644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	struct wl1271_ext_radio_parms_cmd *ext_radio_parms;
277644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	struct conf_rf_settings *rf = &wl->conf.rf;
278644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	int ret;
279644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
280644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	if (!wl->nvs)
281644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen		return -ENODEV;
282644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
283644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	ext_radio_parms = kzalloc(sizeof(*ext_radio_parms), GFP_KERNEL);
284644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	if (!ext_radio_parms)
285644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen		return -ENOMEM;
286644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
287644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	ext_radio_parms->test.id = TEST_CMD_INI_FILE_RF_EXTENDED_PARAM;
288644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
289644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	memcpy(ext_radio_parms->tx_per_channel_power_compensation_2,
290644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	       rf->tx_per_channel_power_compensation_2,
291644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	       CONF_TX_PWR_COMPENSATION_LEN_2);
292644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	memcpy(ext_radio_parms->tx_per_channel_power_compensation_5,
293644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	       rf->tx_per_channel_power_compensation_5,
294644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	       CONF_TX_PWR_COMPENSATION_LEN_5);
295644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
296644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_EXT_RADIO_PARAM: ",
297644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen		    ext_radio_parms, sizeof(*ext_radio_parms));
298644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
299644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	ret = wl1271_cmd_test(wl, ext_radio_parms, sizeof(*ext_radio_parms), 0);
300644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	if (ret < 0)
301644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen		wl1271_warning("TEST_CMD_INI_FILE_RF_EXTENDED_PARAM failed");
302644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
303644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	kfree(ext_radio_parms);
304644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen	return ret;
305644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen}
306644a48607cd40954b6fb095b39a3ccaa0204191eJuuso Oikarinen
30799d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho/*
30899d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho * Poll the mailbox event field until any of the bits in the mask is set or a
30999d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho * timeout occurs (WL1271_EVENT_TIMEOUT in msecs)
31099d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho */
31105285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsovstatic int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask)
31299d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho{
31399d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	u32 events_vector, event;
31499d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	unsigned long timeout;
31599d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho
31699d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT);
31799d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho
31899d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	do {
31952b0e7a61fd4b67fe8efe295297d8549f052f786Juuso Oikarinen		if (time_after(jiffies, timeout)) {
32005285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov			wl1271_debug(DEBUG_CMD, "timeout waiting for event %d",
32105285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov				     (int)mask);
32299d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho			return -ETIMEDOUT;
32352b0e7a61fd4b67fe8efe295297d8549f052f786Juuso Oikarinen		}
32499d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho
32599d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho		msleep(1);
32699d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho
32799d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho		/* read from both event fields */
32899d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho		wl1271_read(wl, wl->mbox_ptr[0], &events_vector,
32999d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho			    sizeof(events_vector), false);
33099d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho		event = events_vector & mask;
33199d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho		wl1271_read(wl, wl->mbox_ptr[1], &events_vector,
33299d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho			    sizeof(events_vector), false);
33399d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho		event |= events_vector & mask;
33499d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	} while (!event);
33599d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho
33699d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	return 0;
33799d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho}
33899d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho
33905285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsovstatic int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask)
34005285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov{
34105285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	int ret;
34205285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov
34305285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask);
34405285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	if (ret != 0) {
34505285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov		ieee80211_queue_work(wl->hw, &wl->recovery_work);
34605285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov		return ret;
34705285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	}
34805285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov
34905285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	return 0;
35005285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov}
35105285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov
35215305498a443c181c8fb5deafb94eae585fe3ad5Juuso Oikarinenint wl1271_cmd_join(struct wl1271 *wl, u8 bss_type)
353f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
354f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct wl1271_cmd_join *join;
355f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret, i;
356f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	u8 *bssid;
357f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
358f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	join = kzalloc(sizeof(*join), GFP_KERNEL);
359f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (!join) {
360f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		ret = -ENOMEM;
361f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
362f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
363f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
364f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd join");
365f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
366f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	/* Reverse order BSSID */
367f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	bssid = (u8 *) &join->bssid_lsb;
368f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	for (i = 0; i < ETH_ALEN; i++)
369f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		bssid[i] = wl->bssid[ETH_ALEN - i - 1];
370f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
371d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	join->rx_config_options = cpu_to_le32(wl->rx_config);
372d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	join->rx_filter_options = cpu_to_le32(wl->rx_filter);
37315305498a443c181c8fb5deafb94eae585fe3ad5Juuso Oikarinen	join->bss_type = bss_type;
37423a7a51c5a35b30aa3edcc31a6a57b01c523b4cdLuciano Coelho	join->basic_rate_set = cpu_to_le32(wl->basic_rate_set);
37572c2d9e511846a4f2759389b38ed8a5553579eb3Eliad Peller	join->supported_rate_set = cpu_to_le32(wl->rate_set);
376f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
377ebba60c66b3aa321a84c9a90a343c91fde972066Juuso Oikarinen	if (wl->band == IEEE80211_BAND_5GHZ)
378a410264553447ff90bf13e3662684e794e5ff83eTeemu Paasikivi		join->bss_type |= WL1271_JOIN_CMD_BSS_TYPE_5GHZ;
379f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
38060e84c2ebb7b04361cf1ba0d325cc93366bd04a6Juuso Oikarinen	join->beacon_interval = cpu_to_le16(wl->beacon_int);
381ae751bab9f55c3152ebf713c89a4fb6f439c2575Luciano Coelho	join->dtim_interval = WL1271_DEFAULT_DTIM_PERIOD;
382a410264553447ff90bf13e3662684e794e5ff83eTeemu Paasikivi
383f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	join->channel = wl->channel;
384f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	join->ssid_len = wl->ssid_len;
385f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	memcpy(join->ssid, wl->ssid, wl->ssid_len);
386f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
387f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET;
388f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
389ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen	/* reset TX security counters */
390ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen	wl->tx_security_last_seq = 0;
39104e36fc5f1ff4e349ea21de8d15e4e1844d04197Juuso Oikarinen	wl->tx_security_seq = 0;
392f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
39372c2d9e511846a4f2759389b38ed8a5553579eb3Eliad Peller	wl1271_debug(DEBUG_CMD, "cmd join: basic_rate_set=0x%x, rate_set=0x%x",
39472c2d9e511846a4f2759389b38ed8a5553579eb3Eliad Peller		join->basic_rate_set, join->supported_rate_set);
39572c2d9e511846a4f2759389b38ed8a5553579eb3Eliad Peller
396fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join), 0);
397f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
398f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_error("failed to initiate cmd join");
399f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out_free;
400f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
401f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
40299d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	ret = wl1271_cmd_wait_for_event(wl, JOIN_EVENT_COMPLETE_ID);
40399d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho	if (ret < 0)
40499d84c1de8fdf5f9b09f07fdbc628857a040bf8bLuciano Coelho		wl1271_error("cmd join event completion error");
405f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
406f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout_free:
407f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	kfree(join);
408f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
409f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout:
410f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
411f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
412f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
413f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/**
414f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * send test command to firmware
415f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho *
416f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @wl: wl struct
417f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @buf: buffer containing the command, with all headers, must work with dma
418f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @len: length of the buffer
419f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @answer: is answer needed
420f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */
421f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer)
422f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
423f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret;
424fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	size_t res_len = 0;
425f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
426f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd test");
427f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
428fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	if (answer)
429fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen		res_len = buf_len;
430fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen
431fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_TEST, buf, buf_len, res_len);
432f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
433f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
434f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_warning("TEST command failed");
435f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		return ret;
436f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
437f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
438fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	return ret;
439f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
440f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
441f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/**
442f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * read acx from firmware
443f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho *
444f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @wl: wl struct
445f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @id: acx id
446f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @buf: buffer for the response, including all headers, must work with dma
447f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @len: lenght of buf
448f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */
449f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len)
450f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
451f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct acx_header *acx = buf;
452f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret;
453f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
454f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd interrogate");
455f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
456d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	acx->id = cpu_to_le16(id);
457f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
458f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	/* payload length, does not include any headers */
459d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	acx->len = cpu_to_le16(len - sizeof(*acx));
460f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
461fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx), len);
462fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	if (ret < 0)
463f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_error("INTERROGATE command failed");
464f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
465f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
466f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
467f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
468f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/**
469f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * write acx value to firmware
470f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho *
471f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @wl: wl struct
472f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @id: acx id
473f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @buf: buffer containing acx, including all headers, must work with dma
474f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @len: length of buf
475f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */
476f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len)
477f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
478f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct acx_header *acx = buf;
479f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret;
480f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
481f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd configure");
482f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
483d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	acx->id = cpu_to_le16(id);
484f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
485f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	/* payload length, does not include any headers */
486d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	acx->len = cpu_to_le16(len - sizeof(*acx));
487f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
488fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len, 0);
489f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
490f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_warning("CONFIGURE command NOK");
491f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		return ret;
492f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
493f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
494f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return 0;
495f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
496f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
49794210897e2b7df8446fdecd360342149e5b4a400Luciano Coelhoint wl1271_cmd_data_path(struct wl1271 *wl, bool enable)
498f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
499f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct cmd_enabledisable_path *cmd;
500f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret;
501f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	u16 cmd_rx, cmd_tx;
502f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
503f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd data path");
504f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
505f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
506f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (!cmd) {
507f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		ret = -ENOMEM;
508f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
509f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
510f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
51194210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho	/* the channel here is only used for calibration, so hardcoded to 1 */
51294210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho	cmd->channel = 1;
513f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
514f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (enable) {
515f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		cmd_rx = CMD_ENABLE_RX;
516f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		cmd_tx = CMD_ENABLE_TX;
517f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	} else {
518f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		cmd_rx = CMD_DISABLE_RX;
519f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		cmd_tx = CMD_DISABLE_TX;
520f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
521f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
522fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd), 0);
523f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
524f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_error("rx %s cmd for channel %d failed",
52594210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho			     enable ? "start" : "stop", cmd->channel);
526f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
527f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
528f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
529f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d",
53094210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho		     enable ? "start" : "stop", cmd->channel);
531f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
532fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd), 0);
533f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
534f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_error("tx %s cmd for channel %d failed",
53594210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho			     enable ? "start" : "stop", cmd->channel);
5361b00f2b560028a68cdbc57a0352163afd79822ddJuuso Oikarinen		goto out;
537f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
538f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
539f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d",
54094210897e2b7df8446fdecd360342149e5b4a400Luciano Coelho		     enable ? "start" : "stop", cmd->channel);
541f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
542f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout:
543f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	kfree(cmd);
544f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
545f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
546f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
547c8bde243421d759844264cf11e4248e7862c2722Eliad Pellerint wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode)
548f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
549f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct wl1271_cmd_ps_params *ps_params = NULL;
550f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret = 0;
551f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
552f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd set ps mode");
553f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
554f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL);
555f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (!ps_params) {
556f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		ret = -ENOMEM;
557f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
558f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
559f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
560f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	ps_params->ps_mode = ps_mode;
561f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
562f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params,
563fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen			      sizeof(*ps_params), 0);
564f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
565f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_error("cmd set_ps_mode failed");
566f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
567f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
568f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
569f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout:
570f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	kfree(ps_params);
571f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
572f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
573f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
574f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id,
575606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen			    void *buf, size_t buf_len, int index, u32 rates)
576f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
577f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct wl1271_cmd_template_set *cmd;
578f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret = 0;
579f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
580f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd template_set %d", template_id);
581f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
582f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	WARN_ON(buf_len > WL1271_CMD_TEMPL_MAX_SIZE);
583f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	buf_len = min_t(size_t, buf_len, WL1271_CMD_TEMPL_MAX_SIZE);
584f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
585f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
586f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (!cmd) {
587f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		ret = -ENOMEM;
588f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
589f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
590f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
591f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->len = cpu_to_le16(buf_len);
592f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->template_type = template_id;
593606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen	cmd->enabled_rates = cpu_to_le32(rates);
5941e05a81888318752e9a6d2158a95ddd6442ae117Arik Nemtsov	cmd->short_retry_limit = wl->conf.tx.tmpl_short_retry_limit;
5951e05a81888318752e9a6d2158a95ddd6442ae117Arik Nemtsov	cmd->long_retry_limit = wl->conf.tx.tmpl_long_retry_limit;
596bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	cmd->index = index;
597f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
598f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (buf)
599f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		memcpy(cmd->template_data, buf, buf_len);
600f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
601fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_SET_TEMPLATE, cmd, sizeof(*cmd), 0);
602f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
603f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_warning("cmd set_template failed: %d", ret);
604f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out_free;
605f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
606f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
607f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout_free:
608f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	kfree(cmd);
609f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
610f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout:
611f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
612f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
613f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
614f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_build_null_data(struct wl1271 *wl)
615f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
616a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	struct sk_buff *skb = NULL;
617a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	int size;
618a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	void *ptr;
619a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	int ret = -ENOMEM;
620f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
621f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
622a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	if (wl->bss_type == BSS_TYPE_IBSS) {
623a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen		size = sizeof(struct wl12xx_null_data_template);
624a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen		ptr = NULL;
625a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	} else {
626a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen		skb = ieee80211_nullfunc_get(wl->hw, wl->vif);
627a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen		if (!skb)
628a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen			goto out;
629a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen		size = skb->len;
630a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen		ptr = skb->data;
631a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	}
632a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen
633606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, ptr, size, 0,
6348eab7b4708b5ef4701ecbe5d659f99743b77b668Juuso Oikarinen				      wl->basic_rate);
635f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
636899e6e65c39990a76c17940625dbe6001f618734Kalle Valoout:
637899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	dev_kfree_skb(skb);
638a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen	if (ret)
639a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen		wl1271_warning("cmd buld null data failed %d", ret);
640a0cb7be4f4fa765dcfa82675811cd7e7713b5610Juuso Oikarinen
641899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	return ret;
642f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
643f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
644f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
645bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinenint wl1271_cmd_build_klv_null_data(struct wl1271 *wl)
646bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen{
647bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	struct sk_buff *skb = NULL;
648bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	int ret = -ENOMEM;
649bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen
650bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	skb = ieee80211_nullfunc_get(wl->hw, wl->vif);
651bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	if (!skb)
652bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen		goto out;
653bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen
654bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_KLV,
655bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen				      skb->data, skb->len,
656606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen				      CMD_TEMPL_KLV_IDX_NULL_DATA,
6578eab7b4708b5ef4701ecbe5d659f99743b77b668Juuso Oikarinen				      wl->basic_rate);
658bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen
659bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinenout:
660bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	dev_kfree_skb(skb);
661bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	if (ret)
662bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen		wl1271_warning("cmd build klv null data failed %d", ret);
663bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen
664bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen	return ret;
665bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen
666bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen}
667bfb24c9e16921f0e57fcec5180ffa20929832545Juuso Oikarinen
668f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid)
669f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
670899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	struct sk_buff *skb;
671899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	int ret = 0;
672c3fea1994ac34dafa3ebb40d4f95354b2782af31Juuso Oikarinen
673899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	skb = ieee80211_pspoll_get(wl->hw, wl->vif);
674899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	if (!skb)
675899e6e65c39990a76c17940625dbe6001f618734Kalle Valo		goto out;
676f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
677899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, skb->data,
678849923f43ca681cc86a401178db31acb60e79f3bJuuso Oikarinen				      skb->len, 0, wl->basic_rate_set);
679f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
680899e6e65c39990a76c17940625dbe6001f618734Kalle Valoout:
681899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	dev_kfree_skb(skb);
682899e6e65c39990a76c17940625dbe6001f618734Kalle Valo	return ret;
683f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
684f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
685818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valoint wl1271_cmd_build_probe_req(struct wl1271 *wl,
686818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo			       const u8 *ssid, size_t ssid_len,
687818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo			       const u8 *ie, size_t ie_len, u8 band)
688f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
689818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo	struct sk_buff *skb;
690abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi	int ret;
691f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
692818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo	skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len,
693818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo				     ie, ie_len);
694818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo	if (!skb) {
695818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo		ret = -ENOMEM;
696818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo		goto out;
697818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo	}
698818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo
699818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo	wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len);
700f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
701abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi	if (band == IEEE80211_BAND_2GHZ)
702abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi		ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
703606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen					      skb->data, skb->len, 0,
704606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen					      wl->conf.tx.basic_rate);
705abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi	else
706abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi		ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
707606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen					      skb->data, skb->len, 0,
708606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen					      wl->conf.tx.basic_rate_5);
709818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo
710818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valoout:
711818e3063a9546fcd826155dd47582a6e2f4d1c37Kalle Valo	dev_kfree_skb(skb);
712abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi	return ret;
713f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
714f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
7152f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinenstruct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
7162f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen					      struct sk_buff *skb)
7172f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen{
7182f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	int ret;
7192f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen
7202f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	if (!skb)
7212f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen		skb = ieee80211_ap_probereq_get(wl->hw, wl->vif);
7222f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	if (!skb)
7232f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen		goto out;
7242f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen
7252f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	wl1271_dump(DEBUG_SCAN, "AP PROBE REQ: ", skb->data, skb->len);
7262f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen
7272f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	if (wl->band == IEEE80211_BAND_2GHZ)
7282f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen		ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
7292f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen					      skb->data, skb->len, 0,
7302f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen					      wl->conf.tx.basic_rate);
7312f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	else
7322f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen		ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
7332f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen					      skb->data, skb->len, 0,
7342f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen					      wl->conf.tx.basic_rate_5);
7352f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen
7362f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	if (ret < 0)
7372f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen		wl1271_error("Unable to set ap probe request template.");
7382f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen
7392f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinenout:
7402f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen	return skb;
7412f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen}
7422f6724b24525fc989c0707974b23d96b36132385Juuso Oikarinen
743c5312772156bb5f9b2e95e4c91526d578426a069Eliad Pellerint wl1271_cmd_build_arp_rsp(struct wl1271 *wl, __be32 ip_addr)
744c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller{
745c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	int ret;
746c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	struct wl12xx_arp_rsp_template tmpl;
747c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	struct ieee80211_hdr_3addr *hdr;
748c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	struct arphdr *arp_hdr;
749c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
750c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	memset(&tmpl, 0, sizeof(tmpl));
751c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
752c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	/* mac80211 header */
753c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	hdr = &tmpl.hdr;
754c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
755c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller					 IEEE80211_STYPE_DATA |
756c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller					 IEEE80211_FCTL_TODS);
757c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	memcpy(hdr->addr1, wl->vif->bss_conf.bssid, ETH_ALEN);
758c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	memcpy(hdr->addr2, wl->vif->addr, ETH_ALEN);
759c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	memset(hdr->addr3, 0xff, ETH_ALEN);
760c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
761c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	/* llc layer */
762c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	memcpy(tmpl.llc_hdr, rfc1042_header, sizeof(rfc1042_header));
7636177eaea277527e48753d050723cd138494c98a8Eliad Peller	tmpl.llc_type = cpu_to_be16(ETH_P_ARP);
764c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
765c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	/* arp header */
766c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	arp_hdr = &tmpl.arp_hdr;
7676177eaea277527e48753d050723cd138494c98a8Eliad Peller	arp_hdr->ar_hrd = cpu_to_be16(ARPHRD_ETHER);
7686177eaea277527e48753d050723cd138494c98a8Eliad Peller	arp_hdr->ar_pro = cpu_to_be16(ETH_P_IP);
769c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	arp_hdr->ar_hln = ETH_ALEN;
770c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	arp_hdr->ar_pln = 4;
7716177eaea277527e48753d050723cd138494c98a8Eliad Peller	arp_hdr->ar_op = cpu_to_be16(ARPOP_REPLY);
772c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
773c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	/* arp payload */
774c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	memcpy(tmpl.sender_hw, wl->vif->addr, ETH_ALEN);
775c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	tmpl.sender_ip = ip_addr;
776c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
777c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	ret = wl1271_cmd_template_set(wl, CMD_TEMPL_ARP_RSP,
778c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller				      &tmpl, sizeof(tmpl), 0,
779c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller				      wl->basic_rate);
780c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
781c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller	return ret;
782c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller}
783c5312772156bb5f9b2e95e4c91526d578426a069Eliad Peller
784023e082609ba3225dbd5c33933a90156d2201d7fKalle Valoint wl1271_build_qos_null_data(struct wl1271 *wl)
785023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo{
786023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	struct ieee80211_qos_hdr template;
787023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo
788023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	memset(&template, 0, sizeof(template));
789023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo
790023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	memcpy(template.addr1, wl->bssid, ETH_ALEN);
791023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	memcpy(template.addr2, wl->mac_addr, ETH_ALEN);
792023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	memcpy(template.addr3, wl->bssid, ETH_ALEN);
793023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo
794023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	template.frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA |
795023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo					     IEEE80211_STYPE_QOS_NULLFUNC |
796023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo					     IEEE80211_FCTL_TODS);
797023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo
798023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	/* FIXME: not sure what priority to use here */
799023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	template.qos_ctrl = cpu_to_le16(0);
800023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo
801023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo	return wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, &template,
802606c1487ac894798121bc2c64d27c1953c5a6210Juuso Oikarinen				       sizeof(template), 0,
8038eab7b4708b5ef4701ecbe5d659f99743b77b668Juuso Oikarinen				       wl->basic_rate);
804023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo}
805023e082609ba3225dbd5c33933a90156d2201d7fKalle Valo
80698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovint wl1271_cmd_set_sta_default_wep_key(struct wl1271 *wl, u8 id)
807f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
80898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	struct wl1271_cmd_set_sta_keys *cmd;
809f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret = 0;
810f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
811f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id);
812f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
813f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
814f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (!cmd) {
815f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		ret = -ENOMEM;
816f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
817f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
818f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
819f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->id = id;
820d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	cmd->key_action = cpu_to_le16(KEY_SET_ID);
821f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->key_type = KEY_WEP;
822f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
823fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0);
824f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
825f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_warning("cmd set_default_wep_key failed: %d", ret);
826f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
827f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
828f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
829f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout:
830f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	kfree(cmd);
831f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
832f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
833f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
834f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
83598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovint wl1271_cmd_set_ap_default_wep_key(struct wl1271 *wl, u8 id)
83698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov{
83798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	struct wl1271_cmd_set_ap_keys *cmd;
83898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	int ret = 0;
83998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
84098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	wl1271_debug(DEBUG_CMD, "cmd set_ap_default_wep_key %d", id);
84198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
84298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
84398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (!cmd) {
84498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		ret = -ENOMEM;
84598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out;
84698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
84798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
84898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->hlid = WL1271_AP_BROADCAST_HLID;
84998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->key_id = id;
85098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->lid_key_type = WEP_DEFAULT_LID_TYPE;
85198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->key_action = cpu_to_le16(KEY_SET_ID);
85298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->key_type = KEY_WEP;
85398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
85498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0);
85598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (ret < 0) {
85698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		wl1271_warning("cmd set_ap_default_wep_key failed: %d", ret);
85798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out;
85898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
85998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
86098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout:
86198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	kfree(cmd);
86298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
86398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	return ret;
86498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov}
86598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
86698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovint wl1271_cmd_set_sta_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
867ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen		       u8 key_size, const u8 *key, const u8 *addr,
868ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen		       u32 tx_seq_32, u16 tx_seq_16)
869f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
87098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	struct wl1271_cmd_set_sta_keys *cmd;
871f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret = 0;
872f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
873f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
874f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (!cmd) {
875f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		ret = -ENOMEM;
876f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		goto out;
877f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
878f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
879f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (key_type != KEY_WEP)
880f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		memcpy(cmd->addr, addr, ETH_ALEN);
881f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
882d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	cmd->key_action = cpu_to_le16(action);
883f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->key_size = key_size;
884f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->key_type = key_type;
885f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
886d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16);
887d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32);
888ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen
889f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	/* we have only one SSID profile */
890f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->ssid_profile = 0;
891f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
892f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	cmd->id = id;
893f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
894f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (key_type == KEY_TKIP) {
895f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		/*
896f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		 * We get the key in the following form:
897f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		 * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes)
898f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		 * but the target is expecting:
899f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		 * TKIP - RX MIC - TX MIC
900f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		 */
901f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		memcpy(cmd->key, key, 16);
902f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		memcpy(cmd->key + 16, key + 24, 8);
903f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		memcpy(cmd->key + 24, key + 16, 8);
904f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
905f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	} else {
906f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		memcpy(cmd->key, key, key_size);
907f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
908f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
909f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_dump(DEBUG_CRYPT, "TARGET KEY: ", cmd, sizeof(*cmd));
910f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
911fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0);
912f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0) {
913f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_warning("could not set keys");
914152ee6e09e2ce54d7d1cc9d338b82c0bf3cbbc95Juuso Oikarinen	goto out;
915f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
916f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
917f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout:
918f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	kfree(cmd);
919f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
920f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
921f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
92225a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho
92398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovint wl1271_cmd_set_ap_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type,
92498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov			u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32,
92598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov			u16 tx_seq_16)
92698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov{
92798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	struct wl1271_cmd_set_ap_keys *cmd;
92898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	int ret = 0;
92998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	u8 lid_type;
93098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
93198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
93298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (!cmd)
93398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		return -ENOMEM;
93498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
93598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (hlid == WL1271_AP_BROADCAST_HLID) {
93698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		if (key_type == KEY_WEP)
93798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov			lid_type = WEP_DEFAULT_LID_TYPE;
93898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		else
93998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov			lid_type = BROADCAST_LID_TYPE;
94098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	} else {
94198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		lid_type = UNICAST_LID_TYPE;
94298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
94398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
94498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	wl1271_debug(DEBUG_CRYPT, "ap key action: %d id: %d lid: %d type: %d"
94598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		     " hlid: %d", (int)action, (int)id, (int)lid_type,
94698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		     (int)key_type, (int)hlid);
94798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
94898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->lid_key_type = lid_type;
94998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->hlid = hlid;
95098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->key_action = cpu_to_le16(action);
95198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->key_size = key_size;
95298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->key_type = key_type;
95398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->key_id = id;
95498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16);
95598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32);
95698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
95798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (key_type == KEY_TKIP) {
95898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		/*
95998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		 * We get the key in the following form:
96098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		 * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes)
96198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		 * but the target is expecting:
96298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		 * TKIP - RX MIC - TX MIC
96398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		 */
96498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		memcpy(cmd->key, key, 16);
96598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		memcpy(cmd->key + 16, key + 24, 8);
96698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		memcpy(cmd->key + 24, key + 16, 8);
96798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	} else {
96898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		memcpy(cmd->key, key, key_size);
96998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
97098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
97198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	wl1271_dump(DEBUG_CRYPT, "TARGET AP KEY: ", cmd, sizeof(*cmd));
97298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
97398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd), 0);
97498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (ret < 0) {
97598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		wl1271_warning("could not set ap keys");
97698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out;
97798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
97898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
97998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout:
98098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	kfree(cmd);
98198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	return ret;
98298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov}
98398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
98425a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelhoint wl1271_cmd_disconnect(struct wl1271 *wl)
98525a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho{
98625a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	struct wl1271_cmd_disconnect *cmd;
98725a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	int ret = 0;
98825a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho
98925a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	wl1271_debug(DEBUG_CMD, "cmd disconnect");
99025a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho
99125a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
99225a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	if (!cmd) {
99325a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho		ret = -ENOMEM;
99425a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho		goto out;
99525a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	}
99625a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho
997d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	cmd->rx_config_options = cpu_to_le32(wl->rx_config);
998d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	cmd->rx_filter_options = cpu_to_le32(wl->rx_filter);
99925a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	/* disconnect reason is not used in immediate disconnections */
100025a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	cmd->type = DISCONNECT_IMMEDIATE;
100125a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho
1002fa867e7355a1bdcd9bf7d55ebe9296f5b9c4028aJuuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_DISCONNECT, cmd, sizeof(*cmd), 0);
100325a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	if (ret < 0) {
100425a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho		wl1271_error("failed to send disconnect command");
100525a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho		goto out_free;
100625a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	}
100725a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho
10082f826f55404ca43efced94d548356182820e764fLuciano Coelho	ret = wl1271_cmd_wait_for_event(wl, DISCONNECT_EVENT_COMPLETE_ID);
10092f826f55404ca43efced94d548356182820e764fLuciano Coelho	if (ret < 0)
10102f826f55404ca43efced94d548356182820e764fLuciano Coelho		wl1271_error("cmd disconnect event completion error");
10112f826f55404ca43efced94d548356182820e764fLuciano Coelho
101225a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelhoout_free:
101325a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	kfree(cmd);
101425a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho
101525a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelhoout:
101625a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho	return ret;
101725a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho}
1018be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen
1019be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinenint wl1271_cmd_set_sta_state(struct wl1271 *wl)
1020be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen{
1021be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	struct wl1271_cmd_set_sta_state *cmd;
1022be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	int ret = 0;
1023be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen
1024be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	wl1271_debug(DEBUG_CMD, "cmd set sta state");
1025be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen
1026be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
1027be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	if (!cmd) {
1028be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen		ret = -ENOMEM;
1029be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen		goto out;
1030be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	}
1031be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen
1032be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	cmd->state = WL1271_CMD_STA_STATE_CONNECTED;
1033be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen
1034be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	ret = wl1271_cmd_send(wl, CMD_SET_STA_STATE, cmd, sizeof(*cmd), 0);
1035be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	if (ret < 0) {
1036be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen		wl1271_error("failed to send set STA state command");
1037be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen		goto out_free;
1038be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	}
1039be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen
1040be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinenout_free:
1041be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	kfree(cmd);
1042be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen
1043be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinenout:
1044be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen	return ret;
1045be86cbea1e9c3a4dd8faedcfa327495d09fe3531Juuso Oikarinen}
104698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
104798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovint wl1271_cmd_start_bss(struct wl1271 *wl)
104898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov{
104998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	struct wl1271_cmd_bss_start *cmd;
105098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
105198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	int ret;
105298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
105398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	wl1271_debug(DEBUG_CMD, "cmd start bss");
105498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
105598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	/*
105698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	 * FIXME: We currently do not support hidden SSID. The real SSID
105798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	 * should be fetched from mac80211 first.
105898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	 */
105998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (wl->ssid_len == 0) {
106098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		wl1271_warning("Hidden SSID currently not supported for AP");
106198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		ret = -EINVAL;
106298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out;
106398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
106498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
106598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
106698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (!cmd) {
106798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		ret = -ENOMEM;
106898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out;
106998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
107098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
107198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	memcpy(cmd->bssid, bss_conf->bssid, ETH_ALEN);
107298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
10731d4801f2689dc2618fdb5e83d4cb7743747491edEliad Peller	cmd->aging_period = cpu_to_le16(WL1271_AP_DEF_INACTIV_SEC);
107498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->bss_index = WL1271_AP_BSS_INDEX;
107598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->global_hlid = WL1271_AP_GLOBAL_HLID;
107698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->broadcast_hlid = WL1271_AP_BROADCAST_HLID;
107798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->basic_rate_set = cpu_to_le32(wl->basic_rate_set);
107898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->beacon_interval = cpu_to_le16(wl->beacon_int);
107998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->dtim_interval = bss_conf->dtim_period;
108098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->beacon_expiry = WL1271_AP_DEF_BEACON_EXP;
108198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->channel = wl->channel;
108298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->ssid_len = wl->ssid_len;
108398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->ssid_type = SSID_TYPE_PUBLIC;
108498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	memcpy(cmd->ssid, wl->ssid, wl->ssid_len);
108598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
108698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	switch (wl->band) {
108798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	case IEEE80211_BAND_2GHZ:
108898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		cmd->band = RADIO_BAND_2_4GHZ;
108998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		break;
109098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	case IEEE80211_BAND_5GHZ:
109198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		cmd->band = RADIO_BAND_5GHZ;
109298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		break;
109398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	default:
109498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		wl1271_warning("bss start - unknown band: %d", (int)wl->band);
109598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		cmd->band = RADIO_BAND_2_4GHZ;
109698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		break;
109798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
109898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
109998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	ret = wl1271_cmd_send(wl, CMD_BSS_START, cmd, sizeof(*cmd), 0);
110098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (ret < 0) {
110198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		wl1271_error("failed to initiate cmd start bss");
110298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out_free;
110398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
110498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
110598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout_free:
110698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	kfree(cmd);
110798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
110898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout:
110998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	return ret;
111098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov}
111198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
111298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovint wl1271_cmd_stop_bss(struct wl1271 *wl)
111398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov{
111498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	struct wl1271_cmd_bss_start *cmd;
111598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	int ret;
111698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
111798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	wl1271_debug(DEBUG_CMD, "cmd stop bss");
111898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
111998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
112098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (!cmd) {
112198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		ret = -ENOMEM;
112298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out;
112398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
112498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
112598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->bss_index = WL1271_AP_BSS_INDEX;
112698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
112798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	ret = wl1271_cmd_send(wl, CMD_BSS_STOP, cmd, sizeof(*cmd), 0);
112898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (ret < 0) {
112998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		wl1271_error("failed to initiate cmd stop bss");
113098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out_free;
113198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
113298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
113398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout_free:
113498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	kfree(cmd);
113598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
113698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout:
113798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	return ret;
113898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov}
113998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
114098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovint wl1271_cmd_add_sta(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid)
114198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov{
114298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	struct wl1271_cmd_add_sta *cmd;
114398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	int ret;
114498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
114598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	wl1271_debug(DEBUG_CMD, "cmd add sta %d", (int)hlid);
114698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
114798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
114898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (!cmd) {
114998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		ret = -ENOMEM;
115098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out;
115198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
115298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
115398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	/* currently we don't support UAPSD */
115498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->sp_len = 0;
115598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
115698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	memcpy(cmd->addr, sta->addr, ETH_ALEN);
115798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->bss_index = WL1271_AP_BSS_INDEX;
115898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->aid = sta->aid;
115998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->hlid = hlid;
116098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
116198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	/*
116298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	 * FIXME: Does STA support QOS? We need to propagate this info from
116398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	 * hostapd. Currently not that important since this is only used for
116498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	 * sending the correct flavor of null-data packet in response to a
116598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	 * trigger.
116698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	 */
116798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->wmm = 0;
116898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
116998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->supported_rates = cpu_to_le32(wl1271_tx_enabled_rates_get(wl,
117098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov						sta->supp_rates[wl->band]));
117198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
117298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	wl1271_debug(DEBUG_CMD, "new sta rates: 0x%x", cmd->supported_rates);
117398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
117498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	ret = wl1271_cmd_send(wl, CMD_ADD_STA, cmd, sizeof(*cmd), 0);
117598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (ret < 0) {
117698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		wl1271_error("failed to initiate cmd add sta");
117798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out_free;
117898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
117998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
118098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout_free:
118198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	kfree(cmd);
118298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
118398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout:
118498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	return ret;
118598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov}
118698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
118798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovint wl1271_cmd_remove_sta(struct wl1271 *wl, u8 hlid)
118898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov{
118998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	struct wl1271_cmd_remove_sta *cmd;
119098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	int ret;
119198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
119298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	wl1271_debug(DEBUG_CMD, "cmd remove sta %d", (int)hlid);
119398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
119498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
119598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (!cmd) {
119698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		ret = -ENOMEM;
119798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out;
119898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
119998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
120098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->hlid = hlid;
120198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	/* We never send a deauth, mac80211 is in charge of this */
120298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->reason_opcode = 0;
120398bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	cmd->send_deauth_flag = 0;
120498bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
120598bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	ret = wl1271_cmd_send(wl, CMD_REMOVE_STA, cmd, sizeof(*cmd), 0);
120698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	if (ret < 0) {
120798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		wl1271_error("failed to initiate cmd remove sta");
120898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov		goto out_free;
120998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	}
121098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
121105285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	/*
121205285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	 * We are ok with a timeout here. The event is sometimes not sent
121305285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	 * due to a firmware bug.
121405285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	 */
121505285cf9b581af05813cfaa60e23227b009b7754Arik Nemtsov	wl1271_cmd_wait_for_event_or_timeout(wl, STA_REMOVE_COMPLETE_EVENT_ID);
121698bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
121798bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout_free:
121898bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	kfree(cmd);
121998bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov
122098bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsovout:
122198bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov	return ret;
122298bdaabbbced007c7eb89cd373f9cb1640635b46Arik Nemtsov}
1223