Add a dummy Console device
This commit is contained in:
		
							parent
							
								
									9f06e2f1a5
								
							
						
					
					
						commit
						7a46d7d993
					
				|  | @ -0,0 +1,136 @@ | ||||||
|  | /* | ||||||
|  |  * SPDX-License-Identifier: BlueOak-1.0.0 | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #![allow(dead_code)] | ||||||
|  | 
 | ||||||
|  | use core::fmt; | ||||||
|  | 
 | ||||||
|  | /// A trait that must be implemented by devices that are candidates for the
 | ||||||
|  | /// global console.
 | ||||||
|  | #[allow(unused_variables)] | ||||||
|  | pub trait ConsoleOps { | ||||||
|  |     fn putc(&self, c: char) {} | ||||||
|  |     fn puts(&self, string: &str) {} | ||||||
|  |     fn getc(&self) -> char { | ||||||
|  |         ' ' | ||||||
|  |     } | ||||||
|  |     fn flush(&self) {} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// A dummy console that just ignores its inputs.
 | ||||||
|  | pub struct NullConsole; | ||||||
|  | impl Drop for NullConsole { | ||||||
|  |     fn drop(&mut self) {} | ||||||
|  | } | ||||||
|  | impl ConsoleOps for NullConsole {} | ||||||
|  | 
 | ||||||
|  | /// Possible outputs which the console can store.
 | ||||||
|  | pub enum Output { | ||||||
|  |     None(NullConsole), | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Generate boilerplate for converting into one of Output enum values
 | ||||||
|  | macro output_from($name:ty, $optname:ident) { | ||||||
|  |     impl From<$name> for Output { | ||||||
|  |         fn from(instance: $name) -> Self { | ||||||
|  |             Output::$optname(instance) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | output_from!(NullConsole, None); | ||||||
|  | pub struct Console { | ||||||
|  |     output: Output, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Default for Console { | ||||||
|  |     fn default() -> Self { | ||||||
|  |         Console { | ||||||
|  |             output: (NullConsole {}).into(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Console { | ||||||
|  |     pub const fn new() -> Console { | ||||||
|  |         Console { | ||||||
|  |             output: Output::None(NullConsole {}), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     #[inline(always)] | ||||||
|  |     fn current_ptr(&self) -> &dyn ConsoleOps { | ||||||
|  |         match &self.output { | ||||||
|  |             Output::None(i) => i, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// Overwrite the current output. The old output will go out of scope and
 | ||||||
|  |     /// it's Drop function will be called.
 | ||||||
|  |     pub fn replace_with(&mut self, x: Output) { | ||||||
|  |         self.current_ptr().flush(); | ||||||
|  | 
 | ||||||
|  |         self.output = x; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /// A command prompt.
 | ||||||
|  |     pub fn command_prompt<'a>(&self, buf: &'a mut [u8]) -> &'a [u8] { | ||||||
|  |         self.puts("\n$> "); | ||||||
|  | 
 | ||||||
|  |         let mut i = 0; | ||||||
|  |         let mut input; | ||||||
|  |         loop { | ||||||
|  |             input = self.getc(); | ||||||
|  | 
 | ||||||
|  |             if input == '\n' { | ||||||
|  |                 self.puts("\n"); // do \r\n output
 | ||||||
|  |                 return &buf[..i]; | ||||||
|  |             } else { | ||||||
|  |                 if i < buf.len() { | ||||||
|  |                     buf[i] = input as u8; | ||||||
|  |                     i += 1; | ||||||
|  |                 } else { | ||||||
|  |                     return &buf[..i]; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 self.putc(input); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Drop for Console { | ||||||
|  |     fn drop(&mut self) {} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Dispatch the respective function to the currently stored output device.
 | ||||||
|  | impl ConsoleOps for Console { | ||||||
|  |     fn putc(&self, c: char) { | ||||||
|  |         self.current_ptr().putc(c); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn puts(&self, string: &str) { | ||||||
|  |         self.current_ptr().puts(string); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn getc(&self) -> char { | ||||||
|  |         self.current_ptr().getc() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn flush(&self) { | ||||||
|  |         self.current_ptr().flush() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /// Implementing this trait enables usage of the format_args! macros, which in
 | ||||||
|  | /// turn are used to implement the kernel's print! and println! macros.
 | ||||||
|  | ///
 | ||||||
|  | /// See src/macros.rs.
 | ||||||
|  | impl fmt::Write for Console { | ||||||
|  |     fn write_str(&mut self, s: &str) -> fmt::Result { | ||||||
|  |         self.current_ptr().puts(s); | ||||||
|  | 
 | ||||||
|  |         Ok(()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,6 @@ | ||||||
|  | /* | ||||||
|  |  * SPDX-License-Identifier: BlueOak-1.0.0 | ||||||
|  |  */ | ||||||
|  | pub mod console; | ||||||
|  | 
 | ||||||
|  | pub use console::{Console, ConsoleOps}; | ||||||
|  | @ -31,6 +31,7 @@ extern crate rlibc; // To enable linking memory intrinsics. | ||||||
| #[macro_use] | #[macro_use] | ||||||
| pub mod arch; | pub mod arch; | ||||||
| pub use arch::*; | pub use arch::*; | ||||||
|  | mod devices; | ||||||
| mod macros; | mod macros; | ||||||
| mod mm; | mod mm; | ||||||
| mod panic; | mod panic; | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue