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