root/drivers/char/tty_ioctl.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. wait_until_sent
  2. unset_locked_termios
  3. set_termios
  4. get_termio
  5. inq_canon
  6. n_tty_ioctl

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

/* [previous][next][first][last][top][bottom][index][help] */