aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog/watchdog_dev.c
diff options
context:
space:
mode:
authorAlan Cox <alan@linux.intel.com>2012-05-10 15:48:59 -0400
committerWim Van Sebroeck <wim@iguana.be>2012-05-30 01:54:25 -0400
commit45f5fed30a6460ec58f159ff297a2974153a97de (patch)
treed173b2d22ed1187fb7ed2cb85015ddf5c545da05 /drivers/watchdog/watchdog_dev.c
parentfb5f6658163412dce22724e906e324ab7fd62c18 (diff)
watchdog: Add multiple device support
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. Revised to fix problems noted by Hans de Goede Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Diffstat (limited to 'drivers/watchdog/watchdog_dev.c')
-rw-r--r--drivers/watchdog/watchdog_dev.c127
1 files changed, 82 insertions, 45 deletions
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
index beaf9cb5541a..3b22582bcb04 100644
--- a/drivers/watchdog/watchdog_dev.c
+++ b/drivers/watchdog/watchdog_dev.c
@@ -44,10 +44,10 @@
44 44
45#include "watchdog_core.h" 45#include "watchdog_core.h"
46 46
47/* make sure we only register one /dev/watchdog device */ 47/* the dev_t structure to store the dynamically allocated watchdog devices */
48static unsigned long watchdog_dev_busy; 48static dev_t watchdog_devt;
49/* the watchdog device behind /dev/watchdog */ 49/* the watchdog device behind /dev/watchdog */
50static struct watchdog_device *wdd; 50static struct watchdog_device *old_wdd;
51 51
52/* 52/*
53 * watchdog_ping: ping the watchdog. 53 * watchdog_ping: ping the watchdog.
@@ -138,6 +138,7 @@ static int watchdog_stop(struct watchdog_device *wddev)
138static ssize_t watchdog_write(struct file *file, const char __user *data, 138static ssize_t watchdog_write(struct file *file, const char __user *data,
139 size_t len, loff_t *ppos) 139 size_t len, loff_t *ppos)
140{ 140{
141 struct watchdog_device *wdd = file->private_data;
141 size_t i; 142 size_t i;
142 char c; 143 char c;
143 144
@@ -177,6 +178,7 @@ static ssize_t watchdog_write(struct file *file, const char __user *data,
177static long watchdog_ioctl(struct file *file, unsigned int cmd, 178static long watchdog_ioctl(struct file *file, unsigned int cmd,
178 unsigned long arg) 179 unsigned long arg)
179{ 180{
181 struct watchdog_device *wdd = file->private_data;
180 void __user *argp = (void __user *)arg; 182 void __user *argp = (void __user *)arg;
181 int __user *p = argp; 183 int __user *p = argp;
182 unsigned int val; 184 unsigned int val;
@@ -249,11 +251,11 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd,
249} 251}
250 252
251/* 253/*
252 * watchdog_open: open the /dev/watchdog device. 254 * watchdog_open: open the /dev/watchdog* devices.
253 * @inode: inode of device 255 * @inode: inode of device
254 * @file: file handle to device 256 * @file: file handle to device
255 * 257 *
256 * When the /dev/watchdog device gets opened, we start the watchdog. 258 * When the /dev/watchdog* device gets opened, we start the watchdog.
257 * Watch out: the /dev/watchdog device is single open, so we make sure 259 * Watch out: the /dev/watchdog device is single open, so we make sure
258 * it can only be opened once. 260 * it can only be opened once.
259 */ 261 */
@@ -261,6 +263,13 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd,
261static int watchdog_open(struct inode *inode, struct file *file) 263static int watchdog_open(struct inode *inode, struct file *file)
262{ 264{
263 int err = -EBUSY; 265 int err = -EBUSY;
266 struct watchdog_device *wdd;
267
268 /* Get the corresponding watchdog device */
269 if (imajor(inode) == MISC_MAJOR)
270 wdd = old_wdd;
271 else
272 wdd = container_of(inode->i_cdev, struct watchdog_device, cdev);
264 273
265 /* the watchdog is single open! */ 274 /* the watchdog is single open! */
266 if (test_and_set_bit(WDOG_DEV_OPEN, &wdd->status)) 275 if (test_and_set_bit(WDOG_DEV_OPEN, &wdd->status))
@@ -277,6 +286,8 @@ static int watchdog_open(struct inode *inode, struct file *file)
277 if (err < 0) 286 if (err < 0)
278 goto out_mod; 287 goto out_mod;
279 288
289 file->private_data = wdd;
290
280 /* dev/watchdog is a virtual (and thus non-seekable) filesystem */ 291 /* dev/watchdog is a virtual (and thus non-seekable) filesystem */
281 return nonseekable_open(inode, file); 292 return nonseekable_open(inode, file);
282 293
@@ -288,9 +299,9 @@ out:
288} 299}
289 300
290/* 301/*
291 * watchdog_release: release the /dev/watchdog device. 302 * watchdog_release: release the watchdog device.
292 * @inode: inode of device 303 * @inode: inode of device
293 * @file: file handle to device 304 * @file: file handle to device
294 * 305 *
295 * This is the code for when /dev/watchdog gets closed. We will only 306 * This is the code for when /dev/watchdog gets closed. We will only
296 * stop the watchdog when we have received the magic char (and nowayout 307 * stop the watchdog when we have received the magic char (and nowayout
@@ -299,6 +310,7 @@ out:
299 310
300static int watchdog_release(struct inode *inode, struct file *file) 311static int watchdog_release(struct inode *inode, struct file *file)
301{ 312{
313 struct watchdog_device *wdd = file->private_data;
302 int err = -EBUSY; 314 int err = -EBUSY;
303 315
304 /* 316 /*
@@ -340,62 +352,87 @@ static struct miscdevice watchdog_miscdev = {
340}; 352};
341 353
342/* 354/*
343 * watchdog_dev_register: 355 * watchdog_dev_register: register a watchdog device
344 * @watchdog: watchdog device 356 * @watchdog: watchdog device
345 * 357 *
346 * Register a watchdog device as /dev/watchdog. /dev/watchdog 358 * Register a watchdog device including handling the legacy
347 * is actually a miscdevice and thus we set it up like that. 359 * /dev/watchdog node. /dev/watchdog is actually a miscdevice and
360 * thus we set it up like that.
348 */ 361 */
349 362
350int watchdog_dev_register(struct watchdog_device *watchdog) 363int watchdog_dev_register(struct watchdog_device *watchdog)
351{ 364{
352 int err; 365 int err, devno;
353 366
354 /* Only one device can register for /dev/watchdog */ 367 if (watchdog->id == 0) {
355 if (test_and_set_bit(0, &watchdog_dev_busy)) { 368 err = misc_register(&watchdog_miscdev);
356 pr_err("only one watchdog can use /dev/watchdog\n"); 369 if (err != 0) {
357 return -EBUSY; 370 pr_err("%s: cannot register miscdev on minor=%d (err=%d).\n",
371 watchdog->info->identity, WATCHDOG_MINOR, err);
372 if (err == -EBUSY)
373 pr_err("%s: a legacy watchdog module is probably present.\n",
374 watchdog->info->identity);
375 return err;
376 }
377 old_wdd = watchdog;
358 } 378 }
359 379
360 wdd = watchdog; 380 /* Fill in the data structures */
361 381 devno = MKDEV(MAJOR(watchdog_devt), watchdog->id);
362 err = misc_register(&watchdog_miscdev); 382 cdev_init(&watchdog->cdev, &watchdog_fops);
363 if (err != 0) { 383 watchdog->cdev.owner = watchdog->ops->owner;
364 pr_err("%s: cannot register miscdev on minor=%d (err=%d)\n", 384
365 watchdog->info->identity, WATCHDOG_MINOR, err); 385 /* Add the device */
366 goto out; 386 err = cdev_add(&watchdog->cdev, devno, 1);
387 if (err) {
388 pr_err("watchdog%d unable to add device %d:%d\n",
389 watchdog->id, MAJOR(watchdog_devt), watchdog->id);
390 if (watchdog->id == 0) {
391 misc_deregister(&watchdog_miscdev);
392 old_wdd = NULL;
393 }
367 } 394 }
368
369 return 0;
370
371out:
372 wdd = NULL;
373 clear_bit(0, &watchdog_dev_busy);
374 return err; 395 return err;
375} 396}
376 397
377/* 398/*
378 * watchdog_dev_unregister: 399 * watchdog_dev_unregister: unregister a watchdog device
379 * @watchdog: watchdog device 400 * @watchdog: watchdog device
380 * 401 *
381 * Deregister the /dev/watchdog device. 402 * Unregister the watchdog and if needed the legacy /dev/watchdog device.
382 */ 403 */
383 404
384int watchdog_dev_unregister(struct watchdog_device *watchdog) 405int watchdog_dev_unregister(struct watchdog_device *watchdog)
385{ 406{
386 /* Check that a watchdog device was registered in the past */ 407 cdev_del(&watchdog->cdev);
387 if (!test_bit(0, &watchdog_dev_busy) || !wdd) 408 if (watchdog->id == 0) {
388 return -ENODEV; 409 misc_deregister(&watchdog_miscdev);
389 410 old_wdd = NULL;
390 /* We can only unregister the watchdog device that was registered */
391 if (watchdog != wdd) {
392 pr_err("%s: watchdog was not registered as /dev/watchdog\n",
393 watchdog->info->identity);
394 return -ENODEV;
395 } 411 }
396
397 misc_deregister(&watchdog_miscdev);
398 wdd = NULL;
399 clear_bit(0, &watchdog_dev_busy);
400 return 0; 412 return 0;
401} 413}
414
415/*
416 * watchdog_dev_init: init dev part of watchdog core
417 *
418 * Allocate a range of chardev nodes to use for watchdog devices
419 */
420
421int __init watchdog_dev_init(void)
422{
423 int err = alloc_chrdev_region(&watchdog_devt, 0, MAX_DOGS, "watchdog");
424 if (err < 0)
425 pr_err("watchdog: unable to allocate char dev region\n");
426 return err;
427}
428
429/*
430 * watchdog_dev_exit: exit dev part of watchdog core
431 *
432 * Release the range of chardev nodes used for watchdog devices
433 */
434
435void __exit watchdog_dev_exit(void)
436{
437 unregister_chrdev_region(watchdog_devt, MAX_DOGS);
438}