diff options
-rw-r--r-- | console.c | 43 | ||||
-rw-r--r-- | console.h | 60 | ||||
-rw-r--r-- | elf.h | 22 | ||||
-rw-r--r-- | envlist.h | 14 | ||||
-rw-r--r-- | gen-icount.h | 2 | ||||
-rw-r--r-- | input.c | 62 | ||||
-rw-r--r-- | qemu-char-android.c | 136 | ||||
-rw-r--r-- | qemu-char.c | 178 | ||||
-rw-r--r-- | qemu-char.h | 17 |
9 files changed, 409 insertions, 125 deletions
@@ -137,6 +137,7 @@ struct TextConsole { TextAttributes t_attrib; /* currently active text attributes */ TextCell *cells; int text_x[2], text_y[2], cursor_invalidate; + int echo; int update_x0; int update_y0; @@ -1069,8 +1070,10 @@ void console_select(unsigned int index) if (index >= MAX_CONSOLES) return; + if (active_console) { active_console->g_width = ds_get_width(active_console->ds); active_console->g_height = ds_get_height(active_console->ds); + } s = consoles[index]; if (s) { DisplayState *ds = s->ds; @@ -1184,9 +1187,15 @@ void kbd_put_keysym(int keysym) *q++ = '\033'; *q++ = '['; *q++ = keysym & 0xff; + } else if (s->echo && (keysym == '\r' || keysym == '\n')) { + console_puts(s->chr, (const uint8_t *) "\r", 1); + *q++ = '\n'; } else { *q++ = keysym; } + if (s->echo) { + console_puts(s->chr, buf, q - buf); + } if (s->chr->chr_read) { qemu_fifo_write(&s->out_fifo, buf, q - buf); kbd_send_chars(s); @@ -1443,6 +1452,13 @@ static int n_text_consoles; static CharDriverState *text_consoles[128]; static QemuOpts *text_console_opts[128]; +static void text_console_set_echo(CharDriverState *chr, bool echo) +{ + TextConsole *s = chr->opaque; + + s->echo = echo; +} + static void text_console_do_init(CharDriverState *chr, DisplayState *ds, QemuOpts *opts) { TextConsole *s; @@ -1526,6 +1542,9 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds, QemuOpt CharDriverState *text_console_init(QemuOpts *opts) { CharDriverState *chr; + TextConsole *s; + unsigned width; + unsigned height; chr = qemu_mallocz(sizeof(CharDriverState)); @@ -1537,6 +1556,30 @@ CharDriverState *text_console_init(QemuOpts *opts) text_console_opts[n_text_consoles] = opts; n_text_consoles++; + width = qemu_opt_get_number(opts, "width", 0); + if (width == 0) + width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH; + + height = qemu_opt_get_number(opts, "height", 0); + if (height == 0) + height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT; + + if (width == 0 || height == 0) { + s = new_console(NULL, TEXT_CONSOLE); + } else { + s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE); + } + + if (!s) { + free(chr); + return NULL; + } + + s->chr = chr; + s->g_width = width; + s->g_height = height; + chr->opaque = s; + chr->chr_set_echo = text_console_set_echo; return chr; } @@ -10,6 +10,7 @@ #define MOUSE_EVENT_LBUTTON 0x01 #define MOUSE_EVENT_RBUTTON 0x02 #define MOUSE_EVENT_MBUTTON 0x04 +extern int multitouch_enabled; /* identical to the ps/2 keyboard bits */ #define QEMU_SCROLL_LOCK_LED (1 << 0) @@ -23,6 +24,10 @@ #define GUI_REFRESH_INTERVAL 30 #endif +typedef int QEMUDisplayCloseCallback(void *opaque); +void qemu_set_display_close_handler(QEMUDisplayCloseCallback *cb, void *opaque); +int qemu_run_display_close_handler(void); + typedef void QEMUPutKBDEvent(void *opaque, int keycode); typedef void QEMUPutLEDEvent(void *opaque, int ledstate); typedef void QEMUPutMouseEvent(void *opaque, int dx, int dy, int dz, int buttons_state); @@ -39,6 +44,14 @@ typedef struct QEMUPutMouseEntry { QTAILQ_ENTRY(QEMUPutMouseEntry) node; } QEMUPutMouseEntry; +typedef struct QEMUPutKBDEntry { + QEMUPutKBDEvent *put_kbd_event; + void *opaque; + + /* used internally by qemu for handling keyboards */ + QTAILQ_ENTRY(QEMUPutKBDEntry) next; +} QEMUPutKBDEntry; + typedef struct QEMUPutLEDEntry { QEMUPutLEDEvent *put_led; void *opaque; @@ -46,7 +59,7 @@ typedef struct QEMUPutLEDEntry { } QEMUPutLEDEntry; void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque); -void qemu_remove_kbd_event_handler(void); +void qemu_remove_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque); QEMUPutMouseEntry *qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, void *opaque, int absolute, const char *name); @@ -165,7 +178,13 @@ struct DisplayChangeListener { void (*dpy_fill)(struct DisplayState *s, int x, int y, int w, int h, uint32_t c); void (*dpy_text_cursor)(struct DisplayState *s, int x, int y); - +#ifdef CONFIG_GLES2 + void (*dpy_updatecaption)(void); +#endif +#ifdef CONFIG_SKINNING + void (*dpy_enablezoom)(struct DisplayState *s, int width, int height); + void (*dpy_getresolution)(int *width, int *height); +#endif struct DisplayChangeListener *next; }; @@ -256,7 +275,6 @@ static inline void register_displayupdatelistener(DisplayState *ds, DisplayUpdat } void unregister_displayupdatelistener(DisplayState *ds, DisplayUpdateListener *dul); - #endif static inline void dpy_update(DisplayState *s, int x, int y, int w, int h) @@ -275,6 +293,20 @@ static inline void dpy_update(DisplayState *s, int x, int y, int w, int h) #endif } +#ifdef CONFIG_GLES2 +static inline void dpy_updatecaption(DisplayState *s) +{ + struct DisplayChangeListener *dcl = s->listeners; + while (dcl != NULL) { + if(dcl->dpy_updatecaption != NULL) + { + dcl->dpy_updatecaption(); + } + dcl = dcl->next; + } +} +#endif + static inline void dpy_resize(DisplayState *s) { struct DisplayChangeListener *dcl = s->listeners; @@ -331,6 +363,26 @@ static inline void dpy_cursor(struct DisplayState *s, int x, int y) { } } +#ifdef CONFIG_SKINNING +static inline void dpy_enablezoom(struct DisplayState *s, int width, int height) +{ + struct DisplayChangeListener *dcl = s->listeners; + while (dcl != NULL) { + if (dcl->dpy_enablezoom) dcl->dpy_enablezoom(s, width, height); + dcl = dcl->next; + } +} + +static inline void dpy_getresolution(struct DisplayState *s, int *width, int *height) +{ + struct DisplayChangeListener *dcl = s->listeners; + while (dcl != NULL) { + if (dcl->dpy_getresolution) dcl->dpy_getresolution(width, height); + dcl = dcl->next; + } +} +#endif + static inline int ds_get_linesize(DisplayState *ds) { return ds->surface->linesize; @@ -366,7 +418,7 @@ static inline void console_write_ch(console_ch_t *dest, uint32_t ch) { if (!(ch & 0xff)) ch |= ' '; - cpu_to_le32wu((uint32_t *) dest, ch); + *dest = ch; } typedef void (*vga_hw_update_ptr)(void *); @@ -104,6 +104,9 @@ typedef int64_t Elf64_Sxword; #define EM_H8_300H 47 /* Hitachi H8/300H */ #define EM_H8S 48 /* Hitachi H8S */ +#define EM_LATTICEMICO32 138 /* LatticeMico32 */ + +#define EM_UNICORE32 110 /* UniCore32 */ /* * This is an interim value that we will use until the committee comes @@ -1191,6 +1194,25 @@ typedef struct elf64_note { Elf64_Word n_type; /* Content type */ } Elf64_Nhdr; + +/* This data structure represents a PT_LOAD segment. */ +struct elf32_fdpic_loadseg { + /* Core address to which the segment is mapped. */ + Elf32_Addr addr; + /* VMA recorded in the program header. */ + Elf32_Addr p_vaddr; + /* Size of this segment in memory. */ + Elf32_Word p_memsz; +}; +struct elf32_fdpic_loadmap { + /* Protocol version number, must be zero. */ + Elf32_Half version; + /* Number of segments in this map. */ + Elf32_Half nsegs; + /* The actual memory map. */ + struct elf32_fdpic_loadseg segs[/*nsegs*/]; +}; + #ifdef ELF_CLASS #if ELF_CLASS == ELFCLASS32 @@ -7,13 +7,13 @@ extern "C" { typedef struct envlist envlist_t; -extern envlist_t *envlist_create(void); -extern void envlist_free(envlist_t *); -extern int envlist_setenv(envlist_t *, const char *); -extern int envlist_unsetenv(envlist_t *, const char *); -extern int envlist_parse_set(envlist_t *, const char *); -extern int envlist_parse_unset(envlist_t *, const char *); -extern char **envlist_to_environ(const envlist_t *, size_t *); +envlist_t *envlist_create(void); +void envlist_free(envlist_t *); +int envlist_setenv(envlist_t *, const char *); +int envlist_unsetenv(envlist_t *, const char *); +int envlist_parse_set(envlist_t *, const char *); +int envlist_parse_unset(envlist_t *, const char *); +char **envlist_to_environ(const envlist_t *, size_t *); #ifdef __cplusplus } diff --git a/gen-icount.h b/gen-icount.h index 8879da6..5fb3829 100644 --- a/gen-icount.h +++ b/gen-icount.h @@ -29,7 +29,7 @@ static void gen_icount_end(TranslationBlock *tb, int num_insns) if (use_icount) { *icount_arg = num_insns; gen_set_label(icount_label); - tcg_gen_exit_tb((long)tb + 2); + tcg_gen_exit_tb((tcg_target_long)tb + 2); } } @@ -28,24 +28,45 @@ #include "console.h" #include "qjson.h" -static QEMUPutKBDEvent *qemu_put_kbd_event; -static void *qemu_put_kbd_event_opaque; +#ifdef CONFIG_SKINNING +QEMUPutMouseEntry *original_qemu_add_mouse_event_handler(QEMUPutMouseEvent *func, + void *opaque, int absolute, + const char *name); +#undef qemu_add_mouse_event_handler +#define qemu_add_mouse_event_handler original_qemu_add_mouse_event_handler +#endif +static QTAILQ_HEAD(, QEMUPutKBDEntry) kbd_handlers = + QTAILQ_HEAD_INITIALIZER(kbd_handlers); static QTAILQ_HEAD(, QEMUPutLEDEntry) led_handlers = QTAILQ_HEAD_INITIALIZER(led_handlers); static QTAILQ_HEAD(, QEMUPutMouseEntry) mouse_handlers = QTAILQ_HEAD_INITIALIZER(mouse_handlers); -static NotifierList mouse_mode_notifiers = +static NotifierList mouse_mode_notifiers = NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers); void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque) { - qemu_put_kbd_event_opaque = opaque; - qemu_put_kbd_event = func; + QEMUPutKBDEntry *s; + + if (func != NULL) { + s = qemu_mallocz(sizeof(QEMUPutKBDEntry)); + + s->put_kbd_event = func; + s->opaque = opaque; + + QTAILQ_INSERT_TAIL(&kbd_handlers, s, next); + } } -void qemu_remove_kbd_event_handler(void) +void qemu_remove_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque) { - qemu_put_kbd_event_opaque = NULL; - qemu_put_kbd_event = NULL; + QEMUPutKBDEntry *cursor, *cursor_next; + if (func != NULL) { + QTAILQ_FOREACH_SAFE(cursor, &kbd_handlers, next, cursor_next) { + if (cursor->put_kbd_event == func && cursor->opaque == opaque) { + QTAILQ_REMOVE(&kbd_handlers, cursor, next); + } + } + } } static void check_mode_change(void) @@ -129,8 +150,9 @@ void qemu_remove_led_event_handler(QEMUPutLEDEntry *entry) void kbd_put_keycode(int keycode) { - if (qemu_put_kbd_event) { - qemu_put_kbd_event(qemu_put_kbd_event_opaque, keycode); + QEMUPutKBDEntry *cursor; + QTAILQ_FOREACH(cursor, &kbd_handlers, next) { + cursor->put_kbd_event(cursor->opaque, keycode); } } @@ -148,7 +170,9 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) QEMUPutMouseEntry *entry; QEMUPutMouseEvent *mouse_event; void *mouse_event_opaque; +#ifndef CONFIG_SKINNING int width; +#endif if (QTAILQ_EMPTY(&mouse_handlers)) { return; @@ -160,16 +184,20 @@ void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) mouse_event_opaque = entry->qemu_put_mouse_event_opaque; if (mouse_event) { +#ifndef CONFIG_SKINNING if (graphic_rotate) { - if (entry->qemu_put_mouse_event_absolute) + if (entry->qemu_put_mouse_event_absolute) { width = 0x7fff; - else + } else { width = graphic_width - 1; - mouse_event(mouse_event_opaque, - width - dy, dx, dz, buttons_state); - } else - mouse_event(mouse_event_opaque, - dx, dy, dz, buttons_state); + } + mouse_event(mouse_event_opaque, width - dy, dx, dz, buttons_state); + } else { + mouse_event(mouse_event_opaque, dx, dy, dz, buttons_state); + } +#else + mouse_event(mouse_event_opaque, dx, dy, dz, buttons_state); +#endif } } diff --git a/qemu-char-android.c b/qemu-char-android.c index a49affd..18f80f7 100644 --- a/qemu-char-android.c +++ b/qemu-char-android.c @@ -52,22 +52,19 @@ #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> #ifdef CONFIG_BSD #include <sys/stat.h> -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #include <libutil.h> #include <dev/ppbus/ppi.h> #include <dev/ppbus/ppbconf.h> +#if defined(__GLIBC__) +#include <pty.h> +#endif #elif defined(__DragonFly__) #include <libutil.h> #include <dev/misc/ppi/ppi.h> @@ -75,8 +72,6 @@ #else #include <util.h> #endif -#elif defined (__GLIBC__) && defined (__FreeBSD_kernel__) -#include <freebsd/stdlib.h> #else #ifdef __linux__ #include <pty.h> @@ -230,6 +225,10 @@ void qemu_chr_add_handlers(CharDriverState *s, IOEventHandler *fd_event, void *opaque) { + if (!opaque && !fd_can_read && !fd_read && !fd_event) { + /* chr driver being released. */ + ++s->avail_connections; + } s->chr_can_read = fd_can_read; s->chr_read = fd_read; s->chr_event = fd_event; @@ -509,6 +508,9 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv) chr->chr_write = mux_chr_write; chr->chr_update_read_handler = mux_chr_update_read_handler; chr->chr_accept_input = mux_chr_accept_input; + /* Frontend guest-open / -close notification is not support with muxes */ + chr->chr_guest_open = NULL; + chr->chr_guest_close = NULL; /* Muxes are always open on creation */ qemu_chr_generic_open(chr); @@ -546,9 +548,10 @@ int send_all(int fd, const void *buf, int len1) #else -static int unix_write(int fd, const uint8_t *buf, int len1) +int send_all(int fd, const void *_buf, int len1) { int ret, len; + const uint8_t *buf = _buf; len = len1; while (len > 0) { @@ -565,11 +568,6 @@ static int unix_write(int fd, const uint8_t *buf, int len1) } return len1 - len; } - -int send_all(int fd, const void *buf, int len1) -{ - return unix_write(fd, buf, len1); -} #endif /* !_WIN32 */ #ifndef _WIN32 @@ -770,7 +768,7 @@ static void stdio_read(void *opaque) /* init terminal so that we can grab keys */ static struct termios oldtty; static int old_fd0_flags; -static int term_atexit_done; +static bool stdio_allow_signal; static void term_exit(void) { @@ -778,32 +776,26 @@ static void term_exit(void) fcntl(0, F_SETFL, old_fd0_flags); } -static void term_init(void) +static void qemu_chr_set_echo_stdio(CharDriverState *chr, bool echo) { struct termios tty; - tcgetattr (0, &tty); - oldtty = tty; - old_fd0_flags = fcntl(0, F_GETFL); - + tty = oldtty; + if (!echo) { tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP |INLCR|IGNCR|ICRNL|IXON); tty.c_oflag |= OPOST; tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN); - /* if graphical mode, we allow Ctrl-C handling */ - if (display_type == DT_NOGRAPHIC) - tty.c_lflag &= ~ISIG; tty.c_cflag &= ~(CSIZE|PARENB); tty.c_cflag |= CS8; tty.c_cc[VMIN] = 1; tty.c_cc[VTIME] = 0; + } + /* if graphical mode, we allow Ctrl-C handling */ + if (!stdio_allow_signal) + tty.c_lflag &= ~ISIG; tcsetattr (0, TCSANOW, &tty); - - if (!term_atexit_done++) - atexit(term_exit); - - fcntl(0, F_SETFL, O_NONBLOCK); } static void qemu_chr_close_stdio(struct CharDriverState *chr) @@ -820,11 +812,20 @@ static CharDriverState *qemu_chr_open_stdio(void) if (stdio_nb_clients >= STDIO_MAX_CLIENTS) return NULL; + if (stdio_nb_clients == 0) { + old_fd0_flags = fcntl(0, F_GETFL); + tcgetattr (0, &oldtty); + fcntl(0, F_SETFL, O_NONBLOCK); + atexit(term_exit); + } + chr = qemu_chr_open_fd(0, 1); chr->chr_close = qemu_chr_close_stdio; + chr->chr_set_echo = qemu_chr_set_echo_stdio; qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, chr); stdio_nb_clients++; - term_init(); + stdio_allow_signal = display_type != DT_NOGRAPHIC; + qemu_chr_set_echo(chr, false); return chr; } @@ -1065,9 +1066,6 @@ static void tty_serial_init(int fd, int speed, speed, parity, data_bits, stop_bits); #endif tcgetattr (fd, &tty); - if (!term_atexit_done) { - oldtty = tty; - } #define check_speed(val) if (speed <= val) { spd = B##val; break; } speed = speed * 10 / 11; @@ -1239,12 +1237,32 @@ static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg) return 0; } +static void qemu_chr_close_tty(CharDriverState *chr) +{ + FDCharDriver *s = chr->opaque; + int fd = -1; + + if (s) { + fd = s->fd_in; + } + + fd_chr_close(chr); + + if (fd >= 0) { + close(fd); + } +} + + static CharDriverState *qemu_chr_open_tty(const char *filename) { CharDriverState *chr; int fd; TFR(fd = open(filename, O_RDWR | O_NONBLOCK)); + if (fd < 0) { + return NULL; + } tty_serial_init(fd, 115200, 'N', 8, 1); chr = qemu_chr_open_fd(fd, fd); if (!chr) { @@ -1252,7 +1270,7 @@ static CharDriverState *qemu_chr_open_tty(const char *filename) return NULL; } chr->chr_ioctl = tty_serial_ioctl; - qemu_chr_reset(chr); + chr->chr_close = qemu_chr_close_tty; return chr; } #else /* _WIN32 */ @@ -1369,6 +1387,7 @@ static void pp_close(CharDriverState *chr) ioctl(fd, PPRELEASE); close(fd); qemu_free(drv); + qemu_chr_event(chr, CHR_EVENT_CLOSED); } static CharDriverState *qemu_chr_open_pp(const char *filename) @@ -1396,16 +1415,16 @@ static CharDriverState *qemu_chr_open_pp(const char *filename) chr->chr_close = pp_close; chr->opaque = drv; - qemu_chr_reset(chr); + qemu_chr_generic_open(chr); return chr; } #endif /* __linux__ */ -#if defined(__FreeBSD__) || defined(__DragonFly__) +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) static int pp_ioctl(CharDriverState *chr, int cmd, void *arg) { - int fd = (int)chr->opaque; + int fd = (int)(intptr_t)chr->opaque; uint8_t b; switch(cmd) { @@ -1450,7 +1469,7 @@ static CharDriverState *qemu_chr_open_pp(const char *filename) return NULL; chr = qemu_mallocz(sizeof(CharDriverState)); - chr->opaque = (void *)fd; + chr->opaque = (void *)(intptr_t)fd; chr->chr_write = null_chr_write; chr->chr_ioctl = pp_ioctl; return chr; @@ -1495,6 +1514,8 @@ static void win_chr_close(CharDriverState *chr) qemu_del_polling_cb(win_chr_pipe_poll, chr); else qemu_del_polling_cb(win_chr_poll, chr); + + qemu_chr_event(chr, CHR_EVENT_CLOSED); } static int win_chr_init(CharDriverState *chr, const char *filename) @@ -1610,7 +1631,7 @@ static void win_chr_readfile(CharDriverState *chr) { WinCharState *s = chr->opaque; int ret, err; - uint8_t buf[1024]; + uint8_t buf[READ_BUF_LEN]; DWORD size; ZeroMemory(&s->orecv, sizeof(s->orecv)); @@ -1673,7 +1694,7 @@ static CharDriverState *qemu_chr_open_win(const char *filename) free(chr); return NULL; } - qemu_chr_reset(chr); + qemu_chr_generic_open(chr); return chr; } @@ -1772,7 +1793,7 @@ static CharDriverState *qemu_chr_open_win_pipe(const char *filename) free(chr); return NULL; } - qemu_chr_reset(chr); + qemu_chr_generic_open(chr); return chr; } @@ -1786,7 +1807,7 @@ static CharDriverState *qemu_chr_open_win_file(HANDLE fd_out) s->hcom = fd_out; chr->opaque = s; chr->chr_write = win_chr_write; - qemu_chr_reset(chr); + qemu_chr_generic_open(chr); return chr; } @@ -1814,7 +1835,7 @@ static CharDriverState *qemu_chr_open_win_file_out(const char *file_out) typedef struct { int fd; SockAddress daddr; - uint8_t buf[1024]; + uint8_t buf[READ_BUF_LEN]; int bufcnt; int bufptr; int max_size; @@ -2016,7 +2037,6 @@ static void tcp_chr_process_IAC_bytes(CharDriverState *chr, *size = j; } -#if 0 static int tcp_get_msgfd(CharDriverState *chr) { TCPCharDriver *s = chr->opaque; @@ -2024,7 +2044,6 @@ static int tcp_get_msgfd(CharDriverState *chr) s->msgfd = -1; return fd; } -#endif #ifndef _WIN32 static void unix_process_msgfd(CharDriverState *chr, struct msghdr *msg) @@ -2183,6 +2202,7 @@ static void tcp_chr_close(CharDriverState *chr) closesocket(s->listen_fd); } qemu_free(s); + qemu_chr_event(chr, CHR_EVENT_CLOSED); } static CharDriverState *qemu_chr_open_tcp(const char *host_str, @@ -2268,18 +2288,21 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, s->connected = 0; s->fd = -1; s->listen_fd = -1; + s->msgfd = -1; s->is_unix = is_unix; s->do_nodelay = do_nodelay && !is_unix; chr->opaque = s; chr->chr_write = tcp_chr_write; chr->chr_close = tcp_chr_close; + chr->get_msgfd = tcp_get_msgfd; if (is_listen) { s->listen_fd = fd; qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr); if (is_telnet) s->do_telnetopt = 1; + } else { s->connected = 1; s->fd = fd; @@ -2293,8 +2316,8 @@ static CharDriverState *qemu_chr_open_tcp(const char *host_str, tcp_chr_accept(chr); socket_set_nonblock(s->listen_fd); } - return chr; + fail: if (fd >= 0) closesocket(fd); @@ -2409,6 +2432,27 @@ CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*i return chr; } +void qemu_chr_set_echo(struct CharDriverState *chr, bool echo) +{ + if (chr->chr_set_echo) { + chr->chr_set_echo(chr, echo); + } +} + +void qemu_chr_guest_open(struct CharDriverState *chr) +{ + if (chr->chr_guest_open) { + chr->chr_guest_open(chr); + } +} + +void qemu_chr_guest_close(struct CharDriverState *chr) +{ + if (chr->chr_guest_close) { + chr->chr_guest_close(chr); + } +} + void qemu_chr_close(CharDriverState *chr) { QTAILQ_REMOVE(&chardevs, chr, next); diff --git a/qemu-char.c b/qemu-char.c index a087813..591ca2d 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -28,7 +28,6 @@ #include "sysemu.h" #include "qemu-timer.h" #include "qemu-char.h" -#include "block.h" #include "hw/usb.h" #include "hw/baum.h" #include "hw/msmouse.h" @@ -52,22 +51,19 @@ #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> #ifdef CONFIG_BSD #include <sys/stat.h> -#ifdef __FreeBSD__ +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #include <libutil.h> #include <dev/ppbus/ppi.h> #include <dev/ppbus/ppbconf.h> +#if defined(__GLIBC__) +#include <pty.h> +#endif #elif defined(__DragonFly__) #include <libutil.h> #include <dev/misc/ppi/ppi.h> @@ -75,8 +71,6 @@ #else #include <util.h> #endif -#elif defined (__GLIBC__) && defined (__FreeBSD_kernel__) -#include <freebsd/stdlib.h> #else #ifdef __linux__ #include <pty.h> @@ -221,6 +215,10 @@ void qemu_chr_add_handlers(CharDriverState *s, IOEventHandler *fd_event, void *opaque) { + if (!opaque && !fd_can_read && !fd_read && !fd_event) { + /* chr driver being released. */ + ++s->avail_connections; + } s->chr_can_read = fd_can_read; s->chr_read = fd_read; s->chr_event = fd_event; @@ -376,12 +374,7 @@ static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch) break; } case 's': - { - int i; - for (i = 0; i < nb_drives; i++) { - bdrv_commit(drives_table[i].bdrv); - } - } + bdrv_commit_all(); break; case 'b': qemu_chr_event(chr, CHR_EVENT_BREAK); @@ -505,6 +498,9 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv) chr->chr_write = mux_chr_write; chr->chr_update_read_handler = mux_chr_update_read_handler; chr->chr_accept_input = mux_chr_accept_input; + /* Frontend guest-open / -close notification is not support with muxes */ + chr->chr_guest_open = NULL; + chr->chr_guest_close = NULL; /* Muxes are always open on creation */ qemu_chr_generic_open(chr); @@ -538,9 +534,10 @@ int send_all(int fd, const void *buf, int len1) #else -static int unix_write(int fd, const uint8_t *buf, int len1) +int send_all(int fd, const void *_buf, int len1) { int ret, len; + const uint8_t *buf = _buf; len = len1; while (len > 0) { @@ -557,11 +554,6 @@ static int unix_write(int fd, const uint8_t *buf, int len1) } return len1 - len; } - -int send_all(int fd, const void *buf, int len1) -{ - return unix_write(fd, buf, len1); -} #endif /* !_WIN32 */ #ifndef _WIN32 @@ -749,7 +741,7 @@ static void stdio_read(void *opaque) /* init terminal so that we can grab keys */ static struct termios oldtty; static int old_fd0_flags; -static int term_atexit_done; +static bool stdio_allow_signal; static void term_exit(void) { @@ -757,32 +749,26 @@ static void term_exit(void) fcntl(0, F_SETFL, old_fd0_flags); } -static void term_init(QemuOpts *opts) +static void qemu_chr_set_echo_stdio(CharDriverState *chr, bool echo) { struct termios tty; - tcgetattr (0, &tty); - oldtty = tty; - old_fd0_flags = fcntl(0, F_GETFL); - + tty = oldtty; + if (!echo) { tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP |INLCR|IGNCR|ICRNL|IXON); tty.c_oflag |= OPOST; tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN); - /* if graphical mode, we allow Ctrl-C handling */ - if (!qemu_opt_get_bool(opts, "signal", display_type != DT_NOGRAPHIC)) - tty.c_lflag &= ~ISIG; tty.c_cflag &= ~(CSIZE|PARENB); tty.c_cflag |= CS8; tty.c_cc[VMIN] = 1; tty.c_cc[VTIME] = 0; + } + /* if graphical mode, we allow Ctrl-C handling */ + if (!stdio_allow_signal) + tty.c_lflag &= ~ISIG; tcsetattr (0, TCSANOW, &tty); - - if (!term_atexit_done++) - atexit(term_exit); - - fcntl(0, F_SETFL, O_NONBLOCK); } static void qemu_chr_close_stdio(struct CharDriverState *chr) @@ -799,11 +785,21 @@ static CharDriverState *qemu_chr_open_stdio(QemuOpts *opts) if (stdio_nb_clients >= STDIO_MAX_CLIENTS) return NULL; + if (stdio_nb_clients == 0) { + old_fd0_flags = fcntl(0, F_GETFL); + tcgetattr (0, &oldtty); + fcntl(0, F_SETFL, O_NONBLOCK); + atexit(term_exit); + } + chr = qemu_chr_open_fd(0, 1); chr->chr_close = qemu_chr_close_stdio; + chr->chr_set_echo = qemu_chr_set_echo_stdio; qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, chr); stdio_nb_clients++; - term_init(opts); + stdio_allow_signal = qemu_opt_get_bool(opts, "signal", + display_type != DT_NOGRAPHIC); + qemu_chr_set_echo(chr, false); return chr; } @@ -1046,9 +1042,6 @@ static void tty_serial_init(int fd, int speed, speed, parity, data_bits, stop_bits); #endif tcgetattr (fd, &tty); - if (!term_atexit_done) { - oldtty = tty; - } #define check_speed(val) if (speed <= val) { spd = B##val; break; } speed = speed * 10 / 11; @@ -1220,11 +1213,6 @@ static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg) return 0; } -static void tty_exit(void) -{ - tcsetattr(0, TCSANOW, &oldtty); -} - static void qemu_chr_close_tty(CharDriverState *chr) { FDCharDriver *s = chr->opaque; @@ -1259,8 +1247,6 @@ static CharDriverState *qemu_chr_open_tty(QemuOpts *opts) } chr->chr_ioctl = tty_serial_ioctl; chr->chr_close = qemu_chr_close_tty; - if (!term_atexit_done++) - atexit(tty_exit); return chr; } #else /* ! __linux__ && ! __sun__ */ @@ -1415,7 +1401,7 @@ static CharDriverState *qemu_chr_open_pp(QemuOpts *opts) #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) static int pp_ioctl(CharDriverState *chr, int cmd, void *arg) { - int fd = (int)(long)chr->opaque; + int fd = (int)(intptr_t)chr->opaque; uint8_t b; switch(cmd) { @@ -1461,7 +1447,7 @@ static CharDriverState *qemu_chr_open_pp(QemuOpts *opts) return NULL; chr = qemu_mallocz(sizeof(CharDriverState)); - chr->opaque = (void *)(long)fd; + chr->opaque = (void *)(intptr_t)fd; chr->chr_write = null_chr_write; chr->chr_ioctl = pp_ioctl; return chr; @@ -2309,6 +2295,70 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) return NULL; } +/***********************************************************/ +/* Memory chardev */ +typedef struct { + size_t outbuf_size; + size_t outbuf_capacity; + uint8_t *outbuf; +} MemoryDriver; + +static int mem_chr_write(CharDriverState *chr, const uint8_t *buf, int len) +{ + MemoryDriver *d = chr->opaque; + + /* TODO: the QString implementation has the same code, we should + * introduce a generic way to do this in cutils.c */ + if (d->outbuf_capacity < d->outbuf_size + len) { + /* grow outbuf */ + d->outbuf_capacity += len; + d->outbuf_capacity *= 2; + d->outbuf = qemu_realloc(d->outbuf, d->outbuf_capacity); + } + + memcpy(d->outbuf + d->outbuf_size, buf, len); + d->outbuf_size += len; + + return len; +} + +void qemu_chr_init_mem(CharDriverState *chr) +{ + MemoryDriver *d; + + d = qemu_malloc(sizeof(*d)); + d->outbuf_size = 0; + d->outbuf_capacity = 4096; + d->outbuf = qemu_mallocz(d->outbuf_capacity); + + memset(chr, 0, sizeof(*chr)); + chr->opaque = d; + chr->chr_write = mem_chr_write; +} + +QString *qemu_chr_mem_to_qs(CharDriverState *chr) +{ + MemoryDriver *d = chr->opaque; + return qstring_from_substr((char *) d->outbuf, 0, d->outbuf_size - 1); +} + +/* NOTE: this driver can not be closed with qemu_chr_close()! */ +void qemu_chr_close_mem(CharDriverState *chr) +{ + MemoryDriver *d = chr->opaque; + + qemu_free(d->outbuf); + qemu_free(chr->opaque); + chr->opaque = NULL; + chr->chr_write = NULL; +} + +size_t qemu_chr_mem_osize(const CharDriverState *chr) +{ + const MemoryDriver *d = chr->opaque; + return d->outbuf_size; +} + QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename) { char host[65], port[33], width[8], height[8]; @@ -2481,6 +2531,11 @@ CharDriverState *qemu_chr_open_opts(QemuOpts *opts, return NULL; } + if (qemu_opt_get(opts, "backend") == NULL) { + fprintf(stderr, "chardev: \"%s\" missing backend\n", + qemu_opts_id(opts)); + return NULL; + } for (i = 0; i < ARRAY_SIZE(backend_table); i++) { if (strcmp(backend_table[i].name, qemu_opt_get(opts, "backend")) == 0) break; @@ -2510,7 +2565,10 @@ CharDriverState *qemu_chr_open_opts(QemuOpts *opts, snprintf(base->label, len, "%s-base", qemu_opts_id(opts)); chr = qemu_chr_open_mux(base); chr->filename = base->filename; + chr->avail_connections = MAX_MUX; QTAILQ_INSERT_TAIL(&chardevs, chr, next); + } else { + chr->avail_connections = 1; } chr->label = qemu_strdup(qemu_opts_id(opts)); return chr; @@ -2534,9 +2592,31 @@ CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*i if (chr && qemu_opt_get_bool(opts, "mux", 0)) { monitor_init(chr, MONITOR_USE_READLINE); } + qemu_opts_del(opts); return chr; } +void qemu_chr_set_echo(struct CharDriverState *chr, bool echo) +{ + if (chr->chr_set_echo) { + chr->chr_set_echo(chr, echo); + } +} + +void qemu_chr_guest_open(struct CharDriverState *chr) +{ + if (chr->chr_guest_open) { + chr->chr_guest_open(chr); + } +} + +void qemu_chr_guest_close(struct CharDriverState *chr) +{ + if (chr->chr_guest_close) { + chr->chr_guest_close(chr); + } +} + void qemu_chr_close(CharDriverState *chr) { QTAILQ_REMOVE(&chardevs, chr, next); diff --git a/qemu-char.h b/qemu-char.h index 7671824..b967493 100644 --- a/qemu-char.h +++ b/qemu-char.h @@ -6,6 +6,7 @@ #include "qemu-option.h" #include "qemu-config.h" #include "qobject.h" +#include "qstring.h" /* character device */ @@ -63,11 +64,15 @@ struct CharDriverState { void (*chr_send_event)(struct CharDriverState *chr, int event); void (*chr_close)(struct CharDriverState *chr); void (*chr_accept_input)(struct CharDriverState *chr); + void (*chr_set_echo)(struct CharDriverState *chr, bool echo); + void (*chr_guest_open)(struct CharDriverState *chr); + void (*chr_guest_close)(struct CharDriverState *chr); void *opaque; QEMUBH *bh; char *label; char *filename; int opened; + int avail_connections; QTAILQ_ENTRY(CharDriverState) next; }; @@ -75,8 +80,12 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename); CharDriverState *qemu_chr_open_opts(QemuOpts *opts, void (*init)(struct CharDriverState *s)); CharDriverState *qemu_chr_open(const char *label, const char *filename, void (*init)(struct CharDriverState *s)); +void qemu_chr_set_echo(struct CharDriverState *chr, bool echo); +void qemu_chr_guest_open(struct CharDriverState *chr); +void qemu_chr_guest_close(struct CharDriverState *chr); void qemu_chr_close(CharDriverState *chr); -void qemu_chr_printf(CharDriverState *s, const char *fmt, ...); +void qemu_chr_printf(CharDriverState *s, const char *fmt, ...) + GCC_FMT_ATTR(2, 3); int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len); void qemu_chr_send_event(CharDriverState *s, int event); void qemu_chr_add_handlers(CharDriverState *s, @@ -100,6 +109,12 @@ CharDriverState *qemu_chr_open_eventfd(int eventfd); extern int term_escape_char; +/* memory chardev */ +void qemu_chr_init_mem(CharDriverState *chr); +void qemu_chr_close_mem(CharDriverState *chr); +QString *qemu_chr_mem_to_qs(CharDriverState *chr); +size_t qemu_chr_mem_osize(const CharDriverState *chr); + /* async I/O support */ int qemu_set_fd_handler2(int fd, |