/* * watchdog_core.c * * (c) Copyright 2008-2011 Alan Cox , * All Rights Reserved. * * (c) Copyright 2008-2011 Wim Van Sebroeck . * * 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 , * Rob Radez , * Rusty Lynch * Satyam Sharma * Randy Dunlap * * 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 /* For EXPORT_SYMBOL/module stuff/... */ #include /* For standard types */ #include /* For the -ENODEV/... values */ #include /* For printk/panic/... */ #include /* For watchdog specific items */ #include /* For __init/__exit/... */ #include /* For ida_* macros */ #include "watchdog_core.h" /* For watchdog_dev_register/... */ static DEFINE_IDA(watchdog_ida); /** * 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, id; 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; /* * Check that we have valid min and max timeout values, if * not reset them both to 0 (=not used or unknown) */ if (wdd->min_timeout > wdd->max_timeout) { pr_info("Invalid min and max timeout values, resetting to 0!\n"); wdd->min_timeout = 0; wdd->max_timeout = 0; } /* * 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! */ id = ida_simple_get(&watchdog_ida, 0, MAX_DOGS, GFP_KERNEL); if (id < 0) return id; wdd->id = id; ret = watchdog_dev_register(wdd); if (ret) { ida_simple_remove(&watchdog_ida, id); if (!(id == 0 && ret == -EBUSY)) return ret; /* Retry in case a legacy watchdog module exists */ id = ida_simple_get(&watchdog_ida, 1, MAX_DOGS, GFP_KERNEL); if (id < 0) return id; wdd->id = id; ret = watchdog_dev_register(wdd); if (ret) { ida_simple_remove(&watchdog_ida, id); 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); ida_simple_remove(&watchdog_ida, wdd->id); } EXPORT_SYMBOL_GPL(watchdog_unregister_device); static int __init watchdog_init(void) { return watchdog_dev_init(); } static void __exit watchdog_exit(void) { watchdog_dev_exit(); ida_destroy(&watchdog_ida); } subsys_initcall(watchdog_init); module_exit(watchdog_exit); MODULE_AUTHOR("Alan Cox "); MODULE_AUTHOR("Wim Van Sebroeck "); MODULE_DESCRIPTION("WatchDog Timer Driver Core"); MODULE_LICENSE("GPL");