您的位置:首页 > 运维架构 > Linux

LINUX下TTY、CONSOLE、串口之间的关系收集

2011-10-02 21:55 393 查看
1、LINUX下TTY、CONSOLE、串口之间是怎样的层次关系?具体的函数接口是怎样的?串口是如何被调用的?

tty和console这些概念主要是一些虚设备的概念,而串口更多的是指一个真正的设备驱动。

Tty实际是一类终端I/O设备的抽象,它实际上更多的是一个管理的概念,它和tty_ldisc(行规程)和tty_driver(真实设备驱动)组合在一起,目的是向上层的VFS提供一个统一的接口。通过file_operations结构中的tty_ioctl可以对其进行配置。查tty_driver,你将得到n个结果,实际都是相关芯片的驱动。因此,可以得到的结论是(实际情况比这复杂得多):每个描述tty设备的tty_struct在初始化时必然挂如了某个具体芯片的字符设备驱动(不一定是字符设备驱动),可以是很多,包括显卡或串口chip。不知道你的ARM
Soc是那一款,不过看情况你们应该用的是常见的chip,这些驱动实际上都有。

而console是一个缓冲的概念,它的目的有一点类似于tty。实际上console不仅和tty连在一起,还和framebuffer连在一起,具体的原因看下面的键盘的中断处理过程。Tty的一个子集需要使用console(典型的如主设备号4,次设备号1―64),但是要注意的是没有console的tty是存在的。

而串口则指的是tty_driver。

举个典型的例子:

分析一下键盘的中断处理过程:

keyboard_interrupt―>handle_kbd_event―>handle_keyboard_event―>handle_scancode

void handle_scancode(unsigned char scancode, int down)

{

……..

tty = ttytab? ttytab[fg_console]: NULL;

if (tty && (!tty->driver_data)) {

……………

tty = NULL;

}

………….

schedule_console_callback();

}

这段代码中的两个地方很值得注意,也就是除了获得tty外(通过全局量tty记录),还进行了console 回显schedule_console_callback。Tty和console的关系在此已经很明了!!!

2、printk函数是把信息发送到控制台上吧?如何让PRINTK把信息通过串口送出?或者说系统在什么地方来决定是将信息送到显示器还是串口?

具体看一下printk函数的实现就知道了,printk不一定是将信息往控制台上输出,设置kernel的启动参数可能可以打到将信息送到显示器的效果。

函数前有一段英文,很有意思:

/*This is printk. It can be called from any context. We want it to work.

*

* We try to grab the console_sem. If we succeed, it's easy - we log the output and

* call the console drivers. If we fail to get the semaphore we place the output

* into the log buffer and return. The current holder of the console_sem will

* notice the new output in release_console_sem() and will send it to the

* consoles before releasing the semaphore.

*

* One effect of this deferred printing is that code which calls printk() and

* then changes console_loglevel may break. This is because console_loglevel

* is inspected when the actual printing occurs.

*/

这段英文的要点:要想对console进行操作,必须先要获得console_sem信号量。如果获得console_sem信号量,则可以“log the output and call the console drivers”,反之,则“place the output into the log buffer and return”,实际上,在代码:

asmlinkage int printk(const char *fmt, ...)

{

va_list args;

unsigned long flags;

int printed_len;

char *p;

static char printk_buf[1024];

static int log_level_unknown = 1;

if (oops_in_progress) { /*如果为1情况下,必然是系统发生crush*/

/* If a crash is occurring, make sure we can't deadlock */

spin_lock_init(&logbuf_lock);

/* And make sure that we print immediately */

init_MUTEX(&console_sem);

}

/* This stops the holder of console_sem just where we want him */

spin_lock_irqsave(&logbuf_lock, flags);

/* Emit the output into the temporary buffer */

va_start(args, fmt);

printed_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);/*对传入的buffer进行处理,注意还不是

真正的对终端写,只是对传入的string进行格式解析*/

va_end(args);

/*Copy the output into log_buf. If the caller didn't provide appropriate log level tags, we insert them here*/

/*注释很清楚*/

for (p = printk_buf; *p; p++) {

if (log_level_unknown) {

if (p[0] != '<' || p[1] < '0' || p[1] > '7' || p[2] != '>') {

emit_log_char('<');

emit_log_char(default_message_loglevel + '0');

emit_log_char('>');

}

log_level_unknown = 0;

}

emit_log_char(*p);

if (*p == '/n')

log_level_unknown = 1;

}

if (!arch_consoles_callable()) {

/*On some architectures, the consoles are not usable on secondary CPUs early in the boot process.*/

spin_unlock_irqrestore(&logbuf_lock, flags);

goto out;

}

if (!down_trylock(&console_sem)) {

/*We own the drivers. We can drop the spinlock and let release_console_sem() print the text*/

spin_unlock_irqrestore(&logbuf_lock, flags);

console_may_schedule = 0;

release_console_sem();

} else {

/*Someone else owns the drivers. We drop the spinlock, which allows the semaphore holder to

proceed and to call the console drivers with the output which we just produced.*/

spin_unlock_irqrestore(&logbuf_lock, flags);

}

out:

return printed_len;

}

实际上printk是将format后的string放到了一个buffer中,在适当的时候再加以show,这也回答了在start_kernel中一开始就用到了printk函数的原因

3、start_kernel中一开始就用到了printk函数(好象是printk(linux_banner什么的),在这个时候整个内核还没跑起来呢。那这时候的printk是如何被调用的?在我们的系统中,系统启动是用的现代公司的BOOTLOADER程序,后来好象跳到了LINUX下的head-armv.s, 然后跳到start_kernel,在bootloader 里串口已经是可用的了,那么在进入内核后是不是要重新设置?

Bootloader一般会做一些基本的初始化,将kernel拷贝物理空间,然后再跳到kernel去执行。可以肯定的是kernel肯定要对串口进行重新设置,原因是Bootloader有很多种,有些不一定对串口进行设置,内核不能依赖于bootloader而存在
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: