1 /**
2  * WinPR: Windows Portable Runtime
3  * Serial Communication API
4  *
5  * Copyright 2011 O.S. Systems Software Ltda.
6  * Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
7  * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
8  * Copyright 2014 Hewlett-Packard Development Company, L.P.
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *     http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  */
22 
23 #if defined __linux__ && !defined ANDROID
24 
25 #include <assert.h>
26 #include <termios.h>
27 
28 #include <winpr/wlog.h>
29 
30 #include "comm_serial_sys.h"
31 
_set_handflow(WINPR_COMM * pComm,const SERIAL_HANDFLOW * pHandflow)32 static BOOL _set_handflow(WINPR_COMM* pComm, const SERIAL_HANDFLOW* pHandflow)
33 {
34 	SERIAL_HANDFLOW SerCxHandflow;
35 	BOOL result = TRUE;
36 	SERIAL_DRIVER* pSerialSys = SerialSys_s();
37 
38 	memcpy(&SerCxHandflow, pHandflow, sizeof(SERIAL_HANDFLOW));
39 
40 	/* filter out unsupported bits by SerCx.sys
41 	 *
42 	 * http://msdn.microsoft.com/en-us/library/windows/hardware/jj680685%28v=vs.85%29.aspx
43 	 */
44 
45 	SerCxHandflow.ControlHandShake =
46 	    pHandflow->ControlHandShake &
47 	    (SERIAL_DTR_CONTROL | SERIAL_DTR_HANDSHAKE | SERIAL_CTS_HANDSHAKE | SERIAL_DSR_HANDSHAKE);
48 	SerCxHandflow.FlowReplace =
49 	    pHandflow->FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE);
50 
51 	if (SerCxHandflow.ControlHandShake != pHandflow->ControlHandShake)
52 	{
53 		if (pHandflow->ControlHandShake & SERIAL_DCD_HANDSHAKE)
54 		{
55 			CommLog_Print(WLOG_WARN,
56 			              "SERIAL_DCD_HANDSHAKE not supposed to be implemented by SerCx.sys");
57 		}
58 
59 		if (pHandflow->ControlHandShake & SERIAL_DSR_SENSITIVITY)
60 		{
61 			CommLog_Print(WLOG_WARN,
62 			              "SERIAL_DSR_SENSITIVITY not supposed to be implemented by SerCx.sys");
63 		}
64 
65 		if (pHandflow->ControlHandShake & SERIAL_ERROR_ABORT)
66 		{
67 			CommLog_Print(WLOG_WARN,
68 			              "SERIAL_ERROR_ABORT not supposed to be implemented by SerCx.sys");
69 		}
70 
71 		SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
72 		result = FALSE;
73 	}
74 
75 	if (SerCxHandflow.FlowReplace != pHandflow->FlowReplace)
76 	{
77 		if (pHandflow->ControlHandShake & SERIAL_AUTO_TRANSMIT)
78 		{
79 			CommLog_Print(WLOG_WARN,
80 			              "SERIAL_AUTO_TRANSMIT not supposed to be implemented by SerCx.sys");
81 		}
82 
83 		if (pHandflow->ControlHandShake & SERIAL_AUTO_RECEIVE)
84 		{
85 			CommLog_Print(WLOG_WARN,
86 			              "SERIAL_AUTO_RECEIVE not supposed to be implemented by SerCx.sys");
87 		}
88 
89 		if (pHandflow->ControlHandShake & SERIAL_ERROR_CHAR)
90 		{
91 			CommLog_Print(WLOG_WARN,
92 			              "SERIAL_ERROR_CHAR not supposed to be implemented by SerCx.sys");
93 		}
94 
95 		if (pHandflow->ControlHandShake & SERIAL_NULL_STRIPPING)
96 		{
97 			CommLog_Print(WLOG_WARN,
98 			              "SERIAL_NULL_STRIPPING not supposed to be implemented by SerCx.sys");
99 		}
100 
101 		if (pHandflow->ControlHandShake & SERIAL_BREAK_CHAR)
102 		{
103 			CommLog_Print(WLOG_WARN,
104 			              "SERIAL_BREAK_CHAR not supposed to be implemented by SerCx.sys");
105 		}
106 
107 		if (pHandflow->ControlHandShake & SERIAL_XOFF_CONTINUE)
108 		{
109 			CommLog_Print(WLOG_WARN,
110 			              "SERIAL_XOFF_CONTINUE not supposed to be implemented by SerCx.sys");
111 		}
112 
113 		SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
114 		result = FALSE;
115 	}
116 
117 	if (!pSerialSys->set_handflow(pComm, &SerCxHandflow))
118 		return FALSE;
119 
120 	return result;
121 }
122 
_get_handflow(WINPR_COMM * pComm,SERIAL_HANDFLOW * pHandflow)123 static BOOL _get_handflow(WINPR_COMM* pComm, SERIAL_HANDFLOW* pHandflow)
124 {
125 	BOOL result;
126 	SERIAL_DRIVER* pSerialSys = SerialSys_s();
127 
128 	result = pSerialSys->get_handflow(pComm, pHandflow);
129 
130 	/* filter out unsupported bits by SerCx.sys
131 	 *
132 	 * http://msdn.microsoft.com/en-us/library/windows/hardware/jj680685%28v=vs.85%29.aspx
133 	 */
134 
135 	pHandflow->ControlHandShake =
136 	    pHandflow->ControlHandShake &
137 	    (SERIAL_DTR_CONTROL | SERIAL_DTR_HANDSHAKE | SERIAL_CTS_HANDSHAKE | SERIAL_DSR_HANDSHAKE);
138 	pHandflow->FlowReplace = pHandflow->FlowReplace & (SERIAL_RTS_CONTROL | SERIAL_RTS_HANDSHAKE);
139 
140 	return result;
141 }
142 
143 /* http://msdn.microsoft.com/en-us/library/windows/hardware/hh439605%28v=vs.85%29.aspx */
144 static const ULONG _SERCX_SYS_SUPPORTED_EV_MASK = SERIAL_EV_RXCHAR |
145                                                   /* SERIAL_EV_RXFLAG   | */
146                                                   SERIAL_EV_TXEMPTY | SERIAL_EV_CTS |
147                                                   SERIAL_EV_DSR | SERIAL_EV_RLSD | SERIAL_EV_BREAK |
148                                                   SERIAL_EV_ERR | SERIAL_EV_RING /* |
149                                                                SERIAL_EV_PERR     |
150                                                                SERIAL_EV_RX80FULL |
151                                                                SERIAL_EV_EVENT1   |
152                                                                SERIAL_EV_EVENT2*/
153     ;
154 
_set_wait_mask(WINPR_COMM * pComm,const ULONG * pWaitMask)155 static BOOL _set_wait_mask(WINPR_COMM* pComm, const ULONG* pWaitMask)
156 {
157 	ULONG possibleMask;
158 	SERIAL_DRIVER* pSerialSys = SerialSys_s();
159 
160 	possibleMask = *pWaitMask & _SERCX_SYS_SUPPORTED_EV_MASK;
161 
162 	if (possibleMask != *pWaitMask)
163 	{
164 		CommLog_Print(WLOG_WARN,
165 		              "Not all wait events supported (SerCx.sys), requested events= 0x%08" PRIX32
166 		              ", possible events= 0x%08" PRIX32 "",
167 		              *pWaitMask, possibleMask);
168 
169 		/* FIXME: shall we really set the possibleMask and return FALSE? */
170 		pComm->WaitEventMask = possibleMask;
171 		return FALSE;
172 	}
173 
174 	/* NB: All events that are supported by SerCx.sys are supported by Serial.sys*/
175 	return pSerialSys->set_wait_mask(pComm, pWaitMask);
176 }
177 
178 /* specific functions only */
179 static SERIAL_DRIVER _SerCxSys = {
180 	.id = SerialDriverSerCxSys,
181 	.name = _T("SerCx.sys"),
182 	.set_baud_rate = NULL,
183 	.get_baud_rate = NULL,
184 	.get_properties = NULL,
185 	.set_serial_chars = NULL,
186 	.get_serial_chars = NULL,
187 	.set_line_control = NULL,
188 	.get_line_control = NULL,
189 	.set_handflow = _set_handflow,
190 	.get_handflow = _get_handflow,
191 	.set_timeouts = NULL,
192 	.get_timeouts = NULL,
193 	.set_dtr = NULL,
194 	.clear_dtr = NULL,
195 	.set_rts = NULL,
196 	.clear_rts = NULL,
197 	.get_modemstatus = NULL,
198 	.set_wait_mask = _set_wait_mask,
199 	.get_wait_mask = NULL,
200 	.wait_on_mask = NULL,
201 	.set_queue_size = NULL,
202 	.purge = NULL,
203 	.get_commstatus = NULL,
204 	.set_break_on = NULL,
205 	.set_break_off = NULL,
206 	.set_xoff = NULL,
207 	.set_xon = NULL,
208 	.get_dtrrts = NULL,
209 	.config_size = NULL, /* not supported by SerCx.sys */
210 	.immediate_char = NULL,
211 	.reset_device = NULL, /* not supported by SerCx.sys */
212 };
213 
SerCxSys_s()214 SERIAL_DRIVER* SerCxSys_s()
215 {
216 	/* _SerCxSys completed with inherited functions from SerialSys */
217 	SERIAL_DRIVER* pSerialSys = SerialSys_s();
218 
219 	_SerCxSys.set_baud_rate = pSerialSys->set_baud_rate;
220 	_SerCxSys.get_baud_rate = pSerialSys->get_baud_rate;
221 
222 	_SerCxSys.get_properties = pSerialSys->get_properties;
223 
224 	_SerCxSys.set_serial_chars = pSerialSys->set_serial_chars;
225 	_SerCxSys.get_serial_chars = pSerialSys->get_serial_chars;
226 	_SerCxSys.set_line_control = pSerialSys->set_line_control;
227 	_SerCxSys.get_line_control = pSerialSys->get_line_control;
228 
229 	_SerCxSys.set_timeouts = pSerialSys->set_timeouts;
230 	_SerCxSys.get_timeouts = pSerialSys->get_timeouts;
231 
232 	_SerCxSys.set_dtr = pSerialSys->set_dtr;
233 	_SerCxSys.clear_dtr = pSerialSys->clear_dtr;
234 
235 	_SerCxSys.set_rts = pSerialSys->set_rts;
236 	_SerCxSys.clear_rts = pSerialSys->clear_rts;
237 
238 	_SerCxSys.get_modemstatus = pSerialSys->get_modemstatus;
239 
240 	_SerCxSys.set_wait_mask = pSerialSys->set_wait_mask;
241 	_SerCxSys.get_wait_mask = pSerialSys->get_wait_mask;
242 	_SerCxSys.wait_on_mask = pSerialSys->wait_on_mask;
243 
244 	_SerCxSys.set_queue_size = pSerialSys->set_queue_size;
245 
246 	_SerCxSys.purge = pSerialSys->purge;
247 
248 	_SerCxSys.get_commstatus = pSerialSys->get_commstatus;
249 
250 	_SerCxSys.set_break_on = pSerialSys->set_break_on;
251 	_SerCxSys.set_break_off = pSerialSys->set_break_off;
252 
253 	_SerCxSys.set_xoff = pSerialSys->set_xoff;
254 	_SerCxSys.set_xon = pSerialSys->set_xon;
255 
256 	_SerCxSys.get_dtrrts = pSerialSys->get_dtrrts;
257 
258 	_SerCxSys.immediate_char = pSerialSys->immediate_char;
259 
260 	return &_SerCxSys;
261 }
262 
263 #endif /* __linux__ */
264