Nearly complete PS/2 driver
This commit is contained in:
		
							parent
							
								
									f784e9a06a
								
							
						
					
					
						commit
						555ad5fd92
					
				
					 2 changed files with 190 additions and 33 deletions
				
			
		|  | @ -8,29 +8,27 @@ pub unsafe fn init() { | ||||||
|     PS2.lock().init(); |     PS2.lock().init(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| mod status { | bitflags! { | ||||||
|     bitflags! { |     flags StatusFlags: u8 { | ||||||
|         pub flags Flags: u8 { |         const OUTPUT_FULL = 1, | ||||||
|             const OUTPUT_FULL = 1, |         const INPUT_FULL = 1 << 1, | ||||||
|             const INPUT_FULL = 1 << 1, |         const SYSTEM = 1 << 2, | ||||||
|             const SYSTEM = 1 << 2, |         const COMMAND = 1 << 3, | ||||||
|             const COMMAND = 1 << 3, |         const TIME_OUT = 1 << 6, | ||||||
|             const TIME_OUT = 1 << 6, |         const PARITY = 1 << 7 | ||||||
|             const PARITY = 1 << 7 |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| mod config { | bitflags! { | ||||||
|     bitflags! { |     flags ConfigFlags: u8 { | ||||||
|         pub flags Flags: u8 { |         const FIRST_INTERRUPT = 1, | ||||||
|             const FIRST_INTERRUPT = 1, |         const SECOND_INTERRUPT = 1 << 1, | ||||||
|             const SECOND_INTERRUPT = 1 << 1, |         const POST_PASSED = 1 << 2, | ||||||
|             const SYSTEM = 1 << 2, |         // 1 << 3 should be zero
 | ||||||
|             const FIRST_DISABLE = 1 << 4, |         const FIRST_DISABLED = 1 << 4, | ||||||
|             const SECOND_DISABLE = 1 << 5, |         const SECOND_DISABLED = 1 << 5, | ||||||
|             const FIRST_TRANSLATE = 1 << 6 |         const FIRST_TRANSLATE = 1 << 6, | ||||||
|         } |         // 1 << 7 should be zero
 | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -49,25 +47,184 @@ enum Command { | ||||||
|     WriteSecond = 0xD4 |     WriteSecond = 0xD4 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[repr(u8)] | ||||||
|  | enum KeyboardCommand { | ||||||
|  |     EnableReporting = 0xF4, | ||||||
|  |     SetDefaults = 0xF6, | ||||||
|  |     Reset = 0xFF | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[repr(u8)] | ||||||
|  | enum MouseCommand { | ||||||
|  |     EnableReporting = 0xF4, | ||||||
|  |     SetDefaults = 0xF6, | ||||||
|  |     Reset = 0xFF | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bitflags! { | ||||||
|  |     flags MousePacketFlags: u8 { | ||||||
|  |         const LEFT_BUTTON = 1, | ||||||
|  |         const RIGHT_BUTTON = 1 << 1, | ||||||
|  |         const MIDDLE_BUTTON = 1 << 2, | ||||||
|  |         const ALWAYS_ON = 1 << 3, | ||||||
|  |         const X_SIGN = 1 << 4, | ||||||
|  |         const Y_SIGN = 1 << 5, | ||||||
|  |         const X_OVERFLOW = 1 << 6, | ||||||
|  |         const Y_OVERFLOW = 1 << 7 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| pub struct Ps2 { | pub struct Ps2 { | ||||||
|     pub data: Pio<u8>, |     data: Pio<u8>, | ||||||
|     pub status: ReadOnly<Pio<u8>>, |     status: ReadOnly<Pio<u8>>, | ||||||
|     pub command: WriteOnly<Pio<u8>> |     command: WriteOnly<Pio<u8>>, | ||||||
|  |     mouse: [u8; 3], | ||||||
|  |     mouse_i: usize | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Ps2 { | impl Ps2 { | ||||||
|     pub const fn new() -> Ps2 { |     const fn new() -> Ps2 { | ||||||
|         Ps2 { |         Ps2 { | ||||||
|             data: Pio::new(0x60), |             data: Pio::new(0x60), | ||||||
|             status: ReadOnly::new(Pio::new(0x64)), |             status: ReadOnly::new(Pio::new(0x64)), | ||||||
|             command: WriteOnly::new(Pio::new(0x64)) |             command: WriteOnly::new(Pio::new(0x64)), | ||||||
|  |             mouse: [0; 3], | ||||||
|  |             mouse_i: 0 | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn init(&mut self) { |     fn status(&mut self) -> StatusFlags { | ||||||
|         print!("Status {:?}\n", status::Flags::from_bits_truncate(self.status.read())); |         StatusFlags::from_bits_truncate(self.status.read()) | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|         self.command.write(Command::ReadConfig as u8); |     fn wait_write(&mut self) { | ||||||
|         print!("Config {:?}\n", config::Flags::from_bits_truncate(self.data.read())); |         while self.status().contains(INPUT_FULL) {} | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn wait_read(&mut self) { | ||||||
|  |         while ! self.status().contains(OUTPUT_FULL) {} | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn flush_read(&mut self) { | ||||||
|  |         while self.status().contains(OUTPUT_FULL) { | ||||||
|  |             self.data.read(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn command(&mut self, command: Command) { | ||||||
|  |         self.wait_write(); | ||||||
|  |         self.command.write(command as u8); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn read(&mut self) -> u8 { | ||||||
|  |         self.wait_read(); | ||||||
|  |         self.data.read() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn write(&mut self, data: u8) { | ||||||
|  |         self.wait_write(); | ||||||
|  |         self.data.write(data); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn config(&mut self) -> ConfigFlags { | ||||||
|  |         self.command(Command::ReadConfig); | ||||||
|  |         ConfigFlags::from_bits_truncate(self.read()) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn set_config(&mut self, config: ConfigFlags) { | ||||||
|  |         self.command(Command::WriteConfig); | ||||||
|  |         self.write(config.bits()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn keyboard_command(&mut self, command: KeyboardCommand) -> u8 { | ||||||
|  |         self.write(command as u8); | ||||||
|  |         self.read() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn mouse_command(&mut self, command: MouseCommand) -> u8 { | ||||||
|  |         self.command(Command::WriteSecond); | ||||||
|  |         self.write(command as u8); | ||||||
|  |         self.read() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn init(&mut self) { | ||||||
|  |         // Disable devices
 | ||||||
|  |         self.command(Command::DisableFirst); | ||||||
|  |         self.command(Command::DisableSecond); | ||||||
|  | 
 | ||||||
|  |         // Clear remaining data
 | ||||||
|  |         self.flush_read(); | ||||||
|  | 
 | ||||||
|  |         // Disable clocks, disable interrupts, and disable translate
 | ||||||
|  |         { | ||||||
|  |             let mut config = self.config(); | ||||||
|  |             config.insert(FIRST_DISABLED); | ||||||
|  |             config.insert(SECOND_DISABLED); | ||||||
|  |             config.remove(FIRST_TRANSLATE); | ||||||
|  |             config.remove(FIRST_INTERRUPT); | ||||||
|  |             config.remove(SECOND_INTERRUPT); | ||||||
|  |             self.set_config(config); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Perform the self test
 | ||||||
|  |         self.command(Command::TestController); | ||||||
|  |         let self_test = self.read(); | ||||||
|  |         if self_test != 0x55 { | ||||||
|  |             // TODO: Do reset on failure
 | ||||||
|  |             print!("PS/2 Self Test Failure: {:X}\n", self_test); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Enable clocks and interrupts
 | ||||||
|  |         { | ||||||
|  |             let mut config = self.config(); | ||||||
|  |             config.remove(FIRST_DISABLED); | ||||||
|  |             config.remove(SECOND_DISABLED); | ||||||
|  |             config.insert(FIRST_INTERRUPT); | ||||||
|  |             config.insert(SECOND_INTERRUPT); | ||||||
|  |             self.set_config(config); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Enable devices
 | ||||||
|  |         self.command(Command::EnableFirst); | ||||||
|  |         self.command(Command::EnableSecond); | ||||||
|  | 
 | ||||||
|  |         // Reset and enable scanning on keyboard
 | ||||||
|  |         // TODO: Check for ack
 | ||||||
|  |         self.keyboard_command(KeyboardCommand::Reset); | ||||||
|  |         self.keyboard_command(KeyboardCommand::EnableReporting); | ||||||
|  | 
 | ||||||
|  |         // Reset and enable scanning on mouse
 | ||||||
|  |         // TODO: Check for ack
 | ||||||
|  |         self.mouse_command(MouseCommand::Reset); | ||||||
|  |         self.mouse_command(MouseCommand::EnableReporting); | ||||||
|  | 
 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn on_keyboard(&mut self) { | ||||||
|  |         let data = self.data.read(); | ||||||
|  |         print!("KEY {:X}\n", data); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn on_mouse(&mut self) { | ||||||
|  |         self.mouse[self.mouse_i] = self.data.read(); | ||||||
|  |         self.mouse_i += 1; | ||||||
|  |         if self.mouse_i >= self.mouse.len() { | ||||||
|  |             self.mouse_i = 0; | ||||||
|  | 
 | ||||||
|  |             let flags = MousePacketFlags::from_bits_truncate(self.mouse[0]); | ||||||
|  | 
 | ||||||
|  |             let mut x = self.mouse[1] as isize; | ||||||
|  |             if flags.contains(X_SIGN) { | ||||||
|  |                 x -= 0x100; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             let mut y = self.mouse[2] as isize; | ||||||
|  |             if flags.contains(Y_SIGN) { | ||||||
|  |                 y -= 0x100; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             print!("MOUSE {}, {}, {:?}\n", x, y, flags); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,5 +1,7 @@ | ||||||
| use x86::io; | use x86::io; | ||||||
| 
 | 
 | ||||||
|  | use device::ps2::PS2; | ||||||
|  | 
 | ||||||
| #[inline(always)] | #[inline(always)] | ||||||
| unsafe fn master_ack() { | unsafe fn master_ack() { | ||||||
|     io::outb(0x20, 0x20); |     io::outb(0x20, 0x20); | ||||||
|  | @ -21,8 +23,7 @@ interrupt!(pit, { | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| interrupt!(keyboard, { | interrupt!(keyboard, { | ||||||
|     let data = io::inb(0x60); |     PS2.lock().on_keyboard(); | ||||||
|     print!("KEYBOARD {:X}\n", data); |  | ||||||
|     master_ack(); |     master_ack(); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
|  | @ -77,8 +78,7 @@ interrupt!(pci3, { | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| interrupt!(mouse, { | interrupt!(mouse, { | ||||||
|     let data = io::inb(0x60); |     PS2.lock().on_mouse(); | ||||||
|     print!("MOUSE {:X}\n", data); |  | ||||||
|     slave_ack(); |     slave_ack(); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Jeremy Soller
						Jeremy Soller