📄 tty.n.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"# 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; /* Sets up physical device defined in ttydevsw[] */ (*ttydevsw[dev].setfnc)(ttydevsw[dev].m_m_dev); tty->tx_ewait = 0; /* Normal output of buffer */ 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){ ttys[dev].nopens--; 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; /* 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 */ sleep((caddr_t)&ttys[dev].inbuf,PTTY); break; case WWAITB: /* Sets process to sleep on txbuf */ sleep((caddr_t)&ttys[dev].outbuf,PTTY); break; case WWAITC: /* Sets process to sleep on txbuf waiting for character to * be written. */ ttys[dev].tx_ewait = 1; sleep((caddr_t)&ttys[dev].outbuf,PTTY); ttys[dev].tx_ewait = 0; break; }}/* * 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 { if(ch == tty->tchars.t_intrc){ /* Send signal to processes flag signal only */ sendgrp(tty->dev,SIGINT,0); dont_put = 1; /* Don't output */ break; } if(ch == tty->tchars.t_quitc){ /* Send signal to processes flag signal only */ sendgrp(tty->dev,SIGQUIT,0); 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)){ tputout(tty->dev,&ch,1); /* No check if done */ } } } /* Sets buffer ready flag if apropriate */ if(bufrdy){ tty->inbuf.outrdy = RDY; wakeup((caddr_t)&tty->inbuf);#ifdef EVENTSON devevent(DEVTTYMAJ, tty->dev);#endif EVENTSON } /* 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; /* Send character imediatly wait untill device ready */ writechar(dev,tty->tchars.t_stopc); } } return 1;}/* * Readchar Will wait until a character is ready * passing through ttywait(), to indicate * that the tty handler is dossing around again. * Then low and behold it gets the character Weyyy! * (ps thats a Mark'ism.) */charreadchar(dev)short dev;{ short intlevel; char ch; intlevel = SPLTTY(); /* Wait until device is ready , only if polled device */ if(!ttydevsw[dev].type){ while(!((*ttydevsw[dev].status)(ttydevsw[dev].m_m_dev) & RRDY)) ttywait(dev,RWAITC); } /* Get character character */ ch = (*ttydevsw[dev].rchar)(ttydevsw[dev].m_m_dev); splx(intlevel); return ch;}/* * Rubout - rubs out chars in buffer * will rub out no more than 'count' chars. * will rub out only till the start of the buffer * Returns actual no. rubbed out. */rubout(tty,count)struct ttystruct *tty;int count;{ char ch; int cnt; char *botbuf; /* Start address of buffer */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -