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); }
/* * 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); }
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); }
/* 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; }
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); }
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; }
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); }
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); }
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); }
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; }
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; } }
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); } }