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