1 /* 2 * hwmon.c - part of lm_sensors, Linux kernel modules for hardware monitoring 3 * 4 * This file defines the sysfs class "hwmon", for use by sensors drivers. 5 * 6 * Copyright (C) 2005 Mark M. Hoffman <mhoffman@lightlink.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; version 2 of the License. 11 */ 12 13 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 14 15 #include <linux/module.h> 16 #include <linux/device.h> 17 #include <linux/err.h> 18 #include <linux/slab.h> 19 #include <linux/kdev_t.h> 20 #include <linux/idr.h> 21 #include <linux/hwmon.h> 22 #include <linux/gfp.h> 23 #include <linux/spinlock.h> 24 #include <linux/pci.h> 25 #include <linux/string.h> 26 27 #define HWMON_ID_PREFIX "hwmon" 28 #define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d" 29 30 struct hwmon_device { 31 const char *name; 32 struct device dev; 33 }; 34 #define to_hwmon_device(d) container_of(d, struct hwmon_device, dev) 35 36 static ssize_t 37 show_name(struct device *dev, struct device_attribute *attr, char *buf) 38 { 39 return sprintf(buf, "%s\n", to_hwmon_device(dev)->name); 40 } 41 static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); 42 43 static struct attribute *hwmon_dev_attrs[] = { 44 &dev_attr_name.attr, 45 NULL 46 }; 47 48 static umode_t hwmon_dev_name_is_visible(struct kobject *kobj, 49 struct attribute *attr, int n) 50 { 51 struct device *dev = container_of(kobj, struct device, kobj); 52 53 if (to_hwmon_device(dev)->name == NULL) 54 return 0; 55 56 return attr->mode; 57 } 58 59 static struct attribute_group hwmon_dev_attr_group = { 60 .attrs = hwmon_dev_attrs, 61 .is_visible = hwmon_dev_name_is_visible, 62 }; 63 64 static const struct attribute_group *hwmon_dev_attr_groups[] = { 65 &hwmon_dev_attr_group, 66 NULL 67 }; 68 69 static void hwmon_dev_release(struct device *dev) 70 { 71 kfree(to_hwmon_device(dev)); 72 } 73 74 static struct class hwmon_class = { 75 .name = "hwmon", 76 .owner = THIS_MODULE, 77 .dev_groups = hwmon_dev_attr_groups, 78 .dev_release = hwmon_dev_release, 79 }; 80 81 static DEFINE_IDA(hwmon_ida); 82 83 /** 84 * hwmon_device_register_with_groups - register w/ hwmon 85 * @dev: the parent device 86 * @name: hwmon name attribute 87 * @drvdata: driver data to attach to created device 88 * @groups: List of attribute groups to create 89 * 90 * hwmon_device_unregister() must be called when the device is no 91 * longer needed. 92 * 93 * Returns the pointer to the new device. 94 */ 95 struct device * 96 hwmon_device_register_with_groups(struct device *dev, const char *name, 97 void *drvdata, 98 const struct attribute_group **groups) 99 { 100 struct hwmon_device *hwdev; 101 int err, id; 102 103 /* Do not accept invalid characters in hwmon name attribute */ 104 if (name && (!strlen(name) || strpbrk(name, "-* \t\n"))) 105 return ERR_PTR(-EINVAL); 106 107 id = ida_simple_get(&hwmon_ida, 0, 0, GFP_KERNEL); 108 if (id < 0) 109 return ERR_PTR(id); 110 111 hwdev = kzalloc(sizeof(*hwdev), GFP_KERNEL); 112 if (hwdev == NULL) { 113 err = -ENOMEM; 114 goto ida_remove; 115 } 116 117 hwdev->name = name; 118 hwdev->dev.class = &hwmon_class; 119 hwdev->dev.parent = dev; 120 hwdev->dev.groups = groups; 121 hwdev->dev.of_node = dev ? dev->of_node : NULL; 122 dev_set_drvdata(&hwdev->dev, drvdata); 123 dev_set_name(&hwdev->dev, HWMON_ID_FORMAT, id); 124 err = device_register(&hwdev->dev); 125 if (err) 126 goto free; 127 128 return &hwdev->dev; 129 130 free: 131 kfree(hwdev); 132 ida_remove: 133 ida_simple_remove(&hwmon_ida, id); 134 return ERR_PTR(err); 135 } 136 EXPORT_SYMBOL_GPL(hwmon_device_register_with_groups); 137 138 /** 139 * hwmon_device_register - register w/ hwmon 140 * @dev: the device to register 141 * 142 * hwmon_device_unregister() must be called when the device is no 143 * longer needed. 144 * 145 * Returns the pointer to the new device. 146 */ 147 struct device *hwmon_device_register(struct device *dev) 148 { 149 return hwmon_device_register_with_groups(dev, NULL, NULL, NULL); 150 } 151 EXPORT_SYMBOL_GPL(hwmon_device_register); 152 153 /** 154 * hwmon_device_unregister - removes the previously registered class device 155 * 156 * @dev: the class device to destroy 157 */ 158 void hwmon_device_unregister(struct device *dev) 159 { 160 int id; 161 162 if (likely(sscanf(dev_name(dev), HWMON_ID_FORMAT, &id) == 1)) { 163 device_unregister(dev); 164 ida_simple_remove(&hwmon_ida, id); 165 } else 166 dev_dbg(dev->parent, 167 "hwmon_device_unregister() failed: bad class ID!\n"); 168 } 169 EXPORT_SYMBOL_GPL(hwmon_device_unregister); 170 171 static void devm_hwmon_release(struct device *dev, void *res) 172 { 173 struct device *hwdev = *(struct device **)res; 174 175 hwmon_device_unregister(hwdev); 176 } 177 178 /** 179 * devm_hwmon_device_register_with_groups - register w/ hwmon 180 * @dev: the parent device 181 * @name: hwmon name attribute 182 * @drvdata: driver data to attach to created device 183 * @groups: List of attribute groups to create 184 * 185 * Returns the pointer to the new device. The new device is automatically 186 * unregistered with the parent device. 187 */ 188 struct device * 189 devm_hwmon_device_register_with_groups(struct device *dev, const char *name, 190 void *drvdata, 191 const struct attribute_group **groups) 192 { 193 struct device **ptr, *hwdev; 194 195 if (!dev) 196 return ERR_PTR(-EINVAL); 197 198 ptr = devres_alloc(devm_hwmon_release, sizeof(*ptr), GFP_KERNEL); 199 if (!ptr) 200 return ERR_PTR(-ENOMEM); 201 202 hwdev = hwmon_device_register_with_groups(dev, name, drvdata, groups); 203 if (IS_ERR(hwdev)) 204 goto error; 205 206 *ptr = hwdev; 207 devres_add(dev, ptr); 208 return hwdev; 209 210 error: 211 devres_free(ptr); 212 return hwdev; 213 } 214 EXPORT_SYMBOL_GPL(devm_hwmon_device_register_with_groups); 215 216 static int devm_hwmon_match(struct device *dev, void *res, void *data) 217 { 218 struct device **hwdev = res; 219 220 return *hwdev == data; 221 } 222 223 /** 224 * devm_hwmon_device_unregister - removes a previously registered hwmon device 225 * 226 * @dev: the parent device of the device to unregister 227 */ 228 void devm_hwmon_device_unregister(struct device *dev) 229 { 230 WARN_ON(devres_release(dev, devm_hwmon_release, devm_hwmon_match, dev)); 231 } 232 EXPORT_SYMBOL_GPL(devm_hwmon_device_unregister); 233 234 static void __init hwmon_pci_quirks(void) 235 { 236 #if defined CONFIG_X86 && defined CONFIG_PCI 237 struct pci_dev *sb; 238 u16 base; 239 u8 enable; 240 241 /* Open access to 0x295-0x296 on MSI MS-7031 */ 242 sb = pci_get_device(PCI_VENDOR_ID_ATI, 0x436c, NULL); 243 if (sb) { 244 if (sb->subsystem_vendor == 0x1462 && /* MSI */ 245 sb->subsystem_device == 0x0031) { /* MS-7031 */ 246 pci_read_config_byte(sb, 0x48, &enable); 247 pci_read_config_word(sb, 0x64, &base); 248 249 if (base == 0 && !(enable & BIT(2))) { 250 dev_info(&sb->dev, 251 "Opening wide generic port at 0x295\n"); 252 pci_write_config_word(sb, 0x64, 0x295); 253 pci_write_config_byte(sb, 0x48, 254 enable | BIT(2)); 255 } 256 } 257 pci_dev_put(sb); 258 } 259 #endif 260 } 261 262 static int __init hwmon_init(void) 263 { 264 int err; 265 266 hwmon_pci_quirks(); 267 268 err = class_register(&hwmon_class); 269 if (err) { 270 pr_err("couldn't register hwmon sysfs class\n"); 271 return err; 272 } 273 return 0; 274 } 275 276 static void __exit hwmon_exit(void) 277 { 278 class_unregister(&hwmon_class); 279 } 280 281 subsys_initcall(hwmon_init); 282 module_exit(hwmon_exit); 283 284 MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>"); 285 MODULE_DESCRIPTION("hardware monitoring sysfs/class support"); 286 MODULE_LICENSE("GPL"); 287 288