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