root/kernel/chr_drv/tty_io.c

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

DEFINITIONS

This source file includes following definitions.
  1. put_tty_queue
  2. get_tty_queue
  3. tty_write_flush
  4. tty_read_flush
  5. change_console
  6. wait_for_keypress
  7. copy_to_cooked
  8. is_ignored
  9. wait_for_canon_input
  10. read_chan
  11. __wait_for_canon_input
  12. available_canon_input
  13. write_chan
  14. tty_read
  15. tty_write
  16. tty_lseek
  17. tty_open
  18. tty_release
  19. tty_select
  20. do_SAK
  21. initialize_tty_struct
  22. reset_tty_termios
  23. tty_init

   1 /*
   2  *  linux/kernel/tty_io.c
   3  *
   4  *  Copyright (C) 1991, 1992  Linus Torvalds
   5  */
   6 
   7 /*
   8  * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles
   9  * or rs-channels. It also implements echoing, cooked mode etc.
  10  *
  11  * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0.
  12  *
  13  * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the
  14  * tty_struct and tty_queue structures.  Previously there was a array
  15  * of 256 tty_struct's which was statically allocated, and the
  16  * tty_queue structures were allocated at boot time.  Both are now
  17  * dynamically allocated only when the tty is open.
  18  *
  19  * Also restructured routines so that there is more of a separation
  20  * between the high-level tty routines (tty_io.c and tty_ioctl.c) and
  21  * the low-level tty routines (serial.c, pty.c, console.c).  This
  22  * makes for cleaner and more compact code.  -TYT, 9/17/92 
  23  */
  24 
  25 #include <linux/types.h>
  26 #include <linux/errno.h>
  27 #include <linux/signal.h>
  28 #include <linux/fcntl.h>
  29 #include <linux/sched.h>
  30 #include <linux/tty.h>
  31 #include <linux/ctype.h>
  32 #include <linux/kd.h>
  33 #include <linux/mm.h>
  34 #include <linux/string.h>
  35 #include <linux/keyboard.h>
  36 
  37 #include <asm/segment.h>
  38 #include <asm/system.h>
  39 #include <asm/bitops.h>
  40 
  41 #include "vt_kern.h"
  42 
  43 struct tty_struct *tty_table[256];
  44 struct termios *tty_termios[256]; /* We need to keep the termios state */
  45                                   /* around, even when a tty is closed */
  46 
  47 /*
  48  * fg_console is the current virtual console,
  49  * redirect is the pseudo-tty that console output
  50  * is redirected to if asked by TIOCCONS.
  51  */
  52 int fg_console = 0;
  53 struct tty_struct * redirect = NULL;
  54 struct wait_queue * keypress_wait = NULL;
  55 
  56 static int initialize_tty_struct(struct tty_struct *tty, int line);
  57 static void reset_tty_termios(int line);
  58 
  59 void put_tty_queue(char c, struct tty_queue * queue)
     /* [previous][next][first][last][top][bottom][index][help] */
  60 {
  61         int head;
  62         unsigned long flags;
  63 
  64         __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
  65         head = (queue->head + 1) & (TTY_BUF_SIZE-1);
  66         if (head != queue->tail) {
  67                 queue->buf[queue->head] = c;
  68                 queue->head = head;
  69         }
  70         __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
  71 }
  72 
  73 int get_tty_queue(struct tty_queue * queue)
     /* [previous][next][first][last][top][bottom][index][help] */
  74 {
  75         int result = -1;
  76         unsigned long flags;
  77 
  78         __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
  79         if (queue->tail != queue->head) {
  80                 result = 0xff & queue->buf[queue->tail];
  81                 queue->tail = (queue->tail + 1) & (TTY_BUF_SIZE-1);
  82         }
  83         __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
  84         return result;
  85 }
  86 
  87 void tty_write_flush(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
  88 {
  89         if (!tty->write || EMPTY(&tty->write_q))
  90                 return;
  91         if (set_bit(TTY_WRITE_BUSY,&tty->flags))
  92                 return;
  93         tty->write(tty);
  94         if (clear_bit(TTY_WRITE_BUSY,&tty->flags))
  95                 printk("tty_write_flush: bit already cleared\n");
  96 }
  97 
  98 void tty_read_flush(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
  99 {
 100         if (!tty || EMPTY(&tty->read_q))
 101                 return;
 102         if (set_bit(TTY_READ_BUSY, &tty->flags))
 103                 return;
 104         copy_to_cooked(tty);
 105         if (clear_bit(TTY_READ_BUSY, &tty->flags))
 106                 printk("tty_read_flush: bit already cleared\n");
 107 }
 108 
 109 void change_console(unsigned int new_console)
     /* [previous][next][first][last][top][bottom][index][help] */
 110 {
 111         if (vt_cons[fg_console].vt_mode == KD_GRAPHICS)
 112                 return;
 113         if (new_console == fg_console || new_console >= NR_CONSOLES)
 114                 return;
 115         update_screen(new_console);
 116 }
 117 
 118 void wait_for_keypress(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 119 {
 120         interruptible_sleep_on(&keypress_wait);
 121 }
 122 
 123 void copy_to_cooked(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 124 {
 125         int c;
 126 
 127         if (!tty) {
 128                 printk("copy_to_cooked: called with NULL tty\n");
 129                 return;
 130         }
 131         if (!tty->write) {
 132                 printk("copy_to_cooked: tty %d has null write routine\n",
 133                        tty->line);
 134         }
 135         while (1) {
 136                 /*
 137                  * Check to see how much room we have left in the
 138                  * secondary queue.  Send a throttle command or abort
 139                  * if necessary.
 140                  */
 141                 c = LEFT(&tty->secondary);
 142                 if (tty->throttle && (c < SQ_THRESHOLD_LW)
 143                     && !set_bit(TTY_SQ_THROTTLED, &tty->flags))
 144                         tty->throttle(tty, TTY_THROTTLE_SQ_FULL);
 145                 if (c == 0)
 146                         break;
 147                 c = get_tty_queue(&tty->read_q);
 148                 if (c < 0)
 149                         break;
 150                 if (I_STRP(tty))
 151                         c &= 0x7f;
 152                 if (c==13) {
 153                         if (I_CRNL(tty))
 154                                 c=10;
 155                         else if (I_NOCR(tty))
 156                                 continue;
 157                 } else if (c==10 && I_NLCR(tty))
 158                         c=13;
 159                 if (I_UCLC(tty))
 160                         c=tolower(c);
 161                 if (L_CANON(tty)) {
 162                         if ((KILL_CHAR(tty) != __DISABLED_CHAR) &&
 163                             (c==KILL_CHAR(tty))) {
 164                                 /* deal with killing the input line */
 165                                 while(!(EMPTY(&tty->secondary) ||
 166                                         (c=LAST(&tty->secondary))==10 ||
 167                                         ((EOF_CHAR(tty) != __DISABLED_CHAR) &&
 168                                          (c==EOF_CHAR(tty))))) {
 169                                         if (L_ECHO(tty)) {
 170                                                 if (c<32) {
 171                                                         put_tty_queue(8, &tty->write_q);
 172                                                         put_tty_queue(' ', &tty->write_q);
 173                                                         put_tty_queue(8,&tty->write_q);
 174                                                 }
 175                                                 put_tty_queue(8,&tty->write_q);
 176                                                 put_tty_queue(' ',&tty->write_q);
 177                                                 put_tty_queue(8,&tty->write_q);
 178                                         }
 179                                         DEC(tty->secondary.head);
 180                                 }
 181                                 continue;
 182                         }
 183                         if ((ERASE_CHAR(tty) != __DISABLED_CHAR) &&
 184                             (c==ERASE_CHAR(tty))) {
 185                                 if (EMPTY(&tty->secondary) ||
 186                                    (c=LAST(&tty->secondary))==10 ||
 187                                    ((EOF_CHAR(tty) != __DISABLED_CHAR) &&
 188                                     (c==EOF_CHAR(tty))))
 189                                         continue;
 190                                 if (L_ECHO(tty)) {
 191                                         if (c<32) {
 192                                                 put_tty_queue(8,&tty->write_q);
 193                                                 put_tty_queue(' ',&tty->write_q);
 194                                                 put_tty_queue(8,&tty->write_q);
 195                                         }
 196                                         put_tty_queue(8,&tty->write_q);
 197                                         put_tty_queue(32,&tty->write_q);
 198                                         put_tty_queue(8,&tty->write_q);
 199                                 }
 200                                 DEC(tty->secondary.head);
 201                                 continue;
 202                         }
 203                 }
 204                 if (I_IXON(tty)) {
 205                         if ((STOP_CHAR(tty) != __DISABLED_CHAR) &&
 206                             (c==STOP_CHAR(tty))) {
 207                                 tty->status_changed = 1;
 208                                 tty->ctrl_status |= TIOCPKT_STOP;
 209                                 tty->stopped=1;
 210                                 continue;
 211                         }
 212                         if (((I_IXANY(tty)) && tty->stopped) ||
 213                             ((START_CHAR(tty) != __DISABLED_CHAR) &&
 214                              (c==START_CHAR(tty)))) {
 215                                 tty->status_changed = 1;
 216                                 tty->ctrl_status |= TIOCPKT_START;
 217                                 tty->stopped=0;
 218                                 continue;
 219                         }
 220                 }
 221                 if (L_ISIG(tty)) {
 222                         if ((INTR_CHAR(tty) != __DISABLED_CHAR) &&
 223                             (c==INTR_CHAR(tty))) {
 224                                 kill_pg(tty->pgrp, SIGINT, 1);
 225                                 flush_input(tty);
 226                                 continue;
 227                         }
 228                         if ((QUIT_CHAR(tty) != __DISABLED_CHAR) &&
 229                             (c==QUIT_CHAR(tty))) {
 230                                 kill_pg(tty->pgrp, SIGQUIT, 1);
 231                                 flush_input(tty);
 232                                 continue;
 233                         }
 234                         if ((SUSPEND_CHAR(tty) != __DISABLED_CHAR) &&
 235                             (c==SUSPEND_CHAR(tty))) {
 236                                 if (!is_orphaned_pgrp(tty->pgrp))
 237                                         kill_pg(tty->pgrp, SIGTSTP, 1);
 238                                 continue;
 239                         }
 240                 }
 241                 if (c==10 || (EOF_CHAR(tty) != __DISABLED_CHAR &&
 242                     c==EOF_CHAR(tty)))
 243                         tty->secondary.data++;
 244                 if ((c==10) && (L_ECHO(tty) || (L_CANON(tty) && L_ECHONL(tty)))) {
 245                         put_tty_queue(10,&tty->write_q);
 246                         put_tty_queue(13,&tty->write_q);
 247                 } else if (L_ECHO(tty)) {
 248                         if (c<32 && L_ECHOCTL(tty)) {
 249                                 put_tty_queue('^',&tty->write_q);
 250                                 put_tty_queue(c+64, &tty->write_q);
 251                         } else
 252                                 put_tty_queue(c, &tty->write_q);
 253                 }
 254                 put_tty_queue(c, &tty->secondary);
 255         }
 256         TTY_WRITE_FLUSH(tty);
 257         if (!EMPTY(&tty->secondary))
 258                 wake_up_interruptible(&tty->secondary.proc_list);
 259         if (tty->write_q.proc_list && LEFT(&tty->write_q) > TTY_BUF_SIZE/2)
 260                 wake_up_interruptible(&tty->write_q.proc_list);
 261         if (tty->throttle && (LEFT(&tty->read_q) >= RQ_THRESHOLD_HW)
 262             && !clear_bit(TTY_RQ_THROTTLED, &tty->flags))
 263                 tty->throttle(tty, TTY_THROTTLE_RQ_AVAIL);
 264         if (tty->throttle && (LEFT(&tty->secondary) >= SQ_THRESHOLD_HW)
 265             && !clear_bit(TTY_SQ_THROTTLED, &tty->flags))
 266                 tty->throttle(tty, TTY_THROTTLE_SQ_AVAIL);
 267 }
 268 
 269 int is_ignored(int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
 270 {
 271         return ((current->blocked & (1<<(sig-1))) ||
 272                 (current->sigaction[sig-1].sa_handler == SIG_IGN));
 273 }
 274 
 275 static int available_canon_input(struct tty_struct *);
 276 static void __wait_for_canon_input(struct tty_struct *);
 277 
 278 static void wait_for_canon_input(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 279 {
 280         if (!available_canon_input(tty))
 281                 __wait_for_canon_input(tty);
 282 }
 283 
 284 static int read_chan(struct tty_struct * tty, struct file * file, char * buf, int nr)
     /* [previous][next][first][last][top][bottom][index][help] */
 285 {
 286         struct wait_queue wait = { current, NULL };
 287         int c;
 288         char * b=buf;
 289         int minimum,time;
 290 
 291         if (L_CANON(tty))
 292                 minimum = time = current->timeout = 0;
 293         else {
 294                 time = 10L*tty->termios->c_cc[VTIME];
 295                 minimum = tty->termios->c_cc[VMIN];
 296                 if (minimum)
 297                         current->timeout = 0xffffffff;
 298                 else {
 299                         if (time)
 300                                 current->timeout = time + jiffies;
 301                         else
 302                                 current->timeout = 0;
 303                         time = 0;
 304                         minimum = 1;
 305                 }
 306         }
 307         if (file->f_flags & O_NONBLOCK) {
 308                 time = current->timeout = 0;
 309                 if (L_CANON(tty)) {
 310                         if (!available_canon_input(tty))
 311                                 return -EAGAIN;
 312                 }
 313         } else if (L_CANON(tty)) {
 314                 wait_for_canon_input(tty);
 315                 if (current->signal & ~current->blocked)
 316                         return -ERESTARTSYS;
 317         }
 318         if (minimum>nr)
 319                 minimum = nr;
 320 
 321         /* deal with packet mode:  First test for status change */
 322         if (tty->packet && tty->link && tty->link->status_changed) {
 323                 put_fs_byte (tty->link->ctrl_status, b);
 324                 tty->link->status_changed = 0;
 325                 return 1;
 326         }
 327           
 328         /* now bump the buffer up one. */
 329         if (tty->packet) {
 330                 put_fs_byte (0,b++);
 331                 nr--;
 332                 /* this really shouldn't happen, but we need to 
 333                 put it here. */
 334                 if (nr == 0)
 335                         return 1;
 336         }
 337         add_wait_queue(&tty->secondary.proc_list, &wait);
 338         while (nr>0) {
 339                 TTY_READ_FLUSH(tty);
 340                 if (tty->link)
 341                         TTY_WRITE_FLUSH(tty->link);
 342                 while (nr > 0 && ((c = get_tty_queue(&tty->secondary)) >= 0)) {
 343                         if ((EOF_CHAR(tty) != __DISABLED_CHAR &&
 344                              c==EOF_CHAR(tty)) || c==10)
 345                                 tty->secondary.data--;
 346                         if ((EOF_CHAR(tty) != __DISABLED_CHAR &&
 347                              c==EOF_CHAR(tty)) && L_CANON(tty))
 348                                 break;
 349                         put_fs_byte(c,b++);
 350                         nr--;
 351                         if (time)
 352                                 current->timeout = time+jiffies;
 353                         if (c==10 && L_CANON(tty))
 354                                 break;
 355                 };
 356                 wake_up_interruptible(&tty->read_q.proc_list);
 357                 /*
 358                  * If there is enough space in the secondary queue
 359                  * now, let the low-level driver know.
 360                  */
 361                 if (tty->throttle && (LEFT(&tty->secondary) >= SQ_THRESHOLD_HW)
 362                     && !clear_bit(TTY_SQ_THROTTLED, &tty->flags))
 363                         tty->throttle(tty, TTY_THROTTLE_SQ_AVAIL);
 364                 if (b-buf >= minimum || !current->timeout)
 365                         break;
 366                 if (current->signal & ~current->blocked) 
 367                         break;
 368                 if (tty->link && !tty->link->count)
 369                         break;
 370                 TTY_READ_FLUSH(tty);
 371                 if (tty->link)
 372                         TTY_WRITE_FLUSH(tty->link);
 373                 if (!EMPTY(&tty->secondary))
 374                         continue;
 375                 current->state = TASK_INTERRUPTIBLE;
 376                 if (EMPTY(&tty->secondary))
 377                         schedule();
 378                 current->state = TASK_RUNNING;
 379         }
 380         remove_wait_queue(&tty->secondary.proc_list, &wait);
 381         TTY_READ_FLUSH(tty);
 382         if (tty->link && tty->link->write)
 383                 TTY_WRITE_FLUSH(tty->link);
 384         current->timeout = 0;
 385 
 386         /* packet mode sticks in an extra 0.  If that's all we've got,
 387            we should count it a zero bytes. */
 388         if (tty->packet) {
 389                 if ((b-buf) > 1)
 390                         return b-buf;
 391         } else {
 392                 if (b-buf)
 393                         return b-buf;
 394         }
 395 
 396         if (current->signal & ~current->blocked)
 397                 return -ERESTARTSYS;
 398         if (file->f_flags & O_NONBLOCK)
 399                 return -EAGAIN;
 400         return 0;
 401 }
 402 
 403 static void __wait_for_canon_input(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 404 {
 405         struct wait_queue wait = { current, NULL };
 406 
 407         add_wait_queue(&tty->secondary.proc_list, &wait);
 408         while (1) {
 409                 current->state = TASK_INTERRUPTIBLE;
 410                 if (available_canon_input(tty))
 411                         break;
 412                 schedule();
 413         }
 414         current->state = TASK_RUNNING;
 415         remove_wait_queue(&tty->secondary.proc_list, &wait);
 416 }
 417 
 418 static int available_canon_input(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 419 {
 420         TTY_READ_FLUSH(tty);
 421         if (tty->link)
 422                 if (tty->link->count)
 423                         TTY_WRITE_FLUSH(tty->link);
 424                 else
 425                         return 1;
 426         if (current->signal & ~current->blocked)
 427                 return 1;
 428         if (FULL(&tty->read_q))
 429                 return 1;
 430         if (tty->secondary.data)
 431                 return 1;
 432         return 0;
 433 }
 434 
 435 static int write_chan(struct tty_struct * tty, struct file * file, char * buf, int nr)
     /* [previous][next][first][last][top][bottom][index][help] */
 436 {
 437         struct wait_queue wait = { current, NULL };
 438         char c, *b=buf;
 439 
 440         if (nr < 0)
 441                 return -EINVAL;
 442         if (!nr)
 443                 return 0;
 444         add_wait_queue(&tty->write_q.proc_list, &wait);
 445         while (nr>0) {
 446                 if (current->signal & ~current->blocked)
 447                         break;
 448                 if (tty->link && !tty->link->count) {
 449                         send_sig(SIGPIPE,current,0);
 450                         break;
 451                 }
 452                 current->state = TASK_INTERRUPTIBLE;
 453                 if (FULL(&tty->write_q)) {
 454                         TTY_WRITE_FLUSH(tty);
 455                         if (FULL(&tty->write_q))
 456                                 schedule();
 457                         current->state = TASK_RUNNING;
 458                         continue;
 459                 }
 460                 current->state = TASK_RUNNING;
 461                 while (nr>0 && !FULL(&tty->write_q)) {
 462                         c=get_fs_byte(b);
 463                         if (O_POST(tty)) {
 464                                 if (c=='\r' && O_CRNL(tty))
 465                                         c='\n';
 466                                 else if (c=='\n' && O_NLRET(tty))
 467                                         c='\r';
 468                                 if (c=='\n' && O_NLCR(tty) &&
 469                                     !set_bit(TTY_CR_PENDING,&tty->flags)) {
 470                                         put_tty_queue(13,&tty->write_q);
 471                                         continue;
 472                                 }
 473                                 if (O_LCUC(tty))
 474                                         c=toupper(c);
 475                         }
 476                         b++; nr--;
 477                         clear_bit(TTY_CR_PENDING,&tty->flags);
 478                         put_tty_queue(c,&tty->write_q);
 479                 }
 480                 if (need_resched)
 481                         schedule();
 482         }
 483         remove_wait_queue(&tty->write_q.proc_list, &wait);
 484         TTY_WRITE_FLUSH(tty);
 485         if (b-buf)
 486                 return b-buf;
 487         if (tty->link && !tty->link->count)
 488                 return -EPIPE;
 489         if (current->signal & ~current->blocked)
 490                 return -ERESTARTSYS;
 491         return 0;
 492 }
 493 
 494 static int tty_read(struct inode * inode, struct file * file, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 495 {
 496         int i, dev;
 497         struct tty_struct * tty;
 498 
 499         dev = file->f_rdev;
 500         if (MAJOR(dev) != 4) {
 501                 printk("tty_read: pseudo-major != 4\n");
 502                 return -EINVAL;
 503         }
 504         dev = MINOR(dev);
 505         tty = TTY_TABLE(dev);
 506         if (!tty)
 507                 return -EIO;
 508         if (MINOR(inode->i_rdev) && (tty->pgrp > 0) &&
 509             (current->tty == dev) &&
 510             (tty->pgrp != current->pgrp))
 511                 if (is_ignored(SIGTTIN) || is_orphaned_pgrp(current->pgrp))
 512                         return -EIO;
 513                 else {
 514                         (void) kill_pg(current->pgrp, SIGTTIN, 1);
 515                         return -ERESTARTSYS;
 516                 }
 517         i = read_chan(tty,file,buf,count);
 518         if (i > 0)
 519                 inode->i_atime = CURRENT_TIME;
 520         return i;
 521 }
 522 
 523 static int tty_write(struct inode * inode, struct file * file, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 524 {
 525         int dev,i;
 526         struct tty_struct * tty;
 527 
 528         dev = file->f_rdev;
 529         if (MAJOR(dev) != 4) {
 530                 printk("tty_write: pseudo-major != 4\n");
 531                 return -EINVAL;
 532         }
 533         dev = MINOR(dev);
 534         if (redirect && ((dev == 0) || (dev == fg_console+1)))
 535                 tty = redirect;
 536         else
 537                 tty = TTY_TABLE(dev);
 538         if (!tty || !tty->write)
 539                 return -EIO;
 540         if (MINOR(inode->i_rdev) &&
 541             L_TOSTOP(tty) && (tty->pgrp > 0) &&
 542             (current->tty == dev) && (tty->pgrp != current->pgrp)) {
 543                 if (is_orphaned_pgrp(tty->pgrp))
 544                         return -EIO;
 545                 if (!is_ignored(SIGTTOU)) {
 546                         (void) kill_pg(current->pgrp, SIGTTOU, 1);
 547                         return -ERESTARTSYS;
 548                 }
 549         }
 550         i = write_chan(tty,file,buf,count);
 551         if (i > 0)
 552                 inode->i_mtime = CURRENT_TIME;
 553         return i;
 554 }
 555 
 556 static int tty_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
     /* [previous][next][first][last][top][bottom][index][help] */
 557 {
 558         return -EBADF;
 559 }
 560 
 561 /*
 562  * tty_open and tty_release keep up the tty count that contains the
 563  * number of opens done on a tty. We cannot use the inode-count, as
 564  * different inodes might point to the same tty.
 565  *
 566  * Open-counting is needed for pty masters, as well as for keeping
 567  * track of serial lines: DTR is dropped when the last close happens.
 568  *
 569  * The termios state of a pty is reset on first open so that
 570  * settings don't persist across reuse.
 571  */
 572 static int tty_open(struct inode * inode, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 573 {
 574         struct tty_struct *tty, *o_tty;
 575         int dev, retval;
 576 
 577         dev = inode->i_rdev;
 578         if (MAJOR(dev) == 5)
 579                 dev = current->tty;
 580         else
 581                 dev = MINOR(dev);
 582         if (dev < 0)
 583                 return -ENXIO;
 584         if (!dev)
 585                 dev = fg_console + 1;
 586         filp->f_rdev = 0x0400 | dev;
 587 /*
 588  * There be race-conditions here... Lots of them. Careful now.
 589  */
 590         tty = o_tty = NULL;
 591         if (!tty_table[dev]) {
 592                 tty = (struct tty_struct *) get_free_page(GFP_KERNEL);
 593                 if (tty) {
 594                         retval = initialize_tty_struct(tty, dev);
 595                         if (retval) {
 596                                 free_page((unsigned long)tty);
 597                                 return retval;
 598                         }
 599                 }
 600         }
 601         if (IS_A_PTY(dev)) {
 602                 if (!tty_table[PTY_OTHER(dev)]) {
 603                         o_tty = (struct tty_struct *) get_free_page(GFP_KERNEL);
 604                         if (o_tty) {
 605                                 retval = initialize_tty_struct(o_tty, PTY_OTHER(dev));
 606                                 if (retval) {
 607                                         free_page((unsigned long) tty);
 608                                         free_page((unsigned long) o_tty);
 609                                         return retval;
 610                                 }
 611                         }
 612                 }
 613                 if (!o_tty && !tty_table[PTY_OTHER(dev)]) {
 614                         free_page((unsigned long) tty);
 615                         return -ENOMEM;
 616                 }
 617         }
 618         if (tty_table[dev]) {
 619                 free_page((unsigned long) tty);
 620                 tty = tty_table[dev];
 621         } else if (tty)
 622                 tty_table[dev] = tty;
 623         else {
 624                 free_page((unsigned long) o_tty);
 625                 return -ENOMEM;
 626         }
 627         if (IS_A_PTY(dev)) {
 628                 if (tty_table[PTY_OTHER(dev)]) {
 629                         free_page((unsigned long) o_tty);
 630                         o_tty = tty_table[PTY_OTHER(dev)];
 631                 } else
 632                         tty_table[PTY_OTHER(dev)] = o_tty;
 633                 tty->link = o_tty;
 634                 o_tty->link = tty;
 635         }
 636         if (IS_A_PTY_MASTER(dev)) {
 637                 if (tty->count)
 638                         return -EAGAIN;
 639                 if (tty->link && tty->link->count++ == 0)
 640                         reset_tty_termios(PTY_OTHER(dev));
 641                 reset_tty_termios(dev);
 642         } else if (IS_A_PTY_SLAVE(dev)) {
 643                 if (tty->count == 0)
 644                         reset_tty_termios(dev);
 645         }
 646         tty->count++;
 647         retval = 0;
 648 
 649         /* clean up the packet stuff. */
 650         tty->status_changed = 0;
 651         tty->ctrl_status = 0;
 652         tty->packet = 0;
 653 
 654         if (!(filp->f_flags & O_NOCTTY) &&
 655             current->leader &&
 656             current->tty<0 &&
 657             tty->session==0) {
 658                 current->tty = dev;
 659                 tty->session = current->session;
 660                 tty->pgrp = current->pgrp;
 661         }
 662         if (tty->open)
 663                 retval = tty->open(tty, filp);
 664         else
 665                 retval = -ENODEV;
 666         if (retval) {
 667                 tty->count--;
 668                 if (IS_A_PTY_MASTER(dev) && tty->link)
 669                         tty->link->count--;
 670         }
 671         return retval;
 672 }
 673 
 674 /*
 675  * Note that releasing a pty master also releases the child, so
 676  * we have to make the redirection checks after that and on both
 677  * sides of a pty.
 678  */
 679 static void tty_release(struct inode * inode, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 680 {
 681         int dev;
 682         struct tty_struct * tty;
 683 
 684         dev = filp->f_rdev;
 685         if (MAJOR(dev) != 4) {
 686                 printk("tty_release: tty pseudo-major != 4\n");
 687                 return;
 688         }
 689         dev = MINOR(filp->f_rdev);
 690         if (!dev)
 691                 dev = fg_console+1;
 692         tty = tty_table[dev];
 693         if (!tty) {
 694                 printk("tty_release: tty_table[%d] was NULL\n", dev);
 695                 return;
 696         }
 697         if (IS_A_PTY_MASTER(dev) && tty->link)  {
 698                 if (--tty->link->count < 0) {
 699                         printk("tty_release: bad tty slave count (dev = %d): %d\n",
 700                                dev, tty->count);        
 701                         tty->link->count = 0;
 702                 }
 703         }
 704         if (--tty->count < 0) {
 705                 printk("tty_release: bad tty_table[%d]->count: %d\n",
 706                        dev, tty->count);
 707                 tty->count = 0;
 708         }
 709         if (tty->count)
 710                 return;
 711         if (tty->close)
 712                 tty->close(tty, filp);
 713         if (tty == redirect)
 714                 redirect = NULL;
 715         if (tty->link && !tty->link->count && (tty->link == redirect))
 716                 redirect = NULL;
 717         if (tty->link) {
 718                 if (tty->link->count)
 719                         return;
 720                 free_page((unsigned long) tty_table[PTY_OTHER(dev)]);
 721                 tty_table[PTY_OTHER(dev)] = 0;
 722         }
 723         free_page((unsigned long) tty_table[dev]);
 724         tty_table[dev] = 0;
 725 }
 726 
 727 static int tty_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
     /* [previous][next][first][last][top][bottom][index][help] */
 728 {
 729         int dev;
 730         struct tty_struct * tty;
 731 
 732         dev = filp->f_rdev;
 733         if (MAJOR(dev) != 4) {
 734                 printk("tty_select: tty pseudo-major != 4\n");
 735                 return 0;
 736         }
 737         dev = MINOR(filp->f_rdev);
 738         tty = TTY_TABLE(dev);
 739         if (!tty) {
 740                 printk("tty_select: tty struct for dev %d was NULL\n", dev);
 741                 return 0;
 742         }
 743         switch (sel_type) {
 744                 case SEL_IN:
 745                         if (!EMPTY(&tty->secondary))
 746                                 return 1;
 747                         if (tty->link && !tty->link->count)
 748                                 return 1;
 749 
 750                         /* see if the status byte can be read. */
 751                         if (tty->packet && tty->link &&
 752                             tty->link->status_changed)
 753                           return 1;
 754 
 755                         select_wait(&tty->secondary.proc_list, wait);
 756                         return 0;
 757                 case SEL_OUT:
 758                         if (!FULL(&tty->write_q))
 759                                 return 1;
 760                         select_wait(&tty->write_q.proc_list, wait);
 761                         return 0;
 762                 case SEL_EX:
 763                         if (tty->link && !tty->link->count)
 764                                 return 1;
 765                         return 0;
 766         }
 767         return 0;
 768 }
 769 
 770 static struct file_operations tty_fops = {
 771         tty_lseek,
 772         tty_read,
 773         tty_write,
 774         NULL,           /* tty_readdir */
 775         tty_select,
 776         tty_ioctl,
 777         NULL,           /* tty_mmap */
 778         tty_open,
 779         tty_release
 780 };
 781 
 782 /*
 783  * This implements the "Secure Attention Key" ---  the idea is to
 784  * prevent trojan horses by killing all processes associated with this
 785  * tty when the user hits the "Secure Attention Key".  Required for
 786  * super-paranoid applications --- see the Orange Book for more details.
 787  * 
 788  * This code could be nicer; ideally it should send a HUP, wait a few
 789  * seconds, then send a INT, and then a KILL signal.  But you then
 790  * have to coordinate with the init process, since all processes associated
 791  * with the current tty must be dead before the new getty is allowed
 792  * to spawn.
 793  */
 794 void do_SAK( struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 795 {
 796         struct task_struct **p;
 797         int line = tty->line;
 798         int session = tty->session;
 799         int             i;
 800         struct file     *filp;
 801         
 802         flush_input(tty);
 803         flush_output(tty);
 804         for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
 805                 if (!(*p))
 806                         continue;
 807                 if (((*p)->tty == line) ||
 808                     ((session > 0) && ((*p)->session == session)))
 809                         send_sig(SIGKILL, *p, 1);
 810                 else {
 811                         for (i=0; i < NR_FILE; i++) {
 812                                 filp = (*p)->filp[i];
 813                                 if (filp && (filp->f_op == &tty_fops) &&
 814                                     (MINOR(filp->f_rdev) == line)) {
 815                                         send_sig(SIGKILL, *p, 1);
 816                                         break;
 817                                 }
 818                         }
 819                 }
 820         }
 821 }
 822 
 823 /*
 824  * This subroutine initializes a tty structure.  We have to set up
 825  * things correctly for each different type of tty.
 826  */
 827 static int initialize_tty_struct(struct tty_struct *tty, int line)
     /* [previous][next][first][last][top][bottom][index][help] */
 828 {
 829         memset(tty, 0, sizeof(struct tty_struct));
 830         tty->line = line;
 831         tty->pgrp = -1;
 832         tty->winsize.ws_row = 24;
 833         tty->winsize.ws_col = 80;
 834         if (!tty_termios[line]) {
 835                 tty_termios[line] = kmalloc(sizeof(struct termios), GFP_KERNEL);
 836                 if (!tty_termios[line])
 837                         return -ENOMEM;
 838                 reset_tty_termios(line);
 839         }
 840         tty->termios = tty_termios[line];
 841         
 842         if (IS_A_CONSOLE(line)) {
 843                 tty->open = con_open;
 844                 tty->winsize.ws_row = video_num_lines;
 845                 tty->winsize.ws_col = video_num_columns;
 846         } else if IS_A_SERIAL(line) {
 847                 tty->open = rs_open;
 848         } else if IS_A_PTY(line) {
 849                 tty->open = pty_open;
 850         }
 851         return 0;
 852 }
 853 
 854 static void reset_tty_termios(int line)
     /* [previous][next][first][last][top][bottom][index][help] */
 855 {
 856         struct termios *tp = tty_termios[line];
 857 
 858         if (!tp) {
 859                 printk("termios of line was NULL\n");
 860                 return;
 861         }
 862         memset(tp, 0, sizeof(struct termios));
 863         memcpy(tp->c_cc, INIT_C_CC, NCCS);
 864         if (IS_A_CONSOLE(line)) {
 865                 tp->c_iflag = ICRNL | IXON;
 866                 tp->c_oflag = OPOST | ONLCR;
 867                 tp->c_cflag = B38400 | CS8 | CREAD;
 868                 tp->c_lflag = ISIG | ICANON | ECHO | ECHOCTL | ECHOKE;
 869         } else if (IS_A_SERIAL(line)) {
 870                 tp->c_cflag = B2400 | CS8 | CREAD | HUPCL;
 871         } else if (IS_A_PTY_MASTER(line)) {
 872                 tp->c_cflag = B9600 | CS8 | CREAD;
 873         } else if (IS_A_PTY_SLAVE(line)) {
 874                 tp->c_iflag = ICRNL | IXON;
 875                 tp->c_oflag = OPOST | ONLCR;
 876                 tp->c_cflag = B38400 | CS8 | CREAD;
 877                 tp->c_lflag = ISIG | ICANON | ECHO | ECHOCTL | ECHOKE;
 878         }
 879 }
 880 
 881 long tty_init(long kmem_start)
     /* [previous][next][first][last][top][bottom][index][help] */
 882 {
 883         int i;
 884 
 885         chrdev_fops[4] = &tty_fops;
 886         chrdev_fops[5] = &tty_fops;
 887         for (i=0 ; i<256 ; i++) {
 888                 tty_table[i] =  0;
 889                 tty_termios[i] = 0;
 890         }
 891         kmem_start = kbd_init(kmem_start);
 892         kmem_start = con_init(kmem_start);
 893         kmem_start = rs_init(kmem_start);
 894         printk("%d virtual consoles\n\r",NR_CONSOLES);
 895         return kmem_start;
 896 }

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