📄 tylib.c
字号:
RNG_ELEM_GET (ringId, &pTyDev->lnBytesLeft, nn); nbytes = min ((int)pTyDev->lnBytesLeft, maxbytes); rngBufGet (ringId, buffer, nbytes); pTyDev->lnBytesLeft -= nbytes; } else nbytes = rngBufGet (ringId, buffer, maxbytes); /* check if XON needs to be output */ if ((pTyDev->options & OPT_TANDEM) && pTyDev->rdState.xoff) { freeBytes = rngFreeBytes (ringId); if (pTyDev->options & OPT_LINE) freeBytes -= pTyDev->lnNBytes + 1; if (freeBytes > tyXonThreshold) tyRdXoff (pTyDev, FALSE); } /* If more characters in ring, enable next reader. * This is necessary in case several tasks blocked when ring was empty - * each must be awoken now */ if (!rngIsEmpty (ringId)) semGive (&pTyDev->rdSyncSem); semGive (&pTyDev->mutexSem); return (nbytes); }/********************************************************************************* tyITx - interrupt-level output** This routine gets a single character to be output to a device. It looks at* the ring buffer for <pTyDev> and gives the caller the next available* character, if there is one. The character to be output is copied to <pChar>.** RETURNS:* OK if there are more characters to send, or* ERROR if there are no more characters.*/STATUS tyITx ( FAST TY_DEV_ID pTyDev, /* pointer to tty device descriptor */ char *pChar /* where to put character to be output */ ) { FAST RING_ID ringId = pTyDev->wrtBuf; FAST int nn; /* check if we need to output XON/XOFF for the read side */ if (pTyDev->rdState.pending) { pTyDev->rdState.pending = FALSE; *pChar = pTyDev->rdState.xoff ? XOFF : XON; /* keep track of the max chars received after we sent xoff - see note * at declaration of tyXoffChars */ if (pTyDev->rdState.xoff) /** TEMP **/ { /** TEMP **/ if (tyXoffChars > tyXoffMax) /** TEMP **/ tyXoffMax = tyXoffChars; /** TEMP **/ tyXoffChars = 0; /** TEMP **/ } /** TEMP **/ } /* if output is in XOFF, or task level is flushing output buffers, * then just turn off xmitter and return */ else if (pTyDev->wrtState.xoff || pTyDev->wrtState.flushingWrtBuf) pTyDev->wrtState.busy = FALSE; /* check for linefeed needed after carriage return (SPR27682) */ /* formerly, this was a check for carriage return needed after * linefeed */ else if (pTyDev->wrtState.cr) { *pChar = '\n'; pTyDev->wrtState.cr = FALSE; } /* check for more characters to output */ else if (RNG_ELEM_GET (ringId, pChar, nn) == 0) /* no more chars */ pTyDev->wrtState.busy = FALSE; else { /* got a character to be output */ pTyDev->wrtState.busy = TRUE; /* check for linefeed needs to be added after carriage return (SPR27682) */ /* formerly, this was a check for carriage return needs to be added after * linefeed */ if ((pTyDev->options & OPT_CRMOD) && (*pChar == '\n')) { *pChar = '\r'; pTyDev->wrtState.cr = TRUE; } /* when we pass the write threshhold, give write synchonization * and release tasks pended in select */ if (rngFreeBytes (ringId) == tyWrtThreshold) { semGive (&pTyDev->wrtSyncSem); if (_func_selWakeupAll != NULL) (* _func_selWakeupAll) (&pTyDev->selWakeupList, SELWRITE); } } return (pTyDev->wrtState.busy ? OK : ERROR); }/********************************************************************************* tyIRd - interrupt-level input** This routine handles interrupt-level character input for tty devices. A* device driver calls this routine when it has received a character. This* routine adds the character to the ring buffer for the specified device, and* gives a semaphore if a task is waiting for it.** This routine also handles all the special characters, as specified in* the option word for the device, such as X-on, X-off, NEWLINE, or backspace.** RETURNS: OK, or ERROR if the ring buffer is full.*/STATUS tyIRd ( FAST TY_DEV_ID pTyDev, /* ptr to tty device descriptor */ FAST char inchar /* character read */ ) { FAST RING_ID ringId; FAST int nn; int freeBytes; BOOL releaseTaskLevel; FAST int options = pTyDev->options; BOOL charEchoed = FALSE; STATUS status = OK; /* if task level is flushing input buffers, then just return */ if (pTyDev->rdState.flushingRdBuf) return (ERROR); /* If there is an input hook routine to call, call it now. * The hook routine will return TRUE if it doesn't want us * to process the character further. */ if (pTyDev->protoHook && (*pTyDev->protoHook)(pTyDev->protoArg, inchar) == TRUE) { return (status); } /* strip off parity bit if '7 bit' option set */ if (options & OPT_7_BIT) inchar &= 0x7f; /* check for abort */ if ((inchar == tyAbortChar) && (options & OPT_ABORT) && tyAbortFunc != NULL) (*tyAbortFunc) (); /* check for trap to rom monitor */ else if ((inchar == tyMonTrapChar) && (options & OPT_MON_TRAP)) { /* attempt to do the reboot from task level, go down no matter what */ if (_func_excJobAdd != NULL) (* _func_excJobAdd) (reboot, BOOT_WARM_AUTOBOOT); else reboot (BOOT_WARM_AUTOBOOT); } /* check for XON/XOFF received */ else if (((inchar == XOFF) || (inchar == XON)) && (options & OPT_TANDEM)) tyWrtXoff (pTyDev, (inchar == XOFF)); else { /* count number of chars received while in xoff - see note at * declaration of tyXoffChars */ if (pTyDev->rdState.xoff) /** TEMP **/ tyXoffChars++; /** TEMP **/ /* check for carriage return needs to be turned into linefeed */ if ((options & OPT_CRMOD) && (inchar == '\r')) inchar = '\n'; /* check for output echo required * only echo if the write buffer isn't being deleted or * written to at task level - note that this implies that characters * aren't guaranteed to be echoed. */ if ((options & OPT_ECHO) && (!pTyDev->wrtState.wrtBufBusy && !pTyDev->wrtState.flushingWrtBuf)) { ringId = pTyDev->wrtBuf; /* echo the char. some special chars are echoed differently */ if (options & OPT_LINE) { if (inchar == tyDeleteLineChar) { /* echo a newline */ RNG_ELEM_PUT (ringId, '\n', nn); charEchoed = TRUE; } else if (inchar == tyBackspaceChar) { if (pTyDev->lnNBytes != 0) { /* echo BS-space-BS */ rngBufPut (ringId, " ", 3); charEchoed = TRUE; } } else if ((inchar < 0x20) && (inchar != '\n')) { /* echo ^-char */ RNG_ELEM_PUT (ringId, '^', nn); RNG_ELEM_PUT (ringId, inchar + '@', nn); charEchoed = TRUE; } else { RNG_ELEM_PUT (ringId, inchar, nn); charEchoed = TRUE; } } else { /* just echo the char */ RNG_ELEM_PUT (ringId, inchar, nn); charEchoed = TRUE; } if (charEchoed) tyTxStartup (pTyDev); } /* put the char in the read buffer. */ ringId = pTyDev->rdBuf; releaseTaskLevel = FALSE; if (!(options & OPT_LINE)) { /* not line-mode; * just enter character and make immediately available to tasks */ if (RNG_ELEM_PUT (ringId, inchar, nn) == 0) status = ERROR; /* buffer full, not entered */ /* only give the sync sem on first char */ if (rngNBytes (ringId) == 1) releaseTaskLevel = TRUE; } else { /* line-mode; * process backspace, line-delete, EOF, and newline chars special */ freeBytes = rngFreeBytes (ringId); if (inchar == tyBackspaceChar) { if (pTyDev->lnNBytes != 0) pTyDev->lnNBytes--; } else if (inchar == tyDeleteLineChar) pTyDev->lnNBytes = 0; else if (inchar == tyEofChar) { /* EOF - check for at least one free byte so there is room * to put the line byte count below */ if (freeBytes > 0) releaseTaskLevel = TRUE; } else { if (freeBytes >= 2) { if (freeBytes >= (pTyDev->lnNBytes + 2)) pTyDev->lnNBytes++; else status = ERROR; /* no room, overwriting last char */ rngPutAhead (ringId, inchar, (int)pTyDev->lnNBytes); if ((inchar == '\n') || (pTyDev->lnNBytes == 255)) releaseTaskLevel = TRUE; } else status = ERROR; /* no room, not even for overwriting */ } /* if line termination indicated, put line byte count * in 0th character of line and advance ring buffer pointers */ if (releaseTaskLevel) { rngPutAhead (ringId, (char) pTyDev->lnNBytes, 0); rngMoveAhead (ringId, (int) pTyDev->lnNBytes + 1); pTyDev->lnNBytes = 0; } } /* check if XON/XOFF needs to be output */ if (options & OPT_TANDEM) { freeBytes = rngFreeBytes (ringId); if (pTyDev->options & OPT_LINE) freeBytes -= pTyDev->lnNBytes + 1; if (!pTyDev->rdState.xoff) { /* if input buffer is close to full, send XOFF */ if (freeBytes < tyXoffThreshold) tyRdXoff (pTyDev, TRUE); } else { /* if input buffer has enough room now, send XON */ if (freeBytes > tyXonThreshold) tyRdXoff (pTyDev, FALSE); } } /* if task level has new input then give read semaphore and * release tasks pended in select */ if (releaseTaskLevel) { semGive (&pTyDev->rdSyncSem); if (_func_selWakeupAll != NULL) (* _func_selWakeupAll) (&pTyDev->selWakeupList, SELREAD); } } return (status); }/******************************************************************************** tyRdXoff - set read side xon/xoff** This routine sets the read side xon/xoff to the specified state.* A flag will be set indicating that the next character sent by the* transmit side should be the xon or xoff character. If the transmitter* is idle, it is started.*/LOCAL void tyRdXoff ( FAST TY_DEV_ID pTyDev, /* pointer to device structure */ FAST BOOL xoff ) { FAST int oldlevel; oldlevel = intLock (); /* LOCK INTERRUPTS */ if (pTyDev->rdState.xoff != xoff) { pTyDev->rdState.xoff = xoff; pTyDev->rdState.pending = TRUE; if (!pTyDev->wrtState.busy) { pTyDev->wrtState.busy = TRUE; intUnlock (oldlevel); /* UNLOCK INTERRUPTS */ (*pTyDev->txStartup) (pTyDev); return; } } intUnlock (oldlevel); /* UNLOCK INTERRUPTS */ }/******************************************************************************** tyWrtXoff - set write side xon/xoff** This routine sets the write side xon/xoff to the specified state.* If the new state is xon and the transmitter is idle, it is started.**/LOCAL void tyWrtXoff ( FAST TY_DEV_ID pTyDev, /* pointer to device structure */ BOOL xoff ) { FAST int oldlevel; /* restart an XOFF'd transmitter */ oldlevel = intLock (); /* LOCK INTERRUPTS */ if (pTyDev->wrtState.xoff != xoff) { pTyDev->wrtState.xoff = xoff; if (!xoff) { if (!pTyDev->wrtState.busy) { pTyDev->wrtState.busy = TRUE; intUnlock (oldlevel); /* UNLOCK INTERRUPTS */ (*pTyDev->txStartup) (pTyDev); return; } } } intUnlock (oldlevel); /* UNLOCK INTERRUPTS */ }/******************************************************************************** tyTxStartup - startup transmitter if necessary** This routine starts the transmitter if it is not already busy.* A flag is maintained so that starting the transmitter can be properly* interlocked with interrupt level, but the startup routine itself is* called at the interrupt level of the caller.*/LOCAL void tyTxStartup ( FAST TY_DEV_ID pTyDev /* pointer to device structure */ ) { FAST int oldlevel; /* if xmitter not busy, start it */ if (!pTyDev->wrtState.busy) { oldlevel = intLock (); /* LOCK INTERRUPTS */ /* check xmitter busy again, now that we're locked out */ if (!pTyDev->wrtState.busy) { pTyDev->wrtState.busy = TRUE; intUnlock (oldlevel); /* UNLOCK INTERRUPTS */ (*pTyDev->txStartup) (pTyDev); return; } intUnlock (oldlevel); /* UNLOCK INTERRUPTS */ } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -