* [PATCH 1/5] watchdog: Add multiple device support
@ 2012-02-28 22:47 Alan Cox
2012-02-28 22:47 ` [PATCH 2/5] watchdog: Add a flag to indicate the watchdog doesn't reboot things Alan Cox
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Alan Cox @ 2012-02-28 22:47 UTC (permalink / raw)
To: wim, linux-watchdog, linux-kernel
From: Alan Cox <alan@linux.intel.com>
We keep the old /dev/watchdog interface file for the first watchdog via
miscdev. This is basically a cut and paste of the relevant interface code
from the rtc driver layer tweaked for watchdog.
Signed-off-by: Alan Cox <alan@linux.intel.com>
---
drivers/watchdog/watchdog_dev.c | 231 ++++++++++++++++++++++++++++++++-------
include/linux/watchdog.h | 6 +
2 files changed, 193 insertions(+), 44 deletions(-)
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
index 1199da0..253e082 100644
--- a/drivers/watchdog/watchdog_dev.c
+++ b/drivers/watchdog/watchdog_dev.c
@@ -42,10 +42,12 @@
#include <linux/init.h> /* For __init/__exit/... */
#include <linux/uaccess.h> /* For copy_to_user/put_user/... */
-/* make sure we only register one /dev/watchdog device */
-static unsigned long watchdog_dev_busy;
+static dev_t dog_devt; /* Watchdog device range */
+static unsigned long dog_mask; /* Watcodgs that are in use */
/* the watchdog device behind /dev/watchdog */
-static struct watchdog_device *wdd;
+static struct watchdog_device *old_wdd;
+
+#define DOG_MAX 32 /* assign_id must be changed to boost this */
/*
* watchdog_ping: ping the watchdog.
@@ -136,6 +138,7 @@ static int watchdog_stop(struct watchdog_device *wddev)
static ssize_t watchdog_write(struct file *file, const char __user *data,
size_t len, loff_t *ppos)
{
+ struct watchdog_device *wdd = file->private_data;
size_t i;
char c;
@@ -175,6 +178,7 @@ static ssize_t watchdog_write(struct file *file, const char __user *data,
static long watchdog_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
+ struct watchdog_device *wdd = file->private_data;
void __user *argp = (void __user *)arg;
int __user *p = argp;
unsigned int val;
@@ -252,7 +256,8 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd,
* it can only be opened once.
*/
-static int watchdog_open(struct inode *inode, struct file *file)
+static int watchdog_do_open(struct watchdog_device *wdd,
+ struct inode *inode, struct file *file)
{
int err = -EBUSY;
@@ -271,6 +276,8 @@ static int watchdog_open(struct inode *inode, struct file *file)
if (err < 0)
goto out_mod;
+ file->private_data = wdd;
+
/* dev/watchdog is a virtual (and thus non-seekable) filesystem */
return nonseekable_open(inode, file);
@@ -282,7 +289,44 @@ out:
}
/*
- * watchdog_release: release the /dev/watchdog device.
+ * watchdog_open: open the /dev/watchdog device.
+ * @inode: inode of device
+ * @file: file handle to device
+ *
+ * When the /dev/watchdog device gets opened, we start the watchdog.
+ * Watch out: the /dev/watchdog device is single open, so we make sure
+ * it can only be opened once.
+ *
+ * FIXME: review locking on old_wdd v unregister
+ */
+
+static int watchdog_open(struct inode *inode, struct file *file)
+{
+ if (old_wdd != NULL)
+ return watchdog_do_open(old_wdd, inode, file);
+ return -ENXIO;
+}
+
+/*
+ * watchdog_mopen: open the newer watchdog devices.
+ * @inode: inode of device
+ * @file: file handle to device
+ *
+ * When the watchdog device gets opened, we start the watchdog.
+ * Watch out: the /dev/watchdog device is single open, so we make sure
+ * it can only be opened once.
+ */
+
+static int watchdog_mopen(struct inode *inode, struct file *file)
+{
+ struct watchdog_device *wdd = container_of(inode->i_cdev,
+ struct watchdog_device, cdev);
+
+ return watchdog_do_open(wdd, inode, file);
+}
+
+/*
+ * watchdog_release: release the watchdog device.
* @inode: inode of device
* @file: file handle to device
*
@@ -293,6 +337,7 @@ out:
static int watchdog_release(struct inode *inode, struct file *file)
{
+ struct watchdog_device *wdd = file->private_data;
int err = -EBUSY;
/*
@@ -327,69 +372,167 @@ static const struct file_operations watchdog_fops = {
.release = watchdog_release,
};
+static const struct file_operations watchdog_multi_fops = {
+ .owner = THIS_MODULE,
+ .write = watchdog_write,
+ .unlocked_ioctl = watchdog_ioctl,
+ .open = watchdog_mopen,
+ .release = watchdog_release,
+};
+
static struct miscdevice watchdog_miscdev = {
.minor = WATCHDOG_MINOR,
.name = "watchdog",
.fops = &watchdog_fops,
};
-/*
- * watchdog_dev_register:
- * @watchdog: watchdog device
+/**
+ * watchdog_assign_id - pick a free watchdog ident
+ * @watchdog: the watchdog device
+ * @first: number to scan from
*
- * Register a watchdog device as /dev/watchdog. /dev/watchdog
- * is actually a miscdevice and thus we set it up like that.
+ * Assign a watchdog number to the device. For the moment we support
+ * a starting offset so that a legacy watchdog can be worked around
*/
+static int watchdog_assign_id(struct watchdog_device *watchdog, int first)
+{
+ int i;
+ for (i = first; i < DOG_MAX; i ++) {
+ if (test_and_set_bit(i, &dog_mask) == 0) {
+ watchdog->id = i;
+ return i;
+ }
+ }
+ pr_err("no free watchdog slots.\n");
+ return -EBUSY;
+}
-int watchdog_dev_register(struct watchdog_device *watchdog)
+/**
+ * watchdog_release_id - release a watchdg id
+ * @watchdog: the watchdog device
+ *
+ * Release the identifier associated with this watchdog. All cdev
+ * resources must have been released first.
+ */
+static void watchdog_release_id(struct watchdog_device *watchdog)
+{
+ clear_bit(watchdog->id, &dog_mask);
+}
+
+/**
+ * watchdog_add_device - add a watchdog device
+ * @watchdog: the watchdog device
+ *
+ * Add a watchdog device node to the system and set up all the
+ * needed structures.
+ */
+static int watchdog_add_device(struct watchdog_device *watchdog)
{
int err;
- /* Only one device can register for /dev/watchdog */
- if (test_and_set_bit(0, &watchdog_dev_busy)) {
- pr_err("only one watchdog can use /dev/watchdog.\n");
- return -EBUSY;
- }
+ /* Fill in the data structures */
+ watchdog->devt = MKDEV(MAJOR(dog_devt), watchdog->id);
+ watchdog->cdev.owner = watchdog->ops->owner;
+ cdev_init(&watchdog->cdev, &watchdog_multi_fops);
- wdd = watchdog;
+ /* Add the device */
+ err = cdev_add(&watchdog->cdev, watchdog->devt, 1);
+ if (err)
+ pr_err("watchdog%d unable to add device %d:%d\n",
+ watchdog->id, MAJOR(dog_devt), watchdog->id);
+ return err;
+}
- err = misc_register(&watchdog_miscdev);
- if (err != 0) {
- pr_err("%s: cannot register miscdev on minor=%d (err=%d).\n",
- watchdog->info->identity, WATCHDOG_MINOR, err);
- goto out;
- }
+/**
+ * watchdog_del_device - delete a watchdog device
+ * @watchdog: the watchdog device
+ *
+ * Delete a watchdog device cdev object
+ */
+static void watchdog_del_device(struct watchdog_device *watchdog)
+{
+ cdev_del(&watchdog->cdev);
+}
- return 0;
+/**
+ * watchdog_dev_register - register a watchdog
+ * @watchdog: watchdog device
+ *
+ * Register a watchdog device including handling the legacy
+ * /dev/watchdog node. /dev/watchdog is actually a miscdevice and
+ * thus we set it up like that.
+ */
+int watchdog_dev_register(struct watchdog_device *watchdog)
+{
+ int err;
-out:
- wdd = NULL;
- clear_bit(0, &watchdog_dev_busy);
+ err = watchdog_assign_id(watchdog, 0);
+ if (err < 0)
+ return err;
+ if (err == 0) {
+ err = misc_register(&watchdog_miscdev);
+ if (err == 0)
+ old_wdd = watchdog;
+ else {
+ pr_err("%s: cannot register miscdev on minor=%d (err=%d).\n",
+ watchdog->info->identity, WATCHDOG_MINOR, err);
+ pr_err("%s: probably a legacy watchdog module is present.\n",
+ watchdog->info->identity);
+ watchdog_release_id(watchdog);
+ err = watchdog_assign_id(watchdog, 1);
+ if (err < 0)
+ return err;
+ }
+ }
+ err = watchdog_add_device(watchdog);
+ if (err < 0) {
+ if (watchdog->id == 0)
+ old_wdd = NULL;
+ watchdog_release_id(watchdog);
+ }
return err;
}
-/*
- * watchdog_dev_unregister:
+/**
+ * watchdog_dev_unregister - unregister a watchdog
* @watchdog: watchdog device
*
- * Deregister the /dev/watchdog device.
+ * Unregister the watchdog and if needed the legacy /dev/watchdog device.
*/
-
int watchdog_dev_unregister(struct watchdog_device *watchdog)
{
- /* Check that a watchdog device was registered in the past */
- if (!test_bit(0, &watchdog_dev_busy) || !wdd)
- return -ENODEV;
-
- /* We can only unregister the watchdog device that was registered */
- if (watchdog != wdd) {
- pr_err("%s: watchdog was not registered as /dev/watchdog.\n",
- watchdog->info->identity);
- return -ENODEV;
+ watchdog_del_device(watchdog);
+ if (watchdog->id == 0) {
+ misc_deregister(&watchdog_miscdev);
+ old_wdd = NULL;
}
-
- misc_deregister(&watchdog_miscdev);
- wdd = NULL;
- clear_bit(0, &watchdog_dev_busy);
+ watchdog_release_id(watchdog);
return 0;
}
+
+/**
+ * watchdog_init - module init call
+ *
+ * Allocate a range of chardev nodes to use for watchdog devices
+ */
+int __init watchdog_init(void)
+{
+ int err = alloc_chrdev_region(&dog_devt, 0, DOG_MAX, "watchdog");
+ if (err < 0)
+ pr_err("watchdog: unable to allocate char dev region\n");
+ return err;
+}
+
+/**
+ * watchdog_exit - module exit
+ *
+ * Release the range of chardev nodes used for watchdog devices
+ */
+void __exit watchdog_exit(void)
+{
+ unregister_chrdev_region(dog_devt, DOG_MAX);
+}
+
+module_init(watchdog_init);
+module_exit(watchdog_exit);
+
diff --git a/include/linux/watchdog.h b/include/linux/watchdog.h
index 43ba5b3..4167fd3 100644
--- a/include/linux/watchdog.h
+++ b/include/linux/watchdog.h
@@ -54,6 +54,8 @@ struct watchdog_info {
#ifdef __KERNEL__
#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
struct watchdog_ops;
struct watchdog_device;
@@ -103,6 +105,10 @@ struct watchdog_ops {
* via the watchdog_set_drvdata and watchdog_get_drvdata helpers.
*/
struct watchdog_device {
+ struct cdev cdev; /* Character device */
+ dev_t devt; /* Our device */
+ int id; /* Watchdog id */
+
const struct watchdog_info *info;
const struct watchdog_ops *ops;
unsigned int bootstatus;
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH 2/5] watchdog: Add a flag to indicate the watchdog doesn't reboot things
2012-02-28 22:47 [PATCH 1/5] watchdog: Add multiple device support Alan Cox
@ 2012-02-28 22:47 ` Alan Cox
2012-02-28 22:48 ` [PATCH 3/5] softdog: convert to watchdog core Alan Cox
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Alan Cox @ 2012-02-28 22:47 UTC (permalink / raw)
To: wim, linux-watchdog, linux-kernel
From: Alan Cox <alan@linux.intel.com>
Some watchdogs merely trigger external alarms and controls. In a managed
environment this is very useful but we want drivers to be able to figure
out which is which now multiple dogs can be loaded. Thus add an ALARMONLY
feature flag.
Signed-off-by: Alan Cox <alan@linux.intel.com>
---
include/linux/watchdog.h | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/include/linux/watchdog.h b/include/linux/watchdog.h
index 4167fd3..c80e1ae 100644
--- a/include/linux/watchdog.h
+++ b/include/linux/watchdog.h
@@ -45,6 +45,8 @@ struct watchdog_info {
#define WDIOF_SETTIMEOUT 0x0080 /* Set timeout (in seconds) */
#define WDIOF_MAGICCLOSE 0x0100 /* Supports magic close char */
#define WDIOF_PRETIMEOUT 0x0200 /* Pretimeout (in seconds), get/set */
+#define WDIOF_ALARMONLY 0x0400 /* Watchdog triggers a management or
+ other external alarm not a reboot */
#define WDIOF_KEEPALIVEPING 0x8000 /* Keep alive ping reply */
#define WDIOS_DISABLECARD 0x0001 /* Turn off the watchdog timer */
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH 3/5] softdog: convert to watchdog core
2012-02-28 22:47 [PATCH 1/5] watchdog: Add multiple device support Alan Cox
2012-02-28 22:47 ` [PATCH 2/5] watchdog: Add a flag to indicate the watchdog doesn't reboot things Alan Cox
@ 2012-02-28 22:48 ` Alan Cox
2012-02-28 22:48 ` [PATCH 4/5] watchdog: create all the proper device files Alan Cox
2012-02-28 22:48 ` [PATCH 5/5] watchdog: use dev_ functions Alan Cox
3 siblings, 0 replies; 5+ messages in thread
From: Alan Cox @ 2012-02-28 22:48 UTC (permalink / raw)
To: wim, linux-watchdog, linux-kernel
From: Alan Cox <alan@linux.intel.com>
This happens to be rather useful for testing multi-device, plus it's handy
to support a software watchdog as backup to the real one
Signed-off-by: Alan Cox <alan@linux.intel.com>
---
drivers/watchdog/softdog.c | 166 +++++++-------------------------------------
1 files changed, 28 insertions(+), 138 deletions(-)
diff --git a/drivers/watchdog/softdog.c b/drivers/watchdog/softdog.c
index bf16ffb..e2f8ba4 100644
--- a/drivers/watchdog/softdog.c
+++ b/drivers/watchdog/softdog.c
@@ -1,5 +1,5 @@
/*
- * SoftDog 0.07: A Software Watchdog Device
+ * SoftDog: A Software Watchdog Device
*
* (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>,
* All Rights Reserved.
@@ -65,11 +65,7 @@ MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
__MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
-#ifdef ONLY_TESTING
-static int soft_noboot = 1;
-#else
static int soft_noboot = 0;
-#endif /* ONLY_TESTING */
module_param(soft_noboot, int, 0);
MODULE_PARM_DESC(soft_noboot,
@@ -89,9 +85,6 @@ static void watchdog_fire(unsigned long);
static struct timer_list watchdog_ticktock =
TIMER_INITIALIZER(watchdog_fire, 0, 0);
-static unsigned long driver_open, orphan_timer;
-static char expect_close;
-
/*
* If the timer expires..
@@ -99,9 +92,6 @@ static char expect_close;
static void watchdog_fire(unsigned long data)
{
- if (test_and_clear_bit(0, &orphan_timer))
- module_put(THIS_MODULE);
-
if (soft_noboot)
printk(KERN_CRIT PFX "Triggered - Reboot ignored.\n");
else if (soft_panic) {
@@ -118,128 +108,25 @@ static void watchdog_fire(unsigned long data)
* Softdog operations
*/
-static int softdog_keepalive(void)
+static int softdog_ping(struct watchdog_device *w)
{
mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ));
return 0;
}
-static int softdog_stop(void)
+static int softdog_stop(struct watchdog_device *w)
{
del_timer(&watchdog_ticktock);
return 0;
}
-static int softdog_set_heartbeat(int t)
+static int softdog_set_timeout(struct watchdog_device *w, unsigned int t)
{
- if ((t < 0x0001) || (t > 0xFFFF))
- return -EINVAL;
-
soft_margin = t;
return 0;
}
/*
- * /dev/watchdog handling
- */
-
-static int softdog_open(struct inode *inode, struct file *file)
-{
- if (test_and_set_bit(0, &driver_open))
- return -EBUSY;
- if (!test_and_clear_bit(0, &orphan_timer))
- __module_get(THIS_MODULE);
- /*
- * Activate timer
- */
- softdog_keepalive();
- return nonseekable_open(inode, file);
-}
-
-static int softdog_release(struct inode *inode, struct file *file)
-{
- /*
- * Shut off the timer.
- * Lock it in if it's a module and we set nowayout
- */
- if (expect_close == 42) {
- softdog_stop();
- module_put(THIS_MODULE);
- } else {
- printk(KERN_CRIT PFX
- "Unexpected close, not stopping watchdog!\n");
- set_bit(0, &orphan_timer);
- softdog_keepalive();
- }
- clear_bit(0, &driver_open);
- expect_close = 0;
- return 0;
-}
-
-static ssize_t softdog_write(struct file *file, const char __user *data,
- size_t len, loff_t *ppos)
-{
- /*
- * Refresh the timer.
- */
- if (len) {
- if (!nowayout) {
- size_t i;
-
- /* In case it was set long ago */
- expect_close = 0;
-
- for (i = 0; i != len; i++) {
- char c;
-
- if (get_user(c, data + i))
- return -EFAULT;
- if (c == 'V')
- expect_close = 42;
- }
- }
- softdog_keepalive();
- }
- return len;
-}
-
-static long softdog_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
- int new_margin;
- static const struct watchdog_info ident = {
- .options = WDIOF_SETTIMEOUT |
- WDIOF_KEEPALIVEPING |
- WDIOF_MAGICCLOSE,
- .firmware_version = 0,
- .identity = "Software Watchdog",
- };
- switch (cmd) {
- case WDIOC_GETSUPPORT:
- return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
- case WDIOC_GETSTATUS:
- case WDIOC_GETBOOTSTATUS:
- return put_user(0, p);
- case WDIOC_KEEPALIVE:
- softdog_keepalive();
- return 0;
- case WDIOC_SETTIMEOUT:
- if (get_user(new_margin, p))
- return -EFAULT;
- if (softdog_set_heartbeat(new_margin))
- return -EINVAL;
- softdog_keepalive();
- /* Fall */
- case WDIOC_GETTIMEOUT:
- return put_user(soft_margin, p);
- default:
- return -ENOTTY;
- }
-}
-
-/*
* Notifier for system down
*/
@@ -248,7 +135,7 @@ static int softdog_notify_sys(struct notifier_block *this, unsigned long code,
{
if (code == SYS_DOWN || code == SYS_HALT)
/* Turn the WDT off */
- softdog_stop();
+ softdog_stop(NULL);
return NOTIFY_DONE;
}
@@ -256,23 +143,28 @@ static int softdog_notify_sys(struct notifier_block *this, unsigned long code,
* Kernel Interfaces
*/
-static const struct file_operations softdog_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .write = softdog_write,
- .unlocked_ioctl = softdog_ioctl,
- .open = softdog_open,
- .release = softdog_release,
+static struct notifier_block softdog_notifier = {
+ .notifier_call = softdog_notify_sys,
};
-static struct miscdevice softdog_miscdev = {
- .minor = WATCHDOG_MINOR,
- .name = "watchdog",
- .fops = &softdog_fops,
+static struct watchdog_info softdog_info = {
+ .identity = "Software Watchdog",
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
};
-static struct notifier_block softdog_notifier = {
- .notifier_call = softdog_notify_sys,
+static struct watchdog_ops softdog_ops = {
+ .owner = THIS_MODULE,
+ .start = softdog_ping,
+ .stop = softdog_stop,
+ .ping = softdog_ping,
+ .set_timeout = softdog_set_timeout,
+};
+
+static struct watchdog_device softdog_dev = {
+ .info = &softdog_info,
+ .ops = &softdog_ops,
+ .min_timeout = 1,
+ .max_timeout = 0xFFFF
};
static char banner[] __initdata = KERN_INFO "Software Watchdog Timer: 0.07 "
@@ -285,12 +177,13 @@ static int __init watchdog_init(void)
/* Check that the soft_margin value is within it's range;
if not reset to the default */
- if (softdog_set_heartbeat(soft_margin)) {
- softdog_set_heartbeat(TIMER_MARGIN);
+ if (soft_margin < 1 || soft_margin > 65535) {
printk(KERN_INFO PFX
"soft_margin must be 0 < soft_margin < 65536, using %d\n",
TIMER_MARGIN);
+ return -EINVAL;
}
+ softdog_dev.timeout = soft_margin;
ret = register_reboot_notifier(&softdog_notifier);
if (ret) {
@@ -299,11 +192,8 @@ static int __init watchdog_init(void)
return ret;
}
- ret = misc_register(&softdog_miscdev);
+ ret = watchdog_register_device(&softdog_dev);
if (ret) {
- printk(KERN_ERR PFX
- "cannot register miscdev on minor=%d (err=%d)\n",
- WATCHDOG_MINOR, ret);
unregister_reboot_notifier(&softdog_notifier);
return ret;
}
@@ -315,7 +205,7 @@ static int __init watchdog_init(void)
static void __exit watchdog_exit(void)
{
- misc_deregister(&softdog_miscdev);
+ watchdog_unregister_device(&softdog_dev);
unregister_reboot_notifier(&softdog_notifier);
}
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH 4/5] watchdog: create all the proper device files
2012-02-28 22:47 [PATCH 1/5] watchdog: Add multiple device support Alan Cox
2012-02-28 22:47 ` [PATCH 2/5] watchdog: Add a flag to indicate the watchdog doesn't reboot things Alan Cox
2012-02-28 22:48 ` [PATCH 3/5] softdog: convert to watchdog core Alan Cox
@ 2012-02-28 22:48 ` Alan Cox
2012-02-28 22:48 ` [PATCH 5/5] watchdog: use dev_ functions Alan Cox
3 siblings, 0 replies; 5+ messages in thread
From: Alan Cox @ 2012-02-28 22:48 UTC (permalink / raw)
To: wim, linux-watchdog, linux-kernel
From: Alan Cox <alan@linux.intel.com>
Signed-off-by: Alan Cox <alan@linux.intel.com>
---
drivers/watchdog/watchdog_dev.c | 29 ++++++++++++++++++++++++-----
include/linux/watchdog.h | 5 ++++-
2 files changed, 28 insertions(+), 6 deletions(-)
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
index 253e082..7edab6d 100644
--- a/drivers/watchdog/watchdog_dev.c
+++ b/drivers/watchdog/watchdog_dev.c
@@ -42,6 +42,8 @@
#include <linux/init.h> /* For __init/__exit/... */
#include <linux/uaccess.h> /* For copy_to_user/put_user/... */
+static struct class *watchdog_class; /* So we have someone to create
+ our devices */
static dev_t dog_devt; /* Watchdog device range */
static unsigned long dog_mask; /* Watcodgs that are in use */
/* the watchdog device behind /dev/watchdog */
@@ -434,13 +436,21 @@ static int watchdog_add_device(struct watchdog_device *watchdog)
watchdog->devt = MKDEV(MAJOR(dog_devt), watchdog->id);
watchdog->cdev.owner = watchdog->ops->owner;
cdev_init(&watchdog->cdev, &watchdog_multi_fops);
-
/* Add the device */
err = cdev_add(&watchdog->cdev, watchdog->devt, 1);
- if (err)
+ if (err) {
pr_err("watchdog%d unable to add device %d:%d\n",
watchdog->id, MAJOR(dog_devt), watchdog->id);
- return err;
+ return err;
+ }
+ watchdog->dev = device_create(watchdog_class, watchdog->busdev,
+ MKDEV(MAJOR(dog_devt), watchdog->id),
+ NULL, "watchdog%d", watchdog->id);
+ if (IS_ERR(watchdog->dev)) {
+ cdev_del(&watchdog->cdev);
+ return PTR_ERR(watchdog->dev);
+ }
+ return 0;
}
/**
@@ -452,6 +462,7 @@ static int watchdog_add_device(struct watchdog_device *watchdog)
static void watchdog_del_device(struct watchdog_device *watchdog)
{
cdev_del(&watchdog->cdev);
+ device_destroy(watchdog_class, MKDEV(MAJOR(dog_devt), watchdog->id));
}
/**
@@ -518,9 +529,16 @@ int watchdog_dev_unregister(struct watchdog_device *watchdog)
int __init watchdog_init(void)
{
int err = alloc_chrdev_region(&dog_devt, 0, DOG_MAX, "watchdog");
- if (err < 0)
+ if (err < 0) {
pr_err("watchdog: unable to allocate char dev region\n");
- return err;
+ return err;
+ }
+ watchdog_class = class_create(THIS_MODULE, "watchdog");
+ if (IS_ERR(watchdog_class)) {
+ unregister_chrdev_region(dog_devt, DOG_MAX);
+ return PTR_ERR(watchdog_class);
+ }
+ return 0;
}
/**
@@ -531,6 +549,7 @@ int __init watchdog_init(void)
void __exit watchdog_exit(void)
{
unregister_chrdev_region(dog_devt, DOG_MAX);
+ class_destroy(watchdog_class);
}
module_init(watchdog_init);
diff --git a/include/linux/watchdog.h b/include/linux/watchdog.h
index c80e1ae..598c407 100644
--- a/include/linux/watchdog.h
+++ b/include/linux/watchdog.h
@@ -108,7 +108,10 @@ struct watchdog_ops {
*/
struct watchdog_device {
struct cdev cdev; /* Character device */
- dev_t devt; /* Our device */
+ struct device *dev; /* Device for our node */
+ struct device *busdev; /* Parent bus device (set by caller
+ if used) */
+ dev_t devt; /* Our device devt */
int id; /* Watchdog id */
const struct watchdog_info *info;
^ permalink raw reply related [flat|nested] 5+ messages in thread* [PATCH 5/5] watchdog: use dev_ functions
2012-02-28 22:47 [PATCH 1/5] watchdog: Add multiple device support Alan Cox
` (2 preceding siblings ...)
2012-02-28 22:48 ` [PATCH 4/5] watchdog: create all the proper device files Alan Cox
@ 2012-02-28 22:48 ` Alan Cox
3 siblings, 0 replies; 5+ messages in thread
From: Alan Cox @ 2012-02-28 22:48 UTC (permalink / raw)
To: wim, linux-watchdog, linux-kernel
From: Alan Cox <alan@linux.intel.com>
While they are registered all our watchdogs now have a valid device object
so we can in turn use that to report problems nicely.
Signed-off-by: Alan Cox <alan@linux.intel.com>
---
drivers/watchdog/watchdog_dev.c | 5 ++---
1 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
index 7edab6d..b38361e 100644
--- a/drivers/watchdog/watchdog_dev.c
+++ b/drivers/watchdog/watchdog_dev.c
@@ -110,8 +110,7 @@ static int watchdog_stop(struct watchdog_device *wddev)
int err = -EBUSY;
if (test_bit(WDOG_NO_WAY_OUT, &wddev->status)) {
- pr_info("%s: nowayout prevents watchdog to be stopped!\n",
- wddev->info->identity);
+ dev_info(wddev->dev, "nowayout prevents watchdog being stopped!\n");
return err;
}
@@ -353,7 +352,7 @@ static int watchdog_release(struct inode *inode, struct file *file)
/* If the watchdog was not stopped, send a keepalive ping */
if (err < 0) {
- pr_crit("%s: watchdog did not stop!\n", wdd->info->identity);
+ dev_crit(wdd->dev, "watchdog did not stop!\n");
watchdog_ping(wdd);
}
^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2012-02-28 22:34 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-02-28 22:47 [PATCH 1/5] watchdog: Add multiple device support Alan Cox
2012-02-28 22:47 ` [PATCH 2/5] watchdog: Add a flag to indicate the watchdog doesn't reboot things Alan Cox
2012-02-28 22:48 ` [PATCH 3/5] softdog: convert to watchdog core Alan Cox
2012-02-28 22:48 ` [PATCH 4/5] watchdog: create all the proper device files Alan Cox
2012-02-28 22:48 ` [PATCH 5/5] watchdog: use dev_ functions Alan Cox
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox