📄 tty.c
字号:
/****************************************************************************** * TTY handler T.Barnaby 1/6/85 ****************************************************************************** * * Interupt or polled driven TTY handler for OMU to emulate the Codata * TTY interface. * * Implements :- * RAW, CBREAK, ECHO, CRMOD, TANDEM, XTABS, CRDELAY * * Knows about special characters (erase, kill, start, * stop, interupt, quit, eof, input delim). * * Does Xon, Xoff properly ? * * Full 8 bits in RAW, 7 bits masked on all other inputs * 8 bits on all outputs * * No parity checking performed, tested, done, thought about * etc etc ... * * Baud rates settable as per Codata On output speed only. * * Most Ioctls work except TIOCEXCL, TIOCNXLL and TIOCHPCL. * * CR and NL delays included with simple loop timmer (delaym()) * NL1 is set to around 5ms * * Quit, and interupt not implemented as yet * * Main routines called from KERNEL are:- * * o_tty() Opens and sets up a new device for I/O * * c_tty() Closes a device * * r_tty() Reads characters from device, waits till * they are available and returns number read. * * w_tty() Write characters to the device waits till * TTY buffer has them all * * i_tty() Ioctl routine does all ioctl's * * Routines for Kernel error print etc (Polled output):- * * putchar() Console character output polled direct * output. * * getchar() Console character input polled direct * input. * * Routines called from device drivers :- * * ttyin() Input a character from the device to input * buffer. * * ttyout() Output a character to device from output * buffer. * * Other routines :- * * ttywait() While the TTY handler is waiting around * it passes through this routine , and is * given the device number and a flag * indicating if the wait is for * write or for read . * This routine calls sleep() which will * cause the process to sleep unitil the * required event has occured. * NOTE Wait during WWAITB could have a race * hazard if sleep is called after the last * character in the buffer has been transmitted * * tputout() Puts a number of characters into the * Output buffer and initiates real device * output. * * tputbuf() Puts as many characters as posible, or * the number given into the input, or output * buffer given. * * tgetbuf() Gets as many characters as posible, or * the number given from the input, or output * buffer given. * * writechar() Does actual character write * * readchar() Does actual character read * * NOTE at the moment the extending of characters on output * (CRMOD, XTABS etc), is done when an interupt or * the next character is required from the buffer. * This means that the extra characters added are * polled out even when in interupt mode. * CR, and NL delays are done here. * * External routines used:- * * All the device driver routines in tty device switch. * * SPLTTY() Mask interupt level (Noramlly level 6 * defined in excep.h). * splx() Sets the interupt level back * sleep() Causes the process to go to sleep awaiting * an event * wakeup() Flags all processes that an event has occured * sendgrp() Sends a signal to a process group using this tty * * Events * If EVENTSON is defined, every time a buffer is ready, * devevent() is called with the major and minor dev numbers. */# include "../../include/param.h"# include <sgtty.h># include <sys/ioctl.h># include "../../include/inode.h"# include "../../include/signal.h"# include "../../include/procs.h"# include "../../include/excep.h"# include "../../include/dev.h"# include "../../include/state.h"#ifdef VIWINDOWS# include <sys/viinfo.h># include <sys/touch.h>#endif# include "tty.h"extern struct ttydev ttydevsw[]; /* TTY dev switch */char putchar(), getchar(), writechar(), readchar();/* TTY structure */struct ttystruct ttys[NDEVS];/* * Open a tty device * * If the minor device is not open it is opened by calling * Its initialisation routine as defined in the * minor, minor tty device switch (ttydevsw[]) */o_tty(dev){ struct ttystruct *tty; /* Check if device valid */ if (dev < NDEVS){ tty = &ttys[dev]; /* Pointer to dev structure */ /* Sets processes controlling terminal if this is it. * Checks if no valid controlling tty if so set it. * I don't like this bit so it may be changed later. */ if(cur_proc->tty == -1) cur_proc->tty = dev; /* If first open set up line */ if (tty->nopens++ == 0){ /* valid device, unopened */ tty->dev = dev; /* Device No */ tty->col = 0; /* Column 0 */ tty->line = 0; /* Line 0 */ /* Input buffer */ flush(&tty->inbuf); /* Output buffer */ flush(&tty->outbuf); tty->inxoff = XONSTATE; /* Xon Xoff flags */ tty->outxoff = XONSTATE; /* Setup tty.sgtty */ tty->sgtty.sg_ispeed = tty->sgtty.sg_ospeed = INITBAUD; tty->sgtty.sg_erase = CERASE; tty->sgtty.sg_kill = CKILL; tty->sgtty.sg_flags = INITFLAGS; /* Gets special charcters */ tty->tchars.t_intrc = CINTR; tty->tchars.t_quitc = CQUIT; tty->tchars.t_startc = CSTART; tty->tchars.t_stopc = CSTOP; tty->tchars.t_eofc = CEOT; tty->tchars.t_brkc = CBRK;#ifdef VIWINDOWS /* Sets up window mode bits */ tty->wintty.wmode = TTYWINOFF; tty->wintty.cpid = cur_proc->pid; tty->wintty.tflag = TFLGNONE; tty->wintty.iflag = IFLGNONE;#endif /* Sets up physical device defined in ttydevsw[] */ (*ttydevsw[dev].setfnc)(ttydevsw[dev].m_m_dev); tty->tx_rdy = RDY; /* Tx is ready for output */ } return 0; } /* invalid minor device */ return -1;}/* * Close a TTY device */c_tty(dev){ /* Check if valid device opened */ if (dev < NDEVS && ttys[dev].nopens > 0){#ifdef VIWINDOWS if(!ttys[dev].nopens--){ /* Sets up window mode bits */ ttys[dev].wintty.wmode = TTYWINOFF; ttys[dev].wintty.tflag = TFLGNONE; ttys[dev].wintty.iflag = IFLGNONE; }#else ttys[dev].nopens--;#endif return 0; } else return -1;}/* * R_tty Read characters from input buffer if available * Returns number actualy read. * Will wait untill the buffer is ready for output * ie in line mode will wait for NL before returning. */r_tty(dev, buffer, nbytes)char *buffer;{ int bytecount; struct ttystruct *tty; tty = &ttys[dev]; /* Waits until characters are available and will return * a maxinum of nbytes */ while(!tty->inbuf.outrdy){ /* If polled Gets a character when available */ if(ttydevsw[dev].type == POLLED){ ttyin(dev); /* Get a character */ } /* Call ttywait to indicate tty handler is dossing around */ else{ ttywait(dev,RWAITB); } } /* Fetches the characters from the buffer */ bytecount = tgetbuf((&tty->inbuf),buffer,nbytes); /* Do tandem bit if nescecary */ if(tty->sgtty.sg_flags & TANDEM){ /* If bellow LW mark and in Xoff state send Xon char */ if(tty->inbuf.inrdy && tty->inxoff){ tty->inxoff = XONSTATE; /* Send character immeadiatly */ writechar(dev, tty->tchars.t_startc); } } return bytecount;}/* * W_tty write characters to output buffer, wait until all * the characters are in the buffer */w_tty(dev, buffer, nbytes)int nbytes;int dev;char *buffer;{ int bytecount; int no;#ifdef VIWINDOWS /* Do these bits if in Window mode */ if(ttys[dev].wintty.wmode & TTYWINON){ return winecho(buffer, nbytes); }#endif /* Write all bytes to tty buffer */ bytecount = nbytes; /* Wait until all bytes are written */ while(bytecount>0){ /* Puts as many bytes as possible to the output buffer * And starts transmission if nessecary */ no = tputout(dev,buffer,bytecount); bytecount -= no; buffer += no; /* Call ttywait to indicate tty handler is dossing around */ if(bytecount > 0) ttywait(dev,WWAITB); } return nbytes;}/* * ttywait All functions withing the tty handler * will pass through here when they are * waiting around for somthing or other. */ttywait(dev,type)short dev;char type;{ int c; switch(type){ case RWAITB: /* Sets process to sleep on rxbuf */ return sleep((caddr_t)&ttys[dev].inbuf,PTTY); case WWAITB: /* Sets process to sleep on txbuf */ return sleep((caddr_t)&ttys[dev].outbuf,PTTY); }}/* * ttyin Character to buffer from device * This routine is called whenever there is a character * ready for input (interupt mode), or when one is required * (polled mode). */ttyin(dev)int dev;{ register struct ttystruct *tty; char ch, bufrdy, dont_put; /* If polled Waits untill there is a character ready before * Getting it. ttywait() is called to indicate that the tty * Handler is dossing arround from within readchar(). */ ch = readchar(dev); tty = &ttys[dev]; /* Gets address of tty structure for device */ tty->inbuf.outrdy = bufrdy = 0; /* Sets buffer to notready for output */ dont_put = 0; /* Dont put character to buffer flag */ /* Checks if not in RAW mode */ if(!(tty->sgtty.sg_flags & RAW)){/* ch &= ~TOPB; */ /* Masks top bit */ /* Check special characters */ do {#ifdef VIWINDOWS /* Do these bits if in Window mode */ if(tty->wintty.wmode & TTYWINON){ switch(tty->wintty.tflag){ case TFLGNONE: /* If Touch Command set command flag */ if(!tty->wintty.iflag && (ch == RTOUCHM0)) tty->wintty.tflag = TFLGCMD; break; case TFLGCMD: /* Command set so get X co-ord */ tty->wintty.ipoint.abs.x = XTOUCH(ch); tty->wintty.tflag = TFLGHASX; break; case TFLGHASX: /* Has X set so get Y co-ord */ tty->wintty.ipoint.abs.y = YTOUCH(ch); tty->wintty.tflag = TFLGHASY; /* Get info on point, mainly PID */ /* controling the window */ /* Get info on point if ok return * touch info */ if(setpoint(tty)){ /* No check if done */ tty->wintty.ipoint.viinfo = IPOINT; tputbuf(&tty->wintty.ipoint,&tty->inbuf,sizeof(struct Ipoint)); bufrdy = 1; } tty->wintty.tflag = TFLGTERM; break; default: break; } switch(tty->wintty.iflag){ case IFLGNONE: /* If Inc Command set command flag */ if(INTYPE(ch) == IINC) tty->wintty.iflag = IFLGCMD; break; case IFLGCMD: tty->wintty.iflag = IFLGNULL; break; case IFLGNULL: tty->wintty.iinc.inc = ch << 8; tty->wintty.iflag = IFLGHIGH; break; case IFLGHIGH: tty->wintty.iinc.inc |= ch; tty->wintty.iflag = IFLGTERM; tty->wintty.iinc.viinfo = IINC; flush(&tty->inbuf); tputbuf(&tty->wintty.iinc,&tty->inbuf,sizeof(struct Iinc)); bufrdy = 1; break; default: break; }#ifdef NEW switch(ch){ case RINCSMALL: case RINCLARGE:#ifdef NEW tty->wintty.iinc.viinfo = IINC; tty->wintty.iinc.inc = 1; tputbuf(&tty->wintty.iinc,&tty->inbuf,sizeof(struct Iinc));#endif /* Put out char */ tputbuf(&ch,&tty->inbuf,1); dont_put = 1; bufrdy = 1; break; case RDECSMALL: case RDECLARGE:#ifdef NEW tty->wintty.iinc.viinfo = IINC; tty->wintty.iinc.inc = -1; tputbuf(&tty->wintty.iinc,&tty->inbuf,sizeof(struct Iinc));#endif /* Put out char */ tputbuf(&ch,&tty->inbuf,1); dont_put = 1; bufrdy = 1; break; default: break; }#endif } /* If point flag set break out */ if(tty->wintty.tflag){ dont_put = 1; if(tty->wintty.tflag == TFLGTERM) tty->wintty.tflag = TFLGNONE; ch = 0; /* To stop further conversions */ break; } /* If Increment flag set break out */ if(tty->wintty.iflag){ dont_put = 1; if(tty->wintty.iflag == IFLGTERM) tty->wintty.iflag = IFLGNONE; ch = 0; /* To stop further conversions */ break; }#endif if(ch == tty->tchars.t_intrc){ /* Send signal to processes flag signal only */#ifdef VIWINDOWS /* Do these bits if in Window mode */ if(tty->wintty.wmode & TTYWINON) sendsig(tty->wintty.cpid, SIGINT, 0); else sendgrp(tty->dev,SIGINT,0);#else sendgrp(tty->dev,SIGINT,0);#endif dont_put = 1; /* Don't output */ break; } if(ch == tty->tchars.t_quitc){ /* Send signal to processes flag signal only */#ifdef VIWINDOWS /* Do these bits if in Window mode */ if(tty->wintty.wmode & TTYWINON) sendsig(tty->wintty.cpid, SIGQUIT, 0); else sendgrp(tty->dev,SIGQUIT,0);#else sendgrp(tty->dev,SIGQUIT,0);#endif dont_put = 1; /* Don't output */ break; } /* Xoff handler , First check if Xoff character */ if(ch == tty->tchars.t_stopc){ dont_put = 1; /* Don't output */ /* Stops output if going */ if(!tty->outxoff){ tty->outxoff = XOFFSTATE; break; } } /* NOTE Xoff can fall through here to allow * Single character Xon/Xoff */ /* Xon handler, first check if Xon character */ if(ch == tty->tchars.t_startc){ dont_put = 1; /* Don't output */ /* Starts output if stoped */ if(tty->outxoff){ tty->outxoff = XONSTATE; if(tty->tx_rdy) ttyout(tty->dev); break; } } /* Do these bits unless in CBREAK mode */ if(!(tty->sgtty.sg_flags & CBREAK)){ /* Eof handler */ if(ch == tty->tchars.t_eofc){ bufrdy = RDY; /* Sets buffer ready */ dont_put = 1; /* Don't output */ break; } /* Erase character */ if(ch == tty->sgtty.sg_erase){ /* rubout - not before start of line */ rubout(tty, 1); dont_put = 1; /* Don't output */ break; } /* Line kill character */ if(ch == tty->sgtty.sg_kill){ /* Rubout till start of buffer */ rubout(tty, tty->inbuf.count); /* Make sure buffer pointers correct */ tty->inbuf.outptr = tty->inbuf.inptr; dont_put = 1; /* Don't output */ break; } } /* End of line character */ if(ch == tty->tchars.t_brkc){ if(ch != (char)(-1)) bufrdy = RDY; break; } }while(0); /* Checks for CRMOD conversion */ if(ch == CR){ /* Check if CRMOD if so do so */ if(tty->sgtty.sg_flags & CRMOD) ch = NL; } /* If line termination set buffer to ready for output */ if(ch == NL) bufrdy = RDY; } /* If RAW or CBREAK set buffer ready all all characters unless * dontput has been set. */ if(!dont_put && (tty->sgtty.sg_flags & (CBREAK | RAW))) bufrdy = RDY; /* Put character to input buffer if required */ if(!dont_put){ /* If no characters have been put then don't echo */ if(tputbuf(&ch,&tty->inbuf,1)){ /* Do echo if required */ if((tty->sgtty.sg_flags & ECHO) && !(tty->sgtty.sg_flags & RAW)){#ifdef VIWINDOWS if(tty->wintty.wmode & TTYWINON){ winecho(&ch, 1); } else{ /* No check if done */ tputout(tty->dev,&ch,1); }#else /* No check if done */ tputout(tty->dev,&ch,1);#endif } } } /* Sets buffer ready flag if apropriate */ if(bufrdy){ tty->inbuf.outrdy = RDY;#ifdef VIWINDOWS /* Do these bits if in Window mode */ if(tty->wintty.wmode & TTYWINON){ wakeupp(tty->wintty.cpid, (caddr_t)&tty->inbuf);#ifdef EVENTSON devevp(tty->wintty.cpid, DEVTTYMAJ, tty->dev);#endif EVENTSON } else { wakeup((caddr_t)&tty->inbuf);#ifdef EVENTSON devevent(DEVTTYMAJ, tty->dev);#endif EVENTSON }#else wakeup((caddr_t)&tty->inbuf);#ifdef EVENTSON devevent(DEVTTYMAJ, tty->dev);#endif EVENTSON#endif } /* Tandem mode check */ if(tty->sgtty.sg_flags & TANDEM){ /* If above HW mark and not in Xoff state send Xoff */ if(!tty->inbuf.inrdy && !tty->inxoff){ tty->inxoff = XOFFSTATE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -