📄 termio.c
字号:
/* $Id: termio.c,v 1.9 2003/07/11 12:03:09 pefo Exp $ *//* * Copyright (c) 2002 Opsycon AB (www.opsycon.se) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Opsycon AB. * 4. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */#include <sys/param.h>#include <stdlib.h>#include <queue.h>#include <stdio.h>#include <stdarg.h>#include <string.h>#include <termio.h>#include <unistd.h>#include <setjmp.h>#include <errno.h>#include <sys/ioctl.h>#include <file.h>#include <pmon.h>int term_open __P((int, const char *, int, int));int term_close __P((int));int term_read __P((int, void *, size_t));int term_write __P((int, const void *, size_t));int term_ioctl (int fd, unsigned long op, ...);static void chwrite __P((DevEntry *, char));extern void vga_putc(char);extern void gsignal __P((struct jmp_buf *, int sig));extern ConfigEntry ConfigTable[];extern int errno;DevEntry DevTable[DEV_MAX];typedef int tFunc __P((int, int, int, int));struct TermEntry { char *name; tFunc *func;};struct TermEntry TermTable[] ={#if 0 {"tvi920", tvi920},#endif {"vt100", vt100}, {0}};struct TermDev { int dev;};static voidsetsane(DevEntry *p){ p->t.c_iflag |= (ISTRIP | ICRNL | IXON); p->t.c_oflag = (ONLCR); p->t.c_lflag = (ICANON | ISIG | ECHO | ECHOE); p->t.c_cc[VINTR] = CNTRL ('c'); p->t.c_cc[VEOL] = '\n'; p->t.c_cc[VEOL2] = CNTRL ('c'); p->t.c_cc[VERASE] = CNTRL ('h'); p->t.c_cc[V_STOP] = CNTRL ('s'); p->t.c_cc[V_START] = CNTRL ('q');}voidreschedule (p) char *p;{ scandevs ();}#define reschedule(p) scandevs()extern void dbglednum(int);intterm_write (int fd, const void *buf, size_t nchar){ DevEntry *p; struct TermDev *devp; char *buf2 = (char *)buf; int i, n; devp = (struct TermDev *)_file[fd].data; p = &DevTable[devp->dev]; n = nchar; while (n > 0) { /* << LOCK >> */ while(!tgt_smplock()); i = Qspace (p->txq); while (i > 2 && n > 0) { if ((p->t.c_oflag & ONLCR) && *buf2 == '\n') { Qput(p->txq, '\r'); i--; } Qput(p->txq, *buf2++); n--; i--; } tgt_smpunlock(); /* << UNLOCK >> */ while (Qused(p->txq)) { scandevs(); } } return (nchar);}/* * High priority write. Just get the char out! */static voidchwrite (DevEntry *p, char ch){ while (!(*p->handler) (OP_TXRDY, p, NULL, NULL)); (*p->handler) (OP_TX, p, NULL, ch);}voidscandevs (){ int s, c, n; int signaled; DevEntry *p; for (p = DevTable; p->rxq;) { signaled = 0; /* << LOCK >> */ while(!tgt_smplock()); /* Read queue */ while ((*p->handler) (OP_RXRDY, p, NULL, NULL)) { c = (*p->handler) (OP_RX, p, NULL, NULL); if (p->t.c_iflag & ISTRIP) c &= 0x7f; if (p->t.c_lflag & ISIG) { if (c == p->t.c_cc[VINTR]) { signaled = 1; break; } } if (p->t.c_iflag & IXON) { if (p->t.c_iflag & IXANY && p->txoff) { p->txoff = 0; continue; } if (c == p->t.c_cc[V_STOP]) { p->txoff = 1; continue; } if (c == p->t.c_cc[V_START]) { p->txoff = 0; continue; } } n = Qspace (p->rxq); if (n > 0) { Qput (p->rxq, c); if (n < 20 && !p->rxoff) { (*p->handler) (OP_RXSTOP, p, NULL, p->rxoff = 1); if (p->t.c_iflag & IXOFF) chwrite (p, CNTRL ('S')); } } } /* Write queue */ if (!signaled) { n = Qused (p->txq); while (n > 0 && !p->txoff && (*p->handler)(OP_TXRDY, p, NULL, NULL)) { char c = Qget(p->txq); (*p->handler) (OP_TX, p, NULL, c); n--; } } tgt_smpunlock(); /* << UNLOCK >> */ if (signaled) gsignal (p->intr/*XXX*/, 2 /*SIGINT*/); else p++; }#if defined(SMP) if (tgt_smpwhoami() != 0) return; /* Only CPU 1 is allowed to run kernel */#endif s = splhigh(); /* Trigg the polled interrupt system */ splx(s);#ifdef NETIO tgt_netpoll (); /* XXX this one should die! */#endif}/** ioctl(fd,op,argp) perform control operation on fd */intterm_ioctl (int fd, unsigned long op, ...){ DevEntry *p; struct termio *at; int i; void *argp; va_list ap; struct TermDev *devp; devp = (struct TermDev *)_file[fd].data; va_start(ap, op); argp = va_arg(ap, void *); va_end(ap); if (devp->dev < 0) return -1; p = &DevTable[devp->dev]; switch (op) { case TCGETA: *(struct termio *)argp = p->t; break; case TCSETAF: /* after flush of input queue */ while (!Qempty (p->rxq)) Qget (p->rxq); (*p->handler) (OP_FLUSH, p, NULL, 1); if (p->rxoff) { (*p->handler) (OP_RXSTOP, p, NULL, p->rxoff = 0); if (p->t.c_iflag & IXOFF) chwrite (p, CNTRL ('Q')); } case TCSETAW: /* after write */ /* no txq, so no delay needed */ at = (struct termio *)argp; if (p->t.c_ispeed != at->c_ispeed) { if ((*p->handler) (OP_BAUD, p, NULL, at->c_ispeed)) return -1; } p->t = *at; break; case FIONREAD: scandevs (); *(int *)argp = Qused (p->rxq); break; case SETINTR: p->intr = (struct jmp_buf *) argp; break; case GETINTR: *(struct jmp_buf **) argp = p->intr; break; case SETSANE: (*p->handler) (OP_RESET, p, NULL, 0); setsane(p); break; case SETNCNE: if (argp) *(struct termio *)argp = p->t; p->t.c_lflag &= ~(ICANON | ECHO | ECHOE); p->t.c_cc[4] = 1; break; case CBREAK: if (argp) *(struct termio *)argp = p->t; p->t.c_lflag &= ~(ICANON | ECHO); p->t.c_cc[4] = 1; break; case GETTERM: *(int *)argp = 0; if (p->tfunc == 0) return (-1); strcpy ((char *)argp, p->tname); break; case SETTERM: for (i = 0; TermTable[i].name; i++) { if (!strcmp(argp, TermTable[i].name)) break; } default: break; } return 0;}intdevinit (void){ int i, brate; ConfigEntry *q; DevEntry *p; char dname[10]; char *s; strcpy(dname, "tty_baud"); for (i = 0; ConfigTable[i].devinfo && i < DEV_MAX; i++) { q = &ConfigTable[i]; p = &DevTable[i]; p->txoff = 0; p->qsize = q->rxqsize; p->sio = q->devinfo; p->chan = q->chan; p->rxoff = 0; p->handler = q->handler; p->tfunc = 0; p->freq = q->freq; p->nopen = 0; if (p->chan == 0) (*p->handler) (OP_INIT, p, NULL, q->rxqsize); p->rxq = Qcreate (p->qsize); p->txq = Qcreate (p->qsize); if (p->rxq == 0 || p->txq == 0) return (-1); /* * program requested baud rate, but fall back to default * if there is a problem *//* XXX don't work. env init is not called yet. has to be solved */ dname[3] = (i < 10) ? i + '0' : i - 10 + 'a'; if ((s = getenv(dname)) == 0 || (brate = getbaudrate(s)) == 0) brate = q->brate; if (brate != q->brate) { if ((*p->handler)(OP_BAUD, p, NULL, brate)) { brate = q->brate; (void)(*p->handler)(OP_BAUD, p, NULL, brate); } } p->t.c_ispeed = brate; p->t.c_ospeed = brate; } return (0);}/* term_open(fname,mode,perms) return fd for fname */intterm_open(int fd, const char *fname, int mode, int perms){ int c, dev; char *dname; struct TermDev *devp; DevEntry *p; dname = (char *)fname; if (strncmp (dname, "/dev/", 5) == 0) dname += 5; if (strlen (dname) == 4 && strncmp (dname, "tty", 3) == 0) { c = dname[3]; if (c >= 'a' && c <= 'z') dev = c - 'a' + 10; else if (c >= 'A' && c <= 'Z') dev = c - 'A' + 10; else if (c >= '0' && c <= '9') dev = c - '0'; if (dev >= DEV_MAX || DevTable[dev].rxq == 0) return -1; devp = (struct TermDev *)malloc(sizeof(struct TermDev)); if (devp == NULL) { errno = ENOMEM; return -1; } devp->dev = dev; _file[fd].data = (void *)devp; p = &DevTable[dev]; (*p->handler) (OP_OPEN, p, NULL, 0); if (p->nopen++ == 0) term_ioctl (fd, SETSANE); } else { return -1; } return fd;}/** term_close(fd) close fd */intterm_close(int fd){ DevEntry *p = &DevTable[(((struct TermDev *)_file[fd].data))->dev]; (*p->handler) (OP_CLOSE, p, NULL, 0); if (p->nopen) p->nopen--; free(_file[fd].data); return 0;}/** term_read(fd,buf,n) read n bytes into buf from fd */intterm_read (fd, buf, n) int fd; size_t n; void *buf;{ int i, used; DevEntry *p; char ch; struct TermDev *devp; char *buf2 = buf; devp = (struct TermDev *)_file[fd].data; p = &DevTable[devp->dev]; for (i = 0; i < n;) { scandevs (); /* << LOCK >> */ while(!tgt_smplock()); if ((used = Qused (p->rxq)) == 0) { tgt_smpunlock(); continue; } if (used < 20 && p->rxoff) { (*p->handler) (OP_RXSTOP, p, NULL, p->rxoff = 0); if (p->t.c_iflag & IXOFF) chwrite (p, CNTRL ('Q')); } ch = Qget (p->rxq); tgt_smpunlock(); /* << UNLOCK >> */ if (p->t.c_iflag & ICRNL && ch == '\r') ch = '\n'; if (p->t.c_lflag & ICANON) { if (ch == p->t.c_cc[VERASE]) { if (i > 0) { i--; if (p->t.c_lflag & ECHOE) write (fd, "\b \b", 3); else if (p->t.c_lflag & ECHO) write (fd, "\b", 1); } continue; } if (p->t.c_lflag & ECHO) write (fd, &ch, 1); buf2[i++] = ch; if (ch == p->t.c_cc[VEOL] || ch == p->t.c_cc[VEOL2]) break; } else { buf2[i++] = ch; } } return i;}static FileSystem termfs ={ "tty", FS_TTY, term_open, term_read, term_write, NULL, term_close, term_ioctl};static void init_fs __P((void)) __attribute__ ((constructor));static void init_fs(){ SBD_DISPLAY ("DEVI", CHKPNT_DEVI); devinit (); /* * Install terminal based file system. */ filefs_init(&termfs); /* * Create the standard i/o files the proper way */ _file[0].valid = 1; _file[0].fs = &termfs; _file[1].valid = 1; _file[1].fs = &termfs; _file[2].valid = 1; _file[2].fs = &termfs; term_open(0, "/dev/tty0", 0, 0); /* stdin */ term_open(1, "/dev/tty0", 0, 0); /* stdout */ term_open(2, "/dev/tty0", 0, 0); /* stderr */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -