root/kernel/chr_drv/tty_ioctl.c

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

DEFINITIONS

This source file includes following definitions.
  1. flush
  2. flush_input
  3. flush_output
  4. wait_until_sent
  5. do_get_ps_info
  6. unset_locked_termios
  7. get_termios
  8. check_change
  9. set_termios
  10. get_termio
  11. set_termio
  12. get_lcktrmios
  13. set_lcktrmios
  14. set_window_size
  15. get_window_size
  16. tty_set_ldisc
  17. tty_ioctl

   1 /*
   2  *  linux/kernel/chr_drv/tty_ioctl.c
   3  *
   4  *  Copyright (C) 1991, 1992  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/tty.h>
  18 #include <linux/fcntl.h>
  19 
  20 #include <asm/io.h>
  21 #include <asm/segment.h>
  22 #include <asm/system.h>
  23 
  24 #undef  DEBUG
  25 #ifdef DEBUG
  26 # define        PRINTK(x)       printk (x)
  27 #else
  28 # define        PRINTK(x)       /**/
  29 #endif
  30 
  31 extern int session_of_pgrp(int pgrp);
  32 extern int do_screendump(int arg);
  33 extern int kill_pg(int pgrp, int sig, int priv);
  34 
  35 #ifdef CONFIG_SELECTION
  36 extern int set_selection(const int arg);
  37 extern int paste_selection(struct tty_struct *tty);
  38 #endif /* CONFIG_SELECTION */
  39 
  40 static int tty_set_ldisc(struct tty_struct *tty, int ldisc);
  41 
  42 static void flush(struct tty_queue * queue)
     /* [previous][next][first][last][top][bottom][index][help] */
  43 {
  44         if (queue) {
  45                 cli();
  46                 queue->head = queue->tail;
  47                 sti();
  48                 wake_up_interruptible(&queue->proc_list);
  49         }
  50 }
  51 
  52 void flush_input(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
  53 {
  54         tty->ctrl_status |= TIOCPKT_FLUSHREAD;
  55         flush(&tty->read_q);
  56         wake_up_interruptible(&tty->read_q.proc_list);
  57         flush(&tty->secondary);
  58         tty->secondary.data = 0;
  59 
  60         if ((tty = tty->link) != NULL) {
  61                 flush(&tty->write_q);
  62                 wake_up_interruptible(&tty->write_q.proc_list);
  63         }
  64 }
  65 
  66 void flush_output(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
  67 {
  68         tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
  69         flush(&tty->write_q);
  70         wake_up_interruptible(&tty->write_q.proc_list);
  71         if ((tty = tty->link) != NULL) {
  72                 flush(&tty->read_q);
  73                 wake_up_interruptible(&tty->read_q.proc_list);
  74                 flush(&tty->secondary);
  75                 tty->secondary.data = 0;
  76         }
  77 }
  78 
  79 void wait_until_sent(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
  80 {
  81         struct wait_queue wait = { current, NULL };
  82 
  83         TTY_WRITE_FLUSH(tty);
  84         if (EMPTY(&tty->write_q))
  85                 return;
  86         add_wait_queue(&tty->write_q.proc_list, &wait);
  87         current->counter = 0;   /* make us low-priority */
  88         while (1) {
  89                 current->state = TASK_INTERRUPTIBLE;
  90                 if (current->signal & ~current->blocked)
  91                         break;
  92                 TTY_WRITE_FLUSH(tty);
  93                 if (EMPTY(&tty->write_q))
  94                         break;
  95                 schedule();
  96         }
  97         current->state = TASK_RUNNING;
  98         remove_wait_queue(&tty->write_q.proc_list, &wait);
  99 }
 100 
 101 static int do_get_ps_info(int arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 102 {
 103         struct tstruct {
 104                 int flag;
 105                 int present[NR_TASKS];
 106                 struct task_struct tasks[NR_TASKS];
 107         };
 108         struct tstruct *ts = (struct tstruct *)arg;
 109         struct task_struct **p;
 110         char *c, *d;
 111         int i, n = 0;
 112         
 113         i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct tstruct));
 114         if (i)
 115                 return i;
 116         for (p = &FIRST_TASK ; p <= &LAST_TASK ; p++, n++)
 117                 if (*p)
 118                 {
 119                         c = (char *)(*p);
 120                         d = (char *)(ts->tasks+n);
 121                         for (i=0 ; i<sizeof(struct task_struct) ; i++)
 122                                 put_fs_byte(*c++, d++);
 123                         put_fs_long(1, (unsigned long *)(ts->present+n));
 124                 }
 125                 else    
 126                         put_fs_long(0, (unsigned long *)(ts->present+n));
 127         return(0);                      
 128 }
 129 
 130 static void unset_locked_termios(struct termios *termios,
     /* [previous][next][first][last][top][bottom][index][help] */
 131                                  struct termios *old,
 132                                  struct termios *locked)
 133 {
 134         int     i;
 135         
 136 #define NOSET_MASK(x,y,z) (x = ((x) & ~(z)) | ((y) & (z)))
 137 
 138         if (!locked) {
 139                 printk("Warning?!? termios_locked is NULL.\n");
 140                 return;
 141         }
 142 
 143         NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
 144         NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
 145         NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
 146         NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
 147         termios->c_line = locked->c_line ? old->c_line : termios->c_line;
 148         for (i=0; i < NCCS; i++)
 149                 termios->c_cc[i] = locked->c_cc[i] ?
 150                         old->c_cc[i] : termios->c_cc[i];
 151 }
 152 
 153 static int get_termios(struct tty_struct * tty, struct termios * termios)
     /* [previous][next][first][last][top][bottom][index][help] */
 154 {
 155         int i;
 156 
 157         i = verify_area(VERIFY_WRITE, termios, sizeof (*termios));
 158         if (i)
 159                 return i;
 160         for (i=0 ; i< (sizeof (*termios)) ; i++)
 161                 put_fs_byte( ((char *)tty->termios)[i] , i+(char *)termios );
 162         return 0;
 163 }
 164 
 165 static int check_change(struct tty_struct * tty, int channel)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 || tty->pgrp == current->pgrp)
 173                 return 0;
 174         if (is_orphaned_pgrp(current->pgrp))
 175                 return -EIO;
 176         if (is_ignored(SIGTTOU))
 177                 return 0;
 178         (void) kill_pg(current->pgrp,SIGTTOU,1);
 179         return -ERESTARTSYS;
 180 }
 181 
 182 static int set_termios(struct tty_struct * tty, struct termios * termios,
     /* [previous][next][first][last][top][bottom][index][help] */
 183                         int channel)
 184 {
 185         int i, old_flow, new_flow;
 186         struct termios old_termios = *tty->termios;
 187 
 188         i = check_change(tty, channel);
 189         if (i)
 190                 return i;
 191         for (i=0 ; i< (sizeof (*termios)) ; i++)
 192                 ((char *)tty->termios)[i]=get_fs_byte(i+(char *)termios);
 193 
 194         /* see if packet mode change of state */
 195 
 196         old_flow = (old_termios.c_iflag & IXON) &&
 197               (old_termios.c_cc[VSTOP] == '\023') &&
 198               (old_termios.c_cc[VSTART] == '\021');
 199 
 200         new_flow = (tty->termios->c_iflag & IXON) &&
 201               (tty->termios->c_cc[VSTOP] == '\023') &&
 202               (tty->termios->c_cc[VSTART] == '\021');
 203 
 204         if (old_flow != new_flow) {
 205           tty->ctrl_status &= ~(TIOCPKT_DOSTOP|TIOCPKT_NOSTOP);
 206           if (new_flow)
 207              tty->ctrl_status |= TIOCPKT_DOSTOP;
 208           else
 209              tty->ctrl_status |= TIOCPKT_NOSTOP;                
 210         }
 211 
 212         /* puting mpty's into echo mode is very bad, and I think under
 213            some situations can cause the kernel to do nothing but
 214            copy characters back and forth. -RAB */
 215         if (IS_A_PTY_MASTER(channel)) tty->termios->c_lflag &= ~ECHO;
 216 
 217         unset_locked_termios(tty->termios, &old_termios,
 218                              termios_locked[tty->line]);
 219 
 220 #if 0
 221         retval = tty_set_ldisc(tty, tty->termios->c_line);
 222         if (retval)
 223                 return retval;
 224 #endif
 225 
 226         if (tty->set_termios)
 227                 (*tty->set_termios)(tty, &old_termios);
 228 
 229         return 0;
 230 }
 231 
 232 static int get_termio(struct tty_struct * tty, struct termio * termio)
     /* [previous][next][first][last][top][bottom][index][help] */
 233 {
 234         int i;
 235         struct termio tmp_termio;
 236 
 237         i = verify_area(VERIFY_WRITE, termio, sizeof (*termio));
 238         if (i)
 239                 return i;
 240         tmp_termio.c_iflag = tty->termios->c_iflag;
 241         tmp_termio.c_oflag = tty->termios->c_oflag;
 242         tmp_termio.c_cflag = tty->termios->c_cflag;
 243         tmp_termio.c_lflag = tty->termios->c_lflag;
 244         tmp_termio.c_line = tty->termios->c_line;
 245         for(i=0 ; i < NCC ; i++)
 246                 tmp_termio.c_cc[i] = tty->termios->c_cc[i];
 247         for (i=0 ; i< (sizeof (*termio)) ; i++)
 248                 put_fs_byte( ((char *)&tmp_termio)[i] , i+(char *)termio );
 249         return 0;
 250 }
 251 
 252 /*
 253  * This only works as the 386 is low-byte-first
 254  */
 255 static int set_termio(struct tty_struct * tty, struct termio * termio,
     /* [previous][next][first][last][top][bottom][index][help] */
 256                         int channel)
 257 {
 258         int i, old_flow, new_flow;
 259         struct termio tmp_termio;
 260         struct termios old_termios = *tty->termios;
 261 
 262         i = check_change(tty, channel);
 263         if (i)
 264                 return i;
 265         for (i=0 ; i< (sizeof (*termio)) ; i++)
 266                 ((char *)&tmp_termio)[i]=get_fs_byte(i+(char *)termio);
 267 
 268         *(unsigned short *)&tty->termios->c_iflag = tmp_termio.c_iflag;
 269         *(unsigned short *)&tty->termios->c_oflag = tmp_termio.c_oflag;
 270         *(unsigned short *)&tty->termios->c_cflag = tmp_termio.c_cflag;
 271         *(unsigned short *)&tty->termios->c_lflag = tmp_termio.c_lflag;
 272         for(i=0 ; i < NCC ; i++)
 273                 tty->termios->c_cc[i] = tmp_termio.c_cc[i];
 274 
 275         /* see if packet mode change of state */
 276 
 277         old_flow = (old_termios.c_iflag & IXON) &&
 278               (old_termios.c_cc[VSTOP] == '\023') &&
 279               (old_termios.c_cc[VSTART] == '\021');
 280 
 281         new_flow = (tty->termios->c_iflag & IXON) &&
 282               (tty->termios->c_cc[VSTOP] == '\023') &&
 283               (tty->termios->c_cc[VSTART] == '\021');
 284 
 285         if (old_flow != new_flow) {
 286           tty->ctrl_status &= ~(TIOCPKT_DOSTOP|TIOCPKT_NOSTOP);
 287           if (new_flow)
 288              tty->ctrl_status |= TIOCPKT_DOSTOP;
 289           else
 290              tty->ctrl_status |= TIOCPKT_NOSTOP;                
 291         }
 292 
 293 
 294         unset_locked_termios(tty->termios, &old_termios,
 295                              termios_locked[tty->line]);
 296 
 297 #if 0
 298         retval = tty_set_ldisc(tty, tmp_termio.c_line);
 299         if (retval)
 300                 return retval;
 301 #endif
 302 
 303         if (tty->set_termios)
 304                 (*tty->set_termios)(tty, &old_termios);
 305 
 306         return 0;
 307 }
 308 
 309 static int get_lcktrmios(struct tty_struct * tty, struct termios * termios,
     /* [previous][next][first][last][top][bottom][index][help] */
 310                          int channel)
 311 {
 312         int i;
 313 
 314         i = verify_area(VERIFY_WRITE, termios, sizeof (*termios));
 315         if (i)
 316                 return i;
 317         for (i=0 ; i< (sizeof (*termios)) ; i++)
 318                 put_fs_byte( ((char *)termios_locked[channel])[i],
 319                             i+(char *)termios);
 320         return 0;
 321 }
 322 
 323 static int set_lcktrmios(struct tty_struct * tty, struct termios * termios,
     /* [previous][next][first][last][top][bottom][index][help] */
 324                          int channel)
 325 {
 326         int i;
 327 
 328         if (!suser())
 329                 return -EPERM;
 330         for (i=0 ; i< (sizeof (*termios)) ; i++)
 331                 ((char *)termios_locked[channel])[i] =
 332                         get_fs_byte(i+(char *)termios);
 333 
 334         return 0;
 335 }
 336 
 337 static int set_window_size(struct tty_struct * tty, struct winsize * ws)
     /* [previous][next][first][last][top][bottom][index][help] */
 338 {
 339         int i,changed;
 340         char c, * tmp;
 341 
 342         if (!ws)
 343                 return -EINVAL;
 344         tmp = (char *) &tty->winsize;
 345         changed = 0;
 346         for (i = 0; i < sizeof (*ws) ; i++,tmp++) {
 347                 c = get_fs_byte(i + (char *) ws);
 348                 if (c == *tmp)
 349                         continue;
 350                 changed = 1;
 351                 *tmp = c;
 352         }
 353         if (changed)
 354                 kill_pg(tty->pgrp, SIGWINCH, 1);
 355         return 0;
 356 }
 357 
 358 static int get_window_size(struct tty_struct * tty, struct winsize * ws)
     /* [previous][next][first][last][top][bottom][index][help] */
 359 {
 360         int i;
 361         char * tmp;
 362 
 363         if (!ws)
 364                 return -EINVAL;
 365         i = verify_area(VERIFY_WRITE, ws, sizeof (*ws));
 366         if (i)
 367                 return i;
 368         tmp = (char *) ws;
 369         for (i = 0; i < sizeof (struct winsize) ; i++,tmp++)
 370                 put_fs_byte(((char *) &tty->winsize)[i], tmp);
 371         return 0;
 372 }
 373 
 374 /* Set the discipline of a tty line. */
 375 static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
     /* [previous][next][first][last][top][bottom][index][help] */
 376 {
 377         if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS) ||
 378             !(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED))
 379                 return -EINVAL;
 380 
 381         if (tty->disc == ldisc)
 382                 return 0;       /* We are already in the desired discipline */
 383 
 384         /* Shutdown the current discipline. */
 385         wait_until_sent(tty);
 386         flush_input(tty);
 387         if (ldiscs[tty->disc].close)
 388                 ldiscs[tty->disc].close(tty);
 389 
 390         /* Now set up the new line discipline. */
 391         tty->disc = ldisc;
 392         tty->termios->c_line = ldisc;
 393         if (ldiscs[tty->disc].open)
 394                 return(ldiscs[tty->disc].open(tty));
 395         else
 396                 return 0;
 397 }
 398 
 399 
 400 int tty_ioctl(struct inode * inode, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
 401         unsigned int cmd, unsigned long arg)
 402 {
 403         struct tty_struct * tty;
 404         struct tty_struct * other_tty;
 405         struct tty_struct * termios_tty;
 406         int pgrp;
 407         int dev;
 408         int termios_dev;
 409         int retval;
 410 
 411         if (MAJOR(file->f_rdev) != 4) {
 412                 printk("tty_ioctl: tty pseudo-major != 4\n");
 413                 return -EINVAL;
 414         }
 415         dev = MINOR(file->f_rdev);
 416         tty = TTY_TABLE(dev);
 417         if (!tty)
 418                 return -EINVAL;
 419         if (IS_A_PTY(dev))
 420                 other_tty = tty_table[PTY_OTHER(dev)];
 421         else
 422                 other_tty = NULL;
 423         termios_tty = tty;
 424         termios_dev = dev;
 425         if (IS_A_PTY_MASTER(dev)) {
 426                 termios_tty = other_tty;
 427                 termios_dev = PTY_OTHER(dev);
 428         }
 429         switch (cmd) {
 430                 case TCGETS:
 431                         return get_termios(termios_tty,(struct termios *) arg);
 432                 case TCSETSF:
 433                         flush_input(tty);
 434                 /* fallthrough */
 435                 case TCSETSW:
 436                         wait_until_sent(tty);
 437                 /* fallthrough */
 438                 case TCSETS:
 439                         return set_termios(termios_tty,(struct termios *) arg, termios_dev);
 440                 case TCGETA:
 441                         return get_termio(termios_tty,(struct termio *) arg);
 442                 case TCSETAF:
 443                         flush_input(tty);
 444                 /* fallthrough */
 445                 case TCSETAW:
 446                         wait_until_sent(tty); /* fallthrough */
 447                 case TCSETA:
 448                         return set_termio(termios_tty,(struct termio *) arg, termios_dev);
 449                 case TCXONC:
 450                         switch (arg) {
 451                         case TCOOFF:
 452                                 tty->stopped = 1;
 453                                 if (tty->stop)
 454                                         (tty->stop)(tty);
 455                                 TTY_WRITE_FLUSH(tty);
 456                                 return 0;
 457                         case TCOON:
 458                                 tty->stopped = 0;
 459                                 if (tty->start)
 460                                         (tty->start)(tty);
 461                                 TTY_WRITE_FLUSH(tty);
 462                                 return 0;
 463                         case TCIOFF:
 464                                 if (STOP_CHAR(tty))
 465                                         put_tty_queue(STOP_CHAR(tty),
 466                                                       &tty->write_q);
 467                                 return 0;
 468                         case TCION:
 469                                 if (START_CHAR(tty))
 470                                         put_tty_queue(START_CHAR(tty),
 471                                                       &tty->write_q);
 472                                 return 0;
 473                         }
 474                         return -EINVAL; /* not implemented */
 475                 case TCFLSH:
 476                         if (arg==0)
 477                                 flush_input(tty);
 478                         else if (arg==1)
 479                                 flush_output(tty);
 480                         else if (arg==2) {
 481                                 flush_input(tty);
 482                                 flush_output(tty);
 483                         } else
 484                                 return -EINVAL;
 485                         return 0;
 486                 case TIOCEXCL:
 487                         return -EINVAL; /* not implemented */
 488                 case TIOCNXCL:
 489                         return -EINVAL; /* not implemented */
 490                 case TIOCSCTTY:
 491                         if ((current->leader && current->tty < 0 &&
 492                              tty->session == 0) ||
 493                             (arg == 1 && suser())) {
 494                                 current->tty = dev;
 495                                 tty->session = current->session;
 496                                 tty->pgrp = current->pgrp;
 497                                 return 0;
 498                         }
 499                         return -EPERM;
 500                 case TIOCGPGRP:
 501                         retval = verify_area(VERIFY_WRITE, (void *) arg,4);
 502                         if (!retval)
 503                                 put_fs_long(termios_tty->pgrp,(unsigned long *) arg);
 504                         return retval;
 505                 case TIOCSPGRP:
 506                         if ((current->tty < 0) ||
 507                             (current->tty != termios_dev) ||
 508                             (termios_tty->session != current->session))
 509                                 return -ENOTTY;
 510                         pgrp=get_fs_long((unsigned long *) arg);
 511                         if (pgrp < 0)
 512                                 return -EINVAL;
 513                         if (session_of_pgrp(pgrp) != current->session)
 514                                 return -EPERM;
 515                         termios_tty->pgrp = pgrp;                       
 516                         return 0;
 517                 case TIOCOUTQ:
 518                         retval = verify_area(VERIFY_WRITE, (void *) arg,4);
 519                         if (!retval)
 520                                 put_fs_long(CHARS(&tty->write_q),
 521                                     (unsigned long *) arg);
 522                         return retval;
 523                 case TIOCINQ:
 524                         retval = verify_area(VERIFY_WRITE, (void *) arg,4);
 525                         if (retval)
 526                                 return retval;
 527                         if (L_CANON(tty) && !tty->secondary.data)
 528                                 put_fs_long(0, (unsigned long *) arg);
 529                         else
 530                                 put_fs_long(CHARS(&tty->secondary),
 531                                         (unsigned long *) arg);
 532                         return 0;
 533                 case TIOCSTI:
 534                         return -EINVAL; /* not implemented */
 535                 case TIOCGWINSZ:
 536                         return get_window_size(tty,(struct winsize *) arg);
 537                 case TIOCSWINSZ:
 538                         if (IS_A_PTY_MASTER(dev))
 539                                 set_window_size(other_tty,(struct winsize *) arg);
 540                         return set_window_size(tty,(struct winsize *) arg);
 541                 case TIOCGSOFTCAR:
 542                         return -EINVAL; /* not implemented */
 543                 case TIOCSSOFTCAR:
 544                         return -EINVAL; /* not implemented */
 545                 case TIOCLINUX:
 546                         switch (get_fs_byte((char *)arg))
 547                         {
 548                                 case 0: 
 549                                         return do_screendump(arg);
 550                                 case 1: 
 551                                         return do_get_ps_info(arg);
 552 #ifdef CONFIG_SELECTION
 553                                 case 2:
 554                                         return set_selection(arg);
 555                                 case 3:
 556                                         return paste_selection(tty);
 557 #endif /* CONFIG_SELECTION */
 558                                 default: 
 559                                         return -EINVAL;
 560                         }
 561                 case TIOCCONS:
 562                         if (IS_A_CONSOLE(dev)) {
 563                                 if (!suser())
 564                                         return -EPERM;
 565                                 redirect = NULL;
 566                                 return 0;
 567                         }
 568                         if (redirect)
 569                                 return -EBUSY;
 570                         if (!suser())
 571                                 return -EPERM;
 572                         if (IS_A_PTY_MASTER(dev))
 573                                 redirect = other_tty;
 574                         else if (IS_A_PTY_SLAVE(dev))
 575                                 redirect = tty;
 576                         else
 577                                 return -EINVAL;
 578                         return 0;
 579                 case FIONBIO:
 580                         arg = get_fs_long((unsigned long *) arg);
 581                         if (arg)
 582                                 file->f_flags |= O_NONBLOCK;
 583                         else
 584                                 file->f_flags &= ~O_NONBLOCK;
 585                         return 0;
 586                 case TIOCNOTTY:
 587                         if (MINOR(file->f_rdev) != current->tty)
 588                                 return -EINVAL;
 589                         current->tty = -1;
 590                         if (current->leader) {
 591                                 if (tty->pgrp > 0)
 592                                         kill_pg(tty->pgrp, SIGHUP, 0);
 593                                 tty->pgrp = -1;
 594                                 tty->session = 0;
 595                         }
 596                         return 0;
 597                 case TIOCGETD:
 598                         retval = verify_area(VERIFY_WRITE, (void *) arg,4);
 599                         if (!retval)
 600                                 put_fs_long(tty->disc, (unsigned long *) arg);
 601                         return retval;
 602                 case TIOCSETD:
 603                         arg = get_fs_long((unsigned long *) arg);
 604                         return tty_set_ldisc(tty, arg);
 605                 case TIOCGLCKTRMIOS:
 606                         arg = get_fs_long((unsigned long *) arg);
 607                         return get_lcktrmios(tty, (struct termios *) arg,
 608                                              termios_dev);
 609                 case TIOCSLCKTRMIOS:
 610                         arg = get_fs_long((unsigned long *) arg);
 611                         return set_lcktrmios(tty, (struct termios *) arg,
 612                                              termios_dev);
 613                 case TIOCPKT:
 614                         {
 615                            int on;
 616                            if (!IS_A_PTY_MASTER(dev))
 617                              return -EINVAL;
 618                            retval = verify_area(VERIFY_READ, (unsigned long *)arg, sizeof (int));
 619                            if (retval)
 620                                 return retval;
 621                            on=get_fs_long ((unsigned long *)arg);
 622                            if (on )
 623                              tty->packet = 1;
 624                            else
 625                              tty->packet = 0;
 626                            return (0);
 627                         }
 628                 case TCSBRK: case TCSBRKP:
 629                         wait_until_sent(tty);
 630                         if (!tty->ioctl)
 631                                 return 0;
 632                         tty->ioctl(tty, file, cmd, arg);
 633                         return 0;
 634                 default:
 635                         if (tty->ioctl) {
 636                                 retval = (tty->ioctl)(tty, file, cmd, arg);
 637                                 if (retval != -EINVAL)
 638                                         return retval;
 639                         }
 640                         if (ldiscs[tty->disc].ioctl) {
 641                                 retval = (ldiscs[tty->disc].ioctl)
 642                                         (tty, file, cmd, arg);
 643                                 return retval;
 644                         }
 645                         return -EINVAL;
 646         }
 647 }

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