1. 程式人生 > 其它 >Android Sensor Input型別 (三) Sensor Class

Android Sensor Input型別 (三) Sensor Class

Sensors Class驅動

感測器類支援是一般 HAL 支援的一部分。它的主要目的是使sensorsHAL 更加通用,所有與硬體相關的配置都由kermel 提供。為了支援此功能,核心驅動程式需要遵循介面。核心驅動程式應該實現幾個關鍵的回撥。為了統一規範,抽象出了 Sensor class;

Sensors class的邏輯相對簡單,與最簡單led子系統邏輯相似
向用戶空間提供可供訪問的device讀寫裝置節點,
向sensor裝置驅動提供統一的註冊介面,定義了統一的 sensors_classdev 資料結構,規範了sensor裝置驅動的架構。

下面是分析下sensors class驅動主要內容:

註冊class

static int __init sensors_init(void)
{
    sensors_class = class_create(THIS_MODULE, "sensors");  //建立 class
    if (IS_ERR(sensors_class))
        return PTR_ERR(sensors_class);
    sensors_class->dev_attrs = sensors_class_attrs;        //填充 class attrs
    return 0;
}
static void __exit sensors_exit(void)
{
    class_destroy(sensors_class);
}
subsys_initcall(sensors_init);  //比普通driver 更早的init
module_exit(sensors_exit);

主要的內容就是建立 名為sensor的class,並且填充其dev_attrs, 這樣的設定之後,在這個class中建立的每一個device都將具備 dev_attrs中設定的讀寫函式,
也正是因為這點才使得每一個註冊到這個class中的 sensor_classdev才具備統一規範的介面、下面來看下 對dev_attrs的設定。

配置ATTRS

static struct device_attribute sensors_class_attrs[] = {
    __ATTR(name, 0444, sensors_name_show, NULL),
    __ATTR(vendor, 0444, sensors_vendor_show, NULL),
    __ATTR(version, 0444, sensors_version_show, NULL),
    __ATTR(handle, 0444, sensors_handle_show, NULL),
    __ATTR(type, 0444, sensors_type_show, NULL),
    __ATTR(max_range, 0444, sensors_max_range_show, NULL),
    __ATTR(resolution, 0444, sensors_resolution_show, NULL),
    __ATTR(sensor_power, 0444, sensors_power_show, NULL),
    __ATTR(min_delay, 0444, sensors_min_delay_show, NULL),
    __ATTR(fifo_reserved_event_count, 0444, sensors_fifo_event_show, NULL),
    __ATTR(fifo_max_event_count, 0444, sensors_fifo_max_show, NULL),
    __ATTR(max_delay, 0444, sensors_max_delay_show, NULL),
    __ATTR(flags, 0444, sensors_flags_show, NULL),
    __ATTR(enable, 0664, sensors_enable_show, sensors_enable_store),
    __ATTR(enable_wakeup, 0664, sensors_enable_wakeup_show,
            sensors_enable_wakeup_store),
    __ATTR(poll_delay, 0664, sensors_delay_show, sensors_delay_store),
    __ATTR(self_test, 0440, sensors_test_show, NULL),
    __ATTR(max_latency, 0660, sensors_max_latency_show, sensors_max_latency_store),
    __ATTR(flush, 0660, sensors_flush_show, sensors_flush_store),
    __ATTR(calibrate, 0664, sensors_calibrate_show, sensors_calibrate_store),
    __ATTR_NULL,
};

這組檔案節點的建立,實現了使用者使用者空間對sensor 裝置驅動的訪問控制,我們先以mmc3416x為例看下,在檔案系統中生成的實際裝置節點。

msm8909:/sys/class/sensors/mmc3416x-mag # ls
calibrate enable_wakeup             flags  max_delay   min_delay  power      sensor_power uevent
device    fifo_max_event_count      flush  max_latency name       resolution subsystem    vendor
enable    fifo_reserved_event_count handle max_range   poll_delay self_test  type         version

以name,poll_delay 為例 分析這些介面的實現:

static ssize_t sensors_name_show(struct device *dev,
        struct device_attribute *attr, char *buf)
{
    struct sensors_classdev *sensors_cdev = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%s\n", sensors_cdev->name);
//就是直接將 在裝置驅動中填充的sensors_cdev->name 返回
}
static ssize_t sensors_enable_store(struct device *dev,
        struct device_attribute *attr, const char *buf, size_t size)
{
    struct sensors_classdev *sensors_cdev = dev_get_drvdata(dev);
    ssize_t ret = -EINVAL;
    unsigned long data = 0;
    ret = kstrtoul(buf, 10, &data); //把使用者空間傳來的時間換算成unsight long
    if (sensors_cdev->sensors_enable == NULL) 
ret = sensors_cdev->sensors_enable(sensors_cdev, data);
 //回撥sensors_cdev中的 enable 函式
    sensors_cdev->enabled = data;
    return size;
}

Sensor_classdev_register

從上面兩個例子可以看出,實際在class中裝置節點中的操作過程很簡單,就是互動sensors_cdev中填充的 裝置資訊與函式回撥,其中 sensors_cdev的獲取是通過dev_get_drvdata(dev);來獲取的。

這個device就是我們註冊的device,在sensor裝置驅動中有將裝置結構體放到 device的私有資料中,這裡再來獲取。

達到相同的處理函式根據不同的device資訊做不同的處理,那下面就看下針對不同device的sensors_cdev的註冊,這也是sensors class對裝置驅動提供的註冊介面。

int sensors_classdev_register(struct device *parent,
                struct sensors_classdev *sensors_cdev)
{
    sensors_cdev->dev = device_create(sensors_class, parent, 0,
                      sensors_cdev, "%s", sensors_cdev->name);  
//建立一個device
    down_write(&sensors_list_lock);
list_add_tail(&sensors_cdev->node, &sensors_list);
//將當前註冊的sensor新增到sensor list中
    up_write(&sensors_list_lock);
    pr_debug("Registered sensors device: %s\n", sensors_cdev->name);
    return 0;
}
EXPORT_SYMBOL(sensors_classdev_register);

在建立裝置時,parent傳遞一個device,在mmc3416 中是傳遞的 inputdev,當然也可以傳我們的sensor裝置結構, 傳遞sensor_cdev為建立device的私有資料,可以使用dev_get_drvdata(dev) 來獲取出來。

在各個裝置節點中都是根據不同的device 取出註冊時傳入的sensor_cdev結構體。如此即可完成對sensor裝置驅動統一的處理。

簡要圖示框架: