/** * WinPR: Windows Portable Runtime * Serial Communication API * * Copyright 2011 O.S. Systems Software Ltda. * Copyright 2011 Eduardo Fiss Beloni * Copyright 2014 Marc-Andre Moreau * Copyright 2014 Hewlett-Packard Development Company, L.P. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #if defined __linux__ && !defined ANDROID #include #include #include #include "comm_serial_sys.h" static BOOL _set_handflow(WINPR_COMM* pComm, const SERIAL_HANDFLOW* pHandflow) { SERIAL_HANDFLOW SerCxHandflow; BOOL result = TRUE; SERIAL_DRIVER* pSerialSys = SerialSys_s(); memcpy(&SerCxHandflow, pHandflow, sizeof(SERIAL_HANDFLOW)); /* filter out unsupported bits by SerCx.sys * * http://msdn.microsoft.com/en-us/library/windows/hardware/jj680685%28v=vs.85%29.aspx */ SerCxHandflow.ControlHandShake = pHandflow->ControlHandShake & (SERIAL_DTR_CONTROL | SERIAL_DTR_HANDSHAKE | SERIAL_CTS_HANDSHAKE | SERIAL_DSR_HANDSHAKE); SerCxHandflow.FlowReplace = pHandflow->FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE); if (SerCxHandflow.ControlHandShake != pHandflow->ControlHandShake) { if (pHandflow->ControlHandShake & SERIAL_DCD_HANDSHAKE) { CommLog_Print(WLOG_WARN, "SERIAL_DCD_HANDSHAKE not supposed to be implemented by SerCx.sys"); } if (pHandflow->ControlHandShake & SERIAL_DSR_SENSITIVITY) { CommLog_Print(WLOG_WARN, "SERIAL_DSR_SENSITIVITY not supposed to be implemented by SerCx.sys"); } if (pHandflow->ControlHandShake & SERIAL_ERROR_ABORT) { CommLog_Print(WLOG_WARN, "SERIAL_ERROR_ABORT not supposed to be implemented by SerCx.sys"); } SetLastError(ERROR_CALL_NOT_IMPLEMENTED); result = FALSE; } if (SerCxHandflow.FlowReplace != pHandflow->FlowReplace) { if (pHandflow->ControlHandShake & SERIAL_AUTO_TRANSMIT) { CommLog_Print(WLOG_WARN, "SERIAL_AUTO_TRANSMIT not supposed to be implemented by SerCx.sys"); } if (pHandflow->ControlHandShake & SERIAL_AUTO_RECEIVE) { CommLog_Print(WLOG_WARN, "SERIAL_AUTO_RECEIVE not supposed to be implemented by SerCx.sys"); } if (pHandflow->ControlHandShake & SERIAL_ERROR_CHAR) { CommLog_Print(WLOG_WARN, "SERIAL_ERROR_CHAR not supposed to be implemented by SerCx.sys"); } if (pHandflow->ControlHandShake & SERIAL_NULL_STRIPPING) { CommLog_Print(WLOG_WARN, "SERIAL_NULL_STRIPPING not supposed to be implemented by SerCx.sys"); } if (pHandflow->ControlHandShake & SERIAL_BREAK_CHAR) { CommLog_Print(WLOG_WARN, "SERIAL_BREAK_CHAR not supposed to be implemented by SerCx.sys"); } if (pHandflow->ControlHandShake & SERIAL_XOFF_CONTINUE) { CommLog_Print(WLOG_WARN, "SERIAL_XOFF_CONTINUE not supposed to be implemented by SerCx.sys"); } SetLastError(ERROR_CALL_NOT_IMPLEMENTED); result = FALSE; } if (!pSerialSys->set_handflow(pComm, &SerCxHandflow)) return FALSE; return result; } static BOOL _get_handflow(WINPR_COMM* pComm, SERIAL_HANDFLOW* pHandflow) { BOOL result; SERIAL_DRIVER* pSerialSys = SerialSys_s(); result = pSerialSys->get_handflow(pComm, pHandflow); /* filter out unsupported bits by SerCx.sys * * http://msdn.microsoft.com/en-us/library/windows/hardware/jj680685%28v=vs.85%29.aspx */ pHandflow->ControlHandShake = pHandflow->ControlHandShake & (SERIAL_DTR_CONTROL | SERIAL_DTR_HANDSHAKE | SERIAL_CTS_HANDSHAKE | SERIAL_DSR_HANDSHAKE); pHandflow->FlowReplace = pHandflow->FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE); return result; } /* http://msdn.microsoft.com/en-us/library/windows/hardware/hh439605%28v=vs.85%29.aspx */ static const ULONG _SERCX_SYS_SUPPORTED_EV_MASK = SERIAL_EV_RXCHAR | /* SERIAL_EV_RXFLAG | */ SERIAL_EV_TXEMPTY | SERIAL_EV_CTS | SERIAL_EV_DSR | SERIAL_EV_RLSD | SERIAL_EV_BREAK | SERIAL_EV_ERR | SERIAL_EV_RING /* | SERIAL_EV_PERR | SERIAL_EV_RX80FULL | SERIAL_EV_EVENT1 | SERIAL_EV_EVENT2*/ ; static BOOL _set_wait_mask(WINPR_COMM* pComm, const ULONG* pWaitMask) { ULONG possibleMask; SERIAL_DRIVER* pSerialSys = SerialSys_s(); possibleMask = *pWaitMask & _SERCX_SYS_SUPPORTED_EV_MASK; if (possibleMask != *pWaitMask) { CommLog_Print(WLOG_WARN, "Not all wait events supported (SerCx.sys), requested events= 0x%08" PRIX32 ", possible events= 0x%08" PRIX32 "", *pWaitMask, possibleMask); /* FIXME: shall we really set the possibleMask and return FALSE? */ pComm->WaitEventMask = possibleMask; return FALSE; } /* NB: All events that are supported by SerCx.sys are supported by Serial.sys*/ return pSerialSys->set_wait_mask(pComm, pWaitMask); } /* specific functions only */ static SERIAL_DRIVER _SerCxSys = { .id = SerialDriverSerCxSys, .name = _T("SerCx.sys"), .set_baud_rate = NULL, .get_baud_rate = NULL, .get_properties = NULL, .set_serial_chars = NULL, .get_serial_chars = NULL, .set_line_control = NULL, .get_line_control = NULL, .set_handflow = _set_handflow, .get_handflow = _get_handflow, .set_timeouts = NULL, .get_timeouts = NULL, .set_dtr = NULL, .clear_dtr = NULL, .set_rts = NULL, .clear_rts = NULL, .get_modemstatus = NULL, .set_wait_mask = _set_wait_mask, .get_wait_mask = NULL, .wait_on_mask = NULL, .set_queue_size = NULL, .purge = NULL, .get_commstatus = NULL, .set_break_on = NULL, .set_break_off = NULL, .set_xoff = NULL, .set_xon = NULL, .get_dtrrts = NULL, .config_size = NULL, /* not supported by SerCx.sys */ .immediate_char = NULL, .reset_device = NULL, /* not supported by SerCx.sys */ }; SERIAL_DRIVER* SerCxSys_s() { /* _SerCxSys completed with inherited functions from SerialSys */ SERIAL_DRIVER* pSerialSys = SerialSys_s(); _SerCxSys.set_baud_rate = pSerialSys->set_baud_rate; _SerCxSys.get_baud_rate = pSerialSys->get_baud_rate; _SerCxSys.get_properties = pSerialSys->get_properties; _SerCxSys.set_serial_chars = pSerialSys->set_serial_chars; _SerCxSys.get_serial_chars = pSerialSys->get_serial_chars; _SerCxSys.set_line_control = pSerialSys->set_line_control; _SerCxSys.get_line_control = pSerialSys->get_line_control; _SerCxSys.set_timeouts = pSerialSys->set_timeouts; _SerCxSys.get_timeouts = pSerialSys->get_timeouts; _SerCxSys.set_dtr = pSerialSys->set_dtr; _SerCxSys.clear_dtr = pSerialSys->clear_dtr; _SerCxSys.set_rts = pSerialSys->set_rts; _SerCxSys.clear_rts = pSerialSys->clear_rts; _SerCxSys.get_modemstatus = pSerialSys->get_modemstatus; _SerCxSys.set_wait_mask = pSerialSys->set_wait_mask; _SerCxSys.get_wait_mask = pSerialSys->get_wait_mask; _SerCxSys.wait_on_mask = pSerialSys->wait_on_mask; _SerCxSys.set_queue_size = pSerialSys->set_queue_size; _SerCxSys.purge = pSerialSys->purge; _SerCxSys.get_commstatus = pSerialSys->get_commstatus; _SerCxSys.set_break_on = pSerialSys->set_break_on; _SerCxSys.set_break_off = pSerialSys->set_break_off; _SerCxSys.set_xoff = pSerialSys->set_xoff; _SerCxSys.set_xon = pSerialSys->set_xon; _SerCxSys.get_dtrrts = pSerialSys->get_dtrrts; _SerCxSys.immediate_char = pSerialSys->immediate_char; return &_SerCxSys; } #endif /* __linux__ */