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