当前位置: 首页 > 安卓培训 > Android开发 > Android-sensor驱动和硬件抽象层
Android-sensor驱动和硬件抽象层 时间:2018-08-16     来源:未知

1. bma250硬件原理

从全志A33的原理图中,我们可以看到关于平板上使用的sensor传感是使用的是bma250。BMA250是一种先进超小,三轴,低g加速度传感器和数字接口,针对低功耗电子消费品的应用程序。这个BMA250允许测量加速度在3个互相垂直的轴,因此感官倾斜,运动,冲击和振动在手机,手机,计算机外设,人机界面,虚拟现实的特性和游戏控制器。我们可以看到这个芯片使用的i2c总线来操作从机设备,从机的地址为0x18。具体的设备信息请参看bma250.pdf文档。

2. Android中bma250驱动的分析

我们接下来看bma250驱动,我们通过它的驱动文件,查看这个功能的实现。参考的文件如下:/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这个函数是由来解析sys_config.fex这个配置文件的,你会发现全志很多配置信息没有在平台代码中填写,而是自己实现了配置文件。这个配置文件存放的路径为fspad-733/lichee$ vi ./tools/pack/out/sys_config.fex。它获取的时候是根据主键值和子键值来获取的。

[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这个总线控制器。

当设备信息通过i2c总线匹配成功之后会执行probe函数,我们可以看到这里有

.class = I2C_CLASS_HWMON,

.detect     = gsensor_detect,

.address_list   = normal_i2c,

I2c总线也可以通过下面的方式匹配成功,重要的就是type,address这两个成员,这种匹配方式前面已经分析过了,这里就不在赘述了。当匹配成功之后会执行probe函数。

.probe      = bma250_probe,

1.定义结构体

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.为结构体分配空间

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

3.结构体成员的初始化

data->bma250_client = client;                  //将client成员赋值给data

bma250_set_bandwidth(client, BMA250_BW_SET);

设置带宽bma250带宽BMA250_BW_SET=4,通过驱动我们知道这里设置的是125hz,也就是说数据会4ms更新一次。

bma250_set_range(client, BMA250_RANGE_SET);

这里是设置加速度传感器的量程范围BMA250_RANGE_SET = 0

INIT_DELAYED_WORK(&data->work, bma250_work_func);

在data结构体中存在一个delayed_work,这个结构体中存在一个工作队列和一个定时器,代码展开情况如下,其中bma250_work_func是中断低半部处理函数。

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);   

在驱动层创建了sysfs接口,HAL层通过这些sysfs接口,对Sensor进行操作,如使能、设置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);

这里一共会创建range,bandwidth,mode,value,delay,enable这些设备文件。range,bandwidth这两个属性文件我们就暂时不分析那么详细了,前面我们已经分析过了,这里主要是对量程范围和带框进行设置的,接下来还有一个mode的属性文件,我们在平板的root@fspad-733:/sys/class/input/input4 #目录下使用cat mode命令可以查看到这个设备文件的默认值为2

#define BMA250_MODE_NORMAL     0

#define BMA250_MODE_LOWPOWER   1

#define BMA250_MODE_SUSPEND     2

从它的定义处我们可以看出这是设置工作模型的,它有三种模式,正常,低电压,挂起等这几种工作模式。Value这个设备文件就是用来存放读取到的当前的加速度计的当前的值的。我们使用cat命令查看。

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

4  12  -268

上面的数字对应的就是读取到的x,y,z轴的数据。

Delay的设备文件就是用来设置当前的延时时间的,enable是用来设置当前bma250是否处在工作状态。接下来我们需要重点分析value,delay,enable这三个设备文件对应的show和store方法。

2.1enable 设备文件分析

static DEVICE_ATTR(enable, S_IRUGO|S_IWUSR|S_IWGRP,

        bma250_enable_show, bma250_enable_store);

通过前面我们所学的sysfs文件系统的知识我们知道,DEVICE_ATTR的后两个参数分别为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结构体中的enable的原子变量的数据,这里只可能是0或1。

