*/
#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 <termios.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
+#include <sys/resource.h>
#include <sys/socket.h>
#include <netinet/in.h>
+#include <net/if.h>
+#ifdef __NetBSD__
+#include <net/if_tap.h>
+#endif
+#ifdef __linux__
+#include <linux/if_tun.h>
+#endif
+#include <arpa/inet.h>
#include <dirent.h>
#include <netdb.h>
#include <sys/select.h>
-#include <arpa/inet.h>
-#ifdef _BSD
+#ifdef HOST_BSD
#include <sys/stat.h>
-#if !defined(__APPLE__) && !defined(__OpenBSD__)
+#ifdef __FreeBSD__
#include <libutil.h>
-#endif
-#ifdef __OpenBSD__
-#include <net/if.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
#elif defined (__GLIBC__) && defined (__FreeBSD_kernel__)
#include <freebsd/stdlib.h>
#else
#ifdef __linux__
-#include <linux/if.h>
#include <pty.h>
#include <linux/ppdev.h>
/***********************************************************/
/* 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;
}
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];
} MuxDriver;
if (term_timestamps_start == -1)
term_timestamps_start = ti;
ti -= term_timestamps_start;
- secs = ti / 1000000000;
+ 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));
}
}
}
}
+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':
term_timestamps = !term_timestamps;
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;
#ifdef _WIN32
-int send_all(int fd, const uint8_t *buf, int len1)
+int send_all(int fd, const void *buf, int len1)
{
int ret, len;
while (len > 0) {
ret = send(fd, buf, len, 0);
if (ret < 0) {
- int errno;
errno = WSAGetLastError();
if (errno != WSAEWOULDBLOCK) {
return -1;
return len1 - len;
}
-int send_all(int fd, const uint8_t *buf, int len1)
+int send_all(int fd, const void *buf, int len1)
{
return unix_write(fd, buf, len1);
}
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;
#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;
}
}
+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:
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);
}
{
CharDriverState *chr = NULL;
TCPCharDriver *s = NULL;
- int fd = -1, ret, err, val;
+ int fd = -1, offset = 0;
int is_listen = 0;
int is_waitconnect = 1;
int do_nodelay = 0;
const char *ptr;
- struct sockaddr_in saddr;
-#ifndef _WIN32
- struct sockaddr_un uaddr;
-#endif
- struct sockaddr *addr;
- socklen_t addrlen;
-
-#ifndef _WIN32
- if (is_unix) {
- addr = (struct sockaddr *)&uaddr;
- addrlen = sizeof(uaddr);
- if (parse_unix_path(&uaddr, host_str) < 0)
- goto fail;
- } else
-#endif
- {
- addr = (struct sockaddr *)&saddr;
- addrlen = sizeof(saddr);
- if (parse_host_port(&saddr, host_str) < 0)
- goto fail;
- }
ptr = host_str;
while((ptr = strchr(ptr,','))) {
is_waitconnect = 0;
} else if (!strncmp(ptr,"nodelay",6)) {
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;
-
-#ifndef _WIN32
- if (is_unix)
- fd = socket(PF_UNIX, SOCK_STREAM, 0);
- else
-#endif
- fd = socket(PF_INET, SOCK_STREAM, 0);
+ if (is_listen) {
+ chr->filename = qemu_malloc(256);
+ if (is_unix) {
+ pstrcpy(chr->filename, 256, "unix:");
+ } else if (is_telnet) {
+ pstrcpy(chr->filename, 256, "telnet:");
+ } else {
+ pstrcpy(chr->filename, 256, "tcp:");
+ }
+ offset = strlen(chr->filename);
+ }
+ if (is_unix) {
+ if (is_listen) {
+ fd = unix_listen(host_str, chr->filename + offset, 256 - offset);
+ } else {
+ fd = unix_connect(host_str);
+ }
+ } else {
+ if (is_listen) {
+ fd = inet_listen(host_str, chr->filename + offset, 256 - offset,
+ SOCK_STREAM, 0);
+ } else {
+ fd = inet_connect(host_str, SOCK_STREAM);
+ }
+ }
if (fd < 0)
goto fail;
chr->chr_close = tcp_chr_close;
if (is_listen) {
- /* allow fast reuse */
-#ifndef _WIN32
- if (is_unix) {
- char path[109];
- pstrcpy(path, sizeof(path), uaddr.sun_path);
- unlink(path);
- } else
-#endif
- {
- val = 1;
- setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
- }
-
- ret = bind(fd, addr, addrlen);
- if (ret < 0)
- goto fail;
-
- ret = listen(fd, 0);
- if (ret < 0)
- goto fail;
-
s->listen_fd = fd;
qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
if (is_telnet)
s->do_telnetopt = 1;
} else {
- for(;;) {
- ret = connect(fd, addr, addrlen);
- if (ret < 0) {
- err = socket_error();
- if (err == EINTR || err == EWOULDBLOCK) {
- } else if (err == EINPROGRESS) {
- break;
-#ifdef _WIN32
- } else if (err == WSAEALREADY) {
- break;
-#endif
- } else {
- goto fail;
- }
- } else {
- s->connected = 1;
- break;
- }
- }
+ s->connected = 1;
s->fd = fd;
socket_set_nodelay(fd);
- if (s->connected)
- tcp_chr_connect(chr);
- else
- qemu_set_fd_handler(s->fd, NULL, tcp_chr_connect, chr);
+ tcp_chr_connect(chr);
}
if (is_listen && is_waitconnect) {
- printf("QEMU waiting for connection on: %s\n", host_str);
+ printf("QEMU waiting for connection on: %s\n",
+ chr->filename ? chr->filename : host_str);
tcp_chr_accept(chr);
socket_set_nonblock(s->listen_fd);
}
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);
}
}