]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
kvm,8250: Implement missing register emulation
authorPekka Enberg <penberg@kernel.org>
Tue, 11 Jan 2011 15:52:22 +0000 (17:52 +0200)
committerPekka Enberg <penberg@kernel.org>
Tue, 11 Jan 2011 16:02:59 +0000 (18:02 +0200)
This patch implements missing register emulation as per "UART register to port
conversion table" here:

  http://www.lammertbies.nl/comm/info/serial-uart.html

Signed-off-by: Pekka Enberg <penberg@kernel.org>
tools/kvm/8250-serial.c

index f53e4faf7003bd7e5ba6dfde63673c0ca734c5a3..f71735a41bda6c10cd7e7273956861b86cc6ce16 100644 (file)
@@ -145,6 +145,28 @@ static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size
 
        offset          = port - dev->iobase;
 
+       /* LSR is factory test and MSR is not used for writes */
+       if (offset == UART_LSR || offset == UART_MSR)
+               return true;
+
+       /* FCR, LCR, MCR, and SCR have the same meaning regardless of DLAB */
+       switch (offset) {
+       case UART_FCR:
+               dev->fcr                = ioport__read8(data);
+               return true;
+       case UART_LCR:
+               dev->lcr                = ioport__read8(data);
+               return true;
+       case UART_MCR:
+               dev->mcr                = ioport__read8(data);
+               return true;
+       case UART_SCR:
+               dev->scr                = ioport__read8(data);
+               return true;
+       default:
+               break;
+       }
+
        if (dev->lcr & UART_LCR_DLAB) {
                switch (offset) {
                case UART_DLL:
@@ -153,14 +175,6 @@ static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size
                case UART_DLM:
                        dev->dlm                = ioport__read8(data);
                        break;
-               case UART_FCR:
-                       dev->fcr                = ioport__read8(data);
-                       break;
-               case UART_LCR:
-                       dev->lcr                = ioport__read8(data);
-                       break;
-               default:
-                       return false;
                }
        } else {
                switch (offset) {
@@ -182,20 +196,6 @@ static bool serial8250_out(struct kvm *self, uint16_t port, void *data, int size
                case UART_IER:
                        dev->ier                = ioport__read8(data);
                        break;
-               case UART_FCR:
-                       dev->fcr                = ioport__read8(data);
-                       break;
-               case UART_LCR:
-                       dev->lcr                = ioport__read8(data);
-                       break;
-               case UART_MCR:
-                       dev->mcr                = ioport__read8(data);
-                       break;
-               case UART_SCR:
-                       dev->scr                = ioport__read8(data);
-                       break;
-               default:
-                       return false;
                }
        }
 
@@ -213,21 +213,34 @@ static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size,
 
        offset          = port - dev->iobase;
 
-       if (dev->lcr & UART_LCR_DLAB)
-               return false;
-
-       switch (offset) {
-       case UART_RX:
-               if (dev->lsr & UART_LSR_DR) {
-                       dev->iir                = UART_IIR_NO_INT;
+       /* DLAB only changes the meaning of the first two registers */
+       if (dev->lcr & UART_LCR_DLAB) {
+               switch (offset) {
+               case UART_DLL:
+                       ioport__write8(data, dev->dll);
+                       return true;
+               case UART_DLM:
+                       ioport__write8(data, dev->dlm);
+                       return true;
+               }
+       } else {
+               switch (offset) {
+               case UART_RX:
+                       if (dev->lsr & UART_LSR_DR) {
+                               dev->iir                = UART_IIR_NO_INT;
 
-                       dev->lsr                &= ~UART_LSR_DR;
-                       ioport__write8(data, dev->rbr);
+                               dev->lsr                &= ~UART_LSR_DR;
+                               ioport__write8(data, dev->rbr);
+                       }
+                       return true;
+               case UART_IER:
+                       ioport__write8(data, dev->ier);
+                       return true;
                }
-               break;
-       case UART_IER:
-               ioport__write8(data, dev->ier);
-               break;
+       }
+
+       /* All other registers have the same meaning regardless of DLAB */
+       switch (offset) {
        case UART_IIR:
                dev->iir &= 0x3f; /* no FIFO for 8250 */
                ioport__write8(data, dev->iir);
@@ -248,8 +261,6 @@ static bool serial8250_in(struct kvm *self, uint16_t port, void *data, int size,
                /* No SCR for 8250 */
                ioport__write8(data, 0);
                break;
-       default:
-               return false;
        }
 
        return true;