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