- [root@localhost dev]# ls -l tty
- crw-rw-rw- 1 root tty 5, 0 2012-01-30 17:26 tty
- [root@localhost dev]# ls -l tty0
- crw--w---- 1 root root 4, 0 2012-01-30 17:26 tty0
- [root@localhost dev]# ls -l console
- crw------- 1 root root 5, 1 2012-01-30 17:26 console
如果当前进程有控制终端(Controlling Terminal)的话,那么/dev/tty就是当前进程的控制终端的设备特殊文件。可以使用命令”ps –ax”来查看进程与哪个控制终端相连。对于你登录的shell,/dev/tty就是你使用的终端,设备号是(5,0)。使用命令”tty”可以查看它具体对应哪个实际终端设备。
控制终端可以是Xwindows模式下的伪终端(/dev/pts/*),也可以是控制台虚拟终端(/dev/tty*)
- if (device == MKDEV(5, 0)) {
-
tty = get_current_tty();
-
if (!tty) {
-
mutex_unlock(&tty_mutex);
-
return -ENXIO;
-
}
-
driver = tty_driver_kref_get(tty->driver);
-
index = tty->index;
-
filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
-
/* noctty = 1; */
-
/* FIXME: Should we take a driver reference ? */
-
tty_kref_put(tty);
-
goto got_driver;
- }
2./dev/tty0则是当前所使用虚拟终端的一个别名
- # tty(查看当前TTY)
- /dev/tty1
- #echo "test tty0" > /dev/tty0
- test tty0
- if (device == MKDEV(4, 0)) {
-
extern struct tty_driver *console_driver;
-
driver = tty_driver_kref_get(console_driver);
-
index = fg_console;
-
noctty = 1;
-
goto got_driver;
- }
3./dev/console即控制台,是与操作系统交互的设备,系统将一些信息直接输出到控制台上
内核实现如下:
- if (device == MKDEV(5, 1)) {
-
struct tty_driver *console_driver = console_device(&index);//如何通过这一句得到tty_driver结构呢,这个结构是哪里来的?我们稍候会提到
-
if (console_driver) {
-
driver = tty_driver_kref_get(console_driver);
-
if (driver) {
-
/* Don't let /dev/console block */
-
filp->f_flags |= O_NONBLOCK;
-
noctty = 1;
-
goto got_driver;
-
}
-
}
-
mutex_unlock(&tty_mutex);
-
return -ENODEV;
- }
在8250.c里,有如下代码:
- static struct console serial8250_console = {
-
.name = "ttyS",
-
.write = serial8250_console_write,
-
.device = uart_console_device,
-
.setup = serial8250_console_setup,
-
.early_setup = serial8250_console_early_setup,
-
.flags = CON_PRINTBUFFER,
-
.index = -1,
-
.data = &serial8250_reg,
-
};
-
-
static int __init serial8250_console_init(void)
-
{
-
if (nr_uarts > UART_NR)
-
nr_uarts = UART_NR;
-
-
serial8250_isa_init_ports();
-
register_console(&serial8250_console);
-
return 0;
- }
而console_device函数遍历console_drivers以得到一个有效的console,得到有效的console以后(在这个例子里,当然会得到serial8250_console),然后会调用他的device方法以得到相应的tty_driver结构,serial8250_console结构的device方法为uart_console_device,uart_console_device的内容如下:
- struct tty_driver *uart_console_device(struct console *co, int *index)
-
{
-
struct uart_driver *p = co->data;
-
*index = co->index;
-
return p->tty_driver;
- }
- static struct uart_driver serial8250_reg = {
-
.owner = THIS_MODULE,
-
.driver_name = "serial",
-
.dev_name = "ttyS",
-
.major = TTY_MAJOR,
-
.minor = 64,
-
.cons = SERIAL8250_CONSOLE,
- };
这样通过/dev/console和具体的uart驱动联系起来,通过co->index,又和具体的uart设备联系了起来,这样,内核通过/dev/console就可以操作串口,进行内核信息的输出了。
内核使用/dev/console的地方为kernel初始化的时候:
start_kernel->rest_init->kernel_init->init_post
- static noinline int init_post(void)
__releases(kernel_lock)
{ - ...
- if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
-
printk(KERN_WARNING "Warning: unable to open an initial console.\n");
-
-
(void) sys_dup(0);
- (void) sys_dup(0);
- ...
这是为调用init进程做准备,之后内核将通过kernel_execve()调用init进程,这样,init进程的输入、输出和错误输出就全部重定向到/dev/console对应的uart设备了.
因为用户应用程序全部为init进程的子或孙进程,所以,默认情况下,用户应用程序的输入、输出和错误输出也全部重定向到了/dev/console对应的uart设备了。