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函数如何被调用,数据如何获取我们还不知道,接下来我们从上层向下层来分析。
Java热点新闻