bma250_enable_store

error = strict_strtoul(buf, 10, &data);  //将字符串转化为整形数据

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);

}

上面函数的功能是设置bma250的工作模式为正常模式,接着会使用schedule_delayed_work来调度中断下半部,但是这里和我们之前使用的schedule_work函数有所区别,区别在于这里会延时一段时间在执行调度函数。这里的延时时间在bma250结构体的delay变量中保存着。这个delay的值猜想应该是在delay这个设备文件中获取的。接着将atomic的enable设置为1。接下来我们看中断低半部函数。

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去取数据

    input_report_abs(bma250->input, ABS_X, acc.x);  //上报x轴的数据

    input_report_abs(bma250->input, ABS_Y, acc.y);  //上报y轴的数据

    input_report_abs(bma250->input, ABS_Z, acc.z);  //上报z轴的数据

    input_sync(bma250->input);                  //发送同步信号

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

    schedule_delayed_work(&bma250->work, delay); //延时调度本函数

}

上述的函数写的很精髓,通过在中断低半部使用schedule_delayed_work来调度中断低半部,这样就形成了循环从驱动中读取数据。本次调度之间都有一个延时。去报驱动已经将数据更新。接下来我们看下这个延时是怎么设置进来的。

static DEVICE_ATTR(delay, S_IRUGO|S_IWUSR|S_IWGRP,

         bma250_delay_show, bma250_delay_store);

从前面的分析我们知道,工作队列在调度时有一个延时,那么这个延时的时间怎么设置?它不可能是一个固定的值,它应该也为用户提供了操作接口,在我们的这个文件中就是通过delay这个设备文件的方式。这个文件同样对应连个方法,分别是show和store。

bma250_delay_show

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

这个函数十分的简单,就是向buf换中区中写入bma250结构体的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);

将用户写的延时值设置进去。在驱动初始化的时候,我们可以看到这里并不是66而是200,那么它在什么时候进行初始化的那?很显然应该是硬件抽象层调用的。这个暂时不用理会。

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);

这里很显然就是将工作队列中更新的值给打印出来。至此整个驱动我们就分析完成了。

3. bma250驱动的加载过程

3.1sys_config.fex文件的解析过程

在讲解bma250驱动加载之前,我们需要在来讲解一些知识。我们知道在bma250驱动的入口函数中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;                      //设备是否可使用

__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);

这里定义的是函数指针数组,上面传递过来的*input_type = 1,其中input_type又是

sensor_config_info结构体的首地址

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

};

所以接下来应该调用gsensor_fetch_sysconfig_para函数,并将结构体的首地址当参数传递过去。

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结构体

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

data->sensor_used = val.val;    

if (1 == data->sensor_used) {      

//如果sensor可使用就解析设备的数据

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函数根据主键值和子键值进行获取,具体的解析过程看如下目录的文件即可。fspad-733/lichee/linux-3.4/arch/arm/mach-sunxi/sys_config.c  这整个过程的作用很明显就是去读sys_config.fex文件,然后决定当前bma250驱动是否能正常执行。

3.2自动检测函数的执行过程

在如下目录中fspad-733/lichee/linux-3.4/drivers/input/ 有sw-device.c的文件,这个文件的功能是自动检测i2c设备,如果检测到有i2c设备可以使用,则将可用的设备写入device.info文件中。接下来我们分析一下这个文件。

从驱动入口函数开始看起

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;   //创建两个属性文件                                                                           

    err = device_register(&sw_device_detect);    //设备文件的注册过程

}

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);

在入口和出口函数中,我们可以看到设备文件的创建,上述

创建的gsensor和ctp(触摸屏)这两个属性文件,但是他们的store

方法都没有实现,只实现了show方法,显示的是设备名字和i2c

的从机地址。

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

device name:bma250

device addr:0x19

在这个文件中我们还看到有uevent函数的实现,这个函数在什么时候会执行那?

