PlatformBus总线驱动
一、什么是platformBUS
platform总线是一种虚拟的总线,并不存在物理实物,其设计原因是为了保证Linux设备和驱动模型的统一性(部分设备挂载在对应总线下与cpu通信,部分设备不依附总线模型)
把不依附总线模型的设备统一挂载到platform总线之下
模型如下图

二、总线框架原理
在总线设备、驱动模型中,需要关心总线、设备和驱动这三个实体,总线将设备和驱动绑定
在系统设备注册时,寻找与之匹配的驱动,匹配由总线完成。
在系统注册驱动时,寻找与之匹配的设备,匹配由总线完成。
总线模型的驱动由两个部分组成,描述设备相关的结构体和描述驱动相关的结构体
与传统驱动代码比较,总线型交由内核统一管理,提高了代码的可移植性和安全性
三、platform总线和设备树
当向系统注册设备时,我们可以通过调用platform_device_register函数,也可以通过修改设备树文件,因为总线类型由内核管理,内核会解析Dtb文件,完成platform device的创建
四、程序框架
三个对象 Bus、driver、device
其中Bus 对象一般不需要我们创建,由系统创建,driver对象和device对象分别用两个结构体来描述
kernel在初始化阶段会创建platform框架,其调用路径为
/*
*start_kernel -> reset_init -> do_basic_setup -> driver_init
*在driver_init中完成paltform总线的初始化
*/
void __init driver_init(void)
{
/* These are the core pieces */
devtmpfs_init();
devices_init();
buses_init();
classes_init();
firmware_init();
hypervisor_init();
/* These are also core pieces, but must come after the
* core core pieces.
*/
platform_bus_init();
system_bus_init();
cpu_dev_init();
memory_dev_init();
}
驱动框架
- 注册一个paltform_driver
- 注册设备号, 并注册file_operations结构体 -----》 为用户提供一个设备标识,同时提供系统调用的接口
- 创建设备节点 ----- 》 class_create
代码示例:
struct cdev * led_cdev = NULL;
dev_t devno;
static struct file_operations fops = {
.owner = THIS_MODULE,
.open = led_open,
.read = led_read,
.write = led_write
}
static int led_probe(struct platform_device* pdev)
{
//申请设备号,创建设备节点
alloc_chrdev_region(&devno, 0, 1, "led")
led_cdev = cdev_alloc();
cdev_init(led_cdev, &fops);
cdev_add(led_cdev, devno, dev_count);
//创建设备节点
led_class = class_create(THIS_MODULE, "led");
class_device_create(led_class, NULL, devno, NULL, "led");
}
static struct platform_driver led_driver = {
.probe = led_proble,
.remove = led_remov,
.driver = {
.owner = THIS_MODULE,
.name = "led",
}
}
static int __init platform_led_init(void)
{
return platform_driver_register(&led_driver);
}
static void __exit platform_led_exit(void)
{
platform_driver_unregister(&mvb_driver);
}
module_init(platform_led_init);
module_exit(platform_led_exit);
MODULE_LICENSE("GPL");
4.初始化硬件 -------》 ioremap(地址) 地址从设备类型结构体获取
5.实现系统调用
ioremap映射内存地址,以及对系统调用的实现,和cdev实现的驱动程序其实都相同的
设备程序编写流程
对于设备程序,我们要主要关心的时platform_device 结构,该结构描述了设备相关的信息,根据查询用户手册,得到设备的一些硬件资源信息
然后通过platform_device_register 函数注册进内核
platform_device 结构体
struct platform_device { const char* name; //设备名称 int id; //设备编号 struct device dev; u32 num_resources; //设备使用各类资源的数量 struct resource* resource; //设备使用的资源 struct platform_device_id *id_entry; }
resource结构体
struct resource { const char *name; unsigned long start, end; unsigned long flags; struct resource *parent, *sibling, *child; };
代码示例
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/string.h>
struct resource mvb_resource[] = {
[0] = {
.start = 0x44E07000,
.end = 0x44E08000,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 0x4804C000,
.end = 0x4804D000,
.flags = IORESOURCE_MEM,
},
[2] = {
.start = 0x481AC000,
.end = 0x481AD000,
.flags = IORESOURCE_MEM,
},
[3] = {
.start = 0x481AE000,
.end = 0x481AF000,
.flags = IORESOURCE_MEM,
}
};
static void platform_device_mvb_release(struct device *dev)
{
}
struct platform_device mvb_device = {
.name = "mvb",
.id = -1,
.num_resources = ARRAY_SIZE(mvb_resource),
.resource = mvb_resource,
.dev = {
.release = platform_device_mvb_release,
}
};
static int __init mvb_device_init(void)
{
int ret;
ret = platform_device_register(&mvb_device);
if(ret){
printk("platform_device_region err\n");
return -EBUSY;
}
return 0;
}
static void __exit mvb_device_exit(void)
{
platform_device_unregister(&mvb_device);
}
module_init(mvb_device_init);
module_exit(mvb_device_exit);
MODULE_AUTHOR("from Chen Xin");
MODULE_LICENSE("GPL");
本文来自博客园,作者:是小陈同学呀,转载请注明原文链接:https://www.cnblogs.com/chenxinblog/p/14202507.html

浙公网安备 33010602011771号