@@ -152,7 +152,12 @@ const DEFAULT_SCRATCH: u8 = 0x00;
152
152
/// let value = serial.read(0);
153
153
///
154
154
/// // Send more bytes to the guest in one shot.
155
- /// serial.enqueue_raw_bytes(&[b'a', b'b', b'c']).unwrap();
155
+ /// let input = &[b'a', b'b', b'c'];
156
+ /// // Before enqueuing bytes we first check if there is enough free space
157
+ /// // in the FIFO.
158
+ /// if serial.fifo_capacity() >= input.len() {
159
+ /// serial.enqueue_raw_bytes(input).unwrap();
160
+ /// }
156
161
/// ```
157
162
pub struct Serial < T : Trigger , W : Write > {
158
163
// Some UART registers.
@@ -183,6 +188,8 @@ pub enum Error<E> {
183
188
Trigger ( E ) ,
184
189
/// Couldn't write/flush to the given destination.
185
190
IOError ( io:: Error ) ,
191
+ /// No space left in FIFO.
192
+ FullFifo ,
186
193
}
187
194
188
195
impl < T : Trigger , W : Write > Serial < T , W > {
@@ -407,6 +414,17 @@ impl<T: Trigger, W: Write> Serial<T, W> {
407
414
}
408
415
}
409
416
417
+ /// Returns how much space is still available in the FIFO.
418
+ ///
419
+ /// # Example
420
+ ///
421
+ /// You can see an example of how to use this function in the
422
+ /// [`Example` section from `Serial`](struct.Serial.html#example).
423
+ #[ inline]
424
+ pub fn fifo_capacity ( & self ) -> usize {
425
+ FIFO_SIZE - self . in_buffer . len ( )
426
+ }
427
+
410
428
/// Helps in sending more bytes to the guest in one shot, by storing
411
429
/// `input` bytes in UART buffer and letting the driver know there is
412
430
/// some pending data to be read by setting RDA bit and its corresponding
@@ -415,31 +433,45 @@ impl<T: Trigger, W: Write> Serial<T, W> {
415
433
/// # Arguments
416
434
/// * `input` - The data to be sent to the guest.
417
435
///
436
+ /// # Returns
437
+ ///
438
+ /// The function returns the number of bytes it was able to write to the fifo,
439
+ /// or `FullFifo` error when the fifo is full. Users can use
440
+ /// [`fifo_capacity`](#method.fifo_capacity) before calling this function
441
+ /// to check the available space.
442
+ ///
418
443
/// # Example
419
444
///
420
445
/// You can see an example of how to use this function in the
421
446
/// [`Example` section from `Serial`](struct.Serial.html#example).
422
- pub fn enqueue_raw_bytes ( & mut self , input : & [ u8 ] ) -> Result < ( ) , Error < T :: E > > {
447
+ pub fn enqueue_raw_bytes ( & mut self , input : & [ u8 ] ) -> Result < usize , Error < T :: E > > {
448
+ let mut write_count = 0 ;
423
449
if !self . is_in_loop_mode ( ) {
424
- self . in_buffer . extend ( input) ;
425
- self . set_lsr_rda_bit ( ) ;
426
- self . received_data_interrupt ( ) . map_err ( Error :: Trigger ) ?;
450
+ if self . fifo_capacity ( ) == 0 {
451
+ return Err ( Error :: FullFifo ) ;
452
+ }
453
+ write_count = std:: cmp:: min ( self . fifo_capacity ( ) , input. len ( ) ) ;
454
+ if write_count > 0 {
455
+ self . in_buffer . extend ( & input[ 0 ..write_count] ) ;
456
+ self . set_lsr_rda_bit ( ) ;
457
+ self . received_data_interrupt ( ) . map_err ( Error :: Trigger ) ?;
458
+ }
427
459
}
428
- Ok ( ( ) )
460
+ Ok ( write_count )
429
461
}
430
462
}
431
463
432
464
#[ cfg( test) ]
433
465
mod tests {
434
466
use super :: * ;
435
- use std:: io:: { sink, Error , Result } ;
467
+ use std:: io:: { sink, Result } ;
436
468
437
469
use vmm_sys_util:: eventfd:: EventFd ;
438
470
439
471
const RAW_INPUT_BUF : [ u8 ; 3 ] = [ b'a' , b'b' , b'c' ] ;
440
472
441
473
impl Trigger for EventFd {
442
- type E = Error ;
474
+ type E = io :: Error ;
443
475
444
476
fn trigger ( & self ) -> Result < ( ) > {
445
477
self . write ( 1 )
@@ -638,4 +670,32 @@ mod tests {
638
670
// have the same value).
639
671
assert_eq ! ( serial. read( MSR_OFFSET ) , MSR_DSR_BIT | MSR_CTS_BIT ) ;
640
672
}
673
+
674
+ #[ test]
675
+ fn test_fifo_max_size ( ) {
676
+ let event_fd = EventFd :: new ( libc:: EFD_NONBLOCK ) . unwrap ( ) ;
677
+ let mut serial = Serial :: new ( event_fd, sink ( ) ) ;
678
+
679
+ // Test case: trying to write too many bytes in an empty fifo will just write
680
+ // `FIFO_SIZE`. Any other subsequent writes, will return a `FullFifo` error.
681
+ let too_many_bytes = vec ! [ 1u8 ; FIFO_SIZE + 1 ] ;
682
+ let written_bytes = serial. enqueue_raw_bytes ( & too_many_bytes) . unwrap ( ) ;
683
+ assert_eq ! ( written_bytes, FIFO_SIZE ) ;
684
+ assert_eq ! ( serial. in_buffer. len( ) , FIFO_SIZE ) ;
685
+
686
+ // A subsequent call to `enqueue_raw_bytes` fails because the fifo is
687
+ // now full.
688
+ let one_byte_input = [ 1u8 ] ;
689
+ match serial. enqueue_raw_bytes ( & one_byte_input) {
690
+ Err ( Error :: FullFifo ) => ( ) ,
691
+ _ => unreachable ! ( ) ,
692
+ }
693
+
694
+ // Test case: consuming one byte from a full fifo does not allow writes
695
+ // bigger than one byte.
696
+ let _ = serial. read ( DATA_OFFSET ) ;
697
+ let written_bytes = serial. enqueue_raw_bytes ( & too_many_bytes[ ..2 ] ) . unwrap ( ) ;
698
+ assert_eq ! ( written_bytes, 1 ) ;
699
+ assert_eq ! ( serial. in_buffer. len( ) , FIFO_SIZE ) ;
700
+ }
641
701
}
0 commit comments