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. 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/segment.h>
  37 #include <asm/system.h>
  38 #include <asm/bitops.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 = NULL;
  54 
  55 int initialize_tty_struct(struct tty_struct *tty, int line);
  56 
  57 void 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 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 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 (!tty || 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 (((I_IXANY(tty)) && tty->stopped) ||
 211                             ((START_CHAR(tty) != __DISABLED_CHAR) &&
 212                              (c==START_CHAR(tty)))) {
 213                                 tty->status_changed = 1;
 214                                 tty->ctrl_status |= TIOCPKT_START;
 215                                 tty->stopped=0;
 216                                 continue;
 217                         }
 218                 }
 219                 if (L_ISIG(tty)) {
 220                         if ((INTR_CHAR(tty) != __DISABLED_CHAR) &&
 221                             (c==INTR_CHAR(tty))) {
 222                                 kill_pg(tty->pgrp, SIGINT, 1);
 223                                 flush_input(tty);
 224                                 continue;
 225                         }
 226                         if ((QUIT_CHAR(tty) != __DISABLED_CHAR) &&
 227                             (c==QUIT_CHAR(tty))) {
 228                                 kill_pg(tty->pgrp, SIGQUIT, 1);
 229                                 flush_input(tty);
 230                                 continue;
 231                         }
 232                         if ((SUSPEND_CHAR(tty) != __DISABLED_CHAR) &&
 233                             (c==SUSPEND_CHAR(tty))) {
 234                                 if (!is_orphaned_pgrp(tty->pgrp))
 235                                         kill_pg(tty->pgrp, SIGTSTP, 1);
 236                                 continue;
 237                         }
 238                 }
 239                 if (c==10 || (EOF_CHAR(tty) != __DISABLED_CHAR &&
 240                     c==EOF_CHAR(tty)))
 241                         tty->secondary.data++;
 242                 if ((c==10) && (L_ECHO(tty) || (L_CANON(tty) && L_ECHONL(tty)))) {
 243                         put_tty_queue(10,&tty->write_q);
 244                         put_tty_queue(13,&tty->write_q);
 245                 } else if (L_ECHO(tty)) {
 246                         if (c<32 && L_ECHOCTL(tty)) {
 247                                 put_tty_queue('^',&tty->write_q);
 248                                 put_tty_queue(c+64, &tty->write_q);
 249                         } else
 250                                 put_tty_queue(c, &tty->write_q);
 251                 }
 252                 put_tty_queue(c, &tty->secondary);
 253         }
 254         TTY_WRITE_FLUSH(tty);
 255         if (!EMPTY(&tty->secondary))
 256                 wake_up(&tty->secondary.proc_list);
 257         if (tty->write_q.proc_list && LEFT(&tty->write_q) > TTY_BUF_SIZE/2)
 258                 wake_up(&tty->write_q.proc_list);
 259         if (tty->throttle && (LEFT(&tty->read_q) >= RQ_THRESHOLD_HW)
 260             && !clear_bit(TTY_RQ_THROTTLED, &tty->flags))
 261                 tty->throttle(tty, TTY_THROTTLE_RQ_AVAIL);
 262         if (tty->throttle && (LEFT(&tty->secondary) >= SQ_THRESHOLD_HW)
 263             && !clear_bit(TTY_SQ_THROTTLED, &tty->flags))
 264                 tty->throttle(tty, TTY_THROTTLE_SQ_AVAIL);
 265 }
 266 
 267 int is_ignored(int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
 268 {
 269         return ((current->blocked & (1<<(sig-1))) ||
 270                 (current->sigaction[sig-1].sa_handler == SIG_IGN));
 271 }
 272 
 273 static int available_canon_input(struct tty_struct *);
 274 static void __wait_for_canon_input(struct tty_struct *);
 275 
 276 static void wait_for_canon_input(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 277 {
 278         if (!available_canon_input(tty))
 279                 __wait_for_canon_input(tty);
 280 }
 281 
 282 static int read_chan(unsigned int channel, struct file * file, char * buf, int nr)
     /* [previous][next][first][last][top][bottom][index][help] */
 283 {
 284         struct tty_struct * tty;
 285         struct wait_queue wait = { current, NULL };
 286         int c;
 287         char * b=buf;
 288         int minimum,time;
 289 
 290         if (channel > 255)
 291                 return -EIO;
 292         tty = TTY_TABLE(channel);
 293         if (!tty)
 294                 return -EIO;
 295         if ((tty->pgrp > 0) &&
 296             (current->tty == channel) &&
 297             (tty->pgrp != current->pgrp))
 298                 if (is_ignored(SIGTTIN) || is_orphaned_pgrp(current->pgrp))
 299                         return -EIO;
 300                 else {
 301                         (void) kill_pg(current->pgrp, SIGTTIN, 1);
 302                         return -ERESTARTSYS;
 303                 }
 304         if (L_CANON(tty))
 305                 minimum = time = current->timeout = 0;
 306         else {
 307                 time = 10L*tty->termios->c_cc[VTIME];
 308                 minimum = tty->termios->c_cc[VMIN];
 309                 if (minimum)
 310                         current->timeout = 0xffffffff;
 311                 else {
 312                         if (time)
 313                                 current->timeout = time + jiffies;
 314                         else
 315                                 current->timeout = 0;
 316                         time = 0;
 317                         minimum = 1;
 318                 }
 319         }
 320         if (file->f_flags & O_NONBLOCK) {
 321                 time = current->timeout = 0;
 322                 if (L_CANON(tty)) {
 323                         if (!available_canon_input(tty))
 324                                 return -EAGAIN;
 325                 }
 326         } else if (L_CANON(tty)) {
 327                 wait_for_canon_input(tty);
 328                 if (current->signal & ~current->blocked)
 329                         return -ERESTARTSYS;
 330         }
 331         if (minimum>nr)
 332                 minimum = nr;
 333 
 334         /* deal with packet mode:  First test for status change */
 335         if (tty->packet && tty->link && tty->link->status_changed) {
 336                 put_fs_byte (tty->link->ctrl_status, b);
 337                 tty->link->status_changed = 0;
 338                 return 1;
 339         }
 340           
 341         /* now bump the buffer up one. */
 342         if (tty->packet) {
 343                 put_fs_byte (0,b++);
 344                 nr--;
 345                 /* this really shouldn't happen, but we need to 
 346                 put it here. */
 347                 if (nr == 0)
 348                         return 1;
 349         }
 350         add_wait_queue(&tty->secondary.proc_list, &wait);
 351         while (nr>0) {
 352                 TTY_READ_FLUSH(tty);
 353                 if (tty->link)
 354                         TTY_WRITE_FLUSH(tty->link);
 355                 while (nr > 0 && ((c = get_tty_queue(&tty->secondary)) >= 0)) {
 356                         if ((EOF_CHAR(tty) != __DISABLED_CHAR &&
 357                              c==EOF_CHAR(tty)) || c==10)
 358                                 tty->secondary.data--;
 359                         if ((EOF_CHAR(tty) != __DISABLED_CHAR &&
 360                              c==EOF_CHAR(tty)) && L_CANON(tty))
 361                                 break;
 362                         put_fs_byte(c,b++);
 363                         nr--;
 364                         if (time)
 365                                 current->timeout = time+jiffies;
 366                         if (c==10 && L_CANON(tty))
 367                                 break;
 368                 };
 369                 wake_up(&tty->read_q.proc_list);
 370                 /*
 371                  * If there is enough space in the secondary queue
 372                  * now, let the low-level driver know.
 373                  */
 374                 if (tty->throttle && (LEFT(&tty->secondary) >= SQ_THRESHOLD_HW)
 375                     && !clear_bit(TTY_SQ_THROTTLED, &tty->flags))
 376                         tty->throttle(tty, TTY_THROTTLE_SQ_AVAIL);
 377                 if (b-buf >= minimum || !current->timeout)
 378                         break;
 379                 if (current->signal & ~current->blocked) 
 380                         break;
 381                 if (tty->link && !tty->link->count)
 382                         break;
 383                 TTY_READ_FLUSH(tty);
 384                 if (tty->link)
 385                         TTY_WRITE_FLUSH(tty->link);
 386                 if (!EMPTY(&tty->secondary))
 387                         continue;
 388                 current->state = TASK_INTERRUPTIBLE;
 389                 if (EMPTY(&tty->secondary))
 390                         schedule();
 391                 current->state = TASK_RUNNING;
 392         }
 393         remove_wait_queue(&tty->secondary.proc_list, &wait);
 394         TTY_READ_FLUSH(tty);
 395         if (tty->link && tty->link->write)
 396                 TTY_WRITE_FLUSH(tty->link);
 397         current->timeout = 0;
 398 
 399         /* packet mode sticks in an extra 0.  If that's all we've got,
 400            we should count it a zero bytes. */
 401         if (tty->packet) {
 402                 if ((b-buf) > 1)
 403                         return b-buf;
 404         } else {
 405                 if (b-buf)
 406                         return b-buf;
 407         }
 408 
 409         if (current->signal & ~current->blocked)
 410                 return -ERESTARTSYS;
 411         if (file->f_flags & O_NONBLOCK)
 412                 return -EAGAIN;
 413         return 0;
 414 }
 415 
 416 static void __wait_for_canon_input(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 417 {
 418         struct wait_queue wait = { current, NULL };
 419 
 420         add_wait_queue(&tty->secondary.proc_list, &wait);
 421         while (1) {
 422                 current->state = TASK_INTERRUPTIBLE;
 423                 if (available_canon_input(tty))
 424                         break;
 425                 schedule();
 426         }
 427         current->state = TASK_RUNNING;
 428         remove_wait_queue(&tty->secondary.proc_list, &wait);
 429 }
 430 
 431 static int available_canon_input(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 432 {
 433         TTY_READ_FLUSH(tty);
 434         if (tty->link)
 435                 if (tty->link->count)
 436                         TTY_WRITE_FLUSH(tty->link);
 437                 else
 438                         return 1;
 439         if (current->signal & ~current->blocked)
 440                 return 1;
 441         if (FULL(&tty->read_q))
 442                 return 1;
 443         if (tty->secondary.data)
 444                 return 1;
 445         return 0;
 446 }
 447 
 448 static int write_chan(unsigned int channel, struct file * file, char * buf, int nr)
     /* [previous][next][first][last][top][bottom][index][help] */
 449 {
 450         struct tty_struct * tty;
 451         struct wait_queue wait = { current, NULL };
 452         char c, *b=buf;
 453 
 454         if (channel > 255)
 455                 return -EIO;
 456         if (redirect && ((channel == 0) || (channel+1 == fg_console)))
 457                 tty = redirect;
 458         else
 459                 tty = TTY_TABLE(channel);
 460         if (!tty || !tty->write)
 461                 return -EIO;
 462         if (L_TOSTOP(tty) && (tty->pgrp > 0) &&
 463             (current->tty == channel) && (tty->pgrp != current->pgrp)) {
 464                 if (is_orphaned_pgrp(tty->pgrp))
 465                         return -EIO;
 466                 if (!is_ignored(SIGTTOU)) {
 467                         (void) kill_pg(current->pgrp, SIGTTOU, 1);
 468                         return -ERESTARTSYS;
 469                 }
 470         }
 471         if (nr < 0)
 472                 return -EINVAL;
 473         if (!nr)
 474                 return 0;
 475         add_wait_queue(&tty->write_q.proc_list, &wait);
 476         while (nr>0) {
 477                 if (current->signal & ~current->blocked)
 478                         break;
 479                 if (tty->link && !tty->link->count) {
 480                         send_sig(SIGPIPE,current,0);
 481                         break;
 482                 }
 483                 current->state = TASK_INTERRUPTIBLE;
 484                 if (FULL(&tty->write_q)) {
 485                         TTY_WRITE_FLUSH(tty);
 486                         if (FULL(&tty->write_q))
 487                                 schedule();
 488                         current->state = TASK_RUNNING;
 489                         continue;
 490                 }
 491                 current->state = TASK_RUNNING;
 492                 while (nr>0 && !FULL(&tty->write_q)) {
 493                         c=get_fs_byte(b);
 494                         if (O_POST(tty)) {
 495                                 if (c=='\r' && O_CRNL(tty))
 496                                         c='\n';
 497                                 else if (c=='\n' && O_NLRET(tty))
 498                                         c='\r';
 499                                 if (c=='\n' && O_NLCR(tty) &&
 500                                     !set_bit(TTY_CR_PENDING,&tty->flags)) {
 501                                         put_tty_queue(13,&tty->write_q);
 502                                         continue;
 503                                 }
 504                                 if (O_LCUC(tty))
 505                                         c=toupper(c);
 506                         }
 507                         b++; nr--;
 508                         clear_bit(TTY_CR_PENDING,&tty->flags);
 509                         put_tty_queue(c,&tty->write_q);
 510                 }
 511                 if (need_resched)
 512                         schedule();
 513         }
 514         remove_wait_queue(&tty->write_q.proc_list, &wait);
 515         TTY_WRITE_FLUSH(tty);
 516         if (b-buf)
 517                 return b-buf;
 518         if (tty->link && !tty->link->count)
 519                 return -EPIPE;
 520         if (current->signal & ~current->blocked)
 521                 return -ERESTARTSYS;
 522         return 0;
 523 }
 524 
 525 static int tty_read(struct inode * inode, struct file * file, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 526 {
 527         int i;
 528 
 529         if (MAJOR(file->f_rdev) != 4) {
 530                 printk("tty_read: pseudo-major != 4\n");
 531                 return -EINVAL;
 532         }
 533         i = read_chan(MINOR(file->f_rdev),file,buf,count);
 534         if (i > 0)
 535                 inode->i_atime = CURRENT_TIME;
 536         return i;
 537 }
 538 
 539 static int tty_write(struct inode * inode, struct file * file, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 540 {
 541         int i;
 542         
 543         if (MAJOR(file->f_rdev) != 4) {
 544                 printk("tty_write: pseudo-major != 4\n");
 545                 return -EINVAL;
 546         }
 547         i = write_chan(MINOR(file->f_rdev),file,buf,count);
 548         if (i > 0)
 549                 inode->i_mtime = CURRENT_TIME;
 550         return i;
 551 }
 552 
 553 static int tty_lseek(struct inode * inode, struct file * file, off_t offset, int orig)
     /* [previous][next][first][last][top][bottom][index][help] */
 554 {
 555         return -EBADF;
 556 }
 557 
 558 /*
 559  * tty_open and tty_release keep up the tty count that contains the
 560  * number of opens done on a tty. We cannot use the inode-count, as
 561  * different inodes might point to the same tty.
 562  *
 563  * Open-counting is needed for pty masters, as well as for keeping
 564  * track of serial lines: DTR is dropped when the last close happens.
 565  */
 566 static int tty_open(struct inode * inode, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 567 {
 568         struct tty_struct *tty, *o_tty;
 569         int dev, retval;
 570 
 571         dev = inode->i_rdev;
 572         if (MAJOR(dev) == 5)
 573                 dev = current->tty;
 574         else
 575                 dev = MINOR(dev);
 576         if (dev < 0)
 577                 return -ENODEV;
 578         filp->f_rdev = 0x0400 | dev;
 579 /*
 580  * There be race-conditions here... Lots of them. Careful now.
 581  */
 582         tty = o_tty = NULL;
 583         if (!TTY_TABLE(dev)) {
 584                 tty = (struct tty_struct *) get_free_page(GFP_KERNEL);
 585                 if (tty) {
 586                         retval = initialize_tty_struct(tty, TTY_TABLE_IDX(dev));
 587                         if (retval) {
 588                                 free_page((unsigned long)tty);
 589                                 return retval;
 590                         }
 591                 }
 592         }
 593         if (IS_A_PTY(dev)) {
 594                 if (!tty_table[PTY_OTHER(dev)]) {
 595                         o_tty = (struct tty_struct *) get_free_page(GFP_KERNEL);
 596                         if (o_tty) {
 597                                 retval = initialize_tty_struct(o_tty, PTY_OTHER(dev));
 598                                 if (retval) {
 599                                         free_page((unsigned long) tty);
 600                                         free_page((unsigned long) o_tty);
 601                                         return retval;
 602                                 }
 603                         }
 604                 }
 605                 if (!o_tty && !tty_table[PTY_OTHER(dev)]) {
 606                         free_page((unsigned long) tty);
 607                         return -ENOMEM;
 608                 }
 609         }
 610         if (TTY_TABLE(dev)) {
 611                 free_page((unsigned long) tty);
 612                 tty = TTY_TABLE(dev);
 613         } else if (tty)
 614                 TTY_TABLE(dev) = tty;
 615         else {
 616                 free_page((unsigned long) o_tty);
 617                 return -ENOMEM;
 618         }
 619         if (IS_A_PTY(dev)) {
 620                 if (tty_table[PTY_OTHER(dev)]) {
 621                         free_page((unsigned long) o_tty);
 622                         o_tty = tty_table[PTY_OTHER(dev)];
 623                 } else
 624                         tty_table[PTY_OTHER(dev)] = o_tty;
 625                 tty->link = o_tty;
 626                 o_tty->link = tty;
 627         }
 628         if (IS_A_PTY_MASTER(dev)) {
 629                 if (tty->count)
 630                         return -EAGAIN;
 631                 if (tty->link)
 632                         tty->link->count++;
 633 
 634                 /* perhaps user applications that don't take care of
 635                    this deserve what the get, but I think my system
 636                    has hung do to this, esp. in X. -RAB */
 637                 tty->termios->c_lflag &= ~ECHO;
 638         }
 639         tty->count++;
 640         retval = 0;
 641 
 642         /* clean up the packet stuff. */
 643         tty->status_changed = 0;
 644         tty->ctrl_status = 0;
 645         tty->packet = 0;
 646 
 647         if (!(filp->f_flags & O_NOCTTY) &&
 648             current->leader &&
 649             current->tty<0 &&
 650             tty->session==0) {
 651                 current->tty = dev;
 652                 tty->session = current->session;
 653                 tty->pgrp = current->pgrp;
 654         }
 655         if (tty->open)
 656                 retval = tty->open(tty, filp);
 657         else
 658                 retval = -ENODEV;
 659         if (retval) {
 660                 tty->count--;
 661                 if (IS_A_PTY_MASTER(dev) && tty->link)
 662                         tty->link->count--;
 663         }
 664         return retval;
 665 }
 666 
 667 /*
 668  * Note that releasing a pty master also releases the child, so
 669  * we have to make the redirection checks after that and on both
 670  * sides of a pty.
 671  */
 672 static void tty_release(struct inode * inode, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 673 {
 674         int dev;
 675         struct tty_struct * tty;
 676 
 677         dev = filp->f_rdev;
 678         if (MAJOR(dev) != 4) {
 679                 printk("tty_release: tty pseudo-major != 4\n");
 680                 return;
 681         }
 682         dev = MINOR(filp->f_rdev);
 683         tty = TTY_TABLE(dev);
 684         if (!tty) {
 685                 printk("tty_release: TTY_TABLE(%d) was NULL\n", dev);
 686                 return;
 687         }
 688         if (IS_A_PTY_MASTER(dev) && tty->link)  {
 689                 if (--tty->link->count < 0) {
 690                         printk("tty_release: bad tty slave count (dev = %d): %d\n",
 691                                dev, tty->count);        
 692                         tty->link->count = 0;
 693                 }
 694         }
 695         if (--tty->count < 0) {
 696                 printk("tty_release: bad TTY_TABLE(%d)->count: %d\n",
 697                        dev, tty->count);
 698                 tty->count = 0;
 699         }
 700         if (tty->count)
 701                 return;
 702         if (tty->close)
 703                 tty->close(tty, filp);
 704         if (tty == redirect)
 705                 redirect = NULL;
 706         if (tty->link && !tty->link->count && (tty->link == redirect))
 707                 redirect = NULL;
 708         if (tty->link) {
 709                 if (tty->link->count)
 710                         return;
 711                 free_page((unsigned long) TTY_TABLE(PTY_OTHER(dev)));
 712                 TTY_TABLE(PTY_OTHER(dev)) = 0;
 713         }
 714         free_page((unsigned long) TTY_TABLE(dev));
 715         TTY_TABLE(dev) = 0;
 716 }
 717 
 718 static int tty_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
     /* [previous][next][first][last][top][bottom][index][help] */
 719 {
 720         int dev;
 721         struct tty_struct * tty;
 722 
 723         dev = filp->f_rdev;
 724         if (MAJOR(dev) != 4) {
 725                 printk("tty_select: tty pseudo-major != 4\n");
 726                 return 0;
 727         }
 728         dev = MINOR(filp->f_rdev);
 729         tty = TTY_TABLE(dev);
 730         if (!tty) {
 731                 printk("tty_select: tty struct for dev %d was NULL\n", dev);
 732                 return 0;
 733         }
 734         switch (sel_type) {
 735                 case SEL_IN:
 736                         if (!EMPTY(&tty->secondary))
 737                                 return 1;
 738                         if (tty->link && !tty->link->count)
 739                                 return 1;
 740 
 741                         /* see if the status byte can be read. */
 742                         if (tty->packet && tty->link &&
 743                             tty->link->status_changed)
 744                           return 1;
 745 
 746                         select_wait(&tty->secondary.proc_list, wait);
 747                         return 0;
 748                 case SEL_OUT:
 749                         if (!FULL(&tty->write_q))
 750                                 return 1;
 751                         select_wait(&tty->write_q.proc_list, wait);
 752                         return 0;
 753                 case SEL_EX:
 754                         if (tty->link && !tty->link->count)
 755                                 return 1;
 756                         return 0;
 757         }
 758         return 0;
 759 }
 760 
 761 static struct file_operations tty_fops = {
 762         tty_lseek,
 763         tty_read,
 764         tty_write,
 765         NULL,           /* tty_readdir */
 766         tty_select,
 767         tty_ioctl,
 768         NULL,           /* tty_mmap */
 769         tty_open,
 770         tty_release
 771 };
 772 
 773 /*
 774  * This implements the "Secure Attention Key" ---  the idea is to
 775  * prevent trojan horses by killing all processes associated with this
 776  * tty when the user hits the "Secure Attention Key".  Required for
 777  * super-paranoid applications --- see the Orange Book for more details.
 778  * 
 779  * This code could be nicer; ideally it should send a HUP, wait a few
 780  * seconds, then send a INT, and then a KILL signal.  But you then
 781  * have to coordinate with the init process, since all processes associated
 782  * with the current tty must be dead before the new getty is allowed
 783  * to spawn.
 784  */
 785 void do_SAK( struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 786 {
 787         struct task_struct **p;
 788         int line = tty->line;
 789         int session = tty->session;
 790         int             i;
 791         struct file     *filp;
 792         
 793         flush_input(tty);
 794         flush_output(tty);
 795         for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
 796                 if (!(*p))
 797                         continue;
 798                 if (((*p)->tty == line) ||
 799                     ((session > 0) && ((*p)->session == session)))
 800                         send_sig(SIGKILL, *p, 1);
 801                 else {
 802                         for (i=0; i < NR_FILE; i++) {
 803                                 filp = (*p)->filp[i];
 804                                 if (filp && (filp->f_op == &tty_fops) &&
 805                                     (MINOR(filp->f_rdev) == line)) {
 806                                         send_sig(SIGKILL, *p, 1);
 807                                         break;
 808                                 }
 809                         }
 810                 }
 811         }
 812 }
 813 
 814 /*
 815  * This subroutine initializes a tty structure.  We have to set up
 816  * things correctly for each different type of tty.
 817  */
 818 int initialize_tty_struct(struct tty_struct *tty, int line)
     /* [previous][next][first][last][top][bottom][index][help] */
 819 {
 820         struct termios *tp;
 821         
 822         memset(tty, 0, sizeof(struct tty_struct));
 823         tty->line = line;
 824         tty->pgrp = -1;
 825         tty->winsize.ws_row = 24;
 826         tty->winsize.ws_col = 80;
 827         if (!tty_termios[line]) {
 828                 tp = tty_termios[line] = kmalloc(sizeof(struct termios),
 829                                                 GFP_KERNEL);
 830                 if (!tp)
 831                         return -ENOMEM;
 832                 memset(tp, 0, sizeof(struct termios));
 833                 memcpy(tp->c_cc, INIT_C_CC, NCCS);
 834                 if (IS_A_CONSOLE(line)) {
 835                         tp->c_iflag = ICRNL | IXON;
 836                         tp->c_oflag = OPOST | ONLCR;
 837                         tp->c_cflag = B38400 | CS8 | CREAD;
 838                         tp->c_lflag = ISIG | ICANON | ECHO | ECHOCTL | ECHOKE;
 839                 } else if (IS_A_SERIAL(line)) {
 840                         tp->c_cflag = B2400 | CS8 | CREAD | HUPCL;
 841                 } else if (IS_A_PTY_MASTER(line)) {
 842                         tp->c_cflag = B9600 | CS8 | CREAD;
 843                 } else if (IS_A_PTY_SLAVE(line)) {
 844                         tp->c_cflag = B9600 | CS8 | CREAD;
 845                         tp->c_lflag = ISIG | ICANON;
 846                 }
 847         }
 848         tty->termios = tty_termios[line];
 849         
 850         if (IS_A_CONSOLE(line)) {
 851                 tty->open = con_open;
 852                 tty->winsize.ws_row = video_num_lines;
 853                 tty->winsize.ws_col = video_num_columns;
 854         } else if IS_A_SERIAL(line) {
 855                 tty->open = rs_open;
 856         } else if IS_A_PTY(line) {
 857                 tty->open = pty_open;
 858         }
 859         return 0;
 860 }
 861 
 862 long tty_init(long kmem_start)
     /* [previous][next][first][last][top][bottom][index][help] */
 863 {
 864         int i;
 865 
 866         chrdev_fops[4] = &tty_fops;
 867         chrdev_fops[5] = &tty_fops;
 868         for (i=0 ; i<256 ; i++) {
 869                 tty_table[i] =  0;
 870                 tty_termios[i] = 0;
 871         }
 872         kmem_start = con_init(kmem_start);
 873         kmem_start = rs_init(kmem_start);
 874         printk("%d virtual consoles\n\r",NR_CONSOLES);
 875         return kmem_start;
 876 }

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