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

下载本文档

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

文档简介

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

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

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

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

5、说的不清楚,也不知道怎么实现,经过自己 摸索,终于把问题解决了。Lin ux启动后串口形式:Linux 启动是将串口作为tty来设置的。看下的调用:start_kernelinit/main.c大家对这个函数不陌生吧,linux启动过程中重要的一个函数con sole_ in it();drivers/tty/tty_io.ctty_register_ldisc(N_TTY, &tty_ldisc_N_TTY); drivers/tty/tty_idisc.c给串口注册一个tty链路层处理函数ops。Source hl«s involved in serial managem

6、ent how they are connected and how flows.00000/L o o o o /停serio 总现在我们需要写一个上层的使用程序,对这个tty进行设置,需要设置波特率,数据位,止位等,最重要的是要将这个tty设备设置成一个serio总线设备,然后把它注册在线上,请看下面的代码:fd = ope n( device, O_RDWR | O_NOCTTY | O_NONBLOCK);if (fd < 0) fprintf(stderr, "inputattach: '%s' - %sn", device, strerro

7、r(errno);return 1;setline(fd, type_>flags, type->speed);ldisc = N_MOUSE;if (ioctl(fd, TIOCSETD, &ldisc) fprintf(stderr, "inputattach: can't set line disciplinen”); return EXIT_FAILURE;devt = type->type | (id << 8) | (extra << 16);if (ioctl(fd, SPIOCSTYPE, & devt

8、) fprin tf(stderr, "in putattach: can't set device typen"); return EXIT_FAILURE;read(fd, NULL, 0);里面的device就是对应要使用的那个串口,linux里面一般是/dev/ttySO,首先是打开串口ope n( device, O_RDWR | O_NOCTTY | O_NONBLOCK)接着设置波特率等setline(fd, CS8, B9600);static void setl in e(i nt fd, int flags, int speed)struct t

9、ermios t;tcgetattr(fd, &t);t.c_cflag = flags | CREAD | HUPCL | CLOCAL;t.c_iflag = IGNBRK | IGNPAR;t.c_oflag = 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, &am

10、p;ldisc)跟踪代码到内核层ioctl:long tty_ioctl(struct file *file, un sig ned int cmd, un sig ned long arg) drivers/tty/tty_io.ccase TIOCSETD:return tiocsetd(tty, p); drivers/tty/tty_io.c tty_set_ldisc(tty, ldisc); drivers/tty/tty_idisc.c , ldisc 等于 N_MOUSE n ew_ldisc = tty_ldisc_get(ldisc);ldops = get_ldops(d

11、isc);这段代码需要得到N_MOUSE的链路层,先在tty_ldiscs里面查找是否有 N_MOUSE链路层的处理函数ops,如果没有,就需要加载serport模块,看看这个模块init函数retval = tty_register_ldisc(N_MOUSE, &serport_ldisc);注册一个N_MOUSE链路层的处理函数ops创建一个新的 N_MOUSE链路层new_ldisc,接着调用tty_ldisc_assign(tty, new_ldisc);把新的链路层放在 tty 里面retval = tty_ldisc_ope n( tty, n ew_ldisc); 打开

12、这个新的链路层ret = ld->ops->open(tty)ld->ops 就是 serport 注册的 serport_ldiscstatic int serport_ldisc_ope n( struct tty_struct *tty) drivers/i nput/serio/serport.c这个函数里面会创建一个serport结构体,并初始化至此,已经给串口增加了一个N_MOUSE的链路层,并且把链路层的处理函数也注册进去了。这个串口当前的链路层就是N_MOUSE。目前为止串口还只是个 tty设备,并没有注册到serio总线上。继续看我们的使用程序:devt =

13、 type->type | (id << 8) | (extra << 16);if (ioctl(fd, SPIOCSTYPE, & devt) fprin tf(stderr, "in putattach: can't set device typen");return EXIT_FAILURE;调用long tty_ioctl(struct file *file, un sig ned int cmd, un sig ned long arg) drivers/tty/tty_io.cretval = ld->ops

14、->ioctl(tty, file, cmd, arg);static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, un sig ned int cmd, un sig ned long arg)设置serport->to = type & OxOOOOOOff;serport->id.id = (type & OxOOOOffOO) >> 8; serport->id.extra = (type & OxOOffOOOO) &g

15、t;> 16;这里三个值一定要和 serio总线驱动里面对应的值一致,serio总线就是靠它们来给设备和驱动建立联系的。调用read(fd, NULL, 0);跟踪代码到内核层 tty_read :static ssize_t tty_read(struct file *file, char _user *buf, size_t count,loff_t *ppos)(ld->ops->read)(tty, file, buf, count) 这个ld就是tty当前的链路层结构,上面我们已 经设置N_MOUSE为tty的当前链路层,因此 ld->ops就是serport

16、注册的serport_ldiscstatic ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, un sig ned char _user* buf, size_t nr)serio_register_port(serport->serio);serio_ ini t_port(serio); serio_queue_eve nt(serio, owner, SERIO_REGISTER_PORT);注册一个serio总线设备,关于serio总线,网络有很多资料介绍,这里就不说了。 至此,我们的

17、串口设备已经当做serio总线设备注册在serio总线上了,如果相应的驱动也在serio总线上,就会进行设备和驱动的匹配,然后调用驱动里面的connect函数,在这个函数里面就会创建in put节点。我们的驱动和设备已经运行起来了,现在看看数据是如何传递的 先看具体串口中断函数:我们以altera_uart.c为例:altera_uart_i nterruptaltera_uart_rx_chars(pp) tty_flip_buffer_push(port->state->port.tty);flush_to_ldisc(&tty->buf.work);disc-&

18、gt;ops->receive_buf(tty, char_buf,flag_buf, count); disc->ops 就是 serport 注册的 serport_ldisc static void serport_ldisc_receive(struct tty_struct *tty, const un sig ned char*cp, char *fp, int count)serio_i nterrupt(serport->serio, cpi, ch_flags); ret = serio->drv ->in terrupt(serio, data, dfl);drv->interrupt就是我们驱动函数提供一个函数,它每次接受一个字符,在这个函数里面,接受到足够信息后,就能得到触摸屏坐标信息,然后通过input_report上报上去。看看数据处理流程图:Data flow and function

温馨提示

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

评论

0/150

提交评论