GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / net / wireless / broadcom / b43 / sysfs.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3
4   Broadcom B43 wireless driver
5
6   SYSFS support routines
7
8   Copyright (c) 2006 Michael Buesch <m@bues.ch>
9
10
11 */
12
13 #include <linux/capability.h>
14 #include <linux/io.h>
15
16 #include "b43.h"
17 #include "sysfs.h"
18 #include "main.h"
19 #include "phy_common.h"
20
21 #define GENERIC_FILESIZE        64
22
23 static int get_integer(const char *buf, size_t count)
24 {
25         char tmp[10 + 1] = { 0 };
26         int ret = -EINVAL;
27
28         if (count == 0)
29                 goto out;
30         count = min_t(size_t, count, 10);
31         memcpy(tmp, buf, count);
32         ret = simple_strtol(tmp, NULL, 10);
33       out:
34         return ret;
35 }
36
37 static ssize_t b43_attr_interfmode_show(struct device *dev,
38                                         struct device_attribute *attr,
39                                         char *buf)
40 {
41         struct b43_wldev *wldev = dev_to_b43_wldev(dev);
42         ssize_t count = 0;
43
44         if (!capable(CAP_NET_ADMIN))
45                 return -EPERM;
46
47         mutex_lock(&wldev->wl->mutex);
48
49         if (wldev->phy.type != B43_PHYTYPE_G) {
50                 mutex_unlock(&wldev->wl->mutex);
51                 return -ENOSYS;
52         }
53
54         switch (wldev->phy.g->interfmode) {
55         case B43_INTERFMODE_NONE:
56                 count =
57                     snprintf(buf, PAGE_SIZE,
58                              "0 (No Interference Mitigation)\n");
59                 break;
60         case B43_INTERFMODE_NONWLAN:
61                 count =
62                     snprintf(buf, PAGE_SIZE,
63                              "1 (Non-WLAN Interference Mitigation)\n");
64                 break;
65         case B43_INTERFMODE_MANUALWLAN:
66                 count =
67                     snprintf(buf, PAGE_SIZE,
68                              "2 (WLAN Interference Mitigation)\n");
69                 break;
70         default:
71                 B43_WARN_ON(1);
72         }
73
74         mutex_unlock(&wldev->wl->mutex);
75
76         return count;
77 }
78
79 static ssize_t b43_attr_interfmode_store(struct device *dev,
80                                          struct device_attribute *attr,
81                                          const char *buf, size_t count)
82 {
83         struct b43_wldev *wldev = dev_to_b43_wldev(dev);
84         int err;
85         int mode;
86
87         if (!capable(CAP_NET_ADMIN))
88                 return -EPERM;
89
90         mode = get_integer(buf, count);
91         switch (mode) {
92         case 0:
93                 mode = B43_INTERFMODE_NONE;
94                 break;
95         case 1:
96                 mode = B43_INTERFMODE_NONWLAN;
97                 break;
98         case 2:
99                 mode = B43_INTERFMODE_MANUALWLAN;
100                 break;
101         case 3:
102                 mode = B43_INTERFMODE_AUTOWLAN;
103                 break;
104         default:
105                 return -EINVAL;
106         }
107
108         mutex_lock(&wldev->wl->mutex);
109
110         if (wldev->phy.ops->interf_mitigation) {
111                 err = wldev->phy.ops->interf_mitigation(wldev, mode);
112                 if (err) {
113                         b43err(wldev->wl, "Interference Mitigation not "
114                                "supported by device\n");
115                 }
116         } else
117                 err = -ENOSYS;
118
119         mutex_unlock(&wldev->wl->mutex);
120
121         return err ? err : count;
122 }
123
124 static DEVICE_ATTR(interference, 0644,
125                    b43_attr_interfmode_show, b43_attr_interfmode_store);
126
127 int b43_sysfs_register(struct b43_wldev *wldev)
128 {
129         struct device *dev = wldev->dev->dev;
130
131         B43_WARN_ON(b43_status(wldev) != B43_STAT_INITIALIZED);
132
133         return device_create_file(dev, &dev_attr_interference);
134 }
135
136 void b43_sysfs_unregister(struct b43_wldev *wldev)
137 {
138         struct device *dev = wldev->dev->dev;
139
140         device_remove_file(dev, &dev_attr_interference);
141 }