copy from :https://blog.csdn.net/weixin_42462202/article/details/99887783
Linux driver entry (a) character device driver basis of
article directories
Linux driver entry (a) device driver base characters
a drive Introduction
II character device driver concept
Third, the registered character device
four or compile the module
five load modules
Sixth, create a device node
seven test
a drive Introduction
Linux driver into character device driver, a block device drivers, network device driver
Character device driver
A devices must character in serial order of access, such as led, a touch screen, a mouse, etc.
Call accessible through open, close, read, write and other systems
Block device driver
Block access device may be in any order, in units of blocks to operate, such as a hard disk, and so the EMMC
There are great differences drive the design block and character devices, but can also be accessed via open, close, read, write and other system calls, but these are generally using the file system to manage
Network device driver
Network device is designed for receiving and sending data packets, in the file system, and there is no corresponding device node, accessed through socket interface
This paper mainly on the character device
Second, the concept of character device drivers
under Linux everything is a file, such as a led device performance in the file system as a device node / dev / led, application layer through open, read, write and other system calls can be control led
For example, want led light, open the device file write 1
int fd;
int val = 1;
Open = FD ( "/ dev / led", XXX);
Write (FD, & Val, the sizeof (Val));
such that it can be led lit
Now think about a question, why so that you can make the led light up?
To get led lights, you must operate the hardware, operating hardware that is part of the work led drive completed
The easiest way is, for the application layer led to the open operation, then the corresponding one of led_open led driver. Led to the application layer for write operations, the operation led to a corresponding one of the driver led_write then led_write operation to control the hardware, then control led
Then on led device nodes open, write system call, how to call to the driver's led_open, led_write it?
When the application layer calls open, read, write and other operations, will cause an exception, causing the system to become kernel mode, and then to execute the corresponding system call sys_open, sys_read, sys_write etc.
Will go to find the appropriate driver sys_open, sys_read, sys_write, and then calls the driver's open, read, write hardware to operate
As shown below
Sys_open then call in a virtual file system, how did you find led driver instead of the other drivers do?
First, tell us about the device number
Each device has a device number, 32-bit, where 12 indicates a high number of master device, 20 represents a lower minor number
Use ls / dev / led -l viewing device, the following information can be obtained
the root-RW. 1 ---- CRW 0 10, 131. 1 12:00 Jan / dev / LED
. 1
wherein 10, 131 denotes a device number, device number 10 indicates the master, minor number 131 denotes
To facilitate understanding, we can consider that there is a character in the kernel array device to the master device index number, the device itself is a character array element, there is a character device file set of operations, a series of operations set function (e.g. led_open, led_write, led_read)
sys_open system calls to find a good array of equipment by the master file, a set of calls to the driver's led_open led by a character device file operations and other functions
Character device driver is to improve the fops (file operation set), and then specify the device number, up to the kernel character device
Third, the character device registered
first look at the character device object
struct file_operations {
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
int (*open) (struct inode *, struct file *);
...
};
struct the cdev {
struct the kobject Kobj;
struct Module1 * owner; / * View Module * /
const struct the file_operations * OPS; / * file operations set * /
struct the list_head List;
the dev_t dev; / * device number * /
unsigned int COUNT;
};
wherein the dev_t members define a device number, 32-bit, high resolution master device 12, 20 for the lower sub-device number
Kernel following two major and minor number macro obtain
MAJOR (dev_t dev) // major number
MINOR (dev_t dev) // minor number
using the following macro acquisition device number
MKDEV (int major, int minor)
each device has its own character corresponding device number range, here's how to apply the device number
No application equipment
Dynamic allocation
This function specifies the number of times a device number and device number can be dynamically assigned major number
/ *
* Dev: application to the device number returned
* baseminor: starting minor number
* count: the number of the application device number
* /
int alloc_chrdev_region (the dev_t * dev, unsigned baseminor, unsigned COUNT,
const char * name)
static allocation
This function must be the number of major and minor number and device number
/ *
* From: Actually device number
* count: the number of device number
* /
int register_chrdev_region (from the dev_t, unsigned COUNT, const char * name)
after the completion of the application device number, you can use this device number to register a character device
Register character device
Function and character-related equipment
void cdev_init (struct the cdev *, struct the file_operations *);
struct the cdev * cdev_alloc (void);
void cdev_put (struct the cdev * P);
int cdev_add (struct the cdev *, the dev_t, unsigned);
void cdev_del (struct the cdev *);
cdev_init : FOPS and equipment associated with the character used, which is a file operation file_operations set, there is provided a series of manipulation functions (e.g. open, read, write)
cdev_alloc: assign a character device object
cdev_add: Registration character device
cdev_del: cancellation of a character device
A step of registering character device
struct cdev * cdev_alloc (void); // assign character device
void cdev_init (struct cdev *, struct file_operations *); // Bind a fops
int cdev_add (struct cdev *, dev_t , unsigned); // character and to apply to the device the device number registered into the kernel
following is a simple character device driver
mydev.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
static dev_t dev_id;
static struct cdev *mydev;
ssize_t mydev_read(struct file *file, char __user *data, size_t size, loff_t * loff)
{
printk("mydev_read\n");
return 0;
}
ssize_t mydev_write(struct file *file, const char __user *data, size_t size, loff_t *loff)
{
printk("mydev_write\n");
return 0;
}
int mydev_open(struct inode *inode, struct file *file)
{
printk("mydev_open\n");
return 0;
}
/* 文件操作集合 */
static struct file_operations mydev_fops = {
.owner = THIS_MODULE,
.read = mydev_read,
.open = mydev_open,
.write = mydev_write,
};
int mydev_init the __init static (void)
{
/ * Application device number * /
alloc_chrdev_region (the dev_id &,. 1,. 1, "that mydev");
/ * Assign character device * /
that mydev cdev_alloc = ();
/ * Set character device * /
cdev_init (that mydev, & mydev_fops);
/ * Register character device * /
cdev_add (mydev, dev_id, 1);
/ * Print request to the major and minor number * /
the printk ( "Major: D%; Minor:% D \ n-", MAJOR (the dev_id), MINOR (the dev_id));
return 0;
}
static __exit void mydev_exit(void)
{
cdev_del(mydev);
kfree(mydev);
unregister_chrdev_region(dev_id, 1);
}
module_init(mydev_init);
module_exit(mydev_exit);
MODULE_LICENSE ( "GPL");
Fourth, the compiler module
written in after the driver, how do we compile the driver, there are two ways, one is compiled into the kernel and drivers together, one is written into the driver alone module
The second presentation here
The drivers are compiled as modules need to write Makefile
Makefile as follows
KERN_DIR = / work / linux / kernel /
all:
make -C $(KERN_DIR) M=`pwd` modules
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order
obj-m + = mydev.o
where KERN_DIR = / work / linux / kernel / kernel tree represents, according to the need to modify the path where your kernel
obj-m + = mydev.o show file to be compiled mydev.c
make -C $ (KERN_DIR) M = pwd modules show a jump to the kernel source tree, compiling module
The Makefile and mydev.c put together, perform make, mydev.ko drive module can be obtained
Fifth, the load module
using the driving module can be loaded insmod xxx.ko
Use lsmod can view the currently loaded module
You can uninstall the driver using rmmod xxx loaded modules
The above mydev.ko copied to generate experimental platform, execute insmod mydev.ko
Once loaded module, the kernel will run module_init (mydev_init) specified module entry, mydev_init function, we apply the device number, registered the character device, and print the major and minor device numbers
You can see the print information
Major: 250; Minor: 1
1
represents the major number 250, minor number 1 (what you see may vary)
At this point the module has been loaded, we can see through the cat / proc / devices that we have registered the character device
But did not generate device nodes, we are still unable to operate the equipment in the / dev directory, here's how to create a device node
Six, create device nodes
create a device node is created automatically and manually created is divided into the following were introduced
Manually create
In the top drivers to print out major: 250; minor: 1, we can use this information to create device nodes
By the following command to create a device node
mknod device name device type (character: c, block: b) major number from the device number
performed
mknod / dev / mydev c 250 1
run after the generation of the device node / dev / mydev
Created automatically
It is automatically created using mdev udev mechanism or mechanisms, when the device driver creates related information / sys, udev mdev or device nodes are created according to the information
The following describes how to create device nodes
static struct class *mydev_class;
mydev_class = class_create (THIS_MODULE, "mydev "); // Create a class
device_create (mydev_class, NULL, dev_id, NULL, "mydev"); // Create a node device according to the device number
destruction device node
device_destroy (mydev_class, dev_id); // device node is destroyed
class_destroy (mydev_class); // class destruction
driving modified
mydev.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/device.h>
static dev_t dev_id;
static struct cdev *mydev;
static struct class *mydev_class;
ssize_t mydev_read(struct file *file, char __user *data, size_t size, loff_t * loff)
{
printk("mydev_read\n");
return 0;
}
ssize_t mydev_write(struct file *file, const char __user *data, size_t size, loff_t *loff)
{
printk("mydev_write\n");
return 0;
}
int mydev_open(struct inode *inode, struct file *file)
{
printk("mydev_open\n");
return 0;
}
static struct file_operations mydev_fops = {
.owner = THIS_MODULE,
.read = mydev_read,
.open = mydev_open,
.write = mydev_write,
};
int mydev_init the __init static (void)
{
/ * Application device number * /
alloc_chrdev_region (the dev_id &,. 1,. 1, "that mydev");
/ * Assign character device * /
that mydev cdev_alloc = ();
/ * Set character device * /
cdev_init (that mydev, & mydev_fops);
/ * Register character device * /
cdev_add (mydev, dev_id, 1);
/ * Print request to the major and minor number * /
the printk ( "Major: D%; Minor:% D \ n-", MAJOR (the dev_id), MINOR (the dev_id));
mydev_class = class_create(THIS_MODULE, "mydev");
device_create(mydev_class, NULL, dev_id, NULL, "mydev");
return 0;
}
static __exit void mydev_exit(void)
{
device_destroy(mydev_class, dev_id);
class_destroy(mydev_class);
cdev_del(mydev);
kfree(mydev);
unregister_chrdev_region(dev_id, 1);
}
module_init(mydev_init);
module_exit(mydev_exit);
MODULE_LICENSE ( "GPL");
recompile module loaded
View / sys / dev / char directory, you will find some more information 250: 1
At this point see ls / dev / mydev, you will find the / dev directory already have a mydev
Seven test
after each driver is finished, you need to write application testing
Here is our test program
mydev_test.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
int val = 1;
int fd = open("/dev/mydev", O_RDWR);
write(fd, &val, sizeof(val));
read(fd, &val, sizeof(val));
0 return;
}
compiled
arm-linux-gcc mydev_test.c
load module
insmod mydev.ko
execute the test program
./a.out
can see the console print
[2639.832633] mydev_open
[2639.833528] mydev_write
[2639.836014] mydev_read
demonstrated normal driver
This article to end here
----------------
Disclaimer: This article is CSDN blogger original article "JT students", following the CC 4.0 BY-SA copyright agreement, reprint Please include links to the original source and this statement.
Original link: https: //blog.csdn.net/weixin_42462202/article/details/99887783