zoukankan      html  css  js  c++  java
  • 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: 33[32m" fmt "33[0m
    ", __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
    ");
                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
    ");
                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
    ", 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!
    ");
                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!
    ");
                goto error_regist_input;
            }
          
            /* setup the gpio -- irq & rst */
            ret = gsl_hw_init();
            if (ret) {
                dev_err(&client->dev, "failed to init hw!
    ");
                goto error_init_hw;
            }
          
            /* setup client data & download fw */
            ret = gsl_sw_init();
            if (ret) {
                dev_err(&client->dev, "failed to init sw!
    ");
                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);
  • 相关阅读:
    一文带你彻底明白如何实现动态添加子节点及修改子节点属性
    一文带你彻底理解 JavaScript 原型对象
    Oracle内存占用高过时的调整策略
    Oracle Instant Client(即时客户端) 安装与配置
    windows环境完全卸载Oracle19c
    Oracle19c常用语句
    cannot mount database in EXCLUSIVE mode解决办法
    oracle存储过程通过游标输出Sql结果集
    Oracle DBlink的创建
    MySQL语法
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/6768361.html
Copyright © 2011-2022 走看看