root/drivers/char/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. inq_canon
  18. 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 
  21 #include <asm/io.h>
  22 #include <asm/bitops.h>
  23 #include <asm/segment.h>
  24 #include <asm/system.h>
  25 
  26 #undef  DEBUG
  27 #ifdef DEBUG
  28 # define        PRINTK(x)       printk (x)
  29 #else
  30 # define        PRINTK(x)       /**/
  31 #endif
  32 
  33 extern int session_of_pgrp(int pgrp);
  34 extern int do_screendump(int arg);
  35 extern int kill_pg(int pgrp, int sig, int priv);
  36 
  37 #ifdef CONFIG_SELECTION
  38 extern int set_selection(const int arg);
  39 extern int paste_selection(struct tty_struct *tty);
  40 #endif /* CONFIG_SELECTION */
  41 
  42 static int tty_set_ldisc(struct tty_struct *tty, int ldisc);
  43 
  44 static void flush(struct tty_queue * queue)
     /* [previous][next][first][last][top][bottom][index][help] */
  45 {
  46         if (queue) {
  47                 cli();
  48                 queue->head = queue->tail;
  49                 sti();
  50                 wake_up_interruptible(&queue->proc_list);
  51         }
  52 }
  53 
  54 void flush_input(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
  55 {
  56         tty->ctrl_status |= TIOCPKT_FLUSHREAD;
  57         if (tty->link)
  58                 wake_up_interruptible(&tty->link->except_q);
  59         flush(&tty->read_q);
  60         wake_up_interruptible(&tty->read_q.proc_list);
  61         flush(&tty->secondary);
  62         tty->secondary.data = 0;
  63 
  64         if ((tty = tty->link) != NULL) {
  65                 flush(&tty->write_q);
  66                 wake_up_interruptible(&tty->write_q.proc_list);
  67         }
  68 }
  69 
  70 void flush_output(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
  71 {
  72         tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
  73         if (tty->link)
  74                 wake_up_interruptible(&tty->link->except_q);
  75         flush(&tty->write_q);
  76         wake_up_interruptible(&tty->write_q.proc_list);
  77         if ((tty = tty->link) != NULL) {
  78                 flush(&tty->read_q);
  79                 wake_up_interruptible(&tty->read_q.proc_list);
  80                 flush(&tty->secondary);
  81                 tty->secondary.data = 0;
  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 static int get_termios(struct tty_struct * tty, struct termios * termios)
     /* [previous][next][first][last][top][bottom][index][help] */
 160 {
 161         int i;
 162 
 163         i = verify_area(VERIFY_WRITE, termios, sizeof (*termios));
 164         if (i)
 165                 return i;
 166         for (i=0 ; i< (sizeof (*termios)) ; i++)
 167                 put_fs_byte( ((char *)tty->termios)[i] , i+(char *)termios );
 168         return 0;
 169 }
 170 
 171 static int check_change(struct tty_struct * tty, int channel)
     /* [previous][next][first][last][top][bottom][index][help] */
 172 {
 173         /* If we try to set the state of terminal and we're not in the
 174            foreground, send a SIGTTOU.  If the signal is blocked or
 175            ignored, go ahead and perform the operation.  POSIX 7.2) */
 176         if (current->tty != channel)
 177                 return 0;
 178         if (tty->pgrp <= 0 || tty->pgrp == current->pgrp)
 179                 return 0;
 180         if (is_orphaned_pgrp(current->pgrp))
 181                 return -EIO;
 182         if (is_ignored(SIGTTOU))
 183                 return 0;
 184         (void) kill_pg(current->pgrp,SIGTTOU,1);
 185         return -ERESTARTSYS;
 186 }
 187 
 188 static int set_termios(struct tty_struct * tty, struct termios * termios,
     /* [previous][next][first][last][top][bottom][index][help] */
 189                         int channel)
 190 {
 191         int i, old_flow, new_flow;
 192         struct termios old_termios = *tty->termios;
 193 
 194         i = check_change(tty, channel);
 195         if (i)
 196                 return i;
 197         for (i=0 ; i< (sizeof (*termios)) ; i++)
 198                 ((char *)tty->termios)[i]=get_fs_byte(i+(char *)termios);
 199 
 200         /* see if packet mode change of state */
 201 
 202         old_flow = (old_termios.c_iflag & IXON) &&
 203               (old_termios.c_cc[VSTOP] == '\023') &&
 204               (old_termios.c_cc[VSTART] == '\021');
 205 
 206         new_flow = (tty->termios->c_iflag & IXON) &&
 207               (tty->termios->c_cc[VSTOP] == '\023') &&
 208               (tty->termios->c_cc[VSTART] == '\021');
 209 
 210         if (old_flow != new_flow) {
 211                 tty->ctrl_status &= ~(TIOCPKT_DOSTOP|TIOCPKT_NOSTOP);
 212                 if (new_flow)
 213                         tty->ctrl_status |= TIOCPKT_DOSTOP;
 214                 else
 215                         tty->ctrl_status |= TIOCPKT_NOSTOP;             
 216                 if (tty->link)
 217                         wake_up_interruptible(&tty->link->except_q);
 218         }
 219 
 220 #if 0
 221         /* puting mpty's into echo mode is very bad, and I think under
 222            some situations can cause the kernel to do nothing but
 223            copy characters back and forth. -RAB */
 224         /* This can no longer happen because a set_termios is redirected
 225            to the pty slave.  -- jrs */
 226         if (IS_A_PTY_MASTER(channel)) tty->termios->c_lflag &= ~ECHO;
 227 #endif
 228 
 229         unset_locked_termios(tty->termios, &old_termios,
 230                              termios_locked[tty->line]);
 231 
 232 #if 0
 233         retval = tty_set_ldisc(tty, tty->termios->c_line);
 234         if (retval)
 235                 return retval;
 236 #endif
 237 
 238         if (tty->set_termios)
 239                 (*tty->set_termios)(tty, &old_termios);
 240 
 241         return 0;
 242 }
 243 
 244 static int get_termio(struct tty_struct * tty, struct termio * termio)
     /* [previous][next][first][last][top][bottom][index][help] */
 245 {
 246         int i;
 247         struct termio tmp_termio;
 248 
 249         i = verify_area(VERIFY_WRITE, termio, sizeof (*termio));
 250         if (i)
 251                 return i;
 252         tmp_termio.c_iflag = tty->termios->c_iflag;
 253         tmp_termio.c_oflag = tty->termios->c_oflag;
 254         tmp_termio.c_cflag = tty->termios->c_cflag;
 255         tmp_termio.c_lflag = tty->termios->c_lflag;
 256         tmp_termio.c_line = tty->termios->c_line;
 257         for(i=0 ; i < NCC ; i++)
 258                 tmp_termio.c_cc[i] = tty->termios->c_cc[i];
 259         for (i=0 ; i< (sizeof (*termio)) ; i++)
 260                 put_fs_byte( ((char *)&tmp_termio)[i] , i+(char *)termio );
 261         return 0;
 262 }
 263 
 264 static int set_termio(struct tty_struct * tty, struct termio * termio,
     /* [previous][next][first][last][top][bottom][index][help] */
 265                         int channel)
 266 {
 267         int i, old_flow, new_flow;
 268         struct termio tmp_termio;
 269         struct termios old_termios = *tty->termios;
 270 
 271 #define SET_LOW_BITS(x,y)       ((x) = (0xffff0000 & (x)) | (y))
 272 
 273         i = check_change(tty, channel);
 274         if (i)
 275                 return i;
 276         memcpy_fromfs(&tmp_termio, termio, sizeof(*termio));
 277 
 278         SET_LOW_BITS(tty->termios->c_iflag, tmp_termio.c_iflag);
 279         SET_LOW_BITS(tty->termios->c_oflag, tmp_termio.c_oflag);
 280         SET_LOW_BITS(tty->termios->c_cflag, tmp_termio.c_cflag);
 281         SET_LOW_BITS(tty->termios->c_lflag, tmp_termio.c_lflag);
 282         memcpy(tty->termios->c_cc, tmp_termio.c_cc, NCC);
 283 
 284         /* see if packet mode change of state */
 285 
 286         old_flow = (old_termios.c_iflag & IXON) &&
 287               (old_termios.c_cc[VSTOP] == '\023') &&
 288               (old_termios.c_cc[VSTART] == '\021');
 289 
 290         new_flow = (tty->termios->c_iflag & IXON) &&
 291               (tty->termios->c_cc[VSTOP] == '\023') &&
 292               (tty->termios->c_cc[VSTART] == '\021');
 293 
 294         if (old_flow != new_flow) {
 295                 tty->ctrl_status &= ~(TIOCPKT_DOSTOP|TIOCPKT_NOSTOP);
 296                 if (new_flow)
 297                         tty->ctrl_status |= TIOCPKT_DOSTOP;
 298                 else
 299                         tty->ctrl_status |= TIOCPKT_NOSTOP;             
 300                 if (tty->link)
 301                         wake_up_interruptible(&tty->link->except_q);
 302         }
 303 
 304         unset_locked_termios(tty->termios, &old_termios,
 305                              termios_locked[tty->line]);
 306 
 307 #if 0
 308         retval = tty_set_ldisc(tty, tmp_termio.c_line);
 309         if (retval)
 310                 return retval;
 311 #endif
 312 
 313         if (tty->set_termios)
 314                 (*tty->set_termios)(tty, &old_termios);
 315 
 316         return 0;
 317 }
 318 
 319 static int get_lcktrmios(struct tty_struct * tty, struct termios * termios,
     /* [previous][next][first][last][top][bottom][index][help] */
 320                          int channel)
 321 {
 322         int i;
 323 
 324         i = verify_area(VERIFY_WRITE, termios, sizeof (*termios));
 325         if (i)
 326                 return i;
 327         for (i=0 ; i< (sizeof (*termios)) ; i++)
 328                 put_fs_byte( ((char *)termios_locked[channel])[i],
 329                             i+(char *)termios);
 330         return 0;
 331 }
 332 
 333 static int set_lcktrmios(struct tty_struct * tty, struct termios * termios,
     /* [previous][next][first][last][top][bottom][index][help] */
 334                          int channel)
 335 {
 336         int i;
 337 
 338         if (!suser())
 339                 return -EPERM;
 340         for (i=0 ; i< (sizeof (*termios)) ; i++)
 341                 ((char *)termios_locked[channel])[i] =
 342                         get_fs_byte(i+(char *)termios);
 343 
 344         return 0;
 345 }
 346 
 347 static int set_window_size(struct tty_struct * tty, struct winsize * ws)
     /* [previous][next][first][last][top][bottom][index][help] */
 348 {
 349         int i,changed;
 350         char c, * tmp;
 351 
 352         if (!ws)
 353                 return -EINVAL;
 354         tmp = (char *) &tty->winsize;
 355         changed = 0;
 356         for (i = 0; i < sizeof (*ws) ; i++,tmp++) {
 357                 c = get_fs_byte(i + (char *) ws);
 358                 if (c == *tmp)
 359                         continue;
 360                 changed = 1;
 361                 *tmp = c;
 362         }
 363         if (changed)
 364                 kill_pg(tty->pgrp, SIGWINCH, 1);
 365         return 0;
 366 }
 367 
 368 static int get_window_size(struct tty_struct * tty, struct winsize * ws)
     /* [previous][next][first][last][top][bottom][index][help] */
 369 {
 370         int i;
 371         char * tmp;
 372 
 373         if (!ws)
 374                 return -EINVAL;
 375         i = verify_area(VERIFY_WRITE, ws, sizeof (*ws));
 376         if (i)
 377                 return i;
 378         tmp = (char *) ws;
 379         for (i = 0; i < sizeof (struct winsize) ; i++,tmp++)
 380                 put_fs_byte(((char *) &tty->winsize)[i], tmp);
 381         return 0;
 382 }
 383 
 384 /* Set the discipline of a tty line. */
 385 static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
     /* [previous][next][first][last][top][bottom][index][help] */
 386 {
 387         if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS) ||
 388             !(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED))
 389                 return -EINVAL;
 390 
 391         if (tty->disc == ldisc)
 392                 return 0;       /* We are already in the desired discipline */
 393 
 394         /* Shutdown the current discipline. */
 395         wait_until_sent(tty);
 396         flush_input(tty);
 397         if (ldiscs[tty->disc].close)
 398                 ldiscs[tty->disc].close(tty);
 399 
 400         /* Now set up the new line discipline. */
 401         tty->disc = ldisc;
 402         tty->termios->c_line = ldisc;
 403         if (ldiscs[tty->disc].open)
 404                 return(ldiscs[tty->disc].open(tty));
 405         else
 406                 return 0;
 407 }
 408 
 409 static int inq_canon(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 410 {
 411         int nr, head, tail;
 412 
 413         if (!tty->secondary.data)
 414                 return 0;
 415         head = tty->secondary.head;
 416         tail = tty->secondary.tail;
 417         nr = (head - tail) & (TTY_BUF_SIZE-1);
 418         /* Skip EOF-chars.. */
 419         if (EOF_CHAR(tty) == __DISABLED_CHAR)
 420                 return nr;
 421         while (head != tail) {
 422                 if (tty->secondary.buf[tail] == EOF_CHAR(tty))
 423                         nr--;
 424                 INC(tail);
 425         }
 426         return nr;
 427 }
 428 
 429 int tty_ioctl(struct inode * inode, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
 430         unsigned int cmd, unsigned long arg)
 431 {
 432         struct tty_struct * tty;
 433         struct tty_struct * other_tty;
 434         struct tty_struct * termios_tty;
 435         int pgrp;
 436         int dev;
 437         int termios_dev;
 438         int retval;
 439 
 440         if (MAJOR(file->f_rdev) != TTY_MAJOR) {
 441                 printk("tty_ioctl: tty pseudo-major != TTY_MAJOR\n");
 442                 return -EINVAL;
 443         }
 444         dev = MINOR(file->f_rdev);
 445         tty = TTY_TABLE(dev);
 446         if (!tty)
 447                 return -EINVAL;
 448         if (IS_A_PTY(dev))
 449                 other_tty = tty_table[PTY_OTHER(dev)];
 450         else
 451                 other_tty = NULL;
 452         termios_tty = tty;
 453         termios_dev = dev;
 454         if (IS_A_PTY_MASTER(dev)) {
 455                 termios_tty = other_tty;
 456                 termios_dev = PTY_OTHER(dev);
 457         }
 458         switch (cmd) {
 459                 case TCGETS:
 460                         return get_termios(termios_tty,(struct termios *) arg);
 461                 case TCSETSF:
 462                         flush_input(tty);
 463                 /* fallthrough */
 464                 case TCSETSW:
 465                         wait_until_sent(tty);
 466                 /* fallthrough */
 467                 case TCSETS:
 468                         return set_termios(termios_tty,(struct termios *) arg, termios_dev);
 469                 case TCGETA:
 470                         return get_termio(termios_tty,(struct termio *) arg);
 471                 case TCSETAF:
 472                         flush_input(tty);
 473                 /* fallthrough */
 474                 case TCSETAW:
 475                         wait_until_sent(tty); /* fallthrough */
 476                 case TCSETA:
 477                         return set_termio(termios_tty,(struct termio *) arg, termios_dev);
 478                 case TCXONC:
 479                         switch (arg) {
 480                         case TCOOFF:
 481                                 tty->stopped = 1;
 482                                 if (tty->stop)
 483                                         (tty->stop)(tty);
 484                                 TTY_WRITE_FLUSH(tty);
 485                                 return 0;
 486                         case TCOON:
 487                                 tty->stopped = 0;
 488                                 if (tty->start)
 489                                         (tty->start)(tty);
 490                                 TTY_WRITE_FLUSH(tty);
 491                                 return 0;
 492                         case TCIOFF:
 493                                 if (STOP_CHAR(tty))
 494                                         put_tty_queue(STOP_CHAR(tty),
 495                                                       &tty->write_q);
 496                                 return 0;
 497                         case TCION:
 498                                 if (START_CHAR(tty))
 499                                         put_tty_queue(START_CHAR(tty),
 500                                                       &tty->write_q);
 501                                 return 0;
 502                         }
 503                         return -EINVAL; /* not implemented */
 504                 case TCFLSH:
 505                         if (arg==0)
 506                                 flush_input(tty);
 507                         else if (arg==1)
 508                                 flush_output(tty);
 509                         else if (arg==2) {
 510                                 flush_input(tty);
 511                                 flush_output(tty);
 512                         } else
 513                                 return -EINVAL;
 514                         return 0;
 515                 case TIOCEXCL:
 516                         set_bit(TTY_EXCLUSIVE, &tty->flags);
 517                         return 0;
 518                 case TIOCNXCL:
 519                         clear_bit(TTY_EXCLUSIVE, &tty->flags);
 520                         return 0;
 521                 case TIOCSCTTY:
 522                         if (current->leader &&
 523                             (current->session == tty->session))
 524                                 return 0;
 525                         /*
 526                          * The process must be a session leader and
 527                          * not have a controlling tty already.
 528                          */
 529                         if (!current->leader || (current->tty >= 0))
 530                                 return -EPERM;
 531                         if (tty->session > 0) {
 532                                 /*
 533                                  * This tty is already the controlling
 534                                  * tty for another session group!
 535                                  */
 536                                 if ((arg == 1) && suser()) {
 537                                         /*
 538                                          * Steal it away
 539                                          */
 540                                         struct task_struct *p;
 541 
 542                                         for_each_task(p)
 543                                                 if (p->tty == dev)
 544                                                         p->tty = -1;
 545                                 } else
 546                                         return -EPERM;
 547                         }
 548                         current->tty = dev;
 549                         tty->session = current->session;
 550                         tty->pgrp = current->pgrp;
 551                         return 0;
 552                 case TIOCGPGRP:
 553                         retval = verify_area(VERIFY_WRITE, (void *) arg,4);
 554                         if (!retval)
 555                                 put_fs_long(termios_tty->pgrp,(unsigned long *) arg);
 556                         return retval;
 557                 case TIOCSPGRP:
 558                         if ((current->tty < 0) ||
 559                             (current->tty != termios_dev) ||
 560                             (termios_tty->session != current->session))
 561                                 return -ENOTTY;
 562                         pgrp=get_fs_long((unsigned long *) arg);
 563                         if (pgrp < 0)
 564                                 return -EINVAL;
 565                         if (session_of_pgrp(pgrp) != current->session)
 566                                 return -EPERM;
 567                         termios_tty->pgrp = pgrp;                       
 568                         return 0;
 569                 case TIOCOUTQ:
 570                         retval = verify_area(VERIFY_WRITE, (void *) arg,4);
 571                         if (!retval)
 572                                 put_fs_long(CHARS(&tty->write_q),
 573                                     (unsigned long *) arg);
 574                         return retval;
 575                 case TIOCINQ:
 576                         retval = verify_area(VERIFY_WRITE, (void *) arg,4);
 577                         if (retval)
 578                                 return retval;
 579                         if (L_CANON(tty))
 580                                 put_fs_long(inq_canon(tty),
 581                                         (unsigned long *) arg);
 582                         else
 583                                 put_fs_long(CHARS(&tty->secondary),
 584                                         (unsigned long *) arg);
 585                         return 0;
 586                 case TIOCSTI:
 587                         put_tty_queue(get_fs_byte((char *) arg), &tty->read_q);
 588                         return 0;
 589                 case TIOCGWINSZ:
 590                         return get_window_size(tty,(struct winsize *) arg);
 591                 case TIOCSWINSZ:
 592                         if (IS_A_PTY_MASTER(dev))
 593                                 set_window_size(other_tty,(struct winsize *) arg);
 594                         return set_window_size(tty,(struct winsize *) arg);
 595                 case TIOCGSOFTCAR:
 596                         return -EINVAL; /* not implemented */
 597                 case TIOCSSOFTCAR:
 598                         return -EINVAL; /* not implemented */
 599                 case TIOCLINUX:
 600                         switch (get_fs_byte((char *)arg))
 601                         {
 602                                 case 0: 
 603                                         return do_screendump(arg);
 604                                 case 1: 
 605                                         return do_get_ps_info(arg);
 606 #ifdef CONFIG_SELECTION
 607                                 case 2:
 608                                         return set_selection(arg);
 609                                 case 3:
 610                                         return paste_selection(tty);
 611 #endif /* CONFIG_SELECTION */
 612                                 default: 
 613                                         return -EINVAL;
 614                         }
 615                 case TIOCCONS:
 616                         if (IS_A_CONSOLE(dev)) {
 617                                 if (!suser())
 618                                         return -EPERM;
 619                                 redirect = NULL;
 620                                 return 0;
 621                         }
 622                         if (redirect)
 623                                 return -EBUSY;
 624                         if (!suser())
 625                                 return -EPERM;
 626                         if (IS_A_PTY_MASTER(dev))
 627                                 redirect = other_tty;
 628                         else if (IS_A_PTY_SLAVE(dev))
 629                                 redirect = tty;
 630                         else
 631                                 return -EINVAL;
 632                         return 0;
 633                 case FIONBIO:
 634                         arg = get_fs_long((unsigned long *) arg);
 635                         if (arg)
 636                                 file->f_flags |= O_NONBLOCK;
 637                         else
 638                                 file->f_flags &= ~O_NONBLOCK;
 639                         return 0;
 640                 case TIOCNOTTY:
 641                         if (MINOR(file->f_rdev) != current->tty)
 642                                 return -EINVAL;
 643                         if (current->leader)
 644                                 disassociate_ctty(0);
 645                         current->tty = -1;
 646                         return 0;
 647                 case TIOCGETD:
 648                         retval = verify_area(VERIFY_WRITE, (void *) arg,4);
 649                         if (!retval)
 650                                 put_fs_long(tty->disc, (unsigned long *) arg);
 651                         return retval;
 652                 case TIOCSETD:
 653                         arg = get_fs_long((unsigned long *) arg);
 654                         return tty_set_ldisc(tty, arg);
 655                 case TIOCGLCKTRMIOS:
 656                         arg = get_fs_long((unsigned long *) arg);
 657                         return get_lcktrmios(tty, (struct termios *) arg,
 658                                              termios_dev);
 659                 case TIOCSLCKTRMIOS:
 660                         arg = get_fs_long((unsigned long *) arg);
 661                         return set_lcktrmios(tty, (struct termios *) arg,
 662                                              termios_dev);
 663                 case TIOCPKT:
 664                         if (!IS_A_PTY_MASTER(dev))
 665                                 return -EINVAL;
 666                         retval = verify_area(VERIFY_READ,
 667                                 (unsigned long *)arg, sizeof (unsigned long));
 668                         if (retval)
 669                                 return retval;
 670                         tty->packet = (get_fs_long ((unsigned long *)arg) != 0);
 671                         return 0;
 672                 case TCSBRK: case TCSBRKP:
 673                         wait_until_sent(tty);
 674                         if (!tty->ioctl)
 675                                 return 0;
 676                         tty->ioctl(tty, file, cmd, arg);
 677                         return 0;
 678                 default:
 679                         if (tty->ioctl) {
 680                                 retval = (tty->ioctl)(tty, file, cmd, arg);
 681                                 if (retval != -EINVAL)
 682                                         return retval;
 683                         }
 684                         if (ldiscs[tty->disc].ioctl) {
 685                                 retval = (ldiscs[tty->disc].ioctl)
 686                                         (tty, file, cmd, arg);
 687                                 return retval;
 688                         }
 689                         return -EINVAL;
 690         }
 691 }

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