linux设备驱动之8250串口驱动Word文档格式.docx
《linux设备驱动之8250串口驱动Word文档格式.docx》由会员分享,可在线阅读,更多相关《linux设备驱动之8250串口驱动Word文档格式.docx(36页珍藏版)》请在冰豆网上搜索。
Serial:
8250/16550driver$Revision:
1.90$"
"
%dports,IRQsharing%sabled\n"
nr_uarts,
share_irqs?
en"
:
dis"
);
for(i=0;
i<
NR_IRQS;
i++)
spin_lock_init(&
irq_lists[i].lock);
ret=uart_register_driver(&
serial8250_reg);
if(ret)
gotoout;
serial8250_isa_devs=platform_device_alloc("
serial8250"
PLAT8250_DEV_LEGACY);
if(!
serial8250_isa_devs){
ret=-ENOMEM;
gotounreg_uart_drv;
}
ret=platform_device_add(serial8250_isa_devs);
gotoput_dev;
serial8250_register_ports(&
serial8250_reg,&
serial8250_isa_devs->
dev);
ret=platform_driver_register(&
serial8250_isa_driver);
if(ret==0)
platform_device_del(serial8250_isa_devs);
put_dev:
platform_device_put(serial8250_isa_devs);
unreg_uart_drv:
uart_unregister_driver(&
out:
returnret;
}
这段代码涉及到的知识要求,如platform,uart等我们在之前都已经做过详细的分析。
这里不再重复。
在代码中UART_NR:
表示串口的个数。
这个参数在编译内核的时候可以自己配置,默认为32。
我们按照代码中的流程一步一步进行研究。
1:
注册uart_driver.
对应uart-driver的结构为serial8250_reg.定义如下:
staticstructuart_driverserial8250_reg={
.owner=THIS_MODULE,
.driver_name="
serial"
.dev_name="
ttyS"
.major=TTY_MAJOR,
.minor=64,
.nr=UART_NR,
.cons=SERIAL8250_CONSOLE,
};
TTY_MAJOR定义如下:
#defineTTY_MAJOR4
从上面可以看出。
串口对应的设备节点为/dev/ttyS0~/dev/ttyS0(UART_NR).设备节点号为(4。
64)起始的UART_NR个节点..
2:
初始化并注册platform_device
相关代码如下:
serial8250_isa_devs=platform_device_alloc("
PAT8250_DEV_LEGACY);
platform_device_add(serial8250_isa_devs);
可以看出。
serial8250_isa_devs.->
name为serial8250。
这个参数是在匹配platform_device和platform_driver使用的.
3:
为uart-driver添加port.
serial8250_register_ports(&
dev)
跟进这个函数看一下:
staticvoid__init
serial8250_register_ports(structuart_driver*drv,structdevice*dev)
inti;
serial8250_isa_init_ports();
nr_uarts;
i++){
structuart_8250_port*up=&
serial8250_ports[i];
up->
port.dev=dev;
uart_add_one_port(drv,&
up->
port);
在这里函数里,初始化了port.然后将挂添加到uart-driver中。
我们还注意到。
生成的deivce节点,在sysfs中是位于platform_deivce对应目录的下面.
serial8250_isa_init_ports()代码如下所示:
staticvoid__initserial8250_isa_init_ports(void)
structuart_8250_port*up;
staticintfirst=1;
first)
return;
first=0;
port.line=i;
port.lock);
init_timer(&
timer);
timer.function=serial8250_timeout;
/*
*ALPHA_KLUDGE_MCRneedstobekilled.
*/
mcr_mask=~ALPHA_KLUDGE_MCR;
mcr_force=ALPHA_KLUDGE_MCR;
port.ops=&
serial8250_pops;
for(i=0,up=serial8250_ports;
ARRAY_SIZE(old_serial_port)&
&
i++,up++){
port.iobase=old_serial_port[i].port;
port.irq=irq_canonicalize(old_serial_port[i].irq);
port.uartclk=old_serial_port[i].baud_base*16;
port.flags=old_serial_port[i].flags;
port.hub6=old_serial_port[i].hub6;
port.membase=old_serial_port[i].iomem_base;
port.iotype=old_serial_port[i].io_type;
port.regshift=old_serial_port[i].iomem_reg_shift;
if(share_irqs)
port.flags|=UPF_SHARE_IRQ;
在这里,我们关注一下注要成员的初始化。
Uart_port的各项操作位于serial8250_pops中.iobaseirq等成员是从old_serial_por这个结构中得来的,这个结构如下所示:
staticconststructold_serial_portold_serial_port[]={
SERIAL_PORT_DFNS/*definedinasm/serial.h*/
#defineSERIAL_PORT_DFNS
/*UARTCLKPORTIRQFLAGS*/
{0,BASE_BAUD,0x3F8,4,STD_COM_FLAGS},/*ttyS0*/
{0,BASE_BAUD,0x2F8,3,STD_COM_FLAGS},/*ttyS1*/
{0,BASE_BAUD,0x3E8,4,STD_COM_FLAGS},/*ttyS2*/
{0,BASE_BAUD,0x2E8,3,STD_COM4_FLAGS},/*ttyS3*/
从上面看到。
前两项对应了com1com2的各项参数。
如寄存器首始地址,Irq号等。
后面两项不太清楚。
在上面的代码中,我们看到了uart_port各项成员的初始化。
在后面很多操作中需要用到这个成员。
我们等分析相关部份的时候,再到这个地方来看相关成员的值。
4:
注册platform_driver
platform_driver_register(&
serial8250_isa_driver定义如下:
staticstructplatform_driverserial8250_isa_driver={
.probe=serial8250_probe,
.remove=__devexit_p(serial8250_remove),
.suspend=serial8250_suspend,
.resume=serial8250_resume,
.driver={
.name="
},
为了以后把分析集中到具体的驱动部份.我们先把这个platform_driver引会的事件讲述完.
经过前面有关platform的分析我们知道.这个platform的name为”serial8250”.刚好跟前面注册的platform_device相匹配.会调用platform_driver->
probe.在这里,对应的接口为:
serial8250_probe().代码如下:
st