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