diff options
author | Wolfram Sang <w.sang@pengutronix.de> | 2011-09-26 09:40:13 -0400 |
---|---|---|
committer | Wim Van Sebroeck <wim@iguana.be> | 2011-11-05 16:25:16 -0400 |
commit | 74cd4c67392c1cee0499ba0977ec843252c7af28 (patch) | |
tree | 1248b9020720ea88c8e24a675ffe75bd317bc272 /Documentation/watchdog | |
parent | deb9197b7031b8f4ed311dc47a14363da4458544 (diff) |
Documentation: watchdog: add guide how to convert drivers to new framework
Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
Cc: Randy Dunlap <rdunlap@xenotime.net>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Diffstat (limited to 'Documentation/watchdog')
-rw-r--r-- | Documentation/watchdog/convert_drivers_to_kernel_api.txt | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/Documentation/watchdog/convert_drivers_to_kernel_api.txt b/Documentation/watchdog/convert_drivers_to_kernel_api.txt new file mode 100644 index 000000000000..ae1e90036d06 --- /dev/null +++ b/Documentation/watchdog/convert_drivers_to_kernel_api.txt | |||
@@ -0,0 +1,195 @@ | |||
1 | Converting old watchdog drivers to the watchdog framework | ||
2 | by Wolfram Sang <w.sang@pengutronix.de> | ||
3 | ========================================================= | ||
4 | |||
5 | Before the watchdog framework came into the kernel, every driver had to | ||
6 | implement the API on its own. Now, as the framework factored out the common | ||
7 | components, those drivers can be lightened making it a user of the framework. | ||
8 | This document shall guide you for this task. The necessary steps are described | ||
9 | as well as things to look out for. | ||
10 | |||
11 | |||
12 | Remove the file_operations struct | ||
13 | --------------------------------- | ||
14 | |||
15 | Old drivers define their own file_operations for actions like open(), write(), | ||
16 | etc... These are now handled by the framework and just call the driver when | ||
17 | needed. So, in general, the 'file_operations' struct and assorted functions can | ||
18 | go. Only very few driver-specific details have to be moved to other functions. | ||
19 | Here 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 | |||
68 | Example 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 | |||
79 | Check the functions for device-specific stuff and keep it for later | ||
80 | refactoring. The rest can go. | ||
81 | |||
82 | |||
83 | Remove the miscdevice | ||
84 | --------------------- | ||
85 | |||
86 | Since the file_operations are gone now, you can also remove the 'struct | ||
87 | miscdevice'. The framework will create it on watchdog_dev_register() called by | ||
88 | watchdog_register_device(). | ||
89 | |||
90 | -static struct miscdevice s3c2410wdt_miscdev = { | ||
91 | - .minor = WATCHDOG_MINOR, | ||
92 | - .name = "watchdog", | ||
93 | - .fops = &s3c2410wdt_fops, | ||
94 | -}; | ||
95 | |||
96 | |||
97 | Remove obsolete includes and defines | ||
98 | ------------------------------------ | ||
99 | |||
100 | Because of the simplifications, a few defines are probably unused now. Remove | ||
101 | them. 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 | |||
108 | Add the watchdog operations | ||
109 | --------------------------- | ||
110 | |||
111 | All possible callbacks are defined in 'struct watchdog_ops'. You can find it | ||
112 | explained in 'watchdog-kernel-api.txt' in this directory. start(), stop() and | ||
113 | owner must be set, the rest are optional. You will easily find corresponding | ||
114 | functions in the old driver. Note that you will now get a pointer to the | ||
115 | watchdog_device as a parameter to these functions, so you probably have to | ||
116 | change the function header. Other changes are most likely not needed, because | ||
117 | here simply happens the direct hardware access. If you have device-specific | ||
118 | code left from the above steps, it should be refactored into these callbacks. | ||
119 | |||
120 | Here 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 | |||
130 | A 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 | |||
146 | Add the watchdog device | ||
147 | ----------------------- | ||
148 | |||
149 | Now we need to create a 'struct watchdog_device' and populate it with the | ||
150 | necessary information for the framework. The struct is also explained in detail | ||
151 | in 'watchdog-kernel-api.txt' in this directory. We pass it the mandatory | ||
152 | watchdog_info struct and the newly created watchdog_ops. Often, old drivers | ||
153 | have their own record-keeping for things like bootstatus and timeout using | ||
154 | static variables. Those have to be converted to use the members in | ||
155 | watchdog_device. Note that the timeout values are unsigned int. Some drivers | ||
156 | use signed int, so this has to be converted, too. | ||
157 | |||
158 | Here 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 | |||
166 | Register the watchdog device | ||
167 | ---------------------------- | ||
168 | |||
169 | Replace misc_register(&miscdev) with watchdog_register_device(&watchdog_dev). | ||
170 | Make sure the return value gets checked and the error message, if present, | ||
171 | still fits. Also convert the unregister case. | ||
172 | |||
173 | - ret = misc_register(&s3c2410wdt_miscdev); | ||
174 | + ret = watchdog_register_device(&s3c2410_wdd); | ||
175 | |||
176 | ... | ||
177 | |||
178 | - misc_deregister(&s3c2410wdt_miscdev); | ||
179 | + watchdog_unregister_device(&s3c2410_wdd); | ||
180 | |||
181 | |||
182 | Update the Kconfig-entry | ||
183 | ------------------------ | ||
184 | |||
185 | The entry for the driver now needs to select WATCHDOG_CORE: | ||
186 | |||
187 | + select WATCHDOG_CORE | ||
188 | |||
189 | |||
190 | Create a patch and send it to upstream | ||
191 | -------------------------------------- | ||
192 | |||
193 | Make sure you understood Documentation/SubmittingPatches and send your patch to | ||
194 | linux-watchdog@vger.kernel.org. We are looking forward to it :) | ||
195 | |||