触摸屏驱动分析

来源:互联网 发布:maxwell仿真软件 编辑:程序博客网 时间:2024/06/11 12:23

一:前言

之前看过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便会被调用。

原创粉丝点击