?? tty_io.c
字號:
}//如果該字符是停止字符(^S),則置tty 停止標志,繼續處理其它字符。 if (c == STOP_CHAR (tty)) { tty->stopped = 1; continue; }// 如果該字符是停止字符(^Q),則復位tty 停止標志,繼續處理其它字符。 if (c == START_CHAR (tty)) { tty->stopped = 0; continue; } }// 若輸入模式標志集中ISIG 標志置位,則在收到INTR、QUIT、SUSP 或DSUSP 字符時,需要為進程// 產生相應的信號。 if (L_ISIG (tty)) {// 如果該字符是鍵盤中斷符(^C),則向當前進程發送鍵盤中斷信號,并繼續處理下一字符。 if (c == INTR_CHAR (tty)) { tty_intr (tty, INTMASK); continue; }// 如果該字符是鍵盤中斷符(^\),則向當前進程發送鍵盤退出信號,并繼續處理下一字符。 if (c == QUIT_CHAR (tty)) { tty_intr (tty, QUITMASK); continue; } }// 如果該字符是換行符NL(10),或者是文件結束符EOF(^D),輔助緩沖隊列字符數加1。[??] if (c == 10 || c == EOF_CHAR (tty)) tty->secondary.data++;// 如果本地模式標志集中回顯標志ECHO 置位,那么,如果字符是換行符NL(10),則將換行符NL(10)// 和回車符CR(13)放入tty 寫隊列緩沖區中;如果字符是控制字符(字符值<32)并且回顯控制字符標志// ECHOCTL 置位,則將字符'^'和字符c+64 放入tty 寫隊列中(也即會顯示^C、^H 等);否則將該字符// 直接放入tty 寫緩沖隊列中。最后調用該tty 的寫操作函數。 if (L_ECHO (tty)) { if (c == 10) { PUTCH (10, tty->write_q); PUTCH (13, tty->write_q); } else if (c < 32) { if (L_ECHOCTL (tty)) { PUTCH ('^', tty->write_q); PUTCH (c + 64, tty->write_q); }
} else PUTCH (c, tty->write_q); tty->write (tty); }// 將該字符放入輔助隊列中。 PUTCH (c, tty->secondary); }// 喚醒等待該輔助緩沖隊列的進程(如果有的話)。 wake_up (&tty->secondary.proc_list);}//// tty 讀函數。// 參數:channel - 子設備號;buf - 緩沖區指針;nr - 欲讀字節數。// 返回已讀字節數。int tty_read (unsigned channel, char *buf, int nr){ struct tty_struct *tty; char c, *b = buf; int minimum, time, flag = 0; long oldalarm;// 本版本linux 內核的終端只有3 個子設備,分別是控制臺(0)、串口終端1(1)和串口終端2(2)。// 所以任何大于2 的子設備號都是非法的。寫的字節數當然也不能小于0 的。 if (channel > 2 || nr < 0) return -1;// tty 指針指向子設備號對應ttb_table 表中的tty 結構。 tty = &tty_table[channel];// 下面首先保存進程原定時值,然后根據控制字符VTIME 和VMIN 設置讀字符操作的超時定時值。// 在非規范模式下,這兩個值是超時定時值。MIN 表示為了滿足讀操作,需要讀取的最少字符數。// TIME 是一個十分之一秒計數的計時值。// 首先取進程中的(報警)定時值(滴答數)。 oldalarm = current->alarm;// 并設置讀操作超時定時值time 和需要最少讀取的字符個數minimum。 time = 10L * tty->termios.c_cc[VTIME]; minimum = tty->termios.c_cc[VMIN];// 如果設置了讀超時定時值time 但沒有設置最少讀取個數minimum,那么在讀到至少一個字符或者// 定時超時后讀操作將立刻返回。所以這里置minimum=1。 if (time && !minimum) { minimum = 1;// 如果進程原定時值是0 或者time+當前系統時間值小于進程原定時值的話,則置重新設置進程定時// 值為time+當前系統時間,并置flag 標志。 if (flag = (!oldalarm || time + jiffies < oldalarm)) current->alarm = time + jiffies; }// 如果設置的最少讀取字符數>欲讀的字符數,則令其等于此次欲讀取的字符數。 if (minimum > nr) minimum = nr;// 當欲讀的字節數>0,則循環執行以下操作。 while (nr > 0) {// 如果flag 不為0(即進程原定時值是0 或者time+當前系統時間值小于進程原定時值)并且進程有定// 時信號SIGALRM,則復位進程的定時信號并中斷循環。 if (flag && (current->signal & ALRMMASK)) { current->signal &= ~ALRMMASK; break; }// 如果當前進程有信號要處理,則退出,返回0。 if (current->signal) break;// 如果輔助緩沖隊列(規范模式隊列)為空,或者設置了規范模式標志并且輔助隊列中字符數為0 以及// 輔助模式緩沖隊列空閑空間>20,則進入可中斷睡眠狀態,返回后繼續處理。 if (EMPTY (tty->secondary) || (L_CANON (tty) && !tty->secondary.data && LEFT (tty->secondary) > 20)) { sleep_if_empty (&tty->secondary); continue; }// 執行以下操作,直到nr=0 或者輔助緩沖隊列為空。 do {// 取輔助緩沖隊列字符c。 GETCH (tty->secondary, c);// 如果該字符是文件結束符(^D)或者是換行符NL(10),則輔助緩沖隊列字符數減1。 if (c == EOF_CHAR (tty) || c == 10) tty->secondary.data--;// 如果該字符是文件結束符(^D)并且規范模式標志置位,則返回已讀字符數,并退出。 if (c == EOF_CHAR (tty) && L_CANON (tty)) return (b - buf);// 否則將該字符放入用戶數據段緩沖區buf 中,欲讀字符數減1,如果欲讀字符數已為0,則中斷循環。 else { put_fs_byte (c, b++); if (!--nr) break; } } while (nr > 0 && !EMPTY (tty->secondary));// 如果超時定時值time 不為0 并且規范模式標志沒有置位(非規范模式),那么: if (time && !L_CANON (tty))// 如果進程原定時值是0 或者time+當前系統時間值小于進程原定時值的話,則置重新設置進程定時值// 為time+當前系統時間,并置flag 標志。否則讓進程的定時值等于進程原定時值。 if (flag = (!oldalarm || time + jiffies < oldalarm)) current->alarm = time + jiffies; else current->alarm = oldalarm;// 如果規范模式標志置位,那么若沒有讀到1 個字符則中斷循環。否則若已讀取數大于或等于最少要// 求讀取的字符數,則也中斷循環。 if (L_CANON (tty)) { if (b - buf) break; } else if (b - buf >= minimum) break; }// 讓進程的定時值等于進程原定時值。 current->alarm = oldalarm;// 如果進程有信號并且沒有讀取任何字符,則返回出錯號(超時)。 if (current->signal && !(b - buf)) return -EINTR; return (b - buf); // 返回已讀取的字符數。}//// tty 寫函數。// 參數:channel - 子設備號;buf - 緩沖區指針;nr - 寫字節數。// 返回已寫字節數。int tty_write (unsigned channel, char *buf, int nr){ static cr_flag = 0; struct tty_struct *tty; char c, *b = buf;// 本版本linux 內核的終端只有3 個子設備,分別是控制臺(0)、串口終端1(1)和串口終端2(2)。// 所以任何大于2 的子設備號都是非法的。寫的字節數當然也不能小于0 的。 if (channel > 2 || nr < 0) return -1;// tty 指針指向子設備號對應ttb_table 表中的tty 結構。 tty = channel + tty_table;// 字符設備是一個一個字符進行處理的,所以這里對于nr 大于0 時對每個字符進行循環處理。 while (nr > 0) {// 如果此時tty 的寫隊列已滿,則當前進程進入可中斷的睡眠狀態。 sleep_if_full (&tty->write_q);// 如果當前進程有信號要處理,則退出,返回0。 if (current->signal) break;// 當要寫的字節數>0 并且tty 的寫隊列不滿時,循環執行以下操作。 while (nr > 0 && !FULL (tty->write_q)) {// 從用戶數據段內存中取一字節c。 c = get_fs_byte (b);// 如果終端輸出模式標志集中的執行輸出處理標志OPOST 置位,則執行下列輸出時處理過程。 if (O_POST (tty)) {// 如果該字符是回車符'\r'(CR,13)并且回車符轉換行符標志OCRNL 置位,則將該字符換成換行符// '\n'(NL,10);否則如果該字符是換行符'\n'(NL,10)并且換行轉回車功能標志ONLRET 置位的話,// 則將該字符換成回車符'\r'(CR,13)。 if (c == '\r' && O_CRNL (tty)) c = '\n'; else if (c == '\n' && O_NLRET (tty)) c = '\r';// 如果該字符是換行符'\n'并且回車標志cr_flag 沒有置位,換行轉回車-換行標志ONLCR 置位的話,// 則將cr_flag 置位,并將一回車符放入寫隊列中。然后繼續處理下一個字符。 if (c == '\n' && !cr_flag && O_NLCR (tty)) { cr_flag = 1; PUTCH (13, tty->write_q); continue; }// 如果小寫轉大寫標志OLCUC 置位的話,就將該字符轉成大寫字符。 if (O_LCUC (tty)) c = toupper (c); }// 用戶數據緩沖指針b 前進1 字節;欲寫字節數減1 字節;復位cr_flag 標志,并將該字節放入tty// 寫隊列中。 b++; nr--; cr_flag = 0; PUTCH (c, tty->write_q); }// 若字節全部寫完,或者寫隊列已滿,則程序執行到這里。調用對應tty 的寫函數,若還有字節要寫,// 則等待寫隊列不滿,所以調用調度程序,先去執行其它任務。 tty->write (tty); if (nr > 0) schedule (); } return (b - buf); // 返回寫入的字節數。}/** 呵,有時我是真得很喜歡386。該子程序是從一個中斷處理程序中調用的,即使在* 中斷處理程序中睡眠也應該絕對沒有問題(我希望如此)。當然,如果有人證明我是* 錯的,那么我將憎恨intel 一輩子?。但是我們必須小心,在調用該子程序之前需* 要恢復中斷。** 我不認為在通常環境下會處在這里睡眠,這樣很好,因為任務睡眠是完全任意的。*///// tty 中斷處理調用函數 - 執行tty 中斷處理。// 參數:tty - 指定的tty 終端號(0,1 或2)。// 將指定tty 終端隊列緩沖區中的字符復制成規范(熟)模式字符并存放在輔助隊列(規范模式隊列)中。// 在串口讀字符中斷(rs_io.s, 109)和鍵盤中斷(kerboard.S, 69)中調用。void do_tty_interrupt (int tty){ copy_to_cooked (tty_table + tty);}//// 字符設備初始化函數??眨瑸橐院髷U展做準備。void chr_dev_init (void){}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -