[ Curiosity,Experimentation ]

Random stuff from the parallel universe of Ones and Zeroes

Writing a Linux character Device Driver

Posted by appusajeev on June 18, 2011


In this post, we would be writing a Linux device driver for a hypothetical character device which reverses any string that is given to it. i.e.  If we write any string to the device file represented by the device and then read that file, we get the string written earlier but reversed (for eg.,  myDev being our device, echo “hello” >/dev/myDev ; cat /dev/ myDev would print “olleh”).
We will be simulating the functionality of the device in the driver itself (and this is precisely what is done in emulation tools like Daemon Tools, Alcohol etc).

Download Code

We will be dealing with

  • Introduction and some basics
  • Creating a device file
  • The driver code
  • Compiling the driver
  • Loading and unloading the driver
  • Testing the driver

The post helps understand how to write a device driver, the significance of a device file and its role in the interaction between a user program and device driver.

Introduction

The devices in UNIX fall in two categories- Character devices and Block devices. Character devices can be compared to normal files in that we can read/write arbitrary bytes at a time (although for most part, seeking is not supported).They work with a stream of bytes. Block devices, on the other hand, operate on blocks of data, not arbitrary bytes. Usual block size is 512 bytes or larger powers of two. However, block devices can be accessed the same was as character devices, the driver does the block management. (Networking devices do not belong to these categories, the interface provided by these drivers in entirely different from that of char/block devices)

The beauty of UNIX is that devices are represented as files. Both character devices and block devices are represented by respective files in the /dev directory. This means that you can read and write into the device by manipulating those file using standard system calls like open, read, write, close etc.
For eg, you could directly write or read the hard disk by accessing /dev/sd* file – a dangerous act unless you know what you are doing (for those interested, try hexdump  –C  /dev/sda   –n  512 – what you see then is the boot sector of your hard disk !). As another example, you could directly see the contents of the RAM by reading /dev/mem.

Every device file represented in this manner is associated with the device driver of that device which is actually responsible for interacting with the device on behalf of the user request. So when you access a device file, the request is forwarded to the respective device driver which does the processing and returns the result.

For instance, you might be knowing about the files /dev/zero (an infinite source of zeroes), /dev/null (a data black hole), /dev/random ( a source of random numbers) etc. When you actually read these files, what happens is that a particular function in the device driver registered for the file is invoked which returns the respective data.

In our example, we will be developing a character device represented by the device file /dev/myDev.  The mechanisms for creating this file will be explained later.

Under the hood

Now how does Linux know which driver is associated with which file? For that, each device and its device file has associated with it, a unique Major number and a Minor number. No two devices have the same major number.  When a device file is opened, Linux examines its major number and forwards the call to the driver registered for that device.  Subsequent calls for read/write/close too are processed by the same driver. As far as kernel is concerned, only major number is important. Minor number is used to identify the specific device instance if the driver controls more than one device of a type.

To know the major, minor number of devices, use the ls – l command as shown below.

ls -l

ls -l

The starting ‘c’  means its a character device, 1 is the major number and 8 is the minor number.

A Linux driver is a Linux module which can be loaded and linked to the kernel at runtime. The driver operates in kernel space and becomes part of the kernel once loaded, the kernel being monolithic. It can then access the symbols exported by the kernel.

When the device driver module is loaded, the driver first registers itself as a driver for a particular device specifying a particular Major number.

It uses the call register_chrdev function for registration. The call takes the Major number, Minor number, device name and an address of a structure of the type file_operations(discussed later) as argument. In our example, we will be using a major number of 89 . The choice of major number is arbitrary but it has to be unique on the system.

The syntax of register_chrdev is

int register_chrdev(unsigned int major,const char *name,struct file_operations *fops)

Driver is unregistered by calling the unregister_chrdev function.

Since device driver is a kernel module, it should implement init_module and cleanup_module functions. The register_chrdev call is done in the init_module function  and unregister_chrdev call is done in the cleanup_module function.

The register_chrdev call returns a non-negative number on success. If we specify the Major number as 0, the kernel returns a Major number unique at that instant which can be used to create a device file.
A device file can be created either before the driver is loaded if we know the major and minor number beforehand or it can be created later after letting the driver specify a major number for us.

Apart from those, the driver must also define certain callback functions that would be invoked when file operations are done on the device file. Ie. It must define functions that would be invoked by the kernel when a process uses open, read, write, close system calls on the file. Every driver must implement functions for processing these requests.
When register_chrdev call is done, the fourth argument is a structure that contains the addresses of these callback functions, callbacks for open, read, write, close system calls. The structure is of the type file_operations and has 4 main fields that should be set  – read,write,open and release. Each field must be assigned an address of a function that would be called when open, read,write , close system calls are called respectively.  For eg

