11236441fSMark M. Hoffman /* 21236441fSMark M. Hoffman hwmon.c - part of lm_sensors, Linux kernel modules for hardware monitoring 31236441fSMark M. Hoffman 41236441fSMark M. Hoffman This file defines the sysfs class "hwmon", for use by sensors drivers. 51236441fSMark M. Hoffman 61236441fSMark M. Hoffman Copyright (C) 2005 Mark M. Hoffman <mhoffman@lightlink.com> 71236441fSMark M. Hoffman 81236441fSMark M. Hoffman This program is free software; you can redistribute it and/or modify 91236441fSMark M. Hoffman it under the terms of the GNU General Public License as published by 101236441fSMark M. Hoffman the Free Software Foundation; version 2 of the License. 111236441fSMark M. Hoffman */ 121236441fSMark M. Hoffman 131236441fSMark M. Hoffman #include <linux/module.h> 141236441fSMark M. Hoffman #include <linux/device.h> 151236441fSMark M. Hoffman #include <linux/err.h> 161236441fSMark M. Hoffman #include <linux/kdev_t.h> 171236441fSMark M. Hoffman #include <linux/idr.h> 181236441fSMark M. Hoffman #include <linux/hwmon.h> 198c65b4a6STim Schmielau #include <linux/gfp.h> 20ded2b666SMark M. Hoffman #include <linux/spinlock.h> 211236441fSMark M. Hoffman 221236441fSMark M. Hoffman #define HWMON_ID_PREFIX "hwmon" 231236441fSMark M. Hoffman #define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d" 241236441fSMark M. Hoffman 251236441fSMark M. Hoffman static struct class *hwmon_class; 261236441fSMark M. Hoffman 271236441fSMark M. Hoffman static DEFINE_IDR(hwmon_idr); 28ded2b666SMark M. Hoffman static DEFINE_SPINLOCK(idr_lock); 291236441fSMark M. Hoffman 301236441fSMark M. Hoffman /** 31*1beeffe4STony Jones * hwmon_device_register - register w/ hwmon 321236441fSMark M. Hoffman * @dev: the device to register 331236441fSMark M. Hoffman * 34*1beeffe4STony Jones * hwmon_device_unregister() must be called when the device is no 351236441fSMark M. Hoffman * longer needed. 361236441fSMark M. Hoffman * 37*1beeffe4STony Jones * Returns the pointer to the new device. 381236441fSMark M. Hoffman */ 39*1beeffe4STony Jones struct device *hwmon_device_register(struct device *dev) 401236441fSMark M. Hoffman { 41*1beeffe4STony Jones struct device *hwdev; 42ded2b666SMark M. Hoffman int id, err; 431236441fSMark M. Hoffman 44ded2b666SMark M. Hoffman again: 45ded2b666SMark M. Hoffman if (unlikely(idr_pre_get(&hwmon_idr, GFP_KERNEL) == 0)) 461236441fSMark M. Hoffman return ERR_PTR(-ENOMEM); 471236441fSMark M. Hoffman 48ded2b666SMark M. Hoffman spin_lock(&idr_lock); 49ded2b666SMark M. Hoffman err = idr_get_new(&hwmon_idr, NULL, &id); 50ded2b666SMark M. Hoffman spin_unlock(&idr_lock); 51ded2b666SMark M. Hoffman 52ded2b666SMark M. Hoffman if (unlikely(err == -EAGAIN)) 53ded2b666SMark M. Hoffman goto again; 54ded2b666SMark M. Hoffman else if (unlikely(err)) 55ded2b666SMark M. Hoffman return ERR_PTR(err); 561236441fSMark M. Hoffman 571236441fSMark M. Hoffman id = id & MAX_ID_MASK; 58*1beeffe4STony Jones hwdev = device_create(hwmon_class, dev, MKDEV(0,0), HWMON_ID_FORMAT, id); 591236441fSMark M. Hoffman 60*1beeffe4STony Jones if (IS_ERR(hwdev)) { 61ded2b666SMark M. Hoffman spin_lock(&idr_lock); 621236441fSMark M. Hoffman idr_remove(&hwmon_idr, id); 63ded2b666SMark M. Hoffman spin_unlock(&idr_lock); 64ded2b666SMark M. Hoffman } 651236441fSMark M. Hoffman 66*1beeffe4STony Jones return hwdev; 671236441fSMark M. Hoffman } 681236441fSMark M. Hoffman 691236441fSMark M. Hoffman /** 701236441fSMark M. Hoffman * hwmon_device_unregister - removes the previously registered class device 711236441fSMark M. Hoffman * 72*1beeffe4STony Jones * @dev: the class device to destroy 731236441fSMark M. Hoffman */ 74*1beeffe4STony Jones void hwmon_device_unregister(struct device *dev) 751236441fSMark M. Hoffman { 761236441fSMark M. Hoffman int id; 771236441fSMark M. Hoffman 78*1beeffe4STony Jones if (likely(sscanf(dev->bus_id, HWMON_ID_FORMAT, &id) == 1)) { 79*1beeffe4STony Jones device_unregister(dev); 80ded2b666SMark M. Hoffman spin_lock(&idr_lock); 811236441fSMark M. Hoffman idr_remove(&hwmon_idr, id); 82ded2b666SMark M. Hoffman spin_unlock(&idr_lock); 831236441fSMark M. Hoffman } else 84*1beeffe4STony Jones dev_dbg(dev->parent, 851236441fSMark M. Hoffman "hwmon_device_unregister() failed: bad class ID!\n"); 861236441fSMark M. Hoffman } 871236441fSMark M. Hoffman 881236441fSMark M. Hoffman static int __init hwmon_init(void) 891236441fSMark M. Hoffman { 901236441fSMark M. Hoffman hwmon_class = class_create(THIS_MODULE, "hwmon"); 911236441fSMark M. Hoffman if (IS_ERR(hwmon_class)) { 921236441fSMark M. Hoffman printk(KERN_ERR "hwmon.c: couldn't create sysfs class\n"); 931236441fSMark M. Hoffman return PTR_ERR(hwmon_class); 941236441fSMark M. Hoffman } 951236441fSMark M. Hoffman return 0; 961236441fSMark M. Hoffman } 971236441fSMark M. Hoffman 981236441fSMark M. Hoffman static void __exit hwmon_exit(void) 991236441fSMark M. Hoffman { 1001236441fSMark M. Hoffman class_destroy(hwmon_class); 1011236441fSMark M. Hoffman } 1021236441fSMark M. Hoffman 10337f54ee5SDavid Brownell subsys_initcall(hwmon_init); 1041236441fSMark M. Hoffman module_exit(hwmon_exit); 1051236441fSMark M. Hoffman 1061236441fSMark M. Hoffman EXPORT_SYMBOL_GPL(hwmon_device_register); 1071236441fSMark M. Hoffman EXPORT_SYMBOL_GPL(hwmon_device_unregister); 1081236441fSMark M. Hoffman 1091236441fSMark M. Hoffman MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>"); 1101236441fSMark M. Hoffman MODULE_DESCRIPTION("hardware monitoring sysfs/class support"); 1111236441fSMark M. Hoffman MODULE_LICENSE("GPL"); 1121236441fSMark M. Hoffman 113