平臺總線開發筆記

設備驅動模型:bus, driver, device
struct bus_type :總線對象,描述一個總線,管理device和driver,完成匹配
struct bus_type {
    const char        *name;
    int (*match)(struct device *dev, struct device_driver *drv);
}
註冊和註銷
    int bus_register(struct bus_type *bus)
    void bus_unregister(struct bus_type *bus)


device對象:設備對象,描述設備信息,包括地址,中斷號,甚至其他自定義的數據
struct device {
    struct kobject kobj;  //所有對象的父類
    const char        *init_name; 
    // 在總線中會有一個名字,用於做匹配,在/sys/bus/mybus/devices/名字
    struct bus_type    *bus; //指向該device對象依附於總線的對象
    void        *platform_data; // 自定義的數據,指向任何類型數據

註冊和註銷的方法:
    int device_register(struct device *dev)
    void device_unregister(struct device *dev)


driver對象:描述設備驅動的方法(代碼邏輯)
struct device_driver {
    const char        *name;
    // 在總線中會有一個名字,用於做匹配,在/sys/bus/mybus/drivers/名字
    struct bus_type        *bus;//指向該driver對象依附於總線的對象
    int (*probe) (struct device *dev); // 如果device和driver匹配之後,driver要做的事情
    int (*remove) (struct device *dev); // 如果device和driver從總線移除之後,driver要做的事情
}
註冊和註銷:
    int driver_register(struct device_driver *drv)
    void driver_unregister(struct device_driver *drv)

如何實現總線匹配,匹配成功之後會自動調用driver的probe方法:
    1, 實現bus對象中 match方法
    2, 保證driver和device中名字要一樣


====================================================================
平臺總線模型:
    爲什麼會有平臺總線:
        用於平臺升級:三星: 2410, 2440, 6410, s5pc100  s5pv210  4412
            硬件平臺升級的時候,部分的模塊的控制方式,基本上是類似的
            但是模塊的地址是不一樣

            gpio控制邏輯: 1, 配置gpio的輸入輸出功能: gpxxconf
                           2, 給gpio的數據寄存器設置高低電平: gpxxdata
                        邏輯操作基本上是一樣的
                        但是地址不一樣
            
            uart控制:1,設置8n1,115200, no AFC
                        UCON,ULCON, UMODOEN, UDIV
                    
                    邏輯基本上是一樣的
                    但是地址不一樣
    
    問題:
        當soc升級的時候, 對於相似的設備驅動,需要編寫很多次(如果不用平臺總線)
        但是會有大部分重複代碼

    解決:引入平臺總線    
            device(中斷/地址)和driver(操作邏輯) 分離
        在升級的時候,只需要修改device中信息即可(中斷/地址)
        實現一個driver代碼能夠驅動多個平臺相似的模塊,並且修改的代碼量很少
        

平臺總線中的三元素:
1, bus
    platform_bus:不需要自己創建,開機的時候自動創建

    struct bus_type platform_bus_type = {
        .name        = "platform",
        .dev_groups    = platform_dev_groups,
        .match        = platform_match,
        .uevent        = platform_uevent,
        .pm        = &platform_dev_pm_ops,
    };
    匹配方法:
        1,優先匹配pdriver中的id_table,裏面包含了支持不同的平臺的名字
        2,直接匹配driver中名字和device中名字

        struct platform_device *pdev = to_platform_device(dev);
        struct platform_driver *pdrv = to_platform_driver(drv);
        if (pdrv->id_table)// 如果pdrv中有idtable,平臺列表名字和pdev中的名字
            return platform_match_id(pdrv->id_table, pdev) != NULL;

        /* fall-back to driver name match */
        return (strcmp(pdev->name, drv->name) == 0);

2,device對象:
    struct platform_device {
        const char    *name;  //用於做匹配
        int        id;  // 一般都是直接給-1
        struct device    dev; // 繼承了device父類
        u32        num_resources; // 資源的個數
        struct resource    *resource; // 資源:包括了一個設備的地址和中斷
    }
    註冊和註銷
        int  platform_device_register(struct platform_device * pdev);
        void  platform_device_unregister(struct platform_device * pdev)

3,driver對象
    struct platform_driver {
            int (*probe)(struct platform_device *); //匹配成功之後被調用的函數
            int (*remove)(struct platform_device *);//device移除的時候調用的函數
            struct device_driver driver; //繼承了driver父類
                                |
                                const char        *name;
            const struct platform_device_id *id_table; //如果driver支持多個平臺,在列表中寫出來
    }
    註冊和註銷
        int platform_driver_register(struct platform_driver *drv);
        void platform_driver_unregister(struct platform_driver *drv)

==========================================
編寫代碼: 編寫一個能在多個平臺下使用的led驅動
1,註冊一個platform_device,定義資源:地址和中斷
            struct resource {
                resource_size_t start; // 開始
                resource_size_t end; //結束
                const char *name; //描述,自定義
                unsigned long flags; //區分當前資源描述的是中斷(IORESOURCE_IRQ)還是內存(IORESOURCE_MEM)
                struct resource *parent, *sibling, *child;
            };

2,註冊一個platform_driver,實現操作設備的代碼
        註冊完畢,同時如果和pdev匹配成功,自動調用probe方法:
                probe方法: 對硬件進行操作
                        a,註冊設備號,並且註冊fops--爲用戶提供一個設備標示,同時提供文件操作io接口
                        b, 創建設備節點
                        c, 初始化硬件
                                    ioremap(地址);  //地址從pdev需要獲取
                                    readl/writle();
                        d,實現各種io接口: xxx_open, xxx_read, ..
            獲取資源的方式:        
            //獲取資源
            // 參數1: 從哪個pdev中獲取資源
            // 參數2:  資源類型
            // 參數3: 表示獲取同種資源的第幾個
                struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num)

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