知识屋:更实用的电脑技术知识网站
所在位置:首页 > 操作系统 > linux

linux驱动编程--设备模型3--平台设备解析

发布时间:2014-09-05 17:41:32作者:知识屋

按照前面理解的设备模型,今天又制作了一个。平台设备版本的 "hello world".

如果选用平台设备作为总线,那么在设备模型这个三角关系中缺少的就只有 devicedriver了。那么现在的问题有两个:

1).怎么把device挂到平台设备bus的设备链表上。

2).怎么把driver添加到总线的设备链表上。

1.添加device到bus上

要添加一个device到总线的设备列表上,使用的通用函数是 device_register() ,但对于平台设备而言,有一个在该函数上封装的更简单易用的注册函数platform_driver_register()。总之就是使用这两个函数来完成注册,而具体的注册有两种方法:

a). 利用板级文件中的设备初始化,将自己的device添加到对应的设备数值中,那么在系统加载时就会自动加载该设备。但这有一个问题就是需要重新编译内核。

b). 利用模块加载,既然模块式内核留给用户的内核门户。那么它除了用来加载驱动之外,就一定可以用来对内核进行修改。下面的程序就是采用了第二种方法。

下面是一个简单例子

// for test driver#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/cdev.h>#include <asm/uaccess.h>#include <linux/device.h>#include <linux/platform_device.h>#define HELLO_NAM	"hello_test"static struct resource hello_res[] = {	[0] = {		.start = 0,		.end = 0x1,		.flags = IORESOURCE_MEM,	},	[1] = {		.start = 0x2,		.end = 0x3,		.flags = IORESOURCE_MEM,	},};static struct platform_device hello_device =  {	.name = HELLO_NAM,	.id = 0,	.num_resources = ARRAY_SIZE(hello_res),	.resource = hello_res,};static int __init hello_init( void){	return platform_device_register( &hello_device);}static void __exit hello_exit(){	platform_device_unregister( &hello_device);}MODULE_LICENSE("GPL");module_init( hello_init);module_exit( hello_exit);

2.添加driver到bus上

在上面device已经成功添加到bus上去了之后,现在就剩下将driver加载上去了。在通用的驱动中使用的信息记录结构体是device_driver,但为了使用方便平台设备又有一个封装结构体platform_driver。在通用的驱动中使用的驱动注册函数是driver_register() ,在设备平台中的封装产品是platform_driver_register() 。那么制作一个完整的例子就是

#include <linux/module.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/cdev.h>#include <asm/uaccess.h>#include <linux/device.h>#include <linux/platform_device.h>#define HELLO_NAME	"hello_test"static int hello_probe(struct platform_device *dev){	struct resource *pRes = NULL;	printk("hello_probe............/n");	pRes = platform_get_resource( dev, IORESOURCE_MEM, 1);	if( NULL!=pRes)		{		printk(" resource : %d, %d, %s/n", pRes->start, pRes->end, pRes->name);	}	device_register(struct device * dev);	return 0;	//返回0表示接受这次探测}static int hello_remove(struct platform_device *dev){	printk(" hello_remove........................./n");	return 0;}static struct platform_driver hello_drv = {	.probe = hello_probe,	.remove = hello_remove,	.driver = {		.name = HELLO_NAME,		.owner = THIS_MODULE,	},};static int __init hello_init( void){	driver_register(struct device_driver * drv);	return platform_driver_register( &hello_drv);}static void __exit hello_exit( void){	platform_driver_unregister( &hello_drv);}MODULE_LICENSE("GPL");module_init( hello_init);module_exit( hello_exit); 

3.platfrom是设备模型的一个实例

从platform源码可以看出其只是设备模型的一个实例。来看一下platforn_device。它的信息结构体是

struct platform_device {	const char	* name;	//设备名,会用来和驱动进行匹配	int		id;	//	struct device	dev;	//通用设备成员	u32		num_resources;	//资源数	struct resource	* resource;	//资源数组	struct platform_device_id	*id_entry;};

从信息结构体中看到,platform_device包含了一个通用设备结构体成员dev。dev就是最终在总线上工作的信息节点。再来看注册函数

int platform_device_add(struct platform_device *pdev){	int i, ret = 0;	if (!pdev)		return -EINVAL;	//	if (!pdev->dev.parent)		pdev->dev.parent = &platform_bus;	pdev->dev.bus = &platform_bus_type;	if (pdev->id != -1)		dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);	else		dev_set_name(&pdev->dev, pdev->name);	//将资源加入一个全局的资源链表	for (i = 0; i < pdev->num_resources; i++) {		struct resource *p, *r = &pdev->resource[i];		if (r->name == NULL)			r->name = dev_name(&pdev->dev);		p = r->parent;		if (!p) {			if (resource_type(r) == IORESOURCE_MEM)	//默认的资源链表				p = &iomem_resource;			else if (resource_type(r) == IORESOURCE_IO)				p = &ioport_resource;		}		if (p && insert_resource(p, r)) {			printk(KERN_ERR			       "%s: failed to claim resource %d/n",			       dev_name(&pdev->dev), i);			ret = -EBUSY;			goto failed;		}	}	//在这里就看到了最熟悉的身影	ret = device_add(&pdev->dev);	......}

最后也就是靠"device_add(&pdev->dev) ",完成了将设备添加到总线(platform总线)的任务。之后的操作就是一般的通用设备注册操作了。

那么现在再来看看,driver部分,其信息结构体为

struct platform_driver {	int (*probe)(struct platform_device *);	//作为探针函数存在,返回0表示选中	int (*remove)(struct platform_device *);	void (*shutdown)(struct platform_device *);	int (*suspend)(struct platform_device *, pm_message_t state);	int (*suspend_late)(struct platform_device *, pm_message_t state);	int (*resume_early)(struct platform_device *);	int (*resume)(struct platform_device *);	struct device_driver driver;	//通用设备驱动成员	struct platform_device_id *id_table;};

这里除了包含了最核心的通用设备驱动成员外,还包含了一些回调函数接口。

int platform_driver_register(struct platform_driver *drv){	//该驱动属于平台设备总线	drv->driver.bus = &platform_bus_type;	if (drv->probe)		drv->driver.probe = platform_drv_probe;	if (drv->remove)		drv->driver.remove = platform_drv_remove;	if (drv->shutdown)		drv->driver.shutdown = platform_drv_shutdown;	if (drv->suspend)		drv->driver.suspend = platform_drv_suspend;	if (drv->resume)		drv->driver.resume = platform_drv_resume;	//熟悉的身影	return driver_register(&drv->driver);}

通过其注册代码,很容易又找到了"driver_register(&drv->driver) "。

通过对上面的device和driver两部分的分析,很容易就能看到设备模型与平台设备的关系。

(免责声明:文章内容如涉及作品内容、版权和其它问题,请及时与我们联系,我们将在第一时间删除内容,文章内容仅供参考)
收藏
  • 人气文章
  • 最新文章
  • 下载排行榜
  • 热门排行榜