Linux系统发明了一种虚拟的总线,称为platform总线,相应的设备名称称为platform_device,而驱动则成为platform_driver。
platform总线实现的功能是:在系统注册一个platform_device设备的时候,会寻找与之匹配的驱动。相反,在向系统注册一个platform_driver驱动的时候,会寻找与之匹配的设备。
关于platform总线详细的介绍:Linux驱动_Platform平台驱动_anieoo的博客-CSDN博客_驱动platform
platform总线关于设备和驱动的方式有四种:
① 基于设备树风格的匹配
② 基于ACPI风格的匹配
③ 匹配ID表(即platform_device设备名是否出现在platform_driver的ID表内)
④ 匹配platform_device设备名和驱动的名字
采用设备树风格匹配的时候,可以把设备资源和数据描述在设备书上,通过对应API进行获取。然而,在采用传统的platform_device和platform_driver匹配的时候,往往需要在设备中描述其资源和数据,在驱动中获取这些信息。
以platform_device结构体为例子:
struct platform_device {
const char *name;
int id;
bool id_auto;
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就是描述设备资源和数据的。该结构体具体的定义如下:
struct resource {
resource_size_t start;
resource_size_t end;
const char *name;
unsigned long flags;
struct resource *parent, *sibling, *child;
};
通常只需要使用start,end和flags这三个字段。分别代表资源的开始值,结束值和资源类型。flags可以为IORESOURCE_MEM、IORESOURCE_IRQ等等。
当flags为 IORESOURCE_MEM时,start和end分别代表内存的开始地址和结束地址
当flags为 IORESOURCE_IRQ时,start和end分别代表使用的中断号开始值和结束值
实例代码:
以一个关于LED的Platform驱动举例,在platform_device中需要加入如下代码:
/*寄存器基地址*/
#define CCM_CCGR1_BASE (0X020C406C)
#define SW_MUX_GPIO1_IO03_BASE (0X020E0068)
#define SW_PAD_GPIO1_IO03_BASE (0X020E02F4)
#define GPIO1_DR_BASE (0X0209C000)
#define GPIO1_GDIR_BASE (0X0209C004)
/*寄存器地址长度*/
#define REGISTER_LENGTH 4
void leddevice_release(struct device *dev) {
printk("leddevice release\r\n");
}
static struct resource led_resources[] = {
[0] = {
.start = CCM_CCGR1_BASE,
.end = CCM_CCGR1_BASE + REGISTER_LENGTH - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = SW_MUX_GPIO1_IO03_BASE,
.end = SW_MUX_GPIO1_IO03_BASE + REGISTER_LENGTH - 1,
.flags = IORESOURCE_MEM,
},
[2] = {
.start = SW_PAD_GPIO1_IO03_BASE,
.end = SW_PAD_GPIO1_IO03_BASE + REGISTER_LENGTH - 1,
.flags = IORESOURCE_MEM,
},
[3] = {
.start = GPIO1_DR_BASE,
.end = GPIO1_DR_BASE + REGISTER_LENGTH - 1,
.flags = IORESOURCE_MEM,
},
[4] = {
.start = GPIO1_GDIR_BASE,
.end = GPIO1_GDIR_BASE + REGISTER_LENGTH - 1,
.flags = IORESOURCE_MEM,
},
};
将寄存器的地址和长度保存到resource中
在platform_driver中需要获取上述资源:
struct resource *ledsource[5];
/*初始化led*/
/*1、从设备中获取资源*/
for(i = 0;i < 5;i++){
ledsource[i] = platform_get_resource(dev, IORESOURCE_MEM, i);
if(ledsource[i] == NULL)
return -EINVAL;
}
这样就实现了platform设备资源的定义和获取了!