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