Ejemplo n.º 1
0
static void speakup_stop_ttys(void)
{
	int i;

	for (i = 0; i < MAX_NR_CONSOLES; i++)
		if ((vc_cons[i].d && (vc_cons[i].d->port.tty)))
			stop_tty(vc_cons[i].d->port.tty);
}
Ejemplo n.º 2
0
/*
 * Send a high priority character to the tty.
 */
void send_prio_char(struct tty_struct *tty, char ch)
{
	int	was_stopped = tty->stopped;

	if (tty->driver->send_xchar) {
		tty->driver->send_xchar(tty, ch);
		return;
	}
	if (was_stopped)
		start_tty(tty);
	tty->driver->write(tty, 0, &ch, 1);
	if (was_stopped)
		stop_tty(tty);
}
Ejemplo n.º 3
0
static void hold(void)
{
	if (rep || !tty)
		return;

	/*
	 * Note: SCROLLOCK will be set (cleared) by stop_tty (start_tty);
	 * these routines are also activated by ^S/^Q.
	 * (And SCROLLOCK can also be set by the ioctl KDSKBLED.)
	 */
	if (tty->stopped)
		start_tty(tty);
	else
		stop_tty(tty);
}
Ejemplo n.º 4
0
/* to unregister a protocol -
 * to be called from protocol stack driver
 */
