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. The basic functions provided by the simple open,close,read,write and other drivers are introduced. 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 point in the prototype does not represent a variable purpose, but a

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

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

Values, as well as some pointers that use pointing to other data. Using a pointer is a method of passing arbitrary data to the IOCTL call; The device can then be exchanged with the user space regardless of the amount of data.

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 that the corresponding application passes, and the same number of parameters passed to the open method. Cmd

The parameters are not changed from the user, and the optional parameter arg is passed in the form of a unsigned long, regardless

Whether it is given by the user as an integer or a pointer. Assuming that the calling program does not pass the 3rd parameter, 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. A simple method is to use a simple set of numbers, for example, from 0 to 9. This situation is generally not a problem, but it is best not to do so, the IOCTL CMD should be within the system is unique, so as to prevent the wrong device to issue the correct command.

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 usually: type (modulus), ordinal, transmission direction, and parameter size.

You can refer to Include/asm/ioctl.h and documentation/ioctl-number.txt two files at the time of definition. The header file defines the macros that build the cmd command. Ioctl-number.txt lists the Tpye that have been used in the kernel, and for uniqueness, try not to overlap with the type here.

Here is a brief introduction to these few bits:

Type

Magic number. Just choose a number (after 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, assuming that this particular command involves data transfer. The possible values are _ioc_none (no transmitted data), _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-space program and allow you to achieve backwards compatibility, assuming that you have changed the size of the relevant data item. Suppose you need a larger data structure, but you can ignore this size member. We are very quick to see 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 

The definition of a lot of other content can be included in the header file for _IOWR and other macros.

3. Return value of the IOCTL

The implementation of the IOCTL is often a switch case statement, and the return value relies on the implementation of each case branch.

What values are returned when an undefined cmd is encountered, and I recommend using-einval. Indicates a useless number of references. Another point, when the case branch is much more. Some people often forget to write break, causing the case branch to run the same, resulting in an error.

4. Arg parameters of the IOCTL

Some IOCTL commands do not require the ARG parameter. The majority of the IOCTL needs to pass the data at the application layer and the kernel layer.

When Arg is an integer, it's easy. We can use it directly to get it. Suppose it is a pointer, you need to be careful.

Data exchange between the application layer and the kernel layer we often use the copy_from_user and Copy_to_user functions. They 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, which is a bit cumbersome with these two functions. 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 specific request for access, and this function checks only without data copy. Data can be transferred securely after using 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 to replace Copy_to_user whenever a single value is to be transferred. These macros have been written to agree to pass whatever type of pointer to Put_user, just to be a user-space address. The transmitted data size depends on the type of PRT parameters, and is determined using compiler built-in macros such as sizeof and typeof at compile time.

As a result, it is assumed that PRT is a char pointer that 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. It returns 0 on success, and returns-efault on error.

__put_user does less checking (it does not call ACCESS_OK), but can still fail assuming that the memory being pointed to is not writable to the user. Therefore, __put_user should be used only 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 a few cycles, or when you copy several items, so. Call ACCESS_OK one time before the first data transfer. As seen above by the IOCTL.

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. Gets the value that is stored locally in the variable Local. The return value indicates whether the operation was successful.

Again, __get_user should be used only for addresses that have been verified with ACCESS_OK.

The above is related to the IOCTL operation, because of the reason for the length. Just write it down here. The next section goes on to write some other advanced methods of operation, such as blocking IO, non-clogging IO, and so on. Please pay attention.

Before the series of articles such as the following, welcome to read attention:

Linux device Drivers First: A brief introduction to device drivers

Linux Device driver Second article: Constructing and executing 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. Reserved

Focus on the public platform: Program Ape Interaction Alliance (coder_online), you can get the first original technical articles, and (Java/c/c++/android/windows/linux) technology Daniel to be friends, online communication programming experience. Get the basics of programming and solve programming problems. Program Ape 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.