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 26 static struct dentry *mwifiex_dfs_dir; 27 28 static 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 */ 73 static ssize_t 74 mwifiex_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 149 free_and_exit: 150 free_page(page); 151 return ret; 152 } 153 154 /* 155 * Proc device dump read handler. 156 * 157 * This function is called when the 'device_dump' file is opened for 158 * reading. 159 * This function dumps driver information and firmware memory segments 160 * (ex. DTCM, ITCM, SQRAM etc.) for 161 * debugging. 162 */ 163 static ssize_t 164 mwifiex_device_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.device_dump) 170 return -EIO; 171 172 priv->adapter->if_ops.device_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 */ 198 static ssize_t 199 mwifiex_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 259 free_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 */ 274 static ssize_t 275 mwifiex_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 350 static ssize_t 351 mwifiex_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 361 static 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 */ 410 static ssize_t 411 mwifiex_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 432 free_and_exit: 433 free_page(page); 434 return ret; 435 } 436 437 static 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 */ 446 static ssize_t 447 mwifiex_regrdwr_write(struct file *file, 448 const char __user *ubuf, size_t count, loff_t *ppos) 449 { 450 char *buf; 451 int ret; 452 u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX; 453 454 buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); 455 if (IS_ERR(buf)) 456 return PTR_ERR(buf); 457 458 sscanf(buf, "%u %x %x", ®_type, ®_offset, ®_value); 459 460 if (reg_type == 0 || reg_offset == 0) { 461 ret = -EINVAL; 462 goto done; 463 } else { 464 saved_reg_type = reg_type; 465 saved_reg_offset = reg_offset; 466 saved_reg_value = reg_value; 467 ret = count; 468 } 469 done: 470 kfree(buf); 471 return ret; 472 } 473 474 /* 475 * Proc regrdwr file read handler. 476 * 477 * This function is called when the 'regrdwr' file is opened for reading 478 * 479 * This function can be used to read from a register. 480 */ 481 static ssize_t 482 mwifiex_regrdwr_read(struct file *file, char __user *ubuf, 483 size_t count, loff_t *ppos) 484 { 485 struct mwifiex_private *priv = 486 (struct mwifiex_private *) file->private_data; 487 unsigned long addr = get_zeroed_page(GFP_KERNEL); 488 char *buf = (char *) addr; 489 int pos = 0, ret = 0; 490 u32 reg_value; 491 492 if (!buf) 493 return -ENOMEM; 494 495 if (!saved_reg_type) { 496 /* No command has been given */ 497 pos += snprintf(buf, PAGE_SIZE, "0"); 498 goto done; 499 } 500 /* Set command has been given */ 501 if (saved_reg_value != UINT_MAX) { 502 ret = mwifiex_reg_write(priv, saved_reg_type, saved_reg_offset, 503 saved_reg_value); 504 505 pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", 506 saved_reg_type, saved_reg_offset, 507 saved_reg_value); 508 509 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 510 511 goto done; 512 } 513 /* Get command has been given */ 514 ret = mwifiex_reg_read(priv, saved_reg_type, 515 saved_reg_offset, ®_value); 516 if (ret) { 517 ret = -EINVAL; 518 goto done; 519 } 520 521 pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", saved_reg_type, 522 saved_reg_offset, reg_value); 523 524 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 525 526 done: 527 free_page(addr); 528 return ret; 529 } 530 531 /* Proc debug_mask file read handler. 532 * This function is called when the 'debug_mask' file is opened for reading 533 * This function can be used read driver debugging mask value. 534 */ 535 static ssize_t 536 mwifiex_debug_mask_read(struct file *file, char __user *ubuf, 537 size_t count, loff_t *ppos) 538 { 539 struct mwifiex_private *priv = 540 (struct mwifiex_private *)file->private_data; 541 unsigned long page = get_zeroed_page(GFP_KERNEL); 542 char *buf = (char *)page; 543 size_t ret = 0; 544 int pos = 0; 545 546 if (!buf) 547 return -ENOMEM; 548 549 pos += snprintf(buf, PAGE_SIZE, "debug mask=0x%08x\n", 550 priv->adapter->debug_mask); 551 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 552 553 free_page(page); 554 return ret; 555 } 556 557 /* Proc debug_mask file read handler. 558 * This function is called when the 'debug_mask' file is opened for reading 559 * This function can be used read driver debugging mask value. 560 */ 561 static ssize_t 562 mwifiex_debug_mask_write(struct file *file, const char __user *ubuf, 563 size_t count, loff_t *ppos) 564 { 565 int ret; 566 unsigned long debug_mask; 567 struct mwifiex_private *priv = (void *)file->private_data; 568 char *buf; 569 570 buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); 571 if (IS_ERR(buf)) 572 return PTR_ERR(buf); 573 574 if (kstrtoul(buf, 0, &debug_mask)) { 575 ret = -EINVAL; 576 goto done; 577 } 578 579 priv->adapter->debug_mask = debug_mask; 580 ret = count; 581 done: 582 kfree(buf); 583 return ret; 584 } 585 586 /* Proc memrw file write handler. 587 * This function is called when the 'memrw' file is opened for writing 588 * This function can be used to write to a memory location. 589 */ 590 static ssize_t 591 mwifiex_memrw_write(struct file *file, const char __user *ubuf, size_t count, 592 loff_t *ppos) 593 { 594 int ret; 595 char cmd; 596 struct mwifiex_ds_mem_rw mem_rw; 597 u16 cmd_action; 598 struct mwifiex_private *priv = (void *)file->private_data; 599 char *buf; 600 601 buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); 602 if (IS_ERR(buf)) 603 return PTR_ERR(buf); 604 605 ret = sscanf(buf, "%c %x %x", &cmd, &mem_rw.addr, &mem_rw.value); 606 if (ret != 3) { 607 ret = -EINVAL; 608 goto done; 609 } 610 611 if ((cmd == 'r') || (cmd == 'R')) { 612 cmd_action = HostCmd_ACT_GEN_GET; 613 mem_rw.value = 0; 614 } else if ((cmd == 'w') || (cmd == 'W')) { 615 cmd_action = HostCmd_ACT_GEN_SET; 616 } else { 617 ret = -EINVAL; 618 goto done; 619 } 620 621 memcpy(&priv->mem_rw, &mem_rw, sizeof(mem_rw)); 622 if (mwifiex_send_cmd(priv, HostCmd_CMD_MEM_ACCESS, cmd_action, 0, 623 &mem_rw, true)) 624 ret = -1; 625 else 626 ret = count; 627 628 done: 629 kfree(buf); 630 return ret; 631 } 632 633 /* Proc memrw file read handler. 634 * This function is called when the 'memrw' file is opened for reading 635 * This function can be used to read from a memory location. 636 */ 637 static ssize_t 638 mwifiex_memrw_read(struct file *file, char __user *ubuf, 639 size_t count, loff_t *ppos) 640 { 641 struct mwifiex_private *priv = (void *)file->private_data; 642 unsigned long addr = get_zeroed_page(GFP_KERNEL); 643 char *buf = (char *)addr; 644 int ret, pos = 0; 645 646 if (!buf) 647 return -ENOMEM; 648 649 pos += snprintf(buf, PAGE_SIZE, "0x%x 0x%x\n", priv->mem_rw.addr, 650 priv->mem_rw.value); 651 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 652 653 free_page(addr); 654 return ret; 655 } 656 657 static u32 saved_offset = -1, saved_bytes = -1; 658 659 /* 660 * Proc rdeeprom file write handler. 661 * 662 * This function is called when the 'rdeeprom' file is opened for writing 663 * 664 * This function can be used to write to a RDEEPROM location. 665 */ 666 static ssize_t 667 mwifiex_rdeeprom_write(struct file *file, 668 const char __user *ubuf, size_t count, loff_t *ppos) 669 { 670 char *buf; 671 int ret = 0; 672 int offset = -1, bytes = -1; 673 674 buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); 675 if (IS_ERR(buf)) 676 return PTR_ERR(buf); 677 678 sscanf(buf, "%d %d", &offset, &bytes); 679 680 if (offset == -1 || bytes == -1) { 681 ret = -EINVAL; 682 goto done; 683 } else { 684 saved_offset = offset; 685 saved_bytes = bytes; 686 ret = count; 687 } 688 done: 689 kfree(buf); 690 return ret; 691 } 692 693 /* 694 * Proc rdeeprom read write handler. 695 * 696 * This function is called when the 'rdeeprom' file is opened for reading 697 * 698 * This function can be used to read from a RDEEPROM location. 699 */ 700 static ssize_t 701 mwifiex_rdeeprom_read(struct file *file, char __user *ubuf, 702 size_t count, loff_t *ppos) 703 { 704 struct mwifiex_private *priv = 705 (struct mwifiex_private *) file->private_data; 706 unsigned long addr = get_zeroed_page(GFP_KERNEL); 707 char *buf = (char *) addr; 708 int pos, ret, i; 709 u8 value[MAX_EEPROM_DATA]; 710 711 if (!buf) 712 return -ENOMEM; 713 714 if (saved_offset == -1) { 715 /* No command has been given */ 716 pos = snprintf(buf, PAGE_SIZE, "0"); 717 goto done; 718 } 719 720 /* Get command has been given */ 721 ret = mwifiex_eeprom_read(priv, (u16) saved_offset, 722 (u16) saved_bytes, value); 723 if (ret) { 724 ret = -EINVAL; 725 goto out_free; 726 } 727 728 pos = snprintf(buf, PAGE_SIZE, "%d %d ", saved_offset, saved_bytes); 729 730 for (i = 0; i < saved_bytes; i++) 731 pos += scnprintf(buf + pos, PAGE_SIZE - pos, "%d ", value[i]); 732 733 done: 734 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 735 out_free: 736 free_page(addr); 737 return ret; 738 } 739 740 /* Proc hscfg file write handler 741 * This function can be used to configure the host sleep parameters. 742 */ 743 static ssize_t 744 mwifiex_hscfg_write(struct file *file, const char __user *ubuf, 745 size_t count, loff_t *ppos) 746 { 747 struct mwifiex_private *priv = (void *)file->private_data; 748 char *buf; 749 int ret, arg_num; 750 struct mwifiex_ds_hs_cfg hscfg; 751 int conditions = HS_CFG_COND_DEF; 752 u32 gpio = HS_CFG_GPIO_DEF, gap = HS_CFG_GAP_DEF; 753 754 buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); 755 if (IS_ERR(buf)) 756 return PTR_ERR(buf); 757 758 arg_num = sscanf(buf, "%d %x %x", &conditions, &gpio, &gap); 759 760 memset(&hscfg, 0, sizeof(struct mwifiex_ds_hs_cfg)); 761 762 if (arg_num > 3) { 763 mwifiex_dbg(priv->adapter, ERROR, 764 "Too many arguments\n"); 765 ret = -EINVAL; 766 goto done; 767 } 768 769 if (arg_num >= 1 && arg_num < 3) 770 mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_GET, 771 MWIFIEX_SYNC_CMD, &hscfg); 772 773 if (arg_num) { 774 if (conditions == HS_CFG_CANCEL) { 775 mwifiex_cancel_hs(priv, MWIFIEX_ASYNC_CMD); 776 ret = count; 777 goto done; 778 } 779 hscfg.conditions = conditions; 780 } 781 if (arg_num >= 2) 782 hscfg.gpio = gpio; 783 if (arg_num == 3) 784 hscfg.gap = gap; 785 786 hscfg.is_invoke_hostcmd = false; 787 mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET, 788 MWIFIEX_SYNC_CMD, &hscfg); 789 790 mwifiex_enable_hs(priv->adapter); 791 priv->adapter->hs_enabling = false; 792 ret = count; 793 done: 794 kfree(buf); 795 return ret; 796 } 797 798 /* Proc hscfg file read handler 799 * This function can be used to read host sleep configuration 800 * parameters from driver. 801 */ 802 static ssize_t 803 mwifiex_hscfg_read(struct file *file, char __user *ubuf, 804 size_t count, loff_t *ppos) 805 { 806 struct mwifiex_private *priv = (void *)file->private_data; 807 unsigned long addr = get_zeroed_page(GFP_KERNEL); 808 char *buf = (char *)addr; 809 int pos, ret; 810 struct mwifiex_ds_hs_cfg hscfg; 811 812 if (!buf) 813 return -ENOMEM; 814 815 mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_GET, 816 MWIFIEX_SYNC_CMD, &hscfg); 817 818 pos = snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", hscfg.conditions, 819 hscfg.gpio, hscfg.gap); 820 821 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 822 823 free_page(addr); 824 return ret; 825 } 826 827 static ssize_t 828 mwifiex_timeshare_coex_read(struct file *file, char __user *ubuf, 829 size_t count, loff_t *ppos) 830 { 831 struct mwifiex_private *priv = file->private_data; 832 char buf[3]; 833 bool timeshare_coex; 834 int ret; 835 unsigned int len; 836 837 if (priv->adapter->fw_api_ver != MWIFIEX_FW_V15) 838 return -EOPNOTSUPP; 839 840 ret = mwifiex_send_cmd(priv, HostCmd_CMD_ROBUST_COEX, 841 HostCmd_ACT_GEN_GET, 0, ×hare_coex, true); 842 if (ret) 843 return ret; 844 845 len = sprintf(buf, "%d\n", timeshare_coex); 846 return simple_read_from_buffer(ubuf, count, ppos, buf, len); 847 } 848 849 static ssize_t 850 mwifiex_timeshare_coex_write(struct file *file, const char __user *ubuf, 851 size_t count, loff_t *ppos) 852 { 853 bool timeshare_coex; 854 struct mwifiex_private *priv = file->private_data; 855 char kbuf[16]; 856 int ret; 857 858 if (priv->adapter->fw_api_ver != MWIFIEX_FW_V15) 859 return -EOPNOTSUPP; 860 861 memset(kbuf, 0, sizeof(kbuf)); 862 863 if (copy_from_user(&kbuf, ubuf, min_t(size_t, sizeof(kbuf) - 1, count))) 864 return -EFAULT; 865 866 if (strtobool(kbuf, ×hare_coex)) 867 return -EINVAL; 868 869 ret = mwifiex_send_cmd(priv, HostCmd_CMD_ROBUST_COEX, 870 HostCmd_ACT_GEN_SET, 0, ×hare_coex, true); 871 if (ret) 872 return ret; 873 else 874 return count; 875 } 876 877 static ssize_t 878 mwifiex_reset_write(struct file *file, 879 const char __user *ubuf, size_t count, loff_t *ppos) 880 { 881 struct mwifiex_private *priv = file->private_data; 882 struct mwifiex_adapter *adapter = priv->adapter; 883 char cmd; 884 bool result; 885 886 if (copy_from_user(&cmd, ubuf, sizeof(cmd))) 887 return -EFAULT; 888 889 if (strtobool(&cmd, &result)) 890 return -EINVAL; 891 892 if (!result) 893 return -EINVAL; 894 895 if (adapter->if_ops.card_reset) { 896 dev_info(adapter->dev, "Resetting per request\n"); 897 adapter->hw_status = MWIFIEX_HW_STATUS_RESET; 898 mwifiex_cancel_all_pending_cmd(adapter); 899 adapter->if_ops.card_reset(adapter); 900 } 901 902 return count; 903 } 904 905 #define MWIFIEX_DFS_ADD_FILE(name) do { \ 906 if (!debugfs_create_file(#name, 0644, priv->dfs_dev_dir, \ 907 priv, &mwifiex_dfs_##name##_fops)) \ 908 return; \ 909 } while (0); 910 911 #define MWIFIEX_DFS_FILE_OPS(name) \ 912 static const struct file_operations mwifiex_dfs_##name##_fops = { \ 913 .read = mwifiex_##name##_read, \ 914 .write = mwifiex_##name##_write, \ 915 .open = simple_open, \ 916 }; 917 918 #define MWIFIEX_DFS_FILE_READ_OPS(name) \ 919 static const struct file_operations mwifiex_dfs_##name##_fops = { \ 920 .read = mwifiex_##name##_read, \ 921 .open = simple_open, \ 922 }; 923 924 #define MWIFIEX_DFS_FILE_WRITE_OPS(name) \ 925 static const struct file_operations mwifiex_dfs_##name##_fops = { \ 926 .write = mwifiex_##name##_write, \ 927 .open = simple_open, \ 928 }; 929 930 931 MWIFIEX_DFS_FILE_READ_OPS(info); 932 MWIFIEX_DFS_FILE_READ_OPS(debug); 933 MWIFIEX_DFS_FILE_READ_OPS(getlog); 934 MWIFIEX_DFS_FILE_READ_OPS(device_dump); 935 MWIFIEX_DFS_FILE_OPS(regrdwr); 936 MWIFIEX_DFS_FILE_OPS(rdeeprom); 937 MWIFIEX_DFS_FILE_OPS(memrw); 938 MWIFIEX_DFS_FILE_OPS(hscfg); 939 MWIFIEX_DFS_FILE_OPS(histogram); 940 MWIFIEX_DFS_FILE_OPS(debug_mask); 941 MWIFIEX_DFS_FILE_OPS(timeshare_coex); 942 MWIFIEX_DFS_FILE_WRITE_OPS(reset); 943 944 /* 945 * This function creates the debug FS directory structure and the files. 946 */ 947 void 948 mwifiex_dev_debugfs_init(struct mwifiex_private *priv) 949 { 950 if (!mwifiex_dfs_dir || !priv) 951 return; 952 953 priv->dfs_dev_dir = debugfs_create_dir(priv->netdev->name, 954 mwifiex_dfs_dir); 955 956 if (!priv->dfs_dev_dir) 957 return; 958 959 MWIFIEX_DFS_ADD_FILE(info); 960 MWIFIEX_DFS_ADD_FILE(debug); 961 MWIFIEX_DFS_ADD_FILE(getlog); 962 MWIFIEX_DFS_ADD_FILE(regrdwr); 963 MWIFIEX_DFS_ADD_FILE(rdeeprom); 964 MWIFIEX_DFS_ADD_FILE(device_dump); 965 MWIFIEX_DFS_ADD_FILE(memrw); 966 MWIFIEX_DFS_ADD_FILE(hscfg); 967 MWIFIEX_DFS_ADD_FILE(histogram); 968 MWIFIEX_DFS_ADD_FILE(debug_mask); 969 MWIFIEX_DFS_ADD_FILE(timeshare_coex); 970 MWIFIEX_DFS_ADD_FILE(reset); 971 } 972 973 /* 974 * This function removes the debug FS directory structure and the files. 975 */ 976 void 977 mwifiex_dev_debugfs_remove(struct mwifiex_private *priv) 978 { 979 if (!priv) 980 return; 981 982 debugfs_remove_recursive(priv->dfs_dev_dir); 983 } 984 985 /* 986 * This function creates the top level proc directory. 987 */ 988 void 989 mwifiex_debugfs_init(void) 990 { 991 if (!mwifiex_dfs_dir) 992 mwifiex_dfs_dir = debugfs_create_dir("mwifiex", NULL); 993 } 994 995 /* 996 * This function removes the top level proc directory. 997 */ 998 void 999 mwifiex_debugfs_remove(void) 1000 { 1001 if (mwifiex_dfs_dir) 1002 debugfs_remove(mwifiex_dfs_dir); 1003 } 1004