2 * Serial back end (Windows-specific).
9 * + looks as if you do this by calling SetCommBreak(handle),
10 * then waiting a bit, then doing ClearCommBreak(handle). A
11 * small job for timing.c, methinks.
13 * - why are we dropping data when talking to judicator?
22 #define SERIAL_MAX_BACKLOG 4096
24 typedef struct serial_backend_data
{
26 struct handle
*out
, *in
;
31 static void serial_terminate(Serial serial
)
34 handle_free(serial
->out
);
38 handle_free(serial
->in
);
42 CloseHandle(serial
->port
);
47 static int serial_gotdata(struct handle
*h
, void *data
, int len
)
49 Serial serial
= (Serial
)handle_get_privdata(h
);
51 const char *error_msg
;
54 * Currently, len==0 should never happen because we're
55 * ignoring EOFs. However, it seems not totally impossible
56 * that this same back end might be usable to talk to named
57 * pipes or some other non-serial device, in which case EOF
58 * may become meaningful here.
61 error_msg
= "End of file reading from serial device";
63 error_msg
= "Error reading from serial device";
65 serial_terminate(serial
);
67 notify_remote_exit(serial
->frontend
);
69 logevent(serial
->frontend
, error_msg
);
71 connection_fatal(serial
->frontend
, "%s", error_msg
);
73 return 0; /* placate optimiser */
75 return from_backend(serial
->frontend
, 0, data
, len
);
79 static void serial_sentdata(struct handle
*h
, int new_backlog
)
81 Serial serial
= (Serial
)handle_get_privdata(h
);
82 if (new_backlog
< 0) {
83 const char *error_msg
= "Error writing to serial device";
85 serial_terminate(serial
);
87 notify_remote_exit(serial
->frontend
);
89 logevent(serial
->frontend
, error_msg
);
91 connection_fatal(serial
->frontend
, "%s", error_msg
);
93 serial
->bufsize
= new_backlog
;
97 static const char *serial_configure(Serial serial
, HANDLE serport
, Config
*cfg
)
100 COMMTIMEOUTS timeouts
;
103 * Set up the serial port parameters. If we can't even
104 * GetCommState, we ignore the problem on the grounds that the
105 * user might have pointed us at some other type of two-way
106 * device instead of a serial port.
108 if (GetCommState(serport
, &dcb
)) {
116 dcb
.fDtrControl
= DTR_CONTROL_ENABLE
;
117 dcb
.fDsrSensitivity
= FALSE
;
118 dcb
.fTXContinueOnXoff
= FALSE
;
121 dcb
.fErrorChar
= FALSE
;
123 dcb
.fRtsControl
= RTS_CONTROL_ENABLE
;
124 dcb
.fAbortOnError
= FALSE
;
125 dcb
.fOutxCtsFlow
= FALSE
;
126 dcb
.fOutxDsrFlow
= FALSE
;
129 * Configurable parameters.
131 dcb
.BaudRate
= cfg
->serspeed
;
132 msg
= dupprintf("Configuring baud rate %d", cfg
->serspeed
);
133 logevent(serial
->frontend
, msg
);
136 dcb
.ByteSize
= cfg
->serdatabits
;
137 msg
= dupprintf("Configuring %d data bits", cfg
->serdatabits
);
138 logevent(serial
->frontend
, msg
);
141 switch (cfg
->serstopbits
) {
142 case 2: dcb
.StopBits
= ONESTOPBIT
; str
= "1"; break;
143 case 3: dcb
.StopBits
= ONE5STOPBITS
; str
= "1.5"; break;
144 case 4: dcb
.StopBits
= TWOSTOPBITS
; str
= "2"; break;
145 default: return "Invalid number of stop bits (need 1, 1.5 or 2)";
147 msg
= dupprintf("Configuring %s data bits", str
);
148 logevent(serial
->frontend
, msg
);
151 switch (cfg
->serparity
) {
152 case SER_PAR_NONE
: dcb
.Parity
= NOPARITY
; str
= "no"; break;
153 case SER_PAR_ODD
: dcb
.Parity
= ODDPARITY
; str
= "odd"; break;
154 case SER_PAR_EVEN
: dcb
.Parity
= EVENPARITY
; str
= "even"; break;
155 case SER_PAR_MARK
: dcb
.Parity
= MARKPARITY
; str
= "mark"; break;
156 case SER_PAR_SPACE
: dcb
.Parity
= SPACEPARITY
; str
= "space"; break;
158 msg
= dupprintf("Configuring %s parity", str
);
159 logevent(serial
->frontend
, msg
);
162 switch (cfg
->serflow
) {
166 case SER_FLOW_XONXOFF
:
167 dcb
.fOutX
= dcb
.fInX
= TRUE
;
170 case SER_FLOW_RTSCTS
:
171 dcb
.fRtsControl
= RTS_CONTROL_HANDSHAKE
;
172 dcb
.fOutxCtsFlow
= TRUE
;
175 case SER_FLOW_DSRDTR
:
176 dcb
.fDtrControl
= DTR_CONTROL_HANDSHAKE
;
177 dcb
.fOutxDsrFlow
= TRUE
;
181 msg
= dupprintf("Configuring %s flow control", str
);
182 logevent(serial
->frontend
, msg
);
185 if (!SetCommState(serport
, &dcb
))
186 return "Unable to configure serial port";
188 timeouts
.ReadIntervalTimeout
= 1;
189 timeouts
.ReadTotalTimeoutMultiplier
= 0;
190 timeouts
.ReadTotalTimeoutConstant
= 0;
191 timeouts
.WriteTotalTimeoutMultiplier
= 0;
192 timeouts
.WriteTotalTimeoutConstant
= 0;
193 if (!SetCommTimeouts(serport
, &timeouts
))
194 return "Unable to configure serial timeouts";
201 * Called to set up the serial connection.
203 * Returns an error message, or NULL on success.
205 * Also places the canonical host name into `realhost'. It must be
206 * freed by the caller.
208 static const char *serial_init(void *frontend_handle
, void **backend_handle
,
210 char *host
, int port
, char **realhost
, int nodelay
,
217 serial
= snew(struct serial_backend_data
);
219 serial
->out
= serial
->in
= NULL
;
221 *backend_handle
= serial
;
223 serial
->frontend
= frontend_handle
;
226 char *msg
= dupprintf("Opening serial device %s", cfg
->serline
);
227 logevent(serial
->frontend
, msg
);
230 serport
= CreateFile(cfg
->serline
, GENERIC_READ
| GENERIC_WRITE
, 0, NULL
,
231 OPEN_EXISTING
, FILE_FLAG_OVERLAPPED
, NULL
);
232 if (serport
== INVALID_HANDLE_VALUE
)
233 return "Unable to open serial port";
235 err
= serial_configure(serial
, serport
, cfg
);
239 serial
->port
= serport
;
240 serial
->out
= handle_output_new(serport
, serial_sentdata
, serial
,
241 HANDLE_FLAG_OVERLAPPED
);
242 serial
->in
= handle_input_new(serport
, serial_gotdata
, serial
,
243 HANDLE_FLAG_OVERLAPPED
|
244 HANDLE_FLAG_IGNOREEOF
|
245 HANDLE_FLAG_UNITBUFFER
);
247 *realhost
= dupstr(cfg
->serline
);
252 static void serial_free(void *handle
)
254 Serial serial
= (Serial
) handle
;
256 serial_terminate(serial
);
260 static void serial_reconfig(void *handle
, Config
*cfg
)
262 Serial serial
= (Serial
) handle
;
265 err
= serial_configure(serial
, serial
->port
, cfg
);
268 * FIXME: what should we do if err returns something?
273 * Called to send data down the serial connection.
275 static int serial_send(void *handle
, char *buf
, int len
)
277 Serial serial
= (Serial
) handle
;
279 if (serial
->out
== NULL
)
282 serial
->bufsize
= handle_write(serial
->out
, buf
, len
);
283 return serial
->bufsize
;
287 * Called to query the current sendability status.
289 static int serial_sendbuffer(void *handle
)
291 Serial serial
= (Serial
) handle
;
292 return serial
->bufsize
;
296 * Called to set the size of the window
298 static void serial_size(void *handle
, int width
, int height
)
305 * Send serial special codes.
307 static void serial_special(void *handle
, Telnet_Special code
)
310 * FIXME: serial break? XON? XOFF?
316 * Return a list of the special codes that make sense in this
319 static const struct telnet_special
*serial_get_specials(void *handle
)
322 * FIXME: serial break? XON? XOFF?
327 static int serial_connected(void *handle
)
329 return 1; /* always connected */
332 static int serial_sendok(void *handle
)
337 static void serial_unthrottle(void *handle
, int backlog
)
339 Serial serial
= (Serial
) handle
;
341 handle_unthrottle(serial
->in
, backlog
);
344 static int serial_ldisc(void *handle
, int option
)
347 * Local editing and local echo are off by default.
352 static void serial_provide_ldisc(void *handle
, void *ldisc
)
354 /* This is a stub. */
357 static void serial_provide_logctx(void *handle
, void *logctx
)
359 /* This is a stub. */
362 static int serial_exitcode(void *handle
)
364 Serial serial
= (Serial
) handle
;
365 if (serial
->port
!= NULL
)
366 return -1; /* still connected */
368 /* Exit codes are a meaningless concept with serial ports */
373 * cfg_info for Serial does nothing at all.
375 static int serial_cfg_info(void *handle
)
380 Backend serial_backend
= {
393 serial_provide_ldisc
,
394 serial_provide_logctx
,