📄 tty.c
字号:
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/kernel/tty.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
11700 /* This file contains the terminal driver, both for the IBM console and regular
11701 * ASCII terminals. It handles only the device-independent part of a TTY, the
11702 * device dependent parts are in console.c, rs232.c, etc. This file contains
11703 * two main entry points, tty_task() and tty_wakeup(), and several minor entry
11704 * points for use by the device-dependent code.
11705 *
11706 * The device-independent part accepts "keyboard" input from the device-
11707 * dependent part, performs input processing (special key interpretation),
11708 * and sends the input to a process reading from the TTY. Output to a TTY
11709 * is sent to the device-dependent code for output processing and "screen"
11710 * display. Input processing is done by the device by calling 'in_process'
11711 * on the input characters, output processing may be done by the device itself
11712 * or by calling 'out_process'. The TTY takes care of input queuing, the
11713 * device does the output queuing. If a device receives an external signal,
11714 * like an interrupt, then it causes tty_wakeup() to be run by the CLOCK task
11715 * to, you guessed it, wake up the TTY to check if input or output can
11716 * continue.
11717 *
11718 * The valid messages and their parameters are:
11719 *
11720 * HARD_INT: output has been completed or input has arrived
11721 * DEV_READ: a process wants to read from a terminal
11722 * DEV_WRITE: a process wants to write on a terminal
11723 * DEV_IOCTL: a process wants to change a terminal's parameters
11724 * DEV_OPEN: a tty line has been opened
11725 * DEV_CLOSE: a tty line has been closed
11726 * CANCEL: terminate a previous incomplete system call immediately
11727 *
11728 * m_type TTY_LINE PROC_NR COUNT TTY_SPEK TTY_FLAGS ADDRESS
11729 * ---------------------------------------------------------------------------
11730 * | HARD_INT | | | | | | |
11731 * |-------------+---------+---------+---------+---------+---------+---------|
11732 * | DEV_READ |minor dev| proc nr | count | O_NONBLOCK| buf ptr |
11733 * |-------------+---------+---------+---------+---------+---------+---------|
11734 * | DEV_WRITE |minor dev| proc nr | count | | | buf ptr |
11735 * |-------------+---------+---------+---------+---------+---------+---------|
11736 * | DEV_IOCTL |minor dev| proc nr |func code|erase etc| flags | |
11737 * |-------------+---------+---------+---------+---------+---------+---------|
11738 * | DEV_OPEN |minor dev| proc nr | O_NOCTTY| | | |
11739 * |-------------+---------+---------+---------+---------+---------+---------|
11740 * | DEV_CLOSE |minor dev| proc nr | | | | |
11741 * |-------------+---------+---------+---------+---------+---------+---------|
11742 * | CANCEL |minor dev| proc nr | | | | |
11743 * ---------------------------------------------------------------------------
11744 */
11745
11746 #include "kernel.h"
11747 #include <termios.h>
11748 #include <sys/ioctl.h>
11749 #include <signal.h>
11750 #include <minix/callnr.h>
11751 #include <minix/com.h>
11752 #include <minix/keymap.h>
11753 #include "tty.h"
11754 #include "proc.h"
11755
11756 /* Address of a tty structure. */
11757 #define tty_addr(line) (&tty_table[line])
11758
11759 /* First minor numbers for the various classes of TTY devices. */
11760 #define CONS_MINOR 0
11761 #define LOG_MINOR 15
11762 #define RS232_MINOR 16
11763 #define TTYPX_MINOR 128
11764 #define PTYPX_MINOR 192
11765
11766 /* Macros for magic tty types. */
11767 #define isconsole(tp) ((tp) < tty_addr(NR_CONS))
11768
11769 /* Macros for magic tty structure pointers. */
11770 #define FIRST_TTY tty_addr(0)
11771 #define END_TTY tty_addr(sizeof(tty_table) / sizeof(tty_table[0]))
11772
11773 /* A device exists if at least its 'devread' function is defined. */
11774 #define tty_active(tp) ((tp)->tty_devread != NULL)
11775
11776 /* RS232 lines or pseudo terminals can be completely configured out. */
11777 #if NR_RS_LINES == 0
11778 #define rs_init(tp) ((void) 0)
11779 #endif
11780 #if NR_PTYS == 0
11781 #define pty_init(tp) ((void) 0)
11782 #define do_pty(tp, mp) ((void) 0)
11783 #endif
11784
11785 FORWARD _PROTOTYPE( void do_cancel, (tty_t *tp, message *m_ptr) );
11786 FORWARD _PROTOTYPE( void do_ioctl, (tty_t *tp, message *m_ptr) );
11787 FORWARD _PROTOTYPE( void do_open, (tty_t *tp, message *m_ptr) );
11788 FORWARD _PROTOTYPE( void do_close, (tty_t *tp, message *m_ptr) );
11789 FORWARD _PROTOTYPE( void do_read, (tty_t *tp, message *m_ptr) );
11790 FORWARD _PROTOTYPE( void do_write, (tty_t *tp, message *m_ptr) );
11791 FORWARD _PROTOTYPE( void in_transfer, (tty_t *tp) );
11792 FORWARD _PROTOTYPE( int echo, (tty_t *tp, int ch) );
11793 FORWARD _PROTOTYPE( void rawecho, (tty_t *tp, int ch) );
11794 FORWARD _PROTOTYPE( int back_over, (tty_t *tp) );
11795 FORWARD _PROTOTYPE( void reprint, (tty_t *tp) );
11796 FORWARD _PROTOTYPE( void dev_ioctl, (tty_t *tp) );
11797 FORWARD _PROTOTYPE( void setattr, (tty_t *tp) );
11798 FORWARD _PROTOTYPE( void tty_icancel, (tty_t *tp) );
11799 FORWARD _PROTOTYPE( void tty_init, (tty_t *tp) );
11800 FORWARD _PROTOTYPE( void settimer, (tty_t *tp, int on) );
11801
11802 /* Default attributes. */
11803 PRIVATE struct termios termios_defaults = {
11804 TINPUT_DEF, TOUTPUT_DEF, TCTRL_DEF, TLOCAL_DEF, TSPEED_DEF, TSPEED_DEF,
11805 {
11806 TEOF_DEF, TEOL_DEF, TERASE_DEF, TINTR_DEF, TKILL_DEF, TMIN_DEF,
11807 TQUIT_DEF, TTIME_DEF, TSUSP_DEF, TSTART_DEF, TSTOP_DEF,
11808 TREPRINT_DEF, TLNEXT_DEF, TDISCARD_DEF,
11809 },
11810 };
11811 PRIVATE struct winsize winsize_defaults; /* = all zeroes */
11812
11813
11814 /*===========================================================================*
11815 * tty_task *
11816 *===========================================================================*/
11817 PUBLIC void tty_task()
11818 {
11819 /* Main routine of the terminal task. */
11820
11821 message tty_mess; /* buffer for all incoming messages */
11822 register tty_t *tp;
11823 unsigned line;
11824
11825 /* Initialize the terminal lines. */
11826 for (tp = FIRST_TTY; tp < END_TTY; tp++) tty_init(tp);
11827
11828 /* Display the Minix startup banner. */
11829 printf("Minix %s.%s Copyright 1997 Prentice-Hall, Inc.\n\n",
11830 OS_RELEASE, OS_VERSION);
11831 printf("Executing in 32-bit protected mode\n\n");
11832
11833 while (TRUE) {
11834 /* Handle any events on any of the ttys. */
11835 for (tp = FIRST_TTY; tp < END_TTY; tp++) {
11836 if (tp->tty_events) handle_events(tp);
11837 }
11838
11839 receive(ANY, &tty_mess);
11840
11841 /* A hardware interrupt is an invitation to check for events. */
11842 if (tty_mess.m_type == HARD_INT) continue;
11843
11844 /* Check the minor device number. */
11845 line = tty_mess.TTY_LINE;
11846 if ((line - CONS_MINOR) < NR_CONS) {
11847 tp = tty_addr(line - CONS_MINOR);
11848 } else
11849 if (line == LOG_MINOR) {
11850 tp = tty_addr(0);
11851 } else
11852 if ((line - RS232_MINOR) < NR_RS_LINES) {
11853 tp = tty_addr(line - RS232_MINOR + NR_CONS);
11854 } else
11855 if ((line - TTYPX_MINOR) < NR_PTYS) {
11856 tp = tty_addr(line - TTYPX_MINOR + NR_CONS + NR_RS_LINES);
11857 } else
11858 if ((line - PTYPX_MINOR) < NR_PTYS) {
11859 tp = tty_addr(line - PTYPX_MINOR + NR_CONS + NR_RS_LINES);
11860 do_pty(tp, &tty_mess);
11861 continue; /* this is a pty, not a tty */
11862 } else {
11863 tp = NULL;
11864 }
11865
11866 /* If the device doesn't exist or is not configured return ENXIO. */
11867 if (tp == NULL || !tty_active(tp)) {
11868 tty_reply(TASK_REPLY, tty_mess.m_source,
11869 tty_mess.PROC_NR, ENXIO);
11870 continue;
11871 }
11872
11873 /* Execute the requested function. */
11874 switch (tty_mess.m_type) {
11875 case DEV_READ: do_read(tp, &tty_mess); break;
11876 case DEV_WRITE: do_write(tp, &tty_mess); break;
11877 case DEV_IOCTL: do_ioctl(tp, &tty_mess); break;
11878 case DEV_OPEN: do_open(tp, &tty_mess); break;
11879 case DEV_CLOSE: do_close(tp, &tty_mess); break;
11880 case CANCEL: do_cancel(tp, &tty_mess); break;
11881 default: tty_reply(TASK_REPLY, tty_mess.m_source,
11882 tty_mess.PROC_NR, EINVAL);
11883 }
11884 }
11885 }
11888 /*===========================================================================*
11889 * do_read *
11890 *===========================================================================*/
11891 PRIVATE void do_read(tp, m_ptr)
11892 register tty_t *tp; /* pointer to tty struct */
11893 message *m_ptr; /* pointer to message sent to the task */
11894 {
11895 /* A process wants to read from a terminal. */
11896 int r;
11897
11898 /* Check if there is already a process hanging in a read, check if the
11899 * parameters are correct, do I/O.
11900 */
11901 if (tp->tty_inleft > 0) {
11902 r = EIO;
11903 } else
11904 if (m_ptr->COUNT <= 0) {
11905 r = EINVAL;
11906 } else
11907 if (numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS, m_ptr->COUNT) == 0) {
11908 r = EFAULT;
11909 } else {
11910 /* Copy information from the message to the tty struct. */
11911 tp->tty_inrepcode = TASK_REPLY;
11912 tp->tty_incaller = m_ptr->m_source;
11913 tp->tty_inproc = m_ptr->PROC_NR;
11914 tp->tty_in_vir = (vir_bytes) m_ptr->ADDRESS;
11915 tp->tty_inleft = m_ptr->COUNT;
11916
11917 if (!(tp->tty_termios.c_lflag & ICANON)
11918 && tp->tty_termios.c_cc[VTIME] > 0) {
11919 if (tp->tty_termios.c_cc[VMIN] == 0) {
11920 /* MIN & TIME specify a read timer that finishes the
11921 * read in TIME/10 seconds if no bytes are available.
11922 */
11923 lock();
11924 settimer(tp, TRUE);
11925 tp->tty_min = 1;
11926 unlock();
11927 } else {
11928 /* MIN & TIME specify an inter-byte timer that may
11929 * have to be cancelled if there are no bytes yet.
11930 */
11931 if (tp->tty_eotct == 0) {
11932 lock();
11933 settimer(tp, FALSE);
11934 unlock();
11935 tp->tty_min = tp->tty_termios.c_cc[VMIN];
11936 }
11937 }
11938 }
11939
11940 /* Anything waiting in the input buffer? Clear it out... */
11941 in_transfer(tp);
11942 /* ...then go back for more */
11943 handle_events(tp);
11944 if (tp->tty_inleft == 0) return; /* already done */
11945
11946 /* There were no bytes in the input queue available, so either suspend
11947 * the caller or break off the read if nonblocking.
11948 */
11949 if (m_ptr->TTY_FLAGS & O_NONBLOCK) {
11950 r = EAGAIN; /* cancel the read */
11951 tp->tty_inleft = tp->tty_incum = 0;
11952 } else {
11953 r = SUSPEND; /* suspend the caller */
11954 tp->tty_inrepcode = REVIVE;
11955 }
11956 }
11957 tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r);
11958 }
11961 /*===========================================================================*
11962 * do_write *
11963 *===========================================================================*/
11964 PRIVATE void do_write(tp, m_ptr)
11965 register tty_t *tp;
11966 register message *m_ptr; /* pointer to message sent to the task */
11967 {
11968 /* A process wants to write on a terminal. */
11969 int r;
11970
11971 /* Check if there is already a process hanging in a write, check if the
11972 * parameters are correct, do I/O.
11973 */
11974 if (tp->tty_outleft > 0) {
11975 r = EIO;
11976 } else
11977 if (m_ptr->COUNT <= 0) {
11978 r = EINVAL;
11979 } else
11980 if (numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS, m_ptr->COUNT) == 0) {
11981 r = EFAULT;
11982 } else {
11983 /* Copy message parameters to the tty structure. */
11984 tp->tty_outrepcode = TASK_REPLY;
11985 tp->tty_outcaller = m_ptr->m_source;
11986 tp->tty_outproc = m_ptr->PROC_NR;
11987 tp->tty_out_vir = (vir_bytes) m_ptr->ADDRESS;
11988 tp->tty_outleft = m_ptr->COUNT;
11989
11990 /* Try to write. */
11991 handle_events(tp);
11992 if (tp->tty_outleft == 0) return; /* already done */
11993
11994 /* None or not all the bytes could be written, so either suspend the
11995 * caller or break off the write if nonblocking.
11996 */
11997 if (m_ptr->TTY_FLAGS & O_NONBLOCK) { /* cancel the write */
11998 r = tp->tty_outcum > 0 ? tp->tty_outcum : EAGAIN;
11999 tp->tty_outleft = tp->tty_outcum = 0;
12000 } else {
12001 r = SUSPEND; /* suspend the caller */
12002 tp->tty_outrepcode = REVIVE;
12003 }
12004 }
12005 tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r);
12006 }
12009 /*===========================================================================*
12010 * do_ioctl *
12011 *===========================================================================*/
12012 PRIVATE void do_ioctl(tp, m_ptr)
12013 register tty_t *tp;
12014 message *m_ptr; /* pointer to message sent to task */
12015 {
12016 /* Perform an IOCTL on this terminal. Posix termios calls are handled
12017 * by the IOCTL system call
12018 */
12019
12020 int r;
12021 union {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -