Hello,

I made similar changes so that several applications we use work. I tested your 
patches, all but one do work. I don't know why one does not, though.

I attached my patch, maybe it is usefull to you.

Regards,
-- 
Wolfgang Walter
Studentenwerk München
Anstalt des öffentlichen Rechts
Abteilungsleiter IT
Leopoldstraße 15
80802 München
>From de0a36a35e36c3d5033fbf7c6593768a8f676844 Mon Sep 17 00:00:00 2001
From: Wolfgang Walter <w...@stwm.de>
Date: Mon, 28 Sep 2009 15:52:32 +0200
Subject: [PATCH] improve handling of usb2serial adapters

wine does not handle most usb2serial adapters very well.

wine decides at compile time if it expects serial interfaces
to support TIOCGICOUNT and TIOCSERGETLSR.

On linux a lot of device drivers of serial use2serial-adapters
don't suport those ioctls.

This patch tries to handle those devices as if
TIOCGICOUNT and TIOCSERGETLSR were not supported by the OS.
---
 dlls/ntdll/serial.c |  132 +++++++++++++++++++++++++++++++--------------------
 1 file changed, 81 insertions(+), 51 deletions(-)

diff --git a/dlls/ntdll/serial.c b/dlls/ntdll/serial.c
index 5551b3c..c00b6a5 100644
--- a/dlls/ntdll/serial.c
+++ b/dlls/ntdll/serial.c
@@ -804,6 +804,7 @@ typedef struct async_commio
  */
 static NTSTATUS get_irq_info(int fd, serial_irq_info *irq_info)
 {
+    NTSTATUS status = STATUS_NOT_IMPLEMENTED;
 #ifdef TIOCGICOUNT
     struct serial_icounter_struct einfo;
     if (!ioctl(fd, TIOCGICOUNT, &einfo))
@@ -815,47 +816,29 @@ 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;
+        return STATUS_SUCCESS;
     }
-    else
-    {
-        TRACE("TIOCGICOUNT err %s\n", strerror(errno));
-        memset(irq_info,0, sizeof(serial_irq_info));
-        return FILE_GetNtStatus();
-    }
-#else
-    memset(irq_info,0, sizeof(serial_irq_info));
-    return STATUS_NOT_IMPLEMENTED;
-#endif
-    irq_info->temt = 0;
-    /* Generate a single TX_TXEMPTY event when the TX Buffer turns empty*/
-#ifdef TIOCSERGETLSR  /* prefer to log the state TIOCSERGETLSR */
-    if (ioctl(fd, TIOCSERGETLSR, &irq_info->temt))
-    {
-        TRACE("TIOCSERGETLSR err %s\n", strerror(errno));
-        return FILE_GetNtStatus();
-    }
-#elif defined(TIOCOUTQ)  /* otherwise we log when the out queue gets empty */
-    if (ioctl(fd, TIOCOUTQ, &irq_info->temt))
-    {
-        TRACE("TIOCOUTQ err %s\n", strerror(errno));
-        return FILE_GetNtStatus();
-    }
-    else
-    {
-        if (irq_info->temt == 0)
-            irq_info->temt = 1;
-    }
+    TRACE("TIOCGICOUNT err %s\n", strerror(errno));
+    /* EINVAL means: TIOCGICOUNT is not supported by serial driver
+     * in this case behave as if TIOCGICOUNT is not defined by OS
+     */
+    if (errno != EINVAL)
+        status = FILE_GetNtStatus();
 #endif
-    return STATUS_SUCCESS;
+    memset(irq_info,0, sizeof(serial_irq_info));
+    return status;
 }
 
 
