⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tty.c

📁 MINIX2.0操作系统源码 MINIX2.0操作系统源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* This file contains the terminal driver, both for the IBM console and regular
 * ASCII terminals.  It handles only the device-independent part of a TTY, the
 * device dependent parts are in console.c, rs232.c, etc.  This file contains
 * two main entry points, tty_task() and tty_wakeup(), and several minor entry
 * points for use by the device-dependent code.
 *
 * The device-independent part accepts "keyboard" input from the device-
 * dependent part, performs input processing (special key interpretation),
 * and sends the input to a process reading from the TTY.  Output to a TTY
 * is sent to the device-dependent code for output processing and "screen"
 * display.  Input processing is done by the device by calling 'in_process'
 * on the input characters, output processing may be done by the device itself
 * or by calling 'out_process'.  The TTY takes care of input queuing, the
 * device does the output queuing.  If a device receives an external signal,
 * like an interrupt, then it causes tty_wakeup() to be run by the CLOCK task
 * to, you guessed it, wake up the TTY to check if input or output can
 * continue.
 *
 * The valid messages and their parameters are:
 *
 *   HARD_INT:     output has been completed or input has arrived
 *   DEV_READ:     a process wants to read from a terminal
 *   DEV_WRITE:    a process wants to write on a terminal
 *   DEV_IOCTL:    a process wants to change a terminal's parameters
 *   DEV_OPEN:     a tty line has been opened
 *   DEV_CLOSE:    a tty line has been closed
 *   CANCEL:       terminate a previous incomplete system call immediately
 *
 *    m_type      TTY_LINE   PROC_NR    COUNT   TTY_SPEK  TTY_FLAGS  ADDRESS
 * ---------------------------------------------------------------------------
 * | HARD_INT    |         |         |         |         |         |         |
 * |-------------+---------+---------+---------+---------+---------+---------|
 * | DEV_READ    |minor dev| proc nr |  count  |         O_NONBLOCK| buf ptr |
 * |-------------+---------+---------+---------+---------+---------+---------|
 * | DEV_WRITE   |minor dev| proc nr |  count  |         |         | buf ptr |
 * |-------------+---------+---------+---------+---------+---------+---------|
 * | DEV_IOCTL   |minor dev| proc nr |func code|erase etc|  flags  |         |
 * |-------------+---------+---------+---------+---------+---------+---------|
 * | DEV_OPEN    |minor dev| proc nr | O_NOCTTY|         |         |         |
 * |-------------+---------+---------+---------+---------+---------+---------|
 * | DEV_CLOSE   |minor dev| proc nr |         |         |         |         |
 * |-------------+---------+---------+---------+---------+---------+---------|
 * | CANCEL      |minor dev| proc nr |         |         |         |         |
 * ---------------------------------------------------------------------------
 */

#include "kernel.h"
#include <termios.h>
#if ENABLE_SRCCOMPAT || ENABLE_BINCOMPAT
#include <sgtty.h>
#endif
#include <sys/ioctl.h>
#include <signal.h>
#include <minix/callnr.h>
#include <minix/com.h>
#if (CHIP == INTEL)
#include <minix/keymap.h>
#endif
#include "tty.h"
#include "proc.h"

/* Address of a tty structure. */
#define tty_addr(line)	(&tty_table[line])

/* First minor numbers for the various classes of TTY devices. */
#define CONS_MINOR	  0
#define LOG_MINOR	 15
#define RS232_MINOR	 16
#define TTYPX_MINOR	128
#define PTYPX_MINOR	192

/* Macros for magic tty types. */
#define isconsole(tp)	((tp) < tty_addr(NR_CONS))

/* Macros for magic tty structure pointers. */
#define FIRST_TTY	tty_addr(0)
#define END_TTY		tty_addr(sizeof(tty_table) / sizeof(tty_table[0]))

/* A device exists if at least its 'devread' function is defined. */
#define tty_active(tp)	((tp)->tty_devread != NULL)

/* RS232 lines or pseudo terminals can be completely configured out. */
#if NR_RS_LINES == 0
#define rs_init(tp)	((void) 0)
#endif
#if NR_PTYS == 0
#define pty_init(tp)	((void) 0)
#define do_pty(tp, mp)	((void) 0)
#endif

