|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v8 09/26] emul/ns16x50: implement MCR/MSR registers
From: Denis Mukhin <dmukhin@xxxxxxxx>
Add MCR/MSR registers emulation to the I/O port handler.
Add implementation of ns16x50_iir_check_msi().
Signed-off-by: Denis Mukhin <dmukhin@xxxxxxxx>
---
xen/common/emul/vuart/ns16x50.c | 76 ++++++++++++++++++++++++++++++++-
1 file changed, 75 insertions(+), 1 deletion(-)
diff --git a/xen/common/emul/vuart/ns16x50.c b/xen/common/emul/vuart/ns16x50.c
index e80815ccf6e2..9f530e589495 100644
--- a/xen/common/emul/vuart/ns16x50.c
+++ b/xen/common/emul/vuart/ns16x50.c
@@ -69,6 +69,10 @@ do { \
*/
#define UART_LSR_MASK (UART_LSR_OE | UART_LSR_BI)
+#define UART_MCR_MASK (UART_MCR_DTR | UART_MCR_RTS | \
+ UART_MCR_OUT1 | UART_MCR_OUT2 | \
+ UART_MCR_LOOP)
+
/*
* Number of supported registers in the UART.
*/
@@ -136,7 +140,7 @@ static bool cf_check ns16x50_iir_check_thr(const struct
vuart_ns16x50 *vdev)
static bool cf_check ns16x50_iir_check_msi(const struct vuart_ns16x50 *vdev)
{
- return false;
+ return vdev->regs[UART_MSR] & UART_MSR_CHANGE;
}
/*
@@ -193,6 +197,13 @@ static void ns16x50_irq_check(struct vuart_ns16x50 *vdev)
uint8_t iir = ns16x50_iir_get(vdev);
bool asserted = !(iir & UART_IIR_NOINT);
+ /*
+ * On a PC-compatible UART OUT2 gates the ISA interrupt.
+ * Linux'es autoconfig_irq() expects when it toggles MCR.OUT2 during IRQ
+ * probing.
+ */
+ asserted &= !!(vdev->regs[UART_MCR] & UART_MCR_OUT2);
+
if ( asserted == vdev->irq_asserted )
return;
@@ -254,12 +265,63 @@ static int ns16x50_io_write8(
regs[UART_LCR] = val;
break;
+ case UART_MCR: {
+ uint8_t msr_curr, msr_next, msr_delta;
+
+ msr_curr = regs[UART_MSR];
+ msr_next = 0;
+ msr_delta = 0;
+
+ if ( val & UART_MCR_RSRVD0 )
+ ns16x50_warn(vdev, "MCR: attempt to set reserved bit: %#x\n",
+ UART_MCR_RSRVD0);
+
+ if ( val & UART_MCR_TCRTLR )
+ ns16x50_warn(vdev, "MCR: not supported: %#x\n",
+ UART_MCR_TCRTLR);
+
+ if ( val & UART_MCR_RSRVD1 )
+ ns16x50_warn(vdev, "MCR: attempt to set reserved bit: %#x\n",
+ UART_MCR_RSRVD1);
+
+ /* Set modem status */
+ if ( val & UART_MCR_LOOP )
+ {
+ if ( val & UART_MCR_DTR )
+ msr_next |= UART_MSR_DSR;
+ if ( val & UART_MCR_RTS )
+ msr_next |= UART_MSR_CTS;
+ if ( val & UART_MCR_OUT1 )
+ msr_next |= UART_MSR_RI;
+ if ( val & UART_MCR_OUT2 )
+ msr_next |= UART_MSR_DCD;
+ }
+ else
+ msr_next |= UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
+
+ /* Calculate changes in modem status */
+ if ( (msr_curr & UART_MSR_CTS) ^ (msr_next & UART_MSR_CTS) )
+ msr_delta |= UART_MSR_DCTS;
+ if ( (msr_curr & UART_MSR_DSR) ^ (msr_next & UART_MSR_DSR) )
+ msr_delta |= UART_MSR_DDSR;
+ if ( !(msr_curr & UART_MSR_RI) && (msr_next & UART_MSR_RI) )
+ msr_delta |= UART_MSR_TERI;
+ if ( (msr_curr & UART_MSR_DCD) ^ (msr_next & UART_MSR_DCD) )
+ msr_delta |= UART_MSR_DDCD;
+
+ regs[UART_MCR] = val & UART_MCR_MASK;
+ regs[UART_MSR] = msr_next | msr_delta;
+
+ break;
+ }
+
/* NB: Firmware (e.g. OVMF) may rely on SCR presence. */
case UART_SCR:
regs[UART_SCR] = val;
break;
case UART_LSR: /* RO */
+ case UART_MSR: /* RO */
default:
rc = -EINVAL;
break;
@@ -360,11 +422,20 @@ static int ns16x50_io_read8(
val = regs[UART_LCR];
break;
+ case UART_MCR:
+ val = regs[UART_MCR];
+ break;
+
case UART_LSR:
val = regs[UART_LSR];
regs[UART_LSR] = val & ~UART_LSR_MASK;
break;
+ case UART_MSR:
+ val = regs[UART_MSR];
+ regs[UART_MSR] &= ~UART_MSR_CHANGE;
+ break;
+
case UART_SCR:
val = regs[UART_SCR];
break;
@@ -529,6 +600,9 @@ static void ns16x50_reset(struct vuart_ns16x50 *vdev)
vdev->irq_asserted = false;
vdev->regs[UART_LSR] = UART_LSR_THRE | UART_LSR_TEMT;
+ vdev->regs[UART_MSR] = UART_MSR_DCD |
+ UART_MSR_DSR |
+ UART_MSR_CTS;
/* NB: report 115200 baud rate. */
vdev->regs[NS16X50_REGS_NUM + UART_DLL] = divisor & UINT8_MAX;
--
2.56.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |