IOCTL Control for Linux Device Drivers

Source: Internet
Author: User

In addition to the ability to read and write devices, most drivers also need the ability to control hardware.

1. In user space, useIOCTL system calls to control devicesThe prototype is as follows:

Int IOCTL (int fd, unsigned long cmd ,...); /* FD: file descriptor cmd: Control Command...: optional parameter: insert * argp. The specific content depends on CMD */

The user program only uses the command code to tell the driver what it wants to do.How to explain these commands and how to implement these commands are all required by the driver.

II,IOCTL driver Method:

INT (* IOCTL) (struct inode * inode, struct file * filp, unsigned int cmd, unsigned long Arg ); /* inode and filp pointers correspond to the file descriptor FD passed by the application, which is the same as the parameter passed by the open method. CMD is directly transmitted to the driver Arg without modification by the user space. Optional. */

In the ioctl function implemented in the driver, there is actually a switch {Case} structure. Each case corresponds to a command code and some operations are performed accordingly. How to implement these operations is a task of every programmer, because the devices are specific. The key is how to organize the command code, because the command code in IOCTL is the only way to contact the user program command and driver support.

In Linux, the core definesCommand codeOf:
____________________________________

| Device type | serial number | direction | data size |

| ---------- | -------- | ------ | ------------- |

| 8 bit | 8 bit | 2 bit | 8 ~ 14 bit |

| ---------- | -------- | ------ | ------------- |

In this way, a command is converted into an order code in the integer form. However, the command code is not intuitive, so some macros are provided in Linux kernel. These macros can generate the command code based on strings that are easy to understand, you can also get some strings that you can understand from the command to indicate the device type, device serial number, data transmission direction, and data transmission size of the command.

1. Define the command:
The kernel provides some macros to help define commands:

// Nr is the serial number, and ype is the data type, such as int_io (type, NR) // The command _ ior (type, NR, datatype) without Parameters) // read data from the driver _ Iow (type, NR, datatype) // write data to the driver _ IOWR (type, NR, datatype) // bidirectional Transfer

Command example:

# Define mem_ioc_magic 'M' // defines the type # define mem_iocset _ Iow (mem_ioc_magic, 0, INT) # define mem_iocgqset _ ior (mem_ioc_magic, 1, INT)

2. Implementation command:
After the command is defined, the next step is to implement the ioctl function. The implementation of IOCTL includes three technical links:
1) return value;
The ioctl function is implemented based on a switch statement executed by the command. However, when the command cannot match any command supported by a device, the-einval (invalid parameter) is usually returned );
2) parameter usage;
The user uses int IOCTL (int fd, unsinged long cmd,...,...Is the parameter to be passed;
Then use int (* IOCTL) (struct inode * inode, struct file * filp, unsigned int cmd, unsigned longARG;
If Arg isInteger, Which can be used directly;
If yesPointer, We must ensure that this user address is valid. Therefore, we need to perform a correct check before use.
Internal check,No detection requiredOf:

copy_from_usercopy_to_userget_userput_user

Need to detectOf:

__get_user__put_user

Detection FunctionAccess_ OK ():

Static inline int access_ OK (INT type, const void * ADDR, unsigned Long SIZE)/* type: verify_read or verify_write indicates whether the user memory is read or written; ADDR: is the user memory address to be operated; Size: Is the operation length. If IOCTL needs to read an integer from the user space, the size parameter is equal to sizeof (INT); Return Value: access_ OK returns a Boolean value: 1, which is successful (no problem with access); 0, yes. IOCTL returns-efault ;*/

3) command operations;

switch(cmd){     case:     ... ...}

III,IOCTL instance analysis:

(1)Memdev. h:

# Ifndef _ memdev_h _ # DEFINE _ memdev_h _ # include <Linux/IOCTL. h> # ifndef memdev_major # define memdev_major 0/* default mem master device Number */# endif # ifndef unique # define memdev_nr_devs 2/* Number of devices */# endif # ifndef memdev_size # define memdev_size 4096 # endif
/* Mem device description struct */struct mem_dev {char * data; unsigned long size ;}; /* define magic number */# define memdev_ioc_magic 'K'/* define command */# define memdev_iocprint _ IO (memdev_ioc_magic, 1) # define memdev_iocgetdata _ ior (memdev_ioc_magic, 2, INT) # define memdev_iocsetdata _ Iow (memdev_ioc_magic, 3, INT) # define memdev_ioc_maxnr 3 # endif/* _ memdev_h _*/

(2)Memdev. C:(Driver)

#include <linux/module.h>#include <linux/types.h>#include <linux/fs.h>#include <linux/errno.h>#include <linux/mm.h>#include <linux/sched.h>#include <linux/init.h>#include <linux/cdev.h>#include <asm/io.h>#include <asm/system.h>#include <asm/uaccess.h>#include "memdev.h"

Static int mem_major = memdev_major; module_param (mem_major, Int, s_irugo); struct mem_dev * mem_devp;/* Device struct pointer */struct cdev; /* file opening function */INT mem_open (struct inode * inode, struct file * filp) {struct mem_dev * dev; /* obtain the device Number */INT num = minor (inode-> I _rdev); If (Num> = memdev_nr_devs) Return-enodev; Dev = & mem_devp [num]; /* assign the device description structure pointer to the file Private Data Pointer */filp-> private_data = dev; return 0;}/* file release function */INT mem _ Release (struct inode * inode, struct file * filp) {return 0;}/* IO operation */INT memdev_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, unsigned long Arg) {int err = 0; int ret = 0; int ioarg = 0;/* Check the command validity */If (_ ioc_type (CMD )! = Memdev_ioc_magic) Return-einval; If (_ ioc_nr (CMD)> memdev_ioc_maxnr) Return-einval;/* depending on the command type, check whether the parameter space can be accessed */If (_ ioc_dir (CMD) & _ ioc_read) Err =! Access_ OK (verify_write, (void *) Arg, _ ioc_size (CMD); else if (_ ioc_dir (CMD) & _ ioc_write) Err =! Access_ OK (verify_read, (void *) Arg, _ ioc_size (CMD); If (ERR) Return-efault;/* execute the corresponding operation according to the command */switch (CMD) {/* print the current device information */case memdev_iocprint: printk ("<--- cmd memdev_iocprint done ---> \ n"); break;/* obtain the parameter */case memdev_iocgetdata: ioarg = 1101; ret = _ put_user (ioarg, (int *) Arg); break;/* set the parameter */case memdev_iocsetdata: ret = _ get_user (ioarg, (int *) Arg); printk ("<--- in kernel memdev_io Csetdata ioarg = % d ---> \ n ", ioarg); break; default: Return-einval;} return ret ;} /* file operation struct */static const struct file_operations mem_fops = {. owner = this_module ,. open = mem_open ,. release = mem_release ,. IOCTL = memdev_ioctl,};/* Device Driver Module Loading Function */static int memdev_init (void) {int result; int I; dev_t devno = mkdev (mem_major, 0 ); /* apply for the device ID statically */If (mem_major) Result = register_chrdev_region (devno, 2 ," Memdev "); else/* dynamically allocate the device Number */{result = alloc_chrdev_region (& devno, 0, 2," memdev "); mem_major = major (devno );} if (result <0) return result;/* initialize the cdev structure */cdev_init (& cdev, & mem_fops); cdev. owner = this_module; cdev. ops = & mem_fops;/* register a character device */cdev_add (& cdev, mkdev (mem_major, 0), memdev_nr_devs ); /* allocate memory for the device description structure */mem_devp = kmalloc (memdev_nr_devs * sizeof (struct mem_dev), gfp_kernel); If (! Mem_devp)/* application failed */{result =-enomem; goto fail_malloc;} memset (mem_devp, 0, sizeof (struct mem_dev )); /* allocate memory for the device */for (I = 0; I <memdev_nr_devs; I ++) {mem_devp [I]. size = memdev_size; mem_devp [I]. data = kmalloc (memdev_size, gfp_kernel); memset (mem_devp [I]. data, 0, memdev_size);} return 0; fail_malloc: unregister_chrdev_region (devno, 1); return result;}/* module unmount function */static void memdev_exit (void) {cdev_del (& cdev);/* log out of the device */kfree (mem_devp);/* release the device struct memory */unregister_chrdev_region (mkdev (mem_major, 0), 2 ); /* release the device Number */} module_author ("David xie"); module_license ("GPL"); module_init (memdev_init); module_exit (memdev_exit );

(3) app-ioctl.c(Application)

# Include <stdio. h> # include <sys/types. h> # include <sys/STAT. h> # include <fcntl. h> # include "memdev. H "/* contains command Definitions */INT main () {int FD = 0; int cmd; int Arg = 0; char Buf [4096]; /* Open the device file */FD = open ("/dev/memdev0", o_rdwr); If (FD <0) {printf ("Open Dev mem0 error! \ N "); Return-1;}/* call the command memdev_iocprint */printf (" <--- Call memdev_iocprint ---> \ n "); cmd = memdev_iocprint; if (IOCTL (FD, CMD, & Arg) <0) {printf ("Call cmd memdev_iocprint fail \ n"); Return-1 ;} /* call the command memdev_iocsetdata */printf ("<--- Call memdev_iocsetdata ---> \ n"); cmd = memdev_iocsetdata; arg = 2007; If (IOCTL (FD, CMD, & Arg) <0) {printf ("Call cmd memdev_iocsetdata fail \ n"); Return-1 ;} /* call the command memdev_iocgetdata */printf ("<--- Call memdev_iocgetdata ---> \ n"); cmd = memdev_iocgetdata; If (IOCTL (FD, CMD, & Arg) <0) {printf ("Call cmd memdev_iocgetdata fail \ n"); Return-1;} printf ("<--- in user space memdev_iocgetdata get data is % d ---> \ n ", arg); close (FD); Return 0 ;}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.