FORWARD _PROTOTYPE( void do_cancel, (tty_t *tp, message *m_ptr)		);
FORWARD _PROTOTYPE( void do_ioctl, (tty_t *tp, message *m_ptr)		);
FORWARD _PROTOTYPE( void do_open, (tty_t *tp, message *m_ptr)		);
FORWARD _PROTOTYPE( void do_close, (tty_t *tp, message *m_ptr)		);
FORWARD _PROTOTYPE( void do_read, (tty_t *tp, message *m_ptr)		);
FORWARD _PROTOTYPE( void do_write, (tty_t *tp, message *m_ptr)		);
FORWARD _PROTOTYPE( void in_transfer, (tty_t *tp)			);
FORWARD _PROTOTYPE( int echo, (tty_t *tp, int ch)			);
FORWARD _PROTOTYPE( void rawecho, (tty_t *tp, int ch)			);
FORWARD _PROTOTYPE( int back_over, (tty_t *tp)				);
FORWARD _PROTOTYPE( void reprint, (tty_t *tp)				);
FORWARD _PROTOTYPE( void dev_ioctl, (tty_t *tp)				);
FORWARD _PROTOTYPE( void setattr, (tty_t *tp)				);
FORWARD _PROTOTYPE( void tty_icancel, (tty_t *tp)			);
FORWARD _PROTOTYPE( void tty_init, (tty_t *tp)				);
FORWARD _PROTOTYPE( void settimer, (tty_t *tp, int on)			);
#if ENABLE_SRCCOMPAT || ENABLE_BINCOMPAT
FORWARD _PROTOTYPE( int compat_getp, (tty_t *tp, struct sgttyb *sg)	);
FORWARD _PROTOTYPE( int compat_getc, (tty_t *tp, struct tchars *sg)	);
FORWARD _PROTOTYPE( int compat_setp, (tty_t *tp, struct sgttyb *sg)	);
FORWARD _PROTOTYPE( int compat_setc, (tty_t *tp, struct tchars *sg)	);
FORWARD _PROTOTYPE( int tspd2sgspd, (speed_t tspd)			);
FORWARD _PROTOTYPE( speed_t sgspd2tspd, (int sgspd)			);
#if ENABLE_BINCOMPAT
FORWARD _PROTOTYPE( void do_ioctl_compat, (tty_t *tp, message *m_ptr)	);
#endif
#endif

/* Default attributes. */
PRIVATE struct termios termios_defaults = {
  TINPUT_DEF, TOUTPUT_DEF, TCTRL_DEF, TLOCAL_DEF, TSPEED_DEF, TSPEED_DEF,
  {
	TEOF_DEF, TEOL_DEF, TERASE_DEF, TINTR_DEF, TKILL_DEF, TMIN_DEF,
	TQUIT_DEF, TTIME_DEF, TSUSP_DEF, TSTART_DEF, TSTOP_DEF,
	TREPRINT_DEF, TLNEXT_DEF, TDISCARD_DEF,
  },
};
PRIVATE struct winsize winsize_defaults;	/* = all zeroes */


/*===========================================================================*
 *				tty_task				     *
 *===========================================================================*/
PUBLIC void tty_task()
{
/* Main routine of the terminal task. */

  message tty_mess;		/* buffer for all incoming messages */
  register tty_t *tp;
  unsigned line;

  /* Initialize the terminal lines. */
  for (tp = FIRST_TTY; tp < END_TTY; tp++) tty_init(tp);

  /* Display the Minix startup banner. */
  printf("Minix %s.%s  Copyright 1997 Prentice-Hall, Inc.\n\n",
						OS_RELEASE, OS_VERSION);

#if (CHIP == INTEL)
  /* Real mode, or 16/32-bit protected mode? */
#if _WORD_SIZE == 4
  printf("Executing in 32-bit protected mode\n\n");
#else
  printf("Executing in %s mode\n\n",
	protected_mode ? "16-bit protected" : "real");
#endif
#endif

  while (TRUE) {
	/* Handle any events on any of the ttys. */
	for (tp = FIRST_TTY; tp < END_TTY; tp++) {
		if (tp->tty_events) handle_events(tp);
	}

	receive(ANY, &tty_mess);

	/* A hardware interrupt is an invitation to check for events. */
	if (tty_mess.m_type == HARD_INT) continue;

	/* Check the minor device number. */
	line = tty_mess.TTY_LINE;
	if ((line - CONS_MINOR) < NR_CONS) {
		tp = tty_addr(line - CONS_MINOR);
	} else
	if (line == LOG_MINOR) {
		tp = tty_addr(0);
	} else
	if ((line - RS232_MINOR) < NR_RS_LINES) {
		tp = tty_addr(line - RS232_MINOR + NR_CONS);
	} else
	if ((line - TTYPX_MINOR) < NR_PTYS) {
		tp = tty_addr(line - TTYPX_MINOR + NR_CONS + NR_RS_LINES);
	} else
	if ((line - PTYPX_MINOR) < NR_PTYS) {
		tp = tty_addr(line - PTYPX_MINOR + NR_CONS + NR_RS_LINES);
		do_pty(tp, &tty_mess);
		continue;			/* this is a pty, not a tty */
	} else {
		tp = NULL;
	}

	/* If the device doesn't exist or is not configured return ENXIO. */
	if (tp == NULL || !tty_active(tp)) {
		tty_reply(TASK_REPLY, tty_mess.m_source,
						tty_mess.PROC_NR, ENXIO);
		continue;
	}

	/* Execute the requested function. */
	switch (tty_mess.m_type) {
	    case DEV_READ:	do_read(tp, &tty_mess);		break;
	    case DEV_WRITE:	do_write(tp, &tty_mess);	break;
	    case DEV_IOCTL:	do_ioctl(tp, &tty_mess);	break;
	    case DEV_OPEN:	do_open(tp, &tty_mess);		break;
	    case DEV_CLOSE:	do_close(tp, &tty_mess);	break;
	    case CANCEL:	do_cancel(tp, &tty_mess);	break;
	    default:		tty_reply(TASK_REPLY, tty_mess.m_source,
						tty_mess.PROC_NR, EINVAL);
	}
  }
}


