android input子系统分析---驱动层

来源:互联网 发布:美拍用的抽奖软件 编辑:程序博客网 时间:2024/05/16 10:24

前言:

Input子系统包括标准Linux,Android核心驱动,Android相关设备驱动,G-sensor的设备驱动程序。传感器作为

一种输入设备,也是通过input系统把其数据上报给系统,或者通过input系统得到用户的配置信息。这里以传感器

为例学习input driver层。

Sensor驱动从通过I2C从寄存器中读取sensor值,然后写入/dev/input/目录下对应的文件。HAL层通过读取该文件的

值进一步传递给Framework层。每个厂商使用的具体的输入驱动硬件不同,因此软件也不尽相同,但是具体的原理都

是一样的。

 

代码路径: kernel\drivers\input。

1,概论

Sensor模块的module_i2c_driver方法会向i2c总线挂载该驱动。

module_i2c_driver(mpu6880_i2c_driver);

mpu6880_i2c_driver结构体如下,

static struct i2c_driver mpu6880_i2c_driver = {.driver= {.name= "mpu6880",.owner= THIS_MODULE,.pm= &mpu6880_pm,.of_match_table = mpu6880_of_match,},.probe= mpu6880_probe,.remove= mpu6880_remove,.id_table= mpu6880_ids,};module_i2c_driver(mpu6880_i2c_driver);

该驱动加载时的probe方法是mpu6880_probe。

mpu6880_probe方法有2个参数,

static int mpu6880_probe(struct i2c_client *client, const struct i2c_device_id *id){

第一个参数client是I2C寄存器在sensor驱动中的客户端,

第二个参数id是I2C寄存器在sensor驱动中的id,

通过这2个参数,sensor就可以从寄存器中读出sensor数据。

mpu6880_probe方法主要如下,

1,sensor模块初始化,

sensor = devm_kzalloc(&client->dev, sizeof(struct mpu6880_sensor), GFP_KERNEL);//申请内存•••sensor->client = client;//为mpu6880_sensor结构体赋值sensor->dev = &client->dev;•••sensor->accel_dev->name = MPU6880_DEV_NAME_ACCEL;sensor->gyro_dev->name = MPU6880_DEV_NAME_GYRO;sensor->accel_dev->id.bustype = BUS_I2C;sensor->gyro_dev->id.bustype = BUS_I2C;sensor->gyro_poll_ms = pdata->gyro_poll_ms;sensor->accel_poll_ms = pdata->accel_poll_ms;

mpu6880_sensor定义如下,

struct mpu6880_sensor {struct i2c_client *client;//i2c客户端struct device *dev; //设备struct input_dev *accel_dev;//加速度sensorstruct input_dev *gyro_dev;struct sensors_classdev accel_cdev;struct sensors_classdev gyro_cdev;struct mpu6880_platform_data *pdata;•••

2,注册2个sensor,

ret = input_register_device(sensor->accel_dev);if (ret) {dev_err(&client->dev, "Failed to register input device\n");goto err_free_irq;}ret = input_register_device(sensor->gyro_dev);if (ret) {dev_err(&client->dev, "Failed to register input device\n");goto err_unregister_accel;}

3,利用定时中断读取sensor数据,

INIT_DELAYED_WORK(&sensor->gyro_poll_work, mpu6880_gyro_work_fn);INIT_DELAYED_WORK(&sensor->accel_poll_work, mpu6880_accel_work_fn);

新建一个内核线程,入口方法为mpu6880_accel_work_fn,重力感应器在此以后就不啰嗦了,整个和加速度完全一样。

Sensor事件在驱动中的主要分为3个部分,

1,驱动层,从I2C寄存器中读取sensor数据。

2,核心层,统一发送给input子系统处理。

3,事件层,将处理后的event写入缓存,供HAL调用。

2,驱动层

2.1 sensor

调用流程如下,


mpu6880_accel_work_fn方法主要分为2个步骤,

1,首先调用mpu6880_read_accel_data方法读取寄存器中的sensor数据

mpu6880_read_accel_data(sensor, &sensor->axis);

2,然后调用mpu6880_accel_report方法进行处理。

mpu6880_accel_report(sensor);

2.1 数据读取

mpu6880_read_accel_data方法如下,

static void mpu6880_read_accel_data(struct mpu6880_sensor *sensor,     struct axis_data *data){u16 buffer[3]; //缓存mpu6880_read_reg(sensor->client, sensor->reg.raw_accel,(u8 *)buffer, MPU6880_RAW_ACCEL_DATA_LEN); //读取sensor数据data->x = be16_to_cpu(buffer[0]);data->y = be16_to_cpu(buffer[1]);data->z = be16_to_cpu(buffer[2]);}

首先调用mpu6880_read_reg方法从寄存器中读取数据,然后将数据写入data结构体中。

mpu6880_read_reg方法如下,

static int mpu6880_read_reg(struct i2c_client *client, u8 start_addr,       u8 *buffer, int length){struct i2c_msg msg[] = {{.addr = client->addr,.flags = 0,.len = 1,.buf = &start_addr,},{.addr = client->addr,.flags = I2C_M_RD,.len = length,.buf = buffer,},};return i2c_transfer(client->adapter, msg, 2);}

首先构造一个i2c_msg结构体,然后直接调用i2c_transfer方法读取数据, i2c_transfer是系统方法。

这样,寄存器的数据终于写入mpu6880_sensor结构体的axis_data结构体。

2.2 sensor处理

mpu6880_accel_report方法的主要逻辑如下,

input_report_abs(sensor->accel_dev, ABS_X, (sensor->axis.x )); //发送x轴加速度input_report_abs(sensor->accel_dev, ABS_Y, (sensor->axis.y )); //发送y轴加速度input_report_abs(sensor->accel_dev, ABS_Z, (sensor->axis.z )); //发送z轴加速度input_event(sensor->accel_dev, EV_SYN, SYN_TIME_SEC, ktime_to_timespec(ts).tv_sec);input_event(sensor->accel_dev, EV_SYN, SYN_TIME_NSEC, ktime_to_timespec(ts).tv_nsec);input_sync(sensor->accel_dev);

首先发送三个方向上的加速度,然后发送系统的当前时间,获取系统当前时间如下,

ktime_t ts;ts = ktime_get_boottime();

注意ktime_t结构体, tv_sec变量单位是s, tv_nsec单位是ns。这2个值同一单位相加就是1970年1月1日

到当前系统sensor数据上报的时间。

input.h的input_report_abs方法也是调用input.c的input_event方法进行处理。

static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value){input_event(dev, EV_ABS, code, value);}

接下来的事就交由input.c 来做了。

原创粉丝点击