root/drivers/char/tty_ioctl.c

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

DEFINITIONS

This source file includes following definitions.
  1. flush_input
  2. flush_output
  3. wait_until_sent
  4. do_get_ps_info
  5. unset_locked_termios
  6. check_change
  7. set_termios_2
  8. set_termios
  9. get_termio
  10. set_termio
  11. set_window_size
  12. tty_set_ldisc
  13. inq_canon
  14. tty_ioctl

   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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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,
     /* [previous][next][first][last][top][bottom][index][help] */
 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 a master pty, return the slave's tpgid.
 491                            If not, only return the tpgid if this is
 492                            the controlling tty. */
 493                         if (tty == termios_tty && current->tty != dev)
 494                                 return -ENOTTY;
 495                         put_fs_long(termios_tty->pgrp, (pid_t *) arg);
 496                         return 0;
 497                 case TIOCSPGRP:
 498                         retval = check_change(termios_tty, termios_dev);
 499                         if (retval)
 500                                 return retval;
 501                         if ((current->tty < 0) ||
 502                             (current->tty != termios_dev) ||
 503                             (termios_tty->session != current->session))
 504                                 return -ENOTTY;
 505                         pgrp = get_fs_long((pid_t *) arg);
 506                         if (pgrp < 0)
 507                                 return -EINVAL;
 508                         if (session_of_pgrp(pgrp) != current->session)
 509                                 return -EPERM;
 510                         termios_tty->pgrp = pgrp;
 511                         return 0;
 512                 case TIOCOUTQ:
 513                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 514                                              sizeof (unsigned long));
 515                         if (retval)
 516                                 return retval;
 517                         put_fs_long(CHARS(&tty->write_q),
 518                                     (unsigned long *) arg);
 519                         return 0;
 520                 case TIOCINQ:
 521                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 522                                              sizeof (unsigned long));
 523                         if (retval)
 524                                 return retval;
 525                         if (L_ICANON(tty))
 526                                 put_fs_long(inq_canon(tty),
 527                                         (unsigned long *) arg);
 528                         else
 529                                 put_fs_long(CHARS(&tty->secondary),
 530                                         (unsigned long *) arg);
 531                         return 0;
 532                 case TIOCSTI:
 533                         if ((current->tty != dev) && !suser())
 534                                 return -EPERM;
 535                         retval = verify_area(VERIFY_READ, (void *) arg, 1);
 536                         if (retval)
 537                                 return retval;
 538                         put_tty_queue(get_fs_byte((char *) arg), &tty->read_q);
 539                         TTY_READ_FLUSH(tty);
 540                         return 0;
 541                 case TIOCGWINSZ:
 542                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 543                                              sizeof (struct winsize));
 544                         if (retval)
 545                                 return retval;
 546                         memcpy_tofs((struct winsize *) arg, &tty->winsize,
 547                                     sizeof (struct winsize));
 548                         return 0;
 549                 case TIOCSWINSZ:
 550                         if (IS_A_PTY_MASTER(dev))
 551                                 set_window_size(other_tty,(struct winsize *) arg);
 552                         return set_window_size(tty,(struct winsize *) arg);
 553                 case TIOCLINUX:
 554                         switch (get_fs_byte((char *)arg))
 555                         {
 556                                 case 0: 
 557                                         return do_screendump(arg);
 558                                 case 1: 
 559                                         return do_get_ps_info(arg);
 560 #ifdef CONFIG_SELECTION
 561                                 case 2:
 562                                         return set_selection(arg);
 563                                 case 3:
 564                                         return paste_selection(tty);
 565                                 case 4:
 566                                         unblank_screen();
 567                                         return 0;
 568 #endif /* CONFIG_SELECTION */
 569                                 default: 
 570                                         return -EINVAL;
 571                         }
 572                 case TIOCCONS:
 573                         if (IS_A_CONSOLE(dev)) {
 574                                 if (!suser())
 575                                         return -EPERM;
 576                                 redirect = NULL;
 577                                 return 0;
 578                         }
 579                         if (redirect)
 580                                 return -EBUSY;
 581                         if (!suser())
 582                                 return -EPERM;
 583                         if (IS_A_PTY_MASTER(dev))
 584                                 redirect = other_tty;
 585                         else if (IS_A_PTY_SLAVE(dev))
 586                                 redirect = tty;
 587                         else
 588                                 return -ENOTTY;
 589                         return 0;
 590                 case FIONBIO:
 591                         arg = get_fs_long((unsigned long *) arg);
 592                         if (arg)
 593                                 file->f_flags |= O_NONBLOCK;
 594                         else
 595                                 file->f_flags &= ~O_NONBLOCK;
 596                         return 0;
 597                 case TIOCNOTTY:
 598                         if (current->tty != dev)
 599                                 return -ENOTTY;
 600                         if (current->leader)
 601                                 disassociate_ctty(0);
 602                         current->tty = -1;
 603                         return 0;
 604                 case TIOCGETD:
 605                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 606                                              sizeof (unsigned long));
 607                         if (retval)
 608                                 return retval;
 609                         put_fs_long(tty->disc, (unsigned long *) arg);
 610                         return 0;
 611                 case TIOCSETD:
 612                         retval = check_change(tty, dev);
 613                         if (retval)
 614                                 return retval;
 615                         arg = get_fs_long((unsigned long *) arg);
 616                         return tty_set_ldisc(tty, arg);
 617                 case TIOCGLCKTRMIOS:
 618                         arg = get_fs_long((unsigned long *) arg);
 619                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 620                                              sizeof (struct termios));
 621                         if (retval)
 622                                 return retval;
 623                         memcpy_tofs((struct termios *) arg,
 624                                     &termios_locked[termios_dev],
 625                                     sizeof (struct termios));
 626                         return 0;
 627                 case TIOCSLCKTRMIOS:
 628                         if (!suser())
 629                                 return -EPERM;
 630                         arg = get_fs_long((unsigned long *) arg);
 631                         memcpy_fromfs(&termios_locked[termios_dev],
 632                                       (struct termios *) arg,
 633                                       sizeof (struct termios));
 634                         return 0;
 635                 case TIOCPKT:
 636                         if (!IS_A_PTY_MASTER(dev))
 637                                 return -ENOTTY;
 638                         retval = verify_area(VERIFY_READ, (void *) arg,
 639                                              sizeof (unsigned long));
 640                         if (retval)
 641                                 return retval;
 642                         if (get_fs_long(arg)) {
 643                                 if (!tty->packet) {
 644                                         tty->packet = 1;
 645                                         tty->link->ctrl_status = 0;
 646                                 }
 647                         } else
 648                                 tty->packet = 0;
 649                         return 0;
 650                 case TCSBRK: case TCSBRKP:
 651                         retval = check_change(tty, dev);
 652                         if (retval)
 653                                 return retval;
 654                         wait_until_sent(tty, 0);
 655                         if (!tty->ioctl)
 656                                 return 0;
 657                         tty->ioctl(tty, file, cmd, arg);
 658                         return 0;
 659                 default:
 660                         if (tty->ioctl) {
 661                                 retval = (tty->ioctl)(tty, file, cmd, arg);
 662                                 if (retval != -EINVAL)
 663                                         return retval;
 664                         }
 665                         if (ldiscs[tty->disc].ioctl) {
 666                                 retval = (ldiscs[tty->disc].ioctl)
 667                                         (tty, file, cmd, arg);
 668                                 return retval;
 669                         }
 670                         return -EINVAL;
 671         }
 672 }

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