linux设备驱动之8250串口驱动(3)

2019-04-08 22:11

#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


linux设备驱动之8250串口驱动(3).doc 将本文的Word文档下载到电脑 下载失败或者文档不完整,请联系客服人员解决!

下一篇:曾仕强经典语录

相关阅读
本类排行
× 注册会员免费下载(下载后可以自由复制和排版)

马上注册会员

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: