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