From b68203ea90464eddddf43ef6521303b2b1da32e8 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Sun, 7 May 2006 14:10:39 +0200 Subject: [PATCH] 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 f9aeb2a851..58e1b13ca7 100644 --- a/dlls/kernel/comm.c +++ b/dlls/kernel/comm.c @@ -989,6 +989,7 @@ BOOL WINAPI SetCommState( HANDLE handle, LPDCB lpdcb) SERIAL_BAUD_RATE sbr; SERIAL_LINE_CONTROL slc; + SERIAL_HANDFLOW shf; if (lpdcb == NULL) { @@ -1003,6 +1004,45 @@ BOOL WINAPI SetCommState( HANDLE handle, LPDCB lpdcb) 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, LPDCB lpdcb) &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, LPDCB lpdcb) 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 @@ BOOL WINAPI SetCommState( HANDLE handle, LPDCB lpdcb) 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 678b4fd604..0225ba82c1 100644 --- a/dlls/ntdll/serial.c +++ b/dlls/ntdll/serial.c @@ -360,6 +360,80 @@ static NTSTATUS set_baud_rate(int fd, const SERIAL_BAUD_RATE* sbr) 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 @@ NTSTATUS COMM_DeviceIoControl(HANDLE hDevice, 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);