1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
30
31#include <linux/module.h>
32#include <linux/types.h>
33#include <linux/errno.h>
34#include <linux/kernel.h>
35#include <linux/watchdog.h>
36#include <linux/init.h>
37#include <linux/idr.h>
38#include <linux/err.h>
39
40#include "watchdog_core.h"
41
42static DEFINE_IDA(watchdog_ida);
43static struct class *watchdog_class;
44
45
46
47
48
49
50
51
52
53
54
55int watchdog_register_device(struct watchdog_device *wdd)
56{
57 int ret, id, devno;
58
59 if (wdd == NULL || wdd->info == NULL || wdd->ops == NULL)
60 return -EINVAL;
61
62
63 if (wdd->ops->start == NULL || wdd->ops->stop == NULL)
64 return -EINVAL;
65
66
67
68
69
70 if (wdd->min_timeout > wdd->max_timeout) {
71 pr_info("Invalid min and max timeout values, resetting to 0!\n");
72 wdd->min_timeout = 0;
73 wdd->max_timeout = 0;
74 }
75
76
77
78
79
80
81
82 mutex_init(&wdd->lock);
83 id = ida_simple_get(&watchdog_ida, 0, MAX_DOGS, GFP_KERNEL);
84 if (id < 0)
85 return id;
86 wdd->id = id;
87
88 ret = watchdog_dev_register(wdd);
89 if (ret) {
90 ida_simple_remove(&watchdog_ida, id);
91 if (!(id == 0 && ret == -EBUSY))
92 return ret;
93
94
95 id = ida_simple_get(&watchdog_ida, 1, MAX_DOGS, GFP_KERNEL);
96 if (id < 0)
97 return id;
98 wdd->id = id;
99
100 ret = watchdog_dev_register(wdd);
101 if (ret) {
102 ida_simple_remove(&watchdog_ida, id);
103 return ret;
104 }
105 }
106
107 devno = wdd->cdev.dev;
108 wdd->dev = device_create(watchdog_class, wdd->parent, devno,
109 NULL, "watchdog%d", wdd->id);
110 if (IS_ERR(wdd->dev)) {
111 watchdog_dev_unregister(wdd);
112 ida_simple_remove(&watchdog_ida, id);
113 ret = PTR_ERR(wdd->dev);
114 return ret;
115 }
116
117 return 0;
118}
119EXPORT_SYMBOL_GPL(watchdog_register_device);
120
121
122
123
124
125
126
127
128void watchdog_unregister_device(struct watchdog_device *wdd)
129{
130 int ret;
131 int devno;
132
133 if (wdd == NULL)
134 return;
135
136 devno = wdd->cdev.dev;
137 ret = watchdog_dev_unregister(wdd);
138 if (ret)
139 pr_err("error unregistering /dev/watchdog (err=%d)\n", ret);
140 device_destroy(watchdog_class, devno);
141 ida_simple_remove(&watchdog_ida, wdd->id);
142 wdd->dev = NULL;
143}
144EXPORT_SYMBOL_GPL(watchdog_unregister_device);
145
146static int __init watchdog_init(void)
147{
148 int err;
149
150 watchdog_class = class_create(THIS_MODULE, "watchdog");
151 if (IS_ERR(watchdog_class)) {
152 pr_err("couldn't create class\n");
153 return PTR_ERR(watchdog_class);
154 }
155
156 err = watchdog_dev_init();
157 if (err < 0) {
158 class_destroy(watchdog_class);
159 return err;
160 }
161
162 return 0;
163}
164
165static void __exit watchdog_exit(void)
166{
167 watchdog_dev_exit();
168 class_destroy(watchdog_class);
169 ida_destroy(&watchdog_ida);
170}
171
172subsys_initcall(watchdog_init);
173module_exit(watchdog_exit);
174
175MODULE_AUTHOR("Alan Cox <alan@lxorguk.ukuu.org.uk>");
176MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>");
177MODULE_DESCRIPTION("WatchDog Timer Driver Core");
178MODULE_LICENSE("GPL");
179