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