Linux driver development 4412 development board learning (D): generation device nodes and write a simple application calls driver

Device nodes

Linux 2.6 version to the huge changes for previous versions of data skip
learning to be "the beginning of the end for the" work less than the time will not go to waste

About miscellaneous equipment

Miscellaneous equipment (device No. 10)
encapsulate the part of a character device, there are some bad drivers also return to categorize miscellaneous equipment
Why introduction of miscellaneous equipment

  • Save major number
    if all the drivers are using a character device, then all the equipment will soon run out of numbers, a total of 255 device number
  • Write driving relatively simple
    if packaged directly miscellaneous equipment, then the process can further reduce the number of registration of the master device

Initialization part of the source file in the "driver / char / misc.c" to force the compiler, Linux official band, for some simple driving easier, to make a simple character device packaging
miscellaneous equipment registered the header file "linux / miscdevice. h "

	struct miscdevice  {
		int minor;//设备号,一般自动分配
		const char *name;//生成设备节点的名称(随意)
		const struct file_operations *fops;//指向一个设备节点文件
		struct list_head list;
		struct device *parent;
		struct device *this_device;
		const char *nodename;
		mode_t mode;
	};

Two important functions

extern int misc_register(struct miscdevice * misc);//杂项设备节点注册
extern int misc_deregister(struct miscdevice *misc);//卸载

Miscellaneous equipment kernel file structure

Sign up device node which is essentially built a special file that contains the file name to open, close, and other operational functions
header file that contains the file structure is "linux / fs.h"
structure follows file_operations file is very important! !
Here Insert Picture Description
Many parameters, choose according to demand
mandatory parameters are:

  • .owner generally THIS_MODULE
  • .open open file functions
  • .release Close File function
    used here mandatory parameters outside
  • .unlocked_ioctl the GPIO operation, traditional values ​​to the underlying application driving

How to generate device nodes

Code

#include <linux/init.h>
#include <linux/module.h>
/*driver register*/
#include <linux/platform_device.h>

/*注册杂项设备头文件*/
#include <linux/miscdevice.h>
/*注册设备节点的文件结构体*/
#include <linux/fs.h>

#define DRIVER_NAME "hello_ctl"
#define DEVICE_NAME "hello_ctl_dev"//设备名
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("GYY");

/*打开文件函数*/
static int hello_open(struct inode * pinode , struct file * pfile )
{
	printk(KERN_EMERG "Hello OPEN !!\n");
	return 0;
}
/*关闭文件函数*/
static int hello_release(struct inode * pinode, struct file * pfile)
{
	printk(KERN_EMERG "Hello RELEASE !!\n");
	return 0;
}
/*IO控制函数*/
static long hello_ioctl(struct file * pfile, unsigned int cmd, unsigned long arg)
{
	printk("cmd is %d,arg is %d\n",cmd,arg);
	return 0;
}
/*杂项设备内核文件结构体,要注册函数*/
static struct file_operations hello_ops = {
	.owner = THIS_MODULE,//所有者,THIS_MODULE
	.open = hello_open,
	.release = hello_release,
	.unlocked_ioctl = hello_ioctl,
	
};

/*杂项设备节点结构体*/
static struct miscdevice hello_dev = {
	.minor = MISC_DYNAMIC_MINOR,//自动分配设备号
	.name = DEVICE_NAME,//设备名
	.fops = &hello_ops,//该成员为杂项设备内核文件结构体
};


static int hello_probe (struct platform_device *pdv){
	
	printk(KERN_EMERG "\tinitialized\n");
	/*生成设备节点*/
	misc_register(&hello_dev);
	
	return 0;
}

static int hello_remove (struct platform_device *pdv){
	
	printk(KERN_EMERG "\tremove\n");
	misc_deregister(&hello_dev);
	return 0;
}

static void hello_shutdown (struct platform_device *pdv){
	
	
}

static int hello_suspend (struct platform_device *pdv,pm_message_t state){
	
	return 0;
}

static int hello_resume (struct platform_device *pdv){
	
	return 0;
}


struct platform_driver hello_driver = {
	.probe = hello_probe,
	.remove = hello_remove,
	.shutdown = hello_shutdown,
	.suspend = hello_suspend,
	.resume = hello_resume,
	.driver = {
		.name = DRIVER_NAME,
		.owner = THIS_MODULE,
	}
};


static int hello_init(void)
{
	int DriverState;
	printk(KERN_EMERG "HELLO WORLD enter!\n");
	DriverState=platform_driver_register(&hello_driver);
	
	printk(KERN_EMERG "\t%d\n",DriverState);
	return 0;
}

static void hello_exit(void)
{
	printk(KERN_EMERG "HELLO WORLD exit!\n");
	platform_driver_unregister(&hello_driver);
}

module_init(hello_init);
module_exit(hello_exit);

Code Analysis

Next, we code a brief analysis of the following section our previous registration driven code is substantially the same, we hello_probe (i.e. drive initialization function) call misc_register in () to register miscellaneous equipment node, miscellaneous equipment node is like a device mounted on the device, like its essence, is a device, so that if the registration is successful we should be able to see our equipment hello_ctl_dev registered in / dev / in. We call misc_deregister in hello_remove in () to unload miscellaneous equipment nodes, indicating that we rmmod the module / dev / in hello_ctl_dev not exist.

The results presentation

Install module
Here Insert Picture Description
View / dev /
Here Insert Picture Description
Here Insert Picture Description
presence hello_ctl_dev, device node generates success
uninstall module
Here Insert Picture Description
View / dev /
Here Insert Picture Description
our device node does not exist

