qemu/chardev/char-fe.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/error-report.h"
  26#include "qapi/error.h"
  27#include "qapi-visit.h"
  28#include "sysemu/replay.h"
  29
  30#include "chardev/char-fe.h"
  31#include "chardev/char-io.h"
  32#include "chardev/char-mux.h"
  33
  34int qemu_chr_fe_write(CharBackend *be, const uint8_t *buf, int len)
  35{
  36    Chardev *s = be->chr;
  37
  38    if (!s) {
  39        return 0;
  40    }
  41
  42    return qemu_chr_write(s, buf, len, false);
  43}
  44
  45int qemu_chr_fe_write_all(CharBackend *be, const uint8_t *buf, int len)
  46{
  47    Chardev *s = be->chr;
  48
  49    if (!s) {
  50        return 0;
  51    }
  52
  53    return qemu_chr_write(s, buf, len, true);
  54}
  55
  56int qemu_chr_fe_read_all(CharBackend *be, uint8_t *buf, int len)
  57{
  58    Chardev *s = be->chr;
  59    int offset = 0, counter = 10;
  60    int res;
  61
  62    if (!s || !CHARDEV_GET_CLASS(s)->chr_sync_read) {
  63        return 0;
  64    }
  65
  66    if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_PLAY) {
  67        return replay_char_read_all_load(buf);
  68    }
  69
  70    while (offset < len) {
  71    retry:
  72        res = CHARDEV_GET_CLASS(s)->chr_sync_read(s, buf + offset,
  73                                                  len - offset);
  74        if (res == -1 && errno == EAGAIN) {
  75            g_usleep(100);
  76            goto retry;
  77        }
  78
  79        if (res == 0) {
  80            break;
  81        }
  82
  83        if (res < 0) {
  84            if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_RECORD) {
  85                replay_char_read_all_save_error(res);
  86            }
  87            return res;
  88        }
  89
  90        offset += res;
  91
  92        if (!counter--) {
  93            break;
  94        }
  95    }
  96
  97    if (qemu_chr_replay(s) && replay_mode == REPLAY_MODE_RECORD) {
  98        replay_char_read_all_save_buf(buf, offset);
  99    }
 100    return offset;
 101}
 102
 103int qemu_chr_fe_ioctl(CharBackend *be, int cmd, void *arg)
 104{
 105    Chardev *s = be->chr;
 106    int res;
 107
 108    if (!s || !CHARDEV_GET_CLASS(s)->chr_ioctl || qemu_chr_replay(s)) {
 109        res = -ENOTSUP;
 110    } else {
 111        res = CHARDEV_GET_CLASS(s)->chr_ioctl(s, cmd, arg);
 112    }
 113
 114    return res;
 115}
 116
 117int qemu_chr_fe_get_msgfd(CharBackend *be)
 118{
 119    Chardev *s = be->chr;
 120    int fd;
 121    int res = (qemu_chr_fe_get_msgfds(be, &fd, 1) == 1) ? fd : -1;
 122    if (s && qemu_chr_replay(s)) {
 123        error_report("Replay: get msgfd is not supported "
 124                     "for serial devices yet");
 125        exit(1);
 126    }
 127    return res;
 128}
 129
 130int qemu_chr_fe_get_msgfds(CharBackend *be, int *fds, int len)
 131{
 132    Chardev *s = be->chr;
 133
 134    if (!s) {
 135        return -1;
 136    }
 137
 138    return CHARDEV_GET_CLASS(s)->get_msgfds ?
 139        CHARDEV_GET_CLASS(s)->get_msgfds(s, fds, len) : -1;
 140}
 141
 142int qemu_chr_fe_set_msgfds(CharBackend *be, int *fds, int num)
 143{
 144    Chardev *s = be->chr;
 145
 146    if (!s) {
 147        return -1;
 148    }
 149
 150    return CHARDEV_GET_CLASS(s)->set_msgfds ?
 151        CHARDEV_GET_CLASS(s)->set_msgfds(s, fds, num) : -1;
 152}
 153
 154void qemu_chr_fe_accept_input(CharBackend *be)
 155{
 156    Chardev *s = be->chr;
 157
 158    if (!s) {
 159        return;
 160    }
 161
 162    if (CHARDEV_GET_CLASS(s)->chr_accept_input) {
 163        CHARDEV_GET_CLASS(s)->chr_accept_input(s);
 164    }
 165    qemu_notify_event();
 166}
 167
 168void qemu_chr_fe_printf(CharBackend *be, const char *fmt, ...)
 169{
 170    char buf[CHR_READ_BUF_LEN];
 171    va_list ap;
 172    va_start(ap, fmt);
 173    vsnprintf(buf, sizeof(buf), fmt, ap);
 174    /* XXX this blocks entire thread. Rewrite to use
 175     * qemu_chr_fe_write and background I/O callbacks */
 176    qemu_chr_fe_write_all(be, (uint8_t *)buf, strlen(buf));
 177    va_end(ap);
 178}
 179
 180Chardev *qemu_chr_fe_get_driver(CharBackend *be)
 181{
 182    /* this is unsafe for the users that support chardev hotswap */
 183    assert(be->chr_be_change == NULL);
 184    return be->chr;
 185}
 186
 187bool qemu_chr_fe_backend_connected(CharBackend *be)
 188{
 189    return !!be->chr;
 190}
 191
 192bool qemu_chr_fe_backend_open(CharBackend *be)
 193{
 194    return be->chr && be->chr->be_open;
 195}
 196
 197bool qemu_chr_fe_init(CharBackend *b, Chardev *s, Error **errp)
 198{
 199    int tag = 0;
 200
 201    if (CHARDEV_IS_MUX(s)) {
 202        MuxChardev *d = MUX_CHARDEV(s);
 203
 204        if (d->mux_cnt >= MAX_MUX) {
 205            goto unavailable;
 206        }
 207
 208        d->backends[d->mux_cnt] = b;
 209        tag = d->mux_cnt++;
 210    } else if (s->be) {
 211        goto unavailable;
 212    } else {
 213        s->be = b;
 214    }
 215
 216    b->fe_open = false;
 217    b->tag = tag;
 218    b->chr = s;
 219    return true;
 220
 221unavailable:
 222    error_setg(errp, QERR_DEVICE_IN_USE, s->label);
 223    return false;
 224}
 225
 226void qemu_chr_fe_deinit(CharBackend *b, bool del)
 227{
 228    assert(b);
 229
 230    if (b->chr) {
 231        qemu_chr_fe_set_handlers(b, NULL, NULL, NULL, NULL, NULL, NULL, true);
 232        if (b->chr->be == b) {
 233            b->chr->be = NULL;
 234        }
 235        if (CHARDEV_IS_MUX(b->chr)) {
 236            MuxChardev *d = MUX_CHARDEV(b->chr);
 237            d->backends[b->tag] = NULL;
 238        }
 239        if (del) {
 240            object_unparent(OBJECT(b->chr));
 241        }
 242        b->chr = NULL;
 243    }
 244}
 245
 246void qemu_chr_fe_set_handlers(CharBackend *b,
 247                              IOCanReadHandler *fd_can_read,
 248                              IOReadHandler *fd_read,
 249                              IOEventHandler *fd_event,
 250                              BackendChangeHandler *be_change,
 251                              void *opaque,
 252                              GMainContext *context,
 253                              bool set_open)
 254{
 255    Chardev *s;
 256    int fe_open;
 257
 258    s = b->chr;
 259    if (!s) {
 260        return;
 261    }
 262
 263    if (!opaque && !fd_can_read && !fd_read && !fd_event) {
 264        fe_open = 0;
 265        remove_fd_in_watch(s);
 266    } else {
 267        fe_open = 1;
 268    }
 269    b->chr_can_read = fd_can_read;
 270    b->chr_read = fd_read;
 271    b->chr_event = fd_event;
 272    b->chr_be_change = be_change;
 273    b->opaque = opaque;
 274
 275    qemu_chr_be_update_read_handlers(s, context);
 276
 277    if (set_open) {
 278        qemu_chr_fe_set_open(b, fe_open);
 279    }
 280
 281    if (fe_open) {
 282        qemu_chr_fe_take_focus(b);
 283        /* We're connecting to an already opened device, so let's make sure we
 284           also get the open event */
 285        if (s->be_open) {
 286            qemu_chr_be_event(s, CHR_EVENT_OPENED);
 287        }
 288    }
 289
 290    if (CHARDEV_IS_MUX(s)) {
 291        mux_chr_set_handlers(s, context);
 292    }
 293}
 294
 295void qemu_chr_fe_take_focus(CharBackend *b)
 296{
 297    if (!b->chr) {
 298        return;
 299    }
 300
 301    if (CHARDEV_IS_MUX(b->chr)) {
 302        mux_set_focus(b->chr, b->tag);
 303    }
 304}
 305
 306int qemu_chr_fe_wait_connected(CharBackend *be, Error **errp)
 307{
 308    if (!be->chr) {
 309        error_setg(errp, "missing associated backend");
 310        return -1;
 311    }
 312
 313    return qemu_chr_wait_connected(be->chr, errp);
 314}
 315
 316void qemu_chr_fe_set_echo(CharBackend *be, bool echo)
 317{
 318    Chardev *chr = be->chr;
 319
 320    if (chr && CHARDEV_GET_CLASS(chr)->chr_set_echo) {
 321        CHARDEV_GET_CLASS(chr)->chr_set_echo(chr, echo);
 322    }
 323}
 324
 325void qemu_chr_fe_set_open(CharBackend *be, int fe_open)
 326{
 327    Chardev *chr = be->chr;
 328
 329    if (!chr) {
 330        return;
 331    }
 332
 333    if (be->fe_open == fe_open) {
 334        return;
 335    }
 336    be->fe_open = fe_open;
 337    if (CHARDEV_GET_CLASS(chr)->chr_set_fe_open) {
 338        CHARDEV_GET_CLASS(chr)->chr_set_fe_open(chr, fe_open);
 339    }
 340}
 341
 342void qemu_chr_fe_set_blocking(CharBackend *be, bool blocking)
 343{
 344    Chardev *chr = be->chr;
 345
 346    if (chr && CHARDEV_GET_CLASS(chr)->chr_set_blocking) {
 347        CHARDEV_GET_CLASS(chr)->chr_set_blocking(chr, blocking);
 348    }
 349}
 350
 351guint qemu_chr_fe_add_watch(CharBackend *be, GIOCondition cond,
 352                            GIOFunc func, void *user_data)
 353{
 354    Chardev *s = be->chr;
 355    GSource *src;
 356    guint tag;
 357
 358    if (!s || CHARDEV_GET_CLASS(s)->chr_add_watch == NULL) {
 359        return 0;
 360    }
 361
 362    src = CHARDEV_GET_CLASS(s)->chr_add_watch(s, cond);
 363    if (!src) {
 364        return 0;
 365    }
 366
 367    g_source_set_callback(src, (GSourceFunc)func, user_data, NULL);
 368    tag = g_source_attach(src, NULL);
 369    g_source_unref(src);
 370
 371    return tag;
 372}
 373
 374void qemu_chr_fe_disconnect(CharBackend *be)
 375{
 376    Chardev *chr = be->chr;
 377
 378    if (chr && CHARDEV_GET_CLASS(chr)->chr_disconnect) {
 379        CHARDEV_GET_CLASS(chr)->chr_disconnect(chr);
 380    }
 381}
 382