/* * This is the function called by the virtual terminal subsystem when * a key is pressed. * * The first thing you should do is to pass the character to the line * discipline. This way, the character will be buffered, so that when * the read system call is made, an entire line will be returned, * rather than just a single character. * * After passing the character off to the line discipline, the result * of receive_char() should be echoed to the screen using the * tty_echo() function. */ void tty_global_driver_callback(void *arg, char c) { /* DRIVERS {{{ */ tty_device_t *tty; tty_ldisc_t *ldisc; tty_driver_t *driver; const char *out; tty = (tty_device_t *)arg; KASSERT(NULL != tty); driver = tty->tty_driver; KASSERT(NULL != driver); KASSERT(NULL != driver->ttd_ops); KASSERT(NULL != driver->ttd_ops->provide_char); ldisc = tty->tty_ldisc; KASSERT(NULL != ldisc); KASSERT(NULL != ldisc->ld_ops); KASSERT(NULL != ldisc->ld_ops->receive_char); out = ldisc->ld_ops->receive_char(ldisc, c); tty_echo(driver, out); /* DRIVERS }}} */ }
/* * This is the function called by the virtual terminal subsystem when * a key is pressed. * * The first thing you should do is to pass the character to the line * discipline. This way, the character will be buffered, so that when * the read system call is made, an entire line will be returned,drivers/tty/tty.c:51:1: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'static' * rather than just a single character. * * After passing the character off to the line discipline, the result * of receive_char() should be echoed to the screen using the * tty_echo() function. */ void tty_global_driver_callback(void *arg, char c) { //tty_device_t * dev = (tty_device_t *)arg; char * echo = ((tty_device_t *)arg)->tty_ldisc->ld_ops->receive_char(((tty_device_t *)arg)->tty_ldisc, c); tty_echo(((tty_device_t *)arg)->tty_driver, echo); NOT_YET_IMPLEMENTED("DRIVERS: tty_global_driver_callback"); }
int caution(void) { int ch; printf("these actions will lead to irreparable consequences\n"); printf("do you want to continue (Y/N) ?"); fflush(stdout); tty_echo(TTY_ECHO_OFF); do { ch = tolower(getchar()); } while (ch != 'y' && ch != 'n'); tty_echo(TTY_ECHO_ON); printf(" %c\n", ch); return ch == 'y'; }
/* * In this function, you should block I/O, process each * character with the line discipline and output the result to * the driver, and then unblock I/O. * * Important: You should return the number of bytes processed, * _NOT_ the number of bytes written out to the driver. */ int tty_write(bytedev_t *dev, int offset, const void *buf, int count) { /*DRIVERS {{{*/ void *data; tty_device_t *tty; tty_ldisc_t *ldisc; tty_driver_t *driver; int i, nbytes; const char *cbuf = (const char *)buf; KASSERT(NULL != dev); tty = bd_to_tty(dev); ldisc = tty->tty_ldisc; KASSERT(NULL != ldisc); KASSERT(NULL != ldisc->ld_ops); KASSERT(NULL != ldisc->ld_ops->process_char); driver = tty->tty_driver; KASSERT(NULL != driver); KASSERT(NULL != driver->ttd_ops); KASSERT(NULL != driver->ttd_ops->provide_char); data = driver->ttd_ops->block_io(driver); nbytes = 0; for (i = 0; i < count; ++i) { const char *out = ldisc->ld_ops->process_char(ldisc, cbuf[i]); ++nbytes; tty_echo(driver, out); } driver->ttd_ops->unblock_io(driver, data); return nbytes; /*DRIVERS }}}*/ return 0; }
//echo in the kshell will call this // call tty_echo int tty_write(bytedev_t *dev, int offset, const void *buf, int count) { char * buffer = (char *) buf; tty_device_t *tty = bd_to_tty(dev); //unit8_t intr = intr_getipl(); void * data = tty->tty_driver->ttd_ops->block_io(tty->tty_driver); int i = 0; while(i < count && buffer[i] != '\0'){ char * tem = tty->tty_ldisc->ld_ops->process_char(tty->tty_ldisc, buffer[i]); tty_echo(tty->tty_driver, tem); //kfree(tem); i++; } //buf = buffer; tty->tty_driver->ttd_ops->unblock_io(tty->tty_driver, data); NOT_YET_IMPLEMENTED("DRIVERS: tty_write"); return 0; }
static int tty_input(struct tty *t, char ch, unsigned char flag) { cc_t *cc = t->termios.c_cc; int ignore_cr; int raw_mode; int is_eol; int got_data; raw_mode = !TC_L(t, ICANON); /* Newline control: IGNCR, ICRNL, INLCR */ ignore_cr = TC_I(t, IGNCR) && ch == '\r'; if (!ignore_cr) { if (TC_I(t, ICRNL) && ch == '\r') ch = '\n'; if (TC_I(t, INLCR) && ch == '\n') ch = '\r'; } is_eol = (ch == '\n' || ch == cc[VEOL]); if (ignore_cr) goto done; /* Handle erase/kill */ if (!raw_mode) { int erase_all = (ch == cc[VKILL]); if (erase_all || ch == cc[VERASE] || ch == '\b') { struct ring edit_ring; size_t erase_len = ring_data_size( tty_edit_ring(t, &edit_ring), TTY_IO_BUFF_SZ); if (erase_len) { if (!erase_all) erase_len = 1; t->i_ring.head -= erase_len - TTY_IO_BUFF_SZ; ring_fixup_head(&t->i_ring, TTY_IO_BUFF_SZ); while (erase_len--) tty_echo_erase(t); } goto done; } } /* Finally, store and echo the char. * * When i_ring is near to become full, only raw or a line ending chars are * handled. This lets canonical read to see the line with \n or EOL at the * end, even when some chars are missing. */ if (ring_room_size(&t->i_ring, TTY_IO_BUFF_SZ) > !(raw_mode || is_eol)) if (ring_write_all_from(&t->i_ring, t->i_buff, TTY_IO_BUFF_SZ, &ch, 1)) tty_echo(t, ch); done: got_data = (raw_mode || is_eol || ch == cc[VEOF]); if (got_data) { t->i_canon_ring.head = t->i_ring.head; if (raw_mode) /* maintain it empty */ t->i_canon_ring.tail = t->i_canon_ring.head; } return got_data; }
int tty_inproc(uint8_t minor, unsigned char c) { unsigned char oc; struct termios *td; struct s_queue *q = &ttyinq[minor]; int canon; uint16_t pgrp = tty_pgrp[minor]; uint8_t wr; td = &ttydata[minor]; canon = td->c_lflag & ICANON; if (td->c_iflag & ISTRIP) c &= 0x7f; /* Strip off parity */ if (canon && !c) return 1; /* Simply quit if Null character */ #ifdef CONFIG_IDUMP if (c == 0x1a) /* ^Z */ idump(); /* (For debugging) */ #endif #ifdef CONFIG_MONITOR if (c == 0x01) /* ^A */ trap_monitor(); #endif if (c == '\r' && (td->c_iflag & ICRNL)) c = '\n'; if (c == '\n' && (td->c_iflag & INLCR)) c = '\r'; if (td->c_lflag & ISIG) { if (c == td->c_cc[VINTR]) { /* ^C */ sgrpsig(pgrp, SIGINT); clrq(q); stopflag[minor] = flshflag[minor] = false; return 1; } else if (c == td->c_cc[VQUIT]) { /* ^\ */ sgrpsig(pgrp, SIGQUIT); clrq(q); stopflag[minor] = flshflag[minor] = false; return 1; } } if (c == td->c_cc[VDISCARD]) { /* ^O */ flshflag[minor] = !flshflag[minor]; return 1; } if (td->c_iflag & IXON) { if (c == td->c_cc[VSTOP]) { /* ^S */ stopflag[minor] = true; return 1; } if (c == td->c_cc[VSTART]) { /* ^Q */ stopflag[minor] = false; wakeup(&stopflag[minor]); return 1; } } if (canon) { if (c == td->c_cc[VERASE]) { if (uninsq(q, &oc)) { if (oc == '\n' || oc == td->c_cc[VEOL]) insq(q, oc); /* Don't erase past nl */ else if (td->c_lflag & ECHOE) tty_erase(minor); return 1; } else if (c == td->c_cc[VKILL]) { while (uninsq(q, &oc)) { if (oc == '\n' || oc == td->c_cc[VEOL]) { insq(q, oc); /* Don't erase past nl */ break; } if (td->c_lflag & ECHOK) tty_erase(minor); } return 1; } } } /* All modes come here */ if (c == '\n') { if ((td->c_oflag & OPOST | ONLCR) == OPOST | ONLCR) tty_echo(minor, '\r'); } wr = insq(q, c); if (wr) tty_echo(minor, c); else if (minor < PTY_OFFSET) tty_putc_wait(minor, '\007'); /* Beep if no more room */ if (!canon || c == td->c_cc[VEOL] || c == '\n' || c == td->c_cc[VEOF]) wakeup(q); return wr; }
/* * Process input of a single character received on a tty. * echo if required. * This may be called with interrupt level. */ void tty_input(int c, struct tty *tp) { unsigned char *cc; tcflag_t iflag, lflag; int sig = -1; DPRINTF(TTYDB_CORE, ("tty_input: %d\n", c)); // Reload power management timer */ pm_notify(PME_USER_ACTIVITY); lflag = tp->t_lflag; iflag = tp->t_iflag; cc = tp->t_cc; #if defined(DEBUG) && defined(CONFIG_KD) if (c == cc[VDDB]) { kd_enter(); tty_flush(tp, FREAD | FWRITE); goto endcase; } #endif /* !CONFIG_KD*/ /* IGNCR, ICRNL, INLCR */ if (c == '\r') { if (iflag & IGNCR) goto endcase; else if (iflag & ICRNL) c = '\n'; } else if (c == '\n' && (iflag & INLCR)) { c = '\r'; } if (iflag & IXON) { /* stop (^S) */ if (c == cc[VSTOP]) { if (!(tp->t_state & TS_TTSTOP)) { tp->t_state |= TS_TTSTOP; return; } if (c != cc[VSTART]) return; /* if VSTART == VSTOP then toggle */ goto endcase; } /* start (^Q) */ if (c == cc[VSTART]) goto restartoutput; } if (lflag & ICANON) { /* erase (^H / ^?) or backspace */ if (c == cc[VERASE] || c == '\b') { if (!ttyq_empty(&tp->t_rawq)) tty_rubout(tty_unputc(&tp->t_rawq), tp); goto endcase; } /* kill (^U) */ if (c == cc[VKILL]) { while (!ttyq_empty(&tp->t_rawq)) tty_rubout(tty_unputc(&tp->t_rawq), tp); goto endcase; } } if (lflag & ISIG) { /* quit (^C) */ if (c == cc[VINTR] || c == cc[VQUIT]) { if (!(lflag & NOFLSH)) { tp->t_state |= TS_ISIG; tty_flush(tp, FREAD | FWRITE); } tty_echo(c, tp); sig = (c == cc[VINTR]) ? SIGINT : SIGQUIT; goto endcase; } /* suspend (^Z) */ if (c == cc[VSUSP]) { if (!(lflag & NOFLSH)) { tp->t_state |= TS_ISIG; tty_flush(tp, FREAD | FWRITE); } tty_echo(c, tp); sig = SIGTSTP; goto endcase; } } /* * Check for input buffer overflow */ if (ttyq_full(&tp->t_rawq)) { tty_flush(tp, FREAD | FWRITE); goto endcase; } tty_putc(c, &tp->t_rawq); if (lflag & ICANON) { if (c == '\n' || c == cc[VEOF] || c == cc[VEOL]) { tty_catq(&tp->t_rawq, &tp->t_canq); sem_post(&tp->t_input); } } else { sem_post(&tp->t_input); } if (lflag & ECHO) tty_echo(c, tp); endcase: /* * IXANY means allow any character to restart output. */ if ((tp->t_state & TS_TTSTOP) && (iflag & IXANY) == 0 && cc[VSTART] != cc[VSTOP]) return; restartoutput: tp->t_state &= ~TS_TTSTOP; if (sig != -1) { if (tp->t_pid) { tp->t_signo = sig; sched_dpc(&tp->t_dpc, &tty_signal, tp); } } tty_start(tp); }
/* This routine processes a character in response to an interrupt. It * adds the character to the tty input queue, echoing and processing * backspace and carriage return. If the queue contains a full line, * it wakes up anything waiting on it. If it is totally full, it beeps * at the user. * UZI180 - This routine is called from the raw Hardware read routine, * either interrupt or polled, to process the input character. HFB */ int tty_inproc(uint8_t minor, unsigned char c) { unsigned char oc; int canon; uint8_t wr; struct tty *t = &ttydata[minor]; struct s_queue *q = &ttyinq[minor]; canon = t->termios.c_lflag & ICANON; if (t->termios.c_iflag & ISTRIP) c &= 0x7f; /* Strip off parity */ if (canon && !c) return 1; /* Simply quit if Null character */ #ifdef CONFIG_IDUMP if (c == 0x1a) /* ^Z */ idump(); /* (For debugging) */ #endif #ifdef CONFIG_MONITOR if (c == 0x01) /* ^A */ trap_monitor(); #endif if (c == '\r' && (t->termios.c_iflag & ICRNL)) c = '\n'; if (c == '\n' && (t->termios.c_iflag & INLCR)) c = '\r'; if (t->termios.c_lflag & ISIG) { if (c == t->termios.c_cc[VINTR]) { /* ^C */ wr = SIGINT; goto sigout; } else if (c == t->termios.c_cc[VQUIT]) { /* ^\ */ wr = SIGQUIT; sigout: sgrpsig(t->pgrp, wr); clrq(q); t->flag &= ~(TTYF_STOP | TTYF_DISCARD); return 1; } } if (c == t->termios.c_cc[VDISCARD]) { /* ^O */ t->flag ^= TTYF_DISCARD; return 1; } if (t->termios.c_iflag & IXON) { if (c == t->termios.c_cc[VSTOP]) { /* ^S */ t->flag |= TTYF_STOP; return 1; } if (c == t->termios.c_cc[VSTART]) { /* ^Q */ t->flag &= ~TTYF_STOP; wakeup(&t->flag); return 1; } } if (canon) { if (c == t->termios.c_cc[VERASE]) { wr = ECHOE; goto eraseout; } else if (c == t->termios.c_cc[VKILL]) { wr = ECHOK; goto eraseout; } } /* All modes come here */ if (c == '\n') { if ((t->termios.c_oflag & (OPOST | ONLCR)) == (OPOST | ONLCR)) tty_echo(minor, '\r'); } wr = insq(q, c); if (wr) tty_echo(minor, c); else tty_putc(minor, '\007'); /* Beep if no more room */ if (!canon || c == t->termios.c_cc[VEOL] || c == '\n' || c == t->termios.c_cc[VEOF]) wakeup(q); return wr; eraseout: while (uninsq(q, &oc)) { if (oc == '\n' || oc == t->termios.c_cc[VEOL]) { insq(q, oc); /* Don't erase past nl */ break; } if (t->termios.c_lflag & wr) tty_erase(minor); if (wr == ECHOE) break; } return 1; }
/* * Process input of a single character received on a tty. * echo if required. * This may be called with interrupt level. */ void tty_input(int c, struct tty *tp) { unsigned char *cc; tcflag_t iflag, lflag; int sig = -1; #ifdef CONFIG_CPUFREQ /* Reload power management timer */ pm_active(); #endif lflag = tp->t_lflag; iflag = tp->t_iflag; cc = tp->t_cc; /* IGNCR, ICRNL, INLCR */ if (c == '\r') { if (iflag & IGNCR) goto endcase; else if (iflag & ICRNL) c = '\n'; } else if (c == '\n' && (iflag & INLCR)) c = '\r'; if (iflag & IXON) { /* stop (^S) */ if (c == cc[VSTOP]) { if (!(tp->t_state & TS_TTSTOP)) { tp->t_state |= TS_TTSTOP; return; } if (c != cc[VSTART]) return; /* if VSTART == VSTOP then toggle */ goto endcase; } /* start (^Q) */ if (c == cc[VSTART]) goto restartoutput; } if (lflag & ICANON) { /* erase (^H / ^?) or backspace */ if (c == cc[VERASE] || c == '\b') { if (!ttyq_empty(&tp->t_rawq)) { ttyq_unputc(&tp->t_rawq); tty_rubout(tp); } goto endcase; } /* kill (^U) */ if (c == cc[VKILL]) { while (!ttyq_empty(&tp->t_rawq)) { ttyq_unputc(&tp->t_rawq); tty_rubout(tp); } goto endcase; } } if (lflag & ISIG) { /* quit (^C) */ if (c == cc[VINTR] || c == cc[VQUIT]) { if (!(lflag & NOFLSH)) tty_flush(tp, FREAD | FWRITE); tty_echo(c, tp); sig = (c == cc[VINTR]) ? SIGINT : SIGQUIT; goto endcase; } /* suspend (^Z) */ if (c == cc[VSUSP]) { if (!(lflag & NOFLSH)) tty_flush(tp, FREAD | FWRITE); tty_echo(c, tp); sig = SIGTSTP; goto endcase; } } /* * Check for input buffer overflow */ if (ttyq_full(&tp->t_rawq)) { tty_flush(tp, FREAD | FWRITE); goto endcase; } ttyq_putc(c, &tp->t_rawq); if (lflag & ICANON) { if (c == '\n' || c == cc[VEOF] || c == cc[VEOL]) { tty_catq(&tp->t_rawq, &tp->t_canq); sched_wakeup(&tp->t_input); } } else sched_wakeup(&tp->t_input); if (lflag & ECHO) tty_echo(c, tp); endcase: /* * IXANY means allow any character to restart output. */ if ((tp->t_state & TS_TTSTOP) && (iflag & IXANY) == 0 && cc[VSTART] != cc[VSTOP]) return; restartoutput: tp->t_state &= ~TS_TTSTOP; if (sig != -1) { if (sig_task) exception_post(sig_task, sig); } tty_start(tp); }
int tty_read(struct inode *inode, struct file *file, char *data, int len) { #if 1 register struct tty *tty = determine_tty(inode->i_rdev); register char *pi = 0; int j, k; int rawmode = (tty->termios.c_lflag & ICANON) ? 0 : 1; int blocking = (file->f_flags & O_NONBLOCK) ? 0 : 1; unsigned char ch; if (len != 0) { do { if (tty->ops->read) { tty->ops->read(tty); blocking = 0; } j = chq_getch(&tty->inq, &ch, blocking); if (j == -1) { if (!blocking) break; return -EINTR; } if (!rawmode && (j == 04)) /* CTRL-D */ break; if (rawmode || (j != '\b')) { pokeb(current->t_regs.ds, (__u16) (data + ((int)pi)), ch); ++pi; tty_echo(tty, ch); } else if (((int)pi) > 0) { --pi; k = ((peekb(current->t_regs.ds, (__u16) (data + ((int)pi))) == '\t') ? TAB_SPACES : 1); do { tty_echo(tty, ch); } while (--k); } } while (((int)pi) < len && (rawmode || j != '\n')); } return (int) pi; #else register struct tty *tty = determine_tty(inode->i_rdev); int i = 0, j = 0, k, lch; int rawmode = (tty->termios.c_lflag & ICANON) ? 0 : 1; int blocking = (file->f_flags & O_NONBLOCK) ? 0 : 1; unsigned char ch; if (len == 0) return 0; do { if (tty->ops->read) { tty->ops->read(tty); blocking = 0; } j = chq_getch(&tty->inq, &ch, blocking); if (j == -1) if (blocking) return -EINTR; else break; if (!rawmode && (j == 04)) /* CTRL-D */ break; if (rawmode || (j != '\b')) { pokeb(current->t_regs.ds, (__u16) (data + i++), ch); tty_echo(tty, ch); } else if (i > 0) { lch = ((peekb(current->t_regs.ds, (__u16) (data + --i)) == '\t') ? TAB_SPACES : 1); for (k = 0; k < lch; k++) tty_echo(tty, ch); } } while (i < len && (rawmode || j != '\n')); return i; #endif }