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 25 #include "qemu/osdep.h" 26 #include "qemu/main-loop.h" 27 #include "qemu/module.h" 28 #include "qapi/error.h" 29 #include "chardev/char-win.h" 30 31 static void win_chr_read(Chardev *chr, DWORD len) 32 { 33 WinChardev *s = WIN_CHARDEV(chr); 34 int max_size = qemu_chr_be_can_write(chr); 35 int ret, err; 36 uint8_t buf[CHR_READ_BUF_LEN]; 37 DWORD size; 38 39 if (len > max_size) { 40 len = max_size; 41 } 42 if (len == 0) { 43 return; 44 } 45 46 ZeroMemory(&s->orecv, sizeof(s->orecv)); 47 s->orecv.hEvent = s->hrecv; 48 ret = ReadFile(s->file, buf, len, &size, &s->orecv); 49 if (!ret) { 50 err = GetLastError(); 51 if (err == ERROR_IO_PENDING) { 52 ret = GetOverlappedResult(s->file, &s->orecv, &size, TRUE); 53 } 54 } 55 56 if (size > 0) { 57 qemu_chr_be_write(chr, buf, size); 58 } 59 } 60 61 static int win_chr_serial_poll(void *opaque) 62 { 63 Chardev *chr = CHARDEV(opaque); 64 WinChardev *s = WIN_CHARDEV(opaque); 65 COMSTAT status; 66 DWORD comerr; 67 68 ClearCommError(s->file, &comerr, &status); 69 if (status.cbInQue > 0) { 70 win_chr_read(chr, status.cbInQue); 71 return 1; 72 } 73 return 0; 74 } 75 76 int win_chr_serial_init(Chardev *chr, const char *filename, Error **errp) 77 { 78 WinChardev *s = WIN_CHARDEV(chr); 79 COMMCONFIG comcfg; 80 COMMTIMEOUTS cto = { 0, 0, 0, 0, 0}; 81 COMSTAT comstat; 82 DWORD size; 83 DWORD err; 84 85 s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL); 86 if (!s->hsend) { 87 error_setg(errp, "Failed CreateEvent"); 88 goto fail; 89 } 90 s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL); 91 if (!s->hrecv) { 92 error_setg(errp, "Failed CreateEvent"); 93 goto fail; 94 } 95 96 s->file = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, 97 OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); 98 if (s->file == INVALID_HANDLE_VALUE) { 99 error_setg(errp, "Failed CreateFile (%lu)", GetLastError()); 100 s->file = NULL; 101 goto fail; 102 } 103 104 if (!SetupComm(s->file, NRECVBUF, NSENDBUF)) { 105 error_setg(errp, "Failed SetupComm"); 106 goto fail; 107 } 108 109 ZeroMemory(&comcfg, sizeof(COMMCONFIG)); 110 size = sizeof(COMMCONFIG); 111 GetDefaultCommConfig(filename, &comcfg, &size); 112 comcfg.dcb.DCBlength = sizeof(DCB); 113 CommConfigDialog(filename, NULL, &comcfg); 114 115 if (!SetCommState(s->file, &comcfg.dcb)) { 116 error_setg(errp, "Failed SetCommState"); 117 goto fail; 118 } 119 120 if (!SetCommMask(s->file, EV_ERR)) { 121 error_setg(errp, "Failed SetCommMask"); 122 goto fail; 123 } 124 125 cto.ReadIntervalTimeout = MAXDWORD; 126 if (!SetCommTimeouts(s->file, &cto)) { 127 error_setg(errp, "Failed SetCommTimeouts"); 128 goto fail; 129 } 130 131 if (!ClearCommError(s->file, &err, &comstat)) { 132 error_setg(errp, "Failed ClearCommError"); 133 goto fail; 134 } 135 qemu_add_polling_cb(win_chr_serial_poll, chr); 136 return 0; 137 138 fail: 139 return -1; 140 } 141 142 int win_chr_pipe_poll(void *opaque) 143 { 144 Chardev *chr = CHARDEV(opaque); 145 WinChardev *s = WIN_CHARDEV(opaque); 146 DWORD size; 147 148 PeekNamedPipe(s->file, NULL, 0, NULL, &size, NULL); 149 if (size > 0) { 150 win_chr_read(chr, size); 151 return 1; 152 } 153 return 0; 154 } 155 156 /* Called with chr_write_lock held. */ 157 static int win_chr_write(Chardev *chr, const uint8_t *buf, int len1) 158 { 159 WinChardev *s = WIN_CHARDEV(chr); 160 DWORD len, ret, size, err; 161 162 len = len1; 163 ZeroMemory(&s->osend, sizeof(s->osend)); 164 s->osend.hEvent = s->hsend; 165 while (len > 0) { 166 if (s->hsend) { 167 ret = WriteFile(s->file, buf, len, &size, &s->osend); 168 } else { 169 ret = WriteFile(s->file, buf, len, &size, NULL); 170 } 171 if (!ret) { 172 err = GetLastError(); 173 if (err == ERROR_IO_PENDING) { 174 ret = GetOverlappedResult(s->file, &s->osend, &size, TRUE); 175 if (ret) { 176 buf += size; 177 len -= size; 178 } else { 179 break; 180 } 181 } else { 182 break; 183 } 184 } else { 185 buf += size; 186 len -= size; 187 } 188 } 189 return len1 - len; 190 } 191 192 static void char_win_finalize(Object *obj) 193 { 194 Chardev *chr = CHARDEV(obj); 195 WinChardev *s = WIN_CHARDEV(chr); 196 197 if (s->hsend) { 198 CloseHandle(s->hsend); 199 } 200 if (s->hrecv) { 201 CloseHandle(s->hrecv); 202 } 203 if (!s->keep_open && s->file) { 204 CloseHandle(s->file); 205 } 206 if (s->fpipe) { 207 qemu_del_polling_cb(win_chr_pipe_poll, chr); 208 } else { 209 qemu_del_polling_cb(win_chr_serial_poll, chr); 210 } 211 212 qemu_chr_be_event(chr, CHR_EVENT_CLOSED); 213 } 214 215 void win_chr_set_file(Chardev *chr, HANDLE file, bool keep_open) 216 { 217 WinChardev *s = WIN_CHARDEV(chr); 218 219 s->keep_open = keep_open; 220 s->file = file; 221 } 222 223 static void char_win_class_init(ObjectClass *oc, void *data) 224 { 225 ChardevClass *cc = CHARDEV_CLASS(oc); 226 227 cc->chr_write = win_chr_write; 228 } 229 230 static const TypeInfo char_win_type_info = { 231 .name = TYPE_CHARDEV_WIN, 232 .parent = TYPE_CHARDEV, 233 .instance_size = sizeof(WinChardev), 234 .instance_finalize = char_win_finalize, 235 .class_init = char_win_class_init, 236 .abstract = true, 237 }; 238 239 static void register_types(void) 240 { 241 type_register_static(&char_win_type_info); 242 } 243 244 type_init(register_types); 245