blob: b778c3f4b84d347da73c516c8bf67859330b57e3 [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
101 [IWL_TM_ATTR_TRACE_ADDR] = { .type = NLA_UNSPEC, },
102 [IWL_TM_ATTR_TRACE_DATA] = { .type = NLA_UNSPEC, },
103
Cindy H. Kao4613e722011-05-06 10:40:15 -0700104};
105
106/*
107 * See the struct iwl_rx_packet in iwl-commands.h for the format of the
108 * received events from the device
109 */
110static inline int get_event_length(struct iwl_rx_mem_buffer *rxb)
111{
112 struct iwl_rx_packet *pkt = rxb_addr(rxb);
113 if (pkt)
114 return le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
115 else
116 return 0;
117}
118
119
120/*
121 * This function multicasts the spontaneous messages from the device to the
122 * user space. It is invoked whenever there is a received messages
123 * from the device. This function is called within the ISR of the rx handlers
124 * in iwlagn driver.
125 *
126 * The parsing of the message content is left to the user space application,
127 * The message content is treated as unattacked raw data and is encapsulated
128 * with IWL_TM_ATTR_UCODE_RX_PKT multicasting to the user space.
129 *
130 * @priv: the instance of iwlwifi device
131 * @rxb: pointer to rx data content received by the ISR
132 *
133 * See the message policies and TLVs in iwl_testmode_gnl_msg_policy[].
134 * For the messages multicasting to the user application, the mandatory
135 * TLV fields are :
136 * IWL_TM_ATTR_COMMAND must be IWL_TM_CMD_DEV2APP_UCODE_RX_PKT
137 * IWL_TM_ATTR_UCODE_RX_PKT for carrying the message content
138 */
139
140static void iwl_testmode_ucode_rx_pkt(struct iwl_priv *priv,
141 struct iwl_rx_mem_buffer *rxb)
142{
143 struct ieee80211_hw *hw = priv->hw;
144 struct sk_buff *skb;
145 void *data;
146 int length;
147
148 data = (void *)rxb_addr(rxb);
149 length = get_event_length(rxb);
150
151 if (!data || length == 0)
152 return;
153
154 skb = cfg80211_testmode_alloc_event_skb(hw->wiphy, 20 + length,
155 GFP_ATOMIC);
156 if (skb == NULL) {
157 IWL_DEBUG_INFO(priv,
158 "Run out of memory for messages to user space ?\n");
159 return;
160 }
161 NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, IWL_TM_CMD_DEV2APP_UCODE_RX_PKT);
162 NLA_PUT(skb, IWL_TM_ATTR_UCODE_RX_PKT, length, data);
163 cfg80211_testmode_event(skb, GFP_ATOMIC);
164 return;
165
166nla_put_failure:
167 kfree_skb(skb);
168 IWL_DEBUG_INFO(priv, "Ouch, overran buffer, check allocation!\n");
169}
170
171void iwl_testmode_init(struct iwl_priv *priv)
172{
173 priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt;
Wey-Yi Guy7a4e5282011-05-06 10:21:28 -0700174 priv->testmode_trace.trace_enabled = false;
175}
176
177static void iwl_trace_cleanup(struct iwl_priv *priv)
178{
179 struct device *dev = &priv->pci_dev->dev;
180
181 if (priv->testmode_trace.trace_enabled) {
182 if (priv->testmode_trace.cpu_addr &&
183 priv->testmode_trace.dma_addr)
184 dma_free_coherent(dev,
185 TRACE_TOTAL_SIZE,
186 priv->testmode_trace.cpu_addr,
187 priv->testmode_trace.dma_addr);
188 priv->testmode_trace.trace_enabled = false;
189 priv->testmode_trace.cpu_addr = NULL;
190 priv->testmode_trace.trace_addr = NULL;
191 priv->testmode_trace.dma_addr = 0;
192 }
193}
194
195
196void iwl_testmode_cleanup(struct iwl_priv *priv)
197{
198 iwl_trace_cleanup(priv);
Cindy H. Kao4613e722011-05-06 10:40:15 -0700199}
200
201/*
202 * This function handles the user application commands to the ucode.
203 *
204 * It retrieves the mandatory fields IWL_TM_ATTR_UCODE_CMD_ID and
205 * IWL_TM_ATTR_UCODE_CMD_DATA and calls to the handler to send the
206 * host command to the ucode.
207 *
208 * If any mandatory field is missing, -ENOMSG is replied to the user space
209 * application; otherwise, the actual execution result of the host command to
210 * ucode is replied.
211 *
212 * @hw: ieee80211_hw object that represents the device
213 * @tb: gnl message fields from the user space
214 */
215static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb)
216{
217 struct iwl_priv *priv = hw->priv;
218 struct iwl_host_cmd cmd;
219
220 memset(&cmd, 0, sizeof(struct iwl_host_cmd));
221
222 if (!tb[IWL_TM_ATTR_UCODE_CMD_ID] ||
223 !tb[IWL_TM_ATTR_UCODE_CMD_DATA]) {
224 IWL_DEBUG_INFO(priv,
225 "Error finding ucode command mandatory fields\n");
226 return -ENOMSG;
227 }
228
229 cmd.id = nla_get_u8(tb[IWL_TM_ATTR_UCODE_CMD_ID]);
Johannes Berg3fa50732011-05-04 07:50:38 -0700230 cmd.data[0] = nla_data(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
231 cmd.len[0] = nla_len(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
Johannes Berg4ce7cc22011-05-13 11:57:40 -0700232 cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
Cindy H. Kao4613e722011-05-06 10:40:15 -0700233 IWL_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x,"
Johannes Berg3fa50732011-05-04 07:50:38 -0700234 " len %d\n", cmd.id, cmd.flags, cmd.len[0]);
Cindy H. Kao4613e722011-05-06 10:40:15 -0700235 /* ok, let's submit the command to ucode */
236 return iwl_send_cmd(priv, &cmd);
237}
238
239
240/*
241 * This function handles the user application commands for register access.
242 *
243 * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the
244 * handlers respectively.
245 *
246 * If it's an unknown commdn ID, -ENOSYS is returned; or -ENOMSG if the
247 * mandatory fields(IWL_TM_ATTR_REG_OFFSET,IWL_TM_ATTR_REG_VALUE32,
248 * IWL_TM_ATTR_REG_VALUE8) are missing; Otherwise 0 is replied indicating
249 * the success of the command execution.
250 *
251 * If IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_REG_READ32, the register read
252 * value is returned with IWL_TM_ATTR_REG_VALUE32.
253 *
254 * @hw: ieee80211_hw object that represents the device
255 * @tb: gnl message fields from the user space
256 */
257static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)
258{
259 struct iwl_priv *priv = hw->priv;
260 u32 ofs, val32;
261 u8 val8;
262 struct sk_buff *skb;
263 int status = 0;
264
265 if (!tb[IWL_TM_ATTR_REG_OFFSET]) {
266 IWL_DEBUG_INFO(priv, "Error finding register offset\n");
267 return -ENOMSG;
268 }
269 ofs = nla_get_u32(tb[IWL_TM_ATTR_REG_OFFSET]);
270 IWL_INFO(priv, "testmode register access command offset 0x%x\n", ofs);
271
272 switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
273 case IWL_TM_CMD_APP2DEV_REG_READ32:
274 val32 = iwl_read32(priv, ofs);
275 IWL_INFO(priv, "32bit value to read 0x%x\n", val32);
276
277 skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
278 if (!skb) {
279 IWL_DEBUG_INFO(priv, "Error allocating memory\n");
280 return -ENOMEM;
281 }
282 NLA_PUT_U32(skb, IWL_TM_ATTR_REG_VALUE32, val32);
283 status = cfg80211_testmode_reply(skb);
284 if (status < 0)
285 IWL_DEBUG_INFO(priv,
286 "Error sending msg : %d\n", status);
287 break;
288 case IWL_TM_CMD_APP2DEV_REG_WRITE32:
289 if (!tb[IWL_TM_ATTR_REG_VALUE32]) {
290 IWL_DEBUG_INFO(priv,
291 "Error finding value to write\n");
292 return -ENOMSG;
293 } else {
294 val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]);
295 IWL_INFO(priv, "32bit value to write 0x%x\n", val32);
296 iwl_write32(priv, ofs, val32);
297 }
298 break;
299 case IWL_TM_CMD_APP2DEV_REG_WRITE8:
300 if (!tb[IWL_TM_ATTR_REG_VALUE8]) {
301 IWL_DEBUG_INFO(priv, "Error finding value to write\n");
302 return -ENOMSG;
303 } else {
304 val8 = nla_get_u8(tb[IWL_TM_ATTR_REG_VALUE8]);
305 IWL_INFO(priv, "8bit value to write 0x%x\n", val8);
306 iwl_write8(priv, ofs, val8);
307 }
308 break;
309 default:
310 IWL_DEBUG_INFO(priv, "Unknown testmode register command ID\n");
311 return -ENOSYS;
312 }
313
314 return status;
315
316nla_put_failure:
317 kfree_skb(skb);
318 return -EMSGSIZE;
319}
320
321
322static int iwl_testmode_cfg_init_calib(struct iwl_priv *priv)
323{
324 struct iwl_notification_wait calib_wait;
325 int ret;
326
327 iwlagn_init_notification_wait(priv, &calib_wait,
328 CALIBRATION_COMPLETE_NOTIFICATION,
329 NULL, NULL);
330 ret = iwlagn_init_alive_start(priv);
331 if (ret) {
332 IWL_DEBUG_INFO(priv,
333 "Error configuring init calibration: %d\n", ret);
334 goto cfg_init_calib_error;
335 }
336
337 ret = iwlagn_wait_notification(priv, &calib_wait, 2 * HZ);
338 if (ret)
339 IWL_DEBUG_INFO(priv, "Error detecting"
340 " CALIBRATION_COMPLETE_NOTIFICATION: %d\n", ret);
341 return ret;
342
343cfg_init_calib_error:
344 iwlagn_remove_notification(priv, &calib_wait);
345 return ret;
346}
347
348/*
349 * This function handles the user application commands for driver.
350 *
351 * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the
352 * handlers respectively.
353 *
354 * If it's an unknown commdn ID, -ENOSYS is replied; otherwise, the returned
355 * value of the actual command execution is replied to the user application.
356 *
357 * If there's any message responding to the user space, IWL_TM_ATTR_SYNC_RSP
358 * is used for carry the message while IWL_TM_ATTR_COMMAND must set to
359 * IWL_TM_CMD_DEV2APP_SYNC_RSP.
360 *
361 * @hw: ieee80211_hw object that represents the device
362 * @tb: gnl message fields from the user space
363 */
364static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
365{
366 struct iwl_priv *priv = hw->priv;
367 struct sk_buff *skb;
368 unsigned char *rsp_data_ptr = NULL;
369 int status = 0, rsp_data_len = 0;
370
371 switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
372 case IWL_TM_CMD_APP2DEV_GET_DEVICENAME:
373 rsp_data_ptr = (unsigned char *)priv->cfg->name;
374 rsp_data_len = strlen(priv->cfg->name);
375 skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
376 rsp_data_len + 20);
377 if (!skb) {
378 IWL_DEBUG_INFO(priv,
379 "Error allocating memory\n");
380 return -ENOMEM;
381 }
382 NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND,
383 IWL_TM_CMD_DEV2APP_SYNC_RSP);
384 NLA_PUT(skb, IWL_TM_ATTR_SYNC_RSP,
385 rsp_data_len, rsp_data_ptr);
386 status = cfg80211_testmode_reply(skb);
387 if (status < 0)
388 IWL_DEBUG_INFO(priv, "Error sending msg : %d\n",
389 status);
390 break;
391
392 case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
393 status = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_init,
394 UCODE_SUBTYPE_INIT, -1);
395 if (status)
396 IWL_DEBUG_INFO(priv,
397 "Error loading init ucode: %d\n", status);
398 break;
399
400 case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
401 iwl_testmode_cfg_init_calib(priv);
402 iwlagn_stop_device(priv);
403 break;
404
405 case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
406 status = iwlagn_load_ucode_wait_alive(priv,
407 &priv->ucode_rt,
408 UCODE_SUBTYPE_REGULAR,
409 UCODE_SUBTYPE_REGULAR_NEW);
410 if (status) {
411 IWL_DEBUG_INFO(priv,
412 "Error loading runtime ucode: %d\n", status);
413 break;
414 }
415 status = iwl_alive_start(priv);
416 if (status)
417 IWL_DEBUG_INFO(priv,
418 "Error starting the device: %d\n", status);
419 break;
420
421 default:
422 IWL_DEBUG_INFO(priv, "Unknown testmode driver command ID\n");
423 return -ENOSYS;
424 }
425 return status;
426
427nla_put_failure:
428 kfree_skb(skb);
429 return -EMSGSIZE;
430}
431
Wey-Yi Guy7a4e5282011-05-06 10:21:28 -0700432
433/*
434 * This function handles the user application commands for uCode trace
435 *
436 * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the
437 * handlers respectively.
438 *
439 * If it's an unknown commdn ID, -ENOSYS is replied; otherwise, the returned
440 * value of the actual command execution is replied to the user application.
441 *
442 * @hw: ieee80211_hw object that represents the device
443 * @tb: gnl message fields from the user space
444 */
445static int iwl_testmode_trace(struct ieee80211_hw *hw, struct nlattr **tb)
446{
447 struct iwl_priv *priv = hw->priv;
448 struct sk_buff *skb;
449 int status = 0;
450 struct device *dev = &priv->pci_dev->dev;
451
452 switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
453 case IWL_TM_CMD_APP2DEV_BEGIN_TRACE:
454 if (priv->testmode_trace.trace_enabled)
455 return -EBUSY;
456
457 priv->testmode_trace.cpu_addr =
458 dma_alloc_coherent(dev,
459 TRACE_TOTAL_SIZE,
460 &priv->testmode_trace.dma_addr,
461 GFP_KERNEL);
462 if (!priv->testmode_trace.cpu_addr)
463 return -ENOMEM;
464 priv->testmode_trace.trace_enabled = true;
465 priv->testmode_trace.trace_addr = (u8 *)PTR_ALIGN(
466 priv->testmode_trace.cpu_addr, 0x100);
467 memset(priv->testmode_trace.trace_addr, 0x03B,
468 TRACE_BUFF_SIZE);
469 skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
470 sizeof(priv->testmode_trace.dma_addr) + 20);
471 if (!skb) {
472 IWL_DEBUG_INFO(priv,
473 "Error allocating memory\n");
474 iwl_trace_cleanup(priv);
475 return -ENOMEM;
476 }
477 NLA_PUT(skb, IWL_TM_ATTR_TRACE_ADDR,
478 sizeof(priv->testmode_trace.dma_addr),
479 (u64 *)&priv->testmode_trace.dma_addr);
480 status = cfg80211_testmode_reply(skb);
481 if (status < 0) {
482 IWL_DEBUG_INFO(priv,
483 "Error sending msg : %d\n",
484 status);
485 }
486 break;
487
488 case IWL_TM_CMD_APP2DEV_END_TRACE:
489 iwl_trace_cleanup(priv);
490 break;
491
492 case IWL_TM_CMD_APP2DEV_READ_TRACE:
493 if (priv->testmode_trace.trace_enabled &&
494 priv->testmode_trace.trace_addr) {
495 skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
496 20 + TRACE_BUFF_SIZE);
497 if (skb == NULL) {
498 IWL_DEBUG_INFO(priv,
499 "Error allocating memory\n");
500 return -ENOMEM;
501 }
502 NLA_PUT(skb, IWL_TM_ATTR_TRACE_DATA,
503 TRACE_BUFF_SIZE,
504 priv->testmode_trace.trace_addr);
505 status = cfg80211_testmode_reply(skb);
506 if (status < 0) {
507 IWL_DEBUG_INFO(priv,
508 "Error sending msg : %d\n", status);
509 }
510 } else
511 return -EFAULT;
512 break;
513
514 default:
515 IWL_DEBUG_INFO(priv, "Unknown testmode mem command ID\n");
516 return -ENOSYS;
517 }
518 return status;
519
520nla_put_failure:
521 kfree_skb(skb);
522 if (nla_get_u32(tb[IWL_TM_ATTR_COMMAND]) ==
523 IWL_TM_CMD_APP2DEV_BEGIN_TRACE)
524 iwl_trace_cleanup(priv);
525 return -EMSGSIZE;
526}
527
Cindy H. Kao4613e722011-05-06 10:40:15 -0700528/* The testmode gnl message handler that takes the gnl message from the
529 * user space and parses it per the policy iwl_testmode_gnl_msg_policy, then
530 * invoke the corresponding handlers.
531 *
532 * This function is invoked when there is user space application sending
533 * gnl message through the testmode tunnel NL80211_CMD_TESTMODE regulated
534 * by nl80211.
535 *
536 * It retrieves the mandatory field, IWL_TM_ATTR_COMMAND, before
537 * dispatching it to the corresponding handler.
538 *
539 * If IWL_TM_ATTR_COMMAND is missing, -ENOMSG is replied to user application;
540 * -ENOSYS is replied to the user application if the command is unknown;
541 * Otherwise, the command is dispatched to the respective handler.
542 *
543 * @hw: ieee80211_hw object that represents the device
544 * @data: pointer to user space message
545 * @len: length in byte of @data
546 */
547int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
548{
549 struct nlattr *tb[IWL_TM_ATTR_MAX - 1];
550 struct iwl_priv *priv = hw->priv;
551 int result;
552
553 result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len,
554 iwl_testmode_gnl_msg_policy);
555 if (result != 0) {
556 IWL_DEBUG_INFO(priv,
557 "Error parsing the gnl message : %d\n", result);
558 return result;
559 }
560
561 /* IWL_TM_ATTR_COMMAND is absolutely mandatory */
562 if (!tb[IWL_TM_ATTR_COMMAND]) {
563 IWL_DEBUG_INFO(priv, "Error finding testmode command type\n");
564 return -ENOMSG;
565 }
566 /* in case multiple accesses to the device happens */
567 mutex_lock(&priv->mutex);
568
569 switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
570 case IWL_TM_CMD_APP2DEV_UCODE:
571 IWL_DEBUG_INFO(priv, "testmode cmd to uCode\n");
572 result = iwl_testmode_ucode(hw, tb);
573 break;
574 case IWL_TM_CMD_APP2DEV_REG_READ32:
575 case IWL_TM_CMD_APP2DEV_REG_WRITE32:
576 case IWL_TM_CMD_APP2DEV_REG_WRITE8:
577 IWL_DEBUG_INFO(priv, "testmode cmd to register\n");
578 result = iwl_testmode_reg(hw, tb);
579 break;
580 case IWL_TM_CMD_APP2DEV_GET_DEVICENAME:
581 case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
582 case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
583 case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
584 IWL_DEBUG_INFO(priv, "testmode cmd to driver\n");
585 result = iwl_testmode_driver(hw, tb);
586 break;
Wey-Yi Guy7a4e5282011-05-06 10:21:28 -0700587
588 case IWL_TM_CMD_APP2DEV_BEGIN_TRACE:
589 case IWL_TM_CMD_APP2DEV_END_TRACE:
590 case IWL_TM_CMD_APP2DEV_READ_TRACE:
591 IWL_DEBUG_INFO(priv, "testmode uCode trace cmd to driver\n");
592 result = iwl_testmode_trace(hw, tb);
593 break;
594
Cindy H. Kao4613e722011-05-06 10:40:15 -0700595 default:
596 IWL_DEBUG_INFO(priv, "Unknown testmode command\n");
597 result = -ENOSYS;
598 break;
599 }
600
601 mutex_unlock(&priv->mutex);
602 return result;
603}