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