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)
     /* [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         while (1) {
  95                 current->state = TASK_INTERRUPTIBLE;
  96                 if (current->signal & ~current->blocked)
  97                         break;
  98                 TTY_WRITE_FLUSH(tty);
  99                 if (EMPTY(&tty->write_q))
 100                         break;
 101                 schedule();
 102         }
 103         current->state = TASK_RUNNING;
 104         remove_wait_queue(&tty->write_q.proc_list, &wait);
 105 }
 106 
 107 static int do_get_ps_info(int arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 108 {
 109         struct tstruct {
 110                 int flag;
 111                 int present[NR_TASKS];
 112                 struct task_struct tasks[NR_TASKS];
 113         };
 114         struct tstruct *ts = (struct tstruct *)arg;
 115         struct task_struct **p;
 116         char *c, *d;
 117         int i, n = 0;
 118         
 119         i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct tstruct));
 120         if (i)
 121                 return i;
 122         for (p = &FIRST_TASK ; p <= &LAST_TASK ; p++, n++)
 123                 if (*p)
 124                 {
 125                         c = (char *)(*p);
 126                         d = (char *)(ts->tasks+n);
 127                         for (i=0 ; i<sizeof(struct task_struct) ; i++)
 128                                 put_fs_byte(*c++, d++);
 129                         put_fs_long(1, (unsigned long *)(ts->present+n));
 130                 }
 131                 else    
 132                         put_fs_long(0, (unsigned long *)(ts->present+n));
 133         return(0);                      
 134 }
 135 
 136 static void unset_locked_termios(struct termios *termios,
     /* [previous][next][first][last][top][bottom][index][help] */
 137                                  struct termios *old,
 138                                  struct termios *locked)
 139 {
 140         int     i;
 141         
 142 #define NOSET_MASK(x,y,z) (x = ((x) & ~(z)) | ((y) & (z)))
 143 
 144         if (!locked) {
 145                 printk("Warning?!? termios_locked is NULL.\n");
 146                 return;
 147         }
 148 
 149         NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
 150         NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
 151         NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
 152         NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
 153         termios->c_line = locked->c_line ? old->c_line : termios->c_line;
 154         for (i=0; i < NCCS; i++)
 155                 termios->c_cc[i] = locked->c_cc[i] ?
 156                         old->c_cc[i] : termios->c_cc[i];
 157 }
 158 
 159 int check_change(struct tty_struct * tty, int channel)
     /* [previous][next][first][last][top][bottom][index][help] */
 160 {
 161         /* If we try to set the state of terminal and we're not in the
 162            foreground, send a SIGTTOU.  If the signal is blocked or
 163            ignored, go ahead and perform the operation.  POSIX 7.2) */
 164         if (current->tty != channel)
 165                 return 0;
 166         if (tty->pgrp <= 0) {
 167                 printk("check_change: tty->pgrp <= 0!\n");
 168                 return 0;
 169         }
 170         if (current->pgrp == tty->pgrp)
 171                 return 0;
 172         if (is_ignored(SIGTTOU))
 173                 return 0;
 174         if (is_orphaned_pgrp(current->pgrp))
 175                 return -EIO;
 176         (void) kill_pg(current->pgrp,SIGTTOU,1);
 177         return -ERESTARTSYS;
 178 }
 179 
 180 static int set_termios_2(struct tty_struct * tty, struct termios * termios)
     /* [previous][next][first][last][top][bottom][index][help] */
 181 {
 182         struct termios old_termios = *tty->termios;
 183         int canon_change;
 184 
 185         canon_change = (old_termios.c_lflag ^ termios->c_lflag) & ICANON;
 186         cli();
 187         *tty->termios = *termios;
 188         if (canon_change) {
 189                 memset(&tty->secondary_flags, 0, sizeof tty->secondary_flags);
 190                 tty->canon_head = tty->secondary.tail;
 191                 tty->canon_data = 0;
 192                 tty->erasing = 0;
 193         }
 194         sti();
 195         if (canon_change && !L_ICANON(tty) && !EMPTY(&tty->secondary))
 196                 /* Get characters left over from canonical mode. */
 197                 wake_up_interruptible(&tty->secondary.proc_list);
 198 
 199         /* see if packet mode change of state */
 200 
 201         if (tty->link && tty->link->packet) {
 202                 int old_flow = ((old_termios.c_iflag & IXON) &&
 203                                 (old_termios.c_cc[VSTOP] == '\023') &&
 204                                 (old_termios.c_cc[VSTART] == '\021'));
 205                 int new_flow = (I_IXON(tty) &&
 206                                 STOP_CHAR(tty) == '\023' &&
 207                                 START_CHAR(tty) == '\021');
 208                 if (old_flow != new_flow) {
 209                         tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
 210                         if (new_flow)
 211                                 tty->ctrl_status |= TIOCPKT_DOSTOP;
 212                         else
 213                                 tty->ctrl_status |= TIOCPKT_NOSTOP;
 214                         wake_up_interruptible(&tty->link->secondary.proc_list);
 215                 }
 216         }
 217 
 218         unset_locked_termios(tty->termios, &old_termios,
 219                              termios_locked[tty->line]);
 220 
 221         if (tty->set_termios)
 222                 (*tty->set_termios)(tty, &old_termios);
 223 
 224         return 0;
 225 }
 226 
 227 static int set_termios(struct tty_struct * tty, struct termios * termios,
     /* [previous][next][first][last][top][bottom][index][help] */
 228                        int channel)
 229 {
 230         struct termios tmp_termios;
 231 
 232         memcpy_fromfs(&tmp_termios, termios, sizeof (struct termios));
 233         return set_termios_2(tty, &tmp_termios);
 234 }
 235 
 236 static int get_termio(struct tty_struct * tty, struct termio * termio)
     /* [previous][next][first][last][top][bottom][index][help] */
 237 {
 238         int i;
 239         struct termio tmp_termio;
 240 
 241         i = verify_area(VERIFY_WRITE, termio, sizeof (struct termio));
 242         if (i)
 243                 return i;
 244         tmp_termio.c_iflag = tty->termios->c_iflag;
 245         tmp_termio.c_oflag = tty->termios->c_oflag;
 246         tmp_termio.c_cflag = tty->termios->c_cflag;
 247         tmp_termio.c_lflag = tty->termios->c_lflag;
 248         tmp_termio.c_line = tty->termios->c_line;
 249         for(i=0 ; i < NCC ; i++)
 250                 tmp_termio.c_cc[i] = tty->termios->c_cc[i];
 251         memcpy_tofs(termio, &tmp_termio, sizeof (struct termio));
 252         return 0;
 253 }
 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         struct termio tmp_termio;
 259         struct termios tmp_termios;
 260 
 261         tmp_termios = *tty->termios;
 262         memcpy_fromfs(&tmp_termio, termio, sizeof (struct termio));
 263 
 264 #define SET_LOW_BITS(x,y)       ((x) = (0xffff0000 & (x)) | (y))
 265 
 266         SET_LOW_BITS(tmp_termios.c_iflag, tmp_termio.c_iflag);
 267         SET_LOW_BITS(tmp_termios.c_oflag, tmp_termio.c_oflag);
 268         SET_LOW_BITS(tmp_termios.c_cflag, tmp_termio.c_cflag);
 269         SET_LOW_BITS(tmp_termios.c_lflag, tmp_termio.c_lflag);
 270         memcpy(&tmp_termios.c_cc, &tmp_termio.c_cc, NCC);
 271 
 272 #undef SET_LOW_BITS
 273 
 274         return set_termios_2(tty, &tmp_termios);
 275 }
 276 
 277 static int set_window_size(struct tty_struct * tty, struct winsize * ws)
     /* [previous][next][first][last][top][bottom][index][help] */
 278 {
 279         struct winsize tmp_ws;
 280 
 281         memcpy_fromfs(&tmp_ws, ws, sizeof (struct winsize));
 282         if (memcmp(&tmp_ws, &tty->winsize, sizeof (struct winsize)) &&
 283             tty->pgrp > 0)
 284                 kill_pg(tty->pgrp, SIGWINCH, 1);
 285         tty->winsize = tmp_ws;
 286         return 0;
 287 }
 288 
 289 /* Set the discipline of a tty line. */
 290 static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
     /* [previous][next][first][last][top][bottom][index][help] */
 291 {
 292         if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS) ||
 293             !(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED))
 294                 return -EINVAL;
 295 
 296         if (tty->disc == ldisc)
 297                 return 0;       /* We are already in the desired discipline */
 298 
 299         /* Shutdown the current discipline. */
 300         wait_until_sent(tty);
 301         flush_input(tty);
 302         if (ldiscs[tty->disc].close)
 303                 ldiscs[tty->disc].close(tty);
 304 
 305         /* Now set up the new line discipline. */
 306         tty->disc = ldisc;
 307         tty->termios->c_line = ldisc;
 308         if (ldiscs[tty->disc].open)
 309                 return(ldiscs[tty->disc].open(tty));
 310         else
 311                 return 0;
 312 }
 313 
 314 static unsigned long inq_canon(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 315 {
 316         int nr, head, tail;
 317 
 318         if (!tty->canon_data)
 319                 return 0;
 320         head = tty->canon_head;
 321         tail = tty->secondary.tail;
 322         nr = (head - tail) & (TTY_BUF_SIZE-1);
 323         /* Skip EOF-chars.. */
 324         while (head != tail) {
 325                 if (test_bit(tail, &tty->secondary_flags) &&
 326                     tty->secondary.buf[tail] == __DISABLED_CHAR)
 327                         nr--;
 328                 INC(tail);
 329         }
 330         return nr;
 331 }
 332 
 333 int tty_ioctl(struct inode * inode, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
 334         unsigned int cmd, unsigned long arg)
 335 {
 336         struct tty_struct * tty;
 337         struct tty_struct * other_tty;
 338         struct tty_struct * termios_tty;
 339         pid_t pgrp;
 340         int dev;
 341         int termios_dev;
 342         int retval;
 343 
 344         if (MAJOR(file->f_rdev) != TTY_MAJOR) {
 345                 printk("tty_ioctl: tty pseudo-major != TTY_MAJOR\n");
 346                 return -EINVAL;
 347         }
 348         dev = MINOR(file->f_rdev);
 349         tty = TTY_TABLE(dev);
 350         if (!tty)
 351                 return -EINVAL;
 352         if (IS_A_PTY(dev))
 353                 other_tty = tty_table[PTY_OTHER(dev)];
 354         else
 355                 other_tty = NULL;
 356         if (IS_A_PTY_MASTER(dev)) {
 357                 termios_tty = other_tty;
 358                 termios_dev = PTY_OTHER(dev);
 359         } else {
 360                 termios_tty = tty;
 361                 termios_dev = dev;
 362         }
 363         switch (cmd) {
 364                 case TCGETS:
 365                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 366                                              sizeof (struct termios));
 367                         if (retval)
 368                                 return retval;
 369                         memcpy_tofs((struct termios *) arg,
 370                                     termios_tty->termios,
 371                                     sizeof (struct termios));
 372                         return 0;
 373                 case TCSETSF:
 374                 case TCSETSW:
 375                 case TCSETS:
 376                         retval = check_change(termios_tty, termios_dev);
 377                         if (retval)
 378                                 return retval;
 379                         if (cmd == TCSETSF || cmd == TCSETSW) {
 380                                 if (cmd == TCSETSF)
 381                                         flush_input(termios_tty);
 382                                 wait_until_sent(termios_tty);
 383                         }
 384                         return set_termios(termios_tty, (struct termios *) arg,
 385                                            termios_dev);
 386                 case TCGETA:
 387                         return get_termio(termios_tty,(struct termio *) arg);
 388                 case TCSETAF:
 389                 case TCSETAW:
 390                 case TCSETA:
 391                         retval = check_change(termios_tty, termios_dev);
 392                         if (retval)
 393                                 return retval;
 394                         if (cmd == TCSETAF || cmd == TCSETAW) {
 395                                 if (cmd == TCSETAF)
 396                                         flush_input(termios_tty);
 397                                 wait_until_sent(termios_tty);
 398                         }
 399                         return set_termio(termios_tty, (struct termio *) arg,
 400                                           termios_dev);
 401                 case TCXONC:
 402                         retval = check_change(tty, dev);
 403                         if (retval)
 404                                 return retval;
 405                         switch (arg) {
 406                         case TCOOFF:
 407                                 stop_tty(tty);
 408                                 break;
 409                         case TCOON:
 410                                 start_tty(tty);
 411                                 break;
 412                         case TCIOFF:
 413                                 if (STOP_CHAR(tty) != __DISABLED_CHAR)
 414                                         put_tty_queue(STOP_CHAR(tty),
 415                                                       &tty->write_q);
 416                                 break;
 417                         case TCION:
 418                                 if (START_CHAR(tty) != __DISABLED_CHAR)
 419                                         put_tty_queue(START_CHAR(tty),
 420                                                       &tty->write_q);
 421                                 break;
 422                         default:
 423                                 return -EINVAL;
 424                         }
 425                         return 0;
 426                 case TCFLSH:
 427                         retval = check_change(tty, dev);
 428                         if (retval)
 429                                 return retval;
 430                         switch (arg) {
 431                         case TCIFLUSH:
 432                                 flush_input(tty);
 433                                 break;
 434                         case TCIOFLUSH:
 435                                 flush_input(tty);
 436                                 /* fall through */
 437                         case TCOFLUSH:
 438                                 flush_output(tty);
 439                                 break;
 440                         default:
 441                                 return -EINVAL;
 442                         }
 443                         return 0;
 444                 case TIOCEXCL:
 445                         set_bit(TTY_EXCLUSIVE, &tty->flags);
 446                         return 0;
 447                 case TIOCNXCL:
 448                         clear_bit(TTY_EXCLUSIVE, &tty->flags);
 449                         return 0;
 450                 case TIOCSCTTY:
 451                         if (current->leader &&
 452                             (current->session == tty->session))
 453                                 return 0;
 454                         /*
 455                          * The process must be a session leader and
 456                          * not have a controlling tty already.
 457                          */
 458                         if (!current->leader || (current->tty >= 0))
 459                                 return -EPERM;
 460                         if (tty->session > 0) {
 461                                 /*
 462                                  * This tty is already the controlling
 463                                  * tty for another session group!
 464                                  */
 465                                 if ((arg == 1) && suser()) {
 466                                         /*
 467                                          * Steal it away
 468                                          */
 469                                         struct task_struct *p;
 470 
 471                                         for_each_task(p)
 472                                                 if (p->tty == dev)
 473                                                         p->tty = -1;
 474                                 } else
 475                                         return -EPERM;
 476                         }
 477                         current->tty = dev;
 478                         tty->session = current->session;
 479                         tty->pgrp = current->pgrp;
 480                         return 0;
 481                 case TIOCGPGRP:
 482                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 483                                              sizeof (pid_t));
 484                         if (retval)
 485                                 return retval;
 486                         put_fs_long(termios_tty->pgrp, (pid_t *) arg);
 487                         return 0;
 488                 case TIOCSPGRP:
 489                         retval = check_change(termios_tty, termios_dev);
 490                         if (retval)
 491                                 return retval;
 492                         if ((current->tty < 0) ||
 493                             (current->tty != termios_dev) ||
 494                             (termios_tty->session != current->session))
 495                                 return -ENOTTY;
 496                         pgrp = get_fs_long((pid_t *) arg);
 497                         if (pgrp < 0)
 498                                 return -EINVAL;
 499                         if (session_of_pgrp(pgrp) != current->session)
 500                                 return -EPERM;
 501                         termios_tty->pgrp = pgrp;
 502                         return 0;
 503                 case TIOCOUTQ:
 504                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 505                                              sizeof (unsigned long));
 506                         if (retval)
 507                                 return retval;
 508                         put_fs_long(CHARS(&tty->write_q),
 509                                     (unsigned long *) arg);
 510                         return 0;
 511                 case TIOCINQ:
 512                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 513                                              sizeof (unsigned long));
 514                         if (retval)
 515                                 return retval;
 516                         if (L_ICANON(tty))
 517                                 put_fs_long(inq_canon(tty),
 518                                         (unsigned long *) arg);
 519                         else
 520                                 put_fs_long(CHARS(&tty->secondary),
 521                                         (unsigned long *) arg);
 522                         return 0;
 523                 case TIOCSTI:
 524                         if ((current->tty != dev) && !suser())
 525                                 return -EACCES;
 526                         retval = verify_area(VERIFY_READ, (void *) arg, 1);
 527                         if (retval)
 528                                 return retval;
 529                         put_tty_queue(get_fs_byte((char *) arg), &tty->read_q);
 530                         TTY_READ_FLUSH(tty);
 531                         return 0;
 532                 case TIOCGWINSZ:
 533                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 534                                              sizeof (struct winsize));
 535                         if (retval)
 536                                 return retval;
 537                         memcpy_tofs((struct winsize *) arg, &tty->winsize,
 538                                     sizeof (struct winsize));
 539                         return 0;
 540                 case TIOCSWINSZ:
 541                         if (IS_A_PTY_MASTER(dev))
 542                                 set_window_size(other_tty,(struct winsize *) arg);
 543                         return set_window_size(tty,(struct winsize *) arg);
 544                 case TIOCLINUX:
 545                         switch (get_fs_byte((char *)arg))
 546                         {
 547                                 case 0: 
 548                                         return do_screendump(arg);
 549                                 case 1: 
 550                                         return do_get_ps_info(arg);
 551 #ifdef CONFIG_SELECTION
 552                                 case 2:
 553                                         return set_selection(arg);
 554                                 case 3:
 555                                         return paste_selection(tty);
 556                                 case 4:
 557                                         unblank_screen();
 558                                         return 0;
 559 #endif /* CONFIG_SELECTION */
 560                                 default: 
 561                                         return -EINVAL;
 562                         }
 563                 case TIOCCONS:
 564                         if (IS_A_CONSOLE(dev)) {
 565                                 if (!suser())
 566                                         return -EPERM;
 567                                 redirect = NULL;
 568                                 return 0;
 569                         }
 570                         if (redirect)
 571                                 return -EBUSY;
 572                         if (!suser())
 573                                 return -EPERM;
 574                         if (IS_A_PTY_MASTER(dev))
 575                                 redirect = other_tty;
 576                         else if (IS_A_PTY_SLAVE(dev))
 577                                 redirect = tty;
 578                         else
 579                                 return -EINVAL;
 580                         return 0;
 581                 case FIONBIO:
 582                         arg = get_fs_long((unsigned long *) arg);
 583                         if (arg)
 584                                 file->f_flags |= O_NONBLOCK;
 585                         else
 586                                 file->f_flags &= ~O_NONBLOCK;
 587                         return 0;
 588                 case TIOCNOTTY:
 589                         if (MINOR(file->f_rdev) != current->tty)
 590                                 return -EINVAL;
 591                         if (current->leader)
 592                                 disassociate_ctty(0);
 593                         current->tty = -1;
 594                         return 0;
 595                 case TIOCGETD:
 596                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 597                                              sizeof (unsigned long));
 598                         if (retval)
 599                                 return retval;
 600                         put_fs_long(tty->disc, (unsigned long *) arg);
 601                         return 0;
 602                 case TIOCSETD:
 603                         retval = check_change(tty, dev);
 604                         if (retval)
 605                                 return retval;
 606                         arg = get_fs_long((unsigned long *) arg);
 607                         return tty_set_ldisc(tty, arg);
 608                 case TIOCGLCKTRMIOS:
 609                         arg = get_fs_long((unsigned long *) arg);
 610                         retval = verify_area(VERIFY_WRITE, (void *) arg,
 611                                              sizeof (struct termios));
 612                         if (retval)
 613                                 return retval;
 614                         memcpy_tofs((struct termios *) arg,
 615                                     &termios_locked[termios_dev],
 616                                     sizeof (struct termios));
 617                         return 0;
 618                 case TIOCSLCKTRMIOS:
 619                         if (!suser())
 620                                 return -EPERM;
 621                         arg = get_fs_long((unsigned long *) arg);
 622                         memcpy_fromfs(&termios_locked[termios_dev],
 623                                       (struct termios *) arg,
 624                                       sizeof (struct termios));
 625                         return 0;
 626                 case TIOCPKT:
 627                         if (!IS_A_PTY_MASTER(dev))
 628                                 return -EINVAL;
 629                         retval = verify_area(VERIFY_READ, (void *) arg,
 630                                              sizeof (unsigned long));
 631                         if (retval)
 632                                 return retval;
 633                         if (get_fs_long(arg)) {
 634                                 if (!tty->packet) {
 635                                         tty->packet = 1;
 636                                         tty->ctrl_status = 0;
 637                                 }
 638                         } else
 639                                 tty->packet = 0;
 640                         return 0;
 641                 case TCSBRK: case TCSBRKP:
 642                         retval = check_change(tty, dev);
 643                         if (retval)
 644                                 return retval;
 645                         wait_until_sent(tty);
 646                         if (!tty->ioctl)
 647                                 return 0;
 648                         tty->ioctl(tty, file, cmd, arg);
 649                         return 0;
 650                 default:
 651                         if (tty->ioctl) {
 652                                 retval = (tty->ioctl)(tty, file, cmd, arg);
 653                                 if (retval != -EINVAL)
 654                                         return retval;
 655                         }
 656                         if (ldiscs[tty->disc].ioctl) {
 657                                 retval = (ldiscs[tty->disc].ioctl)
 658                                         (tty, file, cmd, arg);
 659                                 return retval;
 660                         }
 661                         return -EINVAL;
 662         }
 663 }

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