You are on page 1of 6

7/31/13

Write For Us Submit Tips

Device Drivers, Part 6: Decoding Character Device File Operations - LINUX For You
Subscribe to Print Edition Search

HOME

REVIEWS

HOW-TOS

CODING

INTERVIEWS

FEATURES

OVERVIEW

BLOGS

SERIES

IT ADMIN

Device Drivers, Part 6: Decoding Character Device File Operations


By Anil Kumar Pugalia on May 1, 2011 in Coding, Developers 22 Comments and 0 Reactions

Search for:

Search

Get Connected RSS Feed Twitter

This article, which is part of the series on Linux device drivers, continues to cover the various concepts of character drivers and their implementation, which was dealt with in the previous two articles [1, 2].
So, what was your guess on how Shweta would crack the problem? Obviously, with the help of Pugs. Wasnt it obvious? In our previous article, we saw how Shweta was puzzled by not being able to read any data, even after writing into the / d e v / m y n u l lcharacter device file. Suddenly, a bell rang not inside her head, but a real one at the door. And for sure, there was Pugs. How come youre here? exclaimed Shweta. I saw your tweet. Its cool that you cracked your first character driver all on your own. Thats amazing. So, what are you up to now? asked Pugs. Ill tell you, on the condition that you do not play spoil sport, replied Shweta. Pugs smiled, Okay, Ill only give you advice. And that too, only if I ask for it! I am trying to understand character device file operations, said Shweta. Pugs perked up, saying, I have an idea. Why dont you decode and then explain what youve understood about it? Shweta felt that was a good idea. She t a i l ed the d m e s glog to observe the p r i n t koutput from her driver. Alongside, she opened her null driver code on her console, specifically observing the device file operations m y _ o p e n ,m y _ c l o s e ,m y _ r e a d , and m y _ w r i t e .
s t a t i ci n tm y _ o p e n ( s t r u c ti n o d e* i ,s t r u c tf i l e* f ) { p r i n t k ( K E R N _ I N F O" D r i v e r :o p e n ( ) \ n " ) ; r e t u r n0 ; } s t a t i ci n tm y _ c l o s e ( s t r u c ti n o d e* i ,s t r u c tf i l e* f ) { p r i n t k ( K E R N _ I N F O" D r i v e r :c l o s e ( ) \ n " ) ; r e t u r n0 ; } s t a t i cs s i z e _ tm y _ r e a d ( s t r u c tf i l e* f ,c h a r_ _ u s e r* b u f ,s i z e _ tl e n ,l o f f _ t* o f f ) { p r i n t k ( K E R N _ I N F O" D r i v e r :r e a d ( ) \ n " ) ; r e t u r n0 ; }

LINUX For You on

Follow

+2,456

www.linuxforu.com/2011/05/decoding-character-device-file-operations/

1/6

7/31/13

Device Drivers, Part 6: Decoding Character Device File Operations - LINUX For You
Find us on Facebook

s t a t i cs s i z e _ tm y _ w r i t e ( s t r u c tf i l e* f ,c o n s tc h a r_ _ u s e r* b u f ,s i z e _ tl e n ,l o f f _ t* o f f ) { p r i n t k ( K E R N _ I N F O" D r i v e r :w r i t e ( ) \ n " ) ; r e t u r nl e n ; }

Open Source For You


Like 251,299 people like Open Source For You.

Based on the earlier understanding of the return value of the functions in the kernel, m y _ o p e n ( ) and m y _ c l o s e ( )are trivial, their return types being int, and both of them returning zero, means success. However, the return types of both m y _ r e a d ( )and m y _ w r i t e ( )are not int, rather, it is s s i z e _ t . On further digging through kernel headers, that turns out to be a signed word. So, returning a negative number would be a usual error. But a non-negative return value would have additional meaning. For the read operation, it would be the number of bytes read, and for the write operation, it would be the number of bytes written.

F acebook social plugin

Reading the device file


