Ejemplo n.º 1
0
static void n_tty_set_termios(struct tty_struct *tty, struct termios * old)
{
	if (!tty)
		return;
	
	tty->icanon = (L_ICANON(tty) != 0);
	if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) ||
	    I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) ||
	    I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) ||
	    I_PARMRK(tty)) {
		cli();
		memset(tty->process_char_map, 0, 256/8);

		if (I_IGNCR(tty) || I_ICRNL(tty))
			set_bit('\r', &tty->process_char_map);
		if (I_INLCR(tty))
			set_bit('\n', &tty->process_char_map);

		if (L_ICANON(tty)) {
			set_bit(ERASE_CHAR(tty), &tty->process_char_map);
			set_bit(KILL_CHAR(tty), &tty->process_char_map);
			set_bit(EOF_CHAR(tty), &tty->process_char_map);
			set_bit('\n', &tty->process_char_map);
			set_bit(EOL_CHAR(tty), &tty->process_char_map);
			if (L_IEXTEN(tty)) {
				set_bit(WERASE_CHAR(tty),
					&tty->process_char_map);
				set_bit(LNEXT_CHAR(tty),
					&tty->process_char_map);
				set_bit(EOL2_CHAR(tty),
					&tty->process_char_map);
				if (L_ECHO(tty))
					set_bit(REPRINT_CHAR(tty),
						&tty->process_char_map);
			}
		}
		if (I_IXON(tty)) {
			set_bit(START_CHAR(tty), &tty->process_char_map);
			set_bit(STOP_CHAR(tty), &tty->process_char_map);
		}
		if (L_ISIG(tty)) {
			set_bit(INTR_CHAR(tty), &tty->process_char_map);
			set_bit(QUIT_CHAR(tty), &tty->process_char_map);
			set_bit(SUSP_CHAR(tty), &tty->process_char_map);
		}
		clear_bit(__DISABLED_CHAR, &tty->process_char_map);
		sti();
		tty->raw = 0;
		tty->real_raw = 0;
	} else {
		tty->raw = 1;
		if ((I_IGNBRK(tty) || (!I_BRKINT(tty) && !I_PARMRK(tty))) &&
		    (I_IGNPAR(tty) || !I_INPCK(tty)) &&
		    (tty->driver.flags & TTY_DRIVER_REAL_RAW))
			tty->real_raw = 1;
		else
			tty->real_raw = 0;
	}
}
Ejemplo n.º 2
0
static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
{
	unsigned long flags;
	int parmrk;

	if (tty->raw) {
		put_tty_queue(c, tty);
		return;
	}

	if (I_ISTRIP(tty))
		c &= 0x7f;
	if (I_IUCLC(tty) && L_IEXTEN(tty))
		c = tolower(c);

	if (L_EXTPROC(tty)) {
		put_tty_queue(c, tty);
		return;
	}

	if (tty->stopped && !tty->flow_stopped && I_IXON(tty) &&
	    I_IXANY(tty) && c != START_CHAR(tty) && c != STOP_CHAR(tty) &&
	    c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) && c != SUSP_CHAR(tty)) {
		start_tty(tty);
		process_echoes(tty);
	}

	if (tty->closing) {
		if (I_IXON(tty)) {
			if (c == START_CHAR(tty)) {
				start_tty(tty);
				process_echoes(tty);
			} else if (c == STOP_CHAR(tty))
				stop_tty(tty);
		}
		return;
	}

	if (!test_bit(c, tty->process_char_map) || tty->lnext) {
		tty->lnext = 0;
		parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
		if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
			
			if (L_ECHO(tty))
				process_output('\a', tty);
			return;
		}
		if (L_ECHO(tty)) {
			finish_erasing(tty);
			
			if (tty->canon_head == tty->read_head)
				echo_set_canon_col(tty);
			echo_char(c, tty);
			process_echoes(tty);
		}
		if (parmrk)
			put_tty_queue(c, tty);
		put_tty_queue(c, tty);
		return;
	}

	if (I_IXON(tty)) {
		if (c == START_CHAR(tty)) {
			start_tty(tty);
			process_echoes(tty);
			return;
		}
		if (c == STOP_CHAR(tty)) {
			stop_tty(tty);
			return;
		}
	}

	if (L_ISIG(tty)) {
		int signal;
		signal = SIGINT;
		if (c == INTR_CHAR(tty))
			goto send_signal;
		signal = SIGQUIT;
		if (c == QUIT_CHAR(tty))
			goto send_signal;
		signal = SIGTSTP;
		if (c == SUSP_CHAR(tty)) {
send_signal:
			if (!L_NOFLSH(tty)) {
				n_tty_flush_buffer(tty);
				tty_driver_flush_buffer(tty);
			}
			if (I_IXON(tty))
				start_tty(tty);
			if (L_ECHO(tty)) {
				echo_char(c, tty);
				process_echoes(tty);
			}
			if (tty->pgrp)
				kill_pgrp(tty->pgrp, signal, 1);
			return;
		}
	}

	if (c == '\r') {
		if (I_IGNCR(tty))
			return;
		if (I_ICRNL(tty))
			c = '\n';
	} else if (c == '\n' && I_INLCR(tty))
		c = '\r';

	if (tty->icanon) {
		if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
		    (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
			eraser(c, tty);
			process_echoes(tty);
			return;
		}
		if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {
			tty->lnext = 1;
			if (L_ECHO(tty)) {
				finish_erasing(tty);
				if (L_ECHOCTL(tty)) {
					echo_char_raw('^', tty);
					echo_char_raw('\b', tty);
					process_echoes(tty);
				}
			}
			return;
		}
		if (c == REPRINT_CHAR(tty) && L_ECHO(tty) &&
		    L_IEXTEN(tty)) {
			unsigned long tail = tty->canon_head;

			finish_erasing(tty);
			echo_char(c, tty);
			echo_char_raw('\n', tty);
			while (tail != tty->read_head) {
				echo_char(tty->read_buf[tail], tty);
				tail = (tail+1) & (N_TTY_BUF_SIZE-1);
			}
			process_echoes(tty);
			return;
		}
		if (c == '\n') {
			if (tty->read_cnt >= N_TTY_BUF_SIZE) {
				if (L_ECHO(tty))
					process_output('\a', tty);
				return;
			}
			if (L_ECHO(tty) || L_ECHONL(tty)) {
				echo_char_raw('\n', tty);
				process_echoes(tty);
			}
			goto handle_newline;
		}
		if (c == EOF_CHAR(tty)) {
			if (tty->read_cnt >= N_TTY_BUF_SIZE)
				return;
			if (tty->canon_head != tty->read_head)
				set_bit(TTY_PUSH, &tty->flags);
			c = __DISABLED_CHAR;
			goto handle_newline;
		}
		if ((c == EOL_CHAR(tty)) ||
		    (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) {
			parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty))
				 ? 1 : 0;
			if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk)) {
				if (L_ECHO(tty))
					process_output('\a', tty);
				return;
			}
			if (L_ECHO(tty)) {
				
				if (tty->canon_head == tty->read_head)
					echo_set_canon_col(tty);
				echo_char(c, tty);
				process_echoes(tty);
			}
			if (parmrk)
				put_tty_queue(c, tty);

