#ifdef CONFIG_SERIAL_8250_AU1X00
/* if access method is AU, it is a 16550 with a quirk */
if (up->port.type == PORT_16550A && up->port.iotype == UPIO_AU) up->bugs |= UART_BUG_NOMSR; #endif
serial_outp(up, UART_LCR, save_lcr);
if (up->capabilities != uart_config[up->port.type].flags) { printk(KERN_WARNING
\ up->port.line, up->capabilities, uart_config[up->port.type].flags); }
up->port.fifosize = uart_config[up->port.type].fifo_size; up->capabilities = uart_config[up->port.type].flags; up->tx_loadsz = uart_config[up->port.type].tx_loadsz;
if (up->port.type == PORT_UNKNOWN) goto out;
/*
* Reset the UART.
*/
#ifdef CONFIG_SERIAL_8250_RSA
if (up->port.type == PORT_RSA)
serial_outp(up, UART_RSA_FRR, 0); #endif
serial_outp(up, UART_MCR, save_mcr); serial8250_clear_fifos(up);
serial_in(up, UART_RX);
if (up->capabilities & UART_CAP_UUE)
serial_outp(up, UART_IER, UART_IER_UUE); else
serial_outp(up, UART_IER, 0); out:
spin_unlock_irqrestore(&up->port.lock, flags);
DEBUG_AUTOCONF(\ }
最后,复位串口控制器
我们假设使用的是8250串口芯片.在芯片类型判断的时候就会进入autoconfig_8250().代码如下:
static void autoconfig_8250(struct uart_8250_port *up) {
unsigned char scratch, status1, status2;
up->port.type = PORT_8250;
scratch = serial_in(up, UART_SCR); serial_outp(up, UART_SCR, 0xa5); status1 = serial_in(up, UART_SCR); serial_outp(up, UART_SCR, 0x5a); status2 = serial_in(up, UART_SCR); serial_outp(up, UART_SCR, scratch);
if (status1 == 0xa5 && status2 == 0x5a)
up->port.type = PORT_16450; }
如果存在SCR寄存器,则芯片是16450类型的.这不是我们需要研究的芯片.
回到serial8250_config_port()中,代码片段如下所示:
static void serial8250_config_port(struct uart_port *port, int flags) {
…… ……
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); }
如果定义了自己控测IRQ号(CONFIG_SERIAL_8250_DETECT_IRQ).一般情况下,编译内核的时候一般都将其赋值为CONFIG_SERIAL_8250_DETECT_IRQ = y.此时就会进入autoconfig_irq().代码如下:
static void autoconfig_irq(struct uart_8250_port *up) {
unsigned char save_mcr, save_ier; unsigned char save_ICP = 0; unsigned int ICP = 0; unsigned long irqs; int irq;
if (up->port.flags & UPF_FOURPORT) { ICP = (up->port.iobase & 0xfe0) | 0x1f; save_ICP = inb_p(ICP); outb_p(0x80, ICP); (void) inb_p(ICP); }
/* forget possible initially masked and pending IRQ */ probe_irq_off(probe_irq_on());
save_mcr = serial_inp(up, UART_MCR); save_ier = serial_inp(up, UART_IER);
serial_outp(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2);
irqs = probe_irq_on();
serial_outp(up, UART_MCR, 0); udelay(10);
if (up->port.flags & UPF_FOURPORT) { serial_outp(up, UART_MCR,
UART_MCR_DTR | UART_MCR_RTS); } else {
serial_outp(up, UART_MCR,
UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); }
serial_outp(up, UART_IER, 0x0f); /* enable all intrs */ (void)serial_inp(up, UART_LSR); (void)serial_inp(up, UART_RX); (void)serial_inp(up, UART_IIR); (void)serial_inp(up, UART_MSR); serial_outp(up, UART_TX, 0xFF); udelay(20);
irq = probe_irq_off(irqs);
serial_outp(up, UART_MCR, save_mcr); serial_outp(up, UART_IER, save_ier);
if (up->port.flags & UPF_FOURPORT) outb_p(save_ICP, ICP);
up->port.irq = (irq > 0) ? irq : 0;
}
在上述代码的操作中,先将8250相关中断允许寄存器全打开.然后调用驱动使用的函数, 当它不得不探测来决定哪个中断线被设备在使用. probe_irq_on()将中断暂时关掉,然后配置MCR寄存器使之发送DTR和RTS.之后再用probe_irq_off()来检测IRQ号.如果检测成功,则值赋值
给port->irq.
进行到这里,conifg_port动作就完成了.
经过这个config_port过程后,我们发现,并没有对serial8250_isa_devs->dev-> platform_data赋值,也就是说platform_driver->probe函数并无实质性的处理.在第一次for循环的时,就会因条件不符而退出.
四: startup操作
在前面分析uart驱动架构的时候,曾说过,在open的时候,会调用port->startup().在本次分析的驱动中,对应接口为serial8250_startup().分段分析如下: static int serial8250_startup(struct uart_port *port) {
struct uart_8250_port *up = (struct uart_8250_port *)port; unsigned long flags; unsigned char lsr, iir; int retval;
up->capabilities = uart_config[up->port.type].flags; up->mcr = 0;
if (up->port.type == PORT_16C950) { /* Wake up and initialize UART */ up->acr = 0;
serial_outp(up, UART_LCR, 0xBF);
serial_outp(up, UART_EFR, UART_EFR_ECB); serial_outp(up, UART_IER, 0); serial_outp(up, UART_LCR, 0);
serial_icr_write(up, UART_CSR, 0); /* Reset the UART */ serial_outp(up, UART_LCR, 0xBF);
serial_outp(up, UART_EFR, UART_EFR_ECB); serial_outp(up, UART_LCR, 0); }
#ifdef CONFIG_SERIAL_8250_RSA
/*
* If this is an RSA port, see if we can kick it up to the * higher speed clock. */
enable_rsa(up); #endif /*
* Clear the FIFO buffers and disable them. * (they will be reenabled in set_termios()) */
serial8250_clear_fifos(up);
上面的代码都不是对应8250芯片的情况 /*
* Clear the interrupt registers. */
(void) serial_inp(up, UART_LSR); (void) serial_inp(up, UART_RX); (void) serial_inp(up, UART_IIR); (void) serial_inp(up, UART_MSR); 复位LSR,RX,IIR,MSR寄存器
/*
* At this point, there's no way the LSR could still be 0xff; * if it is, then bail out, because there's likely no UART * here.
*/
if (!(up->port.flags & UPF_BUGGY_UART) &&
(serial_inp(up, UART_LSR) == 0xff)) {
printk(\ return -ENODEV; }
若LSR寄存器中的值为0xFF.异常
/*
* For a XR16C850, we need to set the trigger levels */
if (up->port.type == PORT_16850) { unsigned char fctr;
serial_outp(up, UART_LCR, 0xbf);
fctr = serial_inp(up, UART_FCTR) & ~(UART_FCTR_RX|UART_FCTR_TX); serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_RX); serial_outp(up, UART_TRG, UART_TRG_96);
serial_outp(up, UART_FCTR, fctr | UART_FCTR_TRGD | UART_FCTR_TX); serial_outp(up, UART_TRG, UART_TRG_96);
serial_outp(up, UART_LCR, 0); }
16850系列芯片的处理,忽略
if (is_real_interrupt(up->port.irq)) { /*
* Test for UARTs that do not reassert THRE when the * transmitter is idle and the interrupt has already * been cleared. Real 16550s should always reassert