/*------------------------------------------------------------------------ * eputc - put one character in the echo queue *------------------------------------------------------------------------ */ local void eputc( char ch, /* character to echo */ struct ttycblk *typtr, /* ptr to ttytab entry */ struct uart_csreg *uptr /* address of UART's CSRs */ ) { *typtr->tyetail++ = ch; /* Wrap around buffer, if needed */ if (typtr->tyetail >= &typtr->tyebuff[TY_EBUFLEN]) { typtr->tyetail = typtr->tyebuff; } ttyKickOut(typtr, uptr); return; }
/*------------------------------------------------------------------------ * ttyInit - initialize buffers and modes for a tty line *------------------------------------------------------------------------ */ devcall ttyInit( struct dentry *devptr /* entry in device switch table */ ) { struct ttycblk *typtr; /* pointer to ttytab entry */ struct uart_csreg *uptr; /* address of UART's CSRs */ typtr = &ttytab[ devptr->dvminor ]; /* Initialize values in the tty control block */ typtr->tyihead = typtr->tyitail = /* set up input queue */ &typtr->tyibuff[0]; /* as empty */ typtr->tyisem = semcreate(0); /* input semaphore */ typtr->tyohead = typtr->tyotail = /* set up output queue */ &typtr->tyobuff[0]; /* as empty */ typtr->tyosem = semcreate(TY_OBUFLEN); /* output semaphore */ typtr->tyehead = typtr->tyetail = /* set up echo queue */ &typtr->tyebuff[0]; /* as empty */ typtr->tyimode = TY_IMCOOKED; /* start in cooked mode */ typtr->tyiecho = TRUE; /* echo console input */ typtr->tyieback = TRUE; /* honor erasing bksp */ typtr->tyevis = TRUE; /* visual control chars */ typtr->tyecrlf = TRUE; /* echo CRLF for NEWLINE*/ typtr->tyicrlf = TRUE; /* map CR to NEWLINE */ typtr->tyierase = TRUE; /* do erasing backspace */ typtr->tyierasec = TY_BACKSP; /* erase char is ^H */ typtr->tyeof = TRUE; /* honor eof on input */ typtr->tyeofch = TY_EOFCH; /* end-of-file character*/ typtr->tyikill = TRUE; /* allow line kill */ typtr->tyikillc = TY_KILLCH; /* set line kill to ^U */ typtr->tyicursor = 0; /* start of input line */ typtr->tyoflow = TRUE; /* handle flow control */ typtr->tyoheld = FALSE; /* output not held */ typtr->tyostop = TY_STOPCH; /* stop char is ^S */ typtr->tyostart = TY_STRTCH; /* start char is ^Q */ typtr->tyocrlf = TRUE; /* send CRLF for NEWLINE*/ typtr->tyifullc = TY_FULLCH; /* send ^G when buffer */ /* is full */ /* Initialize the UART */ uptr = (struct uart_csreg *)devptr->dvcsr; /* Set baud rate */ outb((int)&uptr->lcr, UART_LCR_DLAB); outb((int)&uptr->dlm, 0x00); outb((int)&uptr->dll, 0x0c); outb((int)&uptr->lcr, UART_LCR_8N1); /* 8 bit char, No Parity*/ /* and 1 Stop bit */ outb((int)&uptr->fcr, 0x00); /* Disable FIFO for now */ /* OUT2 value is used to control the onboard interrupt tri-state*/ /* buffer. It should be set high to generate interrupts */ outb((int)&uptr->mcr, UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); /* Enbale user-def. OUT2*/ /* Register the interrupt dispatcher for the tty device */ set_evec( devptr->dvirq, (uint32)devptr->dvintr ); /* Enable interrupts on the device */ /* Enable UART FIFOs, clear and set interrupt trigger level */ outb((int)&uptr->fcr, UART_FCR_EFIFO | UART_FCR_RRESET | UART_FCR_TRESET | UART_FCR_TRIG2); ttyKickOut(typtr, uptr); (void)inb((int)&uptr->iir); (void)inb((int)&uptr->lsr); (void)inb((int)&uptr->msr); (void)inb((int)&uptr->buffer); return OK; }
/*------------------------------------------------------------------------ * ttyInter_in -- handle one arriving char (interrupts disabled) *------------------------------------------------------------------------ */ void ttyInter_in ( struct ttycblk *typtr, /* ptr to ttytab entry */ struct uart_csreg *uptr /* address of UART's CSRs */ ) { char ch; /* next char from device */ int32 avail; /* chars available in buffer */ ch = uptr->buffer; /* extract char. from device */ /* Compute chars available */ avail = semcount(typtr->tyisem); if (avail < 0) { /* one or more processes waiting*/ avail = 0; } /* Handle raw mode */ if (typtr->tyimode == TY_IMRAW) { if (avail >= TY_IBUFLEN) { /* no space => ignore input */ return; } /* Place char in buffer with no editing */ *typtr->tyitail++ = ch; /* Wrap buffer pointer */ if (typtr->tyitail >= &typtr->tyibuff[TY_IBUFLEN]) { typtr->tyitail = typtr->tyibuff; } /* Signal input semaphore and return */ signal(typtr->tyisem); return; } /* Handle cooked and cbreak modes (common part) */ if ( (ch == TY_RETURN) && typtr->tyicrlf ) { ch = TY_NEWLINE; } /* If flow control is in effect, handle ^S and ^Q */ if (typtr->tyoflow) { if (ch == typtr->tyostart) { /* ^Q starts output */ typtr->tyoheld = FALSE; ttyKickOut(typtr, uptr); return; } else if (ch == typtr->tyostop) { /* ^S stops output */ typtr->tyoheld = TRUE; return; } } typtr->tyoheld = FALSE; /* Any other char starts output */ if (typtr->tyimode == TY_IMCBREAK) { /* Just cbreak mode */ /* If input buffer is full, send bell to user */ if (avail >= TY_IBUFLEN) { eputc(typtr->tyifullc, typtr, uptr); } else { /* Input buffer has space for this char */ *typtr->tyitail++ = ch; /* Wrap around buffer */ if (typtr->tyitail>=&typtr->tyibuff[TY_IBUFLEN]) { typtr->tyitail = typtr->tyibuff; } if (typtr->tyiecho) { /* are we echoing chars?*/ echoch(ch, typtr, uptr); } } return; } else { /* Just cooked mode (see common code above) */ /* Line kill character arrives - kill entire line */ if (ch == typtr->tyikillc && typtr->tyikill) { typtr->tyitail -= typtr->tyicursor; if (typtr->tyitail < typtr->tyibuff) { typtr->tyihead += TY_IBUFLEN; } typtr->tyicursor = 0; eputc(TY_RETURN, typtr, uptr); eputc(TY_NEWLINE, typtr, uptr); return; } /* Erase (backspace) character */ if ( (ch == typtr->tyierasec) && typtr->tyierase) { if (typtr->tyicursor > 0) { typtr->tyicursor--; erase1(typtr, uptr); } return; } /* End of line */ if ( (ch == TY_NEWLINE) || (ch == TY_RETURN) ) { if (typtr->tyiecho) { echoch(ch, typtr, uptr); } *typtr->tyitail++ = ch; if (typtr->tyitail>=&typtr->tyibuff[TY_IBUFLEN]) { typtr->tyitail = typtr->tyibuff; } /* Make entire line (plus \n or \r) available */ signaln(typtr->tyisem, typtr->tyicursor + 1); typtr->tyicursor = 0; /* Reset for next line */ return; } /* Character to be placed in buffer - send bell if */ /* buffer has overflowed */ avail = semcount(typtr->tyisem); if (avail < 0) { avail = 0; } if ((avail + typtr->tyicursor) >= TY_IBUFLEN-1) { eputc(typtr->tyifullc, typtr, uptr); return; } /* EOF character: recognize at beginning of line, but */ /* print and ignore otherwise. */ if (ch == typtr->tyeofch && typtr->tyeof) { if (typtr->tyiecho) { echoch(ch, typtr, uptr); } if (typtr->tyicursor != 0) { return; } *typtr->tyitail++ = ch; signal(typtr->tyisem); return; } /* Echo the character */ if (typtr->tyiecho) { echoch(ch, typtr, uptr); } /* Insert character in the input buffer */ typtr->tyicursor++; *typtr->tyitail++ = ch; /* Wrap around if needed */ if (typtr->tyitail >= &typtr->tyibuff[TY_IBUFLEN]) { typtr->tyitail = typtr->tyibuff; } return; } }