baa662738895821c37be08a2eb66825ecaf4dc4f
[pandora-kernel.git] / drivers / net / wireless / libertas / persistcfg.c
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
18 static 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  */
40 static 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  */
57 static 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  */
83 static 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  */
100 static 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  */
135 static 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  */
164 static 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  */
206 static 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  */
223 static 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  */
260 static 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  */
277 static 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  */
314 static 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  */
331 static 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
366 static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set);
367 static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set);
368 static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set);
369 static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set);
370 static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set);
371 static DEVICE_ATTR(capability, 0644, capability_get, capability_set);
372
373 static struct attribute *boot_opts_attrs[] = {
374         &dev_attr_bootflag.attr,
375         &dev_attr_boottime.attr,
376         NULL
377 };
378
379 static struct attribute_group boot_opts_group = {
380         .name = "boot_options",
381         .attrs = boot_opts_attrs,
382 };
383
384 static 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
392 static struct attribute_group mesh_ie_group = {
393         .name = "mesh_ie",
394         .attrs = mesh_ie_attrs,
395 };
396
397 void 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
404 void 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 }