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

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