時間:2015-06-28 00:00:00 來源:IT貓撲網(wǎng) 作者:網(wǎng)管聯(lián)盟 我要評論(0)
一:前言
我們在之前分析過input子系統(tǒng)和tty設(shè)備驅(qū)動架構(gòu).今天需要將兩者結(jié)合起來.看看linux中的控制臺是怎么樣實現(xiàn)的.
二:控制臺驅(qū)動的初始化
之前在分析tty驅(qū)動架構(gòu)的時候曾分析到.主設(shè)備為4,次設(shè)備為0的設(shè)備節(jié)點,即/dev/tty0為當前的控制終端.
有tty_init()中,有以下代碼段:
static int __init tty_init(void)
{
……
……
#ifdef CONFIG_VT
cdev_init(&vc0_cdev, &console_fops);
if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
panic("Couldn't register /dev/tty0 driver\n");
device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), "tty0");
vty_init();
#endif
return 0;
}
CONFIG_VT:是指配置虛擬終端.即我們所說的控制臺.在此可以看到TTY_MAJOR(4),0對應(yīng)的設(shè)備節(jié)點操作集為console_fops.
繼續(xù)跟進vty_init()
int __init vty_init(void)
{
vcs_init();
console_driver = alloc_tty_driver(MAX_NR_CONSOLES);
if (!console_driver)
panic("Couldn't allocate console driver\n");
console_driver->owner = THIS_MODULE;
console_driver->name = "tty";
console_driver->name_base = 1;
console_driver->major = TTY_MAJOR;
console_driver->minor_start = 1;
console_driver->type = TTY_DRIVER_TYPE_CONSOLE;
console_driver->init_termios = tty_std_termios;
console_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
tty_set_operations(console_driver, &con_ops);
if (tty_register_driver(console_driver))
panic("Couldn't register console driver\n");
kbd_init();
console_map_init();
#ifdef CONFIG_PROM_CONSOLE
prom_con_init();
#endif
#ifdef CONFIG_MDA_CONSOLE
mda_console_init();
#endif
return 0;
}
經(jīng)過我們之前的tty驅(qū)動架構(gòu)分析,這段代碼看起來就比較簡單了,它就是注冊了一個tty驅(qū)動.這個驅(qū)動對應(yīng)的操作集是位于con_ops里面的.
仔細看.在之后還會調(diào)用kbd_init().顧名思義,這個是一個有關(guān)鍵盤的初始化.控制終端跟鍵盤有什么關(guān)系呢?在之前分析tty的時候,曾提到過,. 對于控制臺而言,它的輸入設(shè)備是鍵盤鼠標,它的輸出設(shè)備是當前顯示器.這兩者是怎么關(guān)聯(lián)起來的呢?不著急.請看下面的分析.
三:控制臺的open操作
在前面分析了,對應(yīng)console的操作集為con_ops.定義如下:
static const struct file_operations console_fops = {
.llseek??? = no_llseek,
.read = tty_read,
.write????? = redirected_tty_write,
.poll???? = tty_poll,
.ioctl??? = tty_ioctl,
.compat_ioctl??? = tty_compat_ioctl,
.open????? = tty_open,
.release??? = tty_release,
.fasync?? = tty_fasync,
};
里面的函數(shù)指針值我們都不陌生了,在之前分析的tty驅(qū)動中已經(jīng)分析過了.
結(jié)合前面的tty驅(qū)動分析.我們知道在open的時候,會調(diào)用ldisc的open和tty_driver.open.
對于ldisc默認是tty_ldiscs[0].我們來看下它的具體賦值.
console_init():
void __init console_init(void)
{
initcall_t *call;
/* Setup the default TTY line discipline. */
(void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
/*
* set up the console device so that later boot sequences can
* inform about problems etc..
*/
call = __con_initcall_start;
while (call < __con_initcall_end) {
(*call)();
call++;
}
}
在這里,通過tty_register_ldisc.將tty_ldisc_N_TTY注冊為了第N_TTY項.即第1項. tty_ldisc_N_TTY定義如下:
struct tty_ldisc tty_ldisc_N_TTY = {
.magic???? = TTY_LDISC_MAGIC,
.name????? = "n_tty",
.open????? = n_tty_open,
.close???? = n_tty_close,
.flush_buffer??? = n_tty_flush_buffer,
.chars_in_buffer = n_tty_chars_in_buffer,
.read????? = read_chan,
.write???? = write_chan,
.ioctl???? = n_tty_ioctl,
.set_termios???? = n_tty_set_termios,
.poll????? = normal_poll,
.receive_buf???? = n_tty_receive_buf,
.write_wakeup??? = n_tty_write_wakeup
}
對應(yīng)的open操作為n_tty_open:
static int n_tty_open(struct tty_struct *tty)
{
if (!tty)
return -EINVAL;
/* This one is ugly. Currently a malloc failure here can panic */
if (!tty->read_buf) {
tty->read_buf = alloc_buf();
if (!tty->read_buf)
return -ENOMEM;
}
memset(tty->read_buf, 0, N_TTY_BUF_SIZE);
reset_._flags(tty);
tty->column = 0;
n_tty_set_termios(tty, NULL);
tty->minimum_to_wake = 1;
tty->closing = 0;
return 0;
}
它為tty->read_buf分配內(nèi)存.這個buffer空間大小為N_TTY_BUF_SIZE.read_buf實際上就是從按鍵的緩存區(qū).然后調(diào)用reset_flags()來初始化tty中的一些字段:
static void reset_buffer_flags(struct tty_struct *tty)
{
unsigned long flags;
spin_lock_irqsave(&tty->read_lock, flags);
tty->read_head = tty->read_tail = tty->read_cnt = 0;
spin_unlock_irqrestore(&tty->read_lock, flags);
tty->canon_head = tty->canon_data = tty->erasing = 0;
memset(&tty->read_flags, 0, sizeof tty->read_flags);
n_tty_set_room(tty);
check_unthrottle(tty);
}
這里比較簡,不再詳細分析.在這里要注意幾個tty成員的含義:
Tty->read_head, tty->read_tail , tty->read_cnt分別代表read_buf中數(shù)據(jù)的寫入位置,讀取位置和數(shù)據(jù)總數(shù).read_buf是一個環(huán)形緩存區(qū).
n_tty_set_room()是設(shè)備read_buf中的可用緩存區(qū)
check_unthrottle():是用來判斷是否需要打開"閥門",允許輸入數(shù)據(jù)流入
對于console tty_driver對應(yīng)的open函數(shù)如下示:
static int con_open(struct tty_struct *tty, struct file *filp)
{
unsigned int currcons = tty->index;
int ret = 0;
acquire_console_sem();
if (tty->driver_data == NULL) {
ret = vc_allocate(currcons);
if (ret == 0) {
struct vc_data *vc = vc_cons[currcons].d;
tty->driver_data = vc;
vc->vc_tty = t
關(guān)鍵詞標簽:linux
相關(guān)閱讀
熱門文章 安裝紅帽子RedHat Linux9.0操作系統(tǒng)教程 Tomcat9.0如何安裝_Tomcat9.0環(huán)境變量配置方法 多種操作系統(tǒng)NTP客戶端配置 Linux操作系統(tǒng)修改IP
人氣排行 Linux下獲取CPUID、硬盤序列號與MAC地址 dmidecode命令查看內(nèi)存型號 linux tc實現(xiàn)ip流量限制 安裝紅帽子RedHat Linux9.0操作系統(tǒng)教程 linux下解壓rar文件 lcx.exe、nc.exe、sc.exe入侵中的使用方法 Ubuntu linux 關(guān)機、重啟、注銷 命令 查看linux服務(wù)器硬盤IO讀寫負載