18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <linux/dcache.h> 38c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 48c2ecf20Sopenharmony_ci#include <linux/delay.h> 58c2ecf20Sopenharmony_ci#include <linux/hardirq.h> 68c2ecf20Sopenharmony_ci#include <linux/mm.h> 78c2ecf20Sopenharmony_ci#include <linux/string.h> 88c2ecf20Sopenharmony_ci#include <linux/slab.h> 98c2ecf20Sopenharmony_ci#include <linux/export.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include "decl.h" 128c2ecf20Sopenharmony_ci#include "cmd.h" 138c2ecf20Sopenharmony_ci#include "debugfs.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic struct dentry *lbs_dir; 168c2ecf20Sopenharmony_cistatic char *szStates[] = { 178c2ecf20Sopenharmony_ci "Connected", 188c2ecf20Sopenharmony_ci "Disconnected" 198c2ecf20Sopenharmony_ci}; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#ifdef PROC_DEBUG 228c2ecf20Sopenharmony_cistatic void lbs_debug_init(struct lbs_private *priv); 238c2ecf20Sopenharmony_ci#endif 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic ssize_t write_file_dummy(struct file *file, const char __user *buf, 268c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci return -EINVAL; 298c2ecf20Sopenharmony_ci} 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic const size_t len = PAGE_SIZE; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic ssize_t lbs_dev_info(struct file *file, char __user *userbuf, 348c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci struct lbs_private *priv = file->private_data; 378c2ecf20Sopenharmony_ci size_t pos = 0; 388c2ecf20Sopenharmony_ci unsigned long addr = get_zeroed_page(GFP_KERNEL); 398c2ecf20Sopenharmony_ci char *buf = (char *)addr; 408c2ecf20Sopenharmony_ci ssize_t res; 418c2ecf20Sopenharmony_ci if (!buf) 428c2ecf20Sopenharmony_ci return -ENOMEM; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci pos += snprintf(buf+pos, len-pos, "state = %s\n", 458c2ecf20Sopenharmony_ci szStates[priv->connect_status]); 468c2ecf20Sopenharmony_ci pos += snprintf(buf+pos, len-pos, "region_code = %02x\n", 478c2ecf20Sopenharmony_ci (u32) priv->regioncode); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci free_page(addr); 528c2ecf20Sopenharmony_ci return res; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic ssize_t lbs_sleepparams_write(struct file *file, 568c2ecf20Sopenharmony_ci const char __user *user_buf, size_t count, 578c2ecf20Sopenharmony_ci loff_t *ppos) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci struct lbs_private *priv = file->private_data; 608c2ecf20Sopenharmony_ci ssize_t ret; 618c2ecf20Sopenharmony_ci struct sleep_params sp; 628c2ecf20Sopenharmony_ci int p1, p2, p3, p4, p5, p6; 638c2ecf20Sopenharmony_ci char *buf; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci buf = memdup_user_nul(user_buf, min(count, len - 1)); 668c2ecf20Sopenharmony_ci if (IS_ERR(buf)) 678c2ecf20Sopenharmony_ci return PTR_ERR(buf); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci ret = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6); 708c2ecf20Sopenharmony_ci if (ret != 6) { 718c2ecf20Sopenharmony_ci ret = -EINVAL; 728c2ecf20Sopenharmony_ci goto out_unlock; 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci sp.sp_error = p1; 758c2ecf20Sopenharmony_ci sp.sp_offset = p2; 768c2ecf20Sopenharmony_ci sp.sp_stabletime = p3; 778c2ecf20Sopenharmony_ci sp.sp_calcontrol = p4; 788c2ecf20Sopenharmony_ci sp.sp_extsleepclk = p5; 798c2ecf20Sopenharmony_ci sp.sp_reserved = p6; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_SET, &sp); 828c2ecf20Sopenharmony_ci if (!ret) 838c2ecf20Sopenharmony_ci ret = count; 848c2ecf20Sopenharmony_ci else if (ret > 0) 858c2ecf20Sopenharmony_ci ret = -EINVAL; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ciout_unlock: 888c2ecf20Sopenharmony_ci kfree(buf); 898c2ecf20Sopenharmony_ci return ret; 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf, 938c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci struct lbs_private *priv = file->private_data; 968c2ecf20Sopenharmony_ci ssize_t ret; 978c2ecf20Sopenharmony_ci size_t pos = 0; 988c2ecf20Sopenharmony_ci struct sleep_params sp; 998c2ecf20Sopenharmony_ci unsigned long addr = get_zeroed_page(GFP_KERNEL); 1008c2ecf20Sopenharmony_ci char *buf = (char *)addr; 1018c2ecf20Sopenharmony_ci if (!buf) 1028c2ecf20Sopenharmony_ci return -ENOMEM; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp); 1058c2ecf20Sopenharmony_ci if (ret) 1068c2ecf20Sopenharmony_ci goto out_unlock; 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci pos += snprintf(buf, len, "%d %d %d %d %d %d\n", sp.sp_error, 1098c2ecf20Sopenharmony_ci sp.sp_offset, sp.sp_stabletime, 1108c2ecf20Sopenharmony_ci sp.sp_calcontrol, sp.sp_extsleepclk, 1118c2ecf20Sopenharmony_ci sp.sp_reserved); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ciout_unlock: 1168c2ecf20Sopenharmony_ci free_page(addr); 1178c2ecf20Sopenharmony_ci return ret; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic ssize_t lbs_host_sleep_write(struct file *file, 1218c2ecf20Sopenharmony_ci const char __user *user_buf, size_t count, 1228c2ecf20Sopenharmony_ci loff_t *ppos) 1238c2ecf20Sopenharmony_ci{ 1248c2ecf20Sopenharmony_ci struct lbs_private *priv = file->private_data; 1258c2ecf20Sopenharmony_ci ssize_t ret; 1268c2ecf20Sopenharmony_ci int host_sleep; 1278c2ecf20Sopenharmony_ci char *buf; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci buf = memdup_user_nul(user_buf, min(count, len - 1)); 1308c2ecf20Sopenharmony_ci if (IS_ERR(buf)) 1318c2ecf20Sopenharmony_ci return PTR_ERR(buf); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci ret = sscanf(buf, "%d", &host_sleep); 1348c2ecf20Sopenharmony_ci if (ret != 1) { 1358c2ecf20Sopenharmony_ci ret = -EINVAL; 1368c2ecf20Sopenharmony_ci goto out_unlock; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci if (host_sleep == 0) 1408c2ecf20Sopenharmony_ci ret = lbs_set_host_sleep(priv, 0); 1418c2ecf20Sopenharmony_ci else if (host_sleep == 1) { 1428c2ecf20Sopenharmony_ci if (priv->wol_criteria == EHS_REMOVE_WAKEUP) { 1438c2ecf20Sopenharmony_ci netdev_info(priv->dev, 1448c2ecf20Sopenharmony_ci "wake parameters not configured\n"); 1458c2ecf20Sopenharmony_ci ret = -EINVAL; 1468c2ecf20Sopenharmony_ci goto out_unlock; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci ret = lbs_set_host_sleep(priv, 1); 1498c2ecf20Sopenharmony_ci } else { 1508c2ecf20Sopenharmony_ci netdev_err(priv->dev, "invalid option\n"); 1518c2ecf20Sopenharmony_ci ret = -EINVAL; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (!ret) 1558c2ecf20Sopenharmony_ci ret = count; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ciout_unlock: 1588c2ecf20Sopenharmony_ci kfree(buf); 1598c2ecf20Sopenharmony_ci return ret; 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic ssize_t lbs_host_sleep_read(struct file *file, char __user *userbuf, 1638c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci struct lbs_private *priv = file->private_data; 1668c2ecf20Sopenharmony_ci ssize_t ret; 1678c2ecf20Sopenharmony_ci size_t pos = 0; 1688c2ecf20Sopenharmony_ci unsigned long addr = get_zeroed_page(GFP_KERNEL); 1698c2ecf20Sopenharmony_ci char *buf = (char *)addr; 1708c2ecf20Sopenharmony_ci if (!buf) 1718c2ecf20Sopenharmony_ci return -ENOMEM; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci pos += snprintf(buf, len, "%d\n", priv->is_host_sleep_activated); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci free_page(addr); 1788c2ecf20Sopenharmony_ci return ret; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci/* 1828c2ecf20Sopenharmony_ci * When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might 1838c2ecf20Sopenharmony_ci * get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the 1848c2ecf20Sopenharmony_ci * firmware. Here's an example: 1858c2ecf20Sopenharmony_ci * 04 01 02 00 00 00 05 01 02 00 00 00 06 01 02 00 1868c2ecf20Sopenharmony_ci * 00 00 07 01 02 00 3c 00 00 00 00 00 00 00 03 03 1878c2ecf20Sopenharmony_ci * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1888c2ecf20Sopenharmony_ci * 1898c2ecf20Sopenharmony_ci * The 04 01 is the TLV type (here TLV_TYPE_RSSI_LOW), 02 00 is the length, 1908c2ecf20Sopenharmony_ci * 00 00 are the data bytes of this TLV. For this TLV, their meaning is 1918c2ecf20Sopenharmony_ci * defined in mrvlietypes_thresholds 1928c2ecf20Sopenharmony_ci * 1938c2ecf20Sopenharmony_ci * This function searches in this TLV data chunk for a given TLV type 1948c2ecf20Sopenharmony_ci * and returns a pointer to the first data byte of the TLV, or to NULL 1958c2ecf20Sopenharmony_ci * if the TLV hasn't been found. 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_cistatic void *lbs_tlv_find(uint16_t tlv_type, const uint8_t *tlv, uint16_t size) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci struct mrvl_ie_header *tlv_h; 2008c2ecf20Sopenharmony_ci uint16_t length; 2018c2ecf20Sopenharmony_ci ssize_t pos = 0; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci while (pos < size) { 2048c2ecf20Sopenharmony_ci tlv_h = (struct mrvl_ie_header *) tlv; 2058c2ecf20Sopenharmony_ci if (!tlv_h->len) 2068c2ecf20Sopenharmony_ci return NULL; 2078c2ecf20Sopenharmony_ci if (tlv_h->type == cpu_to_le16(tlv_type)) 2088c2ecf20Sopenharmony_ci return tlv_h; 2098c2ecf20Sopenharmony_ci length = le16_to_cpu(tlv_h->len) + sizeof(*tlv_h); 2108c2ecf20Sopenharmony_ci pos += length; 2118c2ecf20Sopenharmony_ci tlv += length; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci return NULL; 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistatic ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask, 2188c2ecf20Sopenharmony_ci struct file *file, char __user *userbuf, 2198c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci struct cmd_ds_802_11_subscribe_event *subscribed; 2228c2ecf20Sopenharmony_ci struct mrvl_ie_thresholds *got; 2238c2ecf20Sopenharmony_ci struct lbs_private *priv = file->private_data; 2248c2ecf20Sopenharmony_ci ssize_t ret = 0; 2258c2ecf20Sopenharmony_ci size_t pos = 0; 2268c2ecf20Sopenharmony_ci char *buf; 2278c2ecf20Sopenharmony_ci u8 value; 2288c2ecf20Sopenharmony_ci u8 freq; 2298c2ecf20Sopenharmony_ci int events = 0; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci buf = (char *)get_zeroed_page(GFP_KERNEL); 2328c2ecf20Sopenharmony_ci if (!buf) 2338c2ecf20Sopenharmony_ci return -ENOMEM; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci subscribed = kzalloc(sizeof(*subscribed), GFP_KERNEL); 2368c2ecf20Sopenharmony_ci if (!subscribed) { 2378c2ecf20Sopenharmony_ci ret = -ENOMEM; 2388c2ecf20Sopenharmony_ci goto out_page; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci subscribed->hdr.size = cpu_to_le16(sizeof(*subscribed)); 2428c2ecf20Sopenharmony_ci subscribed->action = cpu_to_le16(CMD_ACT_GET); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, subscribed); 2458c2ecf20Sopenharmony_ci if (ret) 2468c2ecf20Sopenharmony_ci goto out_cmd; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci got = lbs_tlv_find(tlv_type, subscribed->tlv, sizeof(subscribed->tlv)); 2498c2ecf20Sopenharmony_ci if (got) { 2508c2ecf20Sopenharmony_ci value = got->value; 2518c2ecf20Sopenharmony_ci freq = got->freq; 2528c2ecf20Sopenharmony_ci events = le16_to_cpu(subscribed->events); 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci pos += snprintf(buf, len, "%d %d %d\n", value, freq, 2558c2ecf20Sopenharmony_ci !!(events & event_mask)); 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci out_cmd: 2618c2ecf20Sopenharmony_ci kfree(subscribed); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci out_page: 2648c2ecf20Sopenharmony_ci free_page((unsigned long)buf); 2658c2ecf20Sopenharmony_ci return ret; 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask, 2708c2ecf20Sopenharmony_ci struct file *file, 2718c2ecf20Sopenharmony_ci const char __user *userbuf, size_t count, 2728c2ecf20Sopenharmony_ci loff_t *ppos) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci struct cmd_ds_802_11_subscribe_event *events; 2758c2ecf20Sopenharmony_ci struct mrvl_ie_thresholds *tlv; 2768c2ecf20Sopenharmony_ci struct lbs_private *priv = file->private_data; 2778c2ecf20Sopenharmony_ci int value, freq, new_mask; 2788c2ecf20Sopenharmony_ci uint16_t curr_mask; 2798c2ecf20Sopenharmony_ci char *buf; 2808c2ecf20Sopenharmony_ci int ret; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci buf = memdup_user_nul(userbuf, min(count, len - 1)); 2838c2ecf20Sopenharmony_ci if (IS_ERR(buf)) 2848c2ecf20Sopenharmony_ci return PTR_ERR(buf); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci ret = sscanf(buf, "%d %d %d", &value, &freq, &new_mask); 2878c2ecf20Sopenharmony_ci if (ret != 3) { 2888c2ecf20Sopenharmony_ci ret = -EINVAL; 2898c2ecf20Sopenharmony_ci goto out_page; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci events = kzalloc(sizeof(*events), GFP_KERNEL); 2928c2ecf20Sopenharmony_ci if (!events) { 2938c2ecf20Sopenharmony_ci ret = -ENOMEM; 2948c2ecf20Sopenharmony_ci goto out_page; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci events->hdr.size = cpu_to_le16(sizeof(*events)); 2988c2ecf20Sopenharmony_ci events->action = cpu_to_le16(CMD_ACT_GET); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events); 3018c2ecf20Sopenharmony_ci if (ret) 3028c2ecf20Sopenharmony_ci goto out_events; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci curr_mask = le16_to_cpu(events->events); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (new_mask) 3078c2ecf20Sopenharmony_ci new_mask = curr_mask | event_mask; 3088c2ecf20Sopenharmony_ci else 3098c2ecf20Sopenharmony_ci new_mask = curr_mask & ~event_mask; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci /* Now everything is set and we can send stuff down to the firmware */ 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci tlv = (void *)events->tlv; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci events->action = cpu_to_le16(CMD_ACT_SET); 3168c2ecf20Sopenharmony_ci events->events = cpu_to_le16(new_mask); 3178c2ecf20Sopenharmony_ci tlv->header.type = cpu_to_le16(tlv_type); 3188c2ecf20Sopenharmony_ci tlv->header.len = cpu_to_le16(sizeof(*tlv) - sizeof(tlv->header)); 3198c2ecf20Sopenharmony_ci tlv->value = value; 3208c2ecf20Sopenharmony_ci if (tlv_type != TLV_TYPE_BCNMISS) 3218c2ecf20Sopenharmony_ci tlv->freq = freq; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci /* The command header, the action, the event mask, and one TLV */ 3248c2ecf20Sopenharmony_ci events->hdr.size = cpu_to_le16(sizeof(events->hdr) + 4 + sizeof(*tlv)); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if (!ret) 3298c2ecf20Sopenharmony_ci ret = count; 3308c2ecf20Sopenharmony_ci out_events: 3318c2ecf20Sopenharmony_ci kfree(events); 3328c2ecf20Sopenharmony_ci out_page: 3338c2ecf20Sopenharmony_ci kfree(buf); 3348c2ecf20Sopenharmony_ci return ret; 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic ssize_t lbs_lowrssi_read(struct file *file, char __user *userbuf, 3398c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci return lbs_threshold_read(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW, 3428c2ecf20Sopenharmony_ci file, userbuf, count, ppos); 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic ssize_t lbs_lowrssi_write(struct file *file, const char __user *userbuf, 3478c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci return lbs_threshold_write(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW, 3508c2ecf20Sopenharmony_ci file, userbuf, count, ppos); 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic ssize_t lbs_lowsnr_read(struct file *file, char __user *userbuf, 3558c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci return lbs_threshold_read(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW, 3588c2ecf20Sopenharmony_ci file, userbuf, count, ppos); 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic ssize_t lbs_lowsnr_write(struct file *file, const char __user *userbuf, 3638c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci return lbs_threshold_write(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW, 3668c2ecf20Sopenharmony_ci file, userbuf, count, ppos); 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic ssize_t lbs_failcount_read(struct file *file, char __user *userbuf, 3718c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci return lbs_threshold_read(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT, 3748c2ecf20Sopenharmony_ci file, userbuf, count, ppos); 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_cistatic ssize_t lbs_failcount_write(struct file *file, const char __user *userbuf, 3798c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci return lbs_threshold_write(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT, 3828c2ecf20Sopenharmony_ci file, userbuf, count, ppos); 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistatic ssize_t lbs_highrssi_read(struct file *file, char __user *userbuf, 3878c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci return lbs_threshold_read(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH, 3908c2ecf20Sopenharmony_ci file, userbuf, count, ppos); 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_cistatic ssize_t lbs_highrssi_write(struct file *file, const char __user *userbuf, 3958c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci return lbs_threshold_write(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH, 3988c2ecf20Sopenharmony_ci file, userbuf, count, ppos); 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic ssize_t lbs_highsnr_read(struct file *file, char __user *userbuf, 4038c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci return lbs_threshold_read(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH, 4068c2ecf20Sopenharmony_ci file, userbuf, count, ppos); 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cistatic ssize_t lbs_highsnr_write(struct file *file, const char __user *userbuf, 4118c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci return lbs_threshold_write(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH, 4148c2ecf20Sopenharmony_ci file, userbuf, count, ppos); 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic ssize_t lbs_bcnmiss_read(struct file *file, char __user *userbuf, 4188c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci return lbs_threshold_read(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS, 4218c2ecf20Sopenharmony_ci file, userbuf, count, ppos); 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic ssize_t lbs_bcnmiss_write(struct file *file, const char __user *userbuf, 4268c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci return lbs_threshold_write(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS, 4298c2ecf20Sopenharmony_ci file, userbuf, count, ppos); 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_cistatic ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf, 4348c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 4358c2ecf20Sopenharmony_ci{ 4368c2ecf20Sopenharmony_ci struct lbs_private *priv = file->private_data; 4378c2ecf20Sopenharmony_ci ssize_t pos = 0; 4388c2ecf20Sopenharmony_ci int ret; 4398c2ecf20Sopenharmony_ci unsigned long addr = get_zeroed_page(GFP_KERNEL); 4408c2ecf20Sopenharmony_ci char *buf = (char *)addr; 4418c2ecf20Sopenharmony_ci u32 val = 0; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci if (!buf) 4448c2ecf20Sopenharmony_ci return -ENOMEM; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci ret = lbs_get_reg(priv, CMD_MAC_REG_ACCESS, priv->mac_offset, &val); 4478c2ecf20Sopenharmony_ci mdelay(10); 4488c2ecf20Sopenharmony_ci if (!ret) { 4498c2ecf20Sopenharmony_ci pos = snprintf(buf, len, "MAC[0x%x] = 0x%08x\n", 4508c2ecf20Sopenharmony_ci priv->mac_offset, val); 4518c2ecf20Sopenharmony_ci ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci free_page(addr); 4548c2ecf20Sopenharmony_ci return ret; 4558c2ecf20Sopenharmony_ci} 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_cistatic ssize_t lbs_rdmac_write(struct file *file, 4588c2ecf20Sopenharmony_ci const char __user *userbuf, 4598c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci struct lbs_private *priv = file->private_data; 4628c2ecf20Sopenharmony_ci char *buf; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci buf = memdup_user_nul(userbuf, min(count, len - 1)); 4658c2ecf20Sopenharmony_ci if (IS_ERR(buf)) 4668c2ecf20Sopenharmony_ci return PTR_ERR(buf); 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci priv->mac_offset = simple_strtoul(buf, NULL, 16); 4698c2ecf20Sopenharmony_ci kfree(buf); 4708c2ecf20Sopenharmony_ci return count; 4718c2ecf20Sopenharmony_ci} 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_cistatic ssize_t lbs_wrmac_write(struct file *file, 4748c2ecf20Sopenharmony_ci const char __user *userbuf, 4758c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci struct lbs_private *priv = file->private_data; 4798c2ecf20Sopenharmony_ci ssize_t res; 4808c2ecf20Sopenharmony_ci u32 offset, value; 4818c2ecf20Sopenharmony_ci char *buf; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci buf = memdup_user_nul(userbuf, min(count, len - 1)); 4848c2ecf20Sopenharmony_ci if (IS_ERR(buf)) 4858c2ecf20Sopenharmony_ci return PTR_ERR(buf); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci res = sscanf(buf, "%x %x", &offset, &value); 4888c2ecf20Sopenharmony_ci if (res != 2) { 4898c2ecf20Sopenharmony_ci res = -EFAULT; 4908c2ecf20Sopenharmony_ci goto out_unlock; 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci res = lbs_set_reg(priv, CMD_MAC_REG_ACCESS, offset, value); 4948c2ecf20Sopenharmony_ci mdelay(10); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if (!res) 4978c2ecf20Sopenharmony_ci res = count; 4988c2ecf20Sopenharmony_ciout_unlock: 4998c2ecf20Sopenharmony_ci kfree(buf); 5008c2ecf20Sopenharmony_ci return res; 5018c2ecf20Sopenharmony_ci} 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_cistatic ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf, 5048c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci struct lbs_private *priv = file->private_data; 5078c2ecf20Sopenharmony_ci ssize_t pos = 0; 5088c2ecf20Sopenharmony_ci int ret; 5098c2ecf20Sopenharmony_ci unsigned long addr = get_zeroed_page(GFP_KERNEL); 5108c2ecf20Sopenharmony_ci char *buf = (char *)addr; 5118c2ecf20Sopenharmony_ci u32 val; 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci if (!buf) 5148c2ecf20Sopenharmony_ci return -ENOMEM; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci ret = lbs_get_reg(priv, CMD_BBP_REG_ACCESS, priv->bbp_offset, &val); 5178c2ecf20Sopenharmony_ci mdelay(10); 5188c2ecf20Sopenharmony_ci if (!ret) { 5198c2ecf20Sopenharmony_ci pos = snprintf(buf, len, "BBP[0x%x] = 0x%08x\n", 5208c2ecf20Sopenharmony_ci priv->bbp_offset, val); 5218c2ecf20Sopenharmony_ci ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci free_page(addr); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci return ret; 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cistatic ssize_t lbs_rdbbp_write(struct file *file, 5298c2ecf20Sopenharmony_ci const char __user *userbuf, 5308c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 5318c2ecf20Sopenharmony_ci{ 5328c2ecf20Sopenharmony_ci struct lbs_private *priv = file->private_data; 5338c2ecf20Sopenharmony_ci char *buf; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci buf = memdup_user_nul(userbuf, min(count, len - 1)); 5368c2ecf20Sopenharmony_ci if (IS_ERR(buf)) 5378c2ecf20Sopenharmony_ci return PTR_ERR(buf); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci priv->bbp_offset = simple_strtoul(buf, NULL, 16); 5408c2ecf20Sopenharmony_ci kfree(buf); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci return count; 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_cistatic ssize_t lbs_wrbbp_write(struct file *file, 5468c2ecf20Sopenharmony_ci const char __user *userbuf, 5478c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 5488c2ecf20Sopenharmony_ci{ 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci struct lbs_private *priv = file->private_data; 5518c2ecf20Sopenharmony_ci ssize_t res; 5528c2ecf20Sopenharmony_ci u32 offset, value; 5538c2ecf20Sopenharmony_ci char *buf; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci buf = memdup_user_nul(userbuf, min(count, len - 1)); 5568c2ecf20Sopenharmony_ci if (IS_ERR(buf)) 5578c2ecf20Sopenharmony_ci return PTR_ERR(buf); 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci res = sscanf(buf, "%x %x", &offset, &value); 5608c2ecf20Sopenharmony_ci if (res != 2) { 5618c2ecf20Sopenharmony_ci res = -EFAULT; 5628c2ecf20Sopenharmony_ci goto out_unlock; 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci res = lbs_set_reg(priv, CMD_BBP_REG_ACCESS, offset, value); 5668c2ecf20Sopenharmony_ci mdelay(10); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci if (!res) 5698c2ecf20Sopenharmony_ci res = count; 5708c2ecf20Sopenharmony_ciout_unlock: 5718c2ecf20Sopenharmony_ci kfree(buf); 5728c2ecf20Sopenharmony_ci return res; 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_cistatic ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf, 5768c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci struct lbs_private *priv = file->private_data; 5798c2ecf20Sopenharmony_ci ssize_t pos = 0; 5808c2ecf20Sopenharmony_ci int ret; 5818c2ecf20Sopenharmony_ci unsigned long addr = get_zeroed_page(GFP_KERNEL); 5828c2ecf20Sopenharmony_ci char *buf = (char *)addr; 5838c2ecf20Sopenharmony_ci u32 val; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci if (!buf) 5868c2ecf20Sopenharmony_ci return -ENOMEM; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci ret = lbs_get_reg(priv, CMD_RF_REG_ACCESS, priv->rf_offset, &val); 5898c2ecf20Sopenharmony_ci mdelay(10); 5908c2ecf20Sopenharmony_ci if (!ret) { 5918c2ecf20Sopenharmony_ci pos = snprintf(buf, len, "RF[0x%x] = 0x%08x\n", 5928c2ecf20Sopenharmony_ci priv->rf_offset, val); 5938c2ecf20Sopenharmony_ci ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci free_page(addr); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci return ret; 5988c2ecf20Sopenharmony_ci} 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_cistatic ssize_t lbs_rdrf_write(struct file *file, 6018c2ecf20Sopenharmony_ci const char __user *userbuf, 6028c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci struct lbs_private *priv = file->private_data; 6058c2ecf20Sopenharmony_ci char *buf; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci buf = memdup_user_nul(userbuf, min(count, len - 1)); 6088c2ecf20Sopenharmony_ci if (IS_ERR(buf)) 6098c2ecf20Sopenharmony_ci return PTR_ERR(buf); 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci priv->rf_offset = simple_strtoul(buf, NULL, 16); 6128c2ecf20Sopenharmony_ci kfree(buf); 6138c2ecf20Sopenharmony_ci return count; 6148c2ecf20Sopenharmony_ci} 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_cistatic ssize_t lbs_wrrf_write(struct file *file, 6178c2ecf20Sopenharmony_ci const char __user *userbuf, 6188c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci struct lbs_private *priv = file->private_data; 6228c2ecf20Sopenharmony_ci ssize_t res; 6238c2ecf20Sopenharmony_ci u32 offset, value; 6248c2ecf20Sopenharmony_ci char *buf; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci buf = memdup_user_nul(userbuf, min(count, len - 1)); 6278c2ecf20Sopenharmony_ci if (IS_ERR(buf)) 6288c2ecf20Sopenharmony_ci return PTR_ERR(buf); 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci res = sscanf(buf, "%x %x", &offset, &value); 6318c2ecf20Sopenharmony_ci if (res != 2) { 6328c2ecf20Sopenharmony_ci res = -EFAULT; 6338c2ecf20Sopenharmony_ci goto out_unlock; 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci res = lbs_set_reg(priv, CMD_RF_REG_ACCESS, offset, value); 6378c2ecf20Sopenharmony_ci mdelay(10); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci if (!res) 6408c2ecf20Sopenharmony_ci res = count; 6418c2ecf20Sopenharmony_ciout_unlock: 6428c2ecf20Sopenharmony_ci kfree(buf); 6438c2ecf20Sopenharmony_ci return res; 6448c2ecf20Sopenharmony_ci} 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci#define FOPS(fread, fwrite) { \ 6478c2ecf20Sopenharmony_ci .owner = THIS_MODULE, \ 6488c2ecf20Sopenharmony_ci .open = simple_open, \ 6498c2ecf20Sopenharmony_ci .read = (fread), \ 6508c2ecf20Sopenharmony_ci .write = (fwrite), \ 6518c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, \ 6528c2ecf20Sopenharmony_ci} 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_cistruct lbs_debugfs_files { 6558c2ecf20Sopenharmony_ci const char *name; 6568c2ecf20Sopenharmony_ci umode_t perm; 6578c2ecf20Sopenharmony_ci struct file_operations fops; 6588c2ecf20Sopenharmony_ci}; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_cistatic const struct lbs_debugfs_files debugfs_files[] = { 6618c2ecf20Sopenharmony_ci { "info", 0444, FOPS(lbs_dev_info, write_file_dummy), }, 6628c2ecf20Sopenharmony_ci { "sleepparams", 0644, FOPS(lbs_sleepparams_read, 6638c2ecf20Sopenharmony_ci lbs_sleepparams_write), }, 6648c2ecf20Sopenharmony_ci { "hostsleep", 0644, FOPS(lbs_host_sleep_read, 6658c2ecf20Sopenharmony_ci lbs_host_sleep_write), }, 6668c2ecf20Sopenharmony_ci}; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_cistatic const struct lbs_debugfs_files debugfs_events_files[] = { 6698c2ecf20Sopenharmony_ci {"low_rssi", 0644, FOPS(lbs_lowrssi_read, 6708c2ecf20Sopenharmony_ci lbs_lowrssi_write), }, 6718c2ecf20Sopenharmony_ci {"low_snr", 0644, FOPS(lbs_lowsnr_read, 6728c2ecf20Sopenharmony_ci lbs_lowsnr_write), }, 6738c2ecf20Sopenharmony_ci {"failure_count", 0644, FOPS(lbs_failcount_read, 6748c2ecf20Sopenharmony_ci lbs_failcount_write), }, 6758c2ecf20Sopenharmony_ci {"beacon_missed", 0644, FOPS(lbs_bcnmiss_read, 6768c2ecf20Sopenharmony_ci lbs_bcnmiss_write), }, 6778c2ecf20Sopenharmony_ci {"high_rssi", 0644, FOPS(lbs_highrssi_read, 6788c2ecf20Sopenharmony_ci lbs_highrssi_write), }, 6798c2ecf20Sopenharmony_ci {"high_snr", 0644, FOPS(lbs_highsnr_read, 6808c2ecf20Sopenharmony_ci lbs_highsnr_write), }, 6818c2ecf20Sopenharmony_ci}; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_cistatic const struct lbs_debugfs_files debugfs_regs_files[] = { 6848c2ecf20Sopenharmony_ci {"rdmac", 0644, FOPS(lbs_rdmac_read, lbs_rdmac_write), }, 6858c2ecf20Sopenharmony_ci {"wrmac", 0600, FOPS(NULL, lbs_wrmac_write), }, 6868c2ecf20Sopenharmony_ci {"rdbbp", 0644, FOPS(lbs_rdbbp_read, lbs_rdbbp_write), }, 6878c2ecf20Sopenharmony_ci {"wrbbp", 0600, FOPS(NULL, lbs_wrbbp_write), }, 6888c2ecf20Sopenharmony_ci {"rdrf", 0644, FOPS(lbs_rdrf_read, lbs_rdrf_write), }, 6898c2ecf20Sopenharmony_ci {"wrrf", 0600, FOPS(NULL, lbs_wrrf_write), }, 6908c2ecf20Sopenharmony_ci}; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_civoid lbs_debugfs_init(void) 6938c2ecf20Sopenharmony_ci{ 6948c2ecf20Sopenharmony_ci if (!lbs_dir) 6958c2ecf20Sopenharmony_ci lbs_dir = debugfs_create_dir("lbs_wireless", NULL); 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_civoid lbs_debugfs_remove(void) 6998c2ecf20Sopenharmony_ci{ 7008c2ecf20Sopenharmony_ci debugfs_remove(lbs_dir); 7018c2ecf20Sopenharmony_ci} 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_civoid lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev) 7048c2ecf20Sopenharmony_ci{ 7058c2ecf20Sopenharmony_ci int i; 7068c2ecf20Sopenharmony_ci const struct lbs_debugfs_files *files; 7078c2ecf20Sopenharmony_ci if (!lbs_dir) 7088c2ecf20Sopenharmony_ci goto exit; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci priv->debugfs_dir = debugfs_create_dir(dev->name, lbs_dir); 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci for (i=0; i<ARRAY_SIZE(debugfs_files); i++) { 7138c2ecf20Sopenharmony_ci files = &debugfs_files[i]; 7148c2ecf20Sopenharmony_ci priv->debugfs_files[i] = debugfs_create_file(files->name, 7158c2ecf20Sopenharmony_ci files->perm, 7168c2ecf20Sopenharmony_ci priv->debugfs_dir, 7178c2ecf20Sopenharmony_ci priv, 7188c2ecf20Sopenharmony_ci &files->fops); 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci priv->events_dir = debugfs_create_dir("subscribed_events", priv->debugfs_dir); 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci for (i=0; i<ARRAY_SIZE(debugfs_events_files); i++) { 7248c2ecf20Sopenharmony_ci files = &debugfs_events_files[i]; 7258c2ecf20Sopenharmony_ci priv->debugfs_events_files[i] = debugfs_create_file(files->name, 7268c2ecf20Sopenharmony_ci files->perm, 7278c2ecf20Sopenharmony_ci priv->events_dir, 7288c2ecf20Sopenharmony_ci priv, 7298c2ecf20Sopenharmony_ci &files->fops); 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci priv->regs_dir = debugfs_create_dir("registers", priv->debugfs_dir); 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci for (i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) { 7358c2ecf20Sopenharmony_ci files = &debugfs_regs_files[i]; 7368c2ecf20Sopenharmony_ci priv->debugfs_regs_files[i] = debugfs_create_file(files->name, 7378c2ecf20Sopenharmony_ci files->perm, 7388c2ecf20Sopenharmony_ci priv->regs_dir, 7398c2ecf20Sopenharmony_ci priv, 7408c2ecf20Sopenharmony_ci &files->fops); 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci#ifdef PROC_DEBUG 7448c2ecf20Sopenharmony_ci lbs_debug_init(priv); 7458c2ecf20Sopenharmony_ci#endif 7468c2ecf20Sopenharmony_ciexit: 7478c2ecf20Sopenharmony_ci return; 7488c2ecf20Sopenharmony_ci} 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_civoid lbs_debugfs_remove_one(struct lbs_private *priv) 7518c2ecf20Sopenharmony_ci{ 7528c2ecf20Sopenharmony_ci int i; 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci for(i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) 7558c2ecf20Sopenharmony_ci debugfs_remove(priv->debugfs_regs_files[i]); 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci debugfs_remove(priv->regs_dir); 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci for(i=0; i<ARRAY_SIZE(debugfs_events_files); i++) 7608c2ecf20Sopenharmony_ci debugfs_remove(priv->debugfs_events_files[i]); 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_ci debugfs_remove(priv->events_dir); 7638c2ecf20Sopenharmony_ci#ifdef PROC_DEBUG 7648c2ecf20Sopenharmony_ci debugfs_remove(priv->debugfs_debug); 7658c2ecf20Sopenharmony_ci#endif 7668c2ecf20Sopenharmony_ci for(i=0; i<ARRAY_SIZE(debugfs_files); i++) 7678c2ecf20Sopenharmony_ci debugfs_remove(priv->debugfs_files[i]); 7688c2ecf20Sopenharmony_ci debugfs_remove(priv->debugfs_dir); 7698c2ecf20Sopenharmony_ci} 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci/* debug entry */ 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci#ifdef PROC_DEBUG 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci#define item_size(n) (sizeof_field(struct lbs_private, n)) 7788c2ecf20Sopenharmony_ci#define item_addr(n) (offsetof(struct lbs_private, n)) 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_cistruct debug_data { 7828c2ecf20Sopenharmony_ci char name[32]; 7838c2ecf20Sopenharmony_ci u32 size; 7848c2ecf20Sopenharmony_ci size_t addr; 7858c2ecf20Sopenharmony_ci}; 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_ci/* To debug any member of struct lbs_private, simply add one line here. 7888c2ecf20Sopenharmony_ci */ 7898c2ecf20Sopenharmony_cistatic struct debug_data items[] = { 7908c2ecf20Sopenharmony_ci {"psmode", item_size(psmode), item_addr(psmode)}, 7918c2ecf20Sopenharmony_ci {"psstate", item_size(psstate), item_addr(psstate)}, 7928c2ecf20Sopenharmony_ci}; 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_cistatic int num_of_items = ARRAY_SIZE(items); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci/** 7978c2ecf20Sopenharmony_ci * lbs_debugfs_read - proc read function 7988c2ecf20Sopenharmony_ci * 7998c2ecf20Sopenharmony_ci * @file: file to read 8008c2ecf20Sopenharmony_ci * @userbuf: pointer to buffer 8018c2ecf20Sopenharmony_ci * @count: number of bytes to read 8028c2ecf20Sopenharmony_ci * @ppos: read data starting position 8038c2ecf20Sopenharmony_ci * 8048c2ecf20Sopenharmony_ci * returns: amount of data read or negative error code 8058c2ecf20Sopenharmony_ci */ 8068c2ecf20Sopenharmony_cistatic ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf, 8078c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 8088c2ecf20Sopenharmony_ci{ 8098c2ecf20Sopenharmony_ci int val = 0; 8108c2ecf20Sopenharmony_ci size_t pos = 0; 8118c2ecf20Sopenharmony_ci ssize_t res; 8128c2ecf20Sopenharmony_ci char *p; 8138c2ecf20Sopenharmony_ci int i; 8148c2ecf20Sopenharmony_ci struct debug_data *d; 8158c2ecf20Sopenharmony_ci unsigned long addr = get_zeroed_page(GFP_KERNEL); 8168c2ecf20Sopenharmony_ci char *buf = (char *)addr; 8178c2ecf20Sopenharmony_ci if (!buf) 8188c2ecf20Sopenharmony_ci return -ENOMEM; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci p = buf; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci d = file->private_data; 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci for (i = 0; i < num_of_items; i++) { 8258c2ecf20Sopenharmony_ci if (d[i].size == 1) 8268c2ecf20Sopenharmony_ci val = *((u8 *) d[i].addr); 8278c2ecf20Sopenharmony_ci else if (d[i].size == 2) 8288c2ecf20Sopenharmony_ci val = *((u16 *) d[i].addr); 8298c2ecf20Sopenharmony_ci else if (d[i].size == 4) 8308c2ecf20Sopenharmony_ci val = *((u32 *) d[i].addr); 8318c2ecf20Sopenharmony_ci else if (d[i].size == 8) 8328c2ecf20Sopenharmony_ci val = *((u64 *) d[i].addr); 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci pos += sprintf(p + pos, "%s=%d\n", d[i].name, val); 8358c2ecf20Sopenharmony_ci } 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci res = simple_read_from_buffer(userbuf, count, ppos, p, pos); 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci free_page(addr); 8408c2ecf20Sopenharmony_ci return res; 8418c2ecf20Sopenharmony_ci} 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci/** 8448c2ecf20Sopenharmony_ci * lbs_debugfs_write - proc write function 8458c2ecf20Sopenharmony_ci * 8468c2ecf20Sopenharmony_ci * @f: file pointer 8478c2ecf20Sopenharmony_ci * @buf: pointer to data buffer 8488c2ecf20Sopenharmony_ci * @cnt: data number to write 8498c2ecf20Sopenharmony_ci * @ppos: file position 8508c2ecf20Sopenharmony_ci * 8518c2ecf20Sopenharmony_ci * returns: amount of data written 8528c2ecf20Sopenharmony_ci */ 8538c2ecf20Sopenharmony_cistatic ssize_t lbs_debugfs_write(struct file *f, const char __user *buf, 8548c2ecf20Sopenharmony_ci size_t cnt, loff_t *ppos) 8558c2ecf20Sopenharmony_ci{ 8568c2ecf20Sopenharmony_ci int r, i; 8578c2ecf20Sopenharmony_ci char *pdata; 8588c2ecf20Sopenharmony_ci char *p; 8598c2ecf20Sopenharmony_ci char *p0; 8608c2ecf20Sopenharmony_ci char *p1; 8618c2ecf20Sopenharmony_ci char *p2; 8628c2ecf20Sopenharmony_ci struct debug_data *d = f->private_data; 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci if (cnt == 0) 8658c2ecf20Sopenharmony_ci return 0; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci pdata = memdup_user_nul(buf, cnt); 8688c2ecf20Sopenharmony_ci if (IS_ERR(pdata)) 8698c2ecf20Sopenharmony_ci return PTR_ERR(pdata); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci p0 = pdata; 8728c2ecf20Sopenharmony_ci for (i = 0; i < num_of_items; i++) { 8738c2ecf20Sopenharmony_ci do { 8748c2ecf20Sopenharmony_ci p = strstr(p0, d[i].name); 8758c2ecf20Sopenharmony_ci if (p == NULL) 8768c2ecf20Sopenharmony_ci break; 8778c2ecf20Sopenharmony_ci p1 = strchr(p, '\n'); 8788c2ecf20Sopenharmony_ci if (p1 == NULL) 8798c2ecf20Sopenharmony_ci break; 8808c2ecf20Sopenharmony_ci p0 = p1++; 8818c2ecf20Sopenharmony_ci p2 = strchr(p, '='); 8828c2ecf20Sopenharmony_ci if (!p2) 8838c2ecf20Sopenharmony_ci break; 8848c2ecf20Sopenharmony_ci p2++; 8858c2ecf20Sopenharmony_ci r = simple_strtoul(p2, NULL, 0); 8868c2ecf20Sopenharmony_ci if (d[i].size == 1) 8878c2ecf20Sopenharmony_ci *((u8 *) d[i].addr) = (u8) r; 8888c2ecf20Sopenharmony_ci else if (d[i].size == 2) 8898c2ecf20Sopenharmony_ci *((u16 *) d[i].addr) = (u16) r; 8908c2ecf20Sopenharmony_ci else if (d[i].size == 4) 8918c2ecf20Sopenharmony_ci *((u32 *) d[i].addr) = (u32) r; 8928c2ecf20Sopenharmony_ci else if (d[i].size == 8) 8938c2ecf20Sopenharmony_ci *((u64 *) d[i].addr) = (u64) r; 8948c2ecf20Sopenharmony_ci break; 8958c2ecf20Sopenharmony_ci } while (1); 8968c2ecf20Sopenharmony_ci } 8978c2ecf20Sopenharmony_ci kfree(pdata); 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci return (ssize_t)cnt; 9008c2ecf20Sopenharmony_ci} 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_cistatic const struct file_operations lbs_debug_fops = { 9038c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 9048c2ecf20Sopenharmony_ci .open = simple_open, 9058c2ecf20Sopenharmony_ci .write = lbs_debugfs_write, 9068c2ecf20Sopenharmony_ci .read = lbs_debugfs_read, 9078c2ecf20Sopenharmony_ci .llseek = default_llseek, 9088c2ecf20Sopenharmony_ci}; 9098c2ecf20Sopenharmony_ci 9108c2ecf20Sopenharmony_ci/** 9118c2ecf20Sopenharmony_ci * lbs_debug_init - create debug proc file 9128c2ecf20Sopenharmony_ci * 9138c2ecf20Sopenharmony_ci * @priv: pointer to &struct lbs_private 9148c2ecf20Sopenharmony_ci * 9158c2ecf20Sopenharmony_ci * returns: N/A 9168c2ecf20Sopenharmony_ci */ 9178c2ecf20Sopenharmony_cistatic void lbs_debug_init(struct lbs_private *priv) 9188c2ecf20Sopenharmony_ci{ 9198c2ecf20Sopenharmony_ci int i; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci if (!priv->debugfs_dir) 9228c2ecf20Sopenharmony_ci return; 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci for (i = 0; i < num_of_items; i++) 9258c2ecf20Sopenharmony_ci items[i].addr += (size_t) priv; 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci priv->debugfs_debug = debugfs_create_file("debug", 0644, 9288c2ecf20Sopenharmony_ci priv->debugfs_dir, &items[0], 9298c2ecf20Sopenharmony_ci &lbs_debug_fops); 9308c2ecf20Sopenharmony_ci} 9318c2ecf20Sopenharmony_ci#endif 932