00001 // console.cc 00002 // Routines to simulate a serial port to a console device. 00003 // A console has input (a keyboard) and output (a display). 00004 // These are each simulated by operations on UNIX files. 00005 // The simulated device is asynchronous, so we have to invoke 00006 // the interrupt handler (after a simulated delay), to signal that 00007 // a byte has arrived and/or that a written byte has departed. 00008 // 00009 // DO NOT CHANGE -- part of the machine emulation 00010 // 00011 // Copyright (c) 1992-1996 The Regents of the University of California. 00012 // All rights reserved. See copyright.h for copyright notice and limitation 00013 // of liability and disclaimer of warranty provisions. 00014 00015 #include "copyright.h" 00016 #include "console.h" 00017 #include "main.h" 00018 00019 //---------------------------------------------------------------------- 00020 // ConsoleInput::ConsoleInput 00021 // Initialize the simulation of the input for a hardware console device. 00022 // 00023 // "readFile" -- UNIX file simulating the keyboard (NULL -> use stdin) 00024 // "toCall" is the interrupt handler to call when a character arrives 00025 // from the keyboard 00026 //---------------------------------------------------------------------- 00027 00028 ConsoleInput::ConsoleInput(char *readFile, CallBackObj *toCall) 00029 { 00030 if (readFile == NULL) 00031 readFileNo = 0; // keyboard = stdin 00032 else 00033 readFileNo = OpenForReadWrite(readFile, TRUE); // should be read-only 00034 00035 // set up the stuff to emulate asynchronous interrupts 00036 callWhenAvail = toCall; 00037 incoming = EOF; 00038 00039 // start polling for incoming keystrokes 00040 kernel->interrupt->Schedule(this, ConsoleTime, ConsoleReadInt); 00041 } 00042 00043 //---------------------------------------------------------------------- 00044 // ConsoleInput::~ConsoleInput 00045 // Clean up console input emulation 00046 //---------------------------------------------------------------------- 00047 00048 ConsoleInput::~ConsoleInput() 00049 { 00050 if (readFileNo != 0) 00051 Close(readFileNo); 00052 } 00053 00054 00055 //---------------------------------------------------------------------- 00056 // ConsoleInput::CallBack() 00057 // Simulator calls this when a character may be available to be 00058 // read in from the simulated keyboard (eg, the user typed something). 00059 // 00060 // First check to make sure character is available. 00061 // Then invoke the "callBack" registered by whoever wants the character. 00062 //---------------------------------------------------------------------- 00063 00064 void 00065 ConsoleInput::CallBack() 00066 { 00067 char c; 00068 int readCount; 00069 00070 ASSERT(incoming == EOF); 00071 if (!PollFile(readFileNo)) { // nothing to be read 00072 // schedule the next time to poll for a packet 00073 kernel->interrupt->Schedule(this, ConsoleTime, ConsoleReadInt); 00074 } else { 00075 // otherwise, try to read a character 00076 readCount = ReadPartial(readFileNo, &c, sizeof(char)); 00077 if (readCount == 0) { 00078 // this seems to happen at end of file, when the 00079 // console input is a regular file 00080 // don't schedule an interrupt, since there will never 00081 // be any more input 00082 // just do nothing.... 00083 } 00084 else { 00085 // save the character and notify the OS that 00086 // it is available 00087 ASSERT(readCount == sizeof(char)); 00088 incoming = c; 00089 kernel->stats->numConsoleCharsRead++; 00090 } 00091 callWhenAvail->CallBack(); 00092 } 00093 } 00094 00095 //---------------------------------------------------------------------- 00096 // ConsoleInput::GetChar() 00097 // Read a character from the input buffer, if there is any there. 00098 // Either return the character, or EOF if none buffered. 00099 //---------------------------------------------------------------------- 00100 00101 char 00102 ConsoleInput::GetChar() 00103 { 00104 char ch = incoming; 00105 00106 if (incoming != EOF) { // schedule when next char will arrive 00107 kernel->interrupt->Schedule(this, ConsoleTime, ConsoleReadInt); 00108 } 00109 incoming = EOF; 00110 return ch; 00111 } 00112 00113 00114 00115 //---------------------------------------------------------------------- 00116 // ConsoleOutput::ConsoleOutput 00117 // Initialize the simulation of the output for a hardware console device. 00118 // 00119 // "writeFile" -- UNIX file simulating the display (NULL -> use stdout) 00120 // "toCall" is the interrupt handler to call when a write to 00121 // the display completes. 00122 //---------------------------------------------------------------------- 00123 00124 ConsoleOutput::ConsoleOutput(char *writeFile, CallBackObj *toCall) 00125 { 00126 if (writeFile == NULL) 00127 writeFileNo = 1; // display = stdout 00128 else 00129 writeFileNo = OpenForWrite(writeFile); 00130 00131 callWhenDone = toCall; 00132 putBusy = FALSE; 00133 } 00134 00135 //---------------------------------------------------------------------- 00136 // ConsoleOutput::~ConsoleOutput 00137 // Clean up console output emulation 00138 //---------------------------------------------------------------------- 00139 00140 ConsoleOutput::~ConsoleOutput() 00141 { 00142 if (writeFileNo != 1) 00143 Close(writeFileNo); 00144 } 00145 00146 //---------------------------------------------------------------------- 00147 // ConsoleOutput::CallBack() 00148 // Simulator calls this when the next character can be output to the 00149 // display. 00150 //---------------------------------------------------------------------- 00151 00152 void 00153 ConsoleOutput::CallBack() 00154 { 00155 putBusy = FALSE; 00156 kernel->stats->numConsoleCharsWritten++; 00157 callWhenDone->CallBack(); 00158 } 00159 00160 //---------------------------------------------------------------------- 00161 // ConsoleOutput::PutChar() 00162 // Write a character to the simulated display, schedule an interrupt 00163 // to occur in the future, and return. 00164 //---------------------------------------------------------------------- 00165 00166 void 00167 ConsoleOutput::PutChar(char ch) 00168 { 00169 ASSERT(putBusy == FALSE); 00170 WriteFile(writeFileNo, &ch, sizeof(char)); 00171 putBusy = TRUE; 00172 kernel->interrupt->Schedule(this, ConsoleTime, ConsoleWriteInt); 00173 }