forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
watchdog: WatchDog Timer Driver Core - Add basic framework
The WatchDog Timer Driver Core is a framework that contains the common code for all watchdog-driver's. It also introduces a watchdog device structure and the operations that go with it. This is the introduction of this framework. This part supports the minimal watchdog userspace API (or with other words: the functionality to use /dev/watchdog's open, release and write functionality as defined in the simplest watchdog API). Extra functionality will follow in the next set of patches. Signed-off-by: Alan Cox <[email protected]> Signed-off-by: Wim Van Sebroeck <[email protected]> Acked-by: Arnd Bergmann <[email protected]> Acked-by: Wolfram Sang <[email protected]>
- Loading branch information
Wim Van Sebroeck
committed
Jul 28, 2011
1 parent
5efc7a6
commit 4331604
Showing
8 changed files
with
566 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
The Linux WatchDog Timer Driver Core kernel API. | ||
=============================================== | ||
Last reviewed: 22-Jul-2011 | ||
|
||
Wim Van Sebroeck <[email protected]> | ||
|
||
Introduction | ||
------------ | ||
This document does not describe what a WatchDog Timer (WDT) Driver or Device is. | ||
It also does not describe the API which can be used by user space to communicate | ||
with a WatchDog Timer. If you want to know this then please read the following | ||
file: Documentation/watchdog/watchdog-api.txt . | ||
|
||
So what does this document describe? It describes the API that can be used by | ||
WatchDog Timer Drivers that want to use the WatchDog Timer Driver Core | ||
Framework. This framework provides all interfacing towards user space so that | ||
the same code does not have to be reproduced each time. This also means that | ||
a watchdog timer driver then only needs to provide the different routines | ||
(operations) that control the watchdog timer (WDT). | ||
|
||
The API | ||
------- | ||
Each watchdog timer driver that wants to use the WatchDog Timer Driver Core | ||
must #include <linux/watchdog.h> (you would have to do this anyway when | ||
writing a watchdog device driver). This include file contains following | ||
register/unregister routines: | ||
|
||
extern int watchdog_register_device(struct watchdog_device *); | ||
extern void watchdog_unregister_device(struct watchdog_device *); | ||
|
||
The watchdog_register_device routine registers a watchdog timer device. | ||
The parameter of this routine is a pointer to a watchdog_device structure. | ||
This routine returns zero on success and a negative errno code for failure. | ||
|
||
The watchdog_unregister_device routine deregisters a registered watchdog timer | ||
device. The parameter of this routine is the pointer to the registered | ||
watchdog_device structure. | ||
|
||
The watchdog device structure looks like this: | ||
|
||
struct watchdog_device { | ||
const struct watchdog_info *info; | ||
const struct watchdog_ops *ops; | ||
void *driver_data; | ||
unsigned long status; | ||
}; | ||
|
||
It contains following fields: | ||
* info: a pointer to a watchdog_info structure. This structure gives some | ||
additional information about the watchdog timer itself. (Like it's unique name) | ||
* ops: a pointer to the list of watchdog operations that the watchdog supports. | ||
* driver_data: a pointer to the drivers private data of a watchdog device. | ||
This data should only be accessed via the watchdog_set_drvadata and | ||
watchdog_get_drvdata routines. | ||
* status: this field contains a number of status bits that give extra | ||
information about the status of the device (Like: is the device opened via | ||
the /dev/watchdog interface or not, ...). | ||
|
||
The list of watchdog operations is defined as: | ||
|
||
struct watchdog_ops { | ||
struct module *owner; | ||
/* mandatory operations */ | ||
int (*start)(struct watchdog_device *); | ||
int (*stop)(struct watchdog_device *); | ||
/* optional operations */ | ||
int (*ping)(struct watchdog_device *); | ||
}; | ||
|
||
It is important that you first define the module owner of the watchdog timer | ||
driver's operations. This module owner will be used to lock the module when | ||
the watchdog is active. (This to avoid a system crash when you unload the | ||
module and /dev/watchdog is still open). | ||
Some operations are mandatory and some are optional. The mandatory operations | ||
are: | ||
* start: this is a pointer to the routine that starts the watchdog timer | ||
device. | ||
The routine needs a pointer to the watchdog timer device structure as a | ||
parameter. It returns zero on success or a negative errno code for failure. | ||
* stop: with this routine the watchdog timer device is being stopped. | ||
The routine needs a pointer to the watchdog timer device structure as a | ||
parameter. It returns zero on success or a negative errno code for failure. | ||
Some watchdog timer hardware can only be started and not be stopped. The | ||
driver supporting this hardware needs to make sure that a start and stop | ||
routine is being provided. This can be done by using a timer in the driver | ||
that regularly sends a keepalive ping to the watchdog timer hardware. | ||
|
||
Not all watchdog timer hardware supports the same functionality. That's why | ||
all other routines/operations are optional. They only need to be provided if | ||
they are supported. These optional routines/operations are: | ||
* ping: this is the routine that sends a keepalive ping to the watchdog timer | ||
hardware. | ||
The routine needs a pointer to the watchdog timer device structure as a | ||
parameter. It returns zero on success or a negative errno code for failure. | ||
Most hardware that does not support this as a separate function uses the | ||
start function to restart the watchdog timer hardware. And that's also what | ||
the watchdog timer driver core does: to send a keepalive ping to the watchdog | ||
timer hardware it will either use the ping operation (when available) or the | ||
start operation (when the ping operation is not available). | ||
|
||
The status bits should (preferably) be set with the set_bit and clear_bit alike | ||
bit-operations. The status bits that are defined are: | ||
* WDOG_DEV_OPEN: this status bit shows whether or not the watchdog device | ||
was opened via /dev/watchdog. | ||
(This bit should only be used by the WatchDog Timer Driver Core). | ||
|
||
To get or set driver specific data the following two helper functions should be | ||
used: | ||
|
||
static inline void watchdog_set_drvdata(struct watchdog_device *wdd, void *data) | ||
static inline void *watchdog_get_drvdata(struct watchdog_device *wdd) | ||
|
||
The watchdog_set_drvdata function allows you to add driver specific data. The | ||
arguments of this function are the watchdog device where you want to add the | ||
driver specific data to and a pointer to the data itself. | ||
|
||
The watchdog_get_drvdata function allows you to retrieve driver specific data. | ||
The argument of this function is the watchdog device where you want to retrieve | ||
data from. The function retruns the pointer to the driver specific data. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
/* | ||
* watchdog_core.c | ||
* | ||
* (c) Copyright 2008-2011 Alan Cox <[email protected]>, | ||
* All Rights Reserved. | ||
* | ||
* (c) Copyright 2008-2011 Wim Van Sebroeck <[email protected]>. | ||
* | ||
* This source code is part of the generic code that can be used | ||
* by all the watchdog timer drivers. | ||
* | ||
* Based on source code of the following authors: | ||
* Matt Domsch <[email protected]>, | ||
* Rob Radez <[email protected]>, | ||
* Rusty Lynch <[email protected]> | ||
* Satyam Sharma <[email protected]> | ||
* Randy Dunlap <[email protected]> | ||
* | ||
* 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; either version | ||
* 2 of the License, or (at your option) any later version. | ||
* | ||
* Neither Alan Cox, CymruNet Ltd., Wim Van Sebroeck nor Iguana vzw. | ||
* admit liability nor provide warranty for any of this software. | ||
* This material is provided "AS-IS" and at no charge. | ||
*/ | ||
|
||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
|
||
#include <linux/module.h> /* For EXPORT_SYMBOL/module stuff/... */ | ||
#include <linux/types.h> /* For standard types */ | ||
#include <linux/errno.h> /* For the -ENODEV/... values */ | ||
#include <linux/kernel.h> /* For printk/panic/... */ | ||
#include <linux/watchdog.h> /* For watchdog specific items */ | ||
#include <linux/init.h> /* For __init/__exit/... */ | ||
|
||
#include "watchdog_dev.h" /* For watchdog_dev_register/... */ | ||
|
||
/** | ||
* watchdog_register_device() - register a watchdog device | ||
* @wdd: watchdog device | ||
* | ||
* Register a watchdog device with the kernel so that the | ||
* watchdog timer can be accessed from userspace. | ||
* | ||
* A zero is returned on success and a negative errno code for | ||
* failure. | ||
*/ | ||
int watchdog_register_device(struct watchdog_device *wdd) | ||
{ | ||
int ret; | ||
|
||
if (wdd == NULL || wdd->info == NULL || wdd->ops == NULL) | ||
return -EINVAL; | ||
|
||
/* Mandatory operations need to be supported */ | ||
if (wdd->ops->start == NULL || wdd->ops->stop == NULL) | ||
return -EINVAL; | ||
|
||
/* | ||
* Note: now that all watchdog_device data has been verified, we | ||
* will not check this anymore in other functions. If data gets | ||
* corrupted in a later stage then we expect a kernel panic! | ||
*/ | ||
|
||
/* We only support 1 watchdog device via the /dev/watchdog interface */ | ||
ret = watchdog_dev_register(wdd); | ||
if (ret) { | ||
pr_err("error registering /dev/watchdog (err=%d).\n", ret); | ||
return ret; | ||
} | ||
|
||
return 0; | ||
} | ||
EXPORT_SYMBOL_GPL(watchdog_register_device); | ||
|
||
/** | ||
* watchdog_unregister_device() - unregister a watchdog device | ||
* @wdd: watchdog device to unregister | ||
* | ||
* Unregister a watchdog device that was previously successfully | ||
* registered with watchdog_register_device(). | ||
*/ | ||
void watchdog_unregister_device(struct watchdog_device *wdd) | ||
{ | ||
int ret; | ||
|
||
if (wdd == NULL) | ||
return; | ||
|
||
ret = watchdog_dev_unregister(wdd); | ||
if (ret) | ||
pr_err("error unregistering /dev/watchdog (err=%d).\n", ret); | ||
} | ||
EXPORT_SYMBOL_GPL(watchdog_unregister_device); | ||
|
||
MODULE_AUTHOR("Alan Cox <[email protected]>"); | ||
MODULE_AUTHOR("Wim Van Sebroeck <[email protected]>"); | ||
MODULE_DESCRIPTION("WatchDog Timer Driver Core"); | ||
MODULE_LICENSE("GPL"); |
Oops, something went wrong.