ntdll/kernel32: SetCommState & IOCTL_SET_CHARS

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

View File

@ -983,13 +983,10 @@ static void dump_dcb(const DCB* lpdcb)
*/
BOOL WINAPI SetCommState( HANDLE handle, LPDCB lpdcb)
{
struct termios port;
int fd;
BOOL ret;
SERIAL_BAUD_RATE sbr;
SERIAL_LINE_CONTROL slc;
SERIAL_HANDFLOW shf;
SERIAL_CHARS sc;
if (lpdcb == NULL)
{
@ -1040,44 +1037,24 @@ BOOL WINAPI SetCommState( HANDLE handle, LPDCB lpdcb)
shf.XonLimit = lpdcb->XonLim;
shf.XoffLimit = lpdcb->XoffLim;
sc.EofChar = lpdcb->EofChar;
sc.ErrorChar = lpdcb->ErrorChar;
sc.BreakChar = 0;
sc.EventChar = lpdcb->EvtChar;
sc.XonChar = lpdcb->XonChar;
sc.XoffChar = lpdcb->XoffChar;
/* 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;
if (!DeviceIoControl(handle, IOCTL_SERIAL_SET_LINE_CONTROL,
&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;
if ((tcgetattr(fd,&port)) == -1) {
int save_error = errno;
release_comm_fd( handle, fd );
ERR("tcgetattr error '%s'\n", strerror(save_error));
return FALSE;
}
port.c_cc[VMIN] = 0;
port.c_cc[VTIME] = 1;
if (tcsetattr(fd,TCSANOW,&port)==-1) { /* otherwise it hangs with pending input*/
ERR("tcsetattr error '%s'\n", strerror(errno));
ret = FALSE;
} else {
ClearCommError(handle, NULL, NULL);
ret = TRUE;
}
release_comm_fd( handle, fd );
return ret;
return (DeviceIoControl(handle, IOCTL_SERIAL_SET_BAUD_RATE,
&sbr, sizeof(sbr), NULL, 0, NULL, NULL) &&
DeviceIoControl(handle, IOCTL_SERIAL_SET_LINE_CONTROL,
&slc, sizeof(slc), NULL, 0, NULL, NULL) &&
DeviceIoControl(handle, IOCTL_SERIAL_SET_HANDFLOW,
&shf, sizeof(shf), NULL, 0, NULL, NULL) &&
DeviceIoControl(handle, IOCTL_SERIAL_SET_CHARS,
&sc, sizeof(sc), NULL, 0, NULL, NULL));
}

View File

@ -540,6 +540,34 @@ static NTSTATUS set_line_control(int fd, const SERIAL_LINE_CONTROL* slc)
return STATUS_SUCCESS;
}
static NTSTATUS set_special_chars(int fd, const SERIAL_CHARS* sc)
{
struct termios port;
if (tcgetattr(fd, &port) == -1)
{
ERR("tcgetattr error '%s'\n", strerror(errno));
return FILE_GetNtStatus();
}
port.c_cc[VMIN ] = 0;
port.c_cc[VTIME ] = 1;
port.c_cc[VEOF ] = sc->EofChar;
/* FIXME: sc->ErrorChar is not supported */
/* FIXME: sc->BreakChar is not supported */
/* FIXME: sc->EventChar is not supported */
port.c_cc[VSTART] = sc->XonChar;
port.c_cc[VSTOP ] = sc->XoffChar;
if (tcsetattr(fd, TCSANOW, &port) == -1)
{
ERR("tcsetattr error '%s'\n", strerror(errno));
return FILE_GetNtStatus();
}
return STATUS_SUCCESS;
}
static NTSTATUS set_wait_mask(HANDLE hDevice, DWORD mask)
{
NTSTATUS status;
@ -658,6 +686,12 @@ NTSTATUS COMM_DeviceIoControl(HANDLE hDevice,
status = STATUS_NOT_SUPPORTED;
#endif
break;
case IOCTL_SERIAL_SET_CHARS:
if (lpInBuffer && nInBufferSize == sizeof(SERIAL_CHARS))
status = set_special_chars(fd, (const SERIAL_CHARS*)lpInBuffer);
else
status = STATUS_INVALID_PARAMETER;
break;
case IOCTL_SERIAL_SET_HANDFLOW:
if (lpInBuffer && nInBufferSize == sizeof(SERIAL_HANDFLOW))
status = set_handflow(fd, (const SERIAL_HANDFLOW*)lpInBuffer);