1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2876c9d3aSMarcelo Tosatti #include <linux/dcache.h>
3876c9d3aSMarcelo Tosatti #include <linux/debugfs.h>
4876c9d3aSMarcelo Tosatti #include <linux/delay.h>
5a6b7a407SAlexey Dobriyan #include <linux/hardirq.h>
6876c9d3aSMarcelo Tosatti #include <linux/mm.h>
7d8b0fb51SGeert Uytterhoeven #include <linux/string.h>
85a0e3ad6STejun Heo #include <linux/slab.h>
9ee40fa06SPaul Gortmaker #include <linux/export.h>
1046868202SHolger Schurig
11876c9d3aSMarcelo Tosatti #include "decl.h"
123fbe104cSDavid Woodhouse #include "cmd.h"
13e86dc1caSKiran Divekar #include "debugfs.h"
14876c9d3aSMarcelo Tosatti
1510078321SHolger Schurig static struct dentry *lbs_dir;
16876c9d3aSMarcelo Tosatti static char *szStates[] = {
17876c9d3aSMarcelo Tosatti "Connected",
18876c9d3aSMarcelo Tosatti "Disconnected"
19876c9d3aSMarcelo Tosatti };
20876c9d3aSMarcelo Tosatti
2146868202SHolger Schurig #ifdef PROC_DEBUG
22e98a88ddSHolger Schurig static void lbs_debug_init(struct lbs_private *priv);
2346868202SHolger Schurig #endif
24876c9d3aSMarcelo Tosatti
write_file_dummy(struct file * file,const char __user * buf,size_t count,loff_t * ppos)25876c9d3aSMarcelo Tosatti static ssize_t write_file_dummy(struct file *file, const char __user *buf,
26876c9d3aSMarcelo Tosatti size_t count, loff_t *ppos)
27876c9d3aSMarcelo Tosatti {
28876c9d3aSMarcelo Tosatti return -EINVAL;
29876c9d3aSMarcelo Tosatti }
30876c9d3aSMarcelo Tosatti
31876c9d3aSMarcelo Tosatti static const size_t len = PAGE_SIZE;
32876c9d3aSMarcelo Tosatti
lbs_dev_info(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)3310078321SHolger Schurig static ssize_t lbs_dev_info(struct file *file, char __user *userbuf,
34876c9d3aSMarcelo Tosatti size_t count, loff_t *ppos)
35876c9d3aSMarcelo Tosatti {
3669f9032dSHolger Schurig struct lbs_private *priv = file->private_data;
37876c9d3aSMarcelo Tosatti size_t pos = 0;
38876c9d3aSMarcelo Tosatti unsigned long addr = get_zeroed_page(GFP_KERNEL);
39876c9d3aSMarcelo Tosatti char *buf = (char *)addr;
40876c9d3aSMarcelo Tosatti ssize_t res;
41ad43f8bfSKiran Divekar if (!buf)
42ad43f8bfSKiran Divekar return -ENOMEM;
43876c9d3aSMarcelo Tosatti
44876c9d3aSMarcelo Tosatti pos += snprintf(buf+pos, len-pos, "state = %s\n",
45aa21c004SDavid Woodhouse szStates[priv->connect_status]);
46876c9d3aSMarcelo Tosatti pos += snprintf(buf+pos, len-pos, "region_code = %02x\n",
47aa21c004SDavid Woodhouse (u32) priv->regioncode);
48876c9d3aSMarcelo Tosatti
49876c9d3aSMarcelo Tosatti res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
50876c9d3aSMarcelo Tosatti
51876c9d3aSMarcelo Tosatti free_page(addr);
52876c9d3aSMarcelo Tosatti return res;
53876c9d3aSMarcelo Tosatti }
54876c9d3aSMarcelo Tosatti
lbs_sleepparams_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)5510078321SHolger Schurig static ssize_t lbs_sleepparams_write(struct file *file,
56876c9d3aSMarcelo Tosatti const char __user *user_buf, size_t count,
57876c9d3aSMarcelo Tosatti loff_t *ppos)
58876c9d3aSMarcelo Tosatti {
5969f9032dSHolger Schurig struct lbs_private *priv = file->private_data;
60f0fc8696SAl Viro ssize_t ret;
613fbe104cSDavid Woodhouse struct sleep_params sp;
62876c9d3aSMarcelo Tosatti int p1, p2, p3, p4, p5, p6;
63f0fc8696SAl Viro char *buf;
64876c9d3aSMarcelo Tosatti
65f0fc8696SAl Viro buf = memdup_user_nul(user_buf, min(count, len - 1));
66f0fc8696SAl Viro if (IS_ERR(buf))
67f0fc8696SAl Viro return PTR_ERR(buf);
68f0fc8696SAl Viro
693fbe104cSDavid Woodhouse ret = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6);
703fbe104cSDavid Woodhouse if (ret != 6) {
713fbe104cSDavid Woodhouse ret = -EINVAL;
72876c9d3aSMarcelo Tosatti goto out_unlock;
73876c9d3aSMarcelo Tosatti }
743fbe104cSDavid Woodhouse sp.sp_error = p1;
753fbe104cSDavid Woodhouse sp.sp_offset = p2;
763fbe104cSDavid Woodhouse sp.sp_stabletime = p3;
773fbe104cSDavid Woodhouse sp.sp_calcontrol = p4;
783fbe104cSDavid Woodhouse sp.sp_extsleepclk = p5;
793fbe104cSDavid Woodhouse sp.sp_reserved = p6;
80876c9d3aSMarcelo Tosatti
813fbe104cSDavid Woodhouse ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_SET, &sp);
823fbe104cSDavid Woodhouse if (!ret)
833fbe104cSDavid Woodhouse ret = count;
843fbe104cSDavid Woodhouse else if (ret > 0)
853fbe104cSDavid Woodhouse ret = -EINVAL;
86876c9d3aSMarcelo Tosatti
87876c9d3aSMarcelo Tosatti out_unlock:
88f0fc8696SAl Viro kfree(buf);
893fbe104cSDavid Woodhouse return ret;
90876c9d3aSMarcelo Tosatti }
91876c9d3aSMarcelo Tosatti
lbs_sleepparams_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)9210078321SHolger Schurig static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf,
93876c9d3aSMarcelo Tosatti size_t count, loff_t *ppos)
94876c9d3aSMarcelo Tosatti {
9569f9032dSHolger Schurig struct lbs_private *priv = file->private_data;
963fbe104cSDavid Woodhouse ssize_t ret;
97876c9d3aSMarcelo Tosatti size_t pos = 0;
983fbe104cSDavid Woodhouse struct sleep_params sp;
99876c9d3aSMarcelo Tosatti unsigned long addr = get_zeroed_page(GFP_KERNEL);
100876c9d3aSMarcelo Tosatti char *buf = (char *)addr;
101ad43f8bfSKiran Divekar if (!buf)
102ad43f8bfSKiran Divekar return -ENOMEM;
103876c9d3aSMarcelo Tosatti
1043fbe104cSDavid Woodhouse ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp);
1053fbe104cSDavid Woodhouse if (ret)
106876c9d3aSMarcelo Tosatti goto out_unlock;
107876c9d3aSMarcelo Tosatti
1083fbe104cSDavid Woodhouse pos += snprintf(buf, len, "%d %d %d %d %d %d\n", sp.sp_error,
1093fbe104cSDavid Woodhouse sp.sp_offset, sp.sp_stabletime,
1103fbe104cSDavid Woodhouse sp.sp_calcontrol, sp.sp_extsleepclk,
1113fbe104cSDavid Woodhouse sp.sp_reserved);
112876c9d3aSMarcelo Tosatti
1133fbe104cSDavid Woodhouse ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
114876c9d3aSMarcelo Tosatti
115876c9d3aSMarcelo Tosatti out_unlock:
116876c9d3aSMarcelo Tosatti free_page(addr);
1173fbe104cSDavid Woodhouse return ret;
118876c9d3aSMarcelo Tosatti }
119876c9d3aSMarcelo Tosatti
lbs_host_sleep_write(struct file * file,const char __user * user_buf,size_t count,loff_t * ppos)1201311843cSAmitkumar Karwar static ssize_t lbs_host_sleep_write(struct file *file,
1211311843cSAmitkumar Karwar const char __user *user_buf, size_t count,
1221311843cSAmitkumar Karwar loff_t *ppos)
1231311843cSAmitkumar Karwar {
1241311843cSAmitkumar Karwar struct lbs_private *priv = file->private_data;
125f0fc8696SAl Viro ssize_t ret;
1261311843cSAmitkumar Karwar int host_sleep;
127f0fc8696SAl Viro char *buf;
1281311843cSAmitkumar Karwar
129f0fc8696SAl Viro buf = memdup_user_nul(user_buf, min(count, len - 1));
130f0fc8696SAl Viro if (IS_ERR(buf))
131f0fc8696SAl Viro return PTR_ERR(buf);
132f0fc8696SAl Viro
1331311843cSAmitkumar Karwar ret = sscanf(buf, "%d", &host_sleep);
1341311843cSAmitkumar Karwar if (ret != 1) {
1351311843cSAmitkumar Karwar ret = -EINVAL;
1361311843cSAmitkumar Karwar goto out_unlock;
1371311843cSAmitkumar Karwar }
1381311843cSAmitkumar Karwar
1391311843cSAmitkumar Karwar if (host_sleep == 0)
1401311843cSAmitkumar Karwar ret = lbs_set_host_sleep(priv, 0);
1411311843cSAmitkumar Karwar else if (host_sleep == 1) {
1421311843cSAmitkumar Karwar if (priv->wol_criteria == EHS_REMOVE_WAKEUP) {
143f3a57fd1SJoe Perches netdev_info(priv->dev,
144f3a57fd1SJoe Perches "wake parameters not configured\n");
1451311843cSAmitkumar Karwar ret = -EINVAL;
1461311843cSAmitkumar Karwar goto out_unlock;
1471311843cSAmitkumar Karwar }
1481311843cSAmitkumar Karwar ret = lbs_set_host_sleep(priv, 1);
1491311843cSAmitkumar Karwar } else {
150f3a57fd1SJoe Perches netdev_err(priv->dev, "invalid option\n");
1511311843cSAmitkumar Karwar ret = -EINVAL;
1521311843cSAmitkumar Karwar }
1531311843cSAmitkumar Karwar
1541311843cSAmitkumar Karwar if (!ret)
1551311843cSAmitkumar Karwar ret = count;
1561311843cSAmitkumar Karwar
1571311843cSAmitkumar Karwar out_unlock:
158f0fc8696SAl Viro kfree(buf);
1591311843cSAmitkumar Karwar return ret;
1601311843cSAmitkumar Karwar }
1611311843cSAmitkumar Karwar
lbs_host_sleep_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)1621311843cSAmitkumar Karwar static ssize_t lbs_host_sleep_read(struct file *file, char __user *userbuf,
1631311843cSAmitkumar Karwar size_t count, loff_t *ppos)
1641311843cSAmitkumar Karwar {
1651311843cSAmitkumar Karwar struct lbs_private *priv = file->private_data;
1661311843cSAmitkumar Karwar ssize_t ret;
1671311843cSAmitkumar Karwar size_t pos = 0;
1681311843cSAmitkumar Karwar unsigned long addr = get_zeroed_page(GFP_KERNEL);
1691311843cSAmitkumar Karwar char *buf = (char *)addr;
1701311843cSAmitkumar Karwar if (!buf)
1711311843cSAmitkumar Karwar return -ENOMEM;
1721311843cSAmitkumar Karwar
1731311843cSAmitkumar Karwar pos += snprintf(buf, len, "%d\n", priv->is_host_sleep_activated);
1741311843cSAmitkumar Karwar
1751311843cSAmitkumar Karwar ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
1761311843cSAmitkumar Karwar
1771311843cSAmitkumar Karwar free_page(addr);
1781311843cSAmitkumar Karwar return ret;
1791311843cSAmitkumar Karwar }
1801311843cSAmitkumar Karwar
1813a188649SHolger Schurig /*
1823a188649SHolger Schurig * When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might
1833a188649SHolger Schurig * get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the
1843a188649SHolger Schurig * firmware. Here's an example:
1853a188649SHolger Schurig * 04 01 02 00 00 00 05 01 02 00 00 00 06 01 02 00
1863a188649SHolger Schurig * 00 00 07 01 02 00 3c 00 00 00 00 00 00 00 03 03
1873a188649SHolger Schurig * 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
1883a188649SHolger Schurig *
1893a188649SHolger Schurig * The 04 01 is the TLV type (here TLV_TYPE_RSSI_LOW), 02 00 is the length,
1903a188649SHolger Schurig * 00 00 are the data bytes of this TLV. For this TLV, their meaning is
1913a188649SHolger Schurig * defined in mrvlietypes_thresholds
1923a188649SHolger Schurig *
1933a188649SHolger Schurig * This function searches in this TLV data chunk for a given TLV type
1943a188649SHolger Schurig * and returns a pointer to the first data byte of the TLV, or to NULL
1953a188649SHolger Schurig * if the TLV hasn't been found.
1963a188649SHolger Schurig */
lbs_tlv_find(uint16_t tlv_type,const uint8_t * tlv,uint16_t size)1975844d12eSDavid Woodhouse static void *lbs_tlv_find(uint16_t tlv_type, const uint8_t *tlv, uint16_t size)
198876c9d3aSMarcelo Tosatti {
19975b6a61aSDan Williams struct mrvl_ie_header *tlv_h;
2005844d12eSDavid Woodhouse uint16_t length;
2015844d12eSDavid Woodhouse ssize_t pos = 0;
2025844d12eSDavid Woodhouse
2033a188649SHolger Schurig while (pos < size) {
20475b6a61aSDan Williams tlv_h = (struct mrvl_ie_header *) tlv;
2055844d12eSDavid Woodhouse if (!tlv_h->len)
2063a188649SHolger Schurig return NULL;
2075844d12eSDavid Woodhouse if (tlv_h->type == cpu_to_le16(tlv_type))
2085844d12eSDavid Woodhouse return tlv_h;
2095844d12eSDavid Woodhouse length = le16_to_cpu(tlv_h->len) + sizeof(*tlv_h);
2103a188649SHolger Schurig pos += length;
2113a188649SHolger Schurig tlv += length;
2123a188649SHolger Schurig }
2133a188649SHolger Schurig return NULL;
214876c9d3aSMarcelo Tosatti }
215876c9d3aSMarcelo Tosatti
216876c9d3aSMarcelo Tosatti
lbs_threshold_read(uint16_t tlv_type,uint16_t event_mask,struct file * file,char __user * userbuf,size_t count,loff_t * ppos)2175844d12eSDavid Woodhouse static ssize_t lbs_threshold_read(uint16_t tlv_type, uint16_t event_mask,
2183a188649SHolger Schurig struct file *file, char __user *userbuf,
219876c9d3aSMarcelo Tosatti size_t count, loff_t *ppos)
220876c9d3aSMarcelo Tosatti {
2215844d12eSDavid Woodhouse struct cmd_ds_802_11_subscribe_event *subscribed;
22275b6a61aSDan Williams struct mrvl_ie_thresholds *got;
22369f9032dSHolger Schurig struct lbs_private *priv = file->private_data;
2245844d12eSDavid Woodhouse ssize_t ret = 0;
2253a188649SHolger Schurig size_t pos = 0;
2265844d12eSDavid Woodhouse char *buf;
2273a188649SHolger Schurig u8 value;
2283a188649SHolger Schurig u8 freq;
229b6b8abe4SHolger Schurig int events = 0;
230876c9d3aSMarcelo Tosatti
2315844d12eSDavid Woodhouse buf = (char *)get_zeroed_page(GFP_KERNEL);
2325844d12eSDavid Woodhouse if (!buf)
2335844d12eSDavid Woodhouse return -ENOMEM;
234876c9d3aSMarcelo Tosatti
2355844d12eSDavid Woodhouse subscribed = kzalloc(sizeof(*subscribed), GFP_KERNEL);
2365844d12eSDavid Woodhouse if (!subscribed) {
2375844d12eSDavid Woodhouse ret = -ENOMEM;
2385844d12eSDavid Woodhouse goto out_page;
239876c9d3aSMarcelo Tosatti }
240876c9d3aSMarcelo Tosatti
2415844d12eSDavid Woodhouse subscribed->hdr.size = cpu_to_le16(sizeof(*subscribed));
2425844d12eSDavid Woodhouse subscribed->action = cpu_to_le16(CMD_ACT_GET);
2435844d12eSDavid Woodhouse
2445844d12eSDavid Woodhouse ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, subscribed);
2455844d12eSDavid Woodhouse if (ret)
2465844d12eSDavid Woodhouse goto out_cmd;
2475844d12eSDavid Woodhouse
248b6b8abe4SHolger Schurig got = lbs_tlv_find(tlv_type, subscribed->tlv, sizeof(subscribed->tlv));
2493a188649SHolger Schurig if (got) {
2503a188649SHolger Schurig value = got->value;
2513a188649SHolger Schurig freq = got->freq;
252b6b8abe4SHolger Schurig events = le16_to_cpu(subscribed->events);
253876c9d3aSMarcelo Tosatti
2543a188649SHolger Schurig pos += snprintf(buf, len, "%d %d %d\n", value, freq,
255b6b8abe4SHolger Schurig !!(events & event_mask));
2565844d12eSDavid Woodhouse }
257876c9d3aSMarcelo Tosatti
2585844d12eSDavid Woodhouse ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
2593a188649SHolger Schurig
2605844d12eSDavid Woodhouse out_cmd:
2615844d12eSDavid Woodhouse kfree(subscribed);
2625844d12eSDavid Woodhouse
2635844d12eSDavid Woodhouse out_page:
2645844d12eSDavid Woodhouse free_page((unsigned long)buf);
2655844d12eSDavid Woodhouse return ret;
266876c9d3aSMarcelo Tosatti }
267876c9d3aSMarcelo Tosatti
2683a188649SHolger Schurig
lbs_threshold_write(uint16_t tlv_type,uint16_t event_mask,struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)2695844d12eSDavid Woodhouse static ssize_t lbs_threshold_write(uint16_t tlv_type, uint16_t event_mask,
2703a188649SHolger Schurig struct file *file,
2715844d12eSDavid Woodhouse const char __user *userbuf, size_t count,
2725844d12eSDavid Woodhouse loff_t *ppos)
273876c9d3aSMarcelo Tosatti {
2743a188649SHolger Schurig struct cmd_ds_802_11_subscribe_event *events;
27575b6a61aSDan Williams struct mrvl_ie_thresholds *tlv;
2765844d12eSDavid Woodhouse struct lbs_private *priv = file->private_data;
2775844d12eSDavid Woodhouse int value, freq, new_mask;
2785844d12eSDavid Woodhouse uint16_t curr_mask;
2795844d12eSDavid Woodhouse char *buf;
2805844d12eSDavid Woodhouse int ret;
2815844d12eSDavid Woodhouse
282f0fc8696SAl Viro buf = memdup_user_nul(userbuf, min(count, len - 1));
283f0fc8696SAl Viro if (IS_ERR(buf))
284f0fc8696SAl Viro return PTR_ERR(buf);
285876c9d3aSMarcelo Tosatti
2865844d12eSDavid Woodhouse ret = sscanf(buf, "%d %d %d", &value, &freq, &new_mask);
2875844d12eSDavid Woodhouse if (ret != 3) {
2885844d12eSDavid Woodhouse ret = -EINVAL;
2895844d12eSDavid Woodhouse goto out_page;
290876c9d3aSMarcelo Tosatti }
2915844d12eSDavid Woodhouse events = kzalloc(sizeof(*events), GFP_KERNEL);
2925844d12eSDavid Woodhouse if (!events) {
2935844d12eSDavid Woodhouse ret = -ENOMEM;
2945844d12eSDavid Woodhouse goto out_page;
2955844d12eSDavid Woodhouse }
2965844d12eSDavid Woodhouse
2975844d12eSDavid Woodhouse events->hdr.size = cpu_to_le16(sizeof(*events));
2985844d12eSDavid Woodhouse events->action = cpu_to_le16(CMD_ACT_GET);
2995844d12eSDavid Woodhouse
3005844d12eSDavid Woodhouse ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events);
3015844d12eSDavid Woodhouse if (ret)
3025844d12eSDavid Woodhouse goto out_events;
3035844d12eSDavid Woodhouse
3045844d12eSDavid Woodhouse curr_mask = le16_to_cpu(events->events);
305876c9d3aSMarcelo Tosatti
3063a188649SHolger Schurig if (new_mask)
3073a188649SHolger Schurig new_mask = curr_mask | event_mask;
3083a188649SHolger Schurig else
3093a188649SHolger Schurig new_mask = curr_mask & ~event_mask;
310876c9d3aSMarcelo Tosatti
3113a188649SHolger Schurig /* Now everything is set and we can send stuff down to the firmware */
3125844d12eSDavid Woodhouse
3135844d12eSDavid Woodhouse tlv = (void *)events->tlv;
3145844d12eSDavid Woodhouse
3153a188649SHolger Schurig events->action = cpu_to_le16(CMD_ACT_SET);
3163a188649SHolger Schurig events->events = cpu_to_le16(new_mask);
3173a188649SHolger Schurig tlv->header.type = cpu_to_le16(tlv_type);
3185844d12eSDavid Woodhouse tlv->header.len = cpu_to_le16(sizeof(*tlv) - sizeof(tlv->header));
3193a188649SHolger Schurig tlv->value = value;
3203a188649SHolger Schurig if (tlv_type != TLV_TYPE_BCNMISS)
3213a188649SHolger Schurig tlv->freq = freq;
3225844d12eSDavid Woodhouse
323a75eda43SHolger Schurig /* The command header, the action, the event mask, and one TLV */
324a75eda43SHolger Schurig events->hdr.size = cpu_to_le16(sizeof(events->hdr) + 4 + sizeof(*tlv));
3255844d12eSDavid Woodhouse
3265844d12eSDavid Woodhouse ret = lbs_cmd_with_response(priv, CMD_802_11_SUBSCRIBE_EVENT, events);
3275844d12eSDavid Woodhouse
3285844d12eSDavid Woodhouse if (!ret)
3295844d12eSDavid Woodhouse ret = count;
3305844d12eSDavid Woodhouse out_events:
3313a188649SHolger Schurig kfree(events);
3325844d12eSDavid Woodhouse out_page:
333f0fc8696SAl Viro kfree(buf);
3345844d12eSDavid Woodhouse return ret;
335876c9d3aSMarcelo Tosatti }
336876c9d3aSMarcelo Tosatti
3373a188649SHolger Schurig
lbs_lowrssi_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)3385844d12eSDavid Woodhouse static ssize_t lbs_lowrssi_read(struct file *file, char __user *userbuf,
339876c9d3aSMarcelo Tosatti size_t count, loff_t *ppos)
340876c9d3aSMarcelo Tosatti {
3413a188649SHolger Schurig return lbs_threshold_read(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
3423a188649SHolger Schurig file, userbuf, count, ppos);
343876c9d3aSMarcelo Tosatti }
344876c9d3aSMarcelo Tosatti
345876c9d3aSMarcelo Tosatti
lbs_lowrssi_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)3465844d12eSDavid Woodhouse static ssize_t lbs_lowrssi_write(struct file *file, const char __user *userbuf,
347876c9d3aSMarcelo Tosatti size_t count, loff_t *ppos)
348876c9d3aSMarcelo Tosatti {
3493a188649SHolger Schurig return lbs_threshold_write(TLV_TYPE_RSSI_LOW, CMD_SUBSCRIBE_RSSI_LOW,
3503a188649SHolger Schurig file, userbuf, count, ppos);
351876c9d3aSMarcelo Tosatti }
352876c9d3aSMarcelo Tosatti
353876c9d3aSMarcelo Tosatti
lbs_lowsnr_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)3545844d12eSDavid Woodhouse static ssize_t lbs_lowsnr_read(struct file *file, char __user *userbuf,
355876c9d3aSMarcelo Tosatti size_t count, loff_t *ppos)
356876c9d3aSMarcelo Tosatti {
3573a188649SHolger Schurig return lbs_threshold_read(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
3583a188649SHolger Schurig file, userbuf, count, ppos);
359876c9d3aSMarcelo Tosatti }
360876c9d3aSMarcelo Tosatti
361876c9d3aSMarcelo Tosatti
lbs_lowsnr_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)3625844d12eSDavid Woodhouse static ssize_t lbs_lowsnr_write(struct file *file, const char __user *userbuf,
363876c9d3aSMarcelo Tosatti size_t count, loff_t *ppos)
364876c9d3aSMarcelo Tosatti {
3653a188649SHolger Schurig return lbs_threshold_write(TLV_TYPE_SNR_LOW, CMD_SUBSCRIBE_SNR_LOW,
3663a188649SHolger Schurig file, userbuf, count, ppos);
367876c9d3aSMarcelo Tosatti }
368876c9d3aSMarcelo Tosatti
369876c9d3aSMarcelo Tosatti
lbs_failcount_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)3705844d12eSDavid Woodhouse static ssize_t lbs_failcount_read(struct file *file, char __user *userbuf,
371876c9d3aSMarcelo Tosatti size_t count, loff_t *ppos)
372876c9d3aSMarcelo Tosatti {
3733a188649SHolger Schurig return lbs_threshold_read(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
3743a188649SHolger Schurig file, userbuf, count, ppos);
375876c9d3aSMarcelo Tosatti }
376876c9d3aSMarcelo Tosatti
377876c9d3aSMarcelo Tosatti
lbs_failcount_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)3785844d12eSDavid Woodhouse static ssize_t lbs_failcount_write(struct file *file, const char __user *userbuf,
379876c9d3aSMarcelo Tosatti size_t count, loff_t *ppos)
380876c9d3aSMarcelo Tosatti {
3813a188649SHolger Schurig return lbs_threshold_write(TLV_TYPE_FAILCOUNT, CMD_SUBSCRIBE_FAILCOUNT,
3823a188649SHolger Schurig file, userbuf, count, ppos);
383876c9d3aSMarcelo Tosatti }
384876c9d3aSMarcelo Tosatti
385876c9d3aSMarcelo Tosatti
lbs_highrssi_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)3865844d12eSDavid Woodhouse static ssize_t lbs_highrssi_read(struct file *file, char __user *userbuf,
3873a188649SHolger Schurig size_t count, loff_t *ppos)
3883a188649SHolger Schurig {
3893a188649SHolger Schurig return lbs_threshold_read(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
3903a188649SHolger Schurig file, userbuf, count, ppos);
391876c9d3aSMarcelo Tosatti }
392876c9d3aSMarcelo Tosatti
3933a188649SHolger Schurig
lbs_highrssi_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)3945844d12eSDavid Woodhouse static ssize_t lbs_highrssi_write(struct file *file, const char __user *userbuf,
3953a188649SHolger Schurig size_t count, loff_t *ppos)
3963a188649SHolger Schurig {
3973a188649SHolger Schurig return lbs_threshold_write(TLV_TYPE_RSSI_HIGH, CMD_SUBSCRIBE_RSSI_HIGH,
3983a188649SHolger Schurig file, userbuf, count, ppos);
399876c9d3aSMarcelo Tosatti }
400876c9d3aSMarcelo Tosatti
4013a188649SHolger Schurig
lbs_highsnr_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)4025844d12eSDavid Woodhouse static ssize_t lbs_highsnr_read(struct file *file, char __user *userbuf,
4033a188649SHolger Schurig size_t count, loff_t *ppos)
4043a188649SHolger Schurig {
4053a188649SHolger Schurig return lbs_threshold_read(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
4063a188649SHolger Schurig file, userbuf, count, ppos);
407876c9d3aSMarcelo Tosatti }
408876c9d3aSMarcelo Tosatti
4093a188649SHolger Schurig
lbs_highsnr_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)4105844d12eSDavid Woodhouse static ssize_t lbs_highsnr_write(struct file *file, const char __user *userbuf,
4113a188649SHolger Schurig size_t count, loff_t *ppos)
4123a188649SHolger Schurig {
4133a188649SHolger Schurig return lbs_threshold_write(TLV_TYPE_SNR_HIGH, CMD_SUBSCRIBE_SNR_HIGH,
4143a188649SHolger Schurig file, userbuf, count, ppos);
4153a188649SHolger Schurig }
4163a188649SHolger Schurig
lbs_bcnmiss_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)4175844d12eSDavid Woodhouse static ssize_t lbs_bcnmiss_read(struct file *file, char __user *userbuf,
4183a188649SHolger Schurig size_t count, loff_t *ppos)
4193a188649SHolger Schurig {
4203a188649SHolger Schurig return lbs_threshold_read(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
4213a188649SHolger Schurig file, userbuf, count, ppos);
4223a188649SHolger Schurig }
4233a188649SHolger Schurig
4243a188649SHolger Schurig
lbs_bcnmiss_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)4255844d12eSDavid Woodhouse static ssize_t lbs_bcnmiss_write(struct file *file, const char __user *userbuf,
4263a188649SHolger Schurig size_t count, loff_t *ppos)
4273a188649SHolger Schurig {
4283a188649SHolger Schurig return lbs_threshold_write(TLV_TYPE_BCNMISS, CMD_SUBSCRIBE_BCNMISS,
4293a188649SHolger Schurig file, userbuf, count, ppos);
4303a188649SHolger Schurig }
4313a188649SHolger Schurig
4323a188649SHolger Schurig
lbs_rdmac_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)43310078321SHolger Schurig static ssize_t lbs_rdmac_read(struct file *file, char __user *userbuf,
434876c9d3aSMarcelo Tosatti size_t count, loff_t *ppos)
435876c9d3aSMarcelo Tosatti {
43669f9032dSHolger Schurig struct lbs_private *priv = file->private_data;
437876c9d3aSMarcelo Tosatti ssize_t pos = 0;
438876c9d3aSMarcelo Tosatti int ret;
439876c9d3aSMarcelo Tosatti unsigned long addr = get_zeroed_page(GFP_KERNEL);
440876c9d3aSMarcelo Tosatti char *buf = (char *)addr;
4414c7c6e00SDan Williams u32 val = 0;
4424c7c6e00SDan Williams
443ad43f8bfSKiran Divekar if (!buf)
444ad43f8bfSKiran Divekar return -ENOMEM;
445876c9d3aSMarcelo Tosatti
4464c7c6e00SDan Williams ret = lbs_get_reg(priv, CMD_MAC_REG_ACCESS, priv->mac_offset, &val);
447876c9d3aSMarcelo Tosatti mdelay(10);
448c0bbd576SAmitkumar Karwar if (!ret) {
4494c7c6e00SDan Williams pos = snprintf(buf, len, "MAC[0x%x] = 0x%08x\n",
4504c7c6e00SDan Williams priv->mac_offset, val);
451876c9d3aSMarcelo Tosatti ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
452c0bbd576SAmitkumar Karwar }
453876c9d3aSMarcelo Tosatti free_page(addr);
454876c9d3aSMarcelo Tosatti return ret;
455876c9d3aSMarcelo Tosatti }
456876c9d3aSMarcelo Tosatti
lbs_rdmac_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)45710078321SHolger Schurig static ssize_t lbs_rdmac_write(struct file *file,
458876c9d3aSMarcelo Tosatti const char __user *userbuf,
459876c9d3aSMarcelo Tosatti size_t count, loff_t *ppos)
460876c9d3aSMarcelo Tosatti {
46169f9032dSHolger Schurig struct lbs_private *priv = file->private_data;
462f0fc8696SAl Viro char *buf;
463876c9d3aSMarcelo Tosatti
464f0fc8696SAl Viro buf = memdup_user_nul(userbuf, min(count, len - 1));
465f0fc8696SAl Viro if (IS_ERR(buf))
466f0fc8696SAl Viro return PTR_ERR(buf);
467f0fc8696SAl Viro
4682c208890SJoe Perches priv->mac_offset = simple_strtoul(buf, NULL, 16);
469f0fc8696SAl Viro kfree(buf);
470f0fc8696SAl Viro return count;
471876c9d3aSMarcelo Tosatti }
472876c9d3aSMarcelo Tosatti
lbs_wrmac_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)47310078321SHolger Schurig static ssize_t lbs_wrmac_write(struct file *file,
474876c9d3aSMarcelo Tosatti const char __user *userbuf,
475876c9d3aSMarcelo Tosatti size_t count, loff_t *ppos)
476876c9d3aSMarcelo Tosatti {
477876c9d3aSMarcelo Tosatti
47869f9032dSHolger Schurig struct lbs_private *priv = file->private_data;
479f0fc8696SAl Viro ssize_t res;
480876c9d3aSMarcelo Tosatti u32 offset, value;
481f0fc8696SAl Viro char *buf;
482876c9d3aSMarcelo Tosatti
483f0fc8696SAl Viro buf = memdup_user_nul(userbuf, min(count, len - 1));
484f0fc8696SAl Viro if (IS_ERR(buf))
485f0fc8696SAl Viro return PTR_ERR(buf);
486f0fc8696SAl Viro
487876c9d3aSMarcelo Tosatti res = sscanf(buf, "%x %x", &offset, &value);
488876c9d3aSMarcelo Tosatti if (res != 2) {
489876c9d3aSMarcelo Tosatti res = -EFAULT;
490876c9d3aSMarcelo Tosatti goto out_unlock;
491876c9d3aSMarcelo Tosatti }
492876c9d3aSMarcelo Tosatti
4934c7c6e00SDan Williams res = lbs_set_reg(priv, CMD_MAC_REG_ACCESS, offset, value);
494876c9d3aSMarcelo Tosatti mdelay(10);
495876c9d3aSMarcelo Tosatti
496c0bbd576SAmitkumar Karwar if (!res)
497876c9d3aSMarcelo Tosatti res = count;
498876c9d3aSMarcelo Tosatti out_unlock:
499f0fc8696SAl Viro kfree(buf);
500876c9d3aSMarcelo Tosatti return res;
501876c9d3aSMarcelo Tosatti }
502876c9d3aSMarcelo Tosatti
lbs_rdbbp_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)50310078321SHolger Schurig static ssize_t lbs_rdbbp_read(struct file *file, char __user *userbuf,
504876c9d3aSMarcelo Tosatti size_t count, loff_t *ppos)
505876c9d3aSMarcelo Tosatti {
50669f9032dSHolger Schurig struct lbs_private *priv = file->private_data;
507876c9d3aSMarcelo Tosatti ssize_t pos = 0;
508876c9d3aSMarcelo Tosatti int ret;
509876c9d3aSMarcelo Tosatti unsigned long addr = get_zeroed_page(GFP_KERNEL);
510876c9d3aSMarcelo Tosatti char *buf = (char *)addr;
5114c7c6e00SDan Williams u32 val;
5124c7c6e00SDan Williams
513ad43f8bfSKiran Divekar if (!buf)
514ad43f8bfSKiran Divekar return -ENOMEM;
515876c9d3aSMarcelo Tosatti
5164c7c6e00SDan Williams ret = lbs_get_reg(priv, CMD_BBP_REG_ACCESS, priv->bbp_offset, &val);
517876c9d3aSMarcelo Tosatti mdelay(10);
518c0bbd576SAmitkumar Karwar if (!ret) {
5194c7c6e00SDan Williams pos = snprintf(buf, len, "BBP[0x%x] = 0x%08x\n",
5204c7c6e00SDan Williams priv->bbp_offset, val);
521876c9d3aSMarcelo Tosatti ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
522c0bbd576SAmitkumar Karwar }
523876c9d3aSMarcelo Tosatti free_page(addr);
524876c9d3aSMarcelo Tosatti
525876c9d3aSMarcelo Tosatti return ret;
526876c9d3aSMarcelo Tosatti }
527876c9d3aSMarcelo Tosatti
lbs_rdbbp_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)52810078321SHolger Schurig static ssize_t lbs_rdbbp_write(struct file *file,
529876c9d3aSMarcelo Tosatti const char __user *userbuf,
530876c9d3aSMarcelo Tosatti size_t count, loff_t *ppos)
531876c9d3aSMarcelo Tosatti {
53269f9032dSHolger Schurig struct lbs_private *priv = file->private_data;
533f0fc8696SAl Viro char *buf;
534876c9d3aSMarcelo Tosatti
535f0fc8696SAl Viro buf = memdup_user_nul(userbuf, min(count, len - 1));
536f0fc8696SAl Viro if (IS_ERR(buf))
537f0fc8696SAl Viro return PTR_ERR(buf);
538f0fc8696SAl Viro
5392c208890SJoe Perches priv->bbp_offset = simple_strtoul(buf, NULL, 16);
540f0fc8696SAl Viro kfree(buf);
541f0fc8696SAl Viro
542f0fc8696SAl Viro return count;
543876c9d3aSMarcelo Tosatti }
544876c9d3aSMarcelo Tosatti
lbs_wrbbp_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)54510078321SHolger Schurig static ssize_t lbs_wrbbp_write(struct file *file,
546876c9d3aSMarcelo Tosatti const char __user *userbuf,
547876c9d3aSMarcelo Tosatti size_t count, loff_t *ppos)
548876c9d3aSMarcelo Tosatti {
549876c9d3aSMarcelo Tosatti
55069f9032dSHolger Schurig struct lbs_private *priv = file->private_data;
551f0fc8696SAl Viro ssize_t res;
552876c9d3aSMarcelo Tosatti u32 offset, value;
553f0fc8696SAl Viro char *buf;
554876c9d3aSMarcelo Tosatti
555f0fc8696SAl Viro buf = memdup_user_nul(userbuf, min(count, len - 1));
556f0fc8696SAl Viro if (IS_ERR(buf))
557f0fc8696SAl Viro return PTR_ERR(buf);
558f0fc8696SAl Viro
559876c9d3aSMarcelo Tosatti res = sscanf(buf, "%x %x", &offset, &value);
560876c9d3aSMarcelo Tosatti if (res != 2) {
561876c9d3aSMarcelo Tosatti res = -EFAULT;
562876c9d3aSMarcelo Tosatti goto out_unlock;
563876c9d3aSMarcelo Tosatti }
564876c9d3aSMarcelo Tosatti
5654c7c6e00SDan Williams res = lbs_set_reg(priv, CMD_BBP_REG_ACCESS, offset, value);
566876c9d3aSMarcelo Tosatti mdelay(10);
567876c9d3aSMarcelo Tosatti
568c0bbd576SAmitkumar Karwar if (!res)
569876c9d3aSMarcelo Tosatti res = count;
570876c9d3aSMarcelo Tosatti out_unlock:
571f0fc8696SAl Viro kfree(buf);
572876c9d3aSMarcelo Tosatti return res;
573876c9d3aSMarcelo Tosatti }
574876c9d3aSMarcelo Tosatti
lbs_rdrf_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)57510078321SHolger Schurig static ssize_t lbs_rdrf_read(struct file *file, char __user *userbuf,
576876c9d3aSMarcelo Tosatti size_t count, loff_t *ppos)
577876c9d3aSMarcelo Tosatti {
57869f9032dSHolger Schurig struct lbs_private *priv = file->private_data;
579876c9d3aSMarcelo Tosatti ssize_t pos = 0;
580876c9d3aSMarcelo Tosatti int ret;
581876c9d3aSMarcelo Tosatti unsigned long addr = get_zeroed_page(GFP_KERNEL);
582876c9d3aSMarcelo Tosatti char *buf = (char *)addr;
5834c7c6e00SDan Williams u32 val;
5844c7c6e00SDan Williams
585ad43f8bfSKiran Divekar if (!buf)
586ad43f8bfSKiran Divekar return -ENOMEM;
587876c9d3aSMarcelo Tosatti
5884c7c6e00SDan Williams ret = lbs_get_reg(priv, CMD_RF_REG_ACCESS, priv->rf_offset, &val);
589876c9d3aSMarcelo Tosatti mdelay(10);
590c0bbd576SAmitkumar Karwar if (!ret) {
5914c7c6e00SDan Williams pos = snprintf(buf, len, "RF[0x%x] = 0x%08x\n",
5924c7c6e00SDan Williams priv->rf_offset, val);
593876c9d3aSMarcelo Tosatti ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
594c0bbd576SAmitkumar Karwar }
595876c9d3aSMarcelo Tosatti free_page(addr);
596876c9d3aSMarcelo Tosatti
597876c9d3aSMarcelo Tosatti return ret;
598876c9d3aSMarcelo Tosatti }
599876c9d3aSMarcelo Tosatti
lbs_rdrf_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)60010078321SHolger Schurig static ssize_t lbs_rdrf_write(struct file *file,
601876c9d3aSMarcelo Tosatti const char __user *userbuf,
602876c9d3aSMarcelo Tosatti size_t count, loff_t *ppos)
603876c9d3aSMarcelo Tosatti {
60469f9032dSHolger Schurig struct lbs_private *priv = file->private_data;
605f0fc8696SAl Viro char *buf;
606876c9d3aSMarcelo Tosatti
607f0fc8696SAl Viro buf = memdup_user_nul(userbuf, min(count, len - 1));
608f0fc8696SAl Viro if (IS_ERR(buf))
609f0fc8696SAl Viro return PTR_ERR(buf);
610f0fc8696SAl Viro
6114101dec9SJan Engelhardt priv->rf_offset = simple_strtoul(buf, NULL, 16);
612f0fc8696SAl Viro kfree(buf);
613f0fc8696SAl Viro return count;
614876c9d3aSMarcelo Tosatti }
615876c9d3aSMarcelo Tosatti
lbs_wrrf_write(struct file * file,const char __user * userbuf,size_t count,loff_t * ppos)61610078321SHolger Schurig static ssize_t lbs_wrrf_write(struct file *file,
617876c9d3aSMarcelo Tosatti const char __user *userbuf,
618876c9d3aSMarcelo Tosatti size_t count, loff_t *ppos)
619876c9d3aSMarcelo Tosatti {
620876c9d3aSMarcelo Tosatti
62169f9032dSHolger Schurig struct lbs_private *priv = file->private_data;
622f0fc8696SAl Viro ssize_t res;
623876c9d3aSMarcelo Tosatti u32 offset, value;
624f0fc8696SAl Viro char *buf;
625876c9d3aSMarcelo Tosatti
626f0fc8696SAl Viro buf = memdup_user_nul(userbuf, min(count, len - 1));
627f0fc8696SAl Viro if (IS_ERR(buf))
628f0fc8696SAl Viro return PTR_ERR(buf);
629f0fc8696SAl Viro
630876c9d3aSMarcelo Tosatti res = sscanf(buf, "%x %x", &offset, &value);
631876c9d3aSMarcelo Tosatti if (res != 2) {
632876c9d3aSMarcelo Tosatti res = -EFAULT;
633876c9d3aSMarcelo Tosatti goto out_unlock;
634876c9d3aSMarcelo Tosatti }
635876c9d3aSMarcelo Tosatti
6364c7c6e00SDan Williams res = lbs_set_reg(priv, CMD_RF_REG_ACCESS, offset, value);
637876c9d3aSMarcelo Tosatti mdelay(10);
638876c9d3aSMarcelo Tosatti
639c0bbd576SAmitkumar Karwar if (!res)
640876c9d3aSMarcelo Tosatti res = count;
641876c9d3aSMarcelo Tosatti out_unlock:
642f0fc8696SAl Viro kfree(buf);
643876c9d3aSMarcelo Tosatti return res;
644876c9d3aSMarcelo Tosatti }
645876c9d3aSMarcelo Tosatti
646876c9d3aSMarcelo Tosatti #define FOPS(fread, fwrite) { \
647876c9d3aSMarcelo Tosatti .owner = THIS_MODULE, \
648234e3405SStephen Boyd .open = simple_open, \
649876c9d3aSMarcelo Tosatti .read = (fread), \
650876c9d3aSMarcelo Tosatti .write = (fwrite), \
6512b18ab36SArnd Bergmann .llseek = generic_file_llseek, \
652876c9d3aSMarcelo Tosatti }
653876c9d3aSMarcelo Tosatti
65410078321SHolger Schurig struct lbs_debugfs_files {
6554101dec9SJan Engelhardt const char *name;
656f4ae40a6SAl Viro umode_t perm;
657876c9d3aSMarcelo Tosatti struct file_operations fops;
658876c9d3aSMarcelo Tosatti };
659876c9d3aSMarcelo Tosatti
6604101dec9SJan Engelhardt static const struct lbs_debugfs_files debugfs_files[] = {
66110078321SHolger Schurig { "info", 0444, FOPS(lbs_dev_info, write_file_dummy), },
66210078321SHolger Schurig { "sleepparams", 0644, FOPS(lbs_sleepparams_read,
66310078321SHolger Schurig lbs_sleepparams_write), },
6641311843cSAmitkumar Karwar { "hostsleep", 0644, FOPS(lbs_host_sleep_read,
6651311843cSAmitkumar Karwar lbs_host_sleep_write), },
666876c9d3aSMarcelo Tosatti };
667876c9d3aSMarcelo Tosatti
6684101dec9SJan Engelhardt static const struct lbs_debugfs_files debugfs_events_files[] = {
66910078321SHolger Schurig {"low_rssi", 0644, FOPS(lbs_lowrssi_read,
67010078321SHolger Schurig lbs_lowrssi_write), },
67110078321SHolger Schurig {"low_snr", 0644, FOPS(lbs_lowsnr_read,
67210078321SHolger Schurig lbs_lowsnr_write), },
67310078321SHolger Schurig {"failure_count", 0644, FOPS(lbs_failcount_read,
67410078321SHolger Schurig lbs_failcount_write), },
67510078321SHolger Schurig {"beacon_missed", 0644, FOPS(lbs_bcnmiss_read,
67610078321SHolger Schurig lbs_bcnmiss_write), },
67710078321SHolger Schurig {"high_rssi", 0644, FOPS(lbs_highrssi_read,
67810078321SHolger Schurig lbs_highrssi_write), },
67910078321SHolger Schurig {"high_snr", 0644, FOPS(lbs_highsnr_read,
68010078321SHolger Schurig lbs_highsnr_write), },
681876c9d3aSMarcelo Tosatti };
682876c9d3aSMarcelo Tosatti
6834101dec9SJan Engelhardt static const struct lbs_debugfs_files debugfs_regs_files[] = {
68410078321SHolger Schurig {"rdmac", 0644, FOPS(lbs_rdmac_read, lbs_rdmac_write), },
68510078321SHolger Schurig {"wrmac", 0600, FOPS(NULL, lbs_wrmac_write), },
68610078321SHolger Schurig {"rdbbp", 0644, FOPS(lbs_rdbbp_read, lbs_rdbbp_write), },
68710078321SHolger Schurig {"wrbbp", 0600, FOPS(NULL, lbs_wrbbp_write), },
68810078321SHolger Schurig {"rdrf", 0644, FOPS(lbs_rdrf_read, lbs_rdrf_write), },
68910078321SHolger Schurig {"wrrf", 0600, FOPS(NULL, lbs_wrrf_write), },
690876c9d3aSMarcelo Tosatti };
691876c9d3aSMarcelo Tosatti
lbs_debugfs_init(void)69210078321SHolger Schurig void lbs_debugfs_init(void)
693876c9d3aSMarcelo Tosatti {
69410078321SHolger Schurig if (!lbs_dir)
69510078321SHolger Schurig lbs_dir = debugfs_create_dir("lbs_wireless", NULL);
696876c9d3aSMarcelo Tosatti }
697876c9d3aSMarcelo Tosatti
lbs_debugfs_remove(void)69810078321SHolger Schurig void lbs_debugfs_remove(void)
699876c9d3aSMarcelo Tosatti {
70010078321SHolger Schurig debugfs_remove(lbs_dir);
701876c9d3aSMarcelo Tosatti }
702876c9d3aSMarcelo Tosatti
lbs_debugfs_init_one(struct lbs_private * priv,struct net_device * dev)70369f9032dSHolger Schurig void lbs_debugfs_init_one(struct lbs_private *priv, struct net_device *dev)
704876c9d3aSMarcelo Tosatti {
705876c9d3aSMarcelo Tosatti int i;
7064101dec9SJan Engelhardt const struct lbs_debugfs_files *files;
70710078321SHolger Schurig if (!lbs_dir)
708876c9d3aSMarcelo Tosatti goto exit;
709876c9d3aSMarcelo Tosatti
71010078321SHolger Schurig priv->debugfs_dir = debugfs_create_dir(dev->name, lbs_dir);
711876c9d3aSMarcelo Tosatti
712876c9d3aSMarcelo Tosatti for (i=0; i<ARRAY_SIZE(debugfs_files); i++) {
713876c9d3aSMarcelo Tosatti files = &debugfs_files[i];
714876c9d3aSMarcelo Tosatti priv->debugfs_files[i] = debugfs_create_file(files->name,
715876c9d3aSMarcelo Tosatti files->perm,
716876c9d3aSMarcelo Tosatti priv->debugfs_dir,
717876c9d3aSMarcelo Tosatti priv,
718876c9d3aSMarcelo Tosatti &files->fops);
719876c9d3aSMarcelo Tosatti }
720876c9d3aSMarcelo Tosatti
721876c9d3aSMarcelo Tosatti priv->events_dir = debugfs_create_dir("subscribed_events", priv->debugfs_dir);
722876c9d3aSMarcelo Tosatti
723876c9d3aSMarcelo Tosatti for (i=0; i<ARRAY_SIZE(debugfs_events_files); i++) {
724876c9d3aSMarcelo Tosatti files = &debugfs_events_files[i];
725876c9d3aSMarcelo Tosatti priv->debugfs_events_files[i] = debugfs_create_file(files->name,
726876c9d3aSMarcelo Tosatti files->perm,
727876c9d3aSMarcelo Tosatti priv->events_dir,
728876c9d3aSMarcelo Tosatti priv,
729876c9d3aSMarcelo Tosatti &files->fops);
730876c9d3aSMarcelo Tosatti }
731876c9d3aSMarcelo Tosatti
732876c9d3aSMarcelo Tosatti priv->regs_dir = debugfs_create_dir("registers", priv->debugfs_dir);
733876c9d3aSMarcelo Tosatti
734876c9d3aSMarcelo Tosatti for (i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) {
735876c9d3aSMarcelo Tosatti files = &debugfs_regs_files[i];
736876c9d3aSMarcelo Tosatti priv->debugfs_regs_files[i] = debugfs_create_file(files->name,
737876c9d3aSMarcelo Tosatti files->perm,
738876c9d3aSMarcelo Tosatti priv->regs_dir,
739876c9d3aSMarcelo Tosatti priv,
740876c9d3aSMarcelo Tosatti &files->fops);
741876c9d3aSMarcelo Tosatti }
742876c9d3aSMarcelo Tosatti
743876c9d3aSMarcelo Tosatti #ifdef PROC_DEBUG
744e98a88ddSHolger Schurig lbs_debug_init(priv);
745876c9d3aSMarcelo Tosatti #endif
746876c9d3aSMarcelo Tosatti exit:
747876c9d3aSMarcelo Tosatti return;
748876c9d3aSMarcelo Tosatti }
749876c9d3aSMarcelo Tosatti
lbs_debugfs_remove_one(struct lbs_private * priv)75069f9032dSHolger Schurig void lbs_debugfs_remove_one(struct lbs_private *priv)
751876c9d3aSMarcelo Tosatti {
752876c9d3aSMarcelo Tosatti int i;
753876c9d3aSMarcelo Tosatti
754876c9d3aSMarcelo Tosatti for(i=0; i<ARRAY_SIZE(debugfs_regs_files); i++)
755876c9d3aSMarcelo Tosatti debugfs_remove(priv->debugfs_regs_files[i]);
756876c9d3aSMarcelo Tosatti
757876c9d3aSMarcelo Tosatti debugfs_remove(priv->regs_dir);
758876c9d3aSMarcelo Tosatti
7590b7db956SHolger Schurig for(i=0; i<ARRAY_SIZE(debugfs_events_files); i++)
760876c9d3aSMarcelo Tosatti debugfs_remove(priv->debugfs_events_files[i]);
761876c9d3aSMarcelo Tosatti
762876c9d3aSMarcelo Tosatti debugfs_remove(priv->events_dir);
763876c9d3aSMarcelo Tosatti #ifdef PROC_DEBUG
764876c9d3aSMarcelo Tosatti debugfs_remove(priv->debugfs_debug);
765876c9d3aSMarcelo Tosatti #endif
766876c9d3aSMarcelo Tosatti for(i=0; i<ARRAY_SIZE(debugfs_files); i++)
767876c9d3aSMarcelo Tosatti debugfs_remove(priv->debugfs_files[i]);
7680b7db956SHolger Schurig debugfs_remove(priv->debugfs_dir);
769876c9d3aSMarcelo Tosatti }
770876c9d3aSMarcelo Tosatti
77146868202SHolger Schurig
77246868202SHolger Schurig
773876c9d3aSMarcelo Tosatti /* debug entry */
774876c9d3aSMarcelo Tosatti
77546868202SHolger Schurig #ifdef PROC_DEBUG
77646868202SHolger Schurig
777*c593642cSPankaj Bharadiya #define item_size(n) (sizeof_field(struct lbs_private, n))
778aa21c004SDavid Woodhouse #define item_addr(n) (offsetof(struct lbs_private, n))
779876c9d3aSMarcelo Tosatti
78046868202SHolger Schurig
781876c9d3aSMarcelo Tosatti struct debug_data {
782876c9d3aSMarcelo Tosatti char name[32];
783876c9d3aSMarcelo Tosatti u32 size;
7844269e2adSDan Williams size_t addr;
785876c9d3aSMarcelo Tosatti };
786876c9d3aSMarcelo Tosatti
787aa21c004SDavid Woodhouse /* To debug any member of struct lbs_private, simply add one line here.
788876c9d3aSMarcelo Tosatti */
789876c9d3aSMarcelo Tosatti static struct debug_data items[] = {
790876c9d3aSMarcelo Tosatti {"psmode", item_size(psmode), item_addr(psmode)},
791876c9d3aSMarcelo Tosatti {"psstate", item_size(psstate), item_addr(psstate)},
792876c9d3aSMarcelo Tosatti };
793876c9d3aSMarcelo Tosatti
794d2f11e09STony Breeds static int num_of_items = ARRAY_SIZE(items);
795876c9d3aSMarcelo Tosatti
796876c9d3aSMarcelo Tosatti /**
7978973a6e7SRandy Dunlap * lbs_debugfs_read - proc read function
798876c9d3aSMarcelo Tosatti *
7998973a6e7SRandy Dunlap * @file: file to read
8008973a6e7SRandy Dunlap * @userbuf: pointer to buffer
8018973a6e7SRandy Dunlap * @count: number of bytes to read
8028973a6e7SRandy Dunlap * @ppos: read data starting position
8038973a6e7SRandy Dunlap *
8048973a6e7SRandy Dunlap * returns: amount of data read or negative error code
805876c9d3aSMarcelo Tosatti */
lbs_debugfs_read(struct file * file,char __user * userbuf,size_t count,loff_t * ppos)80610078321SHolger Schurig static ssize_t lbs_debugfs_read(struct file *file, char __user *userbuf,
807876c9d3aSMarcelo Tosatti size_t count, loff_t *ppos)
808876c9d3aSMarcelo Tosatti {
809876c9d3aSMarcelo Tosatti int val = 0;
810876c9d3aSMarcelo Tosatti size_t pos = 0;
811876c9d3aSMarcelo Tosatti ssize_t res;
812876c9d3aSMarcelo Tosatti char *p;
813876c9d3aSMarcelo Tosatti int i;
814876c9d3aSMarcelo Tosatti struct debug_data *d;
815876c9d3aSMarcelo Tosatti unsigned long addr = get_zeroed_page(GFP_KERNEL);
816876c9d3aSMarcelo Tosatti char *buf = (char *)addr;
817ad43f8bfSKiran Divekar if (!buf)
818ad43f8bfSKiran Divekar return -ENOMEM;
819876c9d3aSMarcelo Tosatti
820876c9d3aSMarcelo Tosatti p = buf;
821876c9d3aSMarcelo Tosatti
82257674308SJoe Perches d = file->private_data;
823876c9d3aSMarcelo Tosatti
824876c9d3aSMarcelo Tosatti for (i = 0; i < num_of_items; i++) {
825876c9d3aSMarcelo Tosatti if (d[i].size == 1)
826876c9d3aSMarcelo Tosatti val = *((u8 *) d[i].addr);
827876c9d3aSMarcelo Tosatti else if (d[i].size == 2)
828876c9d3aSMarcelo Tosatti val = *((u16 *) d[i].addr);
829876c9d3aSMarcelo Tosatti else if (d[i].size == 4)
830876c9d3aSMarcelo Tosatti val = *((u32 *) d[i].addr);
8314269e2adSDan Williams else if (d[i].size == 8)
8324269e2adSDan Williams val = *((u64 *) d[i].addr);
833876c9d3aSMarcelo Tosatti
834876c9d3aSMarcelo Tosatti pos += sprintf(p + pos, "%s=%d\n", d[i].name, val);
835876c9d3aSMarcelo Tosatti }
836876c9d3aSMarcelo Tosatti
837876c9d3aSMarcelo Tosatti res = simple_read_from_buffer(userbuf, count, ppos, p, pos);
838876c9d3aSMarcelo Tosatti
839876c9d3aSMarcelo Tosatti free_page(addr);
840876c9d3aSMarcelo Tosatti return res;
841876c9d3aSMarcelo Tosatti }
842876c9d3aSMarcelo Tosatti
843876c9d3aSMarcelo Tosatti /**
8448973a6e7SRandy Dunlap * lbs_debugfs_write - proc write function
845876c9d3aSMarcelo Tosatti *
8468973a6e7SRandy Dunlap * @f: file pointer
8478973a6e7SRandy Dunlap * @buf: pointer to data buffer
8488973a6e7SRandy Dunlap * @cnt: data number to write
8498973a6e7SRandy Dunlap * @ppos: file position
8508973a6e7SRandy Dunlap *
8518973a6e7SRandy Dunlap * returns: amount of data written
852876c9d3aSMarcelo Tosatti */
lbs_debugfs_write(struct file * f,const char __user * buf,size_t cnt,loff_t * ppos)85310078321SHolger Schurig static ssize_t lbs_debugfs_write(struct file *f, const char __user *buf,
854876c9d3aSMarcelo Tosatti size_t cnt, loff_t *ppos)
855876c9d3aSMarcelo Tosatti {
856876c9d3aSMarcelo Tosatti int r, i;
857876c9d3aSMarcelo Tosatti char *pdata;
858876c9d3aSMarcelo Tosatti char *p;
859876c9d3aSMarcelo Tosatti char *p0;
860876c9d3aSMarcelo Tosatti char *p1;
861876c9d3aSMarcelo Tosatti char *p2;
86257674308SJoe Perches struct debug_data *d = f->private_data;
863876c9d3aSMarcelo Tosatti
864a497e47dSDan Carpenter if (cnt == 0)
865a497e47dSDan Carpenter return 0;
866a497e47dSDan Carpenter
867f0fc8696SAl Viro pdata = memdup_user_nul(buf, cnt);
868f0fc8696SAl Viro if (IS_ERR(pdata))
869f0fc8696SAl Viro return PTR_ERR(pdata);
870876c9d3aSMarcelo Tosatti
871876c9d3aSMarcelo Tosatti p0 = pdata;
872876c9d3aSMarcelo Tosatti for (i = 0; i < num_of_items; i++) {
873876c9d3aSMarcelo Tosatti do {
874876c9d3aSMarcelo Tosatti p = strstr(p0, d[i].name);
875876c9d3aSMarcelo Tosatti if (p == NULL)
876876c9d3aSMarcelo Tosatti break;
877876c9d3aSMarcelo Tosatti p1 = strchr(p, '\n');
878876c9d3aSMarcelo Tosatti if (p1 == NULL)
879876c9d3aSMarcelo Tosatti break;
880876c9d3aSMarcelo Tosatti p0 = p1++;
881876c9d3aSMarcelo Tosatti p2 = strchr(p, '=');
882876c9d3aSMarcelo Tosatti if (!p2)
883876c9d3aSMarcelo Tosatti break;
884876c9d3aSMarcelo Tosatti p2++;
885d2f11e09STony Breeds r = simple_strtoul(p2, NULL, 0);
886876c9d3aSMarcelo Tosatti if (d[i].size == 1)
887876c9d3aSMarcelo Tosatti *((u8 *) d[i].addr) = (u8) r;
888876c9d3aSMarcelo Tosatti else if (d[i].size == 2)
889876c9d3aSMarcelo Tosatti *((u16 *) d[i].addr) = (u16) r;
890876c9d3aSMarcelo Tosatti else if (d[i].size == 4)
891876c9d3aSMarcelo Tosatti *((u32 *) d[i].addr) = (u32) r;
8924269e2adSDan Williams else if (d[i].size == 8)
8934269e2adSDan Williams *((u64 *) d[i].addr) = (u64) r;
894876c9d3aSMarcelo Tosatti break;
895876c9d3aSMarcelo Tosatti } while (1);
896876c9d3aSMarcelo Tosatti }
897876c9d3aSMarcelo Tosatti kfree(pdata);
898876c9d3aSMarcelo Tosatti
8994269e2adSDan Williams return (ssize_t)cnt;
900876c9d3aSMarcelo Tosatti }
901876c9d3aSMarcelo Tosatti
9024101dec9SJan Engelhardt static const struct file_operations lbs_debug_fops = {
903876c9d3aSMarcelo Tosatti .owner = THIS_MODULE,
904234e3405SStephen Boyd .open = simple_open,
90510078321SHolger Schurig .write = lbs_debugfs_write,
90610078321SHolger Schurig .read = lbs_debugfs_read,
9076038f373SArnd Bergmann .llseek = default_llseek,
908876c9d3aSMarcelo Tosatti };
909876c9d3aSMarcelo Tosatti
910876c9d3aSMarcelo Tosatti /**
9118973a6e7SRandy Dunlap * lbs_debug_init - create debug proc file
912876c9d3aSMarcelo Tosatti *
9138973a6e7SRandy Dunlap * @priv: pointer to &struct lbs_private
9148973a6e7SRandy Dunlap *
9158973a6e7SRandy Dunlap * returns: N/A
916876c9d3aSMarcelo Tosatti */
lbs_debug_init(struct lbs_private * priv)917e98a88ddSHolger Schurig static void lbs_debug_init(struct lbs_private *priv)
918876c9d3aSMarcelo Tosatti {
919876c9d3aSMarcelo Tosatti int i;
920876c9d3aSMarcelo Tosatti
921876c9d3aSMarcelo Tosatti if (!priv->debugfs_dir)
922876c9d3aSMarcelo Tosatti return;
923876c9d3aSMarcelo Tosatti
924876c9d3aSMarcelo Tosatti for (i = 0; i < num_of_items; i++)
925aa21c004SDavid Woodhouse items[i].addr += (size_t) priv;
926876c9d3aSMarcelo Tosatti
927876c9d3aSMarcelo Tosatti priv->debugfs_debug = debugfs_create_file("debug", 0644,
928876c9d3aSMarcelo Tosatti priv->debugfs_dir, &items[0],
92910078321SHolger Schurig &lbs_debug_fops);
930876c9d3aSMarcelo Tosatti }
93146868202SHolger Schurig #endif
932