18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci Broadcom B43legacy wireless driver 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci SYSFS support routines 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci Copyright (c) 2006 Michael Buesch <m@bues.ch> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci*/ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "sysfs.h" 148c2ecf20Sopenharmony_ci#include "b43legacy.h" 158c2ecf20Sopenharmony_ci#include "main.h" 168c2ecf20Sopenharmony_ci#include "phy.h" 178c2ecf20Sopenharmony_ci#include "radio.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/capability.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define GENERIC_FILESIZE 64 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic int get_integer(const char *buf, size_t count) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci char tmp[10 + 1] = { 0 }; 288c2ecf20Sopenharmony_ci int ret = -EINVAL, res; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci if (count == 0) 318c2ecf20Sopenharmony_ci goto out; 328c2ecf20Sopenharmony_ci count = min_t(size_t, count, 10); 338c2ecf20Sopenharmony_ci memcpy(tmp, buf, count); 348c2ecf20Sopenharmony_ci ret = kstrtoint(tmp, 10, &res); 358c2ecf20Sopenharmony_ci if (!ret) 368c2ecf20Sopenharmony_ci return res; 378c2ecf20Sopenharmony_ciout: 388c2ecf20Sopenharmony_ci return ret; 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic int get_boolean(const char *buf, size_t count) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci if (count != 0) { 448c2ecf20Sopenharmony_ci if (buf[0] == '1') 458c2ecf20Sopenharmony_ci return 1; 468c2ecf20Sopenharmony_ci if (buf[0] == '0') 478c2ecf20Sopenharmony_ci return 0; 488c2ecf20Sopenharmony_ci if (count >= 4 && memcmp(buf, "true", 4) == 0) 498c2ecf20Sopenharmony_ci return 1; 508c2ecf20Sopenharmony_ci if (count >= 5 && memcmp(buf, "false", 5) == 0) 518c2ecf20Sopenharmony_ci return 0; 528c2ecf20Sopenharmony_ci if (count >= 3 && memcmp(buf, "yes", 3) == 0) 538c2ecf20Sopenharmony_ci return 1; 548c2ecf20Sopenharmony_ci if (count >= 2 && memcmp(buf, "no", 2) == 0) 558c2ecf20Sopenharmony_ci return 0; 568c2ecf20Sopenharmony_ci if (count >= 2 && memcmp(buf, "on", 2) == 0) 578c2ecf20Sopenharmony_ci return 1; 588c2ecf20Sopenharmony_ci if (count >= 3 && memcmp(buf, "off", 3) == 0) 598c2ecf20Sopenharmony_ci return 0; 608c2ecf20Sopenharmony_ci } 618c2ecf20Sopenharmony_ci return -EINVAL; 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic ssize_t b43legacy_attr_interfmode_show(struct device *dev, 658c2ecf20Sopenharmony_ci struct device_attribute *attr, 668c2ecf20Sopenharmony_ci char *buf) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev); 698c2ecf20Sopenharmony_ci ssize_t count = 0; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) 728c2ecf20Sopenharmony_ci return -EPERM; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci mutex_lock(&wldev->wl->mutex); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci switch (wldev->phy.interfmode) { 778c2ecf20Sopenharmony_ci case B43legacy_INTERFMODE_NONE: 788c2ecf20Sopenharmony_ci count = snprintf(buf, PAGE_SIZE, "0 (No Interference" 798c2ecf20Sopenharmony_ci " Mitigation)\n"); 808c2ecf20Sopenharmony_ci break; 818c2ecf20Sopenharmony_ci case B43legacy_INTERFMODE_NONWLAN: 828c2ecf20Sopenharmony_ci count = snprintf(buf, PAGE_SIZE, "1 (Non-WLAN Interference" 838c2ecf20Sopenharmony_ci " Mitigation)\n"); 848c2ecf20Sopenharmony_ci break; 858c2ecf20Sopenharmony_ci case B43legacy_INTERFMODE_MANUALWLAN: 868c2ecf20Sopenharmony_ci count = snprintf(buf, PAGE_SIZE, "2 (WLAN Interference" 878c2ecf20Sopenharmony_ci " Mitigation)\n"); 888c2ecf20Sopenharmony_ci break; 898c2ecf20Sopenharmony_ci default: 908c2ecf20Sopenharmony_ci B43legacy_WARN_ON(1); 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci mutex_unlock(&wldev->wl->mutex); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci return count; 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic ssize_t b43legacy_attr_interfmode_store(struct device *dev, 998c2ecf20Sopenharmony_ci struct device_attribute *attr, 1008c2ecf20Sopenharmony_ci const char *buf, size_t count) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev); 1038c2ecf20Sopenharmony_ci unsigned long flags; 1048c2ecf20Sopenharmony_ci int err; 1058c2ecf20Sopenharmony_ci int mode; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) 1088c2ecf20Sopenharmony_ci return -EPERM; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci mode = get_integer(buf, count); 1118c2ecf20Sopenharmony_ci switch (mode) { 1128c2ecf20Sopenharmony_ci case 0: 1138c2ecf20Sopenharmony_ci mode = B43legacy_INTERFMODE_NONE; 1148c2ecf20Sopenharmony_ci break; 1158c2ecf20Sopenharmony_ci case 1: 1168c2ecf20Sopenharmony_ci mode = B43legacy_INTERFMODE_NONWLAN; 1178c2ecf20Sopenharmony_ci break; 1188c2ecf20Sopenharmony_ci case 2: 1198c2ecf20Sopenharmony_ci mode = B43legacy_INTERFMODE_MANUALWLAN; 1208c2ecf20Sopenharmony_ci break; 1218c2ecf20Sopenharmony_ci case 3: 1228c2ecf20Sopenharmony_ci mode = B43legacy_INTERFMODE_AUTOWLAN; 1238c2ecf20Sopenharmony_ci break; 1248c2ecf20Sopenharmony_ci default: 1258c2ecf20Sopenharmony_ci return -EINVAL; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci mutex_lock(&wldev->wl->mutex); 1298c2ecf20Sopenharmony_ci spin_lock_irqsave(&wldev->wl->irq_lock, flags); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci err = b43legacy_radio_set_interference_mitigation(wldev, mode); 1328c2ecf20Sopenharmony_ci if (err) 1338c2ecf20Sopenharmony_ci b43legacyerr(wldev->wl, "Interference Mitigation not " 1348c2ecf20Sopenharmony_ci "supported by device\n"); 1358c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wldev->wl->irq_lock, flags); 1368c2ecf20Sopenharmony_ci mutex_unlock(&wldev->wl->mutex); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci return err ? err : count; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic DEVICE_ATTR(interference, 0644, 1428c2ecf20Sopenharmony_ci b43legacy_attr_interfmode_show, 1438c2ecf20Sopenharmony_ci b43legacy_attr_interfmode_store); 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic ssize_t b43legacy_attr_preamble_show(struct device *dev, 1468c2ecf20Sopenharmony_ci struct device_attribute *attr, 1478c2ecf20Sopenharmony_ci char *buf) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev); 1508c2ecf20Sopenharmony_ci ssize_t count; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) 1538c2ecf20Sopenharmony_ci return -EPERM; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci mutex_lock(&wldev->wl->mutex); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci if (wldev->short_preamble) 1588c2ecf20Sopenharmony_ci count = snprintf(buf, PAGE_SIZE, "1 (Short Preamble" 1598c2ecf20Sopenharmony_ci " enabled)\n"); 1608c2ecf20Sopenharmony_ci else 1618c2ecf20Sopenharmony_ci count = snprintf(buf, PAGE_SIZE, "0 (Short Preamble" 1628c2ecf20Sopenharmony_ci " disabled)\n"); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci mutex_unlock(&wldev->wl->mutex); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci return count; 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic ssize_t b43legacy_attr_preamble_store(struct device *dev, 1708c2ecf20Sopenharmony_ci struct device_attribute *attr, 1718c2ecf20Sopenharmony_ci const char *buf, size_t count) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct b43legacy_wldev *wldev = dev_to_b43legacy_wldev(dev); 1748c2ecf20Sopenharmony_ci unsigned long flags; 1758c2ecf20Sopenharmony_ci int value; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (!capable(CAP_NET_ADMIN)) 1788c2ecf20Sopenharmony_ci return -EPERM; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci value = get_boolean(buf, count); 1818c2ecf20Sopenharmony_ci if (value < 0) 1828c2ecf20Sopenharmony_ci return value; 1838c2ecf20Sopenharmony_ci mutex_lock(&wldev->wl->mutex); 1848c2ecf20Sopenharmony_ci spin_lock_irqsave(&wldev->wl->irq_lock, flags); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci wldev->short_preamble = !!value; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&wldev->wl->irq_lock, flags); 1898c2ecf20Sopenharmony_ci mutex_unlock(&wldev->wl->mutex); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci return count; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic DEVICE_ATTR(shortpreamble, 0644, 1958c2ecf20Sopenharmony_ci b43legacy_attr_preamble_show, 1968c2ecf20Sopenharmony_ci b43legacy_attr_preamble_store); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ciint b43legacy_sysfs_register(struct b43legacy_wldev *wldev) 1998c2ecf20Sopenharmony_ci{ 2008c2ecf20Sopenharmony_ci struct device *dev = wldev->dev->dev; 2018c2ecf20Sopenharmony_ci int err; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci B43legacy_WARN_ON(b43legacy_status(wldev) != 2048c2ecf20Sopenharmony_ci B43legacy_STAT_INITIALIZED); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci err = device_create_file(dev, &dev_attr_interference); 2078c2ecf20Sopenharmony_ci if (err) 2088c2ecf20Sopenharmony_ci goto out; 2098c2ecf20Sopenharmony_ci err = device_create_file(dev, &dev_attr_shortpreamble); 2108c2ecf20Sopenharmony_ci if (err) 2118c2ecf20Sopenharmony_ci goto err_remove_interfmode; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ciout: 2148c2ecf20Sopenharmony_ci return err; 2158c2ecf20Sopenharmony_cierr_remove_interfmode: 2168c2ecf20Sopenharmony_ci device_remove_file(dev, &dev_attr_interference); 2178c2ecf20Sopenharmony_ci goto out; 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_civoid b43legacy_sysfs_unregister(struct b43legacy_wldev *wldev) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci struct device *dev = wldev->dev->dev; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci device_remove_file(dev, &dev_attr_shortpreamble); 2258c2ecf20Sopenharmony_ci device_remove_file(dev, &dev_attr_interference); 2268c2ecf20Sopenharmony_ci} 227