diff options
Diffstat (limited to '')
-rw-r--r-- | kernel/old/sio.c (renamed from kernel/old/drivers/serial.c) | 329 |
1 files changed, 197 insertions, 132 deletions
diff --git a/kernel/old/drivers/serial.c b/kernel/old/sio.c index d6572e5..a5c7b75 100644 --- a/kernel/old/drivers/serial.c +++ b/kernel/old/sio.c @@ -1,3 +1,64 @@ +/** +** @file sio.c +** +** @author Warren R. Carithers +** +** @brief SIO module +** +** For maximum compatibility from semester to semester, this code uses +** several "stand-in" type names and macros which should be defined +** in the accompanying "compat.h" header file if they're not part of +** the baseline system: +** +** standard-sized integer types: intN_t, uintN_t +** other types: PCBTYPE, QTYPE +** scheduler functions: SCHED, DISPATCH +** queue functions: QCREATE, QLENGTH, QDEQUE +** other functions: SLENGTH +** sio read queue: QNAME +** +** Our SIO scheme is very simple: +** +** Input: We maintain a buffer of incoming characters that haven't +** yet been read by processes. When a character comes in, if +** there is no process waiting for it, it goes in the buffer; +** otherwise, the first waiting process is awakeneda and it +** gets the character. +** +** When a process invokes readch(), if there is a character in +** the input buffer, the process gets it; otherwise, it is +** blocked until input appears +** +** Communication with system calls is via two routines. +** sio_readc() returns the first available character (if +** there is one), resetting the input variables if this was +** the last character in the buffer. If there are no +** characters in the buffer, sio_read() returns a -1 +** (presumably so the requesting process can be blocked). +** +** sio_read() copies the contents of the input buffer into +** a user-supplied buffer. It returns the number of characters +** copied. If there are no characters available, return a -1. +** +** Output: We maintain a buffer of outgoing characters that haven't +** yet been sent to the device, and an indication of whether +** or not we are in the middle of a transmit sequence. When +** an interrupt comes in, if there is another character to +** send we copy it to the transmitter buffer; otherwise, we +** end the transmit sequence. +** +** Communication with user processes is via three functions. +** sio_writec() writes a single character; sio_write() +** writes a sized buffer full of characters; sio_puts() +** prints a NUL-terminated string. If we are in the middle +** of a transmit sequence, all characters will be added +** to the output buffer (from where they will be sent +** automatically); otherwise, we send the first character +** directly, add the rest of the characters (if there are +** any) to the output buffer, and set the "sending" flag +** to indicate that we're expecting a transmitter interrupt. +*/ + #define KERNEL_SRC // this should do all includes required for this OS @@ -15,28 +76,28 @@ ** PRIVATE DEFINITIONS */ -#define BUF_SIZE 2048 +#define BUF_SIZE 2048 /* ** PRIVATE GLOBALS */ -// input character buffer -static char inbuffer[BUF_SIZE]; + // input character buffer +static char inbuffer[ BUF_SIZE ]; static char *inlast; static char *innext; static uint32_t incount; -// output character buffer -static char outbuffer[BUF_SIZE]; + // output character buffer +static char outbuffer[ BUF_SIZE ]; static char *outlast; static char *outnext; static uint32_t outcount; -// output control flag + // output control flag static int sending; -// interrupt register status + // interrupt register status static uint8_t ier; /* @@ -45,7 +106,7 @@ static uint8_t ier; // queue for read-blocked processes #ifdef QNAME -extern QTYPE QNAME; +QTYPE QNAME; #endif /* @@ -61,40 +122,41 @@ extern QTYPE QNAME; ** @param vector The interrupt vector number for this interrupt ** @param ecode The error code associated with this interrupt */ -static void sio_isr(int vector, int ecode) -{ +static void sio_isr( int vector, int ecode ) { int ch; #if TRACING_SIO_ISR - cio_puts("SIO: int:"); + cio_puts( "SIO: int:" ); #endif // // Must process all pending events; loop until the IRR // says there's nothing else to do. // - for (;;) { + for(;;) { + // get the "pending event" indicator - int iir = inb(UA4_IIR) & UA4_IIR_INT_PRI_MASK; + int iir = inb( UA4_IIR ) & UA4_IIR_INT_PRI_MASK; // process this event - switch (iir) { + switch( iir ) { + case UA4_IIR_LINE_STATUS: // shouldn't happen, but just in case.... - cio_printf("** SIO int, LSR = %02x\n", inb(UA4_LSR)); + cio_printf( "** SIO int, LSR = %02x\n", inb(UA4_LSR) ); break; case UA4_IIR_RX: #if TRACING_SIO_ISR - cio_puts(" RX"); + cio_puts( " RX" ); #endif // get the character - ch = inb(UA4_RXD); - if (ch == '\r') { // map CR to LF + ch = inb( UA4_RXD ); + if( ch == '\r' ) { // map CR to LF ch = '\n'; } #if TRACING_SIO_ISR - cio_printf(" ch %02x", ch); + cio_printf( " ch %02x", ch ); #endif #ifdef QNAME @@ -104,18 +166,18 @@ static void sio_isr(int vector, int ecode) // process and awaken the process. // - if (!QEMPTY(QNAME)) { + if( !QEMPTY(QNAME) ) { PCBTYPE *pcb; - QDEQUE(QNAME, pcb); + QDEQUE( QNAME, pcb ); // make sure we got a non-NULL result - assert(pcb); + assert( pcb ); // return char via arg #2 and count in EAX - char *buf = (char *)ARG(pcb, 2); + char *buf = (char *) ARG(pcb,2); *buf = ch & 0xff; RET(pcb) = 1; - SCHED(pcb); + SCHED( pcb ); } else { #endif /* QNAME */ @@ -125,7 +187,7 @@ static void sio_isr(int vector, int ecode) // if there is room, otherwise just ignore it. // - if (incount < BUF_SIZE) { + if( incount < BUF_SIZE ) { *inlast++ = ch; ++incount; } @@ -137,64 +199,65 @@ static void sio_isr(int vector, int ecode) case UA5_IIR_RX_FIFO: // shouldn't happen, but just in case.... - ch = inb(UA4_RXD); - cio_printf("** SIO FIFO timeout, RXD = %02x\n", ch); + ch = inb( UA4_RXD ); + cio_printf( "** SIO FIFO timeout, RXD = %02x\n", ch ); break; case UA4_IIR_TX: #if TRACING_SIO_ISR - cio_puts(" TX"); + cio_puts( " TX" ); #endif // if there is another character, send it - if (sending && outcount > 0) { + if( sending && outcount > 0 ) { #if TRACING_SIO_ISR - cio_printf(" ch %02x", *outnext); + cio_printf( " ch %02x", *outnext ); #endif - outb(UA4_TXD, *outnext); + outb( UA4_TXD, *outnext ); ++outnext; // wrap around if necessary - if (outnext >= (outbuffer + BUF_SIZE)) { + if( outnext >= (outbuffer + BUF_SIZE) ) { outnext = outbuffer; } --outcount; #if TRACING_SIO_ISR - cio_printf(" (outcount %d)", outcount); + cio_printf( " (outcount %d)", outcount ); #endif } else { #if TRACING_SIO_ISR - cio_puts(" EOS"); + cio_puts( " EOS" ); #endif // no more data - reset the output vars outcount = 0; outlast = outnext = outbuffer; sending = 0; // disable TX interrupts - sio_disable(SIO_TX); + sio_disable( SIO_TX ); } break; case UA4_IIR_NO_INT: #if TRACING_SIO_ISR - cio_puts(" EOI\n"); + cio_puts( " EOI\n" ); #endif // nothing to do - tell the PIC we're done - outb(PIC1_CMD, PIC_EOI); + outb( PIC1_CMD, PIC_EOI ); return; case UA4_IIR_MODEM_STATUS: // shouldn't happen, but just in case.... - cio_printf("** SIO int, MSR = %02x\n", inb(UA4_MSR)); + cio_printf( "** SIO int, MSR = %02x\n", inb(UA4_MSR) ); break; default: // uh-oh.... - sprint(b256, "sio isr: IIR %02x\n", ((uint32_t)iir) & 0xff); - PANIC(0, b256); + sprint( b256, "sio isr: IIR %02x\n", ((uint32_t) iir) & 0xff ); + PANIC( 0, b256 ); } + } // should never reach this point! - assert(false); + assert( false ); } /* @@ -206,27 +269,27 @@ static void sio_isr(int vector, int ecode) ** ** Initialize the UART chip. */ -void sio_init(void) -{ +void sio_init( void ) { + #if TRACING_INIT - cio_puts(" Sio"); + cio_puts( " Sio" ); #endif /* ** Initialize SIO variables. */ - memclr((void *)inbuffer, sizeof(inbuffer)); + memclr( (void *) inbuffer, sizeof(inbuffer) ); inlast = innext = inbuffer; incount = 0; - memclr((void *)outbuffer, sizeof(outbuffer)); + memclr( (void *) outbuffer, sizeof(outbuffer) ); outlast = outnext = outbuffer; outcount = 0; sending = 0; // queue of read-blocked processes - QCREATE(QNAME); + QCREATE( QNAME ); /* ** Next, initialize the UART. @@ -236,11 +299,11 @@ void sio_init(void) ** this is a bizarre little sequence of operations */ - outb(UA5_FCR, 0x20); - outb(UA5_FCR, UA5_FCR_FIFO_RESET); // 0x00 - outb(UA5_FCR, UA5_FCR_FIFO_EN); // 0x01 - outb(UA5_FCR, UA5_FCR_FIFO_EN | UA5_FCR_RXSR); // 0x03 - outb(UA5_FCR, UA5_FCR_FIFO_EN | UA5_FCR_RXSR | UA5_FCR_TXSR); // 0x07 + outb( UA5_FCR, 0x20 ); + outb( UA5_FCR, UA5_FCR_FIFO_RESET ); // 0x00 + outb( UA5_FCR, UA5_FCR_FIFO_EN ); // 0x01 + outb( UA5_FCR, UA5_FCR_FIFO_EN | UA5_FCR_RXSR ); // 0x03 + outb( UA5_FCR, UA5_FCR_FIFO_EN | UA5_FCR_RXSR | UA5_FCR_TXSR ); // 0x07 /* ** disable interrupts @@ -249,36 +312,36 @@ void sio_init(void) ** called to switch them back on */ - outb(UA4_IER, 0); + outb( UA4_IER, 0 ); ier = 0; /* ** select the divisor latch registers and set the data rate */ - outb(UA4_LCR, UA4_LCR_DLAB); - outb(UA4_DLL, BAUD_LOW_BYTE(DL_BAUD_9600)); - outb(UA4_DLM, BAUD_HIGH_BYTE(DL_BAUD_9600)); + outb( UA4_LCR, UA4_LCR_DLAB ); + outb( UA4_DLL, BAUD_LOW_BYTE( DL_BAUD_9600 ) ); + outb( UA4_DLM, BAUD_HIGH_BYTE( DL_BAUD_9600 ) ); /* ** deselect the latch registers, by setting the data ** characteristics in the LCR */ - outb(UA4_LCR, UA4_LCR_WLS_8 | UA4_LCR_1_STOP_BIT | UA4_LCR_NO_PARITY); - + outb( UA4_LCR, UA4_LCR_WLS_8 | UA4_LCR_1_STOP_BIT | UA4_LCR_NO_PARITY ); + /* ** Set the ISEN bit to enable the interrupt request signal, ** and the DTR and RTS bits to enable two-way communication. */ - outb(UA4_MCR, UA4_MCR_ISEN | UA4_MCR_DTR | UA4_MCR_RTS); + outb( UA4_MCR, UA4_MCR_ISEN | UA4_MCR_DTR | UA4_MCR_RTS ); /* ** Install our ISR */ - install_isr(VEC_COM1, sio_isr); + install_isr( VEC_COM1, sio_isr ); } /** @@ -292,8 +355,7 @@ void sio_init(void) ** ** @return the prior IER setting */ -uint8_t sio_enable(uint8_t which) -{ +uint8_t sio_enable( uint8_t which ) { uint8_t old; // remember the current status @@ -302,23 +364,23 @@ uint8_t sio_enable(uint8_t which) // figure out what to enable - if (which & SIO_TX) { + if( which & SIO_TX ) { ier |= UA4_IER_TX_IE; } - if (which & SIO_RX) { + if( which & SIO_RX ) { ier |= UA4_IER_RX_IE; } // if there was a change, make it - if (old != ier) { - outb(UA4_IER, ier); + if( old != ier ) { + outb( UA4_IER, ier ); } // return the prior settings - return (old); + return( old ); } /** @@ -332,8 +394,7 @@ uint8_t sio_enable(uint8_t which) ** ** @return the prior IER setting */ -uint8_t sio_disable(uint8_t which) -{ +uint8_t sio_disable( uint8_t which ) { uint8_t old; // remember the current status @@ -342,23 +403,23 @@ uint8_t sio_disable(uint8_t which) // figure out what to disable - if (which & SIO_TX) { + if( which & SIO_TX ) { ier &= ~UA4_IER_TX_IE; } - if (which & SIO_RX) { + if( which & SIO_RX ) { ier &= ~UA4_IER_RX_IE; } // if there was a change, make it - if (old != ier) { - outb(UA4_IER, ier); + if( old != ier ) { + outb( UA4_IER, ier ); } // return the prior settings - return (old); + return( old ); } /** @@ -370,9 +431,8 @@ uint8_t sio_disable(uint8_t which) ** ** @return the count of characters still in the input queue */ -int sio_inq_length(void) -{ - return (incount); +int sio_inq_length( void ) { + return( incount ); } /** @@ -384,29 +444,31 @@ int sio_inq_length(void) ** ** @return the next character, or -1 if no character is available */ -int sio_readc(void) -{ +int sio_readc( void ) { int ch; // assume there is no character available ch = -1; - // + // // If there is a character, return it // - if (incount > 0) { + if( incount > 0 ) { + // take it out of the input buffer ch = ((int)(*innext++)) & 0xff; --incount; // reset the buffer variables if this was the last one - if (incount < 1) { + if( incount < 1 ) { inlast = innext = inbuffer; } + } - return (ch); + return( ch ); + } /** @@ -422,15 +484,14 @@ int sio_readc(void) ** @return the number of bytes copied, or 0 if no characters were available */ -int sio_read(char *buf, int length) -{ +int sio_read( char *buf, int length ) { char *ptr = buf; int copied = 0; // if there are no characters, just return 0 - if (incount < 1) { - return (0); + if( incount < 1 ) { + return( 0 ); } // @@ -438,9 +499,9 @@ int sio_read(char *buf, int length) // buffer as will fit. // - while (incount > 0 && copied < length) { + while( incount > 0 && copied < length ) { *ptr++ = *innext++ & 0xff; - if (innext > (inbuffer + BUF_SIZE)) { + if( innext > (inbuffer + BUF_SIZE) ) { innext = inbuffer; } --incount; @@ -449,15 +510,16 @@ int sio_read(char *buf, int length) // reset the input buffer if necessary - if (incount < 1) { + if( incount < 1 ) { inlast = innext = inbuffer; } // return the copy count - return (copied); + return( copied ); } + /** ** sio_writec( ch ) ** @@ -467,21 +529,22 @@ int sio_read(char *buf, int length) ** ** @param ch Character to be written (in the low-order 8 bits) */ -void sio_writec(int ch) -{ +void sio_writec( int ch ){ + + // // Must do LF -> CRLF mapping // - if (ch == '\n') { - sio_writec('\r'); + if( ch == '\n' ) { + sio_writec( '\r' ); } // // If we're currently transmitting, just add this to the buffer // - if (sending) { + if( sending ) { *outlast++ = ch; ++outcount; return; @@ -492,11 +555,12 @@ void sio_writec(int ch) // sending = 1; - outb(UA4_TXD, ch); + outb( UA4_TXD, ch ); // Also must enable transmitter interrupts - sio_enable(SIO_TX); + sio_enable( SIO_TX ); + } /** @@ -511,8 +575,7 @@ void sio_writec(int ch) ** ** @return the number of characters copied into the SIO output buffer */ -int sio_write(const char *buffer, int length) -{ +int sio_write( const char *buffer, int length ) { int first = *buffer; const char *ptr = buffer; int copied = 0; @@ -524,15 +587,15 @@ int sio_write(const char *buffer, int length) // sio_writec() to send the first one out. // - if (!sending) { + if( !sending ) { ptr += 1; copied++; } - while (copied < length && outcount < BUF_SIZE) { + while( copied < length && outcount < BUF_SIZE ) { *outlast++ = *ptr++; // wrap around if necessary - if (outlast >= (outbuffer + BUF_SIZE)) { + if( outlast >= (outbuffer + BUF_SIZE) ) { outlast = outbuffer; } ++outcount; @@ -545,13 +608,15 @@ int sio_write(const char *buffer, int length) // variables for us. // - if (!sending) { - sio_writec(first); + if( !sending ) { + sio_writec( first ); } // Return the transfer count - return (copied); + + return( copied ); + } /** @@ -565,14 +630,13 @@ int sio_write(const char *buffer, int length) ** ** @return the count of bytes transferred */ -int sio_puts(const char *buffer) -{ - int n; // must be outside the loop so we can return it +int sio_puts( const char *buffer ) { + int n; // must be outside the loop so we can return it - n = SLENGTH(buffer); - sio_write(buffer, n); + n = SLENGTH( buffer ); + sio_write( buffer, n ); - return (n); + return( n ); } /** @@ -587,43 +651,44 @@ int sio_puts(const char *buffer) ** of the queues) */ -void sio_dump(bool_t full) -{ +void sio_dump( bool_t full ) { int n; char *ptr; // dump basic info into the status region - cio_printf_at(48, 0, "SIO: IER %02x (%c%c%c) in %d ot %d", - ((uint32_t)ier) & 0xff, sending ? '*' : '.', - (ier & UA4_IER_TX_IE) ? 'T' : 't', - (ier & UA4_IER_RX_IE) ? 'R' : 'r', incount, outcount); + cio_printf_at( 48, 0, + "SIO: IER %02x (%c%c%c) in %d ot %d", + ((uint32_t)ier) & 0xff, sending ? '*' : '.', + (ier & UA4_IER_TX_IE) ? 'T' : 't', + (ier & UA4_IER_RX_IE) ? 'R' : 'r', + incount, outcount ); // if we're not doing a full dump, stop now - if (!full) { + if( !full ) { return; } // also want the queue contents, but we'll // dump them into the scrolling region - if (incount) { - cio_puts("SIO input queue: \""); - ptr = innext; - for (n = 0; n < incount; ++n) { - put_char_or_code(*ptr++); + if( incount ) { + cio_puts( "SIO input queue: \"" ); + ptr = innext; + for( n = 0; n < incount; ++n ) { + put_char_or_code( *ptr++ ); } - cio_puts("\"\n"); + cio_puts( "\"\n" ); } - if (outcount) { - cio_puts("SIO output queue: \""); - cio_puts(" ot: \""); - ptr = outnext; - for (n = 0; n < outcount; ++n) { - put_char_or_code(*ptr++); + if( outcount ) { + cio_puts( "SIO output queue: \"" ); + cio_puts( " ot: \"" ); + ptr = outnext; + for( n = 0; n < outcount; ++n ) { + put_char_or_code( *ptr++ ); } - cio_puts("\"\n"); + cio_puts( "\"\n" ); } } |