自己写的intel8250串口芯片驱动.docx

上传人:b****3 文档编号:12906288 上传时间:2023-04-22 格式:DOCX 页数:23 大小:231.69KB
下载 相关 举报
自己写的intel8250串口芯片驱动.docx_第1页
第1页 / 共23页
自己写的intel8250串口芯片驱动.docx_第2页
第2页 / 共23页
自己写的intel8250串口芯片驱动.docx_第3页
第3页 / 共23页
自己写的intel8250串口芯片驱动.docx_第4页
第4页 / 共23页
自己写的intel8250串口芯片驱动.docx_第5页
第5页 / 共23页
点击查看更多>>
下载资源
资源描述

自己写的intel8250串口芯片驱动.docx

《自己写的intel8250串口芯片驱动.docx》由会员分享,可在线阅读,更多相关《自己写的intel8250串口芯片驱动.docx(23页珍藏版)》请在冰豆网上搜索。

自己写的intel8250串口芯片驱动.docx

自己写的intel8250串口芯片驱动

CU网友自己写的intel8250串口芯片驱动

一:

前言

串口是一种常用的接口,嵌入式开发环境中,开发板通常都会提供串口与PC相连,方便开发者进行测试。

在较早的网络环境中。

UNIX主机通过串口连moden再接通电话线来连通对方电脑。

类似于今天的telnet。

串口经常用来做远程终端使用。

类似于我们之前分析的终端控制台驱动。

不过,不相同的是,终端驱动的输入数据是从键盘鼠标等I/O外设中来,到显示器上显示。

而串口终端的数据来源跟数据输出都是串口。

对于运行中的进程来说,它不需要知道运行在什么样的终端。

Tty层把终端层给封装起来了.

查找了一相有关PC平台上的8250串口芯片资料,结合之前分析的uart架构自己写了一个串口驱动。

在写驱动的过程中,并没有参考linux自带的8250芯片驱动。

目的是为了在写完之后,和linux自带的驱动比较,就能发现自己的不足。

在驱动中,按着对端设备的数据模式设定了波特率和数据格式。

并末实现termios库中关于串口参数的设定。

不过在驱动中都写好了接口函数。

按操作接口将其链入即可。

另外:

忽略了moden信号的处理。

二:

串口的硬件架构

在pc中常使用的串口芯片是8250,16450,16450A等。

这些芯片都是从8250发展而来的。

都往下与8250保持兼容。

由于我手头只有8250和16450的详细的资料,代码分析时侧重于这两种类型的芯片分析.如果有朋友能够提供其它芯片的资料,我会感激不尽^_^.

8250提共了9个寄存器。

严格说来,只有8个。

因为其中有两个寄存器是共享同一个寄存器。

各寄存器的作用与寄存位的含义如下表所示:

 

在上图的端口地址标识中,小括号中还有一个地址。

这是因为在PC中。

一般都会有两个串口。

括号外的是主串口的端口地址,而括号里面的是从串口地址。

从上图可以看到8250的寄存器比较繁多,操作比较复杂。

我们依次来看每个寄存器的含义:

数据接收寄存器(RBR):

存放接收到的数据。

这些数据是已经去掉了发送位,停止位和奇偶检验位了的。

也就是串口接收到的有效数据。

 

数据发送寄存器(THR):

用来存放要发送的数据。

这是用户要写入的数据。

不包含上述的附加位。

从上图中可以看到,RBR和THR的端口地址是一样的。

也就是说,它们是操作的是同一个寄存器。

只有在寄存器空闲的时候,才能写入数据。

也就是说,我们在中断/轮询处理过程中,先把这个寄存器的值取出。

然后再写入我们要发送的数据。

 

中断允许寄存器(IER):

8250有四级中断。

分别为:

接收出错中断。

接收寄存器满中断。

发送寄存器空中断。

Moden状态改变中断。

四种中断都对应寄存器的1个位。

剩余四位无意义,为0。

从这里可以看到,发送数据并不是每次都要等接收中断来了,才能发送。

也可以在发送寄存器空的中断处理中发送。

 

中断标识寄存器(IIS):

既然8250对应有四种中断。

那中断过来之后,怎么区分是哪种类型的中断呢?

这就是中断标识寄存器的作用。

IIS中有表示中断状态的对应位。

都是相对于IER来说的。

另外,与IER的高四位始终为0的情况相反的是,IIS的前二位能够驱分芯片的类型。

如:

8250的IIS前二位为00。

而16550A芯片的IIS前二位为11。

这里顺带提一下8250和16550A的区别:

8250每次只能接收或者发送1个字节。

,而16550A则提供了一个FIFO缓存区。

有16个字节的缓存空间。

这样就可以减轻CPU的负担。

在16550A中,新增了一个寄存器FIFO控制寄存器(FCR).其中有一个标识可以启用或者禁用FIFO。

 

线路控制寄存器(LCR):

可以用来控制数据的传输方式。

比如说设置奇偶检验位,数据位的长度,停止位等。

 

Moden控制寄存器(MCR):

