97干视频,99国产精品懂色,亚洲精品99久久久久中文字幕,伊人五月丁香综合AⅤ,国产精品成人免费999

當前位置: 首頁 > 安卓培訓 > Android開發(fā) > Android-sensor驅(qū)動和硬件抽象層
Android-sensor驅(qū)動和硬件抽象層 時間:2018-08-16     來源:未知

1. bma250硬件原理

從全志A33的原理圖中,我們可以看到關(guān)于平板上使用的sensor傳感是使用的是bma250。BMA250是一種先進超小,三軸,低g加速度傳感器和數(shù)字接口,針對低功耗電子消費品的應用程序。這個BMA250允許測量加速度在3個互相垂直的軸,因此感官傾斜,運動,沖擊和振動在手機,手機,計算機外設(shè),人機界面,虛擬現(xiàn)實的特性和游戲控制器。我們可以看到這個芯片使用的i2c總線來操作從機設(shè)備,從機的地址為0x18。具體的設(shè)備信息請參看bma250.pdf文檔。

2. Android中bma250驅(qū)動的分析

我們接下來看bma250驅(qū)動,我們通過它的驅(qū)動文件,查看這個功能的實現(xiàn)。參考的文件如下:/home/linux/fspad-733/lichee/linux-3.4/drivers/hwmon/bma250.c

static int __init BMA250_init(void)

{

    int ret = -1;  

    if (input_fetch_sysconfig_para(&(gsensor_info.input_type))) {

        printk("%s: err.\n", __func__);                                                                                     

        return -1;

    } else

        twi_id = gsensor_info.twi_id;

    ret = i2c_add_driver(&bma250_driver);

    return ret;

}

static void __exit BMA250_exit(void)

{

    i2c_del_driver(&bma250_driver);

}

module_init(BMA250_init);

module_exit(BMA250_exit);

MODULE_LICENSE("GPL");

input_fetch_sysconfig_paraz這個函數(shù)是由來解析sys_config.fex這個配置文件的,你會發(fā)現(xiàn)全志很多配置信息沒有在平臺代碼中填寫,而是自己實現(xiàn)了配置文件。這個配置文件存放的路徑為fspad-733/lichee$ vi ./tools/pack/out/sys_config.fex。它獲取的時候是根據(jù)主鍵值和子鍵值來獲取的。

[gsensor_para]

gsensor_used        = 1

gsensor_twi_id      = 1

gsensor_twi_addr    = 0x18

;gsensor_int1        = port:PB06<4><1><default><default>

[gsensor_list_para]

bma250                    = 1

從這個配置文件中我們可以看到,這里包含從機的地址,i2c的sda和scl的端口地址。bma250=1,表示此傳感器是可以使用的。gsensor_twi_id = 1表示的是使用的i2c-1這個總線控制器。

當設(shè)備信息通過i2c總線匹配成功之后會執(zhí)行probe函數(shù),我們可以看到這里有

.class = I2C_CLASS_HWMON,

.detect     = gsensor_detect,

.address_list   = normal_i2c,

I2c總線也可以通過下面的方式匹配成功,重要的就是type,address這兩個成員,這種匹配方式前面已經(jīng)分析過了,這里就不在贅述了。當匹配成功之后會執(zhí)行probe函數(shù)。

.probe      = bma250_probe,

1.定義結(jié)構(gòu)體

struct bma250_data {

     struct i2c_client *bma250_client;

     unsigned char mode;

     struct input_dev *input;

     struct bma250acc value;

     struct delayed_work work;

     struct work_struct irq_work;

     unsigned char range_state;

     unsigned char bandwidth_state;

 };

2.為結(jié)構(gòu)體分配空間

  data = kzalloc(sizeof(struct bma250_data), GFP_KERNEL);

3.結(jié)構(gòu)體成員的初始化

data->bma250_client = client;                  //將client成員賦值給data

bma250_set_bandwidth(client, BMA250_BW_SET);

設(shè)置帶寬bma250帶寬BMA250_BW_SET=4,通過驅(qū)動我們知道這里設(shè)置的是125hz,也就是說數(shù)據(jù)會4ms更新一次。

bma250_set_range(client, BMA250_RANGE_SET);

這里是設(shè)置加速度傳感器的量程范圍BMA250_RANGE_SET = 0

INIT_DELAYED_WORK(&data->work, bma250_work_func);

在data結(jié)構(gòu)體中存在一個delayed_work,這個結(jié)構(gòu)體中存在一個工作隊列和一個定時器,代碼展開情況如下,其中bma250_work_func是中斷低半部處理函數(shù)。

struct delayed_work {

    struct work_struct work;

    struct timer_list timer;                                                                                                 

};

struct work_struct {                                                                                                         

    atomic_long_t data;

    struct list_head entry;

    work_func_t func;

};

INIT_DELAYED_WORK(&data->work, bma250_work_func); 

#define INIT_DELAYED_WORK(_work, _func)             \                                                                        

    do {                            \

        INIT_WORK(&(_work)->work, (_func));     \

        init_timer(&(_work)->timer);            \

    } while (0)

#define INIT_WORK(_work, _func)                 \                                                                            

    do {                            \

        __INIT_WORK((_work), (_func), 0);       \

    } while (0)

#define init_timer(timer)\                                                                                                   

    init_timer_key((timer), NULL, NULL)

err = bma250_input_init(data);  //初始化input

struct input_dev *dev;

dev = input_allocate_device();

input_set_capability(dev, EV_ABS, ABS_MISC);

input_set_abs_params(dev, ABS_X, ABSMIN_2G, ABSMAX_2G, 0, 0);

input_set_abs_params(dev, ABS_Y, ABSMIN_2G, ABSMAX_2G, 0, 0);                                                           

input_set_abs_params(dev, ABS_Z, ABSMIN_2G, ABSMAX_2G, 0, 0);

input_set_drvdata(dev, bma250);

err = input_register_device(dev);

err = sysfs_create_group(&data->input->dev.kobj,&bma250_attribute_group);   

在驅(qū)動層創(chuàng)建了sysfs接口,HAL層通過這些sysfs接口,對Sensor進行操作,如使能、設(shè)置delay等

static struct attribute_group bma250_attribute_group = {                                                                    

    .attrs = bma250_attributes

};

static struct attribute *bma250_attributes[] = {                                                                            

    &dev_attr_range.attr,

    &dev_attr_bandwidth.attr,

    &dev_attr_mode.attr,

    &dev_attr_value.attr,

    &dev_attr_delay.attr,

    &dev_attr_enable.attr,

    NULL

};

static DEVICE_ATTR(range, S_IRUGO|S_IWUSR|S_IWGRP,

        bma250_range_show, bma250_range_store);

static DEVICE_ATTR(bandwidth, S_IRUGO|S_IWUSR|S_IWGRP,

        bma250_bandwidth_show, bma250_bandwidth_store);

static DEVICE_ATTR(mode, S_IRUGO|S_IWUSR|S_IWGRP,

        bma250_mode_show, bma250_mode_store);

static DEVICE_ATTR(value, S_IRUGO,

        bma250_value_show, NULL);

static DEVICE_ATTR(delay, S_IRUGO|S_IWUSR|S_IWGRP,

        bma250_delay_show, bma250_delay_store);

static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR|S_IWGRP,

        bma250_enable_show, bma250_enable_store);

這里一共會創(chuàng)建range,bandwidth,mode,value,delay,enable這些設(shè)備文件。range,bandwidth這兩個屬性文件我們就暫時不分析那么詳細了,前面我們已經(jīng)分析過了,這里主要是對量程范圍和帶框進行設(shè)置的,接下來還有一個mode的屬性文件,我們在平板的root@fspad-733:/sys/class/input/input4 #目錄下使用cat mode命令可以查看到這個設(shè)備文件的默認值為2

#define BMA250_MODE_NORMAL     0

#define BMA250_MODE_LOWPOWER   1

#define BMA250_MODE_SUSPEND     2

從它的定義處我們可以看出這是設(shè)置工作模型的,它有三種模式,正常,低電壓,掛起等這幾種工作模式。Value這個設(shè)備文件就是用來存放讀取到的當前的加速度計的當前的值的。我們使用cat命令查看。

root@fspad-733:/sys/class/input/input4 # cat value

4  12  -268

上面的數(shù)字對應的就是讀取到的x,y,z軸的數(shù)據(jù)。

Delay的設(shè)備文件就是用來設(shè)置當前的延時時間的,enable是用來設(shè)置當前bma250是否處在工作狀態(tài)。接下來我們需要重點分析value,delay,enable這三個設(shè)備文件對應的show和store方法。

2.1enable 設(shè)備文件分析

static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR|S_IWGRP,

        bma250_enable_show, bma250_enable_store);

通過前面我們所學的sysfs文件系統(tǒng)的知識我們知道,DEVICE_ATTR的后兩個參數(shù)分別為show和store方法。即對應的是bma250_enable_show和bma250_enable_store。

bma250_enable_show

struct bma250_data *bma250 = i2c_get_clientdata(client);   

return sprintf(buf, "%d\n", atomic_read(&bma250->enable));

從上述的代碼我們可以清晰的知道,這里的show方法其實就是打印bma250結(jié)構(gòu)體中的enable的原子變量的數(shù)據(jù),這里只可能是0或1。

bma250_enable_store

error = strict_strtoul(buf, 10, &data);  //將字符串轉(zhuǎn)化為整形數(shù)據(jù)

bma250_set_enable(dev,data);

if(pre_enable ==0){

bma250_set_mode(bma250->bma250_client,BMA250_MODE_NORMAL);        schedule_delayed_work(&bma250->work,

msecs_to_jiffies(atomic_read(&bma250->delay)));

         atomic_set(&bma250->enable, 1);

}

