转自: https://blog.csdn.net/daoshuti/article/details/72983620

AndroidTP驱动之(三)input

0. 前情提要

上文中我们已经完成对设备树的解析工作,获取了tp的硬件信息。 我们知道Linux内核上报输入事件是通过input子系统,TP作为输入设备自然要通过input子系统来上报。 现在的kernel都支持多点触控了,多点触控的协议有两种协议A和协议B,协议A不需要硬件支持,协议B需要硬件支持。 这里我们不讨论协议A/B,有兴趣的同学自己Google。 下面我们就初始化input子系统。

1. probe函数

在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的。具体见下一小节。

2. mytp_input_dev_init函数

函数一开始显示初始化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;
}

3. remove函数

input_unregister_device(data->input_dev);

注销input设备。 另注:

前文中i2c设备在exit函数中注销。  
而设备树,只是从中获取硬件信息,不能注销。  
内存申请时,使用的是devm\_kzalloc函数,其会在驱动模块注销主动释放内存,所以不需要手动free。  

用到的头文件和宏

头文件

#include <linux/input.h>
#include <linux/input/mt.h>

#define MYTP_MT_PROTOCOL_B_EN   1

MYTP_DRIVER_NAME宏,前文已经定义过。 End

至此TP的input初始化完成。

标签: aosp

添加新评论