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