root / hw / serial.c @ 3e35ba93
History | View | Annotate | Download (26.9 kB)
1 | 80cabfad | bellard | /*
|
---|---|---|---|
2 | 81174dae | aliguori | * QEMU 16550A UART emulation
|
3 | 5fafdf24 | ths | *
|
4 | 80cabfad | bellard | * Copyright (c) 2003-2004 Fabrice Bellard
|
5 | 81174dae | aliguori | * Copyright (c) 2008 Citrix Systems, Inc.
|
6 | 5fafdf24 | ths | *
|
7 | 80cabfad | bellard | * Permission is hereby granted, free of charge, to any person obtaining a copy
|
8 | 80cabfad | bellard | * of this software and associated documentation files (the "Software"), to deal
|
9 | 80cabfad | bellard | * in the Software without restriction, including without limitation the rights
|
10 | 80cabfad | bellard | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
11 | 80cabfad | bellard | * copies of the Software, and to permit persons to whom the Software is
|
12 | 80cabfad | bellard | * furnished to do so, subject to the following conditions:
|
13 | 80cabfad | bellard | *
|
14 | 80cabfad | bellard | * The above copyright notice and this permission notice shall be included in
|
15 | 80cabfad | bellard | * all copies or substantial portions of the Software.
|
16 | 80cabfad | bellard | *
|
17 | 80cabfad | bellard | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
18 | 80cabfad | bellard | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
19 | 80cabfad | bellard | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
20 | 80cabfad | bellard | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
21 | 80cabfad | bellard | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
22 | 80cabfad | bellard | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
23 | 80cabfad | bellard | * THE SOFTWARE.
|
24 | 80cabfad | bellard | */
|
25 | 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 | 718b8aec | Stefan Weil | /* Start bit. */
|
236 | 81174dae | aliguori | frame_size = 1;
|
237 | f8d179e3 | bellard | if (s->lcr & 0x08) { |
238 | 718b8aec | Stefan Weil | /* Parity bit. */
|
239 | 718b8aec | Stefan Weil | frame_size++; |
240 | f8d179e3 | bellard | if (s->lcr & 0x10) |
241 | f8d179e3 | bellard | parity = 'E';
|
242 | f8d179e3 | bellard | else
|
243 | f8d179e3 | bellard | parity = 'O';
|
244 | f8d179e3 | bellard | } else {
|
245 | f8d179e3 | bellard | parity = 'N';
|
246 | f8d179e3 | bellard | } |
247 | 5fafdf24 | ths | if (s->lcr & 0x04) |
248 | f8d179e3 | bellard | stop_bits = 2;
|
249 | f8d179e3 | bellard | else
|
250 | f8d179e3 | bellard | stop_bits = 1;
|
251 | 81174dae | aliguori | |
252 | f8d179e3 | bellard | data_bits = (s->lcr & 0x03) + 5; |
253 | 81174dae | aliguori | frame_size += data_bits + stop_bits; |
254 | b6cd0ea1 | aurel32 | speed = s->baudbase / s->divider; |
255 | 2122c51a | bellard | ssp.speed = speed; |
256 | 2122c51a | bellard | ssp.parity = parity; |
257 | 2122c51a | bellard | ssp.data_bits = data_bits; |
258 | 2122c51a | bellard | ssp.stop_bits = stop_bits; |
259 | 6ee093c9 | Juan Quintela | s->char_transmit_time = (get_ticks_per_sec() / speed) * frame_size; |
260 | 2122c51a | bellard | qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp); |
261 | 2122c51a | bellard | #if 0
|
262 | 5fafdf24 | ths | printf("speed=%d parity=%c data=%d stop=%d\n",
|
263 | f8d179e3 | bellard | speed, parity, data_bits, stop_bits);
|
264 | f8d179e3 | bellard | #endif
|
265 | f8d179e3 | bellard | } |
266 | f8d179e3 | bellard | |
267 | 81174dae | aliguori | static void serial_update_msl(SerialState *s) |
268 | 81174dae | aliguori | { |
269 | 81174dae | aliguori | uint8_t omsr; |
270 | 81174dae | aliguori | int flags;
|
271 | 81174dae | aliguori | |
272 | 81174dae | aliguori | qemu_del_timer(s->modem_status_poll); |
273 | 81174dae | aliguori | |
274 | 81174dae | aliguori | if (qemu_chr_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags) == -ENOTSUP) {
|
275 | 81174dae | aliguori | s->poll_msl = -1;
|
276 | 81174dae | aliguori | return;
|
277 | 81174dae | aliguori | } |
278 | 81174dae | aliguori | |
279 | 81174dae | aliguori | omsr = s->msr; |
280 | 81174dae | aliguori | |
281 | 81174dae | aliguori | s->msr = (flags & CHR_TIOCM_CTS) ? s->msr | UART_MSR_CTS : s->msr & ~UART_MSR_CTS; |
282 | 81174dae | aliguori | s->msr = (flags & CHR_TIOCM_DSR) ? s->msr | UART_MSR_DSR : s->msr & ~UART_MSR_DSR; |
283 | 81174dae | aliguori | s->msr = (flags & CHR_TIOCM_CAR) ? s->msr | UART_MSR_DCD : s->msr & ~UART_MSR_DCD; |
284 | 81174dae | aliguori | s->msr = (flags & CHR_TIOCM_RI) ? s->msr | UART_MSR_RI : s->msr & ~UART_MSR_RI; |
285 | 81174dae | aliguori | |
286 | 81174dae | aliguori | if (s->msr != omsr) {
|
287 | 81174dae | aliguori | /* Set delta bits */
|
288 | 81174dae | aliguori | s->msr = s->msr | ((s->msr >> 4) ^ (omsr >> 4)); |
289 | 81174dae | aliguori | /* UART_MSR_TERI only if change was from 1 -> 0 */
|
290 | 81174dae | aliguori | if ((s->msr & UART_MSR_TERI) && !(omsr & UART_MSR_RI))
|
291 | 81174dae | aliguori | s->msr &= ~UART_MSR_TERI; |
292 | 81174dae | aliguori | serial_update_irq(s); |
293 | 81174dae | aliguori | } |
294 | 81174dae | aliguori | |
295 | 81174dae | aliguori | /* The real 16550A apparently has a 250ns response latency to line status changes.
|
296 | 81174dae | aliguori | We'll be lazy and poll only every 10ms, and only poll it at all if MSI interrupts are turned on */
|
297 | 81174dae | aliguori | |
298 | 81174dae | aliguori | if (s->poll_msl)
|
299 | 6ee093c9 | Juan Quintela | qemu_mod_timer(s->modem_status_poll, qemu_get_clock(vm_clock) + get_ticks_per_sec() / 100);
|
300 | 81174dae | aliguori | } |
301 | 81174dae | aliguori | |
302 | 81174dae | aliguori | static void serial_xmit(void *opaque) |
303 | 81174dae | aliguori | { |
304 | 81174dae | aliguori | SerialState *s = opaque; |
305 | 81174dae | aliguori | uint64_t new_xmit_ts = qemu_get_clock(vm_clock); |
306 | 81174dae | aliguori | |
307 | 81174dae | aliguori | if (s->tsr_retry <= 0) { |
308 | 81174dae | aliguori | if (s->fcr & UART_FCR_FE) {
|
309 | 81174dae | aliguori | s->tsr = fifo_get(s,XMIT_FIFO); |
310 | 81174dae | aliguori | if (!s->xmit_fifo.count)
|
311 | 81174dae | aliguori | s->lsr |= UART_LSR_THRE; |
312 | 81174dae | aliguori | } else {
|
313 | 81174dae | aliguori | s->tsr = s->thr; |
314 | 81174dae | aliguori | s->lsr |= UART_LSR_THRE; |
315 | 81174dae | aliguori | } |
316 | 81174dae | aliguori | } |
317 | 81174dae | aliguori | |
318 | 81174dae | aliguori | if (s->mcr & UART_MCR_LOOP) {
|
319 | 81174dae | aliguori | /* in loopback mode, say that we just received a char */
|
320 | 81174dae | aliguori | serial_receive1(s, &s->tsr, 1);
|
321 | 81174dae | aliguori | } else if (qemu_chr_write(s->chr, &s->tsr, 1) != 1) { |
322 | 81174dae | aliguori | if ((s->tsr_retry > 0) && (s->tsr_retry <= MAX_XMIT_RETRY)) { |
323 | 81174dae | aliguori | s->tsr_retry++; |
324 | 81174dae | aliguori | qemu_mod_timer(s->transmit_timer, new_xmit_ts + s->char_transmit_time); |
325 | 81174dae | aliguori | return;
|
326 | 81174dae | aliguori | } else if (s->poll_msl < 0) { |
327 | 81174dae | aliguori | /* If we exceed MAX_XMIT_RETRY and the backend is not a real serial port, then
|
328 | 81174dae | aliguori | drop any further failed writes instantly, until we get one that goes through.
|
329 | 81174dae | aliguori | This is to prevent guests that log to unconnected pipes or pty's from stalling. */
|
330 | 81174dae | aliguori | s->tsr_retry = -1;
|
331 | 81174dae | aliguori | } |
332 | 81174dae | aliguori | } |
333 | 81174dae | aliguori | else {
|
334 | 81174dae | aliguori | s->tsr_retry = 0;
|
335 | 81174dae | aliguori | } |
336 | 81174dae | aliguori | |
337 | 81174dae | aliguori | s->last_xmit_ts = qemu_get_clock(vm_clock); |
338 | 81174dae | aliguori | if (!(s->lsr & UART_LSR_THRE))
|
339 | 81174dae | aliguori | qemu_mod_timer(s->transmit_timer, s->last_xmit_ts + s->char_transmit_time); |
340 | 81174dae | aliguori | |
341 | 81174dae | aliguori | if (s->lsr & UART_LSR_THRE) {
|
342 | 81174dae | aliguori | s->lsr |= UART_LSR_TEMT; |
343 | 81174dae | aliguori | s->thr_ipending = 1;
|
344 | 81174dae | aliguori | serial_update_irq(s); |
345 | 81174dae | aliguori | } |
346 | 81174dae | aliguori | } |
347 | 81174dae | aliguori | |
348 | 81174dae | aliguori | |
349 | b41a2cd1 | bellard | static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
350 | 80cabfad | bellard | { |
351 | b41a2cd1 | bellard | SerialState *s = opaque; |
352 | 3b46e624 | ths | |
353 | 80cabfad | bellard | addr &= 7;
|
354 | 80cabfad | bellard | #ifdef DEBUG_SERIAL
|
355 | 80cabfad | bellard | printf("serial: write addr=0x%02x val=0x%02x\n", addr, val);
|
356 | 80cabfad | bellard | #endif
|
357 | 80cabfad | bellard | switch(addr) {
|
358 | 80cabfad | bellard | default:
|
359 | 80cabfad | bellard | case 0: |
360 | 80cabfad | bellard | if (s->lcr & UART_LCR_DLAB) {
|
361 | 80cabfad | bellard | s->divider = (s->divider & 0xff00) | val;
|
362 | f8d179e3 | bellard | serial_update_parameters(s); |
363 | 80cabfad | bellard | } else {
|
364 | 81174dae | aliguori | s->thr = (uint8_t) val; |
365 | 81174dae | aliguori | if(s->fcr & UART_FCR_FE) {
|
366 | 81174dae | aliguori | fifo_put(s, XMIT_FIFO, s->thr); |
367 | 80cabfad | bellard | s->thr_ipending = 0;
|
368 | 81174dae | aliguori | s->lsr &= ~UART_LSR_TEMT; |
369 | 80cabfad | bellard | s->lsr &= ~UART_LSR_THRE; |
370 | b41a2cd1 | bellard | serial_update_irq(s); |
371 | 6936bfe5 | aurel32 | } else {
|
372 | 81174dae | aliguori | s->thr_ipending = 0;
|
373 | 81174dae | aliguori | s->lsr &= ~UART_LSR_THRE; |
374 | 81174dae | aliguori | serial_update_irq(s); |
375 | 6936bfe5 | aurel32 | } |
376 | 81174dae | aliguori | serial_xmit(s); |
377 | 80cabfad | bellard | } |
378 | 80cabfad | bellard | break;
|
379 | 80cabfad | bellard | case 1: |
380 | 80cabfad | bellard | if (s->lcr & UART_LCR_DLAB) {
|
381 | 80cabfad | bellard | s->divider = (s->divider & 0x00ff) | (val << 8); |
382 | f8d179e3 | bellard | serial_update_parameters(s); |
383 | 80cabfad | bellard | } else {
|
384 | 60e336db | bellard | s->ier = val & 0x0f;
|
385 | 81174dae | aliguori | /* If the backend device is a real serial port, turn polling of the modem
|
386 | 81174dae | aliguori | status lines on physical port on or off depending on UART_IER_MSI state */
|
387 | 81174dae | aliguori | if (s->poll_msl >= 0) { |
388 | 81174dae | aliguori | if (s->ier & UART_IER_MSI) {
|
389 | 81174dae | aliguori | s->poll_msl = 1;
|
390 | 81174dae | aliguori | serial_update_msl(s); |
391 | 81174dae | aliguori | } else {
|
392 | 81174dae | aliguori | qemu_del_timer(s->modem_status_poll); |
393 | 81174dae | aliguori | s->poll_msl = 0;
|
394 | 81174dae | aliguori | } |
395 | 81174dae | aliguori | } |
396 | 60e336db | bellard | if (s->lsr & UART_LSR_THRE) {
|
397 | 60e336db | bellard | s->thr_ipending = 1;
|
398 | 81174dae | aliguori | serial_update_irq(s); |
399 | 60e336db | bellard | } |
400 | 80cabfad | bellard | } |
401 | 80cabfad | bellard | break;
|
402 | 80cabfad | bellard | case 2: |
403 | 81174dae | aliguori | val = val & 0xFF;
|
404 | 81174dae | aliguori | |
405 | 81174dae | aliguori | if (s->fcr == val)
|
406 | 81174dae | aliguori | break;
|
407 | 81174dae | aliguori | |
408 | 81174dae | aliguori | /* Did the enable/disable flag change? If so, make sure FIFOs get flushed */
|
409 | 81174dae | aliguori | if ((val ^ s->fcr) & UART_FCR_FE)
|
410 | 81174dae | aliguori | val |= UART_FCR_XFR | UART_FCR_RFR; |
411 | 81174dae | aliguori | |
412 | 81174dae | aliguori | /* FIFO clear */
|
413 | 81174dae | aliguori | |
414 | 81174dae | aliguori | if (val & UART_FCR_RFR) {
|
415 | 81174dae | aliguori | qemu_del_timer(s->fifo_timeout_timer); |
416 | 81174dae | aliguori | s->timeout_ipending=0;
|
417 | 81174dae | aliguori | fifo_clear(s,RECV_FIFO); |
418 | 81174dae | aliguori | } |
419 | 81174dae | aliguori | |
420 | 81174dae | aliguori | if (val & UART_FCR_XFR) {
|
421 | 81174dae | aliguori | fifo_clear(s,XMIT_FIFO); |
422 | 81174dae | aliguori | } |
423 | 81174dae | aliguori | |
424 | 81174dae | aliguori | if (val & UART_FCR_FE) {
|
425 | 81174dae | aliguori | s->iir |= UART_IIR_FE; |
426 | 81174dae | aliguori | /* Set RECV_FIFO trigger Level */
|
427 | 81174dae | aliguori | switch (val & 0xC0) { |
428 | 81174dae | aliguori | case UART_FCR_ITL_1:
|
429 | 81174dae | aliguori | s->recv_fifo.itl = 1;
|
430 | 81174dae | aliguori | break;
|
431 | 81174dae | aliguori | case UART_FCR_ITL_2:
|
432 | 81174dae | aliguori | s->recv_fifo.itl = 4;
|
433 | 81174dae | aliguori | break;
|
434 | 81174dae | aliguori | case UART_FCR_ITL_3:
|
435 | 81174dae | aliguori | s->recv_fifo.itl = 8;
|
436 | 81174dae | aliguori | break;
|
437 | 81174dae | aliguori | case UART_FCR_ITL_4:
|
438 | 81174dae | aliguori | s->recv_fifo.itl = 14;
|
439 | 81174dae | aliguori | break;
|
440 | 81174dae | aliguori | } |
441 | 81174dae | aliguori | } else
|
442 | 81174dae | aliguori | s->iir &= ~UART_IIR_FE; |
443 | 81174dae | aliguori | |
444 | 81174dae | aliguori | /* Set fcr - or at least the bits in it that are supposed to "stick" */
|
445 | 81174dae | aliguori | s->fcr = val & 0xC9;
|
446 | 81174dae | aliguori | serial_update_irq(s); |
447 | 80cabfad | bellard | break;
|
448 | 80cabfad | bellard | case 3: |
449 | f8d179e3 | bellard | { |
450 | f8d179e3 | bellard | int break_enable;
|
451 | f8d179e3 | bellard | s->lcr = val; |
452 | f8d179e3 | bellard | serial_update_parameters(s); |
453 | f8d179e3 | bellard | break_enable = (val >> 6) & 1; |
454 | f8d179e3 | bellard | if (break_enable != s->last_break_enable) {
|
455 | f8d179e3 | bellard | s->last_break_enable = break_enable; |
456 | 5fafdf24 | ths | qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK, |
457 | 2122c51a | bellard | &break_enable); |
458 | f8d179e3 | bellard | } |
459 | f8d179e3 | bellard | } |
460 | 80cabfad | bellard | break;
|
461 | 80cabfad | bellard | case 4: |
462 | 81174dae | aliguori | { |
463 | 81174dae | aliguori | int flags;
|
464 | 81174dae | aliguori | int old_mcr = s->mcr;
|
465 | 81174dae | aliguori | s->mcr = val & 0x1f;
|
466 | 81174dae | aliguori | if (val & UART_MCR_LOOP)
|
467 | 81174dae | aliguori | break;
|
468 | 81174dae | aliguori | |
469 | 81174dae | aliguori | if (s->poll_msl >= 0 && old_mcr != s->mcr) { |
470 | 81174dae | aliguori | |
471 | 81174dae | aliguori | qemu_chr_ioctl(s->chr,CHR_IOCTL_SERIAL_GET_TIOCM, &flags); |
472 | 81174dae | aliguori | |
473 | 81174dae | aliguori | flags &= ~(CHR_TIOCM_RTS | CHR_TIOCM_DTR); |
474 | 81174dae | aliguori | |
475 | 81174dae | aliguori | if (val & UART_MCR_RTS)
|
476 | 81174dae | aliguori | flags |= CHR_TIOCM_RTS; |
477 | 81174dae | aliguori | if (val & UART_MCR_DTR)
|
478 | 81174dae | aliguori | flags |= CHR_TIOCM_DTR; |
479 | 81174dae | aliguori | |
480 | 81174dae | aliguori | qemu_chr_ioctl(s->chr,CHR_IOCTL_SERIAL_SET_TIOCM, &flags); |
481 | 81174dae | aliguori | /* Update the modem status after a one-character-send wait-time, since there may be a response
|
482 | 81174dae | aliguori | from the device/computer at the other end of the serial line */
|
483 | 81174dae | aliguori | qemu_mod_timer(s->modem_status_poll, qemu_get_clock(vm_clock) + s->char_transmit_time); |
484 | 81174dae | aliguori | } |
485 | 81174dae | aliguori | } |
486 | 80cabfad | bellard | break;
|
487 | 80cabfad | bellard | case 5: |
488 | 80cabfad | bellard | break;
|
489 | 80cabfad | bellard | case 6: |
490 | 80cabfad | bellard | break;
|
491 | 80cabfad | bellard | case 7: |
492 | 80cabfad | bellard | s->scr = val; |
493 | 80cabfad | bellard | break;
|
494 | 80cabfad | bellard | } |
495 | 80cabfad | bellard | } |
496 | 80cabfad | bellard | |
497 | b41a2cd1 | bellard | static uint32_t serial_ioport_read(void *opaque, uint32_t addr) |
498 | 80cabfad | bellard | { |
499 | b41a2cd1 | bellard | SerialState *s = opaque; |
500 | 80cabfad | bellard | uint32_t ret; |
501 | 80cabfad | bellard | |
502 | 80cabfad | bellard | addr &= 7;
|
503 | 80cabfad | bellard | switch(addr) {
|
504 | 80cabfad | bellard | default:
|
505 | 80cabfad | bellard | case 0: |
506 | 80cabfad | bellard | if (s->lcr & UART_LCR_DLAB) {
|
507 | 5fafdf24 | ths | ret = s->divider & 0xff;
|
508 | 80cabfad | bellard | } else {
|
509 | 81174dae | aliguori | if(s->fcr & UART_FCR_FE) {
|
510 | 81174dae | aliguori | ret = fifo_get(s,RECV_FIFO); |
511 | 81174dae | aliguori | if (s->recv_fifo.count == 0) |
512 | 81174dae | aliguori | s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); |
513 | 81174dae | aliguori | else
|
514 | 81174dae | aliguori | qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock (vm_clock) + s->char_transmit_time * 4);
|
515 | 81174dae | aliguori | s->timeout_ipending = 0;
|
516 | 81174dae | aliguori | } else {
|
517 | 81174dae | aliguori | ret = s->rbr; |
518 | 81174dae | aliguori | s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); |
519 | 81174dae | aliguori | } |
520 | b41a2cd1 | bellard | serial_update_irq(s); |
521 | b2a5160c | balrog | if (!(s->mcr & UART_MCR_LOOP)) {
|
522 | b2a5160c | balrog | /* in loopback mode, don't receive any data */
|
523 | b2a5160c | balrog | qemu_chr_accept_input(s->chr); |
524 | b2a5160c | balrog | } |
525 | 80cabfad | bellard | } |
526 | 80cabfad | bellard | break;
|
527 | 80cabfad | bellard | case 1: |
528 | 80cabfad | bellard | if (s->lcr & UART_LCR_DLAB) {
|
529 | 80cabfad | bellard | ret = (s->divider >> 8) & 0xff; |
530 | 80cabfad | bellard | } else {
|
531 | 80cabfad | bellard | ret = s->ier; |
532 | 80cabfad | bellard | } |
533 | 80cabfad | bellard | break;
|
534 | 80cabfad | bellard | case 2: |
535 | 80cabfad | bellard | ret = s->iir; |
536 | 80cabfad | bellard | s->thr_ipending = 0;
|
537 | b41a2cd1 | bellard | serial_update_irq(s); |
538 | 80cabfad | bellard | break;
|
539 | 80cabfad | bellard | case 3: |
540 | 80cabfad | bellard | ret = s->lcr; |
541 | 80cabfad | bellard | break;
|
542 | 80cabfad | bellard | case 4: |
543 | 80cabfad | bellard | ret = s->mcr; |
544 | 80cabfad | bellard | break;
|
545 | 80cabfad | bellard | case 5: |
546 | 80cabfad | bellard | ret = s->lsr; |
547 | 81174dae | aliguori | /* Clear break interrupt */
|
548 | 81174dae | aliguori | if (s->lsr & UART_LSR_BI) {
|
549 | 81174dae | aliguori | s->lsr &= ~UART_LSR_BI; |
550 | 81174dae | aliguori | serial_update_irq(s); |
551 | 81174dae | aliguori | } |
552 | 80cabfad | bellard | break;
|
553 | 80cabfad | bellard | case 6: |
554 | 80cabfad | bellard | if (s->mcr & UART_MCR_LOOP) {
|
555 | 80cabfad | bellard | /* in loopback, the modem output pins are connected to the
|
556 | 80cabfad | bellard | inputs */
|
557 | 80cabfad | bellard | ret = (s->mcr & 0x0c) << 4; |
558 | 80cabfad | bellard | ret |= (s->mcr & 0x02) << 3; |
559 | 80cabfad | bellard | ret |= (s->mcr & 0x01) << 5; |
560 | 80cabfad | bellard | } else {
|
561 | 81174dae | aliguori | if (s->poll_msl >= 0) |
562 | 81174dae | aliguori | serial_update_msl(s); |
563 | 80cabfad | bellard | ret = s->msr; |
564 | 81174dae | aliguori | /* Clear delta bits & msr int after read, if they were set */
|
565 | 81174dae | aliguori | if (s->msr & UART_MSR_ANY_DELTA) {
|
566 | 81174dae | aliguori | s->msr &= 0xF0;
|
567 | 81174dae | aliguori | serial_update_irq(s); |
568 | 81174dae | aliguori | } |
569 | 80cabfad | bellard | } |
570 | 80cabfad | bellard | break;
|
571 | 80cabfad | bellard | case 7: |
572 | 80cabfad | bellard | ret = s->scr; |
573 | 80cabfad | bellard | break;
|
574 | 80cabfad | bellard | } |
575 | 80cabfad | bellard | #ifdef DEBUG_SERIAL
|
576 | 80cabfad | bellard | printf("serial: read addr=0x%02x val=0x%02x\n", addr, ret);
|
577 | 80cabfad | bellard | #endif
|
578 | 80cabfad | bellard | return ret;
|
579 | 80cabfad | bellard | } |
580 | 80cabfad | bellard | |
581 | 82c643ff | bellard | static int serial_can_receive(SerialState *s) |
582 | 80cabfad | bellard | { |
583 | 81174dae | aliguori | if(s->fcr & UART_FCR_FE) {
|
584 | 81174dae | aliguori | if(s->recv_fifo.count < UART_FIFO_LENGTH)
|
585 | 81174dae | aliguori | /* Advertise (fifo.itl - fifo.count) bytes when count < ITL, and 1 if above. If UART_FIFO_LENGTH - fifo.count is
|
586 | 81174dae | aliguori | advertised the effect will be to almost always fill the fifo completely before the guest has a chance to respond,
|
587 | 81174dae | aliguori | effectively overriding the ITL that the guest has set. */
|
588 | 81174dae | aliguori | return (s->recv_fifo.count <= s->recv_fifo.itl) ? s->recv_fifo.itl - s->recv_fifo.count : 1; |
589 | 81174dae | aliguori | else
|
590 | 81174dae | aliguori | return 0; |
591 | 81174dae | aliguori | } else {
|
592 | 80cabfad | bellard | return !(s->lsr & UART_LSR_DR);
|
593 | 81174dae | aliguori | } |
594 | 80cabfad | bellard | } |
595 | 80cabfad | bellard | |
596 | 82c643ff | bellard | static void serial_receive_break(SerialState *s) |
597 | 80cabfad | bellard | { |
598 | 80cabfad | bellard | s->rbr = 0;
|
599 | 40ff1624 | Jason Wessel | /* When the LSR_DR is set a null byte is pushed into the fifo */
|
600 | 40ff1624 | Jason Wessel | fifo_put(s, RECV_FIFO, '\0');
|
601 | 80cabfad | bellard | s->lsr |= UART_LSR_BI | UART_LSR_DR; |
602 | b41a2cd1 | bellard | serial_update_irq(s); |
603 | 80cabfad | bellard | } |
604 | 80cabfad | bellard | |
605 | 81174dae | aliguori | /* There's data in recv_fifo and s->rbr has not been read for 4 char transmit times */
|
606 | 81174dae | aliguori | static void fifo_timeout_int (void *opaque) { |
607 | 81174dae | aliguori | SerialState *s = opaque; |
608 | 81174dae | aliguori | if (s->recv_fifo.count) {
|
609 | 81174dae | aliguori | s->timeout_ipending = 1;
|
610 | 81174dae | aliguori | serial_update_irq(s); |
611 | 81174dae | aliguori | } |
612 | 81174dae | aliguori | } |
613 | 81174dae | aliguori | |
614 | b41a2cd1 | bellard | static int serial_can_receive1(void *opaque) |
615 | 80cabfad | bellard | { |
616 | b41a2cd1 | bellard | SerialState *s = opaque; |
617 | b41a2cd1 | bellard | return serial_can_receive(s);
|
618 | b41a2cd1 | bellard | } |
619 | b41a2cd1 | bellard | |
620 | b41a2cd1 | bellard | static void serial_receive1(void *opaque, const uint8_t *buf, int size) |
621 | b41a2cd1 | bellard | { |
622 | b41a2cd1 | bellard | SerialState *s = opaque; |
623 | 81174dae | aliguori | if(s->fcr & UART_FCR_FE) {
|
624 | 81174dae | aliguori | int i;
|
625 | 81174dae | aliguori | for (i = 0; i < size; i++) { |
626 | 81174dae | aliguori | fifo_put(s, RECV_FIFO, buf[i]); |
627 | 81174dae | aliguori | } |
628 | 81174dae | aliguori | s->lsr |= UART_LSR_DR; |
629 | 81174dae | aliguori | /* call the timeout receive callback in 4 char transmit time */
|
630 | 81174dae | aliguori | qemu_mod_timer(s->fifo_timeout_timer, qemu_get_clock (vm_clock) + s->char_transmit_time * 4);
|
631 | 81174dae | aliguori | } else {
|
632 | 81174dae | aliguori | s->rbr = buf[0];
|
633 | 81174dae | aliguori | s->lsr |= UART_LSR_DR; |
634 | 81174dae | aliguori | } |
635 | 81174dae | aliguori | serial_update_irq(s); |
636 | b41a2cd1 | bellard | } |
637 | 80cabfad | bellard | |
638 | 82c643ff | bellard | static void serial_event(void *opaque, int event) |
639 | 82c643ff | bellard | { |
640 | 82c643ff | bellard | SerialState *s = opaque; |
641 | 81174dae | aliguori | #ifdef DEBUG_SERIAL
|
642 | 81174dae | aliguori | printf("serial: event %x\n", event);
|
643 | 81174dae | aliguori | #endif
|
644 | 82c643ff | bellard | if (event == CHR_EVENT_BREAK)
|
645 | 82c643ff | bellard | serial_receive_break(s); |
646 | 82c643ff | bellard | } |
647 | 82c643ff | bellard | |
648 | d4bfa4d7 | Juan Quintela | static void serial_pre_save(void *opaque) |
649 | 8738a8d0 | bellard | { |
650 | d4bfa4d7 | Juan Quintela | SerialState *s = opaque; |
651 | 747791f1 | Juan Quintela | s->fcr_vmstate = s->fcr; |
652 | 8738a8d0 | bellard | } |
653 | 8738a8d0 | bellard | |
654 | e59fb374 | Juan Quintela | static int serial_post_load(void *opaque, int version_id) |
655 | 747791f1 | Juan Quintela | { |
656 | 747791f1 | Juan Quintela | SerialState *s = opaque; |
657 | 81174dae | aliguori | |
658 | 4c18ce94 | Juan Quintela | if (version_id < 3) { |
659 | 4c18ce94 | Juan Quintela | s->fcr_vmstate = 0;
|
660 | 4c18ce94 | Juan Quintela | } |
661 | 81174dae | aliguori | /* Initialize fcr via setter to perform essential side-effects */
|
662 | 747791f1 | Juan Quintela | serial_ioport_write(s, 0x02, s->fcr_vmstate);
|
663 | 8738a8d0 | bellard | return 0; |
664 | 8738a8d0 | bellard | } |
665 | 8738a8d0 | bellard | |
666 | 747791f1 | Juan Quintela | static const VMStateDescription vmstate_serial = { |
667 | 747791f1 | Juan Quintela | .name = "serial",
|
668 | 747791f1 | Juan Quintela | .version_id = 3,
|
669 | 747791f1 | Juan Quintela | .minimum_version_id = 2,
|
670 | 747791f1 | Juan Quintela | .pre_save = serial_pre_save, |
671 | 747791f1 | Juan Quintela | .post_load = serial_post_load, |
672 | 747791f1 | Juan Quintela | .fields = (VMStateField []) { |
673 | 747791f1 | Juan Quintela | VMSTATE_UINT16_V(divider, SerialState, 2),
|
674 | 747791f1 | Juan Quintela | VMSTATE_UINT8(rbr, SerialState), |
675 | 747791f1 | Juan Quintela | VMSTATE_UINT8(ier, SerialState), |
676 | 747791f1 | Juan Quintela | VMSTATE_UINT8(iir, SerialState), |
677 | 747791f1 | Juan Quintela | VMSTATE_UINT8(lcr, SerialState), |
678 | 747791f1 | Juan Quintela | VMSTATE_UINT8(mcr, SerialState), |
679 | 747791f1 | Juan Quintela | VMSTATE_UINT8(lsr, SerialState), |
680 | 747791f1 | Juan Quintela | VMSTATE_UINT8(msr, SerialState), |
681 | 747791f1 | Juan Quintela | VMSTATE_UINT8(scr, SerialState), |
682 | 747791f1 | Juan Quintela | VMSTATE_UINT8_V(fcr_vmstate, SerialState, 3),
|
683 | 747791f1 | Juan Quintela | VMSTATE_END_OF_LIST() |
684 | 747791f1 | Juan Quintela | } |
685 | 747791f1 | Juan Quintela | }; |
686 | 747791f1 | Juan Quintela | |
687 | b2a5160c | balrog | static void serial_reset(void *opaque) |
688 | b2a5160c | balrog | { |
689 | b2a5160c | balrog | SerialState *s = opaque; |
690 | b2a5160c | balrog | |
691 | b2a5160c | balrog | s->rbr = 0;
|
692 | b2a5160c | balrog | s->ier = 0;
|
693 | b2a5160c | balrog | s->iir = UART_IIR_NO_INT; |
694 | b2a5160c | balrog | s->lcr = 0;
|
695 | b2a5160c | balrog | s->lsr = UART_LSR_TEMT | UART_LSR_THRE; |
696 | b2a5160c | balrog | s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS; |
697 | 718b8aec | Stefan Weil | /* Default to 9600 baud, 1 start bit, 8 data bits, 1 stop bit, no parity. */
|
698 | 81174dae | aliguori | s->divider = 0x0C;
|
699 | 81174dae | aliguori | s->mcr = UART_MCR_OUT2; |
700 | b2a5160c | balrog | s->scr = 0;
|
701 | 81174dae | aliguori | s->tsr_retry = 0;
|
702 | 718b8aec | Stefan Weil | s->char_transmit_time = (get_ticks_per_sec() / 9600) * 10; |
703 | 81174dae | aliguori | s->poll_msl = 0;
|
704 | 81174dae | aliguori | |
705 | 81174dae | aliguori | fifo_clear(s,RECV_FIFO); |
706 | 81174dae | aliguori | fifo_clear(s,XMIT_FIFO); |
707 | 81174dae | aliguori | |
708 | 81174dae | aliguori | s->last_xmit_ts = qemu_get_clock(vm_clock); |
709 | b2a5160c | balrog | |
710 | b2a5160c | balrog | s->thr_ipending = 0;
|
711 | b2a5160c | balrog | s->last_break_enable = 0;
|
712 | b2a5160c | balrog | qemu_irq_lower(s->irq); |
713 | b2a5160c | balrog | } |
714 | b2a5160c | balrog | |
715 | ac0be998 | Gerd Hoffmann | static void serial_init_core(SerialState *s) |
716 | 81174dae | aliguori | { |
717 | ac0be998 | Gerd Hoffmann | if (!s->chr) {
|
718 | 387f4a5a | Aurelien Jarno | fprintf(stderr, "Can't create serial device, empty char device\n");
|
719 | 387f4a5a | Aurelien Jarno | exit(1);
|
720 | 387f4a5a | Aurelien Jarno | } |
721 | 387f4a5a | Aurelien Jarno | |
722 | 81174dae | aliguori | s->modem_status_poll = qemu_new_timer(vm_clock, (QEMUTimerCB *) serial_update_msl, s); |
723 | 81174dae | aliguori | |
724 | 81174dae | aliguori | s->fifo_timeout_timer = qemu_new_timer(vm_clock, (QEMUTimerCB *) fifo_timeout_int, s); |
725 | 81174dae | aliguori | s->transmit_timer = qemu_new_timer(vm_clock, (QEMUTimerCB *) serial_xmit, s); |
726 | 81174dae | aliguori | |
727 | a08d4367 | Jan Kiszka | qemu_register_reset(serial_reset, s); |
728 | 81174dae | aliguori | |
729 | b47543c4 | aurel32 | qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1, |
730 | b47543c4 | aurel32 | serial_event, s); |
731 | 81174dae | aliguori | } |
732 | 81174dae | aliguori | |
733 | 038eaf82 | Stefan Weil | /* Change the main reference oscillator frequency. */
|
734 | 038eaf82 | Stefan Weil | void serial_set_frequency(SerialState *s, uint32_t frequency)
|
735 | 038eaf82 | Stefan Weil | { |
736 | 038eaf82 | Stefan Weil | s->baudbase = frequency; |
737 | 038eaf82 | Stefan Weil | serial_update_parameters(s); |
738 | 038eaf82 | Stefan Weil | } |
739 | 038eaf82 | Stefan Weil | |
740 | e8ee28fb | Gerd Hoffmann | static const int isa_serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; |
741 | e8ee28fb | Gerd Hoffmann | static const int isa_serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 }; |
742 | e8ee28fb | Gerd Hoffmann | |
743 | ac0be998 | Gerd Hoffmann | static int serial_isa_initfn(ISADevice *dev) |
744 | ac0be998 | Gerd Hoffmann | { |
745 | e8ee28fb | Gerd Hoffmann | static int index; |
746 | ac0be998 | Gerd Hoffmann | ISASerialState *isa = DO_UPCAST(ISASerialState, dev, dev); |
747 | ac0be998 | Gerd Hoffmann | SerialState *s = &isa->state; |
748 | ac0be998 | Gerd Hoffmann | |
749 | e8ee28fb | Gerd Hoffmann | if (isa->index == -1) |
750 | e8ee28fb | Gerd Hoffmann | isa->index = index; |
751 | e8ee28fb | Gerd Hoffmann | if (isa->index >= MAX_SERIAL_PORTS)
|
752 | e8ee28fb | Gerd Hoffmann | return -1; |
753 | e8ee28fb | Gerd Hoffmann | if (isa->iobase == -1) |
754 | e8ee28fb | Gerd Hoffmann | isa->iobase = isa_serial_io[isa->index]; |
755 | e8ee28fb | Gerd Hoffmann | if (isa->isairq == -1) |
756 | e8ee28fb | Gerd Hoffmann | isa->isairq = isa_serial_irq[isa->index]; |
757 | e8ee28fb | Gerd Hoffmann | index++; |
758 | e8ee28fb | Gerd Hoffmann | |
759 | ac0be998 | Gerd Hoffmann | s->baudbase = 115200;
|
760 | ac0be998 | Gerd Hoffmann | isa_init_irq(dev, &s->irq, isa->isairq); |
761 | ac0be998 | Gerd Hoffmann | serial_init_core(s); |
762 | ac0be998 | Gerd Hoffmann | vmstate_register(isa->iobase, &vmstate_serial, s); |
763 | ac0be998 | Gerd Hoffmann | |
764 | ac0be998 | Gerd Hoffmann | register_ioport_write(isa->iobase, 8, 1, serial_ioport_write, s); |
765 | ac0be998 | Gerd Hoffmann | register_ioport_read(isa->iobase, 8, 1, serial_ioport_read, s); |
766 | ac0be998 | Gerd Hoffmann | return 0; |
767 | ac0be998 | Gerd Hoffmann | } |
768 | ac0be998 | Gerd Hoffmann | |
769 | ac0be998 | Gerd Hoffmann | SerialState *serial_isa_init(int index, CharDriverState *chr)
|
770 | ac0be998 | Gerd Hoffmann | { |
771 | ac0be998 | Gerd Hoffmann | ISADevice *dev; |
772 | ac0be998 | Gerd Hoffmann | |
773 | ac0be998 | Gerd Hoffmann | dev = isa_create("isa-serial");
|
774 | e8ee28fb | Gerd Hoffmann | qdev_prop_set_uint32(&dev->qdev, "index", index);
|
775 | ac0be998 | Gerd Hoffmann | qdev_prop_set_chr(&dev->qdev, "chardev", chr);
|
776 | 5c17ca25 | Markus Armbruster | if (qdev_init(&dev->qdev) < 0) |
777 | ac0be998 | Gerd Hoffmann | return NULL; |
778 | ac0be998 | Gerd Hoffmann | return &DO_UPCAST(ISASerialState, dev, dev)->state;
|
779 | ac0be998 | Gerd Hoffmann | } |
780 | ac0be998 | Gerd Hoffmann | |
781 | b6cd0ea1 | aurel32 | SerialState *serial_init(int base, qemu_irq irq, int baudbase, |
782 | b6cd0ea1 | aurel32 | CharDriverState *chr) |
783 | b41a2cd1 | bellard | { |
784 | b41a2cd1 | bellard | SerialState *s; |
785 | b41a2cd1 | bellard | |
786 | b41a2cd1 | bellard | s = qemu_mallocz(sizeof(SerialState));
|
787 | 6936bfe5 | aurel32 | |
788 | ac0be998 | Gerd Hoffmann | s->irq = irq; |
789 | ac0be998 | Gerd Hoffmann | s->baudbase = baudbase; |
790 | ac0be998 | Gerd Hoffmann | s->chr = chr; |
791 | ac0be998 | Gerd Hoffmann | serial_init_core(s); |
792 | b41a2cd1 | bellard | |
793 | 747791f1 | Juan Quintela | vmstate_register(base, &vmstate_serial, s); |
794 | 8738a8d0 | bellard | |
795 | b41a2cd1 | bellard | register_ioport_write(base, 8, 1, serial_ioport_write, s); |
796 | b41a2cd1 | bellard | register_ioport_read(base, 8, 1, serial_ioport_read, s); |
797 | b41a2cd1 | bellard | return s;
|
798 | 80cabfad | bellard | } |
799 | e5d13e2f | bellard | |
800 | e5d13e2f | bellard | /* Memory mapped interface */
|
801 | c227f099 | Anthony Liguori | static uint32_t serial_mm_readb(void *opaque, target_phys_addr_t addr) |
802 | e5d13e2f | bellard | { |
803 | e5d13e2f | bellard | SerialState *s = opaque; |
804 | e5d13e2f | bellard | |
805 | 8da3ff18 | pbrook | return serial_ioport_read(s, addr >> s->it_shift) & 0xFF; |
806 | e5d13e2f | bellard | } |
807 | e5d13e2f | bellard | |
808 | c227f099 | Anthony Liguori | static void serial_mm_writeb(void *opaque, target_phys_addr_t addr, |
809 | 802670e6 | Blue Swirl | uint32_t value) |
810 | e5d13e2f | bellard | { |
811 | e5d13e2f | bellard | SerialState *s = opaque; |
812 | e5d13e2f | bellard | |
813 | 8da3ff18 | pbrook | serial_ioport_write(s, addr >> s->it_shift, value & 0xFF);
|
814 | e5d13e2f | bellard | } |
815 | e5d13e2f | bellard | |
816 | c227f099 | Anthony Liguori | static uint32_t serial_mm_readw(void *opaque, target_phys_addr_t addr) |
817 | e5d13e2f | bellard | { |
818 | e5d13e2f | bellard | SerialState *s = opaque; |
819 | e918ee04 | ths | uint32_t val; |
820 | e5d13e2f | bellard | |
821 | 8da3ff18 | pbrook | val = serial_ioport_read(s, addr >> s->it_shift) & 0xFFFF;
|
822 | e918ee04 | ths | #ifdef TARGET_WORDS_BIGENDIAN
|
823 | e918ee04 | ths | val = bswap16(val); |
824 | e918ee04 | ths | #endif
|
825 | e918ee04 | ths | return val;
|
826 | e5d13e2f | bellard | } |
827 | e5d13e2f | bellard | |
828 | c227f099 | Anthony Liguori | static void serial_mm_writew(void *opaque, target_phys_addr_t addr, |
829 | 802670e6 | Blue Swirl | uint32_t value) |
830 | e5d13e2f | bellard | { |
831 | e5d13e2f | bellard | SerialState *s = opaque; |
832 | e918ee04 | ths | #ifdef TARGET_WORDS_BIGENDIAN
|
833 | e918ee04 | ths | value = bswap16(value); |
834 | e918ee04 | ths | #endif
|
835 | 8da3ff18 | pbrook | serial_ioport_write(s, addr >> s->it_shift, value & 0xFFFF);
|
836 | e5d13e2f | bellard | } |
837 | e5d13e2f | bellard | |
838 | c227f099 | Anthony Liguori | static uint32_t serial_mm_readl(void *opaque, target_phys_addr_t addr) |
839 | e5d13e2f | bellard | { |
840 | e5d13e2f | bellard | SerialState *s = opaque; |
841 | e918ee04 | ths | uint32_t val; |
842 | e5d13e2f | bellard | |
843 | 8da3ff18 | pbrook | val = serial_ioport_read(s, addr >> s->it_shift); |
844 | e918ee04 | ths | #ifdef TARGET_WORDS_BIGENDIAN
|
845 | e918ee04 | ths | val = bswap32(val); |
846 | e918ee04 | ths | #endif
|
847 | e918ee04 | ths | return val;
|
848 | e5d13e2f | bellard | } |
849 | e5d13e2f | bellard | |
850 | c227f099 | Anthony Liguori | static void serial_mm_writel(void *opaque, target_phys_addr_t addr, |
851 | 802670e6 | Blue Swirl | uint32_t value) |
852 | e5d13e2f | bellard | { |
853 | e5d13e2f | bellard | SerialState *s = opaque; |
854 | e918ee04 | ths | #ifdef TARGET_WORDS_BIGENDIAN
|
855 | e918ee04 | ths | value = bswap32(value); |
856 | e918ee04 | ths | #endif
|
857 | 8da3ff18 | pbrook | serial_ioport_write(s, addr >> s->it_shift, value); |
858 | e5d13e2f | bellard | } |
859 | e5d13e2f | bellard | |
860 | d60efc6b | Blue Swirl | static CPUReadMemoryFunc * const serial_mm_read[] = { |
861 | e5d13e2f | bellard | &serial_mm_readb, |
862 | e5d13e2f | bellard | &serial_mm_readw, |
863 | e5d13e2f | bellard | &serial_mm_readl, |
864 | e5d13e2f | bellard | }; |
865 | e5d13e2f | bellard | |
866 | d60efc6b | Blue Swirl | static CPUWriteMemoryFunc * const serial_mm_write[] = { |
867 | e5d13e2f | bellard | &serial_mm_writeb, |
868 | e5d13e2f | bellard | &serial_mm_writew, |
869 | e5d13e2f | bellard | &serial_mm_writel, |
870 | e5d13e2f | bellard | }; |
871 | e5d13e2f | bellard | |
872 | c227f099 | Anthony Liguori | SerialState *serial_mm_init (target_phys_addr_t base, int it_shift,
|
873 | b6cd0ea1 | aurel32 | qemu_irq irq, int baudbase,
|
874 | b6cd0ea1 | aurel32 | CharDriverState *chr, int ioregister)
|
875 | e5d13e2f | bellard | { |
876 | e5d13e2f | bellard | SerialState *s; |
877 | e5d13e2f | bellard | int s_io_memory;
|
878 | e5d13e2f | bellard | |
879 | e5d13e2f | bellard | s = qemu_mallocz(sizeof(SerialState));
|
880 | 81174dae | aliguori | |
881 | e5d13e2f | bellard | s->it_shift = it_shift; |
882 | ac0be998 | Gerd Hoffmann | s->irq = irq; |
883 | ac0be998 | Gerd Hoffmann | s->baudbase = baudbase; |
884 | ac0be998 | Gerd Hoffmann | s->chr = chr; |
885 | e5d13e2f | bellard | |
886 | ac0be998 | Gerd Hoffmann | serial_init_core(s); |
887 | 747791f1 | Juan Quintela | vmstate_register(base, &vmstate_serial, s); |
888 | e5d13e2f | bellard | |
889 | a4bc3afc | ths | if (ioregister) {
|
890 | 1eed09cb | Avi Kivity | s_io_memory = cpu_register_io_memory(serial_mm_read, |
891 | a4bc3afc | ths | serial_mm_write, s); |
892 | a4bc3afc | ths | cpu_register_physical_memory(base, 8 << it_shift, s_io_memory);
|
893 | a4bc3afc | ths | } |
894 | 81174dae | aliguori | serial_update_msl(s); |
895 | e5d13e2f | bellard | return s;
|
896 | e5d13e2f | bellard | } |
897 | ac0be998 | Gerd Hoffmann | |
898 | ac0be998 | Gerd Hoffmann | static ISADeviceInfo serial_isa_info = {
|
899 | ac0be998 | Gerd Hoffmann | .qdev.name = "isa-serial",
|
900 | ac0be998 | Gerd Hoffmann | .qdev.size = sizeof(ISASerialState),
|
901 | ac0be998 | Gerd Hoffmann | .init = serial_isa_initfn, |
902 | ac0be998 | Gerd Hoffmann | .qdev.props = (Property[]) { |
903 | 51954d56 | Gerd Hoffmann | DEFINE_PROP_UINT32("index", ISASerialState, index, -1), |
904 | e8ee28fb | Gerd Hoffmann | DEFINE_PROP_HEX32("iobase", ISASerialState, iobase, -1), |
905 | e8ee28fb | Gerd Hoffmann | DEFINE_PROP_UINT32("irq", ISASerialState, isairq, -1), |
906 | ac0be998 | Gerd Hoffmann | DEFINE_PROP_CHR("chardev", ISASerialState, state.chr),
|
907 | ac0be998 | Gerd Hoffmann | DEFINE_PROP_END_OF_LIST(), |
908 | ac0be998 | Gerd Hoffmann | }, |
909 | ac0be998 | Gerd Hoffmann | }; |
910 | ac0be998 | Gerd Hoffmann | |
911 | ac0be998 | Gerd Hoffmann | static void serial_register_devices(void) |
912 | ac0be998 | Gerd Hoffmann | { |
913 | ac0be998 | Gerd Hoffmann | isa_qdev_register(&serial_isa_info); |
914 | ac0be998 | Gerd Hoffmann | } |
915 | ac0be998 | Gerd Hoffmann | |
916 | ac0be998 | Gerd Hoffmann | device_init(serial_register_devices) |