上面函數(shù)的功能是設(shè)置bma250的工作模式為正常模式,接著會使用schedule_delayed_work來調(diào)度中斷下半部,但是這里和我們之前使用的schedule_work函數(shù)有所區(qū)別,區(qū)別在于這里會延時一段時間在執(zhí)行調(diào)度函數(shù)。這里的延時時間在bma250結(jié)構(gòu)體的delay變量中保存著。這個delay的值猜想應該是在delay這個設(shè)備文件中獲取的。接著將atomic的enable設(shè)置為1。接下來我們看中斷低半部函數(shù)。

bma250_work_func

static void bma250_work_func(struct work_struct *work)

{

    struct bma250_data *bma250 = container_of((struct delayed_work *)work,

            struct bma250_data, work);

    static struct bma250acc acc;

    unsigned long delay = msecs_to_jiffies(atomic_read(&bma250->delay));

    bma250_read_accel_xyz(bma250->bma250_client, &acc); //通過i2c去取數(shù)據(jù)

    input_report_abs(bma250->input, ABS_X, acc.x);  //上報x軸的數(shù)據(jù)

    input_report_abs(bma250->input, ABS_Y, acc.y);  //上報y軸的數(shù)據(jù)

    input_report_abs(bma250->input, ABS_Z, acc.z);  //上報z軸的數(shù)據(jù)

    input_sync(bma250->input);                  //發(fā)送同步信號

    bma250->value = acc;                     //將bma250中的value值更新

    schedule_delayed_work(&bma250->work, delay); //延時調(diào)度本函數(shù)

}

上述的函數(shù)寫的很精髓,通過在中斷低半部使用schedule_delayed_work來調(diào)度中斷低半部,這樣就形成了循環(huán)從驅(qū)動中讀取數(shù)據(jù)。本次調(diào)度之間都有一個延時。去報驅(qū)動已經(jīng)將數(shù)據(jù)更新。接下來我們看下這個延時是怎么設(shè)置進來的。

static DEVICE_ATTR(delay, S_IRUGO|S_IWUSR|S_IWGRP,

         bma250_delay_show, bma250_delay_store);

從前面的分析我們知道,工作隊列在調(diào)度時有一個延時,那么這個延時的時間怎么設(shè)置?它不可能是一個固定的值,它應該也為用戶提供了操作接口,在我們的這個文件中就是通過delay這個設(shè)備文件的方式。這個文件同樣對應連個方法,分別是show和store。

bma250_delay_show

return sprintf(buf, "%d\n", atomic_read(&bma250->delay));

這個函數(shù)十分的簡單,就是向buf換中區(qū)中寫入bma250結(jié)構(gòu)體的delay的值。通過測試。

root@fspad-733:/sys/class/input/input4 # cat delay

66

這里我們可以看到它是66毫秒。接下來分析store方法。

bma250_delay_store

error = strict_strtoul(buf, 10, &data);

if (data > BMA250_MAX_DELAY)  //#define BMA250_MAX_DELAY  200                                                                                           

data = BMA250_MAX_DELAY;  //限制延時的大值為200ms

atomic_set(&bma250->delay, (unsigned int) data);

將用戶寫的延時值設(shè)置進去。在驅(qū)動初始化的時候,我們可以看到這里并不是66而是200,那么它在什么時候進行初始化的那?很顯然應該是硬件抽象層調(diào)用的。這個暫時不用理會。

static DEVICE_ATTR(value, S_IRUGO,bma250_value_show, NULL);   

bma250_value_show

return sprintf(buf, "%d %d %d\n", acc_value.x, acc_value.y,acc_value.z);

這里很顯然就是將工作隊列中更新的值給打印出來。至此整個驅(qū)動我們就分析完成了。

3. bma250驅(qū)動的加載過程

3.1sys_config.fex文件的解析過程

