xref: /openbmc/qemu/hw/char/serial.c (revision b5ab62b3c0050612c7f9b0b4baeb44ebab42775a)
149ab747fSPaolo Bonzini /*
249ab747fSPaolo Bonzini  * QEMU 16550A UART emulation
349ab747fSPaolo Bonzini  *
449ab747fSPaolo Bonzini  * Copyright (c) 2003-2004 Fabrice Bellard
549ab747fSPaolo Bonzini  * Copyright (c) 2008 Citrix Systems, Inc.
649ab747fSPaolo Bonzini  *
749ab747fSPaolo Bonzini  * Permission is hereby granted, free of charge, to any person obtaining a copy
849ab747fSPaolo Bonzini  * of this software and associated documentation files (the "Software"), to deal
949ab747fSPaolo Bonzini  * in the Software without restriction, including without limitation the rights
1049ab747fSPaolo Bonzini  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1149ab747fSPaolo Bonzini  * copies of the Software, and to permit persons to whom the Software is
1249ab747fSPaolo Bonzini  * furnished to do so, subject to the following conditions:
1349ab747fSPaolo Bonzini  *
1449ab747fSPaolo Bonzini  * The above copyright notice and this permission notice shall be included in
1549ab747fSPaolo Bonzini  * all copies or substantial portions of the Software.
1649ab747fSPaolo Bonzini  *
1749ab747fSPaolo Bonzini  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1849ab747fSPaolo Bonzini  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1949ab747fSPaolo Bonzini  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
2049ab747fSPaolo Bonzini  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2149ab747fSPaolo Bonzini  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2249ab747fSPaolo Bonzini  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2349ab747fSPaolo Bonzini  * THE SOFTWARE.
2449ab747fSPaolo Bonzini  */
2549ab747fSPaolo Bonzini 
26b6a0aa05SPeter Maydell #include "qemu/osdep.h"
2729daa894SPhilippe Mathieu-Daudé #include "qemu/bitops.h"
2849ab747fSPaolo Bonzini #include "hw/char/serial.h"
2964552b6bSMarkus Armbruster #include "hw/irq.h"
30d6454270SMarkus Armbruster #include "migration/vmstate.h"
317566c6efSMarc-André Lureau #include "chardev/char-serial.h"
32da34e65cSMarkus Armbruster #include "qapi/error.h"
3349ab747fSPaolo Bonzini #include "qemu/timer.h"
3471e8a915SMarkus Armbruster #include "sysemu/reset.h"
3554d31236SMarkus Armbruster #include "sysemu/runstate.h"
364a44d85eSSeiji Aguchi #include "qemu/error-report.h"
3700609186SPhilippe Mathieu-Daudé #include "trace.h"
38ff22c588SMarc-André Lureau #include "hw/qdev-properties.h"
39ce35e229SEduardo Habkost #include "hw/qdev-properties-system.h"
4049ab747fSPaolo Bonzini 
4149ab747fSPaolo Bonzini #define UART_LCR_DLAB   0x80    /* Divisor latch access bit */
4249ab747fSPaolo Bonzini 
4349ab747fSPaolo Bonzini #define UART_IER_MSI    0x08    /* Enable Modem status interrupt */
4449ab747fSPaolo Bonzini #define UART_IER_RLSI   0x04    /* Enable receiver line status interrupt */
4549ab747fSPaolo Bonzini #define UART_IER_THRI   0x02    /* Enable Transmitter holding register int. */
4649ab747fSPaolo Bonzini #define UART_IER_RDI    0x01    /* Enable receiver data interrupt */
4749ab747fSPaolo Bonzini 
4849ab747fSPaolo Bonzini #define UART_IIR_NO_INT 0x01    /* No interrupts pending */
4949ab747fSPaolo Bonzini #define UART_IIR_ID     0x06    /* Mask for the interrupt ID */
5049ab747fSPaolo Bonzini 
5149ab747fSPaolo Bonzini #define UART_IIR_MSI    0x00    /* Modem status interrupt */
5249ab747fSPaolo Bonzini #define UART_IIR_THRI   0x02    /* Transmitter holding register empty */
5349ab747fSPaolo Bonzini #define UART_IIR_RDI    0x04    /* Receiver data interrupt */
5449ab747fSPaolo Bonzini #define UART_IIR_RLSI   0x06    /* Receiver line status interrupt */
5549ab747fSPaolo Bonzini #define UART_IIR_CTI    0x0C    /* Character Timeout Indication */
5649ab747fSPaolo Bonzini 
579b4b4e51SMichael Tokarev #define UART_IIR_FENF   0x80    /* Fifo enabled, but not functioning */
5849ab747fSPaolo Bonzini #define UART_IIR_FE     0xC0    /* Fifo enabled */
5949ab747fSPaolo Bonzini 
6049ab747fSPaolo Bonzini /*
6149ab747fSPaolo Bonzini  * These are the definitions for the Modem Control Register
6249ab747fSPaolo Bonzini  */
6349ab747fSPaolo Bonzini #define UART_MCR_LOOP   0x10    /* Enable loopback test mode */
6449ab747fSPaolo Bonzini #define UART_MCR_OUT2   0x08    /* Out2 complement */
6549ab747fSPaolo Bonzini #define UART_MCR_OUT1   0x04    /* Out1 complement */
6649ab747fSPaolo Bonzini #define UART_MCR_RTS    0x02    /* RTS complement */
6749ab747fSPaolo Bonzini #define UART_MCR_DTR    0x01    /* DTR complement */
6849ab747fSPaolo Bonzini 
6949ab747fSPaolo Bonzini /*
7049ab747fSPaolo Bonzini  * These are the definitions for the Modem Status Register
7149ab747fSPaolo Bonzini  */
7249ab747fSPaolo Bonzini #define UART_MSR_DCD        0x80    /* Data Carrier Detect */
7349ab747fSPaolo Bonzini #define UART_MSR_RI         0x40    /* Ring Indicator */
7449ab747fSPaolo Bonzini #define UART_MSR_DSR        0x20    /* Data Set Ready */
7549ab747fSPaolo Bonzini #define UART_MSR_CTS        0x10    /* Clear to Send */
7649ab747fSPaolo Bonzini #define UART_MSR_DDCD       0x08    /* Delta DCD */
7749ab747fSPaolo Bonzini #define UART_MSR_TERI       0x04    /* Trailing edge ring indicator */
7849ab747fSPaolo Bonzini #define UART_MSR_DDSR       0x02    /* Delta DSR */
7949ab747fSPaolo Bonzini #define UART_MSR_DCTS       0x01    /* Delta CTS */
8049ab747fSPaolo Bonzini #define UART_MSR_ANY_DELTA  0x0F    /* Any of the delta bits! */
8149ab747fSPaolo Bonzini 
8249ab747fSPaolo Bonzini #define UART_LSR_TEMT       0x40    /* Transmitter empty */
8349ab747fSPaolo Bonzini #define UART_LSR_THRE       0x20    /* Transmit-hold-register empty */
8449ab747fSPaolo Bonzini #define UART_LSR_BI         0x10    /* Break interrupt indicator */
8549ab747fSPaolo Bonzini #define UART_LSR_FE         0x08    /* Frame error indicator */
8649ab747fSPaolo Bonzini #define UART_LSR_PE         0x04    /* Parity error indicator */
8749ab747fSPaolo Bonzini #define UART_LSR_OE         0x02    /* Overrun error indicator */
8849ab747fSPaolo Bonzini #define UART_LSR_DR         0x01    /* Receiver data ready */
8949ab747fSPaolo Bonzini #define UART_LSR_INT_ANY    0x1E    /* Any of the lsr-interrupt-triggering status bits */
9049ab747fSPaolo Bonzini 
9149ab747fSPaolo Bonzini /* Interrupt trigger levels. The byte-counts are for 16550A - in newer UARTs the byte-count for each ITL is higher. */
9249ab747fSPaolo Bonzini 
9349ab747fSPaolo Bonzini #define UART_FCR_ITL_1      0x00 /* 1 byte ITL */
9449ab747fSPaolo Bonzini #define UART_FCR_ITL_2      0x40 /* 4 bytes ITL */
9549ab747fSPaolo Bonzini #define UART_FCR_ITL_3      0x80 /* 8 bytes ITL */
9649ab747fSPaolo Bonzini #define UART_FCR_ITL_4      0xC0 /* 14 bytes ITL */
9749ab747fSPaolo Bonzini 
9849ab747fSPaolo Bonzini #define UART_FCR_DMS        0x08    /* DMA Mode Select */
9949ab747fSPaolo Bonzini #define UART_FCR_XFR        0x04    /* XMIT Fifo Reset */
10049ab747fSPaolo Bonzini #define UART_FCR_RFR        0x02    /* RCVR Fifo Reset */
10149ab747fSPaolo Bonzini #define UART_FCR_FE         0x01    /* FIFO Enable */
10249ab747fSPaolo Bonzini 
10349ab747fSPaolo Bonzini #define MAX_XMIT_RETRY      4
10449ab747fSPaolo Bonzini 
10549ab747fSPaolo Bonzini static void serial_receive1(void *opaque, const uint8_t *buf, int size);
106b0585e7eSPaolo Bonzini static void serial_xmit(SerialState *s);
10749ab747fSPaolo Bonzini 
recv_fifo_put(SerialState * s,uint8_t chr)1088e8638faSPeter Crosthwaite static inline void recv_fifo_put(SerialState *s, uint8_t chr)
10949ab747fSPaolo Bonzini {
11049ab747fSPaolo Bonzini     /* Receive overruns do not overwrite FIFO contents. */
1118e8638faSPeter Crosthwaite     if (!fifo8_is_full(&s->recv_fifo)) {
1128e8638faSPeter Crosthwaite         fifo8_push(&s->recv_fifo, chr);
1138e8638faSPeter Crosthwaite     } else {
11449ab747fSPaolo Bonzini         s->lsr |= UART_LSR_OE;
11549ab747fSPaolo Bonzini     }
11649ab747fSPaolo Bonzini }
11749ab747fSPaolo Bonzini 
serial_update_irq(SerialState * s)11849ab747fSPaolo Bonzini static void serial_update_irq(SerialState *s)
11949ab747fSPaolo Bonzini {
12049ab747fSPaolo Bonzini     uint8_t tmp_iir = UART_IIR_NO_INT;
12149ab747fSPaolo Bonzini 
12249ab747fSPaolo Bonzini     if ((s->ier & UART_IER_RLSI) && (s->lsr & UART_LSR_INT_ANY)) {
12349ab747fSPaolo Bonzini         tmp_iir = UART_IIR_RLSI;
12449ab747fSPaolo Bonzini     } else if ((s->ier & UART_IER_RDI) && s->timeout_ipending) {
12549ab747fSPaolo Bonzini         /* Note that(s->ier & UART_IER_RDI) can mask this interrupt,
12649ab747fSPaolo Bonzini          * this is not in the specification but is observed on existing
12749ab747fSPaolo Bonzini          * hardware.  */
12849ab747fSPaolo Bonzini         tmp_iir = UART_IIR_CTI;
12949ab747fSPaolo Bonzini     } else if ((s->ier & UART_IER_RDI) && (s->lsr & UART_LSR_DR) &&
13049ab747fSPaolo Bonzini                (!(s->fcr & UART_FCR_FE) ||
1318e8638faSPeter Crosthwaite                 s->recv_fifo.num >= s->recv_fifo_itl)) {
13249ab747fSPaolo Bonzini         tmp_iir = UART_IIR_RDI;
13349ab747fSPaolo Bonzini     } else if ((s->ier & UART_IER_THRI) && s->thr_ipending) {
13449ab747fSPaolo Bonzini         tmp_iir = UART_IIR_THRI;
13549ab747fSPaolo Bonzini     } else if ((s->ier & UART_IER_MSI) && (s->msr & UART_MSR_ANY_DELTA)) {
13649ab747fSPaolo Bonzini         tmp_iir = UART_IIR_MSI;
13749ab747fSPaolo Bonzini     }
13849ab747fSPaolo Bonzini 
13949ab747fSPaolo Bonzini     s->iir = tmp_iir | (s->iir & 0xF0);
14049ab747fSPaolo Bonzini 
14149ab747fSPaolo Bonzini     if (tmp_iir != UART_IIR_NO_INT) {
14249ab747fSPaolo Bonzini         qemu_irq_raise(s->irq);
14349ab747fSPaolo Bonzini     } else {
14449ab747fSPaolo Bonzini         qemu_irq_lower(s->irq);
14549ab747fSPaolo Bonzini     }
14649ab747fSPaolo Bonzini }
14749ab747fSPaolo Bonzini 
serial_update_parameters(SerialState * s)14849ab747fSPaolo Bonzini static void serial_update_parameters(SerialState *s)
14949ab747fSPaolo Bonzini {
15001478834SCalvin Lee     float speed;
15101478834SCalvin Lee     int parity, data_bits, stop_bits, frame_size;
15249ab747fSPaolo Bonzini     QEMUSerialSetParams ssp;
15349ab747fSPaolo Bonzini 
15449ab747fSPaolo Bonzini     /* Start bit. */
15549ab747fSPaolo Bonzini     frame_size = 1;
15649ab747fSPaolo Bonzini     if (s->lcr & 0x08) {
15749ab747fSPaolo Bonzini         /* Parity bit. */
15849ab747fSPaolo Bonzini         frame_size++;
15949ab747fSPaolo Bonzini         if (s->lcr & 0x10)
16049ab747fSPaolo Bonzini             parity = 'E';
16149ab747fSPaolo Bonzini         else
16249ab747fSPaolo Bonzini             parity = 'O';
16349ab747fSPaolo Bonzini     } else {
16449ab747fSPaolo Bonzini             parity = 'N';
16549ab747fSPaolo Bonzini     }
16601478834SCalvin Lee     if (s->lcr & 0x04) {
16749ab747fSPaolo Bonzini         stop_bits = 2;
16801478834SCalvin Lee     } else {
16949ab747fSPaolo Bonzini         stop_bits = 1;
17001478834SCalvin Lee     }
17149ab747fSPaolo Bonzini 
17249ab747fSPaolo Bonzini     data_bits = (s->lcr & 0x03) + 5;
17349ab747fSPaolo Bonzini     frame_size += data_bits + stop_bits;
17401478834SCalvin Lee     /* Zero divisor should give about 3500 baud */
17501478834SCalvin Lee     speed = (s->divider == 0) ? 3500 : (float) s->baudbase / s->divider;
17649ab747fSPaolo Bonzini     ssp.speed = speed;
17749ab747fSPaolo Bonzini     ssp.parity = parity;
17849ab747fSPaolo Bonzini     ssp.data_bits = data_bits;
17949ab747fSPaolo Bonzini     ssp.stop_bits = stop_bits;
18073bcb24dSRutuja Shah     s->char_transmit_time =  (NANOSECONDS_PER_SECOND / speed) * frame_size;
1815345fdb4SMarc-André Lureau     qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
1824d7b9a63SPhilippe Mathieu-Daudé     trace_serial_update_parameters(speed, parity, data_bits, stop_bits);
18349ab747fSPaolo Bonzini }
18449ab747fSPaolo Bonzini 
serial_update_msl(SerialState * s)18549ab747fSPaolo Bonzini static void serial_update_msl(SerialState *s)
18649ab747fSPaolo Bonzini {
18749ab747fSPaolo Bonzini     uint8_t omsr;
18849ab747fSPaolo Bonzini     int flags;
18949ab747fSPaolo Bonzini 
190bc72ad67SAlex Bligh     timer_del(s->modem_status_poll);
19149ab747fSPaolo Bonzini 
1925345fdb4SMarc-André Lureau     if (qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_GET_TIOCM,
193becdfa00SMarc-André Lureau                           &flags) == -ENOTSUP) {
19449ab747fSPaolo Bonzini         s->poll_msl = -1;
19549ab747fSPaolo Bonzini         return;
19649ab747fSPaolo Bonzini     }
19749ab747fSPaolo Bonzini 
19849ab747fSPaolo Bonzini     omsr = s->msr;
19949ab747fSPaolo Bonzini 
20049ab747fSPaolo Bonzini     s->msr = (flags & CHR_TIOCM_CTS) ? s->msr | UART_MSR_CTS : s->msr & ~UART_MSR_CTS;
20149ab747fSPaolo Bonzini     s->msr = (flags & CHR_TIOCM_DSR) ? s->msr | UART_MSR_DSR : s->msr & ~UART_MSR_DSR;
20249ab747fSPaolo Bonzini     s->msr = (flags & CHR_TIOCM_CAR) ? s->msr | UART_MSR_DCD : s->msr & ~UART_MSR_DCD;
20349ab747fSPaolo Bonzini     s->msr = (flags & CHR_TIOCM_RI) ? s->msr | UART_MSR_RI : s->msr & ~UART_MSR_RI;
20449ab747fSPaolo Bonzini 
20549ab747fSPaolo Bonzini     if (s->msr != omsr) {
20649ab747fSPaolo Bonzini          /* Set delta bits */
20749ab747fSPaolo Bonzini          s->msr = s->msr | ((s->msr >> 4) ^ (omsr >> 4));
20849ab747fSPaolo Bonzini          /* UART_MSR_TERI only if change was from 1 -> 0 */
20949ab747fSPaolo Bonzini          if ((s->msr & UART_MSR_TERI) && !(omsr & UART_MSR_RI))
21049ab747fSPaolo Bonzini              s->msr &= ~UART_MSR_TERI;
21149ab747fSPaolo Bonzini          serial_update_irq(s);
21249ab747fSPaolo Bonzini     }
21349ab747fSPaolo Bonzini 
21449ab747fSPaolo Bonzini     /* The real 16550A apparently has a 250ns response latency to line status changes.
21549ab747fSPaolo Bonzini        We'll be lazy and poll only every 10ms, and only poll it at all if MSI interrupts are turned on */
21649ab747fSPaolo Bonzini 
21773bcb24dSRutuja Shah     if (s->poll_msl) {
21873bcb24dSRutuja Shah         timer_mod(s->modem_status_poll, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
21973bcb24dSRutuja Shah                   NANOSECONDS_PER_SECOND / 100);
22073bcb24dSRutuja Shah     }
22149ab747fSPaolo Bonzini }
22249ab747fSPaolo Bonzini 
serial_watch_cb(void * do_not_use,GIOCondition cond,void * opaque)223bf7b1eabSMarc-André Lureau static gboolean serial_watch_cb(void *do_not_use, GIOCondition cond,
224b0585e7eSPaolo Bonzini                                 void *opaque)
22549ab747fSPaolo Bonzini {
22649ab747fSPaolo Bonzini     SerialState *s = opaque;
227a1df76daSPaolo Bonzini     s->watch_tag = 0;
228b0585e7eSPaolo Bonzini     serial_xmit(s);
22953c7c924SPhilippe Mathieu-Daudé     return G_SOURCE_REMOVE;
230b0585e7eSPaolo Bonzini }
23149ab747fSPaolo Bonzini 
serial_xmit(SerialState * s)232b0585e7eSPaolo Bonzini static void serial_xmit(SerialState *s)
233b0585e7eSPaolo Bonzini {
234f702e62aSKirill Batuzov     do {
2350d931d70SPaolo Bonzini         assert(!(s->lsr & UART_LSR_TEMT));
236807464d8SPaolo Bonzini         if (s->tsr_retry == 0) {
2370d931d70SPaolo Bonzini             assert(!(s->lsr & UART_LSR_THRE));
2380d931d70SPaolo Bonzini 
23949ab747fSPaolo Bonzini             if (s->fcr & UART_FCR_FE) {
2400d931d70SPaolo Bonzini                 assert(!fifo8_is_empty(&s->xmit_fifo));
241dffacd46SDon Slutz                 s->tsr = fifo8_pop(&s->xmit_fifo);
2428e8638faSPeter Crosthwaite                 if (!s->xmit_fifo.num) {
24349ab747fSPaolo Bonzini                     s->lsr |= UART_LSR_THRE;
2447f4f0a22SPeter Crosthwaite                 }
24549ab747fSPaolo Bonzini             } else {
24649ab747fSPaolo Bonzini                 s->tsr = s->thr;
24749ab747fSPaolo Bonzini                 s->lsr |= UART_LSR_THRE;
2480d931d70SPaolo Bonzini             }
2490d931d70SPaolo Bonzini             if ((s->lsr & UART_LSR_THRE) && !s->thr_ipending) {
2500d931d70SPaolo Bonzini                 s->thr_ipending = 1;
2510d931d70SPaolo Bonzini                 serial_update_irq(s);
25249ab747fSPaolo Bonzini             }
25349ab747fSPaolo Bonzini         }
25449ab747fSPaolo Bonzini 
25549ab747fSPaolo Bonzini         if (s->mcr & UART_MCR_LOOP) {
25649ab747fSPaolo Bonzini             /* in loopback mode, say that we just received a char */
25749ab747fSPaolo Bonzini             serial_receive1(s, &s->tsr, 1);
258f3575af1SMarc-André Lureau         } else {
259f3575af1SMarc-André Lureau             int rc = qemu_chr_fe_write(&s->chr, &s->tsr, 1);
260f3575af1SMarc-André Lureau 
261f3575af1SMarc-André Lureau             if ((rc == 0 ||
262f3575af1SMarc-André Lureau                  (rc == -1 && errno == EAGAIN)) &&
263a1df76daSPaolo Bonzini                 s->tsr_retry < MAX_XMIT_RETRY) {
264a1df76daSPaolo Bonzini                 assert(s->watch_tag == 0);
265becdfa00SMarc-André Lureau                 s->watch_tag =
2665345fdb4SMarc-André Lureau                     qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
267a1df76daSPaolo Bonzini                                           serial_watch_cb, s);
268a1df76daSPaolo Bonzini                 if (s->watch_tag > 0) {
26949ab747fSPaolo Bonzini                     s->tsr_retry++;
270b0585e7eSPaolo Bonzini                     return;
27149ab747fSPaolo Bonzini                 }
27249ab747fSPaolo Bonzini             }
273f3575af1SMarc-André Lureau         }
274bce933b8SPaolo Bonzini         s->tsr_retry = 0;
2750d931d70SPaolo Bonzini 
276f702e62aSKirill Batuzov         /* Transmit another byte if it is already available. It is only
277f702e62aSKirill Batuzov            possible when FIFO is enabled and not empty. */
2780d931d70SPaolo Bonzini     } while (!(s->lsr & UART_LSR_THRE));
27949ab747fSPaolo Bonzini 
280bc72ad67SAlex Bligh     s->last_xmit_ts = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
28149ab747fSPaolo Bonzini     s->lsr |= UART_LSR_TEMT;
28249ab747fSPaolo Bonzini }
28349ab747fSPaolo Bonzini 
2847385b275SPavel Dovgalyuk /* Setter for FCR.
2857385b275SPavel Dovgalyuk    is_load flag means, that value is set while loading VM state
2867385b275SPavel Dovgalyuk    and interrupt should not be invoked */
serial_write_fcr(SerialState * s,uint8_t val)2877385b275SPavel Dovgalyuk static void serial_write_fcr(SerialState *s, uint8_t val)
2887385b275SPavel Dovgalyuk {
2897385b275SPavel Dovgalyuk     /* Set fcr - val only has the bits that are supposed to "stick" */
2907385b275SPavel Dovgalyuk     s->fcr = val;
2917385b275SPavel Dovgalyuk 
2927385b275SPavel Dovgalyuk     if (val & UART_FCR_FE) {
2937385b275SPavel Dovgalyuk         s->iir |= UART_IIR_FE;
2947385b275SPavel Dovgalyuk         /* Set recv_fifo trigger Level */
2957385b275SPavel Dovgalyuk         switch (val & 0xC0) {
2967385b275SPavel Dovgalyuk         case UART_FCR_ITL_1:
2977385b275SPavel Dovgalyuk             s->recv_fifo_itl = 1;
2987385b275SPavel Dovgalyuk             break;
2997385b275SPavel Dovgalyuk         case UART_FCR_ITL_2:
3007385b275SPavel Dovgalyuk             s->recv_fifo_itl = 4;
3017385b275SPavel Dovgalyuk             break;
3027385b275SPavel Dovgalyuk         case UART_FCR_ITL_3:
3037385b275SPavel Dovgalyuk             s->recv_fifo_itl = 8;
3047385b275SPavel Dovgalyuk             break;
3057385b275SPavel Dovgalyuk         case UART_FCR_ITL_4:
3067385b275SPavel Dovgalyuk             s->recv_fifo_itl = 14;
3077385b275SPavel Dovgalyuk             break;
3087385b275SPavel Dovgalyuk         }
3097385b275SPavel Dovgalyuk     } else {
3107385b275SPavel Dovgalyuk         s->iir &= ~UART_IIR_FE;
3117385b275SPavel Dovgalyuk     }
3127385b275SPavel Dovgalyuk }
3137385b275SPavel Dovgalyuk 
serial_update_tiocm(SerialState * s)31475735842SAnton Nefedov static void serial_update_tiocm(SerialState *s)
31575735842SAnton Nefedov {
31675735842SAnton Nefedov     int flags;
31775735842SAnton Nefedov 
31875735842SAnton Nefedov     qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_GET_TIOCM, &flags);
31975735842SAnton Nefedov 
32075735842SAnton Nefedov     flags &= ~(CHR_TIOCM_RTS | CHR_TIOCM_DTR);
32175735842SAnton Nefedov 
32275735842SAnton Nefedov     if (s->mcr & UART_MCR_RTS) {
32375735842SAnton Nefedov         flags |= CHR_TIOCM_RTS;
32475735842SAnton Nefedov     }
32575735842SAnton Nefedov     if (s->mcr & UART_MCR_DTR) {
32675735842SAnton Nefedov         flags |= CHR_TIOCM_DTR;
32775735842SAnton Nefedov     }
32875735842SAnton Nefedov 
32975735842SAnton Nefedov     qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_TIOCM, &flags);
33075735842SAnton Nefedov }
33175735842SAnton Nefedov 
serial_ioport_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)33249ab747fSPaolo Bonzini static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val,
33349ab747fSPaolo Bonzini                                 unsigned size)
33449ab747fSPaolo Bonzini {
33549ab747fSPaolo Bonzini     SerialState *s = opaque;
33649ab747fSPaolo Bonzini 
3376ab9be1eSPhilippe Mathieu-Daudé     assert(size == 1 && addr < 8);
338f2336b5fSPhilippe Mathieu-Daudé     trace_serial_write(addr, val);
33949ab747fSPaolo Bonzini     switch(addr) {
34049ab747fSPaolo Bonzini     default:
34149ab747fSPaolo Bonzini     case 0:
34249ab747fSPaolo Bonzini         if (s->lcr & UART_LCR_DLAB) {
34329daa894SPhilippe Mathieu-Daudé             s->divider = deposit32(s->divider, 8 * addr, 8, val);
34449ab747fSPaolo Bonzini             serial_update_parameters(s);
34549ab747fSPaolo Bonzini         } else {
34649ab747fSPaolo Bonzini             s->thr = (uint8_t) val;
34749ab747fSPaolo Bonzini             if(s->fcr & UART_FCR_FE) {
3488e8638faSPeter Crosthwaite                 /* xmit overruns overwrite data, so make space if needed */
3498e8638faSPeter Crosthwaite                 if (fifo8_is_full(&s->xmit_fifo)) {
3508e8638faSPeter Crosthwaite                     fifo8_pop(&s->xmit_fifo);
3518e8638faSPeter Crosthwaite                 }
3528e8638faSPeter Crosthwaite                 fifo8_push(&s->xmit_fifo, s->thr);
353b5601df7SPeter Crosthwaite             }
35449ab747fSPaolo Bonzini             s->thr_ipending = 0;
35549ab747fSPaolo Bonzini             s->lsr &= ~UART_LSR_THRE;
3560d931d70SPaolo Bonzini             s->lsr &= ~UART_LSR_TEMT;
35749ab747fSPaolo Bonzini             serial_update_irq(s);
358807464d8SPaolo Bonzini             if (s->tsr_retry == 0) {
359b0585e7eSPaolo Bonzini                 serial_xmit(s);
36049ab747fSPaolo Bonzini             }
361f702e62aSKirill Batuzov         }
36249ab747fSPaolo Bonzini         break;
36349ab747fSPaolo Bonzini     case 1:
36449ab747fSPaolo Bonzini         if (s->lcr & UART_LCR_DLAB) {
36529daa894SPhilippe Mathieu-Daudé             s->divider = deposit32(s->divider, 8 * addr, 8, val);
36649ab747fSPaolo Bonzini             serial_update_parameters(s);
36749ab747fSPaolo Bonzini         } else {
3681645b8eeSPaolo Bonzini             uint8_t changed = (s->ier ^ val) & 0x0f;
36949ab747fSPaolo Bonzini             s->ier = val & 0x0f;
37049ab747fSPaolo Bonzini             /* If the backend device is a real serial port, turn polling of the modem
3711645b8eeSPaolo Bonzini              * status lines on physical port on or off depending on UART_IER_MSI state.
3721645b8eeSPaolo Bonzini              */
3731645b8eeSPaolo Bonzini             if ((changed & UART_IER_MSI) && s->poll_msl >= 0) {
37449ab747fSPaolo Bonzini                 if (s->ier & UART_IER_MSI) {
37549ab747fSPaolo Bonzini                      s->poll_msl = 1;
37649ab747fSPaolo Bonzini                      serial_update_msl(s);
37749ab747fSPaolo Bonzini                 } else {
378bc72ad67SAlex Bligh                      timer_del(s->modem_status_poll);
37949ab747fSPaolo Bonzini                      s->poll_msl = 0;
38049ab747fSPaolo Bonzini                 }
38149ab747fSPaolo Bonzini             }
3824e02b0fcSPaolo Bonzini 
3834e02b0fcSPaolo Bonzini             /* Turning on the THRE interrupt on IER can trigger the interrupt
3844e02b0fcSPaolo Bonzini              * if LSR.THRE=1, even if it had been masked before by reading IIR.
3854e02b0fcSPaolo Bonzini              * This is not in the datasheet, but Windows relies on it.  It is
3864e02b0fcSPaolo Bonzini              * unclear if THRE has to be resampled every time THRI becomes
3874e02b0fcSPaolo Bonzini              * 1, or only on the rising edge.  Bochs does the latter, and Windows
3881645b8eeSPaolo Bonzini              * always toggles IER to all zeroes and back to all ones, so do the
3891645b8eeSPaolo Bonzini              * same.
3904e02b0fcSPaolo Bonzini              *
3914e02b0fcSPaolo Bonzini              * If IER.THRI is zero, thr_ipending is not used.  Set it to zero
3924e02b0fcSPaolo Bonzini              * so that the thr_ipending subsection is not migrated.
3934e02b0fcSPaolo Bonzini              */
3941645b8eeSPaolo Bonzini             if (changed & UART_IER_THRI) {
3954e02b0fcSPaolo Bonzini                 if ((s->ier & UART_IER_THRI) && (s->lsr & UART_LSR_THRE)) {
39649ab747fSPaolo Bonzini                     s->thr_ipending = 1;
3974e02b0fcSPaolo Bonzini                 } else {
3984e02b0fcSPaolo Bonzini                     s->thr_ipending = 0;
39949ab747fSPaolo Bonzini                 }
4001645b8eeSPaolo Bonzini             }
4011645b8eeSPaolo Bonzini 
4021645b8eeSPaolo Bonzini             if (changed) {
4034e02b0fcSPaolo Bonzini                 serial_update_irq(s);
40449ab747fSPaolo Bonzini             }
4051645b8eeSPaolo Bonzini         }
40649ab747fSPaolo Bonzini         break;
40749ab747fSPaolo Bonzini     case 2:
40849ab747fSPaolo Bonzini         /* Did the enable/disable flag change? If so, make sure FIFOs get flushed */
4097385b275SPavel Dovgalyuk         if ((val ^ s->fcr) & UART_FCR_FE) {
41049ab747fSPaolo Bonzini             val |= UART_FCR_XFR | UART_FCR_RFR;
4117385b275SPavel Dovgalyuk         }
41249ab747fSPaolo Bonzini 
41349ab747fSPaolo Bonzini         /* FIFO clear */
41449ab747fSPaolo Bonzini 
41549ab747fSPaolo Bonzini         if (val & UART_FCR_RFR) {
416023c3a97SPaolo Bonzini             s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
417bc72ad67SAlex Bligh             timer_del(s->fifo_timeout_timer);
41849ab747fSPaolo Bonzini             s->timeout_ipending = 0;
4198e8638faSPeter Crosthwaite             fifo8_reset(&s->recv_fifo);
42049ab747fSPaolo Bonzini         }
42149ab747fSPaolo Bonzini 
42249ab747fSPaolo Bonzini         if (val & UART_FCR_XFR) {
423023c3a97SPaolo Bonzini             s->lsr |= UART_LSR_THRE;
424023c3a97SPaolo Bonzini             s->thr_ipending = 1;
4258e8638faSPeter Crosthwaite             fifo8_reset(&s->xmit_fifo);
42649ab747fSPaolo Bonzini         }
42749ab747fSPaolo Bonzini 
4287385b275SPavel Dovgalyuk         serial_write_fcr(s, val & 0xC9);
42949ab747fSPaolo Bonzini         serial_update_irq(s);
43049ab747fSPaolo Bonzini         break;
43149ab747fSPaolo Bonzini     case 3:
43249ab747fSPaolo Bonzini         {
43349ab747fSPaolo Bonzini             int break_enable;
43449ab747fSPaolo Bonzini             s->lcr = val;
43549ab747fSPaolo Bonzini             serial_update_parameters(s);
43649ab747fSPaolo Bonzini             break_enable = (val >> 6) & 1;
43749ab747fSPaolo Bonzini             if (break_enable != s->last_break_enable) {
43849ab747fSPaolo Bonzini                 s->last_break_enable = break_enable;
4395345fdb4SMarc-André Lureau                 qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
44049ab747fSPaolo Bonzini                                   &break_enable);
44149ab747fSPaolo Bonzini             }
44249ab747fSPaolo Bonzini         }
44349ab747fSPaolo Bonzini         break;
44449ab747fSPaolo Bonzini     case 4:
44549ab747fSPaolo Bonzini         {
44649ab747fSPaolo Bonzini             int old_mcr = s->mcr;
44749ab747fSPaolo Bonzini             s->mcr = val & 0x1f;
44849ab747fSPaolo Bonzini             if (val & UART_MCR_LOOP)
44949ab747fSPaolo Bonzini                 break;
45049ab747fSPaolo Bonzini 
45149ab747fSPaolo Bonzini             if (s->poll_msl >= 0 && old_mcr != s->mcr) {
45275735842SAnton Nefedov                 serial_update_tiocm(s);
45349ab747fSPaolo Bonzini                 /* Update the modem status after a one-character-send wait-time, since there may be a response
45449ab747fSPaolo Bonzini                    from the device/computer at the other end of the serial line */
455bc72ad67SAlex Bligh                 timer_mod(s->modem_status_poll, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->char_transmit_time);
45649ab747fSPaolo Bonzini             }
45749ab747fSPaolo Bonzini         }
45849ab747fSPaolo Bonzini         break;
45949ab747fSPaolo Bonzini     case 5:
46049ab747fSPaolo Bonzini         break;
46149ab747fSPaolo Bonzini     case 6:
46249ab747fSPaolo Bonzini         break;
46349ab747fSPaolo Bonzini     case 7:
46449ab747fSPaolo Bonzini         s->scr = val;
46549ab747fSPaolo Bonzini         break;
46649ab747fSPaolo Bonzini     }
46749ab747fSPaolo Bonzini }
46849ab747fSPaolo Bonzini 
serial_ioport_read(void * opaque,hwaddr addr,unsigned size)46949ab747fSPaolo Bonzini static uint64_t serial_ioport_read(void *opaque, hwaddr addr, unsigned size)
47049ab747fSPaolo Bonzini {
47149ab747fSPaolo Bonzini     SerialState *s = opaque;
47249ab747fSPaolo Bonzini     uint32_t ret;
47349ab747fSPaolo Bonzini 
4746ab9be1eSPhilippe Mathieu-Daudé     assert(size == 1 && addr < 8);
47549ab747fSPaolo Bonzini     switch(addr) {
47649ab747fSPaolo Bonzini     default:
47749ab747fSPaolo Bonzini     case 0:
47849ab747fSPaolo Bonzini         if (s->lcr & UART_LCR_DLAB) {
47929daa894SPhilippe Mathieu-Daudé             ret = extract16(s->divider, 8 * addr, 8);
48049ab747fSPaolo Bonzini         } else {
48149ab747fSPaolo Bonzini             if(s->fcr & UART_FCR_FE) {
482b165b0d8SVladimir Senkov                 ret = fifo8_is_empty(&s->recv_fifo) ?
4838e8638faSPeter Crosthwaite                             0 : fifo8_pop(&s->recv_fifo);
4848e8638faSPeter Crosthwaite                 if (s->recv_fifo.num == 0) {
48549ab747fSPaolo Bonzini                     s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
4867f4f0a22SPeter Crosthwaite                 } else {
487bc72ad67SAlex Bligh                     timer_mod(s->fifo_timeout_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->char_transmit_time * 4);
4887f4f0a22SPeter Crosthwaite                 }
48949ab747fSPaolo Bonzini                 s->timeout_ipending = 0;
49049ab747fSPaolo Bonzini             } else {
49149ab747fSPaolo Bonzini                 ret = s->rbr;
49249ab747fSPaolo Bonzini                 s->lsr &= ~(UART_LSR_DR | UART_LSR_BI);
49349ab747fSPaolo Bonzini             }
49449ab747fSPaolo Bonzini             serial_update_irq(s);
49549ab747fSPaolo Bonzini             if (!(s->mcr & UART_MCR_LOOP)) {
49649ab747fSPaolo Bonzini                 /* in loopback mode, don't receive any data */
4975345fdb4SMarc-André Lureau                 qemu_chr_fe_accept_input(&s->chr);
49849ab747fSPaolo Bonzini             }
49949ab747fSPaolo Bonzini         }
50049ab747fSPaolo Bonzini         break;
50149ab747fSPaolo Bonzini     case 1:
50249ab747fSPaolo Bonzini         if (s->lcr & UART_LCR_DLAB) {
50329daa894SPhilippe Mathieu-Daudé             ret = extract16(s->divider, 8 * addr, 8);
50449ab747fSPaolo Bonzini         } else {
50549ab747fSPaolo Bonzini             ret = s->ier;
50649ab747fSPaolo Bonzini         }
50749ab747fSPaolo Bonzini         break;
50849ab747fSPaolo Bonzini     case 2:
50949ab747fSPaolo Bonzini         ret = s->iir;
51049ab747fSPaolo Bonzini         if ((ret & UART_IIR_ID) == UART_IIR_THRI) {
51149ab747fSPaolo Bonzini             s->thr_ipending = 0;
51249ab747fSPaolo Bonzini             serial_update_irq(s);
51349ab747fSPaolo Bonzini         }
51449ab747fSPaolo Bonzini         break;
51549ab747fSPaolo Bonzini     case 3:
51649ab747fSPaolo Bonzini         ret = s->lcr;
51749ab747fSPaolo Bonzini         break;
51849ab747fSPaolo Bonzini     case 4:
51949ab747fSPaolo Bonzini         ret = s->mcr;
52049ab747fSPaolo Bonzini         break;
52149ab747fSPaolo Bonzini     case 5:
52249ab747fSPaolo Bonzini         ret = s->lsr;
52349ab747fSPaolo Bonzini         /* Clear break and overrun interrupts */
52449ab747fSPaolo Bonzini         if (s->lsr & (UART_LSR_BI|UART_LSR_OE)) {
52549ab747fSPaolo Bonzini             s->lsr &= ~(UART_LSR_BI|UART_LSR_OE);
52649ab747fSPaolo Bonzini             serial_update_irq(s);
52749ab747fSPaolo Bonzini         }
52849ab747fSPaolo Bonzini         break;
52949ab747fSPaolo Bonzini     case 6:
53049ab747fSPaolo Bonzini         if (s->mcr & UART_MCR_LOOP) {
53149ab747fSPaolo Bonzini             /* in loopback, the modem output pins are connected to the
53249ab747fSPaolo Bonzini                inputs */
53349ab747fSPaolo Bonzini             ret = (s->mcr & 0x0c) << 4;
53449ab747fSPaolo Bonzini             ret |= (s->mcr & 0x02) << 3;
53549ab747fSPaolo Bonzini             ret |= (s->mcr & 0x01) << 5;
53649ab747fSPaolo Bonzini         } else {
53749ab747fSPaolo Bonzini             if (s->poll_msl >= 0)
53849ab747fSPaolo Bonzini                 serial_update_msl(s);
53949ab747fSPaolo Bonzini             ret = s->msr;
54049ab747fSPaolo Bonzini             /* Clear delta bits & msr int after read, if they were set */
54149ab747fSPaolo Bonzini             if (s->msr & UART_MSR_ANY_DELTA) {
54249ab747fSPaolo Bonzini                 s->msr &= 0xF0;
54349ab747fSPaolo Bonzini                 serial_update_irq(s);
54449ab747fSPaolo Bonzini             }
54549ab747fSPaolo Bonzini         }
54649ab747fSPaolo Bonzini         break;
54749ab747fSPaolo Bonzini     case 7:
54849ab747fSPaolo Bonzini         ret = s->scr;
54949ab747fSPaolo Bonzini         break;
55049ab747fSPaolo Bonzini     }
551f2336b5fSPhilippe Mathieu-Daudé     trace_serial_read(addr, ret);
55249ab747fSPaolo Bonzini     return ret;
55349ab747fSPaolo Bonzini }
55449ab747fSPaolo Bonzini 
serial_can_receive(SerialState * s)55549ab747fSPaolo Bonzini static int serial_can_receive(SerialState *s)
55649ab747fSPaolo Bonzini {
55749ab747fSPaolo Bonzini     if(s->fcr & UART_FCR_FE) {
5588e8638faSPeter Crosthwaite         if (s->recv_fifo.num < UART_FIFO_LENGTH) {
5597f4f0a22SPeter Crosthwaite             /*
5607f4f0a22SPeter Crosthwaite              * Advertise (fifo.itl - fifo.count) bytes when count < ITL, and 1
5617f4f0a22SPeter Crosthwaite              * if above. If UART_FIFO_LENGTH - fifo.count is advertised the
5627f4f0a22SPeter Crosthwaite              * effect will be to almost always fill the fifo completely before
5637f4f0a22SPeter Crosthwaite              * the guest has a chance to respond, effectively overriding the ITL
5647f4f0a22SPeter Crosthwaite              * that the guest has set.
5657f4f0a22SPeter Crosthwaite              */
5668e8638faSPeter Crosthwaite             return (s->recv_fifo.num <= s->recv_fifo_itl) ?
5678e8638faSPeter Crosthwaite                         s->recv_fifo_itl - s->recv_fifo.num : 1;
5687f4f0a22SPeter Crosthwaite         } else {
56949ab747fSPaolo Bonzini             return 0;
5707f4f0a22SPeter Crosthwaite         }
57149ab747fSPaolo Bonzini     } else {
57249ab747fSPaolo Bonzini         return !(s->lsr & UART_LSR_DR);
57349ab747fSPaolo Bonzini     }
57449ab747fSPaolo Bonzini }
57549ab747fSPaolo Bonzini 
serial_receive_break(SerialState * s)57649ab747fSPaolo Bonzini static void serial_receive_break(SerialState *s)
57749ab747fSPaolo Bonzini {
57849ab747fSPaolo Bonzini     s->rbr = 0;
57949ab747fSPaolo Bonzini     /* When the LSR_DR is set a null byte is pushed into the fifo */
5808e8638faSPeter Crosthwaite     recv_fifo_put(s, '\0');
58149ab747fSPaolo Bonzini     s->lsr |= UART_LSR_BI | UART_LSR_DR;
58249ab747fSPaolo Bonzini     serial_update_irq(s);
58349ab747fSPaolo Bonzini }
58449ab747fSPaolo Bonzini 
58549ab747fSPaolo Bonzini /* There's data in recv_fifo and s->rbr has not been read for 4 char transmit times */
fifo_timeout_int(void * opaque)58649ab747fSPaolo Bonzini static void fifo_timeout_int (void *opaque) {
58749ab747fSPaolo Bonzini     SerialState *s = opaque;
5888e8638faSPeter Crosthwaite     if (s->recv_fifo.num) {
58949ab747fSPaolo Bonzini         s->timeout_ipending = 1;
59049ab747fSPaolo Bonzini         serial_update_irq(s);
59149ab747fSPaolo Bonzini     }
59249ab747fSPaolo Bonzini }
59349ab747fSPaolo Bonzini 
serial_can_receive1(void * opaque)59449ab747fSPaolo Bonzini static int serial_can_receive1(void *opaque)
59549ab747fSPaolo Bonzini {
59649ab747fSPaolo Bonzini     SerialState *s = opaque;
59749ab747fSPaolo Bonzini     return serial_can_receive(s);
59849ab747fSPaolo Bonzini }
59949ab747fSPaolo Bonzini 
serial_receive1(void * opaque,const uint8_t * buf,int size)60049ab747fSPaolo Bonzini static void serial_receive1(void *opaque, const uint8_t *buf, int size)
60149ab747fSPaolo Bonzini {
60249ab747fSPaolo Bonzini     SerialState *s = opaque;
60349ab747fSPaolo Bonzini 
60449ab747fSPaolo Bonzini     if (s->wakeup) {
605fb064112SDaniel Henrique Barboza         qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER, NULL);
60649ab747fSPaolo Bonzini     }
60749ab747fSPaolo Bonzini     if(s->fcr & UART_FCR_FE) {
60849ab747fSPaolo Bonzini         int i;
60949ab747fSPaolo Bonzini         for (i = 0; i < size; i++) {
6108e8638faSPeter Crosthwaite             recv_fifo_put(s, buf[i]);
61149ab747fSPaolo Bonzini         }
61249ab747fSPaolo Bonzini         s->lsr |= UART_LSR_DR;
61349ab747fSPaolo Bonzini         /* call the timeout receive callback in 4 char transmit time */
614bc72ad67SAlex Bligh         timer_mod(s->fifo_timeout_timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->char_transmit_time * 4);
61549ab747fSPaolo Bonzini     } else {
61649ab747fSPaolo Bonzini         if (s->lsr & UART_LSR_DR)
61749ab747fSPaolo Bonzini             s->lsr |= UART_LSR_OE;
61849ab747fSPaolo Bonzini         s->rbr = buf[0];
61949ab747fSPaolo Bonzini         s->lsr |= UART_LSR_DR;
62049ab747fSPaolo Bonzini     }
62149ab747fSPaolo Bonzini     serial_update_irq(s);
62249ab747fSPaolo Bonzini }
62349ab747fSPaolo Bonzini 
serial_event(void * opaque,QEMUChrEvent event)624083b266fSPhilippe Mathieu-Daudé static void serial_event(void *opaque, QEMUChrEvent event)
62549ab747fSPaolo Bonzini {
62649ab747fSPaolo Bonzini     SerialState *s = opaque;
62749ab747fSPaolo Bonzini     if (event == CHR_EVENT_BREAK)
62849ab747fSPaolo Bonzini         serial_receive_break(s);
62949ab747fSPaolo Bonzini }
63049ab747fSPaolo Bonzini 
serial_pre_save(void * opaque)63144b1ff31SDr. David Alan Gilbert static int serial_pre_save(void *opaque)
63249ab747fSPaolo Bonzini {
63349ab747fSPaolo Bonzini     SerialState *s = opaque;
63449ab747fSPaolo Bonzini     s->fcr_vmstate = s->fcr;
63544b1ff31SDr. David Alan Gilbert 
63644b1ff31SDr. David Alan Gilbert     return 0;
63749ab747fSPaolo Bonzini }
63849ab747fSPaolo Bonzini 
serial_pre_load(void * opaque)6397385b275SPavel Dovgalyuk static int serial_pre_load(void *opaque)
6407385b275SPavel Dovgalyuk {
6417385b275SPavel Dovgalyuk     SerialState *s = opaque;
6427385b275SPavel Dovgalyuk     s->thr_ipending = -1;
6437385b275SPavel Dovgalyuk     s->poll_msl = -1;
6447385b275SPavel Dovgalyuk     return 0;
6457385b275SPavel Dovgalyuk }
6467385b275SPavel Dovgalyuk 
serial_post_load(void * opaque,int version_id)64749ab747fSPaolo Bonzini static int serial_post_load(void *opaque, int version_id)
64849ab747fSPaolo Bonzini {
64949ab747fSPaolo Bonzini     SerialState *s = opaque;
65049ab747fSPaolo Bonzini 
65149ab747fSPaolo Bonzini     if (version_id < 3) {
65249ab747fSPaolo Bonzini         s->fcr_vmstate = 0;
65349ab747fSPaolo Bonzini     }
6547385b275SPavel Dovgalyuk     if (s->thr_ipending == -1) {
6557385b275SPavel Dovgalyuk         s->thr_ipending = ((s->iir & UART_IIR_ID) == UART_IIR_THRI);
6567385b275SPavel Dovgalyuk     }
6579f34a35eSPaolo Bonzini 
6589f34a35eSPaolo Bonzini     if (s->tsr_retry > 0) {
6599f34a35eSPaolo Bonzini         /* tsr_retry > 0 implies LSR.TEMT = 0 (transmitter not empty).  */
6609f34a35eSPaolo Bonzini         if (s->lsr & UART_LSR_TEMT) {
6619f34a35eSPaolo Bonzini             error_report("inconsistent state in serial device "
6629f34a35eSPaolo Bonzini                          "(tsr empty, tsr_retry=%d", s->tsr_retry);
6639f34a35eSPaolo Bonzini             return -1;
6649f34a35eSPaolo Bonzini         }
6659f34a35eSPaolo Bonzini 
666807464d8SPaolo Bonzini         if (s->tsr_retry > MAX_XMIT_RETRY) {
667807464d8SPaolo Bonzini             s->tsr_retry = MAX_XMIT_RETRY;
668807464d8SPaolo Bonzini         }
669807464d8SPaolo Bonzini 
6709f34a35eSPaolo Bonzini         assert(s->watch_tag == 0);
6715345fdb4SMarc-André Lureau         s->watch_tag = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
6729f34a35eSPaolo Bonzini                                              serial_watch_cb, s);
6739f34a35eSPaolo Bonzini     } else {
6749f34a35eSPaolo Bonzini         /* tsr_retry == 0 implies LSR.TEMT = 1 (transmitter empty).  */
6759f34a35eSPaolo Bonzini         if (!(s->lsr & UART_LSR_TEMT)) {
6769f34a35eSPaolo Bonzini             error_report("inconsistent state in serial device "
6779f34a35eSPaolo Bonzini                          "(tsr not empty, tsr_retry=0");
6789f34a35eSPaolo Bonzini             return -1;
6799f34a35eSPaolo Bonzini         }
6809f34a35eSPaolo Bonzini     }
6819f34a35eSPaolo Bonzini 
6827385b275SPavel Dovgalyuk     s->last_break_enable = (s->lcr >> 6) & 1;
68349ab747fSPaolo Bonzini     /* Initialize fcr via setter to perform essential side-effects */
6847385b275SPavel Dovgalyuk     serial_write_fcr(s, s->fcr_vmstate);
68549ab747fSPaolo Bonzini     serial_update_parameters(s);
68649ab747fSPaolo Bonzini     return 0;
68749ab747fSPaolo Bonzini }
68849ab747fSPaolo Bonzini 
serial_thr_ipending_needed(void * opaque)6897385b275SPavel Dovgalyuk static bool serial_thr_ipending_needed(void *opaque)
6907385b275SPavel Dovgalyuk {
6917385b275SPavel Dovgalyuk     SerialState *s = opaque;
692bfa73628SPaolo Bonzini 
693bfa73628SPaolo Bonzini     if (s->ier & UART_IER_THRI) {
6947385b275SPavel Dovgalyuk         bool expected_value = ((s->iir & UART_IIR_ID) == UART_IIR_THRI);
6957385b275SPavel Dovgalyuk         return s->thr_ipending != expected_value;
696bfa73628SPaolo Bonzini     } else {
697bfa73628SPaolo Bonzini         /* LSR.THRE will be sampled again when the interrupt is
698bfa73628SPaolo Bonzini          * enabled.  thr_ipending is not used in this case, do
699bfa73628SPaolo Bonzini          * not migrate it.
700bfa73628SPaolo Bonzini          */
701bfa73628SPaolo Bonzini         return false;
702bfa73628SPaolo Bonzini     }
7037385b275SPavel Dovgalyuk }
7047385b275SPavel Dovgalyuk 
70592013cf8SStefan Weil static const VMStateDescription vmstate_serial_thr_ipending = {
7067385b275SPavel Dovgalyuk     .name = "serial/thr_ipending",
7077385b275SPavel Dovgalyuk     .version_id = 1,
7087385b275SPavel Dovgalyuk     .minimum_version_id = 1,
7095cd8cadaSJuan Quintela     .needed = serial_thr_ipending_needed,
710*2f6cab05SRichard Henderson     .fields = (const VMStateField[]) {
7117385b275SPavel Dovgalyuk         VMSTATE_INT32(thr_ipending, SerialState),
7127385b275SPavel Dovgalyuk         VMSTATE_END_OF_LIST()
7137385b275SPavel Dovgalyuk     }
7147385b275SPavel Dovgalyuk };
7157385b275SPavel Dovgalyuk 
serial_tsr_needed(void * opaque)7167385b275SPavel Dovgalyuk static bool serial_tsr_needed(void *opaque)
7177385b275SPavel Dovgalyuk {
7187385b275SPavel Dovgalyuk     SerialState *s = (SerialState *)opaque;
7197385b275SPavel Dovgalyuk     return s->tsr_retry != 0;
7207385b275SPavel Dovgalyuk }
7217385b275SPavel Dovgalyuk 
72292013cf8SStefan Weil static const VMStateDescription vmstate_serial_tsr = {
7237385b275SPavel Dovgalyuk     .name = "serial/tsr",
7247385b275SPavel Dovgalyuk     .version_id = 1,
7257385b275SPavel Dovgalyuk     .minimum_version_id = 1,
7265cd8cadaSJuan Quintela     .needed = serial_tsr_needed,
727*2f6cab05SRichard Henderson     .fields = (const VMStateField[]) {
728807464d8SPaolo Bonzini         VMSTATE_UINT32(tsr_retry, SerialState),
7297385b275SPavel Dovgalyuk         VMSTATE_UINT8(thr, SerialState),
7307385b275SPavel Dovgalyuk         VMSTATE_UINT8(tsr, SerialState),
7317385b275SPavel Dovgalyuk         VMSTATE_END_OF_LIST()
7327385b275SPavel Dovgalyuk     }
7337385b275SPavel Dovgalyuk };
7347385b275SPavel Dovgalyuk 
serial_recv_fifo_needed(void * opaque)7357385b275SPavel Dovgalyuk static bool serial_recv_fifo_needed(void *opaque)
7367385b275SPavel Dovgalyuk {
7377385b275SPavel Dovgalyuk     SerialState *s = (SerialState *)opaque;
7387385b275SPavel Dovgalyuk     return !fifo8_is_empty(&s->recv_fifo);
7397385b275SPavel Dovgalyuk 
7407385b275SPavel Dovgalyuk }
7417385b275SPavel Dovgalyuk 
74292013cf8SStefan Weil static const VMStateDescription vmstate_serial_recv_fifo = {
7437385b275SPavel Dovgalyuk     .name = "serial/recv_fifo",
7447385b275SPavel Dovgalyuk     .version_id = 1,
7457385b275SPavel Dovgalyuk     .minimum_version_id = 1,
7465cd8cadaSJuan Quintela     .needed = serial_recv_fifo_needed,
747*2f6cab05SRichard Henderson     .fields = (const VMStateField[]) {
7487385b275SPavel Dovgalyuk         VMSTATE_STRUCT(recv_fifo, SerialState, 1, vmstate_fifo8, Fifo8),
7497385b275SPavel Dovgalyuk         VMSTATE_END_OF_LIST()
7507385b275SPavel Dovgalyuk     }
7517385b275SPavel Dovgalyuk };
7527385b275SPavel Dovgalyuk 
serial_xmit_fifo_needed(void * opaque)7537385b275SPavel Dovgalyuk static bool serial_xmit_fifo_needed(void *opaque)
7547385b275SPavel Dovgalyuk {
7557385b275SPavel Dovgalyuk     SerialState *s = (SerialState *)opaque;
7567385b275SPavel Dovgalyuk     return !fifo8_is_empty(&s->xmit_fifo);
7577385b275SPavel Dovgalyuk }
7587385b275SPavel Dovgalyuk 
75992013cf8SStefan Weil static const VMStateDescription vmstate_serial_xmit_fifo = {
7607385b275SPavel Dovgalyuk     .name = "serial/xmit_fifo",
7617385b275SPavel Dovgalyuk     .version_id = 1,
7627385b275SPavel Dovgalyuk     .minimum_version_id = 1,
7635cd8cadaSJuan Quintela     .needed = serial_xmit_fifo_needed,
764*2f6cab05SRichard Henderson     .fields = (const VMStateField[]) {
7657385b275SPavel Dovgalyuk         VMSTATE_STRUCT(xmit_fifo, SerialState, 1, vmstate_fifo8, Fifo8),
7667385b275SPavel Dovgalyuk         VMSTATE_END_OF_LIST()
7677385b275SPavel Dovgalyuk     }
7687385b275SPavel Dovgalyuk };
7697385b275SPavel Dovgalyuk 
serial_fifo_timeout_timer_needed(void * opaque)7707385b275SPavel Dovgalyuk static bool serial_fifo_timeout_timer_needed(void *opaque)
7717385b275SPavel Dovgalyuk {
7727385b275SPavel Dovgalyuk     SerialState *s = (SerialState *)opaque;
7737385b275SPavel Dovgalyuk     return timer_pending(s->fifo_timeout_timer);
7747385b275SPavel Dovgalyuk }
7757385b275SPavel Dovgalyuk 
77692013cf8SStefan Weil static const VMStateDescription vmstate_serial_fifo_timeout_timer = {
7777385b275SPavel Dovgalyuk     .name = "serial/fifo_timeout_timer",
7787385b275SPavel Dovgalyuk     .version_id = 1,
7797385b275SPavel Dovgalyuk     .minimum_version_id = 1,
7805cd8cadaSJuan Quintela     .needed = serial_fifo_timeout_timer_needed,
781*2f6cab05SRichard Henderson     .fields = (const VMStateField[]) {
782e720677eSPaolo Bonzini         VMSTATE_TIMER_PTR(fifo_timeout_timer, SerialState),
7837385b275SPavel Dovgalyuk         VMSTATE_END_OF_LIST()
7847385b275SPavel Dovgalyuk     }
7857385b275SPavel Dovgalyuk };
7867385b275SPavel Dovgalyuk 
serial_timeout_ipending_needed(void * opaque)7877385b275SPavel Dovgalyuk static bool serial_timeout_ipending_needed(void *opaque)
7887385b275SPavel Dovgalyuk {
7897385b275SPavel Dovgalyuk     SerialState *s = (SerialState *)opaque;
7907385b275SPavel Dovgalyuk     return s->timeout_ipending != 0;
7917385b275SPavel Dovgalyuk }
7927385b275SPavel Dovgalyuk 
79392013cf8SStefan Weil static const VMStateDescription vmstate_serial_timeout_ipending = {
7947385b275SPavel Dovgalyuk     .name = "serial/timeout_ipending",
7957385b275SPavel Dovgalyuk     .version_id = 1,
7967385b275SPavel Dovgalyuk     .minimum_version_id = 1,
7975cd8cadaSJuan Quintela     .needed = serial_timeout_ipending_needed,
798*2f6cab05SRichard Henderson     .fields = (const VMStateField[]) {
7997385b275SPavel Dovgalyuk         VMSTATE_INT32(timeout_ipending, SerialState),
8007385b275SPavel Dovgalyuk         VMSTATE_END_OF_LIST()
8017385b275SPavel Dovgalyuk     }
8027385b275SPavel Dovgalyuk };
8037385b275SPavel Dovgalyuk 
serial_poll_needed(void * opaque)8047385b275SPavel Dovgalyuk static bool serial_poll_needed(void *opaque)
8057385b275SPavel Dovgalyuk {
8067385b275SPavel Dovgalyuk     SerialState *s = (SerialState *)opaque;
8077385b275SPavel Dovgalyuk     return s->poll_msl >= 0;
8087385b275SPavel Dovgalyuk }
8097385b275SPavel Dovgalyuk 
81092013cf8SStefan Weil static const VMStateDescription vmstate_serial_poll = {
8117385b275SPavel Dovgalyuk     .name = "serial/poll",
8127385b275SPavel Dovgalyuk     .version_id = 1,
8135cd8cadaSJuan Quintela     .needed = serial_poll_needed,
8147385b275SPavel Dovgalyuk     .minimum_version_id = 1,
815*2f6cab05SRichard Henderson     .fields = (const VMStateField[]) {
8167385b275SPavel Dovgalyuk         VMSTATE_INT32(poll_msl, SerialState),
817e720677eSPaolo Bonzini         VMSTATE_TIMER_PTR(modem_status_poll, SerialState),
8187385b275SPavel Dovgalyuk         VMSTATE_END_OF_LIST()
8197385b275SPavel Dovgalyuk     }
8207385b275SPavel Dovgalyuk };
8217385b275SPavel Dovgalyuk 
82249ab747fSPaolo Bonzini const VMStateDescription vmstate_serial = {
82349ab747fSPaolo Bonzini     .name = "serial",
82449ab747fSPaolo Bonzini     .version_id = 3,
82549ab747fSPaolo Bonzini     .minimum_version_id = 2,
82649ab747fSPaolo Bonzini     .pre_save = serial_pre_save,
8277385b275SPavel Dovgalyuk     .pre_load = serial_pre_load,
82849ab747fSPaolo Bonzini     .post_load = serial_post_load,
829*2f6cab05SRichard Henderson     .fields = (const VMStateField[]) {
83049ab747fSPaolo Bonzini         VMSTATE_UINT16_V(divider, SerialState, 2),
83149ab747fSPaolo Bonzini         VMSTATE_UINT8(rbr, SerialState),
83249ab747fSPaolo Bonzini         VMSTATE_UINT8(ier, SerialState),
83349ab747fSPaolo Bonzini         VMSTATE_UINT8(iir, SerialState),
83449ab747fSPaolo Bonzini         VMSTATE_UINT8(lcr, SerialState),
83549ab747fSPaolo Bonzini         VMSTATE_UINT8(mcr, SerialState),
83649ab747fSPaolo Bonzini         VMSTATE_UINT8(lsr, SerialState),
83749ab747fSPaolo Bonzini         VMSTATE_UINT8(msr, SerialState),
83849ab747fSPaolo Bonzini         VMSTATE_UINT8(scr, SerialState),
83949ab747fSPaolo Bonzini         VMSTATE_UINT8_V(fcr_vmstate, SerialState, 3),
84049ab747fSPaolo Bonzini         VMSTATE_END_OF_LIST()
8417385b275SPavel Dovgalyuk     },
842*2f6cab05SRichard Henderson     .subsections = (const VMStateDescription * const []) {
8435cd8cadaSJuan Quintela         &vmstate_serial_thr_ipending,
8445cd8cadaSJuan Quintela         &vmstate_serial_tsr,
8455cd8cadaSJuan Quintela         &vmstate_serial_recv_fifo,
8465cd8cadaSJuan Quintela         &vmstate_serial_xmit_fifo,
8475cd8cadaSJuan Quintela         &vmstate_serial_fifo_timeout_timer,
8485cd8cadaSJuan Quintela         &vmstate_serial_timeout_ipending,
8495cd8cadaSJuan Quintela         &vmstate_serial_poll,
8505cd8cadaSJuan Quintela         NULL
85149ab747fSPaolo Bonzini     }
85249ab747fSPaolo Bonzini };
85349ab747fSPaolo Bonzini 
serial_reset(void * opaque)85449ab747fSPaolo Bonzini static void serial_reset(void *opaque)
85549ab747fSPaolo Bonzini {
85649ab747fSPaolo Bonzini     SerialState *s = opaque;
85749ab747fSPaolo Bonzini 
858a1df76daSPaolo Bonzini     if (s->watch_tag > 0) {
859a1df76daSPaolo Bonzini         g_source_remove(s->watch_tag);
860a1df76daSPaolo Bonzini         s->watch_tag = 0;
861a1df76daSPaolo Bonzini     }
862a1df76daSPaolo Bonzini 
86349ab747fSPaolo Bonzini     s->rbr = 0;
86449ab747fSPaolo Bonzini     s->ier = 0;
86549ab747fSPaolo Bonzini     s->iir = UART_IIR_NO_INT;
86649ab747fSPaolo Bonzini     s->lcr = 0;
86749ab747fSPaolo Bonzini     s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
86849ab747fSPaolo Bonzini     s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS;
86949ab747fSPaolo Bonzini     /* Default to 9600 baud, 1 start bit, 8 data bits, 1 stop bit, no parity. */
87049ab747fSPaolo Bonzini     s->divider = 0x0C;
87149ab747fSPaolo Bonzini     s->mcr = UART_MCR_OUT2;
87249ab747fSPaolo Bonzini     s->scr = 0;
87349ab747fSPaolo Bonzini     s->tsr_retry = 0;
87473bcb24dSRutuja Shah     s->char_transmit_time = (NANOSECONDS_PER_SECOND / 9600) * 10;
87549ab747fSPaolo Bonzini     s->poll_msl = 0;
87649ab747fSPaolo Bonzini 
8777385b275SPavel Dovgalyuk     s->timeout_ipending = 0;
8787385b275SPavel Dovgalyuk     timer_del(s->fifo_timeout_timer);
8797385b275SPavel Dovgalyuk     timer_del(s->modem_status_poll);
8807385b275SPavel Dovgalyuk 
8818e8638faSPeter Crosthwaite     fifo8_reset(&s->recv_fifo);
8828e8638faSPeter Crosthwaite     fifo8_reset(&s->xmit_fifo);
88349ab747fSPaolo Bonzini 
884bc72ad67SAlex Bligh     s->last_xmit_ts = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
88549ab747fSPaolo Bonzini 
88649ab747fSPaolo Bonzini     s->thr_ipending = 0;
88749ab747fSPaolo Bonzini     s->last_break_enable = 0;
88849ab747fSPaolo Bonzini     qemu_irq_lower(s->irq);
889a30cf876SPaolo Bonzini 
890a30cf876SPaolo Bonzini     serial_update_msl(s);
891a30cf876SPaolo Bonzini     s->msr &= ~UART_MSR_ANY_DELTA;
89249ab747fSPaolo Bonzini }
89349ab747fSPaolo Bonzini 
serial_be_change(void * opaque)8941a29cc8fSAnton Nefedov static int serial_be_change(void *opaque)
8951a29cc8fSAnton Nefedov {
8961a29cc8fSAnton Nefedov     SerialState *s = opaque;
8971a29cc8fSAnton Nefedov 
8981a29cc8fSAnton Nefedov     qemu_chr_fe_set_handlers(&s->chr, serial_can_receive1, serial_receive1,
8991a29cc8fSAnton Nefedov                              serial_event, serial_be_change, s, NULL, true);
9001a29cc8fSAnton Nefedov 
9011a29cc8fSAnton Nefedov     serial_update_parameters(s);
9021a29cc8fSAnton Nefedov 
9031a29cc8fSAnton Nefedov     qemu_chr_fe_ioctl(&s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
9041a29cc8fSAnton Nefedov                       &s->last_break_enable);
9051a29cc8fSAnton Nefedov 
9061a29cc8fSAnton Nefedov     s->poll_msl = (s->ier & UART_IER_MSI) ? 1 : 0;
9071a29cc8fSAnton Nefedov     serial_update_msl(s);
9081a29cc8fSAnton Nefedov 
9091a29cc8fSAnton Nefedov     if (s->poll_msl >= 0 && !(s->mcr & UART_MCR_LOOP)) {
9101a29cc8fSAnton Nefedov         serial_update_tiocm(s);
9111a29cc8fSAnton Nefedov     }
9121a29cc8fSAnton Nefedov 
9131a29cc8fSAnton Nefedov     if (s->watch_tag > 0) {
9141a29cc8fSAnton Nefedov         g_source_remove(s->watch_tag);
9151a29cc8fSAnton Nefedov         s->watch_tag = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP,
9161a29cc8fSAnton Nefedov                                              serial_watch_cb, s);
9171a29cc8fSAnton Nefedov     }
9181a29cc8fSAnton Nefedov 
9191a29cc8fSAnton Nefedov     return 0;
9201a29cc8fSAnton Nefedov }
9211a29cc8fSAnton Nefedov 
serial_realize(DeviceState * dev,Error ** errp)922c9808d60SMarc-André Lureau static void serial_realize(DeviceState *dev, Error **errp)
92349ab747fSPaolo Bonzini {
924c9808d60SMarc-André Lureau     SerialState *s = SERIAL(dev);
925c9808d60SMarc-André Lureau 
926bc72ad67SAlex Bligh     s->modem_status_poll = timer_new_ns(QEMU_CLOCK_VIRTUAL, (QEMUTimerCB *) serial_update_msl, s);
92749ab747fSPaolo Bonzini 
928bc72ad67SAlex Bligh     s->fifo_timeout_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, (QEMUTimerCB *) fifo_timeout_int, s);
92949ab747fSPaolo Bonzini     qemu_register_reset(serial_reset, s);
93049ab747fSPaolo Bonzini 
9315345fdb4SMarc-André Lureau     qemu_chr_fe_set_handlers(&s->chr, serial_can_receive1, serial_receive1,
9321a29cc8fSAnton Nefedov                              serial_event, serial_be_change, s, NULL, true);
9338e8638faSPeter Crosthwaite     fifo8_create(&s->recv_fifo, UART_FIFO_LENGTH);
9348e8638faSPeter Crosthwaite     fifo8_create(&s->xmit_fifo, UART_FIFO_LENGTH);
9354df7961fSPaolo Bonzini     serial_reset(s);
93649ab747fSPaolo Bonzini }
93749ab747fSPaolo Bonzini 
serial_unrealize(DeviceState * dev)938b69c3c21SMarkus Armbruster static void serial_unrealize(DeviceState *dev)
93949ab747fSPaolo Bonzini {
940b9975000SMarc-André Lureau     SerialState *s = SERIAL(dev);
941b9975000SMarc-André Lureau 
9421ce2610cSMarc-André Lureau     qemu_chr_fe_deinit(&s->chr, false);
9438409dc88SLi Qiang 
9448409dc88SLi Qiang     timer_free(s->modem_status_poll);
9458409dc88SLi Qiang 
9468409dc88SLi Qiang     timer_free(s->fifo_timeout_timer);
9478409dc88SLi Qiang 
9488409dc88SLi Qiang     fifo8_destroy(&s->recv_fifo);
9498409dc88SLi Qiang     fifo8_destroy(&s->xmit_fifo);
9508409dc88SLi Qiang 
95149ab747fSPaolo Bonzini     qemu_unregister_reset(serial_reset, s);
95249ab747fSPaolo Bonzini }
95349ab747fSPaolo Bonzini 
95449ab747fSPaolo Bonzini const MemoryRegionOps serial_io_ops = {
95549ab747fSPaolo Bonzini     .read = serial_ioport_read,
95649ab747fSPaolo Bonzini     .write = serial_ioport_write,
957769a726cSArwed Meyer     .valid = {
958769a726cSArwed Meyer         .unaligned = 1,
959769a726cSArwed Meyer     },
96049ab747fSPaolo Bonzini     .impl = {
96149ab747fSPaolo Bonzini         .min_access_size = 1,
96249ab747fSPaolo Bonzini         .max_access_size = 1,
96349ab747fSPaolo Bonzini     },
96449ab747fSPaolo Bonzini     .endianness = DEVICE_LITTLE_ENDIAN,
96549ab747fSPaolo Bonzini };
96649ab747fSPaolo Bonzini 
967ff22c588SMarc-André Lureau static Property serial_properties[] = {
968ff22c588SMarc-André Lureau     DEFINE_PROP_CHR("chardev", SerialState, chr),
96996651db4SMarc-André Lureau     DEFINE_PROP_UINT32("baudbase", SerialState, baudbase, 115200),
9701fa2c0ebSPhilippe Mathieu-Daudé     DEFINE_PROP_BOOL("wakeup", SerialState, wakeup, false),
971ff22c588SMarc-André Lureau     DEFINE_PROP_END_OF_LIST(),
972ff22c588SMarc-André Lureau };
973ff22c588SMarc-André Lureau 
serial_class_init(ObjectClass * klass,void * data)9747781b88eSMarc-André Lureau static void serial_class_init(ObjectClass *klass, void* data)
9757781b88eSMarc-André Lureau {
9767781b88eSMarc-André Lureau     DeviceClass *dc = DEVICE_CLASS(klass);
9777781b88eSMarc-André Lureau 
9787781b88eSMarc-André Lureau     /* internal device for serialio/serialmm, not user-creatable */
9797781b88eSMarc-André Lureau     dc->user_creatable = false;
980c9808d60SMarc-André Lureau     dc->realize = serial_realize;
981b9975000SMarc-André Lureau     dc->unrealize = serial_unrealize;
9824f67d30bSMarc-André Lureau     device_class_set_props(dc, serial_properties);
9837781b88eSMarc-André Lureau }
9847781b88eSMarc-André Lureau 
9857781b88eSMarc-André Lureau static const TypeInfo serial_info = {
9867781b88eSMarc-André Lureau     .name = TYPE_SERIAL,
9877781b88eSMarc-André Lureau     .parent = TYPE_DEVICE,
9887781b88eSMarc-André Lureau     .instance_size = sizeof(SerialState),
9897781b88eSMarc-André Lureau     .class_init = serial_class_init,
9907781b88eSMarc-André Lureau };
9917781b88eSMarc-André Lureau 
serial_register_types(void)9927781b88eSMarc-André Lureau static void serial_register_types(void)
9937781b88eSMarc-André Lureau {
9947781b88eSMarc-André Lureau     type_register_static(&serial_info);
9957781b88eSMarc-André Lureau }
9967781b88eSMarc-André Lureau 
9977781b88eSMarc-André Lureau type_init(serial_register_types)
998