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

📄 tty.c

📁 Minix3.11的源码。[MINIX 3是一个为高可靠性应用而设计的自由且简洁的类UNIX系统。]
💻 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 *   SYS_SIG:      e.g., MINIX wants to shutdown; run code to cleanly stop *   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 *   DEV_SELECT:     start select notification request *   DEV_STATUS:     FS wants to know status for SELECT or REVIVE *   CANCEL:         terminate a previous incomplete system call immediately * *    m_type      TTY_LINE   PROC_NR    COUNT   TTY_SPEK  TTY_FLAGS  ADDRESS * --------------------------------------------------------------------------- * | HARD_INT    |         |         |         |         |         |         | * |-------------+---------+---------+---------+---------+---------+---------| * | SYS_SIG     | sig set |         |         |         |         |         | * |-------------+---------+---------+---------+---------+---------+---------| * | 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 |         |         |         |         | * |-------------+---------+---------+---------+---------+---------+---------| * | DEV_SELECT  |         |         |         |         |         |         | * |-------------+---------+---------+---------+---------+---------+---------| * | DEV_STATUS  |         |         |         |         |         |         | * |-------------+---------+---------+---------+---------+---------+---------| * | CANCEL      |minor dev| proc nr |         |         |         |         | * --------------------------------------------------------------------------- * * Changes: *   Jan 20, 2004   moved TTY driver to user-space  (Jorrit N. Herder) *   Sep 20, 2004   local timer management/ sync alarms  (Jorrit N. Herder) *   Jul 13, 2004   support for function key observers  (Jorrit N. Herder)   */#include "../drivers.h"#include <termios.h>#if ENABLE_SRCCOMPAT || ENABLE_BINCOMPAT#include <sgtty.h>#endif#include <sys/ioc_tty.h>#include <signal.h>#include <minix/callnr.h>#if (CHIP == INTEL)#include <minix/keymap.h>#endif#include "tty.h"#include <sys/time.h>#include <sys/select.h>extern int irq_hook_id;unsigned long kbd_irq_set = 0;unsigned long rs_irq_set = 0;/* Address of a tty structure. */#define tty_addr(line)	(&tty_table[line])/* Macros for magic tty types. */#define isconsole(tp)	((tp) < tty_addr(NR_CONS))#define ispty(tp)	((tp) >= tty_addr(NR_CONS+NR_RS_LINES))/* 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)#endifstruct kmessages kmess;FORWARD _PROTOTYPE( void tty_timed_out, (timer_t *tp)			);FORWARD _PROTOTYPE( void expire_timers, (void)				);FORWARD _PROTOTYPE( void settimer, (tty_t *tty_ptr, int enable)		);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 do_select, (tty_t *tp, message *m_ptr)		);FORWARD _PROTOTYPE( void do_status, (message *m_ptr)			);FORWARD _PROTOTYPE( void in_transfer, (tty_t *tp)			);FORWARD _PROTOTYPE( int tty_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, (void)				);#if ENABLE_SRCCOMPAT || ENABLE_BINCOMPATFORWARD _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_BINCOMPATFORWARD _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 *//* Global variables for the TTY task (declared extern in tty.h). */PUBLIC tty_t tty_table[NR_CONS+NR_RS_LINES+NR_PTYS];PUBLIC int ccurrent;			/* currently active console */PUBLIC timer_t *tty_timers;		/* queue of TTY timers */PUBLIC clock_t tty_next_timeout;	/* time that the next alarm is due */PUBLIC struct machine machine;		/* kernel environment variables *//*===========================================================================* *				tty_task				     * *===========================================================================*/PUBLIC void main(void){/* Main routine of the terminal task. */  message tty_mess;		/* buffer for all incoming messages */  unsigned line;  int r, s;  register struct proc *rp;  register tty_t *tp;  /* Initialize the TTY driver. */  tty_init();  /* Get kernel environment (protected_mode, pc_at and ega are needed). */   if (OK != (s=sys_getmachine(&machine))) {    panic("TTY","Couldn't obtain kernel environment.", s);  }  /* Final one-time keyboard initialization. */  kb_init_once();  printf("\n");  while (TRUE) {	/* Check for and handle any events on any of the ttys. */	for (tp = FIRST_TTY; tp < END_TTY; tp++) {		if (tp->tty_events) handle_events(tp);	}	/* Get a request message. */	r= receive(ANY, &tty_mess);	if (r != 0)		panic("TTY", "receive failed with %d", r);	/* First handle all kernel notification types that the TTY supports. 	 *  - An alarm went off, expire all timers and handle the events. 	 *  - A hardware interrupt also is an invitation to check for events. 	 *  - A new kernel message is available for printing.	 *  - Reset the console on system shutdown. 	 * Then see if this message is different from a normal device driver	 * request and should be handled separately. These extra functions	 * do not operate on a device, in constrast to the driver requests. 	 */	switch (tty_mess.m_type) { 	case SYN_ALARM: 		/* fall through */		expire_timers();	/* run watchdogs of expired timers */		continue;		/* contine to check for events */	case DEV_PING:		notify(tty_mess.m_source);		continue;	case HARD_INT: {		/* hardware interrupt notification */		if (tty_mess.NOTIFY_ARG & kbd_irq_set)			kbd_interrupt(&tty_mess);/* fetch chars from keyboard */#if NR_RS_LINES > 0		if (tty_mess.NOTIFY_ARG & rs_irq_set)			rs_interrupt(&tty_mess);/* serial I/O */#endif		expire_timers();	/* run watchdogs of expired timers */		continue;		/* contine to check for events */	}	case SYS_SIG: {			/* system signal */		sigset_t sigset = (sigset_t) tty_mess.NOTIFY_ARG;		if (sigismember(&sigset, SIGKSTOP)) {			cons_stop();		/* switch to primary console */			if (irq_hook_id != -1) {				sys_irqdisable(&irq_hook_id);				sys_irqrmpolicy(KEYBOARD_IRQ, &irq_hook_id);			}		} 		if (sigismember(&sigset, SIGTERM)) cons_stop();			if (sigismember(&sigset, SIGKMESS)) do_new_kmess(&tty_mess);		continue;	}	case PANIC_DUMPS:		/* allow panic dumps */		cons_stop();		/* switch to primary console */		do_panic_dumps(&tty_mess);			continue;	case DIAGNOSTICS: 		/* a server wants to print some */		do_diagnostics(&tty_mess);		continue;	case GET_KMESS:		do_get_kmess(&tty_mess);		continue;	case FKEY_CONTROL:		/* (un)register a fkey observer */		do_fkey_ctl(&tty_mess);		continue;	default:			/* should be a driver request */		;			/* do nothing; end switch */	}	/* Only device requests should get to this point. All requests, 	 * except DEV_STATUS, have a minor device number. Check this	 * exception and get the minor device number otherwise.	 */	if (tty_mess.m_type == DEV_STATUS) {		do_status(&tty_mess);		continue;	}	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);		if (tty_mess.m_type != DEV_IOCTL) {			do_pty(tp, &tty_mess);			continue;		}	} else {		tp = NULL;	}	/* If the device doesn't exist or is not configured return ENXIO. */	if (tp == NULL || ! tty_active(tp)) {		printf("Warning, TTY got illegal request %d from %d\n",			tty_mess.m_type, tty_mess.m_source);		if (tty_mess.m_source != LOG_PROC_NR)		{			tty_reply(TASK_REPLY, tty_mess.m_source,						tty_mess.PROC_NR, ENXIO);		}		continue;	}	/* Execute the requested device driver 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 DEV_SELECT:	 do_select(tp, &tty_mess);	  break;	    case CANCEL:	 do_cancel(tp, &tty_mess);	  break;	    default:				printf("Warning, TTY got unexpected request %d from %d\n",			tty_mess.m_type, tty_mess.m_source);	    tty_reply(TASK_REPLY, tty_mess.m_source,						tty_mess.PROC_NR, EINVAL);	}  }}/*===========================================================================* *				do_status				     * *===========================================================================*/PRIVATE void do_status(m_ptr)message *m_ptr;{  register struct tty *tp;  int event_found;  int status;  int ops;    /* Check for select or revive events on any of the ttys. If we found an,    * event return a single status message for it. The FS will make another    * call to see if there is more.   */  event_found = 0;  for (tp = FIRST_TTY; tp < END_TTY; tp++) {	if ((ops = select_try(tp, tp->tty_select_ops)) && 			tp->tty_select_proc == m_ptr->m_source) {		/* I/O for a selected minor device is ready. */		m_ptr->m_type = DEV_IO_READY;		m_ptr->DEV_MINOR = tp->tty_minor;		m_ptr->DEV_SEL_OPS = ops;		tp->tty_select_ops &= ~ops;	/* unmark select event */  		event_found = 1;		break;	}	else if (tp->tty_inrevived && tp->tty_incaller == m_ptr->m_source) {				/* Suspended request finished. Send a REVIVE. */		m_ptr->m_type = DEV_REVIVE;  		m_ptr->REP_PROC_NR = tp->tty_inproc;  		m_ptr->REP_STATUS = tp->tty_incum;		tp->tty_inleft = tp->tty_incum = 0;		tp->tty_inrevived = 0;		/* unmark revive event */  		event_found = 1;  		break;	}	else if (tp->tty_outrevived && tp->tty_outcaller == m_ptr->m_source) {				/* Suspended request finished. Send a REVIVE. */		m_ptr->m_type = DEV_REVIVE;  		m_ptr->REP_PROC_NR = tp->tty_outproc;  		m_ptr->REP_STATUS = tp->tty_outcum;		tp->tty_outcum = 0;		tp->tty_outrevived = 0;		/* unmark revive event */  		event_found = 1;  		break;	}  }#if NR_PTYS > 0  if (!event_found)  	event_found = pty_status(m_ptr);#endif  if (! event_found) {	/* No events of interest were found. Return an empty message. */  	m_ptr->m_type = DEV_NO_STATUS;  }  /* Almost done. Send back the reply message to the caller. */  if ((status = send(m_ptr->m_source, m_ptr)) != OK) {	panic("TTY","send in do_status failed, status\n", status);  }}/*===========================================================================* *				do_read					     * *===========================================================================*/PRIVATE void do_read(tp, m_ptr)register tty_t *tp;		/* pointer to tty struct */register message *m_ptr;	/* pointer to message sent to the task */{/* A process wants to read from a terminal. */  int r, status;  phys_bytes phys_addr;  /* 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 (sys_umap(m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS, m_ptr->COUNT,		&phys_addr) != OK) {	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.			 */			settimer(tp, TRUE);			tp->tty_min = 1;		} 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) {				settimer(tp, FALSE);				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)  {  		if (tp->tty_select_ops)  			select_retry(tp);		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);  if (tp->tty_select_ops)  	select_retry(tp);}/*===========================================================================* *				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;  phys_bytes phys_addr;  /* 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 (sys_umap(m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS, m_ptr->COUNT,		&phys_addr) != OK) {	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 */

⌨️ 快捷键说明

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