時(shí)間:2015-06-28 00:00:00 來(lái)源:IT貓撲網(wǎng) 作者:網(wǎng)管聯(lián)盟 我要評(píng)論(0)
一:前言
我們?cè)谥胺治鲞^(guò)input子系統(tǒng)和tty設(shè)備驅(qū)動(dòng)架構(gòu).今天需要將兩者結(jié)合起來(lái).看看linux中的控制臺(tái)是怎么樣實(shí)現(xiàn)的.
二:控制臺(tái)驅(qū)動(dòng)的初始化
之前在分析tty驅(qū)動(dòng)架構(gòu)的時(shí)候曾分析到.主設(shè)備為4,次設(shè)備為0的設(shè)備節(jié)點(diǎn),即/dev/tty0為當(dāng)前的控制終端.
有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:是指配置虛擬終端.即我們所說(shuō)的控制臺(tái).在此可以看到TTY_MAJOR(4),0對(duì)應(yīng)的設(shè)備節(jié)點(diǎn)操作集為console_fops.
繼續(xù)跟進(jìn)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)過(guò)我們之前的tty驅(qū)動(dòng)架構(gòu)分析,這段代碼看起來(lái)就比較簡(jiǎn)單了,它就是注冊(cè)了一個(gè)tty驅(qū)動(dòng).這個(gè)驅(qū)動(dòng)對(duì)應(yīng)的操作集是位于con_ops里面的.
仔細(xì)看.在之后還會(huì)調(diào)用kbd_init().顧名思義,這個(gè)是一個(gè)有關(guān)鍵盤(pán)的初始化.控制終端跟鍵盤(pán)有什么關(guān)系呢?在之前分析tty的時(shí)候,曾提到過(guò),. 對(duì)于控制臺(tái)而言,它的輸入設(shè)備是鍵盤(pán)鼠標(biāo),它的輸出設(shè)備是當(dāng)前顯示器.這兩者是怎么關(guān)聯(lián)起來(lái)的呢?不著急.請(qǐng)看下面的分析.
三:控制臺(tái)的open操作
在前面分析了,對(duì)應(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ū)動(dòng)中已經(jīng)分析過(guò)了.
結(jié)合前面的tty驅(qū)動(dòng)分析.我們知道在open的時(shí)候,會(huì)調(diào)用ldisc的open和tty_driver.open.
對(duì)于ldisc默認(rèn)是tty_ldiscs[0].我們來(lái)看下它的具體賦值.
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++;
}
}
在這里,通過(guò)tty_register_ldisc.將tty_ldisc_N_TTY注冊(cè)為了第N_TTY項(xiàng).即第1項(xiàng). 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
}
對(duì)應(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)存.這個(gè)buffer空間大小為N_TTY_BUF_SIZE.read_buf實(shí)際上就是從按鍵的緩存區(qū).然后調(diào)用reset_flags()來(lái)初始化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);
}
這里比較簡(jiǎn),不再詳細(xì)分析.在這里要注意幾個(gè)tty成員的含義:
Tty->read_head, tty->read_tail , tty->read_cnt分別代表read_buf中數(shù)據(jù)的寫(xiě)入位置,讀取位置和數(shù)據(jù)總數(shù).read_buf是一個(gè)環(huán)形緩存區(qū).
n_tty_set_room()是設(shè)備read_buf中的可用緩存區(qū)
check_unthrottle():是用來(lái)判斷是否需要打開(kāi)"閥門(mén)",允許輸入數(shù)據(jù)流入
對(duì)于console tty_driver對(duì)應(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)鍵詞標(biāo)簽:linux
相關(guān)閱讀
熱門(mén)文章 安裝紅帽子RedHat Linux9.0操作系統(tǒng)教程 Tomcat9.0如何安裝_Tomcat9.0環(huán)境變量配置方法 多種操作系統(tǒng)NTP客戶端配置 Linux操作系統(tǒng)修改IP
人氣排行 Linux下獲取CPUID、硬盤(pán)序列號(hào)與MAC地址 dmidecode命令查看內(nèi)存型號(hào) linux tc實(shí)現(xiàn)ip流量限制 安裝紅帽子RedHat Linux9.0操作系統(tǒng)教程 linux下解壓rar文件 lcx.exe、nc.exe、sc.exe入侵中的使用方法 Ubuntu linux 關(guān)機(jī)、重啟、注銷 命令 查看linux服務(wù)器硬盤(pán)IO讀寫(xiě)負(fù)載