handle_newline:
			spin_lock_irqsave(&tty->read_lock, flags);
			set_bit(tty->read_head, tty->read_flags);
			put_tty_queue_nolock(c, tty);
			tty->canon_head = tty->read_head;
			tty->canon_data++;
			spin_unlock_irqrestore(&tty->read_lock, flags);
			kill_fasync(&tty->fasync, SIGIO, POLL_IN);
			if (waitqueue_active(&tty->read_wait))
				wake_up_interruptible(&tty->read_wait);
			return;
		}
	}

	parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0;
	if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {
		
		if (L_ECHO(tty))
			process_output('\a', tty);
		return;
	}
	if (L_ECHO(tty)) {
		finish_erasing(tty);
		if (c == '\n')
			echo_char_raw('\n', tty);
		else {
			
			if (tty->canon_head == tty->read_head)
				echo_set_canon_col(tty);
			echo_char(c, tty);
		}
		process_echoes(tty);
	}

	if (parmrk)
		put_tty_queue(c, tty);

	put_tty_queue(c, tty);
}
Ejemplo n.º 3
0
static void eraser(unsigned char c, struct tty_struct *tty)
{
	enum { ERASE, WERASE, KILL } kill_type;
	int head, seen_alnums, cnt;
	unsigned long flags;

	
	if (tty->read_head == tty->canon_head) {
		 
		return;
	}
	if (c == ERASE_CHAR(tty))
		kill_type = ERASE;
	else if (c == WERASE_CHAR(tty))
		kill_type = WERASE;
	else {
		if (!L_ECHO(tty)) {
			spin_lock_irqsave(&tty->read_lock, flags);
			tty->read_cnt -= ((tty->read_head - tty->canon_head) &
					  (N_TTY_BUF_SIZE - 1));
			tty->read_head = tty->canon_head;
			spin_unlock_irqrestore(&tty->read_lock, flags);
			return;
		}
		if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) {
			spin_lock_irqsave(&tty->read_lock, flags);
			tty->read_cnt -= ((tty->read_head - tty->canon_head) &
					  (N_TTY_BUF_SIZE - 1));
			tty->read_head = tty->canon_head;
			spin_unlock_irqrestore(&tty->read_lock, flags);
			finish_erasing(tty);
			echo_char(KILL_CHAR(tty), tty);
			
			if (L_ECHOK(tty))
				echo_char_raw('\n', tty);
			return;
		}
		kill_type = KILL;
	}

	seen_alnums = 0;
	
	while (tty->read_head != tty->canon_head) {
		head = tty->read_head;

		
		do {
			head = (head - 1) & (N_TTY_BUF_SIZE-1);
			c = tty->read_buf[head];
		} while (is_continuation(c, tty) && head != tty->canon_head);

		
		if (is_continuation(c, tty))
			break;

		if (kill_type == WERASE) {
			
			if (isalnum(c) || c == '_')
				seen_alnums++;
			else if (seen_alnums)
				break;
		}
		cnt = (tty->read_head - head) & (N_TTY_BUF_SIZE-1);
		spin_lock_irqsave(&tty->read_lock, flags);
		tty->read_head = head;
		tty->read_cnt -= cnt;
		spin_unlock_irqrestore(&tty->read_lock, flags);
		if (L_ECHO(tty)) {
			if (L_ECHOPRT(tty)) {
				if (!tty->erasing) {
					echo_char_raw('\\', tty);
					tty->erasing = 1;
				}
				
				echo_char(c, tty);
				while (--cnt > 0) {
					head = (head+1) & (N_TTY_BUF_SIZE-1);
					echo_char_raw(tty->read_buf[head], tty);
					echo_move_back_col(tty);
				}
			} else if (kill_type == ERASE && !L_ECHOE(tty)) {
				echo_char(ERASE_CHAR(tty), tty);
			} else if (c == '\t') {
				unsigned int num_chars = 0;
				int after_tab = 0;
				unsigned long tail = tty->read_head;

				while (tail != tty->canon_head) {
					tail = (tail-1) & (N_TTY_BUF_SIZE-1);
					c = tty->read_buf[tail];
					if (c == '\t') {
						after_tab = 1;
						break;
					} else if (iscntrl(c)) {
						if (L_ECHOCTL(tty))
							num_chars += 2;
					} else if (!is_continuation(c, tty)) {
						num_chars++;
					}
				}
				echo_erase_tab(num_chars, after_tab, tty);
			} else {
				if (iscntrl(c) && L_ECHOCTL(tty)) {
					echo_char_raw('\b', tty);
					echo_char_raw(' ', tty);
					echo_char_raw('\b', tty);
				}
				if (!iscntrl(c) || L_ECHOCTL(tty)) {
					echo_char_raw('\b', tty);
					echo_char_raw(' ', tty);
					echo_char_raw('\b', tty);
				}
			}
		}
		if (kill_type == ERASE)
			break;
	}
	if (tty->read_head == tty->canon_head && L_ECHO(tty))
		finish_erasing(tty);
}
Ejemplo n.º 4
0
static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
{
	int canon_change = 1;
	BUG_ON(!tty);

	if (old)
		canon_change = (old->c_lflag ^ tty->termios->c_lflag) & ICANON;
	if (canon_change) {
		memset(&tty->read_flags, 0, sizeof tty->read_flags);
		tty->canon_head = tty->read_tail;
		tty->canon_data = 0;
		tty->erasing = 0;
	}

	if (canon_change && !L_ICANON(tty) && tty->read_cnt)
		wake_up_interruptible(&tty->read_wait);

	tty->icanon = (L_ICANON(tty) != 0);
	if (test_bit(TTY_HW_COOK_IN, &tty->flags)) {
		tty->raw = 1;
		tty->real_raw = 1;
		n_tty_set_room(tty);
		return;
	}
	if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) ||
	    I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) ||
	    I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) ||
	    I_PARMRK(tty)) {
		memset(tty->process_char_map, 0, 256/8);

		if (I_IGNCR(tty) || I_ICRNL(tty))
			set_bit('\r', tty->process_char_map);
		if (I_INLCR(tty))
			set_bit('\n', tty->process_char_map);

		if (L_ICANON(tty)) {
			set_bit(ERASE_CHAR(tty), tty->process_char_map);
			set_bit(KILL_CHAR(tty), tty->process_char_map);
			set_bit(EOF_CHAR(tty), tty->process_char_map);
			set_bit('\n', tty->process_char_map);
			set_bit(EOL_CHAR(tty), tty->process_char_map);
			if (L_IEXTEN(tty)) {
				set_bit(WERASE_CHAR(tty),
					tty->process_char_map);
				set_bit(LNEXT_CHAR(tty),
					tty->process_char_map);
				set_bit(EOL2_CHAR(tty),
					tty->process_char_map);
				if (L_ECHO(tty))
					set_bit(REPRINT_CHAR(tty),
						tty->process_char_map);
			}
		}
		if (I_IXON(tty)) {
			set_bit(START_CHAR(tty), tty->process_char_map);
			set_bit(STOP_CHAR(tty), tty->process_char_map);
		}
		if (L_ISIG(tty)) {
			set_bit(INTR_CHAR(tty), tty->process_char_map);
			set_bit(QUIT_CHAR(tty), tty->process_char_map);
			set_bit(SUSP_CHAR(tty), tty->process_char_map);
		}
		clear_bit(__DISABLED_CHAR, tty->process_char_map);
		tty->raw = 0;
		tty->real_raw = 0;
	} else {
		tty->raw = 1;
		if ((I_IGNBRK(tty) || (!I_BRKINT(tty) && !I_PARMRK(tty))) &&
		    (I_IGNPAR(tty) || !I_INPCK(tty)) &&
		    (tty->driver->flags & TTY_DRIVER_REAL_RAW))
			tty->real_raw = 1;
		else
			tty->real_raw = 0;
	}
	n_tty_set_room(tty);
	
	wake_up_interruptible(&tty->write_wait);
	wake_up_interruptible(&tty->read_wait);
}
Ejemplo n.º 5
0
static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)
{
	if (tty->raw) {
		put_tty_queue(c, tty);
		return;
	}
	
	if (tty->stopped && I_IXON(tty) && I_IXANY(tty)) {
		start_tty(tty);
		return;
	}
	
	if (I_ISTRIP(tty))
		c &= 0x7f;
	if (I_IUCLC(tty) && L_IEXTEN(tty))
		c=tolower(c);

	if (tty->closing) {
		if (I_IXON(tty)) {
			if (c == START_CHAR(tty))
				start_tty(tty);
			else if (c == STOP_CHAR(tty))
				stop_tty(tty);
		}
		return;
	}

	/*
	 * If the previous character was LNEXT, or we know that this
	 * character is not one of the characters that we'll have to
	 * handle specially, do shortcut processing to speed things
	 * up.
	 */
	if (!test_bit(c, &tty->process_char_map) || tty->lnext) {
		finish_erasing(tty);
		tty->lnext = 0;
		if (L_ECHO(tty)) {
			if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
				put_char('\a', tty); /* beep if no space */
				return;
			}
			/* Record the column of first canon char. */
			if (tty->canon_head == tty->read_head)
				tty->canon_column = tty->column;
			echo_char(c, tty);
		}
		if (I_PARMRK(tty) && c == (unsigned char) '\377')
			put_tty_queue(c, tty);
		put_tty_queue(c, tty);
		return;
	}
		
	if (c == '\r') {
		if (I_IGNCR(tty))
			return;
		if (I_ICRNL(tty))
			c = '\n';
	} else if (c == '\n' && I_INLCR(tty))
		c = '\r';
	if (I_IXON(tty)) {
		if (c == START_CHAR(tty)) {
			start_tty(tty);
			return;
		}
		if (c == STOP_CHAR(tty)) {
			stop_tty(tty);
			return;
		}
	}
	if (L_ISIG(tty)) {
		int signal;
		signal = SIGINT;
		if (c == INTR_CHAR(tty))
			goto send_signal;
		signal = SIGQUIT;
		if (c == QUIT_CHAR(tty))
			goto send_signal;
		signal = SIGTSTP;
		if (c == SUSP_CHAR(tty)) {
send_signal:
			isig(signal, tty, 0);
			return;
		}
	}
	if (L_ICANON(tty)) {
		if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
		    (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
			eraser(c, tty);
			return;
		}
		if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {
			tty->lnext = 1;
			if (L_ECHO(tty)) {
				finish_erasing(tty);
				if (L_ECHOCTL(tty)) {
					put_char('^', tty);
					put_char('\b', tty);
				}
			}
			return;
		}
		if (c == REPRINT_CHAR(tty) && L_ECHO(tty) &&
		    L_IEXTEN(tty)) {
			unsigned long tail = tty->canon_head;

			finish_erasing(tty);
			echo_char(c, tty);
			opost('\n', tty);
			while (tail != tty->read_head) {
				echo_char(tty->read_buf[tail], tty);
				tail = (tail+1) & (N_TTY_BUF_SIZE-1);
			}
			return;
		}
		if (c == '\n') {
			if (L_ECHO(tty) || L_ECHONL(tty)) {
				if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
					put_char('\a', tty);
					return;
				}
				opost('\n', tty);
			}
			goto handle_newline;
		}
		if (c == EOF_CHAR(tty)) {
		        if (tty->canon_head != tty->read_head)
			        set_bit(TTY_PUSH, &tty->flags);
			c = __DISABLED_CHAR;
			goto handle_newline;
		}
		if ((c == EOL_CHAR(tty)) ||
		    (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) {
			/*
			 * XXX are EOL_CHAR and EOL2_CHAR echoed?!?
			 */
			if (L_ECHO(tty)) {
				if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
					put_char('\a', tty);
					return;
				}
				/* Record the column of first canon char. */
				if (tty->canon_head == tty->read_head)
					tty->canon_column = tty->column;
				echo_char(c, tty);
			}
			/*
			 * XXX does PARMRK doubling happen for
			 * EOL_CHAR and EOL2_CHAR?
			 */
			if (I_PARMRK(tty) && c == (unsigned char) '\377')
				put_tty_queue(c, tty);

		handle_newline:
			set_bit(tty->read_head, &tty->read_flags);
			put_tty_queue(c, tty);
			tty->canon_head = tty->read_head;
			tty->canon_data++;
			if (tty->fasync)
				kill_fasync(tty->fasync, SIGIO);
			if (tty->read_wait)
				wake_up_interruptible(&tty->read_wait);
			return;
		}
	}
	
	finish_erasing(tty);
	if (L_ECHO(tty)) {
		if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
			put_char('\a', tty); /* beep if no space */
			return;
		}
		if (c == '\n')
			opost('\n', tty);
		else {
			/* Record the column of first canon char. */
			if (tty->canon_head == tty->read_head)
				tty->canon_column = tty->column;
			echo_char(c, tty);
		}
	}

	if (I_PARMRK(tty) && c == (unsigned char) '\377')
		put_tty_queue(c, tty);

	put_tty_queue(c, tty);
}	
Ejemplo n.º 6
0
static void eraser(unsigned char c, struct tty_struct *tty)
{
	enum { ERASE, WERASE, KILL } kill_type;
	int head, seen_alnums, cnt;
	unsigned long flags;

	if (tty->read_head == tty->canon_head) {
		/* opost('\a', tty); */		/* what do you think? */
		return;
	}
	if (c == ERASE_CHAR(tty))
		kill_type = ERASE;
	else if (c == WERASE_CHAR(tty))
		kill_type = WERASE;
	else {
		if (!L_ECHO(tty)) {
			spin_lock_irqsave(&tty->read_lock, flags);
			tty->read_cnt -= ((tty->read_head - tty->canon_head) &
					  (N_TTY_BUF_SIZE - 1));
			tty->read_head = tty->canon_head;
			spin_unlock_irqrestore(&tty->read_lock, flags);
			return;
		}
		if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) {
			spin_lock_irqsave(&tty->read_lock, flags);
			tty->read_cnt -= ((tty->read_head - tty->canon_head) &
					  (N_TTY_BUF_SIZE - 1));
			tty->read_head = tty->canon_head;
			spin_unlock_irqrestore(&tty->read_lock, flags);
			finish_erasing(tty);
			echo_char(KILL_CHAR(tty), tty);
			/* Add a newline if ECHOK is on and ECHOKE is off. */
			if (L_ECHOK(tty))
				opost('\n', tty);
			return;
		}
		kill_type = KILL;
	}

	seen_alnums = 0;
	while (tty->read_head != tty->canon_head) {
		head = tty->read_head;

		/* erase a single possibly multibyte character */
		do {
			head = (head - 1) & (N_TTY_BUF_SIZE-1);
			c = tty->read_buf[head];
		} while (is_continuation(c, tty) && head != tty->canon_head);

		/* do not partially erase */
		if (is_continuation(c, tty))
			break;

		if (kill_type == WERASE) {
			/* Equivalent to BSD's ALTWERASE. */
			if (isalnum(c) || c == '_')
				seen_alnums++;
			else if (seen_alnums)
				break;
		}
		cnt = (tty->read_head - head) & (N_TTY_BUF_SIZE-1);
		spin_lock_irqsave(&tty->read_lock, flags);
		tty->read_head = head;
		tty->read_cnt -= cnt;
		spin_unlock_irqrestore(&tty->read_lock, flags);
		if (L_ECHO(tty)) {
			if (L_ECHOPRT(tty)) {
				if (!tty->erasing) {
					put_char('\\', tty);
					tty->column++;
					tty->erasing = 1;
				}
				/* if cnt > 1, output a multi-byte character */
				echo_char(c, tty);
				while (--cnt > 0) {
					head = (head+1) & (N_TTY_BUF_SIZE-1);
					put_char(tty->read_buf[head], tty);
				}
			} else if (kill_type == ERASE && !L_ECHOE(tty)) {
				echo_char(ERASE_CHAR(tty), tty);
			} else if (c == '\t') {
				unsigned int col = tty->canon_column;
				unsigned long tail = tty->canon_head;

				/* Find the column of the last char. */
				while (tail != tty->read_head) {
					c = tty->read_buf[tail];
					if (c == '\t')
						col = (col | 7) + 1;
					else if (iscntrl(c)) {
						if (L_ECHOCTL(tty))
							col += 2;
					} else if (!is_continuation(c, tty))
						col++;
					tail = (tail+1) & (N_TTY_BUF_SIZE-1);
				}

				/* should never happen */
				if (tty->column > 0x80000000)
					tty->column = 0; 

				/* Now backup to that column. */
				while (tty->column > col) {
					/* Can't use opost here. */
					put_char('\b', tty);
					if (tty->column > 0)
						tty->column--;
				}
			} else {
				if (iscntrl(c) && L_ECHOCTL(tty)) {
					put_char('\b', tty);
					put_char(' ', tty);
					put_char('\b', tty);
					if (tty->column > 0)
						tty->column--;
				}
				if (!iscntrl(c) || L_ECHOCTL(tty)) {
					put_char('\b', tty);
					put_char(' ', tty);
					put_char('\b', tty);
					if (tty->column > 0)
						tty->column--;
				}
			}
		}
		if (kill_type == ERASE)
			break;
	}
	if (tty->read_head == tty->canon_head)
		finish_erasing(tty);
}
Ejemplo n.º 7
0
static void eraser(unsigned char c, struct tty_struct *tty)
{
	enum { ERASE, WERASE, KILL } kill_type;
	int head, seen_alnums;

	if (tty->read_head == tty->canon_head) {
		/* opost('\a', tty); */		/* what do you think? */
		return;
	}
	if (c == ERASE_CHAR(tty))
		kill_type = ERASE;
	else if (c == WERASE_CHAR(tty))
		kill_type = WERASE;
	else {
		if (!L_ECHO(tty)) {
			tty->read_cnt -= ((tty->read_head - tty->canon_head) &
					  (N_TTY_BUF_SIZE - 1));
			tty->read_head = tty->canon_head;
			return;
		}
		if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) {
			tty->read_cnt -= ((tty->read_head - tty->canon_head) &
					  (N_TTY_BUF_SIZE - 1));
			tty->read_head = tty->canon_head;
			finish_erasing(tty);
			echo_char(KILL_CHAR(tty), tty);
			/* Add a newline if ECHOK is on and ECHOKE is off. */
			if (L_ECHOK(tty))
				opost('\n', tty);
			return;
		}
		kill_type = KILL;
	}

	seen_alnums = 0;
	while (tty->read_head != tty->canon_head) {
		head = (tty->read_head - 1) & (N_TTY_BUF_SIZE-1);
		c = tty->read_buf[head];
		if (kill_type == WERASE) {
			/* Equivalent to BSD's ALTWERASE. */
			if (isalnum(c) || c == '_')
				seen_alnums++;
			else if (seen_alnums)
				break;
		}
		tty->read_head = head;
		tty->read_cnt--;
		if (L_ECHO(tty)) {
			if (L_ECHOPRT(tty)) {
				if (!tty->erasing) {
					put_char('\\', tty);
					tty->column++;
					tty->erasing = 1;
				}
				echo_char(c, tty);
			} else if (kill_type == ERASE && !L_ECHOE(tty)) {
				echo_char(ERASE_CHAR(tty), tty);
			} else if (c == '\t') {
				unsigned int col = tty->canon_column;
				unsigned long tail = tty->canon_head;

				/* Find the column of the last char. */
				while (tail != tty->read_head) {
					c = tty->read_buf[tail];
					if (c == '\t')
						col = (col | 7) + 1;
					else if (iscntrl(c)) {
						if (L_ECHOCTL(tty))
							col += 2;
					} else
						col++;
					tail = (tail+1) & (N_TTY_BUF_SIZE-1);
				}

				/* should never happen */
				if (tty->column > 0x80000000)
					tty->column = 0; 

				/* Now backup to that column. */
				while (tty->column > col) {
					/* Can't use opost here. */
					put_char('\b', tty);
					if (tty->column > 0)
						tty->column--;
				}
			} else {
				if (iscntrl(c) && L_ECHOCTL(tty)) {
					put_char('\b', tty);
					put_char(' ', tty);
					put_char('\b', tty);
					if (tty->column > 0)
						tty->column--;
				}
				if (!iscntrl(c) || L_ECHOCTL(tty)) {
					put_char('\b', tty);
					put_char(' ', tty);
					put_char('\b', tty);
					if (tty->column > 0)
						tty->column--;
				}
			}
		}
		if (kill_type == ERASE)
			break;
	}
	if (tty->read_head == tty->canon_head)
		finish_erasing(tty);
}
Ejemplo n.º 8
0
static void copy_to_cooked(struct tty_struct * tty)
{
	int c, special_flag;
	unsigned long flags;

	if (!tty) {
		printk("copy_to_cooked: called with NULL tty\n");
		return;
	}
	if (!tty->write) {
		printk("copy_to_cooked: tty %d has null write routine\n",
		       tty->line);
	}
	while (1) {
		/*
		 * Check to see how much room we have left in the
		 * secondary queue.  Send a throttle command or abort
		 * if necessary.
		 */
		c = LEFT(&tty->secondary);
		if (tty->throttle && (c < SQ_THRESHOLD_LW)
		    && !set_bit(TTY_SQ_THROTTLED, &tty->flags))
			tty->throttle(tty, TTY_THROTTLE_SQ_FULL);
		if (c == 0)
			break;
		save_flags(flags); cli();
		if (!EMPTY(&tty->read_q)) {
			c = tty->read_q.buf[tty->read_q.tail];
			special_flag = clear_bit(tty->read_q.tail,
						 &tty->readq_flags);
			INC(tty->read_q.tail);
			restore_flags(flags);
		} else {
			restore_flags(flags);
			break;
		}
		if (special_flag) {
			tty->char_error = c;
			continue;
		}
		if (tty->char_error) {
			if (tty->char_error == TTY_BREAK) {
				tty->char_error = 0;
				if (I_IGNBRK(tty))
					continue;
				/* A break is handled by the lower levels. */
				if (I_BRKINT(tty))
					continue;
				if (I_PARMRK(tty)) {
					put_tty_queue('\377', &tty->secondary);
					put_tty_queue('\0', &tty->secondary);
				}
				put_tty_queue('\0', &tty->secondary);
				continue;
			}
			if (tty->char_error == TTY_OVERRUN) {
				tty->char_error = 0;
				printk("tty%d: input overrun\n", tty->line);
				continue;
			}
			/* Must be a parity or frame error */
			tty->char_error = 0;
			if (I_IGNPAR(tty)) {
				continue;
			}
			if (I_PARMRK(tty)) {
				put_tty_queue('\377', &tty->secondary);
				put_tty_queue('\0', &tty->secondary);
				put_tty_queue(c, &tty->secondary);
			} else
				put_tty_queue('\0', &tty->secondary);
			continue;
		}
		if (I_ISTRIP(tty))
			c &= 0x7f;
		if (!tty->lnext) {
			if (c == '\r') {
				if (I_IGNCR(tty))
					continue;
				if (I_ICRNL(tty))
					c = '\n';
			} else if (c == '\n' && I_INLCR(tty))
				c = '\r';
		}
		if (I_IUCLC(tty) && L_IEXTEN(tty))
			c=tolower(c);
		if (c == __DISABLED_CHAR)
			tty->lnext = 1;
		if (L_ICANON(tty) && !tty->lnext) {
			if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) ||
			    (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) {
				eraser(c, tty);
				continue;
			}
			if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) {
				tty->lnext = 1;
				if (L_ECHO(tty)) {
					if (tty->erasing) {
						opost('/', tty);
						tty->erasing = 0;
					}
					if (L_ECHOCTL(tty)) {
						opost('^', tty);
						opost('\b', tty);
					}
				}
				continue;
			}
			if (c == REPRINT_CHAR(tty) && L_ECHO(tty) &&
			    L_IEXTEN(tty)) {
				unsigned long tail = tty->canon_head;

				if (tty->erasing) {
					opost('/', tty);
					tty->erasing = 0;
				}
				echo_char(c, tty);
				opost('\n', tty);
				while (tail != tty->secondary.head) {
					echo_char(tty->secondary.buf[tail],
						  tty);
					INC(tail);
				}
				continue;
			}
		}
		if (I_IXON(tty) && !tty->lnext) {
			if ((tty->stopped && I_IXANY(tty) && L_IEXTEN(tty)) ||
			    c == START_CHAR(tty)) {
				start_tty(tty);
				continue;
			}
			if (c == STOP_CHAR(tty)) {
				stop_tty(tty);
				continue;
			}
		}
		if (L_ISIG(tty) && !tty->lnext) {
			if (c == INTR_CHAR(tty)) {
				isig(SIGINT, tty);
				continue;
			}
			if (c == QUIT_CHAR(tty)) {
				isig(SIGQUIT, tty);
				continue;
			}
			if (c == SUSP_CHAR(tty)) {
				if (!is_orphaned_pgrp(tty->pgrp))
					isig(SIGTSTP, tty);
				continue;
			}
		}

		if (tty->erasing) {
			opost('/', tty);
			tty->erasing = 0;
		}
		if (c == '\n' && !tty->lnext) {
			if (L_ECHO(tty) || (L_ICANON(tty) && L_ECHONL(tty)))
				opost('\n', tty);
		} else if (L_ECHO(tty)) {
			/* Don't echo the EOF char in canonical mode.  Sun
			   handles this differently by echoing the char and
			   then backspacing, but that's a hack. */
			if (c != EOF_CHAR(tty) || !L_ICANON(tty) ||
			    tty->lnext) {
				/* Record the column of first canon char. */
				if (tty->canon_head == tty->secondary.head)
					tty->canon_column = tty->column;
				echo_char(c, tty);
			}
		}

		if (I_PARMRK(tty) && c == (unsigned char) '\377' &&
		    (c != EOF_CHAR(tty) || !L_ICANON(tty) || tty->lnext))
			put_tty_queue(c, &tty->secondary);

		if (L_ICANON(tty) && !tty->lnext &&
		    (c == '\n' || c == EOF_CHAR(tty) || c == EOL_CHAR(tty) ||
		     (c == EOL2_CHAR(tty) && L_IEXTEN(tty)))) {
			if (c == EOF_CHAR(tty))
				c = __DISABLED_CHAR;
			set_bit(tty->secondary.head, &tty->secondary_flags);
			put_tty_queue(c, &tty->secondary);
			tty->canon_head = tty->secondary.head;
			tty->canon_data++;
		} else
			put_tty_queue(c, &tty->secondary);
		tty->lnext = 0;
	}
	if (!EMPTY(&tty->write_q))
		TTY_WRITE_FLUSH(tty);
	if (L_ICANON(tty) ? tty->canon_data : !EMPTY(&tty->secondary))
		wake_up_interruptible(&tty->secondary.proc_list);

	if (tty->throttle && (LEFT(&tty->read_q) >= RQ_THRESHOLD_HW)
	    && clear_bit(TTY_RQ_THROTTLED, &tty->flags))
		tty->throttle(tty, TTY_THROTTLE_RQ_AVAIL);
}
Ejemplo n.º 9
0
static void eraser(unsigned char c, struct tty_struct *tty)
{
	enum { ERASE, WERASE, KILL } kill_type;
	int seen_alnums;

	if (tty->secondary.head == tty->canon_head) {
		/* opost('\a', tty); */		/* what do you think? */
		return;
	}
	if (c == ERASE_CHAR(tty))
		kill_type = ERASE;
	else if (c == WERASE_CHAR(tty))
		kill_type = WERASE;
	else {
		if (!L_ECHO(tty)) {
			tty->secondary.head = tty->canon_head;
			return;
		}
		if (!L_ECHOK(tty) || !L_ECHOKE(tty)) {
			tty->secondary.head = tty->canon_head;
			if (tty->erasing) {
				opost('/', tty);
				tty->erasing = 0;
			}
			echo_char(KILL_CHAR(tty), tty);
			/* Add a newline if ECHOK is on and ECHOKE is off. */
			if (L_ECHOK(tty))
				opost('\n', tty);
			return;
		}
		kill_type = KILL;
	}

	seen_alnums = 0;
	while (tty->secondary.head != tty->canon_head) {
		c = LAST(&tty->secondary);
		if (kill_type == WERASE) {
			/* Equivalent to BSD's ALTWERASE. */
			if (isalnum(c) || c == '_')
				seen_alnums++;
			else if (seen_alnums)
				break;
		}
		DEC(tty->secondary.head);
		if (L_ECHO(tty)) {
			if (L_ECHOPRT(tty)) {
				if (!tty->erasing) {
					opost('\\', tty);
					tty->erasing = 1;
				}
				echo_char(c, tty);
			} else if (!L_ECHOE(tty)) {
				echo_char(ERASE_CHAR(tty), tty);
			} else if (c == '\t') {
				unsigned int col = tty->canon_column;
				unsigned long tail = tty->canon_head;

				/* Find the column of the last char. */
				while (tail != tty->secondary.head) {
					c = tty->secondary.buf[tail];
					if (c == '\t')
						col = (col | 7) + 1;
					else if (iscntrl(c)) {
						if (L_ECHOCTL(tty))
							col += 2;
					} else
						col++;
					INC(tail);
				}

				/* Now backup to that column. */
				while (tty->column > col) {
					/* Can't use opost here. */
					put_tty_queue('\b', &tty->write_q);
					tty->column--;
				}
			} else {
				if (iscntrl(c) && L_ECHOCTL(tty)) {
					opost('\b', tty);
					opost(' ', tty);
					opost('\b', tty);
				}
				if (!iscntrl(c) || L_ECHOCTL(tty)) {
					opost('\b', tty);
					opost(' ', tty);
					opost('\b', tty);
				}
			}
		}
		if (kill_type == ERASE)
			break;
	}
	if (tty->erasing && tty->secondary.head == tty->canon_head) {
		opost('/', tty);
		tty->erasing = 0;
	}
}
Ejemplo n.º 10
0
void copy_to_cooked(struct tty_struct * tty)
{
	unsigned char c;

	while (!EMPTY(tty->read_q) && !FULL(tty->secondary)) {
		GETCH(tty->read_q,c);
		if (c==13)
			if (I_CRNL(tty))
				c=10;
			else if (I_NOCR(tty))
				continue;
			else ;
		else if (c==10 && I_NLCR(tty))
			c=13;
		if (I_UCLC(tty))
			c=tolower(c);
		if (L_CANON(tty)) {
			if (c==KILL_CHAR(tty)) {
				/* deal with killing the input line */
				while(!(EMPTY(tty->secondary) ||
				        (c=LAST(tty->secondary))==10 ||
				        c==EOF_CHAR(tty))) {
					if (L_ECHO(tty)) {
						if (c<32)
							PUTCH(127,tty->write_q);
						PUTCH(127,tty->write_q);
						tty->write(tty);
					}
					DEC(tty->secondary.head);
				}
				continue;
			}
			if (c==ERASE_CHAR(tty)) {
				if (EMPTY(tty->secondary) ||
				   (c=LAST(tty->secondary))==10 ||
				   c==EOF_CHAR(tty))
					continue;
				if (L_ECHO(tty)) {
					if (c<32)
						PUTCH(127,tty->write_q);
					PUTCH(127,tty->write_q);
					tty->write(tty);
				}
				DEC(tty->secondary.head);
				continue;
			}
			if (c==STOP_CHAR(tty)) {
				tty->stopped=1;
				continue;
			}
			if (c==START_CHAR(tty)) {
				tty->stopped=0;
				continue;
			}
		}
		if (L_ISIG(tty)) {
			if (c==INTR_CHAR(tty)) {
				tty_intr(tty,INTMASK);
				continue;
			}
			if (c==QUIT_CHAR(tty)) {
				tty_intr(tty,QUITMASK);
				continue;
			}
		}
		if (c==10 || c==EOF_CHAR(tty))
			tty->secondary.data++;
		if (L_ECHO(tty)) {
			if (c==10) {
				PUTCH(10,tty->write_q);
				PUTCH(13,tty->write_q);
			} else if (c<32) {
				if (L_ECHOCTL(tty)) {
					PUTCH('^',tty->write_q);
					PUTCH(c+64,tty->write_q);
				}
			} else
				PUTCH(c,tty->write_q);
			tty->write(tty);
		}
		PUTCH(c,tty->secondary);
	}
	wake_up(&tty->secondary.proc_list);
}
Ejemplo n.º 11
0
/**
 * @brief Handles a TTY interrupt.
 * 
 * @details Handles a TTY interrupt, putting the received character @p ch in the
 *          raw input buffer of the currently active TTY device. Addiitonally, 
 *          if echo is enable for such device, @p ch is output to the terminal.
 * 
 * @param ch Received character.
 */
PUBLIC void tty_int(unsigned char ch)
{
	/* Output echo character. */
	if (active->term.c_lflag & ECHO)
	{
		/* Canonical mode. */
		if (active->term.c_lflag & ICANON)
		{		
			/* 
			 * Let these characters be handled
			 * when the line is being parsed.
			 */
			if ((ch == ERASE_CHAR(*active)) ||
				(ch == KILL_CHAR(*active)) ||
				(ch == EOL_CHAR(*active)) ||
				(ch == EOF_CHAR(*active)))
				goto out1;
		}
		
		/* Non-printable characters. */
		if ((ch < 32) && (ch != '\n') && (ch != '\t'))
		{
			console_put('^', WHITE);
			console_put(ch + 64, WHITE);
			console_put('\n', WHITE);
		}
		
		/* Any character. */
		else
			console_put(ch, WHITE);
	}
	
	/*
	 * Handle signals. Note that if a signal is
	 * received, no character is put in the raw
	 * input buffer. Otherwise, we could mess it up.
	 */
	if (active->term.c_lflag & ISIG)
	{
		/*
		 * Interrupt. Send signal to all
		 * process in the same group.
		 */
		if (ch == INTR_CHAR(*active))
		{
			tty_signal(SIGINT);
			goto out0;
		}
		
		/* Stop. */
		else if (ch == STOP_CHAR(*active))
		{
			active->flags |= TTY_STOPPED;
			return;
		}
				
		/* Start. */
		else if (ch == START_CHAR(*active))
		{
			active->flags &= ~TTY_STOPPED;
			wakeup(&active->output.chain);
			return;
		}
		
		/* Suspend. */
		else if (ch == SUSP_CHAR(*active))
		{
			tty_signal(SIGTSTP);
			goto out0;
		}
		
		/* Quit. */
		else if (ch == QUIT_CHAR(*active))
		{
			tty_signal(SIGQUIT);
			goto out0;
		}
	}

out1:		
	KBUFFER_PUT(active->rinput, ch);
out0:
	wakeup(&active->rinput.chain);
}
Ejemplo n.º 12
0
/**
 * @brief Reads data from a TTY device.
 * 
 * @details Reads @p n bytes data from the TTY device, which minor device number
 *          is @p minor, to the buffer pointed to by @p buf.
 * 
 * @param minor Minor device number of target TTY device.
 * @param buf   Buffer where data shall be placed.
 * @param n     Number of bytes to be read.
 * 
 * @returns The number of bytes actually read to the TTY device.
 */
PRIVATE ssize_t tty_read(unsigned minor, char *buf, size_t n)
{
	size_t i;         /* # bytes read.      */
	unsigned char ch; /* Working character. */
	unsigned char *p; /* Write pointer.     */
	
	UNUSED(minor);
	
	i = n;
	p = (unsigned char *)buf;
	
	/* Read characters. */
	disable_interrupts();
	while (i > 0)
	{
		/* Canonical mode. */
		if (tty.term.c_lflag & ICANON)
		{
			/* Wait for data to become available. */
			if (tty_sleep_empty(&tty))
			{
				enable_interrupts();
				return (-EINTR);
			}
			
			KBUFFER_GET(tty.rinput, ch);
			
			/* Erase. */
			if (ch == ERASE_CHAR(tty))
			{
				if (!KBUFFER_EMPTY(tty.cinput))
				{
					KBUFFER_TAKEOUT(tty.cinput);
					console_put(ch, WHITE);
				}
			}
			
			/* Kill. */
			else if (ch == KILL_CHAR(tty))
			{
				while (!KBUFFER_EMPTY(tty.cinput))
				{
					i = n;
					p = (unsigned char *)buf;
					KBUFFER_TAKEOUT(tty.cinput);
					console_put('\b', WHITE);
				}
			}
			
			/* End of line. */
			else if (ch == EOL_CHAR(tty))
			{
				console_put('\n', WHITE);
				continue;
			}
			
			else
			{
				/* End of file. */
				if (ch == EOF_CHAR(tty))
					ch = '\0';
			
				KBUFFER_PUT(tty.cinput, ch);
			
				/* Copy data to input buffer. */
				if ((ch == '\n') || (KBUFFER_FULL(tty.cinput)) || (ch == '\0'))
				{		
					/* Copy data from input buffer. */
					while ((i > 0) && (!KBUFFER_EMPTY(tty.cinput)))
					{
						KBUFFER_GET(tty.cinput, ch);
						
						/* EOF. */
						if (ch == '\0')
							goto out;
						
						i--;
						*p++ = ch;
						
						/* Done reading. */
						if (ch == '\n')
							goto out;
					}
				}
			}
		}
		
		/* Non canonical mode. */
		else
		{
			if (MIN_CHAR(tty) > 0)
			{
				/* Case A: MIN>0, TIME>0 */
				if (TIME_CHAR(tty) > 0)
				{
					kprintf("tty: MIN>0, TIME>0");
					goto out;
				}
				
				/* Case B: MIN>0, TIME=0 */
				else
				{
					/* Wait for data to become available. */
					if (tty_sleep_empty(&tty))
					{
						enable_interrupts();
						return (-EINTR);
					}
					
					/* Copy data from input buffer. */
					while ((i > 0) && (!KBUFFER_EMPTY(tty.cinput)))
					{
						KBUFFER_GET(tty.rinput, ch);
						
						i--;
						*p++ = ch;
					}
				}
			}
			
			else
			{
				/* Case C: MIN=0, TIME>0 */
				if (TIME_CHAR(tty) > 0)
				{
					kprintf("tty: MIN=0, TIME>0");
					goto out;
				}
				
				/* Case D: MIN=0, TIME=0 */
				else
				{
					/* Done reading. */
					if (KBUFFER_EMPTY(tty.cinput))
						goto out;
					
					KBUFFER_GET(tty.rinput, ch);
						
					i--;
					*p++ = ch;
				}
			}			
		}
	}

out:

	enable_interrupts();
	
	return ((ssize_t)((char *)p - buf));
}