第十三节、平台总线模型——注册platform设备
本节用于介绍平台总线模型——注册platform设备
1、什么是平台总线模型?
平台总线模型也叫platform总线模型。是Linux内核虚拟出来的一条总线,不是真实的导线。
平台总线模型就是把原来的驱动C文件给分成了俩个C文件,一个是device.c,一个是driver.c
把稳定不变的放在driver.c里面,需要变得就放在了device.c里面。
2、为什么会有平台总线模型?
- 可以提高代码的重用性
- 减少重复性代码。
设备 | 总线 | 驱动 |
---|---|---|
device.c | driver.c |
3、平台总线模型的优点。
4、怎么编写以平台总线模型设计的驱动?
一个是device.c,一个是driver.c,然后分别注册 device.c和 driver.c
平台总线是以名字来匹配的,实际上就是字符串比较。
1、平台总线注册一个platform_device
设备文件device.c里面写的是硬件资源,这里的硬件资源是指寄存器的地址,中断号,时钟等硬件资源。
在Linux内核里面,我们是用一个结构体来描述硬件资源的。
文件位置路径:include/linux/platform_device.h
struct platform_device {
const char *name; //常用,用于平台设备与平台驱动的匹配,会在/sys/bus/platform/devices/下生成name的节点
int id; //常用,设备id,一般为-1,为相同name的设备进行编号的
bool id_auto;
struct device dev; //常用,内嵌的device结构体,
u32 num_resources; //常用,资源的个数
struct resource *resource; //常用,device里面的硬件资源,可以看到这是一个指针,指向的是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;
};
2、填写platform_device里面的resource硬件资源结构体数组
文件位置路径:include/linux/ioport.h
struct resource {
resource_size_t start; //资源的起始地址
resource_size_t end; //资源的结束地址
const char *name; //资源的名字
unsigned long flags; //资源的类型
unsigned long desc;
struct resource *parent, *sibling, *child;
};
这里面的资源的类型有哪些呢?下面是几个常用的类型
#define IORESOURCE_IO //IO的内存
#define IORESOURCE_MEM //最常用,表示一段地址
#define IORESOURCE_IRQ //最常用,表示中断号
#define IORESOURCE_DMA //表示DMA的地址
#define IORESOURCE_BUS //表示总线号
注意:platform_device结构体内的内嵌的device结构体中如果void (*release)(struct device *dev);函数没有实现的话,可能会有内核报警。
[ 2901.445771] Device 'beep_test' does not have a release() function, it is broken and must be fixed.
3、填写platform_device里面的device结构体
文件位置路径:include/linux/device.h
struct device {
...
void (*release)(struct device *dev);
...
}
示例:
void beep_release(struct device *dev)
{
printk("beep_release\n");
}
struct resource beep_res[] = { //resource是一个结构体数组。这个是结构体数组赋值的方式
[0] = {
.start = 0x02310008,
.end = 0x0231000b,
.name = "GPDAT_1",
.flags = IORESOURCE_MEM
}
};
struct platform_device beep_device = {
.name = "beep_test",
.id = -1,
.dev = {
.release = beep_release //函数没有实现的话,可能会有内核报警。这个是结构体内结构体赋值的方式
},
.num_resources = ARRAY_SIZE(beep_res), //资源的个数可以通过ARRAY_SIZE函数来计算长度
.resource = beep_res
};
4、注册和注销平台设备函数
当使用上节的函数创建完成一个platform_device后,使用platform_device_register函数进行平台设备的注册
文件位置路径:include/linux/platform_device.h
实际函数位置路径:drivers/base/platform.c
extern int platform_device_register(struct platform_device *);
int platform_device_register(struct platform_device *pdev)
{
device_initialize(&pdev->dev);
arch_setup_pdev_archdata(pdev);
return platform_device_add(pdev);
}
EXPORT_SYMBOL_GPL(platform_device_register);
//参数
//pdev:要注册的平台设备
extern void platform_device_unregister(struct platform_device *);
void platform_device_unregister(struct platform_device *pdev)
{
platform_device_del(pdev);
platform_device_put(pdev);
}
EXPORT_SYMBOL_GPL(platform_device_unregister);
//参数
//pdev:要注销的平台设备