搜索
查看: 1209|: 0

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

[复制链接]

146

主题

7

回帖

574

积分

高级会员

积分
574
发表于 2014-9-4 11:47:48 | 显示全部楼层 |阅读模式
按照前面理解的设备模型,今天又制作了一个。平台设备版本的 "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两部分的分析,很容易就能看到设备模型与平台设备的关系。

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

大数据中国微信

QQ   

版权所有: Discuz! © 2001-2013 大数据.

GMT+8, 2024-11-1 11:39 , Processed in 0.104772 second(s), 25 queries .

快速回复 返回顶部 返回列表