📄 tty.c
字号:
12022 int i;
12023 /* these non-Posix params are not used now, but the union is retained
12024 * to minimize code differences with backward compatible version
12025 * struct sgttyb sg;
12026 * struct tchars tc;
12027 */
12028 } param;
12029 phys_bytes user_phys;
12030 size_t size;
12031
12032 /* Size of the ioctl parameter. */
12033 switch (m_ptr->TTY_REQUEST) {
12034 case TCGETS: /* Posix tcgetattr function */
12035 case TCSETS: /* Posix tcsetattr function, TCSANOW option */
12036 case TCSETSW: /* Posix tcsetattr function, TCSADRAIN option */
12037 case TCSETSF: /* Posix tcsetattr function, TCSAFLUSH option */
12038 size = sizeof(struct termios);
12039 break;
12040
12041 case TCSBRK: /* Posix tcsendbreak function */
12042 case TCFLOW: /* Posix tcflow function */
12043 case TCFLSH: /* Posix tcflush function */
12044 case TIOCGPGRP: /* Posix tcgetpgrp function */
12045 case TIOCSPGRP: /* Posix tcsetpgrp function */
12046 size = sizeof(int);
12047 break;
12048
12049 case TIOCGWINSZ: /* get window size (not Posix) */
12050 case TIOCSWINSZ: /* set window size (not Posix) */
12051 size = sizeof(struct winsize);
12052 break;
12053
12054 case KIOCSMAP: /* load keymap (Minix extension) */
12055 size = sizeof(keymap_t);
12056 break;
12057
12058 case TIOCSFON: /* load font (Minix extension) */
12059 size = sizeof(u8_t [8192]);
12060 break;
12061
12062 case TCDRAIN: /* Posix tcdrain function -- no parameter */
12063 default: size = 0;
12064 }
12065
12066 if (size != 0) {
12067 user_phys = numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS, size);
12068 if (user_phys == 0) {
12069 tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EFAULT);
12070 return;
12071 }
12072 }
12073
12074 r = OK;
12075 switch (m_ptr->TTY_REQUEST) {
12076 case TCGETS:
12077 /* Get the termios attributes. */
12078 phys_copy(vir2phys(&tp->tty_termios), user_phys, (phys_bytes) size);
12079 break;
12080
12081 case TCSETSW:
12082 case TCSETSF:
12083 case TCDRAIN:
12084 if (tp->tty_outleft > 0) {
12085 /* Wait for all ongoing output processing to finish. */
12086 tp->tty_iocaller = m_ptr->m_source;
12087 tp->tty_ioproc = m_ptr->PROC_NR;
12088 tp->tty_ioreq = m_ptr->REQUEST;
12089 tp->tty_iovir = (vir_bytes) m_ptr->ADDRESS;
12090 r = SUSPEND;
12091 break;
12092 }
12093 if (m_ptr->TTY_REQUEST == TCDRAIN) break;
12094 if (m_ptr->TTY_REQUEST == TCSETSF) tty_icancel(tp);
12095 /*FALL THROUGH*/
12096 case TCSETS:
12097 /* Set the termios attributes. */
12098 phys_copy(user_phys, vir2phys(&tp->tty_termios), (phys_bytes) size);
12099 setattr(tp);
12100 break;
12101
12102 case TCFLSH:
12103 phys_copy(user_phys, vir2phys(¶m.i), (phys_bytes) size);
12104 switch (param.i) {
12105 case TCIFLUSH: tty_icancel(tp); break;
12106 case TCOFLUSH: (*tp->tty_ocancel)(tp); break;
12107 case TCIOFLUSH: tty_icancel(tp); (*tp->tty_ocancel)(tp);break;
12108 default: r = EINVAL;
12109 }
12110 break;
12111
12112 case TCFLOW:
12113 phys_copy(user_phys, vir2phys(¶m.i), (phys_bytes) size);
12114 switch (param.i) {
12115 case TCOOFF:
12116 case TCOON:
12117 tp->tty_inhibited = (param.i == TCOOFF);
12118 tp->tty_events = 1;
12119 break;
12120 case TCIOFF:
12121 (*tp->tty_echo)(tp, tp->tty_termios.c_cc[VSTOP]);
12122 break;
12123 case TCION:
12124 (*tp->tty_echo)(tp, tp->tty_termios.c_cc[VSTART]);
12125 break;
12126 default:
12127 r = EINVAL;
12128 }
12129 break;
12130
12131 case TCSBRK:
12132 if (tp->tty_break != NULL) (*tp->tty_break)(tp);
12133 break;
12134
12135 case TIOCGWINSZ:
12136 phys_copy(vir2phys(&tp->tty_winsize), user_phys, (phys_bytes) size);
12137 break;
12138
12139 case TIOCSWINSZ:
12140 phys_copy(user_phys, vir2phys(&tp->tty_winsize), (phys_bytes) size);
12141 /* SIGWINCH... */
12142 break;
12143
12144 case KIOCSMAP:
12145 /* Load a new keymap (only /dev/console). */
12146 if (isconsole(tp)) r = kbd_loadmap(user_phys);
12147 break;
12148
12149 case TIOCSFON:
12150 /* Load a font into an EGA or VGA card (hs@hck.hr) */
12151 if (isconsole(tp)) r = con_loadfont(user_phys);
12152 break;
12153
12154 /* These Posix functions are allowed to fail if _POSIX_JOB_CONTROL is
12155 * not defined.
12156 */
12157 case TIOCGPGRP:
12158 case TIOCSPGRP:
12159 default:
12160 r = ENOTTY;
12161 }
12162
12163 /* Send the reply. */
12164 tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r);
12165 }
12168 /*===========================================================================*
12169 * do_open *
12170 *===========================================================================*/
12171 PRIVATE void do_open(tp, m_ptr)
12172 register tty_t *tp;
12173 message *m_ptr; /* pointer to message sent to task */
12174 {
12175 /* A tty line has been opened. Make it the callers controlling tty if
12176 * O_NOCTTY is *not* set and it is not the log device. 1 is returned if
12177 * the tty is made the controlling tty, otherwise OK or an error code.
12178 */
12179 int r = OK;
12180
12181 if (m_ptr->TTY_LINE == LOG_MINOR) {
12182 /* The log device is a write-only diagnostics device. */
12183 if (m_ptr->COUNT & R_BIT) r = EACCES;
12184 } else {
12185 if (!(m_ptr->COUNT & O_NOCTTY)) {
12186 tp->tty_pgrp = m_ptr->PROC_NR;
12187 r = 1;
12188 }
12189 tp->tty_openct++;
12190 }
12191 tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r);
12192 }
12195 /*===========================================================================*
12196 * do_close *
12197 *===========================================================================*/
12198 PRIVATE void do_close(tp, m_ptr)
12199 register tty_t *tp;
12200 message *m_ptr; /* pointer to message sent to task */
12201 {
12202 /* A tty line has been closed. Clean up the line if it is the last close. */
12203
12204 if (m_ptr->TTY_LINE != LOG_MINOR && --tp->tty_openct == 0) {
12205 tp->tty_pgrp = 0;
12206 tty_icancel(tp);
12207 (*tp->tty_ocancel)(tp);
12208 (*tp->tty_close)(tp);
12209 tp->tty_termios = termios_defaults;
12210 tp->tty_winsize = winsize_defaults;
12211 setattr(tp);
12212 }
12213 tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, OK);
12214 }
12217 /*===========================================================================*
12218 * do_cancel *
12219 *===========================================================================*/
12220 PRIVATE void do_cancel(tp, m_ptr)
12221 register tty_t *tp;
12222 message *m_ptr; /* pointer to message sent to task */
12223 {
12224 /* A signal has been sent to a process that is hanging trying to read or write.
12225 * The pending read or write must be finished off immediately.
12226 */
12227
12228 int proc_nr;
12229 int mode;
12230
12231 /* Check the parameters carefully, to avoid cancelling twice. */
12232 proc_nr = m_ptr->PROC_NR;
12233 mode = m_ptr->COUNT;
12234 if ((mode & R_BIT) && tp->tty_inleft != 0 && proc_nr == tp->tty_inproc) {
12235 /* Process was reading when killed. Clean up input. */
12236 tty_icancel(tp);
12237 tp->tty_inleft = tp->tty_incum = 0;
12238 }
12239 if ((mode & W_BIT) && tp->tty_outleft != 0 && proc_nr == tp->tty_outproc) {
12240 /* Process was writing when killed. Clean up output. */
12241 (*tp->tty_ocancel)(tp);
12242 tp->tty_outleft = tp->tty_outcum = 0;
12243 }
12244 if (tp->tty_ioreq != 0 && proc_nr == tp->tty_ioproc) {
12245 /* Process was waiting for output to drain. */
12246 tp->tty_ioreq = 0;
12247 }
12248 tp->tty_events = 1;
12249 tty_reply(TASK_REPLY, m_ptr->m_source, proc_nr, EINTR);
12250 }
12253 /*===========================================================================*
12254 * handle_events *
12255 *===========================================================================*/
12256 PUBLIC void handle_events(tp)
12257 tty_t *tp; /* TTY to check for events. */
12258 {
12259 /* Handle any events pending on a TTY. These events are usually device
12260 * interrupts.
12261 *
12262 * Two kinds of events are prominent:
12263 * - a character has been received from the console or an RS232 line.
12264 * - an RS232 line has completed a write request (on behalf of a user).
12265 * The interrupt handler may delay the interrupt message at its discretion
12266 * to avoid swamping the TTY task. Messages may be overwritten when the
12267 * lines are fast or when there are races between different lines, input
12268 * and output, because MINIX only provides single buffering for interrupt
12269 * messages (in proc.c). This is handled by explicitly checking each line
12270 * for fresh input and completed output on each interrupt.
12271 */
12272 char *buf;
12273 unsigned count;
12274
12275 do {
12276 tp->tty_events = 0;
12277
12278 /* Read input and perform input processing. */
12279 (*tp->tty_devread)(tp);
12280
12281 /* Perform output processing and write output. */
12282 (*tp->tty_devwrite)(tp);
12283
12284 /* Ioctl waiting for some event? */
12285 if (tp->tty_ioreq != 0) dev_ioctl(tp);
12286 } while (tp->tty_events);
12287
12288 /* Transfer characters from the input queue to a waiting process. */
12289 in_transfer(tp);
12290
12291 /* Reply if enough bytes are available. */
12292 if (tp->tty_incum >= tp->tty_min && tp->tty_inleft > 0) {
12293 tty_reply(tp->tty_inrepcode, tp->tty_incaller, tp->tty_inproc,
12294 tp->tty_incum);
12295 tp->tty_inleft = tp->tty_incum = 0;
12296 }
12297 }
12300 /*===========================================================================*
12301 * in_transfer *
12302 *===========================================================================*/
12303 PRIVATE void in_transfer(tp)
12304 register tty_t *tp; /* pointer to terminal to read from */
12305 {
12306 /* Transfer bytes from the input queue to a process reading from a terminal. */
12307
12308 int ch;
12309 int count;
12310 phys_bytes buf_phys, user_base;
12311 char buf[64], *bp;
12312
12313 /* Anything to do? */
12314 if (tp->tty_inleft == 0 || tp->tty_eotct < tp->tty_min) return;
12315
12316 buf_phys = vir2phys(buf);
12317 user_base = proc_vir2phys(proc_addr(tp->tty_inproc), 0);
12318 bp = buf;
12319 while (tp->tty_inleft > 0 && tp->tty_eotct > 0) {
12320 ch = *tp->tty_intail;
12321
12322 if (!(ch & IN_EOF)) {
12323 /* One character to be delivered to the user. */
12324 *bp = ch & IN_CHAR;
12325 tp->tty_inleft--;
12326 if (++bp == bufend(buf)) {
12327 /* Temp buffer full, copy to user space. */
12328 phys_copy(buf_phys, user_base + tp->tty_in_vir,
12329 (phys_bytes) buflen(buf));
12330 tp->tty_in_vir += buflen(buf);
12331 tp->tty_incum += buflen(buf);
12332 bp = buf;
12333 }
12334 }
12335
12336 /* Remove the character from the input queue. */
12337 if (++tp->tty_intail == bufend(tp->tty_inbuf))
12338 tp->tty_intail = tp->tty_inbuf;
12339 tp->tty_incount--;
12340 if (ch & IN_EOT) {
12341 tp->tty_eotct--;
12342 /* Don't read past a line break in canonical mode. */
12343 if (tp->tty_termios.c_lflag & ICANON) tp->tty_inleft = 0;
12344 }
12345 }
12346
12347 if (bp > buf) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -