學寫驅動抽象層

驅動的抽象層其實類似一個管理層,管理多種資源,使資源之間更加有序,高效的工作。使軟件的複用性和魯棒性更強。其核心思想是面向對象的編程思想,創建抽象的概念,增加抽象層之間的邏輯給更高層,屏蔽底層的“雜亂無章”。

 

理清芯片之間的關係和邏輯

硬件上8541e通過mipi和i2c連接到9288,9288通過gmsl信號線連接到96705編串器上,96705和0144是通過dvp接口連接,包含i2c。軟件上平臺8541e通過i2c訪問配置9288,通過9288的映射寄存器來訪問96705和0144,所以我們軟件實現的目標是在8541e上獲取0144的圖像數據,9288和96705是一種通信的編串和解串方式,不影響數據格式。

 

所以8541e看到的是關閉打開攝像頭,讀取攝像頭id,設置攝像頭格式,幀率等接口。不需要關心中間環節。這也是驅動抽象層給上層看到的接口。對於軟件的底層,我們可以把serdes抽象成橋,把傳感器抽象成sensor。不管什麼橋,不管什麼sensor都適用這套方法。

創建對象結構體

三個抽象對象:

  1. 面向平臺的camera操作方法和數據
  2. 面向brg的操作方法和數據
  3. 面向sensor的操作方法和數據

1和3的區別在於比如1的power on會包含2和3的power on。

靈活使用鏈表管理

鏈表用於管理已創建的數據對象,把相同的數據結構連起來,方便管理。比如在sensor的power中會用到brg的i2c_rw_0144的方法,就可以遍歷brg的鏈表,查找鏈表中名字爲“9288”的brg,當然如果註冊了多個brg,可以按照名字區分,也可以按照id來區分。

static LIST_HEAD(brg_list);

list_add_tail(&brg->list, &brg_list);

static inline struct serdbrg_device * sensor2brg(void)

{

    struct serdbrg_device *ambrg;

 

    list_for_each_entry(ambrg, &brg_list, list) {

            if (ambrg->id == 0)

                return ambrg;

    }

 

    printk("Can't find serdbrg in list\n");

    return NULL;

}

創建邏輯層,抽象接口

當需要創建一個brg的設備驅動時候,我們需要調用一個註冊的接口:

int _register_serdes_brg(struct serdbrg_device *brg, struct serdbrg_ops *ops)

當需要創建一個sensor的設備驅動時候,我們需要調用一個註冊的接口:

int _register_serdes_brg_device(struct sensor_brg_device *sensor, struct sensor_brg_ops *ops)

 

調用這兩個接口之前,要完成對象結構體的創建,就是傳送到函數的參數。

 

這兩個函數所做的邏輯主要是:

  1. 獲取設備id信息,不成功則退出註冊,並提示用戶失敗。成功進入下一步。
  2. 加入設備到鏈表。
  3. 創建文件系統接口。
  4. 提供文件系統接口訪問邏輯,主要是camera抽象函數的實現,比如:

Camera的stream on方法,上層訪問文件系統接口,傳入參數POWERON,然後底層調用brg和sensor的方法,輸出圖像:

     gbrg->ops->brg_power_on(gbrg,1) ;

     gbrg->ops->brg_hw_init_pre(gbrg);

     gbrg->ops->brg_set_clk_si(gbrg,0);

     gsensor->ops->init_device(gsensor);

    gbrg->ops->brg_vout_config(gbrg,1);
  1. 文件系統接口可以使用字符設備ioctl的方法也可以使用sys文件屬性的方法,都可以實現。

總結

雖然本例程沒有對多個sensor和brg做測試,但是原理上是可以很容易的兼容多個設備,通過id或者名字進行選擇操作方法。

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