Chinaunix首页 | 论坛 | 博客
  • 博客访问: 836806
  • 博文数量: 489
  • 博客积分: 475
  • 博客等级: 下士
  • 技术积分: 3087
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-08 16:28
文章分类

全部博文(489)

文章存档

2013年(7)

2012年(301)

2011年(181)

分类:

2012-05-22 13:15:31

原文地址:Linux平台设备驱动 作者:迷墙人

在设备驱动程序中经常会见到和platform相关的字段,分布在驱动程序的多个角落,这也是2.6内核中比较重要的一种机制,把它原理弄懂,对以 后分析驱动程序很有帮助:在linux2.6设备模型中,关心总线,设备,驱动这三个实体,总线将设备和驱动绑定,在系统每注册一个设备的时候,会寻找与 之匹配的驱动。相反,在系统每注册一个驱动的时候,寻找与之匹配的设备,匹配是由总线来完成的。

一个现实的Linux 设备和驱动通常都需要挂接在一种总线上,对于本身依附于PCI、USB、I2C、SPI 等的设备而言,这自然不是问题,但是在嵌入式系统里面,SoC 系统中集成的独立的外设控制器、挂接在SoC 内存空间的外设等确不依附于此类总线。基于这一背景,Linux 发明了一种虚拟的总线,称为platform 总线。SOC系统中集成的独立外设单元(LCD,RTC,WDT等)都被当作平台设备来处理,而它们本身是字符型设备。

从Linux2.6内核起,引入一套新的驱动管理和注册机制:platform_device 和 platform_driver 。Linux 中大部分的设备驱动,都可以使用这套机制,设备用 platform_device 表示;驱动用platform_driver 进行注册。

(1)平台设备

在Linux设备驱动中,有一类设备被称为“平台设备”,通常把SoC系统中集成的独立外设单元都当作平台设备来处理。平台设备用 platform_device结构体来描述,在2.6.32.2内核中定义在include/linux/platform_devide.h中,其结 构体如下:

  1. struct platform_device {  
  2.        const char      * name;  
  3.        int           id;  
  4.        struct device   dev;  
  5.        u32         num_resources;  
  6.        struct resource       * resource;   //设备使用的资源  
  7.    
  8.        struct platform_device_id      *id_entry;  
  9.    
  10.        /* arch specific additions */  
  11.        struct pdev_archdata     archdata;  
  12. };  
  13. struct resource        //位于include/linux/ioport.h  
  14. {  
  15.      resource_size_t start;  
  16.      resource_size_t end;  
  17.      const char *name;  
  18.      unsigned long flags;  
  19.      struct resource *parent, *sibling, *child;  
  20. };  

我们通常关心start、end 和flags 这3 个字段,分别标明资源的开始值、结束值和类型,flags可以为IORESOURCE_IO、IORESOURCE_MEM、IORESOURCE_IRQ、IORESOURCE_DMA 等。

       在Linux中定义了许多平台设备,比如在:arch/arm/plat-s3c24xx/devs.c中,下面贴出WatchDog的平台设备定义:

  1. static struct resource s3c_wdt_resource[] = {  
  2.        [0] = {  //IO端口资源  
  3.               .start = S3C24XX_PA_WATCHDOG,  
  4.               .end   = S3C24XX_PA_WATCHDOG + S3C24XX_SZ_WATCHDOG - 1,  
  5.               .flags = IORESOURCE_MEM,  
  6.        },  
  7.        [1] = {  //中断资源  
  8.               .start = IRQ_WDT,  
  9.               .end   = IRQ_WDT,  
  10.               .flags = IORESOURCE_IRQ,  
  11.        }  
  12. };  
  13. struct platform_device s3c_device_wdt = {  
  14.        .name               = "s3c2410-wdt",  
  15.        .id             = -1,  
  16.        .num_resources       = ARRAY_SIZE(s3c_wdt_resource),  
  17.        .resource   = s3c_wdt_resource,  
  18. };  
  19. EXPORT_SYMBOL(s3c_device_wdt);  

定义好平台设备后,在系统中怎么使用?在arch/arm/mach-s3c2440/mach-smdk2440.c中,这个ARM2440平台 的系统入口文件,系统初始化函数smdk2440_machine_init中使用platform_add_devices函数将一系列的平台设备添加 到系统中。

  1. static struct platform_device *smdk2440_devices[] __initdata = {  
  2.        &s3c_device_usb,  
  3.        &s3c_device_lcd,  
  4.        &s3c_device_wdt,  
  5.        &s3c_device_i2c0,  
  6.        &s3c_device_iis,  
  7. };  
  8.   
  9. static void __init smdk2440_machine_init(void)  
  10. {        
  11.        s3c24xx_fb_set_platdata(&smdk2440_fb_info);  
  12.        s3c_i2c0_set_platdata(NULL);  
  13.        platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));  
  14.        smdk_machine_init();  
  15. }  

(2)平台驱动

       在Linux系统中为平台设备定义了平台驱动platform_driver,平台驱动结构体中定义了probe、remove、suspend、 resume等接口函数来实现驱动。定义在include/linux/platform_devide.h中。

  1. struct platform_driver {  
  2.        int (*probe)(struct platform_device *);  
  3.        int (*remove)(struct platform_device *);  
  4.        void (*shutdown)(struct platform_device *);  
  5.        int (*suspend)(struct platform_device *, pm_message_t state);  
  6.        int (*resume)(struct platform_device *);  
  7.        struct device_driver driver;  
  8.        struct platform_device_id *id_table;  
  9. };  

下面是WatchDog的platform_driverde初始化,其中driver结构体中初始化了owner、name变量,这里的name要和平台设备的name一致,这样平台设备和平台驱动就关联起来。
  1. static struct platform_driver s3c2410wdt_driver = {  
  2.        .probe            = s3c2410wdt_probe,  
  3.        .remove          = __devexit_p(s3c2410wdt_remove),  
  4.        .shutdown      = s3c2410wdt_shutdown,  
  5.        .suspend  = s3c2410wdt_suspend,  
  6.        .resume          = s3c2410wdt_resume,  
  7.        .driver            = {  
  8.               .owner    = THIS_MODULE,  
  9.               .name      = "s3c2410-wdt",  
  10.        },  
  11. };  

驱动又是如何实现呢,在驱动初始化module_init()这个宏实现平台驱动注册,module_exit()中实现平台驱动注销。
  1. static int __init watchdog_init(void)  
  2. {  
  3.        printk(banner);  
  4.        return platform_driver_register(&s3c2410wdt_driver);  
  5. }  
  6. static void __exit watchdog_exit(void)  
  7. {  
  8.        platform_driver_unregister(&s3c2410wdt_driver);  
  9. }  
  10.   
  11. module_init(watchdog_init);  
  12. module_exit(watchdog_exit);  

阅读(472) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~