?? tty_ioctl.c
字號(hào):
/** linux/kernel/chr_drv/tty_ioctl.c** (C) 1991 Linus Torvalds*/#include <errno.h> // 錯(cuò)誤號(hào)頭文件。包含系統(tǒng)中各種出錯(cuò)號(hào)。(Linus 從minix 中引進(jìn)的)。#include <termios.h> // 終端輸入輸出函數(shù)頭文件。主要定義控制異步通信口的終端接口。#include <linux/sched.h> // 調(diào)度程序頭文件,定義了任務(wù)結(jié)構(gòu)task_struct、初始任務(wù)0 的數(shù)據(jù),// 還有一些有關(guān)描述符參數(shù)設(shè)置和獲取的嵌入式匯編函數(shù)宏語句。#include <linux/kernel.h> // 內(nèi)核頭文件。含有一些內(nèi)核常用函數(shù)的原形定義。#include <linux/tty.h> // tty 頭文件,定義了有關(guān)tty_io,串行通信方面的參數(shù)、常數(shù)。#include <asm/io.h> // io 頭文件。定義硬件端口輸入/輸出宏匯編語句。#include <asm/segment.h> // 段操作頭文件。定義了有關(guān)段寄存器操作的嵌入式匯編函數(shù)。#include <asm/system.h> // 系統(tǒng)頭文件。定義了設(shè)置或修改描述符/中斷門等的嵌入式匯編宏。// 這是波特率因子數(shù)組(或稱為除數(shù)數(shù)組)。波特率與波特率因子的對(duì)應(yīng)關(guān)系參見列表后的說明。static unsigned short quotient[] = { 0, 2304, 1536, 1047, 857, 768, 576, 384, 192, 96, 64, 48, 24, 12, 6, 3};//// 修改傳輸速率。// 參數(shù):tty - 終端對(duì)應(yīng)的tty 數(shù)據(jù)結(jié)構(gòu)。// 在除數(shù)鎖存標(biāo)志DLAB(線路控制寄存器位7)置位情況下,通過端口0x3f8 和0x3f9 向UART 分別寫入// 波特率因子低字節(jié)和高字節(jié)。static voidchange_speed (struct tty_struct *tty){ unsigned short port, quot;// 對(duì)于串口終端,其tty 結(jié)構(gòu)的讀緩沖隊(duì)列data 字段存放的是串行端口號(hào)(0x3f8 或0x2f8)。 if (!(port = tty->read_q.data)) return;// 從tty 的termios 結(jié)構(gòu)控制模式標(biāo)志集中取得設(shè)置的波特率索引號(hào),據(jù)此從波特率因子數(shù)組中取得// 對(duì)應(yīng)的波特率因子值。CBAUD 是控制模式標(biāo)志集中波特率位屏蔽碼。 quot = quotient[tty->termios.c_cflag & CBAUD]; cli (); // 關(guān)中斷。 outb_p (0x80, port + 3); /* set DLAB */// 首先設(shè)置除數(shù)鎖定標(biāo)志DLAB。 outb_p (quot & 0xff, port); /* LS of divisor */// 輸出因子低字節(jié)。 outb_p (quot >> 8, port + 1); /* MS of divisor */// 輸出因子高字節(jié)。 outb (0x03, port + 3); /* reset DLAB */// 復(fù)位DLAB。 sti (); // 開中斷。}//// 刷新tty 緩沖隊(duì)列。// 參數(shù):gueue - 指定的緩沖隊(duì)列指針。// 令緩沖隊(duì)列的頭指針等于尾指針,從而達(dá)到清空緩沖區(qū)(零字符)的目的。static voidflush (struct tty_queue *queue){ cli (); queue->head = queue->tail; sti ();}//// 等待字符發(fā)送出去。static voidwait_until_sent (struct tty_struct *tty){/* do nothing - not implemented *//* 什么都沒做 - 還未實(shí)現(xiàn) */}//// 發(fā)送BREAK 控制符。static voidsend_break (struct tty_struct *tty){/* do nothing - not implemented *//* 什么都沒做 - 還未實(shí)現(xiàn) */}//// 取終端termios 結(jié)構(gòu)信息。// 參數(shù):tty - 指定終端的tty 結(jié)構(gòu)指針;termios - 用戶數(shù)據(jù)區(qū)termios 結(jié)構(gòu)緩沖區(qū)指針。// 返回0 。static intget_termios (struct tty_struct *tty, struct termios *termios){ int i;// 首先驗(yàn)證一下用戶的緩沖區(qū)指針?biāo)竷?nèi)存區(qū)是否足夠,如不夠則分配內(nèi)存。 verify_area (termios, sizeof (*termios));// 復(fù)制指定tty 結(jié)構(gòu)中的termios 結(jié)構(gòu)信息到用戶 termios 結(jié)構(gòu)緩沖區(qū)。 for (i = 0; i < (sizeof (*termios)); i++) put_fs_byte (((char *) &tty->termios)[i], i + (char *) termios); return 0;}//// 設(shè)置終端termios 結(jié)構(gòu)信息。// 參數(shù):tty - 指定終端的tty 結(jié)構(gòu)指針;termios - 用戶數(shù)據(jù)區(qū)termios 結(jié)構(gòu)指針。// 返回0 。static intset_termios (struct tty_struct *tty, struct termios *termios){ int i;// 首先復(fù)制用戶數(shù)據(jù)區(qū)中termios 結(jié)構(gòu)信息到指定tty 結(jié)構(gòu)中。 for (i = 0; i < (sizeof (*termios)); i++) ((char *) &tty->termios)[i] = get_fs_byte (i + (char *) termios);// 用戶有可能已修改了tty 的串行口傳輸波特率,所以根據(jù)termios 結(jié)構(gòu)中的控制模式標(biāo)志c_cflag// 修改串行芯片UART 的傳輸波特率。 change_speed (tty); return 0;}//// 讀取termio 結(jié)構(gòu)中的信息。// 參數(shù):tty - 指定終端的tty 結(jié)構(gòu)指針;termio - 用戶數(shù)據(jù)區(qū)termio 結(jié)構(gòu)緩沖區(qū)指針。// 返回0。static intget_termio (struct tty_struct *tty, struct termio *termio){ int i; struct termio tmp_termio;// 首先驗(yàn)證一下用戶的緩沖區(qū)指針?biāo)竷?nèi)存區(qū)是否足夠,如不夠則分配內(nèi)存。 verify_area (termio, sizeof (*termio));// 將termios 結(jié)構(gòu)的信息復(fù)制到termio 結(jié)構(gòu)中。目的是為了其中模式標(biāo)志集的類型進(jìn)行轉(zhuǎn)換,也即// 從termios 的長(zhǎng)整數(shù)類型轉(zhuǎn)換為termio 的短整數(shù)類型。 tmp_termio.c_iflag = tty->termios.c_iflag; tmp_termio.c_oflag = tty->termios.c_oflag; tmp_termio.c_cflag = tty->termios.c_cflag; tmp_termio.c_lflag = tty->termios.c_lflag;// 兩種結(jié)構(gòu)的c_line 和c_cc[]字段是完全相同的。 tmp_termio.c_line = tty->termios.c_line; for (i = 0; i < NCC; i++) tmp_termio.c_cc[i] = tty->termios.c_cc[i];// 最后復(fù)制指定tty 結(jié)構(gòu)中的termio 結(jié)構(gòu)信息到用戶 termio 結(jié)構(gòu)緩沖區(qū)。 for (i = 0; i < (sizeof (*termio)); i++) put_fs_byte (((char *) &tmp_termio)[i], i + (char *) termio); return 0;}/** This only works as the 386 is low-byt-first*//** 下面的termio 設(shè)置函數(shù)僅在386 低字節(jié)在前的方式下可用。*///// 設(shè)置終端termio 結(jié)構(gòu)信息。// 參數(shù):tty - 指定終端的tty 結(jié)構(gòu)指針;termio - 用戶數(shù)據(jù)區(qū)termio 結(jié)構(gòu)指針。// 將用戶緩沖區(qū)termio 的信息復(fù)制到終端的termios 結(jié)構(gòu)中。返回0 。static intset_termio (struct tty_struct *tty, struct termio *termio){ int i; struct termio tmp_termio;// 首先復(fù)制用戶數(shù)據(jù)區(qū)中termio 結(jié)構(gòu)信息到臨時(shí)termio 結(jié)構(gòu)中。 for (i = 0; i < (sizeof (*termio)); i++) ((char *) &tmp_termio)[i] = get_fs_byte (i + (char *) termio);// 再將termio 結(jié)構(gòu)的信息復(fù)制到tty 的termios 結(jié)構(gòu)中。目的是為了其中模式標(biāo)志集的類型進(jìn)行轉(zhuǎn)換,// 也即從termio 的短整數(shù)類型轉(zhuǎn)換成termios 的長(zhǎng)整數(shù)類型。 *(unsigned short *) &tty->termios.c_iflag = tmp_termio.c_iflag; *(unsigned short *) &tty->termios.c_oflag = tmp_termio.c_oflag; *(unsigned short *) &tty->termios.c_cflag = tmp_termio.c_cflag; *(unsigned short *) &tty->termios.c_lflag = tmp_termio.c_lflag;// 兩種結(jié)構(gòu)的c_line 和c_cc[]字段是完全相同的。 tty->termios.c_line = tmp_termio.c_line; for (i = 0; i < NCC; i++) tty->termios.c_cc[i] = tmp_termio.c_cc[i];// 用戶可能已修改了tty 的串行口傳輸波特率,所以根據(jù)termios 結(jié)構(gòu)中的控制模式標(biāo)志集c_cflag// 修改串行芯片UART 的傳輸波特率。 change_speed (tty); return 0;}//// tty 終端設(shè)備的ioctl 函數(shù)。// 參數(shù):dev - 設(shè)備號(hào);cmd - ioctl 命令;arg - 操作參數(shù)指針。inttty_ioctl (int dev, int cmd, int arg){ struct tty_struct *tty;// 首先取tty 的子設(shè)備號(hào)。如果主設(shè)備號(hào)是5(tty 終端),則進(jìn)程的tty 字段即是子設(shè)備號(hào);如果進(jìn)程// 的tty 子設(shè)備號(hào)是負(fù)數(shù),表明該進(jìn)程沒有控制終端,也即不能發(fā)出該ioctl 調(diào)用,出錯(cuò)死機(jī)。 if (MAJOR (dev) == 5) { dev = current->tty; if (dev < 0) panic ("tty_ioctl: dev<0");// 否則直接從設(shè)備號(hào)中取出子設(shè)備號(hào)。 } else dev = MINOR (dev);// 子設(shè)備號(hào)可以是0(控制臺(tái)終端)、1(串口1 終端)、2(串口2 終端)。// 讓tty 指向?qū)?yīng)子設(shè)備號(hào)的tty 結(jié)構(gòu)。 tty = dev + tty_table;// 根據(jù)tty 的ioctl 命令進(jìn)行分別處理。 switch (cmd) { case TCGETS://取相應(yīng)終端termios 結(jié)構(gòu)中的信息。 return get_termios (tty, (struct termios *) arg); case TCSETSF:// 在設(shè)置termios 的信息之前,需要先等待輸出隊(duì)列中所有數(shù)據(jù)處理完,并且刷新(清空)輸入隊(duì)列。// 再設(shè)置。 flush (&tty->read_q); /* fallthrough */ case TCSETSW:// 在設(shè)置終端termios 的信息之前,需要先等待輸出隊(duì)列中所有數(shù)據(jù)處理完(耗盡)。對(duì)于修改參數(shù)// 會(huì)影響輸出的情況,就需要使用這種形式。 wait_until_sent (tty); /* fallthrough */ case TCSETS:// 設(shè)置相應(yīng)終端termios 結(jié)構(gòu)中的信息。 return set_termios (tty, (struct termios *) arg); case TCGETA:// 取相應(yīng)終端termio 結(jié)構(gòu)中的信息。 return get_termio (tty, (struct termio *) arg); case TCSETAF:// 在設(shè)置termio 的信息之前,需要先等待輸出隊(duì)列中所有數(shù)據(jù)處理完,并且刷新(清空)輸入隊(duì)列。// 再設(shè)置。 flush (&tty->read_q); /* fallthrough */ case TCSETAW:// 在設(shè)置終端termio 的信息之前,需要先等待輸出隊(duì)列中所有數(shù)據(jù)處理完(耗盡)。對(duì)于修改參數(shù)// 會(huì)影響輸出的情況,就需要使用這種形式。 wait_until_sent (tty); /* fallthrough *//* 繼續(xù)執(zhí)行 */ case TCSETA:// 設(shè)置相應(yīng)終端termio 結(jié)構(gòu)中的信息。 return set_termio (tty, (struct termio *) arg); case TCSBRK:// 等待輸出隊(duì)列處理完畢(空),如果參數(shù)值是0,則發(fā)送一個(gè)break。 if (!arg) { wait_until_sent (tty); send_break (tty); } return 0; case TCXONC:// 開始/停止控制。如果參數(shù)值是0,則掛起輸出;如果是1,則重新開啟掛起的輸出;如果是2,則掛起// 輸入;如果是3,則重新開啟掛起的輸入。 return -EINVAL; /* not implemented *//* 未實(shí)現(xiàn) */ case TCFLSH://刷新已寫輸出但還沒發(fā)送或已收但還沒有讀數(shù)據(jù)。如果參數(shù)是0,則刷新(清空)輸入隊(duì)列;如果是1,// 則刷新輸出隊(duì)列;如果是2,則刷新輸入和輸出隊(duì)列。 if (arg == 0) flush (&tty->read_q); else if (arg == 1) flush (&tty->write_q); else if (arg == 2) { flush (&tty->read_q); flush (&tty->write_q); } else return -EINVAL; return 0; case TIOCEXCL:// 設(shè)置終端串行線路專用模式。 return -EINVAL; /* not implemented *//* 未實(shí)現(xiàn) */ case TIOCNXCL:// 復(fù)位終端串行線路專用模式。 return -EINVAL; /* not implemented *//* 未實(shí)現(xiàn) */ case TIOCSCTTY:// 設(shè)置tty 為控制終端。(TIOCNOTTY - 禁止tty 為控制終端)。 return -EINVAL; /* set controlling term NI *//* 設(shè)置控制終端NI */ case TIOCGPGRP: // NI - Not Implemented。// 讀取指定終端設(shè)備進(jìn)程的組id。首先驗(yàn)證用戶緩沖區(qū)長(zhǎng)度,然后復(fù)制tty 的pgrp 字段到用戶緩沖區(qū)。 verify_area ((void *) arg, 4); put_fs_long (tty->pgrp, (unsigned long *) arg); return 0; case TIOCSPGRP:// 設(shè)置指定終端設(shè)備進(jìn)程的組id。 tty->pgrp = get_fs_long ((unsigned long *) arg); return 0; case TIOCOUTQ:// 返回輸出隊(duì)列中還未送出的字符數(shù)。首先驗(yàn)證用戶緩沖區(qū)長(zhǎng)度,然后復(fù)制隊(duì)列中字符數(shù)給用戶。 verify_area ((void *) arg, 4); put_fs_long (CHARS (tty->write_q), (unsigned long *) arg); return 0; case TIOCINQ:// 返回輸入隊(duì)列中還未讀取的字符數(shù)。首先驗(yàn)證用戶緩沖區(qū)長(zhǎng)度,然后復(fù)制隊(duì)列中字符數(shù)給用戶。 verify_area ((void *) arg, 4); put_fs_long (CHARS (tty->secondary), (unsigned long *) arg); return 0; case TIOCSTI:// 模擬終端輸入。該命令以一個(gè)指向字符的指針作為參數(shù),并假裝該字符是在終端上鍵入的。用戶必須// 在該控制終端上具有超級(jí)用戶權(quán)限或具有讀許可權(quán)限。 return -EINVAL; /* not implemented *//* 未實(shí)現(xiàn) */ case TIOCGWINSZ:// 讀取終端設(shè)備窗口大小信息(參見termios.h 中的winsize 結(jié)構(gòu))。 return -EINVAL; /* not implemented *//* 未實(shí)現(xiàn) */ case TIOCSWINSZ:// 設(shè)置終端設(shè)備窗口大小信息(參見winsize 結(jié)構(gòu))。 return -EINVAL; /* not implemented *//* 未實(shí)現(xiàn) */ case TIOCMGET:// 返回modem 狀態(tài)控制引線的當(dāng)前狀態(tài)比特位標(biāo)志集(參見termios.h 中185-196 行)。 return -EINVAL; /* not implemented *//* 未實(shí)現(xiàn) */ case TIOCMBIS:// 設(shè)置單個(gè)modem 狀態(tài)控制引線的狀態(tài)(true 或false)。 return -EINVAL; /* not implemented *//* 未實(shí)現(xiàn) */ case TIOCMBIC:// 復(fù)位單個(gè)modem 狀態(tài)控制引線的狀態(tài)。 return -EINVAL; /* not implemented *//* 未實(shí)現(xiàn) */ case TIOCMSET:// 設(shè)置modem 狀態(tài)引線的狀態(tài)。如果某一比特位置位,則modem 對(duì)應(yīng)的狀態(tài)引線將置為有效。 return -EINVAL; /* not implemented *//* 未實(shí)現(xiàn) */ case TIOCGSOFTCAR:// 讀取軟件載波檢測(cè)標(biāo)志(1 - 開啟;0 - 關(guān)閉)。 return -EINVAL; /* not implemented *//* 未實(shí)現(xiàn) */ case TIOCSSOFTCAR:// 設(shè)置軟件載波檢測(cè)標(biāo)志(1 - 開啟;0 - 關(guān)閉)。 return -EINVAL; /* not implemented *//* 未實(shí)現(xiàn) */ default: return -EINVAL; }}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -