1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3
4 Broadcom B43legacy wireless driver
5
6 SYSFS support routines
7
8 Copyright (c) 2006 Michael Buesch <m@bues.ch>
9
10
11 */
12
13 #include "sysfs.h"
14 #include "b43legacy.h"
15 #include "main.h"
16 #include "phy.h"
17 #include "radio.h"
18
19 #include <linux/capability.h>
20
21
22 #define GENERIC_FILESIZE 64
23
24
get_integer(const char * buf,size_t count)25 static int get_integer(const char *buf, size_t count)
26 {
27 char tmp[10 + 1] = { 0 };
28 int ret = -EINVAL, res;
29
30 if (count == 0)
31 goto out;
32 count = min_t(size_t, count, 10);
33 memcpy(tmp, buf, count);
34 ret = kstrtoint(tmp, 10, &res);
35 if (!ret)
36 return res;
37 out:
38 return ret;
39 }
40
get_boolean(const char * buf,size_t count)41 static int get_boolean(const char *buf, size_t count)
42 {
43 if (count != 0) {
44 if (buf[0] == '1')
45 return 1;
46 if (buf[0] == '0')
47 return 0;
48 if (count >= 4 && memcmp(buf, "true", 4) == 0)
49 return 1;
50 if (count >= 5 && memcmp(buf, "false", 5) == 0)
51 return 0;
52 if (count >= 3 && memcmp(buf, "yes", 3) == 0)
53 return 1;
54 if (count >= 2 && memcmp(buf, "no", 2) == 0)
55 return 0;
56 if (count >= 2 && memcmp(buf, "on", 2) == 0)
57 return 1;
58 if (count >= 3 && memcmp(buf, "off", 3) == 0)
59 return 0;
60 }
61 return -EINVAL;
62 }
63
b43legacy_attr_interfmode_show(struct device * dev,struct device_attribute * attr,char * buf)64 static ssize_t b43legacy_attr_interfmode_show(struct device *dev,
65 struct device_attribute *attr,
66 char *buf)
67 {
68 struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev);
69 ssize_t count = 0;
70
71 if (!capable(CAP_NET_ADMIN))
72 return -EPERM;
73
74 mutex_lock(&wldev->wl->mutex);
75
76 switch (wldev->phy.interfmode) {
77 case B43legacy_INTERFMODE_NONE:
78 count = sysfs_emit(buf, "0 (No Interference Mitigation)\n");
79 break;
80 case B43legacy_INTERFMODE_NONWLAN:
81 count = sysfs_emit(buf,
82 "1 (Non-WLAN Interference Mitigation)\n");
83 break;
84 case B43legacy_INTERFMODE_MANUALWLAN:
85 count = sysfs_emit(buf, "2 (WLAN Interference Mitigation)\n");
86 break;
87 default:
88 B43legacy_WARN_ON(1);
89 }
90
91 mutex_unlock(&wldev->wl->mutex);
92
93 return count;
94 }
95
b43legacy_attr_interfmode_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)96 static ssize_t b43legacy_attr_interfmode_store(struct device *dev,
97 struct device_attribute *attr,
98 const char *buf, size_t count)
99 {
100 struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev);
101 unsigned long flags;
102 int err;
103 int mode;
104
105 if (!capable(CAP_NET_ADMIN))
106 return -EPERM;
107
108 mode = get_integer(buf, count);
109 switch (mode) {
110 case 0:
111 mode = B43legacy_INTERFMODE_NONE;
112 break;
113 case 1:
114 mode = B43legacy_INTERFMODE_NONWLAN;
115 break;
116 case 2:
117 mode = B43legacy_INTERFMODE_MANUALWLAN;
118 break;
119 case 3:
120 mode = B43legacy_INTERFMODE_AUTOWLAN;
121 break;
122 default:
123 return -EINVAL;
124 }
125
126 mutex_lock(&wldev->wl->mutex);
127 spin_lock_irqsave(&wldev->wl->irq_lock, flags);
128
129 err = b43legacy_radio_set_interference_mitigation(wldev, mode);
130 if (err)
131 b43legacyerr(wldev->wl, "Interference Mitigation not "
132 "supported by device\n");
133 spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
134 mutex_unlock(&wldev->wl->mutex);
135
136 return err ? err : count;
137 }
138
139 static DEVICE_ATTR(interference, 0644,
140 b43legacy_attr_interfmode_show,
141 b43legacy_attr_interfmode_store);
142
b43legacy_attr_preamble_show(struct device * dev,struct device_attribute * attr,char * buf)143 static ssize_t b43legacy_attr_preamble_show(struct device *dev,
144 struct device_attribute *attr,
145 char *buf)
146 {
147 struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev);
148 ssize_t count;
149
150 if (!capable(CAP_NET_ADMIN))
151 return -EPERM;
152
153 mutex_lock(&wldev->wl->mutex);
154
155 if (wldev->short_preamble)
156 count = sysfs_emit(buf, "1 (Short Preamble enabled)\n");
157 else
158 count = sysfs_emit(buf, "0 (Short Preamble disabled)\n");
159
160 mutex_unlock(&wldev->wl->mutex);
161
162 return count;
163 }
164
b43legacy_attr_preamble_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)165 static ssize_t b43legacy_attr_preamble_store(struct device *dev,
166 struct device_attribute *attr,
167 const char *buf, size_t count)
168 {
169 struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev);
170 unsigned long flags;
171 int value;
172
173 if (!capable(CAP_NET_ADMIN))
174 return -EPERM;
175
176 value = get_boolean(buf, count);
177 if (value < 0)
178 return value;
179 mutex_lock(&wldev->wl->mutex);
180 spin_lock_irqsave(&wldev->wl->irq_lock, flags);
181
182 wldev->short_preamble = !!value;
183
184 spin_unlock_irqrestore(&wldev->wl->irq_lock, flags);
185 mutex_unlock(&wldev->wl->mutex);
186
187 return count;
188 }
189
190 static DEVICE_ATTR(shortpreamble, 0644,
191 b43legacy_attr_preamble_show,
192 b43legacy_attr_preamble_store);
193
b43legacy_sysfs_register(struct b43legacy_wldev * wldev)194 int b43legacy_sysfs_register(struct b43legacy_wldev *wldev)
195 {
196 struct device *dev = wldev->dev->dev;
197 int err;
198
199 B43legacy_WARN_ON(b43legacy_status(wldev) !=
200 B43legacy_STAT_INITIALIZED);
201
202 err = device_create_file(dev, &dev_attr_interference);
203 if (err)
204 goto out;
205 err = device_create_file(dev, &dev_attr_shortpreamble);
206 if (err)
207 goto err_remove_interfmode;
208
209 out:
210 return err;
211 err_remove_interfmode:
212 device_remove_file(dev, &dev_attr_interference);
213 goto out;
214 }
215
b43legacy_sysfs_unregister(struct b43legacy_wldev * wldev)216 void b43legacy_sysfs_unregister(struct b43legacy_wldev *wldev)
217 {
218 struct device *dev = wldev->dev->dev;
219
220 device_remove_file(dev, &dev_attr_shortpreamble);
221 device_remove_file(dev, &dev_attr_interference);
222 }
223