xref: /linux/drivers/net/wireless/broadcom/b43legacy/sysfs.c (revision c532de5a67a70f8533d495f8f2aaa9a0491c3ad0)
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 
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 
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 
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 
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 
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 
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 
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 
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