root / hw / serial.c @ 8d3a8c1e
History | View | Annotate | Download (29.1 kB)
1 | 80cabfad | bellard | /*
|
---|---|---|---|
2 | 81174dae | aliguori | * QEMU 16550A UART emulation
|
3 | 5fafdf24 | ths | *
|
4 | 80cabfad | bellard | * Copyright (c) 2003-2004 Fabrice Bellard
|
5 | 81174dae | aliguori | * Copyright (c) 2008 Citrix Systems, Inc.
|
6 | 5fafdf24 | ths | *
|
7 | 80cabfad | bellard | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 | 80cabfad | bellard | * of this software and associated documentation files (the "Software"), to deal
|
9 | 80cabfad | bellard | * in the Software without restriction, including without limitation the rights
|
10 | 80cabfad | bellard | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 | 80cabfad | bellard | * copies of the Software, and to permit persons to whom the Software is
|
12 | 80cabfad | bellard | * furnished to do so, subject to the following conditions:
|
13 | 80cabfad | bellard | *
|
14 | 80cabfad | bellard | * The above copyright notice and this permission notice shall be included in
|
15 | 80cabfad | bellard | * all copies or substantial portions of the Software.
|
16 | 80cabfad | bellard | *
|
17 | 80cabfad | bellard | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 | 80cabfad | bellard | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 | 80cabfad | bellard | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
20 | 80cabfad | bellard | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 | 80cabfad | bellard | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 | 80cabfad | bellard | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 | 80cabfad | bellard | * THE SOFTWARE.
|
24 | 80cabfad | bellard | */
|
25 | 87ecb68b | pbrook | #include "hw.h" |
26 | 87ecb68b | pbrook | #include "qemu-char.h" |
27 | 87ecb68b | pbrook | #include "isa.h" |
28 | 87ecb68b | pbrook | #include "pc.h" |
29 | 6936bfe5 | aurel32 | #include "qemu-timer.h" |
30 | 666daa68 | Markus Armbruster | #include "sysemu.h" |
31 | 80cabfad | bellard | |
32 | 80cabfad | bellard | //#define DEBUG_SERIAL
|
33 | 80cabfad | bellard | |
34 | 80cabfad | bellard | #define UART_LCR_DLAB 0x80 /* Divisor latch access bit */ |
35 | 80cabfad | bellard | |
36 | 80cabfad | bellard | #define UART_IER_MSI 0x08 /* Enable Modem status interrupt */ |
37 | 80cabfad | bellard | #define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */ |
38 | 80cabfad | bellard | #define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */ |
39 | 80cabfad | bellard | #define UART_IER_RDI 0x01 /* Enable receiver data interrupt */ |
40 | 80cabfad | bellard | |
41 | 80cabfad | bellard | #define UART_IIR_NO_INT 0x01 /* No interrupts pending */ |
42 | 80cabfad | bellard | #define UART_IIR_ID 0x06 /* Mask for the interrupt ID */ |
43 | 80cabfad | bellard | |
44 | 80cabfad | bellard | #define UART_IIR_MSI 0x00 /* Modem status interrupt */ |
45 | 80cabfad | bellard | #define UART_IIR_THRI 0x02 /* Transmitter holding register empty */ |
46 | 80cabfad | bellard | #define UART_IIR_RDI 0x04 /* Receiver data interrupt */ |
47 | 80cabfad | bellard | #define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */ |
48 | 81174dae | aliguori | #define UART_IIR_CTI 0x0C /* Character Timeout Indication */ |
49 | 81174dae | aliguori | |
50 | 81174dae | aliguori | #define UART_IIR_FENF 0x80 /* Fifo enabled, but not functionning */ |
51 | 81174dae | aliguori | #define UART_IIR_FE 0xC0 /* Fifo enabled */ |
52 | 80cabfad | bellard | |
53 | 80cabfad | bellard | /*
|
54 | 80cabfad | bellard | * These are the definitions for the Modem Control Register
|
55 | 80cabfad | bellard | */
|
56 | 80cabfad | bellard | #define UART_MCR_LOOP 0x10 /* Enable loopback test mode */ |
57 | 80cabfad | bellard | #define UART_MCR_OUT2 0x08 /* Out2 complement */ |
58 | 80cabfad | bellard | #define UART_MCR_OUT1 0x04 /* Out1 complement */ |
59 | 80cabfad | bellard | #define UART_MCR_RTS 0x02 /* RTS complement */ |
60 | 80cabfad | bellard | #define UART_MCR_DTR 0x01 /* DTR complement */ |
61 | 80cabfad | bellard | |
62 | 80cabfad | bellard | /*
|
63 | 80cabfad | bellard | * These are the definitions for the Modem Status Register
|
64 | 80cabfad | bellard | */
|
65 | 80cabfad | bellard | #define UART_MSR_DCD 0x80 /* Data Carrier Detect */ |
66 | 80cabfad | bellard | #define UART_MSR_RI 0x40 /* Ring Indicator */ |
67 | 80cabfad | bellard | #define UART_MSR_DSR 0x20 /* Data Set Ready */ |
68 | 80cabfad | bellard | #define UART_MSR_CTS 0x10 /* Clear to Send */ |
69 | 80cabfad | bellard | #define UART_MSR_DDCD 0x08 /* Delta DCD */ |
70 | 80cabfad | bellard | #define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */ |
71 | 80cabfad | bellard | #define UART_MSR_DDSR 0x02 /* Delta DSR */ |
72 | 80cabfad | bellard | #define UART_MSR_DCTS 0x01 /* Delta CTS */ |
73 | 80cabfad | bellard | #define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */ |
74 | 80cabfad | bellard | |
75 | 80cabfad | bellard | #define UART_LSR_TEMT 0x40 /* Transmitter empty */ |
76 | 80cabfad | bellard | #define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ |
77 | 80cabfad | bellard | #define UART_LSR_BI 0x10 /* Break interrupt indicator */ |
78 | 80cabfad | bellard | #define UART_LSR_FE 0x08 /* Frame error indicator */ |
79 | 80cabfad | bellard | #define UART_LSR_PE 0x04 /* Parity error indicator */ |
80 | 80cabfad | bellard | #define UART_LSR_OE 0x02 /* Overrun error indicator */ |
81 | 80cabfad | bellard | #define UART_LSR_DR 0x01 /* Receiver data ready */ |
82 | 81174dae | aliguori | #define UART_LSR_INT_ANY 0x1E /* Any of the lsr-interrupt-triggering status bits */ |
83 | 80cabfad | bellard | |
84 | 81174dae | aliguori | /* Interrupt trigger levels. The byte-counts are for 16550A - in newer UARTs the byte-count for each ITL is higher. */
|
85 | 81174dae | aliguori | |
86 | 81174dae | aliguori | #define UART_FCR_ITL_1 0x00 /* 1 byte ITL */ |
87 | 81174dae | aliguori | #define UART_FCR_ITL_2 0x40 /* 4 bytes ITL */ |
88 | 81174dae | aliguori | #define UART_FCR_ITL_3 0x80 /* 8 bytes ITL */ |
89 | 81174dae | aliguori | #define UART_FCR_ITL_4 0xC0 /* 14 bytes ITL */ |
90 | 81174dae | aliguori | |
91 | 81174dae | aliguori | #define UART_FCR_DMS 0x08 /* DMA Mode Select */ |
92 | 81174dae | aliguori | #define UART_FCR_XFR 0x04 /* XMIT Fifo Reset */ |
93 | 81174dae | aliguori | #define UART_FCR_RFR 0x02 /* RCVR Fifo Reset */ |
94 | 81174dae | aliguori | #define UART_FCR_FE 0x01 /* FIFO Enable */ |
95 | 81174dae | aliguori | |
96 | 81174dae | aliguori | #define UART_FIFO_LENGTH 16 /* 16550A Fifo Length */ |
97 | 81174dae | aliguori | |
98 | 81174dae | aliguori | #define XMIT_FIFO 0 |
99 | 81174dae | aliguori | #define RECV_FIFO 1 |
100 | 81174dae | aliguori | #define MAX_XMIT_RETRY 4 |
101 | 81174dae | aliguori | |
102 | b6601141 | Michal Novotny | #ifdef DEBUG_SERIAL
|
103 | b6601141 | Michal Novotny | #define DPRINTF(fmt, ...) \
|
104 | 46411f86 | Stefan Weil | do { fprintf(stderr, "serial: " fmt , ## __VA_ARGS__); } while (0) |
105 | b6601141 | Michal Novotny | #else
|
106 | b6601141 | Michal Novotny | #define DPRINTF(fmt, ...) \
|
107 | 46411f86 | Stefan Weil | do {} while (0) |
108 | b6601141 | Michal Novotny | #endif
|
109 | b6601141 | Michal Novotny | |
110 | 2b321d69 | Juan Quintela | typedef struct SerialFIFO { |
111 | 81174dae | aliguori | uint8_t data[UART_FIFO_LENGTH]; |
112 | 81174dae | aliguori | uint8_t count; |
113 | 81174dae | aliguori | uint8_t itl; /* Interrupt Trigger Level */
|
114 | 81174dae | aliguori | uint8_t tail; |
115 | 81174dae | aliguori | uint8_t head; |
116 | 2b321d69 | Juan Quintela | } SerialFIFO; |
117 | 6936bfe5 | aurel32 | |
118 | b41a2cd1 | bellard | struct SerialState {
|
119 | 508d92d0 | bellard | uint16_t divider; |
120 | 80cabfad | bellard | uint8_t rbr; /* receive register */
|
121 | 81174dae | aliguori | uint8_t thr; /* transmit holding register */
|
122 | 81174dae | aliguori | uint8_t tsr; /* transmit shift register */
|
123 | 80cabfad | bellard | uint8_t ier; |
124 | 80cabfad | bellard | uint8_t iir; /* read only */
|
125 | 80cabfad | bellard | uint8_t lcr; |
126 | 80cabfad | bellard | uint8_t mcr; |
127 | 80cabfad | bellard | uint8_t lsr; /* read only */
|
128 | 3e749fe1 | bellard | uint8_t msr; /* read only */
|
129 | 80cabfad | bellard | uint8_t scr; |
130 | 81174dae | aliguori | uint8_t fcr; |
131 | 747791f1 | Juan Quintela | uint8_t fcr_vmstate; /* we can't write directly this value
|
132 | 747791f1 | Juan Quintela | it has side effects */
|
133 | 80cabfad | bellard | /* NOTE: this hidden state is necessary for tx irq generation as
|
134 | 80cabfad | bellard | it can be reset while reading iir */
|
135 | 80cabfad | bellard | int thr_ipending;
|
136 | d537cf6c | pbrook | qemu_irq irq; |
137 | 82c643ff | bellard | CharDriverState *chr; |
138 | f8d179e3 | bellard | int last_break_enable;
|
139 | e5d13e2f | bellard | int it_shift;
|
140 | b6cd0ea1 | aurel32 | int baudbase;
|
141 | 81174dae | aliguori | int tsr_retry;
|
142 | 81174dae | aliguori | |
143 | 81174dae | aliguori | uint64_t last_xmit_ts; /* Time when the last byte was successfully sent out of the tsr */
|
144 | 81174dae | aliguori | SerialFIFO recv_fifo; |
145 | 81174dae | aliguori | SerialFIFO xmit_fifo; |
146 | 81174dae | aliguori | |
147 | 81174dae | aliguori | struct QEMUTimer *fifo_timeout_timer;
|
148 | 81174dae | aliguori | int timeout_ipending; /* timeout interrupt pending state */ |
149 | 81174dae | aliguori | struct QEMUTimer *transmit_timer;
|
150 | 81174dae | aliguori | |
151 | 81174dae | aliguori | |
152 | 81174dae | aliguori | uint64_t char_transmit_time; /* time to transmit a char in ticks*/
|
153 | 81174dae | aliguori | int poll_msl;
|
154 | 81174dae | aliguori | |
155 | 81174dae | aliguori | struct QEMUTimer *modem_status_poll;
|
156 | b41a2cd1 | bellard | }; |
157 | 80cabfad | bellard | |
158 | ac0be998 | Gerd Hoffmann | typedef struct ISASerialState { |
159 | ac0be998 | Gerd Hoffmann | ISADevice dev; |
160 | a941ae45 | Richard Henderson | MemoryRegion io; |
161 | e8ee28fb | Gerd Hoffmann | uint32_t index; |
162 | ac0be998 | Gerd Hoffmann | uint32_t iobase; |
163 | ac0be998 | Gerd Hoffmann | uint32_t isairq; |
164 | ac0be998 | Gerd Hoffmann | SerialState state; |
165 | ac0be998 | Gerd Hoffmann | } ISASerialState; |
166 | ac0be998 | Gerd Hoffmann | |
167 | 81174dae | aliguori | static void serial_receive1(void *opaque, const uint8_t *buf, int size); |
168 | b2a5160c | balrog | |
169 | 81174dae | aliguori | static void fifo_clear(SerialState *s, int fifo) |
170 | 80cabfad | bellard | { |
171 | 81174dae | aliguori | SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo; |
172 | 81174dae | aliguori | memset(f->data, 0, UART_FIFO_LENGTH);
|
173 | 81174dae | aliguori | f->count = 0;
|
174 | 81174dae | aliguori | f->head = 0;
|
175 | 81174dae | aliguori | f->tail = 0;
|
176 | 80cabfad | bellard | } |
177 | 80cabfad | bellard | |
178 | 81174dae | aliguori | static int fifo_put(SerialState *s, int fifo, uint8_t chr) |
179 | 6936bfe5 | aurel32 | { |
180 | 81174dae | aliguori | SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo; |
181 | 6936bfe5 | aurel32 | |
182 | 71e605f8 | Justin T. Gibbs | /* Receive overruns do not overwrite FIFO contents. */
|
183 | 71e605f8 | Justin T. Gibbs | if (fifo == XMIT_FIFO || f->count < UART_FIFO_LENGTH) {
|
184 | 6936bfe5 | aurel32 | |
185 | 71e605f8 | Justin T. Gibbs | f->data[f->head++] = chr; |
186 | 71e605f8 | Justin T. Gibbs | |
187 | 71e605f8 | Justin T. Gibbs | if (f->head == UART_FIFO_LENGTH)
|
188 | 71e605f8 | Justin T. Gibbs | f->head = 0;
|
189 | 71e605f8 | Justin T. Gibbs | } |
190 | 71e605f8 | Justin T. Gibbs | |
191 | 71e605f8 | Justin T. Gibbs | if (f->count < UART_FIFO_LENGTH)
|
192 | 71e605f8 | Justin T. Gibbs | f->count++; |
193 | 71e605f8 | Justin T. Gibbs | else if (fifo == RECV_FIFO) |
194 | 71e605f8 | Justin T. Gibbs | s->lsr |= UART_LSR_OE; |
195 | 81174dae | aliguori | |
196 | 81174dae | aliguori | return 1; |
197 | 81174dae | aliguori | } |
198 | 81174dae | aliguori | |
199 | 81174dae | aliguori | static uint8_t fifo_get(SerialState *s, int fifo) |
200 | 81174dae | aliguori | { |
201 | 81174dae | aliguori | SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo; |
202 | 81174dae | aliguori | uint8_t c; |
203 | 81174dae | aliguori | |
204 | 81174dae | aliguori | if(f->count == 0) |
205 | 81174dae | aliguori | return 0; |
206 | 81174dae | aliguori | |
207 | 81174dae | aliguori | c = f->data[f->tail++]; |
208 | 81174dae | aliguori | if (f->tail == UART_FIFO_LENGTH)
|
209 | 81174dae | aliguori | f->tail = 0;
|
210 | 81174dae | aliguori | f->count--; |
211 | 81174dae | aliguori | |
212 | 81174dae | aliguori | return c;
|
213 | 81174dae | aliguori | } |
214 | 6936bfe5 | aurel32 | |
215 | 81174dae | aliguori | static void serial_update_irq(SerialState *s) |
216 | 81174dae | aliguori | { |
217 | 81174dae | aliguori | uint8_t tmp_iir = UART_IIR_NO_INT; |
218 | 81174dae | aliguori | |
219 | 81174dae | aliguori | if ((s->ier & UART_IER_RLSI) && (s->lsr & UART_LSR_INT_ANY)) {
|
220 | 81174dae | aliguori | tmp_iir = UART_IIR_RLSI; |
221 | 5628a626 | balrog | } else if ((s->ier & UART_IER_RDI) && s->timeout_ipending) { |
222 | c9a33054 | balrog | /* Note that(s->ier & UART_IER_RDI) can mask this interrupt,
|
223 | c9a33054 | balrog | * this is not in the specification but is observed on existing
|
224 | c9a33054 | balrog | * hardware. */
|
225 | 81174dae | aliguori | tmp_iir = UART_IIR_CTI; |
226 | 2d6ee8e7 | Juergen Lock | } else if ((s->ier & UART_IER_RDI) && (s->lsr & UART_LSR_DR) && |
227 | 2d6ee8e7 | Juergen Lock | (!(s->fcr & UART_FCR_FE) || |
228 | 2d6ee8e7 | Juergen Lock | s->recv_fifo.count >= s->recv_fifo.itl)) { |
229 | 2d6ee8e7 | Juergen Lock | tmp_iir = UART_IIR_RDI; |
230 | 81174dae | aliguori | } else if ((s->ier & UART_IER_THRI) && s->thr_ipending) { |
231 | 81174dae | aliguori | tmp_iir = UART_IIR_THRI; |
232 | 81174dae | aliguori | } else if ((s->ier & UART_IER_MSI) && (s->msr & UART_MSR_ANY_DELTA)) { |
233 | 81174dae | aliguori | tmp_iir = UART_IIR_MSI; |
234 | 81174dae | aliguori | } |
235 | 81174dae | aliguori | |
236 | 81174dae | aliguori | s->iir = tmp_iir | (s->iir & 0xF0);
|
237 | 81174dae | aliguori | |
238 | 81174dae | aliguori | if (tmp_iir != UART_IIR_NO_INT) {
|
239 | 81174dae | aliguori | qemu_irq_raise(s->irq); |
240 | 81174dae | aliguori | } else {
|
241 | 81174dae | aliguori | qemu_irq_lower(s->irq); |
242 | 6936bfe5 | aurel32 | } |
243 | 6936bfe5 | aurel32 | } |
244 | 6936bfe5 | aurel32 | |
245 | f8d179e3 | bellard | static void serial_update_parameters(SerialState *s) |
246 | f8d179e3 | bellard | { |
247 | 81174dae | aliguori | int speed, parity, data_bits, stop_bits, frame_size;
|
248 | 2122c51a | bellard | QEMUSerialSetParams ssp; |
249 | f8d179e3 | bellard | |
250 | 81174dae | aliguori | if (s->divider == 0) |
251 | 81174dae | aliguori | return;
|
252 | 81174dae | aliguori | |
253 | 718b8aec | Stefan Weil | /* Start bit. */
|
254 | 81174dae | aliguori | frame_size = 1;
|
255 | f8d179e3 | bellard | if (s->lcr & 0x08) { |
256 | 718b8aec | Stefan Weil | /* Parity bit. */
|
257 | 718b8aec | Stefan Weil | frame_size++; |
258 | f8d179e3 | bellard | if (s->lcr & 0x10) |
259 | f8d179e3 | bellard | parity = 'E';
|
260 | f8d179e3 | bellard | else
|
261 | f8d179e3 | bellard | parity = 'O';
|
262 | f8d179e3 | bellard | } else {
|
263 | f8d179e3 | bellard | parity = 'N';
|
264 | f8d179e3 | bellard | } |
265 | 5fafdf24 | ths | if (s->lcr & 0x04) |
266 | f8d179e3 | bellard | stop_bits = 2;
|
267 | f8d179e3 | bellard | else
|
268 | f8d179e3 | bellard | stop_bits = 1;
|
269 | 81174dae | aliguori | |
270 | f8d179e3 | bellard | data_bits = (s->lcr & 0x03) + 5; |
271 | 81174dae | aliguori | frame_size += data_bits + stop_bits; |
272 | b6cd0ea1 | aurel32 | speed = s->baudbase / s->divider; |
273 | 2122c51a | bellard | ssp.speed = speed; |
274 | 2122c51a | bellard | ssp.parity = parity; |
275 | 2122c51a | bellard | ssp.data_bits = data_bits; |
276 | 2122c51a | bellard | ssp.stop_bits = stop_bits; |
277 | 6ee093c9 | Juan Quintela | s->char_transmit_time = (get_ticks_per_sec() / speed) * frame_size; |
278 | 41084f1b | Anthony Liguori | qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); |
279 | b6601141 | Michal Novotny | |
280 | b6601141 | Michal Novotny | DPRINTF("speed=%d parity=%c data=%d stop=%d\n",
|
281 | f8d179e3 | bellard | speed, parity, data_bits, stop_bits); |
282 | f8d179e3 | bellard | } |
283 | f8d179e3 | bellard | |
284 | 81174dae | aliguori | static void serial_update_msl(SerialState *s) |
285 | 81174dae | aliguori | { |
286 | 81174dae | aliguori | uint8_t omsr; |
287 | 81174dae | aliguori | int flags;
|
288 | 81174dae | aliguori | |
289 | 81174dae | aliguori | qemu_del_timer(s->modem_status_poll); |
290 | 81174dae | aliguori | |
291 | 41084f1b | Anthony Liguori | if (qemu_chr_fe_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP) {
|
292 | 81174dae | aliguori | s->poll_msl = -1;
|
293 | 81174dae | aliguori | return;
|
294 | 81174dae | aliguori | } |
295 | 81174dae | aliguori | |
296 | 81174dae | aliguori | omsr = s->msr; |
297 | 81174dae | aliguori | |
298 | 81174dae | aliguori | s->msr = (flags & CHR_TIOCM_CTS) ? s->msr | UART_MSR_CTS : s->msr & ~UART_MSR_CTS; |
299 | 81174dae | aliguori | s->msr = (flags & CHR_TIOCM_DSR) ? s->msr | UART_MSR_DSR : s->msr & ~UART_MSR_DSR; |
300 | 81174dae | aliguori | s->msr = (flags & CHR_TIOCM_CAR) ? s->msr | UART_MSR_DCD : s->msr & ~UART_MSR_DCD; |
301 | 81174dae | aliguori | s->msr = (flags & CHR_TIOCM_RI) ? s->msr | UART_MSR_RI : s->msr & ~UART_MSR_RI; |
302 | 81174dae | aliguori | |
303 | 81174dae | aliguori | if (s->msr != omsr) {
|
304 | 81174dae | aliguori | /* Set delta bits */
|
305 | 81174dae | aliguori | s->msr = s->msr | ((s->msr >> 4) ^ (omsr >> 4)); |
306 | 81174dae | aliguori | /* UART_MSR_TERI only if change was from 1 -> 0 */
|
307 | 81174dae | aliguori | if ((s->msr & UART_MSR_TERI) && !(omsr & UART_MSR_RI))
|
308 | 81174dae | aliguori | s->msr &= ~UART_MSR_TERI; |
309 | 81174dae | aliguori | serial_update_irq(s); |
310 | 81174dae | aliguori | } |
311 | 81174dae | aliguori | |
312 | 81174dae | aliguori | /* The real 16550A apparently has a 250ns response latency to line status changes.
|
313 | 81174dae | aliguori | We'll be lazy and poll only every 10ms, and only poll it at all if MSI interrupts are turned on */
|
314 | 81174dae | aliguori | |
315 | 81174dae | aliguori | if (s->poll_msl)
|
316 | 74475455 | Paolo Bonzini | qemu_mod_timer(s->modem_status_poll, qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 100);
|
317 | 81174dae | aliguori | } |
318 | 81174dae | aliguori | |
319 | 81174dae | aliguori | static void serial_xmit(void *opaque) |
320 | 81174dae | aliguori | { |
321 | 81174dae | aliguori | SerialState *s = opaque; |
322 | 74475455 | Paolo Bonzini | uint64_t new_xmit_ts = qemu_get_clock_ns(vm_clock); |
323 | 81174dae | aliguori | |
324 | 81174dae | aliguori | if (s->tsr_retry <= 0) { |
325 | 81174dae | aliguori | if (s->fcr & UART_FCR_FE) {
|
326 | 81174dae | aliguori | s->tsr = fifo_get(s,XMIT_FIFO); |
327 | 81174dae | aliguori | if (!s->xmit_fifo.count)
|
328 | 81174dae | aliguori | s->lsr |= UART_LSR_THRE; |
329 | 81174dae | aliguori | } else {
|
330 | 81174dae | aliguori | s->tsr = s->thr; |
331 | 81174dae | aliguori | s->lsr |= UART_LSR_THRE; |
332 | 81174dae | aliguori | } |
333 | 81174dae | aliguori | } |
334 | 81174dae | aliguori | |
335 | 81174dae | aliguori | if (s->mcr & UART_MCR_LOOP) {
|
336 | 81174dae | aliguori | /* in loopback mode, say that we just received a char */
|
337 | 81174dae | aliguori | serial_receive1(s, &s->tsr, 1);
|
338 | 2cc6e0a1 | Anthony Liguori | } else if (qemu_chr_fe_write(s->chr, &s->tsr, 1) != 1) { |
339 | 81174dae | aliguori | if ((s->tsr_retry > 0) && (s->tsr_retry <= MAX_XMIT_RETRY)) { |
340 | 81174dae | aliguori | s->tsr_retry++; |
341 | 81174dae | aliguori | qemu_mod_timer(s->transmit_timer, new_xmit_ts + s->char_transmit_time); |
342 | 81174dae | aliguori | return;
|
343 | 81174dae | aliguori | } else if (s->poll_msl < 0) { |
344 | 81174dae | aliguori | /* If we exceed MAX_XMIT_RETRY and the backend is not a real serial port, then
|
345 | 81174dae | aliguori | drop any further failed writes instantly, until we get one that goes through.
|
346 | 81174dae | aliguori | This is to prevent guests that log to unconnected pipes or pty's from stalling. */
|
347 | 81174dae | aliguori | s->tsr_retry = -1;
|
348 | 81174dae | aliguori | } |
349 | 81174dae | aliguori | } |
350 | 81174dae | aliguori | else {
|
351 | 81174dae | aliguori | s->tsr_retry = 0;
|
352 | 81174dae | aliguori | } |
353 | 81174dae | aliguori | |
354 | 74475455 | Paolo Bonzini | s->last_xmit_ts = qemu_get_clock_ns(vm_clock); |
355 | 81174dae | aliguori | if (!(s->lsr & UART_LSR_THRE))
|
356 | 81174dae | aliguori | qemu_mod_timer(s->transmit_timer, s->last_xmit_ts + s->char_transmit_time); |
357 | 81174dae | aliguori | |
358 | 81174dae | aliguori | if (s->lsr & UART_LSR_THRE) {
|
359 | 81174dae | aliguori | s->lsr |= UART_LSR_TEMT; |
360 | 81174dae | aliguori | s->thr_ipending = 1;
|
361 | 81174dae | aliguori | serial_update_irq(s); |
362 | 81174dae | aliguori | } |
363 | 81174dae | aliguori | } |
364 | 81174dae | aliguori | |
365 | 81174dae | aliguori | |
366 | b41a2cd1 | bellard | static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
367 | 80cabfad | bellard | { |
368 | b41a2cd1 | bellard | SerialState *s = opaque; |
369 | 3b46e624 | ths | |
370 | 80cabfad | bellard | addr &= 7;
|
371 | b6601141 | Michal Novotny | DPRINTF("write addr=0x%02x val=0x%02x\n", addr, val);
|
372 | 80cabfad | bellard | switch(addr) {
|
373 | 80cabfad | bellard | default:
|
374 | 80cabfad | bellard | case 0: |
375 | 80cabfad | bellard | if (s->lcr & UART_LCR_DLAB) {
|
376 | 80cabfad | bellard | s->divider = (s->divider & 0xff00) | val;
|
377 | f8d179e3 | bellard | serial_update_parameters(s); |
378 | 80cabfad | bellard | } else {
|
379 | 81174dae | aliguori | s->thr = (uint8_t) val; |
380 | 81174dae | aliguori | if(s->fcr & UART_FCR_FE) {
|
381 | 2f4f22bd | Aurelien Jarno | fifo_put(s, XMIT_FIFO, s->thr); |
382 | 2f4f22bd | Aurelien Jarno | s->thr_ipending = 0;
|
383 | 2f4f22bd | Aurelien Jarno | s->lsr &= ~UART_LSR_TEMT; |
384 | 2f4f22bd | Aurelien Jarno | s->lsr &= ~UART_LSR_THRE; |
385 | 2f4f22bd | Aurelien Jarno | serial_update_irq(s); |
386 | 6936bfe5 | aurel32 | } else {
|
387 | 2f4f22bd | Aurelien Jarno | s->thr_ipending = 0;
|
388 | 2f4f22bd | Aurelien Jarno | s->lsr &= ~UART_LSR_THRE; |
389 | 2f4f22bd | Aurelien Jarno | serial_update_irq(s); |
390 | 6936bfe5 | aurel32 | } |
391 | 81174dae | aliguori | serial_xmit(s); |
392 | 80cabfad | bellard | } |
393 | 80cabfad | bellard | break;
|
394 | 80cabfad | bellard | case 1: |
395 | 80cabfad | bellard | if (s->lcr & UART_LCR_DLAB) {
|
396 | 80cabfad | bellard | s->divider = (s->divider & 0x00ff) | (val << 8); |
397 | f8d179e3 | bellard | serial_update_parameters(s); |
398 | 80cabfad | bellard | } else {
|
399 | 60e336db | bellard | s->ier = val & 0x0f;
|
400 | 81174dae | aliguori | /* If the backend device is a real serial port, turn polling of the modem
|
401 | 81174dae | aliguori | status lines on physical port on or off depending on UART_IER_MSI state */
|
402 | 81174dae | aliguori | if (s->poll_msl >= 0) { |
403 | 81174dae | aliguori | if (s->ier & UART_IER_MSI) {
|
404 | 81174dae | aliguori | s->poll_msl = 1;
|
405 | 81174dae | aliguori | serial_update_msl(s); |
406 | 81174dae | aliguori | } else {
|
407 | 81174dae | aliguori | qemu_del_timer(s->modem_status_poll); |
408 | 81174dae | aliguori | s->poll_msl = 0;
|
409 | 81174dae | aliguori | } |
410 | 81174dae | aliguori | } |
411 | 60e336db | bellard | if (s->lsr & UART_LSR_THRE) {
|
412 | 60e336db | bellard | s->thr_ipending = 1;
|
413 | 81174dae | aliguori | serial_update_irq(s); |
414 | 60e336db | bellard | } |
415 | 80cabfad | bellard | } |
416 | 80cabfad | bellard | break;
|
417 | 80cabfad | bellard | case 2: |
418 | 81174dae | aliguori | val = val & 0xFF;
|
419 | 81174dae | aliguori | |
420 | 81174dae | aliguori | if (s->fcr == val)
|
421 | 81174dae | aliguori | break;
|
422 | 81174dae | aliguori | |
423 | 81174dae | aliguori | /* Did the enable/disable flag change? If so, make sure FIFOs get flushed */
|
424 | 81174dae | aliguori | if ((val ^ s->fcr) & UART_FCR_FE)
|
425 | 81174dae | aliguori | val |= UART_FCR_XFR | UART_FCR_RFR; |
426 | 81174dae | aliguori | |
427 | 81174dae | aliguori | /* FIFO clear */
|
428 | 81174dae | aliguori | |
429 | 81174dae | aliguori | if (val & UART_FCR_RFR) {
|
430 | 81174dae | aliguori | qemu_del_timer(s->fifo_timeout_timer); |
431 | 81174dae | aliguori | s->timeout_ipending=0;
|
432 | 81174dae | aliguori | fifo_clear(s,RECV_FIFO); |
433 | 81174dae | aliguori | } |
434 | 81174dae | aliguori | |
435 | 81174dae | aliguori | if (val & UART_FCR_XFR) {
|
436 | 81174dae | aliguori | fifo_clear(s,XMIT_FIFO); |
437 | 81174dae | aliguori | } |
438 | 81174dae | aliguori | |
439 | 81174dae | aliguori | if (val & UART_FCR_FE) {
|
440 | 81174dae | aliguori | s->iir |= UART_IIR_FE; |
441 | 81174dae | aliguori | /* Set RECV_FIFO trigger Level */
|
442 | 81174dae | aliguori | switch (val & 0xC0) { |
443 | 81174dae | aliguori | case UART_FCR_ITL_1:
|
444 | 81174dae | aliguori | s->recv_fifo.itl = 1;
|
445 | 81174dae | aliguori | break;
|
446 | 81174dae | aliguori | case UART_FCR_ITL_2:
|
447 | 81174dae | aliguori | s->recv_fifo.itl = 4;
|
448 | 81174dae | aliguori | break;
|
449 | 81174dae | aliguori | case UART_FCR_ITL_3:
|
450 | 81174dae | aliguori | s->recv_fifo.itl = 8;
|
451 | 81174dae | aliguori | break;
|
452 | 81174dae | aliguori | case UART_FCR_ITL_4:
|
453 | 81174dae | aliguori | s->recv_fifo.itl = 14;
|
454 | 81174dae | aliguori | break;
|
455 | 81174dae | aliguori | } |
456 | 81174dae | aliguori | } else
|
457 | 81174dae | aliguori | s->iir &= ~UART_IIR_FE; |
458 | 81174dae | aliguori | |
459 | 81174dae | aliguori | /* Set fcr - or at least the bits in it that are supposed to "stick" */
|
460 | 81174dae | aliguori | s->fcr = val & 0xC9;
|
461 | 81174dae | aliguori | serial_update_irq(s); |
462 | 80cabfad | bellard | break;
|
463 | 80cabfad | bellard | case 3: |
464 | f8d179e3 | bellard | { |
465 | f8d179e3 | bellard | int break_enable;
|
466 | f8d179e3 | bellard | s->lcr = val; |
467 | f8d179e3 | bellard | serial_update_parameters(s); |
468 | f8d179e3 | bellard | break_enable = (val >> 6) & 1; |
469 | f8d179e3 | bellard | if (break_enable != s->last_break_enable) {
|
470 | f8d179e3 | bellard | s->last_break_enable = break_enable; |
471 | 41084f1b | Anthony Liguori | qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK, |
472 | 2122c51a | bellard | &break_enable); |
473 | f8d179e3 | bellard | } |
474 | f8d179e3 | bellard | } |
475 | 80cabfad | bellard | break;
|
476 | 80cabfad | bellard | case 4: |
477 | 81174dae | aliguori | { |
478 | 81174dae | aliguori | int flags;
|
479 | 81174dae | aliguori | int old_mcr = s->mcr;
|
480 | 81174dae | aliguori | s->mcr = val & 0x1f;
|
481 | 81174dae | aliguori | if (val & UART_MCR_LOOP)
|
482 | 81174dae | aliguori | break;
|
483 | 81174dae | aliguori | |
484 | 81174dae | aliguori | if (s->poll_msl >= 0 && old_mcr != s->mcr) { |
485 | 81174dae | aliguori | |
486 | 41084f1b | Anthony Liguori | qemu_chr_fe_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags); |
487 | 81174dae | aliguori | |
488 | 81174dae | aliguori | flags &= ~(CHR_TIOCM_RTS | CHR_TIOCM_DTR); |
489 | 81174dae | aliguori | |
490 | 81174dae | aliguori | if (val & UART_MCR_RTS)
|
491 | 81174dae | aliguori | flags |= CHR_TIOCM_RTS; |
492 | 81174dae | aliguori | if (val & UART_MCR_DTR)
|
493 | 81174dae | aliguori | flags |= CHR_TIOCM_DTR; |
494 | 81174dae | aliguori | |
495 | 41084f1b | Anthony Liguori | qemu_chr_fe_ioctl(s->chr,CHR_IOCTL_SERIAL_SET_TIOCM, &flags); |
496 | 81174dae | aliguori | /* Update the modem status after a one-character-send wait-time, since there may be a response
|
497 | 81174dae | aliguori | from the device/computer at the other end of the serial line */
|
498 | 74475455 | Paolo Bonzini | qemu_mod_timer(s->modem_status_poll, qemu_get_clock_ns(vm_clock) + s->char_transmit_time); |
499 | 81174dae | aliguori | } |
500 | 81174dae | aliguori | } |
501 | 80cabfad | bellard | break;
|
502 | 80cabfad | bellard | case 5: |
503 | 80cabfad | bellard | break;
|
504 | 80cabfad | bellard | case 6: |
505 | 80cabfad | bellard | break;
|
506 | 80cabfad | bellard | case 7: |
507 | 80cabfad | bellard | s->scr = val; |
508 | 80cabfad | bellard | break;
|
509 | 80cabfad | bellard | } |
510 | 80cabfad | bellard | } |
511 | 80cabfad | bellard | |
512 | b41a2cd1 | bellard | static uint32_t serial_ioport_read(void *opaque, uint32_t addr) |
513 | 80cabfad | bellard | { |
514 | b41a2cd1 | bellard | SerialState *s = opaque; |
515 | 80cabfad | bellard | uint32_t ret; |
516 | 80cabfad | bellard | |
517 | 80cabfad | bellard | addr &= 7;
|
518 | 80cabfad | bellard | switch(addr) {
|
519 | 80cabfad | bellard | default:
|
520 | 80cabfad | bellard | case 0: |
521 | 80cabfad | bellard | if (s->lcr & UART_LCR_DLAB) {
|
522 | 5fafdf24 | ths | ret = s->divider & 0xff;
|
523 | 80cabfad | bellard | } else {
|
524 | 81174dae | aliguori | if(s->fcr & UART_FCR_FE) {
|
525 | 81174dae | aliguori | ret = fifo_get(s,RECV_FIFO); |
526 | 81174dae | aliguori | if (s->recv_fifo.count == 0) |
527 | 81174dae | aliguori | s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); |
528 | 81174dae | aliguori | else
|
529 | 74475455 | Paolo Bonzini | qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock_ns (vm_clock) + s->char_transmit_time * 4);
|
530 | 81174dae | aliguori | s->timeout_ipending = 0;
|
531 | 81174dae | aliguori | } else {
|
532 | 81174dae | aliguori | ret = s->rbr; |
533 | 81174dae | aliguori | s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); |
534 | 81174dae | aliguori | } |
535 | b41a2cd1 | bellard | serial_update_irq(s); |
536 | b2a5160c | balrog | if (!(s->mcr & UART_MCR_LOOP)) {
|
537 | b2a5160c | balrog | /* in loopback mode, don't receive any data */
|
538 | b2a5160c | balrog | qemu_chr_accept_input(s->chr); |
539 | b2a5160c | balrog | } |
540 | 80cabfad | bellard | } |
541 | 80cabfad | bellard | break;
|
542 | 80cabfad | bellard | case 1: |
543 | 80cabfad | bellard | if (s->lcr & UART_LCR_DLAB) {
|
544 | 80cabfad | bellard | ret = (s->divider >> 8) & 0xff; |
545 | 80cabfad | bellard | } else {
|
546 | 80cabfad | bellard | ret = s->ier; |
547 | 80cabfad | bellard | } |
548 | 80cabfad | bellard | break;
|
549 | 80cabfad | bellard | case 2: |
550 | 80cabfad | bellard | ret = s->iir; |
551 | cdee7bdf | Aurelien Jarno | if ((ret & UART_IIR_ID) == UART_IIR_THRI) {
|
552 | 80cabfad | bellard | s->thr_ipending = 0;
|
553 | 71e605f8 | Justin T. Gibbs | serial_update_irq(s); |
554 | 71e605f8 | Justin T. Gibbs | } |
555 | 80cabfad | bellard | break;
|
556 | 80cabfad | bellard | case 3: |
557 | 80cabfad | bellard | ret = s->lcr; |
558 | 80cabfad | bellard | break;
|
559 | 80cabfad | bellard | case 4: |
560 | 80cabfad | bellard | ret = s->mcr; |
561 | 80cabfad | bellard | break;
|
562 | 80cabfad | bellard | case 5: |
563 | 80cabfad | bellard | ret = s->lsr; |
564 | 71e605f8 | Justin T. Gibbs | /* Clear break and overrun interrupts */
|
565 | 71e605f8 | Justin T. Gibbs | if (s->lsr & (UART_LSR_BI|UART_LSR_OE)) {
|
566 | 71e605f8 | Justin T. Gibbs | s->lsr &= ~(UART_LSR_BI|UART_LSR_OE); |
567 | 81174dae | aliguori | serial_update_irq(s); |
568 | 81174dae | aliguori | } |
569 | 80cabfad | bellard | break;
|
570 | 80cabfad | bellard | case 6: |
571 | 80cabfad | bellard | if (s->mcr & UART_MCR_LOOP) {
|
572 | 80cabfad | bellard | /* in loopback, the modem output pins are connected to the
|
573 | 80cabfad | bellard | inputs */
|
574 | 80cabfad | bellard | ret = (s->mcr & 0x0c) << 4; |
575 | 80cabfad | bellard | ret |= (s->mcr & 0x02) << 3; |
576 | 80cabfad | bellard | ret |= (s->mcr & 0x01) << 5; |
577 | 80cabfad | bellard | } else {
|
578 | 81174dae | aliguori | if (s->poll_msl >= 0) |
579 | 81174dae | aliguori | serial_update_msl(s); |
580 | 80cabfad | bellard | ret = s->msr; |
581 | 81174dae | aliguori | /* Clear delta bits & msr int after read, if they were set */
|
582 | 81174dae | aliguori | if (s->msr & UART_MSR_ANY_DELTA) {
|
583 | 81174dae | aliguori | s->msr &= 0xF0;
|
584 | 81174dae | aliguori | serial_update_irq(s); |
585 | 81174dae | aliguori | } |
586 | 80cabfad | bellard | } |
587 | 80cabfad | bellard | break;
|
588 | 80cabfad | bellard | case 7: |
589 | 80cabfad | bellard | ret = s->scr; |
590 | 80cabfad | bellard | break;
|
591 | 80cabfad | bellard | } |
592 | b6601141 | Michal Novotny | DPRINTF("read addr=0x%02x val=0x%02x\n", addr, ret);
|
593 | 80cabfad | bellard | return ret;
|
594 | 80cabfad | bellard | } |
595 | 80cabfad | bellard | |
596 | 82c643ff | bellard | static int serial_can_receive(SerialState *s) |
597 | 80cabfad | bellard | { |
598 | 81174dae | aliguori | if(s->fcr & UART_FCR_FE) {
|
599 | 81174dae | aliguori | if(s->recv_fifo.count < UART_FIFO_LENGTH)
|
600 | 81174dae | aliguori | /* Advertise (fifo.itl - fifo.count) bytes when count < ITL, and 1 if above. If UART_FIFO_LENGTH - fifo.count is
|
601 | 81174dae | aliguori | advertised the effect will be to almost always fill the fifo completely before the guest has a chance to respond,
|
602 | 81174dae | aliguori | effectively overriding the ITL that the guest has set. */
|
603 | 81174dae | aliguori | return (s->recv_fifo.count <= s->recv_fifo.itl) ? s->recv_fifo.itl - s->recv_fifo.count : 1; |
604 | 81174dae | aliguori | else
|
605 | 81174dae | aliguori | return 0; |
606 | 81174dae | aliguori | } else {
|
607 | 80cabfad | bellard | return !(s->lsr & UART_LSR_DR);
|
608 | 81174dae | aliguori | } |
609 | 80cabfad | bellard | } |
610 | 80cabfad | bellard | |
611 | 82c643ff | bellard | static void serial_receive_break(SerialState *s) |
612 | 80cabfad | bellard | { |
613 | 80cabfad | bellard | s->rbr = 0;
|
614 | 40ff1624 | Jason Wessel | /* When the LSR_DR is set a null byte is pushed into the fifo */
|
615 | 40ff1624 | Jason Wessel | fifo_put(s, RECV_FIFO, '\0');
|
616 | 80cabfad | bellard | s->lsr |= UART_LSR_BI | UART_LSR_DR; |
617 | b41a2cd1 | bellard | serial_update_irq(s); |
618 | 80cabfad | bellard | } |
619 | 80cabfad | bellard | |
620 | 81174dae | aliguori | /* There's data in recv_fifo and s->rbr has not been read for 4 char transmit times */
|
621 | 81174dae | aliguori | static void fifo_timeout_int (void *opaque) { |
622 | 81174dae | aliguori | SerialState *s = opaque; |
623 | 81174dae | aliguori | if (s->recv_fifo.count) {
|
624 | 81174dae | aliguori | s->timeout_ipending = 1;
|
625 | 81174dae | aliguori | serial_update_irq(s); |
626 | 81174dae | aliguori | } |
627 | 81174dae | aliguori | } |
628 | 81174dae | aliguori | |
629 | b41a2cd1 | bellard | static int serial_can_receive1(void *opaque) |
630 | 80cabfad | bellard | { |
631 | b41a2cd1 | bellard | SerialState *s = opaque; |
632 | b41a2cd1 | bellard | return serial_can_receive(s);
|
633 | b41a2cd1 | bellard | } |
634 | b41a2cd1 | bellard | |
635 | b41a2cd1 | bellard | static void serial_receive1(void *opaque, const uint8_t *buf, int size) |
636 | b41a2cd1 | bellard | { |
637 | b41a2cd1 | bellard | SerialState *s = opaque; |
638 | 81174dae | aliguori | if(s->fcr & UART_FCR_FE) {
|
639 | 81174dae | aliguori | int i;
|
640 | 81174dae | aliguori | for (i = 0; i < size; i++) { |
641 | 81174dae | aliguori | fifo_put(s, RECV_FIFO, buf[i]); |
642 | 81174dae | aliguori | } |
643 | 81174dae | aliguori | s->lsr |= UART_LSR_DR; |
644 | 81174dae | aliguori | /* call the timeout receive callback in 4 char transmit time */
|
645 | 74475455 | Paolo Bonzini | qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock_ns (vm_clock) + s->char_transmit_time * 4);
|
646 | 81174dae | aliguori | } else {
|
647 | 71e605f8 | Justin T. Gibbs | if (s->lsr & UART_LSR_DR)
|
648 | 71e605f8 | Justin T. Gibbs | s->lsr |= UART_LSR_OE; |
649 | 81174dae | aliguori | s->rbr = buf[0];
|
650 | 81174dae | aliguori | s->lsr |= UART_LSR_DR; |
651 | 81174dae | aliguori | } |
652 | 81174dae | aliguori | serial_update_irq(s); |
653 | b41a2cd1 | bellard | } |
654 | 80cabfad | bellard | |
655 | 82c643ff | bellard | static void serial_event(void *opaque, int event) |
656 | 82c643ff | bellard | { |
657 | 82c643ff | bellard | SerialState *s = opaque; |
658 | b6601141 | Michal Novotny | DPRINTF("event %x\n", event);
|
659 | 82c643ff | bellard | if (event == CHR_EVENT_BREAK)
|
660 | 82c643ff | bellard | serial_receive_break(s); |
661 | 82c643ff | bellard | } |
662 | 82c643ff | bellard | |
663 | d4bfa4d7 | Juan Quintela | static void serial_pre_save(void *opaque) |
664 | 8738a8d0 | bellard | { |
665 | d4bfa4d7 | Juan Quintela | SerialState *s = opaque; |
666 | 747791f1 | Juan Quintela | s->fcr_vmstate = s->fcr; |
667 | 8738a8d0 | bellard | } |
668 | 8738a8d0 | bellard | |
669 | e59fb374 | Juan Quintela | static int serial_post_load(void *opaque, int version_id) |
670 | 747791f1 | Juan Quintela | { |
671 | 747791f1 | Juan Quintela | SerialState *s = opaque; |
672 | 81174dae | aliguori | |
673 | 4c18ce94 | Juan Quintela | if (version_id < 3) { |
674 | 4c18ce94 | Juan Quintela | s->fcr_vmstate = 0;
|
675 | 4c18ce94 | Juan Quintela | } |
676 | 81174dae | aliguori | /* Initialize fcr via setter to perform essential side-effects */
|
677 | 747791f1 | Juan Quintela | serial_ioport_write(s, 0x02, s->fcr_vmstate);
|
678 | 9a7c4878 | Michal Novotny | serial_update_parameters(s); |
679 | 8738a8d0 | bellard | return 0; |
680 | 8738a8d0 | bellard | } |
681 | 8738a8d0 | bellard | |
682 | 747791f1 | Juan Quintela | static const VMStateDescription vmstate_serial = { |
683 | 747791f1 | Juan Quintela | .name = "serial",
|
684 | 747791f1 | Juan Quintela | .version_id = 3,
|
685 | 747791f1 | Juan Quintela | .minimum_version_id = 2,
|
686 | 747791f1 | Juan Quintela | .pre_save = serial_pre_save, |
687 | 747791f1 | Juan Quintela | .post_load = serial_post_load, |
688 | 747791f1 | Juan Quintela | .fields = (VMStateField []) { |
689 | 747791f1 | Juan Quintela | VMSTATE_UINT16_V(divider, SerialState, 2),
|
690 | 747791f1 | Juan Quintela | VMSTATE_UINT8(rbr, SerialState), |
691 | 747791f1 | Juan Quintela | VMSTATE_UINT8(ier, SerialState), |
692 | 747791f1 | Juan Quintela | VMSTATE_UINT8(iir, SerialState), |
693 | 747791f1 | Juan Quintela | VMSTATE_UINT8(lcr, SerialState), |
694 | 747791f1 | Juan Quintela | VMSTATE_UINT8(mcr, SerialState), |
695 | 747791f1 | Juan Quintela | VMSTATE_UINT8(lsr, SerialState), |
696 | 747791f1 | Juan Quintela | VMSTATE_UINT8(msr, SerialState), |
697 | 747791f1 | Juan Quintela | VMSTATE_UINT8(scr, SerialState), |
698 | 747791f1 | Juan Quintela | VMSTATE_UINT8_V(fcr_vmstate, SerialState, 3),
|
699 | 747791f1 | Juan Quintela | VMSTATE_END_OF_LIST() |
700 | 747791f1 | Juan Quintela | } |
701 | 747791f1 | Juan Quintela | }; |
702 | 747791f1 | Juan Quintela | |
703 | b2a5160c | balrog | static void serial_reset(void *opaque) |
704 | b2a5160c | balrog | { |
705 | b2a5160c | balrog | SerialState *s = opaque; |
706 | b2a5160c | balrog | |
707 | b2a5160c | balrog | s->rbr = 0;
|
708 | b2a5160c | balrog | s->ier = 0;
|
709 | b2a5160c | balrog | s->iir = UART_IIR_NO_INT; |
710 | b2a5160c | balrog | s->lcr = 0;
|
711 | b2a5160c | balrog | s->lsr = UART_LSR_TEMT | UART_LSR_THRE; |
712 | b2a5160c | balrog | s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS; |
713 | 718b8aec | Stefan Weil | /* Default to 9600 baud, 1 start bit, 8 data bits, 1 stop bit, no parity. */
|
714 | 81174dae | aliguori | s->divider = 0x0C;
|
715 | 81174dae | aliguori | s->mcr = UART_MCR_OUT2; |
716 | b2a5160c | balrog | s->scr = 0;
|
717 | 81174dae | aliguori | s->tsr_retry = 0;
|
718 | 718b8aec | Stefan Weil | s->char_transmit_time = (get_ticks_per_sec() / 9600) * 10; |
719 | 81174dae | aliguori | s->poll_msl = 0;
|
720 | 81174dae | aliguori | |
721 | 81174dae | aliguori | fifo_clear(s,RECV_FIFO); |
722 | 81174dae | aliguori | fifo_clear(s,XMIT_FIFO); |
723 | 81174dae | aliguori | |
724 | 74475455 | Paolo Bonzini | s->last_xmit_ts = qemu_get_clock_ns(vm_clock); |
725 | b2a5160c | balrog | |
726 | b2a5160c | balrog | s->thr_ipending = 0;
|
727 | b2a5160c | balrog | s->last_break_enable = 0;
|
728 | b2a5160c | balrog | qemu_irq_lower(s->irq); |
729 | b2a5160c | balrog | } |
730 | b2a5160c | balrog | |
731 | ac0be998 | Gerd Hoffmann | static void serial_init_core(SerialState *s) |
732 | 81174dae | aliguori | { |
733 | ac0be998 | Gerd Hoffmann | if (!s->chr) {
|
734 | 387f4a5a | Aurelien Jarno | fprintf(stderr, "Can't create serial device, empty char device\n");
|
735 | 387f4a5a | Aurelien Jarno | exit(1);
|
736 | 387f4a5a | Aurelien Jarno | } |
737 | 387f4a5a | Aurelien Jarno | |
738 | 74475455 | Paolo Bonzini | s->modem_status_poll = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) serial_update_msl, s); |
739 | 81174dae | aliguori | |
740 | 74475455 | Paolo Bonzini | s->fifo_timeout_timer = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) fifo_timeout_int, s); |
741 | 74475455 | Paolo Bonzini | s->transmit_timer = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) serial_xmit, s); |
742 | 81174dae | aliguori | |
743 | a08d4367 | Jan Kiszka | qemu_register_reset(serial_reset, s); |
744 | 81174dae | aliguori | |
745 | b47543c4 | aurel32 | qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1, |
746 | b47543c4 | aurel32 | serial_event, s); |
747 | 81174dae | aliguori | } |
748 | 81174dae | aliguori | |
749 | 038eaf82 | Stefan Weil | /* Change the main reference oscillator frequency. */
|
750 | 038eaf82 | Stefan Weil | void serial_set_frequency(SerialState *s, uint32_t frequency)
|
751 | 038eaf82 | Stefan Weil | { |
752 | 038eaf82 | Stefan Weil | s->baudbase = frequency; |
753 | 038eaf82 | Stefan Weil | serial_update_parameters(s); |
754 | 038eaf82 | Stefan Weil | } |
755 | 038eaf82 | Stefan Weil | |
756 | e8ee28fb | Gerd Hoffmann | static const int isa_serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; |
757 | e8ee28fb | Gerd Hoffmann | static const int isa_serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 }; |
758 | e8ee28fb | Gerd Hoffmann | |
759 | a941ae45 | Richard Henderson | static const MemoryRegionPortio serial_portio[] = { |
760 | a941ae45 | Richard Henderson | { 0, 8, 1, .read = serial_ioport_read, .write = serial_ioport_write }, |
761 | a941ae45 | Richard Henderson | PORTIO_END_OF_LIST() |
762 | a941ae45 | Richard Henderson | }; |
763 | a941ae45 | Richard Henderson | |
764 | a941ae45 | Richard Henderson | static const MemoryRegionOps serial_io_ops = { |
765 | a941ae45 | Richard Henderson | .old_portio = serial_portio |
766 | a941ae45 | Richard Henderson | }; |
767 | a941ae45 | Richard Henderson | |
768 | ac0be998 | Gerd Hoffmann | static int serial_isa_initfn(ISADevice *dev) |
769 | ac0be998 | Gerd Hoffmann | { |
770 | e8ee28fb | Gerd Hoffmann | static int index; |
771 | ac0be998 | Gerd Hoffmann | ISASerialState *isa = DO_UPCAST(ISASerialState, dev, dev); |
772 | ac0be998 | Gerd Hoffmann | SerialState *s = &isa->state; |
773 | ac0be998 | Gerd Hoffmann | |
774 | e8ee28fb | Gerd Hoffmann | if (isa->index == -1) |
775 | e8ee28fb | Gerd Hoffmann | isa->index = index; |
776 | e8ee28fb | Gerd Hoffmann | if (isa->index >= MAX_SERIAL_PORTS)
|
777 | e8ee28fb | Gerd Hoffmann | return -1; |
778 | e8ee28fb | Gerd Hoffmann | if (isa->iobase == -1) |
779 | e8ee28fb | Gerd Hoffmann | isa->iobase = isa_serial_io[isa->index]; |
780 | e8ee28fb | Gerd Hoffmann | if (isa->isairq == -1) |
781 | e8ee28fb | Gerd Hoffmann | isa->isairq = isa_serial_irq[isa->index]; |
782 | e8ee28fb | Gerd Hoffmann | index++; |
783 | e8ee28fb | Gerd Hoffmann | |
784 | ac0be998 | Gerd Hoffmann | s->baudbase = 115200;
|
785 | ac0be998 | Gerd Hoffmann | isa_init_irq(dev, &s->irq, isa->isairq); |
786 | ac0be998 | Gerd Hoffmann | serial_init_core(s); |
787 | 1cc9f514 | Jan Kiszka | qdev_set_legacy_instance_id(&dev->qdev, isa->iobase, 3);
|
788 | ac0be998 | Gerd Hoffmann | |
789 | a941ae45 | Richard Henderson | memory_region_init_io(&isa->io, &serial_io_ops, s, "serial", 8); |
790 | a941ae45 | Richard Henderson | isa_register_ioport(dev, &isa->io, isa->iobase); |
791 | ac0be998 | Gerd Hoffmann | return 0; |
792 | ac0be998 | Gerd Hoffmann | } |
793 | ac0be998 | Gerd Hoffmann | |
794 | 1cc9f514 | Jan Kiszka | static const VMStateDescription vmstate_isa_serial = { |
795 | 1cc9f514 | Jan Kiszka | .name = "serial",
|
796 | 1cc9f514 | Jan Kiszka | .version_id = 3,
|
797 | 1cc9f514 | Jan Kiszka | .minimum_version_id = 2,
|
798 | 1cc9f514 | Jan Kiszka | .fields = (VMStateField []) { |
799 | 1cc9f514 | Jan Kiszka | VMSTATE_STRUCT(state, ISASerialState, 0, vmstate_serial, SerialState),
|
800 | 1cc9f514 | Jan Kiszka | VMSTATE_END_OF_LIST() |
801 | 1cc9f514 | Jan Kiszka | } |
802 | 1cc9f514 | Jan Kiszka | }; |
803 | 1cc9f514 | Jan Kiszka | |
804 | b6cd0ea1 | aurel32 | SerialState *serial_init(int base, qemu_irq irq, int baudbase, |
805 | b6cd0ea1 | aurel32 | CharDriverState *chr) |
806 | b41a2cd1 | bellard | { |
807 | b41a2cd1 | bellard | SerialState *s; |
808 | b41a2cd1 | bellard | |
809 | 7267c094 | Anthony Liguori | s = g_malloc0(sizeof(SerialState));
|
810 | 6936bfe5 | aurel32 | |
811 | ac0be998 | Gerd Hoffmann | s->irq = irq; |
812 | ac0be998 | Gerd Hoffmann | s->baudbase = baudbase; |
813 | ac0be998 | Gerd Hoffmann | s->chr = chr; |
814 | ac0be998 | Gerd Hoffmann | serial_init_core(s); |
815 | b41a2cd1 | bellard | |
816 | 0be71e32 | Alex Williamson | vmstate_register(NULL, base, &vmstate_serial, s);
|
817 | 8738a8d0 | bellard | |
818 | b41a2cd1 | bellard | register_ioport_write(base, 8, 1, serial_ioport_write, s); |
819 | b41a2cd1 | bellard | register_ioport_read(base, 8, 1, serial_ioport_read, s); |
820 | b41a2cd1 | bellard | return s;
|
821 | 80cabfad | bellard | } |
822 | e5d13e2f | bellard | |
823 | e5d13e2f | bellard | /* Memory mapped interface */
|
824 | c227f099 | Anthony Liguori | static uint32_t serial_mm_readb(void *opaque, target_phys_addr_t addr) |
825 | e5d13e2f | bellard | { |
826 | e5d13e2f | bellard | SerialState *s = opaque; |
827 | e5d13e2f | bellard | |
828 | 8da3ff18 | pbrook | return serial_ioport_read(s, addr >> s->it_shift) & 0xFF; |
829 | e5d13e2f | bellard | } |
830 | e5d13e2f | bellard | |
831 | c227f099 | Anthony Liguori | static void serial_mm_writeb(void *opaque, target_phys_addr_t addr, |
832 | 802670e6 | Blue Swirl | uint32_t value) |
833 | e5d13e2f | bellard | { |
834 | e5d13e2f | bellard | SerialState *s = opaque; |
835 | e5d13e2f | bellard | |
836 | 8da3ff18 | pbrook | serial_ioport_write(s, addr >> s->it_shift, value & 0xFF);
|
837 | e5d13e2f | bellard | } |
838 | e5d13e2f | bellard | |
839 | 2d48377a | Blue Swirl | static uint32_t serial_mm_readw_be(void *opaque, target_phys_addr_t addr) |
840 | e5d13e2f | bellard | { |
841 | e5d13e2f | bellard | SerialState *s = opaque; |
842 | e918ee04 | ths | uint32_t val; |
843 | e5d13e2f | bellard | |
844 | 8da3ff18 | pbrook | val = serial_ioport_read(s, addr >> s->it_shift) & 0xFFFF;
|
845 | e918ee04 | ths | val = bswap16(val); |
846 | e918ee04 | ths | return val;
|
847 | e5d13e2f | bellard | } |
848 | e5d13e2f | bellard | |
849 | 2d48377a | Blue Swirl | static uint32_t serial_mm_readw_le(void *opaque, target_phys_addr_t addr) |
850 | e5d13e2f | bellard | { |
851 | e5d13e2f | bellard | SerialState *s = opaque; |
852 | 2d48377a | Blue Swirl | uint32_t val; |
853 | 2d48377a | Blue Swirl | |
854 | 2d48377a | Blue Swirl | val = serial_ioport_read(s, addr >> s->it_shift) & 0xFFFF;
|
855 | 2d48377a | Blue Swirl | return val;
|
856 | 2d48377a | Blue Swirl | } |
857 | 2d48377a | Blue Swirl | |
858 | 2d48377a | Blue Swirl | static void serial_mm_writew_be(void *opaque, target_phys_addr_t addr, |
859 | 2d48377a | Blue Swirl | uint32_t value) |
860 | 2d48377a | Blue Swirl | { |
861 | 2d48377a | Blue Swirl | SerialState *s = opaque; |
862 | 2d48377a | Blue Swirl | |
863 | e918ee04 | ths | value = bswap16(value); |
864 | 8da3ff18 | pbrook | serial_ioport_write(s, addr >> s->it_shift, value & 0xFFFF);
|
865 | e5d13e2f | bellard | } |
866 | e5d13e2f | bellard | |
867 | 2d48377a | Blue Swirl | static void serial_mm_writew_le(void *opaque, target_phys_addr_t addr, |
868 | 2d48377a | Blue Swirl | uint32_t value) |
869 | 2d48377a | Blue Swirl | { |
870 | 2d48377a | Blue Swirl | SerialState *s = opaque; |
871 | 2d48377a | Blue Swirl | |
872 | 2d48377a | Blue Swirl | serial_ioport_write(s, addr >> s->it_shift, value & 0xFFFF);
|
873 | 2d48377a | Blue Swirl | } |
874 | 2d48377a | Blue Swirl | |
875 | 2d48377a | Blue Swirl | static uint32_t serial_mm_readl_be(void *opaque, target_phys_addr_t addr) |
876 | e5d13e2f | bellard | { |
877 | e5d13e2f | bellard | SerialState *s = opaque; |
878 | e918ee04 | ths | uint32_t val; |
879 | e5d13e2f | bellard | |
880 | 8da3ff18 | pbrook | val = serial_ioport_read(s, addr >> s->it_shift); |
881 | e918ee04 | ths | val = bswap32(val); |
882 | e918ee04 | ths | return val;
|
883 | e5d13e2f | bellard | } |
884 | e5d13e2f | bellard | |
885 | 2d48377a | Blue Swirl | static uint32_t serial_mm_readl_le(void *opaque, target_phys_addr_t addr) |
886 | 2d48377a | Blue Swirl | { |
887 | 2d48377a | Blue Swirl | SerialState *s = opaque; |
888 | 2d48377a | Blue Swirl | uint32_t val; |
889 | 2d48377a | Blue Swirl | |
890 | 2d48377a | Blue Swirl | val = serial_ioport_read(s, addr >> s->it_shift); |
891 | 2d48377a | Blue Swirl | return val;
|
892 | 2d48377a | Blue Swirl | } |
893 | 2d48377a | Blue Swirl | |
894 | 2d48377a | Blue Swirl | static void serial_mm_writel_be(void *opaque, target_phys_addr_t addr, |
895 | 2d48377a | Blue Swirl | uint32_t value) |
896 | e5d13e2f | bellard | { |
897 | e5d13e2f | bellard | SerialState *s = opaque; |
898 | 2d48377a | Blue Swirl | |
899 | e918ee04 | ths | value = bswap32(value); |
900 | 8da3ff18 | pbrook | serial_ioport_write(s, addr >> s->it_shift, value); |
901 | e5d13e2f | bellard | } |
902 | e5d13e2f | bellard | |
903 | 2d48377a | Blue Swirl | static void serial_mm_writel_le(void *opaque, target_phys_addr_t addr, |
904 | 2d48377a | Blue Swirl | uint32_t value) |
905 | 2d48377a | Blue Swirl | { |
906 | 2d48377a | Blue Swirl | SerialState *s = opaque; |
907 | 2d48377a | Blue Swirl | |
908 | 2d48377a | Blue Swirl | serial_ioport_write(s, addr >> s->it_shift, value); |
909 | 2d48377a | Blue Swirl | } |
910 | 2d48377a | Blue Swirl | |
911 | 2d48377a | Blue Swirl | static CPUReadMemoryFunc * const serial_mm_read_be[] = { |
912 | e5d13e2f | bellard | &serial_mm_readb, |
913 | 2d48377a | Blue Swirl | &serial_mm_readw_be, |
914 | 2d48377a | Blue Swirl | &serial_mm_readl_be, |
915 | e5d13e2f | bellard | }; |
916 | e5d13e2f | bellard | |
917 | 2d48377a | Blue Swirl | static CPUWriteMemoryFunc * const serial_mm_write_be[] = { |
918 | e5d13e2f | bellard | &serial_mm_writeb, |
919 | 2d48377a | Blue Swirl | &serial_mm_writew_be, |
920 | 2d48377a | Blue Swirl | &serial_mm_writel_be, |
921 | 2d48377a | Blue Swirl | }; |
922 | 2d48377a | Blue Swirl | |
923 | 2d48377a | Blue Swirl | static CPUReadMemoryFunc * const serial_mm_read_le[] = { |
924 | 2d48377a | Blue Swirl | &serial_mm_readb, |
925 | 2d48377a | Blue Swirl | &serial_mm_readw_le, |
926 | 2d48377a | Blue Swirl | &serial_mm_readl_le, |
927 | 2d48377a | Blue Swirl | }; |
928 | 2d48377a | Blue Swirl | |
929 | 2d48377a | Blue Swirl | static CPUWriteMemoryFunc * const serial_mm_write_le[] = { |
930 | 2d48377a | Blue Swirl | &serial_mm_writeb, |
931 | 2d48377a | Blue Swirl | &serial_mm_writew_le, |
932 | 2d48377a | Blue Swirl | &serial_mm_writel_le, |
933 | e5d13e2f | bellard | }; |
934 | e5d13e2f | bellard | |
935 | c227f099 | Anthony Liguori | SerialState *serial_mm_init (target_phys_addr_t base, int it_shift,
|
936 | b6cd0ea1 | aurel32 | qemu_irq irq, int baudbase,
|
937 | 2d48377a | Blue Swirl | CharDriverState *chr, int ioregister,
|
938 | 2d48377a | Blue Swirl | int be)
|
939 | e5d13e2f | bellard | { |
940 | e5d13e2f | bellard | SerialState *s; |
941 | e5d13e2f | bellard | int s_io_memory;
|
942 | e5d13e2f | bellard | |
943 | 7267c094 | Anthony Liguori | s = g_malloc0(sizeof(SerialState));
|
944 | 81174dae | aliguori | |
945 | e5d13e2f | bellard | s->it_shift = it_shift; |
946 | ac0be998 | Gerd Hoffmann | s->irq = irq; |
947 | ac0be998 | Gerd Hoffmann | s->baudbase = baudbase; |
948 | ac0be998 | Gerd Hoffmann | s->chr = chr; |
949 | e5d13e2f | bellard | |
950 | ac0be998 | Gerd Hoffmann | serial_init_core(s); |
951 | 0be71e32 | Alex Williamson | vmstate_register(NULL, base, &vmstate_serial, s);
|
952 | e5d13e2f | bellard | |
953 | a4bc3afc | ths | if (ioregister) {
|
954 | 2d48377a | Blue Swirl | if (be) {
|
955 | 2d48377a | Blue Swirl | s_io_memory = cpu_register_io_memory(serial_mm_read_be, |
956 | 2507c12a | Alexander Graf | serial_mm_write_be, s, |
957 | 2507c12a | Alexander Graf | DEVICE_NATIVE_ENDIAN); |
958 | 2d48377a | Blue Swirl | } else {
|
959 | 2d48377a | Blue Swirl | s_io_memory = cpu_register_io_memory(serial_mm_read_le, |
960 | 2507c12a | Alexander Graf | serial_mm_write_le, s, |
961 | 2507c12a | Alexander Graf | DEVICE_NATIVE_ENDIAN); |
962 | 2d48377a | Blue Swirl | } |
963 | a4bc3afc | ths | cpu_register_physical_memory(base, 8 << it_shift, s_io_memory);
|
964 | a4bc3afc | ths | } |
965 | 81174dae | aliguori | serial_update_msl(s); |
966 | e5d13e2f | bellard | return s;
|
967 | e5d13e2f | bellard | } |
968 | ac0be998 | Gerd Hoffmann | |
969 | ac0be998 | Gerd Hoffmann | static ISADeviceInfo serial_isa_info = {
|
970 | ac0be998 | Gerd Hoffmann | .qdev.name = "isa-serial",
|
971 | ac0be998 | Gerd Hoffmann | .qdev.size = sizeof(ISASerialState),
|
972 | 1cc9f514 | Jan Kiszka | .qdev.vmsd = &vmstate_isa_serial, |
973 | ac0be998 | Gerd Hoffmann | .init = serial_isa_initfn, |
974 | ac0be998 | Gerd Hoffmann | .qdev.props = (Property[]) { |
975 | 51954d56 | Gerd Hoffmann | DEFINE_PROP_UINT32("index", ISASerialState, index, -1), |
976 | e8ee28fb | Gerd Hoffmann | DEFINE_PROP_HEX32("iobase", ISASerialState, iobase, -1), |
977 | e8ee28fb | Gerd Hoffmann | DEFINE_PROP_UINT32("irq", ISASerialState, isairq, -1), |
978 | ac0be998 | Gerd Hoffmann | DEFINE_PROP_CHR("chardev", ISASerialState, state.chr),
|
979 | ac0be998 | Gerd Hoffmann | DEFINE_PROP_END_OF_LIST(), |
980 | ac0be998 | Gerd Hoffmann | }, |
981 | ac0be998 | Gerd Hoffmann | }; |
982 | ac0be998 | Gerd Hoffmann | |
983 | ac0be998 | Gerd Hoffmann | static void serial_register_devices(void) |
984 | ac0be998 | Gerd Hoffmann | { |
985 | ac0be998 | Gerd Hoffmann | isa_qdev_register(&serial_isa_info); |
986 | ac0be998 | Gerd Hoffmann | } |
987 | ac0be998 | Gerd Hoffmann | |
988 | ac0be998 | Gerd Hoffmann | device_init(serial_register_devices) |