From 65f137c56ce51eacc709571714aee683c2ac9f90 Mon Sep 17 00:00:00 2001 From: Eric Pouech Date: Sun, 7 May 2006 14:10:36 +0200 Subject: [PATCH] ntdll/kernel32: SetCommState & IOCTL_SET_LINE_CONTROL - implemented ntdll's serial IOCTL SET_LINE_CONTROL - used this IOCTL in kernel32.SetCommState --- dlls/kernel/comm.c | 122 +++++--------------------------------------- dlls/ntdll/serial.c | 112 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 110 deletions(-) diff --git a/dlls/kernel/comm.c b/dlls/kernel/comm.c index a64156777e2..f9aeb2a851b 100644 --- a/dlls/kernel/comm.c +++ b/dlls/kernel/comm.c @@ -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 diff --git a/dlls/ntdll/serial.c b/dlls/ntdll/serial.c index 0a7e56a1db4..678b4fd6048 100644 --- a/dlls/ntdll/serial.c +++ b/dlls/ntdll/serial.c @@ -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)) {