Index: vl.c =================================================================== RCS file: /home/Cvsroot/qemu/vl.c,v retrieving revision 1.1.1.1 diff -B -b -U3 -r1.1.1.1 vl.c --- vl.c 14 Jan 2006 13:19:59 -0000 1.1.1.1 +++ vl.c 15 Jan 2006 20:26:54 -0000 @@ -1468,9 +1468,11 @@ tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP |INLCR|IGNCR|ICRNL|IXON); - tty.c_oflag |= OPOST; +// TODO: OPOST clear or set ? +// tty.c_oflag |= OPOST; + tty.c_oflag = 0; tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG); - tty.c_cflag &= ~(CSIZE|PARENB|PARODD|CRTSCTS); + tty.c_cflag &= ~(CSIZE|PARENB|PARODD|CRTSCTS|CSTOPB); switch(data_bits) { default: case 8: @@ -1486,6 +1488,11 @@ tty.c_cflag |= CS5; break; } + + if(stop_bits > 1) + tty.c_cflag |= CSTOPB; + tty.c_cflag |= CREAD | CLOCAL; + switch(parity) { default: case 'N': @@ -1516,10 +1523,57 @@ case CHR_IOCTL_SERIAL_SET_BREAK: { int enable = *(int *)arg; +#if defined(TIOCSBRK) && !defined(_WIN32) + // Linux should use TIOCSBRK and TIOCCBRK + if(ioctl(s->fd_in, enable ? TIOCSBRK : TIOCCBRK) == 0) + break; + // don't care about pending interrupt ... + if(errno == EINTR) + break; + perror("CHR_IOCTL_SERIAL_SET_BREAK fallback to tcsendbreak()"); +#endif + // here arg=1 is used and in the linux tty driver the code is: + // send_break(tty, arg ? arg*100 : 250); if (enable) tcsendbreak(s->fd_in, 1); } break; + + case CHR_IOCTL_SERIAL_SET_MSTAT: +#if defined(TIOCMBIS) && !defined(_WIN32) + { + int tiomsk = TIOCM_DTR | TIOCM_RTS; + int tiobit = 0; + if((*(int *)arg) & CHR_IOCTL_SERIAL_DTR) tiobit |= TIOCM_DTR; + if((*(int *)arg) & CHR_IOCTL_SERIAL_RTS) tiobit |= TIOCM_RTS; + + if(tiobit != 0) + ioctl(s->fd_in, TIOCMBIS, &tiobit); + if(tiobit != tiomsk) { + tiobit = (~tiobit) & tiomsk; + ioctl(s->fd_in, TIOCMBIC, &tiobit); + } + } +#endif + break; + + case CHR_IOCTL_SERIAL_GET_MSTAT: + { + int tiores = -1; +#if defined(TIOCMGET) && !defined(_WIN32) + int tiobit; + if( ioctl(s->fd_in, TIOCMGET, &tiobit) == 0 ) { + tiores = 0; + if(tiobit & TIOCM_CTS) tiores |= CHR_IOCTL_SERIAL_CTS; + if(tiobit & TIOCM_CAR) tiores |= CHR_IOCTL_SERIAL_DCD; + if(tiobit & TIOCM_RNG) tiores |= CHR_IOCTL_SERIAL_RI; + if(tiobit & TIOCM_DSR) tiores |= CHR_IOCTL_SERIAL_DSR; + } +#endif + *(int *)arg = tiores; + } + break; + default: return -ENOTSUP; } @@ -2620,19 +2674,19 @@ nd->vlan = vlan; nb_nics++; ret = 0; - } else - if (!strcmp(device, "none")) { + } + else if (!strcmp(device, "none")) { /* does nothing. It is needed to signal that no network cards are wanted */ ret = 0; - } else + } #ifdef CONFIG_SLIRP - if (!strcmp(device, "user")) { + else if (!strcmp(device, "user")) { ret = net_slirp_init(vlan); - } else + } #endif #ifndef _WIN32 - if (!strcmp(device, "tap")) { + else if (!strcmp(device, "tap")) { char ifname[64]; char setup_script[1024]; int fd; @@ -2648,8 +2702,8 @@ } ret = net_tap_init(vlan, ifname, setup_script); } - } else - if (!strcmp(device, "socket")) { + } + else if (!strcmp(device, "socket")) { if (get_param_value(buf, sizeof(buf), "fd", p) > 0) { int fd; fd = strtol(buf, NULL, 0); @@ -2666,8 +2720,9 @@ fprintf(stderr, "Unknown socket options: %s\n", p); return -1; } - } else + } #endif + else { fprintf(stderr, "Unknown network device: %s\n", device); return -1; @@ -3655,7 +3710,7 @@ return 0; } -QEMUMachine *find_machine(const char *name) +static QEMUMachine *find_machine(const char *name) { QEMUMachine *m; @@ -3669,7 +3724,7 @@ /***********************************************************/ /* main execution loop */ -void gui_update(void *opaque) +static void gui_update(void *opaque) { display_state.dpy_refresh(&display_state); qemu_mod_timer(gui_timer, GUI_REFRESH_INTERVAL + qemu_get_clock(rt_clock)); @@ -3886,6 +3941,8 @@ /* real time timers */ qemu_run_timers(&active_timers[QEMU_TIMER_REALTIME], qemu_get_clock(rt_clock)); + + // TODO: add a timer to check serial lines for Modem-Status-Register changes } static CPUState *cur_cpu; Index: vl.h =================================================================== RCS file: /home/Cvsroot/qemu/vl.h,v retrieving revision 1.1.1.1 diff -B -b -U3 -r1.1.1.1 vl.h --- vl.h 14 Jan 2006 13:19:59 -0000 1.1.1.1 +++ vl.h 13 Jan 2006 13:43:32 -0000 @@ -219,8 +219,21 @@ int stop_bits; } QEMUSerialSetParams; +// turn BREAK on/off #define CHR_IOCTL_SERIAL_SET_BREAK 2 +// set modemstatus 1:=DTR 2:=RTS (like the two lower bits in MCR) +#define CHR_IOCTL_SERIAL_SET_MSTAT 8 + #define CHR_IOCTL_SERIAL_DTR 0x01 + #define CHR_IOCTL_SERIAL_RTS 0x02 + +// get modemstatus 0x80:=DCD 0x40:=RI 0x20:=DSR 0x10:=CTS (see MSR) +#define CHR_IOCTL_SERIAL_GET_MSTAT 9 + #define CHR_IOCTL_SERIAL_DCD 0x80 + #define CHR_IOCTL_SERIAL_RI 0x40 + #define CHR_IOCTL_SERIAL_DSR 0x20 + #define CHR_IOCTL_SERIAL_CTS 0x10 + #define CHR_IOCTL_PP_READ_DATA 3 #define CHR_IOCTL_PP_WRITE_DATA 4 #define CHR_IOCTL_PP_READ_CONTROL 5 Index: hw/serial.c =================================================================== RCS file: /home/Cvsroot/qemu/hw/serial.c,v retrieving revision 1.1.1.1 diff -B -b -U3 -r1.1.1.1 serial.c --- hw/serial.c 14 Jan 2006 13:19:59 -0000 1.1.1.1 +++ hw/serial.c 15 Jan 2006 18:28:38 -0000 @@ -23,7 +23,7 @@ */ #include "vl.h" -//#define DEBUG_SERIAL +#define DEBUG_SERIAL_ #define UART_LCR_DLAB 0x80 /* Divisor latch access bit */ @@ -71,7 +71,7 @@ #define UART_LSR_DR 0x01 /* Receiver data ready */ struct SerialState { - uint8_t divider; + uint16_t divider; uint8_t rbr; /* receive register */ uint8_t ier; uint8_t iir; /* read only */ @@ -101,7 +101,8 @@ } else { s->iir = UART_IIR_NO_INT; } - if (s->iir != UART_IIR_NO_INT) { + // mcr OUT2 is used to enable interupts! + if (s->iir != UART_IIR_NO_INT && (s->mcr & 8)) { s->set_irq(s->irq_opaque, s->irq, 1); } else { s->set_irq(s->irq_opaque, s->irq, 0); @@ -144,6 +145,7 @@ { SerialState *s = opaque; unsigned char ch; + unsigned int idiv; addr &= 7; #ifdef DEBUG_SERIAL @@ -153,13 +155,17 @@ default: case 0: if (s->lcr & UART_LCR_DLAB) { - s->divider = (s->divider & 0xff00) | val; + idiv = (s->divider & 0xff00) | val; + if(idiv != s->divider) { + s->divider = idiv; serial_update_parameters(s); + } } else { s->thr_ipending = 0; s->lsr &= ~UART_LSR_THRE; serial_update_irq(s); ch = val; +// printf("serial: char %x '%c'\n", val, val >= 32 && val < 127 ? val : '?'); qemu_chr_write(s->chr, &ch, 1); s->thr_ipending = 1; s->lsr |= UART_LSR_THRE; @@ -169,8 +175,11 @@ break; case 1: if (s->lcr & UART_LCR_DLAB) { - s->divider = (s->divider & 0x00ff) | (val << 8); + idiv = (s->divider & 0x00ff) | (val << 8); + if(idiv != s->divider) { + s->divider = idiv; serial_update_parameters(s); + } } else { s->ier = val & 0x0f; if (s->lsr & UART_LSR_THRE) { @@ -184,18 +193,29 @@ case 3: { int break_enable; + if( /*val == 0 ||*/ (s->lcr & 0x3f) != (val & 0x3f)) { s->lcr = val; serial_update_parameters(s); + } + else + s->lcr = val; break_enable = (val >> 6) & 1; if (break_enable != s->last_break_enable) { s->last_break_enable = break_enable; +// printf("serial: %s BREAK\n", break_enable == 0 ? "clear" : "set"); qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK, &break_enable); } } break; case 4: + { // MCR: only the lower 2 bits (DTR and RTS) are supported + int iBit = val & 3; + if((s->mcr & 3) != iBit) + qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_MSTAT, &iBit); + } s->mcr = val & 0x1f; +// printf("serial: modem control %x DTR=%s DSR=%s\n", val, val & 1 ? "on" : "off", val & 2 ? "on" : "off"); break; case 5: break; @@ -256,6 +276,15 @@ ret |= (s->mcr & 0x02) << 3; ret |= (s->mcr & 0x01) << 5; } else { + // TODO: should generate interrupts + int iBit; + qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_GET_MSTAT, &iBit); + if(iBit != -1) { + iBit &= 0xf0; + ret = (((s->msr ^ iBit)) >> 4) & 0xf; + // printf("TIO status bits %x old %x delta %x\n", iBit, s->msr, ret); + s->msr = iBit | ret; + } ret = s->msr; } break; @@ -272,6 +301,7 @@ static int serial_can_receive(SerialState *s) { return !(s->lsr & UART_LSR_DR); +// return (s->lsr & UART_LSR_DR) ? 0 : 16; } static void serial_receive_byte(SerialState *s, int ch) @@ -311,7 +341,7 @@ { SerialState *s = opaque; - qemu_put_8s(f,&s->divider); + qemu_put_be16(f,s->divider); qemu_put_8s(f,&s->rbr); qemu_put_8s(f,&s->ier); qemu_put_8s(f,&s->iir); @@ -325,11 +355,15 @@ static int serial_load(QEMUFile *f, void *opaque, int version_id) { SerialState *s = opaque; + int iBit; - if(version_id != 1) + if(version_id == 1) + s->divider = qemu_get_byte(f); + else if(version_id == 2) + s->divider = qemu_get_be16(f); + else return -EINVAL; - qemu_get_8s(f,&s->divider); qemu_get_8s(f,&s->rbr); qemu_get_8s(f,&s->ier); qemu_get_8s(f,&s->iir); @@ -339,6 +373,10 @@ qemu_get_8s(f,&s->msr); qemu_get_8s(f,&s->scr); + // restore last serial line state ... + serial_update_parameters(s); + iBit = s->mcr & 3; + qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_MSTAT, &iBit); return 0; } @@ -357,7 +395,7 @@ s->lsr = UART_LSR_TEMT | UART_LSR_THRE; s->iir = UART_IIR_NO_INT; - register_savevm("serial", base, 1, serial_save, serial_load, s); + register_savevm("serial", base, 2, serial_save, serial_load, s); register_ioport_write(base, 8, 1, serial_ioport_write, s); register_ioport_read(base, 8, 1, serial_ioport_read, s);