Commit b2a5160c9f11cc5fe64230a6ec8f95e3aecfeacf
1 parent
e41c0f26
Add serial loopback mode (patch from Hervé Poussineau).
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3973 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
39 additions
and
8 deletions
hw/serial.c
... | ... | @@ -93,6 +93,8 @@ struct SerialState { |
93 | 93 | int it_shift; |
94 | 94 | }; |
95 | 95 | |
96 | +static void serial_receive_byte(SerialState *s, int ch); | |
97 | + | |
96 | 98 | static void serial_update_irq(SerialState *s) |
97 | 99 | { |
98 | 100 | if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) { |
... | ... | @@ -161,11 +163,18 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) |
161 | 163 | s->lsr &= ~UART_LSR_THRE; |
162 | 164 | serial_update_irq(s); |
163 | 165 | ch = val; |
164 | - qemu_chr_write(s->chr, &ch, 1); | |
166 | + if (!(s->mcr & UART_MCR_LOOP)) { | |
167 | + /* when not in loopback mode, send the char */ | |
168 | + qemu_chr_write(s->chr, &ch, 1); | |
169 | + } | |
165 | 170 | s->thr_ipending = 1; |
166 | 171 | s->lsr |= UART_LSR_THRE; |
167 | 172 | s->lsr |= UART_LSR_TEMT; |
168 | 173 | serial_update_irq(s); |
174 | + if (s->mcr & UART_MCR_LOOP) { | |
175 | + /* in loopback mode, say that we just received a char */ | |
176 | + serial_receive_byte(s, ch); | |
177 | + } | |
169 | 178 | } |
170 | 179 | break; |
171 | 180 | case 1: |
... | ... | @@ -223,7 +232,10 @@ static uint32_t serial_ioport_read(void *opaque, uint32_t addr) |
223 | 232 | ret = s->rbr; |
224 | 233 | s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); |
225 | 234 | serial_update_irq(s); |
226 | - qemu_chr_accept_input(s->chr); | |
235 | + if (!(s->mcr & UART_MCR_LOOP)) { | |
236 | + /* in loopback mode, don't receive any data */ | |
237 | + qemu_chr_accept_input(s->chr); | |
238 | + } | |
227 | 239 | } |
228 | 240 | break; |
229 | 241 | case 1: |
... | ... | @@ -346,6 +358,25 @@ static int serial_load(QEMUFile *f, void *opaque, int version_id) |
346 | 358 | return 0; |
347 | 359 | } |
348 | 360 | |
361 | +static void serial_reset(void *opaque) | |
362 | +{ | |
363 | + SerialState *s = opaque; | |
364 | + | |
365 | + s->divider = 0; | |
366 | + s->rbr = 0; | |
367 | + s->ier = 0; | |
368 | + s->iir = UART_IIR_NO_INT; | |
369 | + s->lcr = 0; | |
370 | + s->mcr = 0; | |
371 | + s->lsr = UART_LSR_TEMT | UART_LSR_THRE; | |
372 | + s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS; | |
373 | + s->scr = 0; | |
374 | + | |
375 | + s->thr_ipending = 0; | |
376 | + s->last_break_enable = 0; | |
377 | + qemu_irq_lower(s->irq); | |
378 | +} | |
379 | + | |
349 | 380 | /* If fd is zero, it means that the serial device uses the console */ |
350 | 381 | SerialState *serial_init(int base, qemu_irq irq, CharDriverState *chr) |
351 | 382 | { |
... | ... | @@ -355,9 +386,9 @@ SerialState *serial_init(int base, qemu_irq irq, CharDriverState *chr) |
355 | 386 | if (!s) |
356 | 387 | return NULL; |
357 | 388 | s->irq = irq; |
358 | - s->lsr = UART_LSR_TEMT | UART_LSR_THRE; | |
359 | - s->iir = UART_IIR_NO_INT; | |
360 | - s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS; | |
389 | + | |
390 | + qemu_register_reset(serial_reset, s); | |
391 | + serial_reset(s); | |
361 | 392 | |
362 | 393 | register_savevm("serial", base, 2, serial_save, serial_load, s); |
363 | 394 | |
... | ... | @@ -452,12 +483,12 @@ SerialState *serial_mm_init (target_phys_addr_t base, int it_shift, |
452 | 483 | if (!s) |
453 | 484 | return NULL; |
454 | 485 | s->irq = irq; |
455 | - s->lsr = UART_LSR_TEMT | UART_LSR_THRE; | |
456 | - s->iir = UART_IIR_NO_INT; | |
457 | - s->msr = UART_MSR_DCD | UART_MSR_DSR | UART_MSR_CTS; | |
458 | 486 | s->base = base; |
459 | 487 | s->it_shift = it_shift; |
460 | 488 | |
489 | + qemu_register_reset(serial_reset, s); | |
490 | + serial_reset(s); | |
491 | + | |
461 | 492 | register_savevm("serial", base, 2, serial_save, serial_load, s); |
462 | 493 | |
463 | 494 | if (ioregister) { | ... | ... |