Example #1
0
static int read_chan(struct tty_struct *tty, struct file *file,
		     unsigned char *buf, unsigned int nr)
{
	struct wait_queue wait = { current, NULL };
	int c;
	unsigned char *b = buf;
	int minimum, time;
	int retval = 0;
	int size;

do_it_again:

	if (!tty->read_buf) {
		printk("n_tty_read_chan: called with read_buf == NULL?!?\n");
		return -EIO;
	}

	/* Job control check -- must be done at start and after
	   every sleep (POSIX.1 7.1.1.4). */
	/* NOTE: not yet done after every sleep pending a thorough
	   check of the logic of this change. -- jlc */
	/* don't stop on /dev/console */
	if (file->f_inode->i_rdev != CONSOLE_DEV &&
	    current->tty == tty) {
		if (tty->pgrp <= 0)
			printk("read_chan: tty->pgrp <= 0!\n");
		else if (current->pgrp != tty->pgrp) {
			if (is_ignored(SIGTTIN) ||
			    is_orphaned_pgrp(current->pgrp))
				return -EIO;
			kill_pg(current->pgrp, SIGTTIN, 1);
			return -ERESTARTSYS;
		}
	}

	if (L_ICANON(tty)) {
		minimum = time = 0;
		current->timeout = (unsigned long) -1;
	} else {
		time = (HZ / 10) * TIME_CHAR(tty);
		minimum = MIN_CHAR(tty);
		if (minimum) {
		  	current->timeout = (unsigned long) -1;
			if (time)
				tty->minimum_to_wake = 1;
			else if (!waitqueue_active(&tty->read_wait) ||
				 (tty->minimum_to_wake > minimum))
				tty->minimum_to_wake = minimum;
		} else {
			if (time) {
				current->timeout = time + jiffies;
				time = 0;
			} else
				current->timeout = 0;
			tty->minimum_to_wake = minimum = 1;
		}
	}

	add_wait_queue(&tty->read_wait, &wait);
	while (1) {
		/* First test for status change. */
		if (tty->packet && tty->link->ctrl_status) {
			if (b != buf)
				break;
			put_user(tty->link->ctrl_status, b++);
			tty->link->ctrl_status = 0;
			break;
		}
		/* This statement must be first before checking for input
		   so that any interrupt will set the state back to
		   TASK_RUNNING. */
		current->state = TASK_INTERRUPTIBLE;
		
		if (((minimum - (b - buf)) < tty->minimum_to_wake) &&
		    ((minimum - (b - buf)) >= 1))
			tty->minimum_to_wake = (minimum - (b - buf));
		
		if (!input_available_p(tty, 0)) {
			if (tty->flags & (1 << TTY_OTHER_CLOSED)) {
				retval = -EIO;
				break;
			}
			if (tty_hung_up_p(file))
				break;
			if (!current->timeout)
				break;
			if (file->f_flags & O_NONBLOCK) {
				retval = -EAGAIN;
				break;
			}
			if (current->signal & ~current->blocked) {
				retval = -ERESTARTSYS;
				break;
			}
			schedule();
			continue;
		}
		current->state = TASK_RUNNING;

		/* Deal with packet mode. */
		if (tty->packet && b == buf) {
			put_user(TIOCPKT_DATA, b++);
			nr--;
		}

		if (L_ICANON(tty)) {
			while (1) {
				int eol;

				disable_bh(TQUEUE_BH);
				if (!tty->read_cnt) {
					enable_bh(TQUEUE_BH);
					break;
				}
				eol = clear_bit(tty->read_tail,
						&tty->read_flags);
				c = tty->read_buf[tty->read_tail];
				tty->read_tail = ((tty->read_tail+1) &
						  (N_TTY_BUF_SIZE-1));
				tty->read_cnt--;
				enable_bh(TQUEUE_BH);
				if (!eol) {
					put_user(c, b++);
					if (--nr)
						continue;
					break;
				}
				if (--tty->canon_data < 0) {
					tty->canon_data = 0;
				}
				if (c != __DISABLED_CHAR) {
					put_user(c, b++);
					nr--;
				}
				break;
			}
		} else {
			disable_bh(TQUEUE_BH);
			copy_from_read_buf(tty, &b, &nr);
			copy_from_read_buf(tty, &b, &nr);
			enable_bh(TQUEUE_BH);
		}

		/* If there is enough space in the read buffer now, let the
		   low-level driver know. */
		if (tty->driver.unthrottle &&
		    (tty->read_cnt <= TTY_THRESHOLD_UNTHROTTLE)
		    && clear_bit(TTY_THROTTLED, &tty->flags))
			tty->driver.unthrottle(tty);

		if (b - buf >= minimum || !nr)
			break;
		if (time)
			current->timeout = time + jiffies;
	}
	remove_wait_queue(&tty->read_wait, &wait);

	if (!waitqueue_active(&tty->read_wait))
		tty->minimum_to_wake = minimum;

	current->state = TASK_RUNNING;
	current->timeout = 0;
	size = b - buf;
	if (size && nr)
	        clear_bit(TTY_PUSH, &tty->flags);
        if (!size && clear_bit(TTY_PUSH, &tty->flags))
                goto do_it_again;
	if (!size && !retval)
	        clear_bit(TTY_PUSH, &tty->flags);
        return (size ? size : retval);
}
Example #2
0
void __tinit time_init(void)
{
	i8253_init();
	enable_bh(PIT_BH);
	bh_base[PIT_BH].routine = PIT_bh;
}