linuxUART串口驱动开发文档_第1页
linuxUART串口驱动开发文档_第2页
linuxUART串口驱动开发文档_第3页
linuxUART串口驱动开发文档_第4页
linuxUART串口驱动开发文档_第5页
已阅读5页,还剩9页未读 继续免费阅读

下载本文档

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

文档简介

linuxUART内容介绍:Linux下的串口驱动的设计层次及接口,TTY终端之间的关联层次(TTY终端使用Linux下的中断解决机制/中断共享机制,尚有串口缓冲机制当中涉及的软中断机制;w83697/w83977IC方面的知识,具体参考有关手册,对串口的配备寄存器有具体介绍,本文不再进行阐明.目录索引一Linux的串口接口及层次二Linux的中断机制及中断共享机制三Linux的软中断机制四TTY与串口的具体关联一Linux的串口接口及层次串口是使用已经非常广的设备了,linux下面的支持已经很完善了,含有统一的编程接口,IC来做完毕对应的配备宏,这此配备宏涉及读与写中断打开与关闭(如传送与接受中断接受状态解决有FIFO时还要解决FIFO的状态以下我们就首先切入这一部分IC有关的部分在驱动中的解决,这一部分能够说是串口驱动中的最基础部分直接与硬件打交道完毕最底层具体的串口数据传W83697:0x00001K空间.W839770x300000001K空间由于串口设备的特殊性,能够当作终端使用,但是终端的使用在内核尚未完全初始化之前(有关串口与终端的关联及层次在第四节中具体),mem_init()建立内核的虚存管理机制,因此不能通过ioreamp来进行物理内存到虚存的映射(物理内存必须由内核映射成系统管理的虚拟内存后才干进行读写访问这与先前所讲的framebuffer的物理内存映射是不同的,start_kernelrest_init→init(内核初始线程)do_basic_setupdo_initcalls→(Linux下用setup启动早期初始机制与initcallIO_BASE_VIRTIO_SIZE./*WhereinvirtualmemorytheIOdevices(timers,system*andsoon).Thisgetsusedinarch/arm/mach-ep93xx/mm.c.*/#defineIO_BASE_VIRT0xFF000000//VirtualaddressofIO#defineIO_BASE_PHYS0x80000000//PhysicaladdressofIO#defineIO_SIZE0x00A00000//Howmuch?完毕映射的函数是ep93xx_map_io全部要进行映射内存都在ep93xx_io_desc构造当中描文献linux-2.4.21/include/asm-arm/arch-ep93xx/regmap.h#defineIO_W83697_UART_BASE0x0000#defineIO_W83697_UART_SIZE0x1000#defineIO_W83977_UART_BASE0x30000000#defineIO_W83977_UART_SIZE0x1000#defineIO_SIZE_2(IO_SIZE+0x100000)#defineIO_BASE83697_VIRTIO_BASE_VIRT+IO_SIZE#defineIO_BASE83977_VIRTIO_BASE_VIRT+IO_SIZE_2ep93xx_map_ioarchstructmachine_descmdesc这个机器描述构造体,mach-ep93xxarch.c文献中以下宏完毕此构造的初始化:MACHINE_START(EDB9302,"edb9302")MAPIO(ep93xx_map_io初始化map_io=console_init调用之前,因此不会有问题,此种办4k一页,最后调用的是create_mapping(),mach_ep93xx/mm/→献中查找"."节的arm920_proc_infoprocess有关的操作函armARM内存管理的有关手册..section".",#alloc,.type.long.long.sizearm920_proc_info,.-/*pgtable.word.word.word以下,下面将详术以下,并指出其具体被使用的环境上下文<1>.读写数据#defineUART_PUT_CHAR(p,c)writeb((c),(p)->membase+W83697_UARTDR)<2>.接受发送状态#defineUART_GET_RSR(p)((readb((p)->membase+W83697_UARTRSR))&0xff)#defineUART_PUT_RSR(p,c)writeb((c),(p)->membase+W83697_UARTRSR)<3>.发送及接受中断状态#defineUART_GET_CR(p)((readb((p)->membase+W83697_UARTCR))&0xff)#defineUART_PUT_CR(p,c)writeb((c),(p)->membase+W83697_UARTCR)&0xff)<4>.以及其它的中断使能设立等,在传送时打开传送中断即会产生传送中断#defineUART_PUT_ICR(p,c)writeb((c),(p)->membase+<5>FIFO的状态与否读空/与否写满每次读时必须读至FIFO空写时必须等到FIFO不满时才干写(要等硬件传送完).status=while(UART_RX_DATA(status)&&max_count--)}发送中断写FIFO:当发送缓冲区中有数据要传送时置发送中断使能随即即产生传送中断此FIFO为空,FIFO大小的字节,如果发送缓冲区数据传完,则关闭发送中断.<6>.传送时可直接写串口数据口,而不使用中断,FIFO的状态do{status=}while(!UART_TX_READY(status));//waitfortxbuffernotLINUX中的中断共享支持.√串口时钟串口时钟用来转换计算须要设立到配备寄存器当中的波特率比值,其计算办法为:quot(port->uartclk(16*baud));baud115200等值取决于所选的串口时钟源,quot即为要设立到寄存器当中的比值.√串口基址,即串口全部配备寄存器基础址w83697的三个串口对应中断以下:uart1:00x3F8,uart2:00x2F8,uart3:00x3e8,uart4:00x3e8,EGPIO[8].w83977的两个串口对应中断以下:uart1:00x3F8,uart2:00x2F8,port的定义以下{.port=.membase=(void.mapbase=.iotype=.irqW83697_IRQ_UART4//.uartclk1846100,//uart时钟,默认.fifosize8,//fifo大小.ops&amba_pops,//底层驱动的硬件操作集,如开关中断等.flags=.line3,//0计起.dtr_mask=.rts_mask=}有关文献:linux-2.4.21/drivers/serial/core.c下面详述.函数w83697uart_rx_chars(structuart_port*portstructpt_regs描述:串口接受数据中断,此函数中应当注意的要点以下flip放在flag_buf_ptr当中,标志类型有TTY_NORMAL/TTY_PARITYTTY_FRAME等,据往上传输至终端终冲区,队列任务的机制将在背面介绍,它是一种异步执行机制,在函数staticvoidw83697uart_tx_chars(structuart_port描述串口发送数据中断发送中断中要做的事比较少,比起接受中断简朴了好多,注意事项以数据即退出uart_flush_chars()检测当没有数据要传输的时候,关闭传送中断,在传送之前与传送完之后都有检测WAKEUP_CHARS,则能够顺带介绍开关中断接口staticvoidw83697uart_start_tx(structuart_port*port,unsignedinttty_start)staticvoidw83697uart_stop_tx(structuart_port*port,unsignedinttty_stop)函数staticvoidw83697uart_int(intirq,void*dev_id,structpt_regs描述3分为以下几个接受中断传送中断其它不具体解决的中断,必须读对应寄存器清中断函数staticvoidw83697uart_int2(intirqvoid*dev_idstructpt_regs中断向量GPIO串口的参数,GPIOw83697uart_int2决函数staticintw83697uart_startup(structuart_port函数staticvoidw83697uart_shutdown(structuart_port描述:串口关闭函数,去除配备,半闭中断函数staticvoidw83697uart_change_speed(structuart_port*port,unsignedintcflag,unsignedintiflag,unsignedintquot)文献linux-这一层接口是串口驱动中的共用部分代码核心构造为structuart_driver这一层上承TTY终完毕structuart_amba_portamba_ports的.opsportuart_driver当中完毕关联,uart_add_one_port加入.staticintinit{intret,ret=uart_register_driver(&amba_reg);if(ret==0){for(i=0;i<UART_NR;i++)uart_add_one_port(&amba_reg,&amba_ports[i].port);}return}二Linux的中断机制及中断共享机制组当中的一项,structirqdescstructirqactionr的组员action,IBMdeveloperWorksstructirqactionvoid(*handler)(int,void*,structpt_regs*);unsignedlongflags;unsignedlongmask;constchar*name;void*dev_id;structirqaction从上面的构造体与图当中,我们就能够很清晰的看到,一种中断向量表能够对应一种irqaction,irqaction,这当中重要在安装中断的时候通过中断retval=request_irq(port->irq,w83697uart_int,0,"w83697_uart3",retval=request_irq(port->irq,w83697uart_int2,SA_SHIRQ,"w83977_uart5",port);由上即可知,安装共享中断时,只须指定安装的中断标志位flag为SA_SHIRQ进入分析安装三Linux的软中断机制LINUX内核本身应用非常的广它作为一种软性的异步执行机制,只有进一步能更加明白串口驱动某些问题,现在先提出几个问题以下:flip缓冲区当中,这样让人很容易进一步想懂得,的数据与否传送完毕?顾客空间的写串口进程处在什么样的状态?如果是写完缓冲区U使用率,那么何时才应当醒过来?由谁负责醒过来?根据以上这两个问题,我们来进一步代码分析,首先看接受缓冲区中的数据如何上传,前面已tty_flip_buffer_push(),这个函数完毕的功效就是voidtty_flip_buffer_push(structtty_struct{if(tty->low_latency)flush_to_ldisc((void*)tty);queue_task(&tty->flip.tqueue,}tq_timer的执行途径分析tq_timer是一种双链表构造任务队列,每项任务包含一种函数指针组员,它通过run_task_queue每次将当中的全部任务(其实是某些函数指针)全部调用一次,然后清空队列,tq_timertqueue_bh中执行,以下:void{}在voidinitsched_init(void)当中初始化底半的向量如,tqueue_bh初始化在bh_base的init_bh(TIMER_BH,timer_bh);init_bh(TQUEUE_BH,tqueue_bh);init_bh(IMMEDIATE_BH,immediate_bh);voidinit_bh(intnr,void(*routine)(void)){bh_base[nr]=routine;}staticvoidbh_action(unsignedlongnr){…if(bh_base[nr])…}bh_basebh,意即中断底半所做的事tq_timer调用的任务tasklet机制,背面将进行简朴介绍.voidinitsoftirq_init(){intfor(i=0;i<32;i++)tasklet_init(bh_task_vec+i,bh_action,i);}do_timer()mark_bh(TIMER_BH),来激时钟taskletbh_task_vecbh_action.staticinlinevoidmark_bh(intnr){}tasklet的机制简朴分析structvoid(*action)(structsoftirq_action*);void*data;staticstructsoftirq_actionsoftirq_vec[32cacheline_aligned软中断的中断向量[1].初始化软中断向量中断,但是各处所完毕的功效不同,因此分在两个软中断完毕,背面我们仅取其中用于执行时HI_SOFTIRQ为例进行解说,tasklet有关机制,这两项软中断的实始化以下:voidinit{open_softirq(TASKLET_SOFTIRQ,tasklet_action,NULL);open_softirq(HI_SOFTIRQ,tasklet_hi_action,NULL);}open_softirq下所做的事相称简朴,即往软中断向量中赋值,voidopen_softirq(intnr,void(*action)(structsoftirq_action*),void{softirq_vec[nr].data=data;softirq_vec[nr].action=action;}[2].HI_SOFTIRQtasklet_hi_action由上文所讲的初始化过程给NR_CPUS=1.structtasklet_headtasklet_hi_vec[NR_CPUS]cacheline_aligned;[3].tasklettasklet,加在尾部.voidtasklet_hi_schedule(structtasklet_struct{…t->next=tasklet_hi_vec[cpu].list;tasklet_hi_vec[cpu].list=t;cpu_raise_softirq(cpu,HI_SOFTIRQ);…}#definecpu_raise_softirq(cpu,nr)do{softirq_pending(cpu)|=1UL<<(nr);}while(0)[4].软中断所依赖的执行机制讲到最后还没有指出软中断是如何触发执行的,其实很简朴ksoftirqd(),这个线程解决软中断级别是比较do_softirq()中有以下的判断,以决定与否有软中断须要执行,如果没有就直接退出,在[3]中提到的激活软中断时32pending=softirq_pending(cpu);if(pending){}do321的…if(pending&1)pending>>=}while[4].软中断所依赖的执行时期问题if(in_interrupt())/*Areweinaninterruptcontext?Eitherdoingbottom*orhardwareinterrupt#definein_interrupt()({constintcpu=smp_processor_id();(local_irq_count(cpu)+local_bh_count(cpu)!=0);})/*softirq.hissensitivetotheoffsetsofthesefields*/typedefstruct{unsignedintsoftirq_pending;unsignedintlocal_irq_count;unsignedintlocal_bh_count;unsignedintsyscall_count;structtask_struct*ksoftirqd_task;/*waitqueueistoolarge} cacheline_aligned#defineirq_enter(cpu,irq)(local_irq_count(cpu)++)#defineirq_exit(cpu,irq)(local_irq_count(cpu)--)看到这里,不得不再多注意一种构造,那就是irq_cpustat_t先前我们讲与否有软中断产生的标志位,但没有提到softirq_pending32一种软中断对应一种位;do_softirq中有以下几个重要的动作,阐明以下:,irq_exit表达已经完毕解决;pending判断与否有软中断须要解决,每个位用作当作一种软中断与否产生的标志去除全部软中断标志位,由于下面即将解决;但去除之前先缓存起来,由于下面还要使打开硬件中断,让软中断在有硬件中断的环境下执行刻解决本次软中断过程未发生过的软中断向量.之因此会有新的软中断产生,那是由于软中断是在开硬件中断的状况下执行,硬件中断解决是可能又产生了新的软中断.之因asmlinkagevoid{intcpu=u32pending;unsignedlongflags;u32if(in_interrupt())return;pending=softirq_pe

温馨提示

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

评论

0/150

提交评论