[prev in list] [next in list] [prev in thread] [next in thread]
List: qemu-devel
Subject: [Qemu-devel] [PATCH] 1st improvement of serial.c (Modemstatus etc.)
From: Juergen Pfennig <info () j-pfennig ! de>
Date: 2006-01-16 14:19:12
Message-ID: 200601161519.12511.info () j-pfennig ! de
[Download RAW message or body]
Hello,
as I promised I will send QEMU patches even if I don't know about QEMU's patch
policy ... Here a more complex one:
serial.c (and vl.h):
(1) sending break
(2) outgoing modem state
(3) incomming modem state
(4) CHECK THIS: support to disable interrupts (a PC feature)
in vl.c (and vl.h):
(1) host serial implementation extended
(2) CHECK THIS: post-processing disabled
(3) the if/else cascade for -net was cleaned-up a little
This patch is sufficent for win2003 to detect and support a smartcard reader
like towitoko chipdrive micro.
The driver has still missing features like parity error detection, modem
status change interrupts and 16650 support!
Yours Jürgen
["patch2_serial" (text/x-diff)]
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);
_______________________________________________
Qemu-devel mailing list
Qemu-devel@nongnu.org
http://lists.nongnu.org/mailman/listinfo/qemu-devel
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic