From: Michael Tokarev <mjt@tls.msk.ru>
To: KVM list <kvm@vger.kernel.org>
Cc: "David S. Ahern" <daahern@cisco.com>,
Mark Marshall <mark.marshall60@ntlworld.com>,
Marcelo Tosatti <mtosatti@redhat.com>,
Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Subject: [PATCH, finally]: more about serial ports: do they even work?
Date: Thu, 05 Feb 2009 21:33:30 +0300 [thread overview]
Message-ID: <498B30FA.40800@msgid.tls.msk.ru> (raw)
In-Reply-To: <497E1B15.2090908@msgid.tls.msk.ru>
[-- Attachment #1: Type: text/plain, Size: 4194 bytes --]
Michael Tokarev wrote:
> After some debugging and debugging, with a help
> Hollis Blanchard on #kvm@freenode, I discovered
> that kvm (or, rather, qemu) does not work correctly
> with serial ports, at least on linux. One problem
> report has already here, author Cc'd -- see e.g.
> http://marc.info/?l=kvm&m=122995568009533&w=2 .
... [quoted in full below]...
Ok, It's a real shame to see SO many wrong attempts to
do it all, with so many idiotic mistakes all over...
But c'est la vie, it seems... ;)
So here we go. Attached is a patch that fixes two
problems with serial ports &qemu (yes it's a qemu
issue, and, as far as I can see, both probs were
here for a long time).
First is completely f*cked up flags reporting and
setup for TIOCMGET and TIOCMSET ioctls, where ALL
known flags were reported and set in case at least
one flag is set, misusing "if(a|b) foo" instead of
"if(a&b) foo" -- just a typo I assume, but heck of
a typo... ;)
And second - for TIOCMSET it preserves other, unknown
flags. Which fixes the problem that started it all,
since there was a bit set internally in kernel which,
when unset, makes serial port non-working, but TIOCMSET
dropped all "other" bits on the floor.
And for this second one, I'm still unsure. The patch
I'm sending only tries to remove TIOCM_DTR and _RTS
bits (RTS is useless since it's controlled by the connected
device, isn't it?), leaving all others, incl., say,
CAR, RI, CTS etc, in place. The question is -- some
of those bits are "input" lines, i.e., the ones controlled
by the attached device, and I don't know if all platforms
will ignore those instead of reporting error. I.e, maybe
filter also those who are known "inputs"? And while we're
at it, still, how about RTS?
Signed-off-By: Michael Tokarev <mjt@tls.msk.ru>
Thanks!
/ashamed mjt
--- original content follows ---
> Here's what's going on.
>
> When opening a host's port, kvm resets the status
> lines, doing this:
>
> ioctl(13, TIOCMGET, [TIOCM_DTR|TIOCM_RTS|TIOCM_CTS|TIOCM_DSR|0x4000])
> ioctl(13, TIOCMSET, [TIOCM_DTR|TIOCM_RTS])
>
> which results in the following set
>
> ioctl(13, TIOCMGET, [TIOCM_DTR|TIOCM_RTS|TIOCM_CTS|TIOCM_DSR])
>
> Note the difference between the default set and new one: the
> missing bit, 0x4000, which is unknown to strace(1) but is defined
> as TIOCM_OUT2 in linux headers.
>
> After that change (resetting the TIOCM_OUT2 bit), no writes
> to the serial port works anymore, they're all gets accepted
> by host kernel and are buffered in the kernel.
>
> After some time, when the kernel buffer fills up, and since
> the port (on host side) is opened in non-blocking mode, the
> writes starts returning EAGAIN, and kvm process starts
> endless loop, which were seen by David.
>
> Here's the trivial program to demonstrate the idea:
>
> ---- cut ---
> #include <sys/types.h>
> #include <unistd.h>
> #include <fcntl.h>
> #include <sys/ioctl.h>
> #include <termios.h>
>
> int main(int argc, char **argv) {
> fd = open("/dev/ttyS0", O_RDWR|O_NONBLOCK);
> fcntl(fd, F_SETFL, O_RDWR);
> x = TIOCM_DTR|TIOCM_RTS|TIOCM_CTS|TIOCM_DSR // |0x4000
> ;
> ioctl(fd, TIOCMSET, &x);
> ioctl(fd, TIOCMGET, &x);
> write(fd, "at\r", 3);
> read(fd, buf, 20);
> close(fd);
>
> return 0;
> }
> --- cut ---
>
>
> Run it under strace while a dialup modem is connected to /dev/ttyS0
> (i used this way for testing). It will stuck at read, and nothing
> will be written, even when write() will happily return 3. Un-comment
> the |0x4000 thing, and it will work.
>
> I'm not sure what should be done with this, and how much this is
> linux-specific. But it is obvious that bit (TIOCM_OUT2) should
> be left in-place (after which the thing works), at least on linux.
>
> Note that this bit is NOT shown in /proc/tty/driver/serial file
> (which shows other bits).
>
> Note also that this file (/proc/tty/driver/serial) helps to see
> if any write were performed: compare the counters. In 'tx'
> there's number of bytes actually sent to device, as opposed to
> accepted by the kernel. When you write something to /dev/ttyS0,
> that number increases, IF that something actually reached the
> device.
>
> Thanks.
>
> /mjt
[-- Attachment #2: qemu-serial.diff --]
[-- Type: text/x-patch, Size: 1513 bytes --]
--- kvm-83/qemu/qemu-char.c.orig 2009-01-13 16:29:42.000000000 +0300
+++ kvm-83/qemu/qemu-char.c 2009-02-05 21:19:35.972015110 +0300
@@ -1067,17 +1067,17 @@ static int tty_serial_ioctl(CharDriverSt
int *targ = (int *)arg;
ioctl(s->fd_in, TIOCMGET, &sarg);
*targ = 0;
- if (sarg | TIOCM_CTS)
+ if (sarg & TIOCM_CTS)
*targ |= CHR_TIOCM_CTS;
- if (sarg | TIOCM_CAR)
+ if (sarg & TIOCM_CAR)
*targ |= CHR_TIOCM_CAR;
- if (sarg | TIOCM_DSR)
+ if (sarg & TIOCM_DSR)
*targ |= CHR_TIOCM_DSR;
- if (sarg | TIOCM_RI)
+ if (sarg & TIOCM_RI)
*targ |= CHR_TIOCM_RI;
- if (sarg | TIOCM_DTR)
+ if (sarg & TIOCM_DTR)
*targ |= CHR_TIOCM_DTR;
- if (sarg | TIOCM_RTS)
+ if (sarg & TIOCM_RTS)
*targ |= CHR_TIOCM_RTS;
}
break;
@@ -1085,9 +1085,11 @@ static int tty_serial_ioctl(CharDriverSt
{
int sarg = *(int *)arg;
int targ = 0;
- if (sarg | CHR_TIOCM_DTR)
+ ioctl(s->fd_in, TIOCMGET, &targ);
+ targ &= ~(TIOCM_DTR|TIOCM_RTS);
+ if (sarg & CHR_TIOCM_DTR)
targ |= TIOCM_DTR;
- if (sarg | CHR_TIOCM_RTS)
+ if (sarg & CHR_TIOCM_RTS)
targ |= TIOCM_RTS;
ioctl(s->fd_in, TIOCMSET, &targ);
}
prev parent reply other threads:[~2009-02-05 18:33 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-01-26 20:20 more about serial ports: do they even work? Michael Tokarev
2009-01-26 20:39 ` Michael Tokarev
2009-02-02 21:27 ` David S. Ahern
2009-02-02 21:27 ` [Qemu-devel] " David S. Ahern
2009-02-02 21:32 ` Michael Tokarev
2009-02-02 21:32 ` [Qemu-devel] " Michael Tokarev
2009-02-02 21:36 ` David S. Ahern
2009-02-02 21:36 ` [Qemu-devel] " David S. Ahern
2009-02-03 8:13 ` Michael Tokarev
2009-02-03 8:13 ` [Qemu-devel] " Michael Tokarev
2009-02-03 8:41 ` Mark Marshall
2009-02-03 8:41 ` [Qemu-devel] " Mark Marshall
2009-02-04 8:09 ` Marcelo Tosatti
2009-02-04 8:09 ` [Qemu-devel] " Marcelo Tosatti
2009-02-04 8:37 ` Michael Tokarev
2009-02-04 8:37 ` [Qemu-devel] " Michael Tokarev
2009-02-04 8:52 ` Marcelo Tosatti
2009-02-04 8:52 ` [Qemu-devel] " Marcelo Tosatti
2009-02-04 8:56 ` Michael Tokarev
2009-02-04 8:56 ` [Qemu-devel] " Michael Tokarev
2009-02-04 11:09 ` Stefano Stabellini
2009-02-04 11:09 ` [Qemu-devel] " Stefano Stabellini
2009-02-05 18:36 ` David S. Ahern
2009-02-05 18:36 ` [Qemu-devel] " David S. Ahern
2009-02-05 20:50 ` Stefano Stabellini
2009-02-05 20:50 ` [Qemu-devel] " Stefano Stabellini
2009-02-04 11:17 ` Stefano Stabellini
2009-02-04 11:17 ` Stefano Stabellini
2009-02-05 18:33 ` Michael Tokarev [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=498B30FA.40800@msgid.tls.msk.ru \
--to=mjt@tls.msk.ru \
--cc=daahern@cisco.com \
--cc=kvm@vger.kernel.org \
--cc=mark.marshall60@ntlworld.com \
--cc=mtosatti@redhat.com \
--cc=stefano.stabellini@eu.citrix.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.