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