Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * NXP Wireless LAN device driver: debugfs
0004  *
0005  * Copyright 2011-2020 NXP
0006  */
0007 
0008 #include <linux/debugfs.h>
0009 
0010 #include "main.h"
0011 #include "11n.h"
0012 
0013 
0014 static struct dentry *mwifiex_dfs_dir;
0015 
0016 static char *bss_modes[] = {
0017     "UNSPECIFIED",
0018     "ADHOC",
0019     "STATION",
0020     "AP",
0021     "AP_VLAN",
0022     "WDS",
0023     "MONITOR",
0024     "MESH_POINT",
0025     "P2P_CLIENT",
0026     "P2P_GO",
0027     "P2P_DEVICE",
0028 };
0029 
0030 /*
0031  * Proc info file read handler.
0032  *
0033  * This function is called when the 'info' file is opened for reading.
0034  * It prints the following driver related information -
0035  *      - Driver name
0036  *      - Driver version
0037  *      - Driver extended version
0038  *      - Interface name
0039  *      - BSS mode
0040  *      - Media state (connected or disconnected)
0041  *      - MAC address
0042  *      - Total number of Tx bytes
0043  *      - Total number of Rx bytes
0044  *      - Total number of Tx packets
0045  *      - Total number of Rx packets
0046  *      - Total number of dropped Tx packets
0047  *      - Total number of dropped Rx packets
0048  *      - Total number of corrupted Tx packets
0049  *      - Total number of corrupted Rx packets
0050  *      - Carrier status (on or off)
0051  *      - Tx queue status (started or stopped)
0052  *
0053  * For STA mode drivers, it also prints the following extra -
0054  *      - ESSID
0055  *      - BSSID
0056  *      - Channel
0057  *      - Region code
0058  *      - Multicast count
0059  *      - Multicast addresses
0060  */
0061 static ssize_t
0062 mwifiex_info_read(struct file *file, char __user *ubuf,
0063           size_t count, loff_t *ppos)
0064 {
0065     struct mwifiex_private *priv =
0066         (struct mwifiex_private *) file->private_data;
0067     struct net_device *netdev = priv->netdev;
0068     struct netdev_hw_addr *ha;
0069     struct netdev_queue *txq;
0070     unsigned long page = get_zeroed_page(GFP_KERNEL);
0071     char *p = (char *) page, fmt[64];
0072     struct mwifiex_bss_info info;
0073     ssize_t ret;
0074     int i = 0;
0075 
0076     if (!p)
0077         return -ENOMEM;
0078 
0079     memset(&info, 0, sizeof(info));
0080     ret = mwifiex_get_bss_info(priv, &info);
0081     if (ret)
0082         goto free_and_exit;
0083 
0084     mwifiex_drv_get_driver_version(priv->adapter, fmt, sizeof(fmt) - 1);
0085 
0086     mwifiex_get_ver_ext(priv, 0);
0087 
0088     p += sprintf(p, "driver_name = " "\"mwifiex\"\n");
0089     p += sprintf(p, "driver_version = %s", fmt);
0090     p += sprintf(p, "\nverext = %s", priv->version_str);
0091     p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name);
0092 
0093     if (info.bss_mode >= ARRAY_SIZE(bss_modes))
0094         p += sprintf(p, "bss_mode=\"%d\"\n", info.bss_mode);
0095     else
0096         p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]);
0097 
0098     p += sprintf(p, "media_state=\"%s\"\n",
0099              (!priv->media_connected ? "Disconnected" : "Connected"));
0100     p += sprintf(p, "mac_address=\"%pM\"\n", netdev->dev_addr);
0101 
0102     if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) {
0103         p += sprintf(p, "multicast_count=\"%d\"\n",
0104                  netdev_mc_count(netdev));
0105         p += sprintf(p, "essid=\"%.*s\"\n", info.ssid.ssid_len,
0106                  info.ssid.ssid);
0107         p += sprintf(p, "bssid=\"%pM\"\n", info.bssid);
0108         p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan);
0109         p += sprintf(p, "country_code = \"%s\"\n", info.country_code);
0110         p += sprintf(p, "region_code=\"0x%x\"\n",
0111                  priv->adapter->region_code);
0112 
0113         netdev_for_each_mc_addr(ha, netdev)
0114             p += sprintf(p, "multicast_address[%d]=\"%pM\"\n",
0115                     i++, ha->addr);
0116     }
0117 
0118     p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes);
0119     p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes);
0120     p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets);
0121     p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets);
0122     p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped);
0123     p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped);
0124     p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors);
0125     p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors);
0126     p += sprintf(p, "carrier %s\n", ((netif_carrier_ok(priv->netdev))
0127                      ? "on" : "off"));
0128     p += sprintf(p, "tx queue");
0129     for (i = 0; i < netdev->num_tx_queues; i++) {
0130         txq = netdev_get_tx_queue(netdev, i);
0131         p += sprintf(p, " %d:%s", i, netif_tx_queue_stopped(txq) ?
0132                  "stopped" : "started");
0133     }
0134     p += sprintf(p, "\n");
0135 
0136     ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
0137                       (unsigned long) p - page);
0138 
0139 free_and_exit:
0140     free_page(page);
0141     return ret;
0142 }
0143 
0144 /*
0145  * Proc getlog file read handler.
0146  *
0147  * This function is called when the 'getlog' file is opened for reading
0148  * It prints the following log information -
0149  *      - Number of multicast Tx frames
0150  *      - Number of failed packets
0151  *      - Number of Tx retries
0152  *      - Number of multicast Tx retries
0153  *      - Number of duplicate frames
0154  *      - Number of RTS successes
0155  *      - Number of RTS failures
0156  *      - Number of ACK failures
0157  *      - Number of fragmented Rx frames
0158  *      - Number of multicast Rx frames
0159  *      - Number of FCS errors
0160  *      - Number of Tx frames
0161  *      - WEP ICV error counts
0162  *      - Number of received beacons
0163  *      - Number of missed beacons
0164  */
0165 static ssize_t
0166 mwifiex_getlog_read(struct file *file, char __user *ubuf,
0167             size_t count, loff_t *ppos)
0168 {
0169     struct mwifiex_private *priv =
0170         (struct mwifiex_private *) file->private_data;
0171     unsigned long page = get_zeroed_page(GFP_KERNEL);
0172     char *p = (char *) page;
0173     ssize_t ret;
0174     struct mwifiex_ds_get_stats stats;
0175 
0176     if (!p)
0177         return -ENOMEM;
0178 
0179     memset(&stats, 0, sizeof(stats));
0180     ret = mwifiex_get_stats_info(priv, &stats);
0181     if (ret)
0182         goto free_and_exit;
0183 
0184     p += sprintf(p, "\n"
0185              "mcasttxframe     %u\n"
0186              "failed           %u\n"
0187              "retry            %u\n"
0188              "multiretry       %u\n"
0189              "framedup         %u\n"
0190              "rtssuccess       %u\n"
0191              "rtsfailure       %u\n"
0192              "ackfailure       %u\n"
0193              "rxfrag           %u\n"
0194              "mcastrxframe     %u\n"
0195              "fcserror         %u\n"
0196              "txframe          %u\n"
0197              "wepicverrcnt-1   %u\n"
0198              "wepicverrcnt-2   %u\n"
0199              "wepicverrcnt-3   %u\n"
0200              "wepicverrcnt-4   %u\n"
0201              "bcn_rcv_cnt   %u\n"
0202              "bcn_miss_cnt   %u\n",
0203              stats.mcast_tx_frame,
0204              stats.failed,
0205              stats.retry,
0206              stats.multi_retry,
0207              stats.frame_dup,
0208              stats.rts_success,
0209              stats.rts_failure,
0210              stats.ack_failure,
0211              stats.rx_frag,
0212              stats.mcast_rx_frame,
0213              stats.fcs_error,
0214              stats.tx_frame,
0215              stats.wep_icv_error[0],
0216              stats.wep_icv_error[1],
0217              stats.wep_icv_error[2],
0218              stats.wep_icv_error[3],
0219              stats.bcn_rcv_cnt,
0220              stats.bcn_miss_cnt);
0221 
0222 
0223     ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
0224                       (unsigned long) p - page);
0225 
0226 free_and_exit:
0227     free_page(page);
0228     return ret;
0229 }
0230 
0231 /* Sysfs histogram file read handler.
0232  *
0233  * This function is called when the 'histogram' file is opened for reading
0234  * It prints the following histogram information -
0235  *      - Number of histogram samples
0236  *      - Receive packet number of each rx_rate
0237  *      - Receive packet number of each snr
0238  *      - Receive packet number of each nosie_flr
0239  *      - Receive packet number of each signal streath
0240  */
0241 static ssize_t
0242 mwifiex_histogram_read(struct file *file, char __user *ubuf,
0243                size_t count, loff_t *ppos)
0244 {
0245     struct mwifiex_private *priv =
0246         (struct mwifiex_private *)file->private_data;
0247     ssize_t ret;
0248     struct mwifiex_histogram_data *phist_data;
0249     int i, value;
0250     unsigned long page = get_zeroed_page(GFP_KERNEL);
0251     char *p = (char *)page;
0252 
0253     if (!p)
0254         return -ENOMEM;
0255 
0256     if (!priv || !priv->hist_data)
0257         return -EFAULT;
0258     phist_data = priv->hist_data;
0259 
0260     p += sprintf(p, "\n"
0261              "total samples = %d\n",
0262              atomic_read(&phist_data->num_samples));
0263 
0264     p += sprintf(p,
0265              "rx rates (in Mbps): 0=1M   1=2M 2=5.5M  3=11M   4=6M   5=9M  6=12M\n"
0266              "7=18M  8=24M  9=36M  10=48M  11=54M 12-27=MCS0-15(BW20) 28-43=MCS0-15(BW40)\n");
0267 
0268     if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) {
0269         p += sprintf(p,
0270                  "44-53=MCS0-9(VHT:BW20) 54-63=MCS0-9(VHT:BW40) 64-73=MCS0-9(VHT:BW80)\n\n");
0271     } else {
0272         p += sprintf(p, "\n");
0273     }
0274 
0275     for (i = 0; i < MWIFIEX_MAX_RX_RATES; i++) {
0276         value = atomic_read(&phist_data->rx_rate[i]);
0277         if (value)
0278             p += sprintf(p, "rx_rate[%02d] = %d\n", i, value);
0279     }
0280 
0281     if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) {
0282         for (i = MWIFIEX_MAX_RX_RATES; i < MWIFIEX_MAX_AC_RX_RATES;
0283              i++) {
0284             value = atomic_read(&phist_data->rx_rate[i]);
0285             if (value)
0286                 p += sprintf(p, "rx_rate[%02d] = %d\n",
0287                        i, value);
0288         }
0289     }
0290 
0291     for (i = 0; i < MWIFIEX_MAX_SNR; i++) {
0292         value =  atomic_read(&phist_data->snr[i]);
0293         if (value)
0294             p += sprintf(p, "snr[%02ddB] = %d\n", i, value);
0295     }
0296     for (i = 0; i < MWIFIEX_MAX_NOISE_FLR; i++) {
0297         value = atomic_read(&phist_data->noise_flr[i]);
0298         if (value)
0299             p += sprintf(p, "noise_flr[%02ddBm] = %d\n",
0300                 (int)(i-128), value);
0301     }
0302     for (i = 0; i < MWIFIEX_MAX_SIG_STRENGTH; i++) {
0303         value = atomic_read(&phist_data->sig_str[i]);
0304         if (value)
0305             p += sprintf(p, "sig_strength[-%02ddBm] = %d\n",
0306                 i, value);
0307     }
0308 
0309     ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page,
0310                       (unsigned long)p - page);
0311 
0312     return ret;
0313 }
0314 
0315 static ssize_t
0316 mwifiex_histogram_write(struct file *file, const char __user *ubuf,
0317             size_t count, loff_t *ppos)
0318 {
0319     struct mwifiex_private *priv = (void *)file->private_data;
0320 
0321     if (priv && priv->hist_data)
0322         mwifiex_hist_data_reset(priv);
0323     return 0;
0324 }
0325 
0326 static struct mwifiex_debug_info info;
0327 
0328 /*
0329  * Proc debug file read handler.
0330  *
0331  * This function is called when the 'debug' file is opened for reading
0332  * It prints the following log information -
0333  *      - Interrupt count
0334  *      - WMM AC VO packets count
0335  *      - WMM AC VI packets count
0336  *      - WMM AC BE packets count
0337  *      - WMM AC BK packets count
0338  *      - Maximum Tx buffer size
0339  *      - Tx buffer size
0340  *      - Current Tx buffer size
0341  *      - Power Save mode
0342  *      - Power Save state
0343  *      - Deep Sleep status
0344  *      - Device wakeup required status
0345  *      - Number of wakeup tries
0346  *      - Host Sleep configured status
0347  *      - Host Sleep activated status
0348  *      - Number of Tx timeouts
0349  *      - Number of command timeouts
0350  *      - Last timed out command ID
0351  *      - Last timed out command action
0352  *      - Last command ID
0353  *      - Last command action
0354  *      - Last command index
0355  *      - Last command response ID
0356  *      - Last command response index
0357  *      - Last event
0358  *      - Last event index
0359  *      - Number of host to card command failures
0360  *      - Number of sleep confirm command failures
0361  *      - Number of host to card data failure
0362  *      - Number of deauthentication events
0363  *      - Number of disassociation events
0364  *      - Number of link lost events
0365  *      - Number of deauthentication commands
0366  *      - Number of association success commands
0367  *      - Number of association failure commands
0368  *      - Number of commands sent
0369  *      - Number of data packets sent
0370  *      - Number of command responses received
0371  *      - Number of events received
0372  *      - Tx BA stream table (TID, RA)
0373  *      - Rx reorder table (TID, TA, Start window, Window size, Buffer)
0374  */
0375 static ssize_t
0376 mwifiex_debug_read(struct file *file, char __user *ubuf,
0377            size_t count, loff_t *ppos)
0378 {
0379     struct mwifiex_private *priv =
0380         (struct mwifiex_private *) file->private_data;
0381     unsigned long page = get_zeroed_page(GFP_KERNEL);
0382     char *p = (char *) page;
0383     ssize_t ret;
0384 
0385     if (!p)
0386         return -ENOMEM;
0387 
0388     ret = mwifiex_get_debug_info(priv, &info);
0389     if (ret)
0390         goto free_and_exit;
0391 
0392     p += mwifiex_debug_info_to_buffer(priv, p, &info);
0393 
0394     ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
0395                       (unsigned long) p - page);
0396 
0397 free_and_exit:
0398     free_page(page);
0399     return ret;
0400 }
0401 
0402 static u32 saved_reg_type, saved_reg_offset, saved_reg_value;
0403 
0404 /*
0405  * Proc regrdwr file write handler.
0406  *
0407  * This function is called when the 'regrdwr' file is opened for writing
0408  *
0409  * This function can be used to write to a register.
0410  */
0411 static ssize_t
0412 mwifiex_regrdwr_write(struct file *file,
0413               const char __user *ubuf, size_t count, loff_t *ppos)
0414 {
0415     char *buf;
0416     int ret;
0417     u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX;
0418 
0419     buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
0420     if (IS_ERR(buf))
0421         return PTR_ERR(buf);
0422 
0423     sscanf(buf, "%u %x %x", &reg_type, &reg_offset, &reg_value);
0424 
0425     if (reg_type == 0 || reg_offset == 0) {
0426         ret = -EINVAL;
0427         goto done;
0428     } else {
0429         saved_reg_type = reg_type;
0430         saved_reg_offset = reg_offset;
0431         saved_reg_value = reg_value;
0432         ret = count;
0433     }
0434 done:
0435     kfree(buf);
0436     return ret;
0437 }
0438 
0439 /*
0440  * Proc regrdwr file read handler.
0441  *
0442  * This function is called when the 'regrdwr' file is opened for reading
0443  *
0444  * This function can be used to read from a register.
0445  */
0446 static ssize_t
0447 mwifiex_regrdwr_read(struct file *file, char __user *ubuf,
0448              size_t count, loff_t *ppos)
0449 {
0450     struct mwifiex_private *priv =
0451         (struct mwifiex_private *) file->private_data;
0452     unsigned long addr = get_zeroed_page(GFP_KERNEL);
0453     char *buf = (char *) addr;
0454     int pos = 0, ret = 0;
0455     u32 reg_value;
0456 
0457     if (!buf)
0458         return -ENOMEM;
0459 
0460     if (!saved_reg_type) {
0461         /* No command has been given */
0462         pos += snprintf(buf, PAGE_SIZE, "0");
0463         goto done;
0464     }
0465     /* Set command has been given */
0466     if (saved_reg_value != UINT_MAX) {
0467         ret = mwifiex_reg_write(priv, saved_reg_type, saved_reg_offset,
0468                     saved_reg_value);
0469 
0470         pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n",
0471                 saved_reg_type, saved_reg_offset,
0472                 saved_reg_value);
0473 
0474         ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
0475 
0476         goto done;
0477     }
0478     /* Get command has been given */
0479     ret = mwifiex_reg_read(priv, saved_reg_type,
0480                    saved_reg_offset, &reg_value);
0481     if (ret) {
0482         ret = -EINVAL;
0483         goto done;
0484     }
0485 
0486     pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", saved_reg_type,
0487             saved_reg_offset, reg_value);
0488 
0489     ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
0490 
0491 done:
0492     free_page(addr);
0493     return ret;
0494 }
0495 
0496 /* Proc debug_mask file read handler.
0497  * This function is called when the 'debug_mask' file is opened for reading
0498  * This function can be used read driver debugging mask value.
0499  */
0500 static ssize_t
0501 mwifiex_debug_mask_read(struct file *file, char __user *ubuf,
0502             size_t count, loff_t *ppos)
0503 {
0504     struct mwifiex_private *priv =
0505         (struct mwifiex_private *)file->private_data;
0506     unsigned long page = get_zeroed_page(GFP_KERNEL);
0507     char *buf = (char *)page;
0508     size_t ret = 0;
0509     int pos = 0;
0510 
0511     if (!buf)
0512         return -ENOMEM;
0513 
0514     pos += snprintf(buf, PAGE_SIZE, "debug mask=0x%08x\n",
0515             priv->adapter->debug_mask);
0516     ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
0517 
0518     free_page(page);
0519     return ret;
0520 }
0521 
0522 /* Proc debug_mask file read handler.
0523  * This function is called when the 'debug_mask' file is opened for reading
0524  * This function can be used read driver debugging mask value.
0525  */
0526 static ssize_t
0527 mwifiex_debug_mask_write(struct file *file, const char __user *ubuf,
0528              size_t count, loff_t *ppos)
0529 {
0530     int ret;
0531     unsigned long debug_mask;
0532     struct mwifiex_private *priv = (void *)file->private_data;
0533     char *buf;
0534 
0535     buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
0536     if (IS_ERR(buf))
0537         return PTR_ERR(buf);
0538 
0539     if (kstrtoul(buf, 0, &debug_mask)) {
0540         ret = -EINVAL;
0541         goto done;
0542     }
0543 
0544     priv->adapter->debug_mask = debug_mask;
0545     ret = count;
0546 done:
0547     kfree(buf);
0548     return ret;
0549 }
0550 
0551 /* debugfs verext file write handler.
0552  * This function is called when the 'verext' file is opened for write
0553  */
0554 static ssize_t
0555 mwifiex_verext_write(struct file *file, const char __user *ubuf,
0556              size_t count, loff_t *ppos)
0557 {
0558     int ret;
0559     u32 versionstrsel;
0560     struct mwifiex_private *priv = (void *)file->private_data;
0561     char buf[16];
0562 
0563     memset(buf, 0, sizeof(buf));
0564 
0565     if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
0566         return -EFAULT;
0567 
0568     ret = kstrtou32(buf, 10, &versionstrsel);
0569     if (ret)
0570         return ret;
0571 
0572     priv->versionstrsel = versionstrsel;
0573 
0574     return count;
0575 }
0576 
0577 /* Proc verext file read handler.
0578  * This function is called when the 'verext' file is opened for reading
0579  * This function can be used read driver exteneed verion string.
0580  */
0581 static ssize_t
0582 mwifiex_verext_read(struct file *file, char __user *ubuf,
0583             size_t count, loff_t *ppos)
0584 {
0585     struct mwifiex_private *priv =
0586         (struct mwifiex_private *)file->private_data;
0587     char buf[256];
0588     int ret;
0589 
0590     mwifiex_get_ver_ext(priv, priv->versionstrsel);
0591     ret = snprintf(buf, sizeof(buf), "version string: %s\n",
0592                priv->version_str);
0593 
0594     return simple_read_from_buffer(ubuf, count, ppos, buf, ret);
0595 }
0596 
0597 /* Proc memrw file write handler.
0598  * This function is called when the 'memrw' file is opened for writing
0599  * This function can be used to write to a memory location.
0600  */
0601 static ssize_t
0602 mwifiex_memrw_write(struct file *file, const char __user *ubuf, size_t count,
0603             loff_t *ppos)
0604 {
0605     int ret;
0606     char cmd;
0607     struct mwifiex_ds_mem_rw mem_rw;
0608     u16 cmd_action;
0609     struct mwifiex_private *priv = (void *)file->private_data;
0610     char *buf;
0611 
0612     buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
0613     if (IS_ERR(buf))
0614         return PTR_ERR(buf);
0615 
0616     ret = sscanf(buf, "%c %x %x", &cmd, &mem_rw.addr, &mem_rw.value);
0617     if (ret != 3) {
0618         ret = -EINVAL;
0619         goto done;
0620     }
0621 
0622     if ((cmd == 'r') || (cmd == 'R')) {
0623         cmd_action = HostCmd_ACT_GEN_GET;
0624         mem_rw.value = 0;
0625     } else if ((cmd == 'w') || (cmd == 'W')) {
0626         cmd_action = HostCmd_ACT_GEN_SET;
0627     } else {
0628         ret = -EINVAL;
0629         goto done;
0630     }
0631 
0632     memcpy(&priv->mem_rw, &mem_rw, sizeof(mem_rw));
0633     if (mwifiex_send_cmd(priv, HostCmd_CMD_MEM_ACCESS, cmd_action, 0,
0634                  &mem_rw, true))
0635         ret = -1;
0636     else
0637         ret = count;
0638 
0639 done:
0640     kfree(buf);
0641     return ret;
0642 }
0643 
0644 /* Proc memrw file read handler.
0645  * This function is called when the 'memrw' file is opened for reading
0646  * This function can be used to read from a memory location.
0647  */
0648 static ssize_t
0649 mwifiex_memrw_read(struct file *file, char __user *ubuf,
0650            size_t count, loff_t *ppos)
0651 {
0652     struct mwifiex_private *priv = (void *)file->private_data;
0653     unsigned long addr = get_zeroed_page(GFP_KERNEL);
0654     char *buf = (char *)addr;
0655     int ret, pos = 0;
0656 
0657     if (!buf)
0658         return -ENOMEM;
0659 
0660     pos += snprintf(buf, PAGE_SIZE, "0x%x 0x%x\n", priv->mem_rw.addr,
0661             priv->mem_rw.value);
0662     ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
0663 
0664     free_page(addr);
0665     return ret;
0666 }
0667 
0668 static u32 saved_offset = -1, saved_bytes = -1;
0669 
0670 /*
0671  * Proc rdeeprom file write handler.
0672  *
0673  * This function is called when the 'rdeeprom' file is opened for writing
0674  *
0675  * This function can be used to write to a RDEEPROM location.
0676  */
0677 static ssize_t
0678 mwifiex_rdeeprom_write(struct file *file,
0679                const char __user *ubuf, size_t count, loff_t *ppos)
0680 {
0681     char *buf;
0682     int ret = 0;
0683     int offset = -1, bytes = -1;
0684 
0685     buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
0686     if (IS_ERR(buf))
0687         return PTR_ERR(buf);
0688 
0689     sscanf(buf, "%d %d", &offset, &bytes);
0690 
0691     if (offset == -1 || bytes == -1) {
0692         ret = -EINVAL;
0693         goto done;
0694     } else {
0695         saved_offset = offset;
0696         saved_bytes = bytes;
0697         ret = count;
0698     }
0699 done:
0700     kfree(buf);
0701     return ret;
0702 }
0703 
0704 /*
0705  * Proc rdeeprom read write handler.
0706  *
0707  * This function is called when the 'rdeeprom' file is opened for reading
0708  *
0709  * This function can be used to read from a RDEEPROM location.
0710  */
0711 static ssize_t
0712 mwifiex_rdeeprom_read(struct file *file, char __user *ubuf,
0713               size_t count, loff_t *ppos)
0714 {
0715     struct mwifiex_private *priv =
0716         (struct mwifiex_private *) file->private_data;
0717     unsigned long addr = get_zeroed_page(GFP_KERNEL);
0718     char *buf = (char *) addr;
0719     int pos, ret, i;
0720     u8 value[MAX_EEPROM_DATA];
0721 
0722     if (!buf)
0723         return -ENOMEM;
0724 
0725     if (saved_offset == -1) {
0726         /* No command has been given */
0727         pos = snprintf(buf, PAGE_SIZE, "0");
0728         goto done;
0729     }
0730 
0731     /* Get command has been given */
0732     ret = mwifiex_eeprom_read(priv, (u16) saved_offset,
0733                   (u16) saved_bytes, value);
0734     if (ret) {
0735         ret = -EINVAL;
0736         goto out_free;
0737     }
0738 
0739     pos = snprintf(buf, PAGE_SIZE, "%d %d ", saved_offset, saved_bytes);
0740 
0741     for (i = 0; i < saved_bytes; i++)
0742         pos += scnprintf(buf + pos, PAGE_SIZE - pos, "%d ", value[i]);
0743 
0744 done:
0745     ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
0746 out_free:
0747     free_page(addr);
0748     return ret;
0749 }
0750 
0751 /* Proc hscfg file write handler
0752  * This function can be used to configure the host sleep parameters.
0753  */
0754 static ssize_t
0755 mwifiex_hscfg_write(struct file *file, const char __user *ubuf,
0756             size_t count, loff_t *ppos)
0757 {
0758     struct mwifiex_private *priv = (void *)file->private_data;
0759     char *buf;
0760     int ret, arg_num;
0761     struct mwifiex_ds_hs_cfg hscfg;
0762     int conditions = HS_CFG_COND_DEF;
0763     u32 gpio = HS_CFG_GPIO_DEF, gap = HS_CFG_GAP_DEF;
0764 
0765     buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1)));
0766     if (IS_ERR(buf))
0767         return PTR_ERR(buf);
0768 
0769     arg_num = sscanf(buf, "%d %x %x", &conditions, &gpio, &gap);
0770 
0771     memset(&hscfg, 0, sizeof(struct mwifiex_ds_hs_cfg));
0772 
0773     if (arg_num > 3) {
0774         mwifiex_dbg(priv->adapter, ERROR,
0775                 "Too many arguments\n");
0776         ret = -EINVAL;
0777         goto done;
0778     }
0779 
0780     if (arg_num >= 1 && arg_num < 3)
0781         mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_GET,
0782                       MWIFIEX_SYNC_CMD, &hscfg);
0783 
0784     if (arg_num) {
0785         if (conditions == HS_CFG_CANCEL) {
0786             mwifiex_cancel_hs(priv, MWIFIEX_ASYNC_CMD);
0787             ret = count;
0788             goto done;
0789         }
0790         hscfg.conditions = conditions;
0791     }
0792     if (arg_num >= 2)
0793         hscfg.gpio = gpio;
0794     if (arg_num == 3)
0795         hscfg.gap = gap;
0796 
0797     hscfg.is_invoke_hostcmd = false;
0798     mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,
0799                   MWIFIEX_SYNC_CMD, &hscfg);
0800 
0801     mwifiex_enable_hs(priv->adapter);
0802     clear_bit(MWIFIEX_IS_HS_ENABLING, &priv->adapter->work_flags);
0803     ret = count;
0804 done:
0805     kfree(buf);
0806     return ret;
0807 }
0808 
0809 /* Proc hscfg file read handler
0810  * This function can be used to read host sleep configuration
0811  * parameters from driver.
0812  */
0813 static ssize_t
0814 mwifiex_hscfg_read(struct file *file, char __user *ubuf,
0815            size_t count, loff_t *ppos)
0816 {
0817     struct mwifiex_private *priv = (void *)file->private_data;
0818     unsigned long addr = get_zeroed_page(GFP_KERNEL);
0819     char *buf = (char *)addr;
0820     int pos, ret;
0821     struct mwifiex_ds_hs_cfg hscfg;
0822 
0823     if (!buf)
0824         return -ENOMEM;
0825 
0826     mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_GET,
0827                   MWIFIEX_SYNC_CMD, &hscfg);
0828 
0829     pos = snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", hscfg.conditions,
0830                hscfg.gpio, hscfg.gap);
0831 
0832     ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos);
0833 
0834     free_page(addr);
0835     return ret;
0836 }
0837 
0838 static ssize_t
0839 mwifiex_timeshare_coex_read(struct file *file, char __user *ubuf,
0840                 size_t count, loff_t *ppos)
0841 {
0842     struct mwifiex_private *priv = file->private_data;
0843     char buf[3];
0844     bool timeshare_coex;
0845     int ret;
0846     unsigned int len;
0847 
0848     if (priv->adapter->fw_api_ver != MWIFIEX_FW_V15)
0849         return -EOPNOTSUPP;
0850 
0851     ret = mwifiex_send_cmd(priv, HostCmd_CMD_ROBUST_COEX,
0852                    HostCmd_ACT_GEN_GET, 0, &timeshare_coex, true);
0853     if (ret)
0854         return ret;
0855 
0856     len = sprintf(buf, "%d\n", timeshare_coex);
0857     return simple_read_from_buffer(ubuf, count, ppos, buf, len);
0858 }
0859 
0860 static ssize_t
0861 mwifiex_timeshare_coex_write(struct file *file, const char __user *ubuf,
0862                  size_t count, loff_t *ppos)
0863 {
0864     bool timeshare_coex;
0865     struct mwifiex_private *priv = file->private_data;
0866     char kbuf[16];
0867     int ret;
0868 
0869     if (priv->adapter->fw_api_ver != MWIFIEX_FW_V15)
0870         return -EOPNOTSUPP;
0871 
0872     memset(kbuf, 0, sizeof(kbuf));
0873 
0874     if (copy_from_user(&kbuf, ubuf, min_t(size_t, sizeof(kbuf) - 1, count)))
0875         return -EFAULT;
0876 
0877     if (strtobool(kbuf, &timeshare_coex))
0878         return -EINVAL;
0879 
0880     ret = mwifiex_send_cmd(priv, HostCmd_CMD_ROBUST_COEX,
0881                    HostCmd_ACT_GEN_SET, 0, &timeshare_coex, true);
0882     if (ret)
0883         return ret;
0884     else
0885         return count;
0886 }
0887 
0888 static ssize_t
0889 mwifiex_reset_write(struct file *file,
0890             const char __user *ubuf, size_t count, loff_t *ppos)
0891 {
0892     struct mwifiex_private *priv = file->private_data;
0893     struct mwifiex_adapter *adapter = priv->adapter;
0894     bool result;
0895     int rc;
0896 
0897     rc = kstrtobool_from_user(ubuf, count, &result);
0898     if (rc)
0899         return rc;
0900 
0901     if (!result)
0902         return -EINVAL;
0903 
0904     if (adapter->if_ops.card_reset) {
0905         dev_info(adapter->dev, "Resetting per request\n");
0906         adapter->if_ops.card_reset(adapter);
0907     }
0908 
0909     return count;
0910 }
0911 
0912 #define MWIFIEX_DFS_ADD_FILE(name) do {                                 \
0913     debugfs_create_file(#name, 0644, priv->dfs_dev_dir, priv,       \
0914                 &mwifiex_dfs_##name##_fops);                \
0915 } while (0);
0916 
0917 #define MWIFIEX_DFS_FILE_OPS(name)                                      \
0918 static const struct file_operations mwifiex_dfs_##name##_fops = {       \
0919     .read = mwifiex_##name##_read,                                  \
0920     .write = mwifiex_##name##_write,                                \
0921     .open = simple_open,                                            \
0922 };
0923 
0924 #define MWIFIEX_DFS_FILE_READ_OPS(name)                                 \
0925 static const struct file_operations mwifiex_dfs_##name##_fops = {       \
0926     .read = mwifiex_##name##_read,                                  \
0927     .open = simple_open,                                            \
0928 };
0929 
0930 #define MWIFIEX_DFS_FILE_WRITE_OPS(name)                                \
0931 static const struct file_operations mwifiex_dfs_##name##_fops = {       \
0932     .write = mwifiex_##name##_write,                                \
0933     .open = simple_open,                                            \
0934 };
0935 
0936 
0937 MWIFIEX_DFS_FILE_READ_OPS(info);
0938 MWIFIEX_DFS_FILE_READ_OPS(debug);
0939 MWIFIEX_DFS_FILE_READ_OPS(getlog);
0940 MWIFIEX_DFS_FILE_OPS(regrdwr);
0941 MWIFIEX_DFS_FILE_OPS(rdeeprom);
0942 MWIFIEX_DFS_FILE_OPS(memrw);
0943 MWIFIEX_DFS_FILE_OPS(hscfg);
0944 MWIFIEX_DFS_FILE_OPS(histogram);
0945 MWIFIEX_DFS_FILE_OPS(debug_mask);
0946 MWIFIEX_DFS_FILE_OPS(timeshare_coex);
0947 MWIFIEX_DFS_FILE_WRITE_OPS(reset);
0948 MWIFIEX_DFS_FILE_OPS(verext);
0949 
0950 /*
0951  * This function creates the debug FS directory structure and the files.
0952  */
0953 void
0954 mwifiex_dev_debugfs_init(struct mwifiex_private *priv)
0955 {
0956     if (!mwifiex_dfs_dir || !priv)
0957         return;
0958 
0959     priv->dfs_dev_dir = debugfs_create_dir(priv->netdev->name,
0960                            mwifiex_dfs_dir);
0961 
0962     if (!priv->dfs_dev_dir)
0963         return;
0964 
0965     MWIFIEX_DFS_ADD_FILE(info);
0966     MWIFIEX_DFS_ADD_FILE(debug);
0967     MWIFIEX_DFS_ADD_FILE(getlog);
0968     MWIFIEX_DFS_ADD_FILE(regrdwr);
0969     MWIFIEX_DFS_ADD_FILE(rdeeprom);
0970 
0971     MWIFIEX_DFS_ADD_FILE(memrw);
0972     MWIFIEX_DFS_ADD_FILE(hscfg);
0973     MWIFIEX_DFS_ADD_FILE(histogram);
0974     MWIFIEX_DFS_ADD_FILE(debug_mask);
0975     MWIFIEX_DFS_ADD_FILE(timeshare_coex);
0976     MWIFIEX_DFS_ADD_FILE(reset);
0977     MWIFIEX_DFS_ADD_FILE(verext);
0978 }
0979 
0980 /*
0981  * This function removes the debug FS directory structure and the files.
0982  */
0983 void
0984 mwifiex_dev_debugfs_remove(struct mwifiex_private *priv)
0985 {
0986     if (!priv)
0987         return;
0988 
0989     debugfs_remove_recursive(priv->dfs_dev_dir);
0990 }
0991 
0992 /*
0993  * This function creates the top level proc directory.
0994  */
0995 void
0996 mwifiex_debugfs_init(void)
0997 {
0998     if (!mwifiex_dfs_dir)
0999         mwifiex_dfs_dir = debugfs_create_dir("mwifiex", NULL);
1000 }
1001 
1002 /*
1003  * This function removes the top level proc directory.
1004  */
1005 void
1006 mwifiex_debugfs_remove(void)
1007 {
1008     debugfs_remove(mwifiex_dfs_dir);
1009 }