当使用insmod sw-device.ko时这个event函数就会被回调。接下来我们重点分析

回调函数的执行过程

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");

}

...

}

在这个函数中调用很多次sw_register_device_detect函数,这里我们就依gsensor来分析。

首先看一下它的参数gsensor是结构体数组(如下),g_name是一个结构体首地址(成员是不是很熟悉),

device_number是gsensor数组成员的个数。

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结构体

 sw = kzalloc(sizeof(*sw), GFP_KERNEL);  //结构体初始化

 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);

将字符串的信息写入缓冲区中,接着开始调用sw_device_detect_start函数。

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设备中,写入一个字节,检测当前的i2c设备是否可使用

sw_chip_id_detect(sw, now_number)

检测从设备中读取到的id信息是否和表中的相匹配。

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

sw_set_write_info(sw);

如果前面的设备都匹配成功了,这里就会将匹配成功的信息写入到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中的驱动加载过程

从上述的文件中,我们可以看到检测成功的有bma250驱动,还有gslX680new驱动,这两个驱动在编译的时候我们可以通过make menuconfig ARCH=arm看到

Device Drivers  --->

<*> Hardware Monitoring support  --->  

<M>   BMA250 acceleration sensor support

它被编译成了模块侧形式,那么这个驱动什么时候被加载的那?很多同学第一时间会想到应该是在fspad-733/androidL/device/softwinner/fspad-733/ init.sun8i.rc文件中,但是你在这个文件中怎么搜索都搜索不到。难道驱动会自动加载?这种情况是不可能的。回想前面的过程这些驱动是在device.info中写的,如果说想加载这个驱动的话,首先一定会打开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);//获取到的驱动为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, "")

至此,驱动就能够成功加载了。

4.sensor的硬件抽象层的代码分析

sensor的hal层涉及到的结构体

对任意一个sensor设备都会有一个sensor_t结构体,其定义如下:

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

};

每个传感器的数据由sensors_event_t结构体表示,定义如下:

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结构体用来表示不同传感器的数据, 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设备结构体sensors_poll_device_t,对标准硬件设备hw_device_t结构体的扩展,主要完成读取底层数据,并将数据存储在struct sensors_poll_device_t结构体中,poll函数用来获取底层数据,调用时将被阻塞定义如下:

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);

   //获取数据

   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的结构体,但是在这个文件中我们没有发现这个结构体取而代之的是sensors_module_t结构体,它把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++里面的规则。效果是相同的。接下来我们分析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驱动

property_set("sys.sensors", "1");//设置属性

sensorsDetect();  //sensor的自检测

sensors_poll_context_t *dev = new sensors_poll_context_t(); //定义结构体

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;  //将结构体返回给上层

return 0;

}

驱动的安装过程前面我们已经分析过了,终会调用insmod函数。属性的设置暂时不去理会,我们来分析一下驱动的自检测过程。

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)   //读取文件的内容

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芯片,当然下面还有匹配其他的,这里我们暂时不关心,

我们只看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的数组中,将其他的信息

保存在gsensorInfo结构体中。将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();   

//创建加速度计对象,保存在mSensors[0]中,这里会打开/dev/input/eventX设备节点

        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代码的调用过程。

5.hal代码的调用 

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的结构体

if (mSensorModule)  //如果获取的结构体不为空,则调用sensors_open_1函数

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函数填充的sSensorList数组的首地址。

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   //从上面传过来的数据我们知道这里执行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下的设备文件,向enable的设备文件中写入0,暂时关闭bma250功能

}

这是我们从下层向上层的分析的思路,至此我们已经分析完成,但是它的poll函数如何被调用,数据如何获取我们还不知道,接下来我们从上层向下层来分析。

前台专线:010-82525158 企业培训洽谈专线:010-82525379 院校合作洽谈专线:010-82525379 Copyright © 2004-2022 北京华清远见科技发展有限公司

Android培训

版权所有 ,京ICP备16055225号-5,京公海网安备11010802025203号