目录
2.1 platform_driver_register函数流程
3.1 platform_device_register函数流程
简介:
Linux系统为了驱动的可重用性,提出驱动的分离与分层的软件思路,为了保持设备驱动的统一性,platform平台设备驱动模型就此诞生。相对于USB、PCI、I2C、SPI等物理总线来说,platform总线是虚拟、抽象出来的总线,实际中并不存在这样的总线。

说明:本文基于Linux版本为4.1.15
一、初识platform平台设备驱动
platform平台总线下有驱动链表和设备链表,当调用 platform_driver_register() 注册platform驱动,或调用 platform_device_register() 注册platform设备时,都会执行match匹配函数。当链表中有platform驱动和platform设备匹配上,就会调用platform驱动的 probe() 函数。

图解platform_driver和platform_device匹配过程:

比较 platform_driver 的 driver->name 与 platform_device 的 name 相同都为 "myled",就会执行 platform_driver 的 probe函数,这里为 led_probe。led_probe函数由我们自己定义实现注册字符设备等功能。
platform 总线设备驱动大概有以下步骤:
- platform_device_register() 注册平台设备
- platform_driver_register() 注册平台驱动
- platform总线自动匹配name,匹配上就调用 driver 的 .probe
- probe中注册字符设备等操作
1、platform_driver驱动代码框架
#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/io.h>
/* 当驱动driver->name和设备name相同, 则调用驱动的.probe函数, .probe函数可以做任何事情 */
static int led_probe(struct platform_device *pdev)
{
/* 注册字符设备等操作 */
printk("platform_driver probe run!\n");
return 0;
}
static int led_remove(struct platform_device *pdev)
{
/* 卸载字符设备等操作 */
printk("platform_driver remove run!\n");
return 0;
}
/* 定义平台drv,通过.name来比较dev */
struct platform_driver led_drv = {
.probe = led_probe,
.remove = led_remove,
.driver = {
.name = "myled",
}
};
static int led_drv_init(void)
{
platform_driver_register(&led_drv); //注册驱动,最终调用driver_register()
return 0;
}
static void led_drv_exit(void)
{
platform_driver_unregister(&led_drv);
}
module_init(led_drv_init);
module_exit(led_drv_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("dongao");
platform_get_resource()可以从platform_device中获取资源。linux支持设备树后,platform_get_resource() 就不常用了。
2、platform_device设备代码框架
#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/serial_core.h>
#include <linux/platform_device.h>
static void led_release(struct device * dev) //构造一个release函数,防止报错
{
}
/* platform_device结构体.name与platform_driver的driver->name比较 */
static struct platform_device led_dev = {
.name = "myled",
.id = -1,
//.num_resources = ARRAY_SIZE(led_resource), //可以将device的资源传给driver使用
//.resource = led_resource,
.dev = {
.release = led_release,
},
};
static int led_dev_init(void)
{
platform_device_register(&led_dev); //注册1个平台设备,最终调用device_add()
return 0;
}
static void led_dev_exit(void)
{
platform_device_unregister(&led_dev); //卸载1个平台设备
}
module_init(led_dev_init);
module_exit(led_dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("dongao");
3、测试结果
3.1 Makefile编译
KERN_DIR = /home/linux-imx-rel_imx_4.1.15_2.1.0
all:
make -C $(KERN_DIR) M=`pwd` modules
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order
obj-m += led_drv.o
obj-m += led_dev.o
3.2 加载驱动
加载编译出来的2个ko文件。
$ insmod led_dev.ko # 加载 platform_device 驱动
$ insmod led_drv.ko # 加载 platform_driver 驱动
结果:
![]()
结果,运行probe 打印 "platform_driver remove run!"
查看在系统中的驱动:
$ ls /sys/bus/platform/devices
$ ls /sys/bus/platform/drivers/
Linux平台设备驱动总线及设备树解析

最低0.47元/天 解锁文章
1845

被折叠的 条评论
为什么被折叠?