Write a simple application calls driver

Fundamental

In front of our generation device nodes, but also to the device node registered kernel file structures, while in the kernel file structure, we also registered open, close, ioctl function, we do what those purposes are, of course, is these functions supply the upper application use, so as to complete our mission-driven development.
Of course, Linux and all are criteria document greatly facilitate our operations, we just put the device node / dev / is used as a file operation then you can call our driver, file operations Linux system calls are mapped to us written driving function (this process is not particularly understand), we call the function system call, that perform substantially the functions we drive in.

Before writing the code should be aware of

Header files needed

Print header file: #include <stdio.h>
header file needed to invoke applications

  • #include <sys/types.h>基本系统数据类型。系统的基本数据类型在32位编译环境中保持32位值,并会在64位编译环境中增长为64位值
  • #include <sys/stat.h>系统调用函数头文件。可以调用普通文件,目录,管道,socket,字符,块的属性
  • #include <fcntl.h>定义了open函数
  • #include <unistd.h>定义了close函数
  • #include <sys/ioctl.h>定义了ioctl函数

调用的函数

open函数是返回文件描述符
ioctl是应用向驱动传值
close关闭打开的文件

编译代码

使用交叉编译器 arm-none-linux-gnueabi-gcc

实验

代码

#include <stdio.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>

int main()
{
	int fd;//文件描述符
	char *hello_node = "/dev/hello_ctl_dev";//文件地址
	
	/*O_RDWR可读可写,O_NDELAY非阻塞方式打开*/
	if((fd = open(hello_node,O_RDWR|O_NDELAY)) < 0)
	{
		printf("APP open %s failed\n",hello_node);
	}
	else
	{
		printf("APP open %s success\n",hello_node);
		ioctl(fd,1,6);//调用ioctl
	}
	close(fd);//关闭文件
}

代码分析

我们调用open函数来打开文件并返回了文件描述符,当我们执行open函数时,系统会执行我们在驱动代码中所写的hello_open这个函数,应当会打印“Hello OPEN !!”,如果文件描述符不小于0(打开成功)那么会打印我们在应用程序中所写的“APP open /dev/hello_ctl_dev success”,接下来我们调用了ioctl函数,系统会去调用我们在驱动代码中所写的hello_ioctl函数,这个函数将我们的参数打印了出来,所以会打印“cmd is 1,arg is 6”,接下来我们调用close关闭文件,系统会去调用我们在驱动代码中所写hello_release函数,这个函数会打印“Hello RELEASE !!”,这就是我们整个应用程序的分析。
注意:由于printk打印和printf打印的优先级问题,应用程序中的printf打印会在最后被打印,并不是程序逻辑的错误

结果演示

Note: The first generation device nodes in executing the application
execution of the application
Here Insert Picture Description
shows that our analysis is correct, the file operating system call function to call a function that we wrote in the drive, we did it to the top of the interface.

Register the device with the node device driver registration distinction

Generating node code can be placed anywhere, and driver registration and registration equipment is not so tight relationship, not even registered drivers, but also can generate device nodes
when we are at the front of the device node generates a registration drive generated in the probe function the device node, but this is not necessary, we can be generating device node in the init function.

Code demonstrates

#include <linux/init.h>
#include <linux/module.h>
/*driver register*/
#include <linux/platform_device.h>

/*注册杂项设备头文件*/
#include <linux/miscdevice.h>
/*注册设备节点的文件结构体*/
#include <linux/fs.h>

#define DEVICE_NAME "hello_ctl_dev"//设备名
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("GYY");

static int hello_open(struct inode * pinode , struct file * pfile )
{
	printk(KERN_EMERG "Hello OPEN !!\n");
	return 0;
}

static int hello_release(struct inode * pinode, struct file * pfile)
{
	printk(KERN_EMERG "Hello RELEASE !!\n");
	return 0;
}

static long hello_ioctl(struct file * pfile, unsigned int cmd, unsigned long arg)
{
	printk("cmd is %d,arg is %d\n",cmd,arg);
	return 0;
}

static struct file_operations hello_ops = {
	.owner = THIS_MODULE,
	.open = hello_open,
	.release = hello_release,
	.unlocked_ioctl = hello_ioctl,
	
};

static struct miscdevice hello_dev = {
	.minor = MISC_DYNAMIC_MINOR,//自动分配设备号
	.name = DEVICE_NAME,//设备名
	.fops = &hello_ops,
};

static int hello_init(void)
{
	printk(KERN_EMERG "HELLO WORLD enter!\n");
	misc_register(&hello_dev);	
	return 0;
}

static void hello_exit(void)
{
	printk(KERN_EMERG "HELLO WORLD exit!\n");
	misc_deregister(&hello_dev);
}

module_init(hello_init);
module_exit(hello_exit);

In this code, we deleted all the registration section on the drive, a device nodes directly hello_init function, but our core file structure is not changed, the function we want to achieve the same

test

Install the module
Here Insert Picture Description
to execute the application
Here Insert Picture Description
results of application execution and our results are the same as above

Key distinction

Device node is a "pair" in order to allow the application can call
some attention generating device node and device registration does not matter, but the device does not require the node name and the name of the same device
under normal circumstances, the device node is registered into the probe, the but put the init function in the drive is there

Published 123 original articles · won praise 598 · views 340 000 +

Guess you like

Origin blog.csdn.net/a568713197/article/details/89690821