Eric Pouech : ntdll/kernel32: SetCommState & IOCTL_SET_LINE_CONTROL
Alexandre Julliard
julliard at wine.codeweavers.com
Tue May 9 14:15:42 CDT 2006
Module: wine
Branch: refs/heads/master
Commit: 65f137c56ce51eacc709571714aee683c2ac9f90
URL: http://source.winehq.org/git/?p=wine.git;a=commit;h=65f137c56ce51eacc709571714aee683c2ac9f90
Author: Eric Pouech <eric.pouech at wanadoo.fr>
Date: Sun May 7 14:10:36 2006 +0200
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 a641567..f9aeb2a 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,
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,
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 0a7e56a..678b4fd 100644
--- a/dlls/ntdll/serial.c
+++ b/dlls/ntdll/serial.c
@@ -360,6 +360,112 @@ #endif
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 @@ #else
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))
{
More information about the wine-cvs
mailing list