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