input上报流程分析【转】

简介:

转自:http://blog.chinaunix.net/uid-28320320-id-3389196.html

复制代码
1、参考文章
       【Andorid】input系统的事件处理

2、源码分析 linux 3.6.3
    1)查看linux-3.6.3/drivers/input下Makefile

点击(此处)折叠或打开

    obj-$(CONFIG_INPUT) += input-core.o
        input-core-y := input.o input-compat.o input-mt.o ff-core.o


    2)查看文件input.c

点击(此处)折叠或打开

    /* input subsystem entry */
    subsys_initcall(input_init);
    module_exit(input_exit);


    3)input.c搞啥子

点击(此处)折叠或打开

    /* sysfs/procfs/devfs show */
        |-----------|
        |          \/
        | err = class_register(&input_class);
        |
        |-----------|
        |          \/
        | err = input_proc_init();
        |
        |-----------|
        |          \/
        | err = register_chrdev(INPUT_MAJOR, "input", &input_fops);


根据下面的方法,发现手机的tp 对应event1

点击(此处)折叠或打开

        # getevent 
        add device 1: /dev/input/event0
          name: "fluid-keypad"
        add device 2: /dev/input/event3
          name: "7k_handset"
        add device 3: /dev/input/event2
          name: "sensors"
        add device 4: /dev/input/event1
          name: "Synaptics RMI4"
          
        # pwd
        /sys/class/input
        # ls
        event0 event1 event2 event3 input0 input1 input2 input3
          
        # cat /proc/bus/input/devices
        I: Bus=0019 Vendor=0001 Product=0001 Version=0001
        N: Name="fluid-keypad"
        P: Phys=fluid-keypad/input0
        S: Sysfs=/devices/i2c-6/6-0000/pm8058-keypad/input/input0
        U: Uniq=
        H: Handlers=kbd event0
        B: EV=13
        B: KEY=1200000 0 0 c0000 0 0 0
        B: MSC=10
          
        I: Bus=0000 Vendor=0000 Product=0000 Version=0000
        N: Name="Synaptics RMI4"
        P: Phys=Synaptics_rmi
        S: Sysfs=/devices/virtual/input/input1
        U: Uniq=
        H: Handlers=event1
        B: EV=b
        B: KEY=400 0 0 0 2000000 0 40000800 40 0 0 0
        B: ABS=770000 11030003
          
        I: Bus=0018 Vendor=0003 Product=0000 Version=0000
        N: Name="sensors"
        P: Phys=
        S: Sysfs=/devices/virtual/input/input2
        U: Uniq=
        H: Handlers=event2
        B: EV=9
        B: ABS=8000 20304bf
          
        I: Bus=0000 Vendor=0001 Product=0001 Version=0001
        N: Name="7k_handset"
        P: Phys=
        S: Sysfs=/devices/virtual/input/input3
        U: Uniq=
        H: Handlers=kbd event3
        B: EV=23
        B: KEY=4 0 28 0 1c0800 0 0 0
        B: SW=4


    4)touch panel驱动源码

点击(此处)折叠或打开

    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/slab.h>
    #include <linux/platform_device.h>
    #include <linux/i2c.h>
    #include <linux/input.h>
      
    #include "gsl1680.h"
      
    #define gsl_pr(fmt, arg...) \
        printk(KERN_ERR "[GSL]%s: \033[32m" fmt "\033[0m\n", __FUNCTION__, ##arg)
      
    #define GSL_ADAPTER_INDEX 0
    #define GSL1680D0_ID 0
    #define GSL_DEV_NAME "gsl"
      
    /**
     * Description : global var
     */
    static struct gsl_ts_data *ddata = NULL;
    static const struct i2c_device_id gsl_id[] = {
        {GSL_DEV_NAME, GSL1680D0_ID},
        {},
    };
    MODULE_DEVICE_TABLE(silead, gsl_id);
      
    static struct i2c_board_info gsl_i2c_info = {
        .type = GSL_DEV_NAME,
        .addr = 0x40,
    };
      
    /**
     * Description : gsl soc operation
     */
    static int gsl_hw_init(void)
    {
        return 0;
    }
      
    static int gsl_sw_init(void)
    {
        return 0;
    }
      
    /**
     * Description : touch panel driver
     */
    static void gsl_report_work(struct work_struct *work)
    {
    }
      
    static int gsl_request_input(void)
    {
        int ret = 0;
      
        ddata->idev = input_allocate_device();
        if (!ddata->idev) {
            dev_err(&ddata->idev->dev, "could not allocate device\n");
            return -ENODEV;
        }
      
        ddata->idev->name = GSL_DEV_NAME;
        ddata->idev->id.bustype = BUS_I2C;
        ddata->idev->dev.parent = &ddata->client->dev;
        input_set_drvdata(ddata->idev, ddata);
      
        __set_bit(EV_ABS, ddata->idev->evbit);
      
        input_set_abs_params(ddata->idev, ABS_MT_POSITION_X,
            DIS_MIN_X, DIS_MAX_X, 0, 0);
        input_set_abs_params(ddata->idev, ABS_MT_POSITION_Y,
            DIS_MIN_Y, DIS_MAX_Y, 0, 0);
        input_set_abs_params(ddata->idev, ABS_MT_TOUCH_MAJOR,
            MIN_TOUCH, MAX_TOUCH, 0, 0);
        input_set_abs_params(ddata->idev, ABS_MT_WIDTH_MAJOR,
            MIN_WIDTH, MAX_WIDTH, 0, 0);
        input_set_abs_params(ddata->idev, ABS_MT_TRACKING_ID,
            MIN_TRCKID, MAX_TRCKID, 0, 0);
      
        INIT_WORK(&ddata->work, gsl_report_work);
      
        ddata->wq = create_singlethread_workqueue(GSL_DEV_NAME);
        if (!ddata->wq) {
            dev_err(&ddata->idev->dev, "could not create workqueue\n");
            ret = -ENOMEM;
            goto error_wq_create;
        }
    #if 0
        ddata->pm.suspend = gsl_suspend;
        ddata->pm.resume = gsl_resume;
        register_early_suspend(&ddata->pm);
    #endif
        ret = input_register_device(ddata->idev);
        if (ret) {
            dev_err(&ddata->idev->dev, "ret = %d : could not register input device\n", ret);
            goto error_unreg_device;
        }
        return 0;
      
    error_unreg_device:
        destroy_workqueue(ddata->wq);
    error_wq_create:
        input_free_device(ddata->idev);
        return ret;
    }
      
    static __devinit int gsl_probe(struct i2c_client *client,
            const struct i2c_device_id *id)
    {
        int ret = 0;
      
        gsl_pr();
      
        ddata->ti = kzalloc(sizeof(union gsl_touch_info), GFP_KERNEL);
        if (!ddata->ti) {
            dev_err(&client->dev, "failed to alloc ddata->ti memory!\n");
            ret = -ENOMEM;
            goto error_alloc_mem;
        }
      
        /* regist a input dev */
        ret = gsl_request_input();
        if (ret) {
            dev_err(&client->dev, "failed to regist input dev!\n");
            goto error_regist_input;
        }
      
        /* setup the gpio -- irq & rst */
        ret = gsl_hw_init();
        if (ret) {
            dev_err(&client->dev, "failed to init hw!\n");
            goto error_init_hw;
        }
      
        /* setup client data & download fw */
        ret = gsl_sw_init();
        if (ret) {
            dev_err(&client->dev, "failed to init sw!\n");
            goto error_init_sw;
        }
      
        return 0;
      
    error_init_sw:
    error_init_hw:
        destroy_workqueue(ddata->wq);
        input_free_device(ddata->idev);
    error_regist_input:
        kfree(ddata->ti);
        input_unregister_device(ddata->idev);
        destroy_workqueue(ddata->wq);
        input_free_device(ddata->idev);
    error_alloc_mem:
        kfree(ddata);
        return ret;
    }
      
    static __devexit int gsl_remove(struct i2c_client *client)
    {
        return 0;
    }
      
    static struct i2c_driver gsl_driver = {
        .driver = {
            .name = GSL_DEV_NAME,
            .owner = THIS_MODULE,
        },
        .probe = gsl_probe,
        .remove = gsl_remove,
        .id_table = gsl_id,
    };
      
    /**
     * Description : module operation
     */
    static __init int gsl_init(void)
    {
        int ret = 0;
        struct i2c_adapter *adapter;
      
        gsl_pr();
      
        ddata = kzalloc(sizeof(struct gsl_ts_data), GFP_KERNEL);
        if (!ddata) {
            gsl_pr("alloc mem error");
            goto err_mem;
        }
      
        /* tips : try_module_get */
        adapter = i2c_get_adapter(GSL_ADAPTER_INDEX);
        if (!(adapter)) {
            gsl_pr("get %d adapter failed", GSL_ADAPTER_INDEX);
            ret = -ENODEV;
            goto err_adap;
        }
      
        ddata->client = i2c_new_device(adapter, &gsl_i2c_info);
        if (!(ddata->client)) {
            gsl_pr("get i2c device error");
            ret = -ENODEV;
            goto err_dev;
        }
      
        /* release the module */
        i2c_put_adapter(adapter);
      
        ret = i2c_add_driver(&gsl_driver);
        if (ret) {
            gsl_pr("i2c add driver failed");
            goto err_driver;
        }
      
        return 0;
      
    err_driver:
        i2c_unregister_device(ddata->client);
        i2c_put_adapter(adapter);
    err_dev:
    err_adap:
        kfree(ddata);
    err_mem:
        return ret;
    }
      
    static __exit void gsl_exit(void)
    {
        gsl_pr();
      
        /* reverse effect of i2c_new_device() */
        i2c_del_driver(&gsl_driver);
        i2c_unregister_device(ddata->client);
        kfree(ddata);
      
        return;
    }
      
    module_init(gsl_init);
    module_exit(gsl_exit);
      
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("mark");


点击(此处)折叠或打开

    //touch coordinate range
    #define TP_WIDTH 480
    #define TP_LENTH 800
          
    //coordinate direction
    #define TP_DIREC 1 // if 1 is (1,1), then 2(1,-1), 3(-1,-1), 4(-1,1)
          
    //touch threshold
    #define MAI_TRSD 200
    #define SUB_TRSD 40
    #define SUM_TRSD (MAI_TRSD + SUB_TRSD + 20)
          
    //touch tigger condition
    #define TRIG_MOD 1 // 1 is edge, 0 is level
    #define VOLT_LEV 0 // if trig mode is edge,
                                // 0 is IRQF_TRIGGER_RISING, 1 is IRQF_TRIGGER_FALLING
                                // if trig mode is level,
                                // 0 is IRQF_TRIGGER_HIGH, 1 is IRQF_TRIGGER_LOW
          
    //touch sensitivity
    #define TP_DACG 0x00100010 //9f/30
    #define DAC_STEP 0x8e //if TP_DACG=0x00180018,TP_DAC_STEP=0x61
                                        //if TP_DACG=0x00100010,TP_DAC_STEP=0x8e
                                        //if TP_DACG=0x000c000c,TP_DAC_STEP=0xbb
                                        //if TP_DACG=0x000a000a,TP_DAC_STEP=0xdf
                                        //if TP_DACG=0x00080008,TP_DAC_STEP=0x114
                                        //if TP_DACG=0x00060006,TP_DAC_STEP=0x16e
    #define CHANGE_CONDITION 0x0 //0--use average,1--use max
          
    #define GSL_PAGE_REG 0xf0
    #define GSL_CLOCK_REG 0xe4
    #define GSL_START_REG 0xe0
    #define GSL_CLOCK_REG 0xe4
    #define POWE_FAIL_REG 0xbc
    #define TOUCH_INFO_REG 0x80
          
    #define DIS_MIN_X 0
    #define DIS_MAX_X TP_WIDTH
    #define DIS_MIN_Y 0
    #define DIS_MAX_Y TP_LENTH
          
    #define MIN_TOUCH 0
    #define MAX_TOUCH 1
    #define MIN_WIDTH 0
    #define MAX_WIDTH 1
    #define MIN_TRCKID 1
    #define MAX_TRCKID 5
          
    /* the data format of one point */
    union gsl_point_data {
        struct {
            u16 y;
            u16 x : 12;
            u16 id : 4;
        };
        u8 all[4];
    };
          
    /* the 24-byte data of read once */
    union gsl_touch_info {
        struct {
            u32 finger_num : 8;
            u32 : 0;
            union gsl_point_data point[5];
        };
        u8 all[24];
    };
          
    struct gsl_ts_data {
        union gsl_touch_info *ti;
        struct i2c_client *client;
        struct input_dev *idev;
        struct workqueue_struct *wq;
        struct work_struct work;
        unsigned int irq;
    };
          
    /* Fixme mem Alig */
    struct fw_data {
        u32 offset : 8;
        u32 : 0;
        u32 val;
    };
          
    static const struct fw_data GSL1680_D0_FW[] = {
        /* void */
        { },
    };


    5)input_report_abs上报流程

点击(此处)折叠或打开

    /* 观察linux-3.6.3/drivers/input/Kconfig, 对应/dev/input/eventX */
        config INPUT_EVDEV
            tristate "Event interface"
            help
              Say Y here if you want your input device events be accessible
              under char device 13:64+ - /dev/input/eventX in a generic way.
          
              To compile this driver as a module, choose M here: the
              module will be called evdev.

android 4.0 一般报点序列:

点击(此处)折叠或打开

    input_mt_slot(ts->input, id);
    input_report_abs(ts->input, ABS_MT_TRACKING_ID, id);
    input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, 1);
    input_report_abs(ts->input, ABS_MT_POSITION_X, x);
    input_report_abs(ts->input, ABS_MT_POSITION_Y, y);
    input_report_abs(ts->input, ABS_MT_WIDTH_MAJOR, 1);
    input_mt_sync(ts->input);

点击(此处)折叠或打开

    input_sync(ts->input);


input_handle_event(dev, type, code, value)上报流程:

点击(此处)折叠或打开

    ...
    switch (type) {
      
    case EV_SYN:
        switch (code) {
           ...
        case SYN_REPORT:
            if (!dev->sync) {
                dev->sync = true;
                disposition = INPUT_PASS_TO_HANDLERS;
            }
            break;
        case SYN_MT_REPORT:
            dev->sync = false;
            disposition = INPUT_PASS_TO_HANDLERS;
            break;
        }
        break;
      
    case EV_KEY:
        if (is_event_supported(code, dev->keybit, KEY_MAX) &&
            !!test_bit(code, dev->key) != value) {
      
            if (value != 2) {
                __change_bit(code, dev->key);
                if (value)
                    input_start_autorepeat(dev, code);
                else
                    input_stop_autorepeat(dev);
            }
      
            disposition = INPUT_PASS_TO_HANDLERS;
        }
        break;
       ...
    case EV_ABS:
        if (is_event_supported(code, dev->absbit, ABS_MAX))
            disposition = input_handle_abs_event(dev, code, &value);
      
        break;
       ...
    }
      
       ...
    if (disposition & INPUT_PASS_TO_HANDLERS)
        input_pass_event(dev, type, code, value);

 

