1/* 2 * Marvell Wireless LAN device driver: debugfs 3 * 4 * Copyright (C) 2011, 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 26static struct dentry *mwifiex_dfs_dir; 27 28static char *bss_modes[] = { 29 "Unknown", 30 "Ad-hoc", 31 "Managed", 32 "Auto" 33}; 34 35/* size/addr for mwifiex_debug_info */ 36#define item_size(n) (FIELD_SIZEOF(struct mwifiex_debug_info, n)) 37#define item_addr(n) (offsetof(struct mwifiex_debug_info, n)) 38 39/* size/addr for struct mwifiex_adapter */ 40#define adapter_item_size(n) (FIELD_SIZEOF(struct mwifiex_adapter, n)) 41#define adapter_item_addr(n) (offsetof(struct mwifiex_adapter, n)) 42 43struct mwifiex_debug_data { 44 char name[32]; /* variable/array name */ 45 u32 size; /* size of the variable/array */ 46 size_t addr; /* address of the variable/array */ 47 int num; /* number of variables in an array */ 48}; 49 50static struct mwifiex_debug_data items[] = { 51 {"int_counter", item_size(int_counter), 52 item_addr(int_counter), 1}, 53 {"wmm_ac_vo", item_size(packets_out[WMM_AC_VO]), 54 item_addr(packets_out[WMM_AC_VO]), 1}, 55 {"wmm_ac_vi", item_size(packets_out[WMM_AC_VI]), 56 item_addr(packets_out[WMM_AC_VI]), 1}, 57 {"wmm_ac_be", item_size(packets_out[WMM_AC_BE]), 58 item_addr(packets_out[WMM_AC_BE]), 1}, 59 {"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]), 60 item_addr(packets_out[WMM_AC_BK]), 1}, 61 {"max_tx_buf_size", item_size(max_tx_buf_size), 62 item_addr(max_tx_buf_size), 1}, 63 {"tx_buf_size", item_size(tx_buf_size), 64 item_addr(tx_buf_size), 1}, 65 {"curr_tx_buf_size", item_size(curr_tx_buf_size), 66 item_addr(curr_tx_buf_size), 1}, 67 {"ps_mode", item_size(ps_mode), 68 item_addr(ps_mode), 1}, 69 {"ps_state", item_size(ps_state), 70 item_addr(ps_state), 1}, 71 {"is_deep_sleep", item_size(is_deep_sleep), 72 item_addr(is_deep_sleep), 1}, 73 {"wakeup_dev_req", item_size(pm_wakeup_card_req), 74 item_addr(pm_wakeup_card_req), 1}, 75 {"wakeup_tries", item_size(pm_wakeup_fw_try), 76 item_addr(pm_wakeup_fw_try), 1}, 77 {"hs_configured", item_size(is_hs_configured), 78 item_addr(is_hs_configured), 1}, 79 {"hs_activated", item_size(hs_activated), 80 item_addr(hs_activated), 1}, 81 {"num_tx_timeout", item_size(num_tx_timeout), 82 item_addr(num_tx_timeout), 1}, 83 {"num_cmd_timeout", item_size(num_cmd_timeout), 84 item_addr(num_cmd_timeout), 1}, 85 {"timeout_cmd_id", item_size(timeout_cmd_id), 86 item_addr(timeout_cmd_id), 1}, 87 {"timeout_cmd_act", item_size(timeout_cmd_act), 88 item_addr(timeout_cmd_act), 1}, 89 {"last_cmd_id", item_size(last_cmd_id), 90 item_addr(last_cmd_id), DBG_CMD_NUM}, 91 {"last_cmd_act", item_size(last_cmd_act), 92 item_addr(last_cmd_act), DBG_CMD_NUM}, 93 {"last_cmd_index", item_size(last_cmd_index), 94 item_addr(last_cmd_index), 1}, 95 {"last_cmd_resp_id", item_size(last_cmd_resp_id), 96 item_addr(last_cmd_resp_id), DBG_CMD_NUM}, 97 {"last_cmd_resp_index", item_size(last_cmd_resp_index), 98 item_addr(last_cmd_resp_index), 1}, 99 {"last_event", item_size(last_event), 100 item_addr(last_event), DBG_CMD_NUM}, 101 {"last_event_index", item_size(last_event_index), 102 item_addr(last_event_index), 1}, 103 {"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure), 104 item_addr(num_cmd_host_to_card_failure), 1}, 105 {"num_cmd_sleep_cfm_fail", 106 item_size(num_cmd_sleep_cfm_host_to_card_failure), 107 item_addr(num_cmd_sleep_cfm_host_to_card_failure), 1}, 108 {"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure), 109 item_addr(num_tx_host_to_card_failure), 1}, 110 {"num_evt_deauth", item_size(num_event_deauth), 111 item_addr(num_event_deauth), 1}, 112 {"num_evt_disassoc", item_size(num_event_disassoc), 113 item_addr(num_event_disassoc), 1}, 114 {"num_evt_link_lost", item_size(num_event_link_lost), 115 item_addr(num_event_link_lost), 1}, 116 {"num_cmd_deauth", item_size(num_cmd_deauth), 117 item_addr(num_cmd_deauth), 1}, 118 {"num_cmd_assoc_ok", item_size(num_cmd_assoc_success), 119 item_addr(num_cmd_assoc_success), 1}, 120 {"num_cmd_assoc_fail", item_size(num_cmd_assoc_failure), 121 item_addr(num_cmd_assoc_failure), 1}, 122 {"cmd_sent", item_size(cmd_sent), 123 item_addr(cmd_sent), 1}, 124 {"data_sent", item_size(data_sent), 125 item_addr(data_sent), 1}, 126 {"cmd_resp_received", item_size(cmd_resp_received), 127 item_addr(cmd_resp_received), 1}, 128 {"event_received", item_size(event_received), 129 item_addr(event_received), 1}, 130 131 /* variables defined in struct mwifiex_adapter */ 132 {"cmd_pending", adapter_item_size(cmd_pending), 133 adapter_item_addr(cmd_pending), 1}, 134 {"tx_pending", adapter_item_size(tx_pending), 135 adapter_item_addr(tx_pending), 1}, 136 {"rx_pending", adapter_item_size(rx_pending), 137 adapter_item_addr(rx_pending), 1}, 138}; 139 140static int num_of_items = ARRAY_SIZE(items); 141 142/* 143 * Generic proc file open handler. 144 * 145 * This function is called every time a file is accessed for read or write. 146 */ 147static int 148mwifiex_open_generic(struct inode *inode, struct file *file) 149{ 150 file->private_data = inode->i_private; 151 return 0; 152} 153 154/* 155 * Proc info file read handler. 156 * 157 * This function is called when the 'info' file is opened for reading. 158 * It prints the following driver related information - 159 * - Driver name 160 * - Driver version 161 * - Driver extended version 162 * - Interface name 163 * - BSS mode 164 * - Media state (connected or disconnected) 165 * - MAC address 166 * - Total number of Tx bytes 167 * - Total number of Rx bytes 168 * - Total number of Tx packets 169 * - Total number of Rx packets 170 * - Total number of dropped Tx packets 171 * - Total number of dropped Rx packets 172 * - Total number of corrupted Tx packets 173 * - Total number of corrupted Rx packets 174 * - Carrier status (on or off) 175 * - Tx queue status (started or stopped) 176 * 177 * For STA mode drivers, it also prints the following extra - 178 * - ESSID 179 * - BSSID 180 * - Channel 181 * - Region code 182 * - Multicast count 183 * - Multicast addresses 184 */ 185static ssize_t 186mwifiex_info_read(struct file *file, char __user *ubuf, 187 size_t count, loff_t *ppos) 188{ 189 struct mwifiex_private *priv = 190 (struct mwifiex_private *) file->private_data; 191 struct net_device *netdev = priv->netdev; 192 struct netdev_hw_addr *ha; 193 unsigned long page = get_zeroed_page(GFP_KERNEL); 194 char *p = (char *) page, fmt[64]; 195 struct mwifiex_bss_info info; 196 ssize_t ret; 197 int i = 0; 198 199 if (!p) 200 return -ENOMEM; 201 202 memset(&info, 0, sizeof(info)); 203 ret = mwifiex_get_bss_info(priv, &info); 204 if (ret) 205 goto free_and_exit; 206 207 mwifiex_drv_get_driver_version(priv->adapter, fmt, sizeof(fmt) - 1); 208 209 if (!priv->version_str[0]) 210 mwifiex_get_ver_ext(priv); 211 212 p += sprintf(p, "driver_name = " "\"mwifiex\"\n"); 213 p += sprintf(p, "driver_version = %s", fmt); 214 p += sprintf(p, "\nverext = %s", priv->version_str); 215 p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name); 216 p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]); 217 p += sprintf(p, "media_state=\"%s\"\n", 218 (!priv->media_connected ? "Disconnected" : "Connected")); 219 p += sprintf(p, "mac_address=\"%pM\"\n", netdev->dev_addr); 220 221 if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) { 222 p += sprintf(p, "multicast_count=\"%d\"\n", 223 netdev_mc_count(netdev)); 224 p += sprintf(p, "essid=\"%s\"\n", info.ssid.ssid); 225 p += sprintf(p, "bssid=\"%pM\"\n", info.bssid); 226 p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan); 227 p += sprintf(p, "region_code = \"%02x\"\n", info.region_code); 228 229 netdev_for_each_mc_addr(ha, netdev) 230 p += sprintf(p, "multicast_address[%d]=\"%pM\"\n", 231 i++, ha->addr); 232 } 233 234 p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes); 235 p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes); 236 p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets); 237 p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets); 238 p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped); 239 p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped); 240 p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors); 241 p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors); 242 p += sprintf(p, "carrier %s\n", ((netif_carrier_ok(priv->netdev)) 243 ? "on" : "off")); 244 p += sprintf(p, "tx queue %s\n", ((netif_queue_stopped(priv->netdev)) 245 ? "stopped" : "started")); 246 247 ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, 248 (unsigned long) p - page); 249 250free_and_exit: 251 free_page(page); 252 return ret; 253} 254 255/* 256 * Proc getlog file read handler. 257 * 258 * This function is called when the 'getlog' file is opened for reading 259 * It prints the following log information - 260 * - Number of multicast Tx frames 261 * - Number of failed packets 262 * - Number of Tx retries 263 * - Number of multicast Tx retries 264 * - Number of duplicate frames 265 * - Number of RTS successes 266 * - Number of RTS failures 267 * - Number of ACK failures 268 * - Number of fragmented Rx frames 269 * - Number of multicast Rx frames 270 * - Number of FCS errors 271 * - Number of Tx frames 272 * - WEP ICV error counts 273 */ 274static ssize_t 275mwifiex_getlog_read(struct file *file, char __user *ubuf, 276 size_t count, loff_t *ppos) 277{ 278 struct mwifiex_private *priv = 279 (struct mwifiex_private *) file->private_data; 280 unsigned long page = get_zeroed_page(GFP_KERNEL); 281 char *p = (char *) page; 282 ssize_t ret; 283 struct mwifiex_ds_get_stats stats; 284 285 if (!p) 286 return -ENOMEM; 287 288 memset(&stats, 0, sizeof(stats)); 289 ret = mwifiex_get_stats_info(priv, &stats); 290 if (ret) 291 goto free_and_exit; 292 293 p += sprintf(p, "\n" 294 "mcasttxframe %u\n" 295 "failed %u\n" 296 "retry %u\n" 297 "multiretry %u\n" 298 "framedup %u\n" 299 "rtssuccess %u\n" 300 "rtsfailure %u\n" 301 "ackfailure %u\n" 302 "rxfrag %u\n" 303 "mcastrxframe %u\n" 304 "fcserror %u\n" 305 "txframe %u\n" 306 "wepicverrcnt-1 %u\n" 307 "wepicverrcnt-2 %u\n" 308 "wepicverrcnt-3 %u\n" 309 "wepicverrcnt-4 %u\n", 310 stats.mcast_tx_frame, 311 stats.failed, 312 stats.retry, 313 stats.multi_retry, 314 stats.frame_dup, 315 stats.rts_success, 316 stats.rts_failure, 317 stats.ack_failure, 318 stats.rx_frag, 319 stats.mcast_rx_frame, 320 stats.fcs_error, 321 stats.tx_frame, 322 stats.wep_icv_error[0], 323 stats.wep_icv_error[1], 324 stats.wep_icv_error[2], 325 stats.wep_icv_error[3]); 326 327 328 ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, 329 (unsigned long) p - page); 330 331free_and_exit: 332 free_page(page); 333 return ret; 334} 335 336static struct mwifiex_debug_info info; 337 338/* 339 * Proc debug file read handler. 340 * 341 * This function is called when the 'debug' file is opened for reading 342 * It prints the following log information - 343 * - Interrupt count 344 * - WMM AC VO packets count 345 * - WMM AC VI packets count 346 * - WMM AC BE packets count 347 * - WMM AC BK packets count 348 * - Maximum Tx buffer size 349 * - Tx buffer size 350 * - Current Tx buffer size 351 * - Power Save mode 352 * - Power Save state 353 * - Deep Sleep status 354 * - Device wakeup required status 355 * - Number of wakeup tries 356 * - Host Sleep configured status 357 * - Host Sleep activated status 358 * - Number of Tx timeouts 359 * - Number of command timeouts 360 * - Last timed out command ID 361 * - Last timed out command action 362 * - Last command ID 363 * - Last command action 364 * - Last command index 365 * - Last command response ID 366 * - Last command response index 367 * - Last event 368 * - Last event index 369 * - Number of host to card command failures 370 * - Number of sleep confirm command failures 371 * - Number of host to card data failure 372 * - Number of deauthentication events 373 * - Number of disassociation events 374 * - Number of link lost events 375 * - Number of deauthentication commands 376 * - Number of association success commands 377 * - Number of association failure commands 378 * - Number of commands sent 379 * - Number of data packets sent 380 * - Number of command responses received 381 * - Number of events received 382 * - Tx BA stream table (TID, RA) 383 * - Rx reorder table (TID, TA, Start window, Window size, Buffer) 384 */ 385static ssize_t 386mwifiex_debug_read(struct file *file, char __user *ubuf, 387 size_t count, loff_t *ppos) 388{ 389 struct mwifiex_private *priv = 390 (struct mwifiex_private *) file->private_data; 391 struct mwifiex_debug_data *d = &items[0]; 392 unsigned long page = get_zeroed_page(GFP_KERNEL); 393 char *p = (char *) page; 394 ssize_t ret; 395 size_t size, addr; 396 long val; 397 int i, j; 398 399 if (!p) 400 return -ENOMEM; 401 402 ret = mwifiex_get_debug_info(priv, &info); 403 if (ret) 404 goto free_and_exit; 405 406 for (i = 0; i < num_of_items; i++) { 407 p += sprintf(p, "%s=", d[i].name); 408 409 size = d[i].size / d[i].num; 410 411 if (i < (num_of_items - 3)) 412 addr = d[i].addr + (size_t) &info; 413 else /* The last 3 items are struct mwifiex_adapter variables */ 414 addr = d[i].addr + (size_t) priv->adapter; 415 416 for (j = 0; j < d[i].num; j++) { 417 switch (size) { 418 case 1: 419 val = *((u8 *) addr); 420 break; 421 case 2: 422 val = *((u16 *) addr); 423 break; 424 case 4: 425 val = *((u32 *) addr); 426 break; 427 case 8: 428 val = *((long long *) addr); 429 break; 430 default: 431 val = -1; 432 break; 433 } 434 435 p += sprintf(p, "%#lx ", val); 436 addr += size; 437 } 438 439 p += sprintf(p, "\n"); 440 } 441 442 if (info.tx_tbl_num) { 443 p += sprintf(p, "Tx BA stream table:\n"); 444 for (i = 0; i < info.tx_tbl_num; i++) 445 p += sprintf(p, "tid = %d, ra = %pM\n", 446 info.tx_tbl[i].tid, info.tx_tbl[i].ra); 447 } 448 449 if (info.rx_tbl_num) { 450 p += sprintf(p, "Rx reorder table:\n"); 451 for (i = 0; i < info.rx_tbl_num; i++) { 452 p += sprintf(p, "tid = %d, ta = %pM, " 453 "start_win = %d, " 454 "win_size = %d, buffer: ", 455 info.rx_tbl[i].tid, 456 info.rx_tbl[i].ta, 457 info.rx_tbl[i].start_win, 458 info.rx_tbl[i].win_size); 459 460 for (j = 0; j < info.rx_tbl[i].win_size; j++) 461 p += sprintf(p, "%c ", 462 info.rx_tbl[i].buffer[j] ? 463 '1' : '0'); 464 465 p += sprintf(p, "\n"); 466 } 467 } 468 469 ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, 470 (unsigned long) p - page); 471 472free_and_exit: 473 free_page(page); 474 return ret; 475} 476 477static u32 saved_reg_type, saved_reg_offset, saved_reg_value; 478 479/* 480 * Proc regrdwr file write handler. 481 * 482 * This function is called when the 'regrdwr' file is opened for writing 483 * 484 * This function can be used to write to a register. 485 */ 486static ssize_t 487mwifiex_regrdwr_write(struct file *file, 488 const char __user *ubuf, size_t count, loff_t *ppos) 489{ 490 unsigned long addr = get_zeroed_page(GFP_KERNEL); 491 char *buf = (char *) addr; 492 size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1)); 493 int ret; 494 u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX; 495 496 if (!buf) 497 return -ENOMEM; 498 499 500 if (copy_from_user(buf, ubuf, buf_size)) { 501 ret = -EFAULT; 502 goto done; 503 } 504 505 sscanf(buf, "%u %x %x", ®_type, ®_offset, ®_value); 506 507 if (reg_type == 0 || reg_offset == 0) { 508 ret = -EINVAL; 509 goto done; 510 } else { 511 saved_reg_type = reg_type; 512 saved_reg_offset = reg_offset; 513 saved_reg_value = reg_value; 514 ret = count; 515 } 516done: 517 free_page(addr); 518 return ret; 519} 520 521/* 522 * Proc regrdwr file read handler. 523 * 524 * This function is called when the 'regrdwr' file is opened for reading 525 * 526 * This function can be used to read from a register. 527 */ 528static ssize_t 529mwifiex_regrdwr_read(struct file *file, char __user *ubuf, 530 size_t count, loff_t *ppos) 531{ 532 struct mwifiex_private *priv = 533 (struct mwifiex_private *) file->private_data; 534 unsigned long addr = get_zeroed_page(GFP_KERNEL); 535 char *buf = (char *) addr; 536 int pos = 0, ret = 0; 537 u32 reg_value; 538 539 if (!buf) 540 return -ENOMEM; 541 542 if (!saved_reg_type) { 543 /* No command has been given */ 544 pos += snprintf(buf, PAGE_SIZE, "0"); 545 goto done; 546 } 547 /* Set command has been given */ 548 if (saved_reg_value != UINT_MAX) { 549 ret = mwifiex_reg_write(priv, saved_reg_type, saved_reg_offset, 550 saved_reg_value); 551 552 pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", 553 saved_reg_type, saved_reg_offset, 554 saved_reg_value); 555 556 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 557 558 goto done; 559 } 560 /* Get command has been given */ 561 ret = mwifiex_reg_read(priv, saved_reg_type, 562 saved_reg_offset, ®_value); 563 if (ret) { 564 ret = -EINVAL; 565 goto done; 566 } 567 568 pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", saved_reg_type, 569 saved_reg_offset, reg_value); 570 571 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 572 573done: 574 free_page(addr); 575 return ret; 576} 577 578static u32 saved_offset = -1, saved_bytes = -1; 579 580/* 581 * Proc rdeeprom file write handler. 582 * 583 * This function is called when the 'rdeeprom' file is opened for writing 584 * 585 * This function can be used to write to a RDEEPROM location. 586 */ 587static ssize_t 588mwifiex_rdeeprom_write(struct file *file, 589 const char __user *ubuf, size_t count, loff_t *ppos) 590{ 591 unsigned long addr = get_zeroed_page(GFP_KERNEL); 592 char *buf = (char *) addr; 593 size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1)); 594 int ret = 0; 595 int offset = -1, bytes = -1; 596 597 if (!buf) 598 return -ENOMEM; 599 600 601 if (copy_from_user(buf, ubuf, buf_size)) { 602 ret = -EFAULT; 603 goto done; 604 } 605 606 sscanf(buf, "%d %d", &offset, &bytes); 607 608 if (offset == -1 || bytes == -1) { 609 ret = -EINVAL; 610 goto done; 611 } else { 612 saved_offset = offset; 613 saved_bytes = bytes; 614 ret = count; 615 } 616done: 617 free_page(addr); 618 return ret; 619} 620 621/* 622 * Proc rdeeprom read write handler. 623 * 624 * This function is called when the 'rdeeprom' file is opened for reading 625 * 626 * This function can be used to read from a RDEEPROM location. 627 */ 628static ssize_t 629mwifiex_rdeeprom_read(struct file *file, char __user *ubuf, 630 size_t count, loff_t *ppos) 631{ 632 struct mwifiex_private *priv = 633 (struct mwifiex_private *) file->private_data; 634 unsigned long addr = get_zeroed_page(GFP_KERNEL); 635 char *buf = (char *) addr; 636 int pos = 0, ret = 0, i; 637 u8 value[MAX_EEPROM_DATA]; 638 639 if (!buf) 640 return -ENOMEM; 641 642 if (saved_offset == -1) { 643 /* No command has been given */ 644 pos += snprintf(buf, PAGE_SIZE, "0"); 645 goto done; 646 } 647 648 /* Get command has been given */ 649 ret = mwifiex_eeprom_read(priv, (u16) saved_offset, 650 (u16) saved_bytes, value); 651 if (ret) { 652 ret = -EINVAL; 653 goto done; 654 } 655 656 pos += snprintf(buf, PAGE_SIZE, "%d %d ", saved_offset, saved_bytes); 657 658 for (i = 0; i < saved_bytes; i++) 659 pos += snprintf(buf + strlen(buf), PAGE_SIZE, "%d ", value[i]); 660 661 ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 662 663done: 664 free_page(addr); 665 return ret; 666} 667 668 669#define MWIFIEX_DFS_ADD_FILE(name) do { \ 670 if (!debugfs_create_file(#name, 0644, priv->dfs_dev_dir, \ 671 priv, &mwifiex_dfs_##name##_fops)) \ 672 return; \ 673} while (0); 674 675#define MWIFIEX_DFS_FILE_OPS(name) \ 676static const struct file_operations mwifiex_dfs_##name##_fops = { \ 677 .read = mwifiex_##name##_read, \ 678 .write = mwifiex_##name##_write, \ 679 .open = mwifiex_open_generic, \ 680}; 681 682#define MWIFIEX_DFS_FILE_READ_OPS(name) \ 683static const struct file_operations mwifiex_dfs_##name##_fops = { \ 684 .read = mwifiex_##name##_read, \ 685 .open = mwifiex_open_generic, \ 686}; 687 688#define MWIFIEX_DFS_FILE_WRITE_OPS(name) \ 689static const struct file_operations mwifiex_dfs_##name##_fops = { \ 690 .write = mwifiex_##name##_write, \ 691 .open = mwifiex_open_generic, \ 692}; 693 694 695MWIFIEX_DFS_FILE_READ_OPS(info); 696MWIFIEX_DFS_FILE_READ_OPS(debug); 697MWIFIEX_DFS_FILE_READ_OPS(getlog); 698MWIFIEX_DFS_FILE_OPS(regrdwr); 699MWIFIEX_DFS_FILE_OPS(rdeeprom); 700 701/* 702 * This function creates the debug FS directory structure and the files. 703 */ 704void 705mwifiex_dev_debugfs_init(struct mwifiex_private *priv) 706{ 707 if (!mwifiex_dfs_dir || !priv) 708 return; 709 710 priv->dfs_dev_dir = debugfs_create_dir(priv->netdev->name, 711 mwifiex_dfs_dir); 712 713 if (!priv->dfs_dev_dir) 714 return; 715 716 MWIFIEX_DFS_ADD_FILE(info); 717 MWIFIEX_DFS_ADD_FILE(debug); 718 MWIFIEX_DFS_ADD_FILE(getlog); 719 MWIFIEX_DFS_ADD_FILE(regrdwr); 720 MWIFIEX_DFS_ADD_FILE(rdeeprom); 721} 722 723/* 724 * This function removes the debug FS directory structure and the files. 725 */ 726void 727mwifiex_dev_debugfs_remove(struct mwifiex_private *priv) 728{ 729 if (!priv) 730 return; 731 732 debugfs_remove_recursive(priv->dfs_dev_dir); 733} 734 735/* 736 * This function creates the top level proc directory. 737 */ 738void 739mwifiex_debugfs_init(void) 740{ 741 if (!mwifiex_dfs_dir) 742 mwifiex_dfs_dir = debugfs_create_dir("mwifiex", NULL); 743} 744 745/* 746 * This function removes the top level proc directory. 747 */ 748void 749mwifiex_debugfs_remove(void) 750{ 751 if (mwifiex_dfs_dir) 752 debugfs_remove(mwifiex_dfs_dir); 753} 754