上文中我们已经完成对设备树的解析工作,获取了tp的硬件信息。
我们知道Linux内核上报输入事件是通过input子系统,TP作为输入设备自然要通过input子系统来上报。
现在的kernel都支持多点触控了,多点触控的协议有两种协议A和协议B,协议A不需要硬件支持,协议B需要硬件支持。
这里我们不讨论协议A/B,有兴趣的同学自己Google。
下面我们就初始化input子系统。
在probe函数的开始我们先定义了两个结构体指针。为后面的input初始化做准备。
这两个以结构体,一个是input_dev,另一个是自定义的结构体mytp_data。
input_dev自不别说,我们的TP通过这个结构体来上报数据。
mytp_data是我们TP驱动中自定义的结构体,方便我们来编写程序。
具体定义如下:
struct mytp_data
{
struct i2c_client *client;
struct input_dev *input_dev;
struct mytp_platform_data *pdata;
};
如上所示,现在mytp_data结构体的成员很少只有三个,后期随着功能的增加,我们还会添加。
这三个结构体成员都是很重要的,i2c_client用来和TP通信,input_dev用来上报TP数据,mytp_platform_data存放了硬件平台的数据。
probe函数中input初始化代码具体如下:
struct input_dev *input_dev;
struct mytp_data *data;
data = devm_kzalloc(&client->dev, sizeof(struct mytp_data), GFP_KERNEL);
if (!data)
{
PRINT_INFO("[MEMORY]Failed to allocate memory");
return -ENOMEM;
}
input_dev = input_allocate_device();
if (!input_dev)
{
PRINT_INFO("[INPUT]Failed to allocate input device");
return -ENOMEM;
}
data->input_dev = input_dev;
data->client = client;
data->pdata = pdata;
mytp_input_dev_init(client, data, input_dev, pdata);
代码的逻辑很清晰,完成结构体变量的初始化后调用mytp_input_dev_init()函数。
这个函数就是用来初始化input的。具体见下一小节。
函数一开始显示初始化input_dev结构体,
然后将驱动私有的mytp_data结构体指针变量data,通过input_set_drvdata和i2c_set_clientdata函数放入input_dev和client中。
之后通过__set_bit函数设置上报的数据类型,和键值。
通过宏MYTP_MT_PROTOCOL_B_EN选择多点上报的方式。
通过input_register_device注册input设备。
static int mytp_input_dev_init( struct i2c_client *client, struct mytp_data *data, struct input_dev *input_dev, struct mytp_platform_data *pdata)
{
int err, len;
/* Init and register Input device */
input_dev->name = MYTP_DRIVER_NAME;
input_dev->id.bustype = BUS_I2C;
input_dev->dev.parent = &client->dev;
input_set_drvdata(input_dev, data);
i2c_set_clientdata(client, data);
__set_bit(EV_KEY, input_dev->evbit);
if (data->pdata->have_key)
{
PRINT_INFO("set key capabilities");
for (len = 0; len < data->pdata->key_number; len++)
{
input_set_capability(input_dev, EV_KEY, data->pdata->keys[len]);
}
}
__set_bit(EV_ABS, input_dev->evbit);
__set_bit(BTN_TOUCH, input_dev->keybit);
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
#if MYTP_MT_PROTOCOL_B_EN
input_mt_init_slots(input_dev, pdata->max_touch_number, INPUT_MT_DIRECT);
#else
input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0, 0x0f, 0, 0);
#endif
input_set_abs_params(input_dev, ABS_MT_POSITION_X, pdata->x_min, pdata->x_max, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y, pdata->y_min, pdata->y_max, 0, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 0xFF, 0, 0);
err = input_register_device(input_dev);
if (err)
{
PRINT_INFO("Input device registration failed");
goto free_inputdev;
}
return 0;
free_inputdev:
input_free_device(input_dev);
return err;
}
input_unregister_device(data->input_dev);
注销input设备。
另注:
前文中i2c设备在exit函数中注销。
而设备树,只是从中获取硬件信息,不能注销。
内存申请时,使用的是devm\_kzalloc函数,其会在驱动模块注销主动释放内存,所以不需要手动free。
头文件
#include
#include
宏
#define MYTP_MT_PROTOCOL_B_EN 1
MYTP_DRIVER_NAME宏,前文已经定义过。
至此TP的input初始化完成。