1Converting old watchdog drivers to the watchdog framework 2by Wolfram Sang <w.sang@pengutronix.de> 3========================================================= 4 5Before the watchdog framework came into the kernel, every driver had to 6implement the API on its own. Now, as the framework factored out the common 7components, those drivers can be lightened making it a user of the framework. 8This document shall guide you for this task. The necessary steps are described 9as well as things to look out for. 10 11 12Remove the file_operations struct 13--------------------------------- 14 15Old drivers define their own file_operations for actions like open(), write(), 16etc... These are now handled by the framework and just call the driver when 17needed. So, in general, the 'file_operations' struct and assorted functions can 18go. Only very few driver-specific details have to be moved to other functions. 19Here is a overview of the functions and probably needed actions: 20 21- open: Everything dealing with resource management (file-open checks, magic 22 close preparations) can simply go. Device specific stuff needs to go to the 23 driver specific start-function. Note that for some drivers, the start-function 24 also serves as the ping-function. If that is the case and you need start/stop 25 to be balanced (clocks!), you are better off refactoring a separate start-function. 26 27- close: Same hints as for open apply. 28 29- write: Can simply go, all defined behaviour is taken care of by the framework, 30 i.e. ping on write and magic char ('V') handling. 31 32- ioctl: While the driver is allowed to have extensions to the IOCTL interface, 33 the most common ones are handled by the framework, supported by some assistance 34 from the driver: 35 36 WDIOC_GETSUPPORT: 37 Returns the mandatory watchdog_info struct from the driver 38 39 WDIOC_GETSTATUS: 40 Needs the status-callback defined, otherwise returns 0 41 42 WDIOC_GETBOOTSTATUS: 43 Needs the bootstatus member properly set. Make sure it is 0 if you 44 don't have further support! 45 46 WDIOC_SETOPTIONS: 47 No preparations needed 48 49 WDIOC_KEEPALIVE: 50 If wanted, options in watchdog_info need to have WDIOF_KEEPALIVEPING 51 set 52 53 WDIOC_SETTIMEOUT: 54 Options in watchdog_info need to have WDIOF_SETTIMEOUT set 55 and a set_timeout-callback has to be defined. The core will also 56 do limit-checking, if min_timeout and max_timeout in the watchdog 57 device are set. All is optional. 58 59 WDIOC_GETTIMEOUT: 60 No preparations needed 61 62 Other IOCTLs can be served using the ioctl-callback. Note that this is mainly 63 intended for porting old drivers; new drivers should not invent private IOCTLs. 64 Private IOCTLs are processed first. When the callback returns with 65 -ENOIOCTLCMD, the IOCTLs of the framework will be tried, too. Any other error 66 is directly given to the user. 67 68Example conversion: 69 70-static const struct file_operations s3c2410wdt_fops = { 71- .owner = THIS_MODULE, 72- .llseek = no_llseek, 73- .write = s3c2410wdt_write, 74- .unlocked_ioctl = s3c2410wdt_ioctl, 75- .open = s3c2410wdt_open, 76- .release = s3c2410wdt_release, 77-}; 78 79Check the functions for device-specific stuff and keep it for later 80refactoring. The rest can go. 81 82 83Remove the miscdevice 84--------------------- 85 86Since the file_operations are gone now, you can also remove the 'struct 87miscdevice'. The framework will create it on watchdog_dev_register() called by 88watchdog_register_device(). 89 90-static struct miscdevice s3c2410wdt_miscdev = { 91- .minor = WATCHDOG_MINOR, 92- .name = "watchdog", 93- .fops = &s3c2410wdt_fops, 94-}; 95 96 97Remove obsolete includes and defines 98------------------------------------ 99 100Because of the simplifications, a few defines are probably unused now. Remove 101them. Includes can be removed, too. For example: 102 103- #include <linux/fs.h> 104- #include <linux/miscdevice.h> (if MODULE_ALIAS_MISCDEV is not used) 105- #include <linux/uaccess.h> (if no custom IOCTLs are used) 106 107 108Add the watchdog operations 109--------------------------- 110 111All possible callbacks are defined in 'struct watchdog_ops'. You can find it 112explained in 'watchdog-kernel-api.txt' in this directory. start(), stop() and 113owner must be set, the rest are optional. You will easily find corresponding 114functions in the old driver. Note that you will now get a pointer to the 115watchdog_device as a parameter to these functions, so you probably have to 116change the function header. Other changes are most likely not needed, because 117here simply happens the direct hardware access. If you have device-specific 118code left from the above steps, it should be refactored into these callbacks. 119 120Here is a simple example: 121 122+static struct watchdog_ops s3c2410wdt_ops = { 123+ .owner = THIS_MODULE, 124+ .start = s3c2410wdt_start, 125+ .stop = s3c2410wdt_stop, 126+ .ping = s3c2410wdt_keepalive, 127+ .set_timeout = s3c2410wdt_set_heartbeat, 128+}; 129 130A typical function-header change looks like: 131 132-static void s3c2410wdt_keepalive(void) 133+static int s3c2410wdt_keepalive(struct watchdog_device *wdd) 134 { 135... 136+ 137+ return 0; 138 } 139 140... 141 142- s3c2410wdt_keepalive(); 143+ s3c2410wdt_keepalive(&s3c2410_wdd); 144 145 146Add the watchdog device 147----------------------- 148 149Now we need to create a 'struct watchdog_device' and populate it with the 150necessary information for the framework. The struct is also explained in detail 151in 'watchdog-kernel-api.txt' in this directory. We pass it the mandatory 152watchdog_info struct and the newly created watchdog_ops. Often, old drivers 153have their own record-keeping for things like bootstatus and timeout using 154static variables. Those have to be converted to use the members in 155watchdog_device. Note that the timeout values are unsigned int. Some drivers 156use signed int, so this has to be converted, too. 157 158Here is a simple example for a watchdog device: 159 160+static struct watchdog_device s3c2410_wdd = { 161+ .info = &s3c2410_wdt_ident, 162+ .ops = &s3c2410wdt_ops, 163+}; 164 165 166Handle the 'nowayout' feature 167----------------------------- 168 169A few drivers use nowayout statically, i.e. there is no module parameter for it 170and only CONFIG_WATCHDOG_NOWAYOUT determines if the feature is going to be 171used. This needs to be converted by initializing the status variable of the 172watchdog_device like this: 173 174 .status = WATCHDOG_NOWAYOUT_INIT_STATUS, 175 176Most drivers, however, also allow runtime configuration of nowayout, usually 177by adding a module parameter. The conversion for this would be something like: 178 179 watchdog_set_nowayout(&s3c2410_wdd, nowayout); 180 181The module parameter itself needs to stay, everything else related to nowayout 182can go, though. This will likely be some code in open(), close() or write(). 183 184 185Register the watchdog device 186---------------------------- 187 188Replace misc_register(&miscdev) with watchdog_register_device(&watchdog_dev). 189Make sure the return value gets checked and the error message, if present, 190still fits. Also convert the unregister case. 191 192- ret = misc_register(&s3c2410wdt_miscdev); 193+ ret = watchdog_register_device(&s3c2410_wdd); 194 195... 196 197- misc_deregister(&s3c2410wdt_miscdev); 198+ watchdog_unregister_device(&s3c2410_wdd); 199 200 201Update the Kconfig-entry 202------------------------ 203 204The entry for the driver now needs to select WATCHDOG_CORE: 205 206+ select WATCHDOG_CORE 207 208 209Create a patch and send it to upstream 210-------------------------------------- 211 212Make sure you understood Documentation/SubmittingPatches and send your patch to 213linux-watchdog@vger.kernel.org. We are looking forward to it :) 214 215