/*===========================================================================*
 *				do_read					     *
 *===========================================================================*/
PRIVATE void do_read(tp, m_ptr)
register tty_t *tp;		/* pointer to tty struct */
message *m_ptr;			/* pointer to message sent to the task */
{
/* A process wants to read from a terminal. */
  int r;

  /* Check if there is already a process hanging in a read, check if the
   * parameters are correct, do I/O.
   */
  if (tp->tty_inleft > 0) {
	r = EIO;
  } else
  if (m_ptr->COUNT <= 0) {
	r = EINVAL;
  } else
  if (numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS, m_ptr->COUNT) == 0) {
	r = EFAULT;
  } else {
	/* Copy information from the message to the tty struct. */
	tp->tty_inrepcode = TASK_REPLY;
	tp->tty_incaller = m_ptr->m_source;
	tp->tty_inproc = m_ptr->PROC_NR;
	tp->tty_in_vir = (vir_bytes) m_ptr->ADDRESS;
	tp->tty_inleft = m_ptr->COUNT;

	if (!(tp->tty_termios.c_lflag & ICANON)
					&& tp->tty_termios.c_cc[VTIME] > 0) {
		if (tp->tty_termios.c_cc[VMIN] == 0) {
			/* MIN & TIME specify a read timer that finishes the
			 * read in TIME/10 seconds if no bytes are available.
			 */
			lock();
			settimer(tp, TRUE);
			tp->tty_min = 1;
			unlock();
		} else {
			/* MIN & TIME specify an inter-byte timer that may
			 * have to be cancelled if there are no bytes yet.
			 */
			if (tp->tty_eotct == 0) {
				lock();
				settimer(tp, FALSE);
				unlock();
				tp->tty_min = tp->tty_termios.c_cc[VMIN];
			}
		}
	}

	/* Anything waiting in the input buffer? Clear it out... */
	in_transfer(tp);
	/* ...then go back for more */
	handle_events(tp);
	if (tp->tty_inleft == 0) return;		/* already done */

	/* There were no bytes in the input queue available, so either suspend
	 * the caller or break off the read if nonblocking.
	 */
	if (m_ptr->TTY_FLAGS & O_NONBLOCK) {
		r = EAGAIN;				/* cancel the read */
		tp->tty_inleft = tp->tty_incum = 0;
	} else {
		r = SUSPEND;				/* suspend the caller */
		tp->tty_inrepcode = REVIVE;
	}
  }
  tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r);
}


/*===========================================================================*
 *				do_write				     *
 *===========================================================================*/
PRIVATE void do_write(tp, m_ptr)
register tty_t *tp;
register message *m_ptr;	/* pointer to message sent to the task */
{
/* A process wants to write on a terminal. */
  int r;

  /* Check if there is already a process hanging in a write, check if the
   * parameters are correct, do I/O.
   */
  if (tp->tty_outleft > 0) {
	r = EIO;
  } else
  if (m_ptr->COUNT <= 0) {
	r = EINVAL;
  } else
  if (numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS, m_ptr->COUNT) == 0) {
	r = EFAULT;
  } else {
	/* Copy message parameters to the tty structure. */
	tp->tty_outrepcode = TASK_REPLY;
	tp->tty_outcaller = m_ptr->m_source;
	tp->tty_outproc = m_ptr->PROC_NR;
	tp->tty_out_vir = (vir_bytes) m_ptr->ADDRESS;
	tp->tty_outleft = m_ptr->COUNT;

	/* Try to write. */
	handle_events(tp);
	if (tp->tty_outleft == 0) return;		/* already done */

	/* None or not all the bytes could be written, so either suspend the
	 * caller or break off the write if nonblocking.
	 */
	if (m_ptr->TTY_FLAGS & O_NONBLOCK) {		/* cancel the write */
		r = tp->tty_outcum > 0 ? tp->tty_outcum : EAGAIN;
		tp->tty_outleft = tp->tty_outcum = 0;
	} else {
		r = SUSPEND;				/* suspend the caller */
		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;
  phys_bytes user_phys;
  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;
  }

  if (size != 0) {
	user_phys = numap(m_ptr->PROC_NR, (vir_bytes) m_ptr->ADDRESS, size);
	if (user_phys == 0) {
		tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, EFAULT);
		return;
	}
  }

  r = OK;
  switch (m_ptr->TTY_REQUEST) {
    case TCGETS:
	/* Get the termios attributes. */
	phys_copy(vir2phys(&tp->tty_termios), user_phys, (phys_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;
	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -