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,6 +93,8 @@ struct SerialState { | ||
93 | int it_shift; | 93 | int it_shift; |
94 | }; | 94 | }; |
95 | 95 | ||
96 | +static void serial_receive_byte(SerialState *s, int ch); | ||
97 | + | ||
96 | static void serial_update_irq(SerialState *s) | 98 | static void serial_update_irq(SerialState *s) |
97 | { | 99 | { |
98 | if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) { | 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,11 +163,18 @@ static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) | ||
161 | s->lsr &= ~UART_LSR_THRE; | 163 | s->lsr &= ~UART_LSR_THRE; |
162 | serial_update_irq(s); | 164 | serial_update_irq(s); |
163 | ch = val; | 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 | s->thr_ipending = 1; | 170 | s->thr_ipending = 1; |
166 | s->lsr |= UART_LSR_THRE; | 171 | s->lsr |= UART_LSR_THRE; |
167 | s->lsr |= UART_LSR_TEMT; | 172 | s->lsr |= UART_LSR_TEMT; |
168 | serial_update_irq(s); | 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 | break; | 179 | break; |
171 | case 1: | 180 | case 1: |
@@ -223,7 +232,10 @@ static uint32_t serial_ioport_read(void *opaque, uint32_t addr) | @@ -223,7 +232,10 @@ static uint32_t serial_ioport_read(void *opaque, uint32_t addr) | ||
223 | ret = s->rbr; | 232 | ret = s->rbr; |
224 | s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); | 233 | s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); |
225 | serial_update_irq(s); | 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 | break; | 240 | break; |
229 | case 1: | 241 | case 1: |
@@ -346,6 +358,25 @@ static int serial_load(QEMUFile *f, void *opaque, int version_id) | @@ -346,6 +358,25 @@ static int serial_load(QEMUFile *f, void *opaque, int version_id) | ||
346 | return 0; | 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 | /* If fd is zero, it means that the serial device uses the console */ | 380 | /* If fd is zero, it means that the serial device uses the console */ |
350 | SerialState *serial_init(int base, qemu_irq irq, CharDriverState *chr) | 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,9 +386,9 @@ SerialState *serial_init(int base, qemu_irq irq, CharDriverState *chr) | ||
355 | if (!s) | 386 | if (!s) |
356 | return NULL; | 387 | return NULL; |
357 | s->irq = irq; | 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 | register_savevm("serial", base, 2, serial_save, serial_load, s); | 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,12 +483,12 @@ SerialState *serial_mm_init (target_phys_addr_t base, int it_shift, | ||
452 | if (!s) | 483 | if (!s) |
453 | return NULL; | 484 | return NULL; |
454 | s->irq = irq; | 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 | s->base = base; | 486 | s->base = base; |
459 | s->it_shift = it_shift; | 487 | s->it_shift = it_shift; |
460 | 488 | ||
489 | + qemu_register_reset(serial_reset, s); | ||
490 | + serial_reset(s); | ||
491 | + | ||
461 | register_savevm("serial", base, 2, serial_save, serial_load, s); | 492 | register_savevm("serial", base, 2, serial_save, serial_load, s); |
462 | 493 | ||
463 | if (ioregister) { | 494 | if (ioregister) { |