cmd.c revision d0f63b202146f3281800ee44823740c8bbf38f11
1f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/* 2f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * This file is part of wl1271 3f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * 4f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * Copyright (C) 2009 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> 29f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 30f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho#include "wl1271.h" 31f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho#include "wl1271_reg.h" 32f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho#include "wl1271_spi.h" 33f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho#include "wl1271_acx.h" 34f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho#include "wl12xx_80211.h" 35f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho#include "wl1271_cmd.h" 36f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 37f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/* 38f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * send command to firmware 39f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * 40f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @wl: wl struct 41f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @id: command id 42f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @buf: buffer containing the command, must work with dma 43f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @len: length of the buffer 44f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */ 45f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len) 46f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 47f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_cmd_header *cmd; 48f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho unsigned long timeout; 49f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u32 intr; 50f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret = 0; 51f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 52f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd = buf; 53d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho cmd->id = cpu_to_le16(id); 54f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd->status = 0; 55f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 56f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho WARN_ON(len % 4 != 0); 57f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 58746214178774bc7f9adbeaef7d43a634570eb870Juuso Oikarinen wl1271_spi_write(wl, wl->cmd_box_addr, buf, len, false); 59f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 60746214178774bc7f9adbeaef7d43a634570eb870Juuso Oikarinen wl1271_spi_write32(wl, ACX_REG_INTERRUPT_TRIG, INTR_TRIG_CMD); 61f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 62f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT); 63f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 64746214178774bc7f9adbeaef7d43a634570eb870Juuso Oikarinen intr = wl1271_spi_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); 65f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) { 66f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (time_after(jiffies, timeout)) { 67f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_error("command complete timeout"); 68f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = -ETIMEDOUT; 69f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out; 70f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 71f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 72f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho msleep(1); 73f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 74746214178774bc7f9adbeaef7d43a634570eb870Juuso Oikarinen intr = wl1271_spi_read32(wl, ACX_REG_INTERRUPT_NO_CLEAR); 75f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 76f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 77746214178774bc7f9adbeaef7d43a634570eb870Juuso Oikarinen wl1271_spi_write32(wl, ACX_REG_INTERRUPT_ACK, 78f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho WL1271_ACX_INTR_CMD_COMPLETE); 79f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 80f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout: 81f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 82f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 83f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 84938e30c9301fbd7c3677d01ad01c7eb4ad78b998Luciano Coelhostatic int wl1271_cmd_cal_channel_tune(struct wl1271 *wl) 85f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 86f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_cmd_cal_channel_tune *cmd; 87f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret = 0; 88f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 89f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 90f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (!cmd) 91f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return -ENOMEM; 92f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 93f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd->test.id = TEST_CMD_CHANNEL_TUNE; 94f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 95f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd->band = WL1271_CHANNEL_TUNE_BAND_2_4; 96f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* set up any channel, 7 is in the middle of the range */ 97f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd->channel = 7; 98f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 99f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0); 100f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) 101f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_warning("TEST_CMD_CHANNEL_TUNE failed"); 102f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 103f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho kfree(cmd); 104f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 105f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 106f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 107938e30c9301fbd7c3677d01ad01c7eb4ad78b998Luciano Coelhostatic int wl1271_cmd_cal_update_ref_point(struct wl1271 *wl) 108f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 109f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_cmd_cal_update_ref_point *cmd; 110f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret = 0; 111f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 112f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 113f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (!cmd) 114f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return -ENOMEM; 115f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 116f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd->test.id = TEST_CMD_UPDATE_PD_REFERENCE_POINT; 117f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 118f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* FIXME: still waiting for the correct values */ 119f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd->ref_power = 0; 120f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd->ref_detector = 0; 121f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 122f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd->sub_band = WL1271_PD_REFERENCE_POINT_BAND_B_G; 123f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 124f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0); 125f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) 126f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_warning("TEST_CMD_UPDATE_PD_REFERENCE_POINT failed"); 127f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 128f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho kfree(cmd); 129f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 130f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 131f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 132938e30c9301fbd7c3677d01ad01c7eb4ad78b998Luciano Coelhostatic int wl1271_cmd_cal_p2g(struct wl1271 *wl) 133f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 134f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_cmd_cal_p2g *cmd; 135f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret = 0; 136f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 137f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 138f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (!cmd) 139f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return -ENOMEM; 140f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 141f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd->test.id = TEST_CMD_P2G_CAL; 142f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 143f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd->sub_band_mask = WL1271_CAL_P2G_BAND_B_G; 144f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 145f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = wl1271_cmd_test(wl, cmd, sizeof(*cmd), 0); 146f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) 147f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_warning("TEST_CMD_P2G_CAL failed"); 148f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 149f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho kfree(cmd); 150f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 151f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 152f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 153938e30c9301fbd7c3677d01ad01c7eb4ad78b998Luciano Coelhostatic int wl1271_cmd_cal(struct wl1271 *wl) 154f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 155f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* 156f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * FIXME: we must make sure that we're not sleeping when calibration 157f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * is done 158f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */ 159f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret; 160f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 161f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_notice("performing tx calibration"); 162f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 163f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = wl1271_cmd_cal_channel_tune(wl); 164f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) 165f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 166f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 167f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = wl1271_cmd_cal_update_ref_point(wl); 168f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) 169f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 170f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 171f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = wl1271_cmd_cal_p2g(wl); 172f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) 173f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 174f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 175f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 176f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 177f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 178d94cd297e58b55bb272fdfd51ff0de7acbc1941bJuuso Oikarinenint wl1271_cmd_join(struct wl1271 *wl) 179f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 180f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho static bool do_cal = true; 181f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_cmd_join *join; 182f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret, i; 183f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u8 *bssid; 184f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 185f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* FIXME: remove when we get calibration from the factory */ 186f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (do_cal) { 187f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = wl1271_cmd_cal(wl); 188f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) 189f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_warning("couldn't calibrate"); 190f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho else 191f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho do_cal = false; 192f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 193f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 194d6e19d135dadb1895296668914d0a15bc3cafcbfLuciano Coelho /* FIXME: This is a workaround, because with the current stack, we 195d6e19d135dadb1895296668914d0a15bc3cafcbfLuciano Coelho * cannot know when we have disassociated. So, if we have already 196d6e19d135dadb1895296668914d0a15bc3cafcbfLuciano Coelho * joined, we disconnect before joining again. */ 197d6e19d135dadb1895296668914d0a15bc3cafcbfLuciano Coelho if (wl->joined) { 198d6e19d135dadb1895296668914d0a15bc3cafcbfLuciano Coelho ret = wl1271_cmd_disconnect(wl); 199d6e19d135dadb1895296668914d0a15bc3cafcbfLuciano Coelho if (ret < 0) { 200d6e19d135dadb1895296668914d0a15bc3cafcbfLuciano Coelho wl1271_error("failed to disconnect before rejoining"); 201d6e19d135dadb1895296668914d0a15bc3cafcbfLuciano Coelho goto out; 202d6e19d135dadb1895296668914d0a15bc3cafcbfLuciano Coelho } 203d6e19d135dadb1895296668914d0a15bc3cafcbfLuciano Coelho 204d6e19d135dadb1895296668914d0a15bc3cafcbfLuciano Coelho wl->joined = false; 205d6e19d135dadb1895296668914d0a15bc3cafcbfLuciano Coelho } 206d6e19d135dadb1895296668914d0a15bc3cafcbfLuciano Coelho 207f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho join = kzalloc(sizeof(*join), GFP_KERNEL); 208f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (!join) { 209f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = -ENOMEM; 210f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out; 211f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 212f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 213f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_CMD, "cmd join"); 214f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 215f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* Reverse order BSSID */ 216f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho bssid = (u8 *) &join->bssid_lsb; 217f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho for (i = 0; i < ETH_ALEN; i++) 218f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho bssid[i] = wl->bssid[ETH_ALEN - i - 1]; 219f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 220d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho join->rx_config_options = cpu_to_le32(wl->rx_config); 221d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho join->rx_filter_options = cpu_to_le32(wl->rx_filter); 222a410264553447ff90bf13e3662684e794e5ff83eTeemu Paasikivi join->bss_type = wl->bss_type; 223f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 22464a7f67287c75f5bb28018a6ff2750a59ee1195aLuciano Coelho /* 22564a7f67287c75f5bb28018a6ff2750a59ee1195aLuciano Coelho * FIXME: disable temporarily all filters because after commit 22664a7f67287c75f5bb28018a6ff2750a59ee1195aLuciano Coelho * 9cef8737 "mac80211: fix managed mode BSSID handling" broke 22764a7f67287c75f5bb28018a6ff2750a59ee1195aLuciano Coelho * association. The filter logic needs to be implemented properly 22864a7f67287c75f5bb28018a6ff2750a59ee1195aLuciano Coelho * and once that is done, this hack can be removed. 22964a7f67287c75f5bb28018a6ff2750a59ee1195aLuciano Coelho */ 230d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho join->rx_config_options = cpu_to_le32(0); 231d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho join->rx_filter_options = cpu_to_le32(WL1271_DEFAULT_RX_FILTER); 23264a7f67287c75f5bb28018a6ff2750a59ee1195aLuciano Coelho 233a410264553447ff90bf13e3662684e794e5ff83eTeemu Paasikivi if (wl->band == IEEE80211_BAND_2GHZ) 234d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho join->basic_rate_set = cpu_to_le32(CONF_HW_BIT_RATE_1MBPS | 235d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho CONF_HW_BIT_RATE_2MBPS | 236d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho CONF_HW_BIT_RATE_5_5MBPS | 237d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho CONF_HW_BIT_RATE_11MBPS); 238a410264553447ff90bf13e3662684e794e5ff83eTeemu Paasikivi else { 239a410264553447ff90bf13e3662684e794e5ff83eTeemu Paasikivi join->bss_type |= WL1271_JOIN_CMD_BSS_TYPE_5GHZ; 240d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho join->basic_rate_set = cpu_to_le32(CONF_HW_BIT_RATE_6MBPS | 241d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho CONF_HW_BIT_RATE_12MBPS | 242d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho CONF_HW_BIT_RATE_24MBPS); 243a410264553447ff90bf13e3662684e794e5ff83eTeemu Paasikivi } 244f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 245d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho join->beacon_interval = cpu_to_le16(WL1271_DEFAULT_BEACON_INT); 246ae751bab9f55c3152ebf713c89a4fb6f439c2575Luciano Coelho join->dtim_interval = WL1271_DEFAULT_DTIM_PERIOD; 247a410264553447ff90bf13e3662684e794e5ff83eTeemu Paasikivi 248f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho join->channel = wl->channel; 249f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho join->ssid_len = wl->ssid_len; 250f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho memcpy(join->ssid, wl->ssid, wl->ssid_len); 251f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho join->ctrl = WL1271_JOIN_CMD_CTRL_TX_FLUSH; 252f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 253f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* increment the session counter */ 254f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl->session_counter++; 255f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (wl->session_counter >= SESSION_COUNTER_MAX) 256f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl->session_counter = 0; 257f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 258f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho join->ctrl |= wl->session_counter << WL1271_JOIN_CMD_TX_SESSION_OFFSET; 259f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 260ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen /* reset TX security counters */ 261ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen wl->tx_security_last_seq = 0; 262ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen wl->tx_security_seq_16 = 0; 263ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen wl->tx_security_seq_32 = 0; 264f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 265f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = wl1271_cmd_send(wl, CMD_START_JOIN, join, sizeof(*join)); 266f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) { 267f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_error("failed to initiate cmd join"); 268f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out_free; 269f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 270f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 271d6e19d135dadb1895296668914d0a15bc3cafcbfLuciano Coelho wl->joined = true; 272d6e19d135dadb1895296668914d0a15bc3cafcbfLuciano Coelho 273f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* 274f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * ugly hack: we should wait for JOIN_EVENT_COMPLETE_ID but to 275f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * simplify locking we just sleep instead, for now 276f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */ 277d94cd297e58b55bb272fdfd51ff0de7acbc1941bJuuso Oikarinen msleep(10); 278f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 279f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout_free: 280f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho kfree(join); 281f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 282f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout: 283f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 284f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 285f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 286f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/** 287f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * send test command to firmware 288f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * 289f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @wl: wl struct 290f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @buf: buffer containing the command, with all headers, must work with dma 291f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @len: length of the buffer 292f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @answer: is answer needed 293f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */ 294f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_test(struct wl1271 *wl, void *buf, size_t buf_len, u8 answer) 295f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 296f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret; 297f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 298f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_CMD, "cmd test"); 299f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 300f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = wl1271_cmd_send(wl, CMD_TEST, buf, buf_len); 301f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 302f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) { 303f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_warning("TEST command failed"); 304f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 305f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 306f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 307f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (answer) { 308f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_command *cmd_answer; 309d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho u16 status; 310f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 311f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* 312f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * The test command got in, we can read the answer. 313f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * The answer would be a wl1271_command, where the 314f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * parameter array contains the actual answer. 315f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */ 316746214178774bc7f9adbeaef7d43a634570eb870Juuso Oikarinen wl1271_spi_read(wl, wl->cmd_box_addr, buf, buf_len, false); 317f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 318f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd_answer = buf; 319d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho status = le16_to_cpu(cmd_answer->header.status); 320f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 321d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho if (status != CMD_STATUS_SUCCESS) 322d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho wl1271_error("TEST command answer error: %d", status); 323f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 324f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 325f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return 0; 326f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 327f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 328f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/** 329f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * read acx from firmware 330f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * 331f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @wl: wl struct 332f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @id: acx id 333f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @buf: buffer for the response, including all headers, must work with dma 334f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @len: lenght of buf 335f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */ 336f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_interrogate(struct wl1271 *wl, u16 id, void *buf, size_t len) 337f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 338f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct acx_header *acx = buf; 339f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret; 340f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 341f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_CMD, "cmd interrogate"); 342f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 343d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho acx->id = cpu_to_le16(id); 344f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 345f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* payload length, does not include any headers */ 346d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho acx->len = cpu_to_le16(len - sizeof(*acx)); 347f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 348f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = wl1271_cmd_send(wl, CMD_INTERROGATE, acx, sizeof(*acx)); 349f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) { 350f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_error("INTERROGATE command failed"); 351f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out; 352f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 353f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 354f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* the interrogate command got in, we can read the answer */ 355746214178774bc7f9adbeaef7d43a634570eb870Juuso Oikarinen wl1271_spi_read(wl, wl->cmd_box_addr, buf, len, false); 356f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 357f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho acx = buf; 358d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho if (le16_to_cpu(acx->cmd.status) != CMD_STATUS_SUCCESS) 359f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_error("INTERROGATE command error: %d", 360d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho le16_to_cpu(acx->cmd.status)); 361f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 362f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout: 363f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 364f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 365f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 366f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/** 367f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * write acx value to firmware 368f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * 369f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @wl: wl struct 370f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @id: acx id 371f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @buf: buffer containing acx, including all headers, must work with dma 372f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * @len: length of buf 373f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */ 374f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len) 375f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 376f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct acx_header *acx = buf; 377f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret; 378f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 379f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_CMD, "cmd configure"); 380f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 381d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho acx->id = cpu_to_le16(id); 382f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 383f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* payload length, does not include any headers */ 384d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho acx->len = cpu_to_le16(len - sizeof(*acx)); 385f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 386f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = wl1271_cmd_send(wl, CMD_CONFIGURE, acx, len); 387f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) { 388f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_warning("CONFIGURE command NOK"); 389f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 390f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 391f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 392f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return 0; 393f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 394f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 395f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_data_path(struct wl1271 *wl, u8 channel, bool enable) 396f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 397f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct cmd_enabledisable_path *cmd; 398f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret; 399f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u16 cmd_rx, cmd_tx; 400f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 401f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_CMD, "cmd data path"); 402f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 403f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 404f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (!cmd) { 405f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = -ENOMEM; 406f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out; 407f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 408f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 409f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd->channel = channel; 410f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 411f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (enable) { 412f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd_rx = CMD_ENABLE_RX; 413f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd_tx = CMD_ENABLE_TX; 414f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } else { 415f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd_rx = CMD_DISABLE_RX; 416f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd_tx = CMD_DISABLE_TX; 417f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 418f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 419f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = wl1271_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd)); 420f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) { 421f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_error("rx %s cmd for channel %d failed", 422f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho enable ? "start" : "stop", channel); 423f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out; 424f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 425f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 426f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_BOOT, "rx %s cmd channel %d", 427f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho enable ? "start" : "stop", channel); 428f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 429f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = wl1271_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd)); 430f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) { 431f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_error("tx %s cmd for channel %d failed", 432f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho enable ? "start" : "stop", channel); 433f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 434f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 435f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 436f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_BOOT, "tx %s cmd channel %d", 437f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho enable ? "start" : "stop", channel); 438f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 439f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout: 440f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho kfree(cmd); 441f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 442f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 443f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 444f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_ps_mode(struct wl1271 *wl, u8 ps_mode) 445f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 446f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_cmd_ps_params *ps_params = NULL; 447f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret = 0; 448f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 449f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* FIXME: this should be in ps.c */ 45051f2be24328957f9e2acf116b1b1d2dfd10bf41fJuuso Oikarinen ret = wl1271_acx_wake_up_conditions(wl); 451f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) { 452f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_error("couldn't set wake up conditions"); 453f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out; 454f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 455f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 456f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_CMD, "cmd set ps mode"); 457f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 458f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ps_params = kzalloc(sizeof(*ps_params), GFP_KERNEL); 459f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (!ps_params) { 460f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = -ENOMEM; 461f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out; 462f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 463f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 464f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ps_params->ps_mode = ps_mode; 465f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ps_params->send_null_data = 1; 466f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ps_params->retries = 5; 467f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ps_params->hang_over_period = 128; 468d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho ps_params->null_data_rate = cpu_to_le32(1); /* 1 Mbps */ 469f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 470f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = wl1271_cmd_send(wl, CMD_SET_PS_MODE, ps_params, 471f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho sizeof(*ps_params)); 472f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) { 473f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_error("cmd set_ps_mode failed"); 474f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out; 475f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 476f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 477f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout: 478f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho kfree(ps_params); 479f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 480f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 481f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 482f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_read_memory(struct wl1271 *wl, u32 addr, void *answer, 483f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho size_t len) 484f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 485f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct cmd_read_write_memory *cmd; 486f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret = 0; 487f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 488f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_CMD, "cmd read memory"); 489f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 490f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 491f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (!cmd) { 492f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = -ENOMEM; 493f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out; 494f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 495f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 496f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho WARN_ON(len > MAX_READ_SIZE); 497f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho len = min_t(size_t, len, MAX_READ_SIZE); 498f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 499d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho cmd->addr = cpu_to_le32(addr); 500d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho cmd->size = cpu_to_le32(len); 501f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 502f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = wl1271_cmd_send(wl, CMD_READ_MEMORY, cmd, sizeof(*cmd)); 503f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) { 504f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_error("read memory command failed: %d", ret); 505f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out; 506f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 507f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 508f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* the read command got in, we can now read the answer */ 509746214178774bc7f9adbeaef7d43a634570eb870Juuso Oikarinen wl1271_spi_read(wl, wl->cmd_box_addr, cmd, sizeof(*cmd), false); 510f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 511d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho if (le16_to_cpu(cmd->header.status) != CMD_STATUS_SUCCESS) 512f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_error("error in read command result: %d", 513d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho le16_to_cpu(cmd->header.status)); 514f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 515f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho memcpy(answer, cmd->value, len); 516f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 517f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout: 518f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho kfree(cmd); 519f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 520f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 521f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 522f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_scan(struct wl1271 *wl, u8 *ssid, size_t len, 523abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi u8 active_scan, u8 high_prio, u8 band, 524f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u8 probe_requests) 525f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 526f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 527f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_cmd_trigger_scan_to *trigger = NULL; 528f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_cmd_scan *params = NULL; 529311494c47fb670a1fd74eea54fa4d02a56fcc2adTeemu Paasikivi struct ieee80211_channel *channels; 530311494c47fb670a1fd74eea54fa4d02a56fcc2adTeemu Paasikivi int i, j, n_ch, ret; 531f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u16 scan_options = 0; 532abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi u8 ieee_band; 533abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi 534abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi if (band == WL1271_SCAN_BAND_2_4_GHZ) 535abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi ieee_band = IEEE80211_BAND_2GHZ; 536abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi else if (band == WL1271_SCAN_BAND_DUAL && wl1271_11a_enabled()) 537abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi ieee_band = IEEE80211_BAND_2GHZ; 538abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi else if (band == WL1271_SCAN_BAND_5_GHZ && wl1271_11a_enabled()) 539abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi ieee_band = IEEE80211_BAND_5GHZ; 540abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi else 541abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi return -EINVAL; 542f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 543abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi if (wl->hw->wiphy->bands[ieee_band]->channels == NULL) 544f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return -EINVAL; 545f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 546abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi channels = wl->hw->wiphy->bands[ieee_band]->channels; 547abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi n_ch = wl->hw->wiphy->bands[ieee_band]->n_channels; 548abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi 549abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi if (wl->scanning) 550abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi return -EINVAL; 551311494c47fb670a1fd74eea54fa4d02a56fcc2adTeemu Paasikivi 552f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho params = kzalloc(sizeof(*params), GFP_KERNEL); 553f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (!params) 554f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return -ENOMEM; 555f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 556f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho params->params.rx_config_options = cpu_to_le32(CFG_RX_ALL_GOOD); 557f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho params->params.rx_filter_options = 558f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cpu_to_le32(CFG_RX_PRSP_EN | CFG_RX_MGMT_EN | CFG_RX_BCN_EN); 559f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 560f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (!active_scan) 561f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho scan_options |= WL1271_SCAN_OPT_PASSIVE; 562f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (high_prio) 563f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho scan_options |= WL1271_SCAN_OPT_PRIORITY_HIGH; 564d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho params->params.scan_options = cpu_to_le16(scan_options); 565f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 566f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho params->params.num_probe_requests = probe_requests; 567abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi /* Let the fw autodetect suitable tx_rate for probes */ 568abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi params->params.tx_rate = 0; 569f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho params->params.tid_trigger = 0; 570f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho params->params.scan_tag = WL1271_SCAN_DEFAULT_TAG; 571f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 572abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi if (band == WL1271_SCAN_BAND_DUAL) 573abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi params->params.band = WL1271_SCAN_BAND_2_4_GHZ; 574abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi else 575abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi params->params.band = band; 576abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi 577311494c47fb670a1fd74eea54fa4d02a56fcc2adTeemu Paasikivi for (i = 0, j = 0; i < n_ch && i < WL1271_SCAN_MAX_CHANNELS; i++) { 578311494c47fb670a1fd74eea54fa4d02a56fcc2adTeemu Paasikivi if (!(channels[i].flags & IEEE80211_CHAN_DISABLED)) { 579311494c47fb670a1fd74eea54fa4d02a56fcc2adTeemu Paasikivi params->channels[j].min_duration = 580311494c47fb670a1fd74eea54fa4d02a56fcc2adTeemu Paasikivi cpu_to_le32(WL1271_SCAN_CHAN_MIN_DURATION); 581311494c47fb670a1fd74eea54fa4d02a56fcc2adTeemu Paasikivi params->channels[j].max_duration = 582311494c47fb670a1fd74eea54fa4d02a56fcc2adTeemu Paasikivi cpu_to_le32(WL1271_SCAN_CHAN_MAX_DURATION); 583311494c47fb670a1fd74eea54fa4d02a56fcc2adTeemu Paasikivi memset(¶ms->channels[j].bssid_lsb, 0xff, 4); 584311494c47fb670a1fd74eea54fa4d02a56fcc2adTeemu Paasikivi memset(¶ms->channels[j].bssid_msb, 0xff, 2); 585311494c47fb670a1fd74eea54fa4d02a56fcc2adTeemu Paasikivi params->channels[j].early_termination = 0; 586311494c47fb670a1fd74eea54fa4d02a56fcc2adTeemu Paasikivi params->channels[j].tx_power_att = 587311494c47fb670a1fd74eea54fa4d02a56fcc2adTeemu Paasikivi WL1271_SCAN_CURRENT_TX_PWR; 588311494c47fb670a1fd74eea54fa4d02a56fcc2adTeemu Paasikivi params->channels[j].channel = channels[i].hw_value; 589311494c47fb670a1fd74eea54fa4d02a56fcc2adTeemu Paasikivi j++; 590311494c47fb670a1fd74eea54fa4d02a56fcc2adTeemu Paasikivi } 591f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 592f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 593311494c47fb670a1fd74eea54fa4d02a56fcc2adTeemu Paasikivi params->params.num_channels = j; 594311494c47fb670a1fd74eea54fa4d02a56fcc2adTeemu Paasikivi 595f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (len && ssid) { 596f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho params->params.ssid_len = len; 597f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho memcpy(params->params.ssid, ssid, len); 598f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 599f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 600abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi ret = wl1271_cmd_build_probe_req(wl, ssid, len, ieee_band); 601f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) { 602f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_error("PROBE request template failed"); 603f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out; 604f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 605f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 606f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho trigger = kzalloc(sizeof(*trigger), GFP_KERNEL); 607f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (!trigger) { 608f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = -ENOMEM; 609f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out; 610f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 611f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 612f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* disable the timeout */ 613f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho trigger->timeout = 0; 614f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 615f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = wl1271_cmd_send(wl, CMD_TRIGGER_SCAN_TO, trigger, 616f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho sizeof(*trigger)); 617f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) { 618f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_error("trigger scan to failed for hw scan"); 619f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out; 620f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 621f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 622f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_dump(DEBUG_SCAN, "SCAN: ", params, sizeof(*params)); 623f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 624f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl->scanning = true; 625abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi if (wl1271_11a_enabled()) { 626abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi wl->scan.state = band; 627abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi if (band == WL1271_SCAN_BAND_DUAL) { 628abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi wl->scan.active = active_scan; 629abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi wl->scan.high_prio = high_prio; 630abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi wl->scan.probe_requests = probe_requests; 631abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi if (len && ssid) { 632abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi wl->scan.ssid_len = len; 633abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi memcpy(wl->scan.ssid, ssid, len); 634abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi } else 635abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi wl->scan.ssid_len = 0; 636abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi } 637abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi } 638f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 639f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = wl1271_cmd_send(wl, CMD_SCAN, params, sizeof(*params)); 640f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) { 641f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_error("SCAN failed"); 642f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out; 643f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 644f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 645746214178774bc7f9adbeaef7d43a634570eb870Juuso Oikarinen wl1271_spi_read(wl, wl->cmd_box_addr, params, sizeof(*params), 646746214178774bc7f9adbeaef7d43a634570eb870Juuso Oikarinen false); 647f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 648d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho if (le16_to_cpu(params->header.status) != CMD_STATUS_SUCCESS) { 649f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_error("Scan command error: %d", 650d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho le16_to_cpu(params->header.status)); 651f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl->scanning = false; 652f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = -EIO; 653f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out; 654f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 655f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 656f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout: 657f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho kfree(params); 658f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 659f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 660f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 661f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_template_set(struct wl1271 *wl, u16 template_id, 662f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho void *buf, size_t buf_len) 663f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 664f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_cmd_template_set *cmd; 665f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret = 0; 666f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 667f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_CMD, "cmd template_set %d", template_id); 668f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 669f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho WARN_ON(buf_len > WL1271_CMD_TEMPL_MAX_SIZE); 670f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho buf_len = min_t(size_t, buf_len, WL1271_CMD_TEMPL_MAX_SIZE); 671f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 672f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 673f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (!cmd) { 674f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = -ENOMEM; 675f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out; 676f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 677f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 678f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd->len = cpu_to_le16(buf_len); 679f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd->template_type = template_id; 680d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho cmd->enabled_rates = cpu_to_le32(wl->conf.tx.rc_conf.enabled_rates); 68145b531a86f93c82d8e390e19a6258111b3627bb0Juuso Oikarinen cmd->short_retry_limit = wl->conf.tx.rc_conf.short_retry_limit; 68245b531a86f93c82d8e390e19a6258111b3627bb0Juuso Oikarinen cmd->long_retry_limit = wl->conf.tx.rc_conf.long_retry_limit; 683f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 684f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (buf) 685f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho memcpy(cmd->template_data, buf, buf_len); 686f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 687f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = wl1271_cmd_send(wl, CMD_SET_TEMPLATE, cmd, sizeof(*cmd)); 688f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) { 689f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_warning("cmd set_template failed: %d", ret); 690f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out_free; 691f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 692f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 693f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout_free: 694f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho kfree(cmd); 695f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 696f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout: 697f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 698f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 699f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 700abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivistatic int wl1271_build_basic_rates(char *rates, u8 band) 701f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 702f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u8 index = 0; 703f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 704abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi if (band == IEEE80211_BAND_2GHZ) { 705abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi rates[index++] = 706abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_1MB; 707abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi rates[index++] = 708abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_2MB; 709abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi rates[index++] = 710abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_5MB; 711abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi rates[index++] = 712abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi IEEE80211_BASIC_RATE_MASK | IEEE80211_CCK_RATE_11MB; 713abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi } else if (band == IEEE80211_BAND_5GHZ) { 714abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi rates[index++] = 715abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_6MB; 716abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi rates[index++] = 717abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_12MB; 718abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi rates[index++] = 719abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB; 720abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi } else { 721abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi wl1271_error("build_basic_rates invalid band: %d", band); 722abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi } 723f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 724f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return index; 725f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 726f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 727abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivistatic int wl1271_build_extended_rates(char *rates, u8 band) 728f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 729f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u8 index = 0; 730f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 731abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi if (band == IEEE80211_BAND_2GHZ) { 732abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi rates[index++] = IEEE80211_OFDM_RATE_6MB; 733abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi rates[index++] = IEEE80211_OFDM_RATE_9MB; 734abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi rates[index++] = IEEE80211_OFDM_RATE_12MB; 735abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi rates[index++] = IEEE80211_OFDM_RATE_18MB; 736abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi rates[index++] = IEEE80211_OFDM_RATE_24MB; 737abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi rates[index++] = IEEE80211_OFDM_RATE_36MB; 738abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi rates[index++] = IEEE80211_OFDM_RATE_48MB; 739abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi rates[index++] = IEEE80211_OFDM_RATE_54MB; 740abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi } else if (band == IEEE80211_BAND_5GHZ) { 741abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi rates[index++] = 742abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_9MB; 743abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi rates[index++] = 744abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_18MB; 745abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi rates[index++] = 746abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_24MB; 747abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi rates[index++] = 748abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_36MB; 749abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi rates[index++] = 750abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_48MB; 751abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi rates[index++] = 752abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi IEEE80211_BASIC_RATE_MASK | IEEE80211_OFDM_RATE_54MB; 753abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi } else { 754abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi wl1271_error("build_basic_rates invalid band: %d", band); 755abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi } 756f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 757f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return index; 758f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 759f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 760f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_build_null_data(struct wl1271 *wl) 761f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 762f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl12xx_null_data_template template; 763f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 764f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (!is_zero_ether_addr(wl->bssid)) { 765f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho memcpy(template.header.da, wl->bssid, ETH_ALEN); 766f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho memcpy(template.header.bssid, wl->bssid, ETH_ALEN); 767f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } else { 768f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho memset(template.header.da, 0xff, ETH_ALEN); 769f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho memset(template.header.bssid, 0xff, ETH_ALEN); 770f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 771f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 772f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); 773f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho template.header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | 7747a38079e0da19447ab1c41e42094b311c6e945e4Juuso Oikarinen IEEE80211_STYPE_NULLFUNC | 7757a38079e0da19447ab1c41e42094b311c6e945e4Juuso Oikarinen IEEE80211_FCTL_TODS); 776f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 777f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, &template, 778f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho sizeof(template)); 779f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 780f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 781f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 782f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_build_ps_poll(struct wl1271 *wl, u16 aid) 783f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 784f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl12xx_ps_poll_template template; 785f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 786f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho memcpy(template.bssid, wl->bssid, ETH_ALEN); 787f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho memcpy(template.ta, wl->mac_addr, ETH_ALEN); 788c3fea1994ac34dafa3ebb40d4f95354b2782af31Juuso Oikarinen 789c3fea1994ac34dafa3ebb40d4f95354b2782af31Juuso Oikarinen /* aid in PS-Poll has its two MSBs each set to 1 */ 790c3fea1994ac34dafa3ebb40d4f95354b2782af31Juuso Oikarinen template.aid = cpu_to_le16(1 << 15 | 1 << 14 | aid); 791c3fea1994ac34dafa3ebb40d4f95354b2782af31Juuso Oikarinen 792f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho template.fc = cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL); 793f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 794f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return wl1271_cmd_template_set(wl, CMD_TEMPL_PS_POLL, &template, 795f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho sizeof(template)); 796f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 797f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 798f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 799abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikiviint wl1271_cmd_build_probe_req(struct wl1271 *wl, u8 *ssid, size_t ssid_len, 800abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi u8 band) 801f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 802f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl12xx_probe_req_template template; 803f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl12xx_ie_rates *rates; 804f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho char *ptr; 805f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u16 size; 806abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi int ret; 807f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 808f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ptr = (char *)&template; 809f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho size = sizeof(struct ieee80211_header); 810f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 811f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho memset(template.header.da, 0xff, ETH_ALEN); 812f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho memset(template.header.bssid, 0xff, ETH_ALEN); 813f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho memcpy(template.header.sa, wl->mac_addr, ETH_ALEN); 814f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho template.header.frame_ctl = cpu_to_le16(IEEE80211_STYPE_PROBE_REQ); 815f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 816f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* IEs */ 817f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* SSID */ 818f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho template.ssid.header.id = WLAN_EID_SSID; 819f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho template.ssid.header.len = ssid_len; 820f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ssid_len && ssid) 821f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho memcpy(template.ssid.ssid, ssid, ssid_len); 822f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho size += sizeof(struct wl12xx_ie_header) + ssid_len; 823f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ptr += size; 824f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 825f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* Basic Rates */ 826f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho rates = (struct wl12xx_ie_rates *)ptr; 827f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho rates->header.id = WLAN_EID_SUPP_RATES; 828abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi rates->header.len = wl1271_build_basic_rates(rates->rates, band); 829f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho size += sizeof(struct wl12xx_ie_header) + rates->header.len; 830f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ptr += sizeof(struct wl12xx_ie_header) + rates->header.len; 831f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 832f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* Extended rates */ 833f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho rates = (struct wl12xx_ie_rates *)ptr; 834f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho rates->header.id = WLAN_EID_EXT_SUPP_RATES; 835abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi rates->header.len = wl1271_build_extended_rates(rates->rates, band); 836f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho size += sizeof(struct wl12xx_ie_header) + rates->header.len; 837f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 838f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", &template, size); 839f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 840abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi if (band == IEEE80211_BAND_2GHZ) 841abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4, 842abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi &template, size); 843abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi else 844abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5, 845abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi &template, size); 846abb0b3bfb2d2411034b721df21c31964265b851eTeemu Paasikivi return ret; 847f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 848f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 849f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_set_default_wep_key(struct wl1271 *wl, u8 id) 850f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 851f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_cmd_set_keys *cmd; 852f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret = 0; 853f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 854f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_CMD, "cmd set_default_wep_key %d", id); 855f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 856f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 857f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (!cmd) { 858f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = -ENOMEM; 859f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out; 860f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 861f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 862f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd->id = id; 863d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho cmd->key_action = cpu_to_le16(KEY_SET_ID); 864f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd->key_type = KEY_WEP; 865f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 866f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd)); 867f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) { 868f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_warning("cmd set_default_wep_key failed: %d", ret); 869f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out; 870f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 871f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 872f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout: 873f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho kfree(cmd); 874f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 875f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 876f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 877f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 878f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoint wl1271_cmd_set_key(struct wl1271 *wl, u16 action, u8 id, u8 key_type, 879ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen u8 key_size, const u8 *key, const u8 *addr, 880ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen u32 tx_seq_32, u16 tx_seq_16) 881f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 882f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_cmd_set_keys *cmd; 883f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret = 0; 884f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 885f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 886f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (!cmd) { 887f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = -ENOMEM; 888f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out; 889f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 890f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 891f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (key_type != KEY_WEP) 892f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho memcpy(cmd->addr, addr, ETH_ALEN); 893f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 894d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho cmd->key_action = cpu_to_le16(action); 895f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd->key_size = key_size; 896f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd->key_type = key_type; 897f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 898d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho cmd->ac_seq_num16[0] = cpu_to_le16(tx_seq_16); 899d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho cmd->ac_seq_num32[0] = cpu_to_le32(tx_seq_32); 900ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen 901f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* we have only one SSID profile */ 902f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd->ssid_profile = 0; 903f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 904f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho cmd->id = id; 905f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 906f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (key_type == KEY_TKIP) { 907f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* 908f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * We get the key in the following form: 909f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * TKIP (16 bytes) - TX MIC (8 bytes) - RX MIC (8 bytes) 910f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * but the target is expecting: 911f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * TKIP - RX MIC - TX MIC 912f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */ 913f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho memcpy(cmd->key, key, 16); 914f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho memcpy(cmd->key + 16, key + 24, 8); 915f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho memcpy(cmd->key + 24, key + 16, 8); 916f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 917f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } else { 918f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho memcpy(cmd->key, key, key_size); 919f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 920f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 921f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_dump(DEBUG_CRYPT, "TARGET KEY: ", cmd, sizeof(*cmd)); 922f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 923f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = wl1271_cmd_send(wl, CMD_SET_KEYS, cmd, sizeof(*cmd)); 924f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) { 925f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_warning("could not set keys"); 926f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out; 927f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 928f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 929f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout: 930f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho kfree(cmd); 931f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 932f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 933f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 93425a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho 93525a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelhoint wl1271_cmd_disconnect(struct wl1271 *wl) 93625a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho{ 93725a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho struct wl1271_cmd_disconnect *cmd; 93825a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho int ret = 0; 93925a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho 94025a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho wl1271_debug(DEBUG_CMD, "cmd disconnect"); 94125a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho 94225a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 94325a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho if (!cmd) { 94425a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho ret = -ENOMEM; 94525a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho goto out; 94625a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho } 94725a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho 948d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho cmd->rx_config_options = cpu_to_le32(wl->rx_config); 949d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho cmd->rx_filter_options = cpu_to_le32(wl->rx_filter); 95025a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho /* disconnect reason is not used in immediate disconnections */ 95125a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho cmd->type = DISCONNECT_IMMEDIATE; 95225a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho 95325a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho ret = wl1271_cmd_send(wl, CMD_DISCONNECT, cmd, sizeof(*cmd)); 95425a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho if (ret < 0) { 95525a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho wl1271_error("failed to send disconnect command"); 95625a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho goto out_free; 95725a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho } 95825a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho 95925a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelhoout_free: 96025a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho kfree(cmd); 96125a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho 96225a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelhoout: 96325a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho return ret; 96425a7dc6d22adda590be4932ebc772ea35914880cLuciano Coelho} 965