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

前言:

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;//加速度sensor
	struct 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

调用流程如下,

android input子系统分析---驱动层_第1张图片

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 来做了。

你可能感兴趣的:(---【sensor框架分析】)