Merge branch 'for-2.6.24' of master.kernel.org:/pub/scm/linux/kernel/git/galak/powerp...
[linux-2.6] / drivers / net / wireless / b43 / sysfs.c
1 /*
2
3   Broadcom B43 wireless driver
4
5   SYSFS support routines
6
7   Copyright (c) 2006 Michael Buesch <mb@bu3sch.de>
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19   You should have received a copy of the GNU General Public License
20   along with this program; see the file COPYING.  If not, write to
21   the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
22   Boston, MA 02110-1301, USA.
23
24 */
25
26 #include <linux/capability.h>
27 #include <linux/io.h>
28
29 #include "b43.h"
30 #include "sysfs.h"
31 #include "main.h"
32 #include "phy.h"
33
34 #define GENERIC_FILESIZE        64
35
36 static int get_integer(const char *buf, size_t count)
37 {
38         char tmp[10 + 1] = { 0 };
39         int ret = -EINVAL;
40
41         if (count == 0)
42                 goto out;
43         count = min(count, (size_t) 10);
44         memcpy(tmp, buf, count);
45         ret = simple_strtol(tmp, NULL, 10);
46       out:
47         return ret;
48 }
49
50 static int get_boolean(const char *buf, size_t count)
51 {
52         if (count != 0) {
53                 if (buf[0] == '1')
54                         return 1;
55                 if (buf[0] == '0')
56                         return 0;
57                 if (count >= 4 && memcmp(buf, "true", 4) == 0)
58                         return 1;
59                 if (count >= 5 && memcmp(buf, "false", 5) == 0)
60                         return 0;
61                 if (count >= 3 && memcmp(buf, "yes", 3) == 0)
62                         return 1;
63                 if (count >= 2 && memcmp(buf, "no", 2) == 0)
64                         return 0;
65                 if (count >= 2 && memcmp(buf, "on", 2) == 0)
66                         return 1;
67                 if (count >= 3 && memcmp(buf, "off", 3) == 0)
68                         return 0;
69         }
70         return -EINVAL;
71 }
72
73 static ssize_t b43_attr_interfmode_show(struct device *dev,
74                                         struct device_attribute *attr,
75                                         char *buf)
76 {
77         struct b43_wldev *wldev = dev_to_b43_wldev(dev);
78         ssize_t count = 0;
79
80         if (!capable(CAP_NET_ADMIN))
81                 return -EPERM;
82
83         mutex_lock(&wldev->wl->mutex);
84
85         switch (wldev->phy.interfmode) {
86         case B43_INTERFMODE_NONE:
87                 count =
88                     snprintf(buf, PAGE_SIZE,
89                              "0 (No Interference Mitigation)\n");
90                 break;
91         case B43_INTERFMODE_NONWLAN:
92                 count =
93                     snprintf(buf, PAGE_SIZE,
94                              "1 (Non-WLAN Interference Mitigation)\n");
95                 break;
96         case B43_INTERFMODE_MANUALWLAN:
97                 count =
98                     snprintf(buf, PAGE_SIZE,
99                              "2 (WLAN Interference Mitigation)\n");
100                 break;
101         default:
102                 B43_WARN_ON(1);
103         }
104
105         mutex_unlock(&wldev->wl->mutex);
106
107         return count;
108 }
109
110 static ssize_t b43_attr_interfmode_store(struct device *dev,
111                                          struct device_attribute *attr,
112                                          const char *buf, size_t count)
113 {
114         struct b43_wldev *wldev = dev_to_b43_wldev(dev);
115         unsigned long flags;
116         int err;
117         int mode;
118
119         if (!capable(CAP_NET_ADMIN))
120                 return -EPERM;
121
122         mode = get_integer(buf, count);
123         switch (mode) {
124         case 0:
125                 mode = B43_INTERFMODE_NONE;
126                 break;
127         case 1:
128                 mode = B43_INTERFMODE_NONWLAN;
129                 break;
130         case 2:
131                 mode = B43_INTERFMODE_MANUALWLAN;
132                 break;
133         case 3:
134                 mode = B43_INTERFMODE_AUTOWLAN;
135                 break;
136         default:
137                 return -EINVAL;
138         }
139
140         mutex_lock(&wldev->wl->mutex);
141         spin_lock_irqsave(&wldev->wl->irq_lock, flags);
142
143         err = b43_radio_set_interference_mitigation(wldev, mode);
144         if (err) {
145                 b43err(wldev->wl, "Interference Mitigation not "
146                        "supported by device\n");
147         }
148         mmiowb();
149         spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
150         mutex_unlock(&wldev->wl->mutex);
151
152         return err ? err : count;
153 }
154
155 static DEVICE_ATTR(interference, 0644,
156                    b43_attr_interfmode_show, b43_attr_interfmode_store);
157
158 static ssize_t b43_attr_preamble_show(struct device *dev,
159                                       struct device_attribute *attr, char *buf)
160 {
161         struct b43_wldev *wldev = dev_to_b43_wldev(dev);
162         ssize_t count;
163
164         if (!capable(CAP_NET_ADMIN))
165                 return -EPERM;
166
167         mutex_lock(&wldev->wl->mutex);
168
169         if (wldev->short_preamble)
170                 count =
171                     snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n");
172         else
173                 count =
174                     snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n");
175
176         mutex_unlock(&wldev->wl->mutex);
177
178         return count;
179 }
180
181 static ssize_t b43_attr_preamble_store(struct device *dev,
182                                        struct device_attribute *attr,
183                                        const char *buf, size_t count)
184 {
185         struct b43_wldev *wldev = dev_to_b43_wldev(dev);
186         unsigned long flags;
187         int value;
188
189         if (!capable(CAP_NET_ADMIN))
190                 return -EPERM;
191
192         value = get_boolean(buf, count);
193         if (value < 0)
194                 return value;
195         mutex_lock(&wldev->wl->mutex);
196         spin_lock_irqsave(&wldev->wl->irq_lock, flags);
197
198         wldev->short_preamble = !!value;
199
200         spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
201         mutex_unlock(&wldev->wl->mutex);
202
203         return count;
204 }
205
206 static DEVICE_ATTR(shortpreamble, 0644,
207                    b43_attr_preamble_show, b43_attr_preamble_store);
208
209 int b43_sysfs_register(struct b43_wldev *wldev)
210 {
211         struct device *dev = wldev->dev->dev;
212         int err;
213
214         B43_WARN_ON(b43_status(wldev) != B43_STAT_INITIALIZED);
215
216         err = device_create_file(dev, &dev_attr_interference);
217         if (err)
218                 goto out;
219         err = device_create_file(dev, &dev_attr_shortpreamble);
220         if (err)
221                 goto err_remove_interfmode;
222
223       out:
224         return err;
225       err_remove_interfmode:
226         device_remove_file(dev, &dev_attr_interference);
227         goto out;
228 }
229
230 void b43_sysfs_unregister(struct b43_wldev *wldev)
231 {
232         struct device *dev = wldev->dev->dev;
233
234         device_remove_file(dev, &dev_attr_shortpreamble);
235         device_remove_file(dev, &dev_attr_interference);
236 }