#!/bin/bash # # This script shows some of the deficiencies in drivers. Some # of the things that are tested here are only suggestions, and # don't necessarily apply to every driver. # check_all=no if [ "$1" ];then driver=$1 else echo 'check_driver ' exit 1 fi echo "I: ${driver}:" basedriver=$(basename ${driver} .c) # special cases case ${driver} in ni_pcimio.c) driver="${driver} ni_mio_common.c mite.c" ;; ni_atmio.c) driver="${driver} ni_mio_common.c mite.c" ;; ni_mio_cs.c) driver="${driver} ni_mio_common.c mite.c" ;; esac # check to see if it is a driver if grep '^\(static \)*comedi_driver' ${driver} &>/dev/null;then echo "appears to be a driver" else echo "not a driver file" exit 1 fi if ! grep '[[:space:]]\+module:[[:space:]]*THIS_MODULE' ${driver} &>/dev/null;then echo "E: doesn't set driver->module to THIS_MODULE" fi # check Makefile.am for the driver if ! grep "${basedriver}\.ko" Makefile.am &>/dev/null; then echo "E: ${basedriver}.ko missing from module_PROGRAMS in Makefile.am" fi if ! grep "${basedriver}_ko_SOURCES" Makefile.am &>/dev/null; then echo "E: ${basedriver}_ko_SOURCES line missing from Makefile.am" fi # check Kbuild for the driver if ! grep "obj-.*+=.*${basedriver}\.o" Kbuild &>/dev/null; then echo "E: driver missing from Kbuild" fi # check to see if it uses name recognition if grep 'board_name:' ${driver} &>/dev/null;then echo uses recognize to determine type probe=recognize else if grep 'dev..board_ptr' ${driver} &>/dev/null;then echo auto-probes type of board probe=auto else echo only supports one type of board probe=one fi fi # auto checks if [ "$probe" = auto ];then if grep 'dev..board_ptr[[:space:]]*=' ${driver} &>/dev/null;then echo 'sets dev->board_ptr' else echo "E: doesn't set dev->board_ptr" fi fi # recognize checks if [ "$probe" = recognize ];then if ! grep '[[:space:]]\+offset:[[:space:]]*sizeof' ${driver} &>/dev/null;then echo "E: doesn't set driver->offset" fi if ! grep '[[:space:]]\+num_names:[[:space:]]' ${driver} &>/dev/null;then echo "E: doesn't set driver->num_names" fi fi # I would prefer that drivers have a consistent number of subdevices # independent of the particular board type. If a subdevice is not # relevant for a board type, the type should be set to COMEDI_SUBD_UNUSED. # However, for drivers that handle N identical subdevices, it's better # to have a variable number of subdevices. tmp=$(cat ${driver}|grep -c 'dev..n_subdevices[[:space:]]*=' 2>/dev/null) if [ "$tmp" = 0 ];then echo "doesn't set n_subdevices (good)" else echo "W: sets n_subdevices multiple ($tmp) times" fi if grep 'dev..n_subdevices[[:space:]]*=[[:space:]]*[^[:digit:][:space:]]' ${driver} &>/dev/null;then echo "W: sets n_subdevices by variable" fi # Check to see if board_name is set if grep 'dev..board_name[[:space:]]*=' ${driver} &>/dev/null;then echo "board_name is set" else echo "E: board_name not set" fi # Do we use trig? trig[0] has been eliminated if [ "$check_all" = yes ]; then if grep 'trig\[0\]' ${driver} &>/dev/null;then echo "E: uses trig[0]" else echo "doesn't use trig[0]" fi fi # trig[1234] has been eliminated if [ "$check_all" = yes ]; then if grep 'trig\[[1234]\]' ${driver} &>/dev/null;then echo "E: uses trig[1234]" trig1234=yes else echo "doesn't use trig[1234]" trig1234=no fi fi if grep 'comedi_cmd' ${driver} &>/dev/null;then echo "uses cmd" cmd=yes else if [ "$trig1234" == yes ];then echo "E: doesn't use cmd" else echo "doesn't use cmd" fi cmd=no fi if grep 'comedi_insn' ${driver} &>/dev/null;then echo "uses insn" insn=yes else if grep 'subdev_8255_init' ${driver} &>/dev/null;then echo uses subdev_8255_init else echo "E: doesn't use insn" fi insn=no fi # rt_printk() only needs to be used in possible real-time code paths, # which is basically everything except *_attach() and *_detach(). # However, since it works correctly in non-real-time code, just use # it everywhere. if [ "$check_all" = yes ]; then if grep 'printk' ${driver} &>/dev/null;then if ! grep 'rt_printk' ${driver} &>/dev/null;then echo "W: doesn't use rt_printk" fi fi fi # comedi_request_irq() handles real-time interrupts. if grep request_irq ${driver} &>/dev/null;then irq=yes if ! grep 'comedi_request_irq' ${driver} &>/dev/null;then echo "E: doesn't use comedi_request_irq" fi if ! grep 'comedi_free_irq' ${driver} &>/dev/null;then echo "E: doesn't use comedi_free_irq" fi else irq=no fi if grep SA_INTERRUPT ${driver} &>/dev/null;then echo "E: uses SA_INTERRUPT" fi if grep 'request_region' ${driver} &>/dev/null;then if ! grep 'release_region' ${driver} &>/dev/null;then echo "E: release_region() not called" fi fi if grep 'pci_dev' ${driver} &>/dev/null;then pci=yes echo uses pci if ! grep 'pci_get_\(device\|subsys\)' ${driver} &>/dev/null; then echo "W: doesn't use pci_get_device or pci_get_subsys" if grep 'pci_find_device' ${driver} &>/dev/null; then echo "W: recommend using pci_get_device instead of pci_find_device" fi if grep 'pci_find_subsys' ${driver} &>/dev/null; then echo "W: recommend using pci_get_subsys instead of pci_find_subsys" fi else if ! grep 'pci_dev_put' ${driver} &>/dev/null; then echo "E: doesn't use pci_dev_put" fi fi if ! grep 'pci_enable_device' ${driver} &>/dev/null;then echo "W: doesn't use pci_enable_device" else if ! grep 'pci_disable_device' ${driver} &>/dev/null; then echo "W: doesn't use pci_disable_device" echo "W: recommend calling pci_disable_device after pci_release_regions" echo " if pci_enable_device and pci_request_regions succeeded" fi fi if ! grep 'pci_request_regions' ${driver} &>/dev/null; then echo "W: doesn't use pci_request_regions" else if ! grep 'pci_release_regions' ${driver} &>/dev/null; then echo "E: doesn't use pci_release_regions" fi fi if ! grep 'MODULE_DEVICE_TABLE' ${driver} &>/dev/null;then echo "W: doesn't use MODULE_DEVICE_TABLE" fi if grep 'pcibios_' ${driver} &>/dev/null;then echo "W: has pcibios_*() calls" fi else pci=no fi # Who doesn't use comments like this to indicate something needs # to be fixed? if [ "$check_all" = yes ]; then if grep '\(XXX\)\|\(FIX\)' ${driver} &>/dev/null;then echo "W: has FIXME-like comments" fi fi # COMEDI_INITCLEANUP isn't strictly necessary, but it's a one-stop # cleanup to get Comedi to compile as part of the kernel. It is # recommended to use it unless something else is necessary in module # init. if [ "$check_all" = yes ]; then if grep 'int init_module' ${driver} &>/dev/null;then echo "W: suggest using COMEDI_INITCLEANUP" fi fi # range_unknown _should_ be used if the driver can't determine # the I/O range. However, it's commonly used as a marker where # the author has not added more accurate range information. if [ "$check_all" = yes ]; then if grep 'range_unknown' ${driver} &>/dev/null;then echo "W: uses range_unknown" fi fi # cur_trig was removed around 0.7.56 if grep 'cur_trig' ${driver} &>/dev/null;then echo "E: uses cur_trig" fi if grep -E 'cmd..?data' ${driver} &>/dev/null;then echo "E: uses cmd->data or cmd->data_len" fi # buf_int_ptr is (void *), whereas the minimum sample size is # 2 bytes. Should be buf_int_ptr += sizeof(sampl_t) if grep 'buf_int_ptr++' ${driver} &>/dev/null;then echo "E: uses buf_int_ptr++" fi # same if grep 'buf_int_count++' ${driver} &>/dev/null;then echo "E: uses buf_int_count++" fi # remnants of trig[0] if grep 'di_unpack' ${driver} &>/dev/null;then echo "E: di_unpack() is gone" fi # remnants of trig[0] if grep 'do_pack' ${driver} &>/dev/null;then echo "E: do_pack() is gone" fi # This is a bug that causes difficulty to unload a driver. Easy # to fix. if grep 'request_region.*dev *-> *iobase' ${driver} &>/dev/null;then echo "W: recommend assigning dev->iobase after successful request_region()" fi # ds got it wrong in the first driver, and it was subsequently # copied to others. Use ||. # Doesn't check everything. Use check_cmdtest. if grep 'if.*cmd.*&&.*err..;' ${driver} &>/dev/null;then echo "E: Probable logic error in cmdtest" fi # Change in 0.7.59. Drivers need to call subdev_8255_cleanup() # so the 8255 code knows when to free it's private structures. if grep 'subdev_8255_init' ${driver} &>/dev/null;then if ! grep 'subdev_8255_cleanup' ${driver} &>/dev/null;then echo "E: doesn't call subdev_8255_cleanup()" fi fi # Policy change in 0.7.60. Drivers should use comedi_event(), # which has a slightly different behavior. Checks for use # of comedi_done(), comedi_error_done(), comedi_bufcheck(), # comedi_eos(), comedi_eobuf() if grep 'comedi_\(\(done\)\|\(error_done\)\|\(bufcheck\)\|\(eos\)\|\(eobuf\)\)[[:space:]]*(' \ ${driver} &>/dev/null;then echo "W: should be using comedi_event()" fi # Drivers should have documentation in Documentation/comedi/drivers.txt if false; then if grep "^Driver: ${basedriver}.o$" ../../Documentation/comedi/drivers.txt \ &>/dev/null;then echo "entry in drivers.txt" else echo "E: not documented in drivers.txt" fi fi # Drivers should have documentation in the source if grep "^Driver: ${basedriver}.o$" $driver &>/dev/null;then echo "documentation in source" if grep "^Devices:" $driver &>/dev/null;then echo "has devices documentation" else echo "E: documentation: no Devices:" fi if grep "^Author:" $driver &>/dev/null;then echo "has author documentation" else echo "E: documentation: no Author:" fi if grep "^Status:" $driver &>/dev/null;then echo "has status documentation" else echo "E: documentation: no Status:" fi if grep "^Updated:" $driver &>/dev/null;then echo "has updated documentation" else echo "W: documentation: no Updated:" fi if grep "^Description:" $driver &>/dev/null;then echo "has description documentation" else echo "E: documentation: no Description:" fi else echo "E: not documented in source" fi # Check if the driver contains ^M if grep ' ' ${driver} &>/dev/null;then echo "E: driver has ^M characters" fi if [ -f "${basedriver}.o" ];then # .o checks n_syms=$(nm ${basedriver}.o |grep -c ' [TDC] ') echo "number of global symbols: $n_syms" n_xsyms=$(nm ${basedriver}.o |grep -c ' __ksymtab') echo "number of exported symbols: $n_xsyms" if [ $(($n_syms-$n_xsyms)) -gt $(($(grep -c 'MODULE_DEVICE_TABLE' ${basedriver}.c)+2)) ];then echo "W: driver leaks symbols" fi fi # Check if the driver contains SDF_RT, which isn't used by the core if grep ' ' ${driver} &>/dev/null;then echo "E: driver uses SDF_RT" fi if [ $irq = yes ];then if [ $pci = yes ];then if ! grep SA_SHIRQ ${driver} &>/dev/null;then echo "E: PCI drivers need to use SA_SHIRQ" fi else if grep SA_SHIRQ ${driver} &>/dev/null;then echo "E: non PCI device using SA_SHIRQ" fi fi fi if [ $pci = yes ];then if ! grep pci_device_id ${driver} &>/dev/null;then echo "E: PCI drivers should have pci_device_id tables" fi fi if grep 'insn->data' ${driver} &>/dev/null;then echo "E: driver uses insn->data, which is a userspace pointer" fi if grep 'out[wlb] *([^(,]*iobase' ${driver} &>/dev/null; then echo "E: misordered outX(dev->iobase + offset,XXX)" fi if grep 'write[wlb] *([^(,]*iobase' ${driver} &>/dev/null; then echo "E: writeX(dev->iobase + offset,XXX)" fi if grep 'COMEDI_SUBD_AI' ${driver} &>/dev/null;then if ! grep 'SDF_\(GROUND\|COMMON\|DIFF\|OTHER\)' ${driver} &>/dev/null;then echo "E: Driver doesn't set SDF flags for aref's it supports" fi fi if grep -e 'include..linux.version.h' \ -e 'include..linux.config.h' \ -e 'include..linux.kdev_t.h' \ -e 'include..linux.slab.h' \ -e 'include..linux.errno.h' \ -e 'include..linux.spinlock.h' \ -e 'include..linux.wait.h' \ -e 'include..linux.mm.h' \ -e 'include..linux.init.h' \ -e 'include..linux.vmalloc.h' \ -e 'include..asm.uaccess.h' \ ${driver} &>/dev/null;then echo "W: Driver #includes headers included by comedidev.h" fi