Linux内核TTY驱动架构.pdf

上传人:wj 文档编号:3437362 上传时间:2023-05-05 格式:PDF 页数:14 大小:371.92KB
下载 相关 举报
Linux内核TTY驱动架构.pdf_第1页
第1页 / 共14页
Linux内核TTY驱动架构.pdf_第2页
第2页 / 共14页
Linux内核TTY驱动架构.pdf_第3页
第3页 / 共14页
Linux内核TTY驱动架构.pdf_第4页
第4页 / 共14页
Linux内核TTY驱动架构.pdf_第5页
第5页 / 共14页
Linux内核TTY驱动架构.pdf_第6页
第6页 / 共14页
Linux内核TTY驱动架构.pdf_第7页
第7页 / 共14页
Linux内核TTY驱动架构.pdf_第8页
第8页 / 共14页
Linux内核TTY驱动架构.pdf_第9页
第9页 / 共14页
Linux内核TTY驱动架构.pdf_第10页
第10页 / 共14页
Linux内核TTY驱动架构.pdf_第11页
第11页 / 共14页
Linux内核TTY驱动架构.pdf_第12页
第12页 / 共14页
Linux内核TTY驱动架构.pdf_第13页
第13页 / 共14页
Linux内核TTY驱动架构.pdf_第14页
第14页 / 共14页
亲,该文档总共14页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

Linux内核TTY驱动架构.pdf

《Linux内核TTY驱动架构.pdf》由会员分享,可在线阅读,更多相关《Linux内核TTY驱动架构.pdf(14页珍藏版)》请在冰点文库上搜索。

Linux内核TTY驱动架构.pdf

基于基于MX51的的TTY驱动架构驱动架构2012-12-28一、一、任务目标任务目标以uart为实例分析整理TTY驱动架构。

二、层次架构二、层次架构ttycoreserialcoreuart驱动用户空间硬件线路规程图1在linux内核中,串行设备多种多样,内核开发者为了让驱动开发者尽量简单(可复用的东西多),构建了如图1所示的串行设备层次架构。

ttycore里是最基本的字符驱动,经过线路规程处理的数据,通过ttycore提供的数据交互机制与用户空间通信。

图1中线路规程表示对上层或下层传过来数据的处理,不同的处理方式对应不同的协议,如红外、ppp拨号等等。

serialcore是对tty驱动进行了封装,与硬件无关,给底层uart驱动开发提供API,针对具体硬件的操作全在uart驱动中实现。

因为uart同时涉及到以上三层,所以本文档以uart为例,阐述TTY。

三三、数据结构、数据结构设计设计1.数据结构数据结构uart驱动中定义了2个重要的数据结构,structuart_drivermxc_reg,和structuart_mxc_portmxc_port8。

a.structuart_drivermxc_reguart_driver是serial_core提供的重要结构体,下面是代码定义的uart_driver实例,变量的解释见对应注释。

具体结构体见数据结构关系图。

staticstructuart_drivermxc_reg=.driver_name=ttymxc,/驱动名,用于与设备匹配.dev_name=ttymxc,/设备名,用于与驱动匹配,并会在dev下显示/dev/ttymxcID.nr=MXC_UART_NR,/最大支持8个uartprot.cons=MXC_CONSOLE,/serialcore中定义的structconsole,详见serialcore分析;b.structuart_mxr_portmxc_ports8mxc_ports数组是自定义的uart_mxc_port数组,数组大小为8,在mx51中只用到前3个。

mxc_ports中包含的最重要的结构体是structuart_port,它们之间的关系详见数据结构关系图。

staticuart_mxc_port*mxc_portsMXC_UART_NR;/MXC_UART_NR=82.数据结构关系图数据结构关系图uart_driverconstchar*driver_name;constchar*dev_name;structconsole*cons;intnr;*state;*tty_driver;uart_state.port;.xmit;*uart_port;tty_driverintmagic;constchar*driver_name;constchar*name;structcdevcdev;structtty_struct*ttys;structktermios*termios;conststructtty_operations*ops;intnum;structlist_headtty_drivers;uart_mxc_port.port;structclk*clk;uart_portunsignedintirq;unsignedintline;unsignedinttype;unsignedintuartclk;structuart_icounticount;conststructuart_ops*ops;structdevice*dev;structuart_state*state;void*private_data;tty_portstructtty_struct*tty;Conststructtty_port_operations*ops;unsignedchar*xmit_buf;tty_structintmagic;*driver;conststructtty_operations*ops;intindex;structtty_ldisc*ldisc;structtty_bufheadbuf;*port;void*driver_data;char*write_bufcirc_bufchar*buf;inthead;inttail;tty_bufheadstructtty_buffer*head;structtty_buffer*tail;structtty_buffer*free;intmemory_used;tty_bufferstructtty_buffer*next;char*char_buf_ptr;unsignedchar*flag_buf_ptr;intused;intsize;intcommit;intread;unsignedlongdata0;tty_ldiscStructtty_ldisc_ops*ops;四四、uart注册及注册及初始化初始化1.uart注册注册uart驱动程序入口:

module_init(mxcuart_init);staticint_initmxcuart_init(void)/uart_register_driver(uart_driver*)-tty_register_driver(tty_driver*)cdev_add()/最终注册了nr(nr=8)个字符设备驱动ret=uart_register_driver(&mxc_reg);/mxc_reg定义见数据结构1ret=platform_driver_register(&mxcuart_driver);/mxcuart_driver见下面定义在mxcuart_init()函数中,我们重点分析uart_register_driver(structuart_driver*),对于platform_driver_register(),详见平台设备注册文档分析。

下面重点分析uart_register_driver(structuart_driver*)在uart_register_driver()中,构建了tty_driver,并将uart_driver中的相关成员赋值给tty_driver,最终调用到tty_register_driver(structtty_driver*)。

uart_register_driver(structuart_driver*drv)drv-state=kzalloc(sizeof(structuart_state)*drv-nr,GFP_KERNEL);structtty_driver*normal=alloc_tty_driver(drv-nr);/将uart_driver中的成员变量赋值给tty_driver,例如:

主次/设备号,驱动名、设备名、通信相关init_termios设置等tty_set_operations(normal,&uart_ops);tty_port_init(port);/初始化上面申请的(drv-nr)个uart_state中的tty_porttty_register_driver(normal);在tty_register_driver(structtty_driver*)中,最终注册了8个字符设备驱动,其操作函数为tty_fops。

staticconststructfile_operationstty_fops=.read=tty_read,.write=tty_write,.open=tty_open,;下面分析不同层次间几个operations函数的关系,如图:

tty_register_driver(structtty_driver*driver)dev=MKDEV(driver-major,driver-minor_start);register_chrdev_region(dev,driver-num,driver-name);cdev_init(&driver-cdev,&tty_fops);cdev_add(&driver-cdev,dev,driver-num);/注册了8个字符驱动list_add(&driver-tty_drivers,&tty_drivers);/将tty_drivers加入一个全局的tty_drivers链表tty_register_device(driver,i,NULL);/i=07,循环注册8个device在上面前3层中,每一层都给自己的下一层提供了操作函数的接口,tty_core是一个字符设备驱动,实现了字符设备提供的structfile_operations,同时给自己的下层提供了structtty_operations操作接口。

serial_core使用了tty_core提供的structtty_operations操作接口,同时给自己的下层提供了structuart_ops操作接口。

在后面的打开、数据读写过程中我们将会看到具体的层层调用关系。

到这里uart注册告一段落。

2.uart初始化初始化uart平台设备在/arch/arm/mach-mx5/serial.c中arch_initcall(mxc_init_uart)注册,注册了3个平台设备。

uart平台驱动和uart平台设备通过名字“mxcintuart”匹配,匹配成功调用uart平台驱动中的mxcuart_probe()。

