162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * NXP Wireless LAN device driver: debugfs 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2011-2020 NXP 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/debugfs.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "main.h" 1162306a36Sopenharmony_ci#include "11n.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic struct dentry *mwifiex_dfs_dir; 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic char *bss_modes[] = { 1762306a36Sopenharmony_ci "UNSPECIFIED", 1862306a36Sopenharmony_ci "ADHOC", 1962306a36Sopenharmony_ci "STATION", 2062306a36Sopenharmony_ci "AP", 2162306a36Sopenharmony_ci "AP_VLAN", 2262306a36Sopenharmony_ci "WDS", 2362306a36Sopenharmony_ci "MONITOR", 2462306a36Sopenharmony_ci "MESH_POINT", 2562306a36Sopenharmony_ci "P2P_CLIENT", 2662306a36Sopenharmony_ci "P2P_GO", 2762306a36Sopenharmony_ci "P2P_DEVICE", 2862306a36Sopenharmony_ci}; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* 3162306a36Sopenharmony_ci * Proc info file read handler. 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * This function is called when the 'info' file is opened for reading. 3462306a36Sopenharmony_ci * It prints the following driver related information - 3562306a36Sopenharmony_ci * - Driver name 3662306a36Sopenharmony_ci * - Driver version 3762306a36Sopenharmony_ci * - Driver extended version 3862306a36Sopenharmony_ci * - Interface name 3962306a36Sopenharmony_ci * - BSS mode 4062306a36Sopenharmony_ci * - Media state (connected or disconnected) 4162306a36Sopenharmony_ci * - MAC address 4262306a36Sopenharmony_ci * - Total number of Tx bytes 4362306a36Sopenharmony_ci * - Total number of Rx bytes 4462306a36Sopenharmony_ci * - Total number of Tx packets 4562306a36Sopenharmony_ci * - Total number of Rx packets 4662306a36Sopenharmony_ci * - Total number of dropped Tx packets 4762306a36Sopenharmony_ci * - Total number of dropped Rx packets 4862306a36Sopenharmony_ci * - Total number of corrupted Tx packets 4962306a36Sopenharmony_ci * - Total number of corrupted Rx packets 5062306a36Sopenharmony_ci * - Carrier status (on or off) 5162306a36Sopenharmony_ci * - Tx queue status (started or stopped) 5262306a36Sopenharmony_ci * 5362306a36Sopenharmony_ci * For STA mode drivers, it also prints the following extra - 5462306a36Sopenharmony_ci * - ESSID 5562306a36Sopenharmony_ci * - BSSID 5662306a36Sopenharmony_ci * - Channel 5762306a36Sopenharmony_ci * - Region code 5862306a36Sopenharmony_ci * - Multicast count 5962306a36Sopenharmony_ci * - Multicast addresses 6062306a36Sopenharmony_ci */ 6162306a36Sopenharmony_cistatic ssize_t 6262306a36Sopenharmony_cimwifiex_info_read(struct file *file, char __user *ubuf, 6362306a36Sopenharmony_ci size_t count, loff_t *ppos) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci struct mwifiex_private *priv = 6662306a36Sopenharmony_ci (struct mwifiex_private *) file->private_data; 6762306a36Sopenharmony_ci struct net_device *netdev = priv->netdev; 6862306a36Sopenharmony_ci struct netdev_hw_addr *ha; 6962306a36Sopenharmony_ci struct netdev_queue *txq; 7062306a36Sopenharmony_ci unsigned long page = get_zeroed_page(GFP_KERNEL); 7162306a36Sopenharmony_ci char *p = (char *) page, fmt[64]; 7262306a36Sopenharmony_ci struct mwifiex_bss_info info; 7362306a36Sopenharmony_ci ssize_t ret; 7462306a36Sopenharmony_ci int i = 0; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci if (!p) 7762306a36Sopenharmony_ci return -ENOMEM; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci memset(&info, 0, sizeof(info)); 8062306a36Sopenharmony_ci ret = mwifiex_get_bss_info(priv, &info); 8162306a36Sopenharmony_ci if (ret) 8262306a36Sopenharmony_ci goto free_and_exit; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci mwifiex_drv_get_driver_version(priv->adapter, fmt, sizeof(fmt) - 1); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci mwifiex_get_ver_ext(priv, 0); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci p += sprintf(p, "driver_name = " "\"mwifiex\"\n"); 8962306a36Sopenharmony_ci p += sprintf(p, "driver_version = %s", fmt); 9062306a36Sopenharmony_ci p += sprintf(p, "\nverext = %s", priv->version_str); 9162306a36Sopenharmony_ci p += sprintf(p, "\ninterface_name=\"%s\"\n", netdev->name); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (info.bss_mode >= ARRAY_SIZE(bss_modes)) 9462306a36Sopenharmony_ci p += sprintf(p, "bss_mode=\"%d\"\n", info.bss_mode); 9562306a36Sopenharmony_ci else 9662306a36Sopenharmony_ci p += sprintf(p, "bss_mode=\"%s\"\n", bss_modes[info.bss_mode]); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci p += sprintf(p, "media_state=\"%s\"\n", 9962306a36Sopenharmony_ci (!priv->media_connected ? "Disconnected" : "Connected")); 10062306a36Sopenharmony_ci p += sprintf(p, "mac_address=\"%pM\"\n", netdev->dev_addr); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) { 10362306a36Sopenharmony_ci p += sprintf(p, "multicast_count=\"%d\"\n", 10462306a36Sopenharmony_ci netdev_mc_count(netdev)); 10562306a36Sopenharmony_ci p += sprintf(p, "essid=\"%.*s\"\n", info.ssid.ssid_len, 10662306a36Sopenharmony_ci info.ssid.ssid); 10762306a36Sopenharmony_ci p += sprintf(p, "bssid=\"%pM\"\n", info.bssid); 10862306a36Sopenharmony_ci p += sprintf(p, "channel=\"%d\"\n", (int) info.bss_chan); 10962306a36Sopenharmony_ci p += sprintf(p, "country_code = \"%s\"\n", info.country_code); 11062306a36Sopenharmony_ci p += sprintf(p, "region_code=\"0x%x\"\n", 11162306a36Sopenharmony_ci priv->adapter->region_code); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci netdev_for_each_mc_addr(ha, netdev) 11462306a36Sopenharmony_ci p += sprintf(p, "multicast_address[%d]=\"%pM\"\n", 11562306a36Sopenharmony_ci i++, ha->addr); 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci p += sprintf(p, "num_tx_bytes = %lu\n", priv->stats.tx_bytes); 11962306a36Sopenharmony_ci p += sprintf(p, "num_rx_bytes = %lu\n", priv->stats.rx_bytes); 12062306a36Sopenharmony_ci p += sprintf(p, "num_tx_pkts = %lu\n", priv->stats.tx_packets); 12162306a36Sopenharmony_ci p += sprintf(p, "num_rx_pkts = %lu\n", priv->stats.rx_packets); 12262306a36Sopenharmony_ci p += sprintf(p, "num_tx_pkts_dropped = %lu\n", priv->stats.tx_dropped); 12362306a36Sopenharmony_ci p += sprintf(p, "num_rx_pkts_dropped = %lu\n", priv->stats.rx_dropped); 12462306a36Sopenharmony_ci p += sprintf(p, "num_tx_pkts_err = %lu\n", priv->stats.tx_errors); 12562306a36Sopenharmony_ci p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors); 12662306a36Sopenharmony_ci p += sprintf(p, "carrier %s\n", ((netif_carrier_ok(priv->netdev)) 12762306a36Sopenharmony_ci ? "on" : "off")); 12862306a36Sopenharmony_ci p += sprintf(p, "tx queue"); 12962306a36Sopenharmony_ci for (i = 0; i < netdev->num_tx_queues; i++) { 13062306a36Sopenharmony_ci txq = netdev_get_tx_queue(netdev, i); 13162306a36Sopenharmony_ci p += sprintf(p, " %d:%s", i, netif_tx_queue_stopped(txq) ? 13262306a36Sopenharmony_ci "stopped" : "started"); 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci p += sprintf(p, "\n"); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, 13762306a36Sopenharmony_ci (unsigned long) p - page); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cifree_and_exit: 14062306a36Sopenharmony_ci free_page(page); 14162306a36Sopenharmony_ci return ret; 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci/* 14562306a36Sopenharmony_ci * Proc getlog file read handler. 14662306a36Sopenharmony_ci * 14762306a36Sopenharmony_ci * This function is called when the 'getlog' file is opened for reading 14862306a36Sopenharmony_ci * It prints the following log information - 14962306a36Sopenharmony_ci * - Number of multicast Tx frames 15062306a36Sopenharmony_ci * - Number of failed packets 15162306a36Sopenharmony_ci * - Number of Tx retries 15262306a36Sopenharmony_ci * - Number of multicast Tx retries 15362306a36Sopenharmony_ci * - Number of duplicate frames 15462306a36Sopenharmony_ci * - Number of RTS successes 15562306a36Sopenharmony_ci * - Number of RTS failures 15662306a36Sopenharmony_ci * - Number of ACK failures 15762306a36Sopenharmony_ci * - Number of fragmented Rx frames 15862306a36Sopenharmony_ci * - Number of multicast Rx frames 15962306a36Sopenharmony_ci * - Number of FCS errors 16062306a36Sopenharmony_ci * - Number of Tx frames 16162306a36Sopenharmony_ci * - WEP ICV error counts 16262306a36Sopenharmony_ci * - Number of received beacons 16362306a36Sopenharmony_ci * - Number of missed beacons 16462306a36Sopenharmony_ci */ 16562306a36Sopenharmony_cistatic ssize_t 16662306a36Sopenharmony_cimwifiex_getlog_read(struct file *file, char __user *ubuf, 16762306a36Sopenharmony_ci size_t count, loff_t *ppos) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci struct mwifiex_private *priv = 17062306a36Sopenharmony_ci (struct mwifiex_private *) file->private_data; 17162306a36Sopenharmony_ci unsigned long page = get_zeroed_page(GFP_KERNEL); 17262306a36Sopenharmony_ci char *p = (char *) page; 17362306a36Sopenharmony_ci ssize_t ret; 17462306a36Sopenharmony_ci struct mwifiex_ds_get_stats stats; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci if (!p) 17762306a36Sopenharmony_ci return -ENOMEM; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci memset(&stats, 0, sizeof(stats)); 18062306a36Sopenharmony_ci ret = mwifiex_get_stats_info(priv, &stats); 18162306a36Sopenharmony_ci if (ret) 18262306a36Sopenharmony_ci goto free_and_exit; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci p += sprintf(p, "\n" 18562306a36Sopenharmony_ci "mcasttxframe %u\n" 18662306a36Sopenharmony_ci "failed %u\n" 18762306a36Sopenharmony_ci "retry %u\n" 18862306a36Sopenharmony_ci "multiretry %u\n" 18962306a36Sopenharmony_ci "framedup %u\n" 19062306a36Sopenharmony_ci "rtssuccess %u\n" 19162306a36Sopenharmony_ci "rtsfailure %u\n" 19262306a36Sopenharmony_ci "ackfailure %u\n" 19362306a36Sopenharmony_ci "rxfrag %u\n" 19462306a36Sopenharmony_ci "mcastrxframe %u\n" 19562306a36Sopenharmony_ci "fcserror %u\n" 19662306a36Sopenharmony_ci "txframe %u\n" 19762306a36Sopenharmony_ci "wepicverrcnt-1 %u\n" 19862306a36Sopenharmony_ci "wepicverrcnt-2 %u\n" 19962306a36Sopenharmony_ci "wepicverrcnt-3 %u\n" 20062306a36Sopenharmony_ci "wepicverrcnt-4 %u\n" 20162306a36Sopenharmony_ci "bcn_rcv_cnt %u\n" 20262306a36Sopenharmony_ci "bcn_miss_cnt %u\n", 20362306a36Sopenharmony_ci stats.mcast_tx_frame, 20462306a36Sopenharmony_ci stats.failed, 20562306a36Sopenharmony_ci stats.retry, 20662306a36Sopenharmony_ci stats.multi_retry, 20762306a36Sopenharmony_ci stats.frame_dup, 20862306a36Sopenharmony_ci stats.rts_success, 20962306a36Sopenharmony_ci stats.rts_failure, 21062306a36Sopenharmony_ci stats.ack_failure, 21162306a36Sopenharmony_ci stats.rx_frag, 21262306a36Sopenharmony_ci stats.mcast_rx_frame, 21362306a36Sopenharmony_ci stats.fcs_error, 21462306a36Sopenharmony_ci stats.tx_frame, 21562306a36Sopenharmony_ci stats.wep_icv_error[0], 21662306a36Sopenharmony_ci stats.wep_icv_error[1], 21762306a36Sopenharmony_ci stats.wep_icv_error[2], 21862306a36Sopenharmony_ci stats.wep_icv_error[3], 21962306a36Sopenharmony_ci stats.bcn_rcv_cnt, 22062306a36Sopenharmony_ci stats.bcn_miss_cnt); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, 22462306a36Sopenharmony_ci (unsigned long) p - page); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cifree_and_exit: 22762306a36Sopenharmony_ci free_page(page); 22862306a36Sopenharmony_ci return ret; 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci/* Sysfs histogram file read handler. 23262306a36Sopenharmony_ci * 23362306a36Sopenharmony_ci * This function is called when the 'histogram' file is opened for reading 23462306a36Sopenharmony_ci * It prints the following histogram information - 23562306a36Sopenharmony_ci * - Number of histogram samples 23662306a36Sopenharmony_ci * - Receive packet number of each rx_rate 23762306a36Sopenharmony_ci * - Receive packet number of each snr 23862306a36Sopenharmony_ci * - Receive packet number of each nosie_flr 23962306a36Sopenharmony_ci * - Receive packet number of each signal streath 24062306a36Sopenharmony_ci */ 24162306a36Sopenharmony_cistatic ssize_t 24262306a36Sopenharmony_cimwifiex_histogram_read(struct file *file, char __user *ubuf, 24362306a36Sopenharmony_ci size_t count, loff_t *ppos) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci struct mwifiex_private *priv = 24662306a36Sopenharmony_ci (struct mwifiex_private *)file->private_data; 24762306a36Sopenharmony_ci ssize_t ret; 24862306a36Sopenharmony_ci struct mwifiex_histogram_data *phist_data; 24962306a36Sopenharmony_ci int i, value; 25062306a36Sopenharmony_ci unsigned long page = get_zeroed_page(GFP_KERNEL); 25162306a36Sopenharmony_ci char *p = (char *)page; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci if (!p) 25462306a36Sopenharmony_ci return -ENOMEM; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (!priv || !priv->hist_data) { 25762306a36Sopenharmony_ci ret = -EFAULT; 25862306a36Sopenharmony_ci goto free_and_exit; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci phist_data = priv->hist_data; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci p += sprintf(p, "\n" 26462306a36Sopenharmony_ci "total samples = %d\n", 26562306a36Sopenharmony_ci atomic_read(&phist_data->num_samples)); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci p += sprintf(p, 26862306a36Sopenharmony_ci "rx rates (in Mbps): 0=1M 1=2M 2=5.5M 3=11M 4=6M 5=9M 6=12M\n" 26962306a36Sopenharmony_ci "7=18M 8=24M 9=36M 10=48M 11=54M 12-27=MCS0-15(BW20) 28-43=MCS0-15(BW40)\n"); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) { 27262306a36Sopenharmony_ci p += sprintf(p, 27362306a36Sopenharmony_ci "44-53=MCS0-9(VHT:BW20) 54-63=MCS0-9(VHT:BW40) 64-73=MCS0-9(VHT:BW80)\n\n"); 27462306a36Sopenharmony_ci } else { 27562306a36Sopenharmony_ci p += sprintf(p, "\n"); 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci for (i = 0; i < MWIFIEX_MAX_RX_RATES; i++) { 27962306a36Sopenharmony_ci value = atomic_read(&phist_data->rx_rate[i]); 28062306a36Sopenharmony_ci if (value) 28162306a36Sopenharmony_ci p += sprintf(p, "rx_rate[%02d] = %d\n", i, value); 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) { 28562306a36Sopenharmony_ci for (i = MWIFIEX_MAX_RX_RATES; i < MWIFIEX_MAX_AC_RX_RATES; 28662306a36Sopenharmony_ci i++) { 28762306a36Sopenharmony_ci value = atomic_read(&phist_data->rx_rate[i]); 28862306a36Sopenharmony_ci if (value) 28962306a36Sopenharmony_ci p += sprintf(p, "rx_rate[%02d] = %d\n", 29062306a36Sopenharmony_ci i, value); 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci for (i = 0; i < MWIFIEX_MAX_SNR; i++) { 29562306a36Sopenharmony_ci value = atomic_read(&phist_data->snr[i]); 29662306a36Sopenharmony_ci if (value) 29762306a36Sopenharmony_ci p += sprintf(p, "snr[%02ddB] = %d\n", i, value); 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci for (i = 0; i < MWIFIEX_MAX_NOISE_FLR; i++) { 30062306a36Sopenharmony_ci value = atomic_read(&phist_data->noise_flr[i]); 30162306a36Sopenharmony_ci if (value) 30262306a36Sopenharmony_ci p += sprintf(p, "noise_flr[%02ddBm] = %d\n", 30362306a36Sopenharmony_ci (int)(i-128), value); 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci for (i = 0; i < MWIFIEX_MAX_SIG_STRENGTH; i++) { 30662306a36Sopenharmony_ci value = atomic_read(&phist_data->sig_str[i]); 30762306a36Sopenharmony_ci if (value) 30862306a36Sopenharmony_ci p += sprintf(p, "sig_strength[-%02ddBm] = %d\n", 30962306a36Sopenharmony_ci i, value); 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page, 31362306a36Sopenharmony_ci (unsigned long)p - page); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cifree_and_exit: 31662306a36Sopenharmony_ci free_page(page); 31762306a36Sopenharmony_ci return ret; 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_cistatic ssize_t 32162306a36Sopenharmony_cimwifiex_histogram_write(struct file *file, const char __user *ubuf, 32262306a36Sopenharmony_ci size_t count, loff_t *ppos) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci struct mwifiex_private *priv = (void *)file->private_data; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (priv && priv->hist_data) 32762306a36Sopenharmony_ci mwifiex_hist_data_reset(priv); 32862306a36Sopenharmony_ci return 0; 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic struct mwifiex_debug_info info; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci/* 33462306a36Sopenharmony_ci * Proc debug file read handler. 33562306a36Sopenharmony_ci * 33662306a36Sopenharmony_ci * This function is called when the 'debug' file is opened for reading 33762306a36Sopenharmony_ci * It prints the following log information - 33862306a36Sopenharmony_ci * - Interrupt count 33962306a36Sopenharmony_ci * - WMM AC VO packets count 34062306a36Sopenharmony_ci * - WMM AC VI packets count 34162306a36Sopenharmony_ci * - WMM AC BE packets count 34262306a36Sopenharmony_ci * - WMM AC BK packets count 34362306a36Sopenharmony_ci * - Maximum Tx buffer size 34462306a36Sopenharmony_ci * - Tx buffer size 34562306a36Sopenharmony_ci * - Current Tx buffer size 34662306a36Sopenharmony_ci * - Power Save mode 34762306a36Sopenharmony_ci * - Power Save state 34862306a36Sopenharmony_ci * - Deep Sleep status 34962306a36Sopenharmony_ci * - Device wakeup required status 35062306a36Sopenharmony_ci * - Number of wakeup tries 35162306a36Sopenharmony_ci * - Host Sleep configured status 35262306a36Sopenharmony_ci * - Host Sleep activated status 35362306a36Sopenharmony_ci * - Number of Tx timeouts 35462306a36Sopenharmony_ci * - Number of command timeouts 35562306a36Sopenharmony_ci * - Last timed out command ID 35662306a36Sopenharmony_ci * - Last timed out command action 35762306a36Sopenharmony_ci * - Last command ID 35862306a36Sopenharmony_ci * - Last command action 35962306a36Sopenharmony_ci * - Last command index 36062306a36Sopenharmony_ci * - Last command response ID 36162306a36Sopenharmony_ci * - Last command response index 36262306a36Sopenharmony_ci * - Last event 36362306a36Sopenharmony_ci * - Last event index 36462306a36Sopenharmony_ci * - Number of host to card command failures 36562306a36Sopenharmony_ci * - Number of sleep confirm command failures 36662306a36Sopenharmony_ci * - Number of host to card data failure 36762306a36Sopenharmony_ci * - Number of deauthentication events 36862306a36Sopenharmony_ci * - Number of disassociation events 36962306a36Sopenharmony_ci * - Number of link lost events 37062306a36Sopenharmony_ci * - Number of deauthentication commands 37162306a36Sopenharmony_ci * - Number of association success commands 37262306a36Sopenharmony_ci * - Number of association failure commands 37362306a36Sopenharmony_ci * - Number of commands sent 37462306a36Sopenharmony_ci * - Number of data packets sent 37562306a36Sopenharmony_ci * - Number of command responses received 37662306a36Sopenharmony_ci * - Number of events received 37762306a36Sopenharmony_ci * - Tx BA stream table (TID, RA) 37862306a36Sopenharmony_ci * - Rx reorder table (TID, TA, Start window, Window size, Buffer) 37962306a36Sopenharmony_ci */ 38062306a36Sopenharmony_cistatic ssize_t 38162306a36Sopenharmony_cimwifiex_debug_read(struct file *file, char __user *ubuf, 38262306a36Sopenharmony_ci size_t count, loff_t *ppos) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci struct mwifiex_private *priv = 38562306a36Sopenharmony_ci (struct mwifiex_private *) file->private_data; 38662306a36Sopenharmony_ci unsigned long page = get_zeroed_page(GFP_KERNEL); 38762306a36Sopenharmony_ci char *p = (char *) page; 38862306a36Sopenharmony_ci ssize_t ret; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci if (!p) 39162306a36Sopenharmony_ci return -ENOMEM; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci ret = mwifiex_get_debug_info(priv, &info); 39462306a36Sopenharmony_ci if (ret) 39562306a36Sopenharmony_ci goto free_and_exit; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci p += mwifiex_debug_info_to_buffer(priv, p, &info); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page, 40062306a36Sopenharmony_ci (unsigned long) p - page); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cifree_and_exit: 40362306a36Sopenharmony_ci free_page(page); 40462306a36Sopenharmony_ci return ret; 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic u32 saved_reg_type, saved_reg_offset, saved_reg_value; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci/* 41062306a36Sopenharmony_ci * Proc regrdwr file write handler. 41162306a36Sopenharmony_ci * 41262306a36Sopenharmony_ci * This function is called when the 'regrdwr' file is opened for writing 41362306a36Sopenharmony_ci * 41462306a36Sopenharmony_ci * This function can be used to write to a register. 41562306a36Sopenharmony_ci */ 41662306a36Sopenharmony_cistatic ssize_t 41762306a36Sopenharmony_cimwifiex_regrdwr_write(struct file *file, 41862306a36Sopenharmony_ci const char __user *ubuf, size_t count, loff_t *ppos) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci char *buf; 42162306a36Sopenharmony_ci int ret; 42262306a36Sopenharmony_ci u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); 42562306a36Sopenharmony_ci if (IS_ERR(buf)) 42662306a36Sopenharmony_ci return PTR_ERR(buf); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci if (sscanf(buf, "%u %x %x", ®_type, ®_offset, ®_value) != 3) { 42962306a36Sopenharmony_ci ret = -EINVAL; 43062306a36Sopenharmony_ci goto done; 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci if (reg_type == 0 || reg_offset == 0) { 43462306a36Sopenharmony_ci ret = -EINVAL; 43562306a36Sopenharmony_ci goto done; 43662306a36Sopenharmony_ci } else { 43762306a36Sopenharmony_ci saved_reg_type = reg_type; 43862306a36Sopenharmony_ci saved_reg_offset = reg_offset; 43962306a36Sopenharmony_ci saved_reg_value = reg_value; 44062306a36Sopenharmony_ci ret = count; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_cidone: 44362306a36Sopenharmony_ci kfree(buf); 44462306a36Sopenharmony_ci return ret; 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci/* 44862306a36Sopenharmony_ci * Proc regrdwr file read handler. 44962306a36Sopenharmony_ci * 45062306a36Sopenharmony_ci * This function is called when the 'regrdwr' file is opened for reading 45162306a36Sopenharmony_ci * 45262306a36Sopenharmony_ci * This function can be used to read from a register. 45362306a36Sopenharmony_ci */ 45462306a36Sopenharmony_cistatic ssize_t 45562306a36Sopenharmony_cimwifiex_regrdwr_read(struct file *file, char __user *ubuf, 45662306a36Sopenharmony_ci size_t count, loff_t *ppos) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci struct mwifiex_private *priv = 45962306a36Sopenharmony_ci (struct mwifiex_private *) file->private_data; 46062306a36Sopenharmony_ci unsigned long addr = get_zeroed_page(GFP_KERNEL); 46162306a36Sopenharmony_ci char *buf = (char *) addr; 46262306a36Sopenharmony_ci int pos = 0, ret = 0; 46362306a36Sopenharmony_ci u32 reg_value; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci if (!buf) 46662306a36Sopenharmony_ci return -ENOMEM; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci if (!saved_reg_type) { 46962306a36Sopenharmony_ci /* No command has been given */ 47062306a36Sopenharmony_ci pos += snprintf(buf, PAGE_SIZE, "0"); 47162306a36Sopenharmony_ci goto done; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci /* Set command has been given */ 47462306a36Sopenharmony_ci if (saved_reg_value != UINT_MAX) { 47562306a36Sopenharmony_ci ret = mwifiex_reg_write(priv, saved_reg_type, saved_reg_offset, 47662306a36Sopenharmony_ci saved_reg_value); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", 47962306a36Sopenharmony_ci saved_reg_type, saved_reg_offset, 48062306a36Sopenharmony_ci saved_reg_value); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci goto done; 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci /* Get command has been given */ 48762306a36Sopenharmony_ci ret = mwifiex_reg_read(priv, saved_reg_type, 48862306a36Sopenharmony_ci saved_reg_offset, ®_value); 48962306a36Sopenharmony_ci if (ret) { 49062306a36Sopenharmony_ci ret = -EINVAL; 49162306a36Sopenharmony_ci goto done; 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci pos += snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", saved_reg_type, 49562306a36Sopenharmony_ci saved_reg_offset, reg_value); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_cidone: 50062306a36Sopenharmony_ci free_page(addr); 50162306a36Sopenharmony_ci return ret; 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci/* Proc debug_mask file read handler. 50562306a36Sopenharmony_ci * This function is called when the 'debug_mask' file is opened for reading 50662306a36Sopenharmony_ci * This function can be used read driver debugging mask value. 50762306a36Sopenharmony_ci */ 50862306a36Sopenharmony_cistatic ssize_t 50962306a36Sopenharmony_cimwifiex_debug_mask_read(struct file *file, char __user *ubuf, 51062306a36Sopenharmony_ci size_t count, loff_t *ppos) 51162306a36Sopenharmony_ci{ 51262306a36Sopenharmony_ci struct mwifiex_private *priv = 51362306a36Sopenharmony_ci (struct mwifiex_private *)file->private_data; 51462306a36Sopenharmony_ci unsigned long page = get_zeroed_page(GFP_KERNEL); 51562306a36Sopenharmony_ci char *buf = (char *)page; 51662306a36Sopenharmony_ci size_t ret = 0; 51762306a36Sopenharmony_ci int pos = 0; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci if (!buf) 52062306a36Sopenharmony_ci return -ENOMEM; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci pos += snprintf(buf, PAGE_SIZE, "debug mask=0x%08x\n", 52362306a36Sopenharmony_ci priv->adapter->debug_mask); 52462306a36Sopenharmony_ci ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci free_page(page); 52762306a36Sopenharmony_ci return ret; 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci/* Proc debug_mask file read handler. 53162306a36Sopenharmony_ci * This function is called when the 'debug_mask' file is opened for reading 53262306a36Sopenharmony_ci * This function can be used read driver debugging mask value. 53362306a36Sopenharmony_ci */ 53462306a36Sopenharmony_cistatic ssize_t 53562306a36Sopenharmony_cimwifiex_debug_mask_write(struct file *file, const char __user *ubuf, 53662306a36Sopenharmony_ci size_t count, loff_t *ppos) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci int ret; 53962306a36Sopenharmony_ci unsigned long debug_mask; 54062306a36Sopenharmony_ci struct mwifiex_private *priv = (void *)file->private_data; 54162306a36Sopenharmony_ci char *buf; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); 54462306a36Sopenharmony_ci if (IS_ERR(buf)) 54562306a36Sopenharmony_ci return PTR_ERR(buf); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci if (kstrtoul(buf, 0, &debug_mask)) { 54862306a36Sopenharmony_ci ret = -EINVAL; 54962306a36Sopenharmony_ci goto done; 55062306a36Sopenharmony_ci } 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci priv->adapter->debug_mask = debug_mask; 55362306a36Sopenharmony_ci ret = count; 55462306a36Sopenharmony_cidone: 55562306a36Sopenharmony_ci kfree(buf); 55662306a36Sopenharmony_ci return ret; 55762306a36Sopenharmony_ci} 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci/* debugfs verext file write handler. 56062306a36Sopenharmony_ci * This function is called when the 'verext' file is opened for write 56162306a36Sopenharmony_ci */ 56262306a36Sopenharmony_cistatic ssize_t 56362306a36Sopenharmony_cimwifiex_verext_write(struct file *file, const char __user *ubuf, 56462306a36Sopenharmony_ci size_t count, loff_t *ppos) 56562306a36Sopenharmony_ci{ 56662306a36Sopenharmony_ci int ret; 56762306a36Sopenharmony_ci u32 versionstrsel; 56862306a36Sopenharmony_ci struct mwifiex_private *priv = (void *)file->private_data; 56962306a36Sopenharmony_ci char buf[16]; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci memset(buf, 0, sizeof(buf)); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) 57462306a36Sopenharmony_ci return -EFAULT; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci ret = kstrtou32(buf, 10, &versionstrsel); 57762306a36Sopenharmony_ci if (ret) 57862306a36Sopenharmony_ci return ret; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci priv->versionstrsel = versionstrsel; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci return count; 58362306a36Sopenharmony_ci} 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci/* Proc verext file read handler. 58662306a36Sopenharmony_ci * This function is called when the 'verext' file is opened for reading 58762306a36Sopenharmony_ci * This function can be used read driver exteneed verion string. 58862306a36Sopenharmony_ci */ 58962306a36Sopenharmony_cistatic ssize_t 59062306a36Sopenharmony_cimwifiex_verext_read(struct file *file, char __user *ubuf, 59162306a36Sopenharmony_ci size_t count, loff_t *ppos) 59262306a36Sopenharmony_ci{ 59362306a36Sopenharmony_ci struct mwifiex_private *priv = 59462306a36Sopenharmony_ci (struct mwifiex_private *)file->private_data; 59562306a36Sopenharmony_ci char buf[256]; 59662306a36Sopenharmony_ci int ret; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci mwifiex_get_ver_ext(priv, priv->versionstrsel); 59962306a36Sopenharmony_ci ret = snprintf(buf, sizeof(buf), "version string: %s\n", 60062306a36Sopenharmony_ci priv->version_str); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci return simple_read_from_buffer(ubuf, count, ppos, buf, ret); 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci/* Proc memrw file write handler. 60662306a36Sopenharmony_ci * This function is called when the 'memrw' file is opened for writing 60762306a36Sopenharmony_ci * This function can be used to write to a memory location. 60862306a36Sopenharmony_ci */ 60962306a36Sopenharmony_cistatic ssize_t 61062306a36Sopenharmony_cimwifiex_memrw_write(struct file *file, const char __user *ubuf, size_t count, 61162306a36Sopenharmony_ci loff_t *ppos) 61262306a36Sopenharmony_ci{ 61362306a36Sopenharmony_ci int ret; 61462306a36Sopenharmony_ci char cmd; 61562306a36Sopenharmony_ci struct mwifiex_ds_mem_rw mem_rw; 61662306a36Sopenharmony_ci u16 cmd_action; 61762306a36Sopenharmony_ci struct mwifiex_private *priv = (void *)file->private_data; 61862306a36Sopenharmony_ci char *buf; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); 62162306a36Sopenharmony_ci if (IS_ERR(buf)) 62262306a36Sopenharmony_ci return PTR_ERR(buf); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci ret = sscanf(buf, "%c %x %x", &cmd, &mem_rw.addr, &mem_rw.value); 62562306a36Sopenharmony_ci if (ret != 3) { 62662306a36Sopenharmony_ci ret = -EINVAL; 62762306a36Sopenharmony_ci goto done; 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if ((cmd == 'r') || (cmd == 'R')) { 63162306a36Sopenharmony_ci cmd_action = HostCmd_ACT_GEN_GET; 63262306a36Sopenharmony_ci mem_rw.value = 0; 63362306a36Sopenharmony_ci } else if ((cmd == 'w') || (cmd == 'W')) { 63462306a36Sopenharmony_ci cmd_action = HostCmd_ACT_GEN_SET; 63562306a36Sopenharmony_ci } else { 63662306a36Sopenharmony_ci ret = -EINVAL; 63762306a36Sopenharmony_ci goto done; 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci memcpy(&priv->mem_rw, &mem_rw, sizeof(mem_rw)); 64162306a36Sopenharmony_ci if (mwifiex_send_cmd(priv, HostCmd_CMD_MEM_ACCESS, cmd_action, 0, 64262306a36Sopenharmony_ci &mem_rw, true)) 64362306a36Sopenharmony_ci ret = -1; 64462306a36Sopenharmony_ci else 64562306a36Sopenharmony_ci ret = count; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_cidone: 64862306a36Sopenharmony_ci kfree(buf); 64962306a36Sopenharmony_ci return ret; 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci/* Proc memrw file read handler. 65362306a36Sopenharmony_ci * This function is called when the 'memrw' file is opened for reading 65462306a36Sopenharmony_ci * This function can be used to read from a memory location. 65562306a36Sopenharmony_ci */ 65662306a36Sopenharmony_cistatic ssize_t 65762306a36Sopenharmony_cimwifiex_memrw_read(struct file *file, char __user *ubuf, 65862306a36Sopenharmony_ci size_t count, loff_t *ppos) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci struct mwifiex_private *priv = (void *)file->private_data; 66162306a36Sopenharmony_ci unsigned long addr = get_zeroed_page(GFP_KERNEL); 66262306a36Sopenharmony_ci char *buf = (char *)addr; 66362306a36Sopenharmony_ci int ret, pos = 0; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci if (!buf) 66662306a36Sopenharmony_ci return -ENOMEM; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci pos += snprintf(buf, PAGE_SIZE, "0x%x 0x%x\n", priv->mem_rw.addr, 66962306a36Sopenharmony_ci priv->mem_rw.value); 67062306a36Sopenharmony_ci ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci free_page(addr); 67362306a36Sopenharmony_ci return ret; 67462306a36Sopenharmony_ci} 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_cistatic u32 saved_offset = -1, saved_bytes = -1; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci/* 67962306a36Sopenharmony_ci * Proc rdeeprom file write handler. 68062306a36Sopenharmony_ci * 68162306a36Sopenharmony_ci * This function is called when the 'rdeeprom' file is opened for writing 68262306a36Sopenharmony_ci * 68362306a36Sopenharmony_ci * This function can be used to write to a RDEEPROM location. 68462306a36Sopenharmony_ci */ 68562306a36Sopenharmony_cistatic ssize_t 68662306a36Sopenharmony_cimwifiex_rdeeprom_write(struct file *file, 68762306a36Sopenharmony_ci const char __user *ubuf, size_t count, loff_t *ppos) 68862306a36Sopenharmony_ci{ 68962306a36Sopenharmony_ci char *buf; 69062306a36Sopenharmony_ci int ret = 0; 69162306a36Sopenharmony_ci int offset = -1, bytes = -1; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); 69462306a36Sopenharmony_ci if (IS_ERR(buf)) 69562306a36Sopenharmony_ci return PTR_ERR(buf); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci if (sscanf(buf, "%d %d", &offset, &bytes) != 2) { 69862306a36Sopenharmony_ci ret = -EINVAL; 69962306a36Sopenharmony_ci goto done; 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci if (offset == -1 || bytes == -1) { 70362306a36Sopenharmony_ci ret = -EINVAL; 70462306a36Sopenharmony_ci goto done; 70562306a36Sopenharmony_ci } else { 70662306a36Sopenharmony_ci saved_offset = offset; 70762306a36Sopenharmony_ci saved_bytes = bytes; 70862306a36Sopenharmony_ci ret = count; 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_cidone: 71162306a36Sopenharmony_ci kfree(buf); 71262306a36Sopenharmony_ci return ret; 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci/* 71662306a36Sopenharmony_ci * Proc rdeeprom read write handler. 71762306a36Sopenharmony_ci * 71862306a36Sopenharmony_ci * This function is called when the 'rdeeprom' file is opened for reading 71962306a36Sopenharmony_ci * 72062306a36Sopenharmony_ci * This function can be used to read from a RDEEPROM location. 72162306a36Sopenharmony_ci */ 72262306a36Sopenharmony_cistatic ssize_t 72362306a36Sopenharmony_cimwifiex_rdeeprom_read(struct file *file, char __user *ubuf, 72462306a36Sopenharmony_ci size_t count, loff_t *ppos) 72562306a36Sopenharmony_ci{ 72662306a36Sopenharmony_ci struct mwifiex_private *priv = 72762306a36Sopenharmony_ci (struct mwifiex_private *) file->private_data; 72862306a36Sopenharmony_ci unsigned long addr = get_zeroed_page(GFP_KERNEL); 72962306a36Sopenharmony_ci char *buf = (char *) addr; 73062306a36Sopenharmony_ci int pos, ret, i; 73162306a36Sopenharmony_ci u8 value[MAX_EEPROM_DATA]; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci if (!buf) 73462306a36Sopenharmony_ci return -ENOMEM; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci if (saved_offset == -1) { 73762306a36Sopenharmony_ci /* No command has been given */ 73862306a36Sopenharmony_ci pos = snprintf(buf, PAGE_SIZE, "0"); 73962306a36Sopenharmony_ci goto done; 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci /* Get command has been given */ 74362306a36Sopenharmony_ci ret = mwifiex_eeprom_read(priv, (u16) saved_offset, 74462306a36Sopenharmony_ci (u16) saved_bytes, value); 74562306a36Sopenharmony_ci if (ret) { 74662306a36Sopenharmony_ci ret = -EINVAL; 74762306a36Sopenharmony_ci goto out_free; 74862306a36Sopenharmony_ci } 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci pos = snprintf(buf, PAGE_SIZE, "%d %d ", saved_offset, saved_bytes); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci for (i = 0; i < saved_bytes; i++) 75362306a36Sopenharmony_ci pos += scnprintf(buf + pos, PAGE_SIZE - pos, "%d ", value[i]); 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_cidone: 75662306a36Sopenharmony_ci ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 75762306a36Sopenharmony_ciout_free: 75862306a36Sopenharmony_ci free_page(addr); 75962306a36Sopenharmony_ci return ret; 76062306a36Sopenharmony_ci} 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci/* Proc hscfg file write handler 76362306a36Sopenharmony_ci * This function can be used to configure the host sleep parameters. 76462306a36Sopenharmony_ci */ 76562306a36Sopenharmony_cistatic ssize_t 76662306a36Sopenharmony_cimwifiex_hscfg_write(struct file *file, const char __user *ubuf, 76762306a36Sopenharmony_ci size_t count, loff_t *ppos) 76862306a36Sopenharmony_ci{ 76962306a36Sopenharmony_ci struct mwifiex_private *priv = (void *)file->private_data; 77062306a36Sopenharmony_ci char *buf; 77162306a36Sopenharmony_ci int ret, arg_num; 77262306a36Sopenharmony_ci struct mwifiex_ds_hs_cfg hscfg; 77362306a36Sopenharmony_ci int conditions = HS_CFG_COND_DEF; 77462306a36Sopenharmony_ci u32 gpio = HS_CFG_GPIO_DEF, gap = HS_CFG_GAP_DEF; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci buf = memdup_user_nul(ubuf, min(count, (size_t)(PAGE_SIZE - 1))); 77762306a36Sopenharmony_ci if (IS_ERR(buf)) 77862306a36Sopenharmony_ci return PTR_ERR(buf); 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci arg_num = sscanf(buf, "%d %x %x", &conditions, &gpio, &gap); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci memset(&hscfg, 0, sizeof(struct mwifiex_ds_hs_cfg)); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci if (arg_num > 3) { 78562306a36Sopenharmony_ci mwifiex_dbg(priv->adapter, ERROR, 78662306a36Sopenharmony_ci "Too many arguments\n"); 78762306a36Sopenharmony_ci ret = -EINVAL; 78862306a36Sopenharmony_ci goto done; 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci if (arg_num >= 1 && arg_num < 3) 79262306a36Sopenharmony_ci mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_GET, 79362306a36Sopenharmony_ci MWIFIEX_SYNC_CMD, &hscfg); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci if (arg_num) { 79662306a36Sopenharmony_ci if (conditions == HS_CFG_CANCEL) { 79762306a36Sopenharmony_ci mwifiex_cancel_hs(priv, MWIFIEX_ASYNC_CMD); 79862306a36Sopenharmony_ci ret = count; 79962306a36Sopenharmony_ci goto done; 80062306a36Sopenharmony_ci } 80162306a36Sopenharmony_ci hscfg.conditions = conditions; 80262306a36Sopenharmony_ci } 80362306a36Sopenharmony_ci if (arg_num >= 2) 80462306a36Sopenharmony_ci hscfg.gpio = gpio; 80562306a36Sopenharmony_ci if (arg_num == 3) 80662306a36Sopenharmony_ci hscfg.gap = gap; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci hscfg.is_invoke_hostcmd = false; 80962306a36Sopenharmony_ci mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET, 81062306a36Sopenharmony_ci MWIFIEX_SYNC_CMD, &hscfg); 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci mwifiex_enable_hs(priv->adapter); 81362306a36Sopenharmony_ci clear_bit(MWIFIEX_IS_HS_ENABLING, &priv->adapter->work_flags); 81462306a36Sopenharmony_ci ret = count; 81562306a36Sopenharmony_cidone: 81662306a36Sopenharmony_ci kfree(buf); 81762306a36Sopenharmony_ci return ret; 81862306a36Sopenharmony_ci} 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci/* Proc hscfg file read handler 82162306a36Sopenharmony_ci * This function can be used to read host sleep configuration 82262306a36Sopenharmony_ci * parameters from driver. 82362306a36Sopenharmony_ci */ 82462306a36Sopenharmony_cistatic ssize_t 82562306a36Sopenharmony_cimwifiex_hscfg_read(struct file *file, char __user *ubuf, 82662306a36Sopenharmony_ci size_t count, loff_t *ppos) 82762306a36Sopenharmony_ci{ 82862306a36Sopenharmony_ci struct mwifiex_private *priv = (void *)file->private_data; 82962306a36Sopenharmony_ci unsigned long addr = get_zeroed_page(GFP_KERNEL); 83062306a36Sopenharmony_ci char *buf = (char *)addr; 83162306a36Sopenharmony_ci int pos, ret; 83262306a36Sopenharmony_ci struct mwifiex_ds_hs_cfg hscfg; 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci if (!buf) 83562306a36Sopenharmony_ci return -ENOMEM; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_GET, 83862306a36Sopenharmony_ci MWIFIEX_SYNC_CMD, &hscfg); 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci pos = snprintf(buf, PAGE_SIZE, "%u 0x%x 0x%x\n", hscfg.conditions, 84162306a36Sopenharmony_ci hscfg.gpio, hscfg.gap); 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci ret = simple_read_from_buffer(ubuf, count, ppos, buf, pos); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci free_page(addr); 84662306a36Sopenharmony_ci return ret; 84762306a36Sopenharmony_ci} 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_cistatic ssize_t 85062306a36Sopenharmony_cimwifiex_timeshare_coex_read(struct file *file, char __user *ubuf, 85162306a36Sopenharmony_ci size_t count, loff_t *ppos) 85262306a36Sopenharmony_ci{ 85362306a36Sopenharmony_ci struct mwifiex_private *priv = file->private_data; 85462306a36Sopenharmony_ci char buf[3]; 85562306a36Sopenharmony_ci bool timeshare_coex; 85662306a36Sopenharmony_ci int ret; 85762306a36Sopenharmony_ci unsigned int len; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci if (priv->adapter->fw_api_ver != MWIFIEX_FW_V15) 86062306a36Sopenharmony_ci return -EOPNOTSUPP; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci ret = mwifiex_send_cmd(priv, HostCmd_CMD_ROBUST_COEX, 86362306a36Sopenharmony_ci HostCmd_ACT_GEN_GET, 0, ×hare_coex, true); 86462306a36Sopenharmony_ci if (ret) 86562306a36Sopenharmony_ci return ret; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci len = sprintf(buf, "%d\n", timeshare_coex); 86862306a36Sopenharmony_ci return simple_read_from_buffer(ubuf, count, ppos, buf, len); 86962306a36Sopenharmony_ci} 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_cistatic ssize_t 87262306a36Sopenharmony_cimwifiex_timeshare_coex_write(struct file *file, const char __user *ubuf, 87362306a36Sopenharmony_ci size_t count, loff_t *ppos) 87462306a36Sopenharmony_ci{ 87562306a36Sopenharmony_ci bool timeshare_coex; 87662306a36Sopenharmony_ci struct mwifiex_private *priv = file->private_data; 87762306a36Sopenharmony_ci char kbuf[16]; 87862306a36Sopenharmony_ci int ret; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci if (priv->adapter->fw_api_ver != MWIFIEX_FW_V15) 88162306a36Sopenharmony_ci return -EOPNOTSUPP; 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci memset(kbuf, 0, sizeof(kbuf)); 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci if (copy_from_user(&kbuf, ubuf, min_t(size_t, sizeof(kbuf) - 1, count))) 88662306a36Sopenharmony_ci return -EFAULT; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_ci if (kstrtobool(kbuf, ×hare_coex)) 88962306a36Sopenharmony_ci return -EINVAL; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci ret = mwifiex_send_cmd(priv, HostCmd_CMD_ROBUST_COEX, 89262306a36Sopenharmony_ci HostCmd_ACT_GEN_SET, 0, ×hare_coex, true); 89362306a36Sopenharmony_ci if (ret) 89462306a36Sopenharmony_ci return ret; 89562306a36Sopenharmony_ci else 89662306a36Sopenharmony_ci return count; 89762306a36Sopenharmony_ci} 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_cistatic ssize_t 90062306a36Sopenharmony_cimwifiex_reset_write(struct file *file, 90162306a36Sopenharmony_ci const char __user *ubuf, size_t count, loff_t *ppos) 90262306a36Sopenharmony_ci{ 90362306a36Sopenharmony_ci struct mwifiex_private *priv = file->private_data; 90462306a36Sopenharmony_ci struct mwifiex_adapter *adapter = priv->adapter; 90562306a36Sopenharmony_ci bool result; 90662306a36Sopenharmony_ci int rc; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci rc = kstrtobool_from_user(ubuf, count, &result); 90962306a36Sopenharmony_ci if (rc) 91062306a36Sopenharmony_ci return rc; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci if (!result) 91362306a36Sopenharmony_ci return -EINVAL; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci if (adapter->if_ops.card_reset) { 91662306a36Sopenharmony_ci dev_info(adapter->dev, "Resetting per request\n"); 91762306a36Sopenharmony_ci adapter->if_ops.card_reset(adapter); 91862306a36Sopenharmony_ci } 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci return count; 92162306a36Sopenharmony_ci} 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci#define MWIFIEX_DFS_ADD_FILE(name) do { \ 92462306a36Sopenharmony_ci debugfs_create_file(#name, 0644, priv->dfs_dev_dir, priv, \ 92562306a36Sopenharmony_ci &mwifiex_dfs_##name##_fops); \ 92662306a36Sopenharmony_ci} while (0); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci#define MWIFIEX_DFS_FILE_OPS(name) \ 92962306a36Sopenharmony_cistatic const struct file_operations mwifiex_dfs_##name##_fops = { \ 93062306a36Sopenharmony_ci .read = mwifiex_##name##_read, \ 93162306a36Sopenharmony_ci .write = mwifiex_##name##_write, \ 93262306a36Sopenharmony_ci .open = simple_open, \ 93362306a36Sopenharmony_ci}; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci#define MWIFIEX_DFS_FILE_READ_OPS(name) \ 93662306a36Sopenharmony_cistatic const struct file_operations mwifiex_dfs_##name##_fops = { \ 93762306a36Sopenharmony_ci .read = mwifiex_##name##_read, \ 93862306a36Sopenharmony_ci .open = simple_open, \ 93962306a36Sopenharmony_ci}; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci#define MWIFIEX_DFS_FILE_WRITE_OPS(name) \ 94262306a36Sopenharmony_cistatic const struct file_operations mwifiex_dfs_##name##_fops = { \ 94362306a36Sopenharmony_ci .write = mwifiex_##name##_write, \ 94462306a36Sopenharmony_ci .open = simple_open, \ 94562306a36Sopenharmony_ci}; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ciMWIFIEX_DFS_FILE_READ_OPS(info); 94962306a36Sopenharmony_ciMWIFIEX_DFS_FILE_READ_OPS(debug); 95062306a36Sopenharmony_ciMWIFIEX_DFS_FILE_READ_OPS(getlog); 95162306a36Sopenharmony_ciMWIFIEX_DFS_FILE_OPS(regrdwr); 95262306a36Sopenharmony_ciMWIFIEX_DFS_FILE_OPS(rdeeprom); 95362306a36Sopenharmony_ciMWIFIEX_DFS_FILE_OPS(memrw); 95462306a36Sopenharmony_ciMWIFIEX_DFS_FILE_OPS(hscfg); 95562306a36Sopenharmony_ciMWIFIEX_DFS_FILE_OPS(histogram); 95662306a36Sopenharmony_ciMWIFIEX_DFS_FILE_OPS(debug_mask); 95762306a36Sopenharmony_ciMWIFIEX_DFS_FILE_OPS(timeshare_coex); 95862306a36Sopenharmony_ciMWIFIEX_DFS_FILE_WRITE_OPS(reset); 95962306a36Sopenharmony_ciMWIFIEX_DFS_FILE_OPS(verext); 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci/* 96262306a36Sopenharmony_ci * This function creates the debug FS directory structure and the files. 96362306a36Sopenharmony_ci */ 96462306a36Sopenharmony_civoid 96562306a36Sopenharmony_cimwifiex_dev_debugfs_init(struct mwifiex_private *priv) 96662306a36Sopenharmony_ci{ 96762306a36Sopenharmony_ci if (!mwifiex_dfs_dir || !priv) 96862306a36Sopenharmony_ci return; 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci priv->dfs_dev_dir = debugfs_create_dir(priv->netdev->name, 97162306a36Sopenharmony_ci mwifiex_dfs_dir); 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci MWIFIEX_DFS_ADD_FILE(info); 97462306a36Sopenharmony_ci MWIFIEX_DFS_ADD_FILE(debug); 97562306a36Sopenharmony_ci MWIFIEX_DFS_ADD_FILE(getlog); 97662306a36Sopenharmony_ci MWIFIEX_DFS_ADD_FILE(regrdwr); 97762306a36Sopenharmony_ci MWIFIEX_DFS_ADD_FILE(rdeeprom); 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci MWIFIEX_DFS_ADD_FILE(memrw); 98062306a36Sopenharmony_ci MWIFIEX_DFS_ADD_FILE(hscfg); 98162306a36Sopenharmony_ci MWIFIEX_DFS_ADD_FILE(histogram); 98262306a36Sopenharmony_ci MWIFIEX_DFS_ADD_FILE(debug_mask); 98362306a36Sopenharmony_ci MWIFIEX_DFS_ADD_FILE(timeshare_coex); 98462306a36Sopenharmony_ci MWIFIEX_DFS_ADD_FILE(reset); 98562306a36Sopenharmony_ci MWIFIEX_DFS_ADD_FILE(verext); 98662306a36Sopenharmony_ci} 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci/* 98962306a36Sopenharmony_ci * This function removes the debug FS directory structure and the files. 99062306a36Sopenharmony_ci */ 99162306a36Sopenharmony_civoid 99262306a36Sopenharmony_cimwifiex_dev_debugfs_remove(struct mwifiex_private *priv) 99362306a36Sopenharmony_ci{ 99462306a36Sopenharmony_ci if (!priv) 99562306a36Sopenharmony_ci return; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci debugfs_remove_recursive(priv->dfs_dev_dir); 99862306a36Sopenharmony_ci} 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci/* 100162306a36Sopenharmony_ci * This function creates the top level proc directory. 100262306a36Sopenharmony_ci */ 100362306a36Sopenharmony_civoid 100462306a36Sopenharmony_cimwifiex_debugfs_init(void) 100562306a36Sopenharmony_ci{ 100662306a36Sopenharmony_ci if (!mwifiex_dfs_dir) 100762306a36Sopenharmony_ci mwifiex_dfs_dir = debugfs_create_dir("mwifiex", NULL); 100862306a36Sopenharmony_ci} 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci/* 101162306a36Sopenharmony_ci * This function removes the top level proc directory. 101262306a36Sopenharmony_ci */ 101362306a36Sopenharmony_civoid 101462306a36Sopenharmony_cimwifiex_debugfs_remove(void) 101562306a36Sopenharmony_ci{ 101662306a36Sopenharmony_ci debugfs_remove(mwifiex_dfs_dir); 101762306a36Sopenharmony_ci} 1018