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> 20*ded2b666SMark 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); 28*ded2b666SMark M. Hoffman static DEFINE_SPINLOCK(idr_lock); 291236441fSMark M. Hoffman 301236441fSMark M. Hoffman /** 311236441fSMark M. Hoffman * hwmon_device_register - register w/ hwmon sysfs class 321236441fSMark M. Hoffman * @dev: the device to register 331236441fSMark M. Hoffman * 341236441fSMark M. Hoffman * hwmon_device_unregister() must be called when the class device is no 351236441fSMark M. Hoffman * longer needed. 361236441fSMark M. Hoffman * 371236441fSMark M. Hoffman * Returns the pointer to the new struct class device. 381236441fSMark M. Hoffman */ 391236441fSMark M. Hoffman struct class_device *hwmon_device_register(struct device *dev) 401236441fSMark M. Hoffman { 411236441fSMark M. Hoffman struct class_device *cdev; 42*ded2b666SMark M. Hoffman int id, err; 431236441fSMark M. Hoffman 44*ded2b666SMark M. Hoffman again: 45*ded2b666SMark M. Hoffman if (unlikely(idr_pre_get(&hwmon_idr, GFP_KERNEL) == 0)) 461236441fSMark M. Hoffman return ERR_PTR(-ENOMEM); 471236441fSMark M. Hoffman 48*ded2b666SMark M. Hoffman spin_lock(&idr_lock); 49*ded2b666SMark M. Hoffman err = idr_get_new(&hwmon_idr, NULL, &id); 50*ded2b666SMark M. Hoffman spin_unlock(&idr_lock); 51*ded2b666SMark M. Hoffman 52*ded2b666SMark M. Hoffman if (unlikely(err == -EAGAIN)) 53*ded2b666SMark M. Hoffman goto again; 54*ded2b666SMark M. Hoffman else if (unlikely(err)) 55*ded2b666SMark M. Hoffman return ERR_PTR(err); 561236441fSMark M. Hoffman 571236441fSMark M. Hoffman id = id & MAX_ID_MASK; 5853f46542SGreg Kroah-Hartman cdev = class_device_create(hwmon_class, NULL, MKDEV(0,0), dev, 591236441fSMark M. Hoffman HWMON_ID_FORMAT, id); 601236441fSMark M. Hoffman 61*ded2b666SMark M. Hoffman if (IS_ERR(cdev)) { 62*ded2b666SMark M. Hoffman spin_lock(&idr_lock); 631236441fSMark M. Hoffman idr_remove(&hwmon_idr, id); 64*ded2b666SMark M. Hoffman spin_unlock(&idr_lock); 65*ded2b666SMark M. Hoffman } 661236441fSMark M. Hoffman 671236441fSMark M. Hoffman return cdev; 681236441fSMark M. Hoffman } 691236441fSMark M. Hoffman 701236441fSMark M. Hoffman /** 711236441fSMark M. Hoffman * hwmon_device_unregister - removes the previously registered class device 721236441fSMark M. Hoffman * 731236441fSMark M. Hoffman * @cdev: the class device to destroy 741236441fSMark M. Hoffman */ 751236441fSMark M. Hoffman void hwmon_device_unregister(struct class_device *cdev) 761236441fSMark M. Hoffman { 771236441fSMark M. Hoffman int id; 781236441fSMark M. Hoffman 79*ded2b666SMark M. Hoffman if (likely(sscanf(cdev->class_id, HWMON_ID_FORMAT, &id) == 1)) { 801236441fSMark M. Hoffman class_device_unregister(cdev); 81*ded2b666SMark M. Hoffman spin_lock(&idr_lock); 821236441fSMark M. Hoffman idr_remove(&hwmon_idr, id); 83*ded2b666SMark M. Hoffman spin_unlock(&idr_lock); 841236441fSMark M. Hoffman } else 851236441fSMark M. Hoffman dev_dbg(cdev->dev, 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 1041236441fSMark M. Hoffman module_init(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