在mxcuart_probe中主要是将平台资源给mxc_ports中的uart_port,然后调用uart_add_one_port(),它根据uart_port中的line拿到uart_driver中对应的tty_coreserial_coreuart驱动structfile_operations.open.read.writestructtty_operations.open.read.writestructuart_ops.open.read.write字符驱动uart_state,然后配置好这个port并调用tty_register_device()注册该port。

匹配成功后将调用到mxcuart_probe()。

staticstructplatform_drivermxcuart_driver=.driver=.name=mxcintuart,.probe=mxcuart_probe,.remove=mxcuart_remove,.suspend=mxcuart_suspend,.resume=mxcuart_resume,;staticstructplatform_devicemxc_uart_device1=.name=mxcintuart,.id=0,.num_resources=ARRAY_SIZE(mxc_uart_resources1),.resource=mxc_uart_resources1,.dev=.platform_data=&mxc_ports0,;staticstructresourcemxc_uart_resources1=.start=UART1_BASE_ADDR,.end=UART1_BASE_ADDR+0x0B5,.flags=IORESOURCE_MEM,.start=MXC_INT_UART1,.flags=IORESOURCE_IRQ,;staticuart_mxc_portmxc_ports=0=.port=.iotype=SERIAL_IO_MEM,.fifosize=32,.flags=ASYNC_BOOT_AUTOCONF,.line=0,.mode=MODE_DCE,.ir_mode=NO_IRDA,.匹配成功匹配成功uart_driverconstchar*driver_name;constchar*dev_name;structconsole*cons;intnr;*state;*tty_driver;uart_state.port;.xmit;*uart_port;uart_stateuart_state0uart_state1uart_state2uart_state3uart_state4uart_state5uart_state6uart_state7在mxcuart_probe()中最重要的函数是uart_add_one_port()。

五五、uart打开打开在介绍uart打开、读写数据时,首先需要先回顾下不同层次间几个operations函数的关系图,接下来先从总体上分析其大致流程,然后具体分析细节。

uart_add_one_port(structuart_driver*drv,structuart_port*uport)state=drv-state+uport-line;uart_configure_port(drv,state,uport);tty_register_device(drv-tty_driver,uport-line,uport-dev);port-ops-config_port(port,flags);uart_report_port(drv,port);uart_change_pm(state,0);uart_change_pm(state,3);dev_tdev=MKDEV(driver-major,driver-minor_start)+index;tty_line_name(driver,index,name);device_create(tty_class,device,dev,NULL,name);/创建创建/sys/class/tty/ttymxcindexmxcuart_probe(structplatform_device*pdev)intid=pdev-id;mxc_portsid-port.ops=&mxc_ops;/将平台设备中的成员变量赋值给将平台设备中的成员变量赋值给mxc_portsid,主要是对其中的,主要是对其中的/核心核心uart_port成员赋值成员赋值mxc_portsid-clk=clk_get(&pdev-dev,NULL);uart_add_one_port(&mxc_reg,&mxc_portsid-port);下面分5个步骤介绍uart打开的具体细节:

用户空间字符驱动tty_coreserial_coreuart驱动1.用户空间用户空间用户空间通过具体的设备节点拿到主次设备号,通过VFS找到具体的字符驱动设备。

这一过程非常复杂,详细VFS文档分析。

2.字符驱动字符驱动字符驱动会调用tty_core向它注册的file_operations中的tty_open()。

tty_coreserial_coreuart驱动structfile_operations.open=tty_openstructtty_operations.open=uart_open,structuart_ops.startup=mxcuart_startup,字符驱动用户空间open(“/dev/ttymxc0”)tty_open通过节点拿到设备号,通过设备号拿到设备,再通过设备拿到tty_driver和tty_struct已经打开过tty_reopen(tty)tty_init_dev(driver,index,0);YNtty-ops-open(tty,filp);在上述流程中tty_init_dev需要重点概述下:

