Commit 15dbaac0 authored by Javier Cardona's avatar Javier Cardona Committed by John W. Linville

libertas: sysfs interface for accessing non-volatile configuration

This will create the following sysfs directories:
/sys/class/net/mshX
		...
		|-- boot_options
		|   |-- bootflag
		|   `-- boottime
		...
		|-- mesh_ie
		|   |-- capability
		|   |-- mesh_id
		|   |-- metric_id
		|   `-- protocol_id
Signed-off-by: default avatarJavier Cardona <javier@cozybit.com>
Signed-off-by: default avatarDavid Woodhouse <dwmw2@infradead.org>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent edaea5ce
libertas-objs := main.o wext.o \
rx.o tx.o cmd.o \
cmdresp.o scan.o \
11d.o \
debugfs.o \
ethtool.o assoc.o
libertas-objs := main.o wext.o rx.o tx.o cmd.o cmdresp.o scan.o 11d.o \
debugfs.o persistcfg.o ethtool.o assoc.o
usb8xxx-objs += if_usb.o
libertas_cs-objs += if_cs.o
......
......@@ -60,6 +60,10 @@ void lbs_mac_event_disconnected(struct lbs_private *priv);
void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str);
/* persistcfg.c */
void lbs_persist_config_init(struct net_device *net);
void lbs_persist_config_remove(struct net_device *net);
/* main.c */
struct chan_freq_power *lbs_get_region_cfp_table(u8 region,
int *cfp_no);
......
......@@ -40,6 +40,7 @@
#define LBS_DEB_THREAD 0x00100000
#define LBS_DEB_HEX 0x00200000
#define LBS_DEB_SDIO 0x00400000
#define LBS_DEB_SYSFS 0x00800000
extern unsigned int lbs_debug;
......@@ -81,7 +82,8 @@ do { if ((lbs_debug & (grp)) == (grp)) \
#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, (dev)->bus_id, ##args)
#define lbs_deb_cs(fmt, args...) LBS_DEB_LL(LBS_DEB_CS, " cs", fmt, ##args)
#define lbs_deb_thread(fmt, args...) LBS_DEB_LL(LBS_DEB_THREAD, " thread", fmt, ##args)
#define lbs_deb_sdio(fmt, args...) LBS_DEB_LL(LBS_DEB_SDIO, " thread", fmt, ##args)
#define lbs_deb_sdio(fmt, args...) LBS_DEB_LL(LBS_DEB_SDIO, " sdio", fmt, ##args)
#define lbs_deb_sysfs(fmt, args...) LBS_DEB_LL(LBS_DEB_SYSFS, " sysfs", fmt, ##args)
#define lbs_pr_info(format, args...) \
printk(KERN_INFO DRV_NAME": " format, ## args)
......
......@@ -1302,8 +1302,9 @@ void lbs_stop_card(struct lbs_private *priv)
lbs_debugfs_remove_one(priv);
device_remove_file(&dev->dev, &dev_attr_lbs_rtap);
if (priv->mesh_tlv)
if (priv->mesh_tlv) {
device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
}
/* Flush pending command nodes */
del_timer_sync(&priv->command_timer);
......@@ -1372,6 +1373,8 @@ static int lbs_add_mesh(struct lbs_private *priv)
if (ret)
goto err_unregister;
lbs_persist_config_init(mesh_dev);
/* Everything successful */
ret = 0;
goto done;
......@@ -1398,8 +1401,9 @@ static void lbs_remove_mesh(struct lbs_private *priv)
lbs_deb_enter(LBS_DEB_MESH);
netif_stop_queue(mesh_dev);
netif_carrier_off(priv->mesh_dev);
netif_carrier_off(mesh_dev);
sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
lbs_persist_config_remove(mesh_dev);
unregister_netdev(mesh_dev);
priv->mesh_dev = NULL;
free_netdev(mesh_dev);
......
#include <linux/moduleparam.h>
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/kthread.h>
#include <linux/kfifo.h>
#include "host.h"
#include "decl.h"
#include "dev.h"
#include "wext.h"
#include "debugfs.h"
#include "scan.h"
#include "assoc.h"
#include "cmd.h"
static int mesh_get_default_parameters(struct device *dev,
struct mrvl_mesh_defaults *defs)
{
struct lbs_private *priv = to_net_dev(dev)->priv;
struct cmd_ds_mesh_config cmd;
int ret;
memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET,
CMD_TYPE_MESH_GET_DEFAULTS);
if (ret)
return -EOPNOTSUPP;
memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults));
return 0;
}
/**
* @brief Get function for sysfs attribute bootflag
*/
static ssize_t bootflag_get(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mrvl_mesh_defaults defs;
int ret;
ret = mesh_get_default_parameters(dev, &defs);
if (ret)
return ret;
return snprintf(buf, 12, "0x%x\n", le32_to_cpu(defs.bootflag));
}
/**
* @brief Set function for sysfs attribute bootflag
*/
static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct lbs_private *priv = to_net_dev(dev)->priv;
struct cmd_ds_mesh_config cmd;
uint32_t datum;
int ret;
memset(&cmd, 0, sizeof(cmd));
ret = sscanf(buf, "%x", &datum);
if (ret != 1)
return -EINVAL;
*((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum);
cmd.length = cpu_to_le16(sizeof(uint32_t));
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
CMD_TYPE_MESH_SET_BOOTFLAG);
if (ret)
return ret;
return strlen(buf);
}
/**
* @brief Get function for sysfs attribute boottime
*/
static ssize_t boottime_get(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mrvl_mesh_defaults defs;
int ret;
ret = mesh_get_default_parameters(dev, &defs);
if (ret)
return ret;
return snprintf(buf, 12, "0x%x\n", defs.boottime);
}
/**
* @brief Set function for sysfs attribute boottime
*/
static ssize_t boottime_set(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct lbs_private *priv = to_net_dev(dev)->priv;
struct cmd_ds_mesh_config cmd;
uint32_t datum;
int ret;
memset(&cmd, 0, sizeof(cmd));
ret = sscanf(buf, "%x", &datum);
if (ret != 1)
return -EINVAL;
/* A too small boot time will result in the device booting into
* standalone (no-host) mode before the host can take control of it,
* so the change will be hard to revert. This may be a desired
* feature (e.g to configure a very fast boot time for devices that
* will not be attached to a host), but dangerous. So I'm enforcing a
* lower limit of 20 seconds: remove and recompile the driver if this
* does not work for you.
*/
datum = (datum < 20) ? 20 : datum;
cmd.data[0] = datum;
cmd.length = cpu_to_le16(sizeof(uint8_t));
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
CMD_TYPE_MESH_SET_BOOTTIME);
if (ret)
return ret;
return strlen(buf);
}
/**
* @brief Get function for sysfs attribute mesh_id
*/
static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct mrvl_mesh_defaults defs;
int maxlen;
int ret;
ret = mesh_get_default_parameters(dev, &defs);
if (ret)
return ret;
if (defs.meshie.val.mesh_id_len > IW_ESSID_MAX_SIZE) {
printk(KERN_ERR "Inconsistent mesh ID length");
defs.meshie.val.mesh_id_len = IW_ESSID_MAX_SIZE;
}
/* SSID not null terminated: reserve room for \0 + \n */
maxlen = defs.meshie.val.mesh_id_len + 2;
maxlen = (PAGE_SIZE > maxlen) ? maxlen : PAGE_SIZE;
defs.meshie.val.mesh_id[defs.meshie.val.mesh_id_len] = '\0';
return snprintf(buf, maxlen, "%s\n", defs.meshie.val.mesh_id);
}
/**
* @brief Set function for sysfs attribute mesh_id
*/
static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct cmd_ds_mesh_config cmd;
struct mrvl_mesh_defaults defs;
struct mrvl_meshie *ie;
struct lbs_private *priv = to_net_dev(dev)->priv;
int len;
int ret;
if (count < 2 || count > IW_ESSID_MAX_SIZE + 1)
return -EINVAL;
memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
ie = (struct mrvl_meshie *) &cmd.data[0];
/* fetch all other Information Element parameters */
ret = mesh_get_default_parameters(dev, &defs);
cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
/* transfer IE elements */
memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
len = count - 1;
memcpy(ie->val.mesh_id, buf, len);
/* SSID len */
ie->val.mesh_id_len = len;
/* IE len */
ie->hdr.len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len;
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
CMD_TYPE_MESH_SET_MESH_IE);
if (ret)
return ret;
return strlen(buf);
}
/**
* @brief Get function for sysfs attribute protocol_id
*/
static ssize_t protocol_id_get(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mrvl_mesh_defaults defs;
int ret;
ret = mesh_get_default_parameters(dev, &defs);
if (ret)
return ret;
return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id);
}
/**
* @brief Set function for sysfs attribute protocol_id
*/
static ssize_t protocol_id_set(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct cmd_ds_mesh_config cmd;
struct mrvl_mesh_defaults defs;
struct mrvl_meshie *ie;
struct lbs_private *priv = to_net_dev(dev)->priv;
uint32_t datum;
int ret;
memset(&cmd, 0, sizeof(cmd));
ret = sscanf(buf, "%x", &datum);
if (ret != 1)
return -EINVAL;
/* fetch all other Information Element parameters */
ret = mesh_get_default_parameters(dev, &defs);
cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
/* transfer IE elements */
ie = (struct mrvl_meshie *) &cmd.data[0];
memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
/* update protocol id */
ie->val.active_protocol_id = datum;
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
CMD_TYPE_MESH_SET_MESH_IE);
if (ret)
return ret;
return strlen(buf);
}
/**
* @brief Get function for sysfs attribute metric_id
*/
static ssize_t metric_id_get(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mrvl_mesh_defaults defs;
int ret;
ret = mesh_get_default_parameters(dev, &defs);
if (ret)
return ret;
return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id);
}
/**
* @brief Set function for sysfs attribute metric_id
*/
static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct cmd_ds_mesh_config cmd;
struct mrvl_mesh_defaults defs;
struct mrvl_meshie *ie;
struct lbs_private *priv = to_net_dev(dev)->priv;
uint32_t datum;
int ret;
memset(&cmd, 0, sizeof(cmd));
ret = sscanf(buf, "%x", &datum);
if (ret != 1)
return -EINVAL;
/* fetch all other Information Element parameters */
ret = mesh_get_default_parameters(dev, &defs);
cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
/* transfer IE elements */
ie = (struct mrvl_meshie *) &cmd.data[0];
memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
/* update metric id */
ie->val.active_metric_id = datum;
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
CMD_TYPE_MESH_SET_MESH_IE);
if (ret)
return ret;
return strlen(buf);
}
/**
* @brief Get function for sysfs attribute capability
*/
static ssize_t capability_get(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mrvl_mesh_defaults defs;
int ret;
ret = mesh_get_default_parameters(dev, &defs);
if (ret)
return ret;
return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability);
}
/**
* @brief Set function for sysfs attribute capability
*/
static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct cmd_ds_mesh_config cmd;
struct mrvl_mesh_defaults defs;
struct mrvl_meshie *ie;
struct lbs_private *priv = to_net_dev(dev)->priv;
uint32_t datum;
int ret;
memset(&cmd, 0, sizeof(cmd));
ret = sscanf(buf, "%x", &datum);
if (ret != 1)
return -EINVAL;
/* fetch all other Information Element parameters */
ret = mesh_get_default_parameters(dev, &defs);
cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
/* transfer IE elements */
ie = (struct mrvl_meshie *) &cmd.data[0];
memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
/* update value */
ie->val.mesh_capability = datum;
ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
CMD_TYPE_MESH_SET_MESH_IE);
if (ret)
return ret;
return strlen(buf);
}
static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set);
static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set);
static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set);
static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set);
static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set);
static DEVICE_ATTR(capability, 0644, capability_get, capability_set);
static struct attribute *boot_opts_attrs[] = {
&dev_attr_bootflag.attr,
&dev_attr_boottime.attr,
NULL
};
static struct attribute_group boot_opts_group = {
.name = "boot_options",
.attrs = boot_opts_attrs,
};
static struct attribute *mesh_ie_attrs[] = {
&dev_attr_mesh_id.attr,
&dev_attr_protocol_id.attr,
&dev_attr_metric_id.attr,
&dev_attr_capability.attr,
NULL
};
static struct attribute_group mesh_ie_group = {
.name = "mesh_ie",
.attrs = mesh_ie_attrs,
};
void lbs_persist_config_init(struct net_device *dev)
{
int ret;
ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group);
ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group);
}
void lbs_persist_config_remove(struct net_device *dev)
{
sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group);
sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment