Linux终端控制台体系及串口驱动分析Word文档格式.docx

上传人:b****5 文档编号:16451941 上传时间:2022-11-23 格式:DOCX 页数:22 大小:126.49KB
下载 相关 举报
Linux终端控制台体系及串口驱动分析Word文档格式.docx_第1页
第1页 / 共22页
Linux终端控制台体系及串口驱动分析Word文档格式.docx_第2页
第2页 / 共22页
Linux终端控制台体系及串口驱动分析Word文档格式.docx_第3页
第3页 / 共22页
Linux终端控制台体系及串口驱动分析Word文档格式.docx_第4页
第4页 / 共22页
Linux终端控制台体系及串口驱动分析Word文档格式.docx_第5页
第5页 / 共22页
点击查看更多>>
下载资源
资源描述

Linux终端控制台体系及串口驱动分析Word文档格式.docx

《Linux终端控制台体系及串口驱动分析Word文档格式.docx》由会员分享,可在线阅读,更多相关《Linux终端控制台体系及串口驱动分析Word文档格式.docx(22页珍藏版)》请在冰豆网上搜索。

Linux终端控制台体系及串口驱动分析Word文档格式.docx

输入到主设备的数据成为从设备的输出,输入到从设备的数据成为主设备的输出,形成双向管道。

伪终端设备通常用于远程登录服务器来建立网络和终端的关联。

当通过telnet远程登录到另一台主机时,telnet进程与远程主机的telnet服务器相连接。

telnet服务器使用某个主设备并通过对应的从设备与telnet进程相互通信。

终端体系:

从上往下:

TTYcore—>

TTYlinediscipline(可以没有)—>

ttydriver

在Linux中,TTY体系分为:

TTY核心、TTY线路规程、TTY驱动3部分。

TTY核心从用户获取要发送给TTY设备的数据,然后把数据传送给TTY线路规程(协议),它对数据进行处理后,负责把数据传递到TTY驱动程序,TTY驱动程序负责格式化数据,并通过硬件发送出去。

从硬件收到的数据向上通过TTY驱动,进入TTY线路规程,再进入TTY核心,最后被用户获取。

TTY驱动可以直接和TTY核心通讯,但通常TTY线路规程会修改在两者之间的传送的数据。

TTY驱动不能直接和线路规程通信,甚至不知道它的存在,线路规程的工作是格式化从用户或者硬件收到的数据。

这种格式常常实现为一个协议,如PPP或Bluetooth

终端体系—串口(★)

往串口发送数据时的数据流向:

/dev/ttys0(串口的设备文件)—>

tty_io.c(TTYcore)—>

n_tty.c(tty线路规程,必须向core注册)—>

处理完返回ttycore—>

再由ttycore交给驱动程序serial.c—>

驱动程序控制硬件

数据流

读操作:

TTY驱动从硬件接收到数据后,负责把数据传送到TTY核心,TTY核心将从TTY驱动收到的数据缓存到一个tty_flip_buffer类型的结构中。

该结构包含两个数据数组(一个用于读、一个用于写)。

从TTY设备接收到的数据被存储到第一个数组,当这个数组满,等待数据的用户将被通知。

当用户从这个数组读数据时,任何从TTY驱动新来的数据被存储在第2个数组。

当第二个数组存满后,数据再次提交给用户,并且驱动又开始填充第1个数组,以此交替。

驱动描述:

Linux内核使用uart_driver描述串口驱动,它包含串口设备的驱动名、设备名、设备号等信息。

structuart_driver{

structmodule*owner;

constchar*driver_name;

//驱动名

constchar*dev_name;

//设备名

intmajor;

//主设备号

intminor;

//从设备号

intnr;

//设备数

structconsole*cons;

structuart_state*state;

structtty_driver*tty_driver;

};

 

注册驱动:

Linux为串口驱动注册了如下接口:

intuart_register_driver(structuart_driver*drv)

端口描述:

uart_port用于描述一个UART端口(一个串口)的地址、FIFO大小、端口类型等信息。