To understand this in detail, the complete flow has to be given a relook. Lets take the read operation first. When the user does a read from the device file / d e v / m y n u l l , that system call comes to the virtual file system (VFS) layer in the kernel. VFS decodes the < m a j o r ,m i n o r > tuple, and figures out that it needs to redirect it to the drivers function m y _ r e a d ( ) , thats registered with it. So from that angle, m y _ r e a d ( )is invoked as a request to read, from us the device-driver writers. And hence, its return value would indicate to the requesters (i.e., the users), how many bytes they are getting from the read request. In our null driver example, we returned zero which meant no bytes available, or in other words, the end of the file. And hence, when the device file is being read, the result is always nothing, independent of what is written into it. Hmmm So, if I change it to 1, would it start giving me some data? asked Pugs, by way of verifying. Shweta paused for a while, looked at the parameters of the function m y _ r e a d ( )and answered in the affirmative, but with a caveat the data sent would be some junk data, since m y _ r e a d ( )is not really populating data into b u f(the buffer variable that is the second parameter of m y _ r e a d ( ) , provided by the user). In fact, m y _ r e a d ( )should write data into b u f , according to l e n(the third parameter to the function), the count in bytes requested by the user. To be more specific, it should write less than, or equal to, l e nbytes of data into b u f , and the number of bytes written should be passed back as the return value. No, this is not a typo in the read operation, device-driver writers write into the user-supplied buffer. We read the data from (possibly) an underlying device, and then write that data into the user buffer, so that the user can read it. Thats really smart of you, said Pugs, sarcastically.

Popular

Comments

Tag cloud

May 6, 2013 5 Comments Priyanka Sarkar

PHP Development: A Smart Career Move


April 4, 2013 4 Comments Aditya-Pareek

Crunchbang Linux Minimalist and Mac-Friendly


April 4, 2013 3 Comments Claudia

Top 7 Linux Tips And Tricks For Beginners


June 20, 2013 3 Comments Priyanka Sarkar

What it Takes to be an Open Source Expert


April 4, 2013 2 Comments Priyanka Sarkar

Will Certifications Related to FOSS Help You Get a Job?

Writing into the device file


The write operation is the reverse. The user provides l e n(the third parameter of m y _ w r i t e ( ) ) bytes of data to be written, in b u f(the second parameter of m y _ w r i t e ( ) ). The m y _ w r i t e ( ) function would read that data and possibly write it to an underlying device, and return the number of bytes that have been successfully written. Aha!! Thats why all my writes into / d e v /m y n u l lhave been successful, without actually doing any read or write, exclaimed Shweta, filled with happiness at understanding the complete flow of device file operations.

Preserving the last character


With Shweta not giving Pugs any chance to correct her, he came up with a challenge. Okay. Seems like you are thoroughly clear with the read/write fundamentals; so, heres a question for you. Can you modify these m y _ r e a d ( )and m y _ w r i t e ( )functions such that whenever I read / d e v / m y n u l l , I get the last character written into / d e v / m y n u l l ? Confidently, Shweta took on the challenge, and modified m y _ r e a d ( )and m y _ w r i t e ( )as follows, adding a static global character variable:
s t a t i cc h a rc ; s t a t i cs s i z e _ tm y _ r e a d ( s t r u c tf i l e* f ,c h a r_ _ u s e r* b u f ,s i z e _ tl e n ,l o f f _ t* o f f ) { p r i n t k ( K E R N _ I N F O" D r i v e r :r e a d ( ) \ n " ) ; b u f [ 0 ]=c ; r e t u r n1 ; } s t a t i cs s i z e _ tm y _ w r i t e ( s t r u c tf i l e* f ,c o n s tc h a r_ _ u s e r* b u f ,s i z e _ tl e n ,l o f f _ t* o f f )

www.linuxforu.com/2011/05/decoding-character-device-file-operations/

2/6

