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