About Kernel Documentation Linux Kernel Contact Linux Resources Linux Blog

Documentation / watchdog / convert_drivers_to_kernel_api.txt


Based on kernel version 4.16.1. Page generated on 2018-04-09 11:53 EST.

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		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	
72	Example 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	
83	Check the functions for device-specific stuff and keep it for later
84	refactoring. The rest can go.
85	
86	
87	Remove the miscdevice
88	---------------------
89	
90	Since the file_operations are gone now, you can also remove the 'struct
91	miscdevice'. The framework will create it on watchdog_dev_register() called by
92	watchdog_register_device().
93	
94	-static struct miscdevice s3c2410wdt_miscdev = {
95	-       .minor          = WATCHDOG_MINOR,
96	-       .name           = "watchdog",
97	-       .fops           = &s3c2410wdt_fops,
98	-};
99	
100	
101	Remove obsolete includes and defines
102	------------------------------------
103	
104	Because of the simplifications, a few defines are probably unused now. Remove
105	them. 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	
112	Add the watchdog operations
113	---------------------------
114	
115	All possible callbacks are defined in 'struct watchdog_ops'. You can find it
116	explained in 'watchdog-kernel-api.txt' in this directory. start(), stop() and
117	owner must be set, the rest are optional. You will easily find corresponding
118	functions in the old driver. Note that you will now get a pointer to the
119	watchdog_device as a parameter to these functions, so you probably have to
120	change the function header. Other changes are most likely not needed, because
121	here simply happens the direct hardware access. If you have device-specific
122	code left from the above steps, it should be refactored into these callbacks.
123	
124	Here 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	
134	A 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	
150	Add the watchdog device
151	-----------------------
152	
153	Now we need to create a 'struct watchdog_device' and populate it with the
154	necessary information for the framework. The struct is also explained in detail
155	in 'watchdog-kernel-api.txt' in this directory. We pass it the mandatory
156	watchdog_info struct and the newly created watchdog_ops. Often, old drivers
157	have their own record-keeping for things like bootstatus and timeout using
158	static variables. Those have to be converted to use the members in
159	watchdog_device. Note that the timeout values are unsigned int. Some drivers
160	use signed int, so this has to be converted, too.
161	
162	Here 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	
170	Handle the 'nowayout' feature
171	-----------------------------
172	
173	A few drivers use nowayout statically, i.e. there is no module parameter for it
174	and only CONFIG_WATCHDOG_NOWAYOUT determines if the feature is going to be
175	used. This needs to be converted by initializing the status variable of the
176	watchdog_device like this:
177	
178	        .status = WATCHDOG_NOWAYOUT_INIT_STATUS,
179	
180	Most drivers, however, also allow runtime configuration of nowayout, usually
181	by adding a module parameter. The conversion for this would be something like:
182	
183		watchdog_set_nowayout(&s3c2410_wdd, nowayout);
184	
185	The module parameter itself needs to stay, everything else related to nowayout
186	can go, though. This will likely be some code in open(), close() or write().
187	
188	
189	Register the watchdog device
190	----------------------------
191	
192	Replace misc_register(&miscdev) with watchdog_register_device(&watchdog_dev).
193	Make sure the return value gets checked and the error message, if present,
194	still 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	
205	Update the Kconfig-entry
206	------------------------
207	
208	The entry for the driver now needs to select WATCHDOG_CORE:
209	
210	+       select WATCHDOG_CORE
211	
212	
213	Create a patch and send it to upstream
214	--------------------------------------
215	
216	Make sure you understood Documentation/process/submitting-patches.rst and send your patch to
217	linux-watchdog@vger.kernel.org. We are looking forward to it :)
Hide Line Numbers


About Kernel Documentation Linux Kernel Contact Linux Resources Linux Blog