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