当前位置:网站首页>Write a standard character device driver with your hands
Write a standard character device driver with your hands
2022-07-28 15:28:00 【Embedded Yuexiang Garden】
Take you hand-in-hand to write a character device driver
Preface
The key point of character device driver development is to use register_chrdev Function to register character devices , Use when you no longer use the device unregister_chrdev Function to unregister the character device . But this kind of writing is the registration method only used by older versions , This time we use a relatively new way to register the device .
Register a new device
Why register in a new way
We all know how to use it register_chrdev When registering a device, we need to first specify a master device number , There will be two drawbacks :
- We need to determine which main equipment numbers are not used in advance ;
- All secondary equipment numbers under a primary equipment number will be used ;
Why use register_chrdev Registration will use all the secondary device numbers under the primary device number ? Before we understand this problem, we need to know what the primary equipment number and secondary equipment number are .
- The main equipment, : The system is used to determine the driver ( Device type : Such as USB equipment , Hard disk device );
- Secondary device number : The driver is used to determine the specific device ;
We assigned the master device number in the driver , For example, now set LED The main equipment number is 200, that 0~1048575(2^20-1) All the secondary equipment numbers in this section are LED A piece of equipment went away , This will be a great waste of resources .
The best way to solve these two problems is to report to Linux Kernel application , If you need a few, apply for a few , from Linux The kernel allocates the device number that the device can use , Including the main equipment number , It also includes the secondary equipment number , In this way, you can apply for as many as you need , Others that are not used will not be applied .
Apply for equipment number
There are two situations when applying for equipment number in a new way , The first is that the equipment number has been assigned , Then we need to use the following statement to apply for the equipment number :
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)
If the equipment number we need is not specified , Then we can use the following statement to allocate the device number :
int register_chrdev_region(dev_t from, unsigned count, const char *name)
Parameters from Is the starting equipment number to apply for , That is, the given equipment number ; Parameters count Is the number of applications , It's usually a ; Parameters name Is the name of the device .
So how do we know if the equipment number is specified ?
We can apply a if function , By judging the equipment number major Is it 0, To determine whether the equipment number is assigned , The specific statements are as follows :
int major; /* The main equipment, */
int minor; /* Secondary device number */
dev_t devid; /* Device number */
if (major) {
/* Defines the master equipment number */
devid = MKDEV(major, 0); /* Most of the drive sub equipment numbers are selected 0 */
register_chrdev_region(devid, 1, "test");
} else {
/* No device number defined */
alloc_chrdev_region(&devid, 0, 1, "test"); /* Apply for equipment number */
major = MAJOR(devid); /* Get the master device number of the assigned number */
minor = MINOR(devid); /* Get the secondary equipment number of the assigned number */
}
The first 1~3 That's ok : It defines the main function / Secondary device number variable major and minor, And device number variables devid;
The first 5 That's ok : Judge the main equipment number major Whether it works ;
The first 6 That's ok , If major If it works, use MKDEV To construct the construction preparation number , Secondary equipment number selection 0;
The first 7 That's ok , Use register_chrdev_region Function to register the device number .
The first 9~11 That's ok , If major Invalid , That means there is no given equipment number . In this case, we need to use alloc_chrdev_region Function to apply for the device number . The equipment number will be used after successful application MAJOR and MINOR To extract the main equipment number and secondary equipment
So why can I use major To determine whether the equipment number is assigned ?
Because in Linux Generally, if the main equipment number is given in the driver, it means that the equipment number of this equipment has been determined , Because the secondary equipment number is basically selected 0, That's a big deal Linux A conventional rule in driver development .
Cancel device number
If you want to cancel the equipment number , Use the following code :
unregister_chrdev_region(devid, 1); /* Cancel device number */
Register device
stay Linux We use cdev Structure to represent a character device , stay cdev There are many members in the structure , It includes the following members :
struct cdev {
struct kobject kobj;
struct module *owner;
const struct file_operations *ops;
struct list_head list;
dev_t dev;
unsigned int count;
}
stay cdev There are two important member variables in : ops and dev, These two characters are the set of device file operation functions file_operations And equipment number dev_t. among file_operations It is the device driver interface , and dev_t It is the equipment number obtained after the calculation of the main equipment number and secondary equipment number .
Before writing a character device driver, you need to define a cdev Structural variable , This variable represents a character device , As shown below :
struct cdev led_cdev;
cdev It's defined in include/linux/cdev.h in ,cdev yes Linux The structure used to manage character devices , It adopts array structure design in the kernel , In this way, the array size is determined by the number of master device numbers in the system , This equipment number is managed by linked list .
There can be multiple sub devices under the same main equipment number . Device as file , The upper application needs to access the device , Must pass the document ,cdev Contained in the file_operations Structure , This structure is the set of file operations driven .
initialization cdev function
Well defined cdev Variables will be used later cdev_init Function to initialize it , cdev_init The function prototype is as follows :
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
- Parameters
cdevIs to initializecdevStructural variable ; - Parameters
fopsIs a collection of character device file operation functions ;
Use cdev_init Function initialization cdev The example code of the variable is as follows :
struct cdev xxxxxcdev;
/* Device operation function */
static struct file_operations test_fops = {
.owner = THIS_MODULE,
/* Other specific initial items */
};
testcdev.owner = THIS_MODULE;
cdev_init(&xxxxxcdev, &xxxxx_fops); /* initialization cdev Structural variable */
Add character device
cdev_add Function to Linux The system adds character devices, that is cdev Structural variable , use first cdev_init Function completion to cdev Initialization of structure variables , And then use cdev_add Functional direction Linux The system adds this character device .
cdev_add The function prototype is as follows :
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
The above registration method is the new registration method , A lot of character driven devices use this method to drive Linux Add character devices in the kernel .
If you add the procedure for assigning equipment numbers , Then what they implement together is the function register_chrdev The function of . Although the registration process has become complicated , But this registration method will not waste resources .
Summary of registered equipment
Through the above study, we have learned how to apply for equipment number 、 Register device 、 Add equipment , This method is a relatively new form , You can learn the new registration method directly , Some old interfaces have been abandoned , So if you want to use it, use the latest !
Create device nodes
What we used in the previous learning process has always been mknod Manually create a device node . However, for nodes created in this way, we need to manually create nodes after loading the driver module , But today's nodes are created in this way , When we use modprobe If the driver module is loaded successfully, it will be automatically in /dev Create the corresponding device file under the directory .
stay Linux Pass through udev To create and delete device files ,udev It can detect the status of hardware equipment in the system , You can create or delete device files according to the status of hardware devices in the system .
For example, use modprobe After the command successfully loads the driver module, it will be automatically in /dev Create the corresponding device node file in the directory , Use rmmod Command to remove the driver module after unloading /dev The device node file in the directory .
Create and delete classes
The automatic creation of device nodes is done in the driver's entry function , Generally in cdev_add Add the code related to automatically creating the device node after the function . First, create a class class , class It's a structure , Defined in the file include/linux/device.h Inside .
class_create There are two parameters , Parameters owner It's usually THIS_MODULE, Parameters name It's a class name .
The return value is a pointer to the structure class The pointer to , That is, the created class .
When uninstalling the driver, you need to delete the class , The class deletion function is class_destroy, The function prototype is as follows :
void class_destroy(struct class *cls);
Parameters cls Is the class to be deleted .
Create device
Let's create class It will not be possible to automatically create device nodes in the future , We also need to create a device under this class . Use device_create Function to create a device under the class .
device_create The function has the following parameters :
struct device *device_create(struct class *class,
struct device *parent,
dev_t devt,
void *drvdata,
const char *fmt, ...)
device_create It's a variable parameter function :
- Parameters
classThis is the class to be created by the device ; - Parameters
parentIs the parent device , It's usuallyNULL, That is, there is no parent device ;* ParametersdevtIt's the equipment number ; ParametersdrvdataIt is some data that the device may use , It's usuallyNULL; - Parameters
fmtIs the name of the device , If you setfmt=xxxWords , Will generate/dev/xxxThis device file ; - The return value is the created device ;
alike , When uninstalling the driver, you need to delete the created device , The device deletion function is device_destroy.
Set file private data
Every hardware device has some properties , For example, the main equipment number (dev_t), class (class)、 equipment (device)、 Switch status (state) wait , When writing drivers, you can write all these attributes in the form of variables , As shown below :
dev_t devid; /* Device number */
struct cdev cdev; /* cdev */
struct class *class; /* class */
struct device *device; /* equipment */
int major; /* The main equipment, */
int minor; /* Secondary device number */
There must be no problem writing like this , But it's not professional !
For all the attribute information of a device, we'd better make it into a structure . Write driver open Function to add the device structure as private data to the device file , As shown below :
struct test_dev{
dev_t devid; /* Device number */
struct cdev cdev; /* cdev */
struct class *class; /* class */
struct device *device; /* equipment */
int major; /* The main equipment, */
int minor; /* Secondary device number */
};
struct test_dev testdev;
static int test_open(struct inode *inode, struct file *filp)
{
filp->private_data = &testdev; /* Set up private data */
return 0;
}
stay open After setting the private data in the function , stay write、 read、 close Direct reading in equal function private_data The equipment structure can be obtained .
Conclusion
I believe that after this article, you already know how to create classes and devices through new methods , Of course, you may not be able to compile a complete driver file yet , But it doesn't matter , As long as you continue to learn , I believe you will be able to write a device driver by yourself soon !
边栏推荐
- Opencv - closely combine multiple irregular small graphs into large graphs
- Crmeb knowledge paid manual installation tutorial
- An idea of modifying vertex height with shader vertex shader
- 3559. Ring counting
- What functions will be added to crmeb Standard Version 4.4
- crmeb 标准版window+phpstudy8安装教程(二)
- day 7/12
- For loop
- 3540. Binary search tree
- Pytorch - autograd automatic differentiation
猜你喜欢
随机推荐
celery 相关
4518. Minimum ticket price
Understanding of entropy and cross entropy loss function
MIT指出公开预训练模型不能乱用
ArcGIS Pro 中的编辑器
Deepfacelab model parameters collection
Svg verification code recognition experience
树上启发式合并简单题
3477. Simple sorting
3564. Date category
2021-06-29
3559. Ring counting
Repvgg paper explanation and model reproduction using pytoch
sql语句的执行流程
2022年全球程序员平均薪资发布,中国排名很意外
Knowledge payment open source system
The difference between @notnull, @notblank, @notempty of commonly used verification annotations
Principle and configuration of MPLS LDP
[MP error] MP: 'getbasemappe serviceimpl' claims
What functions will be added to crmeb Standard Version 4.4









