aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJavier Cardona <javier@cozybit.com>2008-05-18 00:01:24 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-05-21 21:47:39 -0400
commit15dbaac03e862ee746310832c8d8d694dc0427ee (patch)
tree3f9af03aadd22af9bdd6050d81eafeeda4132c9e
parentedaea5ce05ca804cc55438c586ca2f947d49f56f (diff)
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: Javier Cardona <javier@cozybit.com> Signed-off-by: David Woodhouse <dwmw2@infradead.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r--drivers/net/wireless/libertas/Makefile8
-rw-r--r--drivers/net/wireless/libertas/decl.h4
-rw-r--r--drivers/net/wireless/libertas/defs.h4
-rw-r--r--drivers/net/wireless/libertas/main.c8
-rw-r--r--drivers/net/wireless/libertas/persistcfg.c408
5 files changed, 423 insertions, 9 deletions
diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile
index f0724e31adfd..02080a3682a9 100644
--- a/drivers/net/wireless/libertas/Makefile
+++ b/drivers/net/wireless/libertas/Makefile
@@ -1,9 +1,5 @@
1libertas-objs := main.o wext.o \ 1libertas-objs := main.o wext.o rx.o tx.o cmd.o cmdresp.o scan.o 11d.o \
2 rx.o tx.o cmd.o \ 2 debugfs.o persistcfg.o ethtool.o assoc.o
3 cmdresp.o scan.o \
4 11d.o \
5 debugfs.o \
6 ethtool.o assoc.o
7 3
8usb8xxx-objs += if_usb.o 4usb8xxx-objs += if_usb.o
9libertas_cs-objs += if_cs.o 5libertas_cs-objs += if_cs.o
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h
index 0632b09655d2..a8ac974dacac 100644
--- a/drivers/net/wireless/libertas/decl.h
+++ b/drivers/net/wireless/libertas/decl.h
@@ -60,6 +60,10 @@ void lbs_mac_event_disconnected(struct lbs_private *priv);
60 60
61void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str); 61void lbs_send_iwevcustom_event(struct lbs_private *priv, s8 *str);
62 62
63/* persistcfg.c */
64void lbs_persist_config_init(struct net_device *net);
65void lbs_persist_config_remove(struct net_device *net);
66
63/* main.c */ 67/* main.c */
64struct chan_freq_power *lbs_get_region_cfp_table(u8 region, 68struct chan_freq_power *lbs_get_region_cfp_table(u8 region,
65 int *cfp_no); 69 int *cfp_no);
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
index 3793cb92296a..12e687550bce 100644
--- a/drivers/net/wireless/libertas/defs.h
+++ b/drivers/net/wireless/libertas/defs.h
@@ -40,6 +40,7 @@
40#define LBS_DEB_THREAD 0x00100000 40#define LBS_DEB_THREAD 0x00100000
41#define LBS_DEB_HEX 0x00200000 41#define LBS_DEB_HEX 0x00200000
42#define LBS_DEB_SDIO 0x00400000 42#define LBS_DEB_SDIO 0x00400000
43#define LBS_DEB_SYSFS 0x00800000
43 44
44extern unsigned int lbs_debug; 45extern unsigned int lbs_debug;
45 46
@@ -81,7 +82,8 @@ do { if ((lbs_debug & (grp)) == (grp)) \
81#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, (dev)->bus_id, ##args) 82#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, (dev)->bus_id, ##args)
82#define lbs_deb_cs(fmt, args...) LBS_DEB_LL(LBS_DEB_CS, " cs", fmt, ##args) 83#define lbs_deb_cs(fmt, args...) LBS_DEB_LL(LBS_DEB_CS, " cs", fmt, ##args)
83#define lbs_deb_thread(fmt, args...) LBS_DEB_LL(LBS_DEB_THREAD, " thread", fmt, ##args) 84#define lbs_deb_thread(fmt, args...) LBS_DEB_LL(LBS_DEB_THREAD, " thread", fmt, ##args)
84#define lbs_deb_sdio(fmt, args...) LBS_DEB_LL(LBS_DEB_SDIO, " thread", fmt, ##args) 85#define lbs_deb_sdio(fmt, args...) LBS_DEB_LL(LBS_DEB_SDIO, " sdio", fmt, ##args)
86#define lbs_deb_sysfs(fmt, args...) LBS_DEB_LL(LBS_DEB_SYSFS, " sysfs", fmt, ##args)
85 87
86#define lbs_pr_info(format, args...) \ 88#define lbs_pr_info(format, args...) \
87 printk(KERN_INFO DRV_NAME": " format, ## args) 89 printk(KERN_INFO DRV_NAME": " format, ## args)
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index 01299c8ed27c..db246d0a1eda 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -1302,8 +1302,9 @@ void lbs_stop_card(struct lbs_private *priv)
1302 1302
1303 lbs_debugfs_remove_one(priv); 1303 lbs_debugfs_remove_one(priv);
1304 device_remove_file(&dev->dev, &dev_attr_lbs_rtap); 1304 device_remove_file(&dev->dev, &dev_attr_lbs_rtap);
1305 if (priv->mesh_tlv) 1305 if (priv->mesh_tlv) {
1306 device_remove_file(&dev->dev, &dev_attr_lbs_mesh); 1306 device_remove_file(&dev->dev, &dev_attr_lbs_mesh);
1307 }
1307 1308
1308 /* Flush pending command nodes */ 1309 /* Flush pending command nodes */
1309 del_timer_sync(&priv->command_timer); 1310 del_timer_sync(&priv->command_timer);
@@ -1372,6 +1373,8 @@ static int lbs_add_mesh(struct lbs_private *priv)
1372 if (ret) 1373 if (ret)
1373 goto err_unregister; 1374 goto err_unregister;
1374 1375
1376 lbs_persist_config_init(mesh_dev);
1377
1375 /* Everything successful */ 1378 /* Everything successful */
1376 ret = 0; 1379 ret = 0;
1377 goto done; 1380 goto done;
@@ -1398,8 +1401,9 @@ static void lbs_remove_mesh(struct lbs_private *priv)
1398 1401
1399 lbs_deb_enter(LBS_DEB_MESH); 1402 lbs_deb_enter(LBS_DEB_MESH);
1400 netif_stop_queue(mesh_dev); 1403 netif_stop_queue(mesh_dev);
1401 netif_carrier_off(priv->mesh_dev); 1404 netif_carrier_off(mesh_dev);
1402 sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group); 1405 sysfs_remove_group(&(mesh_dev->dev.kobj), &lbs_mesh_attr_group);
1406 lbs_persist_config_remove(mesh_dev);
1403 unregister_netdev(mesh_dev); 1407 unregister_netdev(mesh_dev);
1404 priv->mesh_dev = NULL; 1408 priv->mesh_dev = NULL;
1405 free_netdev(mesh_dev); 1409 free_netdev(mesh_dev);
diff --git a/drivers/net/wireless/libertas/persistcfg.c b/drivers/net/wireless/libertas/persistcfg.c
new file mode 100644
index 000000000000..baa662738895
--- /dev/null
+++ b/drivers/net/wireless/libertas/persistcfg.c
@@ -0,0 +1,408 @@
1#include <linux/moduleparam.h>
2#include <linux/delay.h>
3#include <linux/etherdevice.h>
4#include <linux/netdevice.h>
5#include <linux/if_arp.h>
6#include <linux/kthread.h>
7#include <linux/kfifo.h>
8
9#include "host.h"
10#include "decl.h"
11#include "dev.h"
12#include "wext.h"
13#include "debugfs.h"
14#include "scan.h"
15#include "assoc.h"
16#include "cmd.h"
17
18static int mesh_get_default_parameters(struct device *dev,
19 struct mrvl_mesh_defaults *defs)
20{
21 struct lbs_private *priv = to_net_dev(dev)->priv;
22 struct cmd_ds_mesh_config cmd;
23 int ret;
24
25 memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
26 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_GET,
27 CMD_TYPE_MESH_GET_DEFAULTS);
28
29 if (ret)
30 return -EOPNOTSUPP;
31
32 memcpy(defs, &cmd.data[0], sizeof(struct mrvl_mesh_defaults));
33
34 return 0;
35}
36
37/**
38 * @brief Get function for sysfs attribute bootflag
39 */
40static ssize_t bootflag_get(struct device *dev,
41 struct device_attribute *attr, char *buf)
42{
43 struct mrvl_mesh_defaults defs;
44 int ret;
45
46 ret = mesh_get_default_parameters(dev, &defs);
47
48 if (ret)
49 return ret;
50
51 return snprintf(buf, 12, "0x%x\n", le32_to_cpu(defs.bootflag));
52}
53
54/**
55 * @brief Set function for sysfs attribute bootflag
56 */
57static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
58 const char *buf, size_t count)
59{
60 struct lbs_private *priv = to_net_dev(dev)->priv;
61 struct cmd_ds_mesh_config cmd;
62 uint32_t datum;
63 int ret;
64
65 memset(&cmd, 0, sizeof(cmd));
66 ret = sscanf(buf, "%x", &datum);
67 if (ret != 1)
68 return -EINVAL;
69
70 *((__le32 *)&cmd.data[0]) = cpu_to_le32(!!datum);
71 cmd.length = cpu_to_le16(sizeof(uint32_t));
72 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
73 CMD_TYPE_MESH_SET_BOOTFLAG);
74 if (ret)
75 return ret;
76
77 return strlen(buf);
78}
79
80/**
81 * @brief Get function for sysfs attribute boottime
82 */
83static ssize_t boottime_get(struct device *dev,
84 struct device_attribute *attr, char *buf)
85{
86 struct mrvl_mesh_defaults defs;
87 int ret;
88
89 ret = mesh_get_default_parameters(dev, &defs);
90
91 if (ret)
92 return ret;
93
94 return snprintf(buf, 12, "0x%x\n", defs.boottime);
95}
96
97/**
98 * @brief Set function for sysfs attribute boottime
99 */
100static ssize_t boottime_set(struct device *dev,
101 struct device_attribute *attr, const char *buf, size_t count)
102{
103 struct lbs_private *priv = to_net_dev(dev)->priv;
104 struct cmd_ds_mesh_config cmd;
105 uint32_t datum;
106 int ret;
107
108 memset(&cmd, 0, sizeof(cmd));
109 ret = sscanf(buf, "%x", &datum);
110 if (ret != 1)
111 return -EINVAL;
112
113 /* A too small boot time will result in the device booting into
114 * standalone (no-host) mode before the host can take control of it,
115 * so the change will be hard to revert. This may be a desired
116 * feature (e.g to configure a very fast boot time for devices that
117 * will not be attached to a host), but dangerous. So I'm enforcing a
118 * lower limit of 20 seconds: remove and recompile the driver if this
119 * does not work for you.
120 */
121 datum = (datum < 20) ? 20 : datum;
122 cmd.data[0] = datum;
123 cmd.length = cpu_to_le16(sizeof(uint8_t));
124 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
125 CMD_TYPE_MESH_SET_BOOTTIME);
126 if (ret)
127 return ret;
128
129 return strlen(buf);
130}
131
132/**
133 * @brief Get function for sysfs attribute mesh_id
134 */
135static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
136 char *buf)
137{
138 struct mrvl_mesh_defaults defs;
139 int maxlen;
140 int ret;
141
142 ret = mesh_get_default_parameters(dev, &defs);
143
144 if (ret)
145 return ret;
146
147 if (defs.meshie.val.mesh_id_len > IW_ESSID_MAX_SIZE) {
148 printk(KERN_ERR "Inconsistent mesh ID length");
149 defs.meshie.val.mesh_id_len = IW_ESSID_MAX_SIZE;
150 }
151
152 /* SSID not null terminated: reserve room for \0 + \n */
153 maxlen = defs.meshie.val.mesh_id_len + 2;
154 maxlen = (PAGE_SIZE > maxlen) ? maxlen : PAGE_SIZE;
155
156 defs.meshie.val.mesh_id[defs.meshie.val.mesh_id_len] = '\0';
157
158 return snprintf(buf, maxlen, "%s\n", defs.meshie.val.mesh_id);
159}
160
161/**
162 * @brief Set function for sysfs attribute mesh_id
163 */
164static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
165 const char *buf, size_t count)
166{
167 struct cmd_ds_mesh_config cmd;
168 struct mrvl_mesh_defaults defs;
169 struct mrvl_meshie *ie;
170 struct lbs_private *priv = to_net_dev(dev)->priv;
171 int len;
172 int ret;
173
174 if (count < 2 || count > IW_ESSID_MAX_SIZE + 1)
175 return -EINVAL;
176
177 memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
178 ie = (struct mrvl_meshie *) &cmd.data[0];
179
180 /* fetch all other Information Element parameters */
181 ret = mesh_get_default_parameters(dev, &defs);
182
183 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
184
185 /* transfer IE elements */
186 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
187
188 len = count - 1;
189 memcpy(ie->val.mesh_id, buf, len);
190 /* SSID len */
191 ie->val.mesh_id_len = len;
192 /* IE len */
193 ie->hdr.len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len;
194
195 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
196 CMD_TYPE_MESH_SET_MESH_IE);
197 if (ret)
198 return ret;
199
200 return strlen(buf);
201}
202
203/**
204 * @brief Get function for sysfs attribute protocol_id
205 */
206static ssize_t protocol_id_get(struct device *dev,
207 struct device_attribute *attr, char *buf)
208{
209 struct mrvl_mesh_defaults defs;
210 int ret;
211
212 ret = mesh_get_default_parameters(dev, &defs);
213
214 if (ret)
215 return ret;
216
217 return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id);
218}
219
220/**
221 * @brief Set function for sysfs attribute protocol_id
222 */
223static ssize_t protocol_id_set(struct device *dev,
224 struct device_attribute *attr, const char *buf, size_t count)
225{
226 struct cmd_ds_mesh_config cmd;
227 struct mrvl_mesh_defaults defs;
228 struct mrvl_meshie *ie;
229 struct lbs_private *priv = to_net_dev(dev)->priv;
230 uint32_t datum;
231 int ret;
232
233 memset(&cmd, 0, sizeof(cmd));
234 ret = sscanf(buf, "%x", &datum);
235 if (ret != 1)
236 return -EINVAL;
237
238 /* fetch all other Information Element parameters */
239 ret = mesh_get_default_parameters(dev, &defs);
240
241 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
242
243 /* transfer IE elements */
244 ie = (struct mrvl_meshie *) &cmd.data[0];
245 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
246 /* update protocol id */
247 ie->val.active_protocol_id = datum;
248
249 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
250 CMD_TYPE_MESH_SET_MESH_IE);
251 if (ret)
252 return ret;
253
254 return strlen(buf);
255}
256
257/**
258 * @brief Get function for sysfs attribute metric_id
259 */
260static ssize_t metric_id_get(struct device *dev,
261 struct device_attribute *attr, char *buf)
262{
263 struct mrvl_mesh_defaults defs;
264 int ret;
265
266 ret = mesh_get_default_parameters(dev, &defs);
267
268 if (ret)
269 return ret;
270
271 return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id);
272}
273
274/**
275 * @brief Set function for sysfs attribute metric_id
276 */
277static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
278 const char *buf, size_t count)
279{
280 struct cmd_ds_mesh_config cmd;
281 struct mrvl_mesh_defaults defs;
282 struct mrvl_meshie *ie;
283 struct lbs_private *priv = to_net_dev(dev)->priv;
284 uint32_t datum;
285 int ret;
286
287 memset(&cmd, 0, sizeof(cmd));
288 ret = sscanf(buf, "%x", &datum);
289 if (ret != 1)
290 return -EINVAL;
291
292 /* fetch all other Information Element parameters */
293 ret = mesh_get_default_parameters(dev, &defs);
294
295 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
296
297 /* transfer IE elements */
298 ie = (struct mrvl_meshie *) &cmd.data[0];
299 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
300 /* update metric id */
301 ie->val.active_metric_id = datum;
302
303 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
304 CMD_TYPE_MESH_SET_MESH_IE);
305 if (ret)
306 return ret;
307
308 return strlen(buf);
309}
310
311/**
312 * @brief Get function for sysfs attribute capability
313 */
314static ssize_t capability_get(struct device *dev,
315 struct device_attribute *attr, char *buf)
316{
317 struct mrvl_mesh_defaults defs;
318 int ret;
319
320 ret = mesh_get_default_parameters(dev, &defs);
321
322 if (ret)
323 return ret;
324
325 return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability);
326}
327
328/**
329 * @brief Set function for sysfs attribute capability
330 */
331static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
332 const char *buf, size_t count)
333{
334 struct cmd_ds_mesh_config cmd;
335 struct mrvl_mesh_defaults defs;
336 struct mrvl_meshie *ie;
337 struct lbs_private *priv = to_net_dev(dev)->priv;
338 uint32_t datum;
339 int ret;
340
341 memset(&cmd, 0, sizeof(cmd));
342 ret = sscanf(buf, "%x", &datum);
343 if (ret != 1)
344 return -EINVAL;
345
346 /* fetch all other Information Element parameters */
347 ret = mesh_get_default_parameters(dev, &defs);
348
349 cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
350
351 /* transfer IE elements */
352 ie = (struct mrvl_meshie *) &cmd.data[0];
353 memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
354 /* update value */
355 ie->val.mesh_capability = datum;
356
357 ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
358 CMD_TYPE_MESH_SET_MESH_IE);
359 if (ret)
360 return ret;
361
362 return strlen(buf);
363}
364
365
366static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set);
367static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set);
368static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set);
369static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set);
370static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set);
371static DEVICE_ATTR(capability, 0644, capability_get, capability_set);
372
373static struct attribute *boot_opts_attrs[] = {
374 &dev_attr_bootflag.attr,
375 &dev_attr_boottime.attr,
376 NULL
377};
378
379static struct attribute_group boot_opts_group = {
380 .name = "boot_options",
381 .attrs = boot_opts_attrs,
382};
383
384static struct attribute *mesh_ie_attrs[] = {
385 &dev_attr_mesh_id.attr,
386 &dev_attr_protocol_id.attr,
387 &dev_attr_metric_id.attr,
388 &dev_attr_capability.attr,
389 NULL
390};
391
392static struct attribute_group mesh_ie_group = {
393 .name = "mesh_ie",
394 .attrs = mesh_ie_attrs,
395};
396
397void lbs_persist_config_init(struct net_device *dev)
398{
399 int ret;
400 ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group);
401 ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group);
402}
403
404void lbs_persist_config_remove(struct net_device *dev)
405{
406 sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group);
407 sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group);
408}