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

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