LinuxDevCenter.com

oreilly.comSafari Books Online.Conferences.

We've expanded our Linux news coverage and improved our search! Search for all things Linux across O'Reilly!

Search
Search Tips

advertisement

Listen Print Discuss Subscribe to Linux Subscribe to Newsletters

/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.


Have you ever been tempted to try writing a device driver? Would you give it a go after reading this article?
You must be logged in to the O'Reilly Network to post a talkback.
Post Comment
Full Threads Oldest First

Showing messages 1 through 8 of 8.

  • Too many < on page 2.
    2009-04-08 16:56:39  jsnx [Reply | View]

    The code on page 2 has a number of spurious XML tag delimiters in it. The linked files are fine, though.

    I don't use C very often and had to ask myself, is </ a C operator?
  • Error during insmod hello_proc
    2007-11-30 04:03:54  georgeneil [Reply | View]

    Hello,
    When i try to insmod hello_proc the following error occurs

    [root@localhost hello_dev]# ls
    hello_dev.c hello.rules Makefile

    [root@localhost hello_dev]# make
    make -C /lib/modules/2.6.21-1.3194.fc7/build M=/root/Download/hello_dev modules
    make[1]: Entering directory `/usr/src/kernels/2.6.23.1-21.fc7-i686'
    CC [M] /root/Download/hello_dev/hello_dev.o
    Building modules, stage 2.
    MODPOST 1 modules
    CC /root/Download/hello_dev/hello_dev.mod.o
    LD [M] /root/Download/hello_dev/hello_dev.ko
    make[1]: Leaving directory `/usr/src/kernels/2.6.23.1-21.fc7-i686'

    [root@localhost hello_dev]# ls
    hello_dev.c hello_dev.ko hello_dev.mod.c hello_dev.mod.o hello_dev.o hello.rules Makefile Module.symvers

    [root@localhost hello_dev]# insmod ./hello_dev.ko
    insmod: error inserting './hello_dev.ko': -1 Unknown symbol in module

    what may be the problems...??
  • Small problem in hello_proc.c?
    2007-07-08 06:12:15  stderr.dk [Reply | View]

    I think there is a small problem in hello_proc.c.

    First you check whether "size" is small then "len" and if so, return -EINVAL.

    If not (and offset==0), you do strcpy(buffer, hello_str); but strcpy() will copy strlen(hello_str) + 1 bytes (since it also copy a '\0' to "buffer").

    If size==len, the buffer only has enough space for "len" bytes, but you're copying "len"+1 bytes.

    Shouldn't it be something like

    if(size <= len)
    return -EINVAL;

    ?
    • Small problem in hello_proc.c?
      2007-07-08 11:47:27  valhenson [Reply | View]

      Yes, you are correct that we are copying one more byte to the buffer than we are testing for. Thanks for catching the bug! In practice, this isn't a problem because the kernel always allocates a full page to pass to the /proc read function. The solution isn't to test for a larger buffer, though - we don't want to copy the null terminating byte to userspace. Instead, we'll use strncpy to avoid copying the terminating byte.


      /*
      * We know the buffer is big enough to hold the string. Don't
      * copy the terminating '\0' - this is file output, not
      * another C string.
      */
      strncpy(buffer, hello_str, len);

  • Thanks
    2007-07-07 10:39:06  bartvan deenen [Reply | View]

    Just wat I needed! Excellent article, examples worked perfectly in Kubuntu/Feisty
  • When insmod ./hello_world.ko, I receive "Segmentation Fault"
    2007-07-06 13:10:35  mvd [Reply | View]

    I'm using debian testing with kernel 2.6.18-4-686. I ran make in the printk version directory of the module. Here is the output:

    make -C /lib/modules/2.6.18-4-686/build M=/home/joneill/downloads/hello_printk modules
    make[1]: Entering directory `/usr/src/linux-headers-2.6.18-4-686'
    CC [M] /home/joneill/downloads/hello_printk/hello_printk.o
    Building modules, stage 2.
    MODPOST
    CC /home/joneill/downloads/hello_printk/hello_printk.mod.o
    LD [M] /home/joneill/downloads/hello_printk/hello_printk.ko
    make[1]: Leaving directory `/usr/src/linux-headers-2.6.18-4-686'

    Then when running the command as root: insmod ./hello_printk.ko

    I get the following error:

    Segmentation fault

    and the module does not load or print to dmesg.
    • When insmod ./hello_world.ko, I receive "Segmentation Fault"
      2007-07-06 13:44:19  valhenson [Reply | View]

      This most likely means that there is a mismatch between one of the following:

      * Your module utilities
      * Your running kernel
      * The kernel you compiled against

      Check the versions with

      $ insmod --version
      $ uname -r
      $ grep "o module-init-tools" /lib/modules/`uname -r`/build/Documentation/Changes

      -VAL
  • No mention of the freely available LDD3 online?
    2007-07-06 13:08:27  EdLolington [Reply | View]

    Seems like quite an oversight, especially since it is published by ORA themselves. (though perhaps that is why...)

    http://lwn.net/Kernel/LDD3/


Tagged Articles

Be the first to post this article to del.icio.us

Sponsored Resources

  • Inside Lightroom
Advertisement

Sponsored by:

O'Reilly Media

©2009, O'Reilly Media, Inc.
(707) 827-7000 / (800) 998-9938
All trademarks and registered trademarks appearing on oreilly.com are the property of their respective owners.
About O'Reilly
Academic Solutions
Authors
Contacts
Customer Service
Jobs
Newsletters
O'Reilly Labs
Press Room
Privacy Policy
RSS Feeds
Terms of Service
User Groups
Writing for O'Reilly
Content Archive
Business Technology
Computer Technology
Google
Microsoft
Mobile
Network
Operating System
Digital Photography
Programming
Software
Web
Web Design
More O'Reilly Sites
O'Reilly Radar
Ignite
Tools of Change for Publishing
Digital Media
Inside iPhone
O'Reilly FYI
makezine.com
craftzine.com
hackszine.com
perl.com
xml.com

Partner Sites
InsideRIA
java.net
O'Reilly Insights on Forbes.com