i++,up++){
up->port.iobase=old_serial_port[i].port;
up->port.irq=irq_canonicalize(old_serial_port[i].irq);
up->port.uartclk=old_serial_port[i].baud_base*16;
up->port.flags=old_serial_port[i].flags;
up->port.hub6=old_serial_port[i].hub6;
up->port.membase=old_serial_port[i].iomem_base;
up->port.iotype=old_serial_port[i].io_type;
up->port.regshift=old_serial_port[i].iomem_reg_shift;
if(share_irqs)
up->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);
serial8250_isa_driver定义如下:
staticstructplatform_driverserial8250_isa_driver={
.probe=serial8250_probe,
.remove=__devexit_p(serial8250_remove),
.suspend=serial8250_suspend,
.resume=serial8250_resume,
.driver={
.name="serial8250",
.owner=THIS_MODULE,
},
}
为了以后把分析集中到具体的驱动部份.我们先把这个platform_driver引会的事件讲述完.
经过前面有关platform的分析我们知道.这个platform的name为”serial8250”.刚好跟前面注册的platform_device相匹配.会调用platform_driver->probe.在这里,对应的接口为:
serial8250_probe().代码如下:
staticint__devinitserial8250_probe(structplatform_device*dev)
{
structplat_serial8250_port*p=dev->dev.platform_data;
structuart_portport;
intret,i;
memset(&port,0,sizeof(structuart_port));
for(i=0;p&&p->flags!
=0;p++,i++){
port.iobase=p->iobase;
port.membase=p->membase;
port.irq=p->irq;
port.uartclk=p->uartclk;
port.regshift=p->regshift;
port.iotype=p->iotype;
port.flags=p->flags;
port.mapbase=p->mapbase;
port.hub6=p->hub6;
port.private_data=p->private_data;
port.dev=&dev->dev;
if(share_irqs)
port.flags|=UPF_SHARE_IRQ;
ret=serial8250_register_port(&port);
if(ret<0){
dev_err(&dev->dev,"unabletoregisterportatindex%d"
"(IO%lxMEM%llxIRQ%d):
%d\n",i,
p->iobase,(unsignedlonglong)p->mapbase,
p->irq,ret);
}
}
return0;
}
从上述代码可以看出.会将dev->dev.platform_data所代表的port添加到uart_driver中.这个dev->dev.platform_data究竟代表什么.我们在看到的时候再来研究它.
现在,我们把精力集中到uart_port的操作上.
三:
config_port过程
在初始化uart_port的过程中,在以下代码片段:
serial8250_isa_init_ports(void)
{
……
……
for(i=0,up=serial8250_ports;
ii++,up++){
up->port.iobase=old_serial_port[i].port;
up->port.irq=irq_canonicalize(old_serial_port[i].irq);
up->port.uartclk=old_serial_port[i].baud_base*16;
up->port.flags=old_serial_port[i].flags;
up->port.hub6=old_serial_port[i].hub6;
up->port.membase=old_serial_port[i].iomem_base;
up->port.iotype=old_serial_port[i].io_type;
up->port.regshift=old_serial_port[i].iomem_reg_shift;
if(share_irqs)
up->port.flags|=UPF_SHARE_IRQ;
}
}
而old_serial_port又定义如下:
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*/
由此可见.port->flags被定义成了STD_COM_FLAGS,定义如下:
#ifdefCONFIG_SERIAL_DETECT_IRQ
#defineSTD_COM_FLAGS(ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST|ASYNC_AUTO_IRQ)
#defineSTD_COM4_FLAGS(ASYNC_BOOT_AUTOCONF|ASYNC_AUTO_IRQ)
#else
#defineSTD_COM_FLAGS(ASYNC_BOOT_AUTOCONF|ASYNC_SKIP_TEST)
#defineSTD_COM4_FLAGSASYNC_BOOT_AUTOCONF
#endif
从这里看到,不管是否自己探测IRQ,都会定义ASYNC_BOOT_AUTOCONF.这样,在uart_add_one_port()的时候.就会进入到port->config_port来配置端口.在8250中,对应的接口为:
serial8250_config_port().代码如下:
staticvoidserial8250_config_port(structuart_port*port,intflags)
{
structuart_8250_port*up=(structuart_8250_port*)port;
intprobeflags=PROBE_ANY;
intret;
/*
*Findtheregionthatwecanprobefor.Thisinturn
*tellsuswhetherwecanprobeforthetypeofport.
*/
ret=serial8250_request_std_resource(up);
if(ret<0)
return;
ret=serial8250_request_rsa_resource(up);
if(ret<0)
probeflags&=~PROBE_RSA;
if(flags&UART_CONFIG_TYPE)
autoconfig(up,probeflags);
if(up->port.type!
=PORT_UNKNOWN&&flags&UART_CONFIG_IRQ)
autoconfig_irq(up);
if(up->port.type!
=PORT_RSA&&probeflags&PROBE_RSA)
serial8250_release_rsa_resource(up);
if(up->port.type==PORT_UNKNOWN)
serial8250_release_std_resource(up);
}
serial8250_request_std_resource和serial8250_request_rsa_resource都是分配操作的端口.回顾在前面的分析中.port的相关参数会从old_serial_port中取得.而old_serial_port中又没有定义port->iotype和port->regshift.也就是说对应这两项全为0.而
#defineUPIO_PORT(0)
即表示是要操作I/O端口.
自己阅读这两个函数代表.会发现在serial8250_request_rsa_resource()中是会返回失败的.
另外,在uart_add_one_port()在进行端口匹配时,会先置flags为UART_CONFIG_TYPE.
这样,在本次操作中,if(flags&UART_CONFIG_TYPE)是会满足的.相应的就会进入autoconfig().
代码如下,这段代码比较长,分段分析如下:
staticvoidautoconfig(structuart_8250_port*up,unsignedintprobeflags)
{
unsignedcharstatus1,scratch,scratch2,scratch3;
unsignedcharsave_lcr,save_mcr;
unsignedlongflags;
if(!
up->port.iobase&&!
up->port.mapbase&&!
up->port.membase)
return;
DEBUG_AUTOCONF("ttyS%d:
autoconf(0x%04x,0x%p):
",
up->port.line,up->port.iobase,up->port.membase);
/*
*WereallydoneedglobalIRQsdisabledhere-we'regoingto
*befrobbingthechipsIRQenableregistertoseeifitexists.
*/
spin_lock_irqsave(&up->port.lock,flags);
up->capabilities=0;
up->bugs=0;
if(!
(up->port.flags&UPF_BUGGY_UART)){
/*
*Doasimpleexistencetestfirst;ifwefailthis,
*there'snopointtryinganythingelse.
*
*0x80isusedasanonsenseporttopreventagainst
*falsepositivesduetoISAbusfloat.The
*assumptionisthat0x80isanon-existentport;
*whichshouldbesafesinceinclude/asm/io.halso
*makesthisassumption.
*
*Note:
thisissafeaslongasMCRbit4isclear
*andthedeviceisin"PC"