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