Stop flooding with EV_TXEMPTY and EV_RXCHAR
Michael Karcher
wine at mkarcher.dialup.fu-berlin.de
Sun May 11 11:27:47 CDT 2008
Do not generate an EV_TXEMPTY event if the transmitter is empty,
but if it got empty. Do not generate a EV_RXCHAR event if some
bytes are in the queue, but if some new bytes got into the queue.
Handle a Linux quirk that TIOCGICOUNT might report characters that
TIOCINQ does not yet report.
Add some further TRACE calls to aid debugging.
---
dlls/ntdll/serial.c | 57 ++++++++++++++++++++++++++++++++------------------
1 files changed, 36 insertions(+), 21 deletions(-)
diff --git a/dlls/ntdll/serial.c b/dlls/ntdll/serial.c
index bdb47e4..78dd2f9 100644
--- a/dlls/ntdll/serial.c
+++ b/dlls/ntdll/serial.c
@@ -366,6 +366,7 @@ static NTSTATUS get_status(int fd, SERIAL_STATUS* ss)
#else
ss->AmountInInQueue = 0; /* FIXME: find a different way to find out */
#endif
+ TRACE("In: %d, Out: %d\n",ss->AmountInInQueue, ss->AmountInOutQueue);
return status;
}
@@ -848,7 +849,7 @@ static NTSTATUS set_XOn(int fd)
*/
typedef struct serial_irq_info
{
- int rx , tx, frame, overrun, parity, brk, buf_overrun;
+ int rx , tx, hardtx, frame, overrun, parity, brk, buf_overrun;
}serial_irq_info;
/***********************************************************************
@@ -874,6 +875,7 @@ static NTSTATUS get_irq_info(int fd, serial_irq_info *irq_info)
struct serial_icounter_struct einfo;
if (!ioctl(fd, TIOCGICOUNT, &einfo))
{
+ int queue;
irq_info->rx = einfo.rx;
irq_info->tx = einfo.tx;
irq_info->frame = einfo.frame;
@@ -881,6 +883,27 @@ static NTSTATUS get_irq_info(int fd, serial_irq_info *irq_info)
irq_info->parity = einfo.parity;
irq_info->brk = einfo.brk;
irq_info->buf_overrun = einfo.buf_overrun;
+/* We really want to know when all characters have gone out of the transmitter */
+#if defined(TIOCSERGETLSR)
+ /* TIOCSERGETLSR strangely just returns the transmitter-shift-reg
+ empty bit, currently on bit position 0. The ioctl() name is
+ misleading */
+ if (ioctl(fd, TIOCSERGETLSR, &queue))
+ WARN("TIOCSERGETLSR returned error\n");
+ else
+ if(!queue) /* NOT empty */
+ queue = 1;
+ else /* empty */
+ queue = 0;
+/* TIOCOUTQ only checks for an empty buffer */
+#elif defined(TIOCOUTQ)
+ if (ioctl(fd, TIOCOUTQ, &queue))
+ {
+ WARN("TIOCOUTQ returned error\n");
+ queue = 0;
+ }
+#endif
+ irq_info->hardtx = irq_info->tx - queue;
return STATUS_SUCCESS;
}
TRACE("TIOCGICOUNT err %s\n", strerror(errno));
@@ -892,7 +915,7 @@ static NTSTATUS get_irq_info(int fd, serial_irq_info *irq_info)
static DWORD WINAPI check_events(int fd, DWORD mask,
- const serial_irq_info *new,
+ serial_irq_info *new,
const serial_irq_info *old,
DWORD new_mstat, DWORD old_mstat)
{
@@ -901,6 +924,7 @@ static DWORD WINAPI check_events(int fd, DWORD mask,
TRACE("mask 0x%08x\n", mask);
TRACE("old->rx 0x%08x vs. new->rx 0x%08x\n", old->rx, new->rx);
TRACE("old->tx 0x%08x vs. new->tx 0x%08x\n", old->tx, new->tx);
+ TRACE("old->hardtx 0x%08x vs. new->hardtx 0x%08x\n", old->hardtx, new->hardtx);
TRACE("old->frame 0x%08x vs. new->frame 0x%08x\n", old->frame, new->frame);
TRACE("old->overrun 0x%08x vs. new->overrun 0x%08x\n", old->overrun, new->overrun);
TRACE("old->parity 0x%08x vs. new->parity 0x%08x\n", old->parity, new->parity);
@@ -908,12 +932,13 @@ static DWORD WINAPI check_events(int fd, DWORD mask,
TRACE("old->buf_overrun 0x%08x vs. new->buf_overrun 0x%08x\n", old->buf_overrun, new->buf_overrun);
if (old->brk != new->brk) ret |= EV_BREAK;
+ if (old->hardtx != new->hardtx) ret |= EV_TXEMPTY;
if ((old_mstat & MS_CTS_ON ) != (new_mstat & MS_CTS_ON )) ret |= EV_CTS;
if ((old_mstat & MS_DSR_ON ) != (new_mstat & MS_DSR_ON )) ret |= EV_DSR;
if ((old_mstat & MS_RING_ON) != (new_mstat & MS_RING_ON)) ret |= EV_RING;
if ((old_mstat & MS_RLSD_ON) != (new_mstat & MS_RLSD_ON)) ret |= EV_RLSD;
if (old->frame != new->frame || old->overrun != new->overrun || old->parity != new->parity) ret |= EV_ERR;
- if (mask & EV_RXCHAR)
+ if (old->rx != new->rx && mask & EV_RXCHAR)
{
queue = 0;
#ifdef TIOCINQ
@@ -922,25 +947,15 @@ static DWORD WINAPI check_events(int fd, DWORD mask,
#endif
if (queue)
ret |= EV_RXCHAR;
+ else
+ {
+ /* Maybe, the read characters did not reach the queue yet.
+ This *does* happen on Linux! */
+ TRACE("Delaying RX_CHAR event due to empty input queue\n");
+ new->rx = old->rx;
+ }
}
- if (mask & EV_TXEMPTY)
- {
- queue = 0;
-/* We really want to know when all characters have gone out of the transmitter */
-#if defined(TIOCSERGETLSR)
- if (ioctl(fd, TIOCSERGETLSR, &queue))
- WARN("TIOCSERGETLSR returned error\n");
- if (queue)
-/* TIOCOUTQ only checks for an empty buffer */
-#elif defined(TIOCOUTQ)
- if (ioctl(fd, TIOCOUTQ, &queue))
- WARN("TIOCOUTQ returned error\n");
- if (!queue)
-#endif
- ret |= EV_TXEMPTY;
- TRACE("OUTQUEUE %d, Transmitter %sempty\n",
- queue, (ret & EV_TXEMPTY) ? "" : "not ");
- }
+ TRACE("ret=%03x\n",ret);
return ret & mask;
}
--
1.5.5.1
More information about the wine-patches
mailing list