点击(此处)折叠或打开

    static void input_pass_event(struct input_dev *dev,
                         unsigned int type, unsigned int code, int value)
    {
         struct input_handler *handler;
         struct input_handle *handle;
          
         rcu_read_lock();
          
         /* 获得一个被RCU保护的指针 */
         handle = rcu_dereference(dev->grab);
         /* (1) 如果是设备专有handle, 仅将事件传给该handler. */
         if (handle)
             handle->handler->event(handle, type, code, value);
         else {
             bool filtered = false;
          
             /* (2)遍历与此设备连接的每一个handle. */
             list_for_each_entry_rcu(handle, &dev->h_list, d_node) {
                /* (3)如果hnadle已经被打开. */
                if (!handle->open)
                    continue;
          
                handler = handle->handler;
                if (!handler->filter) {
                     if (filtered)
                         break;
                     /* (4)将事件分发给handler的事件处理函数. */
                     handler->event(handle, type, code, value);
          
                } else if (handler->filter(handle, type, code, value))
                   filtered = true;
             }
       }
          
       rcu_read_unlock(); 
    }


附上android 4.0上报方式(linux必须2.6.38以上)

点击(此处)折叠或打开

    #include <linux/input/mt.h>



点击(此处)折叠或打开

    //down
        input_mt_slot(ts->input_dev, id);
        //input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, id);
        input_mt_report_slot_state(data->input_dev, MT_TOOL_FINGER, true);
        input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, w);
        input_report_abs(ts->input_dev, ABS_MT_POSITION_X, x);
        input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, y);



