xref: /linux/drivers/hwmon/hwmon.c (revision ded2b66615613093eeb83b81499bc270de8fc499)
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