file_operations structure initialisation

file_operations structure initialisation

It is important to note that all these callback functions have a predefined prototype although the name can be any.

Creating a device file

A device file is a special file. It can’t just be created using cat or gedit or shell redirection for that matter. The shell command mknod is usually used to create device file. The syntax of mknod is

mknod path type major minor

path:-path where the file to be created. It’s not necessary that the device file needs to be created in the /dev directory. It’s a mere convention. A device file can be created just about anywhere.

type: -‘c’ or ‘b’ . Whether the device being represented is a character device or a block device. In our example, we will be simulating a character device and hence we choose ‘c’.

major, minor:- the major and minor number of the device.

Heres how

mknod command

mknod command

chmod, though not necessary is done because, if not done, only processes will root permission can read or write to our device file.

The driver code

Given below is the code of the device driver

 Download Code

Device Driver Code

Device Driver Code

For debugging, I have included some printk messages in the code. To see those messages while the driver is in action, do dmesg|tail

Compiling the driver

A Linux module cannot just be compiled the way we compile normal C files.  cc filename.c won’t work. Compiling a Linux module is a separate process by its own. We use the help of kernel Makefile for compilation. The makefile we will be using is.

makefile for module compilation

makefile for module compilation

Here, we are making use of the kbuild mechanism used for compiling the kernel.
The result of compilation is a ko file (kernel object) which can then be loaded dynamically when required.

Loading and Unloading the Driver

Once the compilation is complete, we can use either insmod or modprobe command ( insmod myDev.ko  or modprobe myDev.ko, of course assuming the current directory contains the compiled module). The difference between insmod and modprobe is that modprobe automatically reads our module to find any dependencies on other modules and loads them before loading our module (these modules must be present in the standard path though!). insmod lacks this feature.

To test if the driver has been loaded successfully, do cat /proc/modules and cat /proc/devices.  We should see our module name in the first case and device name in the second.

cat /proc/modules

cat /proc/modules

cat /proc/devices

cat /proc/modules

To unload the driver, use rmmod command. (rmmod myDev.ko)

Testing the driver

To test the driver, we try writing something to the device file and then reading it. For example,

Testing the driver

Testing the driver

See the output. (The reason for the ‘ugly’ output is because echo automatically writes a newline character to the end of string. When the driver reverses the string, the newline is shifted to the front of the string and there is no newline at the end. Hence the result being ‘ugly’)

To see how this can be done from our program, I wrote a demo program given below

Interacting with the driver

Interacting with the driver

Compile it normally(or run make test) and run ./test  some_string  and see the output.

Testing the driver

Testing the driver

Note: You need to be root to compile the module, load the module and unload the module.

This driver interface presented here is an old one, there is a newer one but the old one is still supported.

