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