Eric Pouech : ntdll/kernel32: SetCommState & IOCTL_SET_HANDFLOW
Alexandre Julliard
julliard at wine.codeweavers.com
Tue May 9 14:15:44 CDT 2006
Module: wine
Branch: refs/heads/master
Commit: b68203ea90464eddddf43ef6521303b2b1da32e8
URL: http://source.winehq.org/git/?p=wine.git;a=commit;h=b68203ea90464eddddf43ef6521303b2b1da32e8
Author: Eric Pouech <eric.pouech at wanadoo.fr>
Date: Sun May 7 14:10:39 2006 +0200
ntdll/kernel32: SetCommState & IOCTL_SET_HANDFLOW
- implemented ntdll's serial IOCTL SET_HANDFLOW
- used this IOCTL in kernel32.SetCommState
---
dlls/kernel/comm.c | 85 ++++++++++++++++++++++++++-------------------------
dlls/ntdll/serial.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 124 insertions(+), 41 deletions(-)
diff --git a/dlls/kernel/comm.c b/dlls/kernel/comm.c
index f9aeb2a..58e1b13 100644
--- a/dlls/kernel/comm.c
+++ b/dlls/kernel/comm.c
@@ -989,6 +989,7 @@ BOOL WINAPI SetCommState( HANDLE handle,
SERIAL_BAUD_RATE sbr;
SERIAL_LINE_CONTROL slc;
+ SERIAL_HANDFLOW shf;
if (lpdcb == NULL)
{
@@ -1003,6 +1004,45 @@ BOOL WINAPI SetCommState( HANDLE handle,
slc.Parity = lpdcb->Parity;
slc.WordLength = lpdcb->ByteSize;
+ shf.ControlHandShake = 0;
+ shf.FlowReplace = 0;
+ if (lpdcb->fOutxCtsFlow) shf.ControlHandShake |= SERIAL_CTS_HANDSHAKE;
+ if (lpdcb->fOutxDsrFlow) shf.ControlHandShake |= SERIAL_DSR_HANDSHAKE;
+ switch (lpdcb->fDtrControl)
+ {
+ case DTR_CONTROL_DISABLE: break;
+ case DTR_CONTROL_ENABLE: shf.ControlHandShake |= SERIAL_DTR_CONTROL; break;
+ case DTR_CONTROL_HANDSHAKE: shf.ControlHandShake |= SERIAL_DTR_HANDSHAKE;break;
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ switch (lpdcb->fDtrControl)
+ {
+ case RTS_CONTROL_DISABLE: break;
+ case RTS_CONTROL_ENABLE: shf.FlowReplace |= SERIAL_RTS_CONTROL; break;
+ case RTS_CONTROL_HANDSHAKE: shf.FlowReplace |= SERIAL_RTS_HANDSHAKE; break;
+ case RTS_CONTROL_TOGGLE: shf.FlowReplace |= SERIAL_RTS_CONTROL |
+ SERIAL_RTS_HANDSHAKE; break;
+ default:
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ if (lpdcb->fDsrSensitivity) shf.ControlHandShake |= SERIAL_DSR_SENSITIVITY;
+ if (lpdcb->fAbortOnError) shf.ControlHandShake |= SERIAL_ERROR_ABORT;
+
+ if (lpdcb->fErrorChar) shf.FlowReplace |= SERIAL_ERROR_CHAR;
+ if (lpdcb->fNull) shf.FlowReplace |= SERIAL_NULL_STRIPPING;
+ if (lpdcb->fTXContinueOnXoff) shf.FlowReplace |= SERIAL_XOFF_CONTINUE;
+ if (lpdcb->fOutX) shf.FlowReplace |= SERIAL_AUTO_TRANSMIT;
+ if (lpdcb->fInX) shf.FlowReplace |= SERIAL_AUTO_RECEIVE;
+
+ shf.XonLimit = lpdcb->XonLim;
+ shf.XoffLimit = lpdcb->XoffLim;
+
+ /* note: change DTR/RTS lines after setting the comm attributes,
+ * so flow control does not interfere.
+ */
if (!DeviceIoControl(handle, IOCTL_SERIAL_SET_BAUD_RATE,
&sbr, sizeof(sbr), NULL, 0, NULL, NULL))
return FALSE;
@@ -1010,6 +1050,10 @@ BOOL WINAPI SetCommState( HANDLE handle,
&slc, sizeof(slc), NULL, 0, NULL, NULL))
return FALSE;
+ if (!DeviceIoControl(handle, IOCTL_SERIAL_SET_HANDFLOW,
+ &shf, sizeof(shf), NULL, 0, NULL, NULL))
+ return FALSE;
+
fd = get_comm_fd( handle, FILE_READ_DATA );
if (fd < 0) return FALSE;
@@ -1023,25 +1067,6 @@ BOOL WINAPI SetCommState( HANDLE handle,
port.c_cc[VMIN] = 0;
port.c_cc[VTIME] = 1;
-#ifdef CRTSCTS
- if ( lpdcb->fOutxCtsFlow ||
- lpdcb->fRtsControl == RTS_CONTROL_HANDSHAKE
- )
- {
- port.c_cflag |= CRTSCTS;
- TRACE("CRTSCTS\n");
- }
-#endif
-
- if (lpdcb->fInX)
- port.c_iflag |= IXON;
- else
- port.c_iflag &= ~IXON;
- if (lpdcb->fOutX)
- port.c_iflag |= IXOFF;
- else
- port.c_iflag &= ~IXOFF;
-
if (tcsetattr(fd,TCSANOW,&port)==-1) { /* otherwise it hangs with pending input*/
ERR("tcsetattr error '%s'\n", strerror(errno));
ret = FALSE;
@@ -1050,28 +1075,6 @@ #endif
ret = TRUE;
}
- /* note: change DTR/RTS lines after setting the comm attributes,
- * so flow control does not interfere. */
-#ifdef TIOCM_DTR
- if (lpdcb->fDtrControl == DTR_CONTROL_HANDSHAKE)
- {
- WARN("DSR/DTR flow control not supported\n");
- } else if(lpdcb->fDtrControl == DTR_CONTROL_DISABLE)
- COMM_WhackModem(fd, ~TIOCM_DTR, 0);
- else
- COMM_WhackModem(fd, 0, TIOCM_DTR);
-#endif
-#ifdef TIOCM_RTS
- if(!lpdcb->fOutxCtsFlow )
- {
- if(lpdcb->fRtsControl == RTS_CONTROL_DISABLE)
- COMM_WhackModem(fd, ~TIOCM_RTS, 0);
- else
- COMM_WhackModem(fd, 0, TIOCM_RTS);
- }
-#endif
- if(lpdcb->fRtsControl == RTS_CONTROL_TOGGLE)
- FIXME("RTS_CONTROL_TOGGLE is not supported.\n");
release_comm_fd( handle, fd );
return ret;
diff --git a/dlls/ntdll/serial.c b/dlls/ntdll/serial.c
index 678b4fd..0225ba8 100644
--- a/dlls/ntdll/serial.c
+++ b/dlls/ntdll/serial.c
@@ -360,6 +360,80 @@ #endif
return STATUS_SUCCESS;
}
+static int whack_modem(int fd, unsigned int andy, unsigned int orrie)
+{
+#ifdef TIOCMGET
+ unsigned int mstat, okay;
+ okay = ioctl(fd, TIOCMGET, &mstat);
+ if (okay) return okay;
+ if (andy) mstat &= andy;
+ mstat |= orrie;
+ return ioctl(fd, TIOCMSET, &mstat);
+#else
+ return 0;
+#endif
+}
+
+static NTSTATUS set_handflow(int fd, const SERIAL_HANDFLOW* shf)
+{
+ struct termios port;
+
+ if ((shf->FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE)) ==
+ (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE))
+ return STATUS_NOT_SUPPORTED;
+
+ if (tcgetattr(fd, &port) == -1)
+ {
+ ERR("tcgetattr error '%s'\n", strerror(errno));
+ return FILE_GetNtStatus();
+ }
+
+#ifdef CRTSCTS
+ if ((shf->ControlHandShake & SERIAL_CTS_HANDSHAKE) ||
+ (shf->FlowReplace & SERIAL_RTS_HANDSHAKE))
+ {
+ port.c_cflag |= CRTSCTS;
+ TRACE("CRTSCTS\n");
+ }
+ else
+ port.c_cflag &= ~CRTSCTS;
+#endif
+#ifdef TIOCM_DTR
+ if (shf->ControlHandShake & SERIAL_DTR_HANDSHAKE)
+ {
+ WARN("DSR/DTR flow control not supported\n");
+ } else if (shf->ControlHandShake & SERIAL_DTR_CONTROL)
+ whack_modem(fd, ~TIOCM_DTR, 0);
+ else
+ whack_modem(fd, 0, TIOCM_DTR);
+#endif
+#ifdef TIOCM_RTS
+ if (!(shf->ControlHandShake & SERIAL_DSR_HANDSHAKE))
+ {
+ if ((shf->FlowReplace & (SERIAL_RTS_CONTROL|SERIAL_RTS_HANDSHAKE)) == 0)
+ whack_modem(fd, ~TIOCM_RTS, 0);
+ else
+ whack_modem(fd, 0, TIOCM_RTS);
+ }
+#endif
+
+ if (shf->FlowReplace & SERIAL_AUTO_RECEIVE)
+ port.c_iflag |= IXON;
+ else
+ port.c_iflag &= ~IXON;
+ if (shf->FlowReplace & SERIAL_AUTO_TRANSMIT)
+ port.c_iflag |= IXOFF;
+ else
+ port.c_iflag &= ~IXOFF;
+ if (tcsetattr(fd, TCSANOW, &port) == -1)
+ {
+ ERR("tcsetattr error '%s'\n", strerror(errno));
+ return FILE_GetNtStatus();
+ }
+
+ return STATUS_SUCCESS;
+}
+
static NTSTATUS set_line_control(int fd, const SERIAL_LINE_CONTROL* slc)
{
struct termios port;
@@ -584,6 +658,12 @@ #else
status = STATUS_NOT_SUPPORTED;
#endif
break;
+ case IOCTL_SERIAL_SET_HANDFLOW:
+ if (lpInBuffer && nInBufferSize == sizeof(SERIAL_HANDFLOW))
+ status = set_handflow(fd, (const SERIAL_HANDFLOW*)lpInBuffer);
+ else
+ status = STATUS_INVALID_PARAMETER;
+ break;
case IOCTL_SERIAL_SET_LINE_CONTROL:
if (lpInBuffer && nInBufferSize == sizeof(SERIAL_LINE_CONTROL))
status = set_line_control(fd, (const SERIAL_LINE_CONTROL*)lpInBuffer);
More information about the wine-cvs
mailing list