先介紹一下驅動的分層/分離。如下圖
input.c為應用程式提供了介面,是核心層,而在核心層下面的那一層由兩方面組成,乙個是純軟體的,裡面是很穩定的**,還有乙個是與硬體相關的**,一般只需要通過修改與硬體相關的**而達到我們的目的。
再介紹乙個概念,匯流排-驅動-裝置模型。如下圖
bus、driver、device實際上都只是乙個結構體。
左邊的device是與硬體相關的**,實現下面的功能:
①通過device_add把device放入bus的dev鍊錶中;
②從bus的drv鍊錶中取出每乙個drv,用bus的match函式判斷drv能否支援dev;
③若可以支援,呼叫drv的probe函式。
而右邊的driver是比較穩定的**,實現下面的功能:
①通過driver_register把driver放入bus的drv鍊錶中;
②從bus的dev鍊錶中取出每乙個dev,用bus的match函式(通過名字)判斷drv能否支援dev;
③若可以支援,呼叫probe函式。
但要注意的是,這只不過是一種使左右兩邊建立聯絡的機制,在probe函式中做什麼由你自己決定,或者註冊乙個字元裝置,或者註冊乙個input_dev結構體,都可以。
下面介紹一下具體怎麼實現,先從device開始。
首先要註冊乙個平台裝置
static struct platform_device led_dev = ;
接下來就是對resource的設定
static struct resource led_resource = ,
[1] = ,
};
其中的flag在linux/ioport.h中定義。
當然還要在入口函式裡註冊平台裝置:platform_device_register(&led_dev);
出口函式裡解除安裝平台裝置:platform_device_unregister(&led_dev);
還要用module_init對入口和出口函式進行修飾。
這樣,乙個平台裝置就完成了。
接下來要註冊乙個平台驅動。
首先要定義乙個平台驅動
struct platform_driver led_drv =
};
要注意的是,.name一定要和之前註冊的平台裝置相同,這樣才能通過match函式找到彼此。至於入口函式、出口函式和修飾,與之前的平台裝置基本一致。
接下來就是構造led_probe和led_remove了,先從簡單的做起,在這兩個函式裡我們先不實現點燈的功能,只是列印一些資訊
static
int led_probe(struct platform_device * pdev)
static
int led_remove(struct platform_device * pdev)
這樣,我們就完成了乙個簡單的例子,把平台驅動和平台裝置編譯載入,可以看到列印出「led_probe,found led」,然後解除安裝的時候又列印出「led_remove,remove led」。與預期一致。
接下來加入複雜的**。
在probe函式中,先要根據platform_device的資源進行ioremap,也就是得到之前在平台裝置裡的led_resource,這就要用platform_get_resource(),然後再用ioremap得到具體的暫存器位址以及引腳。具體的**如下:
struct resource *res;
/*根據platform_device的資源進行ioremap*/
res = platform_get_resource(pdev, ioresource_mem, 0);
gpio_con = ioremap(res->start,res->end - res->start +
1);
gpio_dat = gpio_con +
1; res = platform_get_resource(pdev, ioresource_irq, 0);
pin = res->start;
然後還需要在probe函式裡註冊字元裝置驅動,這都是老一套了,跟以前我們學的過程完全一樣(先構造乙個file_operations結構體,然後設定系統自動分配主裝置號……)具體的**如下:
major = register_chrdev(0, "myled", &led_fops);
cls = class_create(this_module, "myled");
class_device_create(cls, null, mkdev(major, 0), null, "myled");
接下來就是remove函式了,過程基本與probe的註冊過程相反:
class_device_destroy(cls,mkdev(major, 0));// /dev/xyz
class_destroy(cls);
unregister_chrdev(major, "myled");
iounmap(gpio_con);
至於在file_operations結構體定義的open和write函式的實現就不具體說明了,跟以前的一模一樣。
由此,我們就完成了平台裝置和平台驅動的構建。至於測試程式,完全使用第乙個驅動程式的測試程式就行。
倘若我們想要修改led,只需要在平台裝置裡對resource進行修改就行了。
6410之驅動程式的分層分離,匯流排裝置驅動模型
什麼是分離分層的概念?如前面的input子系統所述,分離分層概念可以如下圖所示 input.c和buttons.c,evdev.c形成分層的概念,buttons.c和evdev.c形成分離的概念,一邊是硬體相關的 由編寫驅動的人員編寫,一邊是純軟體是由linux核心所提供的。匯流排驅動裝置模型 該模...
匯流排 裝置 驅動模型
裝置元素 匯流排,驅動,裝置 匯流排 處理器和裝置之間的通道,在裝置模型中,所有的裝置都通過匯流排相連,甚至是內部的虛擬 platform 匯流排 定時器,看門狗並沒有直接相連 在linux裝置模型中,匯流排由bus type結構表示,定義在 匯流排的註冊使用 bus register struct...
匯流排裝置驅動模型
匯流排裝置驅動模型 匯流排是主機和裝置之間的通道,由bus type 結構描述。int bus register struct bus type bus 匯流排的註冊,若成功,新的匯流排將被新增進系統,並可在 sysfs 的 sys bus 下看到。void bus unregister struc...