Platform_device Platform_driver



Linux 2.6 起引入了一套新的驅動管理和註冊機制 :Platform_device Platform_driver



     Linux 中大部分的設備驅動,都可以使用這套機制 , 設備用 Platform_device 表示,驅動用 Platform_driver 進行註冊。


 


    Linux platform driver 機制和傳統的 device driver 機制 ( 通過 driver_register 函數進行註冊 ) 相比,一個十分明顯的優勢在於 platform 機制將設備本身的資源註冊進核心,由核心統一管理,在驅動程序中使用這些資源時通過 platform device 提供的標準接口進行申請並使用。這樣提高了驅動和資源管理的獨立性,並且擁有較好的可移植性和安全性 ( 這些標準接口是安全的 )


 


    Platform 機制的本身使用並不復雜由兩部分組成: platform_device platfrom_driver


    通過 Platform 機制開發發底層驅動的大致流程為 : 定義 platform_device -> 註冊 platform_device-> 定義 platform_driver-> 註冊 platform_driver


 


首先要確認的就是設備的資源信息,例如設備的地址,中斷號等。


2.6 核心中 platform 設備用結構體 platform_device 來描述,該結構體定義在 kernel\include\linux\platform_device.h 中,


 


 


struct platform_device {


const char * name;


u32 id;


struct device dev;


u32 num_resources;


struct resource * resource;


};




另外注意 - struct device dev;


struct device {
    struct klist        klist_children;
    struct klist_node    knode_parent;        /* node in sibling list */
    struct klist_node    knode_driver;
    struct klist_node    knode_bus;
    struct device        *parent;
    struct kobject kobj;
    char    bus_id[BUS_ID_SIZE];    /* position on parent bus */
    struct device_type    *type;
    unsigned        is_registered:1;
    unsigned        uevent_suppress:1;
    struct semaphore    sem;    /* semaphore to synchronize calls to
                     * its driver.
                     */
    struct bus_type    * bus;        /* type of bus device is on */
    struct device_driver *driver;    /* which driver has allocated this
                     device */
    void        *driver_data;    /* data private to the driver */
    void        *platform_data;    /* Platform specific data, device
                     core doesn't touch it */
    struct dev_pm_info    power;
#ifdef CONFIG_NUMA
    int        numa_node;    /* NUMA node this device is close to */
#endif
    u64        *dma_mask;    /* dma mask (if dma'able device) */
    u64        coherent_dma_mask;/* Like dma_mask, but for
                     alloc_coherent mappings as
                     not all hardware supports
                     64 bit addresses for consistent
                     allocations such descriptors. */
    struct list_head    dma_pools;    /* dma pools (if dma'ble) */
    struct dma_coherent_mem    *dma_mem; /* internal for coherent mem
                     override */
    /* arch specific additions */
    struct dev_archdata    archdata;
    spinlock_t        devres_lock;
    struct list_head    devres_head;
    /* class_device migration path */
    struct list_head    node;
    struct class        *class;
    dev_t            devt;        /* dev_t, creates the sysfs "dev" */
    struct attribute_group    **groups;    /* optional groups */
    void    (*release)(struct device * dev);
};






 


    該結構一個重要的元素是 resource ,該元素存入了最為重要的設備資源信息,定義在 kernel\include\linux\ioport.h 中,


 


 


struct resource {


const char *name;


unsigned long start, end;


unsigned long flags;


struct resource *parent, *sibling, *child;


};


 


 


 


下面舉 s3c2410 平台的 i2c 驅動作為例子來說明:


 



/* arch/arm/mach-s3c2410/devs.c */ 
/* I2C */ 
static struct resource s3c_i2c_resource[ ] = { 
         [ 0] = { 
                   . start = S3C24XX_PA_IIC, 
                   . end = S3C24XX_PA_IIC + S3C24XX_SZ_IIC - 1, 
                   . flags = IORESOURCE_MEM, 
         } , 
         [ 1] = { 
                   . start = IRQ_IIC, //S3C2410_IRQ(27) 
                   . end = IRQ_IIC, 
                   . flags = IORESOURCE_IRQ, 
         } 
} ; 
 



 



   
這裡定義了兩組 resource ,它描述了一個 I2C 設備的資源,第 1 組描述了這個 I2C 設備所佔用的總線地址範圍, IORESOURCE_MEM 表示第 1 組描述的是內存類型的資源信息,第 2 組描述了這個 I2C 設備的中斷號, IORESOURCE_IRQ 表示第 2 組描述的是中斷資源信息。設備驅動會根據 flags 來獲取相應的資源信息。


 


