sysfs 檔案系統


    linux 2.6 內核中引入了 sysfs 檔系統,是用戶空間與內核空間進行交互的一個媒介。比起古老的 proc 檔系統,它是基於內核的資料結構,因此組織結構上更加嚴密。它的設計使內核的資訊更易獲取,而且更加清晰。內核空間與用戶空間的映射關係如下表所示:


內核空間(internel)


用戶空間(externel)


內核對象
(kernel objects)


目錄
(directories)


物件屬性
(object attributes)


普通檔
(regular files)


物件關係
(object relationshiops)


符號鏈結
(symbolic links)


 


驅動 


    就溫度感測器來說,驅動程式可以用內核 sysfs 檔系統提供的介面建立對應的溫度感測器的目錄結構。應用程式通過訪問對應目錄下的普通檔,即可獲取相應的溫度感測器屬性值。


 


    可以仿照 linux 2.6 內核提供的 kobject-example.c ( 位於 /samples/kobject/kobject-example.c ) 建立一個溫度感測器的訪問介面。比如可以在驅動中,使用 temperature作為 /sys/kernel/ 目錄下的溫度感測器物件目錄,並在這個目錄下建立一個叫 temp 的檔,即作為溫度感測器的一個屬性,和一個mode檔,提供溫度感測器的工作模式。    根據以上說明,我們的溫度感測器驅動需要在模組初始化中,使用語句


temp_kobj = kobject_create_and_add(“temperature”, kernel_kobj) 


    創建 temperature 目錄,然後利用


sysfs_create_group( temp_kobj,  &attr_group ) 


    創建 temperature 目錄下的屬性檔組( 這裏包含 temp mode 兩個檔 ),其中 attr_group 是我們自己定義的屬性相關檔,通過它,我們描述了 temperature 目錄裏具有的屬性檔,以及各檔的 show  store 函數。對於本例來說,可用一個屬性陣列 attrs 描述這一屬性組 attr_groupattrs 陣列包此處包含兩個元素,分別對應 temp mode 檔。這裏僅就 temp 文件給出說明。temp 檔的 temp_show 提供了應用程式訪問該檔的底層方法,為了類比變化的溫度,應用程式每讀一次 temp 檔,我們就隨機的改變溫度。所以,在 temp_show 方法裏,使用了 linux 提供的 get_random_bytes 函數產生亂數(包含在頭檔 linux/random.h 中)。temp_show 裏根據模式的不同,提供了獲取單時點溫度和平均溫度的兩種方法。


 


 


HAL介面測試


    驅動載入後,我們就可以看到 sysfs 檔系統中多出了 /sys/kernel/temperature/ 這一目錄,且目錄下邊有個檔 temp, 我們可以使用 cat /sys/kernel/temperature/temp 讀取它的值,於是這一檔就為應用程式訪問溫度感測器驅動提供了上層的通用介面。  在測試程式 test_temp.c 裏,通過打開 /sys/kernel/temperature/temp 檔,並每隔一秒讀取一次檔內容( 注:每讀一次應使用 lseek 函數將檔指標移到開頭 )




範例程式



sysfs.c
------------------------------------------------------
#include     //Needed by all modules
#include     //Needed for KERN_ALERT
#include     //gpio_set_value()
#include

#define RED_LED     GPIO_NUM(2, 26)

#define dpm_attr(_name,_prefix)                   \
static struct subsys_attribute _prefix##_attr = { \
        .attr   = {                               \
                .name = __stringify(_name),       \
                .mode = 0644,                     \
        },                                        \
        .show   = _prefix##_show,                 \
        .store = _prefix##_store,                \
}

static ssize_t dpm_control_show(struct subsystem *subsys, char *buf)
{
    ssize_t len = 0;
    printk("<1> in %s()\n", __FUNCTION__);
    return len;
}
static struct timer_list ssl_led_timer;

static void led_timer_handler(unsigned long data)
{
    static int led_status;
    if (led_status == 1) {
        gpio_set_value(RED_LED, 1);
        led_status = 0;
    } else {
        gpio_set_value(RED_LED, 0);
        led_status = 1;
    }
    ssl_led_timer.expires = jiffies + 1 * HZ / 3;
    ssl_led_timer.function = led_timer_handler;
    add_timer(&ssl_led_timer);
}

static ssize_t
dpm_control_store(struct subsystem *subsys, const char *buf, size_t n)
{
    int error = 0;
    if (strncmp(buf, "on", 2) == 0) {
        del_timer(&ssl_led_timer);
        gpio_set_value(RED_LED, 0);
    } else if (strncmp(buf, "off", 3) == 0) {
        del_timer(&ssl_led_timer);
        gpio_set_value(RED_LED, 1);
    } else if (strncmp(buf, "flash", 5) == 0) {
        led_timer_handler(0);
    }

    return error ? error : n;
}

dpm_attr(control, dpm_control);    //create /sys/dpm/control.
                // static struct subsys_attribute _prefix##_attr
                // static struct subsys_attribute dpm_control_attr
                // static ssize_t dpm_control_show()
                // static ssize_t dpm_control_store()

static struct attribute *g[] = {
    &dpm_control_attr.attr,
    NULL,
};

static struct attribute_group dpm_attr_group = {
    .attrs = g,
};

decl_subsys(led, NULL, NULL);    // Declares a subsystem named ' _subsys
                // dpm_subsys is a kset

static int __init hello_init(void)
{
    int ret;
    ret = subsystem_register(&led_subsys);
    if (!ret) {
        ret = sysfs_create_group(&led_subsys.kobj, &dpm_attr_group);
        if (ret)
            printk("<1> sysfs_create_group() err\n");
    }
    ret = gpio_request(RED_LED, "red_led");
    if (ret == -1) {
        return -1;
    }
    gpio_direction_output(RED_LED, 0);
    init_timer(&ssl_led_timer);
    return 0;
}

static void __exit hello_exit(void)
{
    subsystem_unregister(&led_subsys);
    gpio_free(RED_LED);
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("zengxiaolong");
MODULE_DESCRIPTION("A sample driver");
MODULE_SUPPORTED_DEVICE("testdevice");



Makefile
------------------------------------------------------
KERNEL_LOCATION := /home/zengxiaolong/soft/ssl/cm5210a-patch-0912/src/BSP/Kernel/linux-2.6.24-ssl
obj-m += sysfs.o

all:
        make -C $(KERNEL_LOCATION) M=`pwd` modules
clean:
        make -C $(KERNEL_LOCATION) M=`pwd` clean



測試
------------------------------------------------------
/sys # echo flash > /sys/led/control




原文網址


 http://www.emsym.com/blog/?p=1036


http://hi.baidu.com/zengzhaonong/blog/item/cc517dd97f31e92a10df9b0e.html

    全站熱搜

    立你斯 發表在 痞客邦 留言(0) 人氣()