ntdll/kernel32: SetCommState & IOCTL_SET_LINE_CONTROL

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

View File

@ -984,11 +984,12 @@ static void dump_dcb(const DCB* lpdcb)
BOOL WINAPI SetCommState( HANDLE handle, LPDCB lpdcb)
{
struct termios port;
int fd, bytesize, stopbits;
int fd;
BOOL ret;
SERIAL_BAUD_RATE sbr;
SERIAL_BAUD_RATE sbr;
SERIAL_LINE_CONTROL slc;
if (lpdcb == NULL)
{
SetLastError(ERROR_INVALID_PARAMETER);
@ -997,9 +998,17 @@ BOOL WINAPI SetCommState( HANDLE handle, LPDCB lpdcb)
dump_dcb(lpdcb);
sbr.BaudRate = lpdcb->BaudRate;
slc.StopBits = lpdcb->StopBits;
slc.Parity = lpdcb->Parity;
slc.WordLength = lpdcb->ByteSize;
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;
fd = get_comm_fd( handle, FILE_READ_DATA );
if (fd < 0) return FALSE;
@ -1014,113 +1023,6 @@ BOOL WINAPI SetCommState( HANDLE handle, LPDCB lpdcb)
port.c_cc[VMIN] = 0;
port.c_cc[VTIME] = 1;
#ifdef IMAXBEL
port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK|IMAXBEL);
#else
port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK);
#endif
port.c_iflag |= (IGNBRK);
port.c_oflag &= ~(OPOST);
port.c_cflag &= ~(HUPCL);
port.c_cflag |= CLOCAL | CREAD;
port.c_lflag &= ~(ICANON|ECHO|ISIG);
port.c_lflag |= NOFLSH;
bytesize=lpdcb->ByteSize;
stopbits=lpdcb->StopBits;
#ifdef CMSPAR
port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
#else
port.c_cflag &= ~(PARENB | PARODD);
#endif
if (lpdcb->fParity)
port.c_iflag |= INPCK;
else
port.c_iflag &= ~INPCK;
switch (lpdcb->Parity) {
case NOPARITY:
break;
case ODDPARITY:
port.c_cflag |= (PARENB | PARODD);
break;
case EVENPARITY:
port.c_cflag |= PARENB;
break;
#ifdef CMSPAR
/* Linux defines mark/space (stick) parity */
case MARKPARITY:
port.c_cflag |= (PARENB | CMSPAR);
break;
case SPACEPARITY:
port.c_cflag |= (PARENB | PARODD | CMSPAR);
break;
#else
/* try the POSIX way */
case MARKPARITY:
if( stopbits == ONESTOPBIT) {
stopbits = TWOSTOPBITS;
port.c_iflag &= ~INPCK;
} else {
release_comm_fd( handle, fd );
ERR("Cannot set MARK Parity\n");
return FALSE;
}
break;
case SPACEPARITY:
if( bytesize < 8) {
bytesize +=1;
port.c_iflag &= ~INPCK;
} else {
release_comm_fd( handle, fd );
ERR("Cannot set SPACE Parity\n");
return FALSE;
}
break;
#endif
default:
release_comm_fd( handle, fd );
ERR("Parity\n");
return FALSE;
}
port.c_cflag &= ~CSIZE;
switch (bytesize) {
case 5:
port.c_cflag |= CS5;
break;
case 6:
port.c_cflag |= CS6;
break;
case 7:
port.c_cflag |= CS7;
break;
case 8:
port.c_cflag |= CS8;
break;
default:
release_comm_fd( handle, fd );
ERR("ByteSize\n");
return FALSE;
}
switch (stopbits) {
case ONESTOPBIT:
port.c_cflag &= ~CSTOPB;
break;
case ONE5STOPBITS: /* will be selected if bytesize is 5 */
case TWOSTOPBITS:
port.c_cflag |= CSTOPB;
break;
default:
release_comm_fd( handle, fd );
ERR("StopBits\n");
return FALSE;
}
#ifdef CRTSCTS
if ( lpdcb->fOutxCtsFlow ||
lpdcb->fRtsControl == RTS_CONTROL_HANDSHAKE

View File

@ -360,6 +360,112 @@ static NTSTATUS set_baud_rate(int fd, const SERIAL_BAUD_RATE* sbr)
return STATUS_SUCCESS;
}
static NTSTATUS set_line_control(int fd, const SERIAL_LINE_CONTROL* slc)
{
struct termios port;
unsigned bytesize, stopbits;
if (tcgetattr(fd, &port) == -1)
{
ERR("tcgetattr error '%s'\n", strerror(errno));
return FILE_GetNtStatus();
}
#ifdef IMAXBEL
port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK|IMAXBEL);
#else
port.c_iflag &= ~(ISTRIP|BRKINT|IGNCR|ICRNL|INLCR|PARMRK);
#endif
port.c_iflag |= IGNBRK | INPCK;
port.c_oflag &= ~(OPOST);
port.c_cflag &= ~(HUPCL);
port.c_cflag |= CLOCAL | CREAD;
port.c_lflag &= ~(ICANON|ECHO|ISIG);
port.c_lflag |= NOFLSH;
bytesize = slc->WordLength;
stopbits = slc->StopBits;
#ifdef CMSPAR
port.c_cflag &= ~(PARENB | PARODD | CMSPAR);
#else
port.c_cflag &= ~(PARENB | PARODD);
#endif
switch (slc->Parity)
{
case NOPARITY: port.c_iflag &= ~INPCK; break;
case ODDPARITY: port.c_cflag |= PARENB | PARODD; break;
case EVENPARITY: port.c_cflag |= PARENB; break;
#ifdef CMSPAR
/* Linux defines mark/space (stick) parity */
case MARKPARITY: port.c_cflag |= PARENB | CMSPAR; break;
case SPACEPARITY: port.c_cflag |= PARENB | PARODD | CMSPAR; break;
#else
/* try the POSIX way */
case MARKPARITY:
if (slc->StopBits == ONESTOPBIT)
{
stopbits = TWOSTOPBITS;
port.c_iflag &= ~INPCK;
}
else
{
ERR("Cannot set MARK Parity\n");
return STATUS_NOT_SUPPORTED;
}
break;
case SPACEPARITY:
if (slc->WordLength < 8)
{
bytesize +=1;
port.c_iflag &= ~INPCK;
}
else
{
ERR("Cannot set SPACE Parity\n");
return STATUS_NOT_SUPPORTED;
}
break;
#endif
default:
ERR("Parity\n");
return STATUS_NOT_SUPPORTED;
}
port.c_cflag &= ~CSIZE;
switch (bytesize)
{
case 5: port.c_cflag |= CS5; break;
case 6: port.c_cflag |= CS6; break;
case 7: port.c_cflag |= CS7; break;
case 8: port.c_cflag |= CS8; break;
default:
ERR("ByteSize\n");
return STATUS_NOT_SUPPORTED;
}
switch (stopbits)
{
case ONESTOPBIT: port.c_cflag &= ~CSTOPB; break;
case ONE5STOPBITS: /* will be selected if bytesize is 5 */
case TWOSTOPBITS: port.c_cflag |= CSTOPB; break;
default:
ERR("StopBits\n");
return STATUS_NOT_SUPPORTED;
}
/* otherwise it hangs with pending input*/
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;
@ -478,6 +584,12 @@ NTSTATUS COMM_DeviceIoControl(HANDLE hDevice,
status = STATUS_NOT_SUPPORTED;
#endif
break;
case IOCTL_SERIAL_SET_LINE_CONTROL:
if (lpInBuffer && nInBufferSize == sizeof(SERIAL_LINE_CONTROL))
status = set_line_control(fd, (const SERIAL_LINE_CONTROL*)lpInBuffer);
else
status = STATUS_INVALID_PARAMETER;
break;
case IOCTL_SERIAL_SET_WAIT_MASK:
if (lpInBuffer && nInBufferSize == sizeof(DWORD))
{