Linux Device driver Sixth: Iotcl of advanced character driven operation

Source: Internet
Author: User
Tags case statement switch case

Before we introduced how to implement a simple character device driver and introduced the basic functions provided by the simple Open,close,read,write driver. But a real device driver often provides more advanced functionality than simple read and write. In this article we will introduce some of the advanced operations that are used in the driver's implementation.

In addition to providing read and write operations to the device, most drivers also need to provide an interface to the hardware control, such as querying how much resolution a framebuffer device can provide, reading the time of an RTC device, and setting a gpio for high and low power parity. The implementation of these hardware operations is usually accomplished by the IOCTL method.

1. Introduction to Prototypes

The prototype of the IOCTL in user space is:

int ioctl (int fd, unsigned long cmd, ...);

The points in the prototype do not represent a variable number of arguments, but rather a

A single optional parameter, traditionally identified as Char *ARGP. These points are there just to prevent type checking at compile time. 3rd

The actual characteristics of a parameter depend on the specific control command issued (the 2nd parameter). Some commands do not have parameters, some use a whole

values, and some pointers that use points to other data. Using a pointer is a method of passing arbitrary data to the IOCTL call; The device can then exchange any amount of data with the user space.

The prototype of the IOCTL in kernel space is:

Int (*ioctl) (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);

The inode and Filp pointers are the values of the file descriptor fd passed by the corresponding application, and the same parameters passed to the open method. Cmd

Parameters are not changed from the user, and the optional parameter arg parameter is passed as a unsigned long, regardless

Whether it is given by the user as an integer or a pointer. If the calling program does not pass a 3rd argument, the driver receives the

The arg value is undefined. Because the type check is closed on this extra parameter, the compiler cannot warn of this.

2. Selection of IOTCL cmd

Before implementing the IOCTL, we should define a set of IOCTL commands, an easy way to use a simple set of numbers, such as from 0 to 9. This is generally not a problem, but it is best not to do so, and the IOCTL cmd should be unique within the system, which prevents the correct command from being issued to the wrong device. This is not the case if the IOCTL command is unique within the system.

The IOCTL cmd is divided into several bits in Linux to help create a unique cmd. These bits are generally: type (modulus), ordinal, transmission direction and parameter size. You can refer to Include/asm/ioctl.h and documentation/at the time of definition. Ioctl-number.txt two files, header file defines the macros that build the cmd command, and Ioctl-number.txt lists the Tpye that have been used in the kernel, for uniqueness, try not to overlap with the type here.

Here is a brief introduction to these bits:

Type

Magic number. Just select a number (after referencing the ioctl-number.txt) and use it throughout the drive. This member is 8 bits wide (_ioc_typebits).

Number

ordinal (sequential) number. It is 8-bit (_ioc_nrbits) wide.

Direction

The direction of the data transfer, if this particular command involves data transfer. The possible values are _ioc_none (no data transfer), _ioc_read, _ioc_write, and _ioc_read|_ioc_write (data is transmitted in 2 directions). Data transfer is viewed from the perspective of the application; _ioc_read meaning is read from the device, so the device must be written to the user space. Note that this member is a bitmask, so _ioc_read and _ioc_write can be extracted using a logical AND operation.

Size

The size of the user data that is involved. The width of this member is dependent on the system, but it is often 13 or 14 bits. You can find its value in macro _ioc_sizebits for your particular system. You are not forced to use this size member-the kernel does not check it--but it is a good idea. Proper use of this member can help detect errors in the user's space program and enable you to achieve backwards compatibility if you ever need to change the size of the relevant data item. If you need a larger data structure, however, you can ignore this size member. We soon saw how to use this member.

Here is a demonstration that defines the IOCTL command:

