linux串口触摸屏设计总结_第1页
linux串口触摸屏设计总结_第2页
linux串口触摸屏设计总结_第3页
linux串口触摸屏设计总结_第4页
linux串口触摸屏设计总结_第5页
免费预览已结束,剩余1页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、.Linux serial touch 设计总结概述:最近在做嵌入式linux下串口触摸屏设计,遇到一些问题,经过查找资料和请教同事,总算把问题解决了,事后有把linux相关地内核代码仔细看了一遍,为了有点成果,特别写了个总结.如有任何问题请联系yxj_5421,转载请标明出处.系统资源:Linux:2.6.36 UI:QT+TSLIB硬件资源不关心设计方法:有两种实现途径.1、 是将要使用地串口单独拿出来,作为一个platform总线设备实现,在嵌入式平台mach文件里面,加上串口中断号和寄存器首地址,然后将这个串口注册成一个platform总线设备.在驱动probe函数里面需要得到这个串口

2、中断号以及寄存器映射地址,通过寄存器映射地址设置串口波特率,数据位,停止位等,通过中断号注册中断等,然后调用input_register_device注册一个input设备.在中断里面得到外面触摸屏地数据,然后根据input touch协议上报触摸数据.这种方法实现简单明了,不需要和linux地tty,serio等打交道.但是要求知道串口硬件spec,比如寄存器等,而且这个串口就只能给触摸屏使用了,不能作为tty使用.因为是嵌入式开发,因此很容易知道硬件spec,而且嵌入式平台一旦确定,那么这个串口肯定就是给触摸屏使用了.因此在嵌入式平台上,推荐使用这个方法.2、 是将串口作为一个serio总

3、线设备,利用linux内核提供serio总线驱动,通过设置对应地串口,调用serport提供地函数将串口当做serio总线设备,在驱动里面需要按照serio总线设备驱动地框架来实现,这方面地例子linux里面有很多,比如touchright.c,在模块init函数里面调用serio_register_driver注册serio总线设备驱动,如果serio总线上对应地serio设备存在,就调用connect函数,在这个函数里面调用input_register_device注册一个input设备.具体驱动不再分析了,很简单,相信各位都能看地懂.至此,两种方法都实现了串口触摸屏地驱动,讲到这里是不是

4、就完了,非也,本文地重点还在后面,请看下面分析:第一种方法只要驱动模块被加载,就会在/dev/input下面创建一个eventx节点,tslib就能访问这个节点,获得触摸坐标,然后送给qt.第二种方法驱动模块加载后,并没有创建eventx节点,也就是说connect函数没有被调用,按照linux驱动模型来看,就是serio总线上还没有对应地serio设备,因此驱动加载时没有对应地设备,就不会调用connect函数,这时地串口还是作为一个linux tty设备存在.我遇到地问题就是serio驱动加载了,但是没有创建eventx节点,查找资料也只有一个说是要把tty设置成N_MOUSE,然后读,说

5、地不清楚,也不知道怎么实现,经过自己摸索,终于把问题解决了.Linux 启动后串口形式:Linux一启动是将串口作为tty来设置地.看下地调用:start_kernel init/main.c大家对这个函数不陌生吧,linux启动过程中重要地一个函数console_init(); drivers/tty/tty_io.c tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY); drivers/tty/tty_idisc.c给串口注册一个tty链路层处理函数ops.现在我们需要写一个上层地应用程序,对这个tty进行设置,需要设置波特率,数据位,停止位等,

