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 = snprintf(buf, PAGE_SIZE, "0 (No Interference" 79 " Mitigation)\n"); 80 break; 81 case B43legacy_INTERFMODE_NONWLAN: 82 count = snprintf(buf, PAGE_SIZE, "1 (Non-WLAN Interference" 83 " Mitigation)\n"); 84 break; 85 case B43legacy_INTERFMODE_MANUALWLAN: 86 count = snprintf(buf, PAGE_SIZE, "2 (WLAN Interference" 87 " Mitigation)\n"); 88 break; 89 default: 90 B43legacy_WARN_ON(1); 91 } 92 93 mutex_unlock(&wldev->wl->mutex); 94 95 return count; 96 } 97 98 static ssize_t b43legacy_attr_interfmode_store(struct device *dev, 99 struct device_attribute *attr, 100 const char *buf, size_t count) 101 { 102 struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev); 103 unsigned long flags; 104 int err; 105 int mode; 106 107 if (!capable(CAP_NET_ADMIN)) 108 return -EPERM; 109 110 mode = get_integer(buf, count); 111 switch (mode) { 112 case 0: 113 mode = B43legacy_INTERFMODE_NONE; 114 break; 115 case 1: 116 mode = B43legacy_INTERFMODE_NONWLAN; 117 break; 118 case 2: 119 mode = B43legacy_INTERFMODE_MANUALWLAN; 120 break; 121 case 3: 122 mode = B43legacy_INTERFMODE_AUTOWLAN; 123 break; 124 default: 125 return -EINVAL; 126 } 127 128 mutex_lock(&wldev->wl->mutex); 129 spin_lock_irqsave(&wldev->wl->irq_lock, flags); 130 131 err = b43legacy_radio_set_interference_mitigation(wldev, mode); 132 if (err) 133 b43legacyerr(wldev->wl, "Interference Mitigation not " 134 "supported by device\n"); 135 spin_unlock_irqrestore(&wldev->wl->irq_lock, flags); 136 mutex_unlock(&wldev->wl->mutex); 137 138 return err ? err : count; 139 } 140 141 static DEVICE_ATTR(interference, 0644, 142 b43legacy_attr_interfmode_show, 143 b43legacy_attr_interfmode_store); 144 145 static ssize_t b43legacy_attr_preamble_show(struct device *dev, 146 struct device_attribute *attr, 147 char *buf) 148 { 149 struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev); 150 ssize_t count; 151 152 if (!capable(CAP_NET_ADMIN)) 153 return -EPERM; 154 155 mutex_lock(&wldev->wl->mutex); 156 157 if (wldev->short_preamble) 158 count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble" 159 " enabled)\n"); 160 else 161 count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble" 162 " disabled)\n"); 163 164 mutex_unlock(&wldev->wl->mutex); 165 166 return count; 167 } 168 169 static ssize_t b43legacy_attr_preamble_store(struct device *dev, 170 struct device_attribute *attr, 171 const char *buf, size_t count) 172 { 173 struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev); 174 unsigned long flags; 175 int value; 176 177 if (!capable(CAP_NET_ADMIN)) 178 return -EPERM; 179 180 value = get_boolean(buf, count); 181 if (value < 0) 182 return value; 183 mutex_lock(&wldev->wl->mutex); 184 spin_lock_irqsave(&wldev->wl->irq_lock, flags); 185 186 wldev->short_preamble = !!value; 187 188 spin_unlock_irqrestore(&wldev->wl->irq_lock, flags); 189 mutex_unlock(&wldev->wl->mutex); 190 191 return count; 192 } 193 194 static DEVICE_ATTR(shortpreamble, 0644, 195 b43legacy_attr_preamble_show, 196 b43legacy_attr_preamble_store); 197 198 int b43legacy_sysfs_register(struct b43legacy_wldev *wldev) 199 { 200 struct device *dev = wldev->dev->dev; 201 int err; 202 203 B43legacy_WARN_ON(b43legacy_status(wldev) != 204 B43legacy_STAT_INITIALIZED); 205 206 err = device_create_file(dev, &dev_attr_interference); 207 if (err) 208 goto out; 209 err = device_create_file(dev, &dev_attr_shortpreamble); 210 if (err) 211 goto err_remove_interfmode; 212 213 out: 214 return err; 215 err_remove_interfmode: 216 device_remove_file(dev, &dev_attr_interference); 217 goto out; 218 } 219 220 void b43legacy_sysfs_unregister(struct b43legacy_wldev *wldev) 221 { 222 struct device *dev = wldev->dev->dev; 223 224 device_remove_file(dev, &dev_attr_shortpreamble); 225 device_remove_file(dev, &dev_attr_interference); 226 } 227