home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / drivers / char / tty_ioctl.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-08  |  9.6 KB  |  375 lines

  1. /*
  2.  *  linux/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/kernel.h>
  16. #include <linux/major.h>
  17. #include <linux/tty.h>
  18. #include <linux/fcntl.h>
  19. #include <linux/string.h>
  20. #include <linux/mm.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 TTY_DEBUG_WAIT_UNTIL_SENT
  28.  
  29. #undef    DEBUG
  30. #ifdef DEBUG
  31. # define    PRINTK(x)    printk (x)
  32. #else
  33. # define    PRINTK(x)    /**/
  34. #endif
  35.  
  36. /*
  37.  * Internal flag options for termios setting behavior
  38.  */
  39. #define TERMIOS_FLUSH    1
  40. #define TERMIOS_WAIT    2
  41. #define TERMIOS_TERMIO    4
  42.  
  43. void tty_wait_until_sent(struct tty_struct * tty, int timeout)
  44. {
  45.     struct wait_queue wait = { current, NULL };
  46.  
  47. #ifdef TTY_DEBUG_WAIT_UNTIL_SENT
  48.     printk("%s wait until sent...\n", tty_name(tty));
  49. #endif
  50.     if (!tty->driver.chars_in_buffer ||
  51.         !tty->driver.chars_in_buffer(tty))
  52.         return;
  53.     add_wait_queue(&tty->write_wait, &wait);
  54.     current->counter = 0;    /* make us low-priority */
  55.     if (timeout)
  56.         current->timeout = timeout + jiffies;
  57.     else
  58.         current->timeout = (unsigned) -1;
  59.     do {
  60. #ifdef TTY_DEBUG_WAIT_UNTIL_SENT
  61.         printk("waiting %s...(%d)\n", tty_name(tty), tty->driver.chars_in_buffer(tty));
  62. #endif
  63.         current->state = TASK_INTERRUPTIBLE;
  64.         if (current->signal & ~current->blocked)
  65.             break;
  66.         if (!tty->driver.chars_in_buffer(tty))
  67.             break;
  68.         schedule();
  69.     } while (current->timeout);
  70.     current->state = TASK_RUNNING;
  71.     remove_wait_queue(&tty->write_wait, &wait);
  72. }
  73.  
  74. static void unset_locked_termios(struct termios *termios,
  75.                  struct termios *old,
  76.                  struct termios *locked)
  77. {
  78.     int    i;
  79.     
  80. #define NOSET_MASK(x,y,z) (x = ((x) & ~(z)) | ((y) & (z)))
  81.  
  82.     if (!locked) {
  83.         printk("Warning?!? termios_locked is NULL.\n");
  84.         return;
  85.     }
  86.  
  87.     NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
  88.     NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
  89.     NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
  90.     NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
  91.     termios->c_line = locked->c_line ? old->c_line : termios->c_line;
  92.     for (i=0; i < NCCS; i++)
  93.         termios->c_cc[i] = locked->c_cc[i] ?
  94.             old->c_cc[i] : termios->c_cc[i];
  95. }
  96.  
  97. static int set_termios(struct tty_struct * tty, unsigned long arg, int opt)
  98. {
  99.     struct termio tmp_termio;
  100.     struct termios tmp_termios;
  101.     struct termios old_termios = *tty->termios;
  102.     int retval, canon_change;
  103.  
  104.     retval = tty_check_change(tty);
  105.     if (retval)
  106.         return retval;
  107.  
  108.     if (opt & TERMIOS_TERMIO) {
  109.         retval = verify_area(VERIFY_READ, (void *) arg, sizeof(struct termio));
  110.         if (retval)
  111.             return retval;
  112.         tmp_termios = *tty->termios;
  113.         memcpy_fromfs(&tmp_termio, (struct termio *) arg,
  114.                   sizeof (struct termio));
  115.  
  116. #define SET_LOW_BITS(x,y)    ((x) = (0xffff0000 & (x)) | (y))
  117.         SET_LOW_BITS(tmp_termios.c_iflag, tmp_termio.c_iflag);
  118.         SET_LOW_BITS(tmp_termios.c_oflag, tmp_termio.c_oflag);
  119.         SET_LOW_BITS(tmp_termios.c_cflag, tmp_termio.c_cflag);
  120.         SET_LOW_BITS(tmp_termios.c_lflag, tmp_termio.c_lflag);
  121.         memcpy(&tmp_termios.c_cc, &tmp_termio.c_cc, NCC);
  122. #undef SET_LOW_BITS
  123.     } else {
  124.         retval = verify_area(VERIFY_READ, (void *) arg, sizeof(struct termios));
  125.         if (retval)
  126.             return retval;
  127.         memcpy_fromfs(&tmp_termios, (struct termios *) arg,
  128.                   sizeof (struct termios));
  129.     }
  130.  
  131.     if ((opt & TERMIOS_FLUSH) && tty->ldisc.flush_buffer)
  132.         tty->ldisc.flush_buffer(tty);
  133.  
  134.     if (opt & TERMIOS_WAIT)
  135.         tty_wait_until_sent(tty, 0);
  136.  
  137.     cli();
  138.     *tty->termios = tmp_termios;
  139.     unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
  140.     canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
  141.     if (canon_change) {
  142.         memset(&tty->read_flags, 0, sizeof tty->read_flags);
  143.         tty->canon_head = tty->read_tail;
  144.         tty->canon_data = 0;
  145.         tty->erasing = 0;
  146.     }
  147.     sti();
  148.     if (canon_change && !L_ICANON(tty) && tty->read_cnt)
  149.         /* Get characters left over from canonical mode. */
  150.         wake_up_interruptible(&tty->read_wait);
  151.  
  152.     /* see if packet mode change of state */
  153.  
  154.     if (tty->link && tty->link->packet) {
  155.         int old_flow = ((old_termios.c_iflag & IXON) &&
  156.                 (old_termios.c_cc[VSTOP] == '\023') &&
  157.                 (old_termios.c_cc[VSTART] == '\021'));
  158.         int new_flow = (I_IXON(tty) &&
  159.                 STOP_CHAR(tty) == '\023' &&
  160.                 START_CHAR(tty) == '\021');
  161.         if (old_flow != new_flow) {
  162.             tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
  163.             if (new_flow)
  164.                 tty->ctrl_status |= TIOCPKT_DOSTOP;
  165.             else
  166.                 tty->ctrl_status |= TIOCPKT_NOSTOP;
  167.             wake_up_interruptible(&tty->link->read_wait);
  168.         }
  169.     }
  170.  
  171.     if (tty->driver.set_termios)
  172.         (*tty->driver.set_termios)(tty, &old_termios);
  173.  
  174.     if (tty->ldisc.set_termios)
  175.         (*tty->ldisc.set_termios)(tty, &old_termios);
  176.         
  177.     return 0;
  178. }
  179.  
  180. static int get_termio(struct tty_struct * tty, struct termio * termio)
  181. {
  182.     int i;
  183.     struct termio tmp_termio;
  184.  
  185.     i = verify_area(VERIFY_WRITE, termio, sizeof (struct termio));
  186.     if (i)
  187.         return i;
  188.     tmp_termio.c_iflag = tty->termios->c_iflag;
  189.     tmp_termio.c_oflag = tty->termios->c_oflag;
  190.     tmp_termio.c_cflag = tty->termios->c_cflag;
  191.     tmp_termio.c_lflag = tty->termios->c_lflag;
  192.     tmp_termio.c_line = tty->termios->c_line;
  193.     for(i=0 ; i < NCC ; i++)
  194.         tmp_termio.c_cc[i] = tty->termios->c_cc[i];
  195.     memcpy_tofs(termio, &tmp_termio, sizeof (struct termio));
  196.     return 0;
  197. }
  198.  
  199. static unsigned long inq_canon(struct tty_struct * tty)
  200. {
  201.     int nr, head, tail;
  202.  
  203.     if (!tty->canon_data || !tty->read_buf)
  204.         return 0;
  205.     head = tty->canon_head;
  206.     tail = tty->read_tail;
  207.     nr = (head - tail) & (N_TTY_BUF_SIZE-1);
  208.     /* Skip EOF-chars.. */
  209.     while (head != tail) {
  210.         if (test_bit(tail, &tty->read_flags) &&
  211.             tty->read_buf[tail] == __DISABLED_CHAR)
  212.             nr--;
  213.         tail = (tail+1) & (N_TTY_BUF_SIZE-1);
  214.     }
  215.     return nr;
  216. }
  217.  
  218. int n_tty_ioctl(struct tty_struct * tty, struct file * file,
  219.                unsigned int cmd, unsigned long arg)
  220. {
  221.     struct tty_struct * real_tty;
  222.     int retval;
  223.     int opt = 0;
  224.  
  225.     if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
  226.         tty->driver.subtype == PTY_TYPE_MASTER)
  227.         real_tty = tty->link;
  228.     else
  229.         real_tty = tty;
  230.  
  231.     switch (cmd) {
  232.         case TCGETS:
  233.             retval = verify_area(VERIFY_WRITE, (void *) arg,
  234.                          sizeof (struct termios));
  235.             if (retval)
  236.                 return retval;
  237.             memcpy_tofs((struct termios *) arg,
  238.                     real_tty->termios,
  239.                     sizeof (struct termios));
  240.             return 0;
  241.         case TCSETSF:
  242.             opt |= TERMIOS_FLUSH;
  243.         case TCSETSW:
  244.             opt |= TERMIOS_WAIT;
  245.         case TCSETS:
  246.             return set_termios(real_tty, arg, opt);
  247.         case TCGETA:
  248.             return get_termio(real_tty,(struct termio *) arg);
  249.         case TCSETAF:
  250.             opt |= TERMIOS_FLUSH;
  251.         case TCSETAW:
  252.             opt |= TERMIOS_WAIT;
  253.         case TCSETA:
  254.             return set_termios(real_tty, arg, opt|TERMIOS_TERMIO);
  255.         case TCXONC:
  256.             retval = tty_check_change(tty);
  257.             if (retval)
  258.                 return retval;
  259.             switch (arg) {
  260.             case TCOOFF:
  261.                 stop_tty(tty);
  262.                 break;
  263.             case TCOON:
  264.                 start_tty(tty);
  265.                 break;
  266.             case TCIOFF:
  267.                 if (STOP_CHAR(tty) != __DISABLED_CHAR)
  268.                     tty->driver.write(tty, 0,
  269.                               &STOP_CHAR(tty), 1);
  270.                 break;
  271.             case TCION:
  272.                 if (START_CHAR(tty) != __DISABLED_CHAR)
  273.                     tty->driver.write(tty, 0,
  274.                               &START_CHAR(tty), 1);
  275.                 break;
  276.             default:
  277.                 return -EINVAL;
  278.             }
  279.             return 0;
  280.         case TCFLSH:
  281.             retval = tty_check_change(tty);
  282.             if (retval)
  283.                 return retval;
  284.             switch (arg) {
  285.             case TCIFLUSH:
  286.                 if (tty->ldisc.flush_buffer)
  287.                     tty->ldisc.flush_buffer(tty);
  288.                 break;
  289.             case TCIOFLUSH:
  290.                 if (tty->ldisc.flush_buffer)
  291.                     tty->ldisc.flush_buffer(tty);
  292.                 /* fall through */
  293.             case TCOFLUSH:
  294.                 if (tty->driver.flush_buffer)
  295.                     tty->driver.flush_buffer(tty);
  296.                 break;
  297.             default:
  298.                 return -EINVAL;
  299.             }
  300.             return 0;
  301.         case TIOCOUTQ:
  302.             retval = verify_area(VERIFY_WRITE, (void *) arg,
  303.                          sizeof (unsigned long));
  304.             if (retval)
  305.                 return retval;
  306.             if (tty->driver.chars_in_buffer)
  307.                 put_fs_long(tty->driver.chars_in_buffer(tty),
  308.                         (unsigned long *) arg);
  309.             else
  310.                 put_fs_long(0, (unsigned long *) arg);
  311.             return 0;
  312.         case TIOCINQ:
  313.             retval = verify_area(VERIFY_WRITE, (void *) arg,
  314.                          sizeof (unsigned long));
  315.             if (retval)
  316.                 return retval;
  317.             if (L_ICANON(tty))
  318.                 put_fs_long(inq_canon(tty),
  319.                     (unsigned long *) arg);
  320.             else
  321.                 put_fs_long(tty->read_cnt,
  322.                         (unsigned long *) arg);
  323.             return 0;
  324.         case TIOCGLCKTRMIOS:
  325.             retval = verify_area(VERIFY_WRITE, (void *) arg,
  326.                          sizeof (struct termios));
  327.             if (retval)
  328.                 return retval;
  329.             memcpy_tofs((struct termios *) arg,
  330.                     real_tty->termios_locked,
  331.                     sizeof (struct termios));
  332.             return 0;
  333.         case TIOCSLCKTRMIOS:
  334.             if (!suser())
  335.                 return -EPERM;
  336.             retval = verify_area(VERIFY_READ, (void *) arg,
  337.                          sizeof (struct termios));
  338.             if (retval)
  339.                 return retval;
  340.             memcpy_fromfs(real_tty->termios_locked,
  341.                       (struct termios *) arg,
  342.                       sizeof (struct termios));
  343.             return 0;
  344.         case TIOCPKT:
  345.             if (tty->driver.type != TTY_DRIVER_TYPE_PTY ||
  346.                 tty->driver.subtype != PTY_TYPE_MASTER)
  347.                 return -ENOTTY;
  348.             retval = verify_area(VERIFY_READ, (void *) arg,
  349.                          sizeof (unsigned long));
  350.             if (retval)
  351.                 return retval;
  352.             if (get_fs_long(arg)) {
  353.                 if (!tty->packet) {
  354.                     tty->packet = 1;
  355.                     tty->link->ctrl_status = 0;
  356.                 }
  357.             } else
  358.                 tty->packet = 0;
  359.             return 0;
  360.         /* These two ioctl's always return success; even if */
  361.         /* the driver doesn't support them. */
  362.         case TCSBRK: case TCSBRKP:
  363.             retval = tty_check_change(tty);
  364.             if (retval)
  365.                 return retval;
  366.             tty_wait_until_sent(tty, 0);
  367.             if (!tty->driver.ioctl)
  368.                 return 0;
  369.             tty->driver.ioctl(tty, file, cmd, arg);
  370.             return 0;
  371.         default:
  372.             return -ENOIOCTLCMD;
  373.         }
  374. }
  375.