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