root / hw / serial.c @ b8c18e4c
History | View | Annotate | Download (24.5 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 | 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 UART_FIFO_LENGTH 16 /* 16550A Fifo Length */ |
96 | 81174dae | aliguori | |
97 | 81174dae | aliguori | #define XMIT_FIFO 0 |
98 | 81174dae | aliguori | #define RECV_FIFO 1 |
99 | 81174dae | aliguori | #define MAX_XMIT_RETRY 4 |
100 | 81174dae | aliguori | |
101 | 81174dae | aliguori | struct SerialFIFO {
|
102 | 81174dae | aliguori | uint8_t data[UART_FIFO_LENGTH]; |
103 | 81174dae | aliguori | uint8_t count; |
104 | 81174dae | aliguori | uint8_t itl; /* Interrupt Trigger Level */
|
105 | 81174dae | aliguori | uint8_t tail; |
106 | 81174dae | aliguori | uint8_t head; |
107 | 81174dae | aliguori | } typedef SerialFIFO;
|
108 | 6936bfe5 | aurel32 | |
109 | b41a2cd1 | bellard | struct SerialState {
|
110 | 508d92d0 | bellard | uint16_t divider; |
111 | 80cabfad | bellard | uint8_t rbr; /* receive register */
|
112 | 81174dae | aliguori | uint8_t thr; /* transmit holding register */
|
113 | 81174dae | aliguori | uint8_t tsr; /* transmit shift register */
|
114 | 80cabfad | bellard | uint8_t ier; |
115 | 80cabfad | bellard | uint8_t iir; /* read only */
|
116 | 80cabfad | bellard | uint8_t lcr; |
117 | 80cabfad | bellard | uint8_t mcr; |
118 | 80cabfad | bellard | uint8_t lsr; /* read only */
|
119 | 3e749fe1 | bellard | uint8_t msr; /* read only */
|
120 | 80cabfad | bellard | uint8_t scr; |
121 | 81174dae | aliguori | uint8_t fcr; |
122 | 80cabfad | bellard | /* NOTE: this hidden state is necessary for tx irq generation as
|
123 | 80cabfad | bellard | it can be reset while reading iir */
|
124 | 80cabfad | bellard | int thr_ipending;
|
125 | d537cf6c | pbrook | qemu_irq irq; |
126 | 82c643ff | bellard | CharDriverState *chr; |
127 | f8d179e3 | bellard | int last_break_enable;
|
128 | e5d13e2f | bellard | int it_shift;
|
129 | b6cd0ea1 | aurel32 | int baudbase;
|
130 | 81174dae | aliguori | int tsr_retry;
|
131 | 81174dae | aliguori | |
132 | 81174dae | aliguori | uint64_t last_xmit_ts; /* Time when the last byte was successfully sent out of the tsr */
|
133 | 81174dae | aliguori | SerialFIFO recv_fifo; |
134 | 81174dae | aliguori | SerialFIFO xmit_fifo; |
135 | 81174dae | aliguori | |
136 | 81174dae | aliguori | struct QEMUTimer *fifo_timeout_timer;
|
137 | 81174dae | aliguori | int timeout_ipending; /* timeout interrupt pending state */ |
138 | 81174dae | aliguori | struct QEMUTimer *transmit_timer;
|
139 | 81174dae | aliguori | |
140 | 81174dae | aliguori | |
141 | 81174dae | aliguori | uint64_t char_transmit_time; /* time to transmit a char in ticks*/
|
142 | 81174dae | aliguori | int poll_msl;
|
143 | 81174dae | aliguori | |
144 | 81174dae | aliguori | struct QEMUTimer *modem_status_poll;
|
145 | b41a2cd1 | bellard | }; |
146 | 80cabfad | bellard | |
147 | 81174dae | aliguori | static void serial_receive1(void *opaque, const uint8_t *buf, int size); |
148 | b2a5160c | balrog | |
149 | 81174dae | aliguori | static void fifo_clear(SerialState *s, int fifo) |
150 | 80cabfad | bellard | { |
151 | 81174dae | aliguori | SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo; |
152 | 81174dae | aliguori | memset(f->data, 0, UART_FIFO_LENGTH);
|
153 | 81174dae | aliguori | f->count = 0;
|
154 | 81174dae | aliguori | f->head = 0;
|
155 | 81174dae | aliguori | f->tail = 0;
|
156 | 80cabfad | bellard | } |
157 | 80cabfad | bellard | |
158 | 81174dae | aliguori | static int fifo_put(SerialState *s, int fifo, uint8_t chr) |
159 | 6936bfe5 | aurel32 | { |
160 | 81174dae | aliguori | SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo; |
161 | 6936bfe5 | aurel32 | |
162 | 81174dae | aliguori | f->data[f->head++] = chr; |
163 | 6936bfe5 | aurel32 | |
164 | 81174dae | aliguori | if (f->head == UART_FIFO_LENGTH)
|
165 | 81174dae | aliguori | f->head = 0;
|
166 | 81174dae | aliguori | f->count++; |
167 | 81174dae | aliguori | |
168 | 81174dae | aliguori | return 1; |
169 | 81174dae | aliguori | } |
170 | 81174dae | aliguori | |
171 | 81174dae | aliguori | static uint8_t fifo_get(SerialState *s, int fifo) |
172 | 81174dae | aliguori | { |
173 | 81174dae | aliguori | SerialFIFO *f = (fifo) ? &s->recv_fifo : &s->xmit_fifo; |
174 | 81174dae | aliguori | uint8_t c; |
175 | 81174dae | aliguori | |
176 | 81174dae | aliguori | if(f->count == 0) |
177 | 81174dae | aliguori | return 0; |
178 | 81174dae | aliguori | |
179 | 81174dae | aliguori | c = f->data[f->tail++]; |
180 | 81174dae | aliguori | if (f->tail == UART_FIFO_LENGTH)
|
181 | 81174dae | aliguori | f->tail = 0;
|
182 | 81174dae | aliguori | f->count--; |
183 | 81174dae | aliguori | |
184 | 81174dae | aliguori | return c;
|
185 | 81174dae | aliguori | } |
186 | 6936bfe5 | aurel32 | |
187 | 81174dae | aliguori | static void serial_update_irq(SerialState *s) |
188 | 81174dae | aliguori | { |
189 | 81174dae | aliguori | uint8_t tmp_iir = UART_IIR_NO_INT; |
190 | 81174dae | aliguori | |
191 | 81174dae | aliguori | if ((s->ier & UART_IER_RLSI) && (s->lsr & UART_LSR_INT_ANY)) {
|
192 | 81174dae | aliguori | tmp_iir = UART_IIR_RLSI; |
193 | 5628a626 | balrog | } else if ((s->ier & UART_IER_RDI) && s->timeout_ipending) { |
194 | c9a33054 | balrog | /* Note that(s->ier & UART_IER_RDI) can mask this interrupt,
|
195 | c9a33054 | balrog | * this is not in the specification but is observed on existing
|
196 | c9a33054 | balrog | * hardware. */
|
197 | 81174dae | aliguori | tmp_iir = UART_IIR_CTI; |
198 | 81174dae | aliguori | } else if ((s->ier & UART_IER_RDI) && (s->lsr & UART_LSR_DR)) { |
199 | 81174dae | aliguori | if (!(s->fcr & UART_FCR_FE)) {
|
200 | 81174dae | aliguori | tmp_iir = UART_IIR_RDI; |
201 | 81174dae | aliguori | } else if (s->recv_fifo.count >= s->recv_fifo.itl) { |
202 | 81174dae | aliguori | tmp_iir = UART_IIR_RDI; |
203 | 81174dae | aliguori | } |
204 | 81174dae | aliguori | } else if ((s->ier & UART_IER_THRI) && s->thr_ipending) { |
205 | 81174dae | aliguori | tmp_iir = UART_IIR_THRI; |
206 | 81174dae | aliguori | } else if ((s->ier & UART_IER_MSI) && (s->msr & UART_MSR_ANY_DELTA)) { |
207 | 81174dae | aliguori | tmp_iir = UART_IIR_MSI; |
208 | 81174dae | aliguori | } |
209 | 81174dae | aliguori | |
210 | 81174dae | aliguori | s->iir = tmp_iir | (s->iir & 0xF0);
|
211 | 81174dae | aliguori | |
212 | 81174dae | aliguori | if (tmp_iir != UART_IIR_NO_INT) {
|
213 | 81174dae | aliguori | qemu_irq_raise(s->irq); |
214 | 81174dae | aliguori | } else {
|
215 | 81174dae | aliguori | qemu_irq_lower(s->irq); |
216 | 6936bfe5 | aurel32 | } |
217 | 6936bfe5 | aurel32 | } |
218 | 6936bfe5 | aurel32 | |
219 | f8d179e3 | bellard | static void serial_update_parameters(SerialState *s) |
220 | f8d179e3 | bellard | { |
221 | 81174dae | aliguori | int speed, parity, data_bits, stop_bits, frame_size;
|
222 | 2122c51a | bellard | QEMUSerialSetParams ssp; |
223 | f8d179e3 | bellard | |
224 | 81174dae | aliguori | if (s->divider == 0) |
225 | 81174dae | aliguori | return;
|
226 | 81174dae | aliguori | |
227 | 81174dae | aliguori | frame_size = 1;
|
228 | f8d179e3 | bellard | if (s->lcr & 0x08) { |
229 | f8d179e3 | bellard | if (s->lcr & 0x10) |
230 | f8d179e3 | bellard | parity = 'E';
|
231 | f8d179e3 | bellard | else
|
232 | f8d179e3 | bellard | parity = 'O';
|
233 | f8d179e3 | bellard | } else {
|
234 | f8d179e3 | bellard | parity = 'N';
|
235 | 81174dae | aliguori | frame_size = 0;
|
236 | f8d179e3 | bellard | } |
237 | 5fafdf24 | ths | if (s->lcr & 0x04) |
238 | f8d179e3 | bellard | stop_bits = 2;
|
239 | f8d179e3 | bellard | else
|
240 | f8d179e3 | bellard | stop_bits = 1;
|
241 | 81174dae | aliguori | |
242 | f8d179e3 | bellard | data_bits = (s->lcr & 0x03) + 5; |
243 | 81174dae | aliguori | frame_size += data_bits + stop_bits; |
244 | b6cd0ea1 | aurel32 | speed = s->baudbase / s->divider; |
245 | 2122c51a | bellard | ssp.speed = speed; |
246 | 2122c51a | bellard | ssp.parity = parity; |
247 | 2122c51a | bellard | ssp.data_bits = data_bits; |
248 | 2122c51a | bellard | ssp.stop_bits = stop_bits; |
249 | 81174dae | aliguori | s->char_transmit_time = (ticks_per_sec / speed) * frame_size; |
250 | 2122c51a | bellard | qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); |
251 | 2122c51a | bellard | #if 0
|
252 | 5fafdf24 | ths | printf("speed=%d parity=%c data=%d stop=%d\n",
|
253 | f8d179e3 | bellard | speed, parity, data_bits, stop_bits);
|
254 | f8d179e3 | bellard | #endif
|
255 | f8d179e3 | bellard | } |
256 | f8d179e3 | bellard | |
257 | 81174dae | aliguori | static void serial_update_msl(SerialState *s) |
258 | 81174dae | aliguori | { |
259 | 81174dae | aliguori | uint8_t omsr; |
260 | 81174dae | aliguori | int flags;
|
261 | 81174dae | aliguori | |
262 | 81174dae | aliguori | qemu_del_timer(s->modem_status_poll); |
263 | 81174dae | aliguori | |
264 | 81174dae | aliguori | if (qemu_chr_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP) {
|
265 | 81174dae | aliguori | s->poll_msl = -1;
|
266 | 81174dae | aliguori | return;
|
267 | 81174dae | aliguori | } |
268 | 81174dae | aliguori | |
269 | 81174dae | aliguori | omsr = s->msr; |
270 | 81174dae | aliguori | |
271 | 81174dae | aliguori | s->msr = (flags & CHR_TIOCM_CTS) ? s->msr | UART_MSR_CTS : s->msr & ~UART_MSR_CTS; |
272 | 81174dae | aliguori | s->msr = (flags & CHR_TIOCM_DSR) ? s->msr | UART_MSR_DSR : s->msr & ~UART_MSR_DSR; |
273 | 81174dae | aliguori | s->msr = (flags & CHR_TIOCM_CAR) ? s->msr | UART_MSR_DCD : s->msr & ~UART_MSR_DCD; |
274 | 81174dae | aliguori | s->msr = (flags & CHR_TIOCM_RI) ? s->msr | UART_MSR_RI : s->msr & ~UART_MSR_RI; |
275 | 81174dae | aliguori | |
276 | 81174dae | aliguori | if (s->msr != omsr) {
|
277 | 81174dae | aliguori | /* Set delta bits */
|
278 | 81174dae | aliguori | s->msr = s->msr | ((s->msr >> 4) ^ (omsr >> 4)); |
279 | 81174dae | aliguori | /* UART_MSR_TERI only if change was from 1 -> 0 */
|
280 | 81174dae | aliguori | if ((s->msr & UART_MSR_TERI) && !(omsr & UART_MSR_RI))
|
281 | 81174dae | aliguori | s->msr &= ~UART_MSR_TERI; |
282 | 81174dae | aliguori | serial_update_irq(s); |
283 | 81174dae | aliguori | } |
284 | 81174dae | aliguori | |
285 | 81174dae | aliguori | /* The real 16550A apparently has a 250ns response latency to line status changes.
|
286 | 81174dae | aliguori | We'll be lazy and poll only every 10ms, and only poll it at all if MSI interrupts are turned on */
|
287 | 81174dae | aliguori | |
288 | 81174dae | aliguori | if (s->poll_msl)
|
289 | 81174dae | aliguori | qemu_mod_timer(s->modem_status_poll, qemu_get_clock(vm_clock) + ticks_per_sec / 100);
|
290 | 81174dae | aliguori | } |
291 | 81174dae | aliguori | |
292 | 81174dae | aliguori | static void serial_xmit(void *opaque) |
293 | 81174dae | aliguori | { |
294 | 81174dae | aliguori | SerialState *s = opaque; |
295 | 81174dae | aliguori | uint64_t new_xmit_ts = qemu_get_clock(vm_clock); |
296 | 81174dae | aliguori | |
297 | 81174dae | aliguori | if (s->tsr_retry <= 0) { |
298 | 81174dae | aliguori | if (s->fcr & UART_FCR_FE) {
|
299 | 81174dae | aliguori | s->tsr = fifo_get(s,XMIT_FIFO); |
300 | 81174dae | aliguori | if (!s->xmit_fifo.count)
|
301 | 81174dae | aliguori | s->lsr |= UART_LSR_THRE; |
302 | 81174dae | aliguori | } else {
|
303 | 81174dae | aliguori | s->tsr = s->thr; |
304 | 81174dae | aliguori | s->lsr |= UART_LSR_THRE; |
305 | 81174dae | aliguori | } |
306 | 81174dae | aliguori | } |
307 | 81174dae | aliguori | |
308 | 81174dae | aliguori | if (s->mcr & UART_MCR_LOOP) {
|
309 | 81174dae | aliguori | /* in loopback mode, say that we just received a char */
|
310 | 81174dae | aliguori | serial_receive1(s, &s->tsr, 1);
|
311 | 81174dae | aliguori | } else if (qemu_chr_write(s->chr, &s->tsr, 1) != 1) { |
312 | 81174dae | aliguori | if ((s->tsr_retry > 0) && (s->tsr_retry <= MAX_XMIT_RETRY)) { |
313 | 81174dae | aliguori | s->tsr_retry++; |
314 | 81174dae | aliguori | qemu_mod_timer(s->transmit_timer, new_xmit_ts + s->char_transmit_time); |
315 | 81174dae | aliguori | return;
|
316 | 81174dae | aliguori | } else if (s->poll_msl < 0) { |
317 | 81174dae | aliguori | /* If we exceed MAX_XMIT_RETRY and the backend is not a real serial port, then
|
318 | 81174dae | aliguori | drop any further failed writes instantly, until we get one that goes through.
|
319 | 81174dae | aliguori | This is to prevent guests that log to unconnected pipes or pty's from stalling. */
|
320 | 81174dae | aliguori | s->tsr_retry = -1;
|
321 | 81174dae | aliguori | } |
322 | 81174dae | aliguori | } |
323 | 81174dae | aliguori | else {
|
324 | 81174dae | aliguori | s->tsr_retry = 0;
|
325 | 81174dae | aliguori | } |
326 | 81174dae | aliguori | |
327 | 81174dae | aliguori | s->last_xmit_ts = qemu_get_clock(vm_clock); |
328 | 81174dae | aliguori | if (!(s->lsr & UART_LSR_THRE))
|
329 | 81174dae | aliguori | qemu_mod_timer(s->transmit_timer, s->last_xmit_ts + s->char_transmit_time); |
330 | 81174dae | aliguori | |
331 | 81174dae | aliguori | if (s->lsr & UART_LSR_THRE) {
|
332 | 81174dae | aliguori | s->lsr |= UART_LSR_TEMT; |
333 | 81174dae | aliguori | s->thr_ipending = 1;
|
334 | 81174dae | aliguori | serial_update_irq(s); |
335 | 81174dae | aliguori | } |
336 | 81174dae | aliguori | } |
337 | 81174dae | aliguori | |
338 | 81174dae | aliguori | |
339 | b41a2cd1 | bellard | static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
340 | 80cabfad | bellard | { |
341 | b41a2cd1 | bellard | SerialState *s = opaque; |
342 | 3b46e624 | ths | |
343 | 80cabfad | bellard | addr &= 7;
|
344 | 80cabfad | bellard | #ifdef DEBUG_SERIAL
|
345 | 80cabfad | bellard | printf("serial: write addr=0x%02x val=0x%02x\n", addr, val);
|
346 | 80cabfad | bellard | #endif
|
347 | 80cabfad | bellard | switch(addr) {
|
348 | 80cabfad | bellard | default:
|
349 | 80cabfad | bellard | case 0: |
350 | 80cabfad | bellard | if (s->lcr & UART_LCR_DLAB) {
|
351 | 80cabfad | bellard | s->divider = (s->divider & 0xff00) | val;
|
352 | f8d179e3 | bellard | serial_update_parameters(s); |
353 | 80cabfad | bellard | } else {
|
354 | 81174dae | aliguori | s->thr = (uint8_t) val; |
355 | 81174dae | aliguori | if(s->fcr & UART_FCR_FE) {
|
356 | 81174dae | aliguori | fifo_put(s, XMIT_FIFO, s->thr); |
357 | 80cabfad | bellard | s->thr_ipending = 0;
|
358 | 81174dae | aliguori | s->lsr &= ~UART_LSR_TEMT; |
359 | 80cabfad | bellard | s->lsr &= ~UART_LSR_THRE; |
360 | b41a2cd1 | bellard | serial_update_irq(s); |
361 | 6936bfe5 | aurel32 | } else {
|
362 | 81174dae | aliguori | s->thr_ipending = 0;
|
363 | 81174dae | aliguori | s->lsr &= ~UART_LSR_THRE; |
364 | 81174dae | aliguori | serial_update_irq(s); |
365 | 6936bfe5 | aurel32 | } |
366 | 81174dae | aliguori | serial_xmit(s); |
367 | 80cabfad | bellard | } |
368 | 80cabfad | bellard | break;
|
369 | 80cabfad | bellard | case 1: |
370 | 80cabfad | bellard | if (s->lcr & UART_LCR_DLAB) {
|
371 | 80cabfad | bellard | s->divider = (s->divider & 0x00ff) | (val << 8); |
372 | f8d179e3 | bellard | serial_update_parameters(s); |
373 | 80cabfad | bellard | } else {
|
374 | 60e336db | bellard | s->ier = val & 0x0f;
|
375 | 81174dae | aliguori | /* If the backend device is a real serial port, turn polling of the modem
|
376 | 81174dae | aliguori | status lines on physical port on or off depending on UART_IER_MSI state */
|
377 | 81174dae | aliguori | if (s->poll_msl >= 0) { |
378 | 81174dae | aliguori | if (s->ier & UART_IER_MSI) {
|
379 | 81174dae | aliguori | s->poll_msl = 1;
|
380 | 81174dae | aliguori | serial_update_msl(s); |
381 | 81174dae | aliguori | } else {
|
382 | 81174dae | aliguori | qemu_del_timer(s->modem_status_poll); |
383 | 81174dae | aliguori | s->poll_msl = 0;
|
384 | 81174dae | aliguori | } |
385 | 81174dae | aliguori | } |
386 | 60e336db | bellard | if (s->lsr & UART_LSR_THRE) {
|
387 | 60e336db | bellard | s->thr_ipending = 1;
|
388 | 81174dae | aliguori | serial_update_irq(s); |
389 | 60e336db | bellard | } |
390 | 80cabfad | bellard | } |
391 | 80cabfad | bellard | break;
|
392 | 80cabfad | bellard | case 2: |
393 | 81174dae | aliguori | val = val & 0xFF;
|
394 | 81174dae | aliguori | |
395 | 81174dae | aliguori | if (s->fcr == val)
|
396 | 81174dae | aliguori | break;
|
397 | 81174dae | aliguori | |
398 | 81174dae | aliguori | /* Did the enable/disable flag change? If so, make sure FIFOs get flushed */
|
399 | 81174dae | aliguori | if ((val ^ s->fcr) & UART_FCR_FE)
|
400 | 81174dae | aliguori | val |= UART_FCR_XFR | UART_FCR_RFR; |
401 | 81174dae | aliguori | |
402 | 81174dae | aliguori | /* FIFO clear */
|
403 | 81174dae | aliguori | |
404 | 81174dae | aliguori | if (val & UART_FCR_RFR) {
|
405 | 81174dae | aliguori | qemu_del_timer(s->fifo_timeout_timer); |
406 | 81174dae | aliguori | s->timeout_ipending=0;
|
407 | 81174dae | aliguori | fifo_clear(s,RECV_FIFO); |
408 | 81174dae | aliguori | } |
409 | 81174dae | aliguori | |
410 | 81174dae | aliguori | if (val & UART_FCR_XFR) {
|
411 | 81174dae | aliguori | fifo_clear(s,XMIT_FIFO); |
412 | 81174dae | aliguori | } |
413 | 81174dae | aliguori | |
414 | 81174dae | aliguori | if (val & UART_FCR_FE) {
|
415 | 81174dae | aliguori | s->iir |= UART_IIR_FE; |
416 | 81174dae | aliguori | /* Set RECV_FIFO trigger Level */
|
417 | 81174dae | aliguori | switch (val & 0xC0) { |
418 | 81174dae | aliguori | case UART_FCR_ITL_1:
|
419 | 81174dae | aliguori | s->recv_fifo.itl = 1;
|
420 | 81174dae | aliguori | break;
|
421 | 81174dae | aliguori | case UART_FCR_ITL_2:
|
422 | 81174dae | aliguori | s->recv_fifo.itl = 4;
|
423 | 81174dae | aliguori | break;
|
424 | 81174dae | aliguori | case UART_FCR_ITL_3:
|
425 | 81174dae | aliguori | s->recv_fifo.itl = 8;
|
426 | 81174dae | aliguori | break;
|
427 | 81174dae | aliguori | case UART_FCR_ITL_4:
|
428 | 81174dae | aliguori | s->recv_fifo.itl = 14;
|
429 | 81174dae | aliguori | break;
|
430 | 81174dae | aliguori | } |
431 | 81174dae | aliguori | } else
|
432 | 81174dae | aliguori | s->iir &= ~UART_IIR_FE; |
433 | 81174dae | aliguori | |
434 | 81174dae | aliguori | /* Set fcr - or at least the bits in it that are supposed to "stick" */
|
435 | 81174dae | aliguori | s->fcr = val & 0xC9;
|
436 | 81174dae | aliguori | serial_update_irq(s); |
437 | 80cabfad | bellard | break;
|
438 | 80cabfad | bellard | case 3: |
439 | f8d179e3 | bellard | { |
440 | f8d179e3 | bellard | int break_enable;
|
441 | f8d179e3 | bellard | s->lcr = val; |
442 | f8d179e3 | bellard | serial_update_parameters(s); |
443 | f8d179e3 | bellard | break_enable = (val >> 6) & 1; |
444 | f8d179e3 | bellard | if (break_enable != s->last_break_enable) {
|
445 | f8d179e3 | bellard | s->last_break_enable = break_enable; |
446 | 5fafdf24 | ths | qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK, |
447 | 2122c51a | bellard | &break_enable); |
448 | f8d179e3 | bellard | } |
449 | f8d179e3 | bellard | } |
450 | 80cabfad | bellard | break;
|
451 | 80cabfad | bellard | case 4: |
452 | 81174dae | aliguori | { |
453 | 81174dae | aliguori | int flags;
|
454 | 81174dae | aliguori | int old_mcr = s->mcr;
|
455 | 81174dae | aliguori | s->mcr = val & 0x1f;
|
456 | 81174dae | aliguori | if (val & UART_MCR_LOOP)
|
457 | 81174dae | aliguori | break;
|
458 | 81174dae | aliguori | |
459 | 81174dae | aliguori | if (s->poll_msl >= 0 && old_mcr != s->mcr) { |
460 | 81174dae | aliguori | |
461 | 81174dae | aliguori | qemu_chr_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags); |
462 | 81174dae | aliguori | |
463 | 81174dae | aliguori | flags &= ~(CHR_TIOCM_RTS | CHR_TIOCM_DTR); |
464 | 81174dae | aliguori | |
465 | 81174dae | aliguori | if (val & UART_MCR_RTS)
|
466 | 81174dae | aliguori | flags |= CHR_TIOCM_RTS; |
467 | 81174dae | aliguori | if (val & UART_MCR_DTR)
|
468 | 81174dae | aliguori | flags |= CHR_TIOCM_DTR; |
469 | 81174dae | aliguori | |
470 | 81174dae | aliguori | qemu_chr_ioctl(s->chr,CHR_IOCTL_SERIAL_SET_TIOCM, &flags); |
471 | 81174dae | aliguori | /* Update the modem status after a one-character-send wait-time, since there may be a response
|
472 | 81174dae | aliguori | from the device/computer at the other end of the serial line */
|
473 | 81174dae | aliguori | qemu_mod_timer(s->modem_status_poll, qemu_get_clock(vm_clock) + s->char_transmit_time); |
474 | 81174dae | aliguori | } |
475 | 81174dae | aliguori | } |
476 | 80cabfad | bellard | break;
|
477 | 80cabfad | bellard | case 5: |
478 | 80cabfad | bellard | break;
|
479 | 80cabfad | bellard | case 6: |
480 | 80cabfad | bellard | break;
|
481 | 80cabfad | bellard | case 7: |
482 | 80cabfad | bellard | s->scr = val; |
483 | 80cabfad | bellard | break;
|
484 | 80cabfad | bellard | } |
485 | 80cabfad | bellard | } |
486 | 80cabfad | bellard | |
487 | b41a2cd1 | bellard | static uint32_t serial_ioport_read(void *opaque, uint32_t addr) |
488 | 80cabfad | bellard | { |
489 | b41a2cd1 | bellard | SerialState *s = opaque; |
490 | 80cabfad | bellard | uint32_t ret; |
491 | 80cabfad | bellard | |
492 | 80cabfad | bellard | addr &= 7;
|
493 | 80cabfad | bellard | switch(addr) {
|
494 | 80cabfad | bellard | default:
|
495 | 80cabfad | bellard | case 0: |
496 | 80cabfad | bellard | if (s->lcr & UART_LCR_DLAB) {
|
497 | 5fafdf24 | ths | ret = s->divider & 0xff;
|
498 | 80cabfad | bellard | } else {
|
499 | 81174dae | aliguori | if(s->fcr & UART_FCR_FE) {
|
500 | 81174dae | aliguori | ret = fifo_get(s,RECV_FIFO); |
501 | 81174dae | aliguori | if (s->recv_fifo.count == 0) |
502 | 81174dae | aliguori | s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); |
503 | 81174dae | aliguori | else
|
504 | 81174dae | aliguori | qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock (vm_clock) + s->char_transmit_time * 4);
|
505 | 81174dae | aliguori | s->timeout_ipending = 0;
|
506 | 81174dae | aliguori | } else {
|
507 | 81174dae | aliguori | ret = s->rbr; |
508 | 81174dae | aliguori | s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); |
509 | 81174dae | aliguori | } |
510 | b41a2cd1 | bellard | serial_update_irq(s); |
511 | b2a5160c | balrog | if (!(s->mcr & UART_MCR_LOOP)) {
|
512 | b2a5160c | balrog | /* in loopback mode, don't receive any data */
|
513 | b2a5160c | balrog | qemu_chr_accept_input(s->chr); |
514 | b2a5160c | balrog | } |
515 | 80cabfad | bellard | } |
516 | 80cabfad | bellard | break;
|
517 | 80cabfad | bellard | case 1: |
518 | 80cabfad | bellard | if (s->lcr & UART_LCR_DLAB) {
|
519 | 80cabfad | bellard | ret = (s->divider >> 8) & 0xff; |
520 | 80cabfad | bellard | } else {
|
521 | 80cabfad | bellard | ret = s->ier; |
522 | 80cabfad | bellard | } |
523 | 80cabfad | bellard | break;
|
524 | 80cabfad | bellard | case 2: |
525 | 80cabfad | bellard | ret = s->iir; |
526 | 80cabfad | bellard | s->thr_ipending = 0;
|
527 | b41a2cd1 | bellard | serial_update_irq(s); |
528 | 80cabfad | bellard | break;
|
529 | 80cabfad | bellard | case 3: |
530 | 80cabfad | bellard | ret = s->lcr; |
531 | 80cabfad | bellard | break;
|
532 | 80cabfad | bellard | case 4: |
533 | 80cabfad | bellard | ret = s->mcr; |
534 | 80cabfad | bellard | break;
|
535 | 80cabfad | bellard | case 5: |
536 | 80cabfad | bellard | ret = s->lsr; |
537 | 81174dae | aliguori | /* Clear break interrupt */
|
538 | 81174dae | aliguori | if (s->lsr & UART_LSR_BI) {
|
539 | 81174dae | aliguori | s->lsr &= ~UART_LSR_BI; |
540 | 81174dae | aliguori | serial_update_irq(s); |
541 | 81174dae | aliguori | } |
542 | 80cabfad | bellard | break;
|
543 | 80cabfad | bellard | case 6: |
544 | 80cabfad | bellard | if (s->mcr & UART_MCR_LOOP) {
|
545 | 80cabfad | bellard | /* in loopback, the modem output pins are connected to the
|
546 | 80cabfad | bellard | inputs */
|
547 | 80cabfad | bellard | ret = (s->mcr & 0x0c) << 4; |
548 | 80cabfad | bellard | ret |= (s->mcr & 0x02) << 3; |
549 | 80cabfad | bellard | ret |= (s->mcr & 0x01) << 5; |
550 | 80cabfad | bellard | } else {
|
551 | 81174dae | aliguori | if (s->poll_msl >= 0) |
552 | 81174dae | aliguori | serial_update_msl(s); |
553 | 80cabfad | bellard | ret = s->msr; |
554 | 81174dae | aliguori | /* Clear delta bits & msr int after read, if they were set */
|
555 | 81174dae | aliguori | if (s->msr & UART_MSR_ANY_DELTA) {
|
556 | 81174dae | aliguori | s->msr &= 0xF0;
|
557 | 81174dae | aliguori | serial_update_irq(s); |
558 | 81174dae | aliguori | } |
559 | 80cabfad | bellard | } |
560 | 80cabfad | bellard | break;
|
561 | 80cabfad | bellard | case 7: |
562 | 80cabfad | bellard | ret = s->scr; |
563 | 80cabfad | bellard | break;
|
564 | 80cabfad | bellard | } |
565 | 80cabfad | bellard | #ifdef DEBUG_SERIAL
|
566 | 80cabfad | bellard | printf("serial: read addr=0x%02x val=0x%02x\n", addr, ret);
|
567 | 80cabfad | bellard | #endif
|
568 | 80cabfad | bellard | return ret;
|
569 | 80cabfad | bellard | } |
570 | 80cabfad | bellard | |
571 | 82c643ff | bellard | static int serial_can_receive(SerialState *s) |
572 | 80cabfad | bellard | { |
573 | 81174dae | aliguori | if(s->fcr & UART_FCR_FE) {
|
574 | 81174dae | aliguori | if(s->recv_fifo.count < UART_FIFO_LENGTH)
|
575 | 81174dae | aliguori | /* Advertise (fifo.itl - fifo.count) bytes when count < ITL, and 1 if above. If UART_FIFO_LENGTH - fifo.count is
|
576 | 81174dae | aliguori | advertised the effect will be to almost always fill the fifo completely before the guest has a chance to respond,
|
577 | 81174dae | aliguori | effectively overriding the ITL that the guest has set. */
|
578 | 81174dae | aliguori | return (s->recv_fifo.count <= s->recv_fifo.itl) ? s->recv_fifo.itl - s->recv_fifo.count : 1; |
579 | 81174dae | aliguori | else
|
580 | 81174dae | aliguori | return 0; |
581 | 81174dae | aliguori | } else {
|
582 | 80cabfad | bellard | return !(s->lsr & UART_LSR_DR);
|
583 | 81174dae | aliguori | } |
584 | 80cabfad | bellard | } |
585 | 80cabfad | bellard | |
586 | 82c643ff | bellard | static void serial_receive_break(SerialState *s) |
587 | 80cabfad | bellard | { |
588 | 80cabfad | bellard | s->rbr = 0;
|
589 | 80cabfad | bellard | s->lsr |= UART_LSR_BI | UART_LSR_DR; |
590 | b41a2cd1 | bellard | serial_update_irq(s); |
591 | 80cabfad | bellard | } |
592 | 80cabfad | bellard | |
593 | 81174dae | aliguori | /* There's data in recv_fifo and s->rbr has not been read for 4 char transmit times */
|
594 | 81174dae | aliguori | static void fifo_timeout_int (void *opaque) { |
595 | 81174dae | aliguori | SerialState *s = opaque; |
596 | 81174dae | aliguori | if (s->recv_fifo.count) {
|
597 | 81174dae | aliguori | s->timeout_ipending = 1;
|
598 | 81174dae | aliguori | serial_update_irq(s); |
599 | 81174dae | aliguori | } |
600 | 81174dae | aliguori | } |
601 | 81174dae | aliguori | |
602 | b41a2cd1 | bellard | static int serial_can_receive1(void *opaque) |
603 | 80cabfad | bellard | { |
604 | b41a2cd1 | bellard | SerialState *s = opaque; |
605 | b41a2cd1 | bellard | return serial_can_receive(s);
|
606 | b41a2cd1 | bellard | } |
607 | b41a2cd1 | bellard | |
608 | b41a2cd1 | bellard | static void serial_receive1(void *opaque, const uint8_t *buf, int size) |
609 | b41a2cd1 | bellard | { |
610 | b41a2cd1 | bellard | SerialState *s = opaque; |
611 | 81174dae | aliguori | if(s->fcr & UART_FCR_FE) {
|
612 | 81174dae | aliguori | int i;
|
613 | 81174dae | aliguori | for (i = 0; i < size; i++) { |
614 | 81174dae | aliguori | fifo_put(s, RECV_FIFO, buf[i]); |
615 | 81174dae | aliguori | } |
616 | 81174dae | aliguori | s->lsr |= UART_LSR_DR; |
617 | 81174dae | aliguori | /* call the timeout receive callback in 4 char transmit time */
|
618 | 81174dae | aliguori | qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock (vm_clock) + s->char_transmit_time * 4);
|
619 | 81174dae | aliguori | } else {
|
620 | 81174dae | aliguori | s->rbr = buf[0];
|
621 | 81174dae | aliguori | s->lsr |= UART_LSR_DR; |
622 | 81174dae | aliguori | } |
623 | 81174dae | aliguori | serial_update_irq(s); |
624 | b41a2cd1 | bellard | } |
625 | 80cabfad | bellard | |
626 | 82c643ff | bellard | static void serial_event(void *opaque, int event) |
627 | 82c643ff | bellard | { |
628 | 82c643ff | bellard | SerialState *s = opaque; |
629 | 81174dae | aliguori | #ifdef DEBUG_SERIAL
|
630 | 81174dae | aliguori | printf("serial: event %x\n", event);
|
631 | 81174dae | aliguori | #endif
|
632 | 82c643ff | bellard | if (event == CHR_EVENT_BREAK)
|
633 | 82c643ff | bellard | serial_receive_break(s); |
634 | 82c643ff | bellard | } |
635 | 82c643ff | bellard | |
636 | 8738a8d0 | bellard | static void serial_save(QEMUFile *f, void *opaque) |
637 | 8738a8d0 | bellard | { |
638 | 8738a8d0 | bellard | SerialState *s = opaque; |
639 | 8738a8d0 | bellard | |
640 | 508d92d0 | bellard | qemu_put_be16s(f,&s->divider); |
641 | 8738a8d0 | bellard | qemu_put_8s(f,&s->rbr); |
642 | 8738a8d0 | bellard | qemu_put_8s(f,&s->ier); |
643 | 8738a8d0 | bellard | qemu_put_8s(f,&s->iir); |
644 | 8738a8d0 | bellard | qemu_put_8s(f,&s->lcr); |
645 | 8738a8d0 | bellard | qemu_put_8s(f,&s->mcr); |
646 | 8738a8d0 | bellard | qemu_put_8s(f,&s->lsr); |
647 | 8738a8d0 | bellard | qemu_put_8s(f,&s->msr); |
648 | 8738a8d0 | bellard | qemu_put_8s(f,&s->scr); |
649 | 81174dae | aliguori | qemu_put_8s(f,&s->fcr); |
650 | 8738a8d0 | bellard | } |
651 | 8738a8d0 | bellard | |
652 | 8738a8d0 | bellard | static int serial_load(QEMUFile *f, void *opaque, int version_id) |
653 | 8738a8d0 | bellard | { |
654 | 8738a8d0 | bellard | SerialState *s = opaque; |
655 | 81174dae | aliguori | uint8_t fcr = 0;
|
656 | 8738a8d0 | bellard | |
657 | 81174dae | aliguori | if(version_id > 3) |
658 | 8738a8d0 | bellard | return -EINVAL;
|
659 | 8738a8d0 | bellard | |
660 | 508d92d0 | bellard | if (version_id >= 2) |
661 | 508d92d0 | bellard | qemu_get_be16s(f, &s->divider); |
662 | 508d92d0 | bellard | else
|
663 | 508d92d0 | bellard | s->divider = qemu_get_byte(f); |
664 | 8738a8d0 | bellard | qemu_get_8s(f,&s->rbr); |
665 | 8738a8d0 | bellard | qemu_get_8s(f,&s->ier); |
666 | 8738a8d0 | bellard | qemu_get_8s(f,&s->iir); |
667 | 8738a8d0 | bellard | qemu_get_8s(f,&s->lcr); |
668 | 8738a8d0 | bellard | qemu_get_8s(f,&s->mcr); |
669 | 8738a8d0 | bellard | qemu_get_8s(f,&s->lsr); |
670 | 8738a8d0 | bellard | qemu_get_8s(f,&s->msr); |
671 | 8738a8d0 | bellard | qemu_get_8s(f,&s->scr); |
672 | 8738a8d0 | bellard | |
673 | 81174dae | aliguori | if (version_id >= 3) |
674 | 81174dae | aliguori | qemu_get_8s(f,&fcr); |
675 | 81174dae | aliguori | |
676 | 81174dae | aliguori | /* Initialize fcr via setter to perform essential side-effects */
|
677 | 81174dae | aliguori | serial_ioport_write(s, 0x02, fcr);
|
678 | 8738a8d0 | bellard | return 0; |
679 | 8738a8d0 | bellard | } |
680 | 8738a8d0 | bellard | |
681 | b2a5160c | balrog | static void serial_reset(void *opaque) |
682 | b2a5160c | balrog | { |
683 | b2a5160c | balrog | SerialState *s = opaque; |
684 | b2a5160c | balrog | |
685 | b2a5160c | balrog | s->rbr = 0;
|
686 | b2a5160c | balrog | s->ier = 0;
|
687 | b2a5160c | balrog | s->iir = UART_IIR_NO_INT; |
688 | b2a5160c | balrog | s->lcr = 0;
|
689 | b2a5160c | balrog | s->lsr = UART_LSR_TEMT | UART_LSR_THRE; |
690 | b2a5160c | balrog | s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS; |
691 | 81174dae | aliguori | /* Default to 9600 baud, no parity, one stop bit */
|
692 | 81174dae | aliguori | s->divider = 0x0C;
|
693 | 81174dae | aliguori | s->mcr = UART_MCR_OUT2; |
694 | b2a5160c | balrog | s->scr = 0;
|
695 | 81174dae | aliguori | s->tsr_retry = 0;
|
696 | 81174dae | aliguori | s->char_transmit_time = (ticks_per_sec / 9600) * 9; |
697 | 81174dae | aliguori | s->poll_msl = 0;
|
698 | 81174dae | aliguori | |
699 | 81174dae | aliguori | fifo_clear(s,RECV_FIFO); |
700 | 81174dae | aliguori | fifo_clear(s,XMIT_FIFO); |
701 | 81174dae | aliguori | |
702 | 81174dae | aliguori | s->last_xmit_ts = qemu_get_clock(vm_clock); |
703 | b2a5160c | balrog | |
704 | b2a5160c | balrog | s->thr_ipending = 0;
|
705 | b2a5160c | balrog | s->last_break_enable = 0;
|
706 | b2a5160c | balrog | qemu_irq_lower(s->irq); |
707 | b2a5160c | balrog | } |
708 | b2a5160c | balrog | |
709 | 81174dae | aliguori | static void serial_init_core(SerialState *s, qemu_irq irq, int baudbase, |
710 | 81174dae | aliguori | CharDriverState *chr) |
711 | 81174dae | aliguori | { |
712 | 81174dae | aliguori | s->irq = irq; |
713 | 81174dae | aliguori | s->baudbase = baudbase; |
714 | b47543c4 | aurel32 | s->chr = chr ?: qemu_chr_open("null", "null", NULL); |
715 | 81174dae | aliguori | |
716 | 81174dae | aliguori | s->modem_status_poll = qemu_new_timer(vm_clock, (QEMUTimerCB *) serial_update_msl, s); |
717 | 81174dae | aliguori | |
718 | 81174dae | aliguori | s->fifo_timeout_timer = qemu_new_timer(vm_clock, (QEMUTimerCB *) fifo_timeout_int, s); |
719 | 81174dae | aliguori | s->transmit_timer = qemu_new_timer(vm_clock, (QEMUTimerCB *) serial_xmit, s); |
720 | 81174dae | aliguori | |
721 | 81174dae | aliguori | qemu_register_reset(serial_reset, s); |
722 | 81174dae | aliguori | serial_reset(s); |
723 | 81174dae | aliguori | |
724 | b47543c4 | aurel32 | qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1, |
725 | b47543c4 | aurel32 | serial_event, s); |
726 | 81174dae | aliguori | } |
727 | 81174dae | aliguori | |
728 | b41a2cd1 | bellard | /* If fd is zero, it means that the serial device uses the console */
|
729 | b6cd0ea1 | aurel32 | SerialState *serial_init(int base, qemu_irq irq, int baudbase, |
730 | b6cd0ea1 | aurel32 | CharDriverState *chr) |
731 | b41a2cd1 | bellard | { |
732 | b41a2cd1 | bellard | SerialState *s; |
733 | b41a2cd1 | bellard | |
734 | b41a2cd1 | bellard | s = qemu_mallocz(sizeof(SerialState));
|
735 | 6936bfe5 | aurel32 | |
736 | 81174dae | aliguori | serial_init_core(s, irq, baudbase, chr); |
737 | b41a2cd1 | bellard | |
738 | 81174dae | aliguori | register_savevm("serial", base, 3, serial_save, serial_load, s); |
739 | 8738a8d0 | bellard | |
740 | b41a2cd1 | bellard | register_ioport_write(base, 8, 1, serial_ioport_write, s); |
741 | b41a2cd1 | bellard | register_ioport_read(base, 8, 1, serial_ioport_read, s); |
742 | b41a2cd1 | bellard | return s;
|
743 | 80cabfad | bellard | } |
744 | e5d13e2f | bellard | |
745 | e5d13e2f | bellard | /* Memory mapped interface */
|
746 | a4bc3afc | ths | uint32_t serial_mm_readb (void *opaque, target_phys_addr_t addr)
|
747 | e5d13e2f | bellard | { |
748 | e5d13e2f | bellard | SerialState *s = opaque; |
749 | e5d13e2f | bellard | |
750 | 8da3ff18 | pbrook | return serial_ioport_read(s, addr >> s->it_shift) & 0xFF; |
751 | e5d13e2f | bellard | } |
752 | e5d13e2f | bellard | |
753 | a4bc3afc | ths | void serial_mm_writeb (void *opaque, |
754 | a4bc3afc | ths | target_phys_addr_t addr, uint32_t value) |
755 | e5d13e2f | bellard | { |
756 | e5d13e2f | bellard | SerialState *s = opaque; |
757 | e5d13e2f | bellard | |
758 | 8da3ff18 | pbrook | serial_ioport_write(s, addr >> s->it_shift, value & 0xFF);
|
759 | e5d13e2f | bellard | } |
760 | e5d13e2f | bellard | |
761 | a4bc3afc | ths | uint32_t serial_mm_readw (void *opaque, target_phys_addr_t addr)
|
762 | e5d13e2f | bellard | { |
763 | e5d13e2f | bellard | SerialState *s = opaque; |
764 | e918ee04 | ths | uint32_t val; |
765 | e5d13e2f | bellard | |
766 | 8da3ff18 | pbrook | val = serial_ioport_read(s, addr >> s->it_shift) & 0xFFFF;
|
767 | e918ee04 | ths | #ifdef TARGET_WORDS_BIGENDIAN
|
768 | e918ee04 | ths | val = bswap16(val); |
769 | e918ee04 | ths | #endif
|
770 | e918ee04 | ths | return val;
|
771 | e5d13e2f | bellard | } |
772 | e5d13e2f | bellard | |
773 | a4bc3afc | ths | void serial_mm_writew (void *opaque, |
774 | a4bc3afc | ths | target_phys_addr_t addr, uint32_t value) |
775 | e5d13e2f | bellard | { |
776 | e5d13e2f | bellard | SerialState *s = opaque; |
777 | e918ee04 | ths | #ifdef TARGET_WORDS_BIGENDIAN
|
778 | e918ee04 | ths | value = bswap16(value); |
779 | e918ee04 | ths | #endif
|
780 | 8da3ff18 | pbrook | serial_ioport_write(s, addr >> s->it_shift, value & 0xFFFF);
|
781 | e5d13e2f | bellard | } |
782 | e5d13e2f | bellard | |
783 | a4bc3afc | ths | uint32_t serial_mm_readl (void *opaque, target_phys_addr_t addr)
|
784 | e5d13e2f | bellard | { |
785 | e5d13e2f | bellard | SerialState *s = opaque; |
786 | e918ee04 | ths | uint32_t val; |
787 | e5d13e2f | bellard | |
788 | 8da3ff18 | pbrook | val = serial_ioport_read(s, addr >> s->it_shift); |
789 | e918ee04 | ths | #ifdef TARGET_WORDS_BIGENDIAN
|
790 | e918ee04 | ths | val = bswap32(val); |
791 | e918ee04 | ths | #endif
|
792 | e918ee04 | ths | return val;
|
793 | e5d13e2f | bellard | } |
794 | e5d13e2f | bellard | |
795 | a4bc3afc | ths | void serial_mm_writel (void *opaque, |
796 | a4bc3afc | ths | target_phys_addr_t addr, uint32_t value) |
797 | e5d13e2f | bellard | { |
798 | e5d13e2f | bellard | SerialState *s = opaque; |
799 | e918ee04 | ths | #ifdef TARGET_WORDS_BIGENDIAN
|
800 | e918ee04 | ths | value = bswap32(value); |
801 | e918ee04 | ths | #endif
|
802 | 8da3ff18 | pbrook | serial_ioport_write(s, addr >> s->it_shift, value); |
803 | e5d13e2f | bellard | } |
804 | e5d13e2f | bellard | |
805 | e5d13e2f | bellard | static CPUReadMemoryFunc *serial_mm_read[] = {
|
806 | e5d13e2f | bellard | &serial_mm_readb, |
807 | e5d13e2f | bellard | &serial_mm_readw, |
808 | e5d13e2f | bellard | &serial_mm_readl, |
809 | e5d13e2f | bellard | }; |
810 | e5d13e2f | bellard | |
811 | e5d13e2f | bellard | static CPUWriteMemoryFunc *serial_mm_write[] = {
|
812 | e5d13e2f | bellard | &serial_mm_writeb, |
813 | e5d13e2f | bellard | &serial_mm_writew, |
814 | e5d13e2f | bellard | &serial_mm_writel, |
815 | e5d13e2f | bellard | }; |
816 | e5d13e2f | bellard | |
817 | 71db710f | blueswir1 | SerialState *serial_mm_init (target_phys_addr_t base, int it_shift,
|
818 | b6cd0ea1 | aurel32 | qemu_irq irq, int baudbase,
|
819 | b6cd0ea1 | aurel32 | CharDriverState *chr, int ioregister)
|
820 | e5d13e2f | bellard | { |
821 | e5d13e2f | bellard | SerialState *s; |
822 | e5d13e2f | bellard | int s_io_memory;
|
823 | e5d13e2f | bellard | |
824 | e5d13e2f | bellard | s = qemu_mallocz(sizeof(SerialState));
|
825 | 81174dae | aliguori | |
826 | e5d13e2f | bellard | s->it_shift = it_shift; |
827 | e5d13e2f | bellard | |
828 | 81174dae | aliguori | serial_init_core(s, irq, baudbase, chr); |
829 | 81174dae | aliguori | register_savevm("serial", base, 3, serial_save, serial_load, s); |
830 | e5d13e2f | bellard | |
831 | a4bc3afc | ths | if (ioregister) {
|
832 | a4bc3afc | ths | s_io_memory = cpu_register_io_memory(0, serial_mm_read,
|
833 | a4bc3afc | ths | serial_mm_write, s); |
834 | a4bc3afc | ths | cpu_register_physical_memory(base, 8 << it_shift, s_io_memory);
|
835 | a4bc3afc | ths | } |
836 | 81174dae | aliguori | serial_update_msl(s); |
837 | e5d13e2f | bellard | return s;
|
838 | e5d13e2f | bellard | } |