3.tty_core在执行到tty_open()时,会调用serial_core向它注册的tty_operations中的uart_open()。

tty_init_dev(structtty_driver*driver,intidx,intfirst_ok)initialize_tty_struct(tty,driver,idx);/tty_driver_install_tty(driver,tty);/初始化termiostty_ldisc_setup(tty,tty-link);/在默认的情况下使用N_TTY线路规程4.serial_core如上图代码,在tty_core中调用到了serial_core向它注册的uart_open(),同时uart_open()中也用到了uart驱动向它注册的uart_ops中的startup()。

上面注册了中断处理函数,这个函数极为重要,数据接收和发送都要用到它。

此中断是接收发送共用的,当收到中断信号时通过判断相应的寄存器位来区分是接收中断还是发送中断。

5.uart驱动驱动uart驱动做为tty的一个实例,就是按照serial_core提供的注册接口注册,并实现其uart_ops中的回调函数,这些函数大多是与具体硬件操作相关的。

六、六、uart写写数据数据uart写数据是由用户空间发起的,同样我们先从总体上了解它的流程,再具体讲其细节。

irqreturn_tmxcuart_int(intirq,void*dev_id)mxcuart_rx_chars(umxc);mxcuart_tx_chars(umxc);mxcuart_startup(structuart_port*port)request_irq(umxc-port.irq,mxcuart_int,0,mxcintuart,umxc);/申请中断,配置相关寄存器准备开始工作uart_open(structtty_struct*tty,structfile*filp)uart_startup(state,0);uport-ops-startup(uport);uart_update_termios(state);下面分6个步骤介绍uart打开的具体细节:

用户空间字符驱动线路规程tty_coreserial_coreuart驱动1.用户空间用户空间调用write(),通过打开设备节点返回的文件描述符调到tty_core注册的tty_write()。

2.字符驱动字符驱动中的tty_write()会从用户空间拷贝数据,然后调用线路规程的write()函数。

tty_coreserial_coreuart驱动structfile_operations.write=tty_write,structtty_operations.write=uart_write,structuart_ops.start_tx=mxcuart_start_tx,字符驱动用户空间write(fd,constvoid*buf,size_tcount);线路规程structtty_ldisc_ops.write=n_tty_write,3.线路规程线路规程就是对写入或者读到的数据按照指定的协议进行处理。

不同的线路规程处理数据的方式不一样,这里我们用到的是N_TTY,后续单独分析N_TTY,这里我们只要知道数据经过了它,它对输入的数据进行了处理。

4.tty_core线路规程会把处理后的数据给到tty_core层,通过调用serial_core注册的uart_write()。

5.serial_core在上图中可以看到,最后面调用到了uart驱动向serial_core注册的start_tx(),具体的实现是mxcuart_start_tx()函数,它触发了中断,程序将进入中断处理流程。

6.uart驱动uart中实现了中断处理函数,这里面会将数据一个一个写入寄存器。

下面通过图示的方法,结合数据结构关系图,说明具体数据的走向。

/把数据copy到uart_state中的xmit中uart_start(tty);port-ops-start_tx(port);_uart_start(tty);uart_write(structtty_struct*tty,constunsignedchar*buf,intcount)do_tty_write(ld-ops-write,tty,file,buf,count);copy_from_user(tty-write_buf,buf,size);/tty_write(structfile*file,constchar_user*buf,size_tcount,loff_t*ppos)write(tty,file,tty-write_buf,size);/线路规程的write()函数用户void*buftty_struct中的write_buftty_struct中的ldisc:

线路规程uart_state中的xmit从uart_state中的xmit读取数据,写入寄存器七、七、uart读读数据数据uart读数据流程1.mxcuart_rx_chars(umxc);uart_insert_char(&umxc-port,status,MXC_UARTURXD_OVRRUN,ch,flag);tty_insert_flip_char(tty,ch,flag);

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > PPT模板 > 商务科技

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2