1*c2c66affSColin Finck /* -*- c-basic-offset: 8 -*-
2*c2c66affSColin Finck    rdesktop: A Remote Desktop Protocol client.
3*c2c66affSColin Finck 
4*c2c66affSColin Finck    Copyright (C) Matthew Chapman 1999-2005
5*c2c66affSColin Finck 
6*c2c66affSColin Finck    This program is free software; you can redistribute it and/or modify
7*c2c66affSColin Finck    it under the terms of the GNU General Public License as published by
8*c2c66affSColin Finck    the Free Software Foundation; either version 2 of the License, or
9*c2c66affSColin Finck    (at your option) any later version.
10*c2c66affSColin Finck 
11*c2c66affSColin Finck    This program is distributed in the hope that it will be useful,
12*c2c66affSColin Finck    but WITHOUT ANY WARRANTY; without even the implied warranty of
13*c2c66affSColin Finck    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14*c2c66affSColin Finck    GNU General Public License for more details.
15*c2c66affSColin Finck 
16*c2c66affSColin Finck    You should have received a copy of the GNU General Public License along
17*c2c66affSColin Finck    with this program; if not, write to the Free Software Foundation, Inc.,
18*c2c66affSColin Finck    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*c2c66affSColin Finck */
20*c2c66affSColin Finck #include <unistd.h>
21*c2c66affSColin Finck #include <fcntl.h>
22*c2c66affSColin Finck #include <termios.h>
23*c2c66affSColin Finck #include <strings.h>
24*c2c66affSColin Finck #include <sys/ioctl.h>
25*c2c66affSColin Finck 
26*c2c66affSColin Finck #ifdef HAVE_SYS_MODEM_H
27*c2c66affSColin Finck #include <sys/modem.h>
28*c2c66affSColin Finck #endif
29*c2c66affSColin Finck #ifdef HAVE_SYS_FILIO_H
30*c2c66affSColin Finck #include <sys/filio.h>
31*c2c66affSColin Finck #endif
32*c2c66affSColin Finck #ifdef HAVE_SYS_STRTIO_H
33*c2c66affSColin Finck #include <sys/strtio.h>
34*c2c66affSColin Finck #endif
35*c2c66affSColin Finck 
36*c2c66affSColin Finck #include "rdesktop.h"
37*c2c66affSColin Finck 
38*c2c66affSColin Finck #ifdef WITH_DEBUG_SERIAL
39*c2c66affSColin Finck #define DEBUG_SERIAL(args) printf args;
40*c2c66affSColin Finck #else
41*c2c66affSColin Finck #define DEBUG_SERIAL(args)
42*c2c66affSColin Finck #endif
43*c2c66affSColin Finck 
44*c2c66affSColin Finck #define FILE_DEVICE_SERIAL_PORT		0x1b
45*c2c66affSColin Finck 
46*c2c66affSColin Finck #define SERIAL_SET_BAUD_RATE		1
47*c2c66affSColin Finck #define SERIAL_SET_QUEUE_SIZE		2
48*c2c66affSColin Finck #define SERIAL_SET_LINE_CONTROL		3
49*c2c66affSColin Finck #define SERIAL_SET_BREAK_ON		4
50*c2c66affSColin Finck #define SERIAL_SET_BREAK_OFF		5
51*c2c66affSColin Finck #define SERIAL_IMMEDIATE_CHAR		6
52*c2c66affSColin Finck #define SERIAL_SET_TIMEOUTS		7
53*c2c66affSColin Finck #define SERIAL_GET_TIMEOUTS		8
54*c2c66affSColin Finck #define SERIAL_SET_DTR			9
55*c2c66affSColin Finck #define SERIAL_CLR_DTR			10
56*c2c66affSColin Finck #define SERIAL_RESET_DEVICE		11
57*c2c66affSColin Finck #define SERIAL_SET_RTS			12
58*c2c66affSColin Finck #define SERIAL_CLR_RTS			13
59*c2c66affSColin Finck #define SERIAL_SET_XOFF			14
60*c2c66affSColin Finck #define SERIAL_SET_XON			15
61*c2c66affSColin Finck #define SERIAL_GET_WAIT_MASK		16
62*c2c66affSColin Finck #define SERIAL_SET_WAIT_MASK		17
63*c2c66affSColin Finck #define SERIAL_WAIT_ON_MASK		18
64*c2c66affSColin Finck #define SERIAL_PURGE			19
65*c2c66affSColin Finck #define SERIAL_GET_BAUD_RATE		20
66*c2c66affSColin Finck #define SERIAL_GET_LINE_CONTROL		21
67*c2c66affSColin Finck #define SERIAL_GET_CHARS		22
68*c2c66affSColin Finck #define SERIAL_SET_CHARS		23
69*c2c66affSColin Finck #define SERIAL_GET_HANDFLOW		24
70*c2c66affSColin Finck #define SERIAL_SET_HANDFLOW		25
71*c2c66affSColin Finck #define SERIAL_GET_MODEMSTATUS		26
72*c2c66affSColin Finck #define SERIAL_GET_COMMSTATUS		27
73*c2c66affSColin Finck #define SERIAL_XOFF_COUNTER		28
74*c2c66affSColin Finck #define SERIAL_GET_PROPERTIES		29
75*c2c66affSColin Finck #define SERIAL_GET_DTRRTS		30
76*c2c66affSColin Finck #define SERIAL_LSRMST_INSERT		31
77*c2c66affSColin Finck #define SERIAL_CONFIG_SIZE		32
78*c2c66affSColin Finck #define SERIAL_GET_COMMCONFIG		33
79*c2c66affSColin Finck #define SERIAL_SET_COMMCONFIG		34
80*c2c66affSColin Finck #define SERIAL_GET_STATS		35
81*c2c66affSColin Finck #define SERIAL_CLEAR_STATS		36
82*c2c66affSColin Finck #define SERIAL_GET_MODEM_CONTROL	37
83*c2c66affSColin Finck #define SERIAL_SET_MODEM_CONTROL	38
84*c2c66affSColin Finck #define SERIAL_SET_FIFO_CONTROL		39
85*c2c66affSColin Finck 
86*c2c66affSColin Finck #define STOP_BITS_1			0
87*c2c66affSColin Finck #define STOP_BITS_2			2
88*c2c66affSColin Finck 
89*c2c66affSColin Finck #define NO_PARITY			0
90*c2c66affSColin Finck #define ODD_PARITY			1
91*c2c66affSColin Finck #define EVEN_PARITY			2
92*c2c66affSColin Finck 
93*c2c66affSColin Finck #define SERIAL_PURGE_TXABORT 0x00000001
94*c2c66affSColin Finck #define SERIAL_PURGE_RXABORT 0x00000002
95*c2c66affSColin Finck #define SERIAL_PURGE_TXCLEAR 0x00000004
96*c2c66affSColin Finck #define SERIAL_PURGE_RXCLEAR 0x00000008
97*c2c66affSColin Finck 
98*c2c66affSColin Finck /* SERIAL_WAIT_ON_MASK */
99*c2c66affSColin Finck #define SERIAL_EV_RXCHAR           0x0001	/* Any Character received */
100*c2c66affSColin Finck #define SERIAL_EV_RXFLAG           0x0002	/* Received certain character */
101*c2c66affSColin Finck #define SERIAL_EV_TXEMPTY          0x0004	/* Transmitt Queue Empty */
102*c2c66affSColin Finck #define SERIAL_EV_CTS              0x0008	/* CTS changed state */
103*c2c66affSColin Finck #define SERIAL_EV_DSR              0x0010	/* DSR changed state */
104*c2c66affSColin Finck #define SERIAL_EV_RLSD             0x0020	/* RLSD changed state */
105*c2c66affSColin Finck #define SERIAL_EV_BREAK            0x0040	/* BREAK received */
106*c2c66affSColin Finck #define SERIAL_EV_ERR              0x0080	/* Line status error occurred */
107*c2c66affSColin Finck #define SERIAL_EV_RING             0x0100	/* Ring signal detected */
108*c2c66affSColin Finck #define SERIAL_EV_PERR             0x0200	/* Printer error occured */
109*c2c66affSColin Finck #define SERIAL_EV_RX80FULL         0x0400	/* Receive buffer is 80 percent full */
110*c2c66affSColin Finck #define SERIAL_EV_EVENT1           0x0800	/* Provider specific event 1 */
111*c2c66affSColin Finck #define SERIAL_EV_EVENT2           0x1000	/* Provider specific event 2 */
112*c2c66affSColin Finck 
113*c2c66affSColin Finck /* Modem Status */
114*c2c66affSColin Finck #define SERIAL_MS_DTR 0x01
115*c2c66affSColin Finck #define SERIAL_MS_RTS 0x02
116*c2c66affSColin Finck #define SERIAL_MS_CTS 0x10
117*c2c66affSColin Finck #define SERIAL_MS_DSR 0x20
118*c2c66affSColin Finck #define SERIAL_MS_RNG 0x40
119*c2c66affSColin Finck #define SERIAL_MS_CAR 0x80
120*c2c66affSColin Finck 
121*c2c66affSColin Finck /* Handflow */
122*c2c66affSColin Finck #define SERIAL_DTR_CONTROL	0x01
123*c2c66affSColin Finck #define SERIAL_CTS_HANDSHAKE	0x08
124*c2c66affSColin Finck #define SERIAL_ERROR_ABORT	0x80000000
125*c2c66affSColin Finck 
126*c2c66affSColin Finck #define SERIAL_XON_HANDSHAKE	0x01
127*c2c66affSColin Finck #define SERIAL_XOFF_HANDSHAKE	0x02
128*c2c66affSColin Finck #define SERIAL_DSR_SENSITIVITY	0x40
129*c2c66affSColin Finck 
130*c2c66affSColin Finck #define SERIAL_CHAR_EOF		0
131*c2c66affSColin Finck #define SERIAL_CHAR_ERROR	1
132*c2c66affSColin Finck #define SERIAL_CHAR_BREAK	2
133*c2c66affSColin Finck #define SERIAL_CHAR_EVENT	3
134*c2c66affSColin Finck #define SERIAL_CHAR_XON		4
135*c2c66affSColin Finck #define SERIAL_CHAR_XOFF	5
136*c2c66affSColin Finck 
137*c2c66affSColin Finck #ifndef CRTSCTS
138*c2c66affSColin Finck #define CRTSCTS 0
139*c2c66affSColin Finck #endif
140*c2c66affSColin Finck 
141*c2c66affSColin Finck /* FIONREAD should really do the same thing as TIOCINQ, where it is
142*c2c66affSColin Finck  * not available */
143*c2c66affSColin Finck #if !defined(TIOCINQ) && defined(FIONREAD)
144*c2c66affSColin Finck #define TIOCINQ FIONREAD
145*c2c66affSColin Finck #endif
146*c2c66affSColin Finck #if !defined(TIOCOUTQ) && defined(FIONWRITE)
147*c2c66affSColin Finck #define TIOCOUTQ FIONWRITE
148*c2c66affSColin Finck #endif
149*c2c66affSColin Finck 
150*c2c66affSColin Finck static SERIAL_DEVICE *
get_serial_info(RDPCLIENT * This,NTHANDLE handle)151*c2c66affSColin Finck get_serial_info(RDPCLIENT * This, NTHANDLE handle)
152*c2c66affSColin Finck {
153*c2c66affSColin Finck 	int index;
154*c2c66affSColin Finck 
155*c2c66affSColin Finck 	for (index = 0; index < RDPDR_MAX_DEVICES; index++)
156*c2c66affSColin Finck 	{
157*c2c66affSColin Finck 		if (handle == This->rdpdr_device[index].handle)
158*c2c66affSColin Finck 			return (SERIAL_DEVICE *) This->rdpdr_device[index].pdevice_data;
159*c2c66affSColin Finck 	}
160*c2c66affSColin Finck 	return NULL;
161*c2c66affSColin Finck }
162*c2c66affSColin Finck 
163*c2c66affSColin Finck static BOOL
get_termios(SERIAL_DEVICE * pser_inf,NTHANDLE serial_fd)164*c2c66affSColin Finck get_termios(SERIAL_DEVICE * pser_inf, NTHANDLE serial_fd)
165*c2c66affSColin Finck {
166*c2c66affSColin Finck 	speed_t speed;
167*c2c66affSColin Finck 	struct termios *ptermios;
168*c2c66affSColin Finck 
169*c2c66affSColin Finck 	ptermios = pser_inf->ptermios;
170*c2c66affSColin Finck 
171*c2c66affSColin Finck 	if (tcgetattr(serial_fd, ptermios) == -1)
172*c2c66affSColin Finck 		return False;
173*c2c66affSColin Finck 
174*c2c66affSColin Finck 	speed = cfgetispeed(ptermios);
175*c2c66affSColin Finck 	switch (speed)
176*c2c66affSColin Finck 	{
177*c2c66affSColin Finck #ifdef B75
178*c2c66affSColin Finck 		case B75:
179*c2c66affSColin Finck 			pser_inf->baud_rate = 75;
180*c2c66affSColin Finck 			break;
181*c2c66affSColin Finck #endif
182*c2c66affSColin Finck #ifdef B110
183*c2c66affSColin Finck 		case B110:
184*c2c66affSColin Finck 			pser_inf->baud_rate = 110;
185*c2c66affSColin Finck 			break;
186*c2c66affSColin Finck #endif
187*c2c66affSColin Finck #ifdef B134
188*c2c66affSColin Finck 		case B134:
189*c2c66affSColin Finck 			pser_inf->baud_rate = 134;
190*c2c66affSColin Finck 			break;
191*c2c66affSColin Finck #endif
192*c2c66affSColin Finck #ifdef B150
193*c2c66affSColin Finck 		case B150:
194*c2c66affSColin Finck 			pser_inf->baud_rate = 150;
195*c2c66affSColin Finck 			break;
196*c2c66affSColin Finck #endif
197*c2c66affSColin Finck #ifdef B300
198*c2c66affSColin Finck 		case B300:
199*c2c66affSColin Finck 			pser_inf->baud_rate = 300;
200*c2c66affSColin Finck 			break;
201*c2c66affSColin Finck #endif
202*c2c66affSColin Finck #ifdef B600
203*c2c66affSColin Finck 		case B600:
204*c2c66affSColin Finck 			pser_inf->baud_rate = 600;
205*c2c66affSColin Finck 			break;
206*c2c66affSColin Finck #endif
207*c2c66affSColin Finck #ifdef B1200
208*c2c66affSColin Finck 		case B1200:
209*c2c66affSColin Finck 			pser_inf->baud_rate = 1200;
210*c2c66affSColin Finck 			break;
211*c2c66affSColin Finck #endif
212*c2c66affSColin Finck #ifdef B1800
213*c2c66affSColin Finck 		case B1800:
214*c2c66affSColin Finck 			pser_inf->baud_rate = 1800;
215*c2c66affSColin Finck 			break;
216*c2c66affSColin Finck #endif
217*c2c66affSColin Finck #ifdef B2400
218*c2c66affSColin Finck 		case B2400:
219*c2c66affSColin Finck 			pser_inf->baud_rate = 2400;
220*c2c66affSColin Finck 			break;
221*c2c66affSColin Finck #endif
222*c2c66affSColin Finck #ifdef B4800
223*c2c66affSColin Finck 		case B4800:
224*c2c66affSColin Finck 			pser_inf->baud_rate = 4800;
225*c2c66affSColin Finck 			break;
226*c2c66affSColin Finck #endif
227*c2c66affSColin Finck #ifdef B9600
228*c2c66affSColin Finck 		case B9600:
229*c2c66affSColin Finck 			pser_inf->baud_rate = 9600;
230*c2c66affSColin Finck 			break;
231*c2c66affSColin Finck #endif
232*c2c66affSColin Finck #ifdef B19200
233*c2c66affSColin Finck 		case B19200:
234*c2c66affSColin Finck 			pser_inf->baud_rate = 19200;
235*c2c66affSColin Finck 			break;
236*c2c66affSColin Finck #endif
237*c2c66affSColin Finck #ifdef B38400
238*c2c66affSColin Finck 		case B38400:
239*c2c66affSColin Finck 			pser_inf->baud_rate = 38400;
240*c2c66affSColin Finck 			break;
241*c2c66affSColin Finck #endif
242*c2c66affSColin Finck #ifdef B57600
243*c2c66affSColin Finck 		case B57600:
244*c2c66affSColin Finck 			pser_inf->baud_rate = 57600;
245*c2c66affSColin Finck 			break;
246*c2c66affSColin Finck #endif
247*c2c66affSColin Finck #ifdef B115200
248*c2c66affSColin Finck 		case B115200:
249*c2c66affSColin Finck 			pser_inf->baud_rate = 115200;
250*c2c66affSColin Finck 			break;
251*c2c66affSColin Finck #endif
252*c2c66affSColin Finck #ifdef B230400
253*c2c66affSColin Finck 		case B230400:
254*c2c66affSColin Finck 			pser_inf->baud_rate = 230400;
255*c2c66affSColin Finck 			break;
256*c2c66affSColin Finck #endif
257*c2c66affSColin Finck #ifdef B460800
258*c2c66affSColin Finck 		case B460800:
259*c2c66affSColin Finck 			pser_inf->baud_rate = 460800;
260*c2c66affSColin Finck 			break;
261*c2c66affSColin Finck #endif
262*c2c66affSColin Finck 		default:
263*c2c66affSColin Finck 			pser_inf->baud_rate = 9600;
264*c2c66affSColin Finck 			break;
265*c2c66affSColin Finck 	}
266*c2c66affSColin Finck 
267*c2c66affSColin Finck 	speed = cfgetospeed(ptermios);
268*c2c66affSColin Finck 	pser_inf->dtr = (speed == B0) ? 0 : 1;
269*c2c66affSColin Finck 
270*c2c66affSColin Finck 	pser_inf->stop_bits = (ptermios->c_cflag & CSTOPB) ? STOP_BITS_2 : STOP_BITS_1;
271*c2c66affSColin Finck 	pser_inf->parity =
272*c2c66affSColin Finck 		(ptermios->
273*c2c66affSColin Finck 		 c_cflag & PARENB) ? ((ptermios->
274*c2c66affSColin Finck 				       c_cflag & PARODD) ? ODD_PARITY : EVEN_PARITY) : NO_PARITY;
275*c2c66affSColin Finck 	switch (ptermios->c_cflag & CSIZE)
276*c2c66affSColin Finck 	{
277*c2c66affSColin Finck 		case CS5:
278*c2c66affSColin Finck 			pser_inf->word_length = 5;
279*c2c66affSColin Finck 			break;
280*c2c66affSColin Finck 		case CS6:
281*c2c66affSColin Finck 			pser_inf->word_length = 6;
282*c2c66affSColin Finck 			break;
283*c2c66affSColin Finck 		case CS7:
284*c2c66affSColin Finck 			pser_inf->word_length = 7;
285*c2c66affSColin Finck 			break;
286*c2c66affSColin Finck 		default:
287*c2c66affSColin Finck 			pser_inf->word_length = 8;
288*c2c66affSColin Finck 			break;
289*c2c66affSColin Finck 	}
290*c2c66affSColin Finck 
291*c2c66affSColin Finck 	if (ptermios->c_cflag & CRTSCTS)
292*c2c66affSColin Finck 	{
293*c2c66affSColin Finck 		pser_inf->control = SERIAL_DTR_CONTROL | SERIAL_CTS_HANDSHAKE | SERIAL_ERROR_ABORT;
294*c2c66affSColin Finck 	}
295*c2c66affSColin Finck 	else
296*c2c66affSColin Finck 	{
297*c2c66affSColin Finck 		pser_inf->control = SERIAL_DTR_CONTROL | SERIAL_ERROR_ABORT;
298*c2c66affSColin Finck 	}
299*c2c66affSColin Finck 
300*c2c66affSColin Finck 	pser_inf->xonoff = SERIAL_DSR_SENSITIVITY;
301*c2c66affSColin Finck 	if (ptermios->c_iflag & IXON)
302*c2c66affSColin Finck 		pser_inf->xonoff |= SERIAL_XON_HANDSHAKE;
303*c2c66affSColin Finck 
304*c2c66affSColin Finck 	if (ptermios->c_iflag & IXOFF)
305*c2c66affSColin Finck 		pser_inf->xonoff |= SERIAL_XOFF_HANDSHAKE;
306*c2c66affSColin Finck 
307*c2c66affSColin Finck 	pser_inf->chars[SERIAL_CHAR_XON] = ptermios->c_cc[VSTART];
308*c2c66affSColin Finck 	pser_inf->chars[SERIAL_CHAR_XOFF] = ptermios->c_cc[VSTOP];
309*c2c66affSColin Finck 	pser_inf->chars[SERIAL_CHAR_EOF] = ptermios->c_cc[VEOF];
310*c2c66affSColin Finck 	pser_inf->chars[SERIAL_CHAR_BREAK] = ptermios->c_cc[VINTR];
311*c2c66affSColin Finck 	pser_inf->chars[SERIAL_CHAR_ERROR] = ptermios->c_cc[VKILL];
312*c2c66affSColin Finck 
313*c2c66affSColin Finck 	return True;
314*c2c66affSColin Finck }
315*c2c66affSColin Finck 
316*c2c66affSColin Finck static void
set_termios(SERIAL_DEVICE * pser_inf,NTHANDLE serial_fd)317*c2c66affSColin Finck set_termios(SERIAL_DEVICE * pser_inf, NTHANDLE serial_fd)
318*c2c66affSColin Finck {
319*c2c66affSColin Finck 	speed_t speed;
320*c2c66affSColin Finck 
321*c2c66affSColin Finck 	struct termios *ptermios;
322*c2c66affSColin Finck 
323*c2c66affSColin Finck 	ptermios = pser_inf->ptermios;
324*c2c66affSColin Finck 
325*c2c66affSColin Finck 
326*c2c66affSColin Finck 	switch (pser_inf->baud_rate)
327*c2c66affSColin Finck 	{
328*c2c66affSColin Finck #ifdef B75
329*c2c66affSColin Finck 		case 75:
330*c2c66affSColin Finck 			speed = B75;
331*c2c66affSColin Finck 			break;
332*c2c66affSColin Finck #endif
333*c2c66affSColin Finck #ifdef B110
334*c2c66affSColin Finck 		case 110:
335*c2c66affSColin Finck 			speed = B110;
336*c2c66affSColin Finck 			break;
337*c2c66affSColin Finck #endif
338*c2c66affSColin Finck #ifdef B134
339*c2c66affSColin Finck 		case 134:
340*c2c66affSColin Finck 			speed = B134;
341*c2c66affSColin Finck 			break;
342*c2c66affSColin Finck #endif
343*c2c66affSColin Finck #ifdef B150
344*c2c66affSColin Finck 		case 150:
345*c2c66affSColin Finck 			speed = B150;
346*c2c66affSColin Finck 			break;
347*c2c66affSColin Finck #endif
348*c2c66affSColin Finck #ifdef B300
349*c2c66affSColin Finck 		case 300:
350*c2c66affSColin Finck 			speed = B300;
351*c2c66affSColin Finck 			break;
352*c2c66affSColin Finck #endif
353*c2c66affSColin Finck #ifdef B600
354*c2c66affSColin Finck 		case 600:
355*c2c66affSColin Finck 			speed = B600;
356*c2c66affSColin Finck 			break;
357*c2c66affSColin Finck #endif
358*c2c66affSColin Finck #ifdef B1200
359*c2c66affSColin Finck 		case 1200:
360*c2c66affSColin Finck 			speed = B1200;
361*c2c66affSColin Finck 			break;
362*c2c66affSColin Finck #endif
363*c2c66affSColin Finck #ifdef B1800
364*c2c66affSColin Finck 		case 1800:
365*c2c66affSColin Finck 			speed = B1800;
366*c2c66affSColin Finck 			break;
367*c2c66affSColin Finck #endif
368*c2c66affSColin Finck #ifdef B2400
369*c2c66affSColin Finck 		case 2400:
370*c2c66affSColin Finck 			speed = B2400;
371*c2c66affSColin Finck 			break;
372*c2c66affSColin Finck #endif
373*c2c66affSColin Finck #ifdef B4800
374*c2c66affSColin Finck 		case 4800:
375*c2c66affSColin Finck 			speed = B4800;
376*c2c66affSColin Finck 			break;
377*c2c66affSColin Finck #endif
378*c2c66affSColin Finck #ifdef B9600
379*c2c66affSColin Finck 		case 9600:
380*c2c66affSColin Finck 			speed = B9600;
381*c2c66affSColin Finck 			break;
382*c2c66affSColin Finck #endif
383*c2c66affSColin Finck #ifdef B19200
384*c2c66affSColin Finck 		case 19200:
385*c2c66affSColin Finck 			speed = B19200;
386*c2c66affSColin Finck 			break;
387*c2c66affSColin Finck #endif
388*c2c66affSColin Finck #ifdef B38400
389*c2c66affSColin Finck 		case 38400:
390*c2c66affSColin Finck 			speed = B38400;
391*c2c66affSColin Finck 			break;
392*c2c66affSColin Finck #endif
393*c2c66affSColin Finck #ifdef B57600
394*c2c66affSColin Finck 		case 57600:
395*c2c66affSColin Finck 			speed = B57600;
396*c2c66affSColin Finck 			break;
397*c2c66affSColin Finck #endif
398*c2c66affSColin Finck #ifdef B115200
399*c2c66affSColin Finck 		case 115200:
400*c2c66affSColin Finck 			speed = B115200;
401*c2c66affSColin Finck 			break;
402*c2c66affSColin Finck #endif
403*c2c66affSColin Finck #ifdef B230400
404*c2c66affSColin Finck 		case 230400:
405*c2c66affSColin Finck 			speed = B115200;
406*c2c66affSColin Finck 			break;
407*c2c66affSColin Finck #endif
408*c2c66affSColin Finck #ifdef B460800
409*c2c66affSColin Finck 		case 460800:
410*c2c66affSColin Finck 			speed = B115200;
411*c2c66affSColin Finck 			break;
412*c2c66affSColin Finck #endif
413*c2c66affSColin Finck 		default:
414*c2c66affSColin Finck 			speed = B9600;
415*c2c66affSColin Finck 			break;
416*c2c66affSColin Finck 	}
417*c2c66affSColin Finck 
418*c2c66affSColin Finck #ifdef CBAUD
419*c2c66affSColin Finck 	ptermios->c_cflag &= ~CBAUD;
420*c2c66affSColin Finck 	ptermios->c_cflag |= speed;
421*c2c66affSColin Finck #else
422*c2c66affSColin Finck 	/* on systems with separate ispeed and ospeed, we can remember the speed
423*c2c66affSColin Finck 	   in ispeed while changing DTR with ospeed */
424*c2c66affSColin Finck 	cfsetispeed(pser_inf->ptermios, speed);
425*c2c66affSColin Finck 	cfsetospeed(pser_inf->ptermios, pser_inf->dtr ? speed : 0);
426*c2c66affSColin Finck #endif
427*c2c66affSColin Finck 
428*c2c66affSColin Finck 	ptermios->c_cflag &= ~(CSTOPB | PARENB | PARODD | CSIZE | CRTSCTS);
429*c2c66affSColin Finck 	switch (pser_inf->stop_bits)
430*c2c66affSColin Finck 	{
431*c2c66affSColin Finck 		case STOP_BITS_2:
432*c2c66affSColin Finck 			ptermios->c_cflag |= CSTOPB;
433*c2c66affSColin Finck 			break;
434*c2c66affSColin Finck 		default:
435*c2c66affSColin Finck 			ptermios->c_cflag &= ~CSTOPB;
436*c2c66affSColin Finck 			break;
437*c2c66affSColin Finck 	}
438*c2c66affSColin Finck 
439*c2c66affSColin Finck 	switch (pser_inf->parity)
440*c2c66affSColin Finck 	{
441*c2c66affSColin Finck 		case EVEN_PARITY:
442*c2c66affSColin Finck 			ptermios->c_cflag |= PARENB;
443*c2c66affSColin Finck 			break;
444*c2c66affSColin Finck 		case ODD_PARITY:
445*c2c66affSColin Finck 			ptermios->c_cflag |= PARENB | PARODD;
446*c2c66affSColin Finck 			break;
447*c2c66affSColin Finck 		case NO_PARITY:
448*c2c66affSColin Finck 			ptermios->c_cflag &= ~(PARENB | PARODD);
449*c2c66affSColin Finck 			break;
450*c2c66affSColin Finck 	}
451*c2c66affSColin Finck 
452*c2c66affSColin Finck 	switch (pser_inf->word_length)
453*c2c66affSColin Finck 	{
454*c2c66affSColin Finck 		case 5:
455*c2c66affSColin Finck 			ptermios->c_cflag |= CS5;
456*c2c66affSColin Finck 			break;
457*c2c66affSColin Finck 		case 6:
458*c2c66affSColin Finck 			ptermios->c_cflag |= CS6;
459*c2c66affSColin Finck 			break;
460*c2c66affSColin Finck 		case 7:
461*c2c66affSColin Finck 			ptermios->c_cflag |= CS7;
462*c2c66affSColin Finck 			break;
463*c2c66affSColin Finck 		default:
464*c2c66affSColin Finck 			ptermios->c_cflag |= CS8;
465*c2c66affSColin Finck 			break;
466*c2c66affSColin Finck 	}
467*c2c66affSColin Finck 
468*c2c66affSColin Finck #if 0
469*c2c66affSColin Finck 	if (pser_inf->rts)
470*c2c66affSColin Finck 		ptermios->c_cflag |= CRTSCTS;
471*c2c66affSColin Finck 	else
472*c2c66affSColin Finck 		ptermios->c_cflag &= ~CRTSCTS;
473*c2c66affSColin Finck #endif
474*c2c66affSColin Finck 
475*c2c66affSColin Finck 	if (pser_inf->control & SERIAL_CTS_HANDSHAKE)
476*c2c66affSColin Finck 	{
477*c2c66affSColin Finck 		ptermios->c_cflag |= CRTSCTS;
478*c2c66affSColin Finck 	}
479*c2c66affSColin Finck 	else
480*c2c66affSColin Finck 	{
481*c2c66affSColin Finck 		ptermios->c_cflag &= ~CRTSCTS;
482*c2c66affSColin Finck 	}
483*c2c66affSColin Finck 
484*c2c66affSColin Finck 
485*c2c66affSColin Finck 	if (pser_inf->xonoff & SERIAL_XON_HANDSHAKE)
486*c2c66affSColin Finck 	{
487*c2c66affSColin Finck 		ptermios->c_iflag |= IXON | IMAXBEL;
488*c2c66affSColin Finck 	}
489*c2c66affSColin Finck 	if (pser_inf->xonoff & SERIAL_XOFF_HANDSHAKE)
490*c2c66affSColin Finck 	{
491*c2c66affSColin Finck 		ptermios->c_iflag |= IXOFF | IMAXBEL;
492*c2c66affSColin Finck 	}
493*c2c66affSColin Finck 
494*c2c66affSColin Finck 	if ((pser_inf->xonoff & (SERIAL_XOFF_HANDSHAKE | SERIAL_XON_HANDSHAKE)) == 0)
495*c2c66affSColin Finck 	{
496*c2c66affSColin Finck 		ptermios->c_iflag &= ~IXON;
497*c2c66affSColin Finck 		ptermios->c_iflag &= ~IXOFF;
498*c2c66affSColin Finck 	}
499*c2c66affSColin Finck 
500*c2c66affSColin Finck 	ptermios->c_cc[VSTART] = pser_inf->chars[SERIAL_CHAR_XON];
501*c2c66affSColin Finck 	ptermios->c_cc[VSTOP] = pser_inf->chars[SERIAL_CHAR_XOFF];
502*c2c66affSColin Finck 	ptermios->c_cc[VEOF] = pser_inf->chars[SERIAL_CHAR_EOF];
503*c2c66affSColin Finck 	ptermios->c_cc[VINTR] = pser_inf->chars[SERIAL_CHAR_BREAK];
504*c2c66affSColin Finck 	ptermios->c_cc[VKILL] = pser_inf->chars[SERIAL_CHAR_ERROR];
505*c2c66affSColin Finck 
506*c2c66affSColin Finck 	tcsetattr(serial_fd, TCSANOW, ptermios);
507*c2c66affSColin Finck }
508*c2c66affSColin Finck 
509*c2c66affSColin Finck /* Enumeration of devices from rdesktop.c        */
510*c2c66affSColin Finck /* returns numer of units found and initialized. */
511*c2c66affSColin Finck /* optarg looks like ':com1=/dev/ttyS0'           */
512*c2c66affSColin Finck /* when it arrives to this function.              */
513*c2c66affSColin Finck /* :com1=/dev/ttyS0,com2=/dev/ttyS1 */
514*c2c66affSColin Finck int
serial_enum_devices(RDPCLIENT * This,uint32 * id,char * optarg)515*c2c66affSColin Finck serial_enum_devices(RDPCLIENT * This, uint32 * id, char *optarg)
516*c2c66affSColin Finck {
517*c2c66affSColin Finck 	SERIAL_DEVICE *pser_inf;
518*c2c66affSColin Finck 
519*c2c66affSColin Finck 	char *pos = optarg;
520*c2c66affSColin Finck 	char *pos2;
521*c2c66affSColin Finck 	int count = 0;
522*c2c66affSColin Finck 
523*c2c66affSColin Finck 	/* skip the first colon */
524*c2c66affSColin Finck 	optarg++;
525*c2c66affSColin Finck 	while ((pos = next_arg(optarg, ',')) && *id < RDPDR_MAX_DEVICES)
526*c2c66affSColin Finck 	{
527*c2c66affSColin Finck 		/* Init data structures for device */
528*c2c66affSColin Finck 		pser_inf = (SERIAL_DEVICE *) xmalloc(sizeof(SERIAL_DEVICE));
529*c2c66affSColin Finck 		pser_inf->ptermios = (struct termios *) xmalloc(sizeof(struct termios));
530*c2c66affSColin Finck 		memset(pser_inf->ptermios, 0, sizeof(struct termios));
531*c2c66affSColin Finck 		pser_inf->pold_termios = (struct termios *) xmalloc(sizeof(struct termios));
532*c2c66affSColin Finck 		memset(pser_inf->pold_termios, 0, sizeof(struct termios));
533*c2c66affSColin Finck 
534*c2c66affSColin Finck 		pos2 = next_arg(optarg, '=');
535*c2c66affSColin Finck 		strcpy(This->rdpdr_device[*id].name, optarg);
536*c2c66affSColin Finck 
537*c2c66affSColin Finck 		toupper_str(This->rdpdr_device[*id].name);
538*c2c66affSColin Finck 
539*c2c66affSColin Finck 		This->rdpdr_device[*id].local_path = xmalloc(strlen(pos2) + 1);
540*c2c66affSColin Finck 		strcpy(This->rdpdr_device[*id].local_path, pos2);
541*c2c66affSColin Finck 		printf("SERIAL %s to %s\n", This->rdpdr_device[*id].name,
542*c2c66affSColin Finck 		       This->rdpdr_device[*id].local_path);
543*c2c66affSColin Finck 		/* set device type */
544*c2c66affSColin Finck 		This->rdpdr_device[*id].device_type = DEVICE_TYPE_SERIAL;
545*c2c66affSColin Finck 		This->rdpdr_device[*id].pdevice_data = (void *) pser_inf;
546*c2c66affSColin Finck 		count++;
547*c2c66affSColin Finck 		(*id)++;
548*c2c66affSColin Finck 
549*c2c66affSColin Finck 		optarg = pos;
550*c2c66affSColin Finck 	}
551*c2c66affSColin Finck 	return count;
552*c2c66affSColin Finck }
553*c2c66affSColin Finck 
554*c2c66affSColin Finck static NTSTATUS
serial_create(RDPCLIENT * This,uint32 device_id,uint32 access,uint32 share_mode,uint32 disposition,uint32 flags_and_attributes,char * filename,NTHANDLE * handle)555*c2c66affSColin Finck serial_create(RDPCLIENT * This, uint32 device_id, uint32 access, uint32 share_mode, uint32 disposition,
556*c2c66affSColin Finck 	      uint32 flags_and_attributes, char *filename, NTHANDLE * handle)
557*c2c66affSColin Finck {
558*c2c66affSColin Finck 	NTHANDLE serial_fd;
559*c2c66affSColin Finck 	SERIAL_DEVICE *pser_inf;
560*c2c66affSColin Finck 	struct termios *ptermios;
561*c2c66affSColin Finck 
562*c2c66affSColin Finck 	pser_inf = (SERIAL_DEVICE *) This->rdpdr_device[device_id].pdevice_data;
563*c2c66affSColin Finck 	ptermios = pser_inf->ptermios;
564*c2c66affSColin Finck 	serial_fd = open(This->rdpdr_device[device_id].local_path, O_RDWR | O_NOCTTY | O_NONBLOCK);
565*c2c66affSColin Finck 
566*c2c66affSColin Finck 	if (serial_fd == -1)
567*c2c66affSColin Finck 	{
568*c2c66affSColin Finck 		perror("open");
569*c2c66affSColin Finck 		return STATUS_ACCESS_DENIED;
570*c2c66affSColin Finck 	}
571*c2c66affSColin Finck 
572*c2c66affSColin Finck 	if (!get_termios(pser_inf, serial_fd))
573*c2c66affSColin Finck 	{
574*c2c66affSColin Finck 		printf("INFO: SERIAL %s access denied\n", This->rdpdr_device[device_id].name);
575*c2c66affSColin Finck 		fflush(stdout);
576*c2c66affSColin Finck 		return STATUS_ACCESS_DENIED;
577*c2c66affSColin Finck 	}
578*c2c66affSColin Finck 
579*c2c66affSColin Finck 	/* Store handle for later use */
580*c2c66affSColin Finck 	This->rdpdr_device[device_id].handle = serial_fd;
581*c2c66affSColin Finck 
582*c2c66affSColin Finck 	/* some sane information */
583*c2c66affSColin Finck 	DEBUG_SERIAL(("INFO: SERIAL %s to %s\nINFO: speed %u baud, stop bits %u, parity %u, word length %u bits, dtr %u, rts %u\n", This->rdpdr_device[device_id].name, This->rdpdr_device[device_id].local_path, pser_inf->baud_rate, pser_inf->stop_bits, pser_inf->parity, pser_inf->word_length, pser_inf->dtr, pser_inf->rts));
584*c2c66affSColin Finck 
585*c2c66affSColin Finck 	pser_inf->ptermios->c_iflag &=
586*c2c66affSColin Finck 		~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
587*c2c66affSColin Finck 	pser_inf->ptermios->c_oflag &= ~OPOST;
588*c2c66affSColin Finck 	pser_inf->ptermios->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
589*c2c66affSColin Finck 	pser_inf->ptermios->c_cflag &= ~(CSIZE | PARENB);
590*c2c66affSColin Finck 	pser_inf->ptermios->c_cflag |= CS8;
591*c2c66affSColin Finck 
592*c2c66affSColin Finck 	tcsetattr(serial_fd, TCSANOW, pser_inf->ptermios);
593*c2c66affSColin Finck 
594*c2c66affSColin Finck 	pser_inf->event_txempty = 0;
595*c2c66affSColin Finck 	pser_inf->event_cts = 0;
596*c2c66affSColin Finck 	pser_inf->event_dsr = 0;
597*c2c66affSColin Finck 	pser_inf->event_rlsd = 0;
598*c2c66affSColin Finck 	pser_inf->event_pending = 0;
599*c2c66affSColin Finck 
600*c2c66affSColin Finck 	*handle = serial_fd;
601*c2c66affSColin Finck 
602*c2c66affSColin Finck 	/* all read and writes should be non blocking */
603*c2c66affSColin Finck 	if (fcntl(*handle, F_SETFL, O_NONBLOCK) == -1)
604*c2c66affSColin Finck 		perror("fcntl");
605*c2c66affSColin Finck 
606*c2c66affSColin Finck 	pser_inf->read_total_timeout_constant = 5;
607*c2c66affSColin Finck 
608*c2c66affSColin Finck 	return STATUS_SUCCESS;
609*c2c66affSColin Finck }
610*c2c66affSColin Finck 
611*c2c66affSColin Finck static NTSTATUS
serial_close(RDPCLIENT * This,NTHANDLE handle)612*c2c66affSColin Finck serial_close(RDPCLIENT * This, NTHANDLE handle)
613*c2c66affSColin Finck {
614*c2c66affSColin Finck 	int i = get_device_index(This, handle);
615*c2c66affSColin Finck 	if (i >= 0)
616*c2c66affSColin Finck 		This->rdpdr_device[i].handle = 0;
617*c2c66affSColin Finck 
618*c2c66affSColin Finck 	rdpdr_abort_io(This, handle, 0, STATUS_TIMEOUT);
619*c2c66affSColin Finck 	close(handle);
620*c2c66affSColin Finck 	return STATUS_SUCCESS;
621*c2c66affSColin Finck }
622*c2c66affSColin Finck 
623*c2c66affSColin Finck static NTSTATUS
serial_read(RDPCLIENT * This,NTHANDLE handle,uint8 * data,uint32 length,uint32 offset,uint32 * result)624*c2c66affSColin Finck serial_read(RDPCLIENT * This, NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result)
625*c2c66affSColin Finck {
626*c2c66affSColin Finck 	long timeout;
627*c2c66affSColin Finck 	SERIAL_DEVICE *pser_inf;
628*c2c66affSColin Finck 	struct termios *ptermios;
629*c2c66affSColin Finck #ifdef WITH_DEBUG_SERIAL
630*c2c66affSColin Finck 	int bytes_inqueue;
631*c2c66affSColin Finck #endif
632*c2c66affSColin Finck 
633*c2c66affSColin Finck 
634*c2c66affSColin Finck 	timeout = 90;
635*c2c66affSColin Finck 	pser_inf = get_serial_info(This, handle);
636*c2c66affSColin Finck 	ptermios = pser_inf->ptermios;
637*c2c66affSColin Finck 
638*c2c66affSColin Finck 	/* Set timeouts kind of like the windows serial timeout parameters. Multiply timeout
639*c2c66affSColin Finck 	   with requested read size */
640*c2c66affSColin Finck 	if (pser_inf->read_total_timeout_multiplier | pser_inf->read_total_timeout_constant)
641*c2c66affSColin Finck 	{
642*c2c66affSColin Finck 		timeout =
643*c2c66affSColin Finck 			(pser_inf->read_total_timeout_multiplier * length +
644*c2c66affSColin Finck 			 pser_inf->read_total_timeout_constant + 99) / 100;
645*c2c66affSColin Finck 	}
646*c2c66affSColin Finck 	else if (pser_inf->read_interval_timeout)
647*c2c66affSColin Finck 	{
648*c2c66affSColin Finck 		timeout = (pser_inf->read_interval_timeout * length + 99) / 100;
649*c2c66affSColin Finck 	}
650*c2c66affSColin Finck 
651*c2c66affSColin Finck 	/* If a timeout is set, do a blocking read, which times out after some time.
652*c2c66affSColin Finck 	   It will make rdesktop less responsive, but it will improve serial performance, by not
653*c2c66affSColin Finck 	   reading one character at a time. */
654*c2c66affSColin Finck 	if (timeout == 0)
655*c2c66affSColin Finck 	{
656*c2c66affSColin Finck 		ptermios->c_cc[VTIME] = 0;
657*c2c66affSColin Finck 		ptermios->c_cc[VMIN] = 0;
658*c2c66affSColin Finck 	}
659*c2c66affSColin Finck 	else
660*c2c66affSColin Finck 	{
661*c2c66affSColin Finck 		ptermios->c_cc[VTIME] = timeout;
662*c2c66affSColin Finck 		ptermios->c_cc[VMIN] = 1;
663*c2c66affSColin Finck 	}
664*c2c66affSColin Finck 	tcsetattr(handle, TCSANOW, ptermios);
665*c2c66affSColin Finck 
666*c2c66affSColin Finck #if defined(WITH_DEBUG_SERIAL) && defined(TIOCINQ)
667*c2c66affSColin Finck 	ioctl(handle, TIOCINQ, &bytes_inqueue);
668*c2c66affSColin Finck 	DEBUG_SERIAL(("serial_read inqueue: %d expected %d\n", bytes_inqueue, length));
669*c2c66affSColin Finck #endif
670*c2c66affSColin Finck 
671*c2c66affSColin Finck 	*result = read(handle, data, length);
672*c2c66affSColin Finck 
673*c2c66affSColin Finck #ifdef WITH_DEBUG_SERIAL
674*c2c66affSColin Finck 	DEBUG_SERIAL(("serial_read Bytes %d\n", *result));
675*c2c66affSColin Finck 	if (*result > 0)
676*c2c66affSColin Finck 		hexdump(data, *result);
677*c2c66affSColin Finck #endif
678*c2c66affSColin Finck 
679*c2c66affSColin Finck 	return STATUS_SUCCESS;
680*c2c66affSColin Finck }
681*c2c66affSColin Finck 
682*c2c66affSColin Finck static NTSTATUS
serial_write(RDPCLIENT * This,NTHANDLE handle,uint8 * data,uint32 length,uint32 offset,uint32 * result)683*c2c66affSColin Finck serial_write(RDPCLIENT * This, NTHANDLE handle, uint8 * data, uint32 length, uint32 offset, uint32 * result)
684*c2c66affSColin Finck {
685*c2c66affSColin Finck 	SERIAL_DEVICE *pser_inf;
686*c2c66affSColin Finck 
687*c2c66affSColin Finck 	pser_inf = get_serial_info(This, handle);
688*c2c66affSColin Finck 
689*c2c66affSColin Finck 	*result = write(handle, data, length);
690*c2c66affSColin Finck 
691*c2c66affSColin Finck 	if (*result > 0)
692*c2c66affSColin Finck 		pser_inf->event_txempty = *result;
693*c2c66affSColin Finck 
694*c2c66affSColin Finck 	DEBUG_SERIAL(("serial_write length %d, offset %d result %d\n", length, offset, *result));
695*c2c66affSColin Finck 
696*c2c66affSColin Finck 	return STATUS_SUCCESS;
697*c2c66affSColin Finck }
698*c2c66affSColin Finck 
699*c2c66affSColin Finck static NTSTATUS
serial_device_control(RDPCLIENT * This,NTHANDLE handle,uint32 request,STREAM in,STREAM out)700*c2c66affSColin Finck serial_device_control(RDPCLIENT * This, NTHANDLE handle, uint32 request, STREAM in, STREAM out)
701*c2c66affSColin Finck {
702*c2c66affSColin Finck 	int flush_mask, purge_mask;
703*c2c66affSColin Finck 	uint32 result, modemstate;
704*c2c66affSColin Finck 	uint8 immediate;
705*c2c66affSColin Finck 	SERIAL_DEVICE *pser_inf;
706*c2c66affSColin Finck 	struct termios *ptermios;
707*c2c66affSColin Finck 
708*c2c66affSColin Finck 	if ((request >> 16) != FILE_DEVICE_SERIAL_PORT)
709*c2c66affSColin Finck 		return STATUS_INVALID_PARAMETER;
710*c2c66affSColin Finck 
711*c2c66affSColin Finck 	pser_inf = get_serial_info(This, handle);
712*c2c66affSColin Finck 	ptermios = pser_inf->ptermios;
713*c2c66affSColin Finck 
714*c2c66affSColin Finck 	/* extract operation */
715*c2c66affSColin Finck 	request >>= 2;
716*c2c66affSColin Finck 	request &= 0xfff;
717*c2c66affSColin Finck 
718*c2c66affSColin Finck 	switch (request)
719*c2c66affSColin Finck 	{
720*c2c66affSColin Finck 		case SERIAL_SET_BAUD_RATE:
721*c2c66affSColin Finck 			in_uint32_le(in, pser_inf->baud_rate);
722*c2c66affSColin Finck 			set_termios(pser_inf, handle);
723*c2c66affSColin Finck 			DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_BAUD_RATE %d\n",
724*c2c66affSColin Finck 				      pser_inf->baud_rate));
725*c2c66affSColin Finck 			break;
726*c2c66affSColin Finck 		case SERIAL_GET_BAUD_RATE:
727*c2c66affSColin Finck 			out_uint32_le(out, pser_inf->baud_rate);
728*c2c66affSColin Finck 			DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_BAUD_RATE %d\n",
729*c2c66affSColin Finck 				      pser_inf->baud_rate));
730*c2c66affSColin Finck 			break;
731*c2c66affSColin Finck 		case SERIAL_SET_QUEUE_SIZE:
732*c2c66affSColin Finck 			in_uint32_le(in, pser_inf->queue_in_size);
733*c2c66affSColin Finck 			in_uint32_le(in, pser_inf->queue_out_size);
734*c2c66affSColin Finck 			DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_QUEUE_SIZE in %d out %d\n",
735*c2c66affSColin Finck 				      pser_inf->queue_in_size, pser_inf->queue_out_size));
736*c2c66affSColin Finck 			break;
737*c2c66affSColin Finck 		case SERIAL_SET_LINE_CONTROL:
738*c2c66affSColin Finck 			in_uint8(in, pser_inf->stop_bits);
739*c2c66affSColin Finck 			in_uint8(in, pser_inf->parity);
740*c2c66affSColin Finck 			in_uint8(in, pser_inf->word_length);
741*c2c66affSColin Finck 			set_termios(pser_inf, handle);
742*c2c66affSColin Finck 			DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_LINE_CONTROL stop %d parity %d word %d\n", pser_inf->stop_bits, pser_inf->parity, pser_inf->word_length));
743*c2c66affSColin Finck 			break;
744*c2c66affSColin Finck 		case SERIAL_GET_LINE_CONTROL:
745*c2c66affSColin Finck 			DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_LINE_CONTROL\n"));
746*c2c66affSColin Finck 			out_uint8(out, pser_inf->stop_bits);
747*c2c66affSColin Finck 			out_uint8(out, pser_inf->parity);
748*c2c66affSColin Finck 			out_uint8(out, pser_inf->word_length);
749*c2c66affSColin Finck 			break;
750*c2c66affSColin Finck 		case SERIAL_IMMEDIATE_CHAR:
751*c2c66affSColin Finck 			DEBUG_SERIAL(("serial_ioctl -> SERIAL_IMMEDIATE_CHAR\n"));
752*c2c66affSColin Finck 			in_uint8(in, immediate);
753*c2c66affSColin Finck 			serial_write(This, handle, &immediate, 1, 0, &result);
754*c2c66affSColin Finck 			break;
755*c2c66affSColin Finck 		case SERIAL_CONFIG_SIZE:
756*c2c66affSColin Finck 			DEBUG_SERIAL(("serial_ioctl -> SERIAL_CONFIG_SIZE\n"));
757*c2c66affSColin Finck 			out_uint32_le(out, 0);
758*c2c66affSColin Finck 			break;
759*c2c66affSColin Finck 		case SERIAL_GET_CHARS:
760*c2c66affSColin Finck 			DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_CHARS\n"));
761*c2c66affSColin Finck 			out_uint8a(out, pser_inf->chars, 6);
762*c2c66affSColin Finck 			break;
763*c2c66affSColin Finck 		case SERIAL_SET_CHARS:
764*c2c66affSColin Finck 			DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_CHARS\n"));
765*c2c66affSColin Finck 			in_uint8a(in, pser_inf->chars, 6);
766*c2c66affSColin Finck #ifdef WITH_DEBUG_SERIAL
767*c2c66affSColin Finck 			hexdump(pser_inf->chars, 6);
768*c2c66affSColin Finck #endif
769*c2c66affSColin Finck 			set_termios(pser_inf, handle);
770*c2c66affSColin Finck 			break;
771*c2c66affSColin Finck 		case SERIAL_GET_HANDFLOW:
772*c2c66affSColin Finck 			DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_HANDFLOW\n"));
773*c2c66affSColin Finck 			get_termios(pser_inf, handle);
774*c2c66affSColin Finck 			out_uint32_le(out, pser_inf->control);
775*c2c66affSColin Finck 			out_uint32_le(out, pser_inf->xonoff);	/* Xon/Xoff */
776*c2c66affSColin Finck 			out_uint32_le(out, pser_inf->onlimit);
777*c2c66affSColin Finck 			out_uint32_le(out, pser_inf->offlimit);
778*c2c66affSColin Finck 			break;
779*c2c66affSColin Finck 		case SERIAL_SET_HANDFLOW:
780*c2c66affSColin Finck 			in_uint32_le(in, pser_inf->control);
781*c2c66affSColin Finck 			in_uint32_le(in, pser_inf->xonoff);
782*c2c66affSColin Finck 			in_uint32_le(in, pser_inf->onlimit);
783*c2c66affSColin Finck 			in_uint32_le(in, pser_inf->offlimit);
784*c2c66affSColin Finck 			DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_HANDFLOW %x %x %x %x\n",
785*c2c66affSColin Finck 				      pser_inf->control, pser_inf->xonoff, pser_inf->onlimit,
786*c2c66affSColin Finck 				      pser_inf->onlimit));
787*c2c66affSColin Finck 			set_termios(pser_inf, handle);
788*c2c66affSColin Finck 			break;
789*c2c66affSColin Finck 		case SERIAL_SET_TIMEOUTS:
790*c2c66affSColin Finck 			in_uint32(in, pser_inf->read_interval_timeout);
791*c2c66affSColin Finck 			in_uint32(in, pser_inf->read_total_timeout_multiplier);
792*c2c66affSColin Finck 			in_uint32(in, pser_inf->read_total_timeout_constant);
793*c2c66affSColin Finck 			in_uint32(in, pser_inf->write_total_timeout_multiplier);
794*c2c66affSColin Finck 			in_uint32(in, pser_inf->write_total_timeout_constant);
795*c2c66affSColin Finck 			DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_TIMEOUTS read timeout %d %d %d\n",
796*c2c66affSColin Finck 				      pser_inf->read_interval_timeout,
797*c2c66affSColin Finck 				      pser_inf->read_total_timeout_multiplier,
798*c2c66affSColin Finck 				      pser_inf->read_total_timeout_constant));
799*c2c66affSColin Finck 			break;
800*c2c66affSColin Finck 		case SERIAL_GET_TIMEOUTS:
801*c2c66affSColin Finck 			DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_TIMEOUTS read timeout %d %d %d\n",
802*c2c66affSColin Finck 				      pser_inf->read_interval_timeout,
803*c2c66affSColin Finck 				      pser_inf->read_total_timeout_multiplier,
804*c2c66affSColin Finck 				      pser_inf->read_total_timeout_constant));
805*c2c66affSColin Finck 
806*c2c66affSColin Finck 			out_uint32(out, pser_inf->read_interval_timeout);
807*c2c66affSColin Finck 			out_uint32(out, pser_inf->read_total_timeout_multiplier);
808*c2c66affSColin Finck 			out_uint32(out, pser_inf->read_total_timeout_constant);
809*c2c66affSColin Finck 			out_uint32(out, pser_inf->write_total_timeout_multiplier);
810*c2c66affSColin Finck 			out_uint32(out, pser_inf->write_total_timeout_constant);
811*c2c66affSColin Finck 			break;
812*c2c66affSColin Finck 		case SERIAL_GET_WAIT_MASK:
813*c2c66affSColin Finck 			DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_WAIT_MASK %X\n",
814*c2c66affSColin Finck 				      pser_inf->wait_mask));
815*c2c66affSColin Finck 			out_uint32(out, pser_inf->wait_mask);
816*c2c66affSColin Finck 			break;
817*c2c66affSColin Finck 		case SERIAL_SET_WAIT_MASK:
818*c2c66affSColin Finck 			in_uint32(in, pser_inf->wait_mask);
819*c2c66affSColin Finck 			DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_WAIT_MASK %X\n",
820*c2c66affSColin Finck 				      pser_inf->wait_mask));
821*c2c66affSColin Finck 			break;
822*c2c66affSColin Finck 		case SERIAL_SET_DTR:
823*c2c66affSColin Finck 			DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_DTR\n"));
824*c2c66affSColin Finck 			ioctl(handle, TIOCMGET, &result);
825*c2c66affSColin Finck 			result |= TIOCM_DTR;
826*c2c66affSColin Finck 			ioctl(handle, TIOCMSET, &result);
827*c2c66affSColin Finck 			pser_inf->dtr = 1;
828*c2c66affSColin Finck 			break;
829*c2c66affSColin Finck 		case SERIAL_CLR_DTR:
830*c2c66affSColin Finck 			DEBUG_SERIAL(("serial_ioctl -> SERIAL_CLR_DTR\n"));
831*c2c66affSColin Finck 			ioctl(handle, TIOCMGET, &result);
832*c2c66affSColin Finck 			result &= ~TIOCM_DTR;
833*c2c66affSColin Finck 			ioctl(handle, TIOCMSET, &result);
834*c2c66affSColin Finck 			pser_inf->dtr = 0;
835*c2c66affSColin Finck 			break;
836*c2c66affSColin Finck 		case SERIAL_SET_RTS:
837*c2c66affSColin Finck 			DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_RTS\n"));
838*c2c66affSColin Finck 			ioctl(handle, TIOCMGET, &result);
839*c2c66affSColin Finck 			result |= TIOCM_RTS;
840*c2c66affSColin Finck 			ioctl(handle, TIOCMSET, &result);
841*c2c66affSColin Finck 			pser_inf->rts = 1;
842*c2c66affSColin Finck 			break;
843*c2c66affSColin Finck 		case SERIAL_CLR_RTS:
844*c2c66affSColin Finck 			DEBUG_SERIAL(("serial_ioctl -> SERIAL_CLR_RTS\n"));
845*c2c66affSColin Finck 			ioctl(handle, TIOCMGET, &result);
846*c2c66affSColin Finck 			result &= ~TIOCM_RTS;
847*c2c66affSColin Finck 			ioctl(handle, TIOCMSET, &result);
848*c2c66affSColin Finck 			pser_inf->rts = 0;
849*c2c66affSColin Finck 			break;
850*c2c66affSColin Finck 		case SERIAL_GET_MODEMSTATUS:
851*c2c66affSColin Finck 			modemstate = 0;
852*c2c66affSColin Finck #ifdef TIOCMGET
853*c2c66affSColin Finck 			ioctl(handle, TIOCMGET, &result);
854*c2c66affSColin Finck 			if (result & TIOCM_CTS)
855*c2c66affSColin Finck 				modemstate |= SERIAL_MS_CTS;
856*c2c66affSColin Finck 			if (result & TIOCM_DSR)
857*c2c66affSColin Finck 				modemstate |= SERIAL_MS_DSR;
858*c2c66affSColin Finck 			if (result & TIOCM_RNG)
859*c2c66affSColin Finck 				modemstate |= SERIAL_MS_RNG;
860*c2c66affSColin Finck 			if (result & TIOCM_CAR)
861*c2c66affSColin Finck 				modemstate |= SERIAL_MS_CAR;
862*c2c66affSColin Finck 			if (result & TIOCM_DTR)
863*c2c66affSColin Finck 				modemstate |= SERIAL_MS_DTR;
864*c2c66affSColin Finck 			if (result & TIOCM_RTS)
865*c2c66affSColin Finck 				modemstate |= SERIAL_MS_RTS;
866*c2c66affSColin Finck #endif
867*c2c66affSColin Finck 			DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_MODEMSTATUS %X\n", modemstate));
868*c2c66affSColin Finck 			out_uint32_le(out, modemstate);
869*c2c66affSColin Finck 			break;
870*c2c66affSColin Finck 		case SERIAL_GET_COMMSTATUS:
871*c2c66affSColin Finck 			out_uint32_le(out, 0);	/* Errors */
872*c2c66affSColin Finck 			out_uint32_le(out, 0);	/* Hold reasons */
873*c2c66affSColin Finck 
874*c2c66affSColin Finck 			result = 0;
875*c2c66affSColin Finck #ifdef TIOCINQ
876*c2c66affSColin Finck 			ioctl(handle, TIOCINQ, &result);
877*c2c66affSColin Finck #endif
878*c2c66affSColin Finck 			out_uint32_le(out, result);	/* Amount in in queue */
879*c2c66affSColin Finck 			if (result)
880*c2c66affSColin Finck 				DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_COMMSTATUS in queue %d\n",
881*c2c66affSColin Finck 					      result));
882*c2c66affSColin Finck 
883*c2c66affSColin Finck 			result = 0;
884*c2c66affSColin Finck #ifdef TIOCOUTQ
885*c2c66affSColin Finck 			ioctl(handle, TIOCOUTQ, &result);
886*c2c66affSColin Finck #endif
887*c2c66affSColin Finck 			out_uint32_le(out, result);	/* Amount in out queue */
888*c2c66affSColin Finck 			if (result)
889*c2c66affSColin Finck 				DEBUG_SERIAL(("serial_ioctl -> SERIAL_GET_COMMSTATUS out queue %d\n", result));
890*c2c66affSColin Finck 
891*c2c66affSColin Finck 			out_uint8(out, 0);	/* EofReceived */
892*c2c66affSColin Finck 			out_uint8(out, 0);	/* WaitForImmediate */
893*c2c66affSColin Finck 			break;
894*c2c66affSColin Finck 		case SERIAL_PURGE:
895*c2c66affSColin Finck 			in_uint32(in, purge_mask);
896*c2c66affSColin Finck 			DEBUG_SERIAL(("serial_ioctl -> SERIAL_PURGE purge_mask %X\n", purge_mask));
897*c2c66affSColin Finck 			flush_mask = 0;
898*c2c66affSColin Finck 			if (purge_mask & SERIAL_PURGE_TXCLEAR)
899*c2c66affSColin Finck 				flush_mask |= TCOFLUSH;
900*c2c66affSColin Finck 			if (purge_mask & SERIAL_PURGE_RXCLEAR)
901*c2c66affSColin Finck 				flush_mask |= TCIFLUSH;
902*c2c66affSColin Finck 			if (flush_mask != 0)
903*c2c66affSColin Finck 				tcflush(handle, flush_mask);
904*c2c66affSColin Finck 			if (purge_mask & SERIAL_PURGE_TXABORT)
905*c2c66affSColin Finck 				rdpdr_abort_io(This, handle, 4, STATUS_CANCELLED);
906*c2c66affSColin Finck 			if (purge_mask & SERIAL_PURGE_RXABORT)
907*c2c66affSColin Finck 				rdpdr_abort_io(This, handle, 3, STATUS_CANCELLED);
908*c2c66affSColin Finck 			break;
909*c2c66affSColin Finck 		case SERIAL_WAIT_ON_MASK:
910*c2c66affSColin Finck 			DEBUG_SERIAL(("serial_ioctl -> SERIAL_WAIT_ON_MASK %X\n",
911*c2c66affSColin Finck 				      pser_inf->wait_mask));
912*c2c66affSColin Finck 			pser_inf->event_pending = 1;
913*c2c66affSColin Finck 			if (serial_get_event(This, handle, &result))
914*c2c66affSColin Finck 			{
915*c2c66affSColin Finck 				DEBUG_SERIAL(("WAIT end  event = %x\n", result));
916*c2c66affSColin Finck 				out_uint32_le(out, result);
917*c2c66affSColin Finck 				break;
918*c2c66affSColin Finck 			}
919*c2c66affSColin Finck 			return STATUS_PENDING;
920*c2c66affSColin Finck 			break;
921*c2c66affSColin Finck 		case SERIAL_SET_BREAK_ON:
922*c2c66affSColin Finck 			DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_BREAK_ON\n"));
923*c2c66affSColin Finck 			tcsendbreak(handle, 0);
924*c2c66affSColin Finck 			break;
925*c2c66affSColin Finck 		case SERIAL_RESET_DEVICE:
926*c2c66affSColin Finck 			DEBUG_SERIAL(("serial_ioctl -> SERIAL_RESET_DEVICE\n"));
927*c2c66affSColin Finck 			break;
928*c2c66affSColin Finck 		case SERIAL_SET_BREAK_OFF:
929*c2c66affSColin Finck 			DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_BREAK_OFF\n"));
930*c2c66affSColin Finck 			break;
931*c2c66affSColin Finck 		case SERIAL_SET_XOFF:
932*c2c66affSColin Finck 			DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_XOFF\n"));
933*c2c66affSColin Finck 			break;
934*c2c66affSColin Finck 		case SERIAL_SET_XON:
935*c2c66affSColin Finck 			DEBUG_SERIAL(("serial_ioctl -> SERIAL_SET_XON\n"));
936*c2c66affSColin Finck 			tcflow(handle, TCION);
937*c2c66affSColin Finck 			break;
938*c2c66affSColin Finck 		default:
939*c2c66affSColin Finck 			unimpl("SERIAL IOCTL %d\n", request);
940*c2c66affSColin Finck 			return STATUS_INVALID_PARAMETER;
941*c2c66affSColin Finck 	}
942*c2c66affSColin Finck 
943*c2c66affSColin Finck 	return STATUS_SUCCESS;
944*c2c66affSColin Finck }
945*c2c66affSColin Finck 
946*c2c66affSColin Finck BOOL
serial_get_event(RDPCLIENT * This,NTHANDLE handle,uint32 * result)947*c2c66affSColin Finck serial_get_event(RDPCLIENT * This, NTHANDLE handle, uint32 * result)
948*c2c66affSColin Finck {
949*c2c66affSColin Finck 	int index;
950*c2c66affSColin Finck 	SERIAL_DEVICE *pser_inf;
951*c2c66affSColin Finck 	int bytes;
952*c2c66affSColin Finck 	BOOL ret = False;
953*c2c66affSColin Finck 
954*c2c66affSColin Finck 	*result = 0;
955*c2c66affSColin Finck 	index = get_device_index(This, handle);
956*c2c66affSColin Finck 	if (index < 0)
957*c2c66affSColin Finck 		return False;
958*c2c66affSColin Finck 
959*c2c66affSColin Finck #ifdef TIOCINQ
960*c2c66affSColin Finck 	pser_inf = (SERIAL_DEVICE *) This->rdpdr_device[index].pdevice_data;
961*c2c66affSColin Finck 
962*c2c66affSColin Finck 	ioctl(handle, TIOCINQ, &bytes);
963*c2c66affSColin Finck 
964*c2c66affSColin Finck 	if (bytes > 0)
965*c2c66affSColin Finck 	{
966*c2c66affSColin Finck 		DEBUG_SERIAL(("serial_get_event Bytes %d\n", bytes));
967*c2c66affSColin Finck 		if (bytes > pser_inf->event_rlsd)
968*c2c66affSColin Finck 		{
969*c2c66affSColin Finck 			pser_inf->event_rlsd = bytes;
970*c2c66affSColin Finck 			if (pser_inf->wait_mask & SERIAL_EV_RLSD)
971*c2c66affSColin Finck 			{
972*c2c66affSColin Finck 				DEBUG_SERIAL(("Event -> SERIAL_EV_RLSD \n"));
973*c2c66affSColin Finck 				*result |= SERIAL_EV_RLSD;
974*c2c66affSColin Finck 				ret = True;
975*c2c66affSColin Finck 			}
976*c2c66affSColin Finck 
977*c2c66affSColin Finck 		}
978*c2c66affSColin Finck 
979*c2c66affSColin Finck 		if ((bytes > 1) && (pser_inf->wait_mask & SERIAL_EV_RXFLAG))
980*c2c66affSColin Finck 		{
981*c2c66affSColin Finck 			DEBUG_SERIAL(("Event -> SERIAL_EV_RXFLAG Bytes %d\n", bytes));
982*c2c66affSColin Finck 			*result |= SERIAL_EV_RXFLAG;
983*c2c66affSColin Finck 			ret = True;
984*c2c66affSColin Finck 		}
985*c2c66affSColin Finck 		if ((pser_inf->wait_mask & SERIAL_EV_RXCHAR))
986*c2c66affSColin Finck 		{
987*c2c66affSColin Finck 			DEBUG_SERIAL(("Event -> SERIAL_EV_RXCHAR Bytes %d\n", bytes));
988*c2c66affSColin Finck 			*result |= SERIAL_EV_RXCHAR;
989*c2c66affSColin Finck 			ret = True;
990*c2c66affSColin Finck 		}
991*c2c66affSColin Finck 
992*c2c66affSColin Finck 	}
993*c2c66affSColin Finck 	else
994*c2c66affSColin Finck 	{
995*c2c66affSColin Finck 		pser_inf->event_rlsd = 0;
996*c2c66affSColin Finck 	}
997*c2c66affSColin Finck #endif
998*c2c66affSColin Finck 
999*c2c66affSColin Finck #ifdef TIOCOUTQ
1000*c2c66affSColin Finck 	ioctl(handle, TIOCOUTQ, &bytes);
1001*c2c66affSColin Finck 	if ((bytes == 0)
1002*c2c66affSColin Finck 	    && (pser_inf->event_txempty > 0) && (pser_inf->wait_mask & SERIAL_EV_TXEMPTY))
1003*c2c66affSColin Finck 	{
1004*c2c66affSColin Finck 
1005*c2c66affSColin Finck 		DEBUG_SERIAL(("Event -> SERIAL_EV_TXEMPTY\n"));
1006*c2c66affSColin Finck 		*result |= SERIAL_EV_TXEMPTY;
1007*c2c66affSColin Finck 		ret = True;
1008*c2c66affSColin Finck 	}
1009*c2c66affSColin Finck 	pser_inf->event_txempty = bytes;
1010*c2c66affSColin Finck #endif
1011*c2c66affSColin Finck 
1012*c2c66affSColin Finck 	ioctl(handle, TIOCMGET, &bytes);
1013*c2c66affSColin Finck 	if ((bytes & TIOCM_DSR) != pser_inf->event_dsr)
1014*c2c66affSColin Finck 	{
1015*c2c66affSColin Finck 		pser_inf->event_dsr = bytes & TIOCM_DSR;
1016*c2c66affSColin Finck 		if (pser_inf->wait_mask & SERIAL_EV_DSR)
1017*c2c66affSColin Finck 		{
1018*c2c66affSColin Finck 			DEBUG_SERIAL(("event -> SERIAL_EV_DSR %s\n",
1019*c2c66affSColin Finck 				      (bytes & TIOCM_DSR) ? "ON" : "OFF"));
1020*c2c66affSColin Finck 			*result |= SERIAL_EV_DSR;
1021*c2c66affSColin Finck 			ret = True;
1022*c2c66affSColin Finck 		}
1023*c2c66affSColin Finck 	}
1024*c2c66affSColin Finck 
1025*c2c66affSColin Finck 	if ((bytes & TIOCM_CTS) != pser_inf->event_cts)
1026*c2c66affSColin Finck 	{
1027*c2c66affSColin Finck 		pser_inf->event_cts = bytes & TIOCM_CTS;
1028*c2c66affSColin Finck 		if (pser_inf->wait_mask & SERIAL_EV_CTS)
1029*c2c66affSColin Finck 		{
1030*c2c66affSColin Finck 			DEBUG_SERIAL((" EVENT-> SERIAL_EV_CTS %s\n",
1031*c2c66affSColin Finck 				      (bytes & TIOCM_CTS) ? "ON" : "OFF"));
1032*c2c66affSColin Finck 			*result |= SERIAL_EV_CTS;
1033*c2c66affSColin Finck 			ret = True;
1034*c2c66affSColin Finck 		}
1035*c2c66affSColin Finck 	}
1036*c2c66affSColin Finck 
1037*c2c66affSColin Finck 	if (ret)
1038*c2c66affSColin Finck 		pser_inf->event_pending = 0;
1039*c2c66affSColin Finck 
1040*c2c66affSColin Finck 	return ret;
1041*c2c66affSColin Finck }
1042*c2c66affSColin Finck 
1043*c2c66affSColin Finck /* Read timeout for a given file descripter (device) when adding fd's to select() */
1044*c2c66affSColin Finck BOOL
serial_get_timeout(RDPCLIENT * This,NTHANDLE handle,uint32 length,uint32 * timeout,uint32 * itv_timeout)1045*c2c66affSColin Finck serial_get_timeout(RDPCLIENT * This, NTHANDLE handle, uint32 length, uint32 * timeout, uint32 * itv_timeout)
1046*c2c66affSColin Finck {
1047*c2c66affSColin Finck 	int index;
1048*c2c66affSColin Finck 	SERIAL_DEVICE *pser_inf;
1049*c2c66affSColin Finck 
1050*c2c66affSColin Finck 	index = get_device_index(This, handle);
1051*c2c66affSColin Finck 	if (index < 0)
1052*c2c66affSColin Finck 		return True;
1053*c2c66affSColin Finck 
1054*c2c66affSColin Finck 	if (This->rdpdr_device[index].device_type != DEVICE_TYPE_SERIAL)
1055*c2c66affSColin Finck 	{
1056*c2c66affSColin Finck 		return False;
1057*c2c66affSColin Finck 	}
1058*c2c66affSColin Finck 
1059*c2c66affSColin Finck 	pser_inf = (SERIAL_DEVICE *) This->rdpdr_device[index].pdevice_data;
1060*c2c66affSColin Finck 
1061*c2c66affSColin Finck 	*timeout =
1062*c2c66affSColin Finck 		pser_inf->read_total_timeout_multiplier * length +
1063*c2c66affSColin Finck 		pser_inf->read_total_timeout_constant;
1064*c2c66affSColin Finck 	*itv_timeout = pser_inf->read_interval_timeout;
1065*c2c66affSColin Finck 	return True;
1066*c2c66affSColin Finck }
1067*c2c66affSColin Finck 
1068*c2c66affSColin Finck DEVICE_FNS serial_fns = {
1069*c2c66affSColin Finck 	serial_create,
1070*c2c66affSColin Finck 	serial_close,
1071*c2c66affSColin Finck 	serial_read,
1072*c2c66affSColin Finck 	serial_write,
1073*c2c66affSColin Finck 	serial_device_control
1074*c2c66affSColin Finck };
1075