root / hw / serial.c @ 9e2c1298
History | View | Annotate | Download (23.9 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 | 488cb996 | Gerd Hoffmann | |
26 | 488cb996 | Gerd Hoffmann | #include "serial.h" |
27 | 87ecb68b | pbrook | #include "qemu-char.h" |
28 | 6936bfe5 | aurel32 | #include "qemu-timer.h" |
29 | 5ec3a23e | Alexander Graf | #include "exec-memory.h" |
30 | 80cabfad | bellard | |
31 | 80cabfad | bellard | //#define DEBUG_SERIAL
|
32 | 80cabfad | bellard | |
33 | 80cabfad | bellard | #define UART_LCR_DLAB 0x80 /* Divisor latch access bit */ |
34 | 80cabfad | bellard | |
35 | 80cabfad | bellard | #define UART_IER_MSI 0x08 /* Enable Modem status interrupt */ |
36 | 80cabfad | bellard | #define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */ |
37 | 80cabfad | bellard | #define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */ |
38 | 80cabfad | bellard | #define UART_IER_RDI 0x01 /* Enable receiver data interrupt */ |
39 | 80cabfad | bellard | |
40 | 80cabfad | bellard | #define UART_IIR_NO_INT 0x01 /* No interrupts pending */ |
41 | 80cabfad | bellard | #define UART_IIR_ID 0x06 /* Mask for the interrupt ID */ |
42 | 80cabfad | bellard | |
43 | 80cabfad | bellard | #define UART_IIR_MSI 0x00 /* Modem status interrupt */ |
44 | 80cabfad | bellard | #define UART_IIR_THRI 0x02 /* Transmitter holding register empty */ |
45 | 80cabfad | bellard | #define UART_IIR_RDI 0x04 /* Receiver data interrupt */ |
46 | 80cabfad | bellard | #define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */ |
47 | 81174dae | aliguori | #define UART_IIR_CTI 0x0C /* Character Timeout Indication */ |
48 | 81174dae | aliguori | |
49 | 81174dae | aliguori | #define UART_IIR_FENF 0x80 /* Fifo enabled, but not functionning */ |
50 | 81174dae | aliguori | #define UART_IIR_FE 0xC0 /* Fifo enabled */ |
51 | 80cabfad | bellard | |
52 | 80cabfad | bellard | /*
|
53 | 80cabfad | bellard | * These are the definitions for the Modem Control Register
|
54 | 80cabfad | bellard | */
|
55 | 80cabfad | bellard | #define UART_MCR_LOOP 0x10 /* Enable loopback test mode */ |
56 | 80cabfad | bellard | #define UART_MCR_OUT2 0x08 /* Out2 complement */ |
57 | 80cabfad | bellard | #define UART_MCR_OUT1 0x04 /* Out1 complement */ |
58 | 80cabfad | bellard | #define UART_MCR_RTS 0x02 /* RTS complement */ |
59 | 80cabfad | bellard | #define UART_MCR_DTR 0x01 /* DTR complement */ |
60 | 80cabfad | bellard | |
61 | 80cabfad | bellard | /*
|
62 | 80cabfad | bellard | * These are the definitions for the Modem Status Register
|
63 | 80cabfad | bellard | */
|
64 | 80cabfad | bellard | #define UART_MSR_DCD 0x80 /* Data Carrier Detect */ |
65 | 80cabfad | bellard | #define UART_MSR_RI 0x40 /* Ring Indicator */ |
66 | 80cabfad | bellard | #define UART_MSR_DSR 0x20 /* Data Set Ready */ |
67 | 80cabfad | bellard | #define UART_MSR_CTS 0x10 /* Clear to Send */ |
68 | 80cabfad | bellard | #define UART_MSR_DDCD 0x08 /* Delta DCD */ |
69 | 80cabfad | bellard | #define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */ |
70 | 80cabfad | bellard | #define UART_MSR_DDSR 0x02 /* Delta DSR */ |
71 | 80cabfad | bellard | #define UART_MSR_DCTS 0x01 /* Delta CTS */ |
72 | 80cabfad | bellard | #define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */ |
73 | 80cabfad | bellard | |
74 | 80cabfad | bellard | #define UART_LSR_TEMT 0x40 /* Transmitter empty */ |
75 | 80cabfad | bellard | #define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ |
76 | 80cabfad | bellard | #define UART_LSR_BI 0x10 /* Break interrupt indicator */ |
77 | 80cabfad | bellard | #define UART_LSR_FE 0x08 /* Frame error indicator */ |
78 | 80cabfad | bellard | #define UART_LSR_PE 0x04 /* Parity error indicator */ |
79 | 80cabfad | bellard | #define UART_LSR_OE 0x02 /* Overrun error indicator */ |
80 | 80cabfad | bellard | #define UART_LSR_DR 0x01 /* Receiver data ready */ |
81 | 81174dae | aliguori | #define UART_LSR_INT_ANY 0x1E /* Any of the lsr-interrupt-triggering status bits */ |
82 | 80cabfad | bellard | |
83 | 81174dae | aliguori | /* Interrupt trigger levels. The byte-counts are for 16550A - in newer UARTs the byte-count for each ITL is higher. */
|
84 | 81174dae | aliguori | |
85 | 81174dae | aliguori | #define UART_FCR_ITL_1 0x00 /* 1 byte ITL */ |
86 | 81174dae | aliguori | #define UART_FCR_ITL_2 0x40 /* 4 bytes ITL */ |
87 | 81174dae | aliguori | #define UART_FCR_ITL_3 0x80 /* 8 bytes ITL */ |
88 | 81174dae | aliguori | #define UART_FCR_ITL_4 0xC0 /* 14 bytes ITL */ |
89 | 81174dae | aliguori | |
90 | 81174dae | aliguori | #define UART_FCR_DMS 0x08 /* DMA Mode Select */ |
91 | 81174dae | aliguori | #define UART_FCR_XFR 0x04 /* XMIT Fifo Reset */ |
92 | 81174dae | aliguori | #define UART_FCR_RFR 0x02 /* RCVR Fifo Reset */ |
93 | 81174dae | aliguori | #define UART_FCR_FE 0x01 /* FIFO Enable */ |
94 | 81174dae | aliguori | |
95 | 81174dae | aliguori | #define XMIT_FIFO 0 |
96 | 81174dae | aliguori | #define RECV_FIFO 1 |
97 | 81174dae | aliguori | #define MAX_XMIT_RETRY 4 |
98 | 81174dae | aliguori | |
99 | b6601141 | Michal Novotny | #ifdef DEBUG_SERIAL
|
100 | b6601141 | Michal Novotny | #define DPRINTF(fmt, ...) \
|
101 | 46411f86 | Stefan Weil | do { fprintf(stderr, "serial: " fmt , ## __VA_ARGS__); } while (0) |
102 | b6601141 | Michal Novotny | #else
|
103 | b6601141 | Michal Novotny | #define DPRINTF(fmt, ...) \
|
104 | 46411f86 | Stefan Weil | do {} while (0) |
105 | b6601141 | Michal Novotny | #endif
|
106 | b6601141 | Michal Novotny | |
107 | 81174dae | aliguori | static void serial_receive1(void *opaque, const uint8_t *buf, int size); |
108 | b2a5160c | balrog | |
109 | 81174dae | aliguori | static void fifo_clear(SerialState *s, int fifo) |
110 | 80cabfad | bellard | { |
111 | 81174dae | aliguori | SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo; |
112 | 81174dae | aliguori | memset(f->data, 0, UART_FIFO_LENGTH);
|
113 | 81174dae | aliguori | f->count = 0;
|
114 | 81174dae | aliguori | f->head = 0;
|
115 | 81174dae | aliguori | f->tail = 0;
|
116 | 80cabfad | bellard | } |
117 | 80cabfad | bellard | |
118 | 81174dae | aliguori | static int fifo_put(SerialState *s, int fifo, uint8_t chr) |
119 | 6936bfe5 | aurel32 | { |
120 | 81174dae | aliguori | SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo; |
121 | 6936bfe5 | aurel32 | |
122 | 71e605f8 | Justin T. Gibbs | /* Receive overruns do not overwrite FIFO contents. */
|
123 | 71e605f8 | Justin T. Gibbs | if (fifo == XMIT_FIFO || f->count < UART_FIFO_LENGTH) {
|
124 | 6936bfe5 | aurel32 | |
125 | 71e605f8 | Justin T. Gibbs | f->data[f->head++] = chr; |
126 | 71e605f8 | Justin T. Gibbs | |
127 | 71e605f8 | Justin T. Gibbs | if (f->head == UART_FIFO_LENGTH)
|
128 | 71e605f8 | Justin T. Gibbs | f->head = 0;
|
129 | 71e605f8 | Justin T. Gibbs | } |
130 | 71e605f8 | Justin T. Gibbs | |
131 | 71e605f8 | Justin T. Gibbs | if (f->count < UART_FIFO_LENGTH)
|
132 | 71e605f8 | Justin T. Gibbs | f->count++; |
133 | 71e605f8 | Justin T. Gibbs | else if (fifo == RECV_FIFO) |
134 | 71e605f8 | Justin T. Gibbs | s->lsr |= UART_LSR_OE; |
135 | 81174dae | aliguori | |
136 | 81174dae | aliguori | return 1; |
137 | 81174dae | aliguori | } |
138 | 81174dae | aliguori | |
139 | 81174dae | aliguori | static uint8_t fifo_get(SerialState *s, int fifo) |
140 | 81174dae | aliguori | { |
141 | 81174dae | aliguori | SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo; |
142 | 81174dae | aliguori | uint8_t c; |
143 | 81174dae | aliguori | |
144 | 81174dae | aliguori | if(f->count == 0) |
145 | 81174dae | aliguori | return 0; |
146 | 81174dae | aliguori | |
147 | 81174dae | aliguori | c = f->data[f->tail++]; |
148 | 81174dae | aliguori | if (f->tail == UART_FIFO_LENGTH)
|
149 | 81174dae | aliguori | f->tail = 0;
|
150 | 81174dae | aliguori | f->count--; |
151 | 81174dae | aliguori | |
152 | 81174dae | aliguori | return c;
|
153 | 81174dae | aliguori | } |
154 | 6936bfe5 | aurel32 | |
155 | 81174dae | aliguori | static void serial_update_irq(SerialState *s) |
156 | 81174dae | aliguori | { |
157 | 81174dae | aliguori | uint8_t tmp_iir = UART_IIR_NO_INT; |
158 | 81174dae | aliguori | |
159 | 81174dae | aliguori | if ((s->ier & UART_IER_RLSI) && (s->lsr & UART_LSR_INT_ANY)) {
|
160 | 81174dae | aliguori | tmp_iir = UART_IIR_RLSI; |
161 | 5628a626 | balrog | } else if ((s->ier & UART_IER_RDI) && s->timeout_ipending) { |
162 | c9a33054 | balrog | /* Note that(s->ier & UART_IER_RDI) can mask this interrupt,
|
163 | c9a33054 | balrog | * this is not in the specification but is observed on existing
|
164 | c9a33054 | balrog | * hardware. */
|
165 | 81174dae | aliguori | tmp_iir = UART_IIR_CTI; |
166 | 2d6ee8e7 | Juergen Lock | } else if ((s->ier & UART_IER_RDI) && (s->lsr & UART_LSR_DR) && |
167 | 2d6ee8e7 | Juergen Lock | (!(s->fcr & UART_FCR_FE) || |
168 | 2d6ee8e7 | Juergen Lock | s->recv_fifo.count >= s->recv_fifo.itl)) { |
169 | 2d6ee8e7 | Juergen Lock | tmp_iir = UART_IIR_RDI; |
170 | 81174dae | aliguori | } else if ((s->ier & UART_IER_THRI) && s->thr_ipending) { |
171 | 81174dae | aliguori | tmp_iir = UART_IIR_THRI; |
172 | 81174dae | aliguori | } else if ((s->ier & UART_IER_MSI) && (s->msr & UART_MSR_ANY_DELTA)) { |
173 | 81174dae | aliguori | tmp_iir = UART_IIR_MSI; |
174 | 81174dae | aliguori | } |
175 | 81174dae | aliguori | |
176 | 81174dae | aliguori | s->iir = tmp_iir | (s->iir & 0xF0);
|
177 | 81174dae | aliguori | |
178 | 81174dae | aliguori | if (tmp_iir != UART_IIR_NO_INT) {
|
179 | 81174dae | aliguori | qemu_irq_raise(s->irq); |
180 | 81174dae | aliguori | } else {
|
181 | 81174dae | aliguori | qemu_irq_lower(s->irq); |
182 | 6936bfe5 | aurel32 | } |
183 | 6936bfe5 | aurel32 | } |
184 | 6936bfe5 | aurel32 | |
185 | f8d179e3 | bellard | static void serial_update_parameters(SerialState *s) |
186 | f8d179e3 | bellard | { |
187 | 81174dae | aliguori | int speed, parity, data_bits, stop_bits, frame_size;
|
188 | 2122c51a | bellard | QEMUSerialSetParams ssp; |
189 | f8d179e3 | bellard | |
190 | 81174dae | aliguori | if (s->divider == 0) |
191 | 81174dae | aliguori | return;
|
192 | 81174dae | aliguori | |
193 | 718b8aec | Stefan Weil | /* Start bit. */
|
194 | 81174dae | aliguori | frame_size = 1;
|
195 | f8d179e3 | bellard | if (s->lcr & 0x08) { |
196 | 718b8aec | Stefan Weil | /* Parity bit. */
|
197 | 718b8aec | Stefan Weil | frame_size++; |
198 | f8d179e3 | bellard | if (s->lcr & 0x10) |
199 | f8d179e3 | bellard | parity = 'E';
|
200 | f8d179e3 | bellard | else
|
201 | f8d179e3 | bellard | parity = 'O';
|
202 | f8d179e3 | bellard | } else {
|
203 | f8d179e3 | bellard | parity = 'N';
|
204 | f8d179e3 | bellard | } |
205 | 5fafdf24 | ths | if (s->lcr & 0x04) |
206 | f8d179e3 | bellard | stop_bits = 2;
|
207 | f8d179e3 | bellard | else
|
208 | f8d179e3 | bellard | stop_bits = 1;
|
209 | 81174dae | aliguori | |
210 | f8d179e3 | bellard | data_bits = (s->lcr & 0x03) + 5; |
211 | 81174dae | aliguori | frame_size += data_bits + stop_bits; |
212 | b6cd0ea1 | aurel32 | speed = s->baudbase / s->divider; |
213 | 2122c51a | bellard | ssp.speed = speed; |
214 | 2122c51a | bellard | ssp.parity = parity; |
215 | 2122c51a | bellard | ssp.data_bits = data_bits; |
216 | 2122c51a | bellard | ssp.stop_bits = stop_bits; |
217 | 6ee093c9 | Juan Quintela | s->char_transmit_time = (get_ticks_per_sec() / speed) * frame_size; |
218 | 41084f1b | Anthony Liguori | qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); |
219 | b6601141 | Michal Novotny | |
220 | b6601141 | Michal Novotny | DPRINTF("speed=%d parity=%c data=%d stop=%d\n",
|
221 | f8d179e3 | bellard | speed, parity, data_bits, stop_bits); |
222 | f8d179e3 | bellard | } |
223 | f8d179e3 | bellard | |
224 | 81174dae | aliguori | static void serial_update_msl(SerialState *s) |
225 | 81174dae | aliguori | { |
226 | 81174dae | aliguori | uint8_t omsr; |
227 | 81174dae | aliguori | int flags;
|
228 | 81174dae | aliguori | |
229 | 81174dae | aliguori | qemu_del_timer(s->modem_status_poll); |
230 | 81174dae | aliguori | |
231 | 41084f1b | Anthony Liguori | if (qemu_chr_fe_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP) {
|
232 | 81174dae | aliguori | s->poll_msl = -1;
|
233 | 81174dae | aliguori | return;
|
234 | 81174dae | aliguori | } |
235 | 81174dae | aliguori | |
236 | 81174dae | aliguori | omsr = s->msr; |
237 | 81174dae | aliguori | |
238 | 81174dae | aliguori | s->msr = (flags & CHR_TIOCM_CTS) ? s->msr | UART_MSR_CTS : s->msr & ~UART_MSR_CTS; |
239 | 81174dae | aliguori | s->msr = (flags & CHR_TIOCM_DSR) ? s->msr | UART_MSR_DSR : s->msr & ~UART_MSR_DSR; |
240 | 81174dae | aliguori | s->msr = (flags & CHR_TIOCM_CAR) ? s->msr | UART_MSR_DCD : s->msr & ~UART_MSR_DCD; |
241 | 81174dae | aliguori | s->msr = (flags & CHR_TIOCM_RI) ? s->msr | UART_MSR_RI : s->msr & ~UART_MSR_RI; |
242 | 81174dae | aliguori | |
243 | 81174dae | aliguori | if (s->msr != omsr) {
|
244 | 81174dae | aliguori | /* Set delta bits */
|
245 | 81174dae | aliguori | s->msr = s->msr | ((s->msr >> 4) ^ (omsr >> 4)); |
246 | 81174dae | aliguori | /* UART_MSR_TERI only if change was from 1 -> 0 */
|
247 | 81174dae | aliguori | if ((s->msr & UART_MSR_TERI) && !(omsr & UART_MSR_RI))
|
248 | 81174dae | aliguori | s->msr &= ~UART_MSR_TERI; |
249 | 81174dae | aliguori | serial_update_irq(s); |
250 | 81174dae | aliguori | } |
251 | 81174dae | aliguori | |
252 | 81174dae | aliguori | /* The real 16550A apparently has a 250ns response latency to line status changes.
|
253 | 81174dae | aliguori | We'll be lazy and poll only every 10ms, and only poll it at all if MSI interrupts are turned on */
|
254 | 81174dae | aliguori | |
255 | 81174dae | aliguori | if (s->poll_msl)
|
256 | 74475455 | Paolo Bonzini | qemu_mod_timer(s->modem_status_poll, qemu_get_clock_ns(vm_clock) + get_ticks_per_sec() / 100);
|
257 | 81174dae | aliguori | } |
258 | 81174dae | aliguori | |
259 | 81174dae | aliguori | static void serial_xmit(void *opaque) |
260 | 81174dae | aliguori | { |
261 | 81174dae | aliguori | SerialState *s = opaque; |
262 | 74475455 | Paolo Bonzini | uint64_t new_xmit_ts = qemu_get_clock_ns(vm_clock); |
263 | 81174dae | aliguori | |
264 | 81174dae | aliguori | if (s->tsr_retry <= 0) { |
265 | 81174dae | aliguori | if (s->fcr & UART_FCR_FE) {
|
266 | 81174dae | aliguori | s->tsr = fifo_get(s,XMIT_FIFO); |
267 | 81174dae | aliguori | if (!s->xmit_fifo.count)
|
268 | 81174dae | aliguori | s->lsr |= UART_LSR_THRE; |
269 | 67c5322d | Anthony Liguori | } else if ((s->lsr & UART_LSR_THRE)) { |
270 | 67c5322d | Anthony Liguori | return;
|
271 | 81174dae | aliguori | } else {
|
272 | 81174dae | aliguori | s->tsr = s->thr; |
273 | 81174dae | aliguori | s->lsr |= UART_LSR_THRE; |
274 | dfe844c9 | Anthony Liguori | s->lsr &= ~UART_LSR_TEMT; |
275 | 81174dae | aliguori | } |
276 | 81174dae | aliguori | } |
277 | 81174dae | aliguori | |
278 | 81174dae | aliguori | if (s->mcr & UART_MCR_LOOP) {
|
279 | 81174dae | aliguori | /* in loopback mode, say that we just received a char */
|
280 | 81174dae | aliguori | serial_receive1(s, &s->tsr, 1);
|
281 | 2cc6e0a1 | Anthony Liguori | } else if (qemu_chr_fe_write(s->chr, &s->tsr, 1) != 1) { |
282 | 67c5322d | Anthony Liguori | if ((s->tsr_retry >= 0) && (s->tsr_retry <= MAX_XMIT_RETRY)) { |
283 | 81174dae | aliguori | s->tsr_retry++; |
284 | 81174dae | aliguori | qemu_mod_timer(s->transmit_timer, new_xmit_ts + s->char_transmit_time); |
285 | 81174dae | aliguori | return;
|
286 | 81174dae | aliguori | } else if (s->poll_msl < 0) { |
287 | 81174dae | aliguori | /* If we exceed MAX_XMIT_RETRY and the backend is not a real serial port, then
|
288 | 81174dae | aliguori | drop any further failed writes instantly, until we get one that goes through.
|
289 | 81174dae | aliguori | This is to prevent guests that log to unconnected pipes or pty's from stalling. */
|
290 | 81174dae | aliguori | s->tsr_retry = -1;
|
291 | 81174dae | aliguori | } |
292 | 81174dae | aliguori | } |
293 | 81174dae | aliguori | else {
|
294 | 81174dae | aliguori | s->tsr_retry = 0;
|
295 | 81174dae | aliguori | } |
296 | 81174dae | aliguori | |
297 | 74475455 | Paolo Bonzini | s->last_xmit_ts = qemu_get_clock_ns(vm_clock); |
298 | 81174dae | aliguori | if (!(s->lsr & UART_LSR_THRE))
|
299 | 81174dae | aliguori | qemu_mod_timer(s->transmit_timer, s->last_xmit_ts + s->char_transmit_time); |
300 | 81174dae | aliguori | |
301 | 81174dae | aliguori | if (s->lsr & UART_LSR_THRE) {
|
302 | 81174dae | aliguori | s->lsr |= UART_LSR_TEMT; |
303 | 81174dae | aliguori | s->thr_ipending = 1;
|
304 | 81174dae | aliguori | serial_update_irq(s); |
305 | 81174dae | aliguori | } |
306 | 81174dae | aliguori | } |
307 | 81174dae | aliguori | |
308 | 81174dae | aliguori | |
309 | 5ec3a23e | Alexander Graf | static void serial_ioport_write(void *opaque, hwaddr addr, uint64_t val, |
310 | 5ec3a23e | Alexander Graf | unsigned size)
|
311 | 80cabfad | bellard | { |
312 | b41a2cd1 | bellard | SerialState *s = opaque; |
313 | 3b46e624 | ths | |
314 | 80cabfad | bellard | addr &= 7;
|
315 | b6601141 | Michal Novotny | DPRINTF("write addr=0x%02x val=0x%02x\n", addr, val);
|
316 | 80cabfad | bellard | switch(addr) {
|
317 | 80cabfad | bellard | default:
|
318 | 80cabfad | bellard | case 0: |
319 | 80cabfad | bellard | if (s->lcr & UART_LCR_DLAB) {
|
320 | 80cabfad | bellard | s->divider = (s->divider & 0xff00) | val;
|
321 | f8d179e3 | bellard | serial_update_parameters(s); |
322 | 80cabfad | bellard | } else {
|
323 | 81174dae | aliguori | s->thr = (uint8_t) val; |
324 | 81174dae | aliguori | if(s->fcr & UART_FCR_FE) {
|
325 | 2f4f22bd | Aurelien Jarno | fifo_put(s, XMIT_FIFO, s->thr); |
326 | 2f4f22bd | Aurelien Jarno | s->thr_ipending = 0;
|
327 | 2f4f22bd | Aurelien Jarno | s->lsr &= ~UART_LSR_TEMT; |
328 | 2f4f22bd | Aurelien Jarno | s->lsr &= ~UART_LSR_THRE; |
329 | 2f4f22bd | Aurelien Jarno | serial_update_irq(s); |
330 | 6936bfe5 | aurel32 | } else {
|
331 | 2f4f22bd | Aurelien Jarno | s->thr_ipending = 0;
|
332 | 2f4f22bd | Aurelien Jarno | s->lsr &= ~UART_LSR_THRE; |
333 | 2f4f22bd | Aurelien Jarno | serial_update_irq(s); |
334 | 6936bfe5 | aurel32 | } |
335 | 81174dae | aliguori | serial_xmit(s); |
336 | 80cabfad | bellard | } |
337 | 80cabfad | bellard | break;
|
338 | 80cabfad | bellard | case 1: |
339 | 80cabfad | bellard | if (s->lcr & UART_LCR_DLAB) {
|
340 | 80cabfad | bellard | s->divider = (s->divider & 0x00ff) | (val << 8); |
341 | f8d179e3 | bellard | serial_update_parameters(s); |
342 | 80cabfad | bellard | } else {
|
343 | 60e336db | bellard | s->ier = val & 0x0f;
|
344 | 81174dae | aliguori | /* If the backend device is a real serial port, turn polling of the modem
|
345 | 81174dae | aliguori | status lines on physical port on or off depending on UART_IER_MSI state */
|
346 | 81174dae | aliguori | if (s->poll_msl >= 0) { |
347 | 81174dae | aliguori | if (s->ier & UART_IER_MSI) {
|
348 | 81174dae | aliguori | s->poll_msl = 1;
|
349 | 81174dae | aliguori | serial_update_msl(s); |
350 | 81174dae | aliguori | } else {
|
351 | 81174dae | aliguori | qemu_del_timer(s->modem_status_poll); |
352 | 81174dae | aliguori | s->poll_msl = 0;
|
353 | 81174dae | aliguori | } |
354 | 81174dae | aliguori | } |
355 | 60e336db | bellard | if (s->lsr & UART_LSR_THRE) {
|
356 | 60e336db | bellard | s->thr_ipending = 1;
|
357 | 81174dae | aliguori | serial_update_irq(s); |
358 | 60e336db | bellard | } |
359 | 80cabfad | bellard | } |
360 | 80cabfad | bellard | break;
|
361 | 80cabfad | bellard | case 2: |
362 | 81174dae | aliguori | val = val & 0xFF;
|
363 | 81174dae | aliguori | |
364 | 81174dae | aliguori | if (s->fcr == val)
|
365 | 81174dae | aliguori | break;
|
366 | 81174dae | aliguori | |
367 | 81174dae | aliguori | /* Did the enable/disable flag change? If so, make sure FIFOs get flushed */
|
368 | 81174dae | aliguori | if ((val ^ s->fcr) & UART_FCR_FE)
|
369 | 81174dae | aliguori | val |= UART_FCR_XFR | UART_FCR_RFR; |
370 | 81174dae | aliguori | |
371 | 81174dae | aliguori | /* FIFO clear */
|
372 | 81174dae | aliguori | |
373 | 81174dae | aliguori | if (val & UART_FCR_RFR) {
|
374 | 81174dae | aliguori | qemu_del_timer(s->fifo_timeout_timer); |
375 | 81174dae | aliguori | s->timeout_ipending=0;
|
376 | 81174dae | aliguori | fifo_clear(s,RECV_FIFO); |
377 | 81174dae | aliguori | } |
378 | 81174dae | aliguori | |
379 | 81174dae | aliguori | if (val & UART_FCR_XFR) {
|
380 | 81174dae | aliguori | fifo_clear(s,XMIT_FIFO); |
381 | 81174dae | aliguori | } |
382 | 81174dae | aliguori | |
383 | 81174dae | aliguori | if (val & UART_FCR_FE) {
|
384 | 81174dae | aliguori | s->iir |= UART_IIR_FE; |
385 | 81174dae | aliguori | /* Set RECV_FIFO trigger Level */
|
386 | 81174dae | aliguori | switch (val & 0xC0) { |
387 | 81174dae | aliguori | case UART_FCR_ITL_1:
|
388 | 81174dae | aliguori | s->recv_fifo.itl = 1;
|
389 | 81174dae | aliguori | break;
|
390 | 81174dae | aliguori | case UART_FCR_ITL_2:
|
391 | 81174dae | aliguori | s->recv_fifo.itl = 4;
|
392 | 81174dae | aliguori | break;
|
393 | 81174dae | aliguori | case UART_FCR_ITL_3:
|
394 | 81174dae | aliguori | s->recv_fifo.itl = 8;
|
395 | 81174dae | aliguori | break;
|
396 | 81174dae | aliguori | case UART_FCR_ITL_4:
|
397 | 81174dae | aliguori | s->recv_fifo.itl = 14;
|
398 | 81174dae | aliguori | break;
|
399 | 81174dae | aliguori | } |
400 | 81174dae | aliguori | } else
|
401 | 81174dae | aliguori | s->iir &= ~UART_IIR_FE; |
402 | 81174dae | aliguori | |
403 | 81174dae | aliguori | /* Set fcr - or at least the bits in it that are supposed to "stick" */
|
404 | 81174dae | aliguori | s->fcr = val & 0xC9;
|
405 | 81174dae | aliguori | serial_update_irq(s); |
406 | 80cabfad | bellard | break;
|
407 | 80cabfad | bellard | case 3: |
408 | f8d179e3 | bellard | { |
409 | f8d179e3 | bellard | int break_enable;
|
410 | f8d179e3 | bellard | s->lcr = val; |
411 | f8d179e3 | bellard | serial_update_parameters(s); |
412 | f8d179e3 | bellard | break_enable = (val >> 6) & 1; |
413 | f8d179e3 | bellard | if (break_enable != s->last_break_enable) {
|
414 | f8d179e3 | bellard | s->last_break_enable = break_enable; |
415 | 41084f1b | Anthony Liguori | qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK, |
416 | 2122c51a | bellard | &break_enable); |
417 | f8d179e3 | bellard | } |
418 | f8d179e3 | bellard | } |
419 | 80cabfad | bellard | break;
|
420 | 80cabfad | bellard | case 4: |
421 | 81174dae | aliguori | { |
422 | 81174dae | aliguori | int flags;
|
423 | 81174dae | aliguori | int old_mcr = s->mcr;
|
424 | 81174dae | aliguori | s->mcr = val & 0x1f;
|
425 | 81174dae | aliguori | if (val & UART_MCR_LOOP)
|
426 | 81174dae | aliguori | break;
|
427 | 81174dae | aliguori | |
428 | 81174dae | aliguori | if (s->poll_msl >= 0 && old_mcr != s->mcr) { |
429 | 81174dae | aliguori | |
430 | 41084f1b | Anthony Liguori | qemu_chr_fe_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags); |
431 | 81174dae | aliguori | |
432 | 81174dae | aliguori | flags &= ~(CHR_TIOCM_RTS | CHR_TIOCM_DTR); |
433 | 81174dae | aliguori | |
434 | 81174dae | aliguori | if (val & UART_MCR_RTS)
|
435 | 81174dae | aliguori | flags |= CHR_TIOCM_RTS; |
436 | 81174dae | aliguori | if (val & UART_MCR_DTR)
|
437 | 81174dae | aliguori | flags |= CHR_TIOCM_DTR; |
438 | 81174dae | aliguori | |
439 | 41084f1b | Anthony Liguori | qemu_chr_fe_ioctl(s->chr,CHR_IOCTL_SERIAL_SET_TIOCM, &flags); |
440 | 81174dae | aliguori | /* Update the modem status after a one-character-send wait-time, since there may be a response
|
441 | 81174dae | aliguori | from the device/computer at the other end of the serial line */
|
442 | 74475455 | Paolo Bonzini | qemu_mod_timer(s->modem_status_poll, qemu_get_clock_ns(vm_clock) + s->char_transmit_time); |
443 | 81174dae | aliguori | } |
444 | 81174dae | aliguori | } |
445 | 80cabfad | bellard | break;
|
446 | 80cabfad | bellard | case 5: |
447 | 80cabfad | bellard | break;
|
448 | 80cabfad | bellard | case 6: |
449 | 80cabfad | bellard | break;
|
450 | 80cabfad | bellard | case 7: |
451 | 80cabfad | bellard | s->scr = val; |
452 | 80cabfad | bellard | break;
|
453 | 80cabfad | bellard | } |
454 | 80cabfad | bellard | } |
455 | 80cabfad | bellard | |
456 | 5ec3a23e | Alexander Graf | static uint64_t serial_ioport_read(void *opaque, hwaddr addr, unsigned size) |
457 | 80cabfad | bellard | { |
458 | b41a2cd1 | bellard | SerialState *s = opaque; |
459 | 80cabfad | bellard | uint32_t ret; |
460 | 80cabfad | bellard | |
461 | 80cabfad | bellard | addr &= 7;
|
462 | 80cabfad | bellard | switch(addr) {
|
463 | 80cabfad | bellard | default:
|
464 | 80cabfad | bellard | case 0: |
465 | 80cabfad | bellard | if (s->lcr & UART_LCR_DLAB) {
|
466 | 5fafdf24 | ths | ret = s->divider & 0xff;
|
467 | 80cabfad | bellard | } else {
|
468 | 81174dae | aliguori | if(s->fcr & UART_FCR_FE) {
|
469 | 81174dae | aliguori | ret = fifo_get(s,RECV_FIFO); |
470 | 81174dae | aliguori | if (s->recv_fifo.count == 0) |
471 | 81174dae | aliguori | s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); |
472 | 81174dae | aliguori | else
|
473 | 74475455 | Paolo Bonzini | qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock_ns (vm_clock) + s->char_transmit_time * 4);
|
474 | 81174dae | aliguori | s->timeout_ipending = 0;
|
475 | 81174dae | aliguori | } else {
|
476 | 81174dae | aliguori | ret = s->rbr; |
477 | 81174dae | aliguori | s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); |
478 | 81174dae | aliguori | } |
479 | b41a2cd1 | bellard | serial_update_irq(s); |
480 | b2a5160c | balrog | if (!(s->mcr & UART_MCR_LOOP)) {
|
481 | b2a5160c | balrog | /* in loopback mode, don't receive any data */
|
482 | b2a5160c | balrog | qemu_chr_accept_input(s->chr); |
483 | b2a5160c | balrog | } |
484 | 80cabfad | bellard | } |
485 | 80cabfad | bellard | break;
|
486 | 80cabfad | bellard | case 1: |
487 | 80cabfad | bellard | if (s->lcr & UART_LCR_DLAB) {
|
488 | 80cabfad | bellard | ret = (s->divider >> 8) & 0xff; |
489 | 80cabfad | bellard | } else {
|
490 | 80cabfad | bellard | ret = s->ier; |
491 | 80cabfad | bellard | } |
492 | 80cabfad | bellard | break;
|
493 | 80cabfad | bellard | case 2: |
494 | 80cabfad | bellard | ret = s->iir; |
495 | cdee7bdf | Aurelien Jarno | if ((ret & UART_IIR_ID) == UART_IIR_THRI) {
|
496 | 80cabfad | bellard | s->thr_ipending = 0;
|
497 | 71e605f8 | Justin T. Gibbs | serial_update_irq(s); |
498 | 71e605f8 | Justin T. Gibbs | } |
499 | 80cabfad | bellard | break;
|
500 | 80cabfad | bellard | case 3: |
501 | 80cabfad | bellard | ret = s->lcr; |
502 | 80cabfad | bellard | break;
|
503 | 80cabfad | bellard | case 4: |
504 | 80cabfad | bellard | ret = s->mcr; |
505 | 80cabfad | bellard | break;
|
506 | 80cabfad | bellard | case 5: |
507 | 80cabfad | bellard | ret = s->lsr; |
508 | 71e605f8 | Justin T. Gibbs | /* Clear break and overrun interrupts */
|
509 | 71e605f8 | Justin T. Gibbs | if (s->lsr & (UART_LSR_BI|UART_LSR_OE)) {
|
510 | 71e605f8 | Justin T. Gibbs | s->lsr &= ~(UART_LSR_BI|UART_LSR_OE); |
511 | 81174dae | aliguori | serial_update_irq(s); |
512 | 81174dae | aliguori | } |
513 | 80cabfad | bellard | break;
|
514 | 80cabfad | bellard | case 6: |
515 | 80cabfad | bellard | if (s->mcr & UART_MCR_LOOP) {
|
516 | 80cabfad | bellard | /* in loopback, the modem output pins are connected to the
|
517 | 80cabfad | bellard | inputs */
|
518 | 80cabfad | bellard | ret = (s->mcr & 0x0c) << 4; |
519 | 80cabfad | bellard | ret |= (s->mcr & 0x02) << 3; |
520 | 80cabfad | bellard | ret |= (s->mcr & 0x01) << 5; |
521 | 80cabfad | bellard | } else {
|
522 | 81174dae | aliguori | if (s->poll_msl >= 0) |
523 | 81174dae | aliguori | serial_update_msl(s); |
524 | 80cabfad | bellard | ret = s->msr; |
525 | 81174dae | aliguori | /* Clear delta bits & msr int after read, if they were set */
|
526 | 81174dae | aliguori | if (s->msr & UART_MSR_ANY_DELTA) {
|
527 | 81174dae | aliguori | s->msr &= 0xF0;
|
528 | 81174dae | aliguori | serial_update_irq(s); |
529 | 81174dae | aliguori | } |
530 | 80cabfad | bellard | } |
531 | 80cabfad | bellard | break;
|
532 | 80cabfad | bellard | case 7: |
533 | 80cabfad | bellard | ret = s->scr; |
534 | 80cabfad | bellard | break;
|
535 | 80cabfad | bellard | } |
536 | b6601141 | Michal Novotny | DPRINTF("read addr=0x%02x val=0x%02x\n", addr, ret);
|
537 | 80cabfad | bellard | return ret;
|
538 | 80cabfad | bellard | } |
539 | 80cabfad | bellard | |
540 | 82c643ff | bellard | static int serial_can_receive(SerialState *s) |
541 | 80cabfad | bellard | { |
542 | 81174dae | aliguori | if(s->fcr & UART_FCR_FE) {
|
543 | 81174dae | aliguori | if(s->recv_fifo.count < UART_FIFO_LENGTH)
|
544 | 81174dae | aliguori | /* Advertise (fifo.itl - fifo.count) bytes when count < ITL, and 1 if above. If UART_FIFO_LENGTH - fifo.count is
|
545 | 81174dae | aliguori | advertised the effect will be to almost always fill the fifo completely before the guest has a chance to respond,
|
546 | 81174dae | aliguori | effectively overriding the ITL that the guest has set. */
|
547 | 81174dae | aliguori | return (s->recv_fifo.count <= s->recv_fifo.itl) ? s->recv_fifo.itl - s->recv_fifo.count : 1; |
548 | 81174dae | aliguori | else
|
549 | 81174dae | aliguori | return 0; |
550 | 81174dae | aliguori | } else {
|
551 | 80cabfad | bellard | return !(s->lsr & UART_LSR_DR);
|
552 | 81174dae | aliguori | } |
553 | 80cabfad | bellard | } |
554 | 80cabfad | bellard | |
555 | 82c643ff | bellard | static void serial_receive_break(SerialState *s) |
556 | 80cabfad | bellard | { |
557 | 80cabfad | bellard | s->rbr = 0;
|
558 | 40ff1624 | Jason Wessel | /* When the LSR_DR is set a null byte is pushed into the fifo */
|
559 | 40ff1624 | Jason Wessel | fifo_put(s, RECV_FIFO, '\0');
|
560 | 80cabfad | bellard | s->lsr |= UART_LSR_BI | UART_LSR_DR; |
561 | b41a2cd1 | bellard | serial_update_irq(s); |
562 | 80cabfad | bellard | } |
563 | 80cabfad | bellard | |
564 | 81174dae | aliguori | /* There's data in recv_fifo and s->rbr has not been read for 4 char transmit times */
|
565 | 81174dae | aliguori | static void fifo_timeout_int (void *opaque) { |
566 | 81174dae | aliguori | SerialState *s = opaque; |
567 | 81174dae | aliguori | if (s->recv_fifo.count) {
|
568 | 81174dae | aliguori | s->timeout_ipending = 1;
|
569 | 81174dae | aliguori | serial_update_irq(s); |
570 | 81174dae | aliguori | } |
571 | 81174dae | aliguori | } |
572 | 81174dae | aliguori | |
573 | b41a2cd1 | bellard | static int serial_can_receive1(void *opaque) |
574 | 80cabfad | bellard | { |
575 | b41a2cd1 | bellard | SerialState *s = opaque; |
576 | b41a2cd1 | bellard | return serial_can_receive(s);
|
577 | b41a2cd1 | bellard | } |
578 | b41a2cd1 | bellard | |
579 | b41a2cd1 | bellard | static void serial_receive1(void *opaque, const uint8_t *buf, int size) |
580 | b41a2cd1 | bellard | { |
581 | b41a2cd1 | bellard | SerialState *s = opaque; |
582 | 9826fd59 | Gerd Hoffmann | |
583 | 9826fd59 | Gerd Hoffmann | if (s->wakeup) {
|
584 | 9826fd59 | Gerd Hoffmann | qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); |
585 | 9826fd59 | Gerd Hoffmann | } |
586 | 81174dae | aliguori | if(s->fcr & UART_FCR_FE) {
|
587 | 81174dae | aliguori | int i;
|
588 | 81174dae | aliguori | for (i = 0; i < size; i++) { |
589 | 81174dae | aliguori | fifo_put(s, RECV_FIFO, buf[i]); |
590 | 81174dae | aliguori | } |
591 | 81174dae | aliguori | s->lsr |= UART_LSR_DR; |
592 | 81174dae | aliguori | /* call the timeout receive callback in 4 char transmit time */
|
593 | 74475455 | Paolo Bonzini | qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock_ns (vm_clock) + s->char_transmit_time * 4);
|
594 | 81174dae | aliguori | } else {
|
595 | 71e605f8 | Justin T. Gibbs | if (s->lsr & UART_LSR_DR)
|
596 | 71e605f8 | Justin T. Gibbs | s->lsr |= UART_LSR_OE; |
597 | 81174dae | aliguori | s->rbr = buf[0];
|
598 | 81174dae | aliguori | s->lsr |= UART_LSR_DR; |
599 | 81174dae | aliguori | } |
600 | 81174dae | aliguori | serial_update_irq(s); |
601 | b41a2cd1 | bellard | } |
602 | 80cabfad | bellard | |
603 | 82c643ff | bellard | static void serial_event(void *opaque, int event) |
604 | 82c643ff | bellard | { |
605 | 82c643ff | bellard | SerialState *s = opaque; |
606 | b6601141 | Michal Novotny | DPRINTF("event %x\n", event);
|
607 | 82c643ff | bellard | if (event == CHR_EVENT_BREAK)
|
608 | 82c643ff | bellard | serial_receive_break(s); |
609 | 82c643ff | bellard | } |
610 | 82c643ff | bellard | |
611 | d4bfa4d7 | Juan Quintela | static void serial_pre_save(void *opaque) |
612 | 8738a8d0 | bellard | { |
613 | d4bfa4d7 | Juan Quintela | SerialState *s = opaque; |
614 | 747791f1 | Juan Quintela | s->fcr_vmstate = s->fcr; |
615 | 8738a8d0 | bellard | } |
616 | 8738a8d0 | bellard | |
617 | e59fb374 | Juan Quintela | static int serial_post_load(void *opaque, int version_id) |
618 | 747791f1 | Juan Quintela | { |
619 | 747791f1 | Juan Quintela | SerialState *s = opaque; |
620 | 81174dae | aliguori | |
621 | 4c18ce94 | Juan Quintela | if (version_id < 3) { |
622 | 4c18ce94 | Juan Quintela | s->fcr_vmstate = 0;
|
623 | 4c18ce94 | Juan Quintela | } |
624 | 81174dae | aliguori | /* Initialize fcr via setter to perform essential side-effects */
|
625 | 5ec3a23e | Alexander Graf | serial_ioport_write(s, 0x02, s->fcr_vmstate, 1); |
626 | 9a7c4878 | Michal Novotny | serial_update_parameters(s); |
627 | 8738a8d0 | bellard | return 0; |
628 | 8738a8d0 | bellard | } |
629 | 8738a8d0 | bellard | |
630 | 488cb996 | Gerd Hoffmann | const VMStateDescription vmstate_serial = {
|
631 | 747791f1 | Juan Quintela | .name = "serial",
|
632 | 747791f1 | Juan Quintela | .version_id = 3,
|
633 | 747791f1 | Juan Quintela | .minimum_version_id = 2,
|
634 | 747791f1 | Juan Quintela | .pre_save = serial_pre_save, |
635 | 747791f1 | Juan Quintela | .post_load = serial_post_load, |
636 | 747791f1 | Juan Quintela | .fields = (VMStateField []) { |
637 | 747791f1 | Juan Quintela | VMSTATE_UINT16_V(divider, SerialState, 2),
|
638 | 747791f1 | Juan Quintela | VMSTATE_UINT8(rbr, SerialState), |
639 | 747791f1 | Juan Quintela | VMSTATE_UINT8(ier, SerialState), |
640 | 747791f1 | Juan Quintela | VMSTATE_UINT8(iir, SerialState), |
641 | 747791f1 | Juan Quintela | VMSTATE_UINT8(lcr, SerialState), |
642 | 747791f1 | Juan Quintela | VMSTATE_UINT8(mcr, SerialState), |
643 | 747791f1 | Juan Quintela | VMSTATE_UINT8(lsr, SerialState), |
644 | 747791f1 | Juan Quintela | VMSTATE_UINT8(msr, SerialState), |
645 | 747791f1 | Juan Quintela | VMSTATE_UINT8(scr, SerialState), |
646 | 747791f1 | Juan Quintela | VMSTATE_UINT8_V(fcr_vmstate, SerialState, 3),
|
647 | 747791f1 | Juan Quintela | VMSTATE_END_OF_LIST() |
648 | 747791f1 | Juan Quintela | } |
649 | 747791f1 | Juan Quintela | }; |
650 | 747791f1 | Juan Quintela | |
651 | b2a5160c | balrog | static void serial_reset(void *opaque) |
652 | b2a5160c | balrog | { |
653 | b2a5160c | balrog | SerialState *s = opaque; |
654 | b2a5160c | balrog | |
655 | b2a5160c | balrog | s->rbr = 0;
|
656 | b2a5160c | balrog | s->ier = 0;
|
657 | b2a5160c | balrog | s->iir = UART_IIR_NO_INT; |
658 | b2a5160c | balrog | s->lcr = 0;
|
659 | b2a5160c | balrog | s->lsr = UART_LSR_TEMT | UART_LSR_THRE; |
660 | b2a5160c | balrog | s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS; |
661 | 718b8aec | Stefan Weil | /* Default to 9600 baud, 1 start bit, 8 data bits, 1 stop bit, no parity. */
|
662 | 81174dae | aliguori | s->divider = 0x0C;
|
663 | 81174dae | aliguori | s->mcr = UART_MCR_OUT2; |
664 | b2a5160c | balrog | s->scr = 0;
|
665 | 81174dae | aliguori | s->tsr_retry = 0;
|
666 | 718b8aec | Stefan Weil | s->char_transmit_time = (get_ticks_per_sec() / 9600) * 10; |
667 | 81174dae | aliguori | s->poll_msl = 0;
|
668 | 81174dae | aliguori | |
669 | 81174dae | aliguori | fifo_clear(s,RECV_FIFO); |
670 | 81174dae | aliguori | fifo_clear(s,XMIT_FIFO); |
671 | 81174dae | aliguori | |
672 | 74475455 | Paolo Bonzini | s->last_xmit_ts = qemu_get_clock_ns(vm_clock); |
673 | b2a5160c | balrog | |
674 | b2a5160c | balrog | s->thr_ipending = 0;
|
675 | b2a5160c | balrog | s->last_break_enable = 0;
|
676 | b2a5160c | balrog | qemu_irq_lower(s->irq); |
677 | b2a5160c | balrog | } |
678 | b2a5160c | balrog | |
679 | 488cb996 | Gerd Hoffmann | void serial_init_core(SerialState *s)
|
680 | 81174dae | aliguori | { |
681 | ac0be998 | Gerd Hoffmann | if (!s->chr) {
|
682 | 387f4a5a | Aurelien Jarno | fprintf(stderr, "Can't create serial device, empty char device\n");
|
683 | 387f4a5a | Aurelien Jarno | exit(1);
|
684 | 387f4a5a | Aurelien Jarno | } |
685 | 387f4a5a | Aurelien Jarno | |
686 | 74475455 | Paolo Bonzini | s->modem_status_poll = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) serial_update_msl, s); |
687 | 81174dae | aliguori | |
688 | 74475455 | Paolo Bonzini | s->fifo_timeout_timer = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) fifo_timeout_int, s); |
689 | 74475455 | Paolo Bonzini | s->transmit_timer = qemu_new_timer_ns(vm_clock, (QEMUTimerCB *) serial_xmit, s); |
690 | 81174dae | aliguori | |
691 | a08d4367 | Jan Kiszka | qemu_register_reset(serial_reset, s); |
692 | 81174dae | aliguori | |
693 | b47543c4 | aurel32 | qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1, |
694 | b47543c4 | aurel32 | serial_event, s); |
695 | 81174dae | aliguori | } |
696 | 81174dae | aliguori | |
697 | 419ad672 | Gerd Hoffmann | void serial_exit_core(SerialState *s)
|
698 | 419ad672 | Gerd Hoffmann | { |
699 | 419ad672 | Gerd Hoffmann | qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, NULL); |
700 | 419ad672 | Gerd Hoffmann | qemu_unregister_reset(serial_reset, s); |
701 | 419ad672 | Gerd Hoffmann | } |
702 | 419ad672 | Gerd Hoffmann | |
703 | 038eaf82 | Stefan Weil | /* Change the main reference oscillator frequency. */
|
704 | 038eaf82 | Stefan Weil | void serial_set_frequency(SerialState *s, uint32_t frequency)
|
705 | 038eaf82 | Stefan Weil | { |
706 | 038eaf82 | Stefan Weil | s->baudbase = frequency; |
707 | 038eaf82 | Stefan Weil | serial_update_parameters(s); |
708 | 038eaf82 | Stefan Weil | } |
709 | 038eaf82 | Stefan Weil | |
710 | 488cb996 | Gerd Hoffmann | const MemoryRegionOps serial_io_ops = {
|
711 | 5ec3a23e | Alexander Graf | .read = serial_ioport_read, |
712 | 5ec3a23e | Alexander Graf | .write = serial_ioport_write, |
713 | 5ec3a23e | Alexander Graf | .impl = { |
714 | 5ec3a23e | Alexander Graf | .min_access_size = 1,
|
715 | 5ec3a23e | Alexander Graf | .max_access_size = 1,
|
716 | 5ec3a23e | Alexander Graf | }, |
717 | 5ec3a23e | Alexander Graf | .endianness = DEVICE_LITTLE_ENDIAN, |
718 | a941ae45 | Richard Henderson | }; |
719 | a941ae45 | Richard Henderson | |
720 | b6cd0ea1 | aurel32 | SerialState *serial_init(int base, qemu_irq irq, int baudbase, |
721 | 568fd159 | Julien Grall | CharDriverState *chr, MemoryRegion *system_io) |
722 | b41a2cd1 | bellard | { |
723 | b41a2cd1 | bellard | SerialState *s; |
724 | b41a2cd1 | bellard | |
725 | 7267c094 | Anthony Liguori | s = g_malloc0(sizeof(SerialState));
|
726 | 6936bfe5 | aurel32 | |
727 | ac0be998 | Gerd Hoffmann | s->irq = irq; |
728 | ac0be998 | Gerd Hoffmann | s->baudbase = baudbase; |
729 | ac0be998 | Gerd Hoffmann | s->chr = chr; |
730 | ac0be998 | Gerd Hoffmann | serial_init_core(s); |
731 | b41a2cd1 | bellard | |
732 | 0be71e32 | Alex Williamson | vmstate_register(NULL, base, &vmstate_serial, s);
|
733 | 8738a8d0 | bellard | |
734 | 5ec3a23e | Alexander Graf | memory_region_init_io(&s->io, &serial_io_ops, s, "serial", 8); |
735 | 568fd159 | Julien Grall | memory_region_add_subregion(system_io, base, &s->io); |
736 | 5ec3a23e | Alexander Graf | |
737 | b41a2cd1 | bellard | return s;
|
738 | 80cabfad | bellard | } |
739 | e5d13e2f | bellard | |
740 | e5d13e2f | bellard | /* Memory mapped interface */
|
741 | a8170e5e | Avi Kivity | static uint64_t serial_mm_read(void *opaque, hwaddr addr, |
742 | 8e8ffc44 | Richard Henderson | unsigned size)
|
743 | e5d13e2f | bellard | { |
744 | e5d13e2f | bellard | SerialState *s = opaque; |
745 | 5ec3a23e | Alexander Graf | return serial_ioport_read(s, addr >> s->it_shift, 1); |
746 | e5d13e2f | bellard | } |
747 | e5d13e2f | bellard | |
748 | a8170e5e | Avi Kivity | static void serial_mm_write(void *opaque, hwaddr addr, |
749 | 8e8ffc44 | Richard Henderson | uint64_t value, unsigned size)
|
750 | 2d48377a | Blue Swirl | { |
751 | 2d48377a | Blue Swirl | SerialState *s = opaque; |
752 | 8e8ffc44 | Richard Henderson | value &= ~0u >> (32 - (size * 8)); |
753 | 5ec3a23e | Alexander Graf | serial_ioport_write(s, addr >> s->it_shift, value, 1);
|
754 | 2d48377a | Blue Swirl | } |
755 | 2d48377a | Blue Swirl | |
756 | 8e8ffc44 | Richard Henderson | static const MemoryRegionOps serial_mm_ops[3] = { |
757 | 8e8ffc44 | Richard Henderson | [DEVICE_NATIVE_ENDIAN] = { |
758 | 8e8ffc44 | Richard Henderson | .read = serial_mm_read, |
759 | 8e8ffc44 | Richard Henderson | .write = serial_mm_write, |
760 | 8e8ffc44 | Richard Henderson | .endianness = DEVICE_NATIVE_ENDIAN, |
761 | 8e8ffc44 | Richard Henderson | }, |
762 | 8e8ffc44 | Richard Henderson | [DEVICE_LITTLE_ENDIAN] = { |
763 | 8e8ffc44 | Richard Henderson | .read = serial_mm_read, |
764 | 8e8ffc44 | Richard Henderson | .write = serial_mm_write, |
765 | 8e8ffc44 | Richard Henderson | .endianness = DEVICE_LITTLE_ENDIAN, |
766 | 8e8ffc44 | Richard Henderson | }, |
767 | 8e8ffc44 | Richard Henderson | [DEVICE_BIG_ENDIAN] = { |
768 | 8e8ffc44 | Richard Henderson | .read = serial_mm_read, |
769 | 8e8ffc44 | Richard Henderson | .write = serial_mm_write, |
770 | 8e8ffc44 | Richard Henderson | .endianness = DEVICE_BIG_ENDIAN, |
771 | 8e8ffc44 | Richard Henderson | }, |
772 | e5d13e2f | bellard | }; |
773 | e5d13e2f | bellard | |
774 | 39186d8a | Richard Henderson | SerialState *serial_mm_init(MemoryRegion *address_space, |
775 | a8170e5e | Avi Kivity | hwaddr base, int it_shift,
|
776 | 39186d8a | Richard Henderson | qemu_irq irq, int baudbase,
|
777 | 39186d8a | Richard Henderson | CharDriverState *chr, enum device_endian end)
|
778 | e5d13e2f | bellard | { |
779 | e5d13e2f | bellard | SerialState *s; |
780 | e5d13e2f | bellard | |
781 | 7267c094 | Anthony Liguori | s = g_malloc0(sizeof(SerialState));
|
782 | 81174dae | aliguori | |
783 | e5d13e2f | bellard | s->it_shift = it_shift; |
784 | ac0be998 | Gerd Hoffmann | s->irq = irq; |
785 | ac0be998 | Gerd Hoffmann | s->baudbase = baudbase; |
786 | ac0be998 | Gerd Hoffmann | s->chr = chr; |
787 | e5d13e2f | bellard | |
788 | ac0be998 | Gerd Hoffmann | serial_init_core(s); |
789 | 0be71e32 | Alex Williamson | vmstate_register(NULL, base, &vmstate_serial, s);
|
790 | e5d13e2f | bellard | |
791 | 8e8ffc44 | Richard Henderson | memory_region_init_io(&s->io, &serial_mm_ops[end], s, |
792 | 8e8ffc44 | Richard Henderson | "serial", 8 << it_shift); |
793 | 39186d8a | Richard Henderson | memory_region_add_subregion(address_space, base, &s->io); |
794 | 2ff0c7c3 | Richard Henderson | |
795 | 81174dae | aliguori | serial_update_msl(s); |
796 | e5d13e2f | bellard | return s;
|
797 | e5d13e2f | bellard | } |