structuart_port

{

spinlock_tlock;

/*端口锁*/

unsignedintiobase;

/*IO端口基地址*/

unsignedchar__iomem*membase;

/*IO内存基地址*/

unsignedintirq;

/*中断号*/

unsignedcharfifosize;

/*传输fifo大小*/

conststructuart_ops*ops;

……………………..

}

操作串口:

uart_ops定义了针对串口的一系列操作,包括发送、接收及线路设置等。

structuart_ops

{

unsignedint(*tx_empty)(structuart_port*);

void(*set_mctrl)(structuart_port*,unsignedintmctrl);

unsignedint(*get_mctrl)(structuart_port);

void(*stop_tx)(structuart_poart*);

//停止发送

void(*start_tx)(structuart_poart*);

//开始发送

void(*send_xchar)(structuart_poart*,charch);

//发送xchar

void(*stop_rx)(structuart_port*);

//停止接收

………………………………..

添加串口:

串口核心层提供如下函数添加1个端口:

intuart_add_one_port(structuart_driver*drv,structuart_port*port)

★串口驱动设计流程:

1、定义一个uart_driver的变量,并初始化

2、使用uart_regisetr_driver来注册这个驱动

3、初始化uart_port和ops函数表

4、调用uart_add_one_poart()添加初始化好的uart_port

Ø

实例分析—mini2440串口驱动程序分析

1.发送和接收

发送:

循环buffer发送fifo发送移位寄存器

//循环buffer(驱动实现)发送fifo(串口芯片)过程由驱动程序完成;

发送fifo发送移位寄存器过程由硬件完成

接收:

接收移位寄存器接收fifoFlip_buf

发送的过程是:

把数据写到发送fifo中,fifo把收到的数据传给发送移位寄存器(自动的,非driver控制),然后每个时钟脉冲往串口线上写一bit数据。

接收的过程是:

接收移位寄存器收到数据,发送给接收fifo,接收fifo事先设置好了触发门限,当里面的数据量超过门限时就会触发一个中断,调用驱动中的中断处理函数,把数据写到flip_buf中。

2.寄存器

UARTLineControlRegister:

WordLength:

数据位长度

NumberofStopBit:

停止位数

ParityMode:

奇偶校验位类型

Infra-RedMode:

UART/红外模式选择(当以UART模式工作时,需设为“0”)

UARTControlRegister

ReceiveMode:

选择接收模式。

如果是采用DMA模式的话,还需要指定说使用的DMA信道。

TransmitMode:

同上。

SendBreakSignal:

选择是否在传1帧资料中途发送Break信号。

LoopbackMode:

选择是否将UART置于Loopback测试模式。

RxErrorStatusInterruptEnable:

选择是否使能当发生接收异常时,是否产生接收错误中断。

RxTimeOutEnable:

是否使能接收超时中断。

RxInterruptType:

选择接收中断类型。

选择0:

Pulse(脉冲式/边沿式中断。

非FIFO模式时,一旦接收缓冲区中有数据,即产生一个中断;

为FIFO模式时,一旦当FIFO中的资料达到一定的触发水平后,即产生一个中断)

选择1:

Level(电平模式中断。

非FIFO模式时,只要接收缓冲区中有数据,即产生中断;

为FIFO模式时,只有FIFO中的资料达到触发水平后,即产生中断)

TxInterruptType:

类同于RxInterruptType

UARTFIFOConrtolRegister

FIFOEnable:

FIFO使能选择。

RxFIFOReset:

选择当复位接收FIFO时是否自动清除FIFO中的内容。

TxFIFOReset:

选择当复位发送FIFO时是否自动清除FIFO中的内容。

RxFIFOTriggerLevel:

选择接收FIFO的触发水平。

TxFIFOTriggerLevel:

选择发送FIFO的触发水平。

UARTTX/RXStatusRegister

Receivebufferdataready:

当接收缓冲寄存器从UART接收端口接收到有效资料时将自动置“1”。

反之为“0则表示缓冲器中没有资料。

Transmitbufferempty:

当发送缓冲寄存器中为空,自动置“1”;

反之表明缓冲器中正有资料等待发送。

Transmitterempty:

当发送缓冲器中已经没有有效资料时,自动置“1”;

反之表明尚有资料未发送。

UARTFIFOStatusRegister

RxFIFOCount:

接收FIFO中当前存放的字节数。

TxFIFOCount:

发送FIFO中当前存放的字节数。

RxFIFOFull:

为“1“表明接收FIFO已满。

TxFIFOFull:

为“1“表明发送FIFO已满。

3.函数介绍

模块初始化函数:

staticint__inits3c2410uart_init(void)

returnuart_register_driver(&

s3c2410_reg);

使用uart_register_driver注册串口驱动。

staticstructuart_drivers3c2410_reg={

owner:

THIS_MODULE,

normal_major:

SERIAL_S3C2410_MAJOR,

normal_name:

"

ttyS%d"

callout_name:

cua%d"

normal_driver:

&

normal,

callout_major:

CALLOUT_S3C2410_MAJOR,

callout_driver:

callout,

table:

s3c2410_table,

termios:

s3c2410_termios,

termios_locked:

s3c2410_termios_locked,

minor:

MINOR_START,

nr:

UART_NR,

port:

s3c2410_ports,

cons:

S3C2410_CONSOLE,

};

staticstructuart_ports3c2410_ports[UART_NR]={

{

iobase:

(unsignedlong)(UART0_CTL_BASE),

iotype:

SERIAL_IO_PORT,

irq:

IRQ_RXD0,

uartclk:

130252800,

fifosize:

16,

ops:

&

s3c2410_pops,

type:

PORT_S3C2410,

flags:

ASYNC_BOOT_AUTOCONF,

},

staticstructuart_opss3c2410_pops={

tx_empty:

s3c2410uart_tx_empty,

set_mctrl:

s3c2410uart_set_mctrl,

get_mctrl:

s3c2410uart_get_mctrl,

stop_tx:

s3c2410uart_stop_tx,

start_tx:

s3c2410uart_start_tx,

stop_rx:

s3c2410uart_stop_rx,

enable_ms:

s3c2410uart_enable_ms,

break_ctl:

s3c2410uart_break_ctl,

startup:

s3c2410uart_startup,

shutdown:

s3c2410uart_shutdown,

change_speed:

s3c2410uart_change_speed,

s3c2410uart_type,

config_port:

s3c2410uart_config_port,

release_port:

s3c2410uart_release_port,

request_port:

s3c2410uart_request_port,

3.1阻止发送函数uart_stop_tx

staticvoids3c2410uart_stop_tx(structuart_port*port,u_intfrom_tty)

{

disable_irq(TX_IRQ(port));

}

停止发送的功能,其内部的函数disable_irq是停止中断的功能,发送数据是通过中断来完成的,关闭中断也就关闭了发送。

3.2发送使能函数uart_start_tx

staticvoids3c2410uart_start_tx(structuart_port*port,u_intnonempty,

u_intfrom_tty)

enable_irq(TX_IRQ(port));

与上面的过程类似,就是一个相反的过程

3.3阻止接收函数uart_stop_rx

staticvoids3c2410uart_stop_rx(structuart_port*port)

disable_irq(RX_IRQ(port));

3.4发送缓冲空判断函数uart_tx_empty

staticu_ints3c2410uart_tx_empty(structuart_port*port)

return(UART_UTRSTAT(port)&

UTRSTAT_TR_EMP?

0:

TIOCSER_TEMT);

如果发送缓冲为空则返回0,否则返回1。

3.5获取控制信息函数uart_get_mctrl

staticu_ints3c2410uart_get_mctrl(structuart_port*port)

return(TIOCM_CTS|TIOCM_DSR|TIOCM_CAR);

获得控制信息,TIOCM_CTS,TIOCM_DSR和TIOCM_CAR,这几个宏代表串口的控制信息,分别是cleartosend,datasetready和datacarrierdetect(详见SerialProgrammingGuideforPOSIXOperatingSystems)

3.6接收中断函数uart_rx_interrupt

staticvoids3c2410uart_rx_interrupt(intirq,void*dev_id,structpt_regs*regs)

structuart_info*info=dev_id;

structtty_struct*tty=info->

tty;

unsignedintstatus,ch,max_count=256;

structuart_port*port=info->

port;

status=UART_UTRSTAT(port);

while((status&

UTRSTAT_RX_RDY)&

&

max_count--)

{//status&

UTRSTAT_RX_RDY判断有数据

if(tty->

flip.count>

=TTY_FLIPBUF_SIZE)

{//flipbuf已满

tty->

flip.tqueue.routine((void*)tty);

//交换到另一个缓冲数组

=TTY_FLIPBUF_SIZE){//再进行判断

printk(KERN_WARNING"

TTY_DONT_FLIPset\n"

);

return;

ch=UART_URXH(port);

//从寄存器中取数据

*tty->

flip.char_buf_ptr=ch;

flip.flag_buf_ptr=TTY_NORMAL;

port->

icount.rx++;

flip.flag_buf_ptr++;

flip.char_buf_ptr++;

flip.count++;

//处理一个字节

tty_flip_buffer_push(tty);

功能:

主要是是while大循环,首先看循环判断条件status&

UTRSTAT_RX_RDY,前面有status=UART_UTRSTAT(port),查2410的datasheet,status&

UTRSTAT_RX_RDY这个位是判断接收buffer内是否还有有效数据?

按道理一次中断只是把接收的fifobuffer中的数据放到flipbuffer中去,接收的fifo的中断门限是4-12字节,进行一次接收往往要中断好多次,这样中断开销比较大,所以在while的循环条件中判断一下是否还有接收的有效数据,如果有,就继续在中断程序中继续接收,当然,永远都在接收中断中(如果一直有数据要接收)也不合适,所以while循环还有计数,最多循环256次。

在循环中,首先是要判断一下接收数据用的flip-buffer是不是已经满了,if(tty->

=TTY_FLIPBUF_SIZE)如果满了,就要跳到另一个buffer上去,tty->

flip.tqueue.routine((void*)tty)是用来实现跳到另一个buffer上的功能,然后把收到的数据写到flip-buffer中,相应的状态,统计数据都要改,接着再来while循环,循环结束后就要调用tty_flip_buffer_push(tty)来让用户把存在缓冲里的数据取走,接收一次都要把缓存清空。

3.7发送中断函数uart_tx_interrupt

staticvoids3c2410uart_tx_interrupt(intirq,void*dev_id,

structpt_regs*reg){

intcount;

if(port->

x_char){//x_char为停止位

UART_UTXH(port)=port->

x_char;

icount.tx++;

x_char=0;

if(info->

xmit.head==info->

xmit.tail//无数据发送

||info->

stopped||info->

hw_stopped){

s3c2410uart_stop_tx(info->

port,0);

//关闭发送中断

count=port->

fifosize>

>

1;

do{//有数据发送

UART_UTXH(port)=info->

xmit.buf[info->

xmit.tail];

info->

xmit.tail=(info->

xmit.tail+1)&

(UART_XMIT_SIZE-1);

xmit.tail)

break;

}while(--count>

0);

//count=fifpsize(16字节)>

1即8字节

if(CIRC_CNT(info->

xmit.head,info->

xmit.tail,

UART_XMIT_SIZE)<

WAKEUP_CHARS)

uart_event(info,EVT_WRITE_WAKEUP);

//通知上层

(1)首先查看port中的x_char是不是为0,不为0则把x_char发送出去。

x_char是xon/xoff的意思,每发一个字节时在开始前先发xon信号,在结束时发xoff。

(2)如果x_char没有被设置,再看环形缓冲区是否为空,或者info->

stopped和info->

hw_stopped两个位是不是为1,如果这些条件成立的话,就停止发送。

Tty->

stop指示

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

当前位置:首页 > 初中教育 > 数学

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1