实验 101 UART驱动分析Word格式.docx
- 文档编号:16642372
- 上传时间:2022-11-25
- 格式:DOCX
- 页数:23
- 大小:78.64KB
实验 101 UART驱动分析Word格式.docx
《实验 101 UART驱动分析Word格式.docx》由会员分享,可在线阅读,更多相关《实验 101 UART驱动分析Word格式.docx(23页珍藏版)》请在冰豆网上搜索。
.owner=THIS_MODULE,
.driver_name="
PXAserial"
.dev_name="
ttyS"
.major=TTY_MAJOR,
.minor=64,
.nr=ARRAY_SIZE(serial_pxa_ports),
.cons=PXA_CONSOLE,
};
从serial_pxa_reg结构体中,UART使用的设备名为ttySn(n=0~3),主设备号major为4,次设备号minor为64,串口数nr=ARRAY_SIZE(serial_pxa_ports),根据serial_pxa_ports结构体的定义,可以算出串口数nr=4,当然PXA270只有三个串口(FFUART、BTUART、STUART),但是PXA255/26x微处理器还附加了HWUART,serial_pxa_ports定义如下;
staticstructuart_pxa_portserial_pxa_ports[]={
{/*FFUART*/
.name="
FFUART"
.cken=CKEN_FFUART,
.port={
.type=PORT_PXA,
.iotype=UPIO_MEM,
.membase=(void*)&
FFUART,
.mapbase=__PREG(FFUART),
.irq=IRQ_FFUART,
.uartclk=921600*16,
.fifosize=64,
.ops=&
serial_pxa_pops,
.line=0,
},
},{/*BTUART*/
BTUART"
.cken=CKEN_BTUART,
BTUART,
.mapbase=__PREG(BTUART),
.irq=IRQ_BTUART,
.line=1,
},{/*STUART*/
STUART"
.cken=CKEN_STUART,
STUART,
.mapbase=__PREG(STUART),
.irq=IRQ_STUART,
.line=2,
},{/*HWUART*/
HWUART"
.cken=CKEN_HWUART,
HWUART,
.mapbase=__PREG(HWUART),
.irq=IRQ_HWUART,
.line=3,
}
第三步:
UART平台驱动注册
初始化函数然后调用平台驱动注册函数platform_driver_register(structplatform_driver*drv)注册UART驱动,该函数实际上定义有关“伪总线”(pseudo-bus)驱动的相关操作,Linux-2.6.x内核为简化一些片上系统(SoC)系统的集成外设和传统PC接插件的驱动接口,提出了“伪总线”的概念。
打开linux-2.6.22.10\drivers\Base\Platform.c文件,找到platform_driver_register函数:
intplatform_driver_register(structplatform_driver*drv)
drv->
driver.bus=&
platform_bus_type;
if(drv->
probe)
drv->
driver.probe=platform_drv_probe;
remove)
driver.remove=platform_drv_remove;
shutdown)
driver.shutdown=platform_drv_shutdown;
suspend)
driver.suspend=platform_drv_suspend;
resume)
driver.resume=platform_drv_resume;
returndriver_register(&
drv->
driver);
EXPORT_SYMBOL_GPL(platform_driver_register);
platform_driver_register函数中的serial_pxa_driver变量定义如下:
staticstructplatform_driverserial_pxa_driver={
.probe=serial_pxa_probe,
.remove=serial_pxa_remove,
.suspend=serial_pxa_suspend,
.resume=serial_pxa_resume,
.driver={
pxa2xx-uart"
该结构体实际上定义驱动探测(probe)、移除(remove)、挂起(suspend)、重启(resume)等相关函数操作:
\drivers\serial\pxa.c文件本质上完成对所有这些函数的实现。
UART驱动相关操作函数
第四步:
UART驱动侦测函数(probe)
staticintserial_pxa_probe(structplatform_device*dev)
serial_pxa_ports[dev->
id].port.dev=&
dev->
dev;
uart_add_one_port(&
serial_pxa_reg,&
serial_pxa_ports[dev->
id].port);
platform_set_drvdata(dev,&
id]);
return0;
UART驱动侦测函数serial_pxa_probe,首先获取基于平台设备的相关资源,然后调用uart_add_one_port函数实现将驱动和一个实际的端口结构体相关联,然后调用platform_set_drvdata函数将UART驱动添加到平台设备platform_device*dev中。
第五步:
UART驱动卸载函数(remove)
staticintserial_pxa_remove(structplatform_device*dev)
structuart_pxa_port*sport=platform_get_drvdata(dev);
platform_set_drvdata(dev,NULL);
if(sport)
uart_remove_one_port(&
sport->
port);
UART驱动卸载函数与UART驱动侦测函数恰好相反,首先利用platform_get_drvdata函数获取驱动相关数据,如果驱动存在,则利用uart_remove_one_port函数将驱动和实际端口结构体断开连接。
一般对于UART设备,这种情况只有在关闭操作系统时才存在。
第六步:
UART驱动的挂起与重启(suspend、resume)
UART驱动的挂起与重启在具有电源管理功能的系统中才可能发生,当系统进入低功耗或休眠状态,系统将调用serial_pxa_suspend函数使设备进入挂起状态,并将驱动的电源状态切换低功耗状态(3),如果系统被唤醒,则调用驱动的重启serial_pxa_resume,同时将驱动的电源状态切换到全功耗状态(0)。
staticintserial_pxa_suspend(structplatform_device*dev,pm_message_tstate)
uart_suspend_port(&
staticintserial_pxa_resume(structplatform_device*dev)
uart_resume_port(&
}
UART驱动操作
在PXA架构的UART驱动侦测函数(probe)调用uart_add_one_port(&
id].port)完成将驱动和一个实际的端口结构体相关联时,引用了使用serial_pxa_ports[dev->
id].port,而在uart_pxa_port结构体中的port成员变量中,嵌套了一个uart_ops结构体成员变量ops;
,它定义了串口硬件能完成的所有操作(如数据的收发等)。
下面为uart_ops结构体实例,该结构体实例过程实际上将一系列serial_pxa_函数赋值给了uart_ops结构体的成员。
structuart_opsserial_pxa_pops={
.tx_empty=serial_pxa_tx_empty,//发送缓冲区空
.set_mctrl=serial_pxa_set_mctrl,//设置modem控制(MCR)
.get_mctrl=serial_pxa_get_mctrl,//获取modem控制设置
.stop_tx=serial_pxa_stop_tx,//停止接收字符
.start_tx=serial_pxa_start_tx,//开始传输字符
.stop_rx=serial_pxa_stop_rx,//停止接收字符
.enable_ms=serial_pxa_enable_ms,//modem状态中断使能
.break_ctl=serial_pxa_break_ctl,//控制break信号的传输
.startup=serial_pxa_startup,//启动串口
.shutdown=serial_pxa_shutdown,//禁用串口
.set_termios=serial_pxa_set_termios,//改变串口参数
.pm=serial_pxa_pm,//端口电源管理
.type=serial_pxa_type,//返回描述特定端口的常量字符串指针
.release_port=serial_pxa_release_port,//释放串口占用的内存及IO资源
.request_port=serial_pxa_request_port,//申请串口所需的内存和IO资源
.config_port=serial_pxa_config_port,//执行端口所需的自动配置步骤
.verify_port=serial_pxa_verify_port,//验证新的串行端口信息
所有函数的原型定义中linux-2.6.22.10\include\Linux\Serial_core.h文件中structuart_ops结构体中:
/*
*Thisstructuredescribesalltheoperationsthatcanbe
*doneonthephysicalhardware.
*/
structuart_ops{
unsignedint(*tx_empty)(structuart_port*);
void(*set_mctrl)(structuart_port*,unsignedintmctrl);
unsignedint(*get_mctrl)(structuart_port*);
void(*stop_tx)(structuart_port*);
void(*start_tx)(structuart_port*);
void(*send_xchar)(structuart_port*,charch);
void(*stop_rx)(structuart_port*);
void(*enable_ms)(structuart_port*);
void(*break_ctl)(structuart_port*,intctl);
int(*startup)(structuart_port*);
void(*shutdown)(structuart_port*);
void(*set_termios)(structuart_port*,structktermios*new,
structktermios*old);
void(*pm)(structuart_port*,unsignedintstate,unsignedintoldstate);
int(*set_wake)(structuart_port*,unsignedintstate);
/*
*Returnastringdescribingthetypeoftheport
constchar*(*type)(structuart_port*);
*ReleaseIOandmemoryresourcesusedbytheport.
*Thisincludesiounmapifnecessary.
void(*release_port)(structuart_port*);
*RequestIOandmemoryresourcesusedbytheport.
*Thisincludesiomappingtheportifnecessary.
int(*request_port)(structuart_port*);
void(*config_port)(structuart_port*,int);
int(*verify_port)(structuart_port*,structserial_struct*);
int(*ioctl)(structuart_port*,unsignedint,unsignedlong);
set_mctrl()函数的原型为:
void(*set_mctrl)(structuart_port*,unsignedintmctrl);
它将参数port所对应的调制解调器控制线的值设为参数mctrl的值。
get_mctrl()函数的原型为:
unsignedint(*get_mctrl)(structuart_port*);
该函数返回调制解调器控制输入的现有状态,这些状态信息包括:
TIOCM_CD(CD信号状态)、TIOCM_CTS(CTS信号状态)、TIOCM_DSR(DSR信号状态)、TIOCM_RI(RI信号状态)等。
如果信号被置为有效,则对应位将被置位。
端口启动函数startup()的原型为:
int(*startup)(structuart_port*);
该函数申请所有中断资源,初始化底层驱动状态,并开启端口为可接收数据的状态。
shutdown()函数完成与startup()函数的作用相反,其原型:
void(*shutdown)(structuart_port*);
这个函数禁用端口,释放所有的中断资源。
下面主要对串口操作的启动与停止、数据的数据进行分析
第七步:
串口的启动与停止
串口驱动uart_ops结构体的startup()成员函数serial_pxa_startup用于启动端口,申请端口的发送、接收中断,使能端口的发送和接收,其实现如代码:
staticintserial_pxa_startup(structuart_port*port)
structuart_pxa_port*up=(structuart_pxa_port*)port;
unsignedlongflags;
intretval;
if(port->
line==3)/*HWUART*/
up->
mcr|=UART_MCR_AFE;
else
mcr=0;
*AllocatetheIRQ
retval=request_irq(up->
port.irq,serial_pxa_irq,0,up->
name,up);
if(retval)
returnretval;
*CleartheFIFObuffersanddisablethem.
*(theywillbereenabledinset_termios())
serial_out(up,UART_FCR,UART_FCR_ENABLE_FIFO);
serial_out(up,UART_FCR,UART_FCR_ENABLE_FIFO|
UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT);
serial_out(up,UART_FCR,0);
*Cleartheinterruptregisters.
(void)serial_in(up,UART_LSR);
(void)serial_in(up,UART_RX);
(void)serial_in(up,UART_IIR);
(void)serial_in(up,UART_MSR);
*Now,initializetheUART
serial_out(up,UART_LCR,UART_LCR_WLEN8);
spin_lock_irqsave(&
up->
port.lock,flags);
up->
port.mctrl|=TIOCM_OUT2;
serial_pxa_set_mctrl(&
port,up->
port.mctrl);
spin_unlock_irqrestore(&
*Finally,enableinterrupts.Note:
Modemstatusinterrupts
*aresetviaset_termios(),whichwillbeoccurringimminently
*anyway,sowedon'
tenablethemhere.
ier=UART_IER_RLSI|UART_IER_RDI|UART_IER_RTOIE|UART_IER_UUE;
serial_out(up,UART_IER,up->
ier);
*Andcleartheinterruptregistersagainforluck.
串口驱动uart_ops结构体的shutdown()成员函数serial_p
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 实验 101 UART驱动分析 UART 驱动 分析