用来向moden发送RTS/DTR信号。

在这个寄存器中还要注意有二个特殊的位。

一个是自检位。

该位被置之后,数据在8250的内部移动。

可以用来检测8250数据接收与发送功能。

另外的一个位是中断允许位。

它允许8250向CPU产生中断.

 

线路状态寄存器(LSR):

用来检查线路的状态。

例如数据包出错原因,发送寄存器/接收寄存器空状态标识以及终止符检测。

 

Moden状态寄存器检测(MSR):

用来采集moden的状态。

例如DSR和CTS信号检测。

载波检测等.

 

除法寄存器:

一般用来设定波特率:

它是低8位在发送/读取寄存器。

高8位在IER寄存器,通过LCR有最高位来控制除法寄存器是否可用。

 

三:

驱动代码

Kernel版本:

2.6.25

代码:

见附件

调试:

可以用minicom,选择设备节点为:

/dev/8250X(主串口为0,次串口为1)。

如果你没有配置udev或者hotplug,就需要手动在/dev/下mknod相关结点。

附运行时候的截图:

 

 

Makefile

#Comment/uncommentthefollowinglinetodisable/enabledebugging

#DEBUG=y

#Addyourdebuggingflag(ornot)toCFLAGS

ifeq($(DEBUG),y)

DEBFLAGS=-O-g-DSCULL_DEBUG#"-O"isneededtoexpandinlines

else

DEBFLAGS=-O2

endif

#CFLAGS+=$(DEBFLAGS)

#CFLAGS+=-I..

ifneq($(KERNELRELEASE),)

#callfromkernelbuildsystem

obj-m:

=serial_driver.o

else

KERNELDIR?

=/lib/modules/$(shelluname-r)/build

PWD:

=$(shellpwd)

default:

$(MAKE)-C$(KERNELDIR)M=$(PWD)modules

endif

clean:

rm-rf*.o*~core.depend.*.cmd*.ko*.mod.c.tmp_versionsmodule*Module*

depend.dependdep:

$(CC)$(CFLAGS)-M*.c>.depend

ifeq(.depend,$(wildcard.depend))

include.depend

endif

源代码:

#include

#include

#include

#include

#include

#include

#include

#include

#include

MODULE_LICENSE("GPL");

