Linux平台设备框架驱动
平台设备框架(platform)是将一个驱动分为设备层和驱动层两个部分,通过总线模型将设备和驱动进行绑定。在系统中每注册一个设备,都会与之匹配一个驱动,同样的,每注册一个驱动也会与之匹配一个设备。
通常 Linux 设备和驱动通常都需要挂接在一种总线上,对于本身依附于 PCI、 USB、 I2 C、 SPI 等的设备而言,这自然不是问题,但是在嵌入式系统里面, SOC 系统中集成的独立的外设控制器、挂接在 SOC 内存空间的外设等却不依附于此类总线。
基于总线框架的模型结构,Linux下就衍生了平台设备框架模型(platform),平台设备总线是一种虚拟总线,称为platform总线。对应的设备层称为platform_device;驱动层称为platform_driver。设备层和驱动层通过平台设备总线进行匹配管理。
1.平台设备框架特性
平台模型采用了分层结构,把一个设备驱动程序分成了两个部分:
平台设备( platform_device)和平台驱动( platform_driver)。
平台设备将设备本身的资源注册进内核,可以由内核统一管理。
将硬件资源和驱动接口分离,编译代码的维护与移植。
2.平台设备总线相关接口函数
2.1 设备层接口函数
每个设备的系统通过设备结构体struct platform_device保存。结构体原型在 include/linux/platform_devcie.h 中定义。
struct platform_device {
const char * name; //设备名字,驱动层和设备层匹配标志
int id;//通常填-1
struct device dev;//设备结构体信息
u32 num_resources;//资源个数
struct resource * resource;//资源内容
const struct platform_device_id *id_entry;
/* MFD cell pointer */
struct mfd_cell *mfd_cell;
/* arch specific additions */
struct pdev_archdata archdata;
};
- struct device dev结构信息
struct device dev 结构体是用来实现设备模型的。这个结构体中成员比较多,结构体原型在 include/linux/devcie.h 中定义。我们常关心的是其中的两个成员:
平台数据指针: void *platform_data;
资源释放函数: void (*release)(struct device *dev);
平台数据指针platform_data是一个void *类型指针,可以向驱动层传递任意数据,release资源释放函数接口在设备层一定要自己实现,否则在设备层释放资源时会报错。
以下列举其中几个成员结构:
struct device {
const char *init_name; /*逻辑设备的名字*/
struct device_type *type; /* 设备类型 */
struct bus_type *bus; /* 设备所属的总线类型 */
struct device_driver *driver;/* 指向开辟 struct device 结构 driver 指针*/
void *platform_data; /* 平台设备指针 */
dev_t devt; /* 存放设备号 dev_t,creates the sysfs"dev" */
struct class *class; /* 设备所属类*/
void (*release)(struct device *dev);/*设备资源释放函数*/
};
-
struct resource * resource结构信息
struct resource * resource 结构体是用来保存设备资源内容信息。该结构体定义位置: include/linux/ioport.h
struct resource {
resource_size_t start; //资源起始地址
resource_size_t end; //资源结构地址
const char *name;//资源名字
unsigned long flags;//资源类型
struct resource *parent, *sibling, *child;
};
- 设备层注册函数
int platform_device_register(struct platform_device *pdev)
函数功能: 注册平台设备;
形参: pdev --设备结构体;
返回值: 成功返回0,失败返回其它值;
- 设备层注销函数
void platform_device_unregister(struct platform_device *pdev)
函数功能: 注册平台设备;
形参: pdev --设备结构体;
- 向内核添加多个设备
int platform_add_devices(struct platform_device **devs, int num)
函数功能: 向内核注册多个设备;
形参: pdev --设备结构体;
num – 注册的设备个数
返回值: 成功返回0,失败返回其它值;
2.2 驱动层接口函数
驱动层通过struct platform_driver 结构体保存相关信息,结构体定义位置: include/linux/devcie.h
在该结构体中必须要实现接口函数:
资源匹配函数:int (*probe)(struct platform_device *)
资源释放函数:int (*remove)(struct platform_device *);
驱动资源结构体:struct device_driver driver;
一个驱动层可匹配多个设备层,若想同时匹配多个设备层,则通过id_table 指针完成匹配。
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;//匹配多多设备时需要填写
};
- struct device_driver driver 结构信息
struct device_driver driver 结构体中有个成员name必须要填写,当没有实现id_table指针时,设备层和驱动层就是通过该成员完成资源匹配。
struct device_driver {
const char *name; //资源匹配参数
struct bus_type *bus;
struct module *owner;
const char *mod_name; /* used for built-in modules */
bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
const struct of_device_id *of_match_table;
int (*probe) (struct device *dev);
int (*remove) (struct device *dev);
void (*shutdown) (struct device *dev);
int (*suspend) (struct device *dev, pm_message_t state);
int (*resume) (struct device *dev);
const struct attribute_group **groups;
const struct dev_pm_ops *pm;
struct driver_private *p;
};
- const struct platform_device_id *id_table 结构信息
该结构也是用于匹配设备资源,一个驱动层可以同时匹配多个设备层。
struct platform_device_id {
char name[PLATFORM_NAME_SIZE]; //资源匹配参数
kernel_ulong_t driver_data
__attribute__((aligned(sizeof(kernel_ulong_t)))); //匹配设备层的 void *platform_data数据
};
- 驱动层注册和注销函数
//驱动注册函数
int platform_driver_register(struct platform_driver *drv)
//驱动注销函数
void platform_driver_unregister(struct platform_driver *drv)
3.平台设备框架应用示例
3.1 设备层注册示例
设备层注册步骤:
填充struct device结构体,填写设备资源信息struct resource * resource;
调用设备层注册函数platform_device_register();
注销时调用注销函数platform_device_unregister;
#include
#include
#include
#include
#include
#include
#include
#include
#include
static void platform_release(struct device *dev)
{
printk("资源释放完成n");
}
static struct resource resource[]=
{
[0]={
.start=EXYNOS4X12_GPM4(0),
.end=EXYNOS4X12_GPM4(0),
.name="led1",
.flags=IORESOURCE_MEM
},
[1]={
.start=EXYNOS4X12_GPM4(1),
.end=EXYNOS4X12_GPM4(1),
.name="led2",
.flags=IORESOURCE_MEM
},
};
struct platform_device pdev=
{
.name="led_dev",
.id=-1,
.dev=
{
.release=platform_release,//资源释放函数
},
.num_resources=sizeof(resource)/sizeof(resource[0]),
.resource=resource,
};
static int __init wbyq_platform_dev_init(void)
{
platform_device_register(&pdev);
return 0;
}
/*驱动释放*/
static void __exit wbyq_platform_dev_cleanup(void)
{
/*注销设备层*/
platform_device_unregister(&pdev);
}
module_init(wbyq_platform_dev_init);//驱动入口函数
module_exit(wbyq_platform_dev_cleanup);//驱动出口函数
MODULE_LICENSE("GPL");//驱动注册协议
MODULE_AUTHOR("it_ashui");
MODULE_DESCRIPTION("Exynos4 platform_dev Driver");
3.2 驱动层注册示例
驱动层注册步骤:
填充 struct platform_driver结构体,实现资源匹配函数和资源释放函数;
调用设备层注册函数platform_driver_register();
注销时调用注销函数platform_driver_unregister;
#include
#include
#include
#include
#include
#include
#include
#include
#include
static int platform_probe(struct platform_device *dev)
{
printk("资源匹配成功n");
printk("资源个数:%dn",dev->num_resources);
struct resource * resource=platform_get_resource(dev,IORESOURCE_MEM,0);
if(resource)
{
printk("资源名:%ststart=%xtend=%xn",resource->name,resource->start,resource->end);
}
return 0;
}
static int platform_remove(struct platform_device *dev)
{
printk("资源释放成功n");
return 0;
}
static struct platform_device_id id_table[]=
{
[0]=
{
.name="led_dev"
},
[1]=
{
.name="tiny4412_dev"
},
};
static struct platform_driver drv=
{
.probe=platform_probe,
.remove=platform_remove,
.driver=
{
.name="platform_drv",
},
.id_table=id_table,
};
static int __init wbyq_platform_drv_init(void)
{
platform_driver_register(&drv);
printk("驱动层平台设备注册成功n");
return 0;
}
/*驱动释放*/
static void __exit wbyq_platform_drv_cleanup(void)
{
/*注销设备层*/
platform_driver_unregister(&drv);
printk("驱动层平台设备注销成功n");
}
module_init(wbyq_platform_drv_init);//驱动入口函数
module_exit(wbyq_platform_drv_cleanup);//驱动出口函数
MODULE_LICENSE("GPL");//驱动注册协议
MODULE_AUTHOR("it_ashui");
MODULE_DESCRIPTION("Exynos4 platform_drv Driver");
3.3 Makefile文件
KER_ADD=/home/wbyq/src_pack/linux-3.5
all:
make -C $(KER_ADD) M=`pwd` modules
#arm-linux-gcc main.c -o app
cp ./*.ko /home/wbyq/src_pack/rootfs/code
make -C $(KER_ADD) M=`pwd` modules clean
rm app -f
obj-m +=platform_drv.o platform_dev.o platform_dev2.o
4 运行效效果
-
接口
+关注
关注
33文章
8575浏览量
151015 -
Linux
+关注
关注
87文章
11292浏览量
209323 -
函数
+关注
关注
3文章
4327浏览量
62569
发布评论请先 登录
相关推荐
评论