i2c触摸屏驱动文件的实现
转自:http://blog.chinaunix.net/uid-29507718-id-4314013.html
分类: LINUX
linux下触摸屏驱动的移植主要包括这几个步骤:
(1)确定触摸屏IC接口,了解对应接口的API函数,注册设备并加入到相应总线上
(2)关联设备与驱动,并编写具体的驱动代码
(3)熟悉linux 输入设备驱动,在驱动代码中分配一个输入设备并初始化相应数据结构,在驱动实现中引用
这里对应上面几部分,分析I2C接口下触摸屏驱动的实现。先介绍linux下I2C接口与输入子系统架构,然后基于FT5x0x源码逐层展开整个移植过程的实现。
一、I2C驱动架构
linux I2C驱动架构
具体的实现可分为四个层次:
1、提供adapter的硬件驱动,探测、初始化i2c adapter(如申请i2c的io地址和中断号),驱动soc控制的i2c adapter在硬件上产生信号(start、stop、ack)以及处理i2c中断。覆盖图中的硬件实现层。主要数据结构struct i2c_adapter
- struct i2c_adapter {
- struct module *owner;
- unsigned int id;
- unsigned int class;
- struct i2c_algorithm *algo;/* the algorithm to access the bus */
- void *algo_data;
- /* --- administration stuff. */
- int (*client_register)(struct i2c_client *);
- int (*client_unregister)(struct i2c_client *);
- /* data fields that are valid for all devices */
- struct mutex bus_lock;
- struct mutex clist_lock;
- int timeout;
- int retries;
- struct device dev; /* the adapter device */
- struct class_device class_dev; /* the class device */
- int nr;
- struct list_head clients;
- struct list_head list;
- char name[I2C_NAME_SIZE];
- struct completion dev_released;
- struct completion class_dev_released;
- };
这个结构体对应一个控制器。其中包含了控制器名称,algorithm数据,控制器设备等。
2、提供adapter的algorithm,用具体适配器的xxx_xferf()函数来填充i2c_algorithm的master_xfer函数指针,并把赋值后的i2c_algorithm再赋值给i2c_adapter的algo指针。覆盖图中的访问抽象层、i2c核心层。主要数据结构struct
i2c_algorithm
- struct i2c_algorithm {
- int (*master_xfer)(struct i2c_adapter *adap,struct i2c_msg *msgs,
- int num);
- int (*slave_send)(struct i2c_adapter *,char*,int);
- int (*slave_recv)(struct i2c_adapter *,char*,int);
- u32 (*functionality) (struct i2c_adapter *);
- };
这个结构体中定义了一套控制器使用的通信方法。其中关键函数是master_xfer()。实际工作中很重要一点就是要实现这个函数。
3、实现i2c设备驱动中的i2c_driver接口,由结构i2c_client中的数据填充,覆盖图中的driver驱动层。主要数据结构
- struct i2c_client {
- unsigned int flags; /* div., see below */
- unsigned short addr; /* chip address - NOTE: 7bit */
- /* addresses are stored in the */
- /* _LOWER_ 7 bits */
- struct i2c_adapter *adapter; /* the adapter we sit on */
- struct i2c_driver *driver; /* and our access routines */
- int usage_count; /* How many accesses currently */
- /* to the client */
- struct device dev; /* the device structure */
- struct list_head list;
- char name[I2C_NAME_SIZE];
- struct completion released;
- };
这个结构体中的内容是描述设备的。包含了芯片地址,设备名称,设备使用的中断号,设备所依附的控制器,设备所依附的驱动等内容。
4、实现i2c设备所对应的具体device的驱动。覆盖图中的driver驱动层。主要数据结构struct i2c_driver
- struct i2c_driver {
- int id;
- unsigned int class;
- int (*attach_adapter)(struct i2c_adapter *);
- int (*detach_adapter)(struct i2c_adapter *);
- int (*detach_client)(struct i2c_client *);
- int (*command)(struct i2c_client *client,unsigned int cmd, void *arg);
- struct device_driver driver;
- struct list_head list;
- };
这个结构体对应了驱动方法,重要成员函数有probe,remove,suspend,resume与中断处理函数,也是我们需要是实现的函数。另外包括一个重要的数据结构: struct i2c_device_id *id_table; 如果驱动可以支持好几个设备,那么这里面就要包含这些设备的ID。
第一层和第二层是i2c总线驱动,属于芯片内部的驱动,在linux驱动架构中已经实现,不需要我们编写或更改。第三第四属于i2c设备驱动,需要我们根据内核提供的接口去完成具体的代码。
另外就是i2c_core层,起到了承上启下的作用。源代码位于drivers/i2c/i2c-core.c中。在这里可以看到几个重要的函数。
(1)增加/删除i2c控制器的函数
- int i2c_add_adapter(struct i2c_adapter *adapter)
- int i2c_del_adapter(struct i2c_adapter *adap)
(2)增加/删除i2c设备的函数
- struct i2c_client *i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info);
- void i2c_unregister_device(struct i2c_client *client)
(3)增加/删除设备驱动的函数
- int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
- void i2c_del_driver(struct i2c_driver *driver)
(4)I2C传输、发送和接收函数
- int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
- int i2c_master_send(struct i2c_client *client,const char *buf ,int count);
- int i2c_master_recv(struct i2c_client *client, char *buf ,int count);
send和receive分别都调用了transfer函数,而transfer也不是直接和硬件交互,而是调用algorithm中的master_xfer()函数。
二、linux input输入子系统架构
linux输入系统框架
linux输入子系统(linux input subsystem)从上到下由三层实现,分别为:输入子系统事件处理层(Event Handler)、输入子系统核心层(Input Core)和输入子系统设备驱动层。这些层次里的具体机制我们先不涉及,而我们要知道输入子系统里有事件处理层,我们完成驱动时很主要的一点就是为输入设备定义一个符合要求的事件集合。另外,在图中可以看出输入设备不止包括触摸屏,还有很多其他种类的输入设备,如键盘,鼠标等等,所以linux内核已经把各式各样的输入设备进行了抽象,提供了统一的接口,让我们把设备接入到系统中。而我们要做的工作就是申请一个输入设备结构体对象,并填充其里面的数据。
把设备注册进输入子系统里一般要经过以下步骤:
1、申请一个输入设备,定义事件集合。关于输入事件的介绍可以看这里:Linux 内核点触摸接口协议
2、上报从设备中读到的数据。可使用函数
- void input_report_key(struct input_dev *dev, unsigned int code, int value); //上报按键事件
- void input_report_rel(struct input_dev *dev, unsigned int code, int value); //上报相对坐标事件
- void input_report_abs(struct input_dev *dev, unsigned int code, int value); //上报绝对坐标事件
三、基于OMAP FT5x0x驱动源码分析
1、板级初始化代码
板级初始化代码与具体的平台有关,负责相应平台的初始化工作,这里使用的pandaboard平台的代码,在目录arch/arm/mach-omap2/board-omap4panda.c中。触摸屏设备当然需要在这里先声明并注册进系统。具体代码如下:
- static struct i2c_board_info __initdata panda_i2c2_boardinfo[] = {
- {
- I2C_BOARD_INFO("ft5x06_ts", 0x38),
- .irq = OMAP_GPIO_IRQ(34),
- },
- };
- omap_register_i2c_bus(2, 100, panda_i2c2_boardinfo,ARRAY_SIZE(panda_i2c2_boardinfo));
声明一个i2c_board_info结构的数组,这个数组包含pandaboard板上i2c接口的信息。先使用宏I2C_BOARD_INFO宏声明设备名为ft5x06_ts,地址为0x38。要说明的是这里的地址并不是指处理器中i2c寄存器的硬件地址,而是在系统加载后,位于/sys/bus/i2c/devices下的设备名。再申请这个i2c接口的中断口为GPIO34,这从板的硬件连接图可以看出。
然后把这个结构体注册进i2c总线,使用omap_register_i2c_bus函数注册。
2、设备与驱动绑定
设备与驱动绑定的代码位于目录drivers/input/touchscreen/ft5x0x.c中,这个文件包含了i2c设备的具体代码,以模块的形式编译进内核。
- static const struct i2c_device_id ft5x0x_ts_id[] =
- {
- { FT5X0X_NAME, 0 },{ }
- };
- MODULE_DEVICE_TABLE(i2c, ft5x0x_ts_id);
- static struct i2c_driver ft5x0x_ts_driver =
- {
- .probe = ft5x0x_ts_probe,
- .remove = __devexit_p(ft5x0x_ts_remove),
- .id_table = ft5x0x_ts_id,
- .driver =
- {
- .name = FT5X0X_NAME,
- .owner = THIS_MODULE,
- },
- };
- static int __init ft5x0x_ts_init(void)
- {
- return i2c_add_driver(&ft5x0x_ts_driver);
- }
- static void __exit ft5x0x_ts_exit(void)
- {
- i2c_del_driver(&ft5x0x_ts_driver);
- }
- module_init(ft5x0x_ts_init);
- module_exit(ft5x0x_ts_exit);
- MODULE_AUTHOR("");
- MODULE_DESCRIPTION("FocalTech ft5x0x TouchScreen driver");
- MODULE_LICENSE("GPL");
首先建立设备与驱动的映射表ft5x0x_ts_id,通过宏MODULE_DEVICE_TABLE关联起来,MODULE_DEVICE_TABLE第一个参数表示这个设备id是i2c总线上了,第二个参数是指设备,当系统找到这个设备时,就会通过FT5X0X_NAME把设备与这个模块关联起来。
这是个i2c驱动模块,当然需要定义一个i2c_driver结构体来标识这个驱动,并说明实现的驱动函数有probe()和remove()函数。
之后就是添加模块初始化和退出函数,分别是在模块初始化时调用i2c_add_driver()加入i2c驱动,在模块退出时调用i2c_del_driver删除i2c驱动。
3、设备驱动程序实现
从上面i2c_driver结构可以看出,ft5x0x实现了驱动的两个接口函数,分别为probe()和remove()函数。
probe()具体实现函数为ft5x0x_ts_probe(),这个函数在内核初始化时,如果设备和驱动匹配,将调用,实现i2c设备的初始化,具体实现:
- static int ft5x0x_ts_probe(struct i2c_client *client, const struct i2c_device_id *id)
- {
- struct ft5x0x_ts_data *ft5x0x_ts;
- struct input_dev *input_dev;
- int err = 0;
- int rev_id = 0;
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
- err = -ENODEV;
- goto err_out;
- }
- ft5x0x_ts = kzalloc(sizeof(*ft5x0x_ts), GFP_KERNEL);
- if (!ft5x0x_ts) {
- err = -ENOMEM;
- goto err_free_mem;
- }
- this_client = client;
- i2c_set_clientdata(client, ft5x0x_ts);
- rev_id = i2c_smbus_read_byte_data(client, FT5X0X_REG_FT5201ID);
- if (rev_id != FT5X06_ID)
- {
- err = -ENODEV;
- dev_err(&client->dev, "failed to probe FT5X0X touchscreen device\n");
- goto err_free_mem;
- }
- INIT_WORK(&ft5x0x_ts->pen_event_work, ft5x0x_ts_pen_irq_work);
- ft5x0x_ts->ts_workqueue = create_singlethread_workqueue(dev_name(&client->dev));
- if (!ft5x0x_ts->ts_workqueue)
- {
- err = -ESRCH;
- goto err_free_thread;
- }
- err = request_irq(client->irq, ft5x0x_ts_interrupt, IRQF_DISABLED | IRQF_TRIGGER_RISING, "ft5x0x_ts", ft5x0x_ts);
- if (err < 0)
- {
- dev_err(&client->dev, "request irq failed\n");
- goto err_free_irq;
- }
- input_dev = input_allocate_device();
- if (!input_dev)
- {
- err = -ENOMEM;
- dev_err(&client->dev, "failed to allocate input device\n");
- goto err_free_input;
- }
- ft5x0x_ts->input_dev = input_dev;
- #ifdef CONFIG_FT5X0X_MULTITOUCH
- set_bit(ABS_MT_TOUCH_MAJOR, input_dev->absbit);
- set_bit(ABS_MT_POSITION_X, input_dev->absbit);
- set_bit(ABS_MT_POSITION_Y, input_dev->absbit);
- set_bit(ABS_MT_WIDTH_MAJOR, input_dev->absbit);
- set_bit(ABS_PRESSURE, input_dev->absbit);
- input_set_abs_params(input_dev,
- ABS_MT_POSITION_X, 0, SCREEN_MAX_X, 0, 0);
- input_set_abs_params(input_dev,
- ABS_MT_POSITION_Y, 0, SCREEN_MAX_Y, 0, 0);
- input_set_abs_params(input_dev,
- ABS_MT_TOUCH_MAJOR, 0, PRESS_MAX, 0, 0);
- input_set_abs_params(input_dev,
- ABS_MT_WIDTH_MAJOR, 0, 200, 0, 0);
- #else
- set_bit(ABS_X, input_dev->absbit);
- set_bit(ABS_Y, input_dev->absbit);
- set_bit(ABS_PRESSURE, input_dev->absbit);
- set_bit(BTN_TOUCH, input_dev->keybit);
- input_set_abs_params(input_dev, ABS_X, 0, SCREEN_MAX_X, 0, 0);
- input_set_abs_params(input_dev, ABS_Y, 0, SCREEN_MAX_Y, 0, 0);
- input_set_abs_params(input_dev, ABS_PRESSURE, 0, PRESS_MAX, 0 , 0);
- #endif
- set_bit(EV_ABS, input_dev->evbit);
- set_bit(EV_KEY, input_dev->evbit);
- input_dev->name = FT5X0X_NAME;
- err = input_register_device(input_dev);
- if (err)
- {
- dev_err(&client->dev, "failed to register input device: %s\n",
- dev_name(&client->dev));
- goto err_free_input;
- }
- #ifdef CONFIG_HAS_EARLYSUSPEND
- ft5x0x_ts->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
- ft5x0x_ts->early_suspend.suspend = ft5x0x_ts_suspend;
- ft5x0x_ts->early_suspend.resume = ft5x0x_ts_resume;
- register_early_suspend(&ft5x0x_ts->early_suspend);
- #endif
- return 0;
- err_free_input:
- input_free_device(input_dev);
- err_free_irq:
- free_irq(client->irq, ft5x0x_ts);
- err_free_thread:
- cancel_work_sync(&ft5x0x_ts->pen_event_work);
- destroy_workqueue(ft5x0x_ts->ts_workqueue);
- i2c_set_clientdata(client, NULL);
- err_free_mem:
- kfree(ft5x0x_ts);
- err_out:
- return err;
- }
这个函数代码比较长,但是可以分部分去看,每一部分对应不同的初始化工作.大概可以分为这几个部分:
(1)检测适配器是否支持I2C_FUNC_I2C的通信方式 :i2c_check_functionality(client->adapter, I2C_FUNC_I2C)
(2)申请内存存储驱动的数据:ft5x0x_ts = kzalloc(sizeof(*ft5x0x_ts), GFP_KERNEL);并把驱动数据赋值给系统传过来的i2c_client数据:this_client = client; i2c_set_clientdata(client, ft5x0x_ts);
(3)验证将要通信的设备ID:rev_id = i2c_smbus_read_byte_data(client, FT5X0X_REG_FT5201ID);
(4)创建触摸事件的工作队列并初始化工作队列的处理函数:INIT_WORK(&ft5x0x_ts->pen_event_work,
ft5x0x_ts_pen_irq_work); ft5x0x_ts->ts_workqueue =
create_singlethread_workqueue(dev_name(&client->dev));
(5)申请系统中断并声明中断处理函数;request_irq(client->irq, ft5x0x_ts_interrupt,
IRQF_DISABLED | IRQF_TRIGGER_RISING, "ft5x0x_ts", ft5x0x_ts);
(6)分配一个输入设备实例,初始化数据并注册进系统:input_dev = input_allocate_device(); input_register_device(input_dev);
(7)如果定义了earlysuspend,声明其处理函数。earlysuspend用于对触摸屏类设备的电源管理,降低功耗。
(8)最后对执行过程中可能出现的错误进行处理。
当有触摸动作时,触摸屏将会执行(5)中声明的中断处理函数ft5x0x_ts_interrupt,具体实现:
- static irqreturn_t ft5x0x_ts_interrupt(int irq, void *dev_id)
- {
- struct ft5x0x_ts_data *ft5x0x_ts = dev_id;
- if (!work_pending(&ft5x0x_ts->pen_event_work))
- queue_work(ft5x0x_ts->ts_workqueue, &ft5x0x_ts->pen_event_work);
- return IRQ_HANDLED;
- }
可以看到,中断处理就是在判断工作队列在没有被挂起的情况下在触摸时间加入到工作队列中去,等待工作队列处理函数ft5x0x_ts_pen_irq_work()的处理。ft5x0x_ts_pen_irq_work()的实现:
- static void ft5x0x_ts_pen_irq_work(struct work_struct *work)
- {
- int ret = -1;
- ret = ft5x0x_read_data();
- if (ret == 0)
- ft5x0x_report_value();
- }
概括来说这里只做了两件事:从设备中读取数据 ;把数据上报到输入子系统中。
(1)从设备中读取数据由函数ft5x0x_read_data()实现
- static int ft5x0x_read_data(void)
- {
- struct ft5x0x_ts_data *data = i2c_get_clientdata(this_client);
- struct ts_event *event = &data->event;
- u8 buf[32] = {0};
- int ret = -1;
- int status = 0;
- #ifdef CONFIG_FT5X0X_MULTITOUCH
- ret = ft5x0x_i2c_rxdata(buf, 31);
- #else
- ret = ft5x0x_i2c_rxdata(buf, 7);
- #endif
- if (ret < 0)
- {
- printk("%s read_data i2c_rxdata failed: %d\n", __func__, ret);
- return ret;
- }
- memset(event, 0, sizeof(struct ts_event));
- event->touch_point = buf[2] & 0x07;
- if (event->touch_point == 0)
- {
- ft5x0x_ts_inactivate();
- return 1;
- }
- #ifdef CONFIG_FT5X0X_MULTITOUCH
- switch (event->touch_point)
- {
- case 5:
- event->x5 = (s16)(buf[0x1b] & 0x0F)<<8 | (s16)buf[0x1c];
- event->y5 = (s16)(buf[0x1d] & 0x0F)<<8 | (s16)buf[0x1e];
- status = (s16)((buf[0x1b] & 0xc0) >> 6);
- event->touch_ID5=(s16)(buf[0x1D] & 0xF0)>>4;
- if (status == 1) ft5x0x_ts_release();
- case 4:
- event->x4 = (s16)(buf[0x15] & 0x0F)<<8 | (s16)buf[0x16];
- event->y4 = (s16)(buf[0x17] & 0x0F)<<8 | (s16)buf[0x18];
- status = (s16)((buf[0x15] & 0xc0) >> 6);
- event->touch_ID4=(s16)(buf[0x17] & 0xF0)>>4;
- if (status == 1) ft5x0x_ts_release();
- case 3:
- event->x3 = (s16)(buf[0x0f] & 0x0F)<<8 | (s16)buf[0x10];
- event->y3 = (s16)(buf[0x11] & 0x0F)<<8 | (s16)buf[0x12];
- status = (s16)((buf[0x0f] & 0xc0) >> 6);
- event->touch_ID3=(s16)(buf[0x11] & 0xF0)>>4;
- if (status == 1) ft5x0x_ts_release();
- case 2:
- event->x2 = (s16)(buf[9] & 0x0F)<<8 | (s16)buf[10];
- event->y2 = (s16)(buf[11] & 0x0F)<<8 | (s16)buf[12];
- status = (s16)((buf[0x9] & 0xc0) >> 6);
- event->touch_ID2=(s16)(buf[0x0b] & 0xF0)>>4;
- if (status == 1) ft5x0x_ts_release();
- case 1:
- event->x1 = (s16)(buf[3] & 0x0F)<<8 | (s16)buf[4];
- event->y1 = (s16)(buf[5] & 0x0F)<<8 | (s16)buf[6];
- status = (s16)((buf[0x3] & 0xc0) >> 6);
- event->touch_ID1=(s16)(buf[0x05] & 0xF0)>>4;
- if (status == 1) ft5x0x_ts_release();
- break;
- default:
- return -1;
- }
- #else
- if (event->touch_point == 1)
- {
- event->x1 = (s16)(buf[3] & 0x0F)<<8 | (s16)buf[4];
- event->y1 = (s16)(buf[5] & 0x0F)<<8 | (s16)buf[6];
- }
- #endif
- event->pressure = 200;
- dev_dbg(&this_client->dev, "%s: 1:%d %d 2:%d %d \n", __func__,
- event->x1, event->y1, event->x2, event->y2);
- return 0;
- }
从设备中读取数据使用ft5x0x_i2c_rxdata()函数:
- static int ft5x0x_i2c_rxdata(char *rxdata, int length)
- {
- int ret;
- struct i2c_msg msgs[] =
- {
- {
- .addr = this_client->addr,
- .flags = 0,
- .len = 1,
- .buf = rxdata,
- },
- {
- .addr = this_client->addr,
- .flags = I2C_M_RD,
- .len = length,
- .buf = rxdata,
- },
- };
- ret = i2c_transfer(this_client->adapter, msgs, 2);
- if (ret < 0)
- pr_err("msg %s i2c read error: %d\n", __func__, ret);
- return ret;
- }
这个函数里面会构建一个i2c_msg
msg结构去调用i2c_transfer()函数读取数据,在前面已经说过,i2c_transfer()函数最终调用的就是i2c_algorithm中master_xfer()函数进行实际的数据传输,这个函数在adapter驱动中实现。
对读取到的数据处理涉及到IC里面的数据格式,查找芯片的数据手册可以看到寄存器的数据分步。
ft5x0x寄存器映射表
这里为缩小篇幅,只截取一部分寄存器,其余寄存器格式可参照既给出的寄存器信息。
结合图片可以看出,代码先根据是否多点触摸,从寄存器读取数据长度,若是只需要单点触摸就读取7个字节信息,若是多点触摸,就读取31个字节的信息,从代码可以看出最多支持五点触摸。读出信息的第三个字节的低4位为触摸点数,所以event->touch_point
= buf[2] &
0x07;判断触摸点数之后便分别计算触摸点的坐标,这里以第一个点为例,其余点可以依此类推。第一个点的坐标信息包含在地址03h~06h中,坐标信息由12bit组成,分布在两个字节中,另外还包含flag标志信息,用于表示触摸点的状态,还包含触摸点的ID识别。
(2)把数据上报到输入子系统中由函数ft5x0x_report_value()实现
- static void ft5x0x_report_value(void)
- {
- struct ft5x0x_ts_data *data = i2c_get_clientdata(this_client);
- struct ts_event *event = &data->event;
- #ifdef CONFIG_FT5X0X_MULTITOUCH
- switch(event->touch_point)
- {
- case 5:
- input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, event->touch_ID5);
- input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
- input_report_abs(data->input_dev, ABS_MT_POSITION_X, SCREEN_MAX_X - event->x5);
- input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y5);
- input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1);
- input_mt_sync(data->input_dev);
- case 4:
- input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, event->touch_ID4);
- input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
- input_report_abs(data->input_dev, ABS_MT_POSITION_X, SCREEN_MAX_X - event->x4);
- input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y4);
- input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1);
- input_mt_sync(data->input_dev);
- case 3:
- input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, event->touch_ID3);
- input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
- input_report_abs(data->input_dev, ABS_MT_POSITION_X, SCREEN_MAX_X - event->x3);
- input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y3);
- input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1);
- input_mt_sync(data->input_dev);
- case 2:
- input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, event->touch_ID2);
- input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
- input_report_abs(data->input_dev, ABS_MT_POSITION_X, SCREEN_MAX_X - event->x2);
- input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y2);
- input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1);
- input_mt_sync(data->input_dev);
- case 1:
- input_report_abs(data->input_dev, ABS_MT_TRACKING_ID, event->touch_ID1);
- input_report_abs(data->input_dev, ABS_MT_TOUCH_MAJOR, event->pressure);
- input_report_abs(data->input_dev, ABS_MT_POSITION_X, SCREEN_MAX_X - event->x1);
- input_report_abs(data->input_dev, ABS_MT_POSITION_Y, event->y1);
- input_report_abs(data->input_dev, ABS_MT_WIDTH_MAJOR, 1);
- input_mt_sync(data->input_dev);
- default:
- break;
- }
- #else /* CONFIG_FT5X0X_MULTITOUCH*/
- if (event->touch_point == 1)
- {
- input_report_abs(data->input_dev, ABS_X, SCREEN_MAX_X - event->x1);
- input_report_abs(data->input_dev, ABS_Y, event->y1);
- input_report_abs(data->input_dev, ABS_PRESSURE, event->pressure);
- }
- input_report_key(data->input_dev, BTN_TOUCH, 1);
- #endif /* CONFIG_FT5X0X_MULTITOUCH*/
- input_sync(data->input_dev);
- dev_dbg(&this_client->dev, "%s: 1:%d %d 2:%d %d \n", __func__,
- event->x1, event->y1, event->x2, event->y2);
- }
因为触摸屏使用的是绝对坐标系,上报数据使用input_report_abs()函数,参数要注意选择合适的事件集。上报玩数据要记得同步,使用input_mt_sync()表示单个手指信息结束,使用input_sync()表示整个触摸动作的结束。
remove()函数的具体实现是ft5x0x_ts_remove(),做与probe()相反的工作,释放内存。
- static int __devexit ft5x0x_ts_remove(struct i2c_client *client)
- {
- struct ft5x0x_ts_data *ft5x0x_ts = i2c_get_clientdata(client);
- unregister_early_suspend(&ft5x0x_ts->early_suspend);
- free_irq(client->irq, ft5x0x_ts);
- input_unregister_device(ft5x0x_ts->input_dev);
- kfree(ft5x0x_ts);
- cancel_work_sync(&ft5x0x_ts->pen_event_work);
- destroy_workqueue(ft5x0x_ts->ts_workqueue);
- i2c_set_clientdata(client, NULL);
- return 0;
- }
至此,我们从i2c接口及输入子系统的接口清楚了整个触摸屏驱动的结构,并详细分析了触摸屏驱动中的具体实现。
i2c触摸屏驱动文件的实现的更多相关文章
- AM335x(TQ335x)学习笔记——触摸屏驱动编写
前面几篇文章已经通过配置DTS的方式完成了多个驱动的移植,接下来我们解决TQ335x的触摸驱动问题.由于种种原因,TQ335x的触摸屏驱动是以模块方式提供的,且Linux官方内核中也没有带该触摸屏的驱 ...
- i2c总线驱动,总线设备(适配器),从设备,从设备驱动的注册以及匹配
常用链接 我的随笔 我的评论 我的参与 最新评论 我的标签 随笔分类 ARM裸机(13) C(8) C++(8) GNU-ARM汇编 Linux驱动(24) Linux应用编程(5) Makefile ...
- 基于设备树的TQ2440触摸屏驱动移植
平台 开发板:tq2440 内核:Linux-4.9 u-boot:u-boot-2015.04 概述 之前移植了LCD驱动,下面继续移植触摸屏驱动,然后将tslib也移植上去. 正文 一.移植触 ...
- I2C总线驱动框架详解
一.I2C子系统总体架构 1.三大组成部分 (1)I2C核心(i2c-core):I2C核心提供了I2C总线驱动(适配器)和设备驱动的注册.注销方法,I2C通信方法(”algorithm”)上层的,与 ...
- 【6集iCore3_ADP触摸屏驱动讲解视频】6-1 工程及程序构架介绍
视频简介: 该视频由银杏科技有限公司基于iCore3应用开发平台推出,包含 触摸屏驱动工程文件的介绍与程序构架的介绍等. 源视频包下载地址: http://pan.baidu.com/s/1dFz ...
- S3C2440触摸屏驱动实例开发讲解
出处:http://www.embeddedlinux.org.cn/html/yingjianqudong/ 一.开发环境 主 机:VMWare--Fedora 9 开发板:Mini2440--6 ...
- mini2440触摸屏驱动分析
mini2440驱动分析系列之 ---------------------------------------Mini2440触摸屏程序分析 By JeefJiang July,8th,2009 这是 ...
- Linux I2C设备驱动编写(二)
在(一)中简述了Linux I2C子系统的三个主要成员i2c_adapter.i2c_driver.i2c_client.三者的关系也在上一节进行了描述.应该已经算是对Linux I2C子系统有了初步 ...
- Linux I2C设备驱动编写(一)
在Linux驱动中I2C系统中主要包含以下几个成员: I2C adapter 即I2C适配器 I2C driver 某个I2C设备的设备驱动,可以以driver理解. I2C client 某个I2C ...
随机推荐
- Non-negative Integers without Consecutive Ones
n位二进制,求不包含连续1的二进制(n位)数字个数. http://www.geeksforgeeks.org/count-number-binary-strings-without-consecut ...
- js DomContentLoaded 和 load 的区别
如题:DOMContentLoaded和load都是页面加载的时候触发的事件.区别在于触发的时机不一样. 浏览器渲染页面DOM文档加载的步骤: 1.解析HTML结构. 2.加载外部脚本和css文件. ...
- c#tcp源端口号和目的端口怎么理解
在一台机器上,一个进程对应一个端口.端口的作用就是用来唯一标识这个进程.源端口标识发起通信的那个进程,目的端口标识接受通信的那个进程.有了端口号,接受到报文后才能够知道将报文发送到哪个进程.
- Oracle_高级功能(7) 数据字典视图和动态性能视图
oracle数据字典 1.概念数据字典是oracle数据库用来存储数据库结构信息的地方.数据字典是用来描述数据库数据的组织方式的,由表和视图组成.数据字典基表是在任何 Oracle 数据库中创建的第一 ...
- RDMA的原理、传输与Verbs
RDMA的原理.传输与Verbs RDMA最早专属于infiniband架构.在网络融合的大趋势下出现的RoCE,使高速.超低延时.极低cpu使用率的RDMA得以部署在目前使用最广泛的以太网上. ...
- linux 使用笔记6
---恢复内容开始--- 1.内容追加 把一个文件的内容追加到另一个文件中: cat first.txt >> second.txt//追加到second.txt文件的末端 cat ...
- git分支切换时的时间戳问题
1.为什么git仓库没有保留文件修改时的时间戳? 摘自:https://git.wiki.kernel.org/index.php/Git_FAQ#Why_isn.27t_Git_preservin ...
- 10. pt-fk-error-logger
pt-fk-error-logger DSN 外键约束相关的,不关注.
- Spring ApplicationContext(六)BeanPostProcessor
Spring ApplicationContext(六)BeanPostProcessor 产生回顾一下 ApplicationContext 初始化的几个步骤:第一步是刷新环境变量:第二步是刷新 b ...
- java通过接口扩展枚举
package com.hra.riskprice; import com.hra.riskprice.SysEnum.Factor_Type; import com.hra.riskprice.po ...