1503ebefeSMarc-André Lureau /*
2503ebefeSMarc-André Lureau * QEMU System Emulator
3503ebefeSMarc-André Lureau *
4503ebefeSMarc-André Lureau * Copyright (c) 2003-2008 Fabrice Bellard
5503ebefeSMarc-André Lureau *
6503ebefeSMarc-André Lureau * Permission is hereby granted, free of charge, to any person obtaining a copy
7503ebefeSMarc-André Lureau * of this software and associated documentation files (the "Software"), to deal
8503ebefeSMarc-André Lureau * in the Software without restriction, including without limitation the rights
9503ebefeSMarc-André Lureau * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10503ebefeSMarc-André Lureau * copies of the Software, and to permit persons to whom the Software is
11503ebefeSMarc-André Lureau * furnished to do so, subject to the following conditions:
12503ebefeSMarc-André Lureau *
13503ebefeSMarc-André Lureau * The above copyright notice and this permission notice shall be included in
14503ebefeSMarc-André Lureau * all copies or substantial portions of the Software.
15503ebefeSMarc-André Lureau *
16503ebefeSMarc-André Lureau * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17503ebefeSMarc-André Lureau * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18503ebefeSMarc-André Lureau * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19503ebefeSMarc-André Lureau * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20503ebefeSMarc-André Lureau * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21503ebefeSMarc-André Lureau * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22503ebefeSMarc-André Lureau * THE SOFTWARE.
23503ebefeSMarc-André Lureau */
240b8fa32fSMarkus Armbruster
25503ebefeSMarc-André Lureau #include "qemu/osdep.h"
26db725815SMarkus Armbruster #include "qemu/main-loop.h"
270b8fa32fSMarkus Armbruster #include "qemu/module.h"
28503ebefeSMarc-André Lureau #include "qapi/error.h"
298228e353SMarc-André Lureau #include "chardev/char-win.h"
30503ebefeSMarc-André Lureau
win_chr_read(Chardev * chr,DWORD len)316ce8e0ebSMarc-André Lureau static void win_chr_read(Chardev *chr, DWORD len)
32503ebefeSMarc-André Lureau {
33503ebefeSMarc-André Lureau WinChardev *s = WIN_CHARDEV(chr);
34b88ee025SMarc-André Lureau int max_size = qemu_chr_be_can_write(chr);
35503ebefeSMarc-André Lureau int ret, err;
36503ebefeSMarc-André Lureau uint8_t buf[CHR_READ_BUF_LEN];
37503ebefeSMarc-André Lureau DWORD size;
38503ebefeSMarc-André Lureau
396ce8e0ebSMarc-André Lureau if (len > max_size) {
406ce8e0ebSMarc-André Lureau len = max_size;
41b88ee025SMarc-André Lureau }
426ce8e0ebSMarc-André Lureau if (len == 0) {
43b88ee025SMarc-André Lureau return;
44b88ee025SMarc-André Lureau }
45b88ee025SMarc-André Lureau
46503ebefeSMarc-André Lureau ZeroMemory(&s->orecv, sizeof(s->orecv));
47503ebefeSMarc-André Lureau s->orecv.hEvent = s->hrecv;
48ef0f272fSMarc-André Lureau ret = ReadFile(s->file, buf, len, &size, &s->orecv);
49503ebefeSMarc-André Lureau if (!ret) {
50503ebefeSMarc-André Lureau err = GetLastError();
51503ebefeSMarc-André Lureau if (err == ERROR_IO_PENDING) {
52ef0f272fSMarc-André Lureau ret = GetOverlappedResult(s->file, &s->orecv, &size, TRUE);
53503ebefeSMarc-André Lureau }
54503ebefeSMarc-André Lureau }
55503ebefeSMarc-André Lureau
56503ebefeSMarc-André Lureau if (size > 0) {
57503ebefeSMarc-André Lureau qemu_chr_be_write(chr, buf, size);
58503ebefeSMarc-André Lureau }
59503ebefeSMarc-André Lureau }
60503ebefeSMarc-André Lureau
win_chr_serial_poll(void * opaque)61221e659cSMarc-André Lureau static int win_chr_serial_poll(void *opaque)
62503ebefeSMarc-André Lureau {
63503ebefeSMarc-André Lureau Chardev *chr = CHARDEV(opaque);
64503ebefeSMarc-André Lureau WinChardev *s = WIN_CHARDEV(opaque);
65503ebefeSMarc-André Lureau COMSTAT status;
66503ebefeSMarc-André Lureau DWORD comerr;
67503ebefeSMarc-André Lureau
68ef0f272fSMarc-André Lureau ClearCommError(s->file, &comerr, &status);
69503ebefeSMarc-André Lureau if (status.cbInQue > 0) {
706ce8e0ebSMarc-André Lureau win_chr_read(chr, status.cbInQue);
71503ebefeSMarc-André Lureau return 1;
72503ebefeSMarc-André Lureau }
73503ebefeSMarc-André Lureau return 0;
74503ebefeSMarc-André Lureau }
75503ebefeSMarc-André Lureau
win_chr_serial_init(Chardev * chr,const char * filename,Error ** errp)76221e659cSMarc-André Lureau int win_chr_serial_init(Chardev *chr, const char *filename, Error **errp)
77503ebefeSMarc-André Lureau {
78503ebefeSMarc-André Lureau WinChardev *s = WIN_CHARDEV(chr);
79503ebefeSMarc-André Lureau COMMCONFIG comcfg;
80503ebefeSMarc-André Lureau COMMTIMEOUTS cto = { 0, 0, 0, 0, 0};
81503ebefeSMarc-André Lureau COMSTAT comstat;
82503ebefeSMarc-André Lureau DWORD size;
83503ebefeSMarc-André Lureau DWORD err;
84503ebefeSMarc-André Lureau
85503ebefeSMarc-André Lureau s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
86503ebefeSMarc-André Lureau if (!s->hsend) {
87503ebefeSMarc-André Lureau error_setg(errp, "Failed CreateEvent");
88503ebefeSMarc-André Lureau goto fail;
89503ebefeSMarc-André Lureau }
90503ebefeSMarc-André Lureau s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL);
91503ebefeSMarc-André Lureau if (!s->hrecv) {
92503ebefeSMarc-André Lureau error_setg(errp, "Failed CreateEvent");
93503ebefeSMarc-André Lureau goto fail;
94503ebefeSMarc-André Lureau }
95503ebefeSMarc-André Lureau
96ef0f272fSMarc-André Lureau s->file = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
97503ebefeSMarc-André Lureau OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
98ef0f272fSMarc-André Lureau if (s->file == INVALID_HANDLE_VALUE) {
99*4c235193SPhilippe Mathieu-Daudé error_setg_win32(errp, GetLastError(), "Failed CreateFile");
100ef0f272fSMarc-André Lureau s->file = NULL;
101503ebefeSMarc-André Lureau goto fail;
102503ebefeSMarc-André Lureau }
103503ebefeSMarc-André Lureau
104ef0f272fSMarc-André Lureau if (!SetupComm(s->file, NRECVBUF, NSENDBUF)) {
105503ebefeSMarc-André Lureau error_setg(errp, "Failed SetupComm");
106503ebefeSMarc-André Lureau goto fail;
107503ebefeSMarc-André Lureau }
108503ebefeSMarc-André Lureau
109503ebefeSMarc-André Lureau ZeroMemory(&comcfg, sizeof(COMMCONFIG));
110503ebefeSMarc-André Lureau size = sizeof(COMMCONFIG);
111503ebefeSMarc-André Lureau GetDefaultCommConfig(filename, &comcfg, &size);
112503ebefeSMarc-André Lureau comcfg.dcb.DCBlength = sizeof(DCB);
113503ebefeSMarc-André Lureau CommConfigDialog(filename, NULL, &comcfg);
114503ebefeSMarc-André Lureau
115ef0f272fSMarc-André Lureau if (!SetCommState(s->file, &comcfg.dcb)) {
116503ebefeSMarc-André Lureau error_setg(errp, "Failed SetCommState");
117503ebefeSMarc-André Lureau goto fail;
118503ebefeSMarc-André Lureau }
119503ebefeSMarc-André Lureau
120ef0f272fSMarc-André Lureau if (!SetCommMask(s->file, EV_ERR)) {
121503ebefeSMarc-André Lureau error_setg(errp, "Failed SetCommMask");
122503ebefeSMarc-André Lureau goto fail;
123503ebefeSMarc-André Lureau }
124503ebefeSMarc-André Lureau
125503ebefeSMarc-André Lureau cto.ReadIntervalTimeout = MAXDWORD;
126ef0f272fSMarc-André Lureau if (!SetCommTimeouts(s->file, &cto)) {
127503ebefeSMarc-André Lureau error_setg(errp, "Failed SetCommTimeouts");
128503ebefeSMarc-André Lureau goto fail;
129503ebefeSMarc-André Lureau }
130503ebefeSMarc-André Lureau
131ef0f272fSMarc-André Lureau if (!ClearCommError(s->file, &err, &comstat)) {
132503ebefeSMarc-André Lureau error_setg(errp, "Failed ClearCommError");
133503ebefeSMarc-André Lureau goto fail;
134503ebefeSMarc-André Lureau }
135221e659cSMarc-André Lureau qemu_add_polling_cb(win_chr_serial_poll, chr);
136503ebefeSMarc-André Lureau return 0;
137503ebefeSMarc-André Lureau
138503ebefeSMarc-André Lureau fail:
139503ebefeSMarc-André Lureau return -1;
140503ebefeSMarc-André Lureau }
141503ebefeSMarc-André Lureau
win_chr_pipe_poll(void * opaque)142503ebefeSMarc-André Lureau int win_chr_pipe_poll(void *opaque)
143503ebefeSMarc-André Lureau {
144503ebefeSMarc-André Lureau Chardev *chr = CHARDEV(opaque);
145503ebefeSMarc-André Lureau WinChardev *s = WIN_CHARDEV(opaque);
146503ebefeSMarc-André Lureau DWORD size;
147503ebefeSMarc-André Lureau
148ef0f272fSMarc-André Lureau PeekNamedPipe(s->file, NULL, 0, NULL, &size, NULL);
149503ebefeSMarc-André Lureau if (size > 0) {
1506ce8e0ebSMarc-André Lureau win_chr_read(chr, size);
151503ebefeSMarc-André Lureau return 1;
152503ebefeSMarc-André Lureau }
153503ebefeSMarc-André Lureau return 0;
154503ebefeSMarc-André Lureau }
155503ebefeSMarc-André Lureau
156503ebefeSMarc-André Lureau /* Called with chr_write_lock held. */
win_chr_write(Chardev * chr,const uint8_t * buf,int len1)157503ebefeSMarc-André Lureau static int win_chr_write(Chardev *chr, const uint8_t *buf, int len1)
158503ebefeSMarc-André Lureau {
159503ebefeSMarc-André Lureau WinChardev *s = WIN_CHARDEV(chr);
160503ebefeSMarc-André Lureau DWORD len, ret, size, err;
161503ebefeSMarc-André Lureau
162503ebefeSMarc-André Lureau len = len1;
163503ebefeSMarc-André Lureau ZeroMemory(&s->osend, sizeof(s->osend));
164503ebefeSMarc-André Lureau s->osend.hEvent = s->hsend;
165503ebefeSMarc-André Lureau while (len > 0) {
166503ebefeSMarc-André Lureau if (s->hsend) {
167ef0f272fSMarc-André Lureau ret = WriteFile(s->file, buf, len, &size, &s->osend);
168503ebefeSMarc-André Lureau } else {
169ef0f272fSMarc-André Lureau ret = WriteFile(s->file, buf, len, &size, NULL);
170503ebefeSMarc-André Lureau }
171503ebefeSMarc-André Lureau if (!ret) {
172503ebefeSMarc-André Lureau err = GetLastError();
173503ebefeSMarc-André Lureau if (err == ERROR_IO_PENDING) {
174ef0f272fSMarc-André Lureau ret = GetOverlappedResult(s->file, &s->osend, &size, TRUE);
175503ebefeSMarc-André Lureau if (ret) {
176503ebefeSMarc-André Lureau buf += size;
177503ebefeSMarc-André Lureau len -= size;
178503ebefeSMarc-André Lureau } else {
179503ebefeSMarc-André Lureau break;
180503ebefeSMarc-André Lureau }
181503ebefeSMarc-André Lureau } else {
182503ebefeSMarc-André Lureau break;
183503ebefeSMarc-André Lureau }
184503ebefeSMarc-André Lureau } else {
185503ebefeSMarc-André Lureau buf += size;
186503ebefeSMarc-André Lureau len -= size;
187503ebefeSMarc-André Lureau }
188503ebefeSMarc-André Lureau }
189503ebefeSMarc-André Lureau return len1 - len;
190503ebefeSMarc-André Lureau }
191503ebefeSMarc-André Lureau
char_win_finalize(Object * obj)192503ebefeSMarc-André Lureau static void char_win_finalize(Object *obj)
193503ebefeSMarc-André Lureau {
194503ebefeSMarc-André Lureau Chardev *chr = CHARDEV(obj);
195503ebefeSMarc-André Lureau WinChardev *s = WIN_CHARDEV(chr);
196503ebefeSMarc-André Lureau
197503ebefeSMarc-André Lureau if (s->hsend) {
198503ebefeSMarc-André Lureau CloseHandle(s->hsend);
199503ebefeSMarc-André Lureau }
200503ebefeSMarc-André Lureau if (s->hrecv) {
201503ebefeSMarc-André Lureau CloseHandle(s->hrecv);
202503ebefeSMarc-André Lureau }
203541815ffSMarc-André Lureau if (!s->keep_open && s->file) {
204ef0f272fSMarc-André Lureau CloseHandle(s->file);
205503ebefeSMarc-André Lureau }
206503ebefeSMarc-André Lureau if (s->fpipe) {
207503ebefeSMarc-André Lureau qemu_del_polling_cb(win_chr_pipe_poll, chr);
208503ebefeSMarc-André Lureau } else {
209221e659cSMarc-André Lureau qemu_del_polling_cb(win_chr_serial_poll, chr);
210503ebefeSMarc-André Lureau }
211503ebefeSMarc-André Lureau
212503ebefeSMarc-André Lureau qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
213503ebefeSMarc-André Lureau }
214503ebefeSMarc-André Lureau
win_chr_set_file(Chardev * chr,HANDLE file,bool keep_open)215541815ffSMarc-André Lureau void win_chr_set_file(Chardev *chr, HANDLE file, bool keep_open)
216503ebefeSMarc-André Lureau {
217503ebefeSMarc-André Lureau WinChardev *s = WIN_CHARDEV(chr);
218503ebefeSMarc-André Lureau
219541815ffSMarc-André Lureau s->keep_open = keep_open;
220541815ffSMarc-André Lureau s->file = file;
221503ebefeSMarc-André Lureau }
222503ebefeSMarc-André Lureau
char_win_class_init(ObjectClass * oc,void * data)223503ebefeSMarc-André Lureau static void char_win_class_init(ObjectClass *oc, void *data)
224503ebefeSMarc-André Lureau {
225503ebefeSMarc-André Lureau ChardevClass *cc = CHARDEV_CLASS(oc);
226503ebefeSMarc-André Lureau
227503ebefeSMarc-André Lureau cc->chr_write = win_chr_write;
228503ebefeSMarc-André Lureau }
229503ebefeSMarc-André Lureau
230503ebefeSMarc-André Lureau static const TypeInfo char_win_type_info = {
231503ebefeSMarc-André Lureau .name = TYPE_CHARDEV_WIN,
232503ebefeSMarc-André Lureau .parent = TYPE_CHARDEV,
233503ebefeSMarc-André Lureau .instance_size = sizeof(WinChardev),
234503ebefeSMarc-André Lureau .instance_finalize = char_win_finalize,
235503ebefeSMarc-André Lureau .class_init = char_win_class_init,
236503ebefeSMarc-André Lureau .abstract = true,
237503ebefeSMarc-André Lureau };
238503ebefeSMarc-André Lureau
register_types(void)239503ebefeSMarc-André Lureau static void register_types(void)
240503ebefeSMarc-André Lureau {
241503ebefeSMarc-André Lureau type_register_static(&char_win_type_info);
242503ebefeSMarc-André Lureau }
243503ebefeSMarc-André Lureau
244503ebefeSMarc-André Lureau type_init(register_types);
245