1.tty概念分析
- 在Linux系统中,终端是一类字符型设备,它包括多种类型,通常使用tty来简称各种类型的终端设备。由于串口也是一种终端,因此这里引入终端这个概念
- 串口终端(/dev/ttyS*)
<ul><li>串口终端是使用计算机串口连接的终端设备。Linux把每个串行端口都看作是一个字符设备。这些串行端口所对应的设备名称是<strong> /dev/ttySAC0;/dev/ttySAC1……</strong></li> </ul></li> <li>控制台终端(<strong>/dev/console</strong>) <ul><li>在Linux系统中,计算机的输出设备通常被称为<strong>控制台终端(Console)</strong>,这里特指printk信息输出到的设备。<strong>/dev/console</strong>是一个虚拟的设备,它需要映射到真正的tty(物理终端)上,比如通过内核启动参数” <strong>console=ttySAC0</strong>”就把console映射到了串口0。</li> </ul></li> <li>虚拟终端(<strong>/dev/tty*</strong>) <ul><li>当用户登录时,使用的是虚拟终端。使用Ctcl+Alt+[F1—F6]组合键时,我们就可以切换到tty1、tty2、tty3等上面去。tty1–tty6等称为虚拟终端,而tty0则是当前所使用虚拟终端的一个别名。</li> </ul></li> </ul></li> <li>在Linux内核中printk函数处理是交给控制台终端的,控制台终端又把它映射到串口终端或者屏幕终端上。而虚拟终端更多是在应用程序中使用。</li>
- 串口终端(/dev/ttyS*)
2.tty架构解析
- Linux tty子系统包含:tty核心,tty线路规程和tty驱动。tty核心是对整个tty设备的抽象,对用户提供统一的接口,tty线路规程是对传输数据的格式化,tty驱动则是面向tty设备的硬件驱动。它们的关系如下图。
- 表现在代码实现中,流程就是下面图片描述的。
3.回溯串口数据发送
- ttty最底层的发送函数:
-
static void s3c24xx_serial_start_tx(struct uart_port *port)
-
{
-
struct s3c24xx_uart_port *ourport = to_ourport(port);
-
-
dump_stack();
// 回溯函数的调用关系
-
-
if (!tx_enabled(port)) {
-
if (port->flags & UPF_CONS_FLOW)
-
s3c24xx_serial_rx_disable(port);
-
-
enable_irq(ourport->tx_irq);
-
tx_enabled(port) =
1;
-
}
-
}
- 在源码中加入dump_stack(),回溯函数的调用关系。
- 对内核代码重新编译,下载到开发板,终端打印回溯信息:
-
[<c018dddc>] (s3c24xx_serial_start_tx+
0x0/
0x64) from [<c018a114>] (uart_start+
0x68/
0x6c)
-
r5:c38c5800 r4:
60000013
-
-
[<c018a0ac>] (uart_start+
0x0/
0x6c) from [<c018b9ec>] (uart_write+
0xc0/
0xe0)
-
r5:c38c5800 r4:
00000000
-
[<c018b92c>] (uart_write+
0x0/
0xe0) from [<c0176c0c>] (n_tty_write+
0x1d8/
0x448)
-
[<c0176a34>] (n_tty_write+
0x0/
0x448) from [<c0174258>] (tty_write+
0x14c/
0x244)
-
-
[<c017410c>] (tty_write+
0x0/
0x244) from [<c01743d8>] (redirected_tty_write+
0x88/
0x98)
-
[<c0174350>] (redirected_tty_write+
0x0/
0x98) from [<c009ca6c>] (vfs_write+
0xb4/
0xe8)
-
r9:c397e000 r8:c00300c8 r7:
00000004 r6:c397ff78 r5:
40000000
-
r4:c3960100
- 去掉系统调用接口和内核服务例程相关函数。
- redirected_tty_write()函数调用tty核心tty_write(),tty_write()调用线路规程里面的ldisc.write(),然后调用n_tty_write()、uart_start(),最后调用tty驱动函数s3c24xx_serial_start_tx()。