1 /* This program is free software; you can redistribute it and/or modify 2 * it under the terms of the GNU General Public License version 2 3 * as published by the Free Software Foundation. 4 * 5 * This program is distributed in the hope that it will be useful, 6 * but WITHOUT ANY WARRANTY; without even the implied warranty of 7 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 8 * GNU General Public License for more details. 9 * 10 * Authors: 11 * Alexander Aring <aar@pengutronix.de> 12 * 13 * Based on: net/wireless/sysfs.c 14 */ 15 16 #include <linux/device.h> 17 18 #include <net/cfg802154.h> 19 20 #include "core.h" 21 #include "sysfs.h" 22 23 static inline struct cfg802154_registered_device * 24 dev_to_rdev(struct device *dev) 25 { 26 return container_of(dev, struct cfg802154_registered_device, 27 wpan_phy.dev); 28 } 29 30 #define SHOW_FMT(name, fmt, member) \ 31 static ssize_t name ## _show(struct device *dev, \ 32 struct device_attribute *attr, \ 33 char *buf) \ 34 { \ 35 return sprintf(buf, fmt "\n", dev_to_rdev(dev)->member); \ 36 } \ 37 static DEVICE_ATTR_RO(name) 38 39 SHOW_FMT(index, "%d", wpan_phy_idx); 40 41 static ssize_t name_show(struct device *dev, 42 struct device_attribute *attr, 43 char *buf) 44 { 45 struct wpan_phy *wpan_phy = &dev_to_rdev(dev)->wpan_phy; 46 47 return sprintf(buf, "%s\n", dev_name(&wpan_phy->dev)); 48 } 49 static DEVICE_ATTR_RO(name); 50 51 #define MASTER_SHOW_COMPLEX(name, format_string, args...) \ 52 static ssize_t name ## _show(struct device *dev, \ 53 struct device_attribute *attr, char *buf) \ 54 { \ 55 struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev); \ 56 int ret; \ 57 \ 58 mutex_lock(&phy->pib_lock); \ 59 ret = snprintf(buf, PAGE_SIZE, format_string "\n", args); \ 60 mutex_unlock(&phy->pib_lock); \ 61 return ret; \ 62 } \ 63 static DEVICE_ATTR_RO(name) 64 65 #define MASTER_SHOW(field, format_string) \ 66 MASTER_SHOW_COMPLEX(field, format_string, phy->field) 67 68 MASTER_SHOW(current_channel, "%d"); 69 MASTER_SHOW(current_page, "%d"); 70 MASTER_SHOW(transmit_power, "%d +- 1 dB"); 71 MASTER_SHOW_COMPLEX(cca_mode, "%d", phy->cca.mode); 72 73 static ssize_t channels_supported_show(struct device *dev, 74 struct device_attribute *attr, 75 char *buf) 76 { 77 struct wpan_phy *phy = container_of(dev, struct wpan_phy, dev); 78 int ret; 79 int i, len = 0; 80 81 mutex_lock(&phy->pib_lock); 82 for (i = 0; i < 32; i++) { 83 ret = snprintf(buf + len, PAGE_SIZE - len, 84 "%#09x\n", phy->channels_supported[i]); 85 if (ret < 0) 86 break; 87 len += ret; 88 } 89 mutex_unlock(&phy->pib_lock); 90 return len; 91 } 92 static DEVICE_ATTR_RO(channels_supported); 93 94 static void wpan_phy_release(struct device *dev) 95 { 96 struct cfg802154_registered_device *rdev = dev_to_rdev(dev); 97 98 cfg802154_dev_free(rdev); 99 } 100 101 static struct attribute *pmib_attrs[] = { 102 &dev_attr_index.attr, 103 &dev_attr_name.attr, 104 /* below will be removed soon */ 105 &dev_attr_current_channel.attr, 106 &dev_attr_current_page.attr, 107 &dev_attr_channels_supported.attr, 108 &dev_attr_transmit_power.attr, 109 &dev_attr_cca_mode.attr, 110 NULL, 111 }; 112 ATTRIBUTE_GROUPS(pmib); 113 114 struct class wpan_phy_class = { 115 .name = "ieee802154", 116 .dev_release = wpan_phy_release, 117 .dev_groups = pmib_groups, 118 }; 119 120 int wpan_phy_sysfs_init(void) 121 { 122 return class_register(&wpan_phy_class); 123 } 124 125 void wpan_phy_sysfs_exit(void) 126 { 127 class_unregister(&wpan_phy_class); 128 } 129