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