add b43
[openwrt/svn-archive/archive.git] / package / b43 / src / 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 "b43.h"
27 #include "sysfs.h"
28 #include "main.h"
29 #include "phy.h"
30
31 #include <linux/capability.h>
32
33 #define GENERIC_FILESIZE 64
34
35 static int get_integer(const char *buf, size_t count)
36 {
37 char tmp[10 + 1] = { 0 };
38 int ret = -EINVAL;
39
40 if (count == 0)
41 goto out;
42 count = min(count, (size_t) 10);
43 memcpy(tmp, buf, count);
44 ret = simple_strtol(tmp, NULL, 10);
45 out:
46 return ret;
47 }
48
49 static int get_boolean(const char *buf, size_t count)
50 {
51 if (count != 0) {
52 if (buf[0] == '1')
53 return 1;
54 if (buf[0] == '0')
55 return 0;
56 if (count >= 4 && memcmp(buf, "true", 4) == 0)
57 return 1;
58 if (count >= 5 && memcmp(buf, "false", 5) == 0)
59 return 0;
60 if (count >= 3 && memcmp(buf, "yes", 3) == 0)
61 return 1;
62 if (count >= 2 && memcmp(buf, "no", 2) == 0)
63 return 0;
64 if (count >= 2 && memcmp(buf, "on", 2) == 0)
65 return 1;
66 if (count >= 3 && memcmp(buf, "off", 3) == 0)
67 return 0;
68 }
69 return -EINVAL;
70 }
71
72 static ssize_t b43_attr_interfmode_show(struct device *dev,
73 struct device_attribute *attr,
74 char *buf)
75 {
76 struct b43_wldev *wldev = dev_to_b43_wldev(dev);
77 ssize_t count = 0;
78
79 if (!capable(CAP_NET_ADMIN))
80 return -EPERM;
81
82 mutex_lock(&wldev->wl->mutex);
83
84 switch (wldev->phy.interfmode) {
85 case B43_INTERFMODE_NONE:
86 count =
87 snprintf(buf, PAGE_SIZE,
88 "0 (No Interference Mitigation)\n");
89 break;
90 case B43_INTERFMODE_NONWLAN:
91 count =
92 snprintf(buf, PAGE_SIZE,
93 "1 (Non-WLAN Interference Mitigation)\n");
94 break;
95 case B43_INTERFMODE_MANUALWLAN:
96 count =
97 snprintf(buf, PAGE_SIZE,
98 "2 (WLAN Interference Mitigation)\n");
99 break;
100 default:
101 B43_WARN_ON(1);
102 }
103
104 mutex_unlock(&wldev->wl->mutex);
105
106 return count;
107 }
108
109 static ssize_t b43_attr_interfmode_store(struct device *dev,
110 struct device_attribute *attr,
111 const char *buf, size_t count)
112 {
113 struct b43_wldev *wldev = dev_to_b43_wldev(dev);
114 unsigned long flags;
115 int err;
116 int mode;
117
118 if (!capable(CAP_NET_ADMIN))
119 return -EPERM;
120
121 mode = get_integer(buf, count);
122 switch (mode) {
123 case 0:
124 mode = B43_INTERFMODE_NONE;
125 break;
126 case 1:
127 mode = B43_INTERFMODE_NONWLAN;
128 break;
129 case 2:
130 mode = B43_INTERFMODE_MANUALWLAN;
131 break;
132 case 3:
133 mode = B43_INTERFMODE_AUTOWLAN;
134 break;
135 default:
136 return -EINVAL;
137 }
138
139 mutex_lock(&wldev->wl->mutex);
140 spin_lock_irqsave(&wldev->wl->irq_lock, flags);
141
142 err = b43_radio_set_interference_mitigation(wldev, mode);
143 if (err) {
144 b43err(wldev->wl, "Interference Mitigation not "
145 "supported by device\n");
146 }
147 mmiowb();
148 spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
149 mutex_unlock(&wldev->wl->mutex);
150
151 return err ? err : count;
152 }
153
154 static DEVICE_ATTR(interference, 0644,
155 b43_attr_interfmode_show, b43_attr_interfmode_store);
156
157 static ssize_t b43_attr_preamble_show(struct device *dev,
158 struct device_attribute *attr, char *buf)
159 {
160 struct b43_wldev *wldev = dev_to_b43_wldev(dev);
161 ssize_t count;
162
163 if (!capable(CAP_NET_ADMIN))
164 return -EPERM;
165
166 mutex_lock(&wldev->wl->mutex);
167
168 if (wldev->short_preamble)
169 count =
170 snprintf(buf, PAGE_SIZE, "1 (Short Preamble enabled)\n");
171 else
172 count =
173 snprintf(buf, PAGE_SIZE, "0 (Short Preamble disabled)\n");
174
175 mutex_unlock(&wldev->wl->mutex);
176
177 return count;
178 }
179
180 static ssize_t b43_attr_preamble_store(struct device *dev,
181 struct device_attribute *attr,
182 const char *buf, size_t count)
183 {
184 struct b43_wldev *wldev = dev_to_b43_wldev(dev);
185 unsigned long flags;
186 int value;
187
188 if (!capable(CAP_NET_ADMIN))
189 return -EPERM;
190
191 value = get_boolean(buf, count);
192 if (value < 0)
193 return value;
194 mutex_lock(&wldev->wl->mutex);
195 spin_lock_irqsave(&wldev->wl->irq_lock, flags);
196
197 wldev->short_preamble = !!value;
198
199 spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
200 mutex_unlock(&wldev->wl->mutex);
201
202 return count;
203 }
204
205 static DEVICE_ATTR(shortpreamble, 0644,
206 b43_attr_preamble_show, b43_attr_preamble_store);
207
208 int b43_sysfs_register(struct b43_wldev *wldev)
209 {
210 struct device *dev = wldev->dev->dev;
211 int err;
212
213 B43_WARN_ON(b43_status(wldev) != B43_STAT_INITIALIZED);
214
215 err = device_create_file(dev, &dev_attr_interference);
216 if (err)
217 goto out;
218 err = device_create_file(dev, &dev_attr_shortpreamble);
219 if (err)
220 goto err_remove_interfmode;
221
222 out:
223 return err;
224 err_remove_interfmode:
225 device_remove_file(dev, &dev_attr_interference);
226 goto out;
227 }
228
229 void b43_sysfs_unregister(struct b43_wldev *wldev)
230 {
231 struct device *dev = wldev->dev->dev;
232
233 device_remove_file(dev, &dev_attr_shortpreamble);
234 device_remove_file(dev, &dev_attr_interference);
235 }