点击(此处)折叠或打开

    //up
        input_mt_slot(ts->input_dev, id);
        //input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, -1);
        input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, false);



点击(此处)折叠或打开

    //init
        //__set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
        input_mt_init_slots(ts->input_dev, 255);
复制代码

 








本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/sky-heaven/p/6768361.html,如需转载请自行联系原作者

相关文章
|
消息中间件 SQL JSON
阿里云物联网平台 “物模型属性” 的分析&&易错点&&上报属性时Payload如何正确组装?
您是否在纠结设备上报了数据,平台到底有没有收到? 您是否很疑惑物模型属性怎么老是不刷新? 您是否不理解物模型属性下发总是不生效? 您是否不知道上报属性时Payload到底该怎么填? 您是否很纳闷物模型属性一会又携带有时间戳,一会又没有? 您是否怀疑能不能自定义物模型属性的时间戳?又如何取到自定义时间戳? 您是否...
7416 3
阿里云物联网平台 “物模型属性” 的分析&&易错点&&上报属性时Payload如何正确组装?
|
3月前
|
存储 监控 前端开发
前端埋点上报的几种方式
前端埋点上报的几种方式
112 0
|
消息中间件 弹性计算 运维
重新定义分析 - EventBridge实时事件分析平台发布
为了解决事件领域中针对流式事件做分析的难题,EventBridge 近日发布了针对事件/消息领域的全新分析工具--EventBridge 实时事件分析平台。下面简要对 EventBridge 实时事件分析平台的内容进行介绍。
174 0
重新定义分析 - EventBridge实时事件分析平台发布
|
数据采集 缓存 JavaScript
网站流量日志埋点收集- - 方案二--点击事件数据采集实现|学习笔记
快速学习网站流量日志埋点收集- -方案二--点击事件数据采集实现
328 0
网站流量日志埋点收集- - 方案二--点击事件数据采集实现|学习笔记
|
程序员
(简易)测试数据构造平台: 18 (工单系统)
(简易)测试数据构造平台: 18 (工单系统)
(简易)测试数据构造平台: 18 (工单系统)
|
XML Dubbo Java
服务注册流程分析01
在填充该 ServiceBean 的时候会将对应的那个声明了注解的 bean 设置到 ServiceBean 中。 剩下的流程放置到下一篇文章中
94 0
|
Dubbo Java 应用服务中间件
服务注册流程分析02
上一篇文章中、我们已经知道 Dubbo 会额外注册 ServiceBean 到 Spring 容器中、因为需要借助这个 ServiceBean 注册到服务中心
127 0
SAP PP 系统怎么知道某个工单release触发的过程中检验的检验类型是03?
SAP PP 系统怎么知道某个工单release触发的过程中检验的检验类型是03?
SAP PP 系统怎么知道某个工单release触发的过程中检验的检验类型是03?
|
数据采集 数据可视化 算法
TDA-04D8变送器数据上报阿里云
本文将以TDA-04D8变送器作为采集对象,使用海创微联采集控制系统对TDA-04D8变送器进行采集,然后将设备上的毛重、净重、皮重数据采集上传到阿里云物联网平台,阿里云物联网平台将数据实时可视化。
576 0
TDA-04D8变送器数据上报阿里云