当前位置:网站首页>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 !
边栏推荐
- PMP practice once a day | don't get lost in the exam -7.28 (including agility + multiple choices)
- I heard that many merchants of crmeb have added the function of planting grass?
- DJ-131/60C电压继电器
- Table lock query and unlocking in SQL development part 1
- How to write a JMeter script common to the test team
- Here comes the full open source free customer service system
- SRTT-110VDC-4H-C时间继电器
- Pycharm - output exception of program run and default comment of added function
- [Game Testing Engineer] get to know game testing for the first time - do you know it?
- Template injection summary
猜你喜欢
随机推荐
sql语句的执行流程
Introduction to grpc
封装统一返回对象MessageResult
[touch] count the number of engineering documents, code lines, and line comment coverage
游戏测试的概念是什么?测试方法和流程有哪些?
从thinkphp远程代码执行学php反射类
[MP error] MP: 'getbasemappe serviceimpl' claims
crmeb 标准版Window+phpstudy8安装教程(一)
I heard that many merchants of crmeb have added the function of planting grass?
[Game Testing Engineer] get to know game testing for the first time - do you know it?
【LeetCode】35、搜索插入位置
Voltage relay dy-28c
How to set some app application icons on the iPhone Apple phone that you don't want others to see? How to hide the app application settings on the mobile desktop so that they can be used normally afte
PMP每日一练 | 考试不迷路-7.28(包含敏捷+多选)
Hjs-de1/2 time relay
Leetcode - random set, longest multiclass subsequence
流畅到让人头皮发麻的单商户商城,你用过吗?
Stack expression
3588. Permutation and binary
Summary of common redis commands (self provided)








