📄 tty.c
字号:
tp->tty_outrepcode = REVIVE; } } tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r);}/*===========================================================================* * do_ioctl * *===========================================================================*/PRIVATE void do_ioctl(tp, m_ptr)register tty_t *tp;message *m_ptr; /* pointer to message sent to task */{/* Perform an IOCTL on this terminal. Posix termios calls are handled * by the IOCTL system call */ int r; union { int i;#if ENABLE_SRCCOMPAT struct sgttyb sg; struct tchars tc;#endif } param; size_t size; /* Size of the ioctl parameter. */ switch (m_ptr->TTY_REQUEST) { case TCGETS: /* Posix tcgetattr function */ case TCSETS: /* Posix tcsetattr function, TCSANOW option */ case TCSETSW: /* Posix tcsetattr function, TCSADRAIN option */ case TCSETSF: /* Posix tcsetattr function, TCSAFLUSH option */ size = sizeof(struct termios); break; case TCSBRK: /* Posix tcsendbreak function */ case TCFLOW: /* Posix tcflow function */ case TCFLSH: /* Posix tcflush function */ case TIOCGPGRP: /* Posix tcgetpgrp function */ case TIOCSPGRP: /* Posix tcsetpgrp function */ size = sizeof(int); break; case TIOCGWINSZ: /* get window size (not Posix) */ case TIOCSWINSZ: /* set window size (not Posix) */ size = sizeof(struct winsize); break;#if ENABLE_SRCCOMPAT case TIOCGETP: /* BSD-style get terminal properties */ case TIOCSETP: /* BSD-style set terminal properties */ size = sizeof(struct sgttyb); break; case TIOCGETC: /* BSD-style get terminal special characters */ case TIOCSETC: /* BSD-style get terminal special characters */ size = sizeof(struct tchars); break;#endif#if (MACHINE == IBM_PC) case KIOCSMAP: /* load keymap (Minix extension) */ size = sizeof(keymap_t); break; case TIOCSFON: /* load font (Minix extension) */ size = sizeof(u8_t [8192]); break;#endif case TCDRAIN: /* Posix tcdrain function -- no parameter */ default: size = 0; } r = OK; switch (m_ptr->TTY_REQUEST) { case TCGETS: /* Get the termios attributes. */ r = sys_vircopy(SELF, D, (vir_bytes) &tp->tty_termios, m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS, (vir_bytes) size); break; case TCSETSW: case TCSETSF: case TCDRAIN: if (tp->tty_outleft > 0) { /* Wait for all ongoing output processing to finish. */ tp->tty_iocaller = m_ptr->m_source; tp->tty_ioproc = m_ptr->PROC_NR; tp->tty_ioreq = m_ptr->REQUEST; tp->tty_iovir = (vir_bytes) m_ptr->ADDRESS; r = SUSPEND; break; } if (m_ptr->TTY_REQUEST == TCDRAIN) break; if (m_ptr->TTY_REQUEST == TCSETSF) tty_icancel(tp); /*FALL THROUGH*/ case TCSETS: /* Set the termios attributes. */ r = sys_vircopy( m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS, SELF, D, (vir_bytes) &tp->tty_termios, (vir_bytes) size); if (r != OK) break; setattr(tp); break; case TCFLSH: r = sys_vircopy( m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS, SELF, D, (vir_bytes) ¶m.i, (vir_bytes) size); if (r != OK) break; switch (param.i) { case TCIFLUSH: tty_icancel(tp); break; case TCOFLUSH: (*tp->tty_ocancel)(tp, 0); break; case TCIOFLUSH: tty_icancel(tp); (*tp->tty_ocancel)(tp, 0); break; default: r = EINVAL; } break; case TCFLOW: r = sys_vircopy( m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS, SELF, D, (vir_bytes) ¶m.i, (vir_bytes) size); if (r != OK) break; switch (param.i) { case TCOOFF: case TCOON: tp->tty_inhibited = (param.i == TCOOFF); tp->tty_events = 1; break; case TCIOFF: (*tp->tty_echo)(tp, tp->tty_termios.c_cc[VSTOP]); break; case TCION: (*tp->tty_echo)(tp, tp->tty_termios.c_cc[VSTART]); break; default: r = EINVAL; } break; case TCSBRK: if (tp->tty_break != NULL) (*tp->tty_break)(tp,0); break; case TIOCGWINSZ: r = sys_vircopy(SELF, D, (vir_bytes) &tp->tty_winsize, m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS, (vir_bytes) size); break; case TIOCSWINSZ: r = sys_vircopy( m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS, SELF, D, (vir_bytes) &tp->tty_winsize, (vir_bytes) size); sigchar(tp, SIGWINCH); break;#if ENABLE_SRCCOMPAT case TIOCGETP: compat_getp(tp, ¶m.sg); r = sys_vircopy(SELF, D, (vir_bytes) ¶m.sg, m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS, (vir_bytes) size); break; case TIOCSETP: r = sys_vircopy( m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS, SELF, D, (vir_bytes) ¶m.sg, (vir_bytes) size); if (r != OK) break; compat_setp(tp, ¶m.sg); break; case TIOCGETC: compat_getc(tp, ¶m.tc); r = sys_vircopy(SELF, D, (vir_bytes) ¶m.tc, m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS, (vir_bytes) size); break; case TIOCSETC: r = sys_vircopy( m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS, SELF, D, (vir_bytes) ¶m.tc, (vir_bytes) size); if (r != OK) break; compat_setc(tp, ¶m.tc); break;#endif#if (MACHINE == IBM_PC) case KIOCSMAP: /* Load a new keymap (only /dev/console). */ if (isconsole(tp)) r = kbd_loadmap(m_ptr); break; case TIOCSFON: /* Load a font into an EGA or VGA card (hs@hck.hr) */ if (isconsole(tp)) r = con_loadfont(m_ptr); break;#endif#if (MACHINE == ATARI) case VDU_LOADFONT: r = vdu_loadfont(m_ptr); break;#endif/* These Posix functions are allowed to fail if _POSIX_JOB_CONTROL is * not defined. */ case TIOCGPGRP: case TIOCSPGRP: default:#if ENABLE_BINCOMPAT do_ioctl_compat(tp, m_ptr); return;#else r = ENOTTY;#endif } /* Send the reply. */ tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r);}/*===========================================================================* * do_open * *===========================================================================*/PRIVATE void do_open(tp, m_ptr)register tty_t *tp;message *m_ptr; /* pointer to message sent to task */{/* A tty line has been opened. Make it the callers controlling tty if * O_NOCTTY is *not* set and it is not the log device. 1 is returned if * the tty is made the controlling tty, otherwise OK or an error code. */ int r = OK; if (m_ptr->TTY_LINE == LOG_MINOR) { /* The log device is a write-only diagnostics device. */ if (m_ptr->COUNT & R_BIT) r = EACCES; } else { if (!(m_ptr->COUNT & O_NOCTTY)) { tp->tty_pgrp = m_ptr->PROC_NR; r = 1; } tp->tty_openct++; } tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r);}/*===========================================================================* * do_close * *===========================================================================*/PRIVATE void do_close(tp, m_ptr)register tty_t *tp;message *m_ptr; /* pointer to message sent to task */{/* A tty line has been closed. Clean up the line if it is the last close. */ if (m_ptr->TTY_LINE != LOG_MINOR && --tp->tty_openct == 0) { tp->tty_pgrp = 0; tty_icancel(tp); (*tp->tty_ocancel)(tp, 0); (*tp->tty_close)(tp, 0); tp->tty_termios = termios_defaults; tp->tty_winsize = winsize_defaults; setattr(tp); } tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, OK);}/*===========================================================================* * do_cancel * *===========================================================================*/PRIVATE void do_cancel(tp, m_ptr)register tty_t *tp;message *m_ptr; /* pointer to message sent to task */{/* A signal has been sent to a process that is hanging trying to read or write. * The pending read or write must be finished off immediately. */ int proc_nr; int mode; /* Check the parameters carefully, to avoid cancelling twice. */ proc_nr = m_ptr->PROC_NR; mode = m_ptr->COUNT; if ((mode & R_BIT) && tp->tty_inleft != 0 && proc_nr == tp->tty_inproc) { /* Process was reading when killed. Clean up input. */ tty_icancel(tp); tp->tty_inleft = tp->tty_incum = 0; } if ((mode & W_BIT) && tp->tty_outleft != 0 && proc_nr == tp->tty_outproc) { /* Process was writing when killed. Clean up output. */ (*tp->tty_ocancel)(tp, 0); tp->tty_outleft = tp->tty_outcum = 0; } if (tp->tty_ioreq != 0 && proc_nr == tp->tty_ioproc) { /* Process was waiting for output to drain. */ tp->tty_ioreq = 0; } tp->tty_events = 1; tty_reply(TASK_REPLY, m_ptr->m_source, proc_nr, EINTR);}PUBLIC int select_try(struct tty *tp, int ops){ int ready_ops = 0; /* Special case. If line is hung up, no operations will block. * (and it can be seen as an exceptional condition.) */ if (tp->tty_termios.c_ospeed == B0) { ready_ops |= ops; } if (ops & SEL_RD) { /* will i/o not block on read? */ if (tp->tty_inleft > 0) { ready_ops |= SEL_RD; /* EIO - no blocking */ } else if (tp->tty_incount > 0) { /* Is a regular read possible? tty_incount * says there is data. But a read will only succeed * in canonical mode if a newline has been seen. */ if (!(tp->tty_termios.c_lflag & ICANON) || tp->tty_eotct > 0) { ready_ops |= SEL_RD; } } } if (ops & SEL_WR) { if (tp->tty_outleft > 0) ready_ops |= SEL_WR; else if ((*tp->tty_devwrite)(tp, 1)) ready_ops |= SEL_WR; } return ready_ops;}PUBLIC int select_retry(struct tty *tp){ if (select_try(tp, tp->tty_select_ops)) notify(tp->tty_select_proc); return OK;}/*===========================================================================* * handle_events * *===========================================================================*/PUBLIC void handle_events(tp)tty_t *tp; /* TTY to check for events. */{/* Handle any events pending on a TTY. These events are usually device * interrupts. * * Two kinds of events are prominent: * - a character has been received from the console or an RS232 line. * - an RS232 line has completed a write request (on behalf of a user). * The interrupt handler may delay the interrupt message at its discretion * to avoid swamping the TTY task. Messages may be overwritten when the * lines are fast or when there are races between different lines, input * and output, because MINIX only provides single buffering for interrupt * messages (in proc.c). This is handled by explicitly checking each line * for fresh input and completed output on each interrupt. */ char *buf; unsigned count; int status; do { tp->tty_events = 0; /* Read input and perform input processing. */ (*tp->tty_devread)(tp, 0); /* Perform output processing and write output. */ (*tp->tty_devwrite)(tp, 0); /* Ioctl waiting for some event? */ if (tp->tty_ioreq != 0) dev_ioctl(tp); } while (tp->tty_events); /* Transfer characters from the input queue to a waiting process. */ in_transfer(tp); /* Reply if enough bytes are available. */ if (tp->tty_incum >= tp->tty_min && tp->tty_inleft > 0) { if (tp->tty_inrepcode == REVIVE) { notify(tp->tty_incaller); tp->tty_inrevived = 1; } else { tty_reply(tp->tty_inrepcode, tp->tty_incaller, tp->tty_inproc, tp->tty_incum); tp->tty_inleft = tp->tty_incum = 0; } } if (tp->tty_select_ops) select_retry(tp);#if NR_PTYS > 0 if (ispty(tp)) select_retry_pty(tp);#endif}/*===========================================================================* * in_transfer * *===========================================================================*/PRIVATE void in_transfer(tp)register tty_t *tp; /* pointer to terminal to read from */{/* Transfer bytes from the input queue to a process reading from a terminal. */ int ch; int count; char buf[64], *bp; /* Force read to succeed if the line is hung up, looks like EOF to reader. */ if (tp->tty_termios.c_ospeed == B0) tp->tty_min = 0; /* Anything to do? */ if (tp->tty_inleft == 0 || tp->tty_eotct < tp->tty_min) return; bp = buf; while (tp->tty_inleft > 0 && tp->tty_eotct > 0) { ch = *tp->tty_intail; if (!(ch & IN_EOF)) { /* One character to be delivered to the user. */ *bp = ch & IN_CHAR; tp->tty_inleft--; if (++bp == bufend(buf)) { /* Temp buffer full, copy to user space. */ sys_vircopy(SELF, D, (vir_bytes) buf, tp->tty_inproc, D, tp->tty_in_vir, (vir_bytes) buflen(buf)); tp->tty_in_vir += buflen(buf); tp->tty_incum += buflen(buf); bp = buf; } } /* Remove the character from the input queue. */ if (++tp->tty_intail == bufend(tp->tty_inbuf)) tp->tty_intail = tp->tty_inbuf; tp->tty_incount--; if (ch & IN_EOT) { tp->tty_eotct--; /* Don't read past a line break in canonical mode. */ if (tp->tty_termios.c_lflag & ICANON) tp->tty_inleft = 0; } } if (bp > buf) { /* Leftover characters in the buffer. */ count = bp - buf; sys_vircopy(SELF, D, (vir_bytes) buf, tp->tty_inproc, D, tp->tty_in_vir, (vir_bytes) count); tp->tty_in_vir += count; tp->tty_incum += count; } /* Usually reply to the reader, possibly even if incum == 0 (EOF). */ if (tp->tty_inleft == 0) { if (tp->tty_inrepcode == REVIVE) { notify(tp->tty_incaller); tp->tty_inrevived = 1; } else { tty_reply(tp->tty_inrepcode, tp->tty_incaller, tp->tty_inproc, tp->tty_incum); tp->tty_inleft = tp->tty_incum = 0; } }}/*===========================================================================* * in_process * *===========================================================================*/PUBLIC int in_process(tp, buf, count)register tty_t *tp; /* terminal on which character has arrived */char *buf; /* buffer with input characters */int count; /* number of input characters */{/* Characters have just been typed in. Process, save, and echo them. Return * the number of characters processed. */ int ch, sig, ct; int timeset = FALSE; static unsigned char csize_mask[] = { 0x1F, 0x3F, 0x7F, 0xFF }; for (ct = 0; ct < count; ct++) { /* Take one character. */ ch = *buf++ & BYTE; /* Strip to seven bits? */ if (tp->tty_termios.c_iflag & ISTRIP) ch &= 0x7F; /* Input extensions? */ if (tp->tty_termios.c_lflag & IEXTEN) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -