平台总线platform_bus
1.内核定义的一个bus_type,还有其它的bus_type,以及自己都可以定义一个
2.platform_bus架构
-
架构图:
-
原理:
platform_bus下管理着两个链表一条是platform_device一条是platform_driver,如果有任何一边的注册了新的节点过来那么就会遍历另外的一条,根据名字进行匹配,如果匹配到了就执行probe,当devices从节点撤出就会执行其匹配的remove。
driver下的name不能重复,而device下的name可以重复,也就是一个driver可以不用设备树就匹配多个devices
具体可参考:
[(81条消息) 手把手教Linux驱动10-platform总线详解_一口Linux的博客-CSDN博客]
3.简单驱动编写(不包含资源获取)
-
device.c
#include <linux/module.h> #include <linux/init.h> #include <linux/platform_device.h> void my_release(struct device *dev) { printk("--------%s--------%s-----------%d-------\n",__FILE__,__FUNCTION__,__LINE__); return; } static struct platform_device my_device= { .name = "easy", .id = -1, .dev.release = my_release,//不写会报错 }; static int __init my_device_init(void) { printk("--------%s--------%s-----------%d-------\n",__FILE__,__FUNCTION__,__LINE__); platform_device_register(&my_device); return 0; } static void __exit my_device_exit(void) { printk("--------%s--------%s-----------%d-------\n",__FILE__,__FUNCTION__,__LINE__); platform_device_unregister(&my_device); return; } module_init(my_device_init); module_exit(my_device_exit); MODULE_LICENSE("GPL");
-
driver.c
#include <linux/module.h> #include <linux/init.h> #include <linux/platform_device.h> int my_device_probe(struct platform_device *pdev) { printk("--------%s--------%s-----------%d-------\n",__FILE__,__FUNCTION__,__LINE__); return 0; } int my_device_remove(struct platform_device *pdev) { printk("--------%s--------%s-----------%d-------\n",__FILE__,__FUNCTION__,__LINE__); return 0; } static struct platform_driver my_driver= { .probe = my_device_probe, .remove = my_device_remove, .driver.name = "easy", }; static int __init my_driver_init(void) { printk("--------%s--------%s-----------%d-------\n",__FILE__,__FUNCTION__,__LINE__); platform_driver_register(&my_driver); return 0; } static void __exit my_driver_exit(void) { printk("--------%s--------%s-----------%d-------\n",__FILE__,__FUNCTION__,__LINE__); platform_driver_unregister(&my_driver); return; } module_init(my_driver_init); module_exit(my_driver_exit); MODULE_LICENSE("GPL");
-
总结:
1.在没设备树时可以通过.name = "easy",与.driver.name = "easy",匹配 static struct platform_device my_device= { .name = "easy", .id = -1, .dev.release = my_release,//不写会报错 }; static struct platform_driver my_driver= { .probe = my_device_probe, .remove = my_device_remove, .driver.name = "easy", }; 2.dev.release = my_release,//不写会报错 3.my_release只有device remove才会执行,而my_device_remove二者remove都会执行。
4.获取资源
-
deivce描述资源
- flags:描述资源类型
- start与end是u32的地址
- flags:描述资源类型
-
device.c改动
static struct resource res[] = { [0] = { .flags = IORESOURCE_MEM, .start = 0x10000000, .end = 0x10000000+0x3 }, [1] = { .flags = IORESOURCE_IRQ, .start = 66, .end = 66, } }; static struct platform_device my_device= { .name = "easy", .id = -1, .dev.release = my_release,//不写会报错 .num_resources = ARRAY_SIZE(res), .resource = res, };
-
driver.c改动
int my_device_probe(struct platform_device *pdev) { printk("--------%s--------%s-----------%d-------\n",__FILE__,__FUNCTION__,__LINE__); printk("------%x--------\n",pdev->resource[0].start);//把资源打印出来 printk("------%d--------\n",pdev->resource[1].start); return 0; }
5.设备树platform
1.driver.c
1.更改dts文件,添加一个或多个节点(记得要有compatible属性)
2.在driver中添加.of_match_table = &my_table
static struct of_device_id my_table={
.compatible = "myled",
};
static struct platform_driver mydri = {
.driver = {
.name = "hello_dev",
.of_match_table = &my_table,
},
.probe = my_probe,
.remove = my_remove,
};
6.匹配原则
static int platform_match(struct device *dev, struct device_driver *drv)
{
struct platform_device *pdev = to_platform_device(dev);
struct platform_driver *pdrv = to_platform_driver(drv);
if (pdev->driver_override)
return !strcmp(pdev->driver_override, drv->name);
if (of_driver_match_device(dev, drv))
return 1;
if (acpi_driver_match_device(dev, drv))
return 1;
//优先通过设备树中断compitable与id_table的compitable匹配,一个driver可以匹配多个device
if (pdrv->id_table)
return platform_match_id(pdrv->id_table, pdev) != NULL;
//最后才通过name匹配
return (strcmp(pdev->name, drv->name) == 0);
}