long st_unregister(struct st_proto_s *proto)
{
	long err = 0;
	unsigned long flags = 0;
	struct st_data_s	*st_gdata;

	pr_debug("%s: %d \n", __func__, proto->chnl_id);

	st_kim_ref(&st_gdata, 0);
	if (proto->chnl_id >= ST_MAX_CHANNELS) {
		pr_err(" chnl_id %d not supported\n", proto->chnl_id);
		return -EPROTONOSUPPORT;
	}

	spin_lock_irqsave(&st_gdata->lock, flags);

    if (st_gdata->is_registered[proto->chnl_id] == false) {
		pr_err(" chnl_id %d not registered\n", proto->chnl_id);
		spin_unlock_irqrestore(&st_gdata->lock, flags);
		return -EPROTONOSUPPORT;
	}

	st_gdata->protos_registered--;
	remove_channel_from_table(st_gdata, proto);
	spin_unlock_irqrestore(&st_gdata->lock, flags);

    /* paranoid check */
    if (st_gdata->protos_registered < ST_EMPTY)
        st_gdata->protos_registered = ST_EMPTY;

	if ((st_gdata->protos_registered == ST_EMPTY) &&
	    (!test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
		pr_info(" all chnl_ids unregistered \n");

		/* stop traffic on tty */
		if (st_gdata->tty) {
			tty_ldisc_flush(st_gdata->tty);
			stop_tty(st_gdata->tty);
		}

		/* all chnl_ids now unregistered */
		st_kim_stop(st_gdata->kim_data);

		/* disable ST LL */
		st_ll_disable(st_gdata);
	}
	return err;
}
Ejemplo n.º 5
0
static void tty_receive_char(struct tty_struct *tty, char ch)
{
	if(tty == NULL) return;

	if(I_IXON(tty) && !I_IXOFF(tty) && !tty->raw) {
		if(ch == STOP_CHAR(tty)){
			stop_tty(tty);
			return;
		}
		else if(ch == START_CHAR(tty)){
			start_tty(tty);
			return;
		}
	}

	tty_insert_flip_char(tty, ch, TTY_NORMAL);
}
Ejemplo n.º 6
0
static void speakup_stop_ttys(void)
{
	int i;

	if (!in_atomic())
		lock_kernel();
	else if (!kernel_locked()) {
		/* BKL is not held and we are in a critical section, too bad,
		 * let the buffer continue to fill up.
		 *
		 * This only happens with kernel messages and keyboard echo, so
		 * that shouldn't be so much a concern.
		 */
		return;
	}
	for (i = 0; i < MAX_NR_CONSOLES; i++)
		if ((vc_cons[i].d != NULL) && (vc_cons[i].d->vc_tty != NULL))
			stop_tty(vc_cons[i].d->vc_tty);
	if (!in_atomic())
		unlock_kernel();
	return;
}
Ejemplo n.º 7
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.º 8
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.º 9
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.º 10
0
int tty_ioctl(struct inode * inode, struct file * file,
	unsigned int cmd, unsigned long arg)
{
	struct tty_struct * tty;
	struct tty_struct * other_tty;
	struct tty_struct * termios_tty;
	pid_t pgrp;
	int dev;
	int termios_dev;
	int retval;

	if (MAJOR(file->f_rdev) != TTY_MAJOR) {
		printk("tty_ioctl: tty pseudo-major != TTY_MAJOR\n");
		return -EINVAL;
	}
	dev = MINOR(file->f_rdev);
	tty = TTY_TABLE(dev);
	if (!tty)
		return -EINVAL;
	if (IS_A_PTY(dev))
		other_tty = tty_table[PTY_OTHER(dev)];
	else
		other_tty = NULL;
	if (IS_A_PTY_MASTER(dev)) {
		termios_tty = other_tty;
		termios_dev = PTY_OTHER(dev);
	} else {
		termios_tty = tty;
		termios_dev = dev;
	}
	switch (cmd) {
		case TCGETS:
			retval = verify_area(VERIFY_WRITE, (void *) arg,
					     sizeof (struct termios));
			if (retval)
				return retval;
			memcpy_tofs((struct termios *) arg,
				    termios_tty->termios,
				    sizeof (struct termios));
			return 0;
		case TCSETSF:
		case TCSETSW:
		case TCSETS:
			retval = check_change(termios_tty, termios_dev);
			if (retval)
				return retval;
			if (cmd == TCSETSF || cmd == TCSETSW) {
				if (cmd == TCSETSF)
					flush_input(termios_tty);
				wait_until_sent(termios_tty, 0);
			}
			return set_termios(termios_tty, (struct termios *) arg,
					   termios_dev);
		case TCGETA:
			return get_termio(termios_tty,(struct termio *) arg);
		case TCSETAF:
		case TCSETAW:
		case TCSETA:
			retval = check_change(termios_tty, termios_dev);
			if (retval)
				return retval;
			if (cmd == TCSETAF || cmd == TCSETAW) {
				if (cmd == TCSETAF)
					flush_input(termios_tty);
				wait_until_sent(termios_tty, 0);
			}
			return set_termio(termios_tty, (struct termio *) arg,
					  termios_dev);
		case TCXONC:
			retval = check_change(tty, dev);
			if (retval)
				return retval;
			switch (arg) {
			case TCOOFF:
				stop_tty(tty);
				break;
			case TCOON:
				start_tty(tty);
				break;
			case TCIOFF:
				if (STOP_CHAR(tty) != __DISABLED_CHAR)
					put_tty_queue(STOP_CHAR(tty),
						      &tty->write_q);
				break;
			case TCION:
				if (START_CHAR(tty) != __DISABLED_CHAR)
					put_tty_queue(START_CHAR(tty),
						      &tty->write_q);
				break;
			default:
				return -EINVAL;
			}
			return 0;
		case TCFLSH:
			retval = check_change(tty, dev);
			if (retval)
				return retval;
			switch (arg) {
			case TCIFLUSH:
				flush_input(tty);
				break;
			case TCIOFLUSH:
				flush_input(tty);
				/* fall through */
			case TCOFLUSH:
				flush_output(tty);
				break;
			default:
				return -EINVAL;
			}
			return 0;
		case TIOCEXCL:
			set_bit(TTY_EXCLUSIVE, &tty->flags);
			return 0;
		case TIOCNXCL:
			clear_bit(TTY_EXCLUSIVE, &tty->flags);
			return 0;
		case TIOCSCTTY:
			if (current->leader &&
			    (current->session == tty->session))
				return 0;
			/*
			 * The process must be a session leader and
			 * not have a controlling tty already.
			 */
			if (!current->leader || (current->tty >= 0))
				return -EPERM;
			if (tty->session > 0) {
				/*
				 * This tty is already the controlling
				 * tty for another session group!
				 */
				if ((arg == 1) && suser()) {
					/*
					 * Steal it away
					 */
					struct task_struct *p;

					for_each_task(p)
						if (p->tty == dev)
							p->tty = -1;
				} else
					return -EPERM;
			}
			current->tty = dev;
			tty->session = current->session;
			tty->pgrp = current->pgrp;
			return 0;
		case TIOCGPGRP:
			retval = verify_area(VERIFY_WRITE, (void *) arg,
					     sizeof (pid_t));
			if (retval)
				return retval;
			if (current->tty != termios_dev)
				return -ENOTTY;
			put_fs_long(termios_tty->pgrp, (pid_t *) arg);
			return 0;
		case TIOCSPGRP:
			retval = check_change(termios_tty, termios_dev);
			if (retval)
				return retval;
			if ((current->tty < 0) ||
			    (current->tty != termios_dev) ||
			    (termios_tty->session != current->session))
				return -ENOTTY;
			pgrp = get_fs_long((pid_t *) arg);
			if (pgrp < 0)
				return -EINVAL;
			if (session_of_pgrp(pgrp) != current->session)
				return -EPERM;
			termios_tty->pgrp = pgrp;
			return 0;
		case TIOCOUTQ:
			retval = verify_area(VERIFY_WRITE, (void *) arg,
					     sizeof (unsigned long));
			if (retval)
				return retval;
			put_fs_long(CHARS(&tty->write_q),
				    (unsigned long *) arg);
			return 0;
		case TIOCINQ:
			retval = verify_area(VERIFY_WRITE, (void *) arg,
					     sizeof (unsigned long));
			if (retval)
				return retval;
			if (L_ICANON(tty))
				put_fs_long(inq_canon(tty),
					(unsigned long *) arg);
			else
				put_fs_long(CHARS(&tty->secondary),
					(unsigned long *) arg);
			return 0;
		case TIOCSTI:
			if ((current->tty != dev) && !suser())
				return -EPERM;
			retval = verify_area(VERIFY_READ, (void *) arg, 1);
			if (retval)
				return retval;
			put_tty_queue(get_fs_byte((char *) arg), &tty->read_q);
			TTY_READ_FLUSH(tty);
			return 0;
		case TIOCGWINSZ:
			retval = verify_area(VERIFY_WRITE, (void *) arg,
					     sizeof (struct winsize));
			if (retval)
				return retval;
			memcpy_tofs((struct winsize *) arg, &tty->winsize,
				    sizeof (struct winsize));
			return 0;
		case TIOCSWINSZ:
			if (IS_A_PTY_MASTER(dev))
				set_window_size(other_tty,(struct winsize *) arg);
			return set_window_size(tty,(struct winsize *) arg);
		case TIOCLINUX:
			switch (get_fs_byte((char *)arg))
			{
				case 0: 
					return do_screendump(arg);
				case 1: 
					return do_get_ps_info(arg);
#ifdef CONFIG_SELECTION
				case 2:
					return set_selection(arg);
				case 3:
					return paste_selection(tty);
				case 4:
					unblank_screen();
					return 0;
#endif /* CONFIG_SELECTION */
				default: 
					return -EINVAL;
			}
		case TIOCCONS:
			if (IS_A_CONSOLE(dev)) {
				if (!suser())
					return -EPERM;
				redirect = NULL;
				return 0;
			}
			if (redirect)
				return -EBUSY;
			if (!suser())
				return -EPERM;
			if (IS_A_PTY_MASTER(dev))
				redirect = other_tty;
			else if (IS_A_PTY_SLAVE(dev))
				redirect = tty;
			else
				return -ENOTTY;
			return 0;
		case FIONBIO:
			arg = get_fs_long((unsigned long *) arg);
			if (arg)
				file->f_flags |= O_NONBLOCK;
			else
				file->f_flags &= ~O_NONBLOCK;
			return 0;
		case TIOCNOTTY:
			if (current->tty != dev)
				return -ENOTTY;
			if (current->leader)
				disassociate_ctty(0);
			current->tty = -1;
			return 0;
		case TIOCGETD:
			retval = verify_area(VERIFY_WRITE, (void *) arg,
					     sizeof (unsigned long));
			if (retval)
				return retval;
			put_fs_long(tty->disc, (unsigned long *) arg);
			return 0;
		case TIOCSETD:
			retval = check_change(tty, dev);
			if (retval)
				return retval;
			arg = get_fs_long((unsigned long *) arg);
			return tty_set_ldisc(tty, arg);
		case TIOCGLCKTRMIOS:
			arg = get_fs_long((unsigned long *) arg);
			retval = verify_area(VERIFY_WRITE, (void *) arg,
					     sizeof (struct termios));
			if (retval)
				return retval;
			memcpy_tofs((struct termios *) arg,
				    &termios_locked[termios_dev],
				    sizeof (struct termios));
			return 0;
		case TIOCSLCKTRMIOS:
			if (!suser())
				return -EPERM;
			arg = get_fs_long((unsigned long *) arg);
			memcpy_fromfs(&termios_locked[termios_dev],
				      (struct termios *) arg,
				      sizeof (struct termios));
			return 0;
		case TIOCPKT:
			if (!IS_A_PTY_MASTER(dev))
				return -ENOTTY;
			retval = verify_area(VERIFY_READ, (void *) arg,
					     sizeof (unsigned long));
			if (retval)
				return retval;
			if (get_fs_long(arg)) {
				if (!tty->packet) {
					tty->packet = 1;
					tty->link->ctrl_status = 0;
				}
			} else
				tty->packet = 0;
			return 0;
		case TCSBRK: case TCSBRKP:
			retval = check_change(tty, dev);
			if (retval)
				return retval;
			wait_until_sent(tty, 0);
			if (!tty->ioctl)
				return 0;
			tty->ioctl(tty, file, cmd, arg);
			return 0;
		default:
			if (tty->ioctl) {
				retval = (tty->ioctl)(tty, file, cmd, arg);
				if (retval != -EINVAL)
					return retval;
			}
			if (ldiscs[tty->disc].ioctl) {
				retval = (ldiscs[tty->disc].ioctl)
					(tty, file, cmd, arg);
				return retval;
			}
			return -EINVAL;
	}
Ejemplo n.º 11
0
int n_tty_ioctl(struct tty_struct * tty, struct file * file,
		       unsigned int cmd, unsigned long arg)
{
	struct tty_struct * real_tty;
	int retval;

	if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
	    tty->driver->subtype == PTY_TYPE_MASTER)
		real_tty = tty->link;
	else
		real_tty = tty;

	switch (cmd) {
#ifdef TIOCGETP
		case TIOCGETP:
			return get_sgttyb(real_tty, (struct sgttyb *) arg);
		case TIOCSETP:
		case TIOCSETN:
			return set_sgttyb(real_tty, (struct sgttyb *) arg);
#endif
#ifdef TIOCGETC
		case TIOCGETC:
			return get_tchars(real_tty, (struct tchars *) arg);
		case TIOCSETC:
			return set_tchars(real_tty, (struct tchars *) arg);
#endif
#ifdef TIOCGLTC
		case TIOCGLTC:
			return get_ltchars(real_tty, (struct ltchars *) arg);
		case TIOCSLTC:
			return set_ltchars(real_tty, (struct ltchars *) arg);
#endif
		case TCGETS:
			if (kernel_termios_to_user_termios((struct termios *)arg, real_tty->termios))
				return -EFAULT;
			return 0;
		case TCSETSF:
			return set_termios(real_tty, arg,  TERMIOS_FLUSH | TERMIOS_WAIT);
		case TCSETSW:
			return set_termios(real_tty, arg, TERMIOS_WAIT);
		case TCSETS:
			return set_termios(real_tty, arg, 0);
		case TCGETA:
			return get_termio(real_tty,(struct termio *) arg);
		case TCSETAF:
			return set_termios(real_tty, arg, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
		case TCSETAW:
			return set_termios(real_tty, arg, TERMIOS_WAIT | TERMIOS_TERMIO);
		case TCSETA:
			return set_termios(real_tty, arg, TERMIOS_TERMIO);
		case TCXONC:
			retval = tty_check_change(tty);
			if (retval)
				return retval;
			switch (arg) {
			case TCOOFF:
				if (!tty->flow_stopped) {
					tty->flow_stopped = 1;
					stop_tty(tty);
				}
				break;
			case TCOON:
				if (tty->flow_stopped) {
					tty->flow_stopped = 0;
					start_tty(tty);
				}
				break;
			case TCIOFF:
				if (STOP_CHAR(tty) != __DISABLED_CHAR)
					send_prio_char(tty, STOP_CHAR(tty));
				break;
			case TCION:
				if (START_CHAR(tty) != __DISABLED_CHAR)
					send_prio_char(tty, START_CHAR(tty));
				break;
			default:
				return -EINVAL;
			}
			return 0;
		case TCFLSH:
			retval = tty_check_change(tty);
			if (retval)
				return retval;
			switch (arg) {
			case TCIFLUSH:
				if (tty->ldisc.flush_buffer)
					tty->ldisc.flush_buffer(tty);
				break;
			case TCIOFLUSH:
				if (tty->ldisc.flush_buffer)
					tty->ldisc.flush_buffer(tty);
				/* fall through */
			case TCOFLUSH:
				if (tty->driver->flush_buffer)
					tty->driver->flush_buffer(tty);
				break;
			default:
				return -EINVAL;
			}
			return 0;
		case TIOCOUTQ:
			return put_user(tty->driver->chars_in_buffer ?
					tty->driver->chars_in_buffer(tty) : 0,
					(int *) arg);
		case TIOCINQ:
			retval = tty->read_cnt;
			if (L_ICANON(tty))
				retval = inq_canon(tty);
			return put_user(retval, (unsigned int *) arg);
		case TIOCGLCKTRMIOS:
			if (kernel_termios_to_user_termios((struct termios *)arg, real_tty->termios_locked))
				return -EFAULT;
			return 0;

		case TIOCSLCKTRMIOS:
			if (!capable(CAP_SYS_ADMIN))
				return -EPERM;
			if (user_termios_to_kernel_termios(real_tty->termios_locked, (struct termios *) arg))
				return -EFAULT;
			return 0;

		case TIOCPKT:
		{
			int pktmode;

			if (tty->driver->type != TTY_DRIVER_TYPE_PTY ||
			    tty->driver->subtype != PTY_TYPE_MASTER)
				return -ENOTTY;
			if (get_user(pktmode, (int *) arg))
				return -EFAULT;
			if (pktmode) {
				if (!tty->packet) {
					tty->packet = 1;
					tty->link->ctrl_status = 0;
				}
			} else
				tty->packet = 0;
			return 0;
		}
		case TIOCGSOFTCAR:
			return put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg);
		case TIOCSSOFTCAR:
			if (get_user(arg, (unsigned int *) arg))
				return -EFAULT;
			tty->termios->c_cflag =
				((tty->termios->c_cflag & ~CLOCAL) |
				 (arg ? CLOCAL : 0));
			return 0;
		default:
			return -ENOIOCTLCMD;
		}
}
Ejemplo n.º 12
0
static int send_prio_char(struct tty_struct *tty, char ch)
{
	int	was_stopped = tty->stopped;

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26))
	if (tty->ops->send_xchar) {
		tty->ops->send_xchar(tty, ch);
#else
	if (tty->driver->send_xchar) {
		tty->driver->send_xchar(tty, ch);
#endif
		return 0;
	}

	if (tty_write_lock(tty, 0) < 0)
		return -ERESTARTSYS;

	if (was_stopped)
		start_tty(tty);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26))
	tty->ops->write(tty, &ch, 1);
#else
	tty->driver->write(tty, &ch, 1);
#endif
	if (was_stopped)
		stop_tty(tty);
	tty_write_unlock(tty);
	return 0;
}

int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file,
		       unsigned int cmd, unsigned long arg)
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26))
	unsigned long flags;
#endif
	int retval;

	switch (cmd) {
	case TCXONC:
		retval = tty_check_change(tty);
		if (retval)
			return retval;
		switch (arg) {
		case TCOOFF:
			if (!tty->flow_stopped) {
				tty->flow_stopped = 1;
				stop_tty(tty);
			}
			break;
		case TCOON:
			if (tty->flow_stopped) {
				tty->flow_stopped = 0;
				start_tty(tty);
			}
			break;
		case TCIOFF:
			if (STOP_CHAR(tty) != __DISABLED_CHAR)
				return send_prio_char(tty, STOP_CHAR(tty));
			break;
		case TCION:
			if (START_CHAR(tty) != __DISABLED_CHAR)
				return send_prio_char(tty, START_CHAR(tty));
			break;
		default:
			return -EINVAL;
		}
		return 0;
	case TCFLSH:
		return tty_perform_flush(tty, arg);
	case TIOCPKT:
	{
		int pktmode;

		if (tty->driver->type != TTY_DRIVER_TYPE_PTY ||
		    tty->driver->subtype != PTY_TYPE_MASTER)
			return -ENOTTY;
		if (get_user(pktmode, (int __user *) arg))
			return -EFAULT;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26))
		spin_lock_irqsave(&tty->ctrl_lock, flags);
#endif
		if (pktmode) {
			if (!tty->packet) {
				tty->packet = 1;
				tty->link->ctrl_status = 0;
			}
		} else
			tty->packet = 0;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26))
		spin_unlock_irqrestore(&tty->ctrl_lock, flags);
#endif
		return 0;
	}
	default:
		/* Try the mode commands */
		return tty_mode_ioctl(tty, file, cmd, arg);
	}
}