S3C2440驅動篇—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 進行註冊。

 

一.平臺設備

        在Linux設備驅動中,有一類設備被稱爲“平臺設備”,通常把SoC系統中集成的獨立外設單元都當作平臺設備來處理。平臺設備用platform_device結構體來描述,在2.6.32.2內核中定義在include/linux/platform_devide.h中,其結構體如下:

struct platform_device {

       const char      * name;

       int           id;

       struct device   dev;

       u32         num_resources;

       struct resource       * resource;   //設備使用的資源

 

       struct platform_device_id      *id_entry;

 

       /* arch specific additions */

       struct pdev_archdata     archdata;

};

struct resource        //位於include/linux/ioport.h

{

     resource_size_t start;

     resource_size_t end;

     const char *name;

     unsigned long flags;

     struct resource *parent, *sibling, *child;

};

       我們通常關心start、end 和flags 這3 個字段,分別標明資源的開始值、結束值和類型,flags可以爲IORESOURCE_IO、IORESOURCE_MEM、IORESOURCE_IRQ、IORESOURCE_DMA 等。

       在Linux中定義了許多平臺設備,比如在:arch/arm/plat-s3c24xx/devs.c中,下面貼出WatchDog的平臺設備定義:

static struct resource s3c_wdt_resource[] = {

       [0] = {  //IO端口資源

              .start = S3C24XX_PA_WATCHDOG,

              .end   = S3C24XX_PA_WATCHDOG + S3C24XX_SZ_WATCHDOG - 1,

              .flags = IORESOURCE_MEM,

       },

       [1] = {  //中斷資源

              .start = IRQ_WDT,

              .end   = IRQ_WDT,

              .flags = IORESOURCE_IRQ,

       }

};

struct platform_device s3c_device_wdt = {

       .name               = "s3c2410-wdt",

       .id             = -1,

       .num_resources       = ARRAY_SIZE(s3c_wdt_resource),

       .resource   = s3c_wdt_resource,

};

EXPORT_SYMBOL(s3c_device_wdt);

       定義好平臺設備後,在系統中怎麼使用?在arch/arm/mach-s3c2440/mach-smdk2440.c中,這個ARM2440平臺的系統入口文件,系統初始化函數smdk2440_machine_init中使用platform_add_devices函數將一系列的平臺設備添加到系統中。

static struct platform_device *smdk2440_devices[] __initdata = {

       &s3c_device_usb,

       &s3c_device_lcd,

       &s3c_device_wdt,

       &s3c_device_i2c0,

       &s3c_device_iis,

};

static void __init smdk2440_machine_init(void)

{

       s3c24xx_fb_set_platdata(&smdk2440_fb_info);

       s3c_i2c0_set_platdata(NULL);

 

       platform_add_devices(smdk2440_devices, ARRAY_SIZE(smdk2440_devices));

       smdk_machine_init();

}

 

二.平臺驅動

       在Linux系統中爲平臺設備定義了平臺驅動platform_driver,平臺驅動結構體中定義了probe、remove、suspend、resume等接口函數來實現驅動。定義在include/linux/platform_devide.h中。

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 (*resume)(struct platform_device *);

       struct device_driver driver;

       struct platform_device_id *id_table;

};

       下面是WatchDog的platform_driverde初始化,其中driver結構體中初始化了owner、name變量,這裏的name要和平臺設備的name一致,這樣平臺設備和平臺驅動就關聯起來。

static struct platform_driver s3c2410wdt_driver = {

       .probe            = s3c2410wdt_probe,

       .remove          = __devexit_p(s3c2410wdt_remove),

       .shutdown      = s3c2410wdt_shutdown,

       .suspend  = s3c2410wdt_suspend,

       .resume          = s3c2410wdt_resume,

       .driver            = {

              .owner    = THIS_MODULE,

              .name      = "s3c2410-wdt",

       },

};

       驅動又是如何實現呢,在驅動初始化module_init()這個宏實現平臺驅動註冊,module_exit()中實現平臺驅動註銷。

static int __init watchdog_init(void)

{

       printk(banner);

       return platform_driver_register(&s3c2410wdt_driver);

}

static void __exit watchdog_exit(void)

{

       platform_driver_unregister(&s3c2410wdt_driver);

}

module_init(watchdog_init);

module_exit(watchdog_exit);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章