root/kernel/chr_drv/tty_io.c

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

DEFINITIONS

This source file includes following definitions.
  1. tty_init
  2. tty_intr
  3. sleep_if_empty
  4. sleep_if_full
  5. wait_for_keypress
  6. copy_to_cooked
  7. tty_read
  8. tty_write
  9. do_tty_interrupt
  10. chr_dev_init

   1 /*
   2  *  linux/kernel/tty_io.c
   3  *
   4  *  (C) 1991  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.
  12  */
  13 #include <ctype.h>
  14 #include <errno.h>
  15 #include <signal.h>
  16 
  17 #define ALRMMASK (1<<(SIGALRM-1))
  18 #define KILLMASK (1<<(SIGKILL-1))
  19 #define INTMASK (1<<(SIGINT-1))
  20 #define QUITMASK (1<<(SIGQUIT-1))
  21 #define TSTPMASK (1<<(SIGTSTP-1))
  22 
  23 #include <linux/sched.h>
  24 #include <linux/tty.h>
  25 #include <asm/segment.h>
  26 #include <asm/system.h>
  27 
  28 #define _L_FLAG(tty,f)  ((tty)->termios.c_lflag & f)
  29 #define _I_FLAG(tty,f)  ((tty)->termios.c_iflag & f)
  30 #define _O_FLAG(tty,f)  ((tty)->termios.c_oflag & f)
  31 
  32 #define L_CANON(tty)    _L_FLAG((tty),ICANON)
  33 #define L_ISIG(tty)     _L_FLAG((tty),ISIG)
  34 #define L_ECHO(tty)     _L_FLAG((tty),ECHO)
  35 #define L_ECHOE(tty)    _L_FLAG((tty),ECHOE)
  36 #define L_ECHOK(tty)    _L_FLAG((tty),ECHOK)
  37 #define L_ECHOCTL(tty)  _L_FLAG((tty),ECHOCTL)
  38 #define L_ECHOKE(tty)   _L_FLAG((tty),ECHOKE)
  39 
  40 #define I_UCLC(tty)     _I_FLAG((tty),IUCLC)
  41 #define I_NLCR(tty)     _I_FLAG((tty),INLCR)
  42 #define I_CRNL(tty)     _I_FLAG((tty),ICRNL)
  43 #define I_NOCR(tty)     _I_FLAG((tty),IGNCR)
  44 
  45 #define O_POST(tty)     _O_FLAG((tty),OPOST)
  46 #define O_NLCR(tty)     _O_FLAG((tty),ONLCR)
  47 #define O_CRNL(tty)     _O_FLAG((tty),OCRNL)
  48 #define O_NLRET(tty)    _O_FLAG((tty),ONLRET)
  49 #define O_LCUC(tty)     _O_FLAG((tty),OLCUC)
  50 
  51 struct tty_struct tty_table[] = {
  52         {
  53                 {ICRNL,         /* change incoming CR to NL */
  54                 OPOST|ONLCR,    /* change outgoing NL to CRNL */
  55                 0,
  56                 ISIG | ICANON | ECHO | ECHOCTL | ECHOKE,
  57                 0,              /* console termio */
  58                 INIT_C_CC},
  59                 0,                      /* initial pgrp */
  60                 0,                      /* initial stopped */
  61                 con_write,
  62                 {0,0,0,0,""},           /* console read-queue */
  63                 {0,0,0,0,""},           /* console write-queue */
  64                 {0,0,0,0,""}            /* console secondary queue */
  65         },{
  66                 {0, /* no translation */
  67                 0,  /* no translation */
  68                 B2400 | CS8,
  69                 0,
  70                 0,
  71                 INIT_C_CC},
  72                 0,
  73                 0,
  74                 rs_write,
  75                 {0x3f8,0,0,0,""},               /* rs 1 */
  76                 {0x3f8,0,0,0,""},
  77                 {0,0,0,0,""}
  78         },{
  79                 {0, /* no translation */
  80                 0,  /* no translation */
  81                 B2400 | CS8,
  82                 0,
  83                 0,
  84                 INIT_C_CC},
  85                 0,
  86                 0,
  87                 rs_write,
  88                 {0x2f8,0,0,0,""},               /* rs 2 */
  89                 {0x2f8,0,0,0,""},
  90                 {0,0,0,0,""}
  91         }
  92 };
  93 
  94 /*
  95  * these are the tables used by the machine code handlers.
  96  * you can implement pseudo-tty's or something by changing
  97  * them. Currently not done.
  98  */
  99 struct tty_queue * table_list[]={
 100         &tty_table[0].read_q, &tty_table[0].write_q,
 101         &tty_table[1].read_q, &tty_table[1].write_q,
 102         &tty_table[2].read_q, &tty_table[2].write_q
 103         };
 104 
 105 void tty_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 106 {
 107         rs_init();
 108         con_init();
 109 }
 110 
 111 void tty_intr(struct tty_struct * tty, int mask)
     /* [previous][next][first][last][top][bottom][index][help] */
 112 {
 113         int i;
 114 
 115         if (tty->pgrp <= 0)
 116                 return;
 117         for (i=0;i<NR_TASKS;i++)
 118                 if (task[i] && task[i]->pgrp==tty->pgrp)
 119                         task[i]->signal |= mask;
 120 }
 121 
 122 static void sleep_if_empty(struct tty_queue * queue)
     /* [previous][next][first][last][top][bottom][index][help] */
 123 {
 124         cli();
 125         while (!current->signal && EMPTY(*queue))
 126                 interruptible_sleep_on(&queue->proc_list);
 127         sti();
 128 }
 129 
 130 static void sleep_if_full(struct tty_queue * queue)
     /* [previous][next][first][last][top][bottom][index][help] */
 131 {
 132         if (!FULL(*queue))
 133                 return;
 134         cli();
 135         while (!current->signal && LEFT(*queue)<128)
 136                 interruptible_sleep_on(&queue->proc_list);
 137         sti();
 138 }
 139 
 140 void wait_for_keypress(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 141 {
 142         sleep_if_empty(&tty_table[0].secondary);
 143 }
 144 
 145 void copy_to_cooked(struct tty_struct * tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 146 {
 147         signed char c;
 148 
 149         while (!EMPTY(tty->read_q) && !FULL(tty->secondary)) {
 150                 GETCH(tty->read_q,c);
 151                 if (c==13)
 152                         if (I_CRNL(tty))
 153                                 c=10;
 154                         else if (I_NOCR(tty))
 155                                 continue;
 156                         else ;
 157                 else if (c==10 && I_NLCR(tty))
 158                         c=13;
 159                 if (I_UCLC(tty))
 160                         c=tolower(c);
 161                 if (L_CANON(tty)) {
 162                         if (c==KILL_CHAR(tty)) {
 163                                 /* deal with killing the input line */
 164                                 while(!(EMPTY(tty->secondary) ||
 165                                         (c=LAST(tty->secondary))==10 ||
 166                                         c==EOF_CHAR(tty))) {
 167                                         if (L_ECHO(tty)) {
 168                                                 if (c<32)
 169                                                         PUTCH(127,tty->write_q);
 170                                                 PUTCH(127,tty->write_q);
 171                                                 tty->write(tty);
 172                                         }
 173                                         DEC(tty->secondary.head);
 174                                 }
 175                                 continue;
 176                         }
 177                         if (c==ERASE_CHAR(tty)) {
 178                                 if (EMPTY(tty->secondary) ||
 179                                    (c=LAST(tty->secondary))==10 ||
 180                                    c==EOF_CHAR(tty))
 181                                         continue;
 182                                 if (L_ECHO(tty)) {
 183                                         if (c<32)
 184                                                 PUTCH(127,tty->write_q);
 185                                         PUTCH(127,tty->write_q);
 186                                         tty->write(tty);
 187                                 }
 188                                 DEC(tty->secondary.head);
 189                                 continue;
 190                         }
 191                         if (c==STOP_CHAR(tty)) {
 192                                 tty->stopped=1;
 193                                 continue;
 194                         }
 195                         if (c==START_CHAR(tty)) {
 196                                 tty->stopped=0;
 197                                 continue;
 198                         }
 199                 }
 200                 if (L_ISIG(tty)) {
 201                         if (c==INTR_CHAR(tty)) {
 202                                 tty_intr(tty,INTMASK);
 203                                 continue;
 204                         }
 205                         if (c==QUIT_CHAR(tty)) {
 206                                 tty_intr(tty,QUITMASK);
 207                                 continue;
 208                         }
 209                 }
 210                 if (c==10 || c==EOF_CHAR(tty))
 211                         tty->secondary.data++;
 212                 if (L_ECHO(tty)) {
 213                         if (c==10) {
 214                                 PUTCH(10,tty->write_q);
 215                                 PUTCH(13,tty->write_q);
 216                         } else if (c<32) {
 217                                 if (L_ECHOCTL(tty)) {
 218                                         PUTCH('^',tty->write_q);
 219                                         PUTCH(c+64,tty->write_q);
 220                                 }
 221                         } else
 222                                 PUTCH(c,tty->write_q);
 223                         tty->write(tty);
 224                 }
 225                 PUTCH(c,tty->secondary);
 226         }
 227         wake_up(&tty->secondary.proc_list);
 228 }
 229 
 230 int tty_read(unsigned channel, char * buf, int nr)
     /* [previous][next][first][last][top][bottom][index][help] */
 231 {
 232         struct tty_struct * tty;
 233         char c, * b=buf;
 234         int minimum,time,flag=0;
 235         long oldalarm;
 236 
 237         if (channel>2 || nr<0) return -1;
 238         tty = &tty_table[channel];
 239         oldalarm = current->alarm;
 240         time = 10L*tty->termios.c_cc[VTIME];
 241         minimum = tty->termios.c_cc[VMIN];
 242         if (time && !minimum) {
 243                 minimum=1;
 244                 if (flag=(!oldalarm || time+jiffies<oldalarm))
 245                         current->alarm = time+jiffies;
 246         }
 247         if (minimum>nr)
 248                 minimum=nr;
 249         while (nr>0) {
 250                 if (flag && (current->signal & ALRMMASK)) {
 251                         current->signal &= ~ALRMMASK;
 252                         break;
 253                 }
 254                 if (current->signal)
 255                         break;
 256                 if (EMPTY(tty->secondary) || (L_CANON(tty) &&
 257                 !tty->secondary.data && LEFT(tty->secondary)>20)) {
 258                         sleep_if_empty(&tty->secondary);
 259                         continue;
 260                 }
 261                 do {
 262                         GETCH(tty->secondary,c);
 263                         if (c==EOF_CHAR(tty) || c==10)
 264                                 tty->secondary.data--;
 265                         if (c==EOF_CHAR(tty) && L_CANON(tty))
 266                                 return (b-buf);
 267                         else {
 268                                 put_fs_byte(c,b++);
 269                                 if (!--nr)
 270                                         break;
 271                         }
 272                 } while (nr>0 && !EMPTY(tty->secondary));
 273                 if (time && !L_CANON(tty))
 274                         if (flag=(!oldalarm || time+jiffies<oldalarm))
 275                                 current->alarm = time+jiffies;
 276                         else
 277                                 current->alarm = oldalarm;
 278                 if (L_CANON(tty)) {
 279                         if (b-buf)
 280                                 break;
 281                 } else if (b-buf >= minimum)
 282                         break;
 283         }
 284         current->alarm = oldalarm;
 285         if (current->signal && !(b-buf))
 286                 return -EINTR;
 287         return (b-buf);
 288 }
 289 
 290 int tty_write(unsigned channel, char * buf, int nr)
     /* [previous][next][first][last][top][bottom][index][help] */
 291 {
 292         static cr_flag=0;
 293         struct tty_struct * tty;
 294         char c, *b=buf;
 295 
 296         if (channel>2 || nr<0) return -1;
 297         tty = channel + tty_table;
 298         while (nr>0) {
 299                 sleep_if_full(&tty->write_q);
 300                 if (current->signal)
 301                         break;
 302                 while (nr>0 && !FULL(tty->write_q)) {
 303                         c=get_fs_byte(b);
 304                         if (O_POST(tty)) {
 305                                 if (c=='\r' && O_CRNL(tty))
 306                                         c='\n';
 307                                 else if (c=='\n' && O_NLRET(tty))
 308                                         c='\r';
 309                                 if (c=='\n' && !cr_flag && O_NLCR(tty)) {
 310                                         cr_flag = 1;
 311                                         PUTCH(13,tty->write_q);
 312                                         continue;
 313                                 }
 314                                 if (O_LCUC(tty))
 315                                         c=toupper(c);
 316                         }
 317                         b++; nr--;
 318                         cr_flag = 0;
 319                         PUTCH(c,tty->write_q);
 320                 }
 321                 tty->write(tty);
 322                 if (nr>0)
 323                         schedule();
 324         }
 325         return (b-buf);
 326 }
 327 
 328 /*
 329  * Jeh, sometimes I really like the 386.
 330  * This routine is called from an interrupt,
 331  * and there should be absolutely no problem
 332  * with sleeping even in an interrupt (I hope).
 333  * Of course, if somebody proves me wrong, I'll
 334  * hate intel for all time :-). We'll have to
 335  * be careful and see to reinstating the interrupt
 336  * chips before calling this, though.
 337  *
 338  * I don't think we sleep here under normal circumstances
 339  * anyway, which is good, as the task sleeping might be
 340  * totally innocent.
 341  */
 342 void do_tty_interrupt(int tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 343 {
 344         copy_to_cooked(tty_table+tty);
 345 }
 346 
 347 void chr_dev_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 348 {
 349 }

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