summaryrefslogtreecommitdiff
path: root/kernel/old/sio.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--kernel/old/sio.c694
1 files changed, 0 insertions, 694 deletions
diff --git a/kernel/old/sio.c b/kernel/old/sio.c
deleted file mode 100644
index a5c7b75..0000000
--- a/kernel/old/sio.c
+++ /dev/null
@@ -1,694 +0,0 @@
-/**
-** @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
-#include <compat.h>
-
-// all other framework includes are next
-#include <x86/uart.h>
-#include <x86/arch.h>
-#include <x86/pic.h>
-
-#include <sio.h>
-#include <lib.h>
-
-/*
-** PRIVATE DEFINITIONS
-*/
-
-#define BUF_SIZE 2048
-
-/*
-** PRIVATE GLOBALS
-*/
-
- // 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 ];
-static char *outlast;
-static char *outnext;
-static uint32_t outcount;
-
- // output control flag
-static int sending;
-
- // interrupt register status
-static uint8_t ier;
-
-/*
-** PUBLIC GLOBAL VARIABLES
-*/
-
-// queue for read-blocked processes
-#ifdef QNAME
-QTYPE QNAME;
-#endif
-
-/*
-** PRIVATE FUNCTIONS
-*/
-
-/**
-** sio_isr(vector,ecode)
-**
-** Interrupt handler for the SIO module. Handles all pending
-** events (as described by the SIO controller).
-**
-** @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 ) {
- int ch;
-
-#if TRACING_SIO_ISR
- cio_puts( "SIO: int:" );
-#endif
- //
- // Must process all pending events; loop until the IRR
- // says there's nothing else to do.
- //
-
- for(;;) {
-
- // get the "pending event" indicator
- int iir = inb( UA4_IIR ) & UA4_IIR_INT_PRI_MASK;
-
- // process this event
- switch( iir ) {
-
- case UA4_IIR_LINE_STATUS:
- // shouldn't happen, but just in case....
- cio_printf( "** SIO int, LSR = %02x\n", inb(UA4_LSR) );
- break;
-
- case UA4_IIR_RX:
-#if TRACING_SIO_ISR
- cio_puts( " RX" );
-#endif
- // get the character
- ch = inb( UA4_RXD );
- if( ch == '\r' ) { // map CR to LF
- ch = '\n';
- }
-#if TRACING_SIO_ISR
- cio_printf( " ch %02x", ch );
-#endif
-
-#ifdef QNAME
- //
- // If there is a waiting process, this must be
- // the first input character; give it to that
- // process and awaken the process.
- //
-
- if( !QEMPTY(QNAME) ) {
- PCBTYPE *pcb;
-
- QDEQUE( QNAME, pcb );
- // make sure we got a non-NULL result
- assert( pcb );
-
- // return char via arg #2 and count in EAX
- char *buf = (char *) ARG(pcb,2);
- *buf = ch & 0xff;
- RET(pcb) = 1;
- SCHED( pcb );
-
- } else {
-#endif /* QNAME */
-
- //
- // Nobody waiting - add to the input buffer
- // if there is room, otherwise just ignore it.
- //
-
- if( incount < BUF_SIZE ) {
- *inlast++ = ch;
- ++incount;
- }
-
-#ifdef QNAME
- }
-#endif /* QNAME */
- break;
-
- 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 );
- break;
-
- case UA4_IIR_TX:
-#if TRACING_SIO_ISR
- cio_puts( " TX" );
-#endif
- // if there is another character, send it
- if( sending && outcount > 0 ) {
-#if TRACING_SIO_ISR
- cio_printf( " ch %02x", *outnext );
-#endif
- outb( UA4_TXD, *outnext );
- ++outnext;
- // wrap around if necessary
- if( outnext >= (outbuffer + BUF_SIZE) ) {
- outnext = outbuffer;
- }
- --outcount;
-#if TRACING_SIO_ISR
- cio_printf( " (outcount %d)", outcount );
-#endif
- } else {
-#if TRACING_SIO_ISR
- 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 );
- }
- break;
-
- case UA4_IIR_NO_INT:
-#if TRACING_SIO_ISR
- cio_puts( " EOI\n" );
-#endif
- // nothing to do - tell the PIC we're done
- 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) );
- break;
-
- default:
- // uh-oh....
- sprint( b256, "sio isr: IIR %02x\n", ((uint32_t) iir) & 0xff );
- PANIC( 0, b256 );
- }
-
- }
-
- // should never reach this point!
- assert( false );
-}
-
-/*
-** PUBLIC FUNCTIONS
-*/
-
-/**
-** sio_init()
-**
-** Initialize the UART chip.
-*/
-void sio_init( void ) {
-
-#if TRACING_INIT
- cio_puts( " Sio" );
-#endif
-
- /*
- ** Initialize SIO variables.
- */
-
- memclr( (void *) inbuffer, sizeof(inbuffer) );
- inlast = innext = inbuffer;
- incount = 0;
-
- memclr( (void *) outbuffer, sizeof(outbuffer) );
- outlast = outnext = outbuffer;
- outcount = 0;
- sending = 0;
-
- // queue of read-blocked processes
- QCREATE( QNAME );
-
- /*
- ** Next, initialize the UART.
- **
- ** Initialize the FIFOs
- **
- ** 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
-
- /*
- ** disable interrupts
- **
- ** note that we leave them disabled; sio_enable() must be
- ** called to switch them back on
- */
-
- 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 ) );
-
- /*
- ** 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 );
-
- /*
- ** 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 );
-
- /*
- ** Install our ISR
- */
-
- install_isr( VEC_COM1, sio_isr );
-}
-
-/**
-** sio_enable()
-**
-** Enable SIO interrupts
-**
-** usage: uint8_t old = sio_enable( uint8_t which )
-**
-** @param which Bit mask indicating which interrupt(s) to enable
-**
-** @return the prior IER setting
-*/
-uint8_t sio_enable( uint8_t which ) {
- uint8_t old;
-
- // remember the current status
-
- old = ier;
-
- // figure out what to enable
-
- if( which & SIO_TX ) {
- ier |= UA4_IER_TX_IE;
- }
-
- if( which & SIO_RX ) {
- ier |= UA4_IER_RX_IE;
- }
-
- // if there was a change, make it
-
- if( old != ier ) {
- outb( UA4_IER, ier );
- }
-
- // return the prior settings
-
- return( old );
-}
-
-/**
-** sio_disable()
-**
-** Disable SIO interrupts
-**
-** usage: uint8_t old = sio_disable( uint8_t which )
-**
-** @param which Bit mask indicating which interrupt(s) to disable
-**
-** @return the prior IER setting
-*/
-uint8_t sio_disable( uint8_t which ) {
- uint8_t old;
-
- // remember the current status
-
- old = ier;
-
- // figure out what to disable
-
- if( which & SIO_TX ) {
- ier &= ~UA4_IER_TX_IE;
- }
-
- if( which & SIO_RX ) {
- ier &= ~UA4_IER_RX_IE;
- }
-
- // if there was a change, make it
-
- if( old != ier ) {
- outb( UA4_IER, ier );
- }
-
- // return the prior settings
-
- return( old );
-}
-
-/**
-** sio_inq_length()
-**
-** Get the input queue length
-**
-** usage: int num = sio_inq_length()
-**
-** @return the count of characters still in the input queue
-*/
-int sio_inq_length( void ) {
- return( incount );
-}
-
-/**
-** sio_readc()
-**
-** Get the next input character
-**
-** usage: int ch = sio_readc()
-**
-** @return the next character, or -1 if no character is available
-*/
-int sio_readc( void ) {
- int ch;
-
- // assume there is no character available
- ch = -1;
-
- //
- // If there is a character, return it
- //
-
- 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 ) {
- inlast = innext = inbuffer;
- }
-
- }
-
- return( ch );
-
-}
-
-/**
-** sio_read(buf,length)
-**
-** Read the entire input buffer into a user buffer of a specified size
-**
-** usage: int num = sio_read( char *buffer, int length )
-**
-** @param buf The destination buffer
-** @param length Length of the buffer
-**
-** @return the number of bytes copied, or 0 if no characters were available
-*/
-
-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 );
- }
-
- //
- // We have characters. Copy as many of them into the user
- // buffer as will fit.
- //
-
- while( incount > 0 && copied < length ) {
- *ptr++ = *innext++ & 0xff;
- if( innext > (inbuffer + BUF_SIZE) ) {
- innext = inbuffer;
- }
- --incount;
- ++copied;
- }
-
- // reset the input buffer if necessary
-
- if( incount < 1 ) {
- inlast = innext = inbuffer;
- }
-
- // return the copy count
-
- return( copied );
-}
-
-
-/**
-** sio_writec( ch )
-**
-** Write a character to the serial output
-**
-** usage: sio_writec( int ch )
-**
-** @param ch Character to be written (in the low-order 8 bits)
-*/
-void sio_writec( int ch ){
-
-
- //
- // Must do LF -> CRLF mapping
- //
-
- if( ch == '\n' ) {
- sio_writec( '\r' );
- }
-
- //
- // If we're currently transmitting, just add this to the buffer
- //
-
- if( sending ) {
- *outlast++ = ch;
- ++outcount;
- return;
- }
-
- //
- // Not sending - must prime the pump
- //
-
- sending = 1;
- outb( UA4_TXD, ch );
-
- // Also must enable transmitter interrupts
-
- sio_enable( SIO_TX );
-
-}
-
-/**
-** sio_write( buffer, length )
-**
-** Write a buffer of characters to the serial output
-**
-** usage: int num = sio_write( const char *buffer, int length )
-**
-** @param buffer Buffer containing characters to write
-** @param length Number of characters to write
-**
-** @return the number of characters copied into the SIO output buffer
-*/
-int sio_write( const char *buffer, int length ) {
- int first = *buffer;
- const char *ptr = buffer;
- int copied = 0;
-
- //
- // If we are currently sending, we want to append all
- // the characters to the output buffer; else, we want
- // to append all but the first character, and then use
- // sio_writec() to send the first one out.
- //
-
- if( !sending ) {
- ptr += 1;
- copied++;
- }
-
- while( copied < length && outcount < BUF_SIZE ) {
- *outlast++ = *ptr++;
- // wrap around if necessary
- if( outlast >= (outbuffer + BUF_SIZE) ) {
- outlast = outbuffer;
- }
- ++outcount;
- ++copied;
- }
-
- //
- // We use sio_writec() to send out the first character,
- // as it will correctly set all the other necessary
- // variables for us.
- //
-
- if( !sending ) {
- sio_writec( first );
- }
-
- // Return the transfer count
-
-
- return( copied );
-
-}
-
-/**
-** sio_puts( buf )
-**
-** Write a NUL-terminated buffer of characters to the serial output
-**
-** usage: int num = sio_puts( const char *buffer )
-**
-** @param buffer The buffer containing a NUL-terminated string
-**
-** @return the count of bytes transferred
-*/
-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 );
-
- return( n );
-}
-
-/**
-** sio_dump( full )
-**
-** dump the contents of the SIO buffers to the console
-**
-** usage: sio_dump(true) or sio_dump(false)
-**
-** @param full Boolean indicating whether or not a "full" dump
-** is being requested (which includes the contents
-** of the queues)
-*/
-
-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 );
-
- // if we're not doing a full dump, stop now
-
- 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++ );
- }
- 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++ );
- }
- cio_puts( "\"\n" );
- }
-}