Commit 43316044d4f64da008d6aca7d4b60771b9a24eb8
1 parent
5efc7a6222
Exists in
master
and in
38 other branches
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 <alan@lxorguk.ukuu.org.uk> Signed-off-by: Wim Van Sebroeck <wim@iguana.be> Acked-by: Arnd Bergmann <arnd@arndb.de> Acked-by: Wolfram Sang <w.sang@pengutronix.de>
Showing 8 changed files with 566 additions and 0 deletions Side-by-side Diff
Documentation/watchdog/00-INDEX
... | ... | @@ -8,6 +8,8 @@ |
8 | 8 | - directory holding watchdog related example programs. |
9 | 9 | watchdog-api.txt |
10 | 10 | - description of the Linux Watchdog driver API. |
11 | +watchdog-kernel-api.txt | |
12 | + - description of the Linux WatchDog Timer Driver Core kernel API. | |
11 | 13 | watchdog-parameters.txt |
12 | 14 | - information on driver parameters (for drivers other than |
13 | 15 | the ones that have driver-specific files here) |
Documentation/watchdog/watchdog-kernel-api.txt
1 | +The Linux WatchDog Timer Driver Core kernel API. | |
2 | +=============================================== | |
3 | +Last reviewed: 22-Jul-2011 | |
4 | + | |
5 | +Wim Van Sebroeck <wim@iguana.be> | |
6 | + | |
7 | +Introduction | |
8 | +------------ | |
9 | +This document does not describe what a WatchDog Timer (WDT) Driver or Device is. | |
10 | +It also does not describe the API which can be used by user space to communicate | |
11 | +with a WatchDog Timer. If you want to know this then please read the following | |
12 | +file: Documentation/watchdog/watchdog-api.txt . | |
13 | + | |
14 | +So what does this document describe? It describes the API that can be used by | |
15 | +WatchDog Timer Drivers that want to use the WatchDog Timer Driver Core | |
16 | +Framework. This framework provides all interfacing towards user space so that | |
17 | +the same code does not have to be reproduced each time. This also means that | |
18 | +a watchdog timer driver then only needs to provide the different routines | |
19 | +(operations) that control the watchdog timer (WDT). | |
20 | + | |
21 | +The API | |
22 | +------- | |
23 | +Each watchdog timer driver that wants to use the WatchDog Timer Driver Core | |
24 | +must #include <linux/watchdog.h> (you would have to do this anyway when | |
25 | +writing a watchdog device driver). This include file contains following | |
26 | +register/unregister routines: | |
27 | + | |
28 | +extern int watchdog_register_device(struct watchdog_device *); | |
29 | +extern void watchdog_unregister_device(struct watchdog_device *); | |
30 | + | |
31 | +The watchdog_register_device routine registers a watchdog timer device. | |
32 | +The parameter of this routine is a pointer to a watchdog_device structure. | |
33 | +This routine returns zero on success and a negative errno code for failure. | |
34 | + | |
35 | +The watchdog_unregister_device routine deregisters a registered watchdog timer | |
36 | +device. The parameter of this routine is the pointer to the registered | |
37 | +watchdog_device structure. | |
38 | + | |
39 | +The watchdog device structure looks like this: | |
40 | + | |
41 | +struct watchdog_device { | |
42 | + const struct watchdog_info *info; | |
43 | + const struct watchdog_ops *ops; | |
44 | + void *driver_data; | |
45 | + unsigned long status; | |
46 | +}; | |
47 | + | |
48 | +It contains following fields: | |
49 | +* info: a pointer to a watchdog_info structure. This structure gives some | |
50 | + additional information about the watchdog timer itself. (Like it's unique name) | |
51 | +* ops: a pointer to the list of watchdog operations that the watchdog supports. | |
52 | +* driver_data: a pointer to the drivers private data of a watchdog device. | |
53 | + This data should only be accessed via the watchdog_set_drvadata and | |
54 | + watchdog_get_drvdata routines. | |
55 | +* status: this field contains a number of status bits that give extra | |
56 | + information about the status of the device (Like: is the device opened via | |
57 | + the /dev/watchdog interface or not, ...). | |
58 | + | |
59 | +The list of watchdog operations is defined as: | |
60 | + | |
61 | +struct watchdog_ops { | |
62 | + struct module *owner; | |
63 | + /* mandatory operations */ | |
64 | + int (*start)(struct watchdog_device *); | |
65 | + int (*stop)(struct watchdog_device *); | |
66 | + /* optional operations */ | |
67 | + int (*ping)(struct watchdog_device *); | |
68 | +}; | |
69 | + | |
70 | +It is important that you first define the module owner of the watchdog timer | |
71 | +driver's operations. This module owner will be used to lock the module when | |
72 | +the watchdog is active. (This to avoid a system crash when you unload the | |
73 | +module and /dev/watchdog is still open). | |
74 | +Some operations are mandatory and some are optional. The mandatory operations | |
75 | +are: | |
76 | +* start: this is a pointer to the routine that starts the watchdog timer | |
77 | + device. | |
78 | + The routine needs a pointer to the watchdog timer device structure as a | |
79 | + parameter. It returns zero on success or a negative errno code for failure. | |
80 | +* stop: with this routine the watchdog timer device is being stopped. | |
81 | + The routine needs a pointer to the watchdog timer device structure as a | |
82 | + parameter. It returns zero on success or a negative errno code for failure. | |
83 | + Some watchdog timer hardware can only be started and not be stopped. The | |
84 | + driver supporting this hardware needs to make sure that a start and stop | |
85 | + routine is being provided. This can be done by using a timer in the driver | |
86 | + that regularly sends a keepalive ping to the watchdog timer hardware. | |
87 | + | |
88 | +Not all watchdog timer hardware supports the same functionality. That's why | |
89 | +all other routines/operations are optional. They only need to be provided if | |
90 | +they are supported. These optional routines/operations are: | |
91 | +* ping: this is the routine that sends a keepalive ping to the watchdog timer | |
92 | + hardware. | |
93 | + The routine needs a pointer to the watchdog timer device structure as a | |
94 | + parameter. It returns zero on success or a negative errno code for failure. | |
95 | + Most hardware that does not support this as a separate function uses the | |
96 | + start function to restart the watchdog timer hardware. And that's also what | |
97 | + the watchdog timer driver core does: to send a keepalive ping to the watchdog | |
98 | + timer hardware it will either use the ping operation (when available) or the | |
99 | + start operation (when the ping operation is not available). | |
100 | + | |
101 | +The status bits should (preferably) be set with the set_bit and clear_bit alike | |
102 | +bit-operations. The status bits that are defined are: | |
103 | +* WDOG_DEV_OPEN: this status bit shows whether or not the watchdog device | |
104 | + was opened via /dev/watchdog. | |
105 | + (This bit should only be used by the WatchDog Timer Driver Core). | |
106 | + | |
107 | +To get or set driver specific data the following two helper functions should be | |
108 | +used: | |
109 | + | |
110 | +static inline void watchdog_set_drvdata(struct watchdog_device *wdd, void *data) | |
111 | +static inline void *watchdog_get_drvdata(struct watchdog_device *wdd) | |
112 | + | |
113 | +The watchdog_set_drvdata function allows you to add driver specific data. The | |
114 | +arguments of this function are the watchdog device where you want to add the | |
115 | +driver specific data to and a pointer to the data itself. | |
116 | + | |
117 | +The watchdog_get_drvdata function allows you to retrieve driver specific data. | |
118 | +The argument of this function is the watchdog device where you want to retrieve | |
119 | +data from. The function retruns the pointer to the driver specific data. |
drivers/watchdog/Kconfig
... | ... | @@ -28,6 +28,17 @@ |
28 | 28 | |
29 | 29 | if WATCHDOG |
30 | 30 | |
31 | +config WATCHDOG_CORE | |
32 | + bool "WatchDog Timer Driver Core" | |
33 | + ---help--- | |
34 | + Say Y here if you want to use the new watchdog timer driver core. | |
35 | + This driver provides a framework for all watchdog timer drivers | |
36 | + and gives them the /dev/watchdog interface (and later also the | |
37 | + sysfs interface). | |
38 | + | |
39 | + To compile this driver as a module, choose M here: the module will | |
40 | + be called watchdog. | |
41 | + | |
31 | 42 | config WATCHDOG_NOWAYOUT |
32 | 43 | bool "Disable watchdog shutdown on close" |
33 | 44 | help |
drivers/watchdog/Makefile
... | ... | @@ -2,6 +2,10 @@ |
2 | 2 | # Makefile for the WatchDog device drivers. |
3 | 3 | # |
4 | 4 | |
5 | +# The WatchDog Timer Driver Core. | |
6 | +watchdog-objs += watchdog_core.o watchdog_dev.o | |
7 | +obj-$(CONFIG_WATCHDOG_CORE) += watchdog.o | |
8 | + | |
5 | 9 | # Only one watchdog can succeed. We probe the ISA/PCI/USB based |
6 | 10 | # watchdog-cards first, then the architecture specific watchdog |
7 | 11 | # drivers and then the architecture independent "softdog" driver. |
drivers/watchdog/watchdog_core.c
1 | +/* | |
2 | + * watchdog_core.c | |
3 | + * | |
4 | + * (c) Copyright 2008-2011 Alan Cox <alan@lxorguk.ukuu.org.uk>, | |
5 | + * All Rights Reserved. | |
6 | + * | |
7 | + * (c) Copyright 2008-2011 Wim Van Sebroeck <wim@iguana.be>. | |
8 | + * | |
9 | + * This source code is part of the generic code that can be used | |
10 | + * by all the watchdog timer drivers. | |
11 | + * | |
12 | + * Based on source code of the following authors: | |
13 | + * Matt Domsch <Matt_Domsch@dell.com>, | |
14 | + * Rob Radez <rob@osinvestor.com>, | |
15 | + * Rusty Lynch <rusty@linux.co.intel.com> | |
16 | + * Satyam Sharma <satyam@infradead.org> | |
17 | + * Randy Dunlap <randy.dunlap@oracle.com> | |
18 | + * | |
19 | + * This program is free software; you can redistribute it and/or | |
20 | + * modify it under the terms of the GNU General Public License | |
21 | + * as published by the Free Software Foundation; either version | |
22 | + * 2 of the License, or (at your option) any later version. | |
23 | + * | |
24 | + * Neither Alan Cox, CymruNet Ltd., Wim Van Sebroeck nor Iguana vzw. | |
25 | + * admit liability nor provide warranty for any of this software. | |
26 | + * This material is provided "AS-IS" and at no charge. | |
27 | + */ | |
28 | + | |
29 | +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
30 | + | |
31 | +#include <linux/module.h> /* For EXPORT_SYMBOL/module stuff/... */ | |
32 | +#include <linux/types.h> /* For standard types */ | |
33 | +#include <linux/errno.h> /* For the -ENODEV/... values */ | |
34 | +#include <linux/kernel.h> /* For printk/panic/... */ | |
35 | +#include <linux/watchdog.h> /* For watchdog specific items */ | |
36 | +#include <linux/init.h> /* For __init/__exit/... */ | |
37 | + | |
38 | +#include "watchdog_dev.h" /* For watchdog_dev_register/... */ | |
39 | + | |
40 | +/** | |
41 | + * watchdog_register_device() - register a watchdog device | |
42 | + * @wdd: watchdog device | |
43 | + * | |
44 | + * Register a watchdog device with the kernel so that the | |
45 | + * watchdog timer can be accessed from userspace. | |
46 | + * | |
47 | + * A zero is returned on success and a negative errno code for | |
48 | + * failure. | |
49 | + */ | |
50 | +int watchdog_register_device(struct watchdog_device *wdd) | |
51 | +{ | |
52 | + int ret; | |
53 | + | |
54 | + if (wdd == NULL || wdd->info == NULL || wdd->ops == NULL) | |
55 | + return -EINVAL; | |
56 | + | |
57 | + /* Mandatory operations need to be supported */ | |
58 | + if (wdd->ops->start == NULL || wdd->ops->stop == NULL) | |
59 | + return -EINVAL; | |
60 | + | |
61 | + /* | |
62 | + * Note: now that all watchdog_device data has been verified, we | |
63 | + * will not check this anymore in other functions. If data gets | |
64 | + * corrupted in a later stage then we expect a kernel panic! | |
65 | + */ | |
66 | + | |
67 | + /* We only support 1 watchdog device via the /dev/watchdog interface */ | |
68 | + ret = watchdog_dev_register(wdd); | |
69 | + if (ret) { | |
70 | + pr_err("error registering /dev/watchdog (err=%d).\n", ret); | |
71 | + return ret; | |
72 | + } | |
73 | + | |
74 | + return 0; | |
75 | +} | |
76 | +EXPORT_SYMBOL_GPL(watchdog_register_device); | |
77 | + | |
78 | +/** | |
79 | + * watchdog_unregister_device() - unregister a watchdog device | |
80 | + * @wdd: watchdog device to unregister | |
81 | + * | |
82 | + * Unregister a watchdog device that was previously successfully | |
83 | + * registered with watchdog_register_device(). | |
84 | + */ | |
85 | +void watchdog_unregister_device(struct watchdog_device *wdd) | |
86 | +{ | |
87 | + int ret; | |
88 | + | |
89 | + if (wdd == NULL) | |
90 | + return; | |
91 | + | |
92 | + ret = watchdog_dev_unregister(wdd); | |
93 | + if (ret) | |
94 | + pr_err("error unregistering /dev/watchdog (err=%d).\n", ret); | |
95 | +} | |
96 | +EXPORT_SYMBOL_GPL(watchdog_unregister_device); | |
97 | + | |
98 | +MODULE_AUTHOR("Alan Cox <alan@lxorguk.ukuu.org.uk>"); | |
99 | +MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>"); | |
100 | +MODULE_DESCRIPTION("WatchDog Timer Driver Core"); | |
101 | +MODULE_LICENSE("GPL"); |
drivers/watchdog/watchdog_dev.c
1 | +/* | |
2 | + * watchdog_dev.c | |
3 | + * | |
4 | + * (c) Copyright 2008-2011 Alan Cox <alan@lxorguk.ukuu.org.uk>, | |
5 | + * All Rights Reserved. | |
6 | + * | |
7 | + * (c) Copyright 2008-2011 Wim Van Sebroeck <wim@iguana.be>. | |
8 | + * | |
9 | + * | |
10 | + * This source code is part of the generic code that can be used | |
11 | + * by all the watchdog timer drivers. | |
12 | + * | |
13 | + * This part of the generic code takes care of the following | |
14 | + * misc device: /dev/watchdog. | |
15 | + * | |
16 | + * Based on source code of the following authors: | |
17 | + * Matt Domsch <Matt_Domsch@dell.com>, | |
18 | + * Rob Radez <rob@osinvestor.com>, | |
19 | + * Rusty Lynch <rusty@linux.co.intel.com> | |
20 | + * Satyam Sharma <satyam@infradead.org> | |
21 | + * Randy Dunlap <randy.dunlap@oracle.com> | |
22 | + * | |
23 | + * This program is free software; you can redistribute it and/or | |
24 | + * modify it under the terms of the GNU General Public License | |
25 | + * as published by the Free Software Foundation; either version | |
26 | + * 2 of the License, or (at your option) any later version. | |
27 | + * | |
28 | + * Neither Alan Cox, CymruNet Ltd., Wim Van Sebroeck nor Iguana vzw. | |
29 | + * admit liability nor provide warranty for any of this software. | |
30 | + * This material is provided "AS-IS" and at no charge. | |
31 | + */ | |
32 | + | |
33 | +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
34 | + | |
35 | +#include <linux/module.h> /* For module stuff/... */ | |
36 | +#include <linux/types.h> /* For standard types (like size_t) */ | |
37 | +#include <linux/errno.h> /* For the -ENODEV/... values */ | |
38 | +#include <linux/kernel.h> /* For printk/panic/... */ | |
39 | +#include <linux/fs.h> /* For file operations */ | |
40 | +#include <linux/watchdog.h> /* For watchdog specific items */ | |
41 | +#include <linux/miscdevice.h> /* For handling misc devices */ | |
42 | +#include <linux/init.h> /* For __init/__exit/... */ | |
43 | +#include <linux/uaccess.h> /* For copy_to_user/put_user/... */ | |
44 | + | |
45 | +/* make sure we only register one /dev/watchdog device */ | |
46 | +static unsigned long watchdog_dev_busy; | |
47 | +/* the watchdog device behind /dev/watchdog */ | |
48 | +static struct watchdog_device *wdd; | |
49 | + | |
50 | +/* | |
51 | + * watchdog_ping: ping the watchdog. | |
52 | + * @wddev: the watchdog device to ping | |
53 | + * | |
54 | + * If the watchdog has no own ping operation then it needs to be | |
55 | + * restarted via the start operation. This wrapper function does | |
56 | + * exactly that. | |
57 | + */ | |
58 | + | |
59 | +static int watchdog_ping(struct watchdog_device *wddev) | |
60 | +{ | |
61 | + if (wddev->ops->ping) | |
62 | + return wddev->ops->ping(wddev); /* ping the watchdog */ | |
63 | + else | |
64 | + return wddev->ops->start(wddev); /* restart the watchdog */ | |
65 | +} | |
66 | + | |
67 | +/* | |
68 | + * watchdog_write: writes to the watchdog. | |
69 | + * @file: file from VFS | |
70 | + * @data: user address of data | |
71 | + * @len: length of data | |
72 | + * @ppos: pointer to the file offset | |
73 | + * | |
74 | + * A write to a watchdog device is defined as a keepalive ping. | |
75 | + */ | |
76 | + | |
77 | +static ssize_t watchdog_write(struct file *file, const char __user *data, | |
78 | + size_t len, loff_t *ppos) | |
79 | +{ | |
80 | + size_t i; | |
81 | + char c; | |
82 | + | |
83 | + if (len == 0) | |
84 | + return 0; | |
85 | + | |
86 | + for (i = 0; i != len; i++) { | |
87 | + if (get_user(c, data + i)) | |
88 | + return -EFAULT; | |
89 | + } | |
90 | + | |
91 | + /* someone wrote to us, so we send the watchdog a keepalive ping */ | |
92 | + watchdog_ping(wdd); | |
93 | + | |
94 | + return len; | |
95 | +} | |
96 | + | |
97 | +/* | |
98 | + * watchdog_open: open the /dev/watchdog device. | |
99 | + * @inode: inode of device | |
100 | + * @file: file handle to device | |
101 | + * | |
102 | + * When the /dev/watchdog device gets opened, we start the watchdog. | |
103 | + * Watch out: the /dev/watchdog device is single open, so we make sure | |
104 | + * it can only be opened once. | |
105 | + */ | |
106 | + | |
107 | +static int watchdog_open(struct inode *inode, struct file *file) | |
108 | +{ | |
109 | + int err = -EBUSY; | |
110 | + | |
111 | + /* the watchdog is single open! */ | |
112 | + if (test_and_set_bit(WDOG_DEV_OPEN, &wdd->status)) | |
113 | + return -EBUSY; | |
114 | + | |
115 | + /* | |
116 | + * If the /dev/watchdog device is open, we don't want the module | |
117 | + * to be unloaded. | |
118 | + */ | |
119 | + if (!try_module_get(wdd->ops->owner)) | |
120 | + goto out; | |
121 | + | |
122 | + err = wdd->ops->start(wdd); | |
123 | + if (err < 0) | |
124 | + goto out_mod; | |
125 | + | |
126 | + /* dev/watchdog is a virtual (and thus non-seekable) filesystem */ | |
127 | + return nonseekable_open(inode, file); | |
128 | + | |
129 | +out_mod: | |
130 | + module_put(wdd->ops->owner); | |
131 | +out: | |
132 | + clear_bit(WDOG_DEV_OPEN, &wdd->status); | |
133 | + return err; | |
134 | +} | |
135 | + | |
136 | +/* | |
137 | + * watchdog_release: release the /dev/watchdog device. | |
138 | + * @inode: inode of device | |
139 | + * @file: file handle to device | |
140 | + * | |
141 | + * This is the code for when /dev/watchdog gets closed. | |
142 | + */ | |
143 | + | |
144 | +static int watchdog_release(struct inode *inode, struct file *file) | |
145 | +{ | |
146 | + int err; | |
147 | + | |
148 | + err = wdd->ops->stop(wdd); | |
149 | + if (err != 0) { | |
150 | + pr_crit("%s: watchdog did not stop!\n", wdd->info->identity); | |
151 | + watchdog_ping(wdd); | |
152 | + } | |
153 | + | |
154 | + /* Allow the owner module to be unloaded again */ | |
155 | + module_put(wdd->ops->owner); | |
156 | + | |
157 | + /* make sure that /dev/watchdog can be re-opened */ | |
158 | + clear_bit(WDOG_DEV_OPEN, &wdd->status); | |
159 | + | |
160 | + return 0; | |
161 | +} | |
162 | + | |
163 | +static const struct file_operations watchdog_fops = { | |
164 | + .owner = THIS_MODULE, | |
165 | + .write = watchdog_write, | |
166 | + .open = watchdog_open, | |
167 | + .release = watchdog_release, | |
168 | +}; | |
169 | + | |
170 | +static struct miscdevice watchdog_miscdev = { | |
171 | + .minor = WATCHDOG_MINOR, | |
172 | + .name = "watchdog", | |
173 | + .fops = &watchdog_fops, | |
174 | +}; | |
175 | + | |
176 | +/* | |
177 | + * watchdog_dev_register: | |
178 | + * @watchdog: watchdog device | |
179 | + * | |
180 | + * Register a watchdog device as /dev/watchdog. /dev/watchdog | |
181 | + * is actually a miscdevice and thus we set it up like that. | |
182 | + */ | |
183 | + | |
184 | +int watchdog_dev_register(struct watchdog_device *watchdog) | |
185 | +{ | |
186 | + int err; | |
187 | + | |
188 | + /* Only one device can register for /dev/watchdog */ | |
189 | + if (test_and_set_bit(0, &watchdog_dev_busy)) { | |
190 | + pr_err("only one watchdog can use /dev/watchdog.\n"); | |
191 | + return -EBUSY; | |
192 | + } | |
193 | + | |
194 | + wdd = watchdog; | |
195 | + | |
196 | + err = misc_register(&watchdog_miscdev); | |
197 | + if (err != 0) { | |
198 | + pr_err("%s: cannot register miscdev on minor=%d (err=%d).\n", | |
199 | + watchdog->info->identity, WATCHDOG_MINOR, err); | |
200 | + goto out; | |
201 | + } | |
202 | + | |
203 | + return 0; | |
204 | + | |
205 | +out: | |
206 | + wdd = NULL; | |
207 | + clear_bit(0, &watchdog_dev_busy); | |
208 | + return err; | |
209 | +} | |
210 | + | |
211 | +/* | |
212 | + * watchdog_dev_unregister: | |
213 | + * @watchdog: watchdog device | |
214 | + * | |
215 | + * Deregister the /dev/watchdog device. | |
216 | + */ | |
217 | + | |
218 | +int watchdog_dev_unregister(struct watchdog_device *watchdog) | |
219 | +{ | |
220 | + /* Check that a watchdog device was registered in the past */ | |
221 | + if (!test_bit(0, &watchdog_dev_busy) || !wdd) | |
222 | + return -ENODEV; | |
223 | + | |
224 | + /* We can only unregister the watchdog device that was registered */ | |
225 | + if (watchdog != wdd) { | |
226 | + pr_err("%s: watchdog was not registered as /dev/watchdog.\n", | |
227 | + watchdog->info->identity); | |
228 | + return -ENODEV; | |
229 | + } | |
230 | + | |
231 | + misc_deregister(&watchdog_miscdev); | |
232 | + wdd = NULL; | |
233 | + clear_bit(0, &watchdog_dev_busy); | |
234 | + return 0; | |
235 | +} |
drivers/watchdog/watchdog_dev.h
1 | +/* | |
2 | + * watchdog_core.h | |
3 | + * | |
4 | + * (c) Copyright 2008-2011 Alan Cox <alan@lxorguk.ukuu.org.uk>, | |
5 | + * All Rights Reserved. | |
6 | + * | |
7 | + * (c) Copyright 2008-2011 Wim Van Sebroeck <wim@iguana.be>. | |
8 | + * | |
9 | + * This source code is part of the generic code that can be used | |
10 | + * by all the watchdog timer drivers. | |
11 | + * | |
12 | + * Based on source code of the following authors: | |
13 | + * Matt Domsch <Matt_Domsch@dell.com>, | |
14 | + * Rob Radez <rob@osinvestor.com>, | |
15 | + * Rusty Lynch <rusty@linux.co.intel.com> | |
16 | + * Satyam Sharma <satyam@infradead.org> | |
17 | + * Randy Dunlap <randy.dunlap@oracle.com> | |
18 | + * | |
19 | + * This program is free software; you can redistribute it and/or | |
20 | + * modify it under the terms of the GNU General Public License | |
21 | + * as published by the Free Software Foundation; either version | |
22 | + * 2 of the License, or (at your option) any later version. | |
23 | + * | |
24 | + * Neither Alan Cox, CymruNet Ltd., Wim Van Sebroeck nor Iguana vzw. | |
25 | + * admit liability nor provide warranty for any of this software. | |
26 | + * This material is provided "AS-IS" and at no charge. | |
27 | + */ | |
28 | + | |
29 | +/* | |
30 | + * Functions/procedures to be called by the core | |
31 | + */ | |
32 | +int watchdog_dev_register(struct watchdog_device *); | |
33 | +int watchdog_dev_unregister(struct watchdog_device *); |
include/linux/watchdog.h
... | ... | @@ -59,6 +59,67 @@ |
59 | 59 | #define WATCHDOG_NOWAYOUT 0 |
60 | 60 | #endif |
61 | 61 | |
62 | +struct watchdog_ops; | |
63 | +struct watchdog_device; | |
64 | + | |
65 | +/** struct watchdog_ops - The watchdog-devices operations | |
66 | + * | |
67 | + * @owner: The module owner. | |
68 | + * @start: The routine for starting the watchdog device. | |
69 | + * @stop: The routine for stopping the watchdog device. | |
70 | + * @ping: The routine that sends a keepalive ping to the watchdog device. | |
71 | + * | |
72 | + * The watchdog_ops structure contains a list of low-level operations | |
73 | + * that control a watchdog device. It also contains the module that owns | |
74 | + * these operations. The start and stop function are mandatory, all other | |
75 | + * functions are optonal. | |
76 | + */ | |
77 | +struct watchdog_ops { | |
78 | + struct module *owner; | |
79 | + /* mandatory operations */ | |
80 | + int (*start)(struct watchdog_device *); | |
81 | + int (*stop)(struct watchdog_device *); | |
82 | + /* optional operations */ | |
83 | + int (*ping)(struct watchdog_device *); | |
84 | +}; | |
85 | + | |
86 | +/** struct watchdog_device - The structure that defines a watchdog device | |
87 | + * | |
88 | + * @info: Pointer to a watchdog_info structure. | |
89 | + * @ops: Pointer to the list of watchdog operations. | |
90 | + * @driver-data:Pointer to the drivers private data. | |
91 | + * @status: Field that contains the devices internal status bits. | |
92 | + * | |
93 | + * The watchdog_device structure contains all information about a | |
94 | + * watchdog timer device. | |
95 | + * | |
96 | + * The driver-data field may not be accessed directly. It must be accessed | |
97 | + * via the watchdog_set_drvdata and watchdog_get_drvdata helpers. | |
98 | + */ | |
99 | +struct watchdog_device { | |
100 | + const struct watchdog_info *info; | |
101 | + const struct watchdog_ops *ops; | |
102 | + void *driver_data; | |
103 | + unsigned long status; | |
104 | +/* Bit numbers for status flags */ | |
105 | +#define WDOG_DEV_OPEN 1 /* Opened via /dev/watchdog ? */ | |
106 | +}; | |
107 | + | |
108 | +/* Use the following functions to manipulate watchdog driver specific data */ | |
109 | +static inline void watchdog_set_drvdata(struct watchdog_device *wdd, void *data) | |
110 | +{ | |
111 | + wdd->driver_data = data; | |
112 | +} | |
113 | + | |
114 | +static inline void *watchdog_get_drvdata(struct watchdog_device *wdd) | |
115 | +{ | |
116 | + return wdd->driver_data; | |
117 | +} | |
118 | + | |
119 | +/* drivers/watchdog/core/watchdog_core.c */ | |
120 | +extern int watchdog_register_device(struct watchdog_device *); | |
121 | +extern void watchdog_unregister_device(struct watchdog_device *); | |
122 | + | |
62 | 123 | #endif /* __KERNEL__ */ |
63 | 124 | |
64 | 125 | #endif /* ifndef _LINUX_WATCHDOG_H */ |