Linux平臺(tái)設(shè)備框架驅(qū)動(dòng)
? 平臺(tái)設(shè)備框架(platform)是將一個(gè)驅(qū)動(dòng)分為設(shè)備層和驅(qū)動(dòng)層兩個(gè)部分,通過總線模型將設(shè)備和驅(qū)動(dòng)進(jìn)行綁定。在系統(tǒng)中每注冊(cè)一個(gè)設(shè)備,都會(huì)與之匹配一個(gè)驅(qū)動(dòng),同樣的,每注冊(cè)一個(gè)驅(qū)動(dòng)也會(huì)與之匹配一個(gè)設(shè)備。
通常 Linux 設(shè)備和驅(qū)動(dòng)通常都需要掛接在一種總線上,對(duì)于本身依附于 PCI、 USB、 I2 C、 SPI 等的設(shè)備而言,這自然不是問題,但是在嵌入式系統(tǒng)里面, SOC 系統(tǒng)中集成的獨(dú)立的外設(shè)控制器、掛接在 SOC 內(nèi)存空間的外設(shè)等卻不依附于此類總線。
基于總線框架的模型結(jié)構(gòu),Linux下就衍生了平臺(tái)設(shè)備框架模型(platform),平臺(tái)設(shè)備總線是一種虛擬總線,稱為platform總線。對(duì)應(yīng)的設(shè)備層稱為platform_device;驅(qū)動(dòng)層稱為platform_driver。設(shè)備層和驅(qū)動(dòng)層通過平臺(tái)設(shè)備總線進(jìn)行匹配管理。
1.平臺(tái)設(shè)備框架特性
平臺(tái)模型采用了分層結(jié)構(gòu),把一個(gè)設(shè)備驅(qū)動(dòng)程序分成了兩個(gè)部分:
平臺(tái)設(shè)備( platform_device)和平臺(tái)驅(qū)動(dòng)( platform_driver)。
平臺(tái)設(shè)備將設(shè)備本身的資源注冊(cè)進(jìn)內(nèi)核,可以由內(nèi)核統(tǒng)一管理。
將硬件資源和驅(qū)動(dòng)接口分離,編譯代碼的維護(hù)與移植。
2.平臺(tái)設(shè)備總線相關(guān)接口函數(shù)
2.1 設(shè)備層接口函數(shù)
??每個(gè)設(shè)備的系統(tǒng)通過設(shè)備結(jié)構(gòu)體struct platform_device保存。結(jié)構(gòu)體原型在 include/linux/platform_devcie.h 中定義。
struct platform_device {
const char * name; //設(shè)備名字,驅(qū)動(dòng)層和設(shè)備層匹配標(biāo)志
int id;//通常填-1
struct device dev;//設(shè)備結(jié)構(gòu)體信息
u32 num_resources;//資源個(gè)數(shù)
struct resource * resource;//資源內(nèi)容
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結(jié)構(gòu)信息
struct device dev 結(jié)構(gòu)體是用來實(shí)現(xiàn)設(shè)備模型的。這個(gè)結(jié)構(gòu)體中成員比較多,結(jié)構(gòu)體原型在 include/linux/devcie.h 中定義。我們常關(guān)心的是其中的兩個(gè)成員:
平臺(tái)數(shù)據(jù)指針: void *platform_data;
資源釋放函數(shù): void (*release)(struct device *dev);
平臺(tái)數(shù)據(jù)指針platform_data是一個(gè)void *類型指針,可以向驅(qū)動(dòng)層傳遞任意數(shù)據(jù),release資源釋放函數(shù)接口在設(shè)備層一定要自己實(shí)現(xiàn),否則在設(shè)備層釋放資源時(shí)會(huì)報(bào)錯(cuò)。
以下列舉其中幾個(gè)成員結(jié)構(gòu):
struct device {
const char *init_name; /*邏輯設(shè)備的名字*/
struct device_type *type; /* 設(shè)備類型 */
struct bus_type *bus; /* 設(shè)備所屬的總線類型 */
struct device_driver *driver;/* 指向開辟 struct device 結(jié)構(gòu) driver 指針*/
void *platform_data; /* 平臺(tái)設(shè)備指針 */
dev_t devt; /* 存放設(shè)備號(hào) dev_t,creates the sysfs"dev" */
struct class *class; /* 設(shè)備所屬類*/
void (*release)(struct device *dev);/*設(shè)備資源釋放函數(shù)*/
};
-
struct resource * resource結(jié)構(gòu)信息
??struct resource * resource 結(jié)構(gòu)體是用來保存設(shè)備資源內(nèi)容信息。該結(jié)構(gòu)體定義位置: include/linux/ioport.h
struct resource {
resource_size_t start; //資源起始地址
resource_size_t end; //資源結(jié)構(gòu)地址
const char *name;//資源名字
unsigned long flags;//資源類型
struct resource *parent, *sibling, *child;
};
- 設(shè)備層注冊(cè)函數(shù)
int platform_device_register(struct platform_device *pdev)
函數(shù)功能: 注冊(cè)平臺(tái)設(shè)備;
形參: pdev --設(shè)備結(jié)構(gòu)體;
返回值: 成功返回0,失敗返回其它值;
- 設(shè)備層注銷函數(shù)
void platform_device_unregister(struct platform_device *pdev)
函數(shù)功能: 注冊(cè)平臺(tái)設(shè)備;
形參: pdev --設(shè)備結(jié)構(gòu)體;
- 向內(nèi)核添加多個(gè)設(shè)備
int platform_add_devices(struct platform_device **devs, int num)
函數(shù)功能: 向內(nèi)核注冊(cè)多個(gè)設(shè)備;
形參: pdev --設(shè)備結(jié)構(gòu)體;
???num – 注冊(cè)的設(shè)備個(gè)數(shù)
返回值: 成功返回0,失敗返回其它值;
2.2 驅(qū)動(dòng)層接口函數(shù)
驅(qū)動(dòng)層通過struct platform_driver 結(jié)構(gòu)體保存相關(guān)信息,結(jié)構(gòu)體定義位置: include/linux/devcie.h
在該結(jié)構(gòu)體中必須要實(shí)現(xiàn)接口函數(shù):
資源匹配函數(shù):int (*probe)(struct platform_device *)
資源釋放函數(shù):int (*remove)(struct platform_device *);
驅(qū)動(dòng)資源結(jié)構(gòu)體:struct device_driver driver;
一個(gè)驅(qū)動(dòng)層可匹配多個(gè)設(shè)備層,若想同時(shí)匹配多個(gè)設(shè)備層,則通過id_table 指針完成匹配。
struct platform_driver {
int (*probe)(struct platform_device *);//資源匹配函數(shù)
int (*remove)(struct platform_device *);//資源釋放函數(shù)
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *, pm_message_t state);
int (*resume)(struct platform_device *);
struct device_driver driver;//驅(qū)動(dòng)資源結(jié)構(gòu)體
const struct platform_device_id *id_table;//匹配多多設(shè)備時(shí)需要填寫
};
- struct device_driver driver 結(jié)構(gòu)信息
??struct device_driver driver 結(jié)構(gòu)體中有個(gè)成員name必須要填寫,當(dāng)沒有實(shí)現(xiàn)id_table指針時(shí),設(shè)備層和驅(qū)動(dòng)層就是通過該成員完成資源匹配。
struct device_driver {
const char *name; //資源匹配參數(shù)
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 結(jié)構(gòu)信息
??該結(jié)構(gòu)也是用于匹配設(shè)備資源,一個(gè)驅(qū)動(dòng)層可以同時(shí)匹配多個(gè)設(shè)備層。
struct platform_device_id {
char name[PLATFORM_NAME_SIZE]; //資源匹配參數(shù)
kernel_ulong_t driver_data
__attribute__((aligned(sizeof(kernel_ulong_t)))); //匹配設(shè)備層的 void *platform_data數(shù)據(jù)
};
- 驅(qū)動(dòng)層注冊(cè)和注銷函數(shù)
//驅(qū)動(dòng)注冊(cè)函數(shù)
int platform_driver_register(struct platform_driver *drv)
//驅(qū)動(dòng)注銷函數(shù)
void platform_driver_unregister(struct platform_driver *drv)
3.平臺(tái)設(shè)備框架應(yīng)用示例
3.1 設(shè)備層注冊(cè)示例
設(shè)備層注冊(cè)步驟:
填充struct device結(jié)構(gòu)體,填寫設(shè)備資源信息struct resource * resource;
調(diào)用設(shè)備層注冊(cè)函數(shù)platform_device_register();
注銷時(shí)調(diào)用注銷函數(shù)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,//資源釋放函數(shù)
},
.num_resources=sizeof(resource)/sizeof(resource[0]),
.resource=resource,
};
static int __init wbyq_platform_dev_init(void)
{
platform_device_register(&pdev);
return 0;
}
/*驅(qū)動(dòng)釋放*/
static void __exit wbyq_platform_dev_cleanup(void)
{
/*注銷設(shè)備層*/
platform_device_unregister(&pdev);
}
module_init(wbyq_platform_dev_init);//驅(qū)動(dòng)入口函數(shù)
module_exit(wbyq_platform_dev_cleanup);//驅(qū)動(dòng)出口函數(shù)
MODULE_LICENSE("GPL");//驅(qū)動(dòng)注冊(cè)協(xié)議
MODULE_AUTHOR("it_ashui");
MODULE_DESCRIPTION("Exynos4 platform_dev Driver");
3.2 驅(qū)動(dòng)層注冊(cè)示例
驅(qū)動(dòng)層注冊(cè)步驟:
填充 struct platform_driver結(jié)構(gòu)體,實(shí)現(xiàn)資源匹配函數(shù)和資源釋放函數(shù);
調(diào)用設(shè)備層注冊(cè)函數(shù)platform_driver_register();
注銷時(shí)調(diào)用注銷函數(shù)platform_driver_unregister;
#include
#include
#include
#include
#include
#include
#include
#include
#include
static int platform_probe(struct platform_device *dev)
{
printk("資源匹配成功n");
printk("資源個(gè)數(shù):%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("驅(qū)動(dòng)層平臺(tái)設(shè)備注冊(cè)成功n");
return 0;
}
/*驅(qū)動(dòng)釋放*/
static void __exit wbyq_platform_drv_cleanup(void)
{
/*注銷設(shè)備層*/
platform_driver_unregister(&drv);
printk("驅(qū)動(dòng)層平臺(tái)設(shè)備注銷成功n");
}
module_init(wbyq_platform_drv_init);//驅(qū)動(dòng)入口函數(shù)
module_exit(wbyq_platform_drv_cleanup);//驅(qū)動(dòng)出口函數(shù)
MODULE_LICENSE("GPL");//驅(qū)動(dòng)注冊(cè)協(xié)議
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 運(yùn)行效效果
-
接口
+關(guān)注
關(guān)注
33文章
8575瀏覽量
151014 -
Linux
+關(guān)注
關(guān)注
87文章
11292瀏覽量
209318 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4327瀏覽量
62569
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論