Search

Creating an Ioctl command in linux

Ioctl which stand for Input Output control is a system call used in linux to implement system calls which are not be available in the kernel by default.

The major use of this is in case of handling some specific operations of a device for which the kernel does not have a system call by default. For eg: Ejecting the media from a "cd" drive.An ioctl command is implemented to give the eject system call to the cd drive.



Note: The following code is only valid for 2.6 kernels below 2.6.36.
For versions above 2.6.36 refer to the post "Implementing ioctl call for kernel versions above 2.6.36
To implement a new ioctl command we need to follow the following steps.
1. Define the ioctl code in a header file and include the same in the application as well as the module.
The definition is done as follows
#define "ioctl name" __IOX("magic number","command number","argument type")

where IOX can be :
"IO": If the command neither reads any data from the user nor writes any data to the userspace.
"IOW": If the commands needs to write some to the kernel space.
"IOR": If the command needs to read some thing from the kernel space.
"IOWR": If the command does both read as well as write from the user



The Magic Number is a unique number or character that will differentiate our set of ioctl calls from the other ioctl calls. some times the major number for the device is used here.

Command Number is the number that is assigned to the ioctl .It is this number that is used to differentiate the commands from one another .

The last is the type of data that will be written in case of __IOW or read in case of __IOR or both read as well as write in case of __IOWR. In the case of _IO we need not pass any thing.

2. Add the header file linux/ioctl.h to make use of the above mentioned calls.


Let us call the ioctl that we will create as "IOCTL_HELLO" , hence the header file , ioctl_basic.h, would be




3. The next step is to implement the ioctl call we defined in to the corresponding driver. First we will need to #include the header file ioctl_basic.h


Then we need to add the ioctl function which has the prototype



Where
ionde :is the inode number of the file being worked on
filp : is the file pointer to the file that was passed by the application.
cmd : is the ioctl command that was called from the user space.
arg : are the arguments passed from the user space.


With in the function "ioctl" we need to implement all the commands that we define in the header file.As we saw each command is given a command number in the header file, the same number will be used in a switch case statement to implement the calls.
We will just add a print statement to see how the ioctl call works. so the function would look as follows




In the above function the ioctl command "IOCTL_HELLO" will have got the number 0,that we assigned in the header file ioctl_basic.h, The same number would be passed in the argument "cmd" when the ioctl call is made from the user space. Thus using "cmd" in the switch case makes sure that the correct command get executed for the ioctl call.

4. Next step is to inform the kernel that the ioctl calls are implmented in the function "our_ioctl". This is done by making the fops pointer "ioctl" to point to "our_ioctl" as shown below


Note: You can read about fops at "fops implementation"



Now we need to call the new ioctl command from a user application, to test its working.

The call to an ioctl in the user space i.e in an application looks as follows




file descriptor : This the open file on which the ioctl command needs to be
executed, which would generally be device files
ioctl command : ioctl command which is implemented to achieve the desired functionality
arguments: The arguments that needs to be passed to the ioctl command.

Thus is our case the call would look as below

We need to "#include" the header file "ioctl_basic.h" in the user space program too.

The following are the full codes for the header file,the module and the user space application.

Header file: ioctl_basic.h



Module: ioctl_basic.c



User space appliction: user_basic_ioctl.c



Now compile the module using the following makefile



Note : To know more about compiling a module refer to "Inserting into the kernel" and "user access"



The message that was printed in the output of dmesg command is the same message that we have incorporated in the ioctl call implementation in the driver, hence proving that the call from the user space was passed on to the kernel space successfully.

14 comments:

  1. Very good post ... Explained in a way that its very easy for anyone to understand ..Thankyou...

    ReplyDelete
  2. what is "/dev/temp"?

    ReplyDelete
    Replies
    1. /dev/temp is the character device we create using the command mknod.

      I see that the post uses a different name(/dev/char_arr) with mknod, will correct it.

      Thank you

      Delete
  3. Thank you very much for this post ! It helps me a lot to understand how to implement ioctl !

    ReplyDelete
  4. Then we need to add the ioctl function which has the prototype:

    int ioctl_funcs (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)

    'ioctl_funcs' is a user defined function name, could be 'my_ioctl_funcs'.

    ReplyDelete
  5. struct file_operations fops = {
    open: open
    ioctl: our_ioctl, //Mapping the ioctl function
    release: release,
    };
    Don't you think, it is 'ioctl_funcs' and not 'our_ioctl' ? It is little confusing when u define ioctl_funcs() and assign 'our_ioctl' .

    ReplyDelete
    Replies
    1. Thanks for pointing the error, have corrected it.

      Delete
  6. This post was very helpful. Thanks!

    ReplyDelete
  7. i get when compiling :

    error: truct file_operations has no member named ioctl; did you mean iopoll
    ioctl: ioctl_funcs,

    ReplyDelete
    Replies
    1. What is your kernel version, if its abofe 2.36, please use the code in the post https://tuxthink.blogspot.com/2012/12/implementing-ioctl-call-for-kernel.html

      Delete