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