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