?? tty_io.c
字號:
/* passed* linux/kernel/tty_io.c** (C) 1991 Linus Torvalds*/#include <set_seg.h>
/** 'tty_io.c'給tty 一種非相關的感覺,是控制臺還是串行通道。該程序同樣* 實現了回顯、規范(熟)模式等。** Kill-line,謝謝John T Kahl。*/#include <ctype.h> // 字符類型頭文件。定義了一些有關字符類型判斷和轉換的宏。#include <errno.h> // 錯誤號頭文件。包含系統中各種出錯號。(Linus 從minix 中引進的)。#include <signal.h> // 信號頭文件。定義信號符號常量,信號結構以及信號操作函數原型。// 下面給出相應信號在信號位圖中的對應比特位。#define ALRMMASK (1<<(SIGALRM-1)) // 警告(alarm)信號屏蔽位。#define KILLMASK (1<<(SIGKILL-1)) // 終止(kill)信號屏蔽位。#define INTMASK (1<<(SIGINT-1)) // 鍵盤中斷(int)信號屏蔽位。#define QUITMASK (1<<(SIGQUIT-1)) // 鍵盤退出(quit)信號屏蔽位。#define TSTPMASK (1<<(SIGTSTP-1)) // tty 發出的停止進程(tty stop)信號屏蔽位。#include <linux/sched.h> // 調度程序頭文件,定義了任務結構task_struct、初始任務0 的數據,// 還有一些有關描述符參數設置和獲取的嵌入式匯編函數宏語句。#include <linux/tty.h> // tty 頭文件,定義了有關tty_io,串行通信方面的參數、常數。#include <asm/segment.h> // 段操作頭文件。定義了有關段寄存器操作的嵌入式匯編函數。#include <asm/system.h> // 系統頭文件。定義了設置或修改描述符/中斷門等的嵌入式匯編宏。#define _L_FLAG(tty,f) ((tty)->termios.c_lflag & f) // 取termios 結構中的本地模式標志。#define _I_FLAG(tty,f) ((tty)->termios.c_iflag & f) // 取termios 結構中的輸入模式標志。#define _O_FLAG(tty,f) ((tty)->termios.c_oflag & f) // 取termios 結構中的輸出模式標志。// 取termios 結構中本地模式標志集中的一個標志位。#define L_CANON(tty) _L_FLAG((tty),ICANON) // 取本地模式標志集中規范(熟)模式標志位。#define L_ISIG(tty) _L_FLAG((tty),ISIG) // 取信號標志位。#define L_ECHO(tty) _L_FLAG((tty),ECHO) // 取回顯字符標志位。#define L_ECHOE(tty) _L_FLAG((tty),ECHOE) // 規范模式時,取回顯擦出標志位。#define L_ECHOK(tty) _L_FLAG((tty),ECHOK) // 規范模式時,取KILL 擦除當前行標志位。#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL) // 取回顯控制字符標志位。#define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE) // 規范模式時,取KILL 擦除行并回顯標志位。// 取termios 結構中輸入模式標志中的一個標志位。#define I_UCLC(tty) _I_FLAG((tty),IUCLC) // 取輸入模式標志集中大寫到小寫轉換標志位。#define I_NLCR(tty) _I_FLAG((tty),INLCR) // 取換行符NL 轉回車符CR 標志位。#define I_CRNL(tty) _I_FLAG((tty),ICRNL) // 取回車符CR 轉換行符NL 標志位。#define I_NOCR(tty) _I_FLAG((tty),IGNCR) // 取忽略回車符CR 標志位。// 取termios 結構中輸出模式標志中的一個標志位。#define O_POST(tty) _O_FLAG((tty),OPOST) // 取輸出模式標志集中執行輸出處理標志。#define O_NLCR(tty) _O_FLAG((tty),ONLCR) // 取換行符NL 轉回車換行符CR-NL 標志。#define O_CRNL(tty) _O_FLAG((tty),OCRNL) // 取回車符CR 轉換行符NL 標志。#define O_NLRET(tty) _O_FLAG((tty),ONLRET) // 取換行符NL 執行回車功能的標志。#define O_LCUC(tty) _O_FLAG((tty),OLCUC) // 取小寫轉大寫字符標志。// tty 數據結構的tty_table 數組。其中包含三個初始化項數據,分別對應控制臺、串口終端1 和// 串口終端2 的初始化數據。struct tty_struct tty_table[] = {{ {//termios
ICRNL, /* 將輸入的CR 轉換為NL */ OPOST | ONLCR, /* 將輸出的NL 轉CRNL */ 0, // 控制模式標志初始化為0。 ISIG | ICANON | ECHO | ECHOCTL | ECHOKE, // 本地模式標志。 0, /* 控制臺termio。 */ INIT_C_CC // 控制字符數組。
}, 0, /* 所屬初始進程組。 */ 0, /* 初始停止標志。 */ con_write, // tty 寫函數指針。 {0, 0, 0, 0, ""}, /* console read-queue */// tty 控制臺讀隊列。 {0, 0, 0, 0, ""}, /* console write-queue */// tty 控制臺寫隊列。 {0, 0, 0, 0, ""} /* console secondary queue */// tty 控制臺輔助(第二)隊列。}, { {
0, /* no translation */// 輸入模式標志。0,無須轉換。 0, /* no translation */// 輸出模式標志。0,無須轉換。 B2400 | CS8, // 控制模式標志。波特率2400bps,8 位數據位。 0, // 本地模式標志0。 0, // 行規程0。 INIT_C_CC
}, // 控制字符數組。 0, // 所屬初始進程組。 0, // 初始停止標志。 rs_write, // 串口1 tty 寫函數指針。 {0x3f8, 0, 0, 0, ""}, /* rs 1 */// 串行終端1 讀緩沖隊列。 {0x3f8, 0, 0, 0, ""}, // 串行終端1 寫緩沖隊列。 {0, 0, 0, 0, ""} // 串行終端1 輔助緩沖隊列。}, { {
0, /* no translation */// 輸入模式標志。0,無須轉換。 0, /* no translation */// 輸出模式標志。0,無須轉換。 B2400 | CS8, // 控制模式標志。波特率2400bps,8 位數據位。 0, // 本地模式標志0。 0, // 行規程0。 INIT_C_CC
}, // 控制字符數組。 0, // 所屬初始進程組。 0, // 初始停止標志。 rs_write, // 串口2 tty 寫函數指針。 {0x2f8, 0, 0, 0, ""}, /* rs 2 */// 串行終端2 讀緩沖隊列。 {0x2f8, 0, 0, 0, ""}, // 串行終端2 寫緩沖隊列。 {0, 0, 0, 0, ""} // 串行終端2 輔助緩沖隊列。}};/** 下面是匯編程序使用的緩沖隊列地址表。通過修改你可以實現* 偽tty 終端或其它終端類型。目前還沒有這樣做。*/// tty 緩沖隊列地址表。rs_io.s 匯編程序使用,用于取得讀寫緩沖隊列地址。struct tty_queue *table_list[] = { &tty_table[0].read_q, &tty_table[0].write_q, // 控制臺終端讀、寫緩沖隊列地址。 &tty_table[1].read_q, &tty_table[1].write_q, // 串行口1 終端讀、寫緩沖隊列地址。 &tty_table[2].read_q, &tty_table[2].write_q // 串行口2 終端讀、寫緩沖隊列地址。};//// tty 終端初始化函數。// 初始化串口終端和控制臺終端。void tty_init (void){ rs_init (); // 初始化串行中斷程序和串行接口1 和2。(serial.c, 37) con_init (); // 初始化控制臺終端。(console.c, 617)}//// tty 鍵盤終端字符處理函數。// 參數:tty - 相應tty 終端結構指針;mask - 信號屏蔽位。void tty_intr (struct tty_struct *tty, int mask){ int i;// 如果tty 所屬組號小于等于0,則退出。 if (tty->pgrp <= 0) return;// 掃描任務數組,向tty 相應組的所有任務發送指定的信號。 for (i = 0; i < NR_TASKS; i++) { // 如果該項任務指針不為空,并且其組號等于tty 組號,則設置該任務指定的信號mask。 if (task[i] && task[i]->pgrp == tty->pgrp) task[i]->signal |= mask;
}}//// 如果隊列緩沖區空則讓進程進入可中斷的睡眠狀態。// 參數:queue - 指定隊列的指針。// 進程在取隊列緩沖區中字符時調用此函數。static voidsleep_if_empty (struct tty_queue *queue){ cli (); // 關中斷。// 若當前進程沒有信號要處理并且指定的隊列緩沖區空,則讓進程進入可中斷睡眠狀態,并讓// 隊列的進程等待指針指向該進程。 while (!current->signal && EMPTY (*queue)) interruptible_sleep_on (&queue->proc_list); sti (); // 開中斷。}//// 若隊列緩沖區滿則讓進程進入可中斷的睡眠狀態。// 參數:queue - 指定隊列的指針。// 進程在往隊列緩沖區中寫入時調用此函數。static voidsleep_if_full (struct tty_queue *queue){// 若隊列緩沖區不滿,則返回退出。 if (!FULL (*queue)) return; cli (); // 關中斷。// 如果進程沒有信號需要處理并且隊列緩沖區中空閑剩余區長度<128,則讓進程進入可中斷睡眠狀態,// 并讓該隊列的進程等待指針指向該進程。 while (!current->signal && LEFT (*queue) < 128) interruptible_sleep_on (&queue->proc_list); sti (); // 開中斷。}//// 等待按鍵。// 如果控制臺的讀隊列緩沖區空則讓進程進入可中斷的睡眠狀態。void wait_for_keypress (void){ sleep_if_empty (&tty_table[0].secondary);}//// 復制成規范模式字符序列。// 將指定tty 終端隊列緩沖區中的字符復制成規范(熟)模式字符并存放在輔助隊列(規范模式隊列)中。// 參數:tty - 指定終端的tty 結構。void copy_to_cooked (struct tty_struct *tty){ signed char c;// 如果tty 的讀隊列緩沖區不空并且輔助隊列緩沖區為空,則循環執行下列代碼。 while (!EMPTY (tty->read_q) && !FULL (tty->secondary)) {// 從隊列尾處取一字符到c,并前移尾指針。 GETCH (tty->read_q, c);// 下面對輸入字符,利用輸入模式標志集進行處理。// 如果該字符是回車符CR(13),則:若回車轉換行標志CRNL 置位則將該字符轉換為換行符NL(10);// 否則若忽略回車標志NOCR 置位,則忽略該字符,繼續處理其它字符。 if (c == 13) { if (I_CRNL (tty)) c = 10; else if (I_NOCR (tty)) continue; else;// 如果該字符是換行符NL(10)并且換行轉回車標志NLCR 置位,則將其轉換為回車符CR(13)。 } else if (c == 10 && I_NLCR (tty)) c = 13;// 如果大寫轉小寫標志UCLC 置位,則將該字符轉換為小寫字符。 if (I_UCLC (tty)) c = tolower (c);// 如果本地模式標志集中規范(熟)模式標志CANON 置位,則進行以下處理。 if (L_CANON (tty)) {// 如果該字符是鍵盤終止控制字符KILL(^U),則進行刪除輸入行處理。 if (c == KILL_CHAR (tty)) {/* deal with killing the input line *//* 刪除輸入行處理 */// 如果tty 輔助隊列不空,或者輔助隊列中最后一個字符是換行NL(10),或者該字符是文件結束字符// (^D),則循環執行下列代碼。 while (!(EMPTY (tty->secondary) || (c = LAST (tty->secondary)) == 10 || c == EOF_CHAR (tty))) {// 如果本地回顯標志ECHO 置位,那么:若字符是控制字符(值<32),則往tty 的寫隊列中放入擦除// 字符ERASE。再放入一個擦除字符ERASE,并且調用該tty 的寫函數。 if (L_ECHO (tty)) { if (c < 32) PUTCH (127, tty->write_q); PUTCH (127, tty->write_q); tty->write (tty); }// 將tty 輔助隊列頭指針后退1 字節。 DEC (tty->secondary.head); } continue; // 繼續讀取并處理其它字符。 }// 如果該字符是刪除控制字符ERASE(^H),那么: if (c == ERASE_CHAR (tty)) {// 若tty 的輔助隊列為空,或者其最后一個字符是換行符NL(10),或者是文件結束符,繼續處理// 其它字符。 if (EMPTY (tty->secondary) || (c = LAST (tty->secondary)) == 10 || c == EOF_CHAR (tty)) continue;// 如果本地回顯標志ECHO 置位,那么:若字符是控制字符(值<32),則往tty 的寫隊列中放入擦除// 字符ERASE。再放入一個擦除字符ERASE,并且調用該tty 的寫函數。 if (L_ECHO (tty)) { if (c < 32) PUTCH (127, tty->write_q); PUTCH (127, tty->write_q); tty->write (tty); }// 將tty 輔助隊列頭指針后退1 字節,繼續處理其它字符。 DEC (tty->secondary.head); continue;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -