15d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/*
25d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * QEMU System Emulator
35d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
45d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Copyright (c) 2003-2008 Fabrice Bellard
55d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
65d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Permission is hereby granted, free of charge, to any person obtaining a copy
75d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * of this software and associated documentation files (the "Software"), to deal
85d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * in the Software without restriction, including without limitation the rights
95d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * copies of the Software, and to permit persons to whom the Software is
115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * furnished to do so, subject to the following conditions:
125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * The above copyright notice and this permission notice shall be included in
145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * all copies or substantial portions of the Software.
155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * THE SOFTWARE.
235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */
245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu-common.h"
25cc330d4169441727fecf1da08aee806fc021c4e2David 'Digit' Turner#include "android/sockets.h"
26cc330d4169441727fecf1da08aee806fc021c4e2David 'Digit' Turner#include "net/net.h"
276af6765e2f3bc930d0dce21d752bea570a1b1362David 'Digit' Turner#include "monitor/monitor.h"
281c31e3e43ce4cca85a707dfff631e5e102fdecedDavid 'Digit' Turner#include "ui/console.h"
2934c48ff1e3ad5cd2084ca40188754d45f423750bDavid 'Digit' Turner#include "sysemu/sysemu.h"
307a78db75ad42aea283f5073f51891464104a9fc3David 'Digit' Turner#include "qemu/timer.h"
31e7216d82dbaa19892ad62b07402d512234559a6eDavid 'Digit' Turner#include "sysemu/char.h"
32e1e03df288d5a44bfbffbd86588395c7cbbc27dfDavid 'Digit' Turner#include "block/block.h"
335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "hw/usb.h"
345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "hw/baum.h"
355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "hw/msmouse.h"
362a7dde0b2f96b05048320a0840cde7ab3d4be9feDavid 'Digit' Turner#include "qapi/qmp/types.h"
375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <unistd.h>
395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <fcntl.h>
405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <signal.h>
415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <time.h>
425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <errno.h>
435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/time.h>
445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <zlib.h>
455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifndef _WIN32
475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/times.h>
485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/wait.h>
495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <termios.h>
505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/mman.h>
515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/ioctl.h>
525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/resource.h>
535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/socket.h>
545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <netinet/in.h>
555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <net/if.h>
565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <arpa/inet.h>
575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <dirent.h>
585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <netdb.h>
595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/select.h>
602c538c86c15d597cc875dc926e4e39285c5625dfDavid 'Digit' Turner#ifdef CONFIG_BSD
615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/stat.h>
6217410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <libutil.h>
645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <dev/ppbus/ppi.h>
655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <dev/ppbus/ppbconf.h>
6617410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner#if defined(__GLIBC__)
6717410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner#include <pty.h>
6817410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner#endif
695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#elif defined(__DragonFly__)
705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <libutil.h>
715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <dev/misc/ppi/ppi.h>
725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <bus/ppbus/ppbconf.h>
735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else
745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <util.h>
755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else
775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef __linux__
785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <pty.h>
795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <linux/ppdev.h>
815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <linux/parport.h>
825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef __sun__
845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/stat.h>
855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/ethernet.h>
865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/sockio.h>
875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <netinet/arp.h>
885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <netinet/in.h>
895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <netinet/in_systm.h>
905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <netinet/ip.h>
915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <netinet/ip_icmp.h> // must come after ip.h
925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <netinet/udp.h>
935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <netinet/tcp.h>
945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <net/if.h>
955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <syslog.h>
965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <stropts.h>
975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
1005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
101d0edecb426b34ddb9b10b81dea19aee04a61a385David 'Digit' Turner#include "qemu/sockets.h"
1025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1039d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#define READ_BUF_LEN 4096
1049d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
1053b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner#ifdef CONFIG_ANDROID
106e1e03df288d5a44bfbffbd86588395c7cbbc27dfDavid 'Digit' Turner#include "android/charpipe.h"
1073b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner#include "modem_driver.h"
1083b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner#include "android/gps.h"
1093b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner#include "android/hw-kmsg.h"
1103b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner#include "android/hw-qemud.h"
1113b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner#endif /* CONFIG_ANDROID */
1123b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner
1135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/***********************************************************/
1145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* character device */
1155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1169d1188280fa5294f9438424e5e8eae91f645bfd8David Turnerstatic QTAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs =
1179d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    QTAILQ_HEAD_INITIALIZER(chardevs);
1183b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turnerstatic int initial_reset_issued;
1195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void qemu_chr_event(CharDriverState *s, int event)
1215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
1229d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    /* Keep track if the char device is open */
1239d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    switch (event) {
1249d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        case CHR_EVENT_OPENED:
1259d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            s->opened = 1;
1269d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            break;
1279d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        case CHR_EVENT_CLOSED:
1289d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            s->opened = 0;
1299d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            break;
1309d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    }
1319d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
1325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!s->chr_event)
1335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
1345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->chr_event(s->handler_opaque, event);
1355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1379d1188280fa5294f9438424e5e8eae91f645bfd8David Turnerstatic void qemu_chr_generic_open_bh(void *opaque)
1385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
1395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *s = opaque;
140a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turner    qemu_chr_event(s, CHR_EVENT_OPENED);
1415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_bh_delete(s->bh);
1425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->bh = NULL;
1435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1459d1188280fa5294f9438424e5e8eae91f645bfd8David Turnervoid qemu_chr_generic_open(CharDriverState *s)
1469d1188280fa5294f9438424e5e8eae91f645bfd8David Turner{
1479d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    if (s->bh == NULL) {
1489d1188280fa5294f9438424e5e8eae91f645bfd8David Turner	s->bh = qemu_bh_new(qemu_chr_generic_open_bh, s);
1499d1188280fa5294f9438424e5e8eae91f645bfd8David Turner	qemu_bh_schedule(s->bh);
1509d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    }
1519d1188280fa5294f9438424e5e8eae91f645bfd8David Turner}
1529d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
1535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_chr_reset(CharDriverState *s)
1545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
1555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s->bh == NULL && initial_reset_issued) {
1569d1188280fa5294f9438424e5e8eae91f645bfd8David Turner	s->bh = qemu_bh_new(qemu_chr_generic_open_bh, s);
1575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	qemu_bh_schedule(s->bh);
1585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
1595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_chr_initial_reset(void)
1625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
1635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr;
1645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    initial_reset_issued = 1;
1665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
167a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turner    QTAILQ_FOREACH(chr, &chardevs, next) {
1685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_chr_reset(chr);
1695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
1705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len)
1735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
1745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return s->chr_write(s, buf, len);
1755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg)
1785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
1795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!s->chr_ioctl)
1805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -ENOTSUP;
1815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return s->chr_ioctl(s, cmd, arg);
1825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_chr_can_read(CharDriverState *s)
1855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
1865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!s->chr_can_read)
1875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 0;
1885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return s->chr_can_read(s->handler_opaque);
1895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_chr_read(CharDriverState *s, uint8_t *buf, int len)
1925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
1935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->chr_read(s->handler_opaque, buf, len);
1945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1969d1188280fa5294f9438424e5e8eae91f645bfd8David Turnerint qemu_chr_get_msgfd(CharDriverState *s)
1979d1188280fa5294f9438424e5e8eae91f645bfd8David Turner{
1989d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    return s->get_msgfd ? s->get_msgfd(s) : -1;
1999d1188280fa5294f9438424e5e8eae91f645bfd8David Turner}
2009d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
2015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_chr_accept_input(CharDriverState *s)
2025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
2035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s->chr_accept_input)
2045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        s->chr_accept_input(s);
2055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_chr_printf(CharDriverState *s, const char *fmt, ...)
2085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
2099d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    char buf[READ_BUF_LEN];
2105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    va_list ap;
2115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    va_start(ap, fmt);
2125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vsnprintf(buf, sizeof(buf), fmt, ap);
2135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_chr_write(s, (uint8_t *)buf, strlen(buf));
2145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    va_end(ap);
2155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_chr_send_event(CharDriverState *s, int event)
2185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
2195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s->chr_send_event)
2205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        s->chr_send_event(s, event);
2215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_chr_add_handlers(CharDriverState *s,
2244143d8f4c302878923bde0cb2420f4ca27245bcdDavid Turner                           IOCanReadHandler *fd_can_read,
2255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                           IOReadHandler *fd_read,
2265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                           IOEventHandler *fd_event,
2275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                           void *opaque)
2285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
22917410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    if (!opaque && !fd_can_read && !fd_read && !fd_event) {
23017410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner        /* chr driver being released. */
23117410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner        ++s->avail_connections;
23217410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    }
2335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->chr_can_read = fd_can_read;
2345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->chr_read = fd_read;
2355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->chr_event = fd_event;
2365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->handler_opaque = opaque;
2375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s->chr_update_read_handler)
2385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        s->chr_update_read_handler(s);
2399d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
2409d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    /* We're connecting to an already opened device, so let's make sure we
2419d1188280fa5294f9438424e5e8eae91f645bfd8David Turner       also get the open event */
2429d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    if (s->opened) {
2439d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        qemu_chr_generic_open(s);
2449d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    }
2455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
2485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
2495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return len;
2505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2529d1188280fa5294f9438424e5e8eae91f645bfd8David Turnerstatic CharDriverState *qemu_chr_open_null(QemuOpts *opts)
2535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
2545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr;
2555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
256aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    chr = g_malloc0(sizeof(CharDriverState));
2575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->chr_write = null_chr_write;
2585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return chr;
2595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* MUX driver for serial I/O splitting */
2625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define MAX_MUX 4
2635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define MUX_BUFFER_SIZE 32	/* Must be a power of 2.  */
2645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define MUX_BUFFER_MASK (MUX_BUFFER_SIZE - 1)
2655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct {
2664143d8f4c302878923bde0cb2420f4ca27245bcdDavid Turner    IOCanReadHandler *chr_can_read[MAX_MUX];
2675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    IOReadHandler *chr_read[MAX_MUX];
2685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    IOEventHandler *chr_event[MAX_MUX];
2695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    void *ext_opaque[MAX_MUX];
2705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *drv;
2719d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    int focus;
2725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int mux_cnt;
2735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int term_got_escape;
2745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int max_size;
2755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Intermediate input buffer allows to catch escape sequences even if the
2765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       currently active device is not accepting any input - but only until it
2775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       is full as well. */
2785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    unsigned char buffer[MAX_MUX][MUX_BUFFER_SIZE];
2795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int prod[MAX_MUX];
2805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int cons[MAX_MUX];
2815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int timestamps;
2825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int linestart;
2835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int64_t timestamps_start;
2845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} MuxDriver;
2855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
2885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
2895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    MuxDriver *d = chr->opaque;
2905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int ret;
2915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!d->timestamps) {
2925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = d->drv->chr_write(d->drv, buf, len);
2935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
2945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        int i;
2955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = 0;
2975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        for (i = 0; i < len; i++) {
2985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (d->linestart) {
2995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                char buf1[64];
3005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                int64_t ti;
3015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                int secs;
3025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
303dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner                ti = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
3045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                if (d->timestamps_start == -1)
3055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    d->timestamps_start = ti;
3065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                ti -= d->timestamps_start;
3075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                secs = ti / 1000;
3085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                snprintf(buf1, sizeof(buf1),
3095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                         "[%02d:%02d:%02d.%03d] ",
3105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                         secs / 3600,
3115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                         (secs / 60) % 60,
3125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                         secs % 60,
3135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                         (int)(ti % 1000));
3145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                d->drv->chr_write(d->drv, (uint8_t *)buf1, strlen(buf1));
3155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                d->linestart = 0;
3165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
3175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret += d->drv->chr_write(d->drv, buf+i, 1);
3185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (buf[i] == '\n') {
3195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                d->linestart = 1;
3205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
3215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
3225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
3235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return ret;
3245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic const char * const mux_help[] = {
3275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    "% h    print this help\n\r",
3285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    "% x    exit emulator\n\r",
3295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    "% s    save disk data back to file (if -snapshot)\n\r",
3305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    "% t    toggle console timestamps\n\r"
3315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    "% b    send break (magic sysrq)\n\r",
3325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    "% c    switch between console and monitor\n\r",
3335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    "% %  sends %\n\r",
3345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    NULL
3355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner};
3365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint term_escape_char = 0x01; /* ctrl-a is used for escape */
3385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void mux_print_help(CharDriverState *chr)
3395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i, j;
3415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char ebuf[15] = "Escape-Char";
3425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char cbuf[50] = "\n\r";
3435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (term_escape_char > 0 && term_escape_char < 26) {
3455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        snprintf(cbuf, sizeof(cbuf), "\n\r");
3465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        snprintf(ebuf, sizeof(ebuf), "C-%c", term_escape_char - 1 + 'a');
3475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
3485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        snprintf(cbuf, sizeof(cbuf),
3495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                 "\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r",
3505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                 term_escape_char);
3515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
3525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->chr_write(chr, (uint8_t *)cbuf, strlen(cbuf));
3535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (i = 0; mux_help[i] != NULL; i++) {
3545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        for (j=0; mux_help[i][j] != '\0'; j++) {
3555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (mux_help[i][j] == '%')
3565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                chr->chr_write(chr, (uint8_t *)ebuf, strlen(ebuf));
3575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            else
3585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                chr->chr_write(chr, (uint8_t *)&mux_help[i][j], 1);
3595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
3605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
3615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void mux_chr_send_event(MuxDriver *d, int mux_nr, int event)
3645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (d->chr_event[mux_nr])
3665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        d->chr_event[mux_nr](d->ext_opaque[mux_nr], event);
3675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
3705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (d->term_got_escape) {
3725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        d->term_got_escape = 0;
3735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ch == term_escape_char)
3745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            goto send_char;
3755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        switch(ch) {
3765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case '?':
3775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 'h':
3785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            mux_print_help(chr);
3795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
3805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 'x':
3815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            {
3825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                 const char *term =  "QEMU: Terminated\n\r";
3835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                 chr->chr_write(chr,(uint8_t *)term,strlen(term));
3845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                 exit(0);
3855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                 break;
3865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
3875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 's':
38817410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner            bdrv_commit_all();
3895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
3905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 'b':
3915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            qemu_chr_event(chr, CHR_EVENT_BREAK);
3925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
3935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 'c':
3945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            /* Switch to the next registered device */
3959d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT);
3969d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            d->focus++;
3979d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            if (d->focus >= d->mux_cnt)
3989d1188280fa5294f9438424e5e8eae91f645bfd8David Turner                d->focus = 0;
3999d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN);
4005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
4015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 't':
4025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            d->timestamps = !d->timestamps;
4035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            d->timestamps_start = -1;
4045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            d->linestart = 0;
4055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
4065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
4075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else if (ch == term_escape_char) {
4085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        d->term_got_escape = 1;
4095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
4105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    send_char:
4115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 1;
4125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
4135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
4145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
4155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void mux_chr_accept_input(CharDriverState *chr)
4175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
4185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    MuxDriver *d = chr->opaque;
4199d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    int m = d->focus;
4205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (d->prod[m] != d->cons[m] &&
4225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner           d->chr_can_read[m] &&
4235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner           d->chr_can_read[m](d->ext_opaque[m])) {
4245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        d->chr_read[m](d->ext_opaque[m],
4255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                       &d->buffer[m][d->cons[m]++ & MUX_BUFFER_MASK], 1);
4265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
4275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
4285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int mux_chr_can_read(void *opaque)
4305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
4315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr = opaque;
4325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    MuxDriver *d = chr->opaque;
4339d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    int m = d->focus;
4345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if ((d->prod[m] - d->cons[m]) < MUX_BUFFER_SIZE)
4365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 1;
4375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (d->chr_can_read[m])
4385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return d->chr_can_read[m](d->ext_opaque[m]);
4395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
4405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
4415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void mux_chr_read(void *opaque, const uint8_t *buf, int size)
4435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
4445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr = opaque;
4455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    MuxDriver *d = chr->opaque;
4469d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    int m = d->focus;
4475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i;
4485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    mux_chr_accept_input (opaque);
4505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for(i = 0; i < size; i++)
4525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (mux_proc_byte(chr, d, buf[i])) {
4535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (d->prod[m] == d->cons[m] &&
4545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                d->chr_can_read[m] &&
4555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                d->chr_can_read[m](d->ext_opaque[m]))
4565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                d->chr_read[m](d->ext_opaque[m], &buf[i], 1);
4575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            else
4585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                d->buffer[m][d->prod[m]++ & MUX_BUFFER_MASK] = buf[i];
4595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
4605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
4615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void mux_chr_event(void *opaque, int event)
4635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
4645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr = opaque;
4655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    MuxDriver *d = chr->opaque;
4665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i;
4675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Send the event to all registered listeners */
4695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (i = 0; i < d->mux_cnt; i++)
4705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        mux_chr_send_event(d, i, event);
4715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
4725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void mux_chr_update_read_handler(CharDriverState *chr)
4745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
4755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    MuxDriver *d = chr->opaque;
4765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (d->mux_cnt >= MAX_MUX) {
4785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "Cannot add I/O handlers, MUX array is full\n");
4795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
4805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
4815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    d->ext_opaque[d->mux_cnt] = chr->handler_opaque;
4825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    d->chr_can_read[d->mux_cnt] = chr->chr_can_read;
4835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    d->chr_read[d->mux_cnt] = chr->chr_read;
4845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    d->chr_event[d->mux_cnt] = chr->chr_event;
4855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Fix up the real driver with mux routines */
4865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (d->mux_cnt == 0) {
4875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_chr_add_handlers(d->drv, mux_chr_can_read, mux_chr_read,
4885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                              mux_chr_event, chr);
4895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
4909d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    if (d->focus != -1) {
4919d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT);
4929d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    }
4939d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    d->focus = d->mux_cnt;
4945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    d->mux_cnt++;
4959d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_IN);
4965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
4975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
4995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
5005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr;
5015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    MuxDriver *d;
5025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
503aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    chr = g_malloc0(sizeof(CharDriverState));
504aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    d = g_malloc0(sizeof(MuxDriver));
5055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->opaque = d;
5075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    d->drv = drv;
5089d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    d->focus = -1;
5095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->chr_write = mux_chr_write;
5105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->chr_update_read_handler = mux_chr_update_read_handler;
5115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->chr_accept_input = mux_chr_accept_input;
51217410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    /* Frontend guest-open / -close notification is not support with muxes */
51317410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    chr->chr_guest_open = NULL;
51417410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    chr->chr_guest_close = NULL;
5159d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
5169d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    /* Muxes are always open on creation */
5179d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    qemu_chr_generic_open(chr);
5189d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
5195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return chr;
5205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
5215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef _WIN32
5245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint send_all(int fd, const void *buf, int len1)
5255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
5263b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner#if 1
5273b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner	return socket_send(fd, buf, len1);
5283b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner#else
5295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int ret, len;
5305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    len = len1;
5325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (len > 0) {
5335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = send(fd, buf, len, 0);
5345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ret < 0) {
5355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            errno = WSAGetLastError();
5363b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner            if (errno != WSAEWOULDBLOCK && errno != WSAEAGAIN) {
5375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                return -1;
5385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
5395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else if (ret == 0) {
5405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
5415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else {
5425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            buf += ret;
5435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            len -= ret;
5445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
5455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
5465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return len1 - len;
5473b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner#endif
5485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
5495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else
5515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
55217410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turnerint send_all(int fd, const void *_buf, int len1)
5535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
5545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int ret, len;
55517410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    const uint8_t *buf = _buf;
5565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    len = len1;
5585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (len > 0) {
5595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = write(fd, buf, len);
5605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ret < 0) {
5615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (errno != EINTR && errno != EAGAIN)
5625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                return -1;
5635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else if (ret == 0) {
5645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
5655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else {
5665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            buf += ret;
5675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            len -= ret;
5685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
5695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
5705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return len1 - len;
5715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
5725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif /* !_WIN32 */
5735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5743b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turnerstatic CharDriverState *qemu_chr_open_android_modem(QemuOpts* opts)
5753b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner{
5763b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    CharDriverState*  cs;
5773b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    qemu_chr_open_charpipe( &cs, &android_modem_cs );
5783b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    return cs;
5793b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner}
5803b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turnerstatic CharDriverState *qemu_chr_open_android_gps(QemuOpts* opts)
5813b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner{
5823b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    CharDriverState*  cs;
5833b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    qemu_chr_open_charpipe( &cs, &android_gps_cs );
5843b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    return cs;
5853b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner}
5863b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner
5873b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turnerstatic CharDriverState *qemu_chr_open_android_kmsg(QemuOpts* opts)
5883b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner{
5893b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    return android_kmsg_get_cs();
5903b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner}
5913b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner
5923b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turnerstatic CharDriverState *qemu_chr_open_android_qemud(QemuOpts* opts)
5933b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner{
5943b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    return android_qemud_get_cs();
5953b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner}
5963b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner
5973b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner
5985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifndef _WIN32
5995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct {
6015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int fd_in, fd_out;
6025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int max_size;
6035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} FDCharDriver;
6045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define STDIO_MAX_CLIENTS 1
6065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int stdio_nb_clients = 0;
6075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
6095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    FDCharDriver *s = chr->opaque;
6115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return send_all(s->fd_out, buf, len);
6125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int fd_chr_read_poll(void *opaque)
6155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr = opaque;
6175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    FDCharDriver *s = chr->opaque;
6185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->max_size = qemu_chr_can_read(chr);
6205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return s->max_size;
6215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void fd_chr_read(void *opaque)
6245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr = opaque;
6265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    FDCharDriver *s = chr->opaque;
6275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int size, len;
6289d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    uint8_t buf[READ_BUF_LEN];
6295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    len = sizeof(buf);
6315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (len > s->max_size)
6325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len = s->max_size;
6335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (len == 0)
6345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
6355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    size = read(s->fd_in, buf, len);
6365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (size == 0) {
6375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* FD has been closed. Remove it from the active list.  */
6385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL);
6399d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        qemu_chr_event(chr, CHR_EVENT_CLOSED);
6405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
6415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
6425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (size > 0) {
6435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_chr_read(chr, buf, size);
6445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
6455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void fd_chr_update_read_handler(CharDriverState *chr)
6485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    FDCharDriver *s = chr->opaque;
6505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s->fd_in >= 0) {
6525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (display_type == DT_NOGRAPHIC && s->fd_in == 0) {
6535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else {
6545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll,
6555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                 fd_chr_read, NULL, chr);
6565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
6575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
6585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void fd_chr_close(struct CharDriverState *chr)
6615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    FDCharDriver *s = chr->opaque;
6635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s->fd_in >= 0) {
6655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (display_type == DT_NOGRAPHIC && s->fd_in == 0) {
6665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else {
6675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            qemu_set_fd_handler2(s->fd_in, NULL, NULL, NULL, NULL);
6685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
6695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
6705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
671aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    g_free(s);
6729d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    qemu_chr_event(chr, CHR_EVENT_CLOSED);
6735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* open a character device to a unix fd */
6765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out)
6775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr;
6795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    FDCharDriver *s;
6805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
681aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    chr = g_malloc0(sizeof(CharDriverState));
682aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    s = g_malloc0(sizeof(FDCharDriver));
6835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->fd_in = fd_in;
6845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->fd_out = fd_out;
6855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->opaque = s;
6865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->chr_write = fd_chr_write;
6875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->chr_update_read_handler = fd_chr_update_read_handler;
6885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->chr_close = fd_chr_close;
6895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6909d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    qemu_chr_generic_open(chr);
6915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return chr;
6935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6959d1188280fa5294f9438424e5e8eae91f645bfd8David Turnerstatic CharDriverState *qemu_chr_open_file_out(QemuOpts *opts)
6965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int fd_out;
6985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6999d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    TFR(fd_out = qemu_open(qemu_opt_get(opts, "path"),
7009d1188280fa5294f9438424e5e8eae91f645bfd8David Turner                      O_WRONLY | O_TRUNC | O_CREAT | O_BINARY, 0666));
7015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (fd_out < 0)
7025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return NULL;
7035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return qemu_chr_open_fd(-1, fd_out);
7045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
7055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7069d1188280fa5294f9438424e5e8eae91f645bfd8David Turnerstatic CharDriverState *qemu_chr_open_pipe(QemuOpts *opts)
7075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
7085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int fd_in, fd_out;
7095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char filename_in[256], filename_out[256];
7109d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    const char *filename = qemu_opt_get(opts, "path");
7119d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
7129d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    if (filename == NULL) {
7139d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        fprintf(stderr, "chardev: pipe: no filename given\n");
7149d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        return NULL;
7159d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    }
7165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    snprintf(filename_in, 256, "%s.in", filename);
7185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    snprintf(filename_out, 256, "%s.out", filename);
7199d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    TFR(fd_in = qemu_open(filename_in, O_RDWR | O_BINARY));
7209d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    TFR(fd_out = qemu_open(filename_out, O_RDWR | O_BINARY));
7215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (fd_in < 0 || fd_out < 0) {
7225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (fd_in >= 0)
7235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    close(fd_in);
7245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (fd_out >= 0)
7255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    close(fd_out);
7265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        TFR(fd_in = fd_out = open(filename, O_RDWR | O_BINARY));
7275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (fd_in < 0)
7285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return NULL;
7295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
7305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return qemu_chr_open_fd(fd_in, fd_out);
7315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
7325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7333b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner#ifdef CONFIG_ANDROID
7343b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turnerstatic CharDriverState *qemu_chr_open_fdpair(QemuOpts* opts)
7353b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner{
7363b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    int fd_in  = qemu_opt_get_number(opts, "fdin",-1);
7373b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    int fd_out = qemu_opt_get_number(opts, "fdout",-1);
7383b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner
7393b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    if (fd_in < 0 || fd_out < 0)
7403b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner        return NULL;
7413b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner
7423b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    return qemu_chr_open_fd(fd_in, fd_out);
7433b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner}
7443b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner#endif /* CONFIG_ANDROID */
7455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* for STDIO, we handle the case where several clients use it
7475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   (nographic mode) */
7485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define TERM_FIFO_MAX_SIZE 1
7505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic uint8_t term_fifo[TERM_FIFO_MAX_SIZE];
7525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int term_fifo_size;
7535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int stdio_read_poll(void *opaque)
7555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
7565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr = opaque;
7575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* try to flush the queue if needed */
7595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (term_fifo_size != 0 && qemu_chr_can_read(chr) > 0) {
7605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_chr_read(chr, term_fifo, 1);
7615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        term_fifo_size = 0;
7625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
7635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* see if we can absorb more chars */
7645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (term_fifo_size == 0)
7655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 1;
7665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    else
7675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 0;
7685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
7695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void stdio_read(void *opaque)
7715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
7725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int size;
7735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint8_t buf[1];
7745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr = opaque;
7755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    size = read(0, buf, 1);
7775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (size == 0) {
7785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* stdin has been closed. Remove it from the active list.  */
7795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL);
7809d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        qemu_chr_event(chr, CHR_EVENT_CLOSED);
7815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
7825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
7835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (size > 0) {
7845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (qemu_chr_can_read(chr) > 0) {
7855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            qemu_chr_read(chr, buf, 1);
7865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else if (term_fifo_size == 0) {
7875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            term_fifo[term_fifo_size++] = buf[0];
7885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
7895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
7905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
7915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* init terminal so that we can grab keys */
7935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic struct termios oldtty;
7945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int old_fd0_flags;
79517410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turnerstatic bool stdio_allow_signal;
7965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void term_exit(void)
7985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
7995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tcsetattr (0, TCSANOW, &oldtty);
8005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    fcntl(0, F_SETFL, old_fd0_flags);
8015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
8025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
80317410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turnerstatic void qemu_chr_set_echo_stdio(CharDriverState *chr, bool echo)
8045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
8055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct termios tty;
8065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
80717410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    tty = oldtty;
80817410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    if (!echo) {
8095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
8105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                          |INLCR|IGNCR|ICRNL|IXON);
8115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tty.c_oflag |= OPOST;
8125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
8135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tty.c_cflag &= ~(CSIZE|PARENB);
8145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tty.c_cflag |= CS8;
8155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tty.c_cc[VMIN] = 1;
8165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tty.c_cc[VTIME] = 0;
81717410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    }
81817410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    /* if graphical mode, we allow Ctrl-C handling */
81917410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    if (!stdio_allow_signal)
82017410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner        tty.c_lflag &= ~ISIG;
8215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tcsetattr (0, TCSANOW, &tty);
8235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
8245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void qemu_chr_close_stdio(struct CharDriverState *chr)
8265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
8275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    term_exit();
8285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    stdio_nb_clients--;
8295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL);
8305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    fd_chr_close(chr);
8315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
8325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8339d1188280fa5294f9438424e5e8eae91f645bfd8David Turnerstatic CharDriverState *qemu_chr_open_stdio(QemuOpts *opts)
8345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
8355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr;
8365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (stdio_nb_clients >= STDIO_MAX_CLIENTS)
8385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return NULL;
83917410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    if (stdio_nb_clients == 0) {
84017410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner        old_fd0_flags = fcntl(0, F_GETFL);
84117410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner        tcgetattr (0, &oldtty);
84217410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner        fcntl(0, F_SETFL, O_NONBLOCK);
84317410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner        atexit(term_exit);
84417410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    }
84517410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner
8465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr = qemu_chr_open_fd(0, 1);
8475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->chr_close = qemu_chr_close_stdio;
84817410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    chr->chr_set_echo = qemu_chr_set_echo_stdio;
8495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, chr);
8505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    stdio_nb_clients++;
85117410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    stdio_allow_signal = qemu_opt_get_bool(opts, "signal",
85217410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner                                           display_type != DT_NOGRAPHIC);
85317410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    qemu_chr_set_echo(chr, false);
8545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return chr;
8565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
8575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef __sun__
8595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* Once Solaris has openpty(), this is going to be removed. */
8605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int openpty(int *amaster, int *aslave, char *name,
8615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                   struct termios *termp, struct winsize *winp)
8625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
8635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        const char *slave;
8645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        int mfd = -1, sfd = -1;
8655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        *amaster = *aslave = -1;
8675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        mfd = open("/dev/ptmx", O_RDWR | O_NOCTTY);
8695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (mfd < 0)
8705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                goto err;
8715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (grantpt(mfd) == -1 || unlockpt(mfd) == -1)
8735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                goto err;
8745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if ((slave = ptsname(mfd)) == NULL)
8765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                goto err;
8775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if ((sfd = open(slave, O_RDONLY | O_NOCTTY)) == -1)
8795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                goto err;
8805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ioctl(sfd, I_PUSH, "ptem") == -1 ||
8825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            (termp != NULL && tcgetattr(sfd, termp) < 0))
8835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                goto err;
8845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (amaster)
8865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                *amaster = mfd;
8875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (aslave)
8885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                *aslave = sfd;
8895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (winp)
8905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                ioctl(sfd, TIOCSWINSZ, winp);
8915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 0;
8935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnererr:
8955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (sfd != -1)
8965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                close(sfd);
8975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        close(mfd);
8985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
8995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
9005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void cfmakeraw (struct termios *termios_p)
9025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
9035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        termios_p->c_iflag &=
9045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
9055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        termios_p->c_oflag &= ~OPOST;
9065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
9075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        termios_p->c_cflag &= ~(CSIZE|PARENB);
9085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        termios_p->c_cflag |= CS8;
9095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        termios_p->c_cc[VMIN] = 0;
9115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        termios_p->c_cc[VTIME] = 0;
9125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
9135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
9145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9153b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner#ifndef _WIN32
9165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct {
9185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int fd;
9195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int connected;
9205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int polling;
9215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int read_bytes;
9225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    QEMUTimer *timer;
9235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} PtyCharDriver;
9245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void pty_chr_update_read_handler(CharDriverState *chr);
9265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void pty_chr_state(CharDriverState *chr, int connected);
9275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
9295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
9305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    PtyCharDriver *s = chr->opaque;
9315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!s->connected) {
9335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* guest sends data, check for (re-)connect */
9345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        pty_chr_update_read_handler(chr);
9355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 0;
9365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
9375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return send_all(s->fd, buf, len);
9385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
9395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int pty_chr_read_poll(void *opaque)
9415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
9425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr = opaque;
9435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    PtyCharDriver *s = chr->opaque;
9445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->read_bytes = qemu_chr_can_read(chr);
9465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return s->read_bytes;
9475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
9485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void pty_chr_read(void *opaque)
9505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
9515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr = opaque;
9525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    PtyCharDriver *s = chr->opaque;
9535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int size, len;
9549d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    uint8_t buf[READ_BUF_LEN];
9555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    len = sizeof(buf);
9575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (len > s->read_bytes)
9585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len = s->read_bytes;
9595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (len == 0)
9605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
9615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    size = read(s->fd, buf, len);
9625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if ((size == -1 && errno == EIO) ||
9635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        (size == 0)) {
9645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        pty_chr_state(chr, 0);
9655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
9665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
9675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (size > 0) {
9685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        pty_chr_state(chr, 1);
9695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_chr_read(chr, buf, size);
9705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
9715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
9725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void pty_chr_update_read_handler(CharDriverState *chr)
9745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
9755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    PtyCharDriver *s = chr->opaque;
9765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_set_fd_handler2(s->fd, pty_chr_read_poll,
9785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                         pty_chr_read, NULL, chr);
9795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->polling = 1;
9805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /*
9815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * Short timeout here: just need wait long enougth that qemu makes
9825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * it through the poll loop once.  When reconnected we want a
9835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * short timeout so we notice it almost instantly.  Otherwise
9845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * read() gives us -EIO instantly, making pty_chr_state() reset the
9855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * timeout to the normal (much longer) poll interval before the
9865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * timer triggers.
9875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     */
988dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner    timer_mod(s->timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 10);
9895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
9905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void pty_chr_state(CharDriverState *chr, int connected)
9925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
9935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    PtyCharDriver *s = chr->opaque;
9945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!connected) {
9965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
9975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        s->connected = 0;
9985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        s->polling = 0;
9995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* (re-)connect poll interval for idle guests: once per second.
10005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         * We check more frequently in case the guests sends data to
10015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         * the virtual device linked to our pty. */
1002dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner        timer_mod(s->timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
10035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
10045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!s->connected)
10059d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            qemu_chr_generic_open(chr);
10065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        s->connected = 1;
10075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
10085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
10095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void pty_chr_timer(void *opaque)
10115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
10125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct CharDriverState *chr = opaque;
10135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    PtyCharDriver *s = chr->opaque;
10145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s->connected)
10165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
10175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s->polling) {
10185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* If we arrive here without polling being cleared due
10195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner         * read returning -EIO, then we are (re-)connected */
10205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        pty_chr_state(chr, 1);
10215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
10225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
10235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Next poll ... */
10255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    pty_chr_update_read_handler(chr);
10265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
10275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void pty_chr_close(struct CharDriverState *chr)
10295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
10305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    PtyCharDriver *s = chr->opaque;
10315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
10335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    close(s->fd);
1034dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner    timer_del(s->timer);
1035dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner    timer_free(s->timer);
1036aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    g_free(s);
10379d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    qemu_chr_event(chr, CHR_EVENT_CLOSED);
10385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
10395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10409d1188280fa5294f9438424e5e8eae91f645bfd8David Turnerstatic CharDriverState *qemu_chr_open_pty(QemuOpts *opts)
10415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
10425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr;
10435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    PtyCharDriver *s;
10445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct termios tty;
10455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int slave_fd, len;
10465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#if defined(__OpenBSD__) || defined(__DragonFly__)
10475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char pty_name[PATH_MAX];
10485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define q_ptsname(x) pty_name
10495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else
10505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char *pty_name = NULL;
10515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define q_ptsname(x) ptsname(x)
10523b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    //extern char* ptsname(int);
10535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
10545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1055aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    chr = g_malloc0(sizeof(CharDriverState));
1056aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    s = g_malloc0(sizeof(PtyCharDriver));
10575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (openpty(&s->fd, &slave_fd, pty_name, NULL, NULL) < 0) {
10595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return NULL;
10605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
10615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Set raw attributes on the pty. */
10635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tcgetattr(slave_fd, &tty);
10645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    cfmakeraw(&tty);
10655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tcsetattr(slave_fd, TCSAFLUSH, &tty);
10665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    close(slave_fd);
10675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    len = strlen(q_ptsname(s->fd)) + 5;
1069aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    chr->filename = g_malloc(len);
10705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    snprintf(chr->filename, len, "pty:%s", q_ptsname(s->fd));
10719d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    qemu_opt_set(opts, "path", q_ptsname(s->fd));
10725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    fprintf(stderr, "char device redirected to %s\n", q_ptsname(s->fd));
10735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->opaque = s;
10755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->chr_write = pty_chr_write;
10765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->chr_update_read_handler = pty_chr_update_read_handler;
10775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->chr_close = pty_chr_close;
10785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1079dcda949f769a11b197f4784fe299a448d87e6e14David 'Digit' Turner    s->timer = timer_new(QEMU_CLOCK_REALTIME, SCALE_MS, pty_chr_timer, chr);
10805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return chr;
10825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
10835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void tty_serial_init(int fd, int speed,
10855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                            int parity, int data_bits, int stop_bits)
10865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
10875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct termios tty;
10885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    speed_t spd;
10895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#if 0
10915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n",
10925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner           speed, parity, data_bits, stop_bits);
10935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
10945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tcgetattr (fd, &tty);
10959d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
10969d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#define check_speed(val) if (speed <= val) { spd = B##val; break; }
10979d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    speed = speed * 10 / 11;
10989d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    do {
10999d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(50);
11009d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(75);
11019d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(110);
11029d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(134);
11039d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(150);
11049d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(200);
11059d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(300);
11069d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(600);
11079d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(1200);
11089d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(1800);
11099d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(2400);
11109d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(4800);
11119d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(9600);
11129d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(19200);
11139d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(38400);
11149d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        /* Non-Posix values follow. They may be unsupported on some systems. */
11159d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(57600);
11169d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(115200);
11179d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#ifdef B230400
11189d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(230400);
11199d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#endif
11209d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#ifdef B460800
11219d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(460800);
11229d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#endif
11239d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#ifdef B500000
11249d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(500000);
11259d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#endif
11269d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#ifdef B576000
11279d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(576000);
11289d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#endif
11299d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#ifdef B921600
11309d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(921600);
11319d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#endif
11329d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#ifdef B1000000
11339d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(1000000);
11349d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#endif
11359d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#ifdef B1152000
11369d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(1152000);
11379d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#endif
11389d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#ifdef B1500000
11399d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(1500000);
11409d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#endif
11419d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#ifdef B2000000
11429d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(2000000);
11439d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#endif
11449d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#ifdef B2500000
11459d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(2500000);
11469d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#endif
11479d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#ifdef B3000000
11489d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(3000000);
11499d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#endif
11509d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#ifdef B3500000
11519d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(3500000);
11529d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#endif
11539d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#ifdef B4000000
11549d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        check_speed(4000000);
11559d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#endif
11565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        spd = B115200;
11579d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    } while (0);
11585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    cfsetispeed(&tty, spd);
11605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    cfsetospeed(&tty, spd);
11615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
11635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                          |INLCR|IGNCR|ICRNL|IXON);
11645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tty.c_oflag |= OPOST;
11655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN|ISIG);
11665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tty.c_cflag &= ~(CSIZE|PARENB|PARODD|CRTSCTS|CSTOPB);
11675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    switch(data_bits) {
11685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    default:
11695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case 8:
11705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        tty.c_cflag |= CS8;
11715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
11725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case 7:
11735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        tty.c_cflag |= CS7;
11745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
11755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case 6:
11765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        tty.c_cflag |= CS6;
11775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
11785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case 5:
11795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        tty.c_cflag |= CS5;
11805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
11815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
11825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    switch(parity) {
11835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    default:
11845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case 'N':
11855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
11865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case 'E':
11875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        tty.c_cflag |= PARENB;
11885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
11895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case 'O':
11905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        tty.c_cflag |= PARENB | PARODD;
11915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
11925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
11935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (stop_bits == 2)
11945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        tty.c_cflag |= CSTOPB;
11955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tcsetattr (fd, TCSANOW, &tty);
11975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
11985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg)
12005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
12015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    FDCharDriver *s = chr->opaque;
12025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
12035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    switch(cmd) {
12045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case CHR_IOCTL_SERIAL_SET_PARAMS:
12055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        {
12065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            QEMUSerialSetParams *ssp = arg;
12075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            tty_serial_init(s->fd_in, ssp->speed, ssp->parity,
12085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                            ssp->data_bits, ssp->stop_bits);
12095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
12105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
12115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case CHR_IOCTL_SERIAL_SET_BREAK:
12125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        {
12135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            int enable = *(int *)arg;
12145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (enable)
12155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                tcsendbreak(s->fd_in, 1);
12165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
12175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
12185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case CHR_IOCTL_SERIAL_GET_TIOCM:
12195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        {
12205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            int sarg = 0;
12215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            int *targ = (int *)arg;
12225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ioctl(s->fd_in, TIOCMGET, &sarg);
12235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            *targ = 0;
12245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (sarg & TIOCM_CTS)
12255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                *targ |= CHR_TIOCM_CTS;
12265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (sarg & TIOCM_CAR)
12275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                *targ |= CHR_TIOCM_CAR;
12285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (sarg & TIOCM_DSR)
12295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                *targ |= CHR_TIOCM_DSR;
12305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (sarg & TIOCM_RI)
12315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                *targ |= CHR_TIOCM_RI;
12325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (sarg & TIOCM_DTR)
12335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                *targ |= CHR_TIOCM_DTR;
12345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (sarg & TIOCM_RTS)
12355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                *targ |= CHR_TIOCM_RTS;
12365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
12375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
12385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case CHR_IOCTL_SERIAL_SET_TIOCM:
12395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        {
12405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            int sarg = *(int *)arg;
12415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            int targ = 0;
12425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ioctl(s->fd_in, TIOCMGET, &targ);
12435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            targ &= ~(CHR_TIOCM_CTS | CHR_TIOCM_CAR | CHR_TIOCM_DSR
12445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                     | CHR_TIOCM_RI | CHR_TIOCM_DTR | CHR_TIOCM_RTS);
12455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (sarg & CHR_TIOCM_CTS)
12465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                targ |= TIOCM_CTS;
12475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (sarg & CHR_TIOCM_CAR)
12485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                targ |= TIOCM_CAR;
12495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (sarg & CHR_TIOCM_DSR)
12505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                targ |= TIOCM_DSR;
12515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (sarg & CHR_TIOCM_RI)
12525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                targ |= TIOCM_RI;
12535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (sarg & CHR_TIOCM_DTR)
12545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                targ |= TIOCM_DTR;
12555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (sarg & CHR_TIOCM_RTS)
12565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                targ |= TIOCM_RTS;
12575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ioctl(s->fd_in, TIOCMSET, &targ);
12585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
12595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
12605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    default:
12615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -ENOTSUP;
12625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
12635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
12645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
12655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
12669d1188280fa5294f9438424e5e8eae91f645bfd8David Turnerstatic void qemu_chr_close_tty(CharDriverState *chr)
12679d1188280fa5294f9438424e5e8eae91f645bfd8David Turner{
12689d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    FDCharDriver *s = chr->opaque;
12699d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    int fd = -1;
12709d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
12719d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    if (s) {
12729d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        fd = s->fd_in;
12739d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    }
12749d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
12759d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    fd_chr_close(chr);
12769d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
12779d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    if (fd >= 0) {
12789d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        close(fd);
12799d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    }
12809d1188280fa5294f9438424e5e8eae91f645bfd8David Turner}
12819d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
12829d1188280fa5294f9438424e5e8eae91f645bfd8David Turnerstatic CharDriverState *qemu_chr_open_tty(QemuOpts *opts)
12835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
12849d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    const char *filename = qemu_opt_get(opts, "path");
12855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr;
12865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int fd;
12875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
12885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    TFR(fd = open(filename, O_RDWR | O_NONBLOCK));
12899d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    if (fd < 0) {
12909d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        return NULL;
12919d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    }
12925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tty_serial_init(fd, 115200, 'N', 8, 1);
12935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr = qemu_chr_open_fd(fd, fd);
12945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!chr) {
12955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        close(fd);
12965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return NULL;
12975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
12985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->chr_ioctl = tty_serial_ioctl;
12999d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    chr->chr_close = qemu_chr_close_tty;
13005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return chr;
13015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
13023b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner#else  /* _WIN32 */
13039d1188280fa5294f9438424e5e8eae91f645bfd8David Turnerstatic CharDriverState *qemu_chr_open_pty(QemuOpts *opts)
13045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
13055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return NULL;
13065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
13073b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner#endif /* _WIN32 */
13085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
13095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#if defined(__linux__)
13105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct {
13115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int fd;
13125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int mode;
13135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} ParallelCharDriver;
13145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
13155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int pp_hw_mode(ParallelCharDriver *s, uint16_t mode)
13165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
13175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s->mode != mode) {
13185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	int m = mode;
13195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ioctl(s->fd, PPSETMODE, &m) < 0)
13205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return 0;
13215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	s->mode = mode;
13225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
13235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 1;
13245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
13255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
13265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
13275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
13285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ParallelCharDriver *drv = chr->opaque;
13295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int fd = drv->fd;
13305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint8_t b;
13315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
13325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    switch(cmd) {
13335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case CHR_IOCTL_PP_READ_DATA:
13345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ioctl(fd, PPRDATA, &b) < 0)
13355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -ENOTSUP;
13365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        *(uint8_t *)arg = b;
13375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
13385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case CHR_IOCTL_PP_WRITE_DATA:
13395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        b = *(uint8_t *)arg;
13405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ioctl(fd, PPWDATA, &b) < 0)
13415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -ENOTSUP;
13425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
13435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case CHR_IOCTL_PP_READ_CONTROL:
13445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ioctl(fd, PPRCONTROL, &b) < 0)
13455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -ENOTSUP;
13465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	/* Linux gives only the lowest bits, and no way to know data
13475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	   direction! For better compatibility set the fixed upper
13485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	   bits. */
13495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        *(uint8_t *)arg = b | 0xc0;
13505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
13515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case CHR_IOCTL_PP_WRITE_CONTROL:
13525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        b = *(uint8_t *)arg;
13535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ioctl(fd, PPWCONTROL, &b) < 0)
13545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -ENOTSUP;
13555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
13565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case CHR_IOCTL_PP_READ_STATUS:
13575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ioctl(fd, PPRSTATUS, &b) < 0)
13585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -ENOTSUP;
13595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        *(uint8_t *)arg = b;
13605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
13615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case CHR_IOCTL_PP_DATA_DIR:
13625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ioctl(fd, PPDATADIR, (int *)arg) < 0)
13635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -ENOTSUP;
13645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
13655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case CHR_IOCTL_PP_EPP_READ_ADDR:
13665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (pp_hw_mode(drv, IEEE1284_MODE_EPP|IEEE1284_ADDR)) {
13675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    struct ParallelIOArg *parg = arg;
13685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    int n = read(fd, parg->buffer, parg->count);
13695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    if (n != parg->count) {
13705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		return -EIO;
13715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    }
13725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	}
13735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
13745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case CHR_IOCTL_PP_EPP_READ:
13755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
13765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    struct ParallelIOArg *parg = arg;
13775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    int n = read(fd, parg->buffer, parg->count);
13785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    if (n != parg->count) {
13795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		return -EIO;
13805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    }
13815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	}
13825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
13835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case CHR_IOCTL_PP_EPP_WRITE_ADDR:
13845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (pp_hw_mode(drv, IEEE1284_MODE_EPP|IEEE1284_ADDR)) {
13855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    struct ParallelIOArg *parg = arg;
13865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    int n = write(fd, parg->buffer, parg->count);
13875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    if (n != parg->count) {
13885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		return -EIO;
13895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    }
13905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	}
13915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
13925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case CHR_IOCTL_PP_EPP_WRITE:
13935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
13945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    struct ParallelIOArg *parg = arg;
13955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    int n = write(fd, parg->buffer, parg->count);
13965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    if (n != parg->count) {
13975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		return -EIO;
13985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    }
13995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	}
14005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
14015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    default:
14025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -ENOTSUP;
14035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
14045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
14055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
14065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void pp_close(CharDriverState *chr)
14085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
14095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ParallelCharDriver *drv = chr->opaque;
14105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int fd = drv->fd;
14115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    pp_hw_mode(drv, IEEE1284_MODE_COMPAT);
14135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ioctl(fd, PPRELEASE);
14145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    close(fd);
1415aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    g_free(drv);
14169d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    qemu_chr_event(chr, CHR_EVENT_CLOSED);
14175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
14185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14199d1188280fa5294f9438424e5e8eae91f645bfd8David Turnerstatic CharDriverState *qemu_chr_open_pp(QemuOpts *opts)
14205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
14219d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    const char *filename = qemu_opt_get(opts, "path");
14225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr;
14235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ParallelCharDriver *drv;
14245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int fd;
14255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    TFR(fd = open(filename, O_RDWR));
14275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (fd < 0)
14285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return NULL;
14295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ioctl(fd, PPCLAIM) < 0) {
14315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        close(fd);
14325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return NULL;
14335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
14345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1435aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    drv = g_malloc0(sizeof(ParallelCharDriver));
14365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    drv->fd = fd;
14375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    drv->mode = IEEE1284_MODE_COMPAT;
14385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1439aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    chr = g_malloc0(sizeof(CharDriverState));
14405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->chr_write = null_chr_write;
14415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->chr_ioctl = pp_ioctl;
14425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->chr_close = pp_close;
14435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->opaque = drv;
14445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14459d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    qemu_chr_generic_open(chr);
14465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return chr;
14485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
14495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif /* __linux__ */
14505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14519d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
14525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
14535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
145417410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    int fd = (int)(intptr_t)chr->opaque;
14555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint8_t b;
14565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    switch(cmd) {
14585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case CHR_IOCTL_PP_READ_DATA:
14595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ioctl(fd, PPIGDATA, &b) < 0)
14605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -ENOTSUP;
14615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        *(uint8_t *)arg = b;
14625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
14635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case CHR_IOCTL_PP_WRITE_DATA:
14645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        b = *(uint8_t *)arg;
14655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ioctl(fd, PPISDATA, &b) < 0)
14665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -ENOTSUP;
14675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
14685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case CHR_IOCTL_PP_READ_CONTROL:
14695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ioctl(fd, PPIGCTRL, &b) < 0)
14705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -ENOTSUP;
14715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        *(uint8_t *)arg = b;
14725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
14735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case CHR_IOCTL_PP_WRITE_CONTROL:
14745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        b = *(uint8_t *)arg;
14755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ioctl(fd, PPISCTRL, &b) < 0)
14765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -ENOTSUP;
14775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
14785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case CHR_IOCTL_PP_READ_STATUS:
14795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ioctl(fd, PPIGSTATUS, &b) < 0)
14805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return -ENOTSUP;
14815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        *(uint8_t *)arg = b;
14825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        break;
14835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    default:
14845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -ENOTSUP;
14855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
14865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
14875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
14885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14899d1188280fa5294f9438424e5e8eae91f645bfd8David Turnerstatic CharDriverState *qemu_chr_open_pp(QemuOpts *opts)
14905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
14919d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    const char *filename = qemu_opt_get(opts, "path");
14925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr;
14935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int fd;
14945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    fd = open(filename, O_RDWR);
14965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (fd < 0)
14975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return NULL;
14985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1499aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    chr = g_malloc0(sizeof(CharDriverState));
150017410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    chr->opaque = (void *)(intptr_t)fd;
15015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->chr_write = null_chr_write;
15025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->chr_ioctl = pp_ioctl;
15035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return chr;
15045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
15055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
15065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
15075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else /* _WIN32 */
15085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
15095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct {
15105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int max_size;
15115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    HANDLE hcom, hrecv, hsend;
15125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    OVERLAPPED orecv, osend;
15135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    BOOL fpipe;
15145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    DWORD len;
15155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} WinCharState;
15165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
15175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define NSENDBUF 2048
15185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define NRECVBUF 2048
15195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define MAXCONNECT 1
15205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define NTIMEOUT 5000
15215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
15225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int win_chr_poll(void *opaque);
15235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int win_chr_pipe_poll(void *opaque);
15245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
15255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void win_chr_close(CharDriverState *chr)
15265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
15275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    WinCharState *s = chr->opaque;
15285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
15295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s->hsend) {
15305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        CloseHandle(s->hsend);
15315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        s->hsend = NULL;
15325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
15335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s->hrecv) {
15345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        CloseHandle(s->hrecv);
15355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        s->hrecv = NULL;
15365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
15375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s->hcom) {
15385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        CloseHandle(s->hcom);
15395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        s->hcom = NULL;
15405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
15415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s->fpipe)
15425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_del_polling_cb(win_chr_pipe_poll, chr);
15435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    else
15445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_del_polling_cb(win_chr_poll, chr);
15459d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
15469d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    qemu_chr_event(chr, CHR_EVENT_CLOSED);
15475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
15485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
15495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int win_chr_init(CharDriverState *chr, const char *filename)
15505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
15515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    WinCharState *s = chr->opaque;
15525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    COMMCONFIG comcfg;
15535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    COMMTIMEOUTS cto = { 0, 0, 0, 0, 0};
15545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    COMSTAT comstat;
15555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    DWORD size;
15565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    DWORD err;
15575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
15585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
15595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!s->hsend) {
15605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "Failed CreateEvent\n");
15615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
15625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
15635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL);
15645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!s->hrecv) {
15655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "Failed CreateEvent\n");
15665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
15675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
15685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
15695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->hcom = CreateFile(filename, GENERIC_READ|GENERIC_WRITE, 0, NULL,
15705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                      OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
15715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s->hcom == INVALID_HANDLE_VALUE) {
15725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "Failed CreateFile (%lu)\n", GetLastError());
15735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        s->hcom = NULL;
15745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
15755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
15765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
15775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!SetupComm(s->hcom, NRECVBUF, NSENDBUF)) {
15785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "Failed SetupComm\n");
15795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
15805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
15815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
15825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ZeroMemory(&comcfg, sizeof(COMMCONFIG));
15835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    size = sizeof(COMMCONFIG);
15845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    GetDefaultCommConfig(filename, &comcfg, &size);
15855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    comcfg.dcb.DCBlength = sizeof(DCB);
15865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CommConfigDialog(filename, NULL, &comcfg);
15875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
15885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!SetCommState(s->hcom, &comcfg.dcb)) {
15895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "Failed SetCommState\n");
15905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
15915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
15925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
15935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!SetCommMask(s->hcom, EV_ERR)) {
15945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "Failed SetCommMask\n");
15955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
15965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
15975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
15985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    cto.ReadIntervalTimeout = MAXDWORD;
15995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!SetCommTimeouts(s->hcom, &cto)) {
16005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "Failed SetCommTimeouts\n");
16015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
16025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
16035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
16045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!ClearCommError(s->hcom, &err, &comstat)) {
16055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "Failed ClearCommError\n");
16065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
16075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
16085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_add_polling_cb(win_chr_poll, chr);
16095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
16105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
16115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fail:
16125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    win_chr_close(chr);
16135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return -1;
16145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
16155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
16165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int win_chr_write(CharDriverState *chr, const uint8_t *buf, int len1)
16175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
16185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    WinCharState *s = chr->opaque;
16195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    DWORD len, ret, size, err;
16205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
16215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    len = len1;
16225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ZeroMemory(&s->osend, sizeof(s->osend));
16235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->osend.hEvent = s->hsend;
16245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (len > 0) {
16255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (s->hsend)
16265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret = WriteFile(s->hcom, buf, len, &size, &s->osend);
16275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        else
16285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret = WriteFile(s->hcom, buf, len, &size, NULL);
16295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!ret) {
16305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            err = GetLastError();
16315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (err == ERROR_IO_PENDING) {
16325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                ret = GetOverlappedResult(s->hcom, &s->osend, &size, TRUE);
16335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                if (ret) {
16345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    buf += size;
16355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    len -= size;
16365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                } else {
16375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    break;
16385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                }
16395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            } else {
16405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
16415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
16425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else {
16435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            buf += size;
16445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            len -= size;
16455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
16465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
16475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return len1 - len;
16485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
16495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
16505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int win_chr_read_poll(CharDriverState *chr)
16515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
16525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    WinCharState *s = chr->opaque;
16535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
16545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->max_size = qemu_chr_can_read(chr);
16555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return s->max_size;
16565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
16575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
16585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void win_chr_readfile(CharDriverState *chr)
16595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
16605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    WinCharState *s = chr->opaque;
16615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int ret, err;
16629d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    uint8_t buf[READ_BUF_LEN];
16635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    DWORD size;
16645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
16655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ZeroMemory(&s->orecv, sizeof(s->orecv));
16665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->orecv.hEvent = s->hrecv;
16675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ret = ReadFile(s->hcom, buf, s->len, &size, &s->orecv);
16685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!ret) {
16695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        err = GetLastError();
16705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (err == ERROR_IO_PENDING) {
16715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret = GetOverlappedResult(s->hcom, &s->orecv, &size, TRUE);
16725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
16735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
16745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
16755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (size > 0) {
16765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_chr_read(chr, buf, size);
16775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
16785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
16795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
16805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void win_chr_read(CharDriverState *chr)
16815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
16825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    WinCharState *s = chr->opaque;
16835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
16845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s->len > s->max_size)
16855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        s->len = s->max_size;
16865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s->len == 0)
16875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
16885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
16895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    win_chr_readfile(chr);
16905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
16915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
16925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int win_chr_poll(void *opaque)
16935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
16945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr = opaque;
16955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    WinCharState *s = chr->opaque;
16965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    COMSTAT status;
16975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    DWORD comerr;
16985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
16995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ClearCommError(s->hcom, &comerr, &status);
17005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (status.cbInQue > 0) {
17015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        s->len = status.cbInQue;
17025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        win_chr_read_poll(chr);
17035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        win_chr_read(chr);
17045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 1;
17055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
17065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
17075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
17085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
17099d1188280fa5294f9438424e5e8eae91f645bfd8David Turnerstatic CharDriverState *qemu_chr_open_win(QemuOpts *opts)
17105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
17119d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    const char *filename = qemu_opt_get(opts, "path");
17125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr;
17135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    WinCharState *s;
17145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1715aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    chr = g_malloc0(sizeof(CharDriverState));
1716aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    s = g_malloc0(sizeof(WinCharState));
17175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->opaque = s;
17185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->chr_write = win_chr_write;
17195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->chr_close = win_chr_close;
17205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
17215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (win_chr_init(chr, filename) < 0) {
17225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        free(s);
17235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        free(chr);
17245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return NULL;
17255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
17269d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    qemu_chr_generic_open(chr);
17275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return chr;
17285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
17295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
17305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int win_chr_pipe_poll(void *opaque)
17315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
17325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr = opaque;
17335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    WinCharState *s = chr->opaque;
17345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    DWORD size;
17355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
17365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    PeekNamedPipe(s->hcom, NULL, 0, NULL, &size, NULL);
17375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (size > 0) {
17385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        s->len = size;
17395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        win_chr_read_poll(chr);
17405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        win_chr_read(chr);
17415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 1;
17425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
17435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
17445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
17455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
17465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int win_chr_pipe_init(CharDriverState *chr, const char *filename)
17475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
17485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    WinCharState *s = chr->opaque;
17495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    OVERLAPPED ov;
17505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int ret;
17515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    DWORD size;
17525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char openname[256];
17535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
17545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->fpipe = TRUE;
17555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
17565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->hsend = CreateEvent(NULL, TRUE, FALSE, NULL);
17575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!s->hsend) {
17585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "Failed CreateEvent\n");
17595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
17605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
17615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->hrecv = CreateEvent(NULL, TRUE, FALSE, NULL);
17625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!s->hrecv) {
17635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "Failed CreateEvent\n");
17645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
17655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
17665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
17675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    snprintf(openname, sizeof(openname), "\\\\.\\pipe\\%s", filename);
17685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->hcom = CreateNamedPipe(openname, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
17695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                              PIPE_TYPE_BYTE | PIPE_READMODE_BYTE |
17705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                              PIPE_WAIT,
17715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                              MAXCONNECT, NSENDBUF, NRECVBUF, NTIMEOUT, NULL);
17725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s->hcom == INVALID_HANDLE_VALUE) {
17735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "Failed CreateNamedPipe (%lu)\n", GetLastError());
17745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        s->hcom = NULL;
17755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
17765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
17775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
17785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ZeroMemory(&ov, sizeof(ov));
17795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
17805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ret = ConnectNamedPipe(s->hcom, &ov);
17815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ret) {
17825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "Failed ConnectNamedPipe\n");
17835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
17845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
17855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
17865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ret = GetOverlappedResult(s->hcom, &ov, &size, TRUE);
17875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!ret) {
17885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "Failed GetOverlappedResult\n");
17895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ov.hEvent) {
17905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            CloseHandle(ov.hEvent);
17915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ov.hEvent = NULL;
17925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
17935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
17945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
17955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
17965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ov.hEvent) {
17975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        CloseHandle(ov.hEvent);
17985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ov.hEvent = NULL;
17995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
18005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_add_polling_cb(win_chr_pipe_poll, chr);
18015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
18025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
18035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fail:
18045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    win_chr_close(chr);
18055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return -1;
18065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
18075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
18085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
18099d1188280fa5294f9438424e5e8eae91f645bfd8David Turnerstatic CharDriverState *qemu_chr_open_win_pipe(QemuOpts *opts)
18105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
18119d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    const char *filename = qemu_opt_get(opts, "path");
18125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr;
18135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    WinCharState *s;
18145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1815aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    chr = g_malloc0(sizeof(CharDriverState));
1816aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    s = g_malloc0(sizeof(WinCharState));
18175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->opaque = s;
18185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->chr_write = win_chr_write;
18195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->chr_close = win_chr_close;
18205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
18215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (win_chr_pipe_init(chr, filename) < 0) {
18225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        free(s);
18235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        free(chr);
18245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return NULL;
18255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
18269d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    qemu_chr_generic_open(chr);
18275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return chr;
18285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
18295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
18305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic CharDriverState *qemu_chr_open_win_file(HANDLE fd_out)
18315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
18325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr;
18335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    WinCharState *s;
18345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1835aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    chr = g_malloc0(sizeof(CharDriverState));
1836aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    s = g_malloc0(sizeof(WinCharState));
18375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->hcom = fd_out;
18385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->opaque = s;
18395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->chr_write = win_chr_write;
18409d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    qemu_chr_generic_open(chr);
18415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return chr;
18425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
18435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
18449d1188280fa5294f9438424e5e8eae91f645bfd8David Turnerstatic CharDriverState *qemu_chr_open_win_con(QemuOpts *opts)
18455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
18465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return qemu_chr_open_win_file(GetStdHandle(STD_OUTPUT_HANDLE));
18475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
18485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
18499d1188280fa5294f9438424e5e8eae91f645bfd8David Turnerstatic CharDriverState *qemu_chr_open_win_file_out(QemuOpts *opts)
18505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
18519d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    const char *file_out = qemu_opt_get(opts, "path");
18525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    HANDLE fd_out;
18535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
18545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    fd_out = CreateFile(file_out, GENERIC_WRITE, FILE_SHARE_READ, NULL,
18555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
18565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (fd_out == INVALID_HANDLE_VALUE)
18575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return NULL;
18585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
18595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return qemu_chr_open_win_file(fd_out);
18605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
18615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif /* !_WIN32 */
18625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
18635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/***********************************************************/
18645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* UDP Net console */
18655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
18665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct {
18675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int fd;
18683b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    SockAddress  daddr;
18699d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    uint8_t buf[READ_BUF_LEN];
18705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int bufcnt;
18715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int bufptr;
18725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int max_size;
18735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} NetCharDriver;
18745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
18755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int udp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
18765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
18775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    NetCharDriver *s = chr->opaque;
18785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
18793b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    return socket_sendto(s->fd, (const void *)buf, len, &s->daddr);
18805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
18815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
18825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int udp_chr_read_poll(void *opaque)
18835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
18845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr = opaque;
18855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    NetCharDriver *s = chr->opaque;
18865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
18875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->max_size = qemu_chr_can_read(chr);
18885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
18895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* If there were any stray characters in the queue process them
18905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * first
18915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     */
18925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (s->max_size > 0 && s->bufptr < s->bufcnt) {
18935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_chr_read(chr, &s->buf[s->bufptr], 1);
18945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        s->bufptr++;
18955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        s->max_size = qemu_chr_can_read(chr);
18965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
18975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return s->max_size;
18985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
18995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void udp_chr_read(void *opaque)
19015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
19025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr = opaque;
19035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    NetCharDriver *s = chr->opaque;
19045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s->max_size == 0)
19065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
19073b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    s->bufcnt = socket_recv(s->fd, (void *)s->buf, sizeof(s->buf));
19085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->bufptr = s->bufcnt;
19095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s->bufcnt <= 0)
19105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
19115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->bufptr = 0;
19135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (s->max_size > 0 && s->bufptr < s->bufcnt) {
19145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_chr_read(chr, &s->buf[s->bufptr], 1);
19155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        s->bufptr++;
19165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        s->max_size = qemu_chr_can_read(chr);
19175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
19185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
19195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void udp_chr_update_read_handler(CharDriverState *chr)
19215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
19225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    NetCharDriver *s = chr->opaque;
19235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s->fd >= 0) {
19255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_set_fd_handler2(s->fd, udp_chr_read_poll,
19265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                             udp_chr_read, NULL, chr);
19275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
19285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
19295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void udp_chr_close(CharDriverState *chr)
19315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
19325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    NetCharDriver *s = chr->opaque;
19335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s->fd >= 0) {
19345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
19353b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner        socket_close(s->fd);
19365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
1937aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    g_free(s);
19385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
19395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19409d1188280fa5294f9438424e5e8eae91f645bfd8David Turnerstatic CharDriverState *qemu_chr_open_udp(QemuOpts *opts)
19415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
19425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr = NULL;
19435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    NetCharDriver *s = NULL;
19445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int fd = -1;
19455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1946aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    chr = g_malloc0(sizeof(CharDriverState));
1947aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    s   = g_malloc0(sizeof(NetCharDriver));
19485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19499d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    fd = inet_dgram_opts(opts);
19505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (fd < 0) {
19519d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        fprintf(stderr, "inet_dgram_opts failed\n");
19525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto return_err;
19535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
19545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->fd = fd;
19565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->bufcnt = 0;
19575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->bufptr = 0;
19585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->opaque = s;
19595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->chr_write = udp_chr_write;
19605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->chr_update_read_handler = udp_chr_update_read_handler;
19615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->chr_close = udp_chr_close;
19625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return chr;
19635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerreturn_err:
19655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (chr)
19665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        free(chr);
19675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s)
19685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        free(s);
19695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (fd >= 0)
19705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        closesocket(fd);
19715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return NULL;
19725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
19735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/***********************************************************/
19755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* TCP Net console */
19765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct {
19785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int fd, listen_fd;
19795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int connected;
19805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int max_size;
19815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int do_telnetopt;
19825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int do_nodelay;
19835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int is_unix;
19849d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    int msgfd;
19855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} TCPCharDriver;
19865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void tcp_chr_accept(void *opaque);
19885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
19905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
19915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    TCPCharDriver *s = chr->opaque;
19925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s->connected) {
19935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return send_all(s->fd, buf, len);
19945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
19955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* XXX: indicate an error ? */
19965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return len;
19975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
19985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
19995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
20005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int tcp_chr_read_poll(void *opaque)
20015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
20025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr = opaque;
20035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    TCPCharDriver *s = chr->opaque;
20045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!s->connected)
20055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 0;
20065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->max_size = qemu_chr_can_read(chr);
20075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return s->max_size;
20085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
20095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
20105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define IAC 255
20115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define IAC_BREAK 243
20125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void tcp_chr_process_IAC_bytes(CharDriverState *chr,
20135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                      TCPCharDriver *s,
20145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                      uint8_t *buf, int *size)
20155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
20165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Handle any telnet client's basic IAC options to satisfy char by
20175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * char mode with no echo.  All IAC options will be removed from
20185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * the buf and the do_telnetopt variable will be used to track the
20195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * state of the width of the IAC information.
20205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     *
20215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * IAC commands come in sets of 3 bytes with the exception of the
20225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * "IAC BREAK" command and the double IAC.
20235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     */
20245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
20255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i;
20265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int j = 0;
20275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
20285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (i = 0; i < *size; i++) {
20295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (s->do_telnetopt > 1) {
20305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if ((unsigned char)buf[i] == IAC && s->do_telnetopt == 2) {
20315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                /* Double IAC means send an IAC */
20325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                if (j != i)
20335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    buf[j] = buf[i];
20345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                j++;
20355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                s->do_telnetopt = 1;
20365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            } else {
20375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                if ((unsigned char)buf[i] == IAC_BREAK && s->do_telnetopt == 2) {
20385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    /* Handle IAC break commands by sending a serial break */
20395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    qemu_chr_event(chr, CHR_EVENT_BREAK);
20405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    s->do_telnetopt++;
20415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                }
20425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                s->do_telnetopt++;
20435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
20445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (s->do_telnetopt >= 4) {
20455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                s->do_telnetopt = 1;
20465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
20475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else {
20485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if ((unsigned char)buf[i] == IAC) {
20495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                s->do_telnetopt = 2;
20505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            } else {
20515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                if (j != i)
20525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    buf[j] = buf[i];
20535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                j++;
20545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
20555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
20565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
20575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    *size = j;
20585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
20595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
20609d1188280fa5294f9438424e5e8eae91f645bfd8David Turnerstatic int tcp_get_msgfd(CharDriverState *chr)
20619d1188280fa5294f9438424e5e8eae91f645bfd8David Turner{
20629d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    TCPCharDriver *s = chr->opaque;
20639d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    int fd = s->msgfd;
20649d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    s->msgfd = -1;
20659d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    return fd;
20669d1188280fa5294f9438424e5e8eae91f645bfd8David Turner}
20679d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
20689d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#ifndef _WIN32
20699d1188280fa5294f9438424e5e8eae91f645bfd8David Turnerstatic void unix_process_msgfd(CharDriverState *chr, struct msghdr *msg)
20709d1188280fa5294f9438424e5e8eae91f645bfd8David Turner{
20719d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    TCPCharDriver *s = chr->opaque;
20729d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    struct cmsghdr *cmsg;
20739d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
20749d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
20759d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        int fd;
20769d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
20779d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        if (cmsg->cmsg_len != CMSG_LEN(sizeof(int)) ||
20789d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            cmsg->cmsg_level != SOL_SOCKET ||
20799d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            cmsg->cmsg_type != SCM_RIGHTS)
20809d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            continue;
20819d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
20829d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        fd = *((int *)CMSG_DATA(cmsg));
20839d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        if (fd < 0)
20849d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            continue;
20859d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
20869d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        if (s->msgfd != -1)
20879d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            close(s->msgfd);
20889d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        s->msgfd = fd;
20899d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    }
20909d1188280fa5294f9438424e5e8eae91f645bfd8David Turner}
20919d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
20929d1188280fa5294f9438424e5e8eae91f645bfd8David Turnerstatic ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len)
20939d1188280fa5294f9438424e5e8eae91f645bfd8David Turner{
20949d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    TCPCharDriver *s = chr->opaque;
20959d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    struct msghdr msg = { NULL, };
20969d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    struct iovec iov[1];
20979d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    union {
20989d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        struct cmsghdr cmsg;
20999d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        char control[CMSG_SPACE(sizeof(int))];
21009d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    } msg_control;
21019d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    ssize_t ret;
21029d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
21039d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    iov[0].iov_base = buf;
21049d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    iov[0].iov_len = len;
21059d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
21069d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    msg.msg_iov = iov;
21079d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    msg.msg_iovlen = 1;
21089d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    msg.msg_control = &msg_control;
21099d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    msg.msg_controllen = sizeof(msg_control);
21109d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
21119d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    ret = recvmsg(s->fd, &msg, 0);
21129d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    if (ret > 0 && s->is_unix)
21139d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        unix_process_msgfd(chr, &msg);
21149d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
21159d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    return ret;
21169d1188280fa5294f9438424e5e8eae91f645bfd8David Turner}
21179d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#else
21189d1188280fa5294f9438424e5e8eae91f645bfd8David Turnerstatic ssize_t tcp_chr_recv(CharDriverState *chr, char *buf, size_t len)
21199d1188280fa5294f9438424e5e8eae91f645bfd8David Turner{
21209d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    TCPCharDriver *s = chr->opaque;
21219d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    return recv(s->fd, buf, len, 0);
21229d1188280fa5294f9438424e5e8eae91f645bfd8David Turner}
21239d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#endif
21249d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
21255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void tcp_chr_read(void *opaque)
21265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
21275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr = opaque;
21285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    TCPCharDriver *s = chr->opaque;
21299d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    uint8_t buf[READ_BUF_LEN];
21305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int len, size;
21315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
21325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!s->connected || s->max_size <= 0)
21335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
21345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    len = sizeof(buf);
21355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (len > s->max_size)
21365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len = s->max_size;
21379d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    size = tcp_chr_recv(chr, (void *)buf, len);
21385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (size == 0) {
21395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* connection closed */
21405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        s->connected = 0;
21415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (s->listen_fd >= 0) {
21425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
21435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
21445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
21453b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner        socket_close(s->fd);
21465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        s->fd = -1;
21479d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        qemu_chr_event(chr, CHR_EVENT_CLOSED);
21485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else if (size > 0) {
21495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (s->do_telnetopt)
21505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            tcp_chr_process_IAC_bytes(chr, s, buf, &size);
21515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (size > 0)
21525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            qemu_chr_read(chr, buf, size);
21535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
21545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
21555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
21569d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#ifndef _WIN32
21579d1188280fa5294f9438424e5e8eae91f645bfd8David TurnerCharDriverState *qemu_chr_open_eventfd(int eventfd)
21589d1188280fa5294f9438424e5e8eae91f645bfd8David Turner{
21599d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    return qemu_chr_open_fd(eventfd, eventfd);
21609d1188280fa5294f9438424e5e8eae91f645bfd8David Turner}
21619d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#endif
21629d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
21635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void tcp_chr_connect(void *opaque)
21645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
21655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr = opaque;
21665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    TCPCharDriver *s = chr->opaque;
21675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
21685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->connected = 1;
21695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_set_fd_handler2(s->fd, tcp_chr_read_poll,
21705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                         tcp_chr_read, NULL, chr);
21719d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    qemu_chr_generic_open(chr);
21725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
21735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
21745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define IACSET(x,a,b,c) x[0] = a; x[1] = b; x[2] = c;
21755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void tcp_chr_telnet_init(int fd)
21765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
21775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char buf[3];
21785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Send the telnet negotion to put telnet in binary, no echo, single char mode */
21795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    IACSET(buf, 0xff, 0xfb, 0x01);  /* IAC WILL ECHO */
21803b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    socket_send(fd, (char *)buf, 3);
21815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    IACSET(buf, 0xff, 0xfb, 0x03);  /* IAC WILL Suppress go ahead */
21823b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    socket_send(fd, (char *)buf, 3);
21835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    IACSET(buf, 0xff, 0xfb, 0x00);  /* IAC WILL Binary */
21843b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    socket_send(fd, (char *)buf, 3);
21855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    IACSET(buf, 0xff, 0xfd, 0x00);  /* IAC DO Binary */
21863b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    socket_send(fd, (char *)buf, 3);
21875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
21885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
21895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void tcp_chr_accept(void *opaque)
21905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
21915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr = opaque;
21925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    TCPCharDriver *s = chr->opaque;
21935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int fd;
21945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
21955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for(;;) {
21963b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner        fd = socket_accept(s->listen_fd, NULL);
21973b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner        if (fd < 0) {
21985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return;
21995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else if (fd >= 0) {
22005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (s->do_telnetopt)
22015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                tcp_chr_telnet_init(fd);
22025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
22035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
22045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
22055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    socket_set_nonblock(fd);
22065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s->do_nodelay)
22075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        socket_set_nodelay(fd);
22085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->fd = fd;
22095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
22105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    tcp_chr_connect(chr);
22115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
22125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
22135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void tcp_chr_close(CharDriverState *chr)
22145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
22155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    TCPCharDriver *s = chr->opaque;
22165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s->fd >= 0) {
22175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
22185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        closesocket(s->fd);
22195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
22205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s->listen_fd >= 0) {
22215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
22225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        closesocket(s->listen_fd);
22235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
2224aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    g_free(s);
22259d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    qemu_chr_event(chr, CHR_EVENT_CLOSED);
22265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
22275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
22289d1188280fa5294f9438424e5e8eae91f645bfd8David Turnerstatic CharDriverState *qemu_chr_open_socket(QemuOpts *opts)
22295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
22305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr = NULL;
22315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    TCPCharDriver *s = NULL;
22329d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    int fd = -1;
22339d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    int is_listen;
22349d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    int is_waitconnect;
22359d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    int do_nodelay;
22369d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    int is_unix;
22379d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    int is_telnet;
22389d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
22399d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    is_listen      = qemu_opt_get_bool(opts, "server", 0);
22409d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    is_waitconnect = qemu_opt_get_bool(opts, "wait", 1);
22419d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    is_telnet      = qemu_opt_get_bool(opts, "telnet", 0);
22429d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    do_nodelay     = !qemu_opt_get_bool(opts, "delay", 1);
22439d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    is_unix        = qemu_opt_get(opts, "path") != NULL;
22445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!is_listen)
22455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        is_waitconnect = 0;
22465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2247aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    chr = g_malloc0(sizeof(CharDriverState));
2248aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    s = g_malloc0(sizeof(TCPCharDriver));
22495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
22505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (is_unix) {
22515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (is_listen) {
22529d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            fd = unix_listen_opts(opts);
22535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else {
22549d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            fd = unix_connect_opts(opts);
22555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
22565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
22575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (is_listen) {
22589d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            fd = inet_listen_opts(opts, 0);
22595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else {
22609d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            fd = inet_connect_opts(opts);
22615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
22625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
22635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (fd < 0)
22645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
22655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
22665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!is_waitconnect)
22675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        socket_set_nonblock(fd);
22685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
22695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->connected = 0;
22705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->fd = -1;
22715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->listen_fd = -1;
22729d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    s->msgfd = -1;
22735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->is_unix = is_unix;
22745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->do_nodelay = do_nodelay && !is_unix;
22755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
22765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->opaque = s;
22775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->chr_write = tcp_chr_write;
22785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    chr->chr_close = tcp_chr_close;
22799d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    chr->get_msgfd = tcp_get_msgfd;
22805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
22815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (is_listen) {
22825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        s->listen_fd = fd;
22835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_set_fd_handler(s->listen_fd, tcp_chr_accept, NULL, chr);
22845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (is_telnet)
22855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            s->do_telnetopt = 1;
22869d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
22875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
22885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        s->connected = 1;
22895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        s->fd = fd;
22905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        socket_set_nodelay(fd);
22915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        tcp_chr_connect(chr);
22925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
22935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
22949d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    /* for "info chardev" monitor command */
2295aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    chr->filename = g_malloc(256);
22969d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    if (is_unix) {
22979d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        snprintf(chr->filename, 256, "unix:%s%s",
22989d1188280fa5294f9438424e5e8eae91f645bfd8David Turner                 qemu_opt_get(opts, "path"),
22999d1188280fa5294f9438424e5e8eae91f645bfd8David Turner                 qemu_opt_get_bool(opts, "server", 0) ? ",server" : "");
23009d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    } else if (is_telnet) {
23019d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        snprintf(chr->filename, 256, "telnet:%s:%s%s",
23029d1188280fa5294f9438424e5e8eae91f645bfd8David Turner                 qemu_opt_get(opts, "host"), qemu_opt_get(opts, "port"),
23039d1188280fa5294f9438424e5e8eae91f645bfd8David Turner                 qemu_opt_get_bool(opts, "server", 0) ? ",server" : "");
23049d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    } else {
23059d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        snprintf(chr->filename, 256, "tcp:%s:%s%s",
23069d1188280fa5294f9438424e5e8eae91f645bfd8David Turner                 qemu_opt_get(opts, "host"), qemu_opt_get(opts, "port"),
23079d1188280fa5294f9438424e5e8eae91f645bfd8David Turner                 qemu_opt_get_bool(opts, "server", 0) ? ",server" : "");
23089d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    }
23099d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
23105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (is_listen && is_waitconnect) {
23115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        printf("QEMU waiting for connection on: %s\n",
23129d1188280fa5294f9438424e5e8eae91f645bfd8David Turner               chr->filename);
23135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        tcp_chr_accept(chr);
23145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        socket_set_nonblock(s->listen_fd);
23155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
23165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return chr;
23179d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
23185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fail:
23195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (fd >= 0)
23205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        closesocket(fd);
2321aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    g_free(s);
2322aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    g_free(chr);
23235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return NULL;
23245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
23255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
232617410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner/***********************************************************/
232717410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner/* Memory chardev */
232817410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turnertypedef struct {
232917410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    size_t outbuf_size;
233017410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    size_t outbuf_capacity;
233117410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    uint8_t *outbuf;
233217410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner} MemoryDriver;
233317410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner
233417410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turnerstatic int mem_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
233517410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner{
233617410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    MemoryDriver *d = chr->opaque;
233717410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner
233817410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    /* TODO: the QString implementation has the same code, we should
233917410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner     * introduce a generic way to do this in cutils.c */
234017410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    if (d->outbuf_capacity < d->outbuf_size + len) {
234117410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner        /* grow outbuf */
234217410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner        d->outbuf_capacity += len;
234317410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner        d->outbuf_capacity *= 2;
2344aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner        d->outbuf = g_realloc(d->outbuf, d->outbuf_capacity);
234517410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    }
234617410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner
234717410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    memcpy(d->outbuf + d->outbuf_size, buf, len);
234817410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    d->outbuf_size += len;
234917410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner
235017410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    return len;
235117410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner}
235217410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner
235317410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turnervoid qemu_chr_init_mem(CharDriverState *chr)
235417410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner{
235517410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    MemoryDriver *d;
235617410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner
2357aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    d = g_malloc(sizeof(*d));
235817410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    d->outbuf_size = 0;
235917410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    d->outbuf_capacity = 4096;
2360aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    d->outbuf = g_malloc0(d->outbuf_capacity);
236117410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner
236217410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    memset(chr, 0, sizeof(*chr));
236317410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    chr->opaque = d;
236417410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    chr->chr_write = mem_chr_write;
236517410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner}
236617410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner
236717410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' TurnerQString *qemu_chr_mem_to_qs(CharDriverState *chr)
236817410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner{
236917410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    MemoryDriver *d = chr->opaque;
237017410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    return qstring_from_substr((char *) d->outbuf, 0, d->outbuf_size - 1);
237117410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner}
237217410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner
237317410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner/* NOTE: this driver can not be closed with qemu_chr_close()! */
237417410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turnervoid qemu_chr_close_mem(CharDriverState *chr)
237517410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner{
237617410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    MemoryDriver *d = chr->opaque;
237717410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner
2378aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    g_free(d->outbuf);
2379aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    g_free(chr->opaque);
238017410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    chr->opaque = NULL;
238117410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    chr->chr_write = NULL;
238217410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner}
238317410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner
238417410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turnersize_t qemu_chr_mem_osize(const CharDriverState *chr)
238517410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner{
238617410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    const MemoryDriver *d = chr->opaque;
238717410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    return d->outbuf_size;
238817410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner}
238917410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner
23909d1188280fa5294f9438424e5e8eae91f645bfd8David TurnerQemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
23915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
23929d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    char host[65], port[33], width[8], height[8];
23939d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    int pos;
23945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    const char *p;
23959d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    QemuOpts *opts;
23969d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
23979d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    opts = qemu_opts_create(qemu_find_opts("chardev"), label, 1);
23989d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    if (NULL == opts)
23999d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        return NULL;
24005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
24015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (strstart(filename, "mon:", &p)) {
24029d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        filename = p;
24039d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        qemu_opt_set(opts, "mux", "on");
24049d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    }
24059d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
24069d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    if (strcmp(filename, "null")    == 0 ||
24079d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        strcmp(filename, "pty")     == 0 ||
24089d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        strcmp(filename, "msmouse") == 0 ||
24099d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        strcmp(filename, "braille") == 0 ||
24109d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        strcmp(filename, "stdio")   == 0) {
24119d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        qemu_opt_set(opts, "backend", filename);
24129d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        return opts;
24139d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    }
24149d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    if (strstart(filename, "vc", &p)) {
24159d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        qemu_opt_set(opts, "backend", "vc");
24169d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        if (*p == ':') {
24179d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            if (sscanf(p+1, "%8[0-9]x%8[0-9]", width, height) == 2) {
24189d1188280fa5294f9438424e5e8eae91f645bfd8David Turner                /* pixels */
24199d1188280fa5294f9438424e5e8eae91f645bfd8David Turner                qemu_opt_set(opts, "width", width);
24209d1188280fa5294f9438424e5e8eae91f645bfd8David Turner                qemu_opt_set(opts, "height", height);
24219d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            } else if (sscanf(p+1, "%8[0-9]Cx%8[0-9]C", width, height) == 2) {
24229d1188280fa5294f9438424e5e8eae91f645bfd8David Turner                /* chars */
24239d1188280fa5294f9438424e5e8eae91f645bfd8David Turner                qemu_opt_set(opts, "cols", width);
24249d1188280fa5294f9438424e5e8eae91f645bfd8David Turner                qemu_opt_set(opts, "rows", height);
24259d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            } else {
24269d1188280fa5294f9438424e5e8eae91f645bfd8David Turner                goto fail;
24279d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            }
24285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
24299d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        return opts;
24309d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    }
24319d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    if (strcmp(filename, "con:") == 0) {
24329d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        qemu_opt_set(opts, "backend", "console");
24339d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        return opts;
24349d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    }
24359d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    if (strstart(filename, "COM", NULL)) {
24369d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        qemu_opt_set(opts, "backend", "serial");
24379d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        qemu_opt_set(opts, "path", filename);
24389d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        return opts;
24399d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    }
24409d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    if (strstart(filename, "file:", &p)) {
24419d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        qemu_opt_set(opts, "backend", "file");
24429d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        qemu_opt_set(opts, "path", p);
24439d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        return opts;
24449d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    }
24459d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    if (strstart(filename, "pipe:", &p)) {
24469d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        qemu_opt_set(opts, "backend", "pipe");
24479d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        qemu_opt_set(opts, "path", p);
24489d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        return opts;
24499d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    }
24509d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    if (strstart(filename, "tcp:", &p) ||
24519d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        strstart(filename, "telnet:", &p)) {
24529d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) {
24539d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            host[0] = 0;
24549d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            if (sscanf(p, ":%32[^,]%n", port, &pos) < 1)
24559d1188280fa5294f9438424e5e8eae91f645bfd8David Turner                goto fail;
24569d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        }
24579d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        qemu_opt_set(opts, "backend", "socket");
24589d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        qemu_opt_set(opts, "host", host);
24599d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        qemu_opt_set(opts, "port", port);
24609d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        if (p[pos] == ',') {
24619d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            if (qemu_opts_do_parse(opts, p+pos+1, NULL) != 0)
24629d1188280fa5294f9438424e5e8eae91f645bfd8David Turner                goto fail;
24639d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        }
24649d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        if (strstart(filename, "telnet:", &p))
24659d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            qemu_opt_set(opts, "telnet", "on");
24669d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        return opts;
24679d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    }
24689d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    if (strstart(filename, "udp:", &p)) {
24699d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        qemu_opt_set(opts, "backend", "udp");
24709d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        if (sscanf(p, "%64[^:]:%32[^@,]%n", host, port, &pos) < 2) {
24719d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            host[0] = 0;
24729d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            if (sscanf(p, ":%32[^@,]%n", port, &pos) < 1) {
24739d1188280fa5294f9438424e5e8eae91f645bfd8David Turner                goto fail;
24749d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            }
24759d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        }
24769d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        qemu_opt_set(opts, "host", host);
24779d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        qemu_opt_set(opts, "port", port);
24789d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        if (p[pos] == '@') {
24799d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            p += pos + 1;
24809d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) {
24819d1188280fa5294f9438424e5e8eae91f645bfd8David Turner                host[0] = 0;
24829d1188280fa5294f9438424e5e8eae91f645bfd8David Turner                if (sscanf(p, ":%32[^,]%n", port, &pos) < 1) {
24839d1188280fa5294f9438424e5e8eae91f645bfd8David Turner                    goto fail;
24849d1188280fa5294f9438424e5e8eae91f645bfd8David Turner                }
24859d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            }
24869d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            qemu_opt_set(opts, "localaddr", host);
24879d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            qemu_opt_set(opts, "localport", port);
24889d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        }
24899d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        return opts;
24909d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    }
24915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (strstart(filename, "unix:", &p)) {
24929d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        qemu_opt_set(opts, "backend", "socket");
24939d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        if (qemu_opts_do_parse(opts, p, "path") != 0)
24949d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            goto fail;
24959d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        return opts;
24969d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    }
24979d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    if (strstart(filename, "/dev/parport", NULL) ||
24989d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        strstart(filename, "/dev/ppi", NULL)) {
24999d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        qemu_opt_set(opts, "backend", "parport");
25009d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        qemu_opt_set(opts, "path", filename);
25019d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        return opts;
25029d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    }
25035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (strstart(filename, "/dev/", NULL)) {
25049d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        qemu_opt_set(opts, "backend", "tty");
25059d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        qemu_opt_set(opts, "path", filename);
25069d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        return opts;
25079d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    }
25083b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner#ifdef CONFIG_ANDROID
25093b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    if (strstart(filename, "fdpair:", &p)) {
25103b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner        int fdin, fdout;
25113b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner        char temp[8];
25123b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner        qemu_opt_set(opts, "backend", "fdpair");
25133b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner        if (sscanf(p, "%d,%d", &fdin, &fdout) != 2) {
25143b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner            goto fail;
25153b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner        }
25163b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner        if (fdin < 0 || fdout < 0) {
25173b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner            goto fail;
25183b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner        }
25193b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner        snprintf(temp, sizeof temp, "%d", fdin);
25203b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner        qemu_opt_set(opts, "fdin", temp);
25213b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner        snprintf(temp, sizeof temp, "%d", fdout);
25223b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner        qemu_opt_set(opts, "fdout", temp);
25233b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner        return opts;
25243b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    }
25253b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    if (!strcmp(filename, "android-kmsg")) {
25263b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner        qemu_opt_set(opts, "backend", "android-kmsg");
25273b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner        return opts;
25283b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    }
25293b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    if (!strcmp(filename, "android-qemud")) {
25303b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner        qemu_opt_set(opts, "backend", "android-qemud");
25313b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner        return opts;
25323b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    }
25333b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    if (!strcmp(filename, "android-modem")) {
25343b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner        qemu_opt_set(opts, "backend", "android-modem");
25353b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner        return opts;
25363b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    }
25373b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    if (!strcmp(filename, "android-gps")) {
25383b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner        qemu_opt_set(opts, "backend", "android-gps");
25393b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner        return opts;
25403b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    }
25413b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner#endif /* CONFIG_ANDROID */
25429d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
25439d1188280fa5294f9438424e5e8eae91f645bfd8David Turnerfail:
25449d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    qemu_opts_del(opts);
25459d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    return NULL;
25469d1188280fa5294f9438424e5e8eae91f645bfd8David Turner}
25479d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
25489d1188280fa5294f9438424e5e8eae91f645bfd8David Turnerstatic const struct {
25499d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    const char *name;
25509d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    CharDriverState *(*open)(QemuOpts *opts);
25519d1188280fa5294f9438424e5e8eae91f645bfd8David Turner} backend_table[] = {
25529d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    { .name = "null",      .open = qemu_chr_open_null },
25539d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    { .name = "socket",    .open = qemu_chr_open_socket },
25549d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    { .name = "udp",       .open = qemu_chr_open_udp },
25559d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    { .name = "msmouse",   .open = qemu_chr_open_msmouse },
25563b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    { .name = "vc",        .open = text_console_init },
25579d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#ifdef _WIN32
25589d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    { .name = "file",      .open = qemu_chr_open_win_file_out },
25599d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    { .name = "pipe",      .open = qemu_chr_open_win_pipe },
25609d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    { .name = "console",   .open = qemu_chr_open_win_con },
25619d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    { .name = "serial",    .open = qemu_chr_open_win },
25629d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#else
25639d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    { .name = "file",      .open = qemu_chr_open_file_out },
25649d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    { .name = "pipe",      .open = qemu_chr_open_pipe },
25659d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    { .name = "pty",       .open = qemu_chr_open_pty },
25669d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    { .name = "stdio",     .open = qemu_chr_open_stdio },
25675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
25689d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#ifdef CONFIG_ANDROID
25693b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner#ifndef _WIN32
25709d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    { .name = "fdpair",    .open = qemu_chr_open_fdpair },
25715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
25723b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    { .name = "android-qemud", .open = qemu_chr_open_android_qemud },
25733b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    { .name = "android-kmsg",  .open = qemu_chr_open_android_kmsg },
25743b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    { .name = "android-modem", .open = qemu_chr_open_android_modem },
25753b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner    { .name = "android-gps",   .open = qemu_chr_open_android_gps },
25763b2846ad9f156e62574a0abc5ec489f8f13f1121David 'Digit' Turner#endif
25775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef CONFIG_BRLAPI
25789d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    { .name = "braille",   .open = chr_baum_init },
25799d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#endif
25809d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \
25819d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) \
25829d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    || defined(__FreeBSD_kernel__)
25839d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    { .name = "tty",       .open = qemu_chr_open_tty },
25849d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#endif
25859d1188280fa5294f9438424e5e8eae91f645bfd8David Turner#if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__) \
25869d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    || defined(__FreeBSD_kernel__)
25879d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    { .name = "parport",   .open = qemu_chr_open_pp },
25885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
25899d1188280fa5294f9438424e5e8eae91f645bfd8David Turner};
25909d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
25919d1188280fa5294f9438424e5e8eae91f645bfd8David TurnerCharDriverState *qemu_chr_open_opts(QemuOpts *opts,
25929d1188280fa5294f9438424e5e8eae91f645bfd8David Turner                                    void (*init)(struct CharDriverState *s))
25939d1188280fa5294f9438424e5e8eae91f645bfd8David Turner{
25949d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    CharDriverState *chr;
25959d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    int i;
25969d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
25979d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    if (qemu_opts_id(opts) == NULL) {
25989d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        fprintf(stderr, "chardev: no id specified\n");
25999d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        return NULL;
26009d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    }
26019d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
260217410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    if (qemu_opt_get(opts, "backend") == NULL) {
260317410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner        fprintf(stderr, "chardev: \"%s\" missing backend\n",
260417410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner                qemu_opts_id(opts));
260517410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner        return NULL;
260617410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    }
26079d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    for (i = 0; i < ARRAY_SIZE(backend_table); i++) {
26089d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        if (strcmp(backend_table[i].name, qemu_opt_get(opts, "backend")) == 0)
26099d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            break;
26109d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    }
26119d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    if (i == ARRAY_SIZE(backend_table)) {
26129d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        fprintf(stderr, "chardev: backend \"%s\" not found\n",
26139d1188280fa5294f9438424e5e8eae91f645bfd8David Turner                qemu_opt_get(opts, "backend"));
26149d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        return NULL;
26155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
26165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
26179d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    chr = backend_table[i].open(opts);
26189d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    if (!chr) {
26199d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        fprintf(stderr, "chardev: opening backend \"%s\" failed\n",
26209d1188280fa5294f9438424e5e8eae91f645bfd8David Turner                qemu_opt_get(opts, "backend"));
26219d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        return NULL;
26229d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    }
26239d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
26249d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    if (!chr->filename)
2625aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner        chr->filename = g_strdup(qemu_opt_get(opts, "backend"));
26269d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    chr->init = init;
26279d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    QTAILQ_INSERT_TAIL(&chardevs, chr, next);
26289d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
26299d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    if (qemu_opt_get_bool(opts, "mux", 0)) {
26309d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        CharDriverState *base = chr;
26319d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        int len = strlen(qemu_opts_id(opts)) + 6;
2632aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner        base->label = g_malloc(len);
26339d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        snprintf(base->label, len, "%s-base", qemu_opts_id(opts));
26349d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        chr = qemu_chr_open_mux(base);
26359d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        chr->filename = base->filename;
263617410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner        chr->avail_connections = MAX_MUX;
26379d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        QTAILQ_INSERT_TAIL(&chardevs, chr, next);
263817410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    } else {
263917410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner        chr->avail_connections = 1;
26409d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    }
2641aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    chr->label = g_strdup(qemu_opts_id(opts));
26429d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    return chr;
26439d1188280fa5294f9438424e5e8eae91f645bfd8David Turner}
26449d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
26459d1188280fa5294f9438424e5e8eae91f645bfd8David TurnerCharDriverState *qemu_chr_open(const char *label, const char *filename, void (*init)(struct CharDriverState *s))
26469d1188280fa5294f9438424e5e8eae91f645bfd8David Turner{
26479d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    const char *p;
26489d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    CharDriverState *chr;
26499d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    QemuOpts *opts;
26509d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
26519d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    if (strstart(filename, "chardev:", &p)) {
26529d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        return qemu_chr_find(p);
26539d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    }
26549d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
26559d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    opts = qemu_chr_parse_compat(label, filename);
26569d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    if (!opts)
26579d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        return NULL;
26589d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
26599d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    chr = qemu_chr_open_opts(opts, init);
26609d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    if (chr && qemu_opt_get_bool(opts, "mux", 0)) {
26619d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        monitor_init(chr, MONITOR_USE_READLINE);
26625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
266317410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    qemu_opts_del(opts);
26645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return chr;
26655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
26665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
266717410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turnervoid qemu_chr_set_echo(struct CharDriverState *chr, bool echo)
266817410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner{
266917410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    if (chr->chr_set_echo) {
267017410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner        chr->chr_set_echo(chr, echo);
267117410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    }
267217410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner}
267317410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner
267417410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turnervoid qemu_chr_guest_open(struct CharDriverState *chr)
267517410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner{
267617410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    if (chr->chr_guest_open) {
267717410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner        chr->chr_guest_open(chr);
267817410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    }
267917410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner}
268017410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner
268117410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turnervoid qemu_chr_guest_close(struct CharDriverState *chr)
268217410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner{
268317410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    if (chr->chr_guest_close) {
268417410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner        chr->chr_guest_close(chr);
268517410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner    }
268617410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner}
268717410ee4539bb5216421bb9f9dc287b1f678b6cdDavid 'Digit' Turner
26885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_chr_close(CharDriverState *chr)
26895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
26909d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    QTAILQ_REMOVE(&chardevs, chr, next);
26915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (chr->chr_close)
26925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        chr->chr_close(chr);
2693aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    g_free(chr->filename);
2694aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    g_free(chr->label);
2695aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    g_free(chr);
26965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
26975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
26989d1188280fa5294f9438424e5e8eae91f645bfd8David Turnerstatic void qemu_chr_qlist_iter(QObject *obj, void *opaque)
26999d1188280fa5294f9438424e5e8eae91f645bfd8David Turner{
27009d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    QDict *chr_dict;
27019d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    Monitor *mon = opaque;
27029d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
27039d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    chr_dict = qobject_to_qdict(obj);
27049d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    monitor_printf(mon, "%s: filename=%s\n", qdict_get_str(chr_dict, "label"),
27059d1188280fa5294f9438424e5e8eae91f645bfd8David Turner                                         qdict_get_str(chr_dict, "filename"));
27069d1188280fa5294f9438424e5e8eae91f645bfd8David Turner}
27079d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
27089d1188280fa5294f9438424e5e8eae91f645bfd8David Turnervoid qemu_chr_info_print(Monitor *mon, const QObject *ret_data)
27099d1188280fa5294f9438424e5e8eae91f645bfd8David Turner{
27109d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    qlist_iter(qobject_to_qlist(ret_data), qemu_chr_qlist_iter, mon);
27119d1188280fa5294f9438424e5e8eae91f645bfd8David Turner}
27129d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
27139d1188280fa5294f9438424e5e8eae91f645bfd8David Turnervoid qemu_chr_info(Monitor *mon, QObject **ret_data)
27149d1188280fa5294f9438424e5e8eae91f645bfd8David Turner{
27159d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    QList *chr_list;
27169d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    CharDriverState *chr;
27179d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
27189d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    chr_list = qlist_new();
27199d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
27209d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    QTAILQ_FOREACH(chr, &chardevs, next) {
27219d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        QObject *obj = qobject_from_jsonf("{ 'label': %s, 'filename': %s }",
27229d1188280fa5294f9438424e5e8eae91f645bfd8David Turner                                          chr->label, chr->filename);
27239d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        qlist_append_obj(chr_list, obj);
27249d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    }
27259d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
27269d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    *ret_data = QOBJECT(chr_list);
27279d1188280fa5294f9438424e5e8eae91f645bfd8David Turner}
27289d1188280fa5294f9438424e5e8eae91f645bfd8David Turner
27299d1188280fa5294f9438424e5e8eae91f645bfd8David TurnerCharDriverState *qemu_chr_find(const char *name)
27305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
27315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *chr;
27325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2733a5d412078b8e7478d81df03710eacc7a21096ba2David 'Digit' Turner    QTAILQ_FOREACH(chr, &chardevs, next) {
27349d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        if (strcmp(chr->label, name) != 0)
27359d1188280fa5294f9438424e5e8eae91f645bfd8David Turner            continue;
27369d1188280fa5294f9438424e5e8eae91f645bfd8David Turner        return chr;
27375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
27389d1188280fa5294f9438424e5e8eae91f645bfd8David Turner    return NULL;
27395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2740