LinuxDevCenter.com
oreilly.comSafari Books Online.Conferences.

advertisement


/dev/hello_world: A Simple Introduction to Device Drivers under Linux
Pages: 1, 2, 3

Next, we create the file operations struct defining what actions to take when the file is accessed. The only file operation we care about is read.



static const struct file_operations hello_fops = {
        .owner                = THIS_MODULE,
        .read                = hello_read,
};

Now, create the structure containing the information needed to register a miscellaneous device with the kernel.

static struct miscdevice hello_dev = {
        /*
         * We don't care what minor number we end up with, so tell the
         * kernel to just pick one.
         */
        MISC_DYNAMIC_MINOR,
        /*
         * Name ourselves /dev/hello.
         */
        "hello",
        /*
         * What functions to call when a program performs file
         * operations on the device.
         */
        &hello_fops
};

As usual, we register the device in the module's initialization function.

static int __init
hello_init(void)
{
        int ret;

        /*
         * Create the "hello" device in the /sys/class/misc directory.
         * Udev will automatically create the /dev/hello device using
         * the default rules.
         */
        ret = misc_register(&hello_dev);
        if (ret)
                printk(KERN_ERR
                       "Unable to register \"Hello, world!\" misc device\n");

        return ret;
}

module_init(hello_init);

And remember to unregister the device in the exit function.

static void __exit
hello_exit(void)
{
        misc_deregister(&hello_dev);
}

module_exit(hello_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Valerie Henson <val@nmt.edu>");
MODULE_DESCRIPTION("\"Hello, world!\" minimal module");
MODULE_VERSION("dev");

Compile and load the module:

$ cd hello_dev
$ make
$ sudo insmod ./hello_dev.ko

Now there is a device named /dev/hello that will produce "Hello, world!" when read by root:

$ sudo cat /dev/hello
Hello, world!

But we can't read it as a regular user:

$ cat /dev/hello
cat: /dev/hello: Permission denied
$ ls -l /dev/hello
crw-rw---- 1 root root 10, 61 2007-06-20 14:31 /dev/hello

This is what happens with the default udev rule, which says that when a miscellaneous device appears, create a file named /dev/<device name> and give it permissions 0660 (owner and group have read-write access, everyone else has no access). We would really like instead for the device be readable by regular users and have a link to it named /dev/hello_world. In order to do this, we'll write a udev rule.

The udev rule has to do two things: create a symbolic link and change the permissions on device to make world readable. The rule that accomplishes this is:

KERNEL=="hello", SYMLINK+="hello_world", MODE="0444"

We'll break the rule down into parts and explain each part.

KERNEL=="hello" says to execute the rest of the rule when a device with a name the same as this string (the == operator means "comparison") appears in /sys. The hello device appeared when we called misc_register() with a structure containing the device name "hello". See the result for yourself in /sys:

$ ls -d /sys/class/misc/hello/
/sys/class/misc/hello/

SYMLINK+="hello_world" says to add (the += operator means append) hello_world to the list of symbolic links that should be created when the device appears. In our case, we know this is the only symbolic link in the list, but other devices may have multiple udev rules that create multiple different symbolic links, so it is good practice add to the list instead of assigning to it.

MODE="0444" says to set the permissions of the original device file to the 0444 mode, which allows owner, group, and world all to read the file.

In general, it is very important to use the correct operator (==, +=, or =), or unexpected things will happen.

Now that we understand what the rule does, let's install it in the /etc/udev directory. Udev rules files are arranged in much the same manner as the System V init scripts in /etc/init.d/. Udev executes every script the udev rules directory, /etc/udev/rules.d, in alphabetical/numerical order. Like System V init scripts, the files in the /etc/udev/rules.d directory are usually symbolic links to the real rules files, with the symbolic links named so that the rules will be executed in the correct order.

Copy the hello.rules file from the hello_dev directory into the /etc/udev/ directory and create a link to it that will be executed before any other rules file:

$ sudo cp hello.rules /etc/udev/
$ sudo ln -s ../hello.rules /etc/udev/rules.d/010_hello.rules

Now, reload the hello world driver and look at the new /dev entries:

$ sudo rmmod hello_dev
$ sudo insmod ./hello_dev.ko
$ ls -l /dev/hello*
cr--r--r-- 1 root root 10, 61 2007-06-19 21:21 /dev/hello
lrwxrwxrwx 1 root root      5 2007-06-19 21:21 /dev/hello_world -> hello

Now we have /dev/hello_world! Finally, check that you can read the "Hello, world!" devices as a normal user:

$ cat /dev/hello_world
Hello, world!
$ cat /dev/hello
Hello, world!

For more details on writing udev rules, see Writing udev rules, by Daniel Drake.

Valerie Henson is a Linux consultant specializing in file systems, and maintainer of the TCP/IP Drinking Game.


Return to LinuxDevCenter.com.


Linux Online Certification

Linux/Unix System Administration Certificate Series
Linux/Unix System Administration Certificate Series — This course series targets both beginning and intermediate Linux/Unix users who want to acquire advanced system administration skills, and to back those skills up with a Certificate from the University of Illinois Office of Continuing Education.

Enroll today!


Linux Resources
  • Linux Online
  • The Linux FAQ
  • linux.java.net
  • Linux Kernel Archives
  • Kernel Traffic
  • DistroWatch.com


  • Sponsored by: