blob: 69b7e6bf2d6f40adfd1a1a6ab98795730da338f2 [file] [log] [blame]
Cindy H. Kao4613e722011-05-06 10:40:15 -07001/******************************************************************************
2 *
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
5 *
6 * GPL LICENSE SUMMARY
7 *
8 * Copyright(c) 2010 - 2011 Intel Corporation. All rights reserved.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of version 2 of the GNU General Public License as
12 * published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
22 * USA
23 *
24 * The full GNU General Public License is included in this distribution
25 * in the file called LICENSE.GPL.
26 *
27 * Contact Information:
28 * Intel Linux Wireless <ilw@linux.intel.com>
29 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
30 *
31 * BSD LICENSE
32 *
33 * Copyright(c) 2010 - 2011 Intel Corporation. All rights reserved.
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 *
40 * * Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * * Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in
44 * the documentation and/or other materials provided with the
45 * distribution.
46 * * Neither the name Intel Corporation nor the names of its
47 * contributors may be used to endorse or promote products derived
48 * from this software without specific prior written permission.
49 *
50 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
51 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
52 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
53 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
54 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
55 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
56 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
57 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
58 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
59 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
60 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
61 *
62 *****************************************************************************/
63#include <linux/init.h>
64#include <linux/kernel.h>
65#include <linux/module.h>
66#include <net/net_namespace.h>
67#include <linux/netdevice.h>
68#include <net/cfg80211.h>
69#include <net/mac80211.h>
70#include <net/netlink.h>
71
72
73#include "iwl-dev.h"
74#include "iwl-core.h"
75#include "iwl-debug.h"
76#include "iwl-fh.h"
77#include "iwl-io.h"
78#include "iwl-agn.h"
79#include "iwl-testmode.h"
80
81
82/* The TLVs used in the gnl message policy between the kernel module and
83 * user space application. iwl_testmode_gnl_msg_policy is to be carried
84 * through the NL80211_CMD_TESTMODE channel regulated by nl80211.
85 * See iwl-testmode.h
86 */
87static
88struct nla_policy iwl_testmode_gnl_msg_policy[IWL_TM_ATTR_MAX] = {
89 [IWL_TM_ATTR_COMMAND] = { .type = NLA_U32, },
90
91 [IWL_TM_ATTR_UCODE_CMD_ID] = { .type = NLA_U8, },
92 [IWL_TM_ATTR_UCODE_CMD_DATA] = { .type = NLA_UNSPEC, },
93
94 [IWL_TM_ATTR_REG_OFFSET] = { .type = NLA_U32, },
95 [IWL_TM_ATTR_REG_VALUE8] = { .type = NLA_U8, },
96 [IWL_TM_ATTR_REG_VALUE32] = { .type = NLA_U32, },
97
98 [IWL_TM_ATTR_SYNC_RSP] = { .type = NLA_UNSPEC, },
99 [IWL_TM_ATTR_UCODE_RX_PKT] = { .type = NLA_UNSPEC, },
Wey-Yi Guy7a4e5282011-05-06 10:21:28 -0700100
Wey-Yi Guy4babc352011-05-03 18:05:12 -0700101 [IWL_TM_ATTR_EEPROM] = { .type = NLA_UNSPEC, },
102
Wey-Yi Guy7a4e5282011-05-06 10:21:28 -0700103 [IWL_TM_ATTR_TRACE_ADDR] = { .type = NLA_UNSPEC, },
104 [IWL_TM_ATTR_TRACE_DATA] = { .type = NLA_UNSPEC, },
105
Wey-Yi Guy64898542011-05-03 18:05:13 -0700106 [IWL_TM_ATTR_FIXRATE] = { .type = NLA_U32, },
Cindy H. Kao4613e722011-05-06 10:40:15 -0700107};
108
109/*
110 * See the struct iwl_rx_packet in iwl-commands.h for the format of the
111 * received events from the device
112 */
113static inline int get_event_length(struct iwl_rx_mem_buffer *rxb)
114{
115 struct iwl_rx_packet *pkt = rxb_addr(rxb);
116 if (pkt)
117 return le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
118 else
119 return 0;
120}
121
122
123/*
124 * This function multicasts the spontaneous messages from the device to the
125 * user space. It is invoked whenever there is a received messages
126 * from the device. This function is called within the ISR of the rx handlers
127 * in iwlagn driver.
128 *
129 * The parsing of the message content is left to the user space application,
130 * The message content is treated as unattacked raw data and is encapsulated
131 * with IWL_TM_ATTR_UCODE_RX_PKT multicasting to the user space.
132 *
133 * @priv: the instance of iwlwifi device
134 * @rxb: pointer to rx data content received by the ISR
135 *
136 * See the message policies and TLVs in iwl_testmode_gnl_msg_policy[].
137 * For the messages multicasting to the user application, the mandatory
138 * TLV fields are :
139 * IWL_TM_ATTR_COMMAND must be IWL_TM_CMD_DEV2APP_UCODE_RX_PKT
140 * IWL_TM_ATTR_UCODE_RX_PKT for carrying the message content
141 */
142
143static void iwl_testmode_ucode_rx_pkt(struct iwl_priv *priv,
144 struct iwl_rx_mem_buffer *rxb)
145{
146 struct ieee80211_hw *hw = priv->hw;
147 struct sk_buff *skb;
148 void *data;
149 int length;
150
151 data = (void *)rxb_addr(rxb);
152 length = get_event_length(rxb);
153
154 if (!data || length == 0)
155 return;
156
157 skb = cfg80211_testmode_alloc_event_skb(hw->wiphy, 20 + length,
158 GFP_ATOMIC);
159 if (skb == NULL) {
160 IWL_DEBUG_INFO(priv,
161 "Run out of memory for messages to user space ?\n");
162 return;
163 }
164 NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, IWL_TM_CMD_DEV2APP_UCODE_RX_PKT);
165 NLA_PUT(skb, IWL_TM_ATTR_UCODE_RX_PKT, length, data);
166 cfg80211_testmode_event(skb, GFP_ATOMIC);
167 return;
168
169nla_put_failure:
170 kfree_skb(skb);
171 IWL_DEBUG_INFO(priv, "Ouch, overran buffer, check allocation!\n");
172}
173
174void iwl_testmode_init(struct iwl_priv *priv)
175{
176 priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt;
Wey-Yi Guy7a4e5282011-05-06 10:21:28 -0700177 priv->testmode_trace.trace_enabled = false;
178}
179
180static void iwl_trace_cleanup(struct iwl_priv *priv)
181{
182 struct device *dev = &priv->pci_dev->dev;
183
184 if (priv->testmode_trace.trace_enabled) {
185 if (priv->testmode_trace.cpu_addr &&
186 priv->testmode_trace.dma_addr)
187 dma_free_coherent(dev,
188 TRACE_TOTAL_SIZE,
189 priv->testmode_trace.cpu_addr,
190 priv->testmode_trace.dma_addr);
191 priv->testmode_trace.trace_enabled = false;
192 priv->testmode_trace.cpu_addr = NULL;
193 priv->testmode_trace.trace_addr = NULL;
194 priv->testmode_trace.dma_addr = 0;
195 }
196}
197
198
199void iwl_testmode_cleanup(struct iwl_priv *priv)
200{
201 iwl_trace_cleanup(priv);
Cindy H. Kao4613e722011-05-06 10:40:15 -0700202}
203
204/*
205 * This function handles the user application commands to the ucode.
206 *
207 * It retrieves the mandatory fields IWL_TM_ATTR_UCODE_CMD_ID and
208 * IWL_TM_ATTR_UCODE_CMD_DATA and calls to the handler to send the
209 * host command to the ucode.
210 *
211 * If any mandatory field is missing, -ENOMSG is replied to the user space
212 * application; otherwise, the actual execution result of the host command to
213 * ucode is replied.
214 *
215 * @hw: ieee80211_hw object that represents the device
216 * @tb: gnl message fields from the user space
217 */
218static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb)
219{
220 struct iwl_priv *priv = hw->priv;
221 struct iwl_host_cmd cmd;
222
223 memset(&cmd, 0, sizeof(struct iwl_host_cmd));
224
225 if (!tb[IWL_TM_ATTR_UCODE_CMD_ID] ||
226 !tb[IWL_TM_ATTR_UCODE_CMD_DATA]) {
227 IWL_DEBUG_INFO(priv,
228 "Error finding ucode command mandatory fields\n");
229 return -ENOMSG;
230 }
231
232 cmd.id = nla_get_u8(tb[IWL_TM_ATTR_UCODE_CMD_ID]);
Johannes Berg3fa50732011-05-04 07:50:38 -0700233 cmd.data[0] = nla_data(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
234 cmd.len[0] = nla_len(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
Johannes Berg4ce7cc22011-05-13 11:57:40 -0700235 cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
Cindy H. Kao4613e722011-05-06 10:40:15 -0700236 IWL_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x,"
Johannes Berg3fa50732011-05-04 07:50:38 -0700237 " len %d\n", cmd.id, cmd.flags, cmd.len[0]);
Cindy H. Kao4613e722011-05-06 10:40:15 -0700238 /* ok, let's submit the command to ucode */
239 return iwl_send_cmd(priv, &cmd);
240}
241
242
243/*
244 * This function handles the user application commands for register access.
245 *
246 * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the
247 * handlers respectively.
248 *
249 * If it's an unknown commdn ID, -ENOSYS is returned; or -ENOMSG if the
250 * mandatory fields(IWL_TM_ATTR_REG_OFFSET,IWL_TM_ATTR_REG_VALUE32,
251 * IWL_TM_ATTR_REG_VALUE8) are missing; Otherwise 0 is replied indicating
252 * the success of the command execution.
253 *
254 * If IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_REG_READ32, the register read
255 * value is returned with IWL_TM_ATTR_REG_VALUE32.
256 *
257 * @hw: ieee80211_hw object that represents the device
258 * @tb: gnl message fields from the user space
259 */
260static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)
261{
262 struct iwl_priv *priv = hw->priv;
263 u32 ofs, val32;
264 u8 val8;
265 struct sk_buff *skb;
266 int status = 0;
267
268 if (!tb[IWL_TM_ATTR_REG_OFFSET]) {
269 IWL_DEBUG_INFO(priv, "Error finding register offset\n");
270 return -ENOMSG;
271 }
272 ofs = nla_get_u32(tb[IWL_TM_ATTR_REG_OFFSET]);
273 IWL_INFO(priv, "testmode register access command offset 0x%x\n", ofs);
274
275 switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
276 case IWL_TM_CMD_APP2DEV_REG_READ32:
277 val32 = iwl_read32(priv, ofs);
278 IWL_INFO(priv, "32bit value to read 0x%x\n", val32);
279
280 skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
281 if (!skb) {
282 IWL_DEBUG_INFO(priv, "Error allocating memory\n");
283 return -ENOMEM;
284 }
285 NLA_PUT_U32(skb, IWL_TM_ATTR_REG_VALUE32, val32);
286 status = cfg80211_testmode_reply(skb);
287 if (status < 0)
288 IWL_DEBUG_INFO(priv,
289 "Error sending msg : %d\n", status);
290 break;
291 case IWL_TM_CMD_APP2DEV_REG_WRITE32:
292 if (!tb[IWL_TM_ATTR_REG_VALUE32]) {
293 IWL_DEBUG_INFO(priv,
294 "Error finding value to write\n");
295 return -ENOMSG;
296 } else {
297 val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]);
298 IWL_INFO(priv, "32bit value to write 0x%x\n", val32);
299 iwl_write32(priv, ofs, val32);
300 }
301 break;
302 case IWL_TM_CMD_APP2DEV_REG_WRITE8:
303 if (!tb[IWL_TM_ATTR_REG_VALUE8]) {
304 IWL_DEBUG_INFO(priv, "Error finding value to write\n");
305 return -ENOMSG;
306 } else {
307 val8 = nla_get_u8(tb[IWL_TM_ATTR_REG_VALUE8]);
308 IWL_INFO(priv, "8bit value to write 0x%x\n", val8);
309 iwl_write8(priv, ofs, val8);
310 }
311 break;
312 default:
313 IWL_DEBUG_INFO(priv, "Unknown testmode register command ID\n");
314 return -ENOSYS;
315 }
316
317 return status;
318
319nla_put_failure:
320 kfree_skb(skb);
321 return -EMSGSIZE;
322}
323
324
325static int iwl_testmode_cfg_init_calib(struct iwl_priv *priv)
326{
327 struct iwl_notification_wait calib_wait;
328 int ret;
329
330 iwlagn_init_notification_wait(priv, &calib_wait,
331 CALIBRATION_COMPLETE_NOTIFICATION,
332 NULL, NULL);
333 ret = iwlagn_init_alive_start(priv);
334 if (ret) {
335 IWL_DEBUG_INFO(priv,
336 "Error configuring init calibration: %d\n", ret);
337 goto cfg_init_calib_error;
338 }
339
340 ret = iwlagn_wait_notification(priv, &calib_wait, 2 * HZ);
341 if (ret)
342 IWL_DEBUG_INFO(priv, "Error detecting"
343 " CALIBRATION_COMPLETE_NOTIFICATION: %d\n", ret);
344 return ret;
345
346cfg_init_calib_error:
347 iwlagn_remove_notification(priv, &calib_wait);
348 return ret;
349}
350
351/*
352 * This function handles the user application commands for driver.
353 *
354 * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the
355 * handlers respectively.
356 *
357 * If it's an unknown commdn ID, -ENOSYS is replied; otherwise, the returned
358 * value of the actual command execution is replied to the user application.
359 *
360 * If there's any message responding to the user space, IWL_TM_ATTR_SYNC_RSP
361 * is used for carry the message while IWL_TM_ATTR_COMMAND must set to
362 * IWL_TM_CMD_DEV2APP_SYNC_RSP.
363 *
364 * @hw: ieee80211_hw object that represents the device
365 * @tb: gnl message fields from the user space
366 */
367static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
368{
369 struct iwl_priv *priv = hw->priv;
370 struct sk_buff *skb;
371 unsigned char *rsp_data_ptr = NULL;
372 int status = 0, rsp_data_len = 0;
373
374 switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
375 case IWL_TM_CMD_APP2DEV_GET_DEVICENAME:
376 rsp_data_ptr = (unsigned char *)priv->cfg->name;
377 rsp_data_len = strlen(priv->cfg->name);
378 skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
379 rsp_data_len + 20);
380 if (!skb) {
381 IWL_DEBUG_INFO(priv,
382 "Error allocating memory\n");
383 return -ENOMEM;
384 }
385 NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND,
386 IWL_TM_CMD_DEV2APP_SYNC_RSP);
387 NLA_PUT(skb, IWL_TM_ATTR_SYNC_RSP,
388 rsp_data_len, rsp_data_ptr);
389 status = cfg80211_testmode_reply(skb);
390 if (status < 0)
391 IWL_DEBUG_INFO(priv, "Error sending msg : %d\n",
392 status);
393 break;
394
395 case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
396 status = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_init,
397 UCODE_SUBTYPE_INIT, -1);
398 if (status)
399 IWL_DEBUG_INFO(priv,
400 "Error loading init ucode: %d\n", status);
401 break;
402
403 case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
404 iwl_testmode_cfg_init_calib(priv);
405 iwlagn_stop_device(priv);
406 break;
407
408 case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
409 status = iwlagn_load_ucode_wait_alive(priv,
410 &priv->ucode_rt,
411 UCODE_SUBTYPE_REGULAR,
412 UCODE_SUBTYPE_REGULAR_NEW);
413 if (status) {
414 IWL_DEBUG_INFO(priv,
415 "Error loading runtime ucode: %d\n", status);
416 break;
417 }
418 status = iwl_alive_start(priv);
419 if (status)
420 IWL_DEBUG_INFO(priv,
421 "Error starting the device: %d\n", status);
422 break;
423
Wey-Yi Guy4babc352011-05-03 18:05:12 -0700424 case IWL_TM_CMD_APP2DEV_GET_EEPROM:
425 if (priv->eeprom) {
426 skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
427 priv->cfg->base_params->eeprom_size + 20);
428 if (!skb) {
429 IWL_DEBUG_INFO(priv,
430 "Error allocating memory\n");
431 return -ENOMEM;
432 }
433 NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND,
434 IWL_TM_CMD_DEV2APP_EEPROM_RSP);
435 NLA_PUT(skb, IWL_TM_ATTR_EEPROM,
436 priv->cfg->base_params->eeprom_size,
437 priv->eeprom);
438 status = cfg80211_testmode_reply(skb);
439 if (status < 0)
440 IWL_DEBUG_INFO(priv,
441 "Error sending msg : %d\n",
442 status);
443 } else
444 return -EFAULT;
445 break;
446
Wey-Yi Guy64898542011-05-03 18:05:13 -0700447 case IWL_TM_CMD_APP2DEV_FIXRATE_REQ:
448 if (!tb[IWL_TM_ATTR_FIXRATE]) {
449 IWL_DEBUG_INFO(priv,
450 "Error finding fixrate setting\n");
451 return -ENOMSG;
452 }
453 priv->dbg_fixed_rate = nla_get_u32(tb[IWL_TM_ATTR_FIXRATE]);
454 break;
455
Cindy H. Kao4613e722011-05-06 10:40:15 -0700456 default:
457 IWL_DEBUG_INFO(priv, "Unknown testmode driver command ID\n");
458 return -ENOSYS;
459 }
460 return status;
461
462nla_put_failure:
463 kfree_skb(skb);
464 return -EMSGSIZE;
465}
466
Wey-Yi Guy7a4e5282011-05-06 10:21:28 -0700467
468/*
469 * This function handles the user application commands for uCode trace
470 *
471 * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the
472 * handlers respectively.
473 *
474 * If it's an unknown commdn ID, -ENOSYS is replied; otherwise, the returned
475 * value of the actual command execution is replied to the user application.
476 *
477 * @hw: ieee80211_hw object that represents the device
478 * @tb: gnl message fields from the user space
479 */
480static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb)
481{
482 struct iwl_priv *priv = hw->priv;
483 struct sk_buff *skb;
484 int status = 0;
485 struct device *dev = &priv->pci_dev->dev;
486
487 switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
488 case IWL_TM_CMD_APP2DEV_BEGIN_TRACE:
489 if (priv->testmode_trace.trace_enabled)
490 return -EBUSY;
491
492 priv->testmode_trace.cpu_addr =
493 dma_alloc_coherent(dev,
494 TRACE_TOTAL_SIZE,
495 &priv->testmode_trace.dma_addr,
496 GFP_KERNEL);
497 if (!priv->testmode_trace.cpu_addr)
498 return -ENOMEM;
499 priv->testmode_trace.trace_enabled = true;
500 priv->testmode_trace.trace_addr = (u8 *)PTR_ALIGN(
501 priv->testmode_trace.cpu_addr, 0x100);
502 memset(priv->testmode_trace.trace_addr, 0x03B,
503 TRACE_BUFF_SIZE);
504 skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
505 sizeof(priv->testmode_trace.dma_addr) + 20);
506 if (!skb) {
507 IWL_DEBUG_INFO(priv,
508 "Error allocating memory\n");
509 iwl_trace_cleanup(priv);
510 return -ENOMEM;
511 }
512 NLA_PUT(skb, IWL_TM_ATTR_TRACE_ADDR,
513 sizeof(priv->testmode_trace.dma_addr),
514 (u64 *)&priv->testmode_trace.dma_addr);
515 status = cfg80211_testmode_reply(skb);
516 if (status < 0) {
517 IWL_DEBUG_INFO(priv,
518 "Error sending msg : %d\n",
519 status);
520 }
521 break;
522
523 case IWL_TM_CMD_APP2DEV_END_TRACE:
524 iwl_trace_cleanup(priv);
525 break;
526
527 case IWL_TM_CMD_APP2DEV_READ_TRACE:
528 if (priv->testmode_trace.trace_enabled &&
529 priv->testmode_trace.trace_addr) {
530 skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
531 20 + TRACE_BUFF_SIZE);
532 if (skb == NULL) {
533 IWL_DEBUG_INFO(priv,
534 "Error allocating memory\n");
535 return -ENOMEM;
536 }
537 NLA_PUT(skb, IWL_TM_ATTR_TRACE_DATA,
538 TRACE_BUFF_SIZE,
539 priv->testmode_trace.trace_addr);
540 status = cfg80211_testmode_reply(skb);
541 if (status < 0) {
542 IWL_DEBUG_INFO(priv,
543 "Error sending msg : %d\n", status);
544 }
545 } else
546 return -EFAULT;
547 break;
548
549 default:
550 IWL_DEBUG_INFO(priv, "Unknown testmode mem command ID\n");
551 return -ENOSYS;
552 }
553 return status;
554
555nla_put_failure:
556 kfree_skb(skb);
557 if (nla_get_u32(tb[IWL_TM_ATTR_COMMAND]) ==
558 IWL_TM_CMD_APP2DEV_BEGIN_TRACE)
559 iwl_trace_cleanup(priv);
560 return -EMSGSIZE;
561}
562
Cindy H. Kao4613e722011-05-06 10:40:15 -0700563/* The testmode gnl message handler that takes the gnl message from the
564 * user space and parses it per the policy iwl_testmode_gnl_msg_policy, then
565 * invoke the corresponding handlers.
566 *
567 * This function is invoked when there is user space application sending
568 * gnl message through the testmode tunnel NL80211_CMD_TESTMODE regulated
569 * by nl80211.
570 *
571 * It retrieves the mandatory field, IWL_TM_ATTR_COMMAND, before
572 * dispatching it to the corresponding handler.
573 *
574 * If IWL_TM_ATTR_COMMAND is missing, -ENOMSG is replied to user application;
575 * -ENOSYS is replied to the user application if the command is unknown;
576 * Otherwise, the command is dispatched to the respective handler.
577 *
578 * @hw: ieee80211_hw object that represents the device
579 * @data: pointer to user space message
580 * @len: length in byte of @data
581 */
582int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
583{
584 struct nlattr *tb[IWL_TM_ATTR_MAX - 1];
585 struct iwl_priv *priv = hw->priv;
586 int result;
587
588 result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len,
589 iwl_testmode_gnl_msg_policy);
590 if (result != 0) {
591 IWL_DEBUG_INFO(priv,
592 "Error parsing the gnl message : %d\n", result);
593 return result;
594 }
595
596 /* IWL_TM_ATTR_COMMAND is absolutely mandatory */
597 if (!tb[IWL_TM_ATTR_COMMAND]) {
598 IWL_DEBUG_INFO(priv, "Error finding testmode command type\n");
599 return -ENOMSG;
600 }
601 /* in case multiple accesses to the device happens */
602 mutex_lock(&priv->mutex);
603
604 switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
605 case IWL_TM_CMD_APP2DEV_UCODE:
606 IWL_DEBUG_INFO(priv, "testmode cmd to uCode\n");
607 result = iwl_testmode_ucode(hw, tb);
608 break;
609 case IWL_TM_CMD_APP2DEV_REG_READ32:
610 case IWL_TM_CMD_APP2DEV_REG_WRITE32:
611 case IWL_TM_CMD_APP2DEV_REG_WRITE8:
612 IWL_DEBUG_INFO(priv, "testmode cmd to register\n");
613 result = iwl_testmode_reg(hw, tb);
614 break;
615 case IWL_TM_CMD_APP2DEV_GET_DEVICENAME:
616 case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
617 case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
618 case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
Wey-Yi Guy4babc352011-05-03 18:05:12 -0700619 case IWL_TM_CMD_APP2DEV_GET_EEPROM:
Wey-Yi Guy64898542011-05-03 18:05:13 -0700620 case IWL_TM_CMD_APP2DEV_FIXRATE_REQ:
Cindy H. Kao4613e722011-05-06 10:40:15 -0700621 IWL_DEBUG_INFO(priv, "testmode cmd to driver\n");
622 result = iwl_testmode_driver(hw, tb);
623 break;
Wey-Yi Guy7a4e5282011-05-06 10:21:28 -0700624
625 case IWL_TM_CMD_APP2DEV_BEGIN_TRACE:
626 case IWL_TM_CMD_APP2DEV_END_TRACE:
627 case IWL_TM_CMD_APP2DEV_READ_TRACE:
628 IWL_DEBUG_INFO(priv, "testmode uCode trace cmd to driver\n");
629 result = iwl_testmode_trace(hw, tb);
630 break;
631
Cindy H. Kao4613e722011-05-06 10:40:15 -0700632 default:
633 IWL_DEBUG_INFO(priv, "Unknown testmode command\n");
634 result = -ENOSYS;
635 break;
636 }
637
638 mutex_unlock(&priv->mutex);
639 return result;
640}