10e58f177SMarc-André Lureau /*
20e58f177SMarc-André Lureau * QEMU System Emulator
30e58f177SMarc-André Lureau *
40e58f177SMarc-André Lureau * Copyright (c) 2003-2008 Fabrice Bellard
50e58f177SMarc-André Lureau *
60e58f177SMarc-André Lureau * Permission is hereby granted, free of charge, to any person obtaining a copy
70e58f177SMarc-André Lureau * of this software and associated documentation files (the "Software"), to deal
80e58f177SMarc-André Lureau * in the Software without restriction, including without limitation the rights
90e58f177SMarc-André Lureau * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
100e58f177SMarc-André Lureau * copies of the Software, and to permit persons to whom the Software is
110e58f177SMarc-André Lureau * furnished to do so, subject to the following conditions:
120e58f177SMarc-André Lureau *
130e58f177SMarc-André Lureau * The above copyright notice and this permission notice shall be included in
140e58f177SMarc-André Lureau * all copies or substantial portions of the Software.
150e58f177SMarc-André Lureau *
160e58f177SMarc-André Lureau * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
170e58f177SMarc-André Lureau * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
180e58f177SMarc-André Lureau * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
190e58f177SMarc-André Lureau * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
200e58f177SMarc-André Lureau * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
210e58f177SMarc-André Lureau * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
220e58f177SMarc-André Lureau * THE SOFTWARE.
230e58f177SMarc-André Lureau */
240b8fa32fSMarkus Armbruster
250e58f177SMarc-André Lureau #include "qemu/osdep.h"
260e58f177SMarc-André Lureau #include "qapi/error.h"
27db725815SMarkus Armbruster #include "qemu/main-loop.h"
280b8fa32fSMarkus Armbruster #include "qemu/module.h"
298228e353SMarc-André Lureau #include "chardev/char-win.h"
308228e353SMarc-André Lureau #include "chardev/char-win-stdio.h"
31db1015e9SEduardo Habkost #include "qom/object.h"
320e58f177SMarc-André Lureau
33db1015e9SEduardo Habkost struct WinStdioChardev {
340e58f177SMarc-André Lureau Chardev parent;
350e58f177SMarc-André Lureau HANDLE hStdIn;
36*903cc9e1Ssongziming DWORD dwOldMode;
370e58f177SMarc-André Lureau HANDLE hInputReadyEvent;
380e58f177SMarc-André Lureau HANDLE hInputDoneEvent;
390e58f177SMarc-André Lureau HANDLE hInputThread;
400e58f177SMarc-André Lureau uint8_t win_stdio_buf;
41db1015e9SEduardo Habkost };
42db1015e9SEduardo Habkost typedef struct WinStdioChardev WinStdioChardev;
430e58f177SMarc-André Lureau
DECLARE_INSTANCE_CHECKER(WinStdioChardev,WIN_STDIO_CHARDEV,TYPE_CHARDEV_WIN_STDIO)448110fa1dSEduardo Habkost DECLARE_INSTANCE_CHECKER(WinStdioChardev, WIN_STDIO_CHARDEV,
458110fa1dSEduardo Habkost TYPE_CHARDEV_WIN_STDIO)
460e58f177SMarc-André Lureau
470e58f177SMarc-André Lureau static void win_stdio_wait_func(void *opaque)
480e58f177SMarc-André Lureau {
490e58f177SMarc-André Lureau Chardev *chr = CHARDEV(opaque);
500e58f177SMarc-André Lureau WinStdioChardev *stdio = WIN_STDIO_CHARDEV(opaque);
510e58f177SMarc-André Lureau INPUT_RECORD buf[4];
520e58f177SMarc-André Lureau int ret;
530e58f177SMarc-André Lureau DWORD dwSize;
540e58f177SMarc-André Lureau int i;
550e58f177SMarc-André Lureau
560e58f177SMarc-André Lureau ret = ReadConsoleInput(stdio->hStdIn, buf, ARRAY_SIZE(buf), &dwSize);
570e58f177SMarc-André Lureau
580e58f177SMarc-André Lureau if (!ret) {
590e58f177SMarc-André Lureau /* Avoid error storm */
600e58f177SMarc-André Lureau qemu_del_wait_object(stdio->hStdIn, NULL, NULL);
610e58f177SMarc-André Lureau return;
620e58f177SMarc-André Lureau }
630e58f177SMarc-André Lureau
640e58f177SMarc-André Lureau for (i = 0; i < dwSize; i++) {
650e58f177SMarc-André Lureau KEY_EVENT_RECORD *kev = &buf[i].Event.KeyEvent;
660e58f177SMarc-André Lureau
670e58f177SMarc-André Lureau if (buf[i].EventType == KEY_EVENT && kev->bKeyDown) {
680e58f177SMarc-André Lureau int j;
690e58f177SMarc-André Lureau if (kev->uChar.AsciiChar != 0) {
700e58f177SMarc-André Lureau for (j = 0; j < kev->wRepeatCount; j++) {
710e58f177SMarc-André Lureau if (qemu_chr_be_can_write(chr)) {
720e58f177SMarc-André Lureau uint8_t c = kev->uChar.AsciiChar;
730e58f177SMarc-André Lureau qemu_chr_be_write(chr, &c, 1);
740e58f177SMarc-André Lureau }
750e58f177SMarc-André Lureau }
760e58f177SMarc-André Lureau }
770e58f177SMarc-André Lureau }
780e58f177SMarc-André Lureau }
790e58f177SMarc-André Lureau }
800e58f177SMarc-André Lureau
win_stdio_thread(LPVOID param)810e58f177SMarc-André Lureau static DWORD WINAPI win_stdio_thread(LPVOID param)
820e58f177SMarc-André Lureau {
830e58f177SMarc-André Lureau WinStdioChardev *stdio = WIN_STDIO_CHARDEV(param);
840e58f177SMarc-André Lureau int ret;
850e58f177SMarc-André Lureau DWORD dwSize;
860e58f177SMarc-André Lureau
870e58f177SMarc-André Lureau while (1) {
880e58f177SMarc-André Lureau
890e58f177SMarc-André Lureau /* Wait for one byte */
900e58f177SMarc-André Lureau ret = ReadFile(stdio->hStdIn, &stdio->win_stdio_buf, 1, &dwSize, NULL);
910e58f177SMarc-André Lureau
920e58f177SMarc-André Lureau /* Exit in case of error, continue if nothing read */
930e58f177SMarc-André Lureau if (!ret) {
940e58f177SMarc-André Lureau break;
950e58f177SMarc-André Lureau }
960e58f177SMarc-André Lureau if (!dwSize) {
970e58f177SMarc-André Lureau continue;
980e58f177SMarc-André Lureau }
990e58f177SMarc-André Lureau
1000e58f177SMarc-André Lureau /* Some terminal emulator returns \r\n for Enter, just pass \n */
1010e58f177SMarc-André Lureau if (stdio->win_stdio_buf == '\r') {
1020e58f177SMarc-André Lureau continue;
1030e58f177SMarc-André Lureau }
1040e58f177SMarc-André Lureau
1050e58f177SMarc-André Lureau /* Signal the main thread and wait until the byte was eaten */
1060e58f177SMarc-André Lureau if (!SetEvent(stdio->hInputReadyEvent)) {
1070e58f177SMarc-André Lureau break;
1080e58f177SMarc-André Lureau }
1090e58f177SMarc-André Lureau if (WaitForSingleObject(stdio->hInputDoneEvent, INFINITE)
1100e58f177SMarc-André Lureau != WAIT_OBJECT_0) {
1110e58f177SMarc-André Lureau break;
1120e58f177SMarc-André Lureau }
1130e58f177SMarc-André Lureau }
1140e58f177SMarc-André Lureau
1150e58f177SMarc-André Lureau qemu_del_wait_object(stdio->hInputReadyEvent, NULL, NULL);
1160e58f177SMarc-André Lureau return 0;
1170e58f177SMarc-André Lureau }
1180e58f177SMarc-André Lureau
win_stdio_thread_wait_func(void * opaque)1190e58f177SMarc-André Lureau static void win_stdio_thread_wait_func(void *opaque)
1200e58f177SMarc-André Lureau {
1210e58f177SMarc-André Lureau Chardev *chr = CHARDEV(opaque);
1220e58f177SMarc-André Lureau WinStdioChardev *stdio = WIN_STDIO_CHARDEV(opaque);
1230e58f177SMarc-André Lureau
1240e58f177SMarc-André Lureau if (qemu_chr_be_can_write(chr)) {
1250e58f177SMarc-André Lureau qemu_chr_be_write(chr, &stdio->win_stdio_buf, 1);
1260e58f177SMarc-André Lureau }
1270e58f177SMarc-André Lureau
1280e58f177SMarc-André Lureau SetEvent(stdio->hInputDoneEvent);
1290e58f177SMarc-André Lureau }
1300e58f177SMarc-André Lureau
qemu_chr_set_echo_win_stdio(Chardev * chr,bool echo)1310e58f177SMarc-André Lureau static void qemu_chr_set_echo_win_stdio(Chardev *chr, bool echo)
1320e58f177SMarc-André Lureau {
1330e58f177SMarc-André Lureau WinStdioChardev *stdio = WIN_STDIO_CHARDEV(chr);
1340e58f177SMarc-André Lureau DWORD dwMode = 0;
1350e58f177SMarc-André Lureau
1360e58f177SMarc-André Lureau GetConsoleMode(stdio->hStdIn, &dwMode);
1370e58f177SMarc-André Lureau
1380e58f177SMarc-André Lureau if (echo) {
1390e58f177SMarc-André Lureau SetConsoleMode(stdio->hStdIn, dwMode | ENABLE_ECHO_INPUT);
1400e58f177SMarc-André Lureau } else {
1410e58f177SMarc-André Lureau SetConsoleMode(stdio->hStdIn, dwMode & ~ENABLE_ECHO_INPUT);
1420e58f177SMarc-André Lureau }
1430e58f177SMarc-André Lureau }
1440e58f177SMarc-André Lureau
qemu_chr_open_stdio(Chardev * chr,ChardevBackend * backend,bool * be_opened,Error ** errp)1450e58f177SMarc-André Lureau static void qemu_chr_open_stdio(Chardev *chr,
1460e58f177SMarc-André Lureau ChardevBackend *backend,
1470e58f177SMarc-André Lureau bool *be_opened,
1480e58f177SMarc-André Lureau Error **errp)
1490e58f177SMarc-André Lureau {
15006639f8fSBin Meng ChardevStdio *opts = backend->u.stdio.data;
15106639f8fSBin Meng bool stdio_allow_signal = !opts->has_signal || opts->signal;
1520e58f177SMarc-André Lureau WinStdioChardev *stdio = WIN_STDIO_CHARDEV(chr);
1530e58f177SMarc-André Lureau DWORD dwMode;
1540e58f177SMarc-André Lureau int is_console = 0;
1550e58f177SMarc-André Lureau
1560e58f177SMarc-André Lureau stdio->hStdIn = GetStdHandle(STD_INPUT_HANDLE);
1570e58f177SMarc-André Lureau if (stdio->hStdIn == INVALID_HANDLE_VALUE) {
1580e58f177SMarc-André Lureau error_setg(errp, "cannot open stdio: invalid handle");
1590e58f177SMarc-André Lureau return;
1600e58f177SMarc-André Lureau }
1610e58f177SMarc-André Lureau
1620e58f177SMarc-André Lureau is_console = GetConsoleMode(stdio->hStdIn, &dwMode) != 0;
163*903cc9e1Ssongziming stdio->dwOldMode = dwMode;
1640e58f177SMarc-André Lureau
1650e58f177SMarc-André Lureau if (is_console) {
1660e58f177SMarc-André Lureau if (qemu_add_wait_object(stdio->hStdIn,
1670e58f177SMarc-André Lureau win_stdio_wait_func, chr)) {
1680e58f177SMarc-André Lureau error_setg(errp, "qemu_add_wait_object: failed");
1690e58f177SMarc-André Lureau goto err1;
1700e58f177SMarc-André Lureau }
1710e58f177SMarc-André Lureau } else {
1720e58f177SMarc-André Lureau DWORD dwId;
1730e58f177SMarc-André Lureau
1740e58f177SMarc-André Lureau stdio->hInputReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
1750e58f177SMarc-André Lureau stdio->hInputDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
1760e58f177SMarc-André Lureau if (stdio->hInputReadyEvent == INVALID_HANDLE_VALUE
1770e58f177SMarc-André Lureau || stdio->hInputDoneEvent == INVALID_HANDLE_VALUE) {
1780e58f177SMarc-André Lureau error_setg(errp, "cannot create event");
1790e58f177SMarc-André Lureau goto err2;
1800e58f177SMarc-André Lureau }
1810e58f177SMarc-André Lureau if (qemu_add_wait_object(stdio->hInputReadyEvent,
1820e58f177SMarc-André Lureau win_stdio_thread_wait_func, chr)) {
1830e58f177SMarc-André Lureau error_setg(errp, "qemu_add_wait_object: failed");
1840e58f177SMarc-André Lureau goto err2;
1850e58f177SMarc-André Lureau }
1860e58f177SMarc-André Lureau stdio->hInputThread = CreateThread(NULL, 0, win_stdio_thread,
1870e58f177SMarc-André Lureau chr, 0, &dwId);
1880e58f177SMarc-André Lureau
1890e58f177SMarc-André Lureau if (stdio->hInputThread == INVALID_HANDLE_VALUE) {
1900e58f177SMarc-André Lureau error_setg(errp, "cannot create stdio thread");
1910e58f177SMarc-André Lureau goto err3;
1920e58f177SMarc-André Lureau }
1930e58f177SMarc-André Lureau }
1940e58f177SMarc-André Lureau
1951e0c5446SZhang Huasen dwMode |= ENABLE_LINE_INPUT | ENABLE_VIRTUAL_TERMINAL_INPUT;
1960e58f177SMarc-André Lureau
1970e58f177SMarc-André Lureau if (is_console) {
1980e58f177SMarc-André Lureau /* set the terminal in raw mode */
1990e58f177SMarc-André Lureau /* ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS */
20006639f8fSBin Meng if (stdio_allow_signal) {
2010e58f177SMarc-André Lureau dwMode |= ENABLE_PROCESSED_INPUT;
20206639f8fSBin Meng } else {
20306639f8fSBin Meng dwMode &= ~ENABLE_PROCESSED_INPUT;
20406639f8fSBin Meng }
2050e58f177SMarc-André Lureau }
2060e58f177SMarc-André Lureau
2070e58f177SMarc-André Lureau SetConsoleMode(stdio->hStdIn, dwMode);
2080e58f177SMarc-André Lureau
2090e58f177SMarc-André Lureau qemu_chr_set_echo_win_stdio(chr, false);
2100e58f177SMarc-André Lureau
2110e58f177SMarc-André Lureau return;
2120e58f177SMarc-André Lureau
2130e58f177SMarc-André Lureau err3:
2140e58f177SMarc-André Lureau qemu_del_wait_object(stdio->hInputReadyEvent, NULL, NULL);
2150e58f177SMarc-André Lureau err2:
2160e58f177SMarc-André Lureau CloseHandle(stdio->hInputReadyEvent);
2170e58f177SMarc-André Lureau CloseHandle(stdio->hInputDoneEvent);
2180e58f177SMarc-André Lureau err1:
2190e58f177SMarc-André Lureau qemu_del_wait_object(stdio->hStdIn, NULL, NULL);
2200e58f177SMarc-André Lureau }
2210e58f177SMarc-André Lureau
char_win_stdio_finalize(Object * obj)2220e58f177SMarc-André Lureau static void char_win_stdio_finalize(Object *obj)
2230e58f177SMarc-André Lureau {
2240e58f177SMarc-André Lureau WinStdioChardev *stdio = WIN_STDIO_CHARDEV(obj);
2250e58f177SMarc-André Lureau
226*903cc9e1Ssongziming if (stdio->hStdIn != INVALID_HANDLE_VALUE) {
227*903cc9e1Ssongziming SetConsoleMode(stdio->hStdIn, stdio->dwOldMode);
228*903cc9e1Ssongziming }
2290e58f177SMarc-André Lureau if (stdio->hInputReadyEvent != INVALID_HANDLE_VALUE) {
2300e58f177SMarc-André Lureau CloseHandle(stdio->hInputReadyEvent);
2310e58f177SMarc-André Lureau }
2320e58f177SMarc-André Lureau if (stdio->hInputDoneEvent != INVALID_HANDLE_VALUE) {
2330e58f177SMarc-André Lureau CloseHandle(stdio->hInputDoneEvent);
2340e58f177SMarc-André Lureau }
2350e58f177SMarc-André Lureau if (stdio->hInputThread != INVALID_HANDLE_VALUE) {
2360e58f177SMarc-André Lureau TerminateThread(stdio->hInputThread, 0);
2370e58f177SMarc-André Lureau }
2380e58f177SMarc-André Lureau }
2390e58f177SMarc-André Lureau
win_stdio_write(Chardev * chr,const uint8_t * buf,int len)2400e58f177SMarc-André Lureau static int win_stdio_write(Chardev *chr, const uint8_t *buf, int len)
2410e58f177SMarc-André Lureau {
2420e58f177SMarc-André Lureau HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
2430e58f177SMarc-André Lureau DWORD dwSize;
2440e58f177SMarc-André Lureau int len1;
2450e58f177SMarc-André Lureau
2460e58f177SMarc-André Lureau len1 = len;
2470e58f177SMarc-André Lureau
2480e58f177SMarc-André Lureau while (len1 > 0) {
2490e58f177SMarc-André Lureau if (!WriteFile(hStdOut, buf, len1, &dwSize, NULL)) {
2500e58f177SMarc-André Lureau break;
2510e58f177SMarc-André Lureau }
2520e58f177SMarc-André Lureau buf += dwSize;
2530e58f177SMarc-André Lureau len1 -= dwSize;
2540e58f177SMarc-André Lureau }
2550e58f177SMarc-André Lureau
2560e58f177SMarc-André Lureau return len - len1;
2570e58f177SMarc-André Lureau }
2580e58f177SMarc-André Lureau
char_win_stdio_class_init(ObjectClass * oc,void * data)2590e58f177SMarc-André Lureau static void char_win_stdio_class_init(ObjectClass *oc, void *data)
2600e58f177SMarc-André Lureau {
2610e58f177SMarc-André Lureau ChardevClass *cc = CHARDEV_CLASS(oc);
2620e58f177SMarc-André Lureau
2630e58f177SMarc-André Lureau cc->open = qemu_chr_open_stdio;
2640e58f177SMarc-André Lureau cc->chr_write = win_stdio_write;
2650e58f177SMarc-André Lureau cc->chr_set_echo = qemu_chr_set_echo_win_stdio;
2660e58f177SMarc-André Lureau }
2670e58f177SMarc-André Lureau
2680e58f177SMarc-André Lureau static const TypeInfo char_win_stdio_type_info = {
2690e58f177SMarc-André Lureau .name = TYPE_CHARDEV_WIN_STDIO,
2700e58f177SMarc-André Lureau .parent = TYPE_CHARDEV,
2710e58f177SMarc-André Lureau .instance_size = sizeof(WinStdioChardev),
2720e58f177SMarc-André Lureau .instance_finalize = char_win_stdio_finalize,
2730e58f177SMarc-André Lureau .class_init = char_win_stdio_class_init,
2740e58f177SMarc-André Lureau .abstract = true,
2750e58f177SMarc-André Lureau };
2760e58f177SMarc-André Lureau
register_types(void)2770e58f177SMarc-André Lureau static void register_types(void)
2780e58f177SMarc-André Lureau {
2790e58f177SMarc-André Lureau type_register_static(&char_win_stdio_type_info);
2800e58f177SMarc-André Lureau }
2810e58f177SMarc-André Lureau
2820e58f177SMarc-André Lureau type_init(register_types);
283