现在主要谈谈编写s3c2410的触摸屏驱动的收获。模仿已有的驱动自己也写了一个驱动,实现同样的功能。同时为了完成这个驱动,把LDD2 这本书相关部分好好的读了一遍,获益匪浅。
先看看为了完成一个驱动,需要作的事吧。
1. 看datasheet,说白了芯片user manual,对于触摸屏,那些寄存器是主要的关注点,如ADCCON,ADCTSC…..,这些寄存器均会在驱动中使用,驱动也是全凭这些寄存器才完成与硬件的通信。这步很关键的说,虽然只用了了几笔!
2. 接下来应该先熟悉一下驱动中都需要定义些什么接口,如read,write,open,release,这些是基本的。见多了就不怪了,其实就是那些为上层(用户层)预留了访问内核数据的接口,比如此驱动,我在用户层调用用户层的read函数读取数据时,实际上就是在调用内核层(驱动属于内核层)的read来完成读操作。
3. 中断,中断,上课时看似没用的东西,现在用到了吧。啥叫中断,在此不表。怎么实现中断?还记得中断服务程序吗,就是它了。在程序的初始化函数(init)中,先使用ret=request_IRQ(IRQ_ADC_DONE,adc_isr_handler,SA_INTERRUPT,DEVICE_NAME,NULL);申请一个ADC中断,然后调用adc_isr_handler这个中断服务程序,这个程序完成了触摸屏控制器的模数转换,取得寄存器中的x,y值。不过千万别忘了在模块卸载(exit)的时候将中断释放掉,否则的话,很快中断申请线的资源就被占尽了。
4. 调试程序,呵呵,print啊,不过这里是在编驱动,千万别用printf啊,为啥?丢不起这个人啊!内核编程怎能用C函数库的函数?应该用printk!使用打印信息的方法方便实用,再加上一些宏定义开启关闭调试信息的功能,perfect!还有其他的调试方法,不过看过书了不知所云,有待钻研。
5. 还用高级的字符驱动需要的阻塞型I/O,就是等待队列,休眠进程,唤醒进程。。。(偶还没太明白,先写这么几句!)
6. 看似简单的驱动阿,学问咋那么多呢。要真正完成触摸屏的驱动还需要时间流着部分知识,咋地也要让咱的屏屏能进行个识别输入的字母吧。现在我还在调他,本打算调通之后再来完成此篇文章,看来是奢望了。继续调~~
下面我的驱动和 测试 程序就要粉墨登场了,鉴于驱动只完成到可以挂载到内核之上,并不能实现最终的功能,在此就只展出部分,等到全部完成时,就是它与大家见面之曰。
程序片断1:触摸屏驱动
触摸屏的设备数据结构:
typedef struct{
unsigned int penStatus;
TS_RET buf[MAX_TS_BUF];
unsigned int head,tail;
wait_queue_head_t wq;
sPINLOCk_t lock;
}TS_DEV;
下面这两个函数是双胞胎阿,一读一写,文武双全。。。
static int read_xy(TS_RET * ts_ret)
{
spin_lock_irq(&(tsdev.lock));
ts_ret->x = tsdev.buf[tsdev.tail].x;
ts_ret->y = tsdev.buf[tsdev.tail].y;
ts_ret->pressure = tsdev.buf[tsdev.tail].pressure;
tsdev.tail = INCBUF(tsdev.tail, MAX_TS_BUF);
spin_unlock_irq(&(tsdev.lock));
return sizeof(TS_RET);
}
static void ts_write_buf(void)
{
if(tsdev.penStatus==PEN_DOWN)
{
tsdev.buf[tsdev.head].x = x;
tsdev.buf[tsdev.head].y = y;
tsdev.buf[tsdev.head].pressure = PEN_DOWN;
}else{
tsdev.buf[tsdev.head].x = 0;
tsdev.buf[tsdev.head].y = 0;
tsdev.buf[tsdev.head].pressure = PEN_UP;
}
}
下面就是所谓的GNU C对标准C的一种扩展,叫做标记方法的初始化,这是真的,谁在windows下见过这样的写法。
statIC struct file_operations s3c2410_ts_fops={
owner: THIS_MODULE,
open: s3c2410_ts_open,
read: s3c2410_ts_read,
release: s3c2410_ts_release,
};
下面就是所谓的显式的初始化和清除函数,天啊,这个名字是翻书找的。看看里面的东西是不是和我的第一篇心得说的一样??不一样就见鬼了。
static devfs_handle_t devfs_ts_dir,devfs_tsraw; //public paramter
static int __init s3c2410_ts_init(void)
{
int ret;
/*************************/
ret=register_chrdev(ts_major,DEVICE_NAME,&s3c2410_ts_fops);
if(ret<0){
printk(KERN_WARNING "scull: CAN''''t get major %d\n",ts_major);
return ret;
}
if(ts_major == 0 )
ts_major=ret;
set_gpio_CTRl(GPIO_YPON);
set_gpio_ctrl(GPIO_YMON);
set_gpio_ctrl(GPIO_XPON);
set_gpio_ctrl(GPIO_XMON);//这篇文章第一条谈到的,就是看UM(user manual)得到的
/**************************/
#ifdef CONFIG_DEVFS_FS
devfs_ts_dir = devfs_mk_dir(NULL,"touchpanel",NULL);
devfs_tsraw = devfs_register(devfs_ts_dir,"indev", DEVFS_FL_DEFAULT, ts_major, 1, S_IFCHR | S_IRUSR | S_IWUSR, &s3c2410_ts_fops,NULL);
printk(DEVICE_NAME "initialized!\n");
printk( DEVICE_NAME " module init ok!\n");
#endif
/***************************/
//中断申请在什么时候? A: 就在init函数中
ret=request_IRQ(IRQ_ADC_DONE,adc_isr_handler,SA_INTERRUPT,DEVICE_NAME,NULL);
if(ret){
printk(KERN_INFO "adc: can''''t get assigned irq %d\n!",IRQ_ADC_DONE); //62
return ret;
}
ret = request_irq(IRQ_TC,tc_isr_handler,SA_INTERRUPT,DEVICE_NAME,NULL);
if(ret){
printk(KERN_INFO "tc: can''''t get assigned irq %d\n!",IRQ_TC);
return ret;
}
}
static int __exit s3c2410_ts_exit(void)
{
#ifdef CONFIG_DEVFS_FS
devfs_unregister(devfs_tsraw);
devfs_unregister(devfs_ts_dir);
//上面这两个顺序能颠倒一下吗,试一试吧
#endif
unregister_chrdev(ts_major,DEVICE_NAME);
//注销中断
free_IRQ(IRQ_TC,NULL);
free_irq(IRQ_ADC_DONE,NULL);
}
程序2 :触摸屏驱动 测试 程序
#include
#include
#include
#define DEVICENAME "/dev/touchpanel/indev"
typedef struct ts_event {
unsigned short pressure;
unsigned short x;
unsigned short y;
unsigned short pad;
}ts_event;
void main(void)
{
int ts_fd,ret;
int x_raw,y_raw;
ts_event *ts_evt;
ts_fd = open(DEVICENAME,0);
if(!ts_fd)
{
perror("ts_open :");
exit(1);
}
ts_evt=malLOC(sizeof(ts_event));
MEMSet(ts_evt, 0, sizeof(struct ts_event));
while(1)
{
ret = read(ts_fd, ts_evt, sizeof(*ts_evt));
if(ret>0){
printf("x: %d\n", ts_evt->x);
printf("y: %d\n", ts_evt->y);
printf("pressure: %d\n", ts_evt->pressure);
}
else {
perror("read the raw data :");
exit(1);
}
}
close(ts_fd);
free(ts_evt);
}