-static DWORD check_events(int fd, DWORD mask,
+static NTSTATUS check_events(int fd, DWORD mask,
                           const serial_irq_info *new,
                           const serial_irq_info *old,
-                          DWORD new_mstat, DWORD old_mstat)
+                          DWORD new_mstat, DWORD old_mstat, DWORD *ret)
 {
-    DWORD ret = 0, queue;
+    DWORD queue;
+    NTSTATUS status = STATUS_SUCCESS;
+
+    *ret = 0;
 
     TRACE("mask 0x%08x\n", mask);
     TRACE("old->rx          0x%08x vs. new->rx          0x%08x\n", old->rx, new->rx);
@@ -866,28 +849,67 @@ static DWORD check_events(int fd, DWORD mask,
     TRACE("old->brk         0x%08x vs. new->brk         0x%08x\n", old->brk, new->brk);
     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_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 (old->brk != new->brk) *ret |= EV_BREAK;
+    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)
     {
 	queue = 0;
 #ifdef TIOCINQ
 	if (ioctl(fd, TIOCINQ, &queue))
-	    WARN("TIOCINQ returned error\n");
+        {
+            if (errno != EINVAL)
+            {
+                status = FILE_GetNtStatus();
+                WARN("TIOCINQ returned error\n");
+                return status;
+            }
+        }
 #endif
 	if (queue)
-	    ret |= EV_RXCHAR;
+	    *ret |= EV_RXCHAR;
     }
     if (mask & EV_TXEMPTY)
     {
-        if (!old->temt && new->temt)
-            ret |= EV_TXEMPTY;
+        int err = EINVAL;
+	queue = 0;
+/* We really want to know when all characters have gone out of the transmitter
+ * TIOCSERGETLSR is not supported by many drivers, so ignore EINVAL in this case
+ * and fallback to TIOCOUTQ
+ */
+#if defined(TIOCSERGETLSR) 
+        if (!ioctl(fd, TIOCSERGETLSR, &queue))
+        {
+            queue = !queue;
+            err = 0;
+        }
+        else
+        {
+            queue = 0;
+            err = errno;
+        }
+#endif
+#if defined(TIOCOUTQ)
+/* TIOCOUTQ only checks for an empty buffer */
+        if (err == EINVAL && ioctl(fd, TIOCOUTQ, &queue))
+            err = errno;
+#endif
+        if (err && err != EINVAL)
+        {
+            status = FILE_GetNtStatus();
+            WARN("TIOCSERGETLSR/TIOCOUTQ returned error\n");
+            return status;
+        }
+	if (!queue)
+            *ret |= EV_TXEMPTY;
+	TRACE("OUTQUEUE %d, Transmitter %sempty\n",
+              queue, (*ret & EV_TXEMPTY) ? "" : "not ");
     }
-    return ret & mask;
+    *ret &= mask;
+    return status;
 }
 
 /***********************************************************************
@@ -901,6 +923,7 @@ static DWORD CALLBACK wait_for_event(LPVOID arg)
 {
     async_commio *commio = arg;
     int fd, needs_close;
+    NTSTATUS status;
 
     if (!server_get_unix_fd( commio->hDevice, FILE_READ_DATA | FILE_WRITE_DATA, &fd, &needs_close, NULL, NULL ))
     {
@@ -922,12 +945,16 @@ static DWORD CALLBACK wait_for_event(LPVOID arg)
              * We don't handle the EV_RXFLAG (the eventchar)
              */
             NtDelayExecution(FALSE, &time);
-            get_irq_info(fd, &new_irq_info);
+            status = get_irq_info(fd, &new_irq_info);
+            if (status && status != STATUS_NOT_IMPLEMENTED)
+                TRACE("get_irq_status failed\n");
             if (get_modem_status(fd, &new_mstat))
                 TRACE("get_modem_status failed\n");
-            *commio->events = check_events(fd, commio->evtmask,
-                                           &new_irq_info, &commio->irq_info,
-                                           new_mstat, commio->mstat);
+            status = check_events(fd, commio->evtmask,
+                                  &new_irq_info, &commio->irq_info,
+                                  new_mstat, commio->mstat, commio->events);
+            if (status)
+                TRACE("check_events failed\n");
             if (*commio->events) break;
             get_wait_mask(commio->hDevice, &new_evtmask);
             if (commio->evtmask != new_evtmask)
@@ -996,6 +1023,7 @@ static NTSTATUS wait_on(HANDLE hDevice, int fd, HANDLE hEvent, PIO_STATUS_BLOCK
 	FIXME("EV_RXFLAG not handled\n");
 
     if ((status = get_irq_info(fd, &commio->irq_info)) &&
+        ! (status == STATUS_NOT_IMPLEMENTED && (commio->evtmask & (EV_RXCHAR|EV_TXEMPTY))) &&
         (commio->evtmask & (EV_BREAK | EV_ERR)))
 	goto out_now;
 
@@ -1004,9 +1032,11 @@ static NTSTATUS wait_on(HANDLE hDevice, int fd, HANDLE hEvent, PIO_STATUS_BLOCK
 	goto out_now;
 
     /* We might have received something or the TX buffer is delivered */
-    *events = check_events(fd, commio->evtmask,
-                               &commio->irq_info, &commio->irq_info,
-                               commio->mstat, commio->mstat);
+    status = check_events(fd, commio->evtmask,
+                              &commio->irq_info, &commio->irq_info,
+                              commio->mstat, commio->mstat, events);
+    if (status)
+        goto out_now;
     if (*events)
     {
         status = STATUS_SUCCESS;
-- 
1.7.10.4



Reply via email to