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 /** 311beeffe4STony Jones * hwmon_device_register - register w/ hwmon 321236441fSMark M. Hoffman * @dev: the device to register 331236441fSMark M. Hoffman * 341beeffe4STony Jones * hwmon_device_unregister() must be called when the device is no 351236441fSMark M. Hoffman * longer needed. 361236441fSMark M. Hoffman * 371beeffe4STony Jones * Returns the pointer to the new device. 381236441fSMark M. Hoffman */ 391beeffe4STony Jones struct device *hwmon_device_register(struct device *dev) 401236441fSMark M. Hoffman { 411beeffe4STony 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*2871f552SGreg Kroah-Hartman hwdev = device_create_drvdata(hwmon_class, dev, MKDEV(0, 0), NULL, 59*2871f552SGreg Kroah-Hartman HWMON_ID_FORMAT, id); 601236441fSMark M. Hoffman 611beeffe4STony Jones if (IS_ERR(hwdev)) { 62ded2b666SMark M. Hoffman spin_lock(&idr_lock); 631236441fSMark M. Hoffman idr_remove(&hwmon_idr, id); 64ded2b666SMark M. Hoffman spin_unlock(&idr_lock); 65ded2b666SMark M. Hoffman } 661236441fSMark M. Hoffman 671beeffe4STony Jones return hwdev; 681236441fSMark M. Hoffman } 691236441fSMark M. Hoffman 701236441fSMark M. Hoffman /** 711236441fSMark M. Hoffman * hwmon_device_unregister - removes the previously registered class device 721236441fSMark M. Hoffman * 731beeffe4STony Jones * @dev: the class device to destroy 741236441fSMark M. Hoffman */ 751beeffe4STony Jones void hwmon_device_unregister(struct device *dev) 761236441fSMark M. Hoffman { 771236441fSMark M. Hoffman int id; 781236441fSMark M. Hoffman 791beeffe4STony Jones if (likely(sscanf(dev->bus_id, HWMON_ID_FORMAT, &id) == 1)) { 801beeffe4STony Jones device_unregister(dev); 81ded2b666SMark M. Hoffman spin_lock(&idr_lock); 821236441fSMark M. Hoffman idr_remove(&hwmon_idr, id); 83ded2b666SMark M. Hoffman spin_unlock(&idr_lock); 841236441fSMark M. Hoffman } else 851beeffe4STony Jones dev_dbg(dev->parent, 861236441fSMark M. Hoffman "hwmon_device_unregister() failed: bad class ID!\n"); 871236441fSMark M. Hoffman } 881236441fSMark M. Hoffman 891236441fSMark M. Hoffman static int __init hwmon_init(void) 901236441fSMark M. Hoffman { 911236441fSMark M. Hoffman hwmon_class = class_create(THIS_MODULE, "hwmon"); 921236441fSMark M. Hoffman if (IS_ERR(hwmon_class)) { 931236441fSMark M. Hoffman printk(KERN_ERR "hwmon.c: couldn't create sysfs class\n"); 941236441fSMark M. Hoffman return PTR_ERR(hwmon_class); 951236441fSMark M. Hoffman } 961236441fSMark M. Hoffman return 0; 971236441fSMark M. Hoffman } 981236441fSMark M. Hoffman 991236441fSMark M. Hoffman static void __exit hwmon_exit(void) 1001236441fSMark M. Hoffman { 1011236441fSMark M. Hoffman class_destroy(hwmon_class); 1021236441fSMark M. Hoffman } 1031236441fSMark M. Hoffman 10437f54ee5SDavid Brownell subsys_initcall(hwmon_init); 1051236441fSMark M. Hoffman module_exit(hwmon_exit); 1061236441fSMark M. Hoffman 1071236441fSMark M. Hoffman EXPORT_SYMBOL_GPL(hwmon_device_register); 1081236441fSMark M. Hoffman EXPORT_SYMBOL_GPL(hwmon_device_unregister); 1091236441fSMark M. Hoffman 1101236441fSMark M. Hoffman MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>"); 1111236441fSMark M. Hoffman MODULE_DESCRIPTION("hardware monitoring sysfs/class support"); 1121236441fSMark M. Hoffman MODULE_LICENSE("GPL"); 1131236441fSMark M. Hoffman 114