|
按照前面理解的设备模型,今天又制作了一个。平台设备版本的 "hello world".
如果选用平台设备作为总线,那么在设备模型这个三角关系中缺少的就只有 device和 driver了。那么现在的问题有两个:
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两部分的分析,很容易就能看到设备模型与平台设备的关系。
|
|