From patchwork Tue May 7 16:51:54 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Baboval X-Patchwork-Id: 242418 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 339F62C016E for ; Wed, 8 May 2013 03:14:01 +1000 (EST) Received: from localhost ([::1]:36042 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UZl8L-0002Gh-PB for incoming@patchwork.ozlabs.org; Tue, 07 May 2013 12:52:57 -0400 Received: from eggs.gnu.org ([208.118.235.92]:51162) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UZl7x-00028O-8E for qemu-devel@nongnu.org; Tue, 07 May 2013 12:52:36 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1UZl7t-0005rW-Td for qemu-devel@nongnu.org; Tue, 07 May 2013 12:52:33 -0400 Received: from smtp.citrix.com ([66.165.176.89]:56232) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1UZl7t-0005rN-KS for qemu-devel@nongnu.org; Tue, 07 May 2013 12:52:29 -0400 X-IronPort-AV: E=Sophos;i="4.87,629,1363132800"; d="scan'208";a="23790101" Received: from accessns.citrite.net (HELO FTLPEX01CL01.citrite.net) ([10.9.154.239]) by FTLPIPO01.CITRIX.COM with ESMTP/TLS/AES128-SHA; 07 May 2013 16:52:22 +0000 Received: from jbaboval-desktop.citrite.net (10.204.240.225) by FTLPEX01CL01.citrite.net (10.13.107.78) with Microsoft SMTP Server id 14.2.342.3; Tue, 7 May 2013 12:52:21 -0400 From: John Baboval To: Date: Tue, 7 May 2013 12:51:54 -0400 Message-ID: <1367945514-20608-2-git-send-email-john.baboval@citrix.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1367945514-20608-1-git-send-email-john.baboval@citrix.com> References: <5187C18D.5030901@redhat.com> <1367945514-20608-1-git-send-email-john.baboval@citrix.com> MIME-Version: 1.0 X-Originating-IP: [10.204.240.225] X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 66.165.176.89 Cc: "John V. Baboval" , John Baboval Subject: [Qemu-devel] [PATCH] Add 'maxqdepth' as an option to tty character devices. X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: "John V. Baboval" This parameter will cause writes to tty backed chardevs to return -EAGAIN if the backing tty has buffered more than the specified number of characters. When data is sent, the TIOCOUTQ ioctl is invoked to determine the current TTY output buffer depth. Background: Some devices use DTR/DSR as flow control. (eg. Check/Receipt printers with some POS software). When the device de-asserts DTR, the guest OS notifies the application and new data is blocked. When running on a QEMU serial port backed by a TTY, though the guest stops transmitting, all the characters in the TTY output buffer are still sent. The device buffer overflows and data is lost. In this case the user could set maxqdepth=1. Signed-off-by: John Baboval --- include/sysemu/char.h | 2 ++ qapi-schema.json | 5 ++++- qemu-char.c | 40 +++++++++++++++++++++++++++++++++++++++- qemu-options.hx | 4 ++-- 4 files changed, 47 insertions(+), 4 deletions(-) diff --git a/include/sysemu/char.h b/include/sysemu/char.h index 5e42c90..a94c1fb 100644 --- a/include/sysemu/char.h +++ b/include/sysemu/char.h @@ -43,6 +43,7 @@ typedef struct { #define CHR_IOCTL_SERIAL_SET_TIOCM 13 #define CHR_IOCTL_SERIAL_GET_TIOCM 14 +#define CHR_IOCTL_SERIAL_TIOCOUTQ 15 #define CHR_TIOCM_CTS 0x020 #define CHR_TIOCM_CAR 0x040 @@ -77,6 +78,7 @@ struct CharDriverState { int fe_open; int explicit_fe_open; int avail_connections; + uint32_t maxqdepth; QemuOpts *opts; QTAILQ_ENTRY(CharDriverState) next; }; diff --git a/qapi-schema.json b/qapi-schema.json index 7797400..029e7c9 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -3182,11 +3182,14 @@ # # @device: The name of the special file for the device, # i.e. /dev/ttyS0 on Unix or COM1: on Windows +# @maxqdepth: The maximum depth of the underlying tty + output queue (Unix) # @type: What kind of device this is. # # Since: 1.4 ## -{ 'type': 'ChardevHostdev', 'data': { 'device' : 'str' } } +{ 'type': 'ChardevHostdev', 'data': { 'device' : 'str', + 'maxqdepth' : 'int' } } ## # @ChardevSocket: diff --git a/qemu-char.c b/qemu-char.c index 64e824d..e2e4217 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -782,6 +782,7 @@ typedef struct FDCharDriver { GIOChannel *fd_in, *fd_out; guint fd_in_tag; int max_size; + int tiocoutq_failed; QTAILQ_ENTRY(FDCharDriver) node; } FDCharDriver; @@ -1260,6 +1261,22 @@ static CharDriverState *qemu_chr_open_pty(const char *id, return chr; } +static int tty_serial_write(CharDriverState *chr, const uint8_t *buf, int len) +{ + FDCharDriver *s = chr->opaque; + uint32_t inflight = 0; + + qemu_chr_fe_ioctl(chr, CHR_IOCTL_SERIAL_TIOCOUTQ, &inflight); + if (inflight >= chr->maxqdepth) + return -EAGAIN; + + if (inflight + len > chr->maxqdepth) { + len = chr->maxqdepth - inflight; + } + + return io_channel_send(s->fd_out, buf, len); +} + static void tty_serial_init(int fd, int speed, int parity, int data_bits, int stop_bits) { @@ -1438,6 +1455,16 @@ static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg) ioctl(g_io_channel_unix_get_fd(s->fd_in), TIOCMSET, &targ); } break; + case CHR_IOCTL_SERIAL_TIOCOUTQ: + { + if (!s->tiocoutq_failed) + s->tiocoutq_failed = ioctl(g_io_channel_unix_get_fd(s->fd_in), + TIOCOUTQ, arg); + + if (s->tiocoutq_failed) + *(unsigned int *)arg = 0; + } + break; default: return -ENOTSUP; } @@ -1466,6 +1493,7 @@ static CharDriverState *qemu_chr_open_tty_fd(int fd) tty_serial_init(fd, 115200, 'N', 8, 1); chr = qemu_chr_open_fd(fd, fd); + chr->chr_write = tty_serial_write; chr->chr_ioctl = tty_serial_ioctl; chr->chr_close = qemu_chr_close_tty; return chr; @@ -3172,6 +3200,8 @@ static void qemu_chr_parse_serial(QemuOpts *opts, ChardevBackend *backend, } backend->serial = g_new0(ChardevHostdev, 1); backend->serial->device = g_strdup(device); + backend->serial->maxqdepth = + qemu_opt_get_number(opts, "maxqdepth", -1); } static void qemu_chr_parse_parallel(QemuOpts *opts, ChardevBackend *backend, @@ -3575,6 +3605,9 @@ QemuOptsList qemu_chardev_opts = { },{ .name = "size", .type = QEMU_OPT_SIZE, + },{ + .name = "maxqdepth", + .type = QEMU_OPT_NUMBER, }, { /* end of list */ } }, @@ -3653,6 +3686,7 @@ static CharDriverState *qmp_chardev_open_serial(ChardevHostdev *serial, Error **errp) { #ifdef HAVE_CHARDEV_TTY + CharDriverState *chr; int fd; fd = qmp_chardev_open_file_source(serial->device, O_RDWR, errp); @@ -3660,7 +3694,11 @@ static CharDriverState *qmp_chardev_open_serial(ChardevHostdev *serial, return NULL; } qemu_set_nonblock(fd); - return qemu_chr_open_tty_fd(fd); + chr = qemu_chr_open_tty_fd(fd); + if (chr) { + chr->maxqdepth = serial->maxqdepth; + } + return chr; #else error_setg(errp, "character device backend type 'serial' not supported"); return NULL; diff --git a/qemu-options.hx b/qemu-options.hx index e86cc24..c522f13 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1792,8 +1792,8 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev, #endif #if defined(__linux__) || defined(__sun__) || defined(__FreeBSD__) \ || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) - "-chardev serial,id=id,path=path[,mux=on|off]\n" - "-chardev tty,id=id,path=path[,mux=on|off]\n" + "-chardev serial,id=id,path=path[,mux=on|off][,maxqdepth=count]\n" + "-chardev tty,id=id,path=path[,mux=on|off][,maxqdepth=count]\n" #endif #if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__) "-chardev parallel,id=id,path=path[,mux=on|off]\n"