m4/as-linux.m4: don't use backported pcmcia_loop_tuple()
[comedi.git] / scripts / check_driver
1 #!/bin/bash
2 #
3 # This script shows some of the deficiencies in drivers.  Some
4 # of the things that are tested here are only suggestions, and
5 # don't necessarily apply to every driver.
6 #
7
8 check_all=no
9
10 if [ "$1" ];then
11         driver=$1
12 else
13         echo 'check_driver <filename>'
14         exit 1
15 fi
16
17 echo "I: ${driver}:"
18
19 basedriver=$(basename ${driver} .c)
20
21 # special cases
22 case ${driver} in
23         ni_pcimio.c)
24                 driver="${driver} ni_mio_common.c mite.c"
25                 ;;
26         ni_atmio.c)
27                 driver="${driver} ni_mio_common.c mite.c"
28                 ;;
29         ni_mio_cs.c)
30                 driver="${driver} ni_mio_common.c mite.c"
31                 ;;
32 esac
33
34
35
36 # check to see if it is a driver
37 if grep '^\(static \)*comedi_driver' ${driver} &>/dev/null;then
38         echo "appears to be a driver"
39 else
40         echo "not a driver file"
41         exit 1
42 fi
43
44 if ! grep '[[:space:]]\+module:[[:space:]]*THIS_MODULE' ${driver} &>/dev/null;then
45         echo "E: doesn't set driver->module to THIS_MODULE"
46 fi
47
48 # check Makefile.am for the driver
49 if ! grep "${basedriver}\.ko" Makefile.am &>/dev/null; then
50         echo "E: ${basedriver}.ko missing from module_PROGRAMS in Makefile.am"
51 fi
52 if ! grep "${basedriver}_ko_SOURCES" Makefile.am &>/dev/null; then
53         echo "E: ${basedriver}_ko_SOURCES line missing from Makefile.am"
54 fi
55
56 # check Kbuild for the driver
57 if ! grep "obj-.*+=.*${basedriver}\.o" Kbuild &>/dev/null; then
58         echo "E: driver missing from Kbuild"
59 fi
60
61 # check to see if it uses name recognition
62 if grep 'board_name:' ${driver} &>/dev/null;then
63         echo uses recognize to determine type
64         probe=recognize
65 else
66         if grep 'dev..board_ptr' ${driver} &>/dev/null;then
67                 echo auto-probes type of board
68                 probe=auto
69         else
70                 echo only supports one type of board
71                 probe=one
72         fi
73 fi
74
75 # auto checks
76 if [ "$probe" = auto ];then
77         if grep 'dev..board_ptr[[:space:]]*=' ${driver} &>/dev/null;then
78                 echo 'sets dev->board_ptr'
79         else
80                 echo "E: doesn't set dev->board_ptr"
81         fi
82 fi
83
84 # recognize checks
85 if [ "$probe" = recognize ];then
86         if ! grep '[[:space:]]\+offset:[[:space:]]*sizeof' ${driver} &>/dev/null;then
87                 echo "E: doesn't set driver->offset"
88         fi
89         if ! grep '[[:space:]]\+num_names:[[:space:]]' ${driver} &>/dev/null;then
90                 echo "E: doesn't set driver->num_names"
91         fi
92 fi
93
94 # I would prefer that drivers have a consistent number of subdevices
95 # independent of the particular board type.  If a subdevice is not
96 # relevant for a board type, the type should be set to COMEDI_SUBD_UNUSED.
97 # However, for drivers that handle N identical subdevices, it's better
98 # to have a variable number of subdevices.
99 tmp=$(cat ${driver}|grep -c 'dev..n_subdevices[[:space:]]*=' 2>/dev/null)
100 if [ "$tmp" = 0 ];then
101         echo "doesn't set n_subdevices (good)"
102 else
103         echo "W: sets n_subdevices multiple ($tmp) times"
104 fi
105 if grep 'dev..n_subdevices[[:space:]]*=[[:space:]]*[^[:digit:][:space:]]' ${driver} &>/dev/null;then
106         echo "W: sets n_subdevices by variable"
107 fi
108
109 # Check to see if board_name is set
110 if grep 'dev..board_name[[:space:]]*=' ${driver} &>/dev/null;then
111         echo "board_name is set"
112 else
113         echo "E: board_name not set"
114 fi
115
116 # Do we use trig?  trig[0] has been eliminated
117 if [ "$check_all" = yes ]; then
118 if grep 'trig\[0\]' ${driver} &>/dev/null;then
119         echo "E: uses trig[0]"
120 else
121         echo "doesn't use trig[0]"
122 fi
123 fi
124
125 # trig[1234] has been eliminated
126 if [ "$check_all" = yes ]; then
127 if grep 'trig\[[1234]\]' ${driver} &>/dev/null;then
128         echo "E: uses trig[1234]"
129         trig1234=yes
130 else
131         echo "doesn't use trig[1234]"
132         trig1234=no
133 fi
134 fi
135
136 if grep 'comedi_cmd' ${driver} &>/dev/null;then 
137         echo "uses cmd"
138         cmd=yes
139 else
140         if [ "$trig1234" == yes ];then
141                 echo "E: doesn't use cmd"
142         else
143                 echo "doesn't use cmd"
144         fi
145         cmd=no
146 fi
147
148 if grep 'comedi_insn' ${driver} &>/dev/null;then 
149         echo "uses insn"
150         insn=yes
151 else
152         if grep 'subdev_8255_init' ${driver} &>/dev/null;then
153                 echo uses subdev_8255_init
154         else
155                 echo "E: doesn't use insn"
156         fi
157         insn=no
158 fi
159
160 # rt_printk() only needs to be used in possible real-time code paths,
161 # which is basically everything except *_attach() and *_detach().
162 # However, since it works correctly in non-real-time code, just use
163 # it everywhere.
164 if [ "$check_all" = yes ]; then
165 if grep 'printk' ${driver} &>/dev/null;then
166         if ! grep 'rt_printk' ${driver} &>/dev/null;then
167                 echo "W: doesn't use rt_printk"
168         fi
169 fi
170 fi
171
172 # comedi_request_irq() handles real-time interrupts.
173 if grep request_irq ${driver} &>/dev/null;then
174         irq=yes
175         if ! grep 'comedi_request_irq' ${driver} &>/dev/null;then
176                 echo "E: doesn't use comedi_request_irq"
177         fi
178         if ! grep 'comedi_free_irq' ${driver} &>/dev/null;then
179                 echo "E: doesn't use comedi_free_irq"
180         fi
181 else
182         irq=no
183 fi
184 if grep SA_INTERRUPT ${driver} &>/dev/null;then
185         echo "E: uses SA_INTERRUPT"
186 fi
187
188 if grep 'request_region' ${driver} &>/dev/null;then
189         if ! grep 'release_region' ${driver} &>/dev/null;then
190                 echo "E: release_region() not called"
191         fi
192 fi
193
194 if grep 'pci_dev' ${driver} &>/dev/null;then
195         pci=yes
196         echo uses pci
197         if ! grep 'pci_get_\(device\|subsys\)' ${driver} &>/dev/null; then
198                 echo "W: doesn't use pci_get_device or pci_get_subsys"
199                 if grep 'pci_find_device' ${driver} &>/dev/null; then
200                         echo "W: recommend using pci_get_device instead of pci_find_device"
201                 fi
202                 if grep 'pci_find_subsys' ${driver} &>/dev/null; then
203                         echo "W: recommend using pci_get_subsys instead of pci_find_subsys"
204                 fi
205         else
206                 if ! grep 'pci_dev_put' ${driver} &>/dev/null; then
207                         echo "E: doesn't use pci_dev_put"
208                 fi
209         fi
210         if ! grep 'pci_enable_device' ${driver} &>/dev/null;then
211                 echo "W: doesn't use pci_enable_device"
212         else
213                 if ! grep 'pci_disable_device' ${driver} &>/dev/null; then
214                         echo "W: doesn't use pci_disable_device"
215                         echo "W: recommend calling pci_disable_device after pci_release_regions"
216                         echo "   if pci_enable_device and pci_request_regions succeeded"
217                 fi
218         fi
219         if ! grep 'pci_request_regions' ${driver} &>/dev/null; then
220                 echo "W: doesn't use pci_request_regions"
221         else
222                 if ! grep 'pci_release_regions' ${driver} &>/dev/null; then
223                         echo "E: doesn't use pci_release_regions"
224                 fi
225         fi
226         if ! grep 'MODULE_DEVICE_TABLE' ${driver} &>/dev/null;then
227                 echo "W: doesn't use MODULE_DEVICE_TABLE"
228         fi
229         if grep 'pcibios_' ${driver} &>/dev/null;then
230                 echo "W: has pcibios_*() calls"
231         fi
232 else
233         pci=no
234 fi
235
236 # Who doesn't use comments like this to indicate something needs
237 # to be fixed?
238 if [ "$check_all" = yes ]; then
239 if grep '\(XXX\)\|\(FIX\)' ${driver} &>/dev/null;then
240         echo "W: has FIXME-like comments"
241 fi
242 fi
243
244 # COMEDI_INITCLEANUP isn't strictly necessary, but it's a one-stop
245 # cleanup to get Comedi to compile as part of the kernel.  It is
246 # recommended to use it unless something else is necessary in module
247 # init.
248 if [ "$check_all" = yes ]; then
249 if grep 'int init_module' ${driver} &>/dev/null;then
250         echo "W: suggest using COMEDI_INITCLEANUP"
251 fi
252 fi
253
254 # range_unknown _should_ be used if the driver can't determine
255 # the I/O range.  However, it's commonly used as a marker where
256 # the author has not added more accurate range information.
257 if [ "$check_all" = yes ]; then
258 if grep 'range_unknown' ${driver} &>/dev/null;then
259         echo "W: uses range_unknown"
260 fi
261 fi
262
263 # cur_trig was removed around 0.7.56
264 if grep 'cur_trig' ${driver} &>/dev/null;then
265         echo "E: uses cur_trig"
266 fi
267
268 if grep -E 'cmd..?data' ${driver} &>/dev/null;then
269         echo "E: uses cmd->data or cmd->data_len"
270 fi
271
272 # buf_int_ptr is (void *), whereas the minimum sample size is
273 # 2 bytes.  Should be buf_int_ptr += sizeof(sampl_t)
274 if grep 'buf_int_ptr++' ${driver} &>/dev/null;then
275         echo "E: uses buf_int_ptr++"
276 fi
277
278 # same
279 if grep 'buf_int_count++' ${driver} &>/dev/null;then
280         echo "E: uses buf_int_count++"
281 fi
282
283 # remnants of trig[0]
284 if grep 'di_unpack' ${driver} &>/dev/null;then
285         echo "E: di_unpack() is gone"
286 fi
287
288 # remnants of trig[0]
289 if grep 'do_pack' ${driver} &>/dev/null;then
290         echo "E: do_pack() is gone"
291 fi
292
293 # This is a bug that causes difficulty to unload a driver.  Easy
294 # to fix.
295 if grep 'request_region.*dev *-> *iobase' ${driver} &>/dev/null;then
296         echo "W: recommend assigning dev->iobase after successful request_region()"
297 fi
298
299 # ds got it wrong in the first driver, and it was subsequently
300 # copied to others.  Use ||.
301 # Doesn't check everything.  Use check_cmdtest.
302 if grep 'if.*cmd.*&&.*err..;' ${driver} &>/dev/null;then
303         echo "E: Probable logic error in cmdtest"
304 fi
305
306 # Change in 0.7.59.  Drivers need to call subdev_8255_cleanup()
307 # so the 8255 code knows when to free it's private structures.
308 if grep 'subdev_8255_init' ${driver} &>/dev/null;then
309         if ! grep 'subdev_8255_cleanup' ${driver} &>/dev/null;then
310                 echo "E: doesn't call subdev_8255_cleanup()"
311         fi
312 fi
313
314 # Policy change in 0.7.60.  Drivers should use comedi_event(),
315 # which has a slightly different behavior.  Checks for use
316 # of comedi_done(), comedi_error_done(), comedi_bufcheck(),
317 # comedi_eos(), comedi_eobuf()
318 if grep 'comedi_\(\(done\)\|\(error_done\)\|\(bufcheck\)\|\(eos\)\|\(eobuf\)\)[[:space:]]*(' \
319         ${driver} &>/dev/null;then
320         echo "W: should be using comedi_event()"
321 fi
322
323 # Drivers should have documentation in Documentation/comedi/drivers.txt
324 if false; then
325 if grep "^Driver: ${basedriver}.o$" ../../Documentation/comedi/drivers.txt \
326     &>/dev/null;then
327         echo "entry in drivers.txt"
328 else
329         echo "E: not documented in drivers.txt"
330 fi
331 fi
332
333 # Drivers should have documentation in the source
334 if grep "^Driver: ${basedriver}.o$" $driver &>/dev/null;then
335         echo "documentation in source"
336         if grep "^Devices:" $driver &>/dev/null;then
337                 echo "has devices documentation"
338         else
339                 echo "E: documentation: no Devices:"
340         fi
341         if grep "^Author:" $driver &>/dev/null;then
342                 echo "has author documentation"
343         else
344                 echo "E: documentation: no Author:"
345         fi
346         if grep "^Status:" $driver &>/dev/null;then
347                 echo "has status documentation"
348         else
349                 echo "E: documentation: no Status:"
350         fi
351         if grep "^Updated:" $driver &>/dev/null;then
352                 echo "has updated documentation"
353         else
354                 echo "W: documentation: no Updated:"
355         fi
356         if grep "^Description:" $driver &>/dev/null;then
357                 echo "has description documentation"
358         else
359                 echo "E: documentation: no Description:"
360         fi
361 else
362         echo "E: not documented in source"
363 fi
364
365 # Check if the driver contains ^M
366 if grep '\r' ${driver} &>/dev/null;then
367         echo "E: driver has ^M characters"
368 fi
369
370 if [ -f "${basedriver}.o" ];then
371         # .o checks
372         n_syms=$(nm ${basedriver}.o |grep -c ' [TDC] ')
373         echo "number of global symbols: $n_syms"
374         n_xsyms=$(nm ${basedriver}.o |grep -c ' __ksymtab')
375         echo "number of exported symbols: $n_xsyms"
376         if [ $(($n_syms-$n_xsyms)) -gt $(($(grep -c 'MODULE_DEVICE_TABLE' ${basedriver}.c)+2)) ];then
377                 echo "W: driver leaks symbols"
378         fi
379 fi
380
381 # Check if the driver contains SDF_RT, which isn't used by the core
382 if grep '\r' ${driver} &>/dev/null;then
383         echo "E: driver uses SDF_RT"
384 fi
385
386 if [ $irq = yes ];then
387 if [ $pci = yes ];then
388         if ! grep SA_SHIRQ ${driver} &>/dev/null;then
389                 echo "E: PCI drivers need to use SA_SHIRQ"
390         fi
391 else
392         if grep SA_SHIRQ ${driver} &>/dev/null;then
393                 echo "E: non PCI device using SA_SHIRQ"
394         fi
395 fi
396 fi
397
398 if [ $pci = yes ];then
399         if ! grep pci_device_id ${driver} &>/dev/null;then
400                 echo "E: PCI drivers should have pci_device_id tables"
401         fi
402 fi
403
404 if grep 'insn->data' ${driver} &>/dev/null;then
405         echo "E: driver uses insn->data, which is a userspace pointer"
406 fi
407
408 if grep 'out[wlb] *([^(,]*iobase' ${driver} &>/dev/null; then
409         echo "E: misordered outX(dev->iobase + offset,XXX)"
410 fi
411
412 if grep 'write[wlb] *([^(,]*iobase' ${driver} &>/dev/null; then
413         echo "E: writeX(dev->iobase + offset,XXX)"
414 fi
415
416 if grep 'COMEDI_SUBD_AI' ${driver} &>/dev/null;then
417         if ! grep 'SDF_\(GROUND\|COMMON\|DIFF\|OTHER\)' ${driver} &>/dev/null;then
418                 echo "E: Driver doesn't set SDF flags for aref's it supports"
419         fi
420 fi
421
422 if grep -e 'include..linux.version.h' \
423         -e 'include..linux.config.h' \
424         -e 'include..linux.kdev_t.h' \
425         -e 'include..linux.slab.h' \
426         -e 'include..linux.errno.h' \
427         -e 'include..linux.spinlock.h' \
428         -e 'include..linux.wait.h' \
429         -e 'include..linux.mm.h' \
430         -e 'include..linux.init.h' \
431         -e 'include..linux.vmalloc.h' \
432         -e 'include..asm.uaccess.h' \
433         ${driver} &>/dev/null;then
434         echo "W: Driver #includes headers included by comedidev.h"
435 fi
436