为了方便驱动的编写,提高软件的重用性和跨平台性能,于是就提出了Linux驱动的分离和分层
驱动的分层,分层的目的时为了在不同的层处理不同的内容,最简单的驱动分层是input子系统负责管理所有跟输入有关的驱动、最底层的就是设备原始驱动,负责获取输入设备的原始值,获取到的输入时间上报给input核心层。input核心层会处理各种IO模型,并且提供file_operations操作集合。
input核心层----提供统一的框架
👆
input层
👆
最底层(设备原始驱动)----不同的设备使用统一的框架
根据驱动的分离和分层衍生出总线–驱动–设备驱动框架。总线代码由Linux内核提供。当向总线注册驱动的时候,会检测当前总线下的所有设备有没有和此驱动匹配的设备,如果有,就会执行probe函数(probe函数需要我们自己编写)。如果先安装设备就设备去找驱动,如果先安装驱动就驱动去找设备。
platform
Linux内核提供了一个虚拟总线:platform。相应的就有platform_driver 和 platform_device。
platform驱动就是platform_driver。这个属于一个结构体,定义在include/linux/platform_device.h
struct platform_driver {
int (*probe)(struct platform_device *);
int (*remove)(struct platform_device *);
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*resume)(struct platform_device *);
struct device_driver driver;
const struct platform_device_id *id_table;
bool prevent_deferred_probe;
};
结论:向内核注册platform驱动的时候,如果驱动和设备匹配成功,最终会执行platform_driver的probe函数 ,无设备树的时候,此时需要驱动开发人员编写设备注册文件,使用platform_device_register函数注册设备;有设备树时,只需要修改设备树的设备节点即可。
platform的匹配过程:platform总线下的match就是platform_mach函数。
无设备树设备驱动框架编写:
本来打算把点灯的功能加上的,但是再把点灯的步骤加上去会导致文章过于冗杂,于是设备文件中有点灯的代码,但是驱动文件中没有写上去。
1.搭建好基本的框架,这里就用到以前所需要的头文件
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/of_irq.h>
#include <linux/irq.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/poll.h>
#include <linux/fcntl.h>
#include <linux/interrupt.h>
#include <linux/platform_deivce.h>
/*设备加载*/
static int __init leddevice_init(void)
{
return 0;
}
/*设备卸载*/
static void __exit leddevice_exit(void)
{
}
module_init(leddevice_init);
module_exit(leddevice_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Kong");
2.添加一个空的设备结构体,并且在设备加载和卸载中执行platform的注册和注销
static struct platform_device leddevice = {
};
/*设备加载*/
static int __init leddevice_init(void)
{
/*注册platform设备*/
return platform_device_register(&leddevice);
}
/*设备卸载*/
static void __exit