现在的位置: 首页 > 综合 > 正文

修正串口控制台无法输入的BUG

2013年10月09日 ⁄ 综合 ⁄ 共 1985字 ⁄ 字号 评论关闭

问题:输入字符,没有回显,输入命令没有输出

4020使用的串口完全兼容8250,8250调用串口顺序如下:

serial8250_interrupt(串口芯片层)->
seirial8250_handle_port(串口芯片层)->
   receive_chars(串口芯片层)->
    uart_insert_char(串口抽象层)->
     tty_insert_flip_char(终端设备层)//保存受到的数据及其他标记是否有错误
    tty_flip_buffer_push(终端设备层)->
     flush_to_idisc(终端设备层)->
      disc->receive_buf,即n_tty_receive_buf(行规层)->
       n_tty_receive_char(行规层)->
        n_tty_receive_char(终端设备层)->
         echo_char(回显)

可以看出要经过这么多层调用才会出现echo_char(),回显你输入的字符,经过排查,我们发现问题出在tty_io.c的函数:
tty_flip_buffer_push()

void tty_flip_buffer_push(struct tty_struct *tty)
{
unsigned long flags;
spin_lock_irqsave(&tty->buf.lock, flags);
if (tty->buf.tail != NULL) {
   tty->buf.tail->active = 0;
   tty->buf.tail->commit = tty->buf.tail->used;
}
spin_unlock_irqrestore(&tty->buf.lock, flags);

if (tty->low_latency)
   flush_to_ldisc((void *) tty);
else
   schedule_delayed_work(&tty->buf.work, 1);

其中
if (tty->low_latency)
   flush_to_ldisc((void *) tty);

low_latency的值一直为0,所以进不了flush_to_ldisc()。

在《linux内核驱动第三版》中提到:

“如果 tty 驱动可高速接收数据, tty->low_latency 标志应当设置,
它是对 tty_flip_buffer_pus 的调用被立刻执行当调用时. 否则, tty_flip_buffer_push
调用会调度它自己来将数据推出缓冲, 在之后近期的一个时间点.”

可惜还是不懂是什么意思,跟踪这个函数的赋值情况,发现在serial_core.c以下函数中有调用:

uart_open()

* Once we set tty->driver_data here, we are guaranteed that
* uart_close() will decrement the driver module use count.
* Any failures from here onwards should not touch the count.
*/
tty->driver_data = state;
tty->low_latency = (state->port->flags & UPF_LOW_LATENCY) ? 1 : 0;
tty->alt_speed = 0;
state->info->tty = tty;

其中这句话tty->low_latency = (state->port->flags & UPF_LOW_LATENCY) ? 1 : 0;,对low_latency变量进行了赋值,还有个open函数也进行了同样的赋值。

UPF_LOW_LATENCY是一个宏定义,在serial_core.h中有定义:

#define UPF_LOW_LATENCY   ((__force upf_t) (1 << 13))

因此赋值语句的含义:是state->port->flags中需要对UPF_LOW_LATENCY位进行赋值。解决方法如下:
在/arch/arm/Machsep-4020/4020.c文件中对uart初始话的flag结构中添加UPF_LOW_LATENCY位

static struct plat_serial8250_port serial_platform_data[] = {
{
   .membase = (void*)UART0_BASE_V,
   .mapbase = UART0_BASE,
   .irq   = INTSRC_UART0,
   .uartclk = 88000000,
   .regshift = 2,
   .iotype   = UPIO_MEM,
.flags   = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_LOW_LATENCY,
},

重新编译,可以正确操作控制台输入输出。

抱歉!评论已关闭.