Merge branch 'hotfixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris...
[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, "%d\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, "%d", &datum);
67         if ((ret != 1) || (datum > 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, "%d\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, "%d", &datum);
110         if ((ret != 1) || (datum > 255))
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 channel
134  */
135 static ssize_t channel_get(struct device *dev,
136                            struct device_attribute *attr, char *buf)
137 {
138         struct mrvl_mesh_defaults defs;
139         int ret;
140
141         ret = mesh_get_default_parameters(dev, &defs);
142
143         if (ret)
144                 return ret;
145
146         return snprintf(buf, 12, "%d\n", le16_to_cpu(defs.channel));
147 }
148
149 /**
150  * @brief Set function for sysfs attribute channel
151  */
152 static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
153                            const char *buf, size_t count)
154 {
155         struct lbs_private *priv = to_net_dev(dev)->priv;
156         struct cmd_ds_mesh_config cmd;
157         uint32_t datum;
158         int ret;
159
160         memset(&cmd, 0, sizeof(cmd));
161         ret = sscanf(buf, "%d", &datum);
162         if (ret != 1 || datum < 1 || datum > 11)
163                 return -EINVAL;
164
165         *((__le16 *)&cmd.data[0]) = cpu_to_le16(datum);
166         cmd.length = cpu_to_le16(sizeof(uint16_t));
167         ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
168                                    CMD_TYPE_MESH_SET_DEF_CHANNEL);
169         if (ret)
170                 return ret;
171
172         return strlen(buf);
173 }
174
175 /**
176  * @brief Get function for sysfs attribute mesh_id
177  */
178 static ssize_t mesh_id_get(struct device *dev, struct device_attribute *attr,
179                            char *buf)
180 {
181         struct mrvl_mesh_defaults defs;
182         int maxlen;
183         int ret;
184
185         ret = mesh_get_default_parameters(dev, &defs);
186
187         if (ret)
188                 return ret;
189
190         if (defs.meshie.val.mesh_id_len > IW_ESSID_MAX_SIZE) {
191                 lbs_pr_err("inconsistent mesh ID length");
192                 defs.meshie.val.mesh_id_len = IW_ESSID_MAX_SIZE;
193         }
194
195         /* SSID not null terminated: reserve room for \0 + \n */
196         maxlen = defs.meshie.val.mesh_id_len + 2;
197         maxlen = (PAGE_SIZE > maxlen) ? maxlen : PAGE_SIZE;
198
199         defs.meshie.val.mesh_id[defs.meshie.val.mesh_id_len] = '\0';
200
201         return snprintf(buf, maxlen, "%s\n", defs.meshie.val.mesh_id);
202 }
203
204 /**
205  * @brief Set function for sysfs attribute mesh_id
206  */
207 static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
208                            const char *buf, size_t count)
209 {
210         struct cmd_ds_mesh_config cmd;
211         struct mrvl_mesh_defaults defs;
212         struct mrvl_meshie *ie;
213         struct lbs_private *priv = to_net_dev(dev)->priv;
214         int len;
215         int ret;
216
217         if (count < 2 || count > IW_ESSID_MAX_SIZE + 1)
218                 return -EINVAL;
219
220         memset(&cmd, 0, sizeof(struct cmd_ds_mesh_config));
221         ie = (struct mrvl_meshie *) &cmd.data[0];
222
223         /* fetch all other Information Element parameters */
224         ret = mesh_get_default_parameters(dev, &defs);
225
226         cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
227
228         /* transfer IE elements */
229         memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
230
231         len = count - 1;
232         memcpy(ie->val.mesh_id, buf, len);
233         /* SSID len */
234         ie->val.mesh_id_len = len;
235         /* IE len */
236         ie->hdr.len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len;
237
238         ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
239                                    CMD_TYPE_MESH_SET_MESH_IE);
240         if (ret)
241                 return ret;
242
243         return strlen(buf);
244 }
245
246 /**
247  * @brief Get function for sysfs attribute protocol_id
248  */
249 static ssize_t protocol_id_get(struct device *dev,
250                                struct device_attribute *attr, char *buf)
251 {
252         struct mrvl_mesh_defaults defs;
253         int ret;
254
255         ret = mesh_get_default_parameters(dev, &defs);
256
257         if (ret)
258                 return ret;
259
260         return snprintf(buf, 5, "%d\n", defs.meshie.val.active_protocol_id);
261 }
262
263 /**
264  * @brief Set function for sysfs attribute protocol_id
265  */
266 static ssize_t protocol_id_set(struct device *dev,
267                 struct device_attribute *attr, const char *buf, size_t count)
268 {
269         struct cmd_ds_mesh_config cmd;
270         struct mrvl_mesh_defaults defs;
271         struct mrvl_meshie *ie;
272         struct lbs_private *priv = to_net_dev(dev)->priv;
273         uint32_t datum;
274         int ret;
275
276         memset(&cmd, 0, sizeof(cmd));
277         ret = sscanf(buf, "%d", &datum);
278         if ((ret != 1) || (datum > 255))
279                 return -EINVAL;
280
281         /* fetch all other Information Element parameters */
282         ret = mesh_get_default_parameters(dev, &defs);
283
284         cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
285
286         /* transfer IE elements */
287         ie = (struct mrvl_meshie *) &cmd.data[0];
288         memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
289         /* update protocol id */
290         ie->val.active_protocol_id = datum;
291
292         ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
293                                    CMD_TYPE_MESH_SET_MESH_IE);
294         if (ret)
295                 return ret;
296
297         return strlen(buf);
298 }
299
300 /**
301  * @brief Get function for sysfs attribute metric_id
302  */
303 static ssize_t metric_id_get(struct device *dev,
304                 struct device_attribute *attr, char *buf)
305 {
306         struct mrvl_mesh_defaults defs;
307         int ret;
308
309         ret = mesh_get_default_parameters(dev, &defs);
310
311         if (ret)
312                 return ret;
313
314         return snprintf(buf, 5, "%d\n", defs.meshie.val.active_metric_id);
315 }
316
317 /**
318  * @brief Set function for sysfs attribute metric_id
319  */
320 static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
321                              const char *buf, size_t count)
322 {
323         struct cmd_ds_mesh_config cmd;
324         struct mrvl_mesh_defaults defs;
325         struct mrvl_meshie *ie;
326         struct lbs_private *priv = to_net_dev(dev)->priv;
327         uint32_t datum;
328         int ret;
329
330         memset(&cmd, 0, sizeof(cmd));
331         ret = sscanf(buf, "%d", &datum);
332         if ((ret != 1) || (datum > 255))
333                 return -EINVAL;
334
335         /* fetch all other Information Element parameters */
336         ret = mesh_get_default_parameters(dev, &defs);
337
338         cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
339
340         /* transfer IE elements */
341         ie = (struct mrvl_meshie *) &cmd.data[0];
342         memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
343         /* update metric id */
344         ie->val.active_metric_id = datum;
345
346         ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
347                                    CMD_TYPE_MESH_SET_MESH_IE);
348         if (ret)
349                 return ret;
350
351         return strlen(buf);
352 }
353
354 /**
355  * @brief Get function for sysfs attribute capability
356  */
357 static ssize_t capability_get(struct device *dev,
358                 struct device_attribute *attr, char *buf)
359 {
360         struct mrvl_mesh_defaults defs;
361         int ret;
362
363         ret = mesh_get_default_parameters(dev, &defs);
364
365         if (ret)
366                 return ret;
367
368         return snprintf(buf, 5, "%d\n", defs.meshie.val.mesh_capability);
369 }
370
371 /**
372  * @brief Set function for sysfs attribute capability
373  */
374 static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
375                               const char *buf, size_t count)
376 {
377         struct cmd_ds_mesh_config cmd;
378         struct mrvl_mesh_defaults defs;
379         struct mrvl_meshie *ie;
380         struct lbs_private *priv = to_net_dev(dev)->priv;
381         uint32_t datum;
382         int ret;
383
384         memset(&cmd, 0, sizeof(cmd));
385         ret = sscanf(buf, "%d", &datum);
386         if ((ret != 1) || (datum > 255))
387                 return -EINVAL;
388
389         /* fetch all other Information Element parameters */
390         ret = mesh_get_default_parameters(dev, &defs);
391
392         cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie));
393
394         /* transfer IE elements */
395         ie = (struct mrvl_meshie *) &cmd.data[0];
396         memcpy(ie, &defs.meshie, sizeof(struct mrvl_meshie));
397         /* update value */
398         ie->val.mesh_capability = datum;
399
400         ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET,
401                                    CMD_TYPE_MESH_SET_MESH_IE);
402         if (ret)
403                 return ret;
404
405         return strlen(buf);
406 }
407
408
409 static DEVICE_ATTR(bootflag, 0644, bootflag_get, bootflag_set);
410 static DEVICE_ATTR(boottime, 0644, boottime_get, boottime_set);
411 static DEVICE_ATTR(channel, 0644, channel_get, channel_set);
412 static DEVICE_ATTR(mesh_id, 0644, mesh_id_get, mesh_id_set);
413 static DEVICE_ATTR(protocol_id, 0644, protocol_id_get, protocol_id_set);
414 static DEVICE_ATTR(metric_id, 0644, metric_id_get, metric_id_set);
415 static DEVICE_ATTR(capability, 0644, capability_get, capability_set);
416
417 static struct attribute *boot_opts_attrs[] = {
418         &dev_attr_bootflag.attr,
419         &dev_attr_boottime.attr,
420         &dev_attr_channel.attr,
421         NULL
422 };
423
424 static struct attribute_group boot_opts_group = {
425         .name = "boot_options",
426         .attrs = boot_opts_attrs,
427 };
428
429 static struct attribute *mesh_ie_attrs[] = {
430         &dev_attr_mesh_id.attr,
431         &dev_attr_protocol_id.attr,
432         &dev_attr_metric_id.attr,
433         &dev_attr_capability.attr,
434         NULL
435 };
436
437 static struct attribute_group mesh_ie_group = {
438         .name = "mesh_ie",
439         .attrs = mesh_ie_attrs,
440 };
441
442 void lbs_persist_config_init(struct net_device *dev)
443 {
444         int ret;
445         ret = sysfs_create_group(&(dev->dev.kobj), &boot_opts_group);
446         ret = sysfs_create_group(&(dev->dev.kobj), &mesh_ie_group);
447 }
448
449 void lbs_persist_config_remove(struct net_device *dev)
450 {
451         sysfs_remove_group(&(dev->dev.kobj), &boot_opts_group);
452         sysfs_remove_group(&(dev->dev.kobj), &mesh_ie_group);
453 }