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 mwifiex_get_ver_ext(priv, 0); 99 100 p += sprintf(p, "driver_name = " "\"mwifiex\"\n"); 101 p += sprintf(p, "driver_version = %s", fmt); 102 p += sprintf(p, "\nverext = %s", priv->version_str); 103 p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name); 104 105 if (info.bss_mode >= ARRAY_SIZE(bss_modes)) 106 p += sprintf(p, "bss_mode=\"%d\"\n", info.bss_mode); 107 else 108 p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]); 109 110 p += sprintf(p, "media_state=\"%s\"\n", 111 (!priv->media_connected ? "Disconnected" : "Connected")); 112 p += sprintf(p, "mac_address=\"%pM\"\n", netdev->dev_addr); 113 114 if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) { 115 p += sprintf(p, "multicast_count=\"%d\"\n", 116 netdev_mc_count(netdev)); 117 p += sprintf(p, "essid=\"%s\"\n", info.ssid.ssid); 118 p += sprintf(p, "bssid=\"%pM\"\n", info.bssid); 119 p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan); 120 p += sprintf(p, "country_code = \"%s\"\n", info.country_code); 121 p += sprintf(p, "region_code=\"0x%x\"\n", 122 priv->adapter->region_code); 123 124 netdev_for_each_mc_addr(ha, netdev) 125 p += sprintf(p, "multicast_address[%d]=\"%pM\"\n", 126 i++, ha->addr); 127 } 128 129 p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes); 130 p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes); 131 p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets); 132 p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets); 133 p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped); 134 p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped); 135 p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors); 136 p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors); 137 p += sprintf(p, "carrier %s\n", ((netif_carrier_ok(priv->netdev)) 138 ? "on" : "off")); 139 p += sprintf(p, "tx queue"); 140 for (i = 0; i < netdev->num_tx_queues; i++) { 141 txq = netdev_get_tx_queue(netdev, i); 142 p += sprintf(p, " %d:%s", i, netif_tx_queue_stopped(txq) ? 143 "stopped" : "started"); 144 } 145 p += sprintf(p, "\n"); 146 147 ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, 148 (unsigned long) p - page); 149 150 free_and_exit: 151 free_page(page); 152 return ret; 153 } 154 155 /* 156 * Proc device dump read handler. 157 * 158 * This function is called when the 'device_dump' file is opened for 159 * reading. 160 * This function dumps driver information and firmware memory segments 161 * (ex. DTCM, ITCM, SQRAM etc.) for 162 * debugging. 163 */ 164 static ssize_t 165 mwifiex_device_dump_read(struct file *file, char __user *ubuf, 166 size_t count, loff_t *ppos) 167 { 168 struct mwifiex_private *priv = file->private_data; 169 170 if (!priv->adapter->if_ops.device_dump) 171 return -EIO; 172 173 priv->adapter->if_ops.device_dump(priv->adapter); 174 175 return 0; 176 } 177 178 /* 179 * Proc getlog file read handler. 180 * 181 * This function is called when the 'getlog' file is opened for reading 182 * It prints the following log information - 183 * - Number of multicast Tx frames 184 * - Number of failed packets 185 * - Number of Tx retries 186 * - Number of multicast Tx retries 187 * - Number of duplicate frames 188 * - Number of RTS successes 189 * - Number of RTS failures 190 * - Number of ACK failures 191 * - Number of fragmented Rx frames 192 * - Number of multicast Rx frames 193 * - Number of FCS errors 194 * - Number of Tx frames 195 * - WEP ICV error counts 196 * - Number of received beacons 197 * - Number of missed beacons 198 */ 199 static ssize_t 200 mwifiex_getlog_read(struct file *file, char __user *ubuf, 201 size_t count, loff_t *ppos) 202 { 203 struct mwifiex_private *priv = 204 (struct mwifiex_private *) file->private_data; 205 unsigned long page = get_zeroed_page(GFP_KERNEL); 206 char *p = (char *) page; 207 ssize_t ret; 208 struct mwifiex_ds_get_stats stats; 209 210 if (!p) 211 return -ENOMEM; 212 213 memset(&stats, 0, sizeof(stats)); 214 ret = mwifiex_get_stats_info(priv, &stats); 215 if (ret) 216 goto free_and_exit; 217 218 p += sprintf(p, "\n" 219 "mcasttxframe %u\n" 220 "failed %u\n" 221 "retry %u\n" 222 "multiretry %u\n" 223 "framedup %u\n" 224 "rtssuccess %u\n" 225 "rtsfailure %u\n" 226 "ackfailure %u\n" 227 "rxfrag %u\n" 228 "mcastrxframe %u\n" 229 "fcserror %u\n" 230 "txframe %u\n" 231 "wepicverrcnt-1 %u\n" 232 "wepicverrcnt-2 %u\n" 233 "wepicverrcnt-3 %u\n" 234 "wepicverrcnt-4 %u\n" 235 "bcn_rcv_cnt %u\n" 236 "bcn_miss_cnt %u\n", 237 stats.mcast_tx_frame, 238 stats.failed, 239 stats.retry, 240 stats.multi_retry, 241 stats.frame_dup, 242 stats.rts_success, 243 stats.rts_failure, 244 stats.ack_failure, 245 stats.rx_frag, 246 stats.mcast_rx_frame, 247 stats.fcs_error, 248 stats.tx_frame, 249 stats.wep_icv_error[0], 250 stats.wep_icv_error[1], 251 stats.wep_icv_error[2], 252 stats.wep_icv_error[3], 253 stats.bcn_rcv_cnt, 254 stats.bcn_miss_cnt); 255 256 257 ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, 258 (unsigned long) p - page); 259 260 free_and_exit: 261 free_page(page); 262 return ret; 263 } 264 265 /* Sysfs histogram file read handler. 266 * 267 * This function is called when the 'histogram' file is opened for reading 268 * It prints the following histogram information - 269 * - Number of histogram samples 270 * - Receive packet number of each rx_rate 271 * - Receive packet number of each snr 272 * - Receive packet number of each nosie_flr 273 * - Receive packet number of each signal streath 274 */ 275 static ssize_t 276 mwifiex_histogram_read(struct file *file, char __user *ubuf, 277 size_t count, loff_t *ppos) 278 { 279 struct mwifiex_private *priv = 280 (struct mwifiex_private *)file->private_data; 281 ssize_t ret; 282 struct mwifiex_histogram_data *phist_data; 283 int i, value; 284 unsigned long page = get_zeroed_page(GFP_KERNEL); 285 char *p = (char *)page; 286 287 if (!p) 288 return -ENOMEM; 289 290 if (!priv || !priv->hist_data) 291 return -EFAULT; 292 phist_data = priv->hist_data; 293 294 p += sprintf(p, "\n" 295 "total samples = %d\n", 296 atomic_read(&phist_data->num_samples)); 297 298 p += sprintf(p, "rx rates (in Mbps): 0=1M 1=2M"); 299 p += sprintf(p, "2=5.5M 3=11M 4=6M 5=9M 6=12M\n"); 300 p += sprintf(p, "7=18M 8=24M 9=36M 10=48M 11=54M"); 301 p += sprintf(p, "12-27=MCS0-15(BW20) 28-43=MCS0-15(BW40)\n"); 302 303 if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) { 304 p += sprintf(p, "44-53=MCS0-9(VHT:BW20)"); 305 p += sprintf(p, "54-63=MCS0-9(VHT:BW40)"); 306 p += sprintf(p, "64-73=MCS0-9(VHT:BW80)\n\n"); 307 } else { 308 p += sprintf(p, "\n"); 309 } 310 311 for (i = 0; i < MWIFIEX_MAX_RX_RATES; i++) { 312 value = atomic_read(&phist_data->rx_rate[i]); 313 if (value) 314 p += sprintf(p, "rx_rate[%02d] = %d\n", i, value); 315 } 316 317 if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) { 318 for (i = MWIFIEX_MAX_RX_RATES; i < MWIFIEX_MAX_AC_RX_RATES; 319 i++) { 320 value = atomic_read(&phist_data->rx_rate[i]); 321 if (value) 322 p += sprintf(p, "rx_rate[%02d] = %d\n", 323 i, value); 324 } 325 } 326 327 for (i = 0; i < MWIFIEX_MAX_SNR; i++) { 328 value = atomic_read(&phist_data->snr[i]); 329 if (value) 330 p += sprintf(p, "snr[%02ddB] = %d\n", i, value); 331 } 332 for (i = 0; i < MWIFIEX_MAX_NOISE_FLR; i++) { 333 value = atomic_read(&phist_data->noise_flr[i]); 334 if (value) 335 p += sprintf(p, "noise_flr[-%02ddBm] = %d\n", 336 (int)(i-128), value); 337 } 338 for (i = 0; i < MWIFIEX_MAX_SIG_STRENGTH; i++) { 339 value = atomic_read(&phist_data->sig_str[i]); 340 if (value) 341 p += sprintf(p, "sig_strength[-%02ddBm] = %d\n", 342 i, value); 343 } 344 345 ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page, 346 (unsigned long)p - page); 347 348 return ret; 349 } 350 351 static ssize_t 352 mwifiex_histogram_write(struct file *file, const char __user *ubuf, 353 size_t count, loff_t *ppos) 354 { 355 struct mwifiex_private *priv = (void *)file->private_data; 356 357 if (priv && priv->hist_data) 358 mwifiex_hist_data_reset(priv); 359 return 0; 360 } 361 362 static struct mwifiex_debug_info info; 363 364 /* 365 * Proc debug file read handler. 366 * 367 * This function is called when the 'debug' file is opened for reading 368 * It prints the following log information - 369 * - Interrupt count 370 * - WMM AC VO packets count 371 * - WMM AC VI packets count 372 * - WMM AC BE packets count 373 * - WMM AC BK packets count 374 * - Maximum Tx buffer size 375 * - Tx buffer size 376 * - Current Tx buffer size 377 * - Power Save mode 378 * - Power Save state 379 * - Deep Sleep status 380 * - Device wakeup required status 381 * - Number of wakeup tries 382 * - Host Sleep configured status 383 * - Host Sleep activated status 384 * - Number of Tx timeouts 385 * - Number of command timeouts 386 * - Last timed out command ID 387 * - Last timed out command action 388 * - Last command ID 389 * - Last command action 390 * - Last command index 391 * - Last command response ID 392 * - Last command response index 393 * - Last event 394 * - Last event index 395 * - Number of host to card command failures 396 * - Number of sleep confirm command failures 397 * - Number of host to card data failure 398 * - Number of deauthentication events 399 * - Number of disassociation events 400 * - Number of link lost events 401 * - Number of deauthentication commands 402 * - Number of association success commands 403 * - Number of association failure commands 404 * - Number of commands sent 405 * - Number of data packets sent 406 * - Number of command responses received 407 * - Number of events received 408 * - Tx BA stream table (TID, RA) 409 * - Rx reorder table (TID, TA, Start window, Window size, Buffer) 410 */ 411 static ssize_t 412 mwifiex_debug_read(struct file *file, char __user *ubuf, 413 size_t count, loff_t *ppos) 414 { 415 struct mwifiex_private *priv = 416 (struct mwifiex_private *) file->private_data; 417 unsigned long page = get_zeroed_page(GFP_KERNEL); 418 char *p = (char *) page; 419 ssize_t ret; 420 421 if (!p) 422 return -ENOMEM; 423 424 ret = mwifiex_get_debug_info(priv, &info); 425 if (ret) 426 goto free_and_exit; 427 428 p += mwifiex_debug_info_to_buffer(priv, p, &info); 429 430 ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, 431 (unsigned long) p - page); 432 433 free_and_exit: 434 free_page(page); 435 return ret; 436 } 437 438 static u32 saved_reg_type, saved_reg_offset, saved_reg_value; 439 440 /* 441 * Proc regrdwr file write handler. 442 * 443 * This function is called when the 'regrdwr' file is opened for writing 444 * 445 * This function can be used to write to a register. 446 */ 447 static ssize_t 448 mwifiex_regrdwr_write(struct file *file, 449 const char __user *ubuf, size_t count, loff_t *ppos) 450 { 451 char *buf; 452 int ret; 453 u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX; 454 455 buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); 456 if (IS_ERR(buf)) 457 return PTR_ERR(buf); 458 459 sscanf(buf, "%u %x %x", ®_type, ®_offset, ®_value); 460 461 if (reg_type == 0 || reg_offset == 0) { 462 ret = -EINVAL; 463 goto done; 464 } else { 465 saved_reg_type = reg_type; 466 saved_reg_offset = reg_offset; 467 saved_reg_value = reg_value; 468 ret = count; 469 } 470 done: 471 kfree(buf); 472 return ret; 473 } 474 475 /* 476 * Proc regrdwr file read handler. 477 * 478 * This function is called when the 'regrdwr' file is opened for reading 479 * 480 * This function can be used to read from a register. 481 */ 482 static ssize_t 483 mwifiex_regrdwr_read(struct file *file, char __user *ubuf, 484 size_t count, loff_t *ppos) 485 { 486 struct mwifiex_private *priv = 487 (struct mwifiex_private *) file->private_data; 488 unsigned long addr = get_zeroed_page(GFP_KERNEL); 489 char *buf = (char *) addr; 490 int pos = 0, ret = 0; 491 u32 reg_value; 492 493 if (!buf) 494 return -ENOMEM; 495 496 if (!saved_reg_type) { 497 /* No command has been given */ 498 pos += snprintf(buf, PAGE_SIZE, "0"); 499 goto done; 500 } 501 /* Set command has been given */ 502 if (saved_reg_value != UINT_MAX) { 503 ret = mwifiex_reg_write(priv, saved_reg_type, saved_reg_offset, 504 saved_reg_value); 505 506 pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", 507 saved_reg_type, saved_reg_offset, 508 saved_reg_value); 509 510 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 511 512 goto done; 513 } 514 /* Get command has been given */ 515 ret = mwifiex_reg_read(priv, saved_reg_type, 516 saved_reg_offset, ®_value); 517 if (ret) { 518 ret = -EINVAL; 519 goto done; 520 } 521 522 pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", saved_reg_type, 523 saved_reg_offset, reg_value); 524 525 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 526 527 done: 528 free_page(addr); 529 return ret; 530 } 531 532 /* Proc debug_mask file read handler. 533 * This function is called when the 'debug_mask' file is opened for reading 534 * This function can be used read driver debugging mask value. 535 */ 536 static ssize_t 537 mwifiex_debug_mask_read(struct file *file, char __user *ubuf, 538 size_t count, loff_t *ppos) 539 { 540 struct mwifiex_private *priv = 541 (struct mwifiex_private *)file->private_data; 542 unsigned long page = get_zeroed_page(GFP_KERNEL); 543 char *buf = (char *)page; 544 size_t ret = 0; 545 int pos = 0; 546 547 if (!buf) 548 return -ENOMEM; 549 550 pos += snprintf(buf, PAGE_SIZE, "debug mask=0x%08x\n", 551 priv->adapter->debug_mask); 552 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 553 554 free_page(page); 555 return ret; 556 } 557 558 /* Proc debug_mask file read handler. 559 * This function is called when the 'debug_mask' file is opened for reading 560 * This function can be used read driver debugging mask value. 561 */ 562 static ssize_t 563 mwifiex_debug_mask_write(struct file *file, const char __user *ubuf, 564 size_t count, loff_t *ppos) 565 { 566 int ret; 567 unsigned long debug_mask; 568 struct mwifiex_private *priv = (void *)file->private_data; 569 char *buf; 570 571 buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); 572 if (IS_ERR(buf)) 573 return PTR_ERR(buf); 574 575 if (kstrtoul(buf, 0, &debug_mask)) { 576 ret = -EINVAL; 577 goto done; 578 } 579 580 priv->adapter->debug_mask = debug_mask; 581 ret = count; 582 done: 583 kfree(buf); 584 return ret; 585 } 586 587 /* debugfs verext file write handler. 588 * This function is called when the 'verext' file is opened for write 589 */ 590 static ssize_t 591 mwifiex_verext_write(struct file *file, const char __user *ubuf, 592 size_t count, loff_t *ppos) 593 { 594 int ret; 595 u32 versionstrsel; 596 struct mwifiex_private *priv = (void *)file->private_data; 597 char buf[16]; 598 599 memset(buf, 0, sizeof(buf)); 600 601 if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) 602 return -EFAULT; 603 604 ret = kstrtou32(buf, 10, &versionstrsel); 605 if (ret) 606 return ret; 607 608 priv->versionstrsel = versionstrsel; 609 610 return count; 611 } 612 613 /* Proc verext file read handler. 614 * This function is called when the 'verext' file is opened for reading 615 * This function can be used read driver exteneed verion string. 616 */ 617 static ssize_t 618 mwifiex_verext_read(struct file *file, char __user *ubuf, 619 size_t count, loff_t *ppos) 620 { 621 struct mwifiex_private *priv = 622 (struct mwifiex_private *)file->private_data; 623 char buf[256]; 624 int ret; 625 626 mwifiex_get_ver_ext(priv, priv->versionstrsel); 627 ret = snprintf(buf, sizeof(buf), "version string: %s\n", 628 priv->version_str); 629 630 return simple_read_from_buffer(ubuf, count, ppos, buf, ret); 631 } 632 633 /* Proc memrw file write handler. 634 * This function is called when the 'memrw' file is opened for writing 635 * This function can be used to write to a memory location. 636 */ 637 static ssize_t 638 mwifiex_memrw_write(struct file *file, const char __user *ubuf, size_t count, 639 loff_t *ppos) 640 { 641 int ret; 642 char cmd; 643 struct mwifiex_ds_mem_rw mem_rw; 644 u16 cmd_action; 645 struct mwifiex_private *priv = (void *)file->private_data; 646 char *buf; 647 648 buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); 649 if (IS_ERR(buf)) 650 return PTR_ERR(buf); 651 652 ret = sscanf(buf, "%c %x %x", &cmd, &mem_rw.addr, &mem_rw.value); 653 if (ret != 3) { 654 ret = -EINVAL; 655 goto done; 656 } 657 658 if ((cmd == 'r') || (cmd == 'R')) { 659 cmd_action = HostCmd_ACT_GEN_GET; 660 mem_rw.value = 0; 661 } else if ((cmd == 'w') || (cmd == 'W')) { 662 cmd_action = HostCmd_ACT_GEN_SET; 663 } else { 664 ret = -EINVAL; 665 goto done; 666 } 667 668 memcpy(&priv->mem_rw, &mem_rw, sizeof(mem_rw)); 669 if (mwifiex_send_cmd(priv, HostCmd_CMD_MEM_ACCESS, cmd_action, 0, 670 &mem_rw, true)) 671 ret = -1; 672 else 673 ret = count; 674 675 done: 676 kfree(buf); 677 return ret; 678 } 679 680 /* Proc memrw file read handler. 681 * This function is called when the 'memrw' file is opened for reading 682 * This function can be used to read from a memory location. 683 */ 684 static ssize_t 685 mwifiex_memrw_read(struct file *file, char __user *ubuf, 686 size_t count, loff_t *ppos) 687 { 688 struct mwifiex_private *priv = (void *)file->private_data; 689 unsigned long addr = get_zeroed_page(GFP_KERNEL); 690 char *buf = (char *)addr; 691 int ret, pos = 0; 692 693 if (!buf) 694 return -ENOMEM; 695 696 pos += snprintf(buf, PAGE_SIZE, "0x%x 0x%x\n", priv->mem_rw.addr, 697 priv->mem_rw.value); 698 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 699 700 free_page(addr); 701 return ret; 702 } 703 704 static u32 saved_offset = -1, saved_bytes = -1; 705 706 /* 707 * Proc rdeeprom file write handler. 708 * 709 * This function is called when the 'rdeeprom' file is opened for writing 710 * 711 * This function can be used to write to a RDEEPROM location. 712 */ 713 static ssize_t 714 mwifiex_rdeeprom_write(struct file *file, 715 const char __user *ubuf, size_t count, loff_t *ppos) 716 { 717 char *buf; 718 int ret = 0; 719 int offset = -1, bytes = -1; 720 721 buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); 722 if (IS_ERR(buf)) 723 return PTR_ERR(buf); 724 725 sscanf(buf, "%d %d", &offset, &bytes); 726 727 if (offset == -1 || bytes == -1) { 728 ret = -EINVAL; 729 goto done; 730 } else { 731 saved_offset = offset; 732 saved_bytes = bytes; 733 ret = count; 734 } 735 done: 736 kfree(buf); 737 return ret; 738 } 739 740 /* 741 * Proc rdeeprom read write handler. 742 * 743 * This function is called when the 'rdeeprom' file is opened for reading 744 * 745 * This function can be used to read from a RDEEPROM location. 746 */ 747 static ssize_t 748 mwifiex_rdeeprom_read(struct file *file, char __user *ubuf, 749 size_t count, loff_t *ppos) 750 { 751 struct mwifiex_private *priv = 752 (struct mwifiex_private *) file->private_data; 753 unsigned long addr = get_zeroed_page(GFP_KERNEL); 754 char *buf = (char *) addr; 755 int pos, ret, i; 756 u8 value[MAX_EEPROM_DATA]; 757 758 if (!buf) 759 return -ENOMEM; 760 761 if (saved_offset == -1) { 762 /* No command has been given */ 763 pos = snprintf(buf, PAGE_SIZE, "0"); 764 goto done; 765 } 766 767 /* Get command has been given */ 768 ret = mwifiex_eeprom_read(priv, (u16) saved_offset, 769 (u16) saved_bytes, value); 770 if (ret) { 771 ret = -EINVAL; 772 goto out_free; 773 } 774 775 pos = snprintf(buf, PAGE_SIZE, "%d %d ", saved_offset, saved_bytes); 776 777 for (i = 0; i < saved_bytes; i++) 778 pos += scnprintf(buf + pos, PAGE_SIZE - pos, "%d ", value[i]); 779 780 done: 781 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 782 out_free: 783 free_page(addr); 784 return ret; 785 } 786 787 /* Proc hscfg file write handler 788 * This function can be used to configure the host sleep parameters. 789 */ 790 static ssize_t 791 mwifiex_hscfg_write(struct file *file, const char __user *ubuf, 792 size_t count, loff_t *ppos) 793 { 794 struct mwifiex_private *priv = (void *)file->private_data; 795 char *buf; 796 int ret, arg_num; 797 struct mwifiex_ds_hs_cfg hscfg; 798 int conditions = HS_CFG_COND_DEF; 799 u32 gpio = HS_CFG_GPIO_DEF, gap = HS_CFG_GAP_DEF; 800 801 buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); 802 if (IS_ERR(buf)) 803 return PTR_ERR(buf); 804 805 arg_num = sscanf(buf, "%d %x %x", &conditions, &gpio, &gap); 806 807 memset(&hscfg, 0, sizeof(struct mwifiex_ds_hs_cfg)); 808 809 if (arg_num > 3) { 810 mwifiex_dbg(priv->adapter, ERROR, 811 "Too many arguments\n"); 812 ret = -EINVAL; 813 goto done; 814 } 815 816 if (arg_num >= 1 && arg_num < 3) 817 mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_GET, 818 MWIFIEX_SYNC_CMD, &hscfg); 819 820 if (arg_num) { 821 if (conditions == HS_CFG_CANCEL) { 822 mwifiex_cancel_hs(priv, MWIFIEX_ASYNC_CMD); 823 ret = count; 824 goto done; 825 } 826 hscfg.conditions = conditions; 827 } 828 if (arg_num >= 2) 829 hscfg.gpio = gpio; 830 if (arg_num == 3) 831 hscfg.gap = gap; 832 833 hscfg.is_invoke_hostcmd = false; 834 mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET, 835 MWIFIEX_SYNC_CMD, &hscfg); 836 837 mwifiex_enable_hs(priv->adapter); 838 priv->adapter->hs_enabling = false; 839 ret = count; 840 done: 841 kfree(buf); 842 return ret; 843 } 844 845 /* Proc hscfg file read handler 846 * This function can be used to read host sleep configuration 847 * parameters from driver. 848 */ 849 static ssize_t 850 mwifiex_hscfg_read(struct file *file, char __user *ubuf, 851 size_t count, loff_t *ppos) 852 { 853 struct mwifiex_private *priv = (void *)file->private_data; 854 unsigned long addr = get_zeroed_page(GFP_KERNEL); 855 char *buf = (char *)addr; 856 int pos, ret; 857 struct mwifiex_ds_hs_cfg hscfg; 858 859 if (!buf) 860 return -ENOMEM; 861 862 mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_GET, 863 MWIFIEX_SYNC_CMD, &hscfg); 864 865 pos = snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", hscfg.conditions, 866 hscfg.gpio, hscfg.gap); 867 868 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 869 870 free_page(addr); 871 return ret; 872 } 873 874 static ssize_t 875 mwifiex_timeshare_coex_read(struct file *file, char __user *ubuf, 876 size_t count, loff_t *ppos) 877 { 878 struct mwifiex_private *priv = file->private_data; 879 char buf[3]; 880 bool timeshare_coex; 881 int ret; 882 unsigned int len; 883 884 if (priv->adapter->fw_api_ver != MWIFIEX_FW_V15) 885 return -EOPNOTSUPP; 886 887 ret = mwifiex_send_cmd(priv, HostCmd_CMD_ROBUST_COEX, 888 HostCmd_ACT_GEN_GET, 0, ×hare_coex, true); 889 if (ret) 890 return ret; 891 892 len = sprintf(buf, "%d\n", timeshare_coex); 893 return simple_read_from_buffer(ubuf, count, ppos, buf, len); 894 } 895 896 static ssize_t 897 mwifiex_timeshare_coex_write(struct file *file, const char __user *ubuf, 898 size_t count, loff_t *ppos) 899 { 900 bool timeshare_coex; 901 struct mwifiex_private *priv = file->private_data; 902 char kbuf[16]; 903 int ret; 904 905 if (priv->adapter->fw_api_ver != MWIFIEX_FW_V15) 906 return -EOPNOTSUPP; 907 908 memset(kbuf, 0, sizeof(kbuf)); 909 910 if (copy_from_user(&kbuf, ubuf, min_t(size_t, sizeof(kbuf) - 1, count))) 911 return -EFAULT; 912 913 if (strtobool(kbuf, ×hare_coex)) 914 return -EINVAL; 915 916 ret = mwifiex_send_cmd(priv, HostCmd_CMD_ROBUST_COEX, 917 HostCmd_ACT_GEN_SET, 0, ×hare_coex, true); 918 if (ret) 919 return ret; 920 else 921 return count; 922 } 923 924 static ssize_t 925 mwifiex_reset_write(struct file *file, 926 const char __user *ubuf, size_t count, loff_t *ppos) 927 { 928 struct mwifiex_private *priv = file->private_data; 929 struct mwifiex_adapter *adapter = priv->adapter; 930 bool result; 931 int rc; 932 933 rc = kstrtobool_from_user(ubuf, count, &result); 934 if (rc) 935 return rc; 936 937 if (!result) 938 return -EINVAL; 939 940 if (adapter->if_ops.card_reset) { 941 dev_info(adapter->dev, "Resetting per request\n"); 942 adapter->hw_status = MWIFIEX_HW_STATUS_RESET; 943 mwifiex_cancel_all_pending_cmd(adapter); 944 adapter->if_ops.card_reset(adapter); 945 } 946 947 return count; 948 } 949 950 #define MWIFIEX_DFS_ADD_FILE(name) do { \ 951 if (!debugfs_create_file(#name, 0644, priv->dfs_dev_dir, \ 952 priv, &mwifiex_dfs_##name##_fops)) \ 953 return; \ 954 } while (0); 955 956 #define MWIFIEX_DFS_FILE_OPS(name) \ 957 static const struct file_operations mwifiex_dfs_##name##_fops = { \ 958 .read = mwifiex_##name##_read, \ 959 .write = mwifiex_##name##_write, \ 960 .open = simple_open, \ 961 }; 962 963 #define MWIFIEX_DFS_FILE_READ_OPS(name) \ 964 static const struct file_operations mwifiex_dfs_##name##_fops = { \ 965 .read = mwifiex_##name##_read, \ 966 .open = simple_open, \ 967 }; 968 969 #define MWIFIEX_DFS_FILE_WRITE_OPS(name) \ 970 static const struct file_operations mwifiex_dfs_##name##_fops = { \ 971 .write = mwifiex_##name##_write, \ 972 .open = simple_open, \ 973 }; 974 975 976 MWIFIEX_DFS_FILE_READ_OPS(info); 977 MWIFIEX_DFS_FILE_READ_OPS(debug); 978 MWIFIEX_DFS_FILE_READ_OPS(getlog); 979 MWIFIEX_DFS_FILE_READ_OPS(device_dump); 980 MWIFIEX_DFS_FILE_OPS(regrdwr); 981 MWIFIEX_DFS_FILE_OPS(rdeeprom); 982 MWIFIEX_DFS_FILE_OPS(memrw); 983 MWIFIEX_DFS_FILE_OPS(hscfg); 984 MWIFIEX_DFS_FILE_OPS(histogram); 985 MWIFIEX_DFS_FILE_OPS(debug_mask); 986 MWIFIEX_DFS_FILE_OPS(timeshare_coex); 987 MWIFIEX_DFS_FILE_WRITE_OPS(reset); 988 MWIFIEX_DFS_FILE_OPS(verext); 989 990 /* 991 * This function creates the debug FS directory structure and the files. 992 */ 993 void 994 mwifiex_dev_debugfs_init(struct mwifiex_private *priv) 995 { 996 if (!mwifiex_dfs_dir || !priv) 997 return; 998 999 priv->dfs_dev_dir = debugfs_create_dir(priv->netdev->name, 1000 mwifiex_dfs_dir); 1001 1002 if (!priv->dfs_dev_dir) 1003 return; 1004 1005 MWIFIEX_DFS_ADD_FILE(info); 1006 MWIFIEX_DFS_ADD_FILE(debug); 1007 MWIFIEX_DFS_ADD_FILE(getlog); 1008 MWIFIEX_DFS_ADD_FILE(regrdwr); 1009 MWIFIEX_DFS_ADD_FILE(rdeeprom); 1010 MWIFIEX_DFS_ADD_FILE(device_dump); 1011 MWIFIEX_DFS_ADD_FILE(memrw); 1012 MWIFIEX_DFS_ADD_FILE(hscfg); 1013 MWIFIEX_DFS_ADD_FILE(histogram); 1014 MWIFIEX_DFS_ADD_FILE(debug_mask); 1015 MWIFIEX_DFS_ADD_FILE(timeshare_coex); 1016 MWIFIEX_DFS_ADD_FILE(reset); 1017 MWIFIEX_DFS_ADD_FILE(verext); 1018 } 1019 1020 /* 1021 * This function removes the debug FS directory structure and the files. 1022 */ 1023 void 1024 mwifiex_dev_debugfs_remove(struct mwifiex_private *priv) 1025 { 1026 if (!priv) 1027 return; 1028 1029 debugfs_remove_recursive(priv->dfs_dev_dir); 1030 } 1031 1032 /* 1033 * This function creates the top level proc directory. 1034 */ 1035 void 1036 mwifiex_debugfs_init(void) 1037 { 1038 if (!mwifiex_dfs_dir) 1039 mwifiex_dfs_dir = debugfs_create_dir("mwifiex", NULL); 1040 } 1041 1042 /* 1043 * This function removes the top level proc directory. 1044 */ 1045 void 1046 mwifiex_debugfs_remove(void) 1047 { 1048 if (mwifiex_dfs_dir) 1049 debugfs_remove(mwifiex_dfs_dir); 1050 } 1051