qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

char-win.c (6503B)


      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 
     31 static 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 
     61 static 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 
     76 int 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 
    142 int 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.  */
    157 static 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 
    192 static 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 
    215 void 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 
    223 static 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 
    230 static 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 
    239 static void register_types(void)
    240 {
    241     type_register_static(&char_win_type_info);
    242 }
    243 
    244 type_init(register_types);