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
);
246 *realhost
= dupstr(cfg
->serline
);
251 static void serial_free(void *handle
)
253 Serial serial
= (Serial
) handle
;
255 serial_terminate(serial
);
259 static void serial_reconfig(void *handle
, Config
*cfg
)
261 Serial serial
= (Serial
) handle
;
264 err
= serial_configure(serial
, serial
->port
, cfg
);
267 * FIXME: what should we do if err returns something?
272 * Called to send data down the serial connection.
274 static int serial_send(void *handle
, char *buf
, int len
)
276 Serial serial
= (Serial
) handle
;
278 if (serial
->out
== NULL
)
281 serial
->bufsize
= handle_write(serial
->out
, buf
, len
);
282 return serial
->bufsize
;
286 * Called to query the current sendability status.
288 static int serial_sendbuffer(void *handle
)
290 Serial serial
= (Serial
) handle
;
291 return serial
->bufsize
;
295 * Called to set the size of the window
297 static void serial_size(void *handle
, int width
, int height
)
304 * Send serial special codes.
306 static void serial_special(void *handle
, Telnet_Special code
)
309 * FIXME: serial break? XON? XOFF?
315 * Return a list of the special codes that make sense in this
318 static const struct telnet_special
*serial_get_specials(void *handle
)
321 * FIXME: serial break? XON? XOFF?
326 static int serial_connected(void *handle
)
328 return 1; /* always connected */
331 static int serial_sendok(void *handle
)
336 static void serial_unthrottle(void *handle
, int backlog
)
338 Serial serial
= (Serial
) handle
;
340 handle_unthrottle(serial
->in
, backlog
);
343 static int serial_ldisc(void *handle
, int option
)
346 * Local editing and local echo are off by default.
351 static void serial_provide_ldisc(void *handle
, void *ldisc
)
353 /* This is a stub. */
356 static void serial_provide_logctx(void *handle
, void *logctx
)
358 /* This is a stub. */
361 static int serial_exitcode(void *handle
)
363 Serial serial
= (Serial
) handle
;
364 if (serial
->port
!= NULL
)
365 return -1; /* still connected */
367 /* Exit codes are a meaningless concept with serial ports */
372 * cfg_info for Serial does nothing at all.
374 static int serial_cfg_info(void *handle
)
379 Backend serial_backend
= {
392 serial_provide_ldisc
,
393 serial_provide_logctx
,