root/drivers/char/tty_ioctl.c

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

DEFINITIONS

This source file includes following definitions.
  1. tty_wait_until_sent
  2. unset_locked_termios
  3. change_termios
  4. set_termios
  5. get_termio
  6. inq_canon
  7. get_sgflags
  8. get_sgttyb
  9. set_sgflags
  10. set_sgttyb
  11. get_tchars
  12. set_tchars
  13. get_ltchars
  14. set_ltchars
  15. 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 #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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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,
     /* [previous][next][first][last][top][bottom][index][help] */
  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 void change_termios(struct tty_struct * tty, struct termios * new_termios)
     /* [previous][next][first][last][top][bottom][index][help] */
  98 {
  99         int canon_change;
 100         struct termios old_termios = *tty->termios;
 101 
 102         cli();
 103         *tty->termios = *new_termios;
 104         unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
 105         canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
 106         if (canon_change) {
 107                 memset(&tty->read_flags, 0, sizeof tty->read_flags);
 108                 tty->canon_head = tty->read_tail;
 109                 tty->canon_data = 0;
 110                 tty->erasing = 0;
 111         }
 112         sti();
 113         if (canon_change && !L_ICANON(tty) && tty->read_cnt)
 114                 /* Get characters left over from canonical mode. */
 115                 wake_up_interruptible(&tty->read_wait);
 116 
 117         /* see if packet mode change of state */
 118 
 119         if (tty->link && tty->link->packet) {
 120                 int old_flow = ((old_termios.c_iflag & IXON) &&
 121                                 (old_termios.c_cc[VSTOP] == '\023') &&
 122                                 (old_termios.c_cc[VSTART] == '\021'));
 123                 int new_flow = (I_IXON(tty) &&
 124                                 STOP_CHAR(tty) == '\023' &&
 125                                 START_CHAR(tty) == '\021');
 126                 if (old_flow != new_flow) {
 127                         tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
 128                         if (new_flow)
 129                                 tty->ctrl_status |= TIOCPKT_DOSTOP;
 130                         else
 131                                 tty->ctrl_status |= TIOCPKT_NOSTOP;
 132                         wake_up_interruptible(&tty->link->read_wait);
 133                 }
 134         }
 135 
 136         if (tty->driver.set_termios)
 137                 (*tty->driver.set_termios)(tty, &old_termios);
 138 
 139         if (tty->ldisc.set_termios)
 140                 (*tty->ldisc.set_termios)(tty, &old_termios);
 141 }
 142 
 143 static int set_termios(struct tty_struct * tty, unsigned long arg, int opt)
     /* [previous][next][first][last][top][bottom][index][help] */
 144 {
 145         struct termios tmp_termios;
 146         int retval;
 147 
 148         retval = tty_check_change(tty);
 149         if (retval)
 150                 return retval;
 151 
 152         if (opt & TERMIOS_TERMIO) {
 153                 struct termio tmp_termio;
 154                 retval = verify_area(VERIFY_READ, (void *) arg, sizeof(struct termio));
 155                 if (retval)
 156                         return retval;
 157                 tmp_termios = *tty->termios;
 158                 memcpy_fromfs(&tmp_termio, (struct termio *) arg,
 159                               sizeof (struct termio));
 160                 trans_from_termio(&tmp_termio, &tmp_termios);
 161         } else {
 162                 retval = verify_area(VERIFY_READ, (void *) arg, sizeof(struct termios));
 163                 if (retval)
 164                         return retval;
 165                 memcpy_fromfs(&tmp_termios, (struct termios *) arg,
 166                               sizeof (struct termios));
 167         }
 168 
 169         if ((opt & TERMIOS_FLUSH) && tty->ldisc.flush_buffer)
 170                 tty->ldisc.flush_buffer(tty);
 171 
 172         if (opt & TERMIOS_WAIT)
 173                 tty_wait_until_sent(tty, 0);
 174 
 175         change_termios(tty, &tmp_termios);
 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         trans_to_termio(tty->termios, &tmp_termio);
 188         memcpy_tofs(termio, &tmp_termio, sizeof (struct termio));
 189         return 0;
 190 }
 191 
 192 static unsigned long inq_canon(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 193 {
 194         int nr, head, tail;
 195 
 196         if (!tty->canon_data || !tty->read_buf)
 197                 return 0;
 198         head = tty->canon_head;
 199         tail = tty->read_tail;
 200         nr = (head - tail) & (N_TTY_BUF_SIZE-1);
 201         /* Skip EOF-chars.. */
 202         while (head != tail) {
 203                 if (test_bit(tail, &tty->read_flags) &&
 204                     tty->read_buf[tail] == __DISABLED_CHAR)
 205                         nr--;
 206                 tail = (tail+1) & (N_TTY_BUF_SIZE-1);
 207         }
 208         return nr;
 209 }
 210 
 211 #ifdef TIOCGETP
 212 /*
 213  * These are depracated, but there is limited support..
 214  *
 215  * The "sg_flags" translation is a joke..
 216  */
 217 static int get_sgflags(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 218 {
 219         int flags = 0;
 220 
 221         if (!(tty->termios->c_lflag & ICANON))
 222                 if (tty->termios->c_lflag & ISIG)
 223                         flags |= 0x02;          /* cbreak */
 224                 else
 225                         flags |= 0x20;          /* raw */
 226         if (tty->termios->c_lflag & ECHO)
 227                 flags |= 0x08;                  /* echo */
 228         if (tty->termios->c_oflag & OPOST)
 229                 if (tty->termios->c_oflag & ONLCR)
 230                         flags |= 0x10;          /* crmod */
 231         return flags;
 232 }
 233 
 234 static int get_sgttyb(struct tty_struct * tty, struct sgttyb * sgttyb)
     /* [previous][next][first][last][top][bottom][index][help] */
 235 {
 236         int retval;
 237         struct sgttyb tmp;
 238 
 239         retval = verify_area(VERIFY_WRITE, sgttyb, sizeof(struct sgttyb));
 240         if (retval)
 241                 return retval;
 242         tmp.sg_ispeed = 0;
 243         tmp.sg_ospeed = 0;
 244         tmp.sg_erase = tty->termios->c_cc[VERASE];
 245         tmp.sg_kill = tty->termios->c_cc[VKILL];
 246         tmp.sg_flags = get_sgflags(tty);
 247         memcpy_tofs(sgttyb, &tmp, sizeof(tmp));
 248         return 0;
 249 }
 250 
 251 static void set_sgflags(struct termios * termios, int flags)
     /* [previous][next][first][last][top][bottom][index][help] */
 252 {
 253         termios->c_iflag = ICRNL | IXON;
 254         termios->c_oflag = 0;
 255         termios->c_lflag = ISIG | ICANON;
 256         if (flags & 0x02) {     /* cbreak */
 257                 termios->c_iflag = 0;
 258                 termios->c_lflag &= ~ICANON;
 259         }
 260         if (flags & 0x08) {             /* echo */
 261                 termios->c_lflag |= ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN;
 262         }
 263         if (flags & 0x10) {             /* crmod */
 264                 termios->c_oflag |= OPOST | ONLCR;
 265         }
 266         if (flags & 0x20) {     /* raw */
 267                 termios->c_iflag = 0;
 268                 termios->c_lflag &= ~(ISIG | ICANON);
 269         }
 270         if (!(termios->c_lflag & ICANON)) {
 271                 termios->c_cc[VMIN] = 1;
 272                 termios->c_cc[VTIME] = 0;
 273         }
 274 }
 275 
 276 static int set_sgttyb(struct tty_struct * tty, struct sgttyb * sgttyb)
     /* [previous][next][first][last][top][bottom][index][help] */
 277 {
 278         int retval;
 279         struct sgttyb tmp;
 280         struct termios termios;
 281 
 282         retval = verify_area(VERIFY_READ, sgttyb, sizeof(struct sgttyb));
 283         if (retval)
 284                 return retval;
 285         retval = tty_check_change(tty);
 286         if (retval)
 287                 return retval;
 288         termios =  *tty->termios;
 289         memcpy_fromfs(&tmp, sgttyb, sizeof(tmp));
 290         termios.c_cc[VERASE] = tmp.sg_erase;
 291         termios.c_cc[VKILL] = tmp.sg_kill;
 292         set_sgflags(&termios, tmp.sg_flags);
 293         change_termios(tty, &termios);
 294         return 0;
 295 }
 296 #endif
 297 
 298 #ifdef TIOCGETC
 299 static int get_tchars(struct tty_struct * tty, struct tchars * tchars)
     /* [previous][next][first][last][top][bottom][index][help] */
 300 {
 301         int retval;
 302         struct tchars tmp;
 303 
 304         retval = verify_area(VERIFY_WRITE, tchars, sizeof(struct tchars));
 305         if (retval)
 306                 return retval;
 307         tmp.t_intrc = tty->termios->c_cc[VINTR];
 308         tmp.t_quitc = tty->termios->c_cc[VQUIT];
 309         tmp.t_startc = tty->termios->c_cc[VSTART];
 310         tmp.t_stopc = tty->termios->c_cc[VSTOP];
 311         tmp.t_eofc = tty->termios->c_cc[VEOF];
 312         tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */
 313         memcpy_tofs(tchars, &tmp, sizeof(tmp));
 314         return 0;
 315 }
 316 
 317 static int set_tchars(struct tty_struct * tty, struct tchars * tchars)
     /* [previous][next][first][last][top][bottom][index][help] */
 318 {
 319         int retval;
 320         struct tchars tmp;
 321 
 322         retval = verify_area(VERIFY_READ, tchars, sizeof(struct tchars));
 323         if (retval)
 324                 return retval;
 325         memcpy_fromfs(&tmp, tchars, sizeof(tmp));
 326         tty->termios->c_cc[VINTR] = tmp.t_intrc;
 327         tty->termios->c_cc[VQUIT] = tmp.t_quitc;
 328         tty->termios->c_cc[VSTART] = tmp.t_startc;
 329         tty->termios->c_cc[VSTOP] = tmp.t_stopc;
 330         tty->termios->c_cc[VEOF] = tmp.t_eofc;
 331         tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
 332         return 0;
 333 }
 334 #endif
 335 
 336 #ifdef TIOCGLTC
 337 static int get_ltchars(struct tty_struct * tty, struct ltchars * ltchars)
     /* [previous][next][first][last][top][bottom][index][help] */
 338 {
 339         int retval;
 340         struct ltchars tmp;
 341 
 342         retval = verify_area(VERIFY_WRITE, ltchars, sizeof(struct ltchars));
 343         if (retval)
 344                 return retval;
 345         tmp.t_suspc = tty->termios->c_cc[VSUSP];
 346         tmp.t_dsuspc = tty->termios->c_cc[VSUSP];       /* what is dsuspc anyway? */
 347         tmp.t_rprntc = tty->termios->c_cc[VREPRINT];
 348         tmp.t_flushc = tty->termios->c_cc[VEOL2];       /* what is flushc anyway? */
 349         tmp.t_werasc = tty->termios->c_cc[VWERASE];
 350         tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
 351         memcpy_tofs(ltchars, &tmp, sizeof(tmp));
 352         return 0;
 353 }
 354 
 355 static int set_ltchars(struct tty_struct * tty, struct ltchars * ltchars)
     /* [previous][next][first][last][top][bottom][index][help] */
 356 {
 357         int retval;
 358         struct ltchars tmp;
 359 
 360         retval = verify_area(VERIFY_READ, ltchars, sizeof(struct ltchars));
 361         if (retval)
 362                 return retval;
 363         memcpy_fromfs(&tmp, ltchars, sizeof(tmp));
 364         tty->termios->c_cc[VSUSP] = tmp.t_suspc;
 365         tty->termios->c_cc[VEOL2] = tmp.t_dsuspc;       /* what is dsuspc anyway? */
 366         tty->termios->c_cc[VREPRINT] = tmp.t_rprntc;
 367         tty->termios->c_cc[VEOL2] = tmp.t_flushc;       /* what is flushc anyway? */
 368         tty->termios->c_cc[VWERASE] = tmp.t_werasc;
 369         tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;
 370         return 0;
 371 }
 372 #endif
 373 
 374 int n_tty_ioctl(struct tty_struct * tty, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
 375                        unsigned int cmd, unsigned long arg)
 376 {
 377         struct tty_struct * real_tty;
 378         int retval;
 379         int opt = 0;
 380 
 381         if (tty->driver.type == TTY_DRIVER_TYPE_PTY &&
 382             tty->driver.subtype == PTY_TYPE_MASTER)
 383                 real_tty = tty->link;
 384         else
 385                 real_tty = tty;
 386 
 387         switch (cmd) {
 388 #ifdef TIOCGETP
 389                 case TIOCGETP:
 390                         return get_sgttyb(real_tty, (struct sgttyb *) arg);
 391                 case TIOCSETP:
 392                 case TIOCSETN:
 393                         return set_sgttyb(real_tty, (struct sgttyb *) arg);
 394 #endif
 395 #ifdef TIOCGETC
 396                 case TIOCGETC:
 397                         return get_tchars(real_tty, (struct tchars *) arg);
 398                 case TIOCSETC:
 399                         return set_tchars(real_tty, (struct tchars *) arg);
 400 #endif
 401 #ifdef TIOCGLTC
 402                 case TIOCGLTC:
 403                         return get_ltchars(real_tty, (struct ltchars *) arg);
 404                 case TIOCSLTC:
 405                         return set_ltchars(real_tty, (struct ltchars *) arg);
 406 #endif
 407                 case TCGETS:
 408                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 409                                              sizeof (struct termios));
 410                         if (retval)
 411                                 return retval;
 412                         memcpy_tofs((struct termios *) arg,
 413                                     real_tty->termios,
 414                                     sizeof (struct termios));
 415                         return 0;
 416                 case TCSETSF:
 417                         opt |= TERMIOS_FLUSH;
 418                 case TCSETSW:
 419                         opt |= TERMIOS_WAIT;
 420                 case TCSETS:
 421                         return set_termios(real_tty, arg, opt);
 422                 case TCGETA:
 423                         return get_termio(real_tty,(struct termio *) arg);
 424                 case TCSETAF:
 425                         opt |= TERMIOS_FLUSH;
 426                 case TCSETAW:
 427                         opt |= TERMIOS_WAIT;
 428                 case TCSETA:
 429                         return set_termios(real_tty, arg, opt|TERMIOS_TERMIO);
 430                 case TCXONC:
 431                         retval = tty_check_change(tty);
 432                         if (retval)
 433                                 return retval;
 434                         switch (arg) {
 435                         case TCOOFF:
 436                                 stop_tty(tty);
 437                                 break;
 438                         case TCOON:
 439                                 start_tty(tty);
 440                                 break;
 441                         case TCIOFF:
 442                                 if (STOP_CHAR(tty) != __DISABLED_CHAR)
 443                                         tty->driver.write(tty, 0,
 444                                                           &STOP_CHAR(tty), 1);
 445                                 break;
 446                         case TCION:
 447                                 if (START_CHAR(tty) != __DISABLED_CHAR)
 448                                         tty->driver.write(tty, 0,
 449                                                           &START_CHAR(tty), 1);
 450                                 break;
 451                         default:
 452                                 return -EINVAL;
 453                         }
 454                         return 0;
 455                 case TCFLSH:
 456                         retval = tty_check_change(tty);
 457                         if (retval)
 458                                 return retval;
 459                         switch (arg) {
 460                         case TCIFLUSH:
 461                                 if (tty->ldisc.flush_buffer)
 462                                         tty->ldisc.flush_buffer(tty);
 463                                 break;
 464                         case TCIOFLUSH:
 465                                 if (tty->ldisc.flush_buffer)
 466                                         tty->ldisc.flush_buffer(tty);
 467                                 /* fall through */
 468                         case TCOFLUSH:
 469                                 if (tty->driver.flush_buffer)
 470                                         tty->driver.flush_buffer(tty);
 471                                 break;
 472                         default:
 473                                 return -EINVAL;
 474                         }
 475                         return 0;
 476                 case TIOCOUTQ:
 477                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 478                                              sizeof (int));
 479                         if (retval)
 480                                 return retval;
 481                         if (tty->driver.chars_in_buffer)
 482                                 put_user(tty->driver.chars_in_buffer(tty),
 483                                          (int *) arg);
 484                         else
 485                                 put_user(0, (int *) arg);
 486                         return 0;
 487                 case TIOCINQ:
 488                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 489                                              sizeof (unsigned long));
 490                         if (retval)
 491                                 return retval;
 492                         if (L_ICANON(tty))
 493                                 put_fs_long(inq_canon(tty),
 494                                         (unsigned long *) arg);
 495                         else
 496                                 put_fs_long(tty->read_cnt,
 497                                             (unsigned long *) arg);
 498                         return 0;
 499                 case TIOCGLCKTRMIOS:
 500                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 501                                              sizeof (struct termios));
 502                         if (retval)
 503                                 return retval;
 504                         memcpy_tofs((struct termios *) arg,
 505                                     real_tty->termios_locked,
 506                                     sizeof (struct termios));
 507                         return 0;
 508                 case TIOCSLCKTRMIOS:
 509                         if (!suser())
 510                                 return -EPERM;
 511                         retval = verify_area(VERIFY_READ, (void *) arg,
 512                                              sizeof (struct termios));
 513                         if (retval)
 514                                 return retval;
 515                         memcpy_fromfs(real_tty->termios_locked,
 516                                       (struct termios *) arg,
 517                                       sizeof (struct termios));
 518                         return 0;
 519                 case TIOCPKT:
 520                         if (tty->driver.type != TTY_DRIVER_TYPE_PTY ||
 521                             tty->driver.subtype != PTY_TYPE_MASTER)
 522                                 return -ENOTTY;
 523                         retval = verify_area(VERIFY_READ, (void *) arg,
 524                                              sizeof (int));
 525                         if (retval)
 526                                 return retval;
 527                         if (get_user((int*)arg)) {
 528                                 if (!tty->packet) {
 529                                         tty->packet = 1;
 530                                         tty->link->ctrl_status = 0;
 531                                 }
 532                         } else
 533                                 tty->packet = 0;
 534                         return 0;
 535                 /* These two ioctl's always return success; even if */
 536                 /* the driver doesn't support them. */
 537                 case TCSBRK: case TCSBRKP:
 538                         retval = tty_check_change(tty);
 539                         if (retval)
 540                                 return retval;
 541                         tty_wait_until_sent(tty, 0);
 542                         if (!tty->driver.ioctl)
 543                                 return 0;
 544                         tty->driver.ioctl(tty, file, cmd, arg);
 545                         return 0;
 546                 default:
 547                         return -ENOIOCTLCMD;
 548                 }
 549 }

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