博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
触摸屏驱动分析
阅读量:4102 次
发布时间:2019-05-25

本文共 4513 字,大约阅读时间需要 15 分钟。

一:前言

之前看过s3c2440上的触摸屏驱动,不过那个是电阻的。现在手机上用的都是电容式的。触摸屏相对来说还是属于比较简单的模块,拿龙歌的话来说都是属于入门级的。我大概看了一下代码,总的代码好像是不多,但里面所涉及到的东西好像还挺多的。1.I2C驱动;2.中断-工作队列;3.input子系统

二:I2C驱动回顾

按照华清的那本《linux设备驱动开发详解》上面讲的来看I2C驱动分 I2C核心;I2C总线驱动;I2C设备驱动。在我所处的环境当中I2C核心和总线驱动已经是做好了,我所要添加的触摸屏属于一个I2C设备驱动。

1.所涉及数据结构: i2c_driver,i2c_client ,i2c_adapter ,i2c_algorithm ,他们的具体定义都在i2c.h当中。i2c_adapter 对应于物理上的一个适配器,而i2c_algorithm对应一套通信方法。一个I2C适配器需要i2c_algorithm中提供的通信函数来控制适配器上产生特定的访问周期。缺少 i2c_algorithm 的 i2c_adapter 什么也做不了,因此 i2c_adapter 中包含其使用的i2c_algorithm的指针。 i2c_algorithm则是I2C适配器与I2C设备通信方法的描述。i2c_driver 对应一套驱动方法,是纯粹的用于辅助作用的数据结构,它不对应于任何的物理实体。i2c_client对应于真实的物理设备,每个 I2C设备都需要一个i2c_client来描述。 i2c_client 则是对应一个具体的i2c设备,它里面还包含i2c_driver 和i2c_adapter ,这样三者也都联系在一起了。
struct i2c_driver {
unsigned int class;
int (*attach_adapter)(struct i2c_adapter *);
int (*detach_adapter)(struct i2c_adapter *);
/* Standard driver model interfaces */
int (*probe)(struct i2c_client *, const struct i2c_device_id *);
int (*remove)(struct i2c_client *);
/* driver model interfaces that don't relate to enumeration  */
void (*shutdown)(struct i2c_client *);
int (*suspend)(struct i2c_client *, pm_message_t mesg);
int (*resume)(struct i2c_client *);
void (*alert)(struct i2c_client *, unsigned int data);
int (*command)(struct i2c_client *client, unsigned int cmd, void *arg);
struct device_driver driver;
const struct i2c_device_id *id_table;
/* Device detection callback for automatic device creation */
int (*detect)(struct i2c_client *, struct i2c_board_info *);
const unsigned short *address_list;
struct list_head clients;
};
struct i2c_client {
unsigned short flags;/* div., see below */
unsigned short addr;/* chip address - NOTE: 7bit */
/* addresses are stored in the*/
/* _LOWER_ 7 bits*/
char name[I2C_NAME_SIZE];
struct i2c_adapter *adapter;/* the adapter we sit on */
struct i2c_driver *driver;/* and our access routines */
struct device dev;/* the device structure */
int irq; /* irq issued by device */
struct list_head detected;
};
struct i2c_adapter {
struct module *owner;
unsigned int id;
unsigned int class; /* classes to allow probing for */
const struct i2c_algorithm *algo; /* the algorithm to access the bus */
void *algo_data;
/* data fields that are valid for all devices*/
struct rt_mutex bus_lock;
int timeout; /* in jiffies */
int retries;
struct device dev;/* the adapter device */
int nr;
char name[48];
struct completion dev_released;
struct list_head userspace_clients;
};
struct i2c_algorithm {
int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs,
  int num);
int (*smbus_xfer) (struct i2c_adapter *adap, u16 addr,
  unsigned short flags, char read_write,
  u8 command, int size, union i2c_smbus_data *data);
/* To determine what the adapter supports */
u32 (*functionality) (struct i2c_adapter *);
};
2-1 :
board-xxx.c里面定义i2c_board_info
static struct i2c_board_info i2c_devices[] = {
#ifdef CONFIG_QT602240
{
I2C_BOARD_INFO(ATMEL_QT602240_NAME, 0x94 >> 1),
.platform_data = &supersonic_atmel_ts_data,
.irq = MSM_GPIO_TO_INT(SUPERSONIC_GPIO_TP_INT_N)
},
#endif
}可以看到这里面包含设备名字,设备地址,所用的中断引脚,还有一个platform_data的成员,这个所含的信息就多了,由我们自己定义。
xxx-init函数中将i2c_board_info注册上。
i2c_register_board_info(0, i2c_devices, ARRAY_SIZE(i2c_devices));
查看i2c_register_board_info的实现可知它创建了一个devinfo然后将它挂在了__i2c_board_list链表上。
2-2:
touch-xxx.c具体的TP设备驱动文件。
定义i2c_driver。
static struct i2c_driver atmel_ts_driver = {
.id_table = atml_ts_i2c_id,
.probe = atmel_ts_probe,
.remove = atmel_ts_remove,
#ifndef CONFIG_HAS_EARLYSUSPEND
.suspend = atmel_ts_suspend,
.resume = atmel_ts_resume,
#endif
.driver = {
.name = ATMEL_QT602240_NAME,
},
};
首先当然是从module_init函数看起:
static int __devinit xxx_init(void)
{
printk(KERN_INFO "atmel_ts_init():\n");
return i2c_add_driver(&atmel_ts_driver);
}
通常看完init函数就看它的probe函数,这是从平台设备驱动的架构得来的经验,至于这其间的具体过程就留到后面来分析吧!

三:中断-工作队列 相关

3.1 创建一个单个工作者线程的工作队列 

ts->atmel_wq = create_singlethread_workqueue("atmel_wq");
3-2 初始化一个工作
INIT_WORK(&ts->work, atmel_ts_work_func);
atmel_ts_work_func这个函数就是最后给用户空间报数据的。
3-3 申请中断
ret = request_irq(client->irq, atmel_ts_irq_handler,  IRQF_TRIGGER_LOW,
client->name, ts);
当触屏有人按下的时候,便会触发中断,从而调用 atmel_ts_irq_handler函数。
static irqreturn_t atmel_ts_irq_handler(int irq, void *dev_id)
{
struct atmel_ts_data *ts = dev_id;
// printk(KERN_INFO "LiuQi in irq enter %s %d\n", __func__, __LINE__);
disable_irq_nosync(ts->client->irq);
queue_work(ts->atmel_wq, &ts->work);
//printk(KERN_INFO "LiuQi in irq out %s %d\n", __func__, __LINE__);
return IRQ_HANDLED;
}
这个函数里面就是将上面所创建的工作加入到工作队列中,此后工作对应的函数atmel_ts_work_func便会被调用。

转载地址:http://lzbsi.baihongyu.com/

你可能感兴趣的文章
深究Java中的RMI底层原理
查看>>
用idea创建一个maven web项目
查看>>
Kafka
查看>>
9.1 为我们的角色划分权限
查看>>
维吉尼亚之加解密及破解
查看>>
DES加解密
查看>>
TCP/IP协议三次握手与四次握手流程解析
查看>>
PHP 扩展开发 : 编写一个hello world !
查看>>
inet_ntoa、 inet_aton、inet_addr
查看>>
用模板写单链表
查看>>
用模板写单链表
查看>>
链表各类操作详解
查看>>
C++实现 简单 单链表
查看>>
数据结构之单链表——C++模板类实现
查看>>
Linux的SOCKET编程 简单演示
查看>>
正则匹配函数
查看>>
Linux并发服务器编程之多线程并发服务器
查看>>
聊聊gcc参数中的-I, -L和-l
查看>>
[C++基础]034_C++模板编程里的主版本模板类、全特化、偏特化(C++ Type Traits)
查看>>
C语言内存检测
查看>>