1. 平台总线介绍
平台总线模型将一个驱动分成两部分 device.c
, driver.c
。一个描述硬件, 一个控制硬件。
平台总线通过比较字符串, 将name相同的device.c
和driver.c
匹配到一起来控制硬件。
driver通过平台总线去拿到device.c内容。
平台总线的优点是减少重复代码 提高效率。
类似.h
和.c
的关系
平台总线的原则是先分离, 后搭档。
2.注册Platform设备
在Linux内核里用platform_device
的结构体描述硬件资源
struct platform_device {
const char *name; //device的名字, 将和driver的名字进行匹配
int id; //名字+id 为/sys/bus/platform/devices 下的名称
bool id_auto; // 自动设置id 一般不用
struct device dev;
u32 num_resources; // 存储资源的个数
struct resource *resource;
const struct platform_device_id *id_entry;
char *driver_override; /* Driver name to force a match */
/* MFD cell pointer */
struct mfd_cell *mfd_cell;
/* arch specific additions */
struct pdev_archdata archdata;
};
struct resource {
resource_size_t start; //根据不同资源 理解不同 如 flags = REG 则代表起始地址
resource_size_t end;
const char *name; // 资源名称 如中断:irq
unsigned long flags; // 资源类型. 如IO MEM REG IRQ DMA BUS
unsigned long desc;
struct resource *parent, *sibling, *child;
};
补充:
该结构体的名称为name + id
可以在/sys/bus/platform/devices
下查看。假设id=-1
则id
不会显示。
下面是device的示例代码
执行完成在在/sys/bus/platform/devices
目录下可以找到
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
static struct resource my_device_resources[] = {
[0] = {
.start = 0xFDD60000,
.start = 0xFDD60004,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = 13,
.start = 13,
.flags = IORESOURCE_IRQ,
},
};
void mydevice_release(struct device *dev) {
printk("device release ok...\n");
}
struct platform_device platform_device_test = {
.name = "mydeivce",
.id = -1,
.resource = my_device_resources,
.num_resources = ARRAY_SIZE(my_device_resources),
.dev = {
.release = mydevice_release,// 必须实现
}
};
static void platform_device_exit(void)
{
platform_device_unregister(&platform_device_test);
printk("device exit release ok...\n");
}
static int platform_device_init(void)
{
platform_device_register(&platform_device_test);
printk("device init release ok...\n");
return 0;
}
module_init(platform_device_init);
module_exit(platform_device_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("fashi");
MODULE_VERSION("V1.0");
3.注册Platform驱动
platform driver
结构体
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; //设备列表数组 里面可以存放多个设备名字符串 也可以用来匹配设备 优先级大于driver.name
bool prevent_deferred_probe;
};
驱动加载匹配成功的时候会打印"This i mydriver_probe"
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
int mydriver_probe(struct platform_device *dev);
struct platform_driver platform_driver_test = {
.probe = mydriver_probe,
.driver = {
.name = "mydeivce" //和匹配device name保持一致
}
};
/* 匹配到的device结构体指针会传进来 */
int mydriver_probe(struct platform_device *dev)
{
printk("This is mydriver_probe\n");
printk("IRQ is %lld\n", dev->resource[1]->start);//获取在mydevice设备里定义的IRQ start 也可以使用platform_get_resource获取
return 0;
}
static int platform_driver_init(void)
{
platform_driver_register(&platform_driver_test);
printk("driver init release ok...\n");
return 0;
}
static void platform_driver_exit(void)
{
platform_driver_unregister(&platform_driver_test);
printk("driver exit release ok...\n");
}
module_init(platform_driver_init);
module_exit(platform_driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("fashi");
MODULE_VERSION("V1.0");
reference:
https://www.bilibili.com/video/BV1bP4y1v7Gc/?spm_id_from=333.999.0.0&vd_source=378aafb211994a6d9b19c51b8c69b7be