在講解bma250驅(qū)動加載之前,我們需要在來講解一些知識。我們知道在bma250驅(qū)動的入口函數(shù)中input_fetch_sysconfig_para(&(gsensor_info.input_type),有這樣一句話,它的作用是解析sys_config.fex文件中的配置信息。

input_fetch_sysconfig_para(&(gsensor_info.input_type)

static struct sensor_config_info gsensor_info = {                                                                           

.input_type = GSENSOR_TYPE,

};

struct sensor_config_info{                                                                                                   

enum input_sensor_type input_type;    //gsensor類型   1

int sensor_used;                      //設(shè)備是否可使用

__u32 twi_id;

u32 int_number;

struct gpio_config irq_gpio;

char* ldo;

struct device *dev;

struct pinctrl *pinctrl;

};

ret = (*fetch_sysconfig_para[*input_type])(input_type);

這里定義的是函數(shù)指針數(shù)組,上面?zhèn)鬟f過來的*input_type = 1,其中input_type又是

sensor_config_info結(jié)構(gòu)體的首地址

static int (* const fetch_sysconfig_para[])(enum input_sensor_type *input_type) = {

ctp_fetch_sysconfig_para,

gsensor_fetch_sysconfig_para,

gyr_fetch_sysconfig_para,

e_compass_fetch_sysconfig_para,

ls_fetch_sysconfig_para,

ir_fetch_sysconfig_para,

ths_fetch_sysconfig_para,                                                                                               

motor_fetch_sysconfig_para,

bat_fetch_sysconfig_para

};

所以接下來應該調(diào)用gsensor_fetch_sysconfig_para函數(shù),并將結(jié)構(gòu)體的首地址當參數(shù)傳遞過去。

static int gsensor_fetch_sysconfig_para(enum input_sensor_type *gsensor_type)

{

struct sensor_config_info *data = 

container_of(gsensor_type,struct sensor_config_info, input_type); 

//獲取sensor_config_info結(jié)構(gòu)體

type = script_get_item("gsensor_para", "gsensor_used", &val);

data->sensor_used = val.val;    

if (1 == data->sensor_used) {      

//如果sensor可使用就解析設(shè)備的數(shù)據(jù)

type = script_get_item("gsensor_para", "gsensor_twi_id", &val);

}

data->twi_id = val.val;

}

; G sensor configuration

; gs_twi_id ---  TWI ID for controlling Gsensor (0: TWI0, 1: TWI1, 2: TWI2)

[gsensor_para]

gsensor_used        = 1                                                                                                     

gsensor_twi_id      = 1

gsensor_twi_addr    = 0x18

;gsensor_int1        = port:PB06<4><1><default><default>

script_get_item函數(shù)根據(jù)主鍵值和子鍵值進行獲取,具體的解析過程看如下目錄的文件即可。fspad-733/lichee/linux-3.4/arch/arm/mach-sunxi/sys_config.c  這整個過程的作用很明顯就是去讀sys_config.fex文件,然后決定當前bma250驅(qū)動是否能正常執(zhí)行。

3.2自動檢測函數(shù)的執(zhí)行過程

在如下目錄中fspad-733/lichee/linux-3.4/drivers/input/ 有sw-device.c的文件,這個文件的功能是自動檢測i2c設(shè)備,如果檢測到有i2c設(shè)備可以使用,則將可用的設(shè)備寫入device.info文件中。接下來我們分析一下這個文件。

從驅(qū)動入口函數(shù)開始看起

static struct device sw_device_detect = {

        .init_name = "sw_device",

        .release = sw_device_release,

};  

static int __init sw_device_init(void)

{

    sw_device_detect.groups = dev_attr_groups;   //創(chuàng)建兩個屬性文件                                                                           

    err = device_register(&sw_device_detect);    //設(shè)備文件的注冊過程

}

static void __exit sw_device_exit(void)

{

    printk(" sw device driver exit!\n");

    device_unregister(&sw_device_detect);   

}

static DEVICE_ATTR(gsensor, S_IRUGO|S_IWUSR|S_IWGRP, sw_device_gsensor_show, sw_device_gsensor_store);

static DEVICE_ATTR(ctp, S_IRUGO|S_IWUSR|S_IWGRP, sw_device_ctp_show, sw_device_ctp_store);

在入口和出口函數(shù)中,我們可以看到設(shè)備文件的創(chuàng)建,上述

創(chuàng)建的gsensor和ctp(觸摸屏)這兩個屬性文件,但是他們的store

方法都沒有實現(xiàn),只實現(xiàn)了show方法,顯示的是設(shè)備名字和i2c

的從機地址。

root@fspad-733:/sys/devices/sw_device # cat gsensor

device name:bma250

device addr:0x19

在這個文件中我們還看到有uevent函數(shù)的實現(xiàn),這個函數(shù)在什么時候會執(zhí)行那?

當使用insmod sw-device.ko時這個event函數(shù)就會被回調(diào)。接下來我們重點分析

回調(diào)函數(shù)的執(zhí)行過程

static void sw_devices_events(struct work_struct *work)

{

int ret = -1;

int device_number = 0;                                                                                              

get_power_para(&c_power);

sw_devices_set_power(&c_power);

if(ctp_mask != 1) {

device_number = (sizeof(gsensors)) / (sizeof(gsensors[0]));

       ret = sw_register_device_detect(gsensors, &g_name, device_number);

if(ret < 0)

printk("gsensor detect fail!\n");

}

...

}

在這個函數(shù)中調(diào)用很多次sw_register_device_detect函數(shù),這里我們就依gsensor來分析。

首先看一下它的參數(shù)gsensor是結(jié)構(gòu)體數(shù)組(如下),g_name是一個結(jié)構(gòu)體首地址(成員是不是很熟悉),

device_number是gsensor數(shù)組成員的個數(shù)。

static struct sw_device_info gsensors[] = {                                                                                 

        {   "lsm9ds0_acc_mag", 0, {0x1e, 0x1d }, 0x0f, {0x49 }, 0},

        {    "bma250", 0, {0x18, 0x19, 0x08, 0x38}, 0x00, {0x02,0x03,0xf9,0xf8}, 0},

        {   "stk831x", 0, {0x3d, 0x22 }, 0x00, {0x00 }, 1},

        {   "mma8452", 0, {0x1c, 0x1d }, 0x0d, {0x2A}, 0},

        {   "mma7660", 0, {0x4c }, 0x00, {0x00 }, 0},

...

};

static struct para_name g_name = {                                                                                          

"gsensor_para",

"gsensor_used",

"gsensor_list_para",

"gsensor_det_used",

"gsensor_twi_id",

GSENSOR_DEVICE_KEY_NAME,

};

sw_register_device_detect(gsensors, &g_name, device_number);

 struct sw_device *sw;                   //定義sw_device結(jié)構(gòu)體

 sw = kzalloc(sizeof(*sw), GFP_KERNEL);  //結(jié)構(gòu)體初始化

 sw->temp_client = client;               //地址賦值 

 sw->info = info;

 sw->name = name;

 sw->support_number = number;                                                                                            

 sw->total_raw = DEFAULT_TOTAL_ROW;

#define NOTE_INFO1  ";Behind the equals sign said detected equipment

corresponding to the name of the driver\n"

#define NOTE_INFO2 ";Note: don't change the file format!\n"

#define GSENSOR_DEVICE_KEY_NAME "gsensor_module_name"                                                                        

#define CTP_DEVICE_KEY_NAME     "ctp_module_name"

#define LSENSOR_DEVICE_KEY_NAME "light sensor_module_name"

#define GYR_SENSOR_DEVICE_KEY_NAME "gyr sensor_module_name"

strcpy(sw->write_info[0].str_info, NOTE_INFO1);

strcpy(sw->write_info[1].str_info, NOTE_INFO2);

sprintf(sw->write_info[2].str_info, "%s=\"\"\n", GSENSOR_DEVICE_KEY_NAME);

sprintf(sw->write_info[3].str_info, "%s=\"\"\n", CTP_DEVICE_KEY_NAME);

sprintf(sw->write_info[4].str_info, "%s=\"\"\n", LSENSOR_DEVICE_KEY_NAME);

sprintf(sw->write_info[5].str_info, "%s=\"\"\n", GYR_SENSOR_DEVICE_KEY_NAME);

sprintf(sw->write_info[6].str_info, "%s=\"\"\n", COMPASS_SENSOR_DEVICE_KEY_NAME);

將字符串的信息寫入緩沖區(qū)中,接著開始調(diào)用sw_device_detect_start函數(shù)。

sw_device_detect_start(sw);

/*step1: Get sysconfig.fex profile information*/

sw_sysconfig_get_para(sw)

/*step 2:Read the device.info file information ,get device name!*/

sw_get_write_info(tmp, sw)

/*step 3: The i2c address detection equipment, find the device used at present.*/

sw_i2c_test(sw);

sw_device_response_test(sw, now_number);

adap = i2c_get_adapter(sw->twi_id);   //獲取adapter

ret = i2c_test(sw->temp_client);

ret = i2c_write_bytes(client, test_data, 1);   //Test i2c.

向當前的i2c設(shè)備中,寫入一個字節(jié),檢測當前的i2c設(shè)備是否可使用

sw_chip_id_detect(sw, now_number)

檢測從設(shè)備中讀取到的id信息是否和表中的相匹配。

/*step 4:Update the device.info file information*/

sw_set_write_info(sw);

如果前面的設(shè)備都匹配成功了,這里就會將匹配成功的信息寫入到device.info中。在平板運行的時候我們可以找到它在sensors_cache/device.info目錄下,我們可以看到它的信息如下:

;Behind the equals sign said detected equipment corresponding to

           the name of the driver

;Note: don't change the file format!

gsensor_module_name="bma250"

ctp_module_name="gslX680new"

light sensor_module_name=""

gyr sensor_module_name=""

compass sensor_module_name=""

3.3device.info中的驅(qū)動加載過程

從上述的文件中,我們可以看到檢測成功的有bma250驅(qū)動,還有g(shù)slX680new驅(qū)動,這兩個驅(qū)動在編譯的時候我們可以通過make menuconfig ARCH=arm看到

Device Drivers  --->

<*> Hardware Monitoring support  --->  

<M>   BMA250 acceleration sensor support

它被編譯成了模塊側(cè)形式,那么這個驅(qū)動什么時候被加載的那?很多同學第一時間會想到應該是在fspad-733/androidL/device/softwinner/fspad-733/ init.sun8i.rc文件中,但是你在這個文件中怎么搜索都搜索不到。難道驅(qū)動會自動加載?這種情況是不可能的;叵肭懊娴倪^程這些驅(qū)動是在device.info中寫的,如果說想加載這個驅(qū)動的話,首先一定會打開sensors_cache/device.info這個文件,基于這種思想,你可以使用grep “sensors_cache/device.info” * -nR。終你會找到fspad-733/androidL/device/softwinner/common/hardware/libhardware/libsensors/aw_sensors/insmodDevice.cpp這個文件。

struct sensors_module_t HAL_MODULE_INFO_SYM 

methods: &sensors_module_methods,

        open: open_sensors

insmodDevice();

get_cfg()

fp = fopen(I2C_DEVICE_CONFIG_PATH,"rb") 

#define I2C_DEVICE_CONFIG_PATH     ("sensors_cache/device.info")  

fgets(buf, LINE_LENGTH , fp)

insmod_modules(buf)

module_name = get_module_name(buf);//獲取到的驅(qū)動為bma250

#define INSMOD_PATH      ("system/vendor/modules/")  

char ko[] = ".ko";

sprintf(insmod_name,"%s%s%s",INSMOD_PATH,module_name,ko);

終insmod_name = system/vendor/modules/bma250.ko

insmod(insmod_name, "")

至此,驅(qū)動就能夠成功加載了。

4.sensor的硬件抽象層的代碼分析

sensor的hal層涉及到的結(jié)構(gòu)體

對任意一個sensor設(shè)備都會有一個sensor_t結(jié)構(gòu)體,其定義如下:

struct sensor_t {

   constchar*    name;      //傳感器名字

   constchar*    vendor;

   int            version;    //版本

   int            handle;    //傳感器的handle句柄

   int            type;      //傳感器類型

   float          maxRange;  //大范圍

   float          resolution;   //解析度

   float          power;      //消耗能源

   int32_t        minDelay;   //事件間隔小時間

   void*          reserved[8];  //保留字段,必須為0

};

每個傳感器的數(shù)據(jù)由sensors_event_t結(jié)構(gòu)體表示,定義如下:

typedef structsensors_event_t {

   int32_t version;

   int32_tsensor;           //標識符

   int32_ttype;            //傳感器類型

   int32_t reserved0;

   int64_ttimestamp;       //時間戳

   union {

       float          data[16];

       sensors_vec_t  acceleration;  //加速度

       sensors_vec_t  magnetic;     //磁矢量

       sensors_vec_t  orientation;    //方向

       sensors_vec_t  gyro;         //陀螺儀

       float          temperature;    //溫度

       float          distance;       //距離

       float          light;          //光照

       float          pressure;        //壓力

       float          relative_humidity; //相對濕度

   };

   uint32_t       reserved1[4];

}sensors_event_t;

其中,sensor為傳感器的標志符,而不同的傳感器則采用union方式來表示,sensors_vec_t結(jié)構(gòu)體用來表示不同傳感器的數(shù)據(jù), sensors_vec_t 定義如下:

typedef struct {

   union {

       float v[3];

       struct {

           float x;

           float y;

           float z;

       };

       struct {

           float azimuth;

           float pitch;

           float roll;

       };

   };

   int8_t status;

   uint8_t reserved[3];

} sensors_vec_t;

 Sensor設(shè)備結(jié)構(gòu)體sensors_poll_device_t,對標準硬件設(shè)備hw_device_t結(jié)構(gòu)體的擴展,主要完成讀取底層數(shù)據(jù),并將數(shù)據(jù)存儲在struct sensors_poll_device_t結(jié)構(gòu)體中,poll函數(shù)用來獲取底層數(shù)據(jù),調(diào)用時將被阻塞定義如下:

struct sensors_poll_device_t {

struct hw_device_t common;

//Activate/deactivate one sensor

   int(*activate)(struct sensors_poll_device_t *dev,

           int handle, int enabled);

   //Set the delay between sensor events in nanoseconds for a givensensor.

   int(*setDelay)(struct sensors_poll_device_t *dev,

           int handle, int64_t ns);

   //獲取數(shù)據(jù)

   int(*poll)(struct sensors_poll_device_t *dev,

           sensors_event_t* data, int count);

};

Gsensor的硬件抽象層的代碼在fspad-733/androidL/device/softwinner/common/hardware/libhardware/libsensors/aw_sensors目錄下,對應的文件是sensors.cpp和sensors.h。硬件抽象層代碼在編寫的時候首先要定義hw_module_t的結(jié)構(gòu)體,但是在這個文件中我們沒有發(fā)現(xiàn)這個結(jié)構(gòu)體取而代之的是sensors_module_t結(jié)構(gòu)體,它把hw_module_t放在首元素的位置。

//#define SENSORS_HARDWARE_MODULE_ID "sensors"

struct sensors_module_t HAL_MODULE_INFO_SYM = {

common: {

id: SENSORS_HARDWARE_MODULE_ID,  

methods: &sensors_module_methods,

        },

get_sensors_list: sensors__get_sensors_list,

};

struct sensors_module_t {

    struct hw_module_t common;

    int (*get_sensors_list)(struct sensors_module_t* module,

            struct sensor_t const** list);

};

上述對sensors_module_t中不必要的成員進程了剔除,可能有些同學看著很別扭,賦值不是使用=嗎?為什么這里使用的是:。這是c++里面的規(guī)則。效果是相同的。接下來我們分析sensor中的操作方法。

static struct hw_module_methods_t sensors_module_methods = {                                                                 

open: open_sensors

};

static int open_sensors(const struct hw_module_t* module, const char* id, 

                        struct hw_device_t** device)

{                                                                                                                                

int status = -EINVAL;

insmodDevice();   //安裝bma250驅(qū)動

property_set("sys.sensors", "1");//設(shè)置屬性

sensorsDetect();  //sensor的自檢測

sensors_poll_context_t *dev = new sensors_poll_context_t(); //定義結(jié)構(gòu)體

memset(&dev->device, 0, sizeof(sensors_poll_device_t));

dev->device.common.tag = HARDWARE_DEVICE_TAG;

dev->device.common.version  = 0;

dev->device.common.module   = const_cast<hw_module_t*>(module);

dev->device.common.close    = poll__close; 

dev->device.activate        = poll__activate;

dev->device.setDelay        = poll__setDelay;

dev->device.poll            = poll__poll;  //填充操作方法

*device = &dev->device.common;  //將結(jié)構(gòu)體返回給上層

return 0;

}

驅(qū)動的安裝過程前面我們已經(jīng)分析過了,終會調(diào)用insmod函數(shù)。屬性的設(shè)置暫時不去理會,我們來分析一下驅(qū)動的自檢測過程。

sensorsDetect();

char *dirname =(char *) "/sys/class/input";

dir = opendir(dirname);  //打開dirname獲取這個目錄的流指針

de = readdir(dir)        //讀取目錄下的文件

strncmp(de->d_name, "input", strlen("input")) //匹配和input相同的項

sprintf(classPath, "%s/%s", dirname, de->d_name);

classPath = /sys/class/input/input(0-n)

snprintf(buf, sizeof(buf), "%s/name", classPath);

buf = /sys/class/input/input0/name

fd = open(buf, O_RDONLY);  //打開上述找到的屬性文件

read(fd, buf, sizeof(buf)   //讀取文件的內(nèi)容

axp22-supplyer        input0

headset               input1

sunxi-ths             input2

sunxi-keyboard        input3

bma250                input4

gslX680               input5

searchDevice(buf, classPath);

otherDeviceDetect(buf); 

/*static struct o_device otherDevice[] = {                                                                                         

{

0, "sw-",

}, {

0, "axp",

},

};*/

if(!otherDevice[number0].isFind){                                                                                    

                if (!strncmp(buf, otherDevice[number0].name,strlen(otherDevice[number0].name))) {

                    otherDevice[number0].isFind = 1;

                    re_value = 1;

                }

從這里我們可以看到它匹配的是axp芯片,當然下面還有匹配其他的,這里我們暫時不關(guān)心,

我們只看bma250的匹配過程。

/*struct sensor_extend_t gsensorList[] = {

{                                                                                                                         

{

"bma250", LSG_BMA250,

}, {

"Bosch 3-axis Accelerometer",

"Bosch",

1, 0,

SENSOR_TYPE_ACCELEROMETER,

4.0f*9.81f,

(4.0f*9.81f)/1024.0f,

0.2f, 0,

0,0,SENSOR_STRING_TYPE_ACCELEROMETER,

0,0,SENSOR_FLAG_WAKE_UP,

{ },

},

}

}*/

ret = getDevice(gsensorList, &gsensorInfo, buf, classPath,ARRAY_SIZE(gsensorList));

if (!strncmp(buf, list[ret].sensors.name, strlen(buf))) {

info->priData = list[ret].sensors.lsg;

setSensorData(sNumber, &list[ret].sList);

sSensorList[number].name = sensorList->name;

sSensorList[number].vendor = sensorList->vendor;

strncpy(info->sensorName, buf,strlen(buf));

strncpy(info->classPath, classPath, strlen(classPath));

}

將匹配到的信息進行賦值,將sensor_t的信息保存在sSensorList的數(shù)組中,將其他的信息

保存在gsensorInfo結(jié)構(gòu)體中。將classPath也保存進去。

struct sensors_poll_device_t {                                                                                              

    struct hw_device_t common;

    int (*activate)(struct sensors_poll_device_t *dev,int sensor_handle, int enabled);

    int (*setDelay)(struct sensors_poll_device_t *dev,int sensor_handle, int64_t sampling_period_ns);

    int (*poll)(struct sensors_poll_device_t *dev,sensors_event_t* data, int count);

}; 

struct sensors_poll_context_t {

    struct sensors_poll_device_t device; // must be first                                                                                                                               

    int activate(int handle, int enabled);

    int setDelay(int handle, int64_t ns);

    int pollEvents(sensors_event_t* data, int count);

    private:

    int accel;

    static const size_t wake = 10;

    static const char WAKE_MESSAGE = 'W';

    struct pollfd mPollFds[11];

    int mWritePipeFd;

    SensorBase* mSensors[10];                                                                                                                        

    int handleToDriver(int handle) const {

        switch (handle) {

            case ID_A:

                return accel;

        }

        return -EINVAL;

    }

};

sensors_poll_context_t *dev = new sensors_poll_context_t();

sensors_poll_context_t::sensors_poll_context_t()

    :gyro(-1),

    orn(-1),

    press(-1)

{

    if((seStatus[ID_A].isUsed == true) && (seStatus[ID_A].isFound == true)) {

        first = first + 1;

        accel = first;

        mSensors[first] = new AccelSensor();   

//創(chuàng)建加速度計對象,保存在mSensors[0]中,這里會打開/dev/input/eventX設(shè)備節(jié)點

        mPollFds[first].fd = mSensors[accel]->getFd();

        mPollFds[first].events = POLLIN;

        mPollFds[first].revents = 0;

    }

...

int wakeFds[2];

    int result = pipe(wakeFds);

    ALOGE_IF(result<0, "error creating wake pipe (%s)", strerror(errno));

    fcntl(wakeFds[0], F_SETFL, O_NONBLOCK);                                                                                      

    fcntl(wakeFds[1], F_SETFL, O_NONBLOCK);

    mWritePipeFd = wakeFds[1];

    mPollFds[wake].fd = wakeFds[0];

    mPollFds[wake].events = POLLIN;

    mPollFds[wake].revents = 0;

}

Hal層的代碼我們暫時分析到這里,接下來我們分析jni代碼的調(diào)用過程。

5.hal代碼的調(diào)用 

fspad-733/androidL/frameworks/native/services/sensorservice/SensorDevice.cpp

SensorDevice::SensorDevice()                                                                                                     

    :  mSensorDevice(0),

       mSensorModule(0)

{

    status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID, //”sensors”

            (hw_module_t const**)&mSensorModule);

fspad-733/androidL/frameworks/native/services/sensorservice/SensorDevice.cpp

SensorDevice::SensorDevice()                                                                                                     

    :  mSensorDevice(0),

       mSensorModule(0)

{

    status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID, //”sensors”

            (hw_module_t const**)&mSensorModule);

//通過SENSORS_HARDWARE_MODULE_ID來獲取sensors_module_t的結(jié)構(gòu)體

if (mSensorModule)  //如果獲取的結(jié)構(gòu)體不為空,則調(diào)用sensors_open_1函數(shù)

err = sensors_open_1(&mSensorModule->common, &mSensorDevice);

module->methods->open(module,SENSORS_HARDWARE_POLL, (struct hw_device_t**)device);

這個open的過程就是前面我們所分析的。

ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list);

get_sensors_list: sensors__get_sensors_list,  

static int sensors__get_sensors_list(struct sensors_module_t* module,struct sensor_t const** list)    

*list = sSensorList;

返回sensorsDetect函數(shù)填充的sSensorList數(shù)組的首地址。

mSensorDevice->activate((struct sensors_poll_device_t *)(mSensorDevice),list[i].handle, 0);

dev->device.activate        = poll__activate;

sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev;

        return ctx->activate(handle, enabled);

int sensors_poll_context_t::activate(int handle, int enabled) {

int index = handleToDriver(handle);

int handleToDriver(int handle) const {

switch (handle) {

case ID_A:

return accel;  //這個handle=0,代碼取出的是加速度計的變量

err |=  mSensors[index]->setEnable(handle, enabled);

int AccelSensor::setEnable(int32_t handle, int en)

if(mUser > 0)

err = enable_sensor();

else   //從上面?zhèn)鬟^來的數(shù)據(jù)我們知道這里執(zhí)行else語句

err = disable_sensor();

int AccelSensor::disable_sensor() {                                                                                              

return writeEnable(0);

int bytes = sprintf(buf, "%d", isEnable);

err = set_sysfs_input_attr(gsensorInfo.classPath,"enable",buf,bytes);

snprintf(path, sizeof(path), "%s/%s", class_path, attr);

path = /sys/class/input/input4/enable

fd = open(path, O_RDWR);

write(fd, value, len) 

//操作sys下的設(shè)備文件,向enable的設(shè)備文件中寫入0,暫時關(guān)閉bma250功能

}

這是我們從下層向上層的分析的思路,至此我們已經(jīng)分析完成,但是它的poll函數(shù)如何被調(diào)用,數(shù)據(jù)如何獲取我們還不知道,接下來我們從上層向下層來分析。

前臺專線:010-82525158 企業(yè)培訓洽談專線:010-82525379 院校合作洽談專線:010-82525379 Copyright © 2004-2022 北京華清遠見科技發(fā)展有限公司

Android培訓

版權(quán)所有 ,京ICP備16055225號-5,京公海網(wǎng)安備11010802025203號