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); }
void __tinit time_init(void) { i8253_init(); enable_bh(PIT_BH); bh_base[PIT_BH].routine = PIT_bh; }