1/* 2 * Marvell Wireless LAN device driver: debugfs 3 * 4 * Copyright (C) 2011-2014, Marvell International Ltd. 5 * 6 * This software file (the "File") is distributed by Marvell International 7 * Ltd. under the terms of the GNU General Public License Version 2, June 1991 8 * (the "License"). You may use, redistribute and/or modify this File in 9 * accordance with the terms and conditions of the License, a copy of which 10 * is available by writing to the Free Software Foundation, Inc., 11 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the 12 * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. 13 * 14 * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE 16 * ARE EXPRESSLY DISCLAIMED. The License provides additional details about 17 * this warranty disclaimer. 18 */ 19 20#include <linux/debugfs.h> 21 22#include "main.h" 23#include "11n.h" 24 25 26static struct dentry *mwifiex_dfs_dir; 27 28static char *bss_modes[] = { 29 "UNSPECIFIED", 30 "ADHOC", 31 "STATION", 32 "AP", 33 "AP_VLAN", 34 "WDS", 35 "MONITOR", 36 "MESH_POINT", 37 "P2P_CLIENT", 38 "P2P_GO", 39 "P2P_DEVICE", 40}; 41 42/* 43 * Proc info file read handler. 44 * 45 * This function is called when the 'info' file is opened for reading. 46 * It prints the following driver related information - 47 * - Driver name 48 * - Driver version 49 * - Driver extended version 50 * - Interface name 51 * - BSS mode 52 * - Media state (connected or disconnected) 53 * - MAC address 54 * - Total number of Tx bytes 55 * - Total number of Rx bytes 56 * - Total number of Tx packets 57 * - Total number of Rx packets 58 * - Total number of dropped Tx packets 59 * - Total number of dropped Rx packets 60 * - Total number of corrupted Tx packets 61 * - Total number of corrupted Rx packets 62 * - Carrier status (on or off) 63 * - Tx queue status (started or stopped) 64 * 65 * For STA mode drivers, it also prints the following extra - 66 * - ESSID 67 * - BSSID 68 * - Channel 69 * - Region code 70 * - Multicast count 71 * - Multicast addresses 72 */ 73static ssize_t 74mwifiex_info_read(struct file *file, char __user *ubuf, 75 size_t count, loff_t *ppos) 76{ 77 struct mwifiex_private *priv = 78 (struct mwifiex_private *) file->private_data; 79 struct net_device *netdev = priv->netdev; 80 struct netdev_hw_addr *ha; 81 struct netdev_queue *txq; 82 unsigned long page = get_zeroed_page(GFP_KERNEL); 83 char *p = (char *) page, fmt[64]; 84 struct mwifiex_bss_info info; 85 ssize_t ret; 86 int i = 0; 87 88 if (!p) 89 return -ENOMEM; 90 91 memset(&info, 0, sizeof(info)); 92 ret = mwifiex_get_bss_info(priv, &info); 93 if (ret) 94 goto free_and_exit; 95 96 mwifiex_drv_get_driver_version(priv->adapter, fmt, sizeof(fmt) - 1); 97 98 if (!priv->version_str[0]) 99 mwifiex_get_ver_ext(priv); 100 101 p += sprintf(p, "driver_name = " "\"mwifiex\"\n"); 102 p += sprintf(p, "driver_version = %s", fmt); 103 p += sprintf(p, "\nverext = %s", priv->version_str); 104 p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name); 105 106 if (info.bss_mode >= ARRAY_SIZE(bss_modes)) 107 p += sprintf(p, "bss_mode=\"%d\"\n", info.bss_mode); 108 else 109 p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]); 110 111 p += sprintf(p, "media_state=\"%s\"\n", 112 (!priv->media_connected ? "Disconnected" : "Connected")); 113 p += sprintf(p, "mac_address=\"%pM\"\n", netdev->dev_addr); 114 115 if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) { 116 p += sprintf(p, "multicast_count=\"%d\"\n", 117 netdev_mc_count(netdev)); 118 p += sprintf(p, "essid=\"%s\"\n", info.ssid.ssid); 119 p += sprintf(p, "bssid=\"%pM\"\n", info.bssid); 120 p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan); 121 p += sprintf(p, "country_code = \"%s\"\n", info.country_code); 122 123 netdev_for_each_mc_addr(ha, netdev) 124 p += sprintf(p, "multicast_address[%d]=\"%pM\"\n", 125 i++, ha->addr); 126 } 127 128 p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes); 129 p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes); 130 p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets); 131 p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets); 132 p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped); 133 p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped); 134 p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors); 135 p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors); 136 p += sprintf(p, "carrier %s\n", ((netif_carrier_ok(priv->netdev)) 137 ? "on" : "off")); 138 p += sprintf(p, "tx queue"); 139 for (i = 0; i < netdev->num_tx_queues; i++) { 140 txq = netdev_get_tx_queue(netdev, i); 141 p += sprintf(p, " %d:%s", i, netif_tx_queue_stopped(txq) ? 142 "stopped" : "started"); 143 } 144 p += sprintf(p, "\n"); 145 146 ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, 147 (unsigned long) p - page); 148 149free_and_exit: 150 free_page(page); 151 return ret; 152} 153 154/* 155 * Proc firmware dump read handler. 156 * 157 * This function is called when the 'fw_dump' file is opened for 158 * reading. 159 * This function dumps firmware memory in different files 160 * (ex. DTCM, ITCM, SQRAM etc.) based on the the segments for 161 * debugging. 162 */ 163static ssize_t 164mwifiex_fw_dump_read(struct file *file, char __user *ubuf, 165 size_t count, loff_t *ppos) 166{ 167 struct mwifiex_private *priv = file->private_data; 168 169 if (!priv->adapter->if_ops.fw_dump) 170 return -EIO; 171 172 priv->adapter->if_ops.fw_dump(priv->adapter); 173 174 return 0; 175} 176 177/* 178 * Proc getlog file read handler. 179 * 180 * This function is called when the 'getlog' file is opened for reading 181 * It prints the following log information - 182 * - Number of multicast Tx frames 183 * - Number of failed packets 184 * - Number of Tx retries 185 * - Number of multicast Tx retries 186 * - Number of duplicate frames 187 * - Number of RTS successes 188 * - Number of RTS failures 189 * - Number of ACK failures 190 * - Number of fragmented Rx frames 191 * - Number of multicast Rx frames 192 * - Number of FCS errors 193 * - Number of Tx frames 194 * - WEP ICV error counts 195 * - Number of received beacons 196 * - Number of missed beacons 197 */ 198static ssize_t 199mwifiex_getlog_read(struct file *file, char __user *ubuf, 200 size_t count, loff_t *ppos) 201{ 202 struct mwifiex_private *priv = 203 (struct mwifiex_private *) file->private_data; 204 unsigned long page = get_zeroed_page(GFP_KERNEL); 205 char *p = (char *) page; 206 ssize_t ret; 207 struct mwifiex_ds_get_stats stats; 208 209 if (!p) 210 return -ENOMEM; 211 212 memset(&stats, 0, sizeof(stats)); 213 ret = mwifiex_get_stats_info(priv, &stats); 214 if (ret) 215 goto free_and_exit; 216 217 p += sprintf(p, "\n" 218 "mcasttxframe %u\n" 219 "failed %u\n" 220 "retry %u\n" 221 "multiretry %u\n" 222 "framedup %u\n" 223 "rtssuccess %u\n" 224 "rtsfailure %u\n" 225 "ackfailure %u\n" 226 "rxfrag %u\n" 227 "mcastrxframe %u\n" 228 "fcserror %u\n" 229 "txframe %u\n" 230 "wepicverrcnt-1 %u\n" 231 "wepicverrcnt-2 %u\n" 232 "wepicverrcnt-3 %u\n" 233 "wepicverrcnt-4 %u\n" 234 "bcn_rcv_cnt %u\n" 235 "bcn_miss_cnt %u\n", 236 stats.mcast_tx_frame, 237 stats.failed, 238 stats.retry, 239 stats.multi_retry, 240 stats.frame_dup, 241 stats.rts_success, 242 stats.rts_failure, 243 stats.ack_failure, 244 stats.rx_frag, 245 stats.mcast_rx_frame, 246 stats.fcs_error, 247 stats.tx_frame, 248 stats.wep_icv_error[0], 249 stats.wep_icv_error[1], 250 stats.wep_icv_error[2], 251 stats.wep_icv_error[3], 252 stats.bcn_rcv_cnt, 253 stats.bcn_miss_cnt); 254 255 256 ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, 257 (unsigned long) p - page); 258 259free_and_exit: 260 free_page(page); 261 return ret; 262} 263 264/* Sysfs histogram file read handler. 265 * 266 * This function is called when the 'histogram' file is opened for reading 267 * It prints the following histogram information - 268 * - Number of histogram samples 269 * - Receive packet number of each rx_rate 270 * - Receive packet number of each snr 271 * - Receive packet number of each nosie_flr 272 * - Receive packet number of each signal streath 273 */ 274static ssize_t 275mwifiex_histogram_read(struct file *file, char __user *ubuf, 276 size_t count, loff_t *ppos) 277{ 278 struct mwifiex_private *priv = 279 (struct mwifiex_private *)file->private_data; 280 ssize_t ret; 281 struct mwifiex_histogram_data *phist_data; 282 int i, value; 283 unsigned long page = get_zeroed_page(GFP_KERNEL); 284 char *p = (char *)page; 285 286 if (!p) 287 return -ENOMEM; 288 289 if (!priv || !priv->hist_data) 290 return -EFAULT; 291 phist_data = priv->hist_data; 292 293 p += sprintf(p, "\n" 294 "total samples = %d\n", 295 atomic_read(&phist_data->num_samples)); 296 297 p += sprintf(p, "rx rates (in Mbps): 0=1M 1=2M"); 298 p += sprintf(p, "2=5.5M 3=11M 4=6M 5=9M 6=12M\n"); 299 p += sprintf(p, "7=18M 8=24M 9=36M 10=48M 11=54M"); 300 p += sprintf(p, "12-27=MCS0-15(BW20) 28-43=MCS0-15(BW40)\n"); 301 302 if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) { 303 p += sprintf(p, "44-53=MCS0-9(VHT:BW20)"); 304 p += sprintf(p, "54-63=MCS0-9(VHT:BW40)"); 305 p += sprintf(p, "64-73=MCS0-9(VHT:BW80)\n\n"); 306 } else { 307 p += sprintf(p, "\n"); 308 } 309 310 for (i = 0; i < MWIFIEX_MAX_RX_RATES; i++) { 311 value = atomic_read(&phist_data->rx_rate[i]); 312 if (value) 313 p += sprintf(p, "rx_rate[%02d] = %d\n", i, value); 314 } 315 316 if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) { 317 for (i = MWIFIEX_MAX_RX_RATES; i < MWIFIEX_MAX_AC_RX_RATES; 318 i++) { 319 value = atomic_read(&phist_data->rx_rate[i]); 320 if (value) 321 p += sprintf(p, "rx_rate[%02d] = %d\n", 322 i, value); 323 } 324 } 325 326 for (i = 0; i < MWIFIEX_MAX_SNR; i++) { 327 value = atomic_read(&phist_data->snr[i]); 328 if (value) 329 p += sprintf(p, "snr[%02ddB] = %d\n", i, value); 330 } 331 for (i = 0; i < MWIFIEX_MAX_NOISE_FLR; i++) { 332 value = atomic_read(&phist_data->noise_flr[i]); 333 if (value) 334 p += sprintf(p, "noise_flr[-%02ddBm] = %d\n", 335 (int)(i-128), value); 336 } 337 for (i = 0; i < MWIFIEX_MAX_SIG_STRENGTH; i++) { 338 value = atomic_read(&phist_data->sig_str[i]); 339 if (value) 340 p += sprintf(p, "sig_strength[-%02ddBm] = %d\n", 341 i, value); 342 } 343 344 ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page, 345 (unsigned long)p - page); 346 347 return ret; 348} 349 350static ssize_t 351mwifiex_histogram_write(struct file *file, const char __user *ubuf, 352 size_t count, loff_t *ppos) 353{ 354 struct mwifiex_private *priv = (void *)file->private_data; 355 356 if (priv && priv->hist_data) 357 mwifiex_hist_data_reset(priv); 358 return 0; 359} 360 361static struct mwifiex_debug_info info; 362 363/* 364 * Proc debug file read handler. 365 * 366 * This function is called when the 'debug' file is opened for reading 367 * It prints the following log information - 368 * - Interrupt count 369 * - WMM AC VO packets count 370 * - WMM AC VI packets count 371 * - WMM AC BE packets count 372 * - WMM AC BK packets count 373 * - Maximum Tx buffer size 374 * - Tx buffer size 375 * - Current Tx buffer size 376 * - Power Save mode 377 * - Power Save state 378 * - Deep Sleep status 379 * - Device wakeup required status 380 * - Number of wakeup tries 381 * - Host Sleep configured status 382 * - Host Sleep activated status 383 * - Number of Tx timeouts 384 * - Number of command timeouts 385 * - Last timed out command ID 386 * - Last timed out command action 387 * - Last command ID 388 * - Last command action 389 * - Last command index 390 * - Last command response ID 391 * - Last command response index 392 * - Last event 393 * - Last event index 394 * - Number of host to card command failures 395 * - Number of sleep confirm command failures 396 * - Number of host to card data failure 397 * - Number of deauthentication events 398 * - Number of disassociation events 399 * - Number of link lost events 400 * - Number of deauthentication commands 401 * - Number of association success commands 402 * - Number of association failure commands 403 * - Number of commands sent 404 * - Number of data packets sent 405 * - Number of command responses received 406 * - Number of events received 407 * - Tx BA stream table (TID, RA) 408 * - Rx reorder table (TID, TA, Start window, Window size, Buffer) 409 */ 410static ssize_t 411mwifiex_debug_read(struct file *file, char __user *ubuf, 412 size_t count, loff_t *ppos) 413{ 414 struct mwifiex_private *priv = 415 (struct mwifiex_private *) file->private_data; 416 unsigned long page = get_zeroed_page(GFP_KERNEL); 417 char *p = (char *) page; 418 ssize_t ret; 419 420 if (!p) 421 return -ENOMEM; 422 423 ret = mwifiex_get_debug_info(priv, &info); 424 if (ret) 425 goto free_and_exit; 426 427 p += mwifiex_debug_info_to_buffer(priv, p, &info); 428 429 ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, 430 (unsigned long) p - page); 431 432free_and_exit: 433 free_page(page); 434 return ret; 435} 436 437static u32 saved_reg_type, saved_reg_offset, saved_reg_value; 438 439/* 440 * Proc regrdwr file write handler. 441 * 442 * This function is called when the 'regrdwr' file is opened for writing 443 * 444 * This function can be used to write to a register. 445 */ 446static ssize_t 447mwifiex_regrdwr_write(struct file *file, 448 const char __user *ubuf, size_t count, loff_t *ppos) 449{ 450 unsigned long addr = get_zeroed_page(GFP_KERNEL); 451 char *buf = (char *) addr; 452 size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1); 453 int ret; 454 u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX; 455 456 if (!buf) 457 return -ENOMEM; 458 459 460 if (copy_from_user(buf, ubuf, buf_size)) { 461 ret = -EFAULT; 462 goto done; 463 } 464 465 sscanf(buf, "%u %x %x", ®_type, ®_offset, ®_value); 466 467 if (reg_type == 0 || reg_offset == 0) { 468 ret = -EINVAL; 469 goto done; 470 } else { 471 saved_reg_type = reg_type; 472 saved_reg_offset = reg_offset; 473 saved_reg_value = reg_value; 474 ret = count; 475 } 476done: 477 free_page(addr); 478 return ret; 479} 480 481/* 482 * Proc regrdwr file read handler. 483 * 484 * This function is called when the 'regrdwr' file is opened for reading 485 * 486 * This function can be used to read from a register. 487 */ 488static ssize_t 489mwifiex_regrdwr_read(struct file *file, char __user *ubuf, 490 size_t count, loff_t *ppos) 491{ 492 struct mwifiex_private *priv = 493 (struct mwifiex_private *) file->private_data; 494 unsigned long addr = get_zeroed_page(GFP_KERNEL); 495 char *buf = (char *) addr; 496 int pos = 0, ret = 0; 497 u32 reg_value; 498 499 if (!buf) 500 return -ENOMEM; 501 502 if (!saved_reg_type) { 503 /* No command has been given */ 504 pos += snprintf(buf, PAGE_SIZE, "0"); 505 goto done; 506 } 507 /* Set command has been given */ 508 if (saved_reg_value != UINT_MAX) { 509 ret = mwifiex_reg_write(priv, saved_reg_type, saved_reg_offset, 510 saved_reg_value); 511 512 pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", 513 saved_reg_type, saved_reg_offset, 514 saved_reg_value); 515 516 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 517 518 goto done; 519 } 520 /* Get command has been given */ 521 ret = mwifiex_reg_read(priv, saved_reg_type, 522 saved_reg_offset, ®_value); 523 if (ret) { 524 ret = -EINVAL; 525 goto done; 526 } 527 528 pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", saved_reg_type, 529 saved_reg_offset, reg_value); 530 531 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 532 533done: 534 free_page(addr); 535 return ret; 536} 537 538static u32 saved_offset = -1, saved_bytes = -1; 539 540/* 541 * Proc rdeeprom file write handler. 542 * 543 * This function is called when the 'rdeeprom' file is opened for writing 544 * 545 * This function can be used to write to a RDEEPROM location. 546 */ 547static ssize_t 548mwifiex_rdeeprom_write(struct file *file, 549 const char __user *ubuf, size_t count, loff_t *ppos) 550{ 551 unsigned long addr = get_zeroed_page(GFP_KERNEL); 552 char *buf = (char *) addr; 553 size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1); 554 int ret = 0; 555 int offset = -1, bytes = -1; 556 557 if (!buf) 558 return -ENOMEM; 559 560 561 if (copy_from_user(buf, ubuf, buf_size)) { 562 ret = -EFAULT; 563 goto done; 564 } 565 566 sscanf(buf, "%d %d", &offset, &bytes); 567 568 if (offset == -1 || bytes == -1) { 569 ret = -EINVAL; 570 goto done; 571 } else { 572 saved_offset = offset; 573 saved_bytes = bytes; 574 ret = count; 575 } 576done: 577 free_page(addr); 578 return ret; 579} 580 581/* 582 * Proc rdeeprom read write handler. 583 * 584 * This function is called when the 'rdeeprom' file is opened for reading 585 * 586 * This function can be used to read from a RDEEPROM location. 587 */ 588static ssize_t 589mwifiex_rdeeprom_read(struct file *file, char __user *ubuf, 590 size_t count, loff_t *ppos) 591{ 592 struct mwifiex_private *priv = 593 (struct mwifiex_private *) file->private_data; 594 unsigned long addr = get_zeroed_page(GFP_KERNEL); 595 char *buf = (char *) addr; 596 int pos, ret, i; 597 u8 value[MAX_EEPROM_DATA]; 598 599 if (!buf) 600 return -ENOMEM; 601 602 if (saved_offset == -1) { 603 /* No command has been given */ 604 pos = snprintf(buf, PAGE_SIZE, "0"); 605 goto done; 606 } 607 608 /* Get command has been given */ 609 ret = mwifiex_eeprom_read(priv, (u16) saved_offset, 610 (u16) saved_bytes, value); 611 if (ret) { 612 ret = -EINVAL; 613 goto out_free; 614 } 615 616 pos = snprintf(buf, PAGE_SIZE, "%d %d ", saved_offset, saved_bytes); 617 618 for (i = 0; i < saved_bytes; i++) 619 pos += scnprintf(buf + pos, PAGE_SIZE - pos, "%d ", value[i]); 620 621done: 622 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 623out_free: 624 free_page(addr); 625 return ret; 626} 627 628/* Proc hscfg file write handler 629 * This function can be used to configure the host sleep parameters. 630 */ 631static ssize_t 632mwifiex_hscfg_write(struct file *file, const char __user *ubuf, 633 size_t count, loff_t *ppos) 634{ 635 struct mwifiex_private *priv = (void *)file->private_data; 636 unsigned long addr = get_zeroed_page(GFP_KERNEL); 637 char *buf = (char *)addr; 638 size_t buf_size = min_t(size_t, count, PAGE_SIZE - 1); 639 int ret, arg_num; 640 struct mwifiex_ds_hs_cfg hscfg; 641 int conditions = HS_CFG_COND_DEF; 642 u32 gpio = HS_CFG_GPIO_DEF, gap = HS_CFG_GAP_DEF; 643 644 if (!buf) 645 return -ENOMEM; 646 647 if (copy_from_user(buf, ubuf, buf_size)) { 648 ret = -EFAULT; 649 goto done; 650 } 651 652 arg_num = sscanf(buf, "%d %x %x", &conditions, &gpio, &gap); 653 654 memset(&hscfg, 0, sizeof(struct mwifiex_ds_hs_cfg)); 655 656 if (arg_num > 3) { 657 dev_err(priv->adapter->dev, "Too many arguments\n"); 658 ret = -EINVAL; 659 goto done; 660 } 661 662 if (arg_num >= 1 && arg_num < 3) 663 mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_GET, 664 MWIFIEX_SYNC_CMD, &hscfg); 665 666 if (arg_num) { 667 if (conditions == HS_CFG_CANCEL) { 668 mwifiex_cancel_hs(priv, MWIFIEX_ASYNC_CMD); 669 ret = count; 670 goto done; 671 } 672 hscfg.conditions = conditions; 673 } 674 if (arg_num >= 2) 675 hscfg.gpio = gpio; 676 if (arg_num == 3) 677 hscfg.gap = gap; 678 679 hscfg.is_invoke_hostcmd = false; 680 mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET, 681 MWIFIEX_SYNC_CMD, &hscfg); 682 683 mwifiex_enable_hs(priv->adapter); 684 priv->adapter->hs_enabling = false; 685 ret = count; 686done: 687 free_page(addr); 688 return ret; 689} 690 691/* Proc hscfg file read handler 692 * This function can be used to read host sleep configuration 693 * parameters from driver. 694 */ 695static ssize_t 696mwifiex_hscfg_read(struct file *file, char __user *ubuf, 697 size_t count, loff_t *ppos) 698{ 699 struct mwifiex_private *priv = (void *)file->private_data; 700 unsigned long addr = get_zeroed_page(GFP_KERNEL); 701 char *buf = (char *)addr; 702 int pos, ret; 703 struct mwifiex_ds_hs_cfg hscfg; 704 705 if (!buf) 706 return -ENOMEM; 707 708 mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_GET, 709 MWIFIEX_SYNC_CMD, &hscfg); 710 711 pos = snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", hscfg.conditions, 712 hscfg.gpio, hscfg.gap); 713 714 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 715 716 free_page(addr); 717 return ret; 718} 719 720#define MWIFIEX_DFS_ADD_FILE(name) do { \ 721 if (!debugfs_create_file(#name, 0644, priv->dfs_dev_dir, \ 722 priv, &mwifiex_dfs_##name##_fops)) \ 723 return; \ 724} while (0); 725 726#define MWIFIEX_DFS_FILE_OPS(name) \ 727static const struct file_operations mwifiex_dfs_##name##_fops = { \ 728 .read = mwifiex_##name##_read, \ 729 .write = mwifiex_##name##_write, \ 730 .open = simple_open, \ 731}; 732 733#define MWIFIEX_DFS_FILE_READ_OPS(name) \ 734static const struct file_operations mwifiex_dfs_##name##_fops = { \ 735 .read = mwifiex_##name##_read, \ 736 .open = simple_open, \ 737}; 738 739#define MWIFIEX_DFS_FILE_WRITE_OPS(name) \ 740static const struct file_operations mwifiex_dfs_##name##_fops = { \ 741 .write = mwifiex_##name##_write, \ 742 .open = simple_open, \ 743}; 744 745 746MWIFIEX_DFS_FILE_READ_OPS(info); 747MWIFIEX_DFS_FILE_READ_OPS(debug); 748MWIFIEX_DFS_FILE_READ_OPS(getlog); 749MWIFIEX_DFS_FILE_READ_OPS(fw_dump); 750MWIFIEX_DFS_FILE_OPS(regrdwr); 751MWIFIEX_DFS_FILE_OPS(rdeeprom); 752MWIFIEX_DFS_FILE_OPS(hscfg); 753MWIFIEX_DFS_FILE_OPS(histogram); 754 755/* 756 * This function creates the debug FS directory structure and the files. 757 */ 758void 759mwifiex_dev_debugfs_init(struct mwifiex_private *priv) 760{ 761 if (!mwifiex_dfs_dir || !priv) 762 return; 763 764 priv->dfs_dev_dir = debugfs_create_dir(priv->netdev->name, 765 mwifiex_dfs_dir); 766 767 if (!priv->dfs_dev_dir) 768 return; 769 770 MWIFIEX_DFS_ADD_FILE(info); 771 MWIFIEX_DFS_ADD_FILE(debug); 772 MWIFIEX_DFS_ADD_FILE(getlog); 773 MWIFIEX_DFS_ADD_FILE(regrdwr); 774 MWIFIEX_DFS_ADD_FILE(rdeeprom); 775 MWIFIEX_DFS_ADD_FILE(fw_dump); 776 MWIFIEX_DFS_ADD_FILE(hscfg); 777 MWIFIEX_DFS_ADD_FILE(histogram); 778} 779 780/* 781 * This function removes the debug FS directory structure and the files. 782 */ 783void 784mwifiex_dev_debugfs_remove(struct mwifiex_private *priv) 785{ 786 if (!priv) 787 return; 788 789 debugfs_remove_recursive(priv->dfs_dev_dir); 790} 791 792/* 793 * This function creates the top level proc directory. 794 */ 795void 796mwifiex_debugfs_init(void) 797{ 798 if (!mwifiex_dfs_dir) 799 mwifiex_dfs_dir = debugfs_create_dir("mwifiex", NULL); 800} 801 802/* 803 * This function removes the top level proc directory. 804 */ 805void 806mwifiex_debugfs_remove(void) 807{ 808 if (mwifiex_dfs_dir) 809 debugfs_remove(mwifiex_dfs_dir); 810} 811