Introduction to the concept of Linux character drive

1. Character-driven framework

Q: How do the applications open, read, and write find the driver's open, read, and write functions?

Answer: The application's open, read, and write are implemented in the C library. It uses the swi val instruction to trigger an exception. This exception will enter the kernel space. In the kernel's exception handling function, there is an input based on us Val to decide whether to call the system_open or system_read, system_write functions, these functions have different properties according to our open different files, different files have different attributes (such as device type (character device or block device or network device), main device number) These attributes find the lower-level driver.

 

Q: What is the major device number and what is the minor device number

Answer: The Linux major device number is used to distinguish between different hardware device types, such as the difference between LED and serial port;
Linux minor device number is used to distinguish between different hardware devices, such as the difference between serial port 1 and serial port 2;

 

Q: What method is used to find the open function of the driver

Answer: Through a registration function + device node

The registration functions are as follows (old registration functions, new ones will be discussed later):

register_chrdev(unsigned int major, const char * name, const struct file_operations * fops)

Parameter 1: Major device number (important)

Parameter 2: Name (not important)

Parameter 3: file_operations structure (important)

Device node:

It can be created manually or automatically. For the time being, it will only be created manually.

mknod  /dev/xxx  c  252  0

Create a device node named / dev / xxx, c represents the character device node, 252 is the major device number, and 0 is the minor device number.

 

Q: The application program is generally executed by the main function, so what is the driver program to execute first?

Answer: Through a macro, specify the entry function of the driver, and the entry function will be executed when the driver is loaded.

For example: module_init (first_drv_init); // Used to modify the entry function

Naturally, the exit function of the driver will be executed when the driver is unloaded.

For example: module_exit (first_drv_exit); // Used to modify the export function
 

 

The driver source program is as follows:

#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/module.h>
 
 
int major;
static int first_drv_open(struct inode * inode, struct file * filp)
{
	printk("first_drv_open\n");
	return 0;
}
static int first_drv_write(struct file * file, const char __user * buffer, size_t count, loff_t * ppos)
{
	printk("first_drv_write\n");
	return 0;
}
 
/* File operations struct for character device */
static const struct file_operations first_drv_fops = {
	.owner		= THIS_MODULE,
	.open		= first_drv_open,
	.write      = first_drv_write,
};
 
/* 驱动入口函数 */
static int first_drv_init(void)
{
	/* 主设备号设置为0表示由系统自动分配主设备号 */
	major = register_chrdev(0, "first_drv", &first_drv_fops);
	return 0;
}
 
/* 驱动出口函数 */
static void first_drv_exit(void)
{
	unregister_chrdev(major, "first_drv");
}
 
module_init(first_drv_init);  //用于修饰入口函数
module_exit(first_drv_exit);  //用于修饰出口函数	
 
MODULE_AUTHOR("LWJ");
MODULE_DESCRIPTION("Just for Demon");
MODULE_LICENSE("GPL");  //遵循GPL协议

Makefile source code is as follows:

ifneq ($(KERNELRELEASE),)
 
obj-m := first_drv.o
 
else
	
KDIR := /home/opt/EmbedSky/linux-2.6.30.4
 
all:
	make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
clean:
	rm -f *.ko *.o *.mod.o *.mod.c *.symvers
 
endif

The test procedure is as follows:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
 
int main(void)
 
{
	int fd;
	int val = 1;
	fd = open("/dev/xxx",O_RDWR);    //打开名为  /dev/xxx  的设备节点
	if(fd < 0)
	{
		printf("open error\n");
	}
	
	write(fd,&val,4);
	
	return 0;
}

The test steps on the development board are as follows:

[WJ2440]# insmod first_drv.ko 
[WJ2440]# ./first_test 
open error                    //没有创建设备节点
[WJ2440]# cat proc/devices 
Character devices:
  1 mem
  4 /dev/vc/0
  4 tty
  5 /dev/tty
  5 /dev/console
  5 /dev/ptmx
  7 vcs
 10 misc
 13 input
 14 sound
 29 fb
 81 video4linux
 89 i2c
 90 mtd
116 alsa
128 ptm
136 pts
180 usb
188 ttyUSB
189 usb_device
204 tq2440_serial
252 first_drv                //我们创建的字符设备,主设备号252
253 usb_endpoint
254 rtc
 
Block devices:
259 blkext
  7 loop
  8 sd
 31 mtdblock
 65 sd
 66 sd
 67 sd
 68 sd
 69 sd
 70 sd
 71 sd
128 sd
129 sd
130 sd
131 sd
132 sd
133 sd
134 sd
135 sd
179 mmc
[WJ2440]# mknod /dev/xxx c 252 0        //手动创建一个字符设备节点
[WJ2440]# ls -l /dev/xxx 
crw-r--r--    1 root     root      252,   0 Jan  1 20:49 /dev/xxx
[WJ2440]# ./first_test                 //有设备节点后成功我们的应用程序运行了
first_drv_open
first_drv_write
[WJ2440]# 

This article refers to:

https://blog.csdn.net/lwj103862095/article/details/17468587

Published 42 original articles · Like 10 · Visitors 10,000+

Guess you like

Origin blog.csdn.net/qq_37659294/article/details/104302700