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; 29 30 if (count == 0) 31 goto out; 32 count = min_t(size_t, count, 10); 33 memcpy(tmp, buf, count); 34 ret = simple_strtol(tmp, NULL, 10); 35 out: 36 return ret; 37 } 38 39 static int get_boolean(const char *buf, size_t count) 40 { 41 if (count != 0) { 42 if (buf[0] == '1') 43 return 1; 44 if (buf[0] == '0') 45 return 0; 46 if (count >= 4 && memcmp(buf, "true", 4) == 0) 47 return 1; 48 if (count >= 5 && memcmp(buf, "false", 5) == 0) 49 return 0; 50 if (count >= 3 && memcmp(buf, "yes", 3) == 0) 51 return 1; 52 if (count >= 2 && memcmp(buf, "no", 2) == 0) 53 return 0; 54 if (count >= 2 && memcmp(buf, "on", 2) == 0) 55 return 1; 56 if (count >= 3 && memcmp(buf, "off", 3) == 0) 57 return 0; 58 } 59 return -EINVAL; 60 } 61 62 static ssize_t b43legacy_attr_interfmode_show(struct device *dev, 63 struct device_attribute *attr, 64 char *buf) 65 { 66 struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev); 67 ssize_t count = 0; 68 69 if (!capable(CAP_NET_ADMIN)) 70 return -EPERM; 71 72 mutex_lock(&wldev->wl->mutex); 73 74 switch (wldev->phy.interfmode) { 75 case B43legacy_INTERFMODE_NONE: 76 count = snprintf(buf, PAGE_SIZE, "0 (No Interference" 77 " Mitigation)\n"); 78 break; 79 case B43legacy_INTERFMODE_NONWLAN: 80 count = snprintf(buf, PAGE_SIZE, "1 (Non-WLAN Interference" 81 " Mitigation)\n"); 82 break; 83 case B43legacy_INTERFMODE_MANUALWLAN: 84 count = snprintf(buf, PAGE_SIZE, "2 (WLAN Interference" 85 " 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 = snprintf(buf, PAGE_SIZE, "1 (Short Preamble" 157 " enabled)\n"); 158 else 159 count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble" 160 " disabled)\n"); 161 162 mutex_unlock(&wldev->wl->mutex); 163 164 return count; 165 } 166 167 static ssize_t b43legacy_attr_preamble_store(struct device *dev, 168 struct device_attribute *attr, 169 const char *buf, size_t count) 170 { 171 struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev); 172 unsigned long flags; 173 int value; 174 175 if (!capable(CAP_NET_ADMIN)) 176 return -EPERM; 177 178 value = get_boolean(buf, count); 179 if (value < 0) 180 return value; 181 mutex_lock(&wldev->wl->mutex); 182 spin_lock_irqsave(&wldev->wl->irq_lock, flags); 183 184 wldev->short_preamble = !!value; 185 186 spin_unlock_irqrestore(&wldev->wl->irq_lock, flags); 187 mutex_unlock(&wldev->wl->mutex); 188 189 return count; 190 } 191 192 static DEVICE_ATTR(shortpreamble, 0644, 193 b43legacy_attr_preamble_show, 194 b43legacy_attr_preamble_store); 195 196 int b43legacy_sysfs_register(struct b43legacy_wldev *wldev) 197 { 198 struct device *dev = wldev->dev->dev; 199 int err; 200 201 B43legacy_WARN_ON(b43legacy_status(wldev) != 202 B43legacy_STAT_INITIALIZED); 203 204 err = device_create_file(dev, &dev_attr_interference); 205 if (err) 206 goto out; 207 err = device_create_file(dev, &dev_attr_shortpreamble); 208 if (err) 209 goto err_remove_interfmode; 210 211 out: 212 return err; 213 err_remove_interfmode: 214 device_remove_file(dev, &dev_attr_interference); 215 goto out; 216 } 217 218 void b43legacy_sysfs_unregister(struct b43legacy_wldev *wldev) 219 { 220 struct device *dev = wldev->dev->dev; 221 222 device_remove_file(dev, &dev_attr_shortpreamble); 223 device_remove_file(dev, &dev_attr_interference); 224 } 225