欢迎访问电子工程网!   登录 | 免费注册 ]   

yd2763132的个人空间 http://www.eechina.com/space-uid-36266.html [收藏] [复制] [分享] [RSS]

博客

平台设备使用介绍

已有 323 次阅读2011-5-13 22:00 |个人分类:linux

设备驱动中,平台设备作为一个虚拟的设备和总线可以大大简化设计难度。
??其由两部分构成 platform_device和 platform_driver。其设计顺序为定义 platform_device -> 注册 platform_device-> 定义 platform_driver-> 注册 platform_driver 。platform_device 来描述该结构一个重要的元素是 resource ,该元素存入了最为重要的设备资源信息
struct platform_device {                   struct resource {
const char * name; //设备名称                   const char *name; //设备名称
u32 id; //取-1                         unsigned long start, end;//地址或是中断号
struct device dev;//设备结构                    unsigned long flags; 
                                     //IORESOURCE_IO IORESOURCE_MEM IORESOURCE_IRQ IORESOURCE_DMA
u32 num_resources; // resource结构个数     struct resource *parent, *sibling, *child;
struct resource * resource; //resource地址
};                           };
使用platform_get_resource函数来查找相应的数组.

      定义好了platform_device 结构体后就可以调用函数 platform_add_devices 或platform_device_register向系统中注册设备,前者可以一次性注册多个平台设备。要注意的是,这里的 platform_device 设备的注册过程必须在相应设备驱动加载之前被调用,即执行注册之前。因为驱动注册时需要匹配内核中所以已注册的设备名。 platform_device 是在系统启动时在 cpu.c 里的 s3c_arch_init() 函数里进行注册的。这个函数申明为 arch_initcall(s3c_arch_init); 会在系统初始化阶段被调用。arch_initcall 的优先级高于module_init 。所以会在Platform 驱动注册之前调用。详细参考 include/linux/init.h。现在内核中不是采用arch_initcall(s3c_arch_init) 注册platform_device 结构体而是通过.init_machine成员将其保存在arch_initcall(customize_machine)等待调用;其实质时一样的均放在.initcall3.init等待调用.然后定义结构体 struct platform_driver,在驱动初始化函数中调用函数 platform_driver_register() 注册 platform_driver ,需要注意的是platform_device 结构中 name 元素和 platform_driver 结构中 driver.name 必须是相同的。

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 (*suspend_late)(struct platform_device *, pm_message_t state);
         int (*resume_early)(struct platform_device *);
         int (*resume)(struct platform_device *); //恢复函数,在开机时被调用
         struct device_driver driver; //设备驱动结构
};
       在内核初始化时do_basic_setup()->driver_init()->platform_bus_init()初始化platform bus(虚拟总线),设备注册的时候platform_device_register()->platform_device_add()内核把设备挂在虚拟的platform bus下,驱动注册的时候 platform_driver_register()->driver_register()->bus_add_driver()->driver_attach()->bus_for_each_dev() 对每个挂在虚拟的platform bus的设备作 __driver_attach()->driver_probe_device()->drv->bus->match()==platform_match()-& gt比较strncmp(pdev->name, drv->name, BUS_ID_SIZE),如果相符就调用platform_drv_probe()->driver->probe(),如果probe成功则绑定该设备到该驱动。
      probe函数一般完成硬件设备使能, struct resource的获取以及虚拟地址的动态映射和具体类型设备的注册(因为平台设备只是一种虚拟的设备类型);remove函数完成硬件设备的关闭struct resource的获取以及虚拟地址的动态映射的释放和具体类型设备的注销。只要和内核本身运行依赖性不大的外围设备 ( 换句话说只要不在内核运行所需的一个最小系统之内的设备 ), 相对独立的 , 拥有各自独自的资源 (addresses and IRQs) ,都可以用 platform_driver 实现。如: lcd,usb,uart 等,都可以用 platfrom_driver 写,而 timer,irq 等最小系统之内的设备则最好不用 platfrom_driver 机制,实际上内核实现也是这样的。

说明:
在开发过程中内核版本的不同对于平台设备驱动注册方式也有不同的表示方法。
如2.6.14.1中的注册和注销                    如2.6.26.1中的注册和注销
static int __init s3c2410_rtc_init(void)    static int __init s3c2410_rtc_init(void)
{                                           {
   return driver_register(&s3c2410_rtcdrv);     return platform_driver_register(&s3c2410_rtcdrv);
}                                           }
static void __exit s3c2410_rtc_exit(void)   static void __exit s3c2410_rtc_exit(void)
{                                           {
   driver_unregister(&s3c2410_rtcdrv);          platform_driver_unregister(&s3c2410_rtcdrv);
}                                           }
   如2.6.14.1中                                  如2.6.26.1中
static struct device_driver s3c2410_rtcdrv={   static struct platform_driver s3c2410_rtcdrv = {
    .name = "s3c2410-rtc",                        .probe = s3c2410_rtc_probe,
    .owner = THIS_MODULE,                         .remove = s3c2410_rtc_remove,
    .bus = &platform_bus_type,                    .suspend = s3c2410_rtc_suspend,
    .probe = s3c2410_rtc_probe,                   .resume = s3c2410_rtc_resume,
    .remove = s3c2410_rtc_remove,                 .driver = {
    .suspend = s3c2410_rtc_suspend,                  .name = "s3c2410-rtc",
    .resume = s3c2410_rtc_resume,                    .owner = THIS_MODULE,}
};                                              };

platform_driver_register源代码如下://drivers/base/platform.c
int platform_driver_register(struct platform_driver *drv) {
         drv->driver.bus = &platform_bus_type; //定义总线为platform bus
         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);
}
       由以上可见platform_driver的一系列函数,在这儿全部赋值给了其成员struct device_driver driver里面的函数指针。


路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 立即注册

回顶部