60 Responses to “Writing a Linux character Device Driver”

  1. vidya said

    good efforts

  2. Farhan said

    This is phenomenal. Thank you very much.

    I plan on using this as a springboard to learning how to write kernel modules for “actual” devices. As of yet, I’m a bit in the dark on how all this works.
    Do you know of any documentation on how to operate with USB devices?

    My long-term plan is to learn how to build my own devices, but that’s years in the future.

  3. Brad said

    Handy template, thanks!

    I have a question – what editor are you using, and what color theme? In your OS post, you had a grey background, but in this one you have a blue background with an overall color theme I really like. I’d like to see if I can grab it (rather than replicate it piecemeal) for emacs.

  4. Suja said

    Really helpfull. Thanks.

  5. […] in case some one else like me needs it: http://pete.akeo.ie/2011/08/writing-…r-kernels.html and https://appusajeev.wordpress.com/2011…device-driver/ The above one was easy to understand for a newbie like me.You could download the sample code […]

  6. khanduji said

    Its awesome for starters, Good work. Keep it up.

  7. Lakshmi said

    Thanks for your Post

    I have a question: i just downloaded the code. when i make i am able to see mydev.ko, mydev.o, mydev.mod.o, modules.order, Modules.symvers,
    But when i execute insmod mydev.ko it throwing an error saying “insmod: error inserting ‘mydev.ko': -1 Invalid module format”
    modprobe: “WARNING: All config files need .conf: /etc/modprobe.d/modprobe.con, it will be ignored in a future release.
    FATAL: Module mydev.ko not found.”

    I am using fedora 14 system for compilation

    would u please help me solve this problem.

    Regards,
    Lakshmi

  8. luiseth said

    Hey congrats on this great write-up about linux drivers. I’ll be trying it up soon!

  9. Shridhar said

    Great post!

  10. naven said

    Nice…Helpful for beginners

  11. Manikishore said

    excellent effort.it is helpful for learners..

  12. ravi said

    from here i can start learn device driver thank u ,can u send how to debug in kernel mode,

  13. Kappasm said

    Can your reupload a “Download Code” ?

    Thanks very much.

    Kappasm

  14. ayush jain said

    thnx alot … post is really helpfull ,,, i tried it n all went well ,,,, now i want to know nxt step means what should i try after trying this ,,, means next level so that i can learn more …

  15. ayush jain said

    thnx alot … post is really helpfull ,,, i tried it n all went well ,,,, now i want to know nxt step means what should i try after trying this ,,, means next level so that i can learn more … reply pls .. :)

  16. Vahe said

    Hi, can you activate link Download source, I can’t download , thanks, or send to my mail

  17. Prabhu said

    Very much useful …. ThnX alot ….

  18. anisha said

    after mknod /dev/mydev c 89 1 ..am getting “permission denied ” error… am trying this on dvsdk linux

  19. anisha said

    on execution of test its printing input fine, but for output ” Reversed by the driver : ” is blank. its not printing anything. please reply soon.

  20. anisha said

    no…that mknod problem is solved..but now the issue is on execution of test file..its displaying the input ..but not the output…when i tried first it worked..then the second time its giving this problem …

    • appusajeev said

      ok, so u have did insmod as root, did mknod as root(which needs to be done only once, till next reboot) and when you ran the script, nothing was printed, rt???
      did you give write permission to the device file for all users? try running cat /proc/modules, is the module listed there? run cat /proc/devices, is ‘myDev’ listed there ??? also, did u restart in between?

  21. anisha said

    hey, now on the target side, ./test is not getting executed..but am getting the reversed output with echo “hello” > /dev/mydev .. cat /dev/myDev cmd …..with ./test “hello” its giving error line 1: syntax error: “(” unexpected

  22. your download code is not working…..
    can you mail me the code at nikhil199029@gmail.com please

  23. raj said

    very help full for beginner who learning device driver.

  24. mahendra said

    I read this topic in book but I didnt understand anything .thanks for giving this information in an simple language.

  25. ravi said

    super sir hands-off to you

  26. vishal said

    Thanks….so helpful

  27. […] Writing a Linux character device driver […]

  28. dk said

    I have tried to follow the same procedure as mentioned in this blog for but i am getting “bash: /dev/myDev : permission denied” how can i resolve this …. m new to linux os .

  29. dustychints said

    i stucked at first step…
    mknod is not working on root…
    i tried this “”” mknod /dev/myDev c 89 1 “””..but this is coming instead..
    “mknod: `/dev/myDev': Permission denied” …

  30. Nagaraj V said

    Hi,

    Trying to download the source, but cannot. Can you enable please?

    Thanks for your efforts.

  31. Pradip vaishnav said

    yes this is really helpful but how we can call application in run time without use of terminal like product

  32. wanchao said

    Thank you very much.
    I understood about character device driver.

  33. harry said

    hii …i am not able to download the source code ..plz help …..thanks ……

  34. Thanks for this! For those who needs the code sample i uploaded to github what i’ve used: https://github.com/cirocosta/linux-chardev-driver-sample

  35. Paloma said

    Thank you!!!

  36. Lokesh said

    Thanks It really helped me . Excellent article for beginners

  37. pradeep said

    Can u please fix download link again ? It will be helpful if u can send code to pradeep@tectredz.com

  38. bharat said

    hi!
    i am running your sample driver module and ….when i try to unload the module it says device/resource busy…
    cat /proc/modules..gives …mydev.ko 2106 0 [permanant]
    ..please suggest me a solution

  39. Sam said

    DOWNLOAD link does not work, is there any way l can access the source code?
    THX

  40. karan arora said

    Thank you so much dude..
    Really very good efforts.
    i like it very much :): )
    gives you 100/100 ******

  41. Ralf said

    Would like to test your code, but the download link is broken – please fix.

  42. Brijendra Dwivedi said

    Really, Very helpful for beginners like me

  43. Sethu said

    This is a superb explanation of linux device driver. Very well said. Great Job Sajeev!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
Follow

Get every new post delivered to your Inbox.

Join 30 other followers

%d bloggers like this: