]>
Commit | Line | Data |
---|---|---|
503ebefe MAL |
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" | |
8228e353 | 27 | #include "chardev/char-win.h" |
503ebefe | 28 | |
6ce8e0eb | 29 | static void win_chr_read(Chardev *chr, DWORD len) |
503ebefe MAL |
30 | { |
31 | WinChardev *s = WIN_CHARDEV(chr); | |
b88ee025 | 32 | int max_size = qemu_chr_be_can_write(chr); |
503ebefe MAL |
33 | int ret, err; |
34 | uint8_t buf[CHR_READ_BUF_LEN]; | |
35 | DWORD size; | |
36 | ||
6ce8e0eb MAL |
37 | if (len > max_size) { |
38 | len = max_size; | |
b88ee025 | 39 | } |
6ce8e0eb | 40 | if (len == 0) { |
b88ee025 MAL |
41 | return; |
42 | } | |
43 | ||
503ebefe MAL |
44 | ZeroMemory(&s->orecv, sizeof(s->orecv)); |
45 | s->orecv.hEvent = s->hrecv; | |
ef0f272f | 46 | ret = ReadFile(s->file, buf, len, &size, &s->orecv); |
503ebefe MAL |
47 | if (!ret) { |
48 | err = GetLastError(); | |
49 | if (err == ERROR_IO_PENDING) { | |
ef0f272f | 50 | ret = GetOverlappedResult(s->file, &s->orecv, &size, TRUE); |
503ebefe MAL |
51 | } |
52 | } | |
53 | ||
54 | if (size > 0) { | |
55 | qemu_chr_be_write(chr, buf, size); | |
56 | } | |
57 | } | |
58 | ||
221e659c | 59 | static int win_chr_serial_poll(void *opaque) |
503ebefe MAL |
60 | { |
61 | Chardev *chr = CHARDEV(opaque); | |
62 | WinChardev *s = WIN_CHARDEV(opaque); | |
63 | COMSTAT status; | |
64 | DWORD comerr; | |
65 | ||
ef0f272f | 66 | ClearCommError(s->file, &comerr, &status); |
503ebefe | 67 | if (status.cbInQue > 0) { |
6ce8e0eb | 68 | win_chr_read(chr, status.cbInQue); |
503ebefe MAL |
69 | return 1; |
70 | } | |
71 | return 0; | |
72 | } | |
73 | ||
221e659c | 74 | int win_chr_serial_init(Chardev *chr, const char *filename, Error **errp) |
503ebefe MAL |
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 | ||
ef0f272f | 94 | s->file = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL, |
503ebefe | 95 | OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); |
ef0f272f | 96 | if (s->file == INVALID_HANDLE_VALUE) { |
503ebefe | 97 | error_setg(errp, "Failed CreateFile (%lu)", GetLastError()); |
ef0f272f | 98 | s->file = NULL; |
503ebefe MAL |
99 | goto fail; |
100 | } | |
101 | ||
ef0f272f | 102 | if (!SetupComm(s->file, NRECVBUF, NSENDBUF)) { |
503ebefe MAL |
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 | ||
ef0f272f | 113 | if (!SetCommState(s->file, &comcfg.dcb)) { |
503ebefe MAL |
114 | error_setg(errp, "Failed SetCommState"); |
115 | goto fail; | |
116 | } | |
117 | ||
ef0f272f | 118 | if (!SetCommMask(s->file, EV_ERR)) { |
503ebefe MAL |
119 | error_setg(errp, "Failed SetCommMask"); |
120 | goto fail; | |
121 | } | |
122 | ||
123 | cto.ReadIntervalTimeout = MAXDWORD; | |
ef0f272f | 124 | if (!SetCommTimeouts(s->file, &cto)) { |
503ebefe MAL |
125 | error_setg(errp, "Failed SetCommTimeouts"); |
126 | goto fail; | |
127 | } | |
128 | ||
ef0f272f | 129 | if (!ClearCommError(s->file, &err, &comstat)) { |
503ebefe MAL |
130 | error_setg(errp, "Failed ClearCommError"); |
131 | goto fail; | |
132 | } | |
221e659c | 133 | qemu_add_polling_cb(win_chr_serial_poll, chr); |
503ebefe MAL |
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 | ||
ef0f272f | 146 | PeekNamedPipe(s->file, NULL, 0, NULL, &size, NULL); |
503ebefe | 147 | if (size > 0) { |
6ce8e0eb | 148 | win_chr_read(chr, size); |
503ebefe MAL |
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) { | |
ef0f272f | 165 | ret = WriteFile(s->file, buf, len, &size, &s->osend); |
503ebefe | 166 | } else { |
ef0f272f | 167 | ret = WriteFile(s->file, buf, len, &size, NULL); |
503ebefe MAL |
168 | } |
169 | if (!ret) { | |
170 | err = GetLastError(); | |
171 | if (err == ERROR_IO_PENDING) { | |
ef0f272f | 172 | ret = GetOverlappedResult(s->file, &s->osend, &size, TRUE); |
503ebefe MAL |
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 | ||
503ebefe MAL |
195 | if (s->hsend) { |
196 | CloseHandle(s->hsend); | |
197 | } | |
198 | if (s->hrecv) { | |
199 | CloseHandle(s->hrecv); | |
200 | } | |
541815ff | 201 | if (!s->keep_open && s->file) { |
ef0f272f | 202 | CloseHandle(s->file); |
503ebefe MAL |
203 | } |
204 | if (s->fpipe) { | |
205 | qemu_del_polling_cb(win_chr_pipe_poll, chr); | |
206 | } else { | |
221e659c | 207 | qemu_del_polling_cb(win_chr_serial_poll, chr); |
503ebefe MAL |
208 | } |
209 | ||
210 | qemu_chr_be_event(chr, CHR_EVENT_CLOSED); | |
211 | } | |
212 | ||
541815ff | 213 | void win_chr_set_file(Chardev *chr, HANDLE file, bool keep_open) |
503ebefe MAL |
214 | { |
215 | WinChardev *s = WIN_CHARDEV(chr); | |
216 | ||
541815ff MAL |
217 | s->keep_open = keep_open; |
218 | s->file = file; | |
503ebefe MAL |
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); |