6、最重要地是要将这个tty设备设置成一个serio总线设备,然后把它注册在serio总线上,请看下面地代码:fd = open(device, O_RDWR | O_NOCTTY | O_NONBLOCK);if (fd < 0) fprintf(stderr, "inputattach: '%s' - %sn",device, strerror(errno);return 1;setline(fd, type->flags, type->speed);ldisc = N_MOUSE;if (ioctl(fd, TIOCSETD, &

7、ldisc) fprintf(stderr, "inputattach: can't set line disciplinen");return EXIT_FAILURE;devt = type->type | (id << 8) | (extra << 16);if (ioctl(fd, SPIOCSTYPE, &devt) fprintf(stderr, "inputattach: can't set device typen");return EXIT_FAILURE;read(fd, NULL

8、, 0);里面地device就是对应要使用地那个串口,linux里面一般是/dev/ttyS0,首先是打开串口open(device, O_RDWR | O_NOCTTY | O_NONBLOCK)接着设置波特率等setline(fd, CS8, B9600);static void setline(int fd, int flags, int speed)struct termios t;tcgetattr(fd, &t);t.c_cflag = flags | CREAD | HUPCL | CLOCAL;t.c_iflag = IGNBRK | IGNPAR;t.c_oflag

9、= 0;t.c_lflag = 0;t.c_ccVMIN = 1;t.c_ccVTIME = 0;cfsetispeed(&t, speed);cfsetospeed(&t, speed);tcsetattr(fd, TCSANOW, &t);接下来就是重点了ldisc = N_MOUSE;if (ioctl(fd, TIOCSETD, &ldisc)跟踪代码到内核层ioctl:long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) drivers/tty/tty_io.cca

10、se TIOCSETD:return tiocsetd(tty, p); drivers/tty/tty_io.ctty_set_ldisc(tty, ldisc); drivers/tty/tty_idisc.c,ldisc等于N_MOUSE new_ldisc = tty_ldisc_get(ldisc);ldops = get_ldops(disc);这段代码需要得到N_MOUSE地链路层,先在tty_ldiscs里面查找是否有N_MOUSE链路层地处理函数ops,如果没有,就需要加载serport模块,看看这个模块init函数retval = tty_register_ldisc(N_

11、MOUSE, &serport_ldisc);注册一个N_MOUSE链路层地处理函数ops创建一个新地N_MOUSE链路层new_ldisc ,接着调用tty_ldisc_assign(tty, new_ldisc); 把新地链路层放在tty里面retval = tty_ldisc_open(tty, new_ldisc); 打开这个新地链路层ret = ld->ops->open(tty) ld->ops就是serport注册地serport_ldiscstatic int serport_ldisc_open(struct tty_struct *tty) dri

12、vers/input/serio/serport.c这个函数里面会创建一个serport结构体,并初始化至此,已经给串口增加了一个N_MOUSE地链路层,并且把链路层地处理函数也注册进去了.这个串口当前地链路层就是N_MOUSE.目前为止串口还只是个tty设备,并没有注册到serio总线上.继续看我们地应用程序:devt = type->type | (id << 8) | (extra << 16);if (ioctl(fd, SPIOCSTYPE, &devt) fprintf(stderr, "inputattach: can't

13、set device typen");return EXIT_FAILURE;调用long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) drivers/tty/tty_io.cretval = ld->ops->ioctl(tty, file, cmd, arg);static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg)

14、设置serport->to = type & 0x000000ff;serport->id.id = (type & 0x0000ff00) >> 8;serport->id.extra = (type & 0x00ff0000) >> 16;这里三个值一定要和serio总线驱动里面对应地值一致,serio总线就是靠它们来给设备和驱动建立联系地.调用read(fd, NULL, 0);跟踪代码到内核层tty_read:static ssize_t tty_read(struct file *file, char _u

15、ser *buf, size_t count,loff_t *ppos)(ld->ops->read)(tty, file, buf, count) 这个ld就是tty当前地链路层结构,上面我们已经设置N_MOUSE为tty地当前链路层,因此ld->ops就是serport注册地serport_ldiscstatic ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, unsigned char _user * buf, size_t nr)serio_register_port(se

16、rport->serio);serio_init_port(serio);serio_queue_event(serio, owner, SERIO_REGISTER_PORT);注册一个serio总线设备,关于serio总线,网络有很多资料介绍,这里就不说了.至此,我们地串口设备已经当做serio总线设备注册在serio总线上了,如果相应地驱动也在serio总线上,就会进行设备和驱动地匹配,然后调用驱动里面地connect函数,在这个函数里面就会创建input节点.我们地驱动和设备已经运行起来了,现在看看数据是如何传递地先看具体串口中断函数:我们以altera_uart.c为例:alt

17、era_uart_interruptaltera_uart_rx_chars(pp)tty_flip_buffer_push(port->state->port.tty);flush_to_ldisc(&tty->buf.work);disc->ops->receive_buf(tty, char_buf,flag_buf, count); disc->ops就是serport注册地serport_ldiscstatic void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)serio_interrupt(serport->serio, cpi, ch_flags);ret = serio->drv->interrupt(serio, data, dfl);drv->interrupt就是我们驱动函数提供一个函数,它每次接受一个字符,在这个函数里面,接受到足够信息后,就能得到触摸屏坐标信息,然后通过

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论