1 /* 2 * QEMU System Emulator 3 * 4 * Copyright (c) 2003-2008 Fabrice Bellard 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 #include "qemu/osdep.h" 25 #include "qemu-common.h" 26 #include "qapi/error.h" 27 #include "chardev/char-win.h" 28 29 static void win_chr_read(Chardev *chr, DWORD len) 30 { 31 WinChardev *s = WIN_CHARDEV(chr); 32 int max_size = qemu_chr_be_can_write(chr); 33 int ret, err; 34 uint8_t buf[CHR_READ_BUF_LEN]; 35 DWORD size; 36 37 if (len > max_size) { 38 len = max_size; 39 } 40 if (len == 0) { 41 return; 42 } 43 44 ZeroMemory(&s->orecv, sizeof(s->orecv)); 45 s->orecv.hEvent = s->hrecv; 46 ret = ReadFile(s->file, buf, len, &size, &s->orecv); 47 if (!ret) { 48 err = GetLastError(); 49 if (err == ERROR_IO_PENDING) { 50 ret = GetOverlappedResult(s->file, &s->orecv, &size, TRUE); 51 } 52 } 53 54 if (size > 0) { 55 qemu_chr_be_write(chr, buf, size); 56 } 57 } 58 59 static int win_chr_serial_poll(void *opaque) 60 { 61 Chardev *chr = CHARDEV(opaque); 62 WinChardev *s = WIN_CHARDEV(opaque); 63 COMSTAT status; 64 DWORD comerr; 65 66 ClearCommError(s->file, &comerr, &status); 67 if (status.cbInQue > 0) { 68 win_chr_read(chr, status.cbInQue); 69 return 1; 70 } 71 return 0; 72 } 73 74 int win_chr_serial_init(Chardev *chr, const char *filename, Error **errp) 75 { 76 WinChardev *s = WIN_CHARDEV(chr); 77 COMMCONFIG comcfg; 78 COMMTIMEOUTS cto = { 0, 0, 0, 0, 0}; 79 COMSTAT comstat; 80 DWORD size; 81 DWORD err; 82 83 s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL); 84 if (!s->hsend) { 85 error_setg(errp, "Failed CreateEvent"); 86 goto fail; 87 } 88 s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL); 89 if (!s->hrecv) { 90 error_setg(errp, "Failed CreateEvent"); 91 goto fail; 92 } 93 94 s->file = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, 95 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); 96 if (s->file == INVALID_HANDLE_VALUE) { 97 error_setg(errp, "Failed CreateFile (%lu)", GetLastError()); 98 s->file = NULL; 99 goto fail; 100 } 101 102 if (!SetupComm(s->file, NRECVBUF, NSENDBUF)) { 103 error_setg(errp, "Failed SetupComm"); 104 goto fail; 105 } 106 107 ZeroMemory(&comcfg, sizeof(COMMCONFIG)); 108 size = sizeof(COMMCONFIG); 109 GetDefaultCommConfig(filename, &comcfg, &size); 110 comcfg.dcb.DCBlength = sizeof(DCB); 111 CommConfigDialog(filename, NULL, &comcfg); 112 113 if (!SetCommState(s->file, &comcfg.dcb)) { 114 error_setg(errp, "Failed SetCommState"); 115 goto fail; 116 } 117 118 if (!SetCommMask(s->file, EV_ERR)) { 119 error_setg(errp, "Failed SetCommMask"); 120 goto fail; 121 } 122 123 cto.ReadIntervalTimeout = MAXDWORD; 124 if (!SetCommTimeouts(s->file, &cto)) { 125 error_setg(errp, "Failed SetCommTimeouts"); 126 goto fail; 127 } 128 129 if (!ClearCommError(s->file, &err, &comstat)) { 130 error_setg(errp, "Failed ClearCommError"); 131 goto fail; 132 } 133 qemu_add_polling_cb(win_chr_serial_poll, chr); 134 return 0; 135 136 fail: 137 return -1; 138 } 139 140 int win_chr_pipe_poll(void *opaque) 141 { 142 Chardev *chr = CHARDEV(opaque); 143 WinChardev *s = WIN_CHARDEV(opaque); 144 DWORD size; 145 146 PeekNamedPipe(s->file, NULL, 0, NULL, &size, NULL); 147 if (size > 0) { 148 win_chr_read(chr, size); 149 return 1; 150 } 151 return 0; 152 } 153 154 /* Called with chr_write_lock held. */ 155 static int win_chr_write(Chardev *chr, const uint8_t *buf, int len1) 156 { 157 WinChardev *s = WIN_CHARDEV(chr); 158 DWORD len, ret, size, err; 159 160 len = len1; 161 ZeroMemory(&s->osend, sizeof(s->osend)); 162 s->osend.hEvent = s->hsend; 163 while (len > 0) { 164 if (s->hsend) { 165 ret = WriteFile(s->file, buf, len, &size, &s->osend); 166 } else { 167 ret = WriteFile(s->file, buf, len, &size, NULL); 168 } 169 if (!ret) { 170 err = GetLastError(); 171 if (err == ERROR_IO_PENDING) { 172 ret = GetOverlappedResult(s->file, &s->osend, &size, TRUE); 173 if (ret) { 174 buf += size; 175 len -= size; 176 } else { 177 break; 178 } 179 } else { 180 break; 181 } 182 } else { 183 buf += size; 184 len -= size; 185 } 186 } 187 return len1 - len; 188 } 189 190 static void char_win_finalize(Object *obj) 191 { 192 Chardev *chr = CHARDEV(obj); 193 WinChardev *s = WIN_CHARDEV(chr); 194 195 if (s->hsend) { 196 CloseHandle(s->hsend); 197 } 198 if (s->hrecv) { 199 CloseHandle(s->hrecv); 200 } 201 if (!s->keep_open && s->file) { 202 CloseHandle(s->file); 203 } 204 if (s->fpipe) { 205 qemu_del_polling_cb(win_chr_pipe_poll, chr); 206 } else { 207 qemu_del_polling_cb(win_chr_serial_poll, chr); 208 } 209 210 qemu_chr_be_event(chr, CHR_EVENT_CLOSED); 211 } 212 213 void win_chr_set_file(Chardev *chr, HANDLE file, bool keep_open) 214 { 215 WinChardev *s = WIN_CHARDEV(chr); 216 217 s->keep_open = keep_open; 218 s->file = file; 219 } 220 221 static void char_win_class_init(ObjectClass *oc, void *data) 222 { 223 ChardevClass *cc = CHARDEV_CLASS(oc); 224 225 cc->chr_write = win_chr_write; 226 } 227 228 static const TypeInfo char_win_type_info = { 229 .name = TYPE_CHARDEV_WIN, 230 .parent = TYPE_CHARDEV, 231 .instance_size = sizeof(WinChardev), 232 .instance_finalize = char_win_finalize, 233 .class_init = char_win_class_init, 234 .abstract = true, 235 }; 236 237 static void register_types(void) 238 { 239 type_register_static(&char_win_type_info); 240 } 241 242 type_init(register_types); 243