*/
#include "qemu-common.h"
#include "net.h"
+#include "monitor.h"
#include "console.h"
#include "sysemu.h"
#include "qemu-timer.h"
#include "block.h"
#include "hw/usb.h"
#include "hw/baum.h"
+#include "hw/msmouse.h"
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <netdb.h>
#include <sys/select.h>
-#ifdef _BSD
+#ifdef HOST_BSD
#include <sys/stat.h>
#ifdef __FreeBSD__
#include <libutil.h>
+#include <dev/ppbus/ppi.h>
+#include <dev/ppbus/ppbconf.h>
+#elif defined(__DragonFly__)
+#include <libutil.h>
+#include <dev/misc/ppi/ppi.h>
+#include <bus/ppbus/ppbconf.h>
#else
#include <util.h>
#endif
/***********************************************************/
/* character device */
+static TAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs =
+ TAILQ_HEAD_INITIALIZER(chardevs);
+static int initial_reset_issued;
+
static void qemu_chr_event(CharDriverState *s, int event)
{
if (!s->chr_event)
void qemu_chr_reset(CharDriverState *s)
{
- if (s->bh == NULL) {
+ if (s->bh == NULL && initial_reset_issued) {
s->bh = qemu_bh_new(qemu_chr_reset_bh, s);
qemu_bh_schedule(s->bh);
}
}
+void qemu_chr_initial_reset(void)
+{
+ CharDriverState *chr;
+
+ initial_reset_issued = 1;
+
+ TAILQ_FOREACH(chr, &chardevs, next) {
+ qemu_chr_reset(chr);
+ }
+}
+
int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len)
{
return s->chr_write(s, buf, len);
CharDriverState *chr;
chr = qemu_mallocz(sizeof(CharDriverState));
- if (!chr)
- return NULL;
chr->chr_write = null_chr_write;
return chr;
}
/* MUX driver for serial I/O splitting */
-static int term_timestamps;
-static int64_t term_timestamps_start;
#define MAX_MUX 4
#define MUX_BUFFER_SIZE 32 /* Must be a power of 2. */
#define MUX_BUFFER_MASK (MUX_BUFFER_SIZE - 1)
IOEventHandler *chr_event[MAX_MUX];
void *ext_opaque[MAX_MUX];
CharDriverState *drv;
- unsigned char buffer[MUX_BUFFER_SIZE];
- int prod;
- int cons;
int mux_cnt;
int term_got_escape;
int max_size;
+ /* Intermediate input buffer allows to catch escape sequences even if the
+ currently active device is not accepting any input - but only until it
+ is full as well. */
+ unsigned char buffer[MAX_MUX][MUX_BUFFER_SIZE];
+ int prod[MAX_MUX];
+ int cons[MAX_MUX];
+ int timestamps;
+ int linestart;
+ int64_t timestamps_start;
} MuxDriver;
{
MuxDriver *d = chr->opaque;
int ret;
- if (!term_timestamps) {
+ if (!d->timestamps) {
ret = d->drv->chr_write(d->drv, buf, len);
} else {
int i;
ret = 0;
- for(i = 0; i < len; i++) {
- ret += d->drv->chr_write(d->drv, buf+i, 1);
- if (buf[i] == '\n') {
+ for (i = 0; i < len; i++) {
+ if (d->linestart) {
char buf1[64];
int64_t ti;
int secs;
ti = qemu_get_clock(rt_clock);
- if (term_timestamps_start == -1)
- term_timestamps_start = ti;
- ti -= term_timestamps_start;
- secs = ti / 1000000000;
+ if (d->timestamps_start == -1)
+ d->timestamps_start = ti;
+ ti -= d->timestamps_start;
+ secs = ti / 1000;
snprintf(buf1, sizeof(buf1),
"[%02d:%02d:%02d.%03d] ",
secs / 3600,
(secs / 60) % 60,
secs % 60,
- (int)((ti / 1000000) % 1000));
+ (int)(ti % 1000));
d->drv->chr_write(d->drv, (uint8_t *)buf1, strlen(buf1));
+ d->linestart = 0;
+ }
+ ret += d->drv->chr_write(d->drv, buf+i, 1);
+ if (buf[i] == '\n') {
+ d->linestart = 1;
}
}
}
}
}
+static void mux_chr_send_event(MuxDriver *d, int mux_nr, int event)
+{
+ if (d->chr_event[mux_nr])
+ d->chr_event[mux_nr](d->ext_opaque[mux_nr], event);
+}
+
static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
{
if (d->term_got_escape) {
break;
case 'c':
/* Switch to the next registered device */
+ mux_chr_send_event(d, chr->focus, CHR_EVENT_MUX_OUT);
chr->focus++;
if (chr->focus >= d->mux_cnt)
chr->focus = 0;
+ mux_chr_send_event(d, chr->focus, CHR_EVENT_MUX_IN);
+ break;
+ case 't':
+ d->timestamps = !d->timestamps;
+ d->timestamps_start = -1;
+ d->linestart = 0;
break;
- case 't':
- term_timestamps = !term_timestamps;
- term_timestamps_start = -1;
- break;
}
} else if (ch == term_escape_char) {
d->term_got_escape = 1;
int m = chr->focus;
MuxDriver *d = chr->opaque;
- while (d->prod != d->cons &&
+ while (d->prod[m] != d->cons[m] &&
d->chr_can_read[m] &&
d->chr_can_read[m](d->ext_opaque[m])) {
d->chr_read[m](d->ext_opaque[m],
- &d->buffer[d->cons++ & MUX_BUFFER_MASK], 1);
+ &d->buffer[m][d->cons[m]++ & MUX_BUFFER_MASK], 1);
}
}
{
CharDriverState *chr = opaque;
MuxDriver *d = chr->opaque;
+ int m = chr->focus;
- if ((d->prod - d->cons) < MUX_BUFFER_SIZE)
+ if ((d->prod[m] - d->cons[m]) < MUX_BUFFER_SIZE)
return 1;
- if (d->chr_can_read[chr->focus])
- return d->chr_can_read[chr->focus](d->ext_opaque[chr->focus]);
+ if (d->chr_can_read[m])
+ return d->chr_can_read[m](d->ext_opaque[m]);
return 0;
}
for(i = 0; i < size; i++)
if (mux_proc_byte(chr, d, buf[i])) {
- if (d->prod == d->cons &&
+ if (d->prod[m] == d->cons[m] &&
d->chr_can_read[m] &&
d->chr_can_read[m](d->ext_opaque[m]))
d->chr_read[m](d->ext_opaque[m], &buf[i], 1);
else
- d->buffer[d->prod++ & MUX_BUFFER_MASK] = buf[i];
+ d->buffer[m][d->prod[m]++ & MUX_BUFFER_MASK] = buf[i];
}
}
/* Send the event to all registered listeners */
for (i = 0; i < d->mux_cnt; i++)
- if (d->chr_event[i])
- d->chr_event[i](d->ext_opaque[i], event);
+ mux_chr_send_event(d, i, event);
}
static void mux_chr_update_read_handler(CharDriverState *chr)
MuxDriver *d;
chr = qemu_mallocz(sizeof(CharDriverState));
- if (!chr)
- return NULL;
d = qemu_mallocz(sizeof(MuxDriver));
- if (!d) {
- free(chr);
- return NULL;
- }
chr->opaque = d;
d->drv = drv;
while (len > 0) {
ret = send(fd, buf, len, 0);
if (ret < 0) {
- int errno;
errno = WSAGetLastError();
if (errno != WSAEWOULDBLOCK) {
return -1;
FDCharDriver *s = chr->opaque;
if (s->fd_in >= 0) {
- if (nographic && s->fd_in == 0) {
+ if (display_type == DT_NOGRAPHIC && s->fd_in == 0) {
} else {
qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll,
fd_chr_read, NULL, chr);
FDCharDriver *s = chr->opaque;
if (s->fd_in >= 0) {
- if (nographic && s->fd_in == 0) {
+ if (display_type == DT_NOGRAPHIC && s->fd_in == 0) {
} else {
qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL);
}
FDCharDriver *s;
chr = qemu_mallocz(sizeof(CharDriverState));
- if (!chr)
- return NULL;
s = qemu_mallocz(sizeof(FDCharDriver));
- if (!s) {
- free(chr);
- return NULL;
- }
s->fd_in = fd_in;
s->fd_out = fd_out;
chr->opaque = s;
tty.c_oflag |= OPOST;
tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
/* if graphical mode, we allow Ctrl-C handling */
- if (nographic)
+ if (display_type == DT_NOGRAPHIC)
tty.c_lflag &= ~ISIG;
tty.c_cflag &= ~(CSIZE|PARENB);
tty.c_cflag |= CS8;
#ifdef __sun__
/* Once Solaris has openpty(), this is going to be removed. */
-int openpty(int *amaster, int *aslave, char *name,
- struct termios *termp, struct winsize *winp)
+static int openpty(int *amaster, int *aslave, char *name,
+ struct termios *termp, struct winsize *winp)
{
const char *slave;
int mfd = -1, sfd = -1;
return -1;
}
-void cfmakeraw (struct termios *termios_p)
+static void cfmakeraw (struct termios *termios_p)
{
termios_p->c_iflag &=
~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
#endif
#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
- || defined(__NetBSD__) || defined(__OpenBSD__)
+ || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
typedef struct {
int fd;
qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
close(s->fd);
+ qemu_del_timer(s->timer);
+ qemu_free_timer(s->timer);
qemu_free(s);
}
PtyCharDriver *s;
struct termios tty;
int slave_fd, len;
-#if defined(__OpenBSD__)
+#if defined(__OpenBSD__) || defined(__DragonFly__)
char pty_name[PATH_MAX];
#define q_ptsname(x) pty_name
#else
#endif
chr = qemu_mallocz(sizeof(CharDriverState));
- if (!chr)
- return NULL;
s = qemu_mallocz(sizeof(PtyCharDriver));
- if (!s) {
- qemu_free(chr);
- return NULL;
- }
if (openpty(&s->fd, &slave_fd, pty_name, NULL, NULL) < 0) {
return NULL;
}
/* Set raw attributes on the pty. */
+ tcgetattr(slave_fd, &tty);
cfmakeraw(&tty);
tcsetattr(slave_fd, TCSAFLUSH, &tty);
close(slave_fd);
int *targ = (int *)arg;
ioctl(s->fd_in, TIOCMGET, &sarg);
*targ = 0;
- if (sarg | TIOCM_CTS)
+ if (sarg & TIOCM_CTS)
*targ |= CHR_TIOCM_CTS;
- if (sarg | TIOCM_CAR)
+ if (sarg & TIOCM_CAR)
*targ |= CHR_TIOCM_CAR;
- if (sarg | TIOCM_DSR)
+ if (sarg & TIOCM_DSR)
*targ |= CHR_TIOCM_DSR;
- if (sarg | TIOCM_RI)
+ if (sarg & TIOCM_RI)
*targ |= CHR_TIOCM_RI;
- if (sarg | TIOCM_DTR)
+ if (sarg & TIOCM_DTR)
*targ |= CHR_TIOCM_DTR;
- if (sarg | TIOCM_RTS)
+ if (sarg & TIOCM_RTS)
*targ |= CHR_TIOCM_RTS;
}
break;
{
int sarg = *(int *)arg;
int targ = 0;
- if (sarg | CHR_TIOCM_DTR)
+ ioctl(s->fd_in, TIOCMGET, &targ);
+ targ &= ~(CHR_TIOCM_CTS | CHR_TIOCM_CAR | CHR_TIOCM_DSR
+ | CHR_TIOCM_RI | CHR_TIOCM_DTR | CHR_TIOCM_RTS);
+ if (sarg & CHR_TIOCM_CTS)
+ targ |= TIOCM_CTS;
+ if (sarg & CHR_TIOCM_CAR)
+ targ |= TIOCM_CAR;
+ if (sarg & CHR_TIOCM_DSR)
+ targ |= TIOCM_DSR;
+ if (sarg & CHR_TIOCM_RI)
+ targ |= TIOCM_RI;
+ if (sarg & CHR_TIOCM_DTR)
targ |= TIOCM_DTR;
- if (sarg | CHR_TIOCM_RTS)
+ if (sarg & CHR_TIOCM_RTS)
targ |= TIOCM_RTS;
ioctl(s->fd_in, TIOCMSET, &targ);
}
}
drv = qemu_mallocz(sizeof(ParallelCharDriver));
- if (!drv) {
- close(fd);
- return NULL;
- }
drv->fd = fd;
drv->mode = IEEE1284_MODE_COMPAT;
chr = qemu_mallocz(sizeof(CharDriverState));
- if (!chr) {
- qemu_free(drv);
- close(fd);
- return NULL;
- }
chr->chr_write = null_chr_write;
chr->chr_ioctl = pp_ioctl;
chr->chr_close = pp_close;
}
#endif /* __linux__ */
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
+{
+ int fd = (int)chr->opaque;
+ uint8_t b;
+
+ switch(cmd) {
+ case CHR_IOCTL_PP_READ_DATA:
+ if (ioctl(fd, PPIGDATA, &b) < 0)
+ return -ENOTSUP;
+ *(uint8_t *)arg = b;
+ break;
+ case CHR_IOCTL_PP_WRITE_DATA:
+ b = *(uint8_t *)arg;
+ if (ioctl(fd, PPISDATA, &b) < 0)
+ return -ENOTSUP;
+ break;
+ case CHR_IOCTL_PP_READ_CONTROL:
+ if (ioctl(fd, PPIGCTRL, &b) < 0)
+ return -ENOTSUP;
+ *(uint8_t *)arg = b;
+ break;
+ case CHR_IOCTL_PP_WRITE_CONTROL:
+ b = *(uint8_t *)arg;
+ if (ioctl(fd, PPISCTRL, &b) < 0)
+ return -ENOTSUP;
+ break;
+ case CHR_IOCTL_PP_READ_STATUS:
+ if (ioctl(fd, PPIGSTATUS, &b) < 0)
+ return -ENOTSUP;
+ *(uint8_t *)arg = b;
+ break;
+ default:
+ return -ENOTSUP;
+ }
+ return 0;
+}
+
+static CharDriverState *qemu_chr_open_pp(const char *filename)
+{
+ CharDriverState *chr;
+ int fd;
+
+ fd = open(filename, O_RDWR);
+ if (fd < 0)
+ return NULL;
+
+ chr = qemu_mallocz(sizeof(CharDriverState));
+ chr->opaque = (void *)fd;
+ chr->chr_write = null_chr_write;
+ chr->chr_ioctl = pp_ioctl;
+ return chr;
+}
+#endif
+
#else /* _WIN32 */
typedef struct {
WinCharState *s;
chr = qemu_mallocz(sizeof(CharDriverState));
- if (!chr)
- return NULL;
s = qemu_mallocz(sizeof(WinCharState));
- if (!s) {
- free(chr);
- return NULL;
- }
chr->opaque = s;
chr->chr_write = win_chr_write;
chr->chr_close = win_chr_close;
WinCharState *s;
chr = qemu_mallocz(sizeof(CharDriverState));
- if (!chr)
- return NULL;
s = qemu_mallocz(sizeof(WinCharState));
- if (!s) {
- free(chr);
- return NULL;
- }
chr->opaque = s;
chr->chr_write = win_chr_write;
chr->chr_close = win_chr_close;
WinCharState *s;
chr = qemu_mallocz(sizeof(CharDriverState));
- if (!chr)
- return NULL;
s = qemu_mallocz(sizeof(WinCharState));
- if (!s) {
- free(chr);
- return NULL;
- }
s->hcom = fd_out;
chr->opaque = s;
chr->chr_write = win_chr_write;
{
NetCharDriver *s = chr->opaque;
- return sendto(s->fd, buf, len, 0,
+ return sendto(s->fd, (const void *)buf, len, 0,
(struct sockaddr *)&s->daddr, sizeof(struct sockaddr_in));
}
if (s->max_size == 0)
return;
- s->bufcnt = recv(s->fd, s->buf, sizeof(s->buf), 0);
+ s->bufcnt = recv(s->fd, (void *)s->buf, sizeof(s->buf), 0);
s->bufptr = s->bufcnt;
if (s->bufcnt <= 0)
return;
}
}
+static void udp_chr_close(CharDriverState *chr)
+{
+ NetCharDriver *s = chr->opaque;
+ if (s->fd >= 0) {
+ qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
+ closesocket(s->fd);
+ }
+ qemu_free(s);
+}
+
static CharDriverState *qemu_chr_open_udp(const char *def)
{
CharDriverState *chr = NULL;
struct sockaddr_in saddr;
chr = qemu_mallocz(sizeof(CharDriverState));
- if (!chr)
- goto return_err;
s = qemu_mallocz(sizeof(NetCharDriver));
- if (!s)
- goto return_err;
fd = socket(PF_INET, SOCK_DGRAM, 0);
if (fd < 0) {
chr->opaque = s;
chr->chr_write = udp_chr_write;
chr->chr_update_read_handler = udp_chr_update_read_handler;
+ chr->chr_close = udp_chr_close;
return chr;
return_err:
len = sizeof(buf);
if (len > s->max_size)
len = s->max_size;
- size = recv(s->fd, buf, len, 0);
+ size = recv(s->fd, (void *)buf, len, 0);
if (size == 0) {
/* connection closed */
s->connected = 0;
static void tcp_chr_close(CharDriverState *chr)
{
TCPCharDriver *s = chr->opaque;
- if (s->fd >= 0)
+ if (s->fd >= 0) {
+ qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
closesocket(s->fd);
- if (s->listen_fd >= 0)
+ }
+ if (s->listen_fd >= 0) {
+ qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
closesocket(s->listen_fd);
+ }
qemu_free(s);
}
do_nodelay = 1;
} else if (!strncmp(ptr,"to=",3)) {
/* nothing, inet_listen() parses this one */;
+ } else if (!strncmp(ptr,"ipv4",4)) {
+ /* nothing, inet_connect() and inet_listen() parse this one */;
+ } else if (!strncmp(ptr,"ipv6",4)) {
+ /* nothing, inet_connect() and inet_listen() parse this one */;
} else {
printf("Unknown option: %s\n", ptr);
goto fail;
is_waitconnect = 0;
chr = qemu_mallocz(sizeof(CharDriverState));
- if (!chr)
- goto fail;
s = qemu_mallocz(sizeof(TCPCharDriver));
- if (!s)
- goto fail;
if (is_listen) {
chr->filename = qemu_malloc(256);
if (is_unix) {
- strcpy(chr->filename, "unix:");
+ pstrcpy(chr->filename, 256, "unix:");
} else if (is_telnet) {
- strcpy(chr->filename, "telnet:");
+ pstrcpy(chr->filename, 256, "telnet:");
} else {
- strcpy(chr->filename, "tcp:");
+ pstrcpy(chr->filename, 256, "tcp:");
}
offset = strlen(chr->filename);
}
return NULL;
}
-static TAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs
-= TAILQ_HEAD_INITIALIZER(chardevs);
-
-CharDriverState *qemu_chr_open(const char *label, const char *filename)
+CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*init)(struct CharDriverState *s))
{
const char *p;
CharDriverState *chr;
if (!strcmp(filename, "vc")) {
- chr = text_console_init(&display_state, 0);
+ chr = text_console_init(0);
} else
if (strstart(filename, "vc:", &p)) {
- chr = text_console_init(&display_state, p);
+ chr = text_console_init(p);
} else
if (!strcmp(filename, "null")) {
chr = qemu_chr_open_null();
chr = qemu_chr_open_udp(p);
} else
if (strstart(filename, "mon:", &p)) {
- chr = qemu_chr_open(label, p);
+ chr = qemu_chr_open(label, p, NULL);
if (chr) {
chr = qemu_chr_open_mux(chr);
- monitor_init(chr, !nographic);
+ monitor_init(chr, MONITOR_USE_READLINE);
} else {
printf("Unable to open driver: %s\n", p);
}
+ } else if (!strcmp(filename, "msmouse")) {
+ chr = qemu_chr_open_msmouse();
} else
#ifndef _WIN32
if (strstart(filename, "unix:", &p)) {
if (strstart(filename, "/dev/parport", NULL)) {
chr = qemu_chr_open_pp(filename);
} else
+#elif defined(__FreeBSD__) || defined(__DragonFly__)
+ if (strstart(filename, "/dev/ppi", NULL)) {
+ chr = qemu_chr_open_pp(filename);
+ } else
#endif
#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
- || defined(__NetBSD__) || defined(__OpenBSD__)
+ || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
if (strstart(filename, "/dev/", NULL)) {
chr = qemu_chr_open_tty(filename);
} else
if (chr) {
if (!chr->filename)
chr->filename = qemu_strdup(filename);
+ chr->init = init;
chr->label = qemu_strdup(label);
TAILQ_INSERT_TAIL(&chardevs, chr, next);
}
qemu_free(chr);
}
-void qemu_chr_info(void)
+void qemu_chr_info(Monitor *mon)
{
CharDriverState *chr;
TAILQ_FOREACH(chr, &chardevs, next) {
- term_printf("%s: filename=%s\n", chr->label, chr->filename);
+ monitor_printf(mon, "%s: filename=%s\n", chr->label, chr->filename);
}
}