1c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo/* 2c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo * This file is part of wl1271 3c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo * 4c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo * Copyright (C) 2010 Nokia Corporation 5c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo * 6c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo * Contact: Luciano Coelho <luciano.coelho@nokia.com> 7c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo * 8c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo * This program is free software; you can redistribute it and/or 9c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo * modify it under the terms of the GNU General Public License 10c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo * version 2 as published by the Free Software Foundation. 11c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo * 12c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo * This program is distributed in the hope that it will be useful, but 13c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo * WITHOUT ANY WARRANTY; without even the implied warranty of 14c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo * General Public License for more details. 16c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo * 17c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo * You should have received a copy of the GNU General Public License 18c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo * along with this program; if not, write to the Free Software 19c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo * 02110-1301 USA 21c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo * 22c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo */ 2300d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "testmode.h" 24c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 255a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 26c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo#include <net/genetlink.h> 27c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 2800d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "wl12xx.h" 290f4e31222a2c0b93f25a87effd2033cb78c7a79cLuciano Coelho#include "debug.h" 3000d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "acx.h" 31bc765bf3b9a095b3e41c8cda80643901884c3dd4Shahar Levi#include "reg.h" 32abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller#include "ps.h" 3375f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho#include "io.h" 34c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 35c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo#define WL1271_TM_MAX_DATA_LENGTH 1024 36c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 37c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valoenum wl1271_tm_commands { 38c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo WL1271_TM_CMD_UNSPEC, 39c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo WL1271_TM_CMD_TEST, 40c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo WL1271_TM_CMD_INTERROGATE, 41c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo WL1271_TM_CMD_CONFIGURE, 423f1764945eaac532c20ab1f23afa352a40f797b2Pontus Fuchs WL1271_TM_CMD_NVS_PUSH, /* Not in use. Keep to not break ABI */ 43c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo WL1271_TM_CMD_SET_PLT_MODE, 44e285a5250c0772c5596a9137041a96b2c1f744d6Eliad Peller WL1271_TM_CMD_RECOVER, 4575f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho WL1271_TM_CMD_GET_MAC, 46c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 47c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo __WL1271_TM_CMD_AFTER_LAST 48c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo}; 49c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo#define WL1271_TM_CMD_MAX (__WL1271_TM_CMD_AFTER_LAST - 1) 50c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 51c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valoenum wl1271_tm_attrs { 52c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo WL1271_TM_ATTR_UNSPEC, 53c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo WL1271_TM_ATTR_CMD_ID, 54c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo WL1271_TM_ATTR_ANSWER, 55c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo WL1271_TM_ATTR_DATA, 56c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo WL1271_TM_ATTR_IE_ID, 57c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo WL1271_TM_ATTR_PLT_MODE, 58c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 59c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo __WL1271_TM_ATTR_AFTER_LAST 60c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo}; 61c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo#define WL1271_TM_ATTR_MAX (__WL1271_TM_ATTR_AFTER_LAST - 1) 62c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 63c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valostatic struct nla_policy wl1271_tm_policy[WL1271_TM_ATTR_MAX + 1] = { 64c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo [WL1271_TM_ATTR_CMD_ID] = { .type = NLA_U32 }, 65c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo [WL1271_TM_ATTR_ANSWER] = { .type = NLA_U8 }, 66c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo [WL1271_TM_ATTR_DATA] = { .type = NLA_BINARY, 67c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo .len = WL1271_TM_MAX_DATA_LENGTH }, 68c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo [WL1271_TM_ATTR_IE_ID] = { .type = NLA_U32 }, 69c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo [WL1271_TM_ATTR_PLT_MODE] = { .type = NLA_U32 }, 70c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo}; 71c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 72c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 73c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valostatic int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[]) 74c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo{ 75c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo int buf_len, ret, len; 76c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo struct sk_buff *skb; 77c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo void *buf; 78c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo u8 answer = 0; 79c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 80c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo wl1271_debug(DEBUG_TESTMODE, "testmode cmd test"); 81c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 82c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo if (!tb[WL1271_TM_ATTR_DATA]) 83c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo return -EINVAL; 84c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 85c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo buf = nla_data(tb[WL1271_TM_ATTR_DATA]); 86c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo buf_len = nla_len(tb[WL1271_TM_ATTR_DATA]); 87c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 88c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo if (tb[WL1271_TM_ATTR_ANSWER]) 89c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo answer = nla_get_u8(tb[WL1271_TM_ATTR_ANSWER]); 90c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 91c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo if (buf_len > sizeof(struct wl1271_command)) 92c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo return -EMSGSIZE; 93c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 94c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo mutex_lock(&wl->mutex); 95c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 96abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller if (wl->state == WL1271_STATE_OFF) { 97abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller ret = -EINVAL; 98abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller goto out; 99abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller } 100abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller 101abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller ret = wl1271_ps_elp_wakeup(wl); 102abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller if (ret < 0) 103abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller goto out; 104abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller 105abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller ret = wl1271_cmd_test(wl, buf, buf_len, answer); 106c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo if (ret < 0) { 107c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo wl1271_warning("testmode cmd test failed: %d", ret); 108abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller goto out_sleep; 109c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo } 110c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 111c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo if (answer) { 112c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo len = nla_total_size(buf_len); 113c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, len); 114abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller if (!skb) { 115abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller ret = -ENOMEM; 116abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller goto out_sleep; 117abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller } 118c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 119c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo NLA_PUT(skb, WL1271_TM_ATTR_DATA, buf_len, buf); 120c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo ret = cfg80211_testmode_reply(skb); 121c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo if (ret < 0) 122abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller goto out_sleep; 123c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo } 124c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 125abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Pellerout_sleep: 126abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller wl1271_ps_elp_sleep(wl); 127abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Pellerout: 128abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller mutex_unlock(&wl->mutex); 129abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller 130abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller return ret; 131c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 132c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valonla_put_failure: 133c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo kfree_skb(skb); 134abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller ret = -EMSGSIZE; 135abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller goto out_sleep; 136c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo} 137c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 138c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valostatic int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[]) 139c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo{ 140c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo int ret; 141c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo struct wl1271_command *cmd; 142c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo struct sk_buff *skb; 143c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo u8 ie_id; 144c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 145c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo wl1271_debug(DEBUG_TESTMODE, "testmode cmd interrogate"); 146c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 147c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo if (!tb[WL1271_TM_ATTR_IE_ID]) 148c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo return -EINVAL; 149c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 150c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]); 151c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 152abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller mutex_lock(&wl->mutex); 153abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller 154abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller if (wl->state == WL1271_STATE_OFF) { 155abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller ret = -EINVAL; 156abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller goto out; 157abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller } 158abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller 159abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller ret = wl1271_ps_elp_wakeup(wl); 160abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller if (ret < 0) 161abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller goto out; 162abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller 163c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 164abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller if (!cmd) { 165abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller ret = -ENOMEM; 166abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller goto out_sleep; 167abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller } 168c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 169c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo ret = wl1271_cmd_interrogate(wl, ie_id, cmd, sizeof(*cmd)); 170c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo if (ret < 0) { 171c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo wl1271_warning("testmode cmd interrogate failed: %d", ret); 172abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller goto out_free; 173c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo } 174c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 175c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, sizeof(*cmd)); 176f8afdf481f0fef5e170c6c928cec42879d505654Julia Lawall if (!skb) { 177abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller ret = -ENOMEM; 178abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller goto out_free; 179f8afdf481f0fef5e170c6c928cec42879d505654Julia Lawall } 180c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 181c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo NLA_PUT(skb, WL1271_TM_ATTR_DATA, sizeof(*cmd), cmd); 1823dbb5846db1f5df3619b927cc2a7dcaf65a38f1eEliad Peller ret = cfg80211_testmode_reply(skb); 1833dbb5846db1f5df3619b927cc2a7dcaf65a38f1eEliad Peller if (ret < 0) 1843dbb5846db1f5df3619b927cc2a7dcaf65a38f1eEliad Peller goto out_free; 185c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 186abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Pellerout_free: 187abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller kfree(cmd); 188abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Pellerout_sleep: 189abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller wl1271_ps_elp_sleep(wl); 190abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Pellerout: 191abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller mutex_unlock(&wl->mutex); 192abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller 193abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller return ret; 194c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 195c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valonla_put_failure: 196c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo kfree_skb(skb); 197abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller ret = -EMSGSIZE; 198abc47470ef63cdde2efdf358ae373afb16f358c0Eliad Peller goto out_free; 199c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo} 200c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 201c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valostatic int wl1271_tm_cmd_configure(struct wl1271 *wl, struct nlattr *tb[]) 202c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo{ 203c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo int buf_len, ret; 204c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo void *buf; 205c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo u8 ie_id; 206c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 207c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo wl1271_debug(DEBUG_TESTMODE, "testmode cmd configure"); 208c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 209c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo if (!tb[WL1271_TM_ATTR_DATA]) 210c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo return -EINVAL; 211c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo if (!tb[WL1271_TM_ATTR_IE_ID]) 212c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo return -EINVAL; 213c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 214c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo ie_id = nla_get_u8(tb[WL1271_TM_ATTR_IE_ID]); 215c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo buf = nla_data(tb[WL1271_TM_ATTR_DATA]); 216c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo buf_len = nla_len(tb[WL1271_TM_ATTR_DATA]); 217c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 218c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo if (buf_len > sizeof(struct wl1271_command)) 219c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo return -EMSGSIZE; 220c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 221c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo mutex_lock(&wl->mutex); 222c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo ret = wl1271_cmd_configure(wl, ie_id, buf, buf_len); 223c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo mutex_unlock(&wl->mutex); 224c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 225c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo if (ret < 0) { 226c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo wl1271_warning("testmode cmd configure failed: %d", ret); 227c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo return ret; 228c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo } 229c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 230c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo return 0; 231c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo} 232c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 233c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valostatic int wl1271_tm_cmd_set_plt_mode(struct wl1271 *wl, struct nlattr *tb[]) 234c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo{ 235c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo u32 val; 236c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo int ret; 237c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 238c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo wl1271_debug(DEBUG_TESTMODE, "testmode cmd set plt mode"); 239c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 240c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo if (!tb[WL1271_TM_ATTR_PLT_MODE]) 241c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo return -EINVAL; 242c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 243c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo val = nla_get_u32(tb[WL1271_TM_ATTR_PLT_MODE]); 244c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 245c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo switch (val) { 246c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo case 0: 247c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo ret = wl1271_plt_stop(wl); 248c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo break; 249c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo case 1: 250c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo ret = wl1271_plt_start(wl); 251c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo break; 252c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo default: 253c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo ret = -EINVAL; 254c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo break; 255c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo } 256c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 257c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo return ret; 258c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo} 259c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 260e285a5250c0772c5596a9137041a96b2c1f744d6Eliad Pellerstatic int wl1271_tm_cmd_recover(struct wl1271 *wl, struct nlattr *tb[]) 261e285a5250c0772c5596a9137041a96b2c1f744d6Eliad Peller{ 262e285a5250c0772c5596a9137041a96b2c1f744d6Eliad Peller wl1271_debug(DEBUG_TESTMODE, "testmode cmd recover"); 263e285a5250c0772c5596a9137041a96b2c1f744d6Eliad Peller 264baacb9aed020b890ddf6a57837a169092a25fc9bIdo Yariv wl12xx_queue_recovery_work(wl); 265e285a5250c0772c5596a9137041a96b2c1f744d6Eliad Peller 266e285a5250c0772c5596a9137041a96b2c1f744d6Eliad Peller return 0; 267e285a5250c0772c5596a9137041a96b2c1f744d6Eliad Peller} 268e285a5250c0772c5596a9137041a96b2c1f744d6Eliad Peller 26975f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelhostatic int wl12xx_tm_cmd_get_mac(struct wl1271 *wl, struct nlattr *tb[]) 27075f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho{ 27175f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho struct sk_buff *skb; 27275f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho u8 mac_addr[ETH_ALEN]; 27375f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho int ret = 0; 27475f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho 27575f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho mutex_lock(&wl->mutex); 27675f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho 2773fcdab7066a31ae90ac2beba7d38e8e606374998Eliad Peller if (!wl->plt) { 27875f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho ret = -EINVAL; 27975f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho goto out; 28075f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho } 28175f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho 28275f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho if (wl->fuse_oui_addr == 0 && wl->fuse_nic_addr == 0) { 28375f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho ret = -EOPNOTSUPP; 28475f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho goto out; 28575f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho } 28675f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho 28775f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho mac_addr[0] = (u8)(wl->fuse_oui_addr >> 16); 28875f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho mac_addr[1] = (u8)(wl->fuse_oui_addr >> 8); 28975f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho mac_addr[2] = (u8) wl->fuse_oui_addr; 29075f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho mac_addr[3] = (u8)(wl->fuse_nic_addr >> 16); 29175f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho mac_addr[4] = (u8)(wl->fuse_nic_addr >> 8); 29275f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho mac_addr[5] = (u8) wl->fuse_nic_addr; 29375f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho 29475f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, ETH_ALEN); 29575f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho if (!skb) { 29675f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho ret = -ENOMEM; 29775f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho goto out; 29875f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho } 29975f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho 30075f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho NLA_PUT(skb, WL1271_TM_ATTR_DATA, ETH_ALEN, mac_addr); 30175f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho ret = cfg80211_testmode_reply(skb); 30275f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho if (ret < 0) 30375f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho goto out; 30475f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho 30575f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelhoout: 30675f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho mutex_unlock(&wl->mutex); 30775f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho return ret; 30875f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho 30975f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelhonla_put_failure: 31075f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho kfree_skb(skb); 31175f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho ret = -EMSGSIZE; 31275f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho goto out; 31375f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho} 31475f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho 315c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valoint wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len) 316c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo{ 317c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo struct wl1271 *wl = hw->priv; 318c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo struct nlattr *tb[WL1271_TM_ATTR_MAX + 1]; 319c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo int err; 320c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 321c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo err = nla_parse(tb, WL1271_TM_ATTR_MAX, data, len, wl1271_tm_policy); 322c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo if (err) 323c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo return err; 324c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 325c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo if (!tb[WL1271_TM_ATTR_CMD_ID]) 326c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo return -EINVAL; 327c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo 328c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo switch (nla_get_u32(tb[WL1271_TM_ATTR_CMD_ID])) { 329c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo case WL1271_TM_CMD_TEST: 330c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo return wl1271_tm_cmd_test(wl, tb); 331c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo case WL1271_TM_CMD_INTERROGATE: 332c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo return wl1271_tm_cmd_interrogate(wl, tb); 333c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo case WL1271_TM_CMD_CONFIGURE: 334c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo return wl1271_tm_cmd_configure(wl, tb); 335c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo case WL1271_TM_CMD_SET_PLT_MODE: 336c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo return wl1271_tm_cmd_set_plt_mode(wl, tb); 337e285a5250c0772c5596a9137041a96b2c1f744d6Eliad Peller case WL1271_TM_CMD_RECOVER: 338e285a5250c0772c5596a9137041a96b2c1f744d6Eliad Peller return wl1271_tm_cmd_recover(wl, tb); 33975f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho case WL1271_TM_CMD_GET_MAC: 34075f25548bea11d35b7cb0879eea595d3f86a0cc4Luciano Coelho return wl12xx_tm_cmd_get_mac(wl, tb); 341c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo default: 342c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo return -EOPNOTSUPP; 343c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo } 344c8c90873520ef4c201cfd03b4892ca8bbf551e2eKalle Valo} 345