ntdll/kernel32: SetCommState & IOCTL_SET_HANDFLOW

- implemented ntdll's serial IOCTL SET_HANDFLOW
- used this IOCTL in kernel32.SetCommState
This commit is contained in:
Eric Pouech 2006-05-07 14:10:39 +02:00 committed by Alexandre Julliard
parent 65f137c56c
commit b68203ea90
2 changed files with 124 additions and 41 deletions

View File

@ -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;

View File

@ -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);