// SPDX-License-Identifier: GPL-2.0
#include <linux/dcache.h>
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/hardirq.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/export.h>
#include "decl.h"
#include "cmd.h"
#include "debugfs.h"
static struct dentry *lbs_dir;
static char *szStates[] = {
"Connected",
"Disconnected"
};
#ifdef PROC_DEBUG
static void lbs_debug_init(struct lbs_private *priv);
#endif
static ssize_t write_file_dummy(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
return -EINVAL;
}
static const size_t len = PAGE_SIZE;
static ssize_t lbs_dev_info(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
struct lbs_private *priv = file->private_data;
size_t pos = 0;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
ssize_t res;
if (!buf)
return -ENOMEM;
pos += snprintf(buf+pos, len-pos, "state = %s\n",
szStates[priv->connect_status]);
pos += snprintf(buf+pos, len-pos, "region_code = %02x\n",
(u32) priv->regioncode);
res = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
free_page(addr);
return res;
}
static ssize_t lbs_sleepparams_write(struct file *file,
const char __user *user_buf, size_t count,
loff_t *ppos)
{
struct lbs_private *priv = file->private_data;
ssize_t ret;
struct sleep_params sp;
int p1, p2, p3, p4, p5, p6;
char *buf;
buf = memdup_user_nul(user_buf, min(count, len - 1));
if (IS_ERR(buf))
return PTR_ERR(buf);
ret = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6);
if (ret != 6) {
ret = -EINVAL;
goto out_unlock;
}
sp.sp_error = p1;
sp.sp_offset = p2;
sp.sp_stabletime = p3;
sp.sp_calcontrol = p4;
sp.sp_extsleepclk = p5;
sp.sp_reserved = p6;
ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_SET, &sp);
if (!ret)
ret = count;
else if (ret > 0)
ret = -EINVAL;
out_unlock:
kfree(buf);
return ret;
}
static ssize_t lbs_sleepparams_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
struct lbs_private *priv = file->private_data;
ssize_t ret;
size_t pos = 0;
struct sleep_params sp;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
if (!buf)
return -ENOMEM;
ret = lbs_cmd_802_11_sleep_params(priv, CMD_ACT_GET, &sp);
if (ret)
goto out_unlock;
pos += snprintf(buf, len, "%d %d %d %d %d %d\n", sp.sp_error,
sp.sp_offset, sp.sp_stabletime,
sp.sp_calcontrol, sp.sp_extsleepclk,
sp.sp_reserved);
ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
out_unlock:
free_page(addr);
return ret;
}
static ssize_t lbs_host_sleep_write(struct file *file,
const char __user *user_buf, size_t count,
loff_t *ppos)
{
struct lbs_private *priv = file->private_data;
ssize_t ret;
int host_sleep;
char *buf;
buf = memdup_user_nul(user_buf, min(count, len - 1));
if (IS_ERR(buf))
return PTR_ERR(buf);
ret = sscanf(buf, "%d", &host_sleep);
if (ret != 1) {
ret = -EINVAL;
goto out_unlock;
}
if (host_sleep == 0)
ret = lbs_set_host_sleep(priv, 0);
else if (host_sleep == 1) {
if (priv->wol_criteria == EHS_REMOVE_WAKEUP) {
netdev_info(priv->dev,
"wake parameters not configured\n");
ret = -EINVAL;
goto out_unlock;
}
ret = lbs_set_host_sleep(priv, 1);
} else {
netdev_err(priv->dev, "invalid option\n");
ret = -EINVAL;
}
if (!ret)
ret = count;
out_unlock:
kfree(buf);
return ret;
}
static ssize_t lbs_host_sleep_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
struct lbs_private *priv = file->private_data;
ssize_t ret;
size_t pos = 0;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *)addr;
if (!buf)
return -ENOMEM;
pos += snprintf(buf, len, "%d\n", priv->is_host_sleep_activated);
ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos);
free_page(addr);
return ret;
}
/*
* When calling CMD_802_11_SUBSCRIBE_EVENT with CMD_ACT_GET, me might
* get a bunch of vendor-specific TLVs (a.k.a. IEs) back from the
* firmware. Here's an example:
* 04 01 02 00 00 00 05 01 02 00 00 00 06 01 02 00
* 00 00 07 01 02 00 3c 00 00 00 00 00 00 00 03 03
* 00 00 00 00 0