7/31/13
{

Device Drivers, Part 6: Decoding Character Device File Operations - LINUX For You
p r i n t k ( K E R N _ I N F O" D r i v e r :w r i t e ( ) \ n " ) ; c=b u f [ l e n1 ] ; r e t u r nl e n ;

Almost there, but what if the user has provided an invalid buffer, or if the user buffer is swapped out. Wouldnt this direct access of the user-space b u fjust crash and oops the kernel? pounced Pugs. Shweta, refusing to be intimidated, dived into her collated material and figured out that there are two APIs just to ensure that user-space buffers are safe to access, and then updated them. With the complete understanding of the APIs, she rewrote the above code snippet as follows:
s t a t i cc h a rc ; s t a t i cs s i z e _ tm y _ r e a d ( s t r u c tf i l e* f ,c h a r_ _ u s e r* b u f ,s i z e _ tl e n ,l o f f _ t* o f f ) { p r i n t k ( K E R N _ I N F O" D r i v e r :r e a d ( ) \ n " ) ; i f( c o p y _ t o _ u s e r ( b u f ,& c ,1 )! =0 ) r e t u r nE F A U L T ; e l s e r e t u r n1 ; } s t a t i cs s i z e _ tm y _ w r i t e ( s t r u c tf i l e* f ,c o n s tc h a r_ _ u s e r* b u f ,s i z e _ tl e n ,l o f f _ t* o f f ) { p r i n t k ( K E R N _ I N F O" D r i v e r :w r i t e ( ) \ n " ) ; i f( c o p y _ f r o m _ u s e r ( & c ,b u f+l e n1 ,1 )! =0 ) r e t u r nE F A U L T ; e l s e r e t u r nl e n ; }

Then Shweta repeated the usual build-and-test steps as follows: 1. Build the modified null driver (. k ofile) by running m a k e . 2. Load the driver using i n s m o d . 3. Write into / d e v / m y n u l l , say, using e c h on" P u g s ">/ d e v /m y n u l l 4. Read from / d e v / m y n u l lusing cat / d e v / m y n u l l(stop by using Ctrl+C) 5. Unload the driver using r m m o d . On c a t ing / d e v / m y n u l l , the output was a non-stop infinite sequence of s , as m y _ r e a d ( )gives the last one character forever. So, Pugs intervened and pressed Ctrl+C to stop the infinite read, and tried to explain, If this is to be changed to the last character only once, m y _ r e a d ( )needs to return 1 the first time, and zero from the second time onwards. This can be achieved using off (the fourth parameter of m y _ r e a d ( ) ). Shweta nodded her head obligingly, just to bolster Pugs ego.

Related Posts:
Device Drivers, Part 5: Character Device Files Creation & Operations Device Drivers, Part 13: Data Transfer to and from USB Devices Device Drivers, Part 7: Generic Hardware Access in Linux Device Drivers, Part 4: Linux Character Drivers Device Drivers, Part 16: Kernel Window Peeping through /proc
Tags: character device, character device driver, device drivers, LFY May 2011, linux device drivers, Linux Device Drivers Series, struct inode

Article written by:


Anil Kumar Pugalia
The author is a freelance trainer in Linux internals, Linux device drivers, embedded Linux and related topics. Prior to this, he had worked at Intel and Nvidia. He has been exploring Linux since 1994. A gold medallist from the Indian Institute of Science, Linux and knowledge-sharing are two of his many passions. Connect with him: Website - Twitter - Facebook - Google+

Previous Post

Next Post

When Should I Consider an Open Source Database?

Linux Kernel Development Using Git

ALSO ON LINUX FOR YOU

AROUND THE WEB

What's this?

www.linuxforu.com/2011/05/decoding-character-device-file-operations/

OpenMP Schedule Clause Parallel Matrix Multiplication 6 months ago

Billionaires Dump Stocks, Prepare for Collapse Moneynews

3/6

7/31/13

Device Drivers, Part 6: Decoding Character Device File Operations - LINUX For You
6 months ago 1 comment

Matrix Multiplication

for Collapse

Moneynews

Getting Your First Job Code Sport


1 comment

Pastor Reveals 7 Shocking Biblical Truths on Investing Moneynews Citizens Over 50 May Qualify to Get $20,500 this Year Moneynews Heartburn: An Early Warning Sign of These 4 Cancers Newsmax Health

File Systems A Semester Project-II, Part-19 6 comments

22 comments Leave a message...


Newest ans Community

Share

7 days ago

The post is very very good. But when I try to use your .... static ssize_t my_read(struct file *f, char __user *buf, size_t len, loff_t *off) { printk(KERN_INFO "Driver: read()\n"); if (*off == 0) { if (copy_to_user(buf, &c, 1) != 0) return -EFAULT; else { (*off)++; return 1; } } else return 0; } code ,it give me only the last character of the word what ever I enter as input for the file. so, please tell me what to do to see the whole word ?
Reply Share

anil_pugalia

> ans

6 days ago


S ubas h

That's an exercise for you. Try it out and post the solution. :)
Reply Share

16 days ago

Hi How to implement a select interface for a char driver?


Reply Share

anil_pugalia

> Subash

16 days ago


A udhil

Implement the poll system call.


Reply Share

2 months ago

I can't understand what you are trying to say regarding stopping infinite loop using off parameter...Can you elaborate ..?
Reply Share

anil_pugalia

> Audhil

2 months ago

Basically, by using off parameter, one can return 0 (i.e. create an end of file scenario), say after returning the first character for the first time. It would make more sense, if you had tried Shweta's test steps, above. Precisely writing, thereafter check out the following and see the difference for yourself:
s t a t i cs s i z e _ tm y _ r e a d ( s t r u c tf i l e* f ,c h a r_ _ u s e r* b u f ,s i z e _ tl e n ,l o f f _ t* o f f ) {

www.linuxforu.com/2011/05/decoding-character-device-file-operations/

4/6

7/31/13
{

Device Drivers, Part 6: Decoding Character Device File Operations - LINUX For You
p r i n t k ( K E R N _ I N F O" D r i v e r :r e a d ( ) \ n " ) ; i f( * o f f= =0 ) { i f( c o p y _ t o _ u s e r ( b u f ,& c ,1 )! =0 ) r e t u r nE F A U L T ; e l s e { ( * o f f ) + + ; r e t u r n1 ; } } e l s e r e t u r n0 ; }


Rahul

Reply

Share

3 months ago

Awesome article ....


Reply Share

anil_pugalia 1 A mit

> Rahul

3 months ago

Thanks for reading & appreciating.

Reply

Share

7 months ago

thanks sir , for your contribution... sir, is there any way to track down how control is going from when we call open to .open in operation struct any tool or any other way to know the control flow in device driver..
Reply Share

anil_pugalia 1 S ab

> Amit

7 months ago

You may try strace, printk in kernel, ... to name a few.

Reply

Share

8 months ago

Firstly , great article. I bought the Linux device driver book buy Oreilly but could not understand much. Most of my learning has been from your website. If you write a book please do let me know. I will be the first to buy it :-).I tried to use the value of *off and I printed it to my logs, but it appears that it is always 0. I had to use a separate variable to make it print only once. Could you please explain as to how to do it using the long offset pointer
Reply Share

anil_pugalia

> Sab

8 months ago

Thanks for reading & appreciating the article. *off would change only if the driver changes it. So, in read when it is 0, you need to put the value in buf & then increment the *off, i.e. do a (*off)++;
1

Reply

Share

S ab

> anil_pugalia
Reply

8 months ago

Okay. That clears things up. Thanks

Share

S urjy a Naray ana P adhi

10 months ago

I am able to compile successfully, then i insmod the module, then I did the write openration as you mentioned the "$ echo -1 "Pugs" > /dev/mynull ". Now I tried to read the file using "$ sudo cat /dev/mynull" but see something in infinite loop, but I am not able to see any character. I can't see anything and the read() operation in loop. Where I am going wrong?
1

Reply

Share

anil_pugalia

> Surjya Narayana Padhi


Share

8 months ago

It should be "echo -n" not "echo -1". Please correct it & try.
www.linuxforu.com/2011/05/decoding-character-device-file-operations/

Reply

5/6

7/31/13
1

Device Drivers, Part 6: Decoding Character Device File Operations - LINUX For You
Reply

Share

Haris Ibrahim K . V .

a year ago

I made the changes in my write and read functions and built the driver. However, after writing to the driver using echo, when I tried "cat /dev/mynull" nothing happened. The output was same as in last article. Any idea where I might have gone wrong? UPDATE : I gave -a_number instead of -n in the echo command. Corrected it.
1

Reply

Share

Haris Ibrahim K . V .

a year ago

Please mention to add the < asm / uaccess. h > header in order for the copy_to_user and copy_from_user function calls to work properly. I'm following each and every step of your guide. :)
1

Reply

Share

anil_pugalia

> Haris Ibrahim K. V.


Share

a year ago

Thanks for the addendum.


Reply

Reply

Gues t

a year ago

You might want to add the linux header uaccess.h to access those api calls.
Share

anil_pugalia

> Guest

a year ago


jerrins g

You are right. I missed mentioning that.


Reply Share

a year ago

Could you explain how the fourth parameter 'off' can be used to prevent the infinite output sequence. Thanks in advance.

Reply

Share

anil_pugalia

> jerrinsg

a year ago


r
C o m m e n t fe e d

For that please understand, why is the infinite sequence in the first place. It is because the read never says end of file by returning a zero, but always keep on giving data, whenever asked for. With this a user code doing a read till end of file would go into infinite loop. Hence, to fix this you need to have a case of returning a zero. In our case, we used the case to be "when you try to read the second time or second byte", which is very well captured by the fourth parameter 'off', telling us where exactly was it already reading.
Reply Share

Su b s cri b e vi a e m a i l

Reviews

How-Tos

Coding

Interviews

Features

Overview

Blogs

Search
Popular tags
Linux , ubuntu, Java, MySQL, Google, python, Fedora, Android, PHP, C, html, w eb applications , India, Microsoft, unix , Window s , Red Hat, Oracle, Security , Apache, xml, LFY April 2012, FOSS, GNOME, http, JavaScript, LFY June 2011, open source, RAM, operating systems

For You & Me Developers Sysadmins Open Gurus CXOs Columns

All published articles are released under Creative Commons Attribution-NonCommercial 3.0 Unported License, unless otherw ise noted. LINUX For You is pow ered by WordPress, w hich gladly sits on top of a CentOS-based LEMP stack.

www.linuxforu.com/2011/05/decoding-character-device-file-operations/

6/6

You might also like