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(lock: &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 | fmt: "0 (No Interference Mitigation)\n" ); |
59 | break; |
60 | case B43_INTERFMODE_NONWLAN: |
61 | count = |
62 | snprintf(buf, PAGE_SIZE, |
63 | fmt: "1 (Non-WLAN Interference Mitigation)\n" ); |
64 | break; |
65 | case B43_INTERFMODE_MANUALWLAN: |
66 | count = |
67 | snprintf(buf, PAGE_SIZE, |
68 | fmt: "2 (WLAN Interference Mitigation)\n" ); |
69 | break; |
70 | default: |
71 | B43_WARN_ON(1); |
72 | } |
73 | |
74 | mutex_unlock(lock: &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(wl: wldev->wl, fmt: "Interference Mitigation not " |
114 | "supported by device\n" ); |
115 | } |
116 | } else |
117 | err = -ENOSYS; |
118 | |
119 | mutex_unlock(lock: &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(device: dev, entry: &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, attr: &dev_attr_interference); |
141 | } |
142 | |