Loading qemu-char.c +225 −2 Original line number Diff line number Diff line Loading @@ -538,6 +538,9 @@ int send_all(int fd, const void *_buf, int len1) } #endif /* !_WIN32 */ #define STDIO_MAX_CLIENTS 1 static int stdio_nb_clients; #ifndef _WIN32 typedef struct { Loading @@ -545,8 +548,6 @@ typedef struct { int max_size; } FDCharDriver; #define STDIO_MAX_CLIENTS 1 static int stdio_nb_clients = 0; static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { Loading Loading @@ -1451,6 +1452,8 @@ static int qemu_chr_open_pp(QemuOpts *opts, CharDriverState **_chr) #else /* _WIN32 */ static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS]; typedef struct { int max_size; HANDLE hcom, hrecv, hsend; Loading @@ -1459,6 +1462,14 @@ typedef struct { DWORD len; } WinCharState; typedef struct { HANDLE hStdIn; HANDLE hInputReadyEvent; HANDLE hInputDoneEvent; HANDLE hInputThread; uint8_t win_stdio_buf; } WinStdioCharState; #define NSENDBUF 2048 #define NRECVBUF 2048 #define MAXCONNECT 1 Loading Loading @@ -1809,6 +1820,217 @@ static int qemu_chr_open_win_file_out(QemuOpts *opts, CharDriverState **_chr) return qemu_chr_open_win_file(fd_out, _chr); } static int win_stdio_write(CharDriverState *chr, const uint8_t *buf, int len) { HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); DWORD dwSize; int len1; len1 = len; while (len1 > 0) { if (!WriteFile(hStdOut, buf, len1, &dwSize, NULL)) { break; } buf += dwSize; len1 -= dwSize; } return len - len1; } static void win_stdio_wait_func(void *opaque) { CharDriverState *chr = opaque; WinStdioCharState *stdio = chr->opaque; INPUT_RECORD buf[4]; int ret; DWORD dwSize; int i; ret = ReadConsoleInput(stdio->hStdIn, buf, sizeof(buf) / sizeof(*buf), &dwSize); if (!ret) { /* Avoid error storm */ qemu_del_wait_object(stdio->hStdIn, NULL, NULL); return; } for (i = 0; i < dwSize; i++) { KEY_EVENT_RECORD *kev = &buf[i].Event.KeyEvent; if (buf[i].EventType == KEY_EVENT && kev->bKeyDown) { int j; if (kev->uChar.AsciiChar != 0) { for (j = 0; j < kev->wRepeatCount; j++) { if (qemu_chr_be_can_write(chr)) { uint8_t c = kev->uChar.AsciiChar; qemu_chr_be_write(chr, &c, 1); } } } } } } static DWORD WINAPI win_stdio_thread(LPVOID param) { CharDriverState *chr = param; WinStdioCharState *stdio = chr->opaque; int ret; DWORD dwSize; while (1) { /* Wait for one byte */ ret = ReadFile(stdio->hStdIn, &stdio->win_stdio_buf, 1, &dwSize, NULL); /* Exit in case of error, continue if nothing read */ if (!ret) { break; } if (!dwSize) { continue; } /* Some terminal emulator returns \r\n for Enter, just pass \n */ if (stdio->win_stdio_buf == '\r') { continue; } /* Signal the main thread and wait until the byte was eaten */ if (!SetEvent(stdio->hInputReadyEvent)) { break; } if (WaitForSingleObject(stdio->hInputDoneEvent, INFINITE) != WAIT_OBJECT_0) { break; } } qemu_del_wait_object(stdio->hInputReadyEvent, NULL, NULL); return 0; } static void win_stdio_thread_wait_func(void *opaque) { CharDriverState *chr = opaque; WinStdioCharState *stdio = chr->opaque; if (qemu_chr_be_can_write(chr)) { qemu_chr_be_write(chr, &stdio->win_stdio_buf, 1); } SetEvent(stdio->hInputDoneEvent); } static void qemu_chr_set_echo_win_stdio(CharDriverState *chr, bool echo) { WinStdioCharState *stdio = chr->opaque; DWORD dwMode = 0; GetConsoleMode(stdio->hStdIn, &dwMode); if (echo) { SetConsoleMode(stdio->hStdIn, dwMode | ENABLE_ECHO_INPUT); } else { SetConsoleMode(stdio->hStdIn, dwMode & ~ENABLE_ECHO_INPUT); } } static void win_stdio_close(CharDriverState *chr) { WinStdioCharState *stdio = chr->opaque; if (stdio->hInputReadyEvent != INVALID_HANDLE_VALUE) { CloseHandle(stdio->hInputReadyEvent); } if (stdio->hInputDoneEvent != INVALID_HANDLE_VALUE) { CloseHandle(stdio->hInputDoneEvent); } if (stdio->hInputThread != INVALID_HANDLE_VALUE) { TerminateThread(stdio->hInputThread, 0); } g_free(chr->opaque); g_free(chr); stdio_nb_clients--; } static int qemu_chr_open_win_stdio(QemuOpts *opts, CharDriverState **_chr) { CharDriverState *chr; WinStdioCharState *stdio; DWORD dwMode; int is_console = 0; if (stdio_nb_clients >= STDIO_MAX_CLIENTS || ((display_type != DT_NOGRAPHIC) && (stdio_nb_clients != 0))) { return -EIO; } chr = g_malloc0(sizeof(CharDriverState)); stdio = g_malloc0(sizeof(WinStdioCharState)); stdio->hStdIn = GetStdHandle(STD_INPUT_HANDLE); if (stdio->hStdIn == INVALID_HANDLE_VALUE) { fprintf(stderr, "cannot open stdio: invalid handle\n"); exit(1); } is_console = GetConsoleMode(stdio->hStdIn, &dwMode) != 0; chr->opaque = stdio; chr->chr_write = win_stdio_write; chr->chr_close = win_stdio_close; if (stdio_nb_clients == 0) { if (is_console) { if (qemu_add_wait_object(stdio->hStdIn, win_stdio_wait_func, chr)) { fprintf(stderr, "qemu_add_wait_object: failed\n"); } } else { DWORD dwId; stdio->hInputReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); stdio->hInputDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL); stdio->hInputThread = CreateThread(NULL, 0, win_stdio_thread, chr, 0, &dwId); if (stdio->hInputThread == INVALID_HANDLE_VALUE || stdio->hInputReadyEvent == INVALID_HANDLE_VALUE || stdio->hInputDoneEvent == INVALID_HANDLE_VALUE) { fprintf(stderr, "cannot create stdio thread or event\n"); exit(1); } if (qemu_add_wait_object(stdio->hInputReadyEvent, win_stdio_thread_wait_func, chr)) { fprintf(stderr, "qemu_add_wait_object: failed\n"); } } } dwMode |= ENABLE_LINE_INPUT; stdio_clients[stdio_nb_clients++] = chr; if (stdio_nb_clients == 1 && is_console) { /* set the terminal in raw mode */ /* ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS */ dwMode |= ENABLE_PROCESSED_INPUT; } SetConsoleMode(stdio->hStdIn, dwMode); chr->chr_set_echo = qemu_chr_set_echo_win_stdio; qemu_chr_fe_set_echo(chr, false); *_chr = chr; return 0; } #endif /* !_WIN32 */ /***********************************************************/ Loading Loading @@ -2519,6 +2741,7 @@ static const struct { { .name = "pipe", .open = qemu_chr_open_win_pipe }, { .name = "console", .open = qemu_chr_open_win_con }, { .name = "serial", .open = qemu_chr_open_win }, { .name = "stdio", .open = qemu_chr_open_win_stdio }, #else { .name = "file", .open = qemu_chr_open_file_out }, { .name = "pipe", .open = qemu_chr_open_pipe }, Loading Loading
qemu-char.c +225 −2 Original line number Diff line number Diff line Loading @@ -538,6 +538,9 @@ int send_all(int fd, const void *_buf, int len1) } #endif /* !_WIN32 */ #define STDIO_MAX_CLIENTS 1 static int stdio_nb_clients; #ifndef _WIN32 typedef struct { Loading @@ -545,8 +548,6 @@ typedef struct { int max_size; } FDCharDriver; #define STDIO_MAX_CLIENTS 1 static int stdio_nb_clients = 0; static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len) { Loading Loading @@ -1451,6 +1452,8 @@ static int qemu_chr_open_pp(QemuOpts *opts, CharDriverState **_chr) #else /* _WIN32 */ static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS]; typedef struct { int max_size; HANDLE hcom, hrecv, hsend; Loading @@ -1459,6 +1462,14 @@ typedef struct { DWORD len; } WinCharState; typedef struct { HANDLE hStdIn; HANDLE hInputReadyEvent; HANDLE hInputDoneEvent; HANDLE hInputThread; uint8_t win_stdio_buf; } WinStdioCharState; #define NSENDBUF 2048 #define NRECVBUF 2048 #define MAXCONNECT 1 Loading Loading @@ -1809,6 +1820,217 @@ static int qemu_chr_open_win_file_out(QemuOpts *opts, CharDriverState **_chr) return qemu_chr_open_win_file(fd_out, _chr); } static int win_stdio_write(CharDriverState *chr, const uint8_t *buf, int len) { HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); DWORD dwSize; int len1; len1 = len; while (len1 > 0) { if (!WriteFile(hStdOut, buf, len1, &dwSize, NULL)) { break; } buf += dwSize; len1 -= dwSize; } return len - len1; } static void win_stdio_wait_func(void *opaque) { CharDriverState *chr = opaque; WinStdioCharState *stdio = chr->opaque; INPUT_RECORD buf[4]; int ret; DWORD dwSize; int i; ret = ReadConsoleInput(stdio->hStdIn, buf, sizeof(buf) / sizeof(*buf), &dwSize); if (!ret) { /* Avoid error storm */ qemu_del_wait_object(stdio->hStdIn, NULL, NULL); return; } for (i = 0; i < dwSize; i++) { KEY_EVENT_RECORD *kev = &buf[i].Event.KeyEvent; if (buf[i].EventType == KEY_EVENT && kev->bKeyDown) { int j; if (kev->uChar.AsciiChar != 0) { for (j = 0; j < kev->wRepeatCount; j++) { if (qemu_chr_be_can_write(chr)) { uint8_t c = kev->uChar.AsciiChar; qemu_chr_be_write(chr, &c, 1); } } } } } } static DWORD WINAPI win_stdio_thread(LPVOID param) { CharDriverState *chr = param; WinStdioCharState *stdio = chr->opaque; int ret; DWORD dwSize; while (1) { /* Wait for one byte */ ret = ReadFile(stdio->hStdIn, &stdio->win_stdio_buf, 1, &dwSize, NULL); /* Exit in case of error, continue if nothing read */ if (!ret) { break; } if (!dwSize) { continue; } /* Some terminal emulator returns \r\n for Enter, just pass \n */ if (stdio->win_stdio_buf == '\r') { continue; } /* Signal the main thread and wait until the byte was eaten */ if (!SetEvent(stdio->hInputReadyEvent)) { break; } if (WaitForSingleObject(stdio->hInputDoneEvent, INFINITE) != WAIT_OBJECT_0) { break; } } qemu_del_wait_object(stdio->hInputReadyEvent, NULL, NULL); return 0; } static void win_stdio_thread_wait_func(void *opaque) { CharDriverState *chr = opaque; WinStdioCharState *stdio = chr->opaque; if (qemu_chr_be_can_write(chr)) { qemu_chr_be_write(chr, &stdio->win_stdio_buf, 1); } SetEvent(stdio->hInputDoneEvent); } static void qemu_chr_set_echo_win_stdio(CharDriverState *chr, bool echo) { WinStdioCharState *stdio = chr->opaque; DWORD dwMode = 0; GetConsoleMode(stdio->hStdIn, &dwMode); if (echo) { SetConsoleMode(stdio->hStdIn, dwMode | ENABLE_ECHO_INPUT); } else { SetConsoleMode(stdio->hStdIn, dwMode & ~ENABLE_ECHO_INPUT); } } static void win_stdio_close(CharDriverState *chr) { WinStdioCharState *stdio = chr->opaque; if (stdio->hInputReadyEvent != INVALID_HANDLE_VALUE) { CloseHandle(stdio->hInputReadyEvent); } if (stdio->hInputDoneEvent != INVALID_HANDLE_VALUE) { CloseHandle(stdio->hInputDoneEvent); } if (stdio->hInputThread != INVALID_HANDLE_VALUE) { TerminateThread(stdio->hInputThread, 0); } g_free(chr->opaque); g_free(chr); stdio_nb_clients--; } static int qemu_chr_open_win_stdio(QemuOpts *opts, CharDriverState **_chr) { CharDriverState *chr; WinStdioCharState *stdio; DWORD dwMode; int is_console = 0; if (stdio_nb_clients >= STDIO_MAX_CLIENTS || ((display_type != DT_NOGRAPHIC) && (stdio_nb_clients != 0))) { return -EIO; } chr = g_malloc0(sizeof(CharDriverState)); stdio = g_malloc0(sizeof(WinStdioCharState)); stdio->hStdIn = GetStdHandle(STD_INPUT_HANDLE); if (stdio->hStdIn == INVALID_HANDLE_VALUE) { fprintf(stderr, "cannot open stdio: invalid handle\n"); exit(1); } is_console = GetConsoleMode(stdio->hStdIn, &dwMode) != 0; chr->opaque = stdio; chr->chr_write = win_stdio_write; chr->chr_close = win_stdio_close; if (stdio_nb_clients == 0) { if (is_console) { if (qemu_add_wait_object(stdio->hStdIn, win_stdio_wait_func, chr)) { fprintf(stderr, "qemu_add_wait_object: failed\n"); } } else { DWORD dwId; stdio->hInputReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); stdio->hInputDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL); stdio->hInputThread = CreateThread(NULL, 0, win_stdio_thread, chr, 0, &dwId); if (stdio->hInputThread == INVALID_HANDLE_VALUE || stdio->hInputReadyEvent == INVALID_HANDLE_VALUE || stdio->hInputDoneEvent == INVALID_HANDLE_VALUE) { fprintf(stderr, "cannot create stdio thread or event\n"); exit(1); } if (qemu_add_wait_object(stdio->hInputReadyEvent, win_stdio_thread_wait_func, chr)) { fprintf(stderr, "qemu_add_wait_object: failed\n"); } } } dwMode |= ENABLE_LINE_INPUT; stdio_clients[stdio_nb_clients++] = chr; if (stdio_nb_clients == 1 && is_console) { /* set the terminal in raw mode */ /* ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS */ dwMode |= ENABLE_PROCESSED_INPUT; } SetConsoleMode(stdio->hStdIn, dwMode); chr->chr_set_echo = qemu_chr_set_echo_win_stdio; qemu_chr_fe_set_echo(chr, false); *_chr = chr; return 0; } #endif /* !_WIN32 */ /***********************************************************/ Loading Loading @@ -2519,6 +2741,7 @@ static const struct { { .name = "pipe", .open = qemu_chr_open_win_pipe }, { .name = "console", .open = qemu_chr_open_win_con }, { .name = "serial", .open = qemu_chr_open_win }, { .name = "stdio", .open = qemu_chr_open_win_stdio }, #else { .name = "file", .open = qemu_chr_open_file_out }, { .name = "pipe", .open = qemu_chr_open_pipe }, Loading