如果在核心配置的時候有開啟config_gpio_sysfs標誌,核心就會在/sys目錄下匯出gpio的使用者空間操作介面。gpiolib_sysfs_init(drivers/gpio/gpiolib.c)是gpio lib的初始化函式,該函式首先在/sys/class/目錄下面建立乙個gpio的class,然後把所有註冊到gpio lib的控制器匯出到/sys/class/gpio/目錄下面。
static int __init gpiolib_sysfs_init(void)
......
}gpio_class的name定義為gpio,所以我們可以在/sys/class/下面看到gpio的目錄。class_attr被定義為gpio_class_attrs,裡面定義了class的兩個屬性export和unexport,該屬性最終會在使用者空間生成對應的檔案。class_attribute包含乙個attribute變數和show/sotre兩個方法,其中attribute用來標示該屬性的名字和操作許可權,show/store是對該屬性進行操作的函式,對應使用者空間的cat/echo操作。所以在/sys/class/gpio目錄下面可以看到兩個檔案分別為export和unexport,同時可以看到這兩個檔案的屬性為所有者可寫,即對應建立時定義的0200。所以這兩個檔案只能用echo向檔案寫內容,而不能通過cat顯示檔案的內容。從export和unexport的定義也可以驗證這點,它們的show都定義為null,shore分別定義export_store和unexport_store,由此可以得知這兩個函式就是使用者空間操作的最終執行函式。先跳過這兩個函式,繼續看gpiolib_sysfs_init的第二部分工作。
static struct class_attribute gpio_class_attrs = ;
#define __attr(_name,_mode,_show,_store) ,\
.show= _show,
.store= _store, }
第二部分的工作就是遍歷每乙個註冊的gpio pin,然後把註冊到gpio lib的gpio控制器匯出到使用者空間。首先在建立乙個名為gpiochip*的裝置,所以可以在/sys/class/gpio目錄下面看到對應的gpiochip*目錄,以及該目錄下面的subsystem和uevent兩個屬性檔案。然後再在該目錄下面建立定義的屬性檔案,從屬性陣列gpiochip_attrs可以看到總共定義了三個屬性,分別為base,label和ngpio,屬性的許可權為所有使用者可讀。最後把該控制器的exported標誌設定為1,表示已經匯出到使用者空間。
static int gpiochip_export(struct gpio_chip *chip)
回到第一部分來看export_store函式,該函式同樣分成gpio_request()和gpio_export()兩個階段。在gpio_request中,首先判斷該pin的有效性,即該pin的pin num不能超過最大的gpio pin腳數,然後把flag_requested標記設為1,表示該pin已被申請使用,同時把label屬性設定為sysfs,最後呼叫gpio chip註冊時定義的request函式,由前面的硬體驅動分析可知,該函式直接返回乙個0值。gpio_export()的執行過程和gpiochip_export比較類似,先建立乙個gpio*的裝置,該過程會在使用者空間的/sys/class/gpio目錄下面匯出gpio*的目錄和該目錄下面的subsytem/uevent屬性檔案。
int gpio_export(unsigned gpio, bool direction_may_change)
在/sys/class/gpio/目錄下面匯出gpio*目錄後,再在該目錄下生成各種屬性檔案。首先建立的是gpio_attr_group屬性組,該組裡面包含value和active_low兩個屬性,這兩個屬性用device_attr來定義,從定義可以看出,屬性檔案的許可權是0644,即所有者可讀可寫可執行,使用者組和其他使用者是可讀。在使用者空間可以通過value檢視和設定gpio pin的值,通過active_low來檢視和設定pin的active_low的標誌位。如果註冊的gpio chip有定義gpio方向操作的函式,則建立direction屬性,該屬性同樣是用device_attr巨集來建立,屬性的許可權也為0644,使用者可以利用/sys/class/gpio/gpio*/direction檔案來控制gpio pin的操作方向。如果要匯出的pin可以作中斷使用,同時該pin沒有設定flag_is_out位,則用建立edge屬性;當該pin作為中斷pin使用時,使用者可以利用/sys/class/gpio/gpio*/edge檔案設定中斷觸發的方式。
static const device_attr(active_low, 0644,gpio_active_low_show, gpio_active_low_store);
static const device_attr(value, 0644,gpio_value_show, gpio_value_store);
static /* const */ device_attr(direction, 0644,gpio_direction_show, gpio_direction_store);
static device_attr(edge, 0644, gpio_edge_show, gpio_edge_store);
以value屬性來分析屬性檔案的具體操作,當使用者在使用者空間用cat開啟value檔案檢視gpio pin的值時,gpio_value_show()會被呼叫。該函式的主要呼叫路徑為 gpio_get_value_cansleep()->gpio_to_chip()->chip->get,即通過gpio pin找到該pin對應的gpio chip,然後利用該chip的get函式從gpio控制器的暫存器裡面讀到具體的值。
當使用者在使用者空間用ehco把值寫到value檔案時,gpio_value_store會被呼叫,該函式的作用跟gpio_value_show相反,是把使用者空間傳遞過來的值寫到gpio控制器的暫存器。呼叫路徑為gpio_set_value_cansleep()->gpio_to_chip()->chip->set。
linux gpio驅動示例
include include include include include include include include include include define jt gpio magic k define jt gpio read io jt gpio magic,1 define j...
Linux GPIO驅動 驅動框架概述
gpio是嵌入式開發中最常見的介面,之前自己就有寫過小的gpio驅動,提供ioctl介面給使用者空間操作。但直到最近才發現linux自身就有完善的gpio驅動框架,並且通過sysfs向使用者空間提供操作介面。linux的gpio驅動框架層次及資料結構如下 最上層是用來向向使用者空間提供介面,使用者可...
linux gpio字元裝置驅動
在linux下編寫led驅動,控制相應的gpio管腳。在這裡有兩種方式 1 直接操作相應的暫存器 2 通過核心提供的gpio操作庫函式 第一種方式就省略了,只講第二種方式。這裡板卡上有兩個led燈,在使用者空間採用兩種方式控制led 1.dev led0 dev led1 fd0 open dev ...