有了 resource 信息,就可以定義 platform_device 了:


 


 


 


struct platform_device s3c_device_i2c = { 
         . name = "s3c2410-i2c" , 
         . id = - 1, 
         . num_resources = ARRAY_SIZE( s3c_i2c_resource) , 
         . resource = s3c_i2c_resource, 
} ; 
 



   


      定義好了 platform_device 結構體後就可以呼叫函數 platform_add_devices 向系統中添加該設備了,之後可以呼叫 platform_device_register() 進行設備註冊。要注意的是,這裡的 platform_device 設備的註冊過程必須在相應設備驅動加載之前被呼叫,即執行 platform_driver_register 之前 , 原因是因為驅動註冊時需要匹配核心中所以已註冊的設備名。


 


   


    s3c2410-i2c platform_device 是在系統啟動時,在cpu.c 裡的 s3c_arch_init() 函數里進行註冊的,這個函數申明為 arch_initcall(s3c_arch_init); 會在系統初始化階段被呼叫。


 


 


    arch_initcall 的優先級高於 module_init 。所以會在 Platform 驅動註冊之前呼叫。 ( 詳細參考 include/linux/init.h)


 


s3c_arch_init 函數如下:


 



/* arch/arm/mach-3sc2410/cpu.c */ 
static int __init s3c_arch_init( void ) 

    int ret; 
     ……
/*
這裡board指針指向在mach-smdk2410.c裡的定義的smdk2410_board,裡麵包含了預先定義的I2C Platform_device. */ 
    if ( board ! = NULL ) { 
        struct platform_device * * ptr = board- > devices; 
        int i;


        for ( i = 0; i < board- > devices_count; i+ + , ptr+ + ) { 
             ret = platform_device_register( * ptr) ;      //
在這裡進行註冊


            if ( ret) { 
                 printk( KERN_ERR "s3c24xx: failed to add board device %s (%d) @%p\n" , ( * ptr) - > name, 
ret, * ptr) ; 
            } 
        } 
         /* mask any error, we may not need all these board
         * devices */ 
         ret = 0; 
    } 
    return ret; 
}


 



 



同時被註冊還有很多其他平台的 platform_device ,詳細查看 arch/arm/mach-s3c2410/mach-smdk2410.c 裡的 smdk2410_devices 結構體。


 


 


 


 


驅動程序需要實現結構體 struct platform_driver ,參考 drivers/i2c/busses



/* device driver for platform bus bits */



static struct platform_driver s3c2410_i2c_driver = { 
         . probe = s3c24xx_i2c_probe, 
         . remove = s3c24xx_i2c_remove, 
         . resume = s3c24xx_i2c_resume, 
         . driver = { 
                   . owner = THIS_MODULE, 
                   . name = "s3c2410-i2c" , 
         } , 
} ; 
 



 



 


 


 


在驅動初始化函數中呼叫函數 platform_driver_register() 註冊 platform_driver ,需要注意的是 s3c_device_i2c 結構中 name 元素和 s3c2410_i2c_driver 結構中 driver.name 必須是相同的,這樣在 platform_driver_register() 註冊時會對所有已註冊的所有 platform_device 中的 name 和當前註冊的 platform_driver driver.name 進行比較,只有找到相同的名稱的 platfomr_device 才能註冊成功,當註冊成功時會呼叫 platform_driver 結構元素 probe 函數指針,這裡就是 s3c24xx_i2c_probe, 當進入 probe 函數後,需要獲取設備的資源信息,常用獲取資源的函數主要是:


 


struct resource * platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num);


根據參數 type 所指定類型,例如 IORESOURCE_MEM ,來獲取指定的資源。


 


 


 


struct int platform_get_irq(struct platform_device *dev, unsigned int num);


獲取資源中的中斷號。


 


下面舉 s3c24xx_i2c_probe 函數分析 , 看看這些接口是怎麼用的。


前面已經講了, s3c2410_i2c_driver 註冊成功後會呼叫 s3c24xx_i2c_probe 執行,下面看代碼:


/* s3c24xx_i2c_probe
*
* called by the bus driver when a suitable device is found
*/


arrow
arrow
    全站熱搜

    立你斯 發表在 痞客邦 留言(0) 人氣()