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