/* use ' K ' as magic number */#define SCULL_IOC_MAGIC ' k '/* * Use a different 8-bit number in your code */#define Scul L_iocreset _io (scull_ioc_magic, 0)/* * S means "Set" through a ptr, * T means "tell" directly with the argument value * G means "Get": Reply by setting through a pointer * Q means "Query": response was on the return value * X means "eXchange": s  Witch G and S atomically * H means "sHift": Switch T and Q atomically */#define Scull_iocsquantum _iow (scull_ioc_magic, 1, int) #define Scull_iocsqset _iow (scull_ioc_magic, 2, int) #define Scull_ioctquantum _io (scull_ioc_magic, 3) #define SCULL _ioctqset _io (scull_ioc_magic, 4) #define Scull_iocgquantum _ior (scull_ioc_magic, 5, int) #define SCULL_IOCGQSET _IOR ( Scull_ioc_magic, 6, int) #define Scull_iocqquantum _io (scull_ioc_magic, 7) #define Scull_iocqqset _io (Scull_ioc_magic, 8 ) #define Scull_iocxquantum _IOWR (scull_ioc_magic, 9, int) #define Scull_iocxqset _iowr (scull_ioc_magic,10, int) #define Scull_iochquantum _io (Scull_ioc_magic, 11) #define Scull_iochqset _io (scull_ioc_magic,) #define SCULL_IOC_MAXNR 14 

  

For more information on macro definitions such as _IOWR, refer to the definitions in the header file.

3. Return value of the IOCTL

The implementation of the IOCTL is often a switch case statement, and the return value depends on the implementation of each case branch. What values are returned when a CMD is not defined, and I recommend using-einval to represent useless arguments. Another point, when the case branch is more, some people often forget to write a break, resulting in the subsequent cases branch execution, resulting in an error.

4. Arg parameter of the IOCTL

Some IOCTL commands do not require the ARG parameter, and most of the IOCTL needs to pass the data at the application and kernel levels. When the arg parameter is an integer, it's very simple, and we can use it directly. If it's a pointer, you need to be careful.

Data exchange between application layer and kernel layer we often use the copy_from_user and Copy_to_user functions, which can be used safely to move data. These functions are also available in the IOCTL method. But the data items in the IOCTL are often very small data, and with these two functions a bit cumbersome, we can try to use other methods to implement the data transfer.

int ACCESS_OK (int type, const void *ADDR, unsigned long size);

This function is used to check whether a given address satisfies a particular access requirement, and this function checks for no data copy. You can safely transfer data after you use ACCESS_OK. The following interfaces can be used to transfer data:

Put_user (Datum, PTR)
__put_user (Datum, PTR)
These macros define write datum to user space, they are relatively fast, and should be called instead of copy_to_user whenever a single value is to be transferred. These macros have been written to allow any type of pointer to be passed to Put_user, as long as it is a user-space address. The transmitted data size depends on the type of PRT parameter and is determined at compile time using compiler built-in macros such as sizeof and TypeOf. The result is that if PRT is a char pointer, it transmits a byte, as well as for 2, 4, and possibly 8 bytes.

Put_user checks to ensure that the process can write to the given memory address, which returns 0 on success and returns-efault on error. __put_user does less checking (it does not call ACCESS_OK), but can still fail if the memory being pointed to is not writable to the user. Therefore, __put_user should only be used when the memory area has been checked with ACCESS_OK.

As a general rule, when you implement a read method, call __put_user to save several cycles, or when you copy several items, so call Access_ok once before the first data transfer, as shown in the IOCTL above.

Get_user (local, PTR)
__get_user (local, PTR)
These macro definitions are used to receive individual data from the user space. They are like Put_user and __put_user, but pass data in the opposite direction. The obtained value is stored locally on the local variable, and the return value indicates whether the operation was successful. Again, __get_user should only be used for addresses that have been verified with ACCESS_OK.

These are the IOCTL operations related content, because of the length of the reason, it is written here, the next section and then write some other advanced methods, such as blocking IO, non-blocking IO and so on. Please pay attention.

Before the series of articles like below, welcome to read attention:

Linux device driver First article: Introduction to device drivers

Linux Device driver Second article: Building and running modules

Linux Device driver Third article: write a simple character device driver

Linux Device driver Fourth: A case study of the Oops Information positioning code behavior the driving debugging method

Linux device driver Fifth: Concurrency and the state of drive

This article is original, reproduced please indicate the source, offenders must investigate

Focus on the public platform: the Programmer Interaction Alliance (coder_online), you can get the first original technical articles, and (Java/c/c++/android/windows/linux) technology Daniel Friends, online communication programming experience, get programming basics, Solve programming problems. Programmer Interactive Alliance, Developer's own home.

Linux Device driver Sixth: Iotcl of advanced character driven operation

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.