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);

 

时间: 2024-09-27 03:37:03

input上报流程分析【转】的相关文章

MapReduce V1:MapTask执行流程分析

我们基于Hadoop 1.2.1源码分析MapReduce V1的处理流程. 在文章<MapReduce V1:TaskTracker设计要点概要分析>中我们已经了解了org.apache.hadoop.mapred.Child启动的基本流程,在Child VM启动的过程中会运行MapTask,实际是运行用户编写的MapReduce程序中的map方法中的处理逻辑,我们首先看一下,在Child类中,Child基于TaskUmbilicalProtocol协议与TaskTracker通信,获取到该

myeclipse-MyEclipse启动后的运行流程分析

问题描述 MyEclipse启动后的运行流程分析 例如数据流的流向,以及在各个部分的编码格式转化问题等等. tomcat网卡监听的是什么数据?post提交的表单需要被tomcat编码一下不?tomcat端有jsp界面否? 解决方案 MyEclipse是开发环境,tomcat是web服务器,和网卡打交道的是操作系统和驱动,三者根本没关系,你在问什么. 解决方案二: Hadoop运行流程分析Hadoop运行流程分析SpringMVC运行流程分析 解决方案三: 编程尚未成功,同志仍需努力! Myecl

Glide加载图片流程(Part Two)之缓存流程分析

承接上文,我们简单了解了Glide加载图片的流程,在这篇博文中,我们就来了解下Glide是如何缓存图片的. 在上篇博文中我们知道,在初始化Glide对象时,GlideBuilder为我们配置了默认的缓存机制: Glide createGlide() { if (sourceService == null) { final int cores = Math.max(1, Runtime.getRuntime().availableProcessors()); sourceService = new

HBase源码分析之HRegion上compact流程分析(三)

        在<HBase源码分析之HRegion上compact流程分析(二)>一文中,我们没有讲解真正执行合并的CompactionContext的compact()方法.现在我们来分析下它的具体实现.         首先,CompactionContext表示合并的上下文信息,它只是一个抽象类,其compact()并没有实现,代码如下: /** * Runs the compaction based on current selection. select/forceSelect

WebGL 启动加载触发更新流程分析

WebGL 启动加载触发更新流程分析 太阳火神的美丽人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:太阳火神的美丽人生 -  本博客专注于 敏捷开发及移动和物联设备研究:iOS.Android.Html5.Arduino.pcDuino,否则,出自本博客的文章拒绝转载或再转载,谢谢合作. requestAnimFrame(tick); 此命令是 HTML5 中新增的用于替换定时器触发更新的命令,

Php中文件下载功能实现超详细流程分析_php技巧

客户端从服务端下载文件的流程分析: 浏览器发送一个请求,请求访问服务器中的某个网页(如:down.php),该网页的代码如下. 服务器接受到该请求以后,马上运行该down.php文件 运行该文件的时候,必然要把将要被下载的文件读入内存当中(这里是圣诞狂欢.jpg这张图片),这里通过fopen()函数完成该动作 注意:任何有关从服务器下载的文件操作,必然需要先在服务端将文件读入内存当中 现在文件已经在内存当中了,这是需要从内存当中读取文件,通过fread()函数完成该动作 需要注意的是,如果文件较

php实现文件下载功能的流程分析

客户端从服务端下载文件的流程分析: 浏览器发送一个请求,请求访问服务器中的某个网页(如:down.php),该网页的代码如下. 服务器接受到该请求以后,马上运行该down.php文件 运行该文件的时候,必然要把将要被下载的文件读入内存当中(这里是圣诞狂欢.jpg这张图片),这里通过fopen()函数完成该动作 代码:    代码如下 复制代码 <?php      header("Content-type:text/html;charset=utf-8");  //    $fi

A5营销团队:网站降权后处理流程分析(二)

中介交易 SEO诊断 淘宝客 云主机 技术大厅 在上一期的< A5营销团队:网站降权后处理流程分析(一)>中,我们对网站降权以及处理流程做了一个分析.本次A5营销团队(http://seo.admin5.com)贺贵江在站长网论坛整理了一些较为热点的优化问题,并做公益分享. 一:残留死链接降权 网站改版仅仅是对模板进行替换吗,需要注意一些什么呢?对此我们着重强调一点:谨慎修改URL结构.有些网站在改版中会对URL链接进行调整,甚至删除掉弃之不用的HTML页面.此类站点:修改页面较少基本不会产生

Cloudsim3_0仿真流程分析

Cloudsim3_0仿真流程分析 王燕妮 吴文辉 文章研究了Cloudsim3.0仿真软件的仿真流程,并结合实例进行说明. 关键词-Cloudsim3.0 仿真流程 Cloudsim3_0仿真流程分析