qemu/chardev/char-win.c
<<
>>
Prefs
   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"
  27#include "chardev/char-win.h"
  28
  29static void win_chr_read(Chardev *chr, DWORD len)
  30{
  31    WinChardev *s = WIN_CHARDEV(chr);
  32    int max_size = qemu_chr_be_can_write(chr);
  33    int ret, err;
  34    uint8_t buf[CHR_READ_BUF_LEN];
  35    DWORD size;
  36
  37    if (len > max_size) {
  38        len = max_size;
  39    }
  40    if (len == 0) {
  41        return;
  42    }
  43
  44    ZeroMemory(&s->orecv, sizeof(s->orecv));
  45    s->orecv.hEvent = s->hrecv;
  46    ret = ReadFile(s->file, buf, len, &size, &s->orecv);
  47    if (!ret) {
  48        err = GetLastError();
  49        if (err == ERROR_IO_PENDING) {
  50            ret = GetOverlappedResult(s->file, &s->orecv, &size, TRUE);
  51        }
  52    }
  53
  54    if (size > 0) {
  55        qemu_chr_be_write(chr, buf, size);
  56    }
  57}
  58
  59static int win_chr_serial_poll(void *opaque)
  60{
  61    Chardev *chr = CHARDEV(opaque);
  62    WinChardev *s = WIN_CHARDEV(opaque);
  63    COMSTAT status;
  64    DWORD comerr;
  65
  66    ClearCommError(s->file, &comerr, &status);
  67    if (status.cbInQue > 0) {
  68        win_chr_read(chr, status.cbInQue);
  69        return 1;
  70    }
  71    return 0;
  72}
  73
  74int win_chr_serial_init(Chardev *chr, const char *filename, Error **errp)
  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
  94    s->file = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, 0, NULL,
  95                      OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
  96    if (s->file == INVALID_HANDLE_VALUE) {
  97        error_setg(errp, "Failed CreateFile (%lu)", GetLastError());
  98        s->file = NULL;
  99        goto fail;
 100    }
 101
 102    if (!SetupComm(s->file, NRECVBUF, NSENDBUF)) {
 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
 113    if (!SetCommState(s->file, &comcfg.dcb)) {
 114        error_setg(errp, "Failed SetCommState");
 115        goto fail;
 116    }
 117
 118    if (!SetCommMask(s->file, EV_ERR)) {
 119        error_setg(errp, "Failed SetCommMask");
 120        goto fail;
 121    }
 122
 123    cto.ReadIntervalTimeout = MAXDWORD;
 124    if (!SetCommTimeouts(s->file, &cto)) {
 125        error_setg(errp, "Failed SetCommTimeouts");
 126        goto fail;
 127    }
 128
 129    if (!ClearCommError(s->file, &err, &comstat)) {
 130        error_setg(errp, "Failed ClearCommError");
 131        goto fail;
 132    }
 133    qemu_add_polling_cb(win_chr_serial_poll, chr);
 134    return 0;
 135
 136 fail:
 137    return -1;
 138}
 139
 140int win_chr_pipe_poll(void *opaque)
 141{
 142    Chardev *chr = CHARDEV(opaque);
 143    WinChardev *s = WIN_CHARDEV(opaque);
 144    DWORD size;
 145
 146    PeekNamedPipe(s->file, NULL, 0, NULL, &size, NULL);
 147    if (size > 0) {
 148        win_chr_read(chr, size);
 149        return 1;
 150    }
 151    return 0;
 152}
 153
 154/* Called with chr_write_lock held.  */
 155static 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) {
 165            ret = WriteFile(s->file, buf, len, &size, &s->osend);
 166        } else {
 167            ret = WriteFile(s->file, buf, len, &size, NULL);
 168        }
 169        if (!ret) {
 170            err = GetLastError();
 171            if (err == ERROR_IO_PENDING) {
 172                ret = GetOverlappedResult(s->file, &s->osend, &size, TRUE);
 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
 190static void char_win_finalize(Object *obj)
 191{
 192    Chardev *chr = CHARDEV(obj);
 193    WinChardev *s = WIN_CHARDEV(chr);
 194
 195    if (s->hsend) {
 196        CloseHandle(s->hsend);
 197    }
 198    if (s->hrecv) {
 199        CloseHandle(s->hrecv);
 200    }
 201    if (!s->keep_open && s->file) {
 202        CloseHandle(s->file);
 203    }
 204    if (s->fpipe) {
 205        qemu_del_polling_cb(win_chr_pipe_poll, chr);
 206    } else {
 207        qemu_del_polling_cb(win_chr_serial_poll, chr);
 208    }
 209
 210    qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
 211}
 212
 213void win_chr_set_file(Chardev *chr, HANDLE file, bool keep_open)
 214{
 215    WinChardev *s = WIN_CHARDEV(chr);
 216
 217    s->keep_open = keep_open;
 218    s->file = file;
 219}
 220
 221static 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
 228static 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
 237static void register_types(void)
 238{
 239    type_register_static(&char_win_type_info);
 240}
 241
 242type_init(register_types);
 243