linux/Documentation/watchdog/convert_drivers_to_kernel_api.txt
<<
>>
Prefs
   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        WDIOC_GETTIMELEFT:
  63                It needs get_timeleft() callback to be defined. Otherwise it
  64                will return EOPNOTSUPP
  65
  66  Other IOCTLs can be served using the ioctl-callback. Note that this is mainly
  67  intended for porting old drivers; new drivers should not invent private IOCTLs.
  68  Private IOCTLs are processed first. When the callback returns with
  69  -ENOIOCTLCMD, the IOCTLs of the framework will be tried, too. Any other error
  70  is directly given to the user.
  71
  72Example conversion:
  73
  74-static const struct file_operations s3c2410wdt_fops = {
  75-       .owner          = THIS_MODULE,
  76-       .llseek         = no_llseek,
  77-       .write          = s3c2410wdt_write,
  78-       .unlocked_ioctl = s3c2410wdt_ioctl,
  79-       .open           = s3c2410wdt_open,
  80-       .release        = s3c2410wdt_release,
  81-};
  82
  83Check the functions for device-specific stuff and keep it for later
  84refactoring. The rest can go.
  85
  86
  87Remove the miscdevice
  88---------------------
  89
  90Since the file_operations are gone now, you can also remove the 'struct
  91miscdevice'. The framework will create it on watchdog_dev_register() called by
  92watchdog_register_device().
  93
  94-static struct miscdevice s3c2410wdt_miscdev = {
  95-       .minor          = WATCHDOG_MINOR,
  96-       .name           = "watchdog",
  97-       .fops           = &s3c2410wdt_fops,
  98-};
  99
 100
 101Remove obsolete includes and defines
 102------------------------------------
 103
 104Because of the simplifications, a few defines are probably unused now. Remove
 105them. Includes can be removed, too. For example:
 106
 107- #include <linux/fs.h>
 108- #include <linux/miscdevice.h> (if MODULE_ALIAS_MISCDEV is not used)
 109- #include <linux/uaccess.h> (if no custom IOCTLs are used)
 110
 111
 112Add the watchdog operations
 113---------------------------
 114
 115All possible callbacks are defined in 'struct watchdog_ops'. You can find it
 116explained in 'watchdog-kernel-api.txt' in this directory. start(), stop() and
 117owner must be set, the rest are optional. You will easily find corresponding
 118functions in the old driver. Note that you will now get a pointer to the
 119watchdog_device as a parameter to these functions, so you probably have to
 120change the function header. Other changes are most likely not needed, because
 121here simply happens the direct hardware access. If you have device-specific
 122code left from the above steps, it should be refactored into these callbacks.
 123
 124Here is a simple example:
 125
 126+static struct watchdog_ops s3c2410wdt_ops = {
 127+       .owner = THIS_MODULE,
 128+       .start = s3c2410wdt_start,
 129+       .stop = s3c2410wdt_stop,
 130+       .ping = s3c2410wdt_keepalive,
 131+       .set_timeout = s3c2410wdt_set_heartbeat,
 132+};
 133
 134A typical function-header change looks like:
 135
 136-static void s3c2410wdt_keepalive(void)
 137+static int s3c2410wdt_keepalive(struct watchdog_device *wdd)
 138 {
 139...
 140+
 141+       return 0;
 142 }
 143
 144...
 145
 146-       s3c2410wdt_keepalive();
 147+       s3c2410wdt_keepalive(&s3c2410_wdd);
 148
 149
 150Add the watchdog device
 151-----------------------
 152
 153Now we need to create a 'struct watchdog_device' and populate it with the
 154necessary information for the framework. The struct is also explained in detail
 155in 'watchdog-kernel-api.txt' in this directory. We pass it the mandatory
 156watchdog_info struct and the newly created watchdog_ops. Often, old drivers
 157have their own record-keeping for things like bootstatus and timeout using
 158static variables. Those have to be converted to use the members in
 159watchdog_device. Note that the timeout values are unsigned int. Some drivers
 160use signed int, so this has to be converted, too.
 161
 162Here is a simple example for a watchdog device:
 163
 164+static struct watchdog_device s3c2410_wdd = {
 165+       .info = &s3c2410_wdt_ident,
 166+       .ops = &s3c2410wdt_ops,
 167+};
 168
 169
 170Handle the 'nowayout' feature
 171-----------------------------
 172
 173A few drivers use nowayout statically, i.e. there is no module parameter for it
 174and only CONFIG_WATCHDOG_NOWAYOUT determines if the feature is going to be
 175used. This needs to be converted by initializing the status variable of the
 176watchdog_device like this:
 177
 178        .status = WATCHDOG_NOWAYOUT_INIT_STATUS,
 179
 180Most drivers, however, also allow runtime configuration of nowayout, usually
 181by adding a module parameter. The conversion for this would be something like:
 182
 183        watchdog_set_nowayout(&s3c2410_wdd, nowayout);
 184
 185The module parameter itself needs to stay, everything else related to nowayout
 186can go, though. This will likely be some code in open(), close() or write().
 187
 188
 189Register the watchdog device
 190----------------------------
 191
 192Replace misc_register(&miscdev) with watchdog_register_device(&watchdog_dev).
 193Make sure the return value gets checked and the error message, if present,
 194still fits. Also convert the unregister case.
 195
 196-       ret = misc_register(&s3c2410wdt_miscdev);
 197+       ret = watchdog_register_device(&s3c2410_wdd);
 198
 199...
 200
 201-       misc_deregister(&s3c2410wdt_miscdev);
 202+       watchdog_unregister_device(&s3c2410_wdd);
 203
 204
 205Update the Kconfig-entry
 206------------------------
 207
 208The entry for the driver now needs to select WATCHDOG_CORE:
 209
 210+       select WATCHDOG_CORE
 211
 212
 213Create a patch and send it to upstream
 214--------------------------------------
 215
 216Make sure you understood Documentation/SubmittingPatches and send your patch to
 217linux-watchdog@vger.kernel.org. We are looking forward to it :)
 218
 219
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.