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