I am using a proprietary PCI card from Sensoray in my Ubunut 14.04 machine (I intend to upgrade to 18.04 soon). The card comes with the source code for the driver and a Makefile to build and install the driver. The portion of the Makefile relevant to the driver is here:

# for kernel modeule level driver:

# Kernel directory
KDIR        := /lib/modules/$(shell uname -r)/build
# Module directory
MODDIR      := /lib/modules/$(shell uname -r)/kernel/drivers/sensoray

# System values
PWD     := $(shell pwd)
KERNEL_24   := $(if $(wildcard $(KDIR)/Rules.make),1,0)

# Target file
obj-m       := s626.o

# Source files
ifeq    ($(KERNEL_24),0) # > 2.4
s626-objs   := s626drv.o 
else # <= 2.4
s626-objs   := s626drv.o

.PHONY:     all clean modules_install

ifeq    ($(KERNEL_24),0) # > 2.4
ifeq    ($(KERNELRELEASE),)
        $(MAKE) -C $(KDIR) M=$(PWD) SUBDIRS=$(PWD)
clean modules_install:
        $(MAKE) -C $(KDIR) M=$(PWD) SUBDIRS=$(PWD) $@

else    # <= 2.4

ifneq   ($(KERNELRELEASE),)

include $(KDIR)/Rules.make

s626.o: $(s626-objs)
        $(Q)$(LD) $(LD_RFLAG) -r -o $@ $(s626-objs)

        $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
        rm -f *.ko *.o .*.cmd .*.o.flags *.mod.c


endif   # KERNEL_24

ifeq    ($(KERNEL_24),1) # <= 2.4

install:        s626.o
    @if [ -d /lib/modules/$(shell uname -r)/kernel/drivers/sensoray/ ];\
    then rm -f /lib/modules/$(shell uname -r)/kernel/drivers/sensoray/s626.*;\
    @if [ -d /lib/modules/$(shell uname -r)/extra/ ];\
    then rm -f /lib/modules/$(shell uname -r)/extra/s626.*;\
    su -c "set -x;./MAKEDEV;mkdir -p $(MODDIR);cp -v s626.o $(MODDIR);depmod -a"

install:        s626.ko
    @if [ -d /lib/modules/$(shell uname -r)/kernel/drivers/sensoray/ ];\
    then rm -f /lib/modules/$(shell uname -r)/kernel/drivers/sensoray/s626.*; \
    @if [ -d /lib/modules/$(shell uname -r)/extra/ ];\
    then rm -f /lib/modules/$(shell uname -r)/extra/s626.*;\
    @if [ -d /lib/modules/$(shell uname -r)/kernel/drivers/staging/comedi/drivers ];\
    then rm -f /lib/modules/$(shell uname -r)/kernel/drivers/staging/comedi/drivers/s626.*;\
    su -c "set -x;./MAKEDEV;mkdir -p $(MODDIR);cp -v s626.ko $(MODDIR);install -m 444 s626.ko $(MODDIR);depmod -a"
endif  # KERNEL > 2.4

At the end of the Makefile, it looks like once the .ko file has been created, it is simply being copied to the /lib/modules/$(shell uname -r)/kernel/drivers/sensoray directory. There is a custom MAKEDEV shell script as well that is being executed to create the device files. That script is given here:


function makedev () {

    for dev in 0 1 2 3; do
        echo "/dev/$1$dev: char $2 $dev"
        rm -f /dev/$1$dev
        mknod /dev/$1$dev c $2 $dev
        chmod 666 /dev/$1$dev

    # symlink for default device
    rm -f /dev/$1
    ln -s /dev/${1}0 /dev/$1

makedev s626a 146

The problem is that whenever the system reboots. It looks like the driver gets loaded correctly, but the device files in /dev disappear. I don't know much about driver development, but I have researched this issue a lot and I've found conflicting information on how to get these device files to be created at boot time. Some say that creating a udev rule is best, others say that udev rules should not be used to create missing device files or that udev isn't in charge of device file creation anymore referencing a new devtempfs. My question is: What is the correct way to fix this issue? I have tried the udev rule approach in which I essentially call the custom MAKEDEV script from Sensoray, but this only works if my rule does not reference any specific property of the pci card. For example, the following rule works:

ACTION=="add", SUBSYSTEM=="pci", RUN+="/home/kpopek/MAKEDEV"

This rule does not

ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x1131", RUN+="/home/kpopek/MAKEDEV"

There doesn't seem to be any uevent at boot time matching the Sensoray pci card, which may be the root of the reason there are missing device files. I have not figured out how to log the uevents at boot time to verify this. If udev rules are the right approach, I really would want a rule that is specific to the card and not a generic rule that happens to run the script due to a uevent from another device.


It very much looks like the custom driver does not generate the needed udev events (one would have to look at the driver to confirm this).

So the proper way would be to fix the driver to generate the events. In the simplest case, you'd have code similar to this. In a more complicated case, you can have additional udev rules that do more complicated things.

If you can't or don't want to modify the kernel module, IMHO any kind of solution that works is permissable. Ideally you'd want to have a dependency that creates the device when the module is loaded, and removes it when it is unloaded, but you need udev events for that (see above). So the next best thing is to create it at boot time, which means I'd simple add a init.d or systemd script.

If you can hijack an existing udev event for your hardware, that would be also fine, but it looks like you already tried and didn't find one.

  • So is the current standard way for the driver to create the files, or for the driver to generate uevents that create the files. For example: is it kernel recognizes device, kernel sends uevent, udev loads module in response to uevent, module init function creates device files. Or is it kernel recognizes device, kernel sends uevent, udev loads module in response to uevent, module init function triggers another uevent (through the kernel), udev creates device files in response to second uevent? – Adam Sperry Oct 29 '18 at 22:34
  • I've read in many places that udev is not in charge of loading modules or creating device files anymore, but rather it's just in charge of convenience things like consistently named symlinks and such. – Adam Sperry Oct 29 '18 at 22:38
  • 1
    Close: Kernel recognizes a device, kernel looks for matching module (use modinfo to see the patterns embedded in the modules used for recognition; most use vendor and device id), kernel loads module, module creates devices and/or sends uevents, module sends additional uevents if the device has subdevices (harddisks attached to ATA etc.). Udev never was in charge of loading modules, AFAIK. – dirkt Oct 30 '18 at 7:00
  • 1
    However, if the module creates a device, it calls a kernel function, and AFAIK, this function eventually calls udev in a generic way, which creates the base device. So udev is involved in the creation of base devices. However, yes, nearly all udev rules (and that's when you need to touch udev) are for consistently named symlinks, looking up configuration details in hwdb, running programs to further identify device contents etc. So what you read "in many places" is correct. – dirkt Oct 30 '18 at 7:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.