summary refs log tree commit diff
path: root/devices/src/serial.rs
diff options
context:
space:
mode:
authorDaniel Verkamp <dverkamp@chromium.org>2019-05-20 13:37:54 -0700
committerchrome-bot <chrome-bot@chromium.org>2019-05-23 02:14:11 -0700
commit207b1fd2b5727fa09f0f0528d83ea2920628ddc2 (patch)
treef35794f1b1570f52e637dc66b6c87d574a8da58e /devices/src/serial.rs
parentaf00eb7e26116180ab19dcd840e981b532916afd (diff)
downloadcrosvm-207b1fd2b5727fa09f0f0528d83ea2920628ddc2.tar
crosvm-207b1fd2b5727fa09f0f0528d83ea2920628ddc2.tar.gz
crosvm-207b1fd2b5727fa09f0f0528d83ea2920628ddc2.tar.bz2
crosvm-207b1fd2b5727fa09f0f0528d83ea2920628ddc2.tar.lz
crosvm-207b1fd2b5727fa09f0f0528d83ea2920628ddc2.tar.xz
crosvm-207b1fd2b5727fa09f0f0528d83ea2920628ddc2.tar.zst
crosvm-207b1fd2b5727fa09f0f0528d83ea2920628ddc2.zip
devices: serial: implement MSR loop behavior
This fixes the Linux serial driver loopback test for the 4th serial port
(COM4, aka /dev/ttyS3).

The default value of the modem status register is always returned in the
current crosvm implementation; however, this doesn't match the expected
value in the loopback mode test used by the Linux kernel 8250 serial
driver.  The other 3 serial ports (/dev/ttyS[012]) skip this test
because of the UPF_SKIP_TEST flag in STD_COMX_FLAGS, but the 4th port
uses STD_COM4_FLAGS instead, which doesn't have UPF_SKIP_TEST.

The mapping of MCR to MSR bits is defined in the 16550 UART data sheet:
http://www.ti.com/product/pc16550d

BUG=chromium:953983
TEST=`echo test > /dev/ttyS3` in crosvm

Change-Id: I1b52111235a500fef2dee00c5803a2221a25e0c6
Signed-off-by: Daniel Verkamp <dverkamp@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1620704
Tested-by: kokoro <noreply+kokoro@google.com>
Legacy-Commit-Queue: Commit Bot <commit-bot@chromium.org>
Reviewed-by: Zach Reizner <zachr@chromium.org>
Diffstat (limited to 'devices/src/serial.rs')
-rw-r--r--devices/src/serial.rs35
1 files changed, 32 insertions, 3 deletions
diff --git a/devices/src/serial.rs b/devices/src/serial.rs
index 1fa7b61..fb0886f 100644
--- a/devices/src/serial.rs
+++ b/devices/src/serial.rs
@@ -39,13 +39,22 @@ const LSR_DATA_BIT: u8 = 0x1;
 const LSR_EMPTY_BIT: u8 = 0x20;
 const LSR_IDLE_BIT: u8 = 0x40;
 
+const MCR_DTR_BIT: u8 = 0x01; // Data Terminal Ready
+const MCR_RTS_BIT: u8 = 0x02; // Request to Send
+const MCR_OUT1_BIT: u8 = 0x04;
+const MCR_OUT2_BIT: u8 = 0x08;
 const MCR_LOOP_BIT: u8 = 0x10;
 
+const MSR_CTS_BIT: u8 = 0x10; // Clear to Send
+const MSR_DSR_BIT: u8 = 0x20; // Data Set Ready
+const MSR_RI_BIT: u8 = 0x40; // Ring Indicator
+const MSR_DCD_BIT: u8 = 0x80; // Data Carrier Detect
+
 const DEFAULT_INTERRUPT_IDENTIFICATION: u8 = IIR_NONE_BIT; // no pending interrupt
 const DEFAULT_LINE_STATUS: u8 = LSR_EMPTY_BIT | LSR_IDLE_BIT; // THR empty and line is idle
 const DEFAULT_LINE_CONTROL: u8 = 0x3; // 8-bits per character
-const DEFAULT_MODEM_CONTROL: u8 = 0x8; // Auxiliary output 2
-const DEFAULT_MODEM_STATUS: u8 = 0x20 | 0x10 | 0x80; // data ready, clear to send, carrier detect
+const DEFAULT_MODEM_CONTROL: u8 = MCR_OUT2_BIT;
+const DEFAULT_MODEM_STATUS: u8 = MSR_DSR_BIT | MSR_CTS_BIT | MSR_DCD_BIT;
 const DEFAULT_BAUD_DIVISOR: u16 = 12; // 9600 bps
 
 #[derive(Debug)]
@@ -378,7 +387,27 @@ impl BusDevice for Serial {
             LCR => self.line_control,
             MCR => self.modem_control,
             LSR => self.line_status,
-            MSR => self.modem_status,
+            MSR => {
+                if self.is_loop() {
+                    let mut msr =
+                        self.modem_status & !(MSR_DSR_BIT | MSR_CTS_BIT | MSR_RI_BIT | MSR_DCD_BIT);
+                    if self.modem_control & MCR_DTR_BIT != 0 {
+                        msr |= MSR_DSR_BIT;
+                    }
+                    if self.modem_control & MCR_RTS_BIT != 0 {
+                        msr |= MSR_CTS_BIT;
+                    }
+                    if self.modem_control & MCR_OUT1_BIT != 0 {
+                        msr |= MSR_RI_BIT;
+                    }
+                    if self.modem_control & MCR_OUT2_BIT != 0 {
+                        msr |= MSR_DCD_BIT;
+                    }
+                    msr
+                } else {
+                    self.modem_status
+                }
+            }
             SCR => self.scratch,
             _ => 0,
         };