[1/2] server: Use tcdrain() instead of tcflush() to implement FlushFileBuffers() for a COM port. Take 2.

Dmitry Timoshkov dmitry at baikal.ru
Mon Aug 26 22:12:52 CDT 2013


Based on a patch of Wolfgang Walter.

MSDN for FlushFileBuffers says:
Flushes the buffers of a specified file and causes all buffered data to be
written to a file.

Linux man page says:
tcdrain() waits until all output written to the object referred to by fd has
been transmitted.
tcflush() discards data written to the object referred to by fd but not transmitted,
or data received but not read.

tcdrain() better matches the FlushFileBuffers() MSDN description, and this patch
allows Garmin MapSource to successfully download maps from the GPS device connected
via a USB-serial cable. Without this patch MapSource can't even see the device because
WriteFile() folowed by FlushFileBuffers() makes ClearCommError() return non-zero
AmountInOutQueue.

A simple program which does:

    fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NONBLOCK);
    write(fd, "\0\0\0\0\0\0\0", 7);
    tcflush(fd, TCOFLUSH);
    ioctl(fd, TIOCOUTQ, &out);
    printf("out queue %d bytes\n", out);
    close(fd);

prints "out queue 7 bytes".

After replacing tcflush() by tcdrain() it prints
"out queue 0 bytes".
---
 dlls/ntdll/file.c | 23 +++++++++++++++++++++++
 server/serial.c   | 11 +----------
 2 files changed, 24 insertions(+), 10 deletions(-)

diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 5147ef5..aedeb62 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -27,6 +27,9 @@
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif
+#ifdef HAVE_TERMIOS_H
+#include <termios.h>
+#endif
 #ifdef HAVE_LINUX_MAJOR_H
 # include <linux/major.h>
 #endif
@@ -2749,6 +2752,26 @@ NTSTATUS WINAPI NtFlushBuffersFile( HANDLE hFile, IO_STATUS_BLOCK* IoStatusBlock
 {
     NTSTATUS ret;
     HANDLE hEvent = NULL;
+    int fd, needs_close;
+    enum server_fd_type type;
+
+    if (!server_get_unix_fd( hFile, FILE_WRITE_DATA, &fd, &needs_close, &type, NULL ) &&
+        type == FD_TYPE_SERIAL)
+    {
+        ret = STATUS_SUCCESS;
+
+        while (tcdrain( fd ) == -1)
+        {
+            if (errno != EAGAIN && errno != EINTR)
+            {
+                ret = FILE_GetNtStatus();
+                break;
+            }
+        }
+
+        if (needs_close) close( fd );
+        return ret;
+    }
 
     SERVER_START_REQ( flush_file )
     {
diff --git a/server/serial.c b/server/serial.c
index 587fee1..aac20fa 100644
--- a/server/serial.c
+++ b/server/serial.c
@@ -61,7 +61,6 @@ static struct fd *serial_get_fd( struct object *obj );
 static void serial_destroy(struct object *obj);
 
 static enum server_fd_type serial_get_fd_type( struct fd *fd );
-static void serial_flush( struct fd *fd, struct event **event );
 static void serial_queue_async( struct fd *fd, const async_data_t *data, int type, int count );
 
 struct serial
@@ -107,7 +106,7 @@ static const struct fd_ops serial_fd_ops =
 {
     default_fd_get_poll_events,   /* get_poll_events */
     default_poll_event,           /* poll_event */
-    serial_flush,                 /* flush */
+    no_flush,                     /* flush */
     serial_get_fd_type,           /* get_fd_type */
     default_fd_ioctl,             /* ioctl */
     serial_queue_async,           /* queue_async */
@@ -196,14 +195,6 @@ static void serial_queue_async( struct fd *fd, const async_data_t *data, int typ
     }
 }
 
-static void serial_flush( struct fd *fd, struct event **event )
-{
-    /* MSDN says: If hFile is a handle to a communications device,
-     * the function only flushes the transmit buffer.
-     */
-    if (tcflush( get_unix_fd(fd), TCOFLUSH ) == -1) file_set_error();
-}
-
 DECL_HANDLER(get_serial_info)
 {
     struct serial *serial;
-- 
1.8.3.4




More information about the wine-patches mailing list