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_CTS_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 |= IXOFF; else port.c_iflag &= ~IXOFF; if (shf->FlowReplace & SERIAL_AUTO_TRANSMIT) port.c_iflag |= IXON; else port.c_iflag &= ~IXON; if (tcsetattr(fd, TCSANOW, &port) == -1) { ERR("tcsetattr error '%s'\n", strerror(errno)); return FILE_GetNtStatus(); } return STATUS_SUCCESS; }
/****************************************************************** * COMM_DeviceIoControl * * */ NTSTATUS COMM_DeviceIoControl(HANDLE hDevice, HANDLE hEvent, PIO_APC_ROUTINE UserApcRoutine, PVOID UserApcContext, PIO_STATUS_BLOCK piosb, ULONG dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize) { DWORD sz = 0, access = FILE_READ_DATA; NTSTATUS status = STATUS_SUCCESS; int fd = -1; TRACE("%p %s %p %ld %p %ld %p\n", hDevice, iocode2str(dwIoControlCode), lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, piosb); piosb->Information = 0; if (dwIoControlCode != IOCTL_SERIAL_GET_TIMEOUTS) if ((status = wine_server_handle_to_fd( hDevice, access, &fd, NULL ))) goto error; switch (dwIoControlCode) { case IOCTL_SERIAL_CLR_DTR: #ifdef TIOCM_DTR if (whack_modem(fd, ~TIOCM_DTR, 0) == -1) status = FILE_GetNtStatus(); #else status = STATUS_NOT_SUPPORTED; #endif break; case IOCTL_SERIAL_CLR_RTS: #ifdef TIOCM_RTS if (whack_modem(fd, ~TIOCM_RTS, 0) == -1) status = FILE_GetNtStatus(); #else status = STATUS_NOT_SUPPORTED; #endif break; case IOCTL_SERIAL_GET_BAUD_RATE: if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_BAUD_RATE)) { if (!(status = get_baud_rate(fd, (SERIAL_BAUD_RATE*)lpOutBuffer))) sz = sizeof(SERIAL_BAUD_RATE); } else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_GET_CHARS: if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_CHARS)) { if (!(status = get_special_chars(fd, (SERIAL_CHARS*)lpOutBuffer))) sz = sizeof(SERIAL_CHARS); } else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_GET_COMMSTATUS: if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_STATUS)) { if (!(status = get_status(fd, (SERIAL_STATUS*)lpOutBuffer))) sz = sizeof(SERIAL_STATUS); } else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_GET_HANDFLOW: if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_HANDFLOW)) { if (!(status = get_hand_flow(fd, (SERIAL_HANDFLOW*)lpOutBuffer))) sz = sizeof(SERIAL_HANDFLOW); } else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_GET_LINE_CONTROL: if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_LINE_CONTROL)) { if (!(status = get_line_control(fd, (SERIAL_LINE_CONTROL*)lpOutBuffer))) sz = sizeof(SERIAL_LINE_CONTROL); } else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_GET_MODEMSTATUS: if (lpOutBuffer && nOutBufferSize == sizeof(DWORD)) { if (!(status = get_modem_status(fd, (DWORD*)lpOutBuffer))) sz = sizeof(DWORD); } else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_GET_TIMEOUTS: if (lpOutBuffer && nOutBufferSize == sizeof(SERIAL_TIMEOUTS)) { if (!(status = get_timeouts(hDevice, (SERIAL_TIMEOUTS*)lpOutBuffer))) sz = sizeof(SERIAL_TIMEOUTS); } else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_GET_WAIT_MASK: if (lpOutBuffer && nOutBufferSize == sizeof(DWORD)) { if (!(status = get_wait_mask(hDevice, (DWORD*)lpOutBuffer))) sz = sizeof(DWORD); } else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_IMMEDIATE_CHAR: if (lpInBuffer && nInBufferSize == sizeof(CHAR)) status = xmit_immediate(hDevice, fd, lpInBuffer); else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_PURGE: if (lpInBuffer && nInBufferSize == sizeof(DWORD)) status = purge(fd, *(DWORD*)lpInBuffer); else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_RESET_DEVICE: FIXME("Unsupported\n"); break; case IOCTL_SERIAL_SET_BAUD_RATE: if (lpInBuffer && nInBufferSize == sizeof(SERIAL_BAUD_RATE)) status = set_baud_rate(fd, (const SERIAL_BAUD_RATE*)lpInBuffer); else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_SET_BREAK_OFF: #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */ if (ioctl(fd, TIOCCBRK, 0) == -1) { TRACE("ioctl failed\n"); status = FILE_GetNtStatus(); } #else FIXME("ioctl not available\n"); status = STATUS_NOT_SUPPORTED; #endif break; case IOCTL_SERIAL_SET_BREAK_ON: #if defined(TIOCSBRK) && defined(TIOCCBRK) /* check if available for compilation */ if (ioctl(fd, TIOCSBRK, 0) == -1) { TRACE("ioctl failed\n"); status = FILE_GetNtStatus(); } #else FIXME("ioctl not available\n"); 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_DTR: #ifdef TIOCM_DTR if (whack_modem(fd, 0, TIOCM_DTR) == -1) status = FILE_GetNtStatus(); #else 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); else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_SET_QUEUE_SIZE: if (lpInBuffer && nInBufferSize == sizeof(SERIAL_QUEUE_SIZE)) status = set_queue_size(fd, (const SERIAL_QUEUE_SIZE*)lpInBuffer); else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_SET_RTS: #ifdef TIOCM_RTS if (whack_modem(fd, 0, TIOCM_RTS) == -1) status = FILE_GetNtStatus(); #else status = STATUS_NOT_SUPPORTED; #endif break; case IOCTL_SERIAL_SET_TIMEOUTS: if (lpInBuffer && nInBufferSize == sizeof(SERIAL_TIMEOUTS)) status = set_timeouts(hDevice, fd, (const SERIAL_TIMEOUTS*)lpInBuffer); else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_SET_WAIT_MASK: if (lpInBuffer && nInBufferSize == sizeof(DWORD)) { status = set_wait_mask(hDevice, *(DWORD*)lpInBuffer); } else status = STATUS_INVALID_PARAMETER; break; case IOCTL_SERIAL_SET_XOFF: status = set_XOff(fd); break; case IOCTL_SERIAL_SET_XON: status = set_XOn(fd); break; default: FIXME("Unsupported IOCTL %lx (type=%lx access=%lx func=%lx meth=%lx)\n", dwIoControlCode, dwIoControlCode >> 16, (dwIoControlCode >> 14) & 3, (dwIoControlCode >> 2) & 0xFFF, dwIoControlCode & 3); sz = 0; status = STATUS_INVALID_PARAMETER; break; } if (fd != -1) wine_server_release_fd( hDevice, fd ); error: piosb->u.Status = status; piosb->Information = sz; if (hEvent) NtSetEvent(hEvent, NULL); return status; }