MODULE_AUTHOR("ericxiao:

xgr178@");

#defineSERIAL8250_TYPE99

inlinestaticvoidserial8250_stop_send(structuart_port*port);

spinlock_tmy_lock=SPIN_LOCK_UNLOCKED;

enumcheck_type

{

odd_check,

even_check,

no_check,

};

//#defineSER_DBG1

#defineDEF_baudrate9600

#defineDEF_databit8

#defineDEF_stopbit1

#defineDEF_checkno_check

#defineARRY_SIZE(arry)sizeof((arry))/sizeof((arry)[0])

#ifSER_DBG

#defineSer_dbg(args...)printk(args)

#else

#defineSer_dbg(args...)

#endif

staticunsignedlongbaudrate_arry[]={110,300,600,1200,2400,4800,9600,14400,19200,38400,57600,115200,230400,380400,460800,921600};

 

staticintbaudrate=DEF_baudrate;

staticintcheck=DEF_check;

staticintstopbit=DEF_stopbit;

staticintdatabit=DEF_databit;

enumreg_type

{

RBR=0,

THR=0,

DIVR_L=0,

DIVR_H=1,

IER=1,

IIR,

LCR,

MCR,

LSR,

MSR,

FIFO,

MAX_REG,

};

//LCRbit

#defineLCR_DIVENABLEBIT7

#defineLCR_DATABIT0

#defineLCR_STOPBIT2

#defineLCR_CHECKENABLE3

#defineLCR_CHECKBIT4

//IERbit

#defineIER_RECEVEINTE0

#defineIER_SENTEMPTYINTE1

#defineIER_LINESTATAINTE2

#defineIER_MODESTATAINTE3

//MCRbit

#defineMCR_SELFTEST4

#defineMCR_INTRENABLE3

//IIRbit

#defineIIR_ISINTR0

#defineIIR_INTERIDENT1

 

staticirqreturn_tserial8259_intr(intirqno,void*dev_id)

{

u8reg_data=0;

intcount=0;

unsignedlongsave;

structuart_port*port=(structuart_port*)dev_id;

u32database=port->iobase;

charc;

inttail;

inthead;

if(port->irq!

=irqno)

returnIRQ_NONE;

while

(1)

{

reg_data=inb(database+IIR);

if(reg_data&(1<

{

Ser_dbg("Nothaveinterrupt.\n");

break;

}else

{

switch((reg_data&(0x03<>IIR_INTERIDENT)

{

case0:

Ser_dbg("Modenstatechange.\n");

reg_data=0;

reg_data=inb(database+MSR);

break;

case1:

Ser_dbg("Sentbufferempty.\n");

//spin_lock_irqsave(&port->lock,save);

tail=port->info->xmit.tail;

//ifthebufferisempty

if(!

uart_circ_empty(&port->info->xmit))

{

head=port->info->xmit.head;

c=port->info->xmit.buf[tail];

tail=(tail+1)&(UART_XMIT_SIZE-1);

port->info->xmit.tail=tail;

outb(c,database+THR);

Ser_dbg("input:

%c\n",c);

}else{

serial8250_stop_send(port);

Ser_dbg("bufferempty.\n");

}

//spin_unlock_irqrestore(&port->lock,save);

break;

case2:

Ser_dbg("Recvebufferfull.\n");

reg_data=0;

reg_data=inb(database+RBR);

uart_insert_char(port,0,0,reg_data,0);

tty_flip_buffer_push(port->info->tty);

//printk("%c",reg_data);

break;

case3:

Ser_dbg("Recvedataerron.\n");

reg_data=0;

reg_data=inb(database+LSR);

break;

}

}

}

returnIRQ_HANDLED;

}

inlinestaticvoidserial8250_start_send(structuart_port*port)

{

u8reg_data;

u32database=port->iobase;

reg_data=inb(database+IER);

reg_data|=1<

outb(reg_data,database+IER);

return;

}

inlinestaticvoidserial8250_stop_send(structuart_port*port)

{

u8reg_data;

u32database=port->iobase;

reg_data=inb(database+IER);

reg_data&=~(1<

outb(reg_data,database+IER);

return;

}

inlinestaticvoidserial8250_set_enableinter(structuart_port*port)

{

u8reg_data;

u32database=port->iobase;

//enableintrrupte.allowallinterrupt,exceptsentbufferemptyinterrupt

reg_data=0;

reg_data|=1<

reg_data|=1<

reg_data|=1<

outb(reg_data,database+IER);

Ser_dbg("IER:

%0x.\n",reg_data);

//enablesentinterruptesingleto8259

reg_data=inb(database+MCR);

reg_data&=~(1<

reg_data|=1<

reg_data|=3;

outb(reg_data,database+MCR);

 

return0;

}

inlinestaticintserial8250_set_dataformat(structuart_port*port,intdatabit,intstopbit,intcheck)

{

u8reg_data=0;

u8data_bit=0;

u32database;

database=port->iobase;

switch(databit)

{

case5:

data_bit=0<

break;

case6:

data_bit=1<

break;

case7:

data_bit=2<

break;

case8:

data_bit=3<

break;

default:

Ser_dbg("setdatabit(%d)isnotallowed.\n",databit);

return-1;

}

reg_data|=data_bit;

//setstopbit

if(stopbit==1)

reg_data&=~(1<

//setodd/evencheck

if(check==no_check)

reg_data&=~(1<

else

{

if(check==odd_check)

reg_data&=~(1<

elseif(check==even_check)

reg_data|=1<

reg_data|=1<

}

outb(reg_data,database+LCR);

return0;

}

inlinestaticintserial8250_set_baudrate(structuart_port*port,unsignedlongbaudrate)

{

intret=-1;

inti;

u16divnum;

u8div_l;

u8div_h;

u8reg_data=0;

u32database;

database=port->iobase;

for(i=1;i

{

if(baudrate_arry[i]==baudrate)

ret=0;

}

if(ret==0)

{

divnum=1843200/(16*baudrate);

div_l=*(u8*)(&divnum);

div_h=*(u8*)((u8*)&divnum+sizeof(u8));

Ser_dbg("divnum=%0x;div_l=%0x;div_h=%0x.\n",divnum,div_l,div_h);

//setlcrbit7=1

reg_data=inb(database+LCR);

reg_data|=(1<

outb(reg_data,database+LCR);

outb(div_l,database+DIVR_L);

outb(div_h,database+DIVR_H);

reg_data&=~(1<

outb(reg_data,database+LCR);

}

returnret;

}

 

inlinestaticintserial8250_init(structuart_port*port)

{

u16divnum;

u8div_l;

u8div_h;

u8reg_data;

u8data_bit=0;

u32database=port->iobase;

if(!

request_region(database,MAX_REG,"8250port"))

{

printk("8250requestregionerron.\n");

return-1;

}

//clearFIFOreg

reg_data=0;

outb(reg_data,database+FIFO);

if(serial8250_set_baudrate(port,baudrate)||serial8250_set_dataformat(port,databit,stopbit,check))

gotoerron;

serial8250_set_enableinter(port);

//resetMSRLSRRBRregiset

inb(database+MSR);

inb(database+LSR);

inb(database+RBR);

return0;

erron:

printk("serial8250configureerron.\n");

return-1;

}

voidserial8250_config_port(structuart_port*port,intline)

{

Ser_dbg("serial8250configport...\n");

port->type=SERIAL8250_TYPE;

serial8250_init(port);

return;

}

voidserial8250_release_port(structuart_port*port)

{

Ser_dbg("serial8250_release_port...\n");

return;

}

voidserial8250_set_mctrl(structuart_port*port,unsignedintmctrl)

{

Ser_dbg("serial8250_set_mctrl...\n");

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

当前位置:首页 > PPT模板 > 可爱清新

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

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