自己写的intel8250串口芯片驱动.docx
- 文档编号:1260427
- 上传时间:2023-04-30
- 格式:DOCX
- 页数:23
- 大小:231.69KB
自己写的intel8250串口芯片驱动.docx
《自己写的intel8250串口芯片驱动.docx》由会员分享,可在线阅读,更多相关《自己写的intel8250串口芯片驱动.docx(23页珍藏版)》请在冰点文库上搜索。
自己写的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< { 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文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 自己 intel8250 串口 芯片 驱动
![提示](https://static.bingdoc.com/images/bang_tan.gif)