11use alloc:: collections:: VecDeque ;
2- use core:: num:: NonZero ;
2+ use core:: num:: NonZeroU8 ;
33
44use hermit_sync:: { InterruptTicketMutex , Lazy } ;
55use x86_64:: instructions:: port:: Port ;
66
77use crate :: kernel:: interrupts;
8+ use crate :: synch:: semaphore:: Semaphore ;
89
910const PS2_DATA_PORT : u16 = 0x60 ;
1011const PS2_CMD_PORT : u16 = 0x64 ;
@@ -13,10 +14,13 @@ const PS2_CMD_WRITE_CNFG: u8 = 0x60;
1314const PS2_CMD_DISABLE_KEYBOARD : u8 = 0xad ;
1415const PS2_CMD_DISABLE_MOUSE : u8 = 0xa7 ;
1516const PS2_CMD_ENABLE_KEYBOARD : u8 = 0xae ;
17+ #[ allow( dead_code) ]
18+ const PS2_CMD_ENABLE_MOUSE : u8 = 0xa8 ;
1619const PS2_CNFG_ENABLE_KEYBOARD_INTERRUPT : u8 = 0x01 ;
1720const PS2_BUFFER_FULL : u8 = 0x01 ;
1821
1922const BUFFER_SIZE : usize = 256 ;
23+ static KEYBOARD_SEMAPHORE : Semaphore = Semaphore :: new ( 0 ) ;
2024
2125struct Ps2 ;
2226impl Ps2 {
@@ -37,26 +41,34 @@ impl Ps2 {
3741 }
3842}
3943
40- static KEYBOARD_BUFFER : Lazy < InterruptTicketMutex < VecDeque < u8 > > > =
44+ static KEYBOARD_BUFFER : Lazy < InterruptTicketMutex < VecDeque < NonZeroU8 > > > =
4145 Lazy :: new ( || InterruptTicketMutex :: new ( VecDeque :: with_capacity ( BUFFER_SIZE ) ) ) ;
4246
4347fn keyboard_handler ( ) {
4448 let scancode = Ps2 :: read_data ( ) ;
45- let mut buffer = KEYBOARD_BUFFER . lock ( ) ;
46-
47- // Don't allow the buffer to grow infinitely, pop the oldest scancode if the buffer is full.
48- if buffer. len ( ) >= BUFFER_SIZE {
49- buffer. pop_front ( ) ;
49+ if let Some ( valid_scancode) = NonZeroU8 :: new ( scancode) {
50+ let mut sem = true ;
51+ {
52+ let mut buffer = KEYBOARD_BUFFER . lock ( ) ;
53+
54+ // Pop the oldest scancode if the buffer is full.
55+ if buffer. len ( ) >= BUFFER_SIZE {
56+ buffer. pop_front ( ) ;
57+ sem = false ;
58+ }
59+ buffer. push_back ( valid_scancode) ;
60+ }
61+ if sem {
62+ KEYBOARD_SEMAPHORE . release ( ) ;
63+ }
5064 }
51-
52- buffer. push_back ( scancode) ;
5365}
5466
5567pub ( crate ) fn get_keyboard_handler ( ) -> ( u8 , fn ( ) ) {
5668 Ps2 :: write_cmd ( PS2_CMD_DISABLE_KEYBOARD ) ;
5769 Ps2 :: write_cmd ( PS2_CMD_DISABLE_MOUSE ) ;
5870
59- // Ensure an empty buffer to guard against stuck data
71+ // Ensure an empty buffer to guard against stuck/garbage data
6072 while ( Ps2 :: read_status ( ) & PS2_BUFFER_FULL ) != 0 {
6173 let _ = Ps2 :: read_data ( ) ;
6274 }
@@ -79,7 +91,27 @@ pub(crate) fn get_keyboard_handler() -> (u8, fn()) {
7991 ( 1 , keyboard_handler)
8092}
8193
82- /// Pops a scancode from the keyboard buffer, returning None if the buffer is empty.
83- pub fn pop_scancode ( ) -> Option < NonZero < u8 > > {
84- KEYBOARD_BUFFER . lock ( ) . pop_front ( )
94+ /// Pops scancodes from the keyboard buffer into the provided slice. If `nonblocking` is false, the
95+ /// function will sleep the current thread until a scancode has been received. Returns the number of scancodes
96+ /// popped into the slice.
97+ pub fn pop_scancodes ( slice : & mut [ u8 ] , nonblocking : bool ) -> usize {
98+ if slice. is_empty ( ) {
99+ return 0 ;
100+ }
101+ if nonblocking {
102+ if !KEYBOARD_SEMAPHORE . try_acquire ( ) {
103+ return 0 ;
104+ }
105+ } else {
106+ KEYBOARD_SEMAPHORE . acquire ( None ) ;
107+ }
108+ let mut amount: usize = 1 ;
109+ while amount < slice. len ( ) && KEYBOARD_SEMAPHORE . try_acquire ( ) {
110+ amount += 1 ;
111+ }
112+ let mut buffer = KEYBOARD_BUFFER . lock ( ) ;
113+ for scancode in slice[ ..amount] . iter_mut ( ) {
114+ * scancode = buffer. pop_front ( ) . unwrap ( ) . get ( ) ;
115+ }
116+ amount
85117}
0 commit comments