xref: /openbsd-src/gnu/usr.bin/binutils/gdb/serial.c (revision 63addd46c1e40ca0f49488ddcdc4ab598023b0c1)
1e93f7393Sniklas /* Generic serial interface routines
2b725ae77Skettenis 
3b725ae77Skettenis    Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
4b725ae77Skettenis    2001, 2002 Free Software Foundation, Inc.
5e93f7393Sniklas 
6e93f7393Sniklas    This file is part of GDB.
7e93f7393Sniklas 
8e93f7393Sniklas    This program is free software; you can redistribute it and/or modify
9e93f7393Sniklas    it under the terms of the GNU General Public License as published by
10e93f7393Sniklas    the Free Software Foundation; either version 2 of the License, or
11e93f7393Sniklas    (at your option) any later version.
12e93f7393Sniklas 
13e93f7393Sniklas    This program is distributed in the hope that it will be useful,
14e93f7393Sniklas    but WITHOUT ANY WARRANTY; without even the implied warranty of
15e93f7393Sniklas    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16e93f7393Sniklas    GNU General Public License for more details.
17e93f7393Sniklas 
18e93f7393Sniklas    You should have received a copy of the GNU General Public License
19e93f7393Sniklas    along with this program; if not, write to the Free Software
20b725ae77Skettenis    Foundation, Inc., 59 Temple Place - Suite 330,
21b725ae77Skettenis    Boston, MA 02111-1307, USA.  */
22e93f7393Sniklas 
23e93f7393Sniklas #include "defs.h"
24e93f7393Sniklas #include <ctype.h>
25e93f7393Sniklas #include "serial.h"
26e93f7393Sniklas #include "gdb_string.h"
27e93f7393Sniklas #include "gdbcmd.h"
28e93f7393Sniklas 
29b725ae77Skettenis extern void _initialize_serial (void);
30b725ae77Skettenis 
31b725ae77Skettenis /* Is serial being debugged? */
32b725ae77Skettenis 
33b725ae77Skettenis static int global_serial_debug_p;
34b725ae77Skettenis 
35e93f7393Sniklas /* Linked list of serial I/O handlers */
36e93f7393Sniklas 
37e93f7393Sniklas static struct serial_ops *serial_ops_list = NULL;
38e93f7393Sniklas 
39e93f7393Sniklas /* This is the last serial stream opened.  Used by connect command. */
40e93f7393Sniklas 
41b725ae77Skettenis static struct serial *last_serial_opened = NULL;
42e93f7393Sniklas 
43e93f7393Sniklas /* Pointer to list of scb's. */
44e93f7393Sniklas 
45b725ae77Skettenis static struct serial *scb_base;
46e93f7393Sniklas 
47e93f7393Sniklas /* Non-NULL gives filename which contains a recording of the remote session,
48e93f7393Sniklas    suitable for playback by gdbserver. */
49e93f7393Sniklas 
50e93f7393Sniklas static char *serial_logfile = NULL;
51b725ae77Skettenis static struct ui_file *serial_logfp = NULL;
52e93f7393Sniklas 
53b725ae77Skettenis static struct serial_ops *serial_interface_lookup (char *);
54b725ae77Skettenis static void serial_logchar (struct ui_file *stream, int ch_type, int ch, int timeout);
55b725ae77Skettenis static const char logbase_hex[] = "hex";
56b725ae77Skettenis static const char logbase_octal[] = "octal";
57b725ae77Skettenis static const char logbase_ascii[] = "ascii";
58b725ae77Skettenis static const char *logbase_enums[] =
59b725ae77Skettenis {logbase_hex, logbase_octal, logbase_ascii, NULL};
60b725ae77Skettenis static const char *serial_logbase = logbase_ascii;
61e93f7393Sniklas 
62e93f7393Sniklas 
63b725ae77Skettenis static int serial_current_type = 0;
64e93f7393Sniklas 
65b725ae77Skettenis /* Log char CH of type CHTYPE, with TIMEOUT */
66e93f7393Sniklas 
67e93f7393Sniklas /* Define bogus char to represent a BREAK.  Should be careful to choose a value
68e93f7393Sniklas    that can't be confused with a normal char, or an error code.  */
69e93f7393Sniklas #define SERIAL_BREAK 1235
70e93f7393Sniklas 
71e93f7393Sniklas static void
serial_logchar(struct ui_file * stream,int ch_type,int ch,int timeout)72b725ae77Skettenis serial_logchar (struct ui_file *stream, int ch_type, int ch, int timeout)
73e93f7393Sniklas {
74b725ae77Skettenis   if (ch_type != serial_current_type)
75b725ae77Skettenis     {
76b725ae77Skettenis       fprintf_unfiltered (stream, "\n%c ", ch_type);
77b725ae77Skettenis       serial_current_type = ch_type;
78b725ae77Skettenis     }
79b725ae77Skettenis 
80e93f7393Sniklas   if (serial_logbase != logbase_ascii)
81b725ae77Skettenis     fputc_unfiltered (' ', stream);
82e93f7393Sniklas 
83e93f7393Sniklas   switch (ch)
84e93f7393Sniklas     {
85e93f7393Sniklas     case SERIAL_TIMEOUT:
86b725ae77Skettenis       fprintf_unfiltered (stream, "<Timeout: %d seconds>", timeout);
87e93f7393Sniklas       return;
88e93f7393Sniklas     case SERIAL_ERROR:
89b725ae77Skettenis       fprintf_unfiltered (stream, "<Error: %s>", safe_strerror (errno));
90e93f7393Sniklas       return;
91e93f7393Sniklas     case SERIAL_EOF:
92b725ae77Skettenis       fputs_unfiltered ("<Eof>", stream);
93e93f7393Sniklas       return;
94e93f7393Sniklas     case SERIAL_BREAK:
95b725ae77Skettenis       fputs_unfiltered ("<Break>", stream);
96e93f7393Sniklas       return;
97e93f7393Sniklas     default:
98e93f7393Sniklas       if (serial_logbase == logbase_hex)
99b725ae77Skettenis 	fprintf_unfiltered (stream, "%02x", ch & 0xff);
100e93f7393Sniklas       else if (serial_logbase == logbase_octal)
101b725ae77Skettenis 	fprintf_unfiltered (stream, "%03o", ch & 0xff);
102e93f7393Sniklas       else
103e93f7393Sniklas 	switch (ch)
104e93f7393Sniklas 	  {
105b725ae77Skettenis 	  case '\\':
106b725ae77Skettenis 	    fputs_unfiltered ("\\\\", stream);
107b725ae77Skettenis 	    break;
108b725ae77Skettenis 	  case '\b':
109b725ae77Skettenis 	    fputs_unfiltered ("\\b", stream);
110b725ae77Skettenis 	    break;
111b725ae77Skettenis 	  case '\f':
112b725ae77Skettenis 	    fputs_unfiltered ("\\f", stream);
113b725ae77Skettenis 	    break;
114b725ae77Skettenis 	  case '\n':
115b725ae77Skettenis 	    fputs_unfiltered ("\\n", stream);
116b725ae77Skettenis 	    break;
117b725ae77Skettenis 	  case '\r':
118b725ae77Skettenis 	    fputs_unfiltered ("\\r", stream);
119b725ae77Skettenis 	    break;
120b725ae77Skettenis 	  case '\t':
121b725ae77Skettenis 	    fputs_unfiltered ("\\t", stream);
122b725ae77Skettenis 	    break;
123b725ae77Skettenis 	  case '\v':
124b725ae77Skettenis 	    fputs_unfiltered ("\\v", stream);
125b725ae77Skettenis 	    break;
126b725ae77Skettenis 	  default:
127b725ae77Skettenis 	    fprintf_unfiltered (stream, isprint (ch) ? "%c" : "\\x%02x", ch & 0xFF);
128b725ae77Skettenis 	    break;
129e93f7393Sniklas 	  }
130e93f7393Sniklas     }
131e93f7393Sniklas }
132e93f7393Sniklas 
133b725ae77Skettenis void
serial_log_command(const char * cmd)134b725ae77Skettenis serial_log_command (const char *cmd)
135e93f7393Sniklas {
136b725ae77Skettenis   if (!serial_logfp)
137b725ae77Skettenis     return;
138e93f7393Sniklas 
139b725ae77Skettenis   serial_current_type = 'c';
140b725ae77Skettenis 
141b725ae77Skettenis   fputs_unfiltered ("\nc ", serial_logfp);
142b725ae77Skettenis   fputs_unfiltered (cmd, serial_logfp);
143b725ae77Skettenis 
144e93f7393Sniklas   /* Make sure that the log file is as up-to-date as possible,
145e93f7393Sniklas      in case we are getting ready to dump core or something. */
146b725ae77Skettenis   gdb_flush (serial_logfp);
147e93f7393Sniklas }
148e93f7393Sniklas 
149b725ae77Skettenis 
150e93f7393Sniklas static struct serial_ops *
serial_interface_lookup(char * name)151b725ae77Skettenis serial_interface_lookup (char *name)
152e93f7393Sniklas {
153e93f7393Sniklas   struct serial_ops *ops;
154e93f7393Sniklas 
155e93f7393Sniklas   for (ops = serial_ops_list; ops; ops = ops->next)
156e93f7393Sniklas     if (strcmp (name, ops->name) == 0)
157e93f7393Sniklas       return ops;
158e93f7393Sniklas 
159e93f7393Sniklas   return NULL;
160e93f7393Sniklas }
161e93f7393Sniklas 
162e93f7393Sniklas void
serial_add_interface(struct serial_ops * optable)163b725ae77Skettenis serial_add_interface (struct serial_ops *optable)
164e93f7393Sniklas {
165e93f7393Sniklas   optable->next = serial_ops_list;
166e93f7393Sniklas   serial_ops_list = optable;
167e93f7393Sniklas }
168e93f7393Sniklas 
169e93f7393Sniklas /* Open up a device or a network socket, depending upon the syntax of NAME. */
170e93f7393Sniklas 
171b725ae77Skettenis struct serial *
serial_open(const char * name)172b725ae77Skettenis serial_open (const char *name)
173e93f7393Sniklas {
174b725ae77Skettenis   struct serial *scb;
175e93f7393Sniklas   struct serial_ops *ops;
176b725ae77Skettenis   const char *open_name = name;
177e93f7393Sniklas 
178e93f7393Sniklas   for (scb = scb_base; scb; scb = scb->next)
179e93f7393Sniklas     if (scb->name && strcmp (scb->name, name) == 0)
180e93f7393Sniklas       {
181e93f7393Sniklas 	scb->refcnt++;
182e93f7393Sniklas 	return scb;
183e93f7393Sniklas       }
184e93f7393Sniklas 
185e93f7393Sniklas   if (strcmp (name, "pc") == 0)
186e93f7393Sniklas     ops = serial_interface_lookup ("pc");
187e93f7393Sniklas   else if (strchr (name, ':'))
188e93f7393Sniklas     ops = serial_interface_lookup ("tcp");
189e93f7393Sniklas   else if (strncmp (name, "lpt", 3) == 0)
190e93f7393Sniklas     ops = serial_interface_lookup ("parallel");
191b725ae77Skettenis   else if (strncmp (name, "|", 1) == 0)
192b725ae77Skettenis     {
193b725ae77Skettenis       ops = serial_interface_lookup ("pipe");
194b725ae77Skettenis       open_name = name + 1; /* discard ``|'' */
195b725ae77Skettenis     }
196e93f7393Sniklas   else
197e93f7393Sniklas     ops = serial_interface_lookup ("hardwire");
198e93f7393Sniklas 
199e93f7393Sniklas   if (!ops)
200e93f7393Sniklas     return NULL;
201e93f7393Sniklas 
202b725ae77Skettenis   scb = XMALLOC (struct serial);
203e93f7393Sniklas 
204e93f7393Sniklas   scb->ops = ops;
205e93f7393Sniklas 
206e93f7393Sniklas   scb->bufcnt = 0;
207e93f7393Sniklas   scb->bufp = scb->buf;
208e93f7393Sniklas 
209b725ae77Skettenis   if (scb->ops->open (scb, open_name))
210e93f7393Sniklas     {
211b725ae77Skettenis       xfree (scb);
212e93f7393Sniklas       return NULL;
213e93f7393Sniklas     }
214e93f7393Sniklas 
215b725ae77Skettenis   scb->name = xstrdup (name);
216e93f7393Sniklas   scb->next = scb_base;
217e93f7393Sniklas   scb->refcnt = 1;
218b725ae77Skettenis   scb->debug_p = 0;
219b725ae77Skettenis   scb->async_state = 0;
220b725ae77Skettenis   scb->async_handler = NULL;
221b725ae77Skettenis   scb->async_context = NULL;
222e93f7393Sniklas   scb_base = scb;
223e93f7393Sniklas 
224e93f7393Sniklas   last_serial_opened = scb;
225e93f7393Sniklas 
226e93f7393Sniklas   if (serial_logfile != NULL)
227e93f7393Sniklas     {
228b725ae77Skettenis       serial_logfp = gdb_fopen (serial_logfile, "w");
229e93f7393Sniklas       if (serial_logfp == NULL)
230e93f7393Sniklas 	perror_with_name (serial_logfile);
231e93f7393Sniklas     }
232e93f7393Sniklas 
233e93f7393Sniklas   return scb;
234e93f7393Sniklas }
235e93f7393Sniklas 
236b725ae77Skettenis struct serial *
serial_fdopen(const int fd)237b725ae77Skettenis serial_fdopen (const int fd)
238e93f7393Sniklas {
239b725ae77Skettenis   struct serial *scb;
240e93f7393Sniklas   struct serial_ops *ops;
241e93f7393Sniklas 
242e93f7393Sniklas   for (scb = scb_base; scb; scb = scb->next)
243e93f7393Sniklas     if (scb->fd == fd)
244e93f7393Sniklas       {
245e93f7393Sniklas 	scb->refcnt++;
246e93f7393Sniklas 	return scb;
247e93f7393Sniklas       }
248e93f7393Sniklas 
249e93f7393Sniklas   ops = serial_interface_lookup ("hardwire");
250e93f7393Sniklas 
251e93f7393Sniklas   if (!ops)
252e93f7393Sniklas     return NULL;
253e93f7393Sniklas 
254b725ae77Skettenis   scb = XMALLOC (struct serial);
255e93f7393Sniklas 
256e93f7393Sniklas   scb->ops = ops;
257e93f7393Sniklas 
258e93f7393Sniklas   scb->bufcnt = 0;
259e93f7393Sniklas   scb->bufp = scb->buf;
260e93f7393Sniklas 
261e93f7393Sniklas   scb->fd = fd;
262e93f7393Sniklas 
263e93f7393Sniklas   scb->name = NULL;
264e93f7393Sniklas   scb->next = scb_base;
265e93f7393Sniklas   scb->refcnt = 1;
266b725ae77Skettenis   scb->debug_p = 0;
267b725ae77Skettenis   scb->async_state = 0;
268b725ae77Skettenis   scb->async_handler = NULL;
269b725ae77Skettenis   scb->async_context = NULL;
270e93f7393Sniklas   scb_base = scb;
271e93f7393Sniklas 
272e93f7393Sniklas   last_serial_opened = scb;
273e93f7393Sniklas 
274e93f7393Sniklas   return scb;
275e93f7393Sniklas }
276e93f7393Sniklas 
277b725ae77Skettenis static void
do_serial_close(struct serial * scb,int really_close)278b725ae77Skettenis do_serial_close (struct serial *scb, int really_close)
279e93f7393Sniklas {
280b725ae77Skettenis   struct serial *tmp_scb;
281e93f7393Sniklas 
282e93f7393Sniklas   last_serial_opened = NULL;
283e93f7393Sniklas 
284e93f7393Sniklas   if (serial_logfp)
285e93f7393Sniklas     {
286b725ae77Skettenis       fputs_unfiltered ("\nEnd of log\n", serial_logfp);
287b725ae77Skettenis       serial_current_type = 0;
288b725ae77Skettenis 
289b725ae77Skettenis       /* XXX - What if serial_logfp == gdb_stdout or gdb_stderr? */
290b725ae77Skettenis       ui_file_delete (serial_logfp);
291e93f7393Sniklas       serial_logfp = NULL;
292e93f7393Sniklas     }
293e93f7393Sniklas 
294e93f7393Sniklas /* This is bogus.  It's not our fault if you pass us a bad scb...!  Rob, you
295e93f7393Sniklas    should fix your code instead.  */
296e93f7393Sniklas 
297e93f7393Sniklas   if (!scb)
298e93f7393Sniklas     return;
299e93f7393Sniklas 
300e93f7393Sniklas   scb->refcnt--;
301e93f7393Sniklas   if (scb->refcnt > 0)
302e93f7393Sniklas     return;
303e93f7393Sniklas 
304b725ae77Skettenis   /* ensure that the FD has been taken out of async mode */
305b725ae77Skettenis   if (scb->async_handler != NULL)
306b725ae77Skettenis     serial_async (scb, NULL, NULL);
307b725ae77Skettenis 
308e93f7393Sniklas   if (really_close)
309e93f7393Sniklas     scb->ops->close (scb);
310e93f7393Sniklas 
311e93f7393Sniklas   if (scb->name)
312b725ae77Skettenis     xfree (scb->name);
313e93f7393Sniklas 
314e93f7393Sniklas   if (scb_base == scb)
315e93f7393Sniklas     scb_base = scb_base->next;
316e93f7393Sniklas   else
317e93f7393Sniklas     for (tmp_scb = scb_base; tmp_scb; tmp_scb = tmp_scb->next)
318e93f7393Sniklas       {
319e93f7393Sniklas 	if (tmp_scb->next != scb)
320e93f7393Sniklas 	  continue;
321e93f7393Sniklas 
322e93f7393Sniklas 	tmp_scb->next = tmp_scb->next->next;
323e93f7393Sniklas 	break;
324e93f7393Sniklas       }
325e93f7393Sniklas 
326b725ae77Skettenis   xfree (scb);
327e93f7393Sniklas }
328e93f7393Sniklas 
329b725ae77Skettenis void
serial_close(struct serial * scb)330b725ae77Skettenis serial_close (struct serial *scb)
331b725ae77Skettenis {
332b725ae77Skettenis   do_serial_close (scb, 1);
333b725ae77Skettenis }
334b725ae77Skettenis 
335b725ae77Skettenis void
serial_un_fdopen(struct serial * scb)336b725ae77Skettenis serial_un_fdopen (struct serial *scb)
337b725ae77Skettenis {
338b725ae77Skettenis   do_serial_close (scb, 0);
339b725ae77Skettenis }
340b725ae77Skettenis 
341b725ae77Skettenis int
serial_readchar(struct serial * scb,int timeout)342b725ae77Skettenis serial_readchar (struct serial *scb, int timeout)
343b725ae77Skettenis {
344b725ae77Skettenis   int ch;
345b725ae77Skettenis 
346b725ae77Skettenis   /* FIXME: cagney/1999-10-11: Don't enable this check until the ASYNC
347b725ae77Skettenis      code is finished. */
348b725ae77Skettenis   if (0 && serial_is_async_p (scb) && timeout < 0)
349b725ae77Skettenis     internal_error (__FILE__, __LINE__,
350b725ae77Skettenis 		    "serial_readchar: blocking read in async mode");
351b725ae77Skettenis 
352b725ae77Skettenis   ch = scb->ops->readchar (scb, timeout);
353b725ae77Skettenis   if (serial_logfp != NULL)
354b725ae77Skettenis     {
355b725ae77Skettenis       serial_logchar (serial_logfp, 'r', ch, timeout);
356b725ae77Skettenis 
357b725ae77Skettenis       /* Make sure that the log file is as up-to-date as possible,
358b725ae77Skettenis          in case we are getting ready to dump core or something. */
359b725ae77Skettenis       gdb_flush (serial_logfp);
360b725ae77Skettenis     }
361b725ae77Skettenis   if (serial_debug_p (scb))
362b725ae77Skettenis     {
363b725ae77Skettenis       fprintf_unfiltered (gdb_stdlog, "[");
364b725ae77Skettenis       serial_logchar (gdb_stdlog, 'r', ch, timeout);
365b725ae77Skettenis       fprintf_unfiltered (gdb_stdlog, "]");
366b725ae77Skettenis       gdb_flush (gdb_stdlog);
367b725ae77Skettenis     }
368b725ae77Skettenis 
369b725ae77Skettenis   return (ch);
370b725ae77Skettenis }
371b725ae77Skettenis 
372b725ae77Skettenis int
serial_write(struct serial * scb,const char * str,int len)373b725ae77Skettenis serial_write (struct serial *scb, const char *str, int len)
374b725ae77Skettenis {
375b725ae77Skettenis   if (serial_logfp != NULL)
376b725ae77Skettenis     {
377b725ae77Skettenis       int count;
378b725ae77Skettenis 
379b725ae77Skettenis       for (count = 0; count < len; count++)
380b725ae77Skettenis 	serial_logchar (serial_logfp, 'w', str[count] & 0xff, 0);
381b725ae77Skettenis 
382b725ae77Skettenis       /* Make sure that the log file is as up-to-date as possible,
383b725ae77Skettenis          in case we are getting ready to dump core or something. */
384b725ae77Skettenis       gdb_flush (serial_logfp);
385b725ae77Skettenis     }
386b725ae77Skettenis 
387b725ae77Skettenis   return (scb->ops->write (scb, str, len));
388b725ae77Skettenis }
389b725ae77Skettenis 
390b725ae77Skettenis void
serial_printf(struct serial * desc,const char * format,...)391b725ae77Skettenis serial_printf (struct serial *desc, const char *format,...)
392b725ae77Skettenis {
393b725ae77Skettenis   va_list args;
394b725ae77Skettenis   char *buf;
395b725ae77Skettenis   va_start (args, format);
396b725ae77Skettenis 
397*63addd46Skettenis   buf = xstrvprintf (format, args);
398b725ae77Skettenis   serial_write (desc, buf, strlen (buf));
399b725ae77Skettenis 
400b725ae77Skettenis   xfree (buf);
401b725ae77Skettenis   va_end (args);
402b725ae77Skettenis }
403b725ae77Skettenis 
404b725ae77Skettenis int
serial_drain_output(struct serial * scb)405b725ae77Skettenis serial_drain_output (struct serial *scb)
406b725ae77Skettenis {
407b725ae77Skettenis   return scb->ops->drain_output (scb);
408b725ae77Skettenis }
409b725ae77Skettenis 
410b725ae77Skettenis int
serial_flush_output(struct serial * scb)411b725ae77Skettenis serial_flush_output (struct serial *scb)
412b725ae77Skettenis {
413b725ae77Skettenis   return scb->ops->flush_output (scb);
414b725ae77Skettenis }
415b725ae77Skettenis 
416b725ae77Skettenis int
serial_flush_input(struct serial * scb)417b725ae77Skettenis serial_flush_input (struct serial *scb)
418b725ae77Skettenis {
419b725ae77Skettenis   return scb->ops->flush_input (scb);
420b725ae77Skettenis }
421b725ae77Skettenis 
422b725ae77Skettenis int
serial_send_break(struct serial * scb)423b725ae77Skettenis serial_send_break (struct serial *scb)
424b725ae77Skettenis {
425b725ae77Skettenis   if (serial_logfp != NULL)
426b725ae77Skettenis     serial_logchar (serial_logfp, 'w', SERIAL_BREAK, 0);
427b725ae77Skettenis 
428b725ae77Skettenis   return (scb->ops->send_break (scb));
429b725ae77Skettenis }
430b725ae77Skettenis 
431b725ae77Skettenis void
serial_raw(struct serial * scb)432b725ae77Skettenis serial_raw (struct serial *scb)
433b725ae77Skettenis {
434b725ae77Skettenis   scb->ops->go_raw (scb);
435b725ae77Skettenis }
436b725ae77Skettenis 
437b725ae77Skettenis serial_ttystate
serial_get_tty_state(struct serial * scb)438b725ae77Skettenis serial_get_tty_state (struct serial *scb)
439b725ae77Skettenis {
440b725ae77Skettenis   return scb->ops->get_tty_state (scb);
441b725ae77Skettenis }
442b725ae77Skettenis 
443b725ae77Skettenis int
serial_set_tty_state(struct serial * scb,serial_ttystate ttystate)444b725ae77Skettenis serial_set_tty_state (struct serial *scb, serial_ttystate ttystate)
445b725ae77Skettenis {
446b725ae77Skettenis   return scb->ops->set_tty_state (scb, ttystate);
447b725ae77Skettenis }
448b725ae77Skettenis 
449b725ae77Skettenis void
serial_print_tty_state(struct serial * scb,serial_ttystate ttystate,struct ui_file * stream)450b725ae77Skettenis serial_print_tty_state (struct serial *scb,
451b725ae77Skettenis 			serial_ttystate ttystate,
452b725ae77Skettenis 			struct ui_file *stream)
453b725ae77Skettenis {
454b725ae77Skettenis   scb->ops->print_tty_state (scb, ttystate, stream);
455b725ae77Skettenis }
456b725ae77Skettenis 
457b725ae77Skettenis int
serial_noflush_set_tty_state(struct serial * scb,serial_ttystate new_ttystate,serial_ttystate old_ttystate)458b725ae77Skettenis serial_noflush_set_tty_state (struct serial *scb,
459b725ae77Skettenis 			      serial_ttystate new_ttystate,
460b725ae77Skettenis 			      serial_ttystate old_ttystate)
461b725ae77Skettenis {
462b725ae77Skettenis   return scb->ops->noflush_set_tty_state (scb, new_ttystate, old_ttystate);
463b725ae77Skettenis }
464b725ae77Skettenis 
465b725ae77Skettenis int
serial_setbaudrate(struct serial * scb,int rate)466b725ae77Skettenis serial_setbaudrate (struct serial *scb, int rate)
467b725ae77Skettenis {
468b725ae77Skettenis   return scb->ops->setbaudrate (scb, rate);
469b725ae77Skettenis }
470b725ae77Skettenis 
471b725ae77Skettenis int
serial_setstopbits(struct serial * scb,int num)472b725ae77Skettenis serial_setstopbits (struct serial *scb, int num)
473b725ae77Skettenis {
474b725ae77Skettenis   return scb->ops->setstopbits (scb, num);
475b725ae77Skettenis }
476b725ae77Skettenis 
477b725ae77Skettenis int
serial_can_async_p(struct serial * scb)478b725ae77Skettenis serial_can_async_p (struct serial *scb)
479b725ae77Skettenis {
480b725ae77Skettenis   return (scb->ops->async != NULL);
481b725ae77Skettenis }
482b725ae77Skettenis 
483b725ae77Skettenis int
serial_is_async_p(struct serial * scb)484b725ae77Skettenis serial_is_async_p (struct serial *scb)
485b725ae77Skettenis {
486b725ae77Skettenis   return (scb->ops->async != NULL) && (scb->async_handler != NULL);
487b725ae77Skettenis }
488b725ae77Skettenis 
489b725ae77Skettenis void
serial_async(struct serial * scb,serial_event_ftype * handler,void * context)490b725ae77Skettenis serial_async (struct serial *scb,
491b725ae77Skettenis 	      serial_event_ftype *handler,
492b725ae77Skettenis 	      void *context)
493b725ae77Skettenis {
494b725ae77Skettenis   /* Only change mode if there is a need. */
495b725ae77Skettenis   if ((scb->async_handler == NULL)
496b725ae77Skettenis       != (handler == NULL))
497b725ae77Skettenis     scb->ops->async (scb, handler != NULL);
498b725ae77Skettenis   scb->async_handler = handler;
499b725ae77Skettenis   scb->async_context = context;
500b725ae77Skettenis }
501b725ae77Skettenis 
502b725ae77Skettenis int
deprecated_serial_fd(struct serial * scb)503b725ae77Skettenis deprecated_serial_fd (struct serial *scb)
504b725ae77Skettenis {
505b725ae77Skettenis   /* FIXME: should this output a warning that deprecated code is being
506b725ae77Skettenis      called? */
507b725ae77Skettenis   if (scb->fd < 0)
508b725ae77Skettenis     {
509b725ae77Skettenis       internal_error (__FILE__, __LINE__,
510b725ae77Skettenis 		      "serial: FD not valid");
511b725ae77Skettenis     }
512b725ae77Skettenis   return scb->fd; /* sigh */
513b725ae77Skettenis }
514b725ae77Skettenis 
515b725ae77Skettenis void
serial_debug(struct serial * scb,int debug_p)516b725ae77Skettenis serial_debug (struct serial *scb, int debug_p)
517b725ae77Skettenis {
518b725ae77Skettenis   scb->debug_p = debug_p;
519b725ae77Skettenis }
520b725ae77Skettenis 
521b725ae77Skettenis int
serial_debug_p(struct serial * scb)522b725ae77Skettenis serial_debug_p (struct serial *scb)
523b725ae77Skettenis {
524b725ae77Skettenis   return scb->debug_p || global_serial_debug_p;
525b725ae77Skettenis }
526b725ae77Skettenis 
527b725ae77Skettenis 
528e93f7393Sniklas #if 0
529b725ae77Skettenis /* The connect command is #if 0 because I hadn't thought of an elegant
530b725ae77Skettenis    way to wait for I/O on two `struct serial *'s simultaneously.  Two
531b725ae77Skettenis    solutions came to mind:
532e93f7393Sniklas 
533e93f7393Sniklas    1) Fork, and have have one fork handle the to user direction,
534e93f7393Sniklas    and have the other hand the to target direction.  This
535e93f7393Sniklas    obviously won't cut it for MSDOS.
536e93f7393Sniklas 
537e93f7393Sniklas    2) Use something like select.  This assumes that stdin and
538e93f7393Sniklas    the target side can both be waited on via the same
539e93f7393Sniklas    mechanism.  This may not be true for DOS, if GDB is
540e93f7393Sniklas    talking to the target via a TCP socket.
541b725ae77Skettenis    -grossman, 8 Jun 93 */
542e93f7393Sniklas 
543e93f7393Sniklas /* Connect the user directly to the remote system.  This command acts just like
544e93f7393Sniklas    the 'cu' or 'tip' command.  Use <CR>~. or <CR>~^D to break out.  */
545e93f7393Sniklas 
546b725ae77Skettenis static struct serial *tty_desc;	/* Controlling terminal */
547e93f7393Sniklas 
548e93f7393Sniklas static void
549b725ae77Skettenis cleanup_tty (serial_ttystate ttystate)
550e93f7393Sniklas {
551e93f7393Sniklas   printf_unfiltered ("\r\n[Exiting connect mode]\r\n");
552b725ae77Skettenis   serial_set_tty_state (tty_desc, ttystate);
553b725ae77Skettenis   xfree (ttystate);
554b725ae77Skettenis   serial_close (tty_desc);
555e93f7393Sniklas }
556e93f7393Sniklas 
557e93f7393Sniklas static void
558b725ae77Skettenis connect_command (char *args, int fromtty)
559e93f7393Sniklas {
560e93f7393Sniklas   int c;
561e93f7393Sniklas   char cur_esc = 0;
562e93f7393Sniklas   serial_ttystate ttystate;
563b725ae77Skettenis   struct serial *port_desc;		/* TTY port */
564e93f7393Sniklas 
565e93f7393Sniklas   dont_repeat ();
566e93f7393Sniklas 
567e93f7393Sniklas   if (args)
568e93f7393Sniklas     fprintf_unfiltered (gdb_stderr, "This command takes no args.  They have been ignored.\n");
569e93f7393Sniklas 
570e93f7393Sniklas   printf_unfiltered ("[Entering connect mode.  Use ~. or ~^D to escape]\n");
571e93f7393Sniklas 
572b725ae77Skettenis   tty_desc = serial_fdopen (0);
573e93f7393Sniklas   port_desc = last_serial_opened;
574e93f7393Sniklas 
575b725ae77Skettenis   ttystate = serial_get_tty_state (tty_desc);
576e93f7393Sniklas 
577b725ae77Skettenis   serial_raw (tty_desc);
578b725ae77Skettenis   serial_raw (port_desc);
579e93f7393Sniklas 
580e93f7393Sniklas   make_cleanup (cleanup_tty, ttystate);
581e93f7393Sniklas 
582e93f7393Sniklas   while (1)
583e93f7393Sniklas     {
584e93f7393Sniklas       int mask;
585e93f7393Sniklas 
586b725ae77Skettenis       mask = serial_wait_2 (tty_desc, port_desc, -1);
587e93f7393Sniklas 
588e93f7393Sniklas       if (mask & 2)
589e93f7393Sniklas 	{			/* tty input */
590e93f7393Sniklas 	  char cx;
591e93f7393Sniklas 
592e93f7393Sniklas 	  while (1)
593e93f7393Sniklas 	    {
594b725ae77Skettenis 	      c = serial_readchar (tty_desc, 0);
595e93f7393Sniklas 
596e93f7393Sniklas 	      if (c == SERIAL_TIMEOUT)
597e93f7393Sniklas 		break;
598e93f7393Sniklas 
599e93f7393Sniklas 	      if (c < 0)
600e93f7393Sniklas 		perror_with_name ("connect");
601e93f7393Sniklas 
602e93f7393Sniklas 	      cx = c;
603b725ae77Skettenis 	      serial_write (port_desc, &cx, 1);
604e93f7393Sniklas 
605e93f7393Sniklas 	      switch (cur_esc)
606e93f7393Sniklas 		{
607e93f7393Sniklas 		case 0:
608e93f7393Sniklas 		  if (c == '\r')
609e93f7393Sniklas 		    cur_esc = c;
610e93f7393Sniklas 		  break;
611e93f7393Sniklas 		case '\r':
612e93f7393Sniklas 		  if (c == '~')
613e93f7393Sniklas 		    cur_esc = c;
614e93f7393Sniklas 		  else
615e93f7393Sniklas 		    cur_esc = 0;
616e93f7393Sniklas 		  break;
617e93f7393Sniklas 		case '~':
618e93f7393Sniklas 		  if (c == '.' || c == '\004')
619e93f7393Sniklas 		    return;
620e93f7393Sniklas 		  else
621e93f7393Sniklas 		    cur_esc = 0;
622e93f7393Sniklas 		}
623e93f7393Sniklas 	    }
624e93f7393Sniklas 	}
625e93f7393Sniklas 
626e93f7393Sniklas       if (mask & 1)
627e93f7393Sniklas 	{			/* Port input */
628e93f7393Sniklas 	  char cx;
629e93f7393Sniklas 
630e93f7393Sniklas 	  while (1)
631e93f7393Sniklas 	    {
632b725ae77Skettenis 	      c = serial_readchar (port_desc, 0);
633e93f7393Sniklas 
634e93f7393Sniklas 	      if (c == SERIAL_TIMEOUT)
635e93f7393Sniklas 		break;
636e93f7393Sniklas 
637e93f7393Sniklas 	      if (c < 0)
638e93f7393Sniklas 		perror_with_name ("connect");
639e93f7393Sniklas 
640e93f7393Sniklas 	      cx = c;
641e93f7393Sniklas 
642b725ae77Skettenis 	      serial_write (tty_desc, &cx, 1);
643e93f7393Sniklas 	    }
644e93f7393Sniklas 	}
645e93f7393Sniklas     }
646e93f7393Sniklas }
647e93f7393Sniklas #endif /* 0 */
648e93f7393Sniklas 
649b725ae77Skettenis /* Serial set/show framework.  */
650b725ae77Skettenis 
651b725ae77Skettenis static struct cmd_list_element *serial_set_cmdlist;
652b725ae77Skettenis static struct cmd_list_element *serial_show_cmdlist;
653b725ae77Skettenis 
654b725ae77Skettenis static void
serial_set_cmd(char * args,int from_tty)655b725ae77Skettenis serial_set_cmd (char *args, int from_tty)
656e93f7393Sniklas {
657b725ae77Skettenis   printf_unfiltered ("\"set serial\" must be followed by the name of a command.\n");
658b725ae77Skettenis   help_list (serial_set_cmdlist, "set serial ", -1, gdb_stdout);
659e93f7393Sniklas }
660e93f7393Sniklas 
661b725ae77Skettenis static void
serial_show_cmd(char * args,int from_tty)662b725ae77Skettenis serial_show_cmd (char *args, int from_tty)
663e93f7393Sniklas {
664b725ae77Skettenis   cmd_show_list (serial_show_cmdlist, from_tty, "");
665b725ae77Skettenis }
666e93f7393Sniklas 
667b725ae77Skettenis 
668b725ae77Skettenis void
_initialize_serial(void)669b725ae77Skettenis _initialize_serial (void)
670b725ae77Skettenis {
671e93f7393Sniklas #if 0
672e93f7393Sniklas   add_com ("connect", class_obscure, connect_command,
673e93f7393Sniklas 	   "Connect the terminal directly up to the command monitor.\n\
674e93f7393Sniklas Use <CR>~. or <CR>~^D to break out.");
675e93f7393Sniklas #endif /* 0 */
676e93f7393Sniklas 
677b725ae77Skettenis   add_prefix_cmd ("serial", class_maintenance, serial_set_cmd, "\
678b725ae77Skettenis Set default serial/parallel port configuration.",
679b725ae77Skettenis 		  &serial_set_cmdlist, "set serial ",
680b725ae77Skettenis 		  0/*allow-unknown*/,
681b725ae77Skettenis 		  &setlist);
682b725ae77Skettenis 
683b725ae77Skettenis   add_prefix_cmd ("serial", class_maintenance, serial_show_cmd, "\
684b725ae77Skettenis Show default serial/parallel port configuration.",
685b725ae77Skettenis 		  &serial_show_cmdlist, "show serial ",
686b725ae77Skettenis 		  0/*allow-unknown*/,
687b725ae77Skettenis 		  &showlist);
688b725ae77Skettenis 
689*63addd46Skettenis   deprecated_add_show_from_set
690b725ae77Skettenis     (add_set_cmd ("remotelogfile", no_class,
691e93f7393Sniklas 		  var_filename, (char *) &serial_logfile,
692e93f7393Sniklas 		  "Set filename for remote session recording.\n\
693e93f7393Sniklas This file is used to record the remote session for future playback\n\
694b725ae77Skettenis by gdbserver.",
695e93f7393Sniklas 		  &setlist),
696e93f7393Sniklas      &showlist);
697b725ae77Skettenis 
698*63addd46Skettenis   deprecated_add_show_from_set
699b725ae77Skettenis     (add_set_enum_cmd ("remotelogbase", no_class,
700b725ae77Skettenis 		       logbase_enums, &serial_logbase,
701b725ae77Skettenis 		       "Set numerical base for remote session logging",
702b725ae77Skettenis 		       &setlist),
703b725ae77Skettenis      &showlist);
704b725ae77Skettenis 
705*63addd46Skettenis   deprecated_add_show_from_set
706*63addd46Skettenis     (add_set_cmd ("serial",
707b725ae77Skettenis 		  class_maintenance,
708b725ae77Skettenis 		  var_zinteger,
709b725ae77Skettenis 		  (char *)&global_serial_debug_p,
710b725ae77Skettenis 		  "Set serial debugging.\n\
711b725ae77Skettenis When non-zero, serial port debugging is enabled.", &setdebuglist),
712b725ae77Skettenis      &showdebuglist);
713e93f7393Sniklas }
714