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