對於字符設備驅動程序,之前都是在驅動程序中定義並設置file_operations結構體,實現各種需要用到的函數,註冊file_operations結構體,框架比較簡單,但是在Linux中,卻很少看見這樣框架的代碼,那是因爲在Linux中設備驅動模型一般都由總線、設備、驅動這個三大部分組成。這是一種分層分離的思想:
分層:核心層和設備相關層分開。
分離:講硬件相關的代碼和驅動分開。
這就是總線設備驅動(bus_drv_dev)模型:
對於dev模塊,當調用device_add函數時:
a.會將device結構體放入bus的device鏈表
b.從bus的drv鏈表中取出每一個結構體,利用match函數進行對比,判斷是否當前的這個dev
c.如支持,則調用驅動額probe函數
對於drv模塊,當調用driver_register時:
a.會將driver結構體放入bus的driver結構體
b.從bus的dev結構體中取出每一個結構體,通過match函數比較,判斷是否支持當前driver
c.若支持,這調用驅動的probe函數
match函數的比較:
match函數是根據device中的bus_id和driver的name是否一致來匹配的,如果一樣就調用driver中的probe函數
編寫驅動的步驟:
一.在device部分(device.c)
1.定義並設置一個platform_device結構體:包括name(要和driver中的名字對應)、dev結構體下完成一個release函數、一個resource結構體(需要自己定義並填充),這個結構體中有着硬件相關的地址
如:static resource led_dev_resource[]={
[0]={
.start=0x56000050,
.end=0x56000050+4-1,
.flags=IORESOURCE_MEM,
},
[1]={
.start=4,
.end=4,
.flags=IORESOURCE_IRQ,
},
};
static void led_dev_release(struct device * dev)
{
}
static platform_device led_dev={
.name = "myled",
.id = -1,
.resource=led_dev_resource,
.dev={
.release=led_dev_release,
},
};
2.註冊platform_device結構體
int platform_device_register(struct platform_device * pdev)//註冊platform_device結構體
void platform_device_unregister(struct platform_device * pdev)//卸載
二.在driver部分(driver.c)
1.定義並設置一個platform_driver結構體,
如:static platform_driver led_drv={
.probe=led_drv_probe,//匹配後講調用的函數
.remove=led_drv_remove,//與probe相關的清理工作
.driver={
.name="myled",//名字必須與platform_device中的name相同
.owner=THIS_MODULE,
},
};
2.註冊
int platform_device_register(struct platform_device * pdev)
例子:講led點燈拆分成dev和dri兩個部分
在dev.c中(部分核心代碼)
在drv中(部分代碼)
整體上實現了一個bus-dev-drv模型的驅動程序,這樣做的好處:當我們需要修改硬件的時候,只需要修改dev中的代碼即可,不需要動dri中的代碼。