aha/drivers/hwmon/hwmon.c
David Brownell 37f54ee546 hwmon: Use subsys_initcall
Subsystem infrastructure should normally register with "subsys_initcall",
so that it's available to drivers that may need to initialize early.

This patch updates "hwmon" to do so.  It's common for embedded systems to
have multifunction chips with hardware monitoring interfaces, and to have
those chips be used during system bringup ... before a normal "module_init"
would kick, or maybe just linked so they'd init before hwmon.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Jean Delvare <khali@linux-fr.org>
2007-02-14 21:15:04 +01:00

113 lines
2.7 KiB
C

/*
hwmon.c - part of lm_sensors, Linux kernel modules for hardware monitoring
This file defines the sysfs class "hwmon", for use by sensors drivers.
Copyright (C) 2005 Mark M. Hoffman <mhoffman@lightlink.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/kdev_t.h>
#include <linux/idr.h>
#include <linux/hwmon.h>
#include <linux/gfp.h>
#include <linux/spinlock.h>
#define HWMON_ID_PREFIX "hwmon"
#define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d"
static struct class *hwmon_class;
static DEFINE_IDR(hwmon_idr);
static DEFINE_SPINLOCK(idr_lock);
/**
* hwmon_device_register - register w/ hwmon sysfs class
* @dev: the device to register
*
* hwmon_device_unregister() must be called when the class device is no
* longer needed.
*
* Returns the pointer to the new struct class device.
*/
struct class_device *hwmon_device_register(struct device *dev)
{
struct class_device *cdev;
int id, err;
again:
if (unlikely(idr_pre_get(&hwmon_idr, GFP_KERNEL) == 0))
return ERR_PTR(-ENOMEM);
spin_lock(&idr_lock);
err = idr_get_new(&hwmon_idr, NULL, &id);
spin_unlock(&idr_lock);
if (unlikely(err == -EAGAIN))
goto again;
else if (unlikely(err))
return ERR_PTR(err);
id = id & MAX_ID_MASK;
cdev = class_device_create(hwmon_class, NULL, MKDEV(0,0), dev,
HWMON_ID_FORMAT, id);
if (IS_ERR(cdev)) {
spin_lock(&idr_lock);
idr_remove(&hwmon_idr, id);
spin_unlock(&idr_lock);
}
return cdev;
}
/**
* hwmon_device_unregister - removes the previously registered class device
*
* @cdev: the class device to destroy
*/
void hwmon_device_unregister(struct class_device *cdev)
{
int id;
if (likely(sscanf(cdev->class_id, HWMON_ID_FORMAT, &id) == 1)) {
class_device_unregister(cdev);
spin_lock(&idr_lock);
idr_remove(&hwmon_idr, id);
spin_unlock(&idr_lock);
} else
dev_dbg(cdev->dev,
"hwmon_device_unregister() failed: bad class ID!\n");
}
static int __init hwmon_init(void)
{
hwmon_class = class_create(THIS_MODULE, "hwmon");
if (IS_ERR(hwmon_class)) {
printk(KERN_ERR "hwmon.c: couldn't create sysfs class\n");
return PTR_ERR(hwmon_class);
}
return 0;
}
static void __exit hwmon_exit(void)
{
class_destroy(hwmon_class);
}
subsys_initcall(hwmon_init);
module_exit(hwmon_exit);
EXPORT_SYMBOL_GPL(hwmon_device_register);
EXPORT_SYMBOL_GPL(hwmon_device_unregister);
MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
MODULE_DESCRIPTION("hardware monitoring sysfs/class support");
MODULE_LICENSE("GPL");