home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.0 / LINUX-1.0 / LINUX-1 / linux / drivers / char / tty_ioctl.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-01  |  16.7 KB  |  670 lines

  1. /*
  2.  *  linux/kernel/drivers/char/tty_ioctl.c
  3.  *
  4.  *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
  5.  *
  6.  * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
  7.  * which can be dynamically activated and de-activated by the line
  8.  * discipline handling modules (like SLIP).
  9.  */
  10.  
  11. #include <linux/types.h>
  12. #include <linux/termios.h>
  13. #include <linux/errno.h>
  14. #include <linux/sched.h>
  15. #include <linux/config.h>
  16. #include <linux/kernel.h>
  17. #include <linux/major.h>
  18. #include <linux/tty.h>
  19. #include <linux/fcntl.h>
  20. #include <linux/string.h>
  21.  
  22. #include <asm/io.h>
  23. #include <asm/bitops.h>
  24. #include <asm/segment.h>
  25. #include <asm/system.h>
  26.  
  27. #undef    DEBUG
  28. #ifdef DEBUG
  29. # define    PRINTK(x)    printk (x)
  30. #else
  31. # define    PRINTK(x)    /**/
  32. #endif
  33.  
  34. extern int session_of_pgrp(int pgrp);
  35. extern int do_screendump(int arg);
  36. extern int kill_pg(int pgrp, int sig, int priv);
  37.  
  38. #ifdef CONFIG_SELECTION
  39. extern int set_selection(const int arg);
  40. extern int paste_selection(struct tty_struct *tty);
  41. #endif /* CONFIG_SELECTION */
  42.  
  43. static int tty_set_ldisc(struct tty_struct *tty, int ldisc);
  44.  
  45. void flush_input(struct tty_struct * tty)
  46. {
  47.     cli();
  48.     tty->read_q.head = tty->read_q.tail = 0;
  49.     tty->secondary.head = tty->secondary.tail = 0;
  50.     tty->canon_head = tty->canon_data = tty->erasing = 0;
  51.     memset(&tty->readq_flags, 0, sizeof tty->readq_flags);
  52.     memset(&tty->secondary_flags, 0, sizeof tty->secondary_flags);
  53.     sti();
  54.     if (!tty->link)
  55.         return;
  56.     /* No cli() since ptys don't use interrupts. */
  57.     tty->link->write_q.head = tty->link->write_q.tail = 0;
  58.     wake_up_interruptible(&tty->link->write_q.proc_list);
  59.     if (tty->link->packet) {
  60.         tty->ctrl_status |= TIOCPKT_FLUSHREAD;
  61.         wake_up_interruptible(&tty->link->secondary.proc_list);
  62.     }
  63. }
  64.  
  65. void flush_output(struct tty_struct * tty)
  66. {
  67.     cli();
  68.     tty->write_q.head = tty->write_q.tail = 0;
  69.     sti();
  70.     wake_up_interruptible(&tty->write_q.proc_list);
  71.     if (!tty->link)
  72.         return;
  73.     /* No cli() since ptys don't use interrupts. */
  74.     tty->link->read_q.head = tty->link->read_q.tail = 0;
  75.     tty->link->secondary.head = tty->link->secondary.tail = 0;
  76.     tty->link->canon_head = tty->link->canon_data = tty->link->erasing = 0;
  77.     memset(&tty->link->readq_flags, 0, sizeof tty->readq_flags);
  78.     memset(&tty->link->secondary_flags, 0, sizeof tty->secondary_flags);
  79.     if (tty->link->packet) {
  80.         tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
  81.         wake_up_interruptible(&tty->link->secondary.proc_list);
  82.     }
  83. }
  84.  
  85. void wait_until_sent(struct tty_struct * tty, int timeout)
  86. {
  87.     struct wait_queue wait = { current, NULL };
  88.  
  89.     TTY_WRITE_FLUSH(tty);
  90.     if (EMPTY(&tty->write_q))
  91.         return;
  92.     add_wait_queue(&tty->write_q.proc_list, &wait);
  93.     current->counter = 0;    /* make us low-priority */
  94.     if (timeout)
  95.         current->timeout = timeout + jiffies;
  96.     else
  97.         current->timeout = (unsigned) -1;
  98.     do {
  99.         current->state = TASK_INTERRUPTIBLE;
  100.         if (current->signal & ~current->blocked)
  101.             break;
  102.         TTY_WRITE_FLUSH(tty);
  103.         if (EMPTY(&tty->write_q))
  104.             break;
  105.         schedule();
  106.     } while (current->timeout);
  107.     current->state = TASK_RUNNING;
  108.     remove_wait_queue(&tty->write_q.proc_list, &wait);
  109. }
  110.  
  111. static int do_get_ps_info(int arg)
  112. {
  113.     struct tstruct {
  114.         int flag;
  115.         int present[NR_TASKS];
  116.         struct task_struct tasks[NR_TASKS];
  117.     };
  118.     struct tstruct *ts = (struct tstruct *)arg;
  119.     struct task_struct **p;
  120.     char *c, *d;
  121.     int i, n = 0;
  122.     
  123.     i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct tstruct));
  124.     if (i)
  125.         return i;
  126.     for (p = &FIRST_TASK ; p <= &LAST_TASK ; p++, n++)
  127.         if (*p)
  128.         {
  129.             c = (char *)(*p);
  130.             d = (char *)(ts->tasks+n);
  131.             for (i=0 ; i<sizeof(struct task_struct) ; i++)
  132.                 put_fs_byte(*c++, d++);
  133.             put_fs_long(1, (unsigned long *)(ts->present+n));
  134.         }
  135.         else    
  136.             put_fs_long(0, (unsigned long *)(ts->present+n));
  137.     return(0);            
  138. }
  139.  
  140. static void unset_locked_termios(struct termios *termios,
  141.                  struct termios *old,
  142.                  struct termios *locked)
  143. {
  144.     int    i;
  145.     
  146. #define NOSET_MASK(x,y,z) (x = ((x) & ~(z)) | ((y) & (z)))
  147.  
  148.     if (!locked) {
  149.         printk("Warning?!? termios_locked is NULL.\n");
  150.         return;
  151.     }
  152.  
  153.     NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
  154.     NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
  155.     NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
  156.     NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
  157.     termios->c_line = locked->c_line ? old->c_line : termios->c_line;
  158.     for (i=0; i < NCCS; i++)
  159.         termios->c_cc[i] = locked->c_cc[i] ?
  160.             old->c_cc[i] : termios->c_cc[i];
  161. }
  162.  
  163. int check_change(struct tty_struct * tty, int channel)
  164. {
  165.     /* If we try to set the state of terminal and we're not in the
  166.        foreground, send a SIGTTOU.  If the signal is blocked or
  167.        ignored, go ahead and perform the operation.  POSIX 7.2) */
  168.     if (current->tty != channel)
  169.         return 0;
  170.     if (tty->pgrp <= 0) {
  171.         printk("check_change: tty->pgrp <= 0!\n");
  172.         return 0;
  173.     }
  174.     if (current->pgrp == tty->pgrp)
  175.         return 0;
  176.     if (is_ignored(SIGTTOU))
  177.         return 0;
  178.     if (is_orphaned_pgrp(current->pgrp))
  179.         return -EIO;
  180.     (void) kill_pg(current->pgrp,SIGTTOU,1);
  181.     return -ERESTARTSYS;
  182. }
  183.  
  184. static int set_termios_2(struct tty_struct * tty, struct termios * termios)
  185. {
  186.     struct termios old_termios = *tty->termios;
  187.     int canon_change;
  188.  
  189.     canon_change = (old_termios.c_lflag ^ termios->c_lflag) & ICANON;
  190.     cli();
  191.     *tty->termios = *termios;
  192.     if (canon_change) {
  193.         memset(&tty->secondary_flags, 0, sizeof tty->secondary_flags);
  194.         tty->canon_head = tty->secondary.tail;
  195.         tty->canon_data = 0;
  196.         tty->erasing = 0;
  197.     }
  198.     sti();
  199.     if (canon_change && !L_ICANON(tty) && !EMPTY(&tty->secondary))
  200.         /* Get characters left over from canonical mode. */
  201.         wake_up_interruptible(&tty->secondary.proc_list);
  202.  
  203.     /* see if packet mode change of state */
  204.  
  205.     if (tty->link && tty->link->packet) {
  206.         int old_flow = ((old_termios.c_iflag & IXON) &&
  207.                 (old_termios.c_cc[VSTOP] == '\023') &&
  208.                 (old_termios.c_cc[VSTART] == '\021'));
  209.         int new_flow = (I_IXON(tty) &&
  210.                 STOP_CHAR(tty) == '\023' &&
  211.                 START_CHAR(tty) == '\021');
  212.         if (old_flow != new_flow) {
  213.             tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
  214.             if (new_flow)
  215.                 tty->ctrl_status |= TIOCPKT_DOSTOP;
  216.             else
  217.                 tty->ctrl_status |= TIOCPKT_NOSTOP;
  218.             wake_up_interruptible(&tty->link->secondary.proc_list);
  219.         }
  220.     }
  221.  
  222.     unset_locked_termios(tty->termios, &old_termios,
  223.                  termios_locked[tty->line]);
  224.  
  225.     if (tty->set_termios)
  226.         (*tty->set_termios)(tty, &old_termios);
  227.  
  228.     return 0;
  229. }
  230.  
  231. static int set_termios(struct tty_struct * tty, struct termios * termios,
  232.                int channel)
  233. {
  234.     struct termios tmp_termios;
  235.  
  236.     memcpy_fromfs(&tmp_termios, termios, sizeof (struct termios));
  237.     return set_termios_2(tty, &tmp_termios);
  238. }
  239.  
  240. static int get_termio(struct tty_struct * tty, struct termio * termio)
  241. {
  242.     int i;
  243.     struct termio tmp_termio;
  244.  
  245.     i = verify_area(VERIFY_WRITE, termio, sizeof (struct termio));
  246.     if (i)
  247.         return i;
  248.     tmp_termio.c_iflag = tty->termios->c_iflag;
  249.     tmp_termio.c_oflag = tty->termios->c_oflag;
  250.     tmp_termio.c_cflag = tty->termios->c_cflag;
  251.     tmp_termio.c_lflag = tty->termios->c_lflag;
  252.     tmp_termio.c_line = tty->termios->c_line;
  253.     for(i=0 ; i < NCC ; i++)
  254.         tmp_termio.c_cc[i] = tty->termios->c_cc[i];
  255.     memcpy_tofs(termio, &tmp_termio, sizeof (struct termio));
  256.     return 0;
  257. }
  258.  
  259. static int set_termio(struct tty_struct * tty, struct termio * termio,
  260.               int channel)
  261. {
  262.     struct termio tmp_termio;
  263.     struct termios tmp_termios;
  264.  
  265.     tmp_termios = *tty->termios;
  266.     memcpy_fromfs(&tmp_termio, termio, sizeof (struct termio));
  267.  
  268. #define SET_LOW_BITS(x,y)    ((x) = (0xffff0000 & (x)) | (y))
  269.  
  270.     SET_LOW_BITS(tmp_termios.c_iflag, tmp_termio.c_iflag);
  271.     SET_LOW_BITS(tmp_termios.c_oflag, tmp_termio.c_oflag);
  272.     SET_LOW_BITS(tmp_termios.c_cflag, tmp_termio.c_cflag);
  273.     SET_LOW_BITS(tmp_termios.c_lflag, tmp_termio.c_lflag);
  274.     memcpy(&tmp_termios.c_cc, &tmp_termio.c_cc, NCC);
  275.  
  276. #undef SET_LOW_BITS
  277.  
  278.     return set_termios_2(tty, &tmp_termios);
  279. }
  280.  
  281. static int set_window_size(struct tty_struct * tty, struct winsize * ws)
  282. {
  283.     struct winsize tmp_ws;
  284.  
  285.     memcpy_fromfs(&tmp_ws, ws, sizeof (struct winsize));
  286.     if (memcmp(&tmp_ws, &tty->winsize, sizeof (struct winsize)) &&
  287.         tty->pgrp > 0)
  288.         kill_pg(tty->pgrp, SIGWINCH, 1);
  289.     tty->winsize = tmp_ws;
  290.     return 0;
  291. }
  292.  
  293. /* Set the discipline of a tty line. */
  294. static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
  295. {
  296.     if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS) ||
  297.         !(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED))
  298.         return -EINVAL;
  299.  
  300.     if (tty->disc == ldisc)
  301.         return 0;    /* We are already in the desired discipline */
  302.  
  303.     /* Shutdown the current discipline. */
  304.     wait_until_sent(tty, 0);
  305.     flush_input(tty);
  306.     if (ldiscs[tty->disc].close)
  307.         ldiscs[tty->disc].close(tty);
  308.  
  309.     /* Now set up the new line discipline. */
  310.     tty->disc = ldisc;
  311.     tty->termios->c_line = ldisc;
  312.     if (ldiscs[tty->disc].open)
  313.         return(ldiscs[tty->disc].open(tty));
  314.     else
  315.         return 0;
  316. }
  317.  
  318. static unsigned long inq_canon(struct tty_struct * tty)
  319. {
  320.     int nr, head, tail;
  321.  
  322.     if (!tty->canon_data)
  323.         return 0;
  324.     head = tty->canon_head;
  325.     tail = tty->secondary.tail;
  326.     nr = (head - tail) & (TTY_BUF_SIZE-1);
  327.     /* Skip EOF-chars.. */
  328.     while (head != tail) {
  329.         if (test_bit(tail, &tty->secondary_flags) &&
  330.             tty->secondary.buf[tail] == __DISABLED_CHAR)
  331.             nr--;
  332.         INC(tail);
  333.     }
  334.     return nr;
  335. }
  336.  
  337. int tty_ioctl(struct inode * inode, struct file * file,
  338.     unsigned int cmd, unsigned long arg)
  339. {
  340.     struct tty_struct * tty;
  341.     struct tty_struct * other_tty;
  342.     struct tty_struct * termios_tty;
  343.     pid_t pgrp;
  344.     int dev;
  345.     int termios_dev;
  346.     int retval;
  347.  
  348.     if (MAJOR(file->f_rdev) != TTY_MAJOR) {
  349.         printk("tty_ioctl: tty pseudo-major != TTY_MAJOR\n");
  350.         return -EINVAL;
  351.     }
  352.     dev = MINOR(file->f_rdev);
  353.     tty = TTY_TABLE(dev);
  354.     if (!tty)
  355.         return -EINVAL;
  356.     if (IS_A_PTY(dev))
  357.         other_tty = tty_table[PTY_OTHER(dev)];
  358.     else
  359.         other_tty = NULL;
  360.     if (IS_A_PTY_MASTER(dev)) {
  361.         termios_tty = other_tty;
  362.         termios_dev = PTY_OTHER(dev);
  363.     } else {
  364.         termios_tty = tty;
  365.         termios_dev = dev;
  366.     }
  367.     switch (cmd) {
  368.         case TCGETS:
  369.             retval = verify_area(VERIFY_WRITE, (void *) arg,
  370.                          sizeof (struct termios));
  371.             if (retval)
  372.                 return retval;
  373.             memcpy_tofs((struct termios *) arg,
  374.                     termios_tty->termios,
  375.                     sizeof (struct termios));
  376.             return 0;
  377.         case TCSETSF:
  378.         case TCSETSW:
  379.         case TCSETS:
  380.             retval = check_change(termios_tty, termios_dev);
  381.             if (retval)
  382.                 return retval;
  383.             if (cmd == TCSETSF || cmd == TCSETSW) {
  384.                 if (cmd == TCSETSF)
  385.                     flush_input(termios_tty);
  386.                 wait_until_sent(termios_tty, 0);
  387.             }
  388.             return set_termios(termios_tty, (struct termios *) arg,
  389.                        termios_dev);
  390.         case TCGETA:
  391.             return get_termio(termios_tty,(struct termio *) arg);
  392.         case TCSETAF:
  393.         case TCSETAW:
  394.         case TCSETA:
  395.             retval = check_change(termios_tty, termios_dev);
  396.             if (retval)
  397.                 return retval;
  398.             if (cmd == TCSETAF || cmd == TCSETAW) {
  399.                 if (cmd == TCSETAF)
  400.                     flush_input(termios_tty);
  401.                 wait_until_sent(termios_tty, 0);
  402.             }
  403.             return set_termio(termios_tty, (struct termio *) arg,
  404.                       termios_dev);
  405.         case TCXONC:
  406.             retval = check_change(tty, dev);
  407.             if (retval)
  408.                 return retval;
  409.             switch (arg) {
  410.             case TCOOFF:
  411.                 stop_tty(tty);
  412.                 break;
  413.             case TCOON:
  414.                 start_tty(tty);
  415.                 break;
  416.             case TCIOFF:
  417.                 if (STOP_CHAR(tty) != __DISABLED_CHAR)
  418.                     put_tty_queue(STOP_CHAR(tty),
  419.                               &tty->write_q);
  420.                 break;
  421.             case TCION:
  422.                 if (START_CHAR(tty) != __DISABLED_CHAR)
  423.                     put_tty_queue(START_CHAR(tty),
  424.                               &tty->write_q);
  425.                 break;
  426.             default:
  427.                 return -EINVAL;
  428.             }
  429.             return 0;
  430.         case TCFLSH:
  431.             retval = check_change(tty, dev);
  432.             if (retval)
  433.                 return retval;
  434.             switch (arg) {
  435.             case TCIFLUSH:
  436.                 flush_input(tty);
  437.                 break;
  438.             case TCIOFLUSH:
  439.                 flush_input(tty);
  440.                 /* fall through */
  441.             case TCOFLUSH:
  442.                 flush_output(tty);
  443.                 break;
  444.             default:
  445.                 return -EINVAL;
  446.             }
  447.             return 0;
  448.         case TIOCEXCL:
  449.             set_bit(TTY_EXCLUSIVE, &tty->flags);
  450.             return 0;
  451.         case TIOCNXCL:
  452.             clear_bit(TTY_EXCLUSIVE, &tty->flags);
  453.             return 0;
  454.         case TIOCSCTTY:
  455.             if (current->leader &&
  456.                 (current->session == tty->session))
  457.                 return 0;
  458.             /*
  459.              * The process must be a session leader and
  460.              * not have a controlling tty already.
  461.              */
  462.             if (!current->leader || (current->tty >= 0))
  463.                 return -EPERM;
  464.             if (tty->session > 0) {
  465.                 /*
  466.                  * This tty is already the controlling
  467.                  * tty for another session group!
  468.                  */
  469.                 if ((arg == 1) && suser()) {
  470.                     /*
  471.                      * Steal it away
  472.                      */
  473.                     struct task_struct *p;
  474.  
  475.                     for_each_task(p)
  476.                         if (p->tty == dev)
  477.                             p->tty = -1;
  478.                 } else
  479.                     return -EPERM;
  480.             }
  481.             current->tty = dev;
  482.             tty->session = current->session;
  483.             tty->pgrp = current->pgrp;
  484.             return 0;
  485.         case TIOCGPGRP:
  486.             retval = verify_area(VERIFY_WRITE, (void *) arg,
  487.                          sizeof (pid_t));
  488.             if (retval)
  489.                 return retval;
  490.             if (current->tty != termios_dev)
  491.                 return -ENOTTY;
  492.             put_fs_long(termios_tty->pgrp, (pid_t *) arg);
  493.             return 0;
  494.         case TIOCSPGRP:
  495.             retval = check_change(termios_tty, termios_dev);
  496.             if (retval)
  497.                 return retval;
  498.             if ((current->tty < 0) ||
  499.                 (current->tty != termios_dev) ||
  500.                 (termios_tty->session != current->session))
  501.                 return -ENOTTY;
  502.             pgrp = get_fs_long((pid_t *) arg);
  503.             if (pgrp < 0)
  504.                 return -EINVAL;
  505.             if (session_of_pgrp(pgrp) != current->session)
  506.                 return -EPERM;
  507.             termios_tty->pgrp = pgrp;
  508.             return 0;
  509.         case TIOCOUTQ:
  510.             retval = verify_area(VERIFY_WRITE, (void *) arg,
  511.                          sizeof (unsigned long));
  512.             if (retval)
  513.                 return retval;
  514.             put_fs_long(CHARS(&tty->write_q),
  515.                     (unsigned long *) arg);
  516.             return 0;
  517.         case TIOCINQ:
  518.             retval = verify_area(VERIFY_WRITE, (void *) arg,
  519.                          sizeof (unsigned long));
  520.             if (retval)
  521.                 return retval;
  522.             if (L_ICANON(tty))
  523.                 put_fs_long(inq_canon(tty),
  524.                     (unsigned long *) arg);
  525.             else
  526.                 put_fs_long(CHARS(&tty->secondary),
  527.                     (unsigned long *) arg);
  528.             return 0;
  529.         case TIOCSTI:
  530.             if ((current->tty != dev) && !suser())
  531.                 return -EPERM;
  532.             retval = verify_area(VERIFY_READ, (void *) arg, 1);
  533.             if (retval)
  534.                 return retval;
  535.             put_tty_queue(get_fs_byte((char *) arg), &tty->read_q);
  536.             TTY_READ_FLUSH(tty);
  537.             return 0;
  538.         case TIOCGWINSZ:
  539.             retval = verify_area(VERIFY_WRITE, (void *) arg,
  540.                          sizeof (struct winsize));
  541.             if (retval)
  542.                 return retval;
  543.             memcpy_tofs((struct winsize *) arg, &tty->winsize,
  544.                     sizeof (struct winsize));
  545.             return 0;
  546.         case TIOCSWINSZ:
  547.             if (IS_A_PTY_MASTER(dev))
  548.                 set_window_size(other_tty,(struct winsize *) arg);
  549.             return set_window_size(tty,(struct winsize *) arg);
  550.         case TIOCLINUX:
  551.             switch (get_fs_byte((char *)arg))
  552.             {
  553.                 case 0: 
  554.                     return do_screendump(arg);
  555.                 case 1: 
  556.                     return do_get_ps_info(arg);
  557. #ifdef CONFIG_SELECTION
  558.                 case 2:
  559.                     return set_selection(arg);
  560.                 case 3:
  561.                     return paste_selection(tty);
  562.                 case 4:
  563.                     unblank_screen();
  564.                     return 0;
  565. #endif /* CONFIG_SELECTION */
  566.                 default: 
  567.                     return -EINVAL;
  568.             }
  569.         case TIOCCONS:
  570.             if (IS_A_CONSOLE(dev)) {
  571.                 if (!suser())
  572.                     return -EPERM;
  573.                 redirect = NULL;
  574.                 return 0;
  575.             }
  576.             if (redirect)
  577.                 return -EBUSY;
  578.             if (!suser())
  579.                 return -EPERM;
  580.             if (IS_A_PTY_MASTER(dev))
  581.                 redirect = other_tty;
  582.             else if (IS_A_PTY_SLAVE(dev))
  583.                 redirect = tty;
  584.             else
  585.                 return -ENOTTY;
  586.             return 0;
  587.         case FIONBIO:
  588.             arg = get_fs_long((unsigned long *) arg);
  589.             if (arg)
  590.                 file->f_flags |= O_NONBLOCK;
  591.             else
  592.                 file->f_flags &= ~O_NONBLOCK;
  593.             return 0;
  594.         case TIOCNOTTY:
  595.             if (current->tty != dev)
  596.                 return -ENOTTY;
  597.             if (current->leader)
  598.                 disassociate_ctty(0);
  599.             current->tty = -1;
  600.             return 0;
  601.         case TIOCGETD:
  602.             retval = verify_area(VERIFY_WRITE, (void *) arg,
  603.                          sizeof (unsigned long));
  604.             if (retval)
  605.                 return retval;
  606.             put_fs_long(tty->disc, (unsigned long *) arg);
  607.             return 0;
  608.         case TIOCSETD:
  609.             retval = check_change(tty, dev);
  610.             if (retval)
  611.                 return retval;
  612.             arg = get_fs_long((unsigned long *) arg);
  613.             return tty_set_ldisc(tty, arg);
  614.         case TIOCGLCKTRMIOS:
  615.             arg = get_fs_long((unsigned long *) arg);
  616.             retval = verify_area(VERIFY_WRITE, (void *) arg,
  617.                          sizeof (struct termios));
  618.             if (retval)
  619.                 return retval;
  620.             memcpy_tofs((struct termios *) arg,
  621.                     &termios_locked[termios_dev],
  622.                     sizeof (struct termios));
  623.             return 0;
  624.         case TIOCSLCKTRMIOS:
  625.             if (!suser())
  626.                 return -EPERM;
  627.             arg = get_fs_long((unsigned long *) arg);
  628.             memcpy_fromfs(&termios_locked[termios_dev],
  629.                       (struct termios *) arg,
  630.                       sizeof (struct termios));
  631.             return 0;
  632.         case TIOCPKT:
  633.             if (!IS_A_PTY_MASTER(dev))
  634.                 return -ENOTTY;
  635.             retval = verify_area(VERIFY_READ, (void *) arg,
  636.                          sizeof (unsigned long));
  637.             if (retval)
  638.                 return retval;
  639.             if (get_fs_long(arg)) {
  640.                 if (!tty->packet) {
  641.                     tty->packet = 1;
  642.                     tty->link->ctrl_status = 0;
  643.                 }
  644.             } else
  645.                 tty->packet = 0;
  646.             return 0;
  647.         case TCSBRK: case TCSBRKP:
  648.             retval = check_change(tty, dev);
  649.             if (retval)
  650.                 return retval;
  651.             wait_until_sent(tty, 0);
  652.             if (!tty->ioctl)
  653.                 return 0;
  654.             tty->ioctl(tty, file, cmd, arg);
  655.             return 0;
  656.         default:
  657.             if (tty->ioctl) {
  658.                 retval = (tty->ioctl)(tty, file, cmd, arg);
  659.                 if (retval != -EINVAL)
  660.                     return retval;
  661.             }
  662.             if (ldiscs[tty->disc].ioctl) {
  663.                 retval = (ldiscs[tty->disc].ioctl)
  664.                     (tty, file, cmd, arg);
  665.                 return retval;
  666.             }
  667.             return -EINVAL;
  668.     }
  669. }
  670.