Via:http://blog.sina.com.cn/s/blog_7ec8fc2c010157lc.html
1. Driver design
1) Drive classification
The drive is divided into character device driver, network interface driver, block device driver! These three categories, of which the first two are the focus.
①, character devices
A character device is a device that is accessed on its own, and the character driver is responsible for driving the character device, which is usually the first open, close, read, and write system calls!
②, block equipment
In most Unix systems, block devices cannot process data in bytes, and can only transmit a single block of data at a time or multiple lengths of 512 bytes (or a larger number of 2 powers).
For Linux, it allows a block device to transmit any number of bytes. Therefore, the difference between a block and a character device is only driven by a different interface to the kernel.
③, network interface
Any kind of network is done through an interface, an interface is usually a hardware device (eth0), but it can also be a purely software device, such as a loopback interface (LO). A network interface is responsible for sending and receiving data messages.
2) Driver installation
Method one, module mode
Method Two, directly compiled into the kernel
This method is to directly modify the Kconfig and Makefie (these two files should be placed in the location of your program, such as:/drivers/char directory you want to put a hello.c program, and then modify the directory of Kconfig and Makefile Oh, yes.)
3) Use of the driver
Directly take the country to embed the diagram is OH:
2, character device driver program design
First of all, introduce the following knowledge points:
▲: Device number
▲: Create a Device file
▲: Device Registration
▲: Important Data structure
▲: Equipment operation
1) Primary and secondary equipment number
The character device is accessed by a self-out device file. The character device file uses the "C" identifier of the first column of the output of ls-l.
If you use the Ls-l command, you will see that the number of friends in the device file entry is 2 (separated by a comma) These numbers are the primary and secondary device numbers for the device files.
①, device number function
The main device number is used to identify the driver that is connected to the device file (that is, the main device number is connected to the character device file and character device driver ). The secondary device number is used by the driver to determine which device is operating.
that is, the main device number is used to reflect the device type, and the secondary device number is used to differentiate between devices of the same type.
Description of ②, device number
▲: The kernel uses dev_t to describe the device number (which is essentially the unsigned int 32-bit integer, where the high 12 bits are the primary device number, and the lower 20 bits are the secondary device number).
▲:major (dev_t Dev)
Break out the main device number from the dev_t!
▲:minor (dev_t Dev)
Break out the secondary device number from the dev_t!
③, assigning the main device number
Static applications can be used, dynamic allocation of two methods.
A, static application
Method:
First, according to Documentation/devices.txt, determine a master device number that is not used, and then use the Register_chrdev_region function to register the device number!
Advantages:
Simple
Disadvantages:
Once the drive is widely used, this randomly selected master device number may cause a device number conflict and prevent the driver from registering.
Register_chrdev_region
function function:
Request to use count devices starting from (the main device number is unchanged, the secondary device number increases or decreases).
Function Prototypes:
int register_chrdev_region (dev_t from,unsigned count,const char *name)
Parameter description:
From: You want to apply the first device number
Count: Number of device numbers you would like to request to use
Name: Device name (reflected in/proc/devices).
Tip: The device number consists of the main device number and the secondary device number, the kernel provides macro MKDEV (Ma,mi) to form the device number, the macro MAJOR (dev) can be extracted from the device number of the main device number, through the macro MINOR (dev) can be raised from the device number from the device number.
return value:
Successful return 0, failed with a negative return value of the error number.
B, dynamic distribution
Method:
Assigning a device number using alloc_chrdev_region
Advantages:
Simple, easy to drive promotion
Disadvantages:
The device file cannot be created before the driver can be installed (because the main device number was not assigned before the installation).
Workaround:
After the driver is installed, query the device number from the/proc/devices
Alloc_chrdev_region
function function:
The request kernel dynamically allocates count number of device numbers, and this device number starts at Baseinor
Function Prototypes:
int alloc_chrdev_region (dev_t *dev,unsigned baseminor,unsigned count,const char *name)
Parameter description:
Dev: The device number assigned to
Baseminor: Start this device number
Count: Number of secondary device numbers that need to be assigned
Name: Device name (reflected in/proc/devices)
return value:
Successful return 0, failed with a negative return value of the error number.
④, logoff device number
Regardless of the method you use to assign the device number, you should release the device numbers when they are not being used.
Unregister_chrdev_region
function function:
To release count number of devices from start
Function Prototypes:
void Unregister_chrdev_region (dev_t from,unsigned count)
Parameter description:
From: The first device number to be deleted
Count: Number of device numbers to remove
return value:
No
⑤, creating a device file
Method One,
Manually created using the Mknod command
Where Mknod usage:
Mknod filename Type Major minor
Parameter meaning:
FileName: Device file name
Type: Device file type
Major: Main device number
Minor: Secondary device number
Routines:
Mknod serial0 C 100 0
Method two, automatically create
He said it would be introduced later, so we'll talk about it later!
2) Important structure
In the Linux character device driver program, there are three very important data structures:
struct file
struct Innod
struct file_operations
①, struct file
Represents an open file. Each open file in the system has an associated struct file in the kernel space (note: This file will be generated every time it is opened). It is created by the kernel when the file is opened and released after the file is closed!
Important Members:
loff_t F_pos
struct File_operation *f_op
②, struct inode
Used to log the physical information of a file. Therefore, it differs from the file structure that represents open files. A file can correspond to multiple file structures, but only one inode structure!
Important Members:
dev_t I_rdev: Device number
③, struct file_operations
A collection of function pointers that define the operations that can be run on the device.
The members in the struct point to functions in the drive that implement a special operation and leave NULL for unsupported operations.
For example, this structure can be written like this:
struct File_operation mem_fops = {
. Owner = This_module,
. Llseek = Mem_seek,
. Read = Mem_read,
. write = Mem_write,
. IOCTL = Mem_ioctl,
. open = Mem_open,
. Release = Mem_release,
};
3) Device Registration
In the Linux 2.6 kernel, character devices are described using struct Cdev.
The registration of a character device can be divided into the following 3 steps:
▲: Allocation Cdev
▲: Initialize Cdev
▲: Add Cdev
①, device registration (allocation)
Assign a struct CDEV
Function Prototypes:
Stuct Cdev *cdev_alloc (void)
return value:
A pointer to the CDEV struct was returned successfully, and NULL was returned by failure.
②, device registration (initialization)
The allocation of struct Cdev can be done using the Cdev_alloc function.
function function:
Initializes a struct CDEV
Function Prototypes:
void Cdev_init (Cdev *cdev,const struct file_operations *fops)
Parameter description:
Cdev: Cdev structure to initialize
FoPs: The set of operating functions corresponding to the device (where the main members of the file_operations structure are already described above)!
return value:
No
③, device registration (ADD)
The initialization of struct Cdev is done using the Cdev_init function.
function function:
Register a Struct_cdev, add the system to add the character device
Function Prototypes:
int Cdev_add (struct Cdev *p,dev_t dev,unsigned count)
Parameter description:
P: Character device structure to be added to the kernel
Dev: Device number
Count: Number of devices added
return value:
Successful return 0, failed with a negative return value of the error number.
④, logoff character device
Function Prototypes:
int Cdev_del (struct Cdev *p)
Parameter description:
P: The character device structure to unregister
return value:
Successful return 0, failed to return negative error number
4) Device operation
After completing the registration of the driver, the next step is to implement the operation supported by the device!!!
That is to implement the corresponding member in the file_operations structure.
①, open
Function Description:
The first operation in a device file does not require the driver to declare a corresponding method.
If this item is NULL, the device is turned on successfully, but your driver will not be notified.
Function Prototypes:
Int (*open) (struct inode *inode,struct file *filp)
Parameter description:
Inode: As a file node, there is only one node, no matter how many files the user opens, it only corresponds to an inode structure.
FILP: Whenever a file is opened, it corresponds to the file struct, which is usually used to track the state information of the files at run time.
②, Release
Function Description:
The kernel invokes the driver release () function when the last user process that opens the device executes a close () system call. The main task of the function is to clean up the unfinished input and output operations, release the resources, and customize the reset of the flag for the user.
This operation is referenced when the file structure is disposed, as if open,release could be NULL.
Function Prototypes:
Int (*release) (struct inode *inode,struct file *filp)
Parameter description:
With open operation
③, read
Function Description:
Used to fetch data from the device. The return value represents the number of bytes successfully read
Function Prototypes:
ssize_t (*read) (struct file *filp,char __user *buffer,size_t size,loff_t *p)
Function Description:
FILP: Target file struct-body pointer
Buffer: buffers that correspond to the placement of information (both the User space memory address)
Size: Length of information to read
P: The position of the read relative to the beginning of the file offset, after reading the information, the pointer will generally move, the value of the move is to read the length of the information value)
④, write
Function Description:
Sends the data to the device, and the return value represents the byte function that was successfully written (note: This operation and the previous read of the file file are blocking operations).
Function Prototypes:
ssize_t (*write) (struct file *filp,contst char __user *buffer,size_t count,loff_t *ppos)
Parameter description:
FILP: Target file struct-body pointer
Buffer: The hehe buffer to write to the file
Size: The length of information to write
Poos: The current offset position, which is usually used to determine if the write file is out of bounds
⑤, Llseek
Function Description:
Initializes a struct CDEV
Function Prototypes:
loft_t (*llseek) (struct file *filp,loff_t p,int orig)
Parameter description:
FILP: Target file struct-body pointer
P: Target offset for file positioning
Orig: The starting address for the location of the file, which can be the beginning of the file (Seek_set, 0), the current position (Seek_cur, 1), the end of the file (Seek_end, 2).
5) Read and write
For reading and writing, here are some explanations:
FILP is a file pointer, and count is the amount of data that is requested for transmission. The buff parameter points to the data cache, and finally, OFFP indicates where the file is currently accessed!
Where: The buff parameter of the read and write methods is a user-space pointer. Therefore, it cannot be consumed directly by the kernel code, for the following reasons:
User hole home pointers may not be valid at all in kernel space-there is no mapping for that address!
In this way, the kernel provides a special function to permanently access the user space of the pointer, for example:
int copy_from_user (void *to,const void __user *from,int N)
int Copy_to_user (void __user *to,const void *from,int N)
By the way, let's introduce some more:
A function that can pass a variable of kernel space to the address of a user's space is similar to the following:
Get_user (VAR,PTR);
Put_user (VAR,PTR);
Long Stmcpy_from_user (char *dst,const char __user *src,long count);
Strlen_user (str);
These functions are used to make the necessary data interactions with the user space using kernel space, which is too restrictive to pass the data using the return value of the system call.
Character device driver (program design)-①