From: Eberhard Mattes <mattes@azu.informatik.uni-stuttgart.de>
[deliverable/binutils-gdb.git] / gdb / serial.c
CommitLineData
4e772f44 1/* Generic serial interface routines
c84e5000 2 Copyright 1992, 1993, 1996 Free Software Foundation, Inc.
4e772f44
SG
3
4This file is part of GDB.
5
6This program is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2 of the License, or
9(at your option) any later version.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program; if not, write to the Free Software
6c9638b4 18Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
4e772f44
SG
19
20#include "defs.h"
72ae15f6 21#include <ctype.h>
4e772f44 22#include "serial.h"
0694bce6 23#include "gdb_string.h"
e8f1ad9a 24#include "gdbcmd.h"
4e772f44 25
38dc5e12 26/* Linked list of serial I/O handlers */
4e772f44
SG
27
28static struct serial_ops *serial_ops_list = NULL;
29
38dc5e12
SG
30/* This is the last serial stream opened. Used by connect command. */
31
32static serial_t last_serial_opened = NULL;
33
bbcc95bd
PS
34/* Pointer to list of scb's. */
35
36static serial_t scb_base;
37
e8f1ad9a
FF
38/* Non-NULL gives filename which contains a recording of the remote session,
39 suitable for playback by gdbserver. */
40
41char *serial_logfile = NULL;
42FILE *serial_logfp = NULL;
43
b607efe7
FF
44static struct serial_ops *serial_interface_lookup PARAMS ((char *));
45static void serial_logchar PARAMS ((int));
46
e8f1ad9a
FF
47\f
48static int serial_reading = 0;
49static int serial_writing = 0;
50
51void
52serial_log_command (cmd)
53 const char *cmd;
54{
55 if (serial_reading || serial_writing)
56 {
0db5a6fe 57 fputc_unfiltered ('\n', serial_logfp);
e8f1ad9a
FF
58 serial_reading = 0;
59 serial_writing = 0;
60 }
0db5a6fe 61 fprintf_unfiltered (serial_logfp, "c %s\n", cmd);
e8f1ad9a
FF
62 /* Make sure that the log file is as up-to-date as possible,
63 in case we are getting ready to dump core or something. */
64 fflush (serial_logfp);
65}
66
67static void
68serial_logchar (ch)
69 int ch;
70{
71 switch (ch)
72 {
0db5a6fe
FF
73 case '\\': fputs_unfiltered ("\\\\", serial_logfp); break;
74 case '\b': fputs_unfiltered ("\\b", serial_logfp); break;
75 case '\f': fputs_unfiltered ("\\f", serial_logfp); break;
76 case '\n': fputs_unfiltered ("\\n", serial_logfp); break;
77 case '\r': fputs_unfiltered ("\\r", serial_logfp); break;
78 case '\t': fputs_unfiltered ("\\t", serial_logfp); break;
79 case '\v': fputs_unfiltered ("\\v", serial_logfp); break;
80 default: fprintf_unfiltered (serial_logfp, isprint (ch) ? "%c" : "\\x%02x", ch & 0xFF); break;
e8f1ad9a
FF
81 }
82}
83
84int
85serial_write (scb, str, len)
86 serial_t scb;
87 const char *str;
88 int len;
89{
90 int count;
91
92 if (serial_logfp != NULL)
93 {
94 if (serial_reading)
95 {
0db5a6fe 96 fputc_unfiltered ('\n', serial_logfp);
e8f1ad9a
FF
97 serial_reading = 0;
98 }
99 if (!serial_writing)
100 {
101 serial_logchar ('w');
102 serial_logchar (' ');
103 serial_writing = 1;
104 }
105 for (count = 0; count < len; count++)
106 {
107 serial_logchar (str[count]);
108 }
109 /* Make sure that the log file is as up-to-date as possible,
110 in case we are getting ready to dump core or something. */
111 fflush (serial_logfp);
112 }
113 return (scb -> ops -> write (scb, str, len));
114}
115
116int
117serial_readchar (scb, timeout)
118 serial_t scb;
119 int timeout;
120{
121 int ch;
122
123 ch = scb -> ops -> readchar (scb, timeout);
124 if (serial_logfp != NULL)
125 {
126 if (serial_writing)
127 {
0db5a6fe 128 fputc_unfiltered ('\n', serial_logfp);
e8f1ad9a
FF
129 serial_writing = 0;
130 }
131 if (!serial_reading)
132 {
133 serial_logchar ('r');
134 serial_logchar (' ');
135 serial_reading = 1;
136 }
137 serial_logchar (ch);
138 /* Make sure that the log file is as up-to-date as possible,
139 in case we are getting ready to dump core or something. */
140 fflush (serial_logfp);
141 }
142 return (ch);
143}
144
4e772f44
SG
145static struct serial_ops *
146serial_interface_lookup (name)
147 char *name;
148{
149 struct serial_ops *ops;
150
151 for (ops = serial_ops_list; ops; ops = ops->next)
152 if (strcmp (name, ops->name) == 0)
153 return ops;
154
155 return NULL;
156}
157
158void
159serial_add_interface(optable)
160 struct serial_ops *optable;
161{
162 optable->next = serial_ops_list;
163 serial_ops_list = optable;
164}
165
38dc5e12
SG
166/* Open up a device or a network socket, depending upon the syntax of NAME. */
167
4e772f44 168serial_t
55679787 169serial_open (name)
4e772f44
SG
170 const char *name;
171{
172 serial_t scb;
173 struct serial_ops *ops;
174
4887063b
SG
175 for (scb = scb_base; scb; scb = scb->next)
176 if (scb->name && strcmp (scb->name, name) == 0)
177 {
178 scb->refcnt++;
179 return scb;
180 }
181
55679787
SC
182 if (strcmp (name, "pc") == 0)
183 ops = serial_interface_lookup ("pc");
184 else if (strchr (name, ':'))
38dc5e12 185 ops = serial_interface_lookup ("tcp");
c84e5000
SC
186 else if (strncmp (name, "lpt", 3) == 0)
187 ops = serial_interface_lookup ("parallel");
38dc5e12
SG
188 else
189 ops = serial_interface_lookup ("hardwire");
4e772f44
SG
190
191 if (!ops)
192 return NULL;
193
194 scb = (serial_t)xmalloc (sizeof (struct _serial_t));
195
196 scb->ops = ops;
197
198 scb->bufcnt = 0;
199 scb->bufp = scb->buf;
200
4febd102 201 if (scb->ops->open(scb, name))
4e772f44
SG
202 {
203 free (scb);
204 return NULL;
205 }
206
4887063b
SG
207 scb->name = strsave (name);
208 scb->next = scb_base;
209 scb->refcnt = 1;
210 scb_base = scb;
211
38dc5e12
SG
212 last_serial_opened = scb;
213
e8f1ad9a
FF
214 if (serial_logfile != NULL)
215 {
216 serial_logfp = fopen (serial_logfile, "w");
217 if (serial_logfp == NULL)
218 {
219 perror_with_name (serial_logfile);
220 }
221 }
222
38dc5e12
SG
223 return scb;
224}
225
226serial_t
4887063b 227serial_fdopen (fd)
38dc5e12
SG
228 const int fd;
229{
230 serial_t scb;
231 struct serial_ops *ops;
232
4887063b
SG
233 for (scb = scb_base; scb; scb = scb->next)
234 if (scb->fd == fd)
235 {
236 scb->refcnt++;
237 return scb;
238 }
239
38dc5e12
SG
240 ops = serial_interface_lookup ("hardwire");
241
242 if (!ops)
243 return NULL;
244
245 scb = (serial_t)xmalloc (sizeof (struct _serial_t));
246
247 scb->ops = ops;
248
249 scb->bufcnt = 0;
250 scb->bufp = scb->buf;
251
252 scb->fd = fd;
253
4887063b
SG
254 scb->name = NULL;
255 scb->next = scb_base;
256 scb->refcnt = 1;
257 scb_base = scb;
258
38dc5e12
SG
259 last_serial_opened = scb;
260
4e772f44
SG
261 return scb;
262}
263
4febd102 264void
bbcc95bd 265serial_close(scb, really_close)
4febd102 266 serial_t scb;
bbcc95bd 267 int really_close;
4febd102 268{
4887063b
SG
269 serial_t tmp_scb;
270
38dc5e12
SG
271 last_serial_opened = NULL;
272
e8f1ad9a
FF
273 if (serial_logfp)
274 {
275 if (serial_reading || serial_writing)
276 {
0db5a6fe 277 fputc_unfiltered ('\n', serial_logfp);
e8f1ad9a
FF
278 serial_reading = 0;
279 serial_writing = 0;
280 }
281 fclose (serial_logfp);
282 serial_logfp = NULL;
283 }
284
a037b21e
SG
285/* This is bogus. It's not our fault if you pass us a bad scb...! Rob, you
286 should fix your code instead. */
287
288 if (!scb)
289 return;
290
4887063b
SG
291 scb->refcnt--;
292 if (scb->refcnt > 0)
293 return;
294
bbcc95bd
PS
295 if (really_close)
296 scb->ops->close (scb);
4887063b
SG
297
298 if (scb->name)
299 free (scb->name);
300
301 if (scb_base == scb)
302 scb_base = scb_base->next;
303 else
304 for (tmp_scb = scb_base; tmp_scb; tmp_scb = tmp_scb->next)
305 {
306 if (tmp_scb->next != scb)
307 continue;
308
309 tmp_scb->next = tmp_scb->next->next;
310 break;
311 }
312
a037b21e 313 free(scb);
4febd102
SG
314}
315
4e772f44 316#if 0
bf3b8abd
JK
317/*
318The connect command is #if 0 because I hadn't thought of an elegant
319way to wait for I/O on two serial_t's simultaneously. Two solutions
320came to mind:
321
322 1) Fork, and have have one fork handle the to user direction,
323 and have the other hand the to target direction. This
324 obviously won't cut it for MSDOS.
325
326 2) Use something like select. This assumes that stdin and
327 the target side can both be waited on via the same
328 mechanism. This may not be true for DOS, if GDB is
329 talking to the target via a TCP socket.
330-grossman, 8 Jun 93
331*/
38dc5e12 332
4e772f44
SG
333/* Connect the user directly to the remote system. This command acts just like
334 the 'cu' or 'tip' command. Use <CR>~. or <CR>~^D to break out. */
335
38dc5e12
SG
336static serial_t tty_desc; /* Controlling terminal */
337
4e772f44
SG
338static void
339cleanup_tty(ttystate)
38dc5e12 340 serial_ttystate ttystate;
4e772f44 341{
199b2450 342 printf_unfiltered ("\r\n[Exiting connect mode]\r\n");
38dc5e12
SG
343 SERIAL_SET_TTY_STATE (tty_desc, ttystate);
344 free (ttystate);
345 SERIAL_CLOSE (tty_desc);
4e772f44
SG
346}
347
348static void
349connect_command (args, fromtty)
350 char *args;
351 int fromtty;
352{
4e772f44
SG
353 int c;
354 char cur_esc = 0;
38dc5e12
SG
355 serial_ttystate ttystate;
356 serial_t port_desc; /* TTY port */
4e772f44
SG
357
358 dont_repeat();
359
4e772f44 360 if (args)
199b2450 361 fprintf_unfiltered(gdb_stderr, "This command takes no args. They have been ignored.\n");
4e772f44 362
199b2450 363 printf_unfiltered("[Entering connect mode. Use ~. or ~^D to escape]\n");
4e772f44 364
38dc5e12
SG
365 tty_desc = SERIAL_FDOPEN (0);
366 port_desc = last_serial_opened;
4e772f44 367
38dc5e12 368 ttystate = SERIAL_GET_TTY_STATE (tty_desc);
4e772f44 369
38dc5e12
SG
370 SERIAL_RAW (tty_desc);
371 SERIAL_RAW (port_desc);
372
373 make_cleanup (cleanup_tty, ttystate);
4e772f44
SG
374
375 while (1)
376 {
38dc5e12 377 int mask;
4e772f44 378
38dc5e12 379 mask = SERIAL_WAIT_2 (tty_desc, port_desc, -1);
4e772f44 380
38dc5e12
SG
381 if (mask & 2)
382 { /* tty input */
4e772f44
SG
383 char cx;
384
38dc5e12 385 while (1)
4e772f44 386 {
38dc5e12
SG
387 c = SERIAL_READCHAR(tty_desc, 0);
388
389 if (c == SERIAL_TIMEOUT)
390 break;
391
392 if (c < 0)
393 perror_with_name("connect");
394
395 cx = c;
396 SERIAL_WRITE(port_desc, &cx, 1);
397
398 switch (cur_esc)
399 {
400 case 0:
401 if (c == '\r')
402 cur_esc = c;
403 break;
404 case '\r':
405 if (c == '~')
406 cur_esc = c;
407 else
408 cur_esc = 0;
409 break;
410 case '~':
411 if (c == '.' || c == '\004')
412 return;
413 else
414 cur_esc = 0;
415 }
4e772f44
SG
416 }
417 }
418
38dc5e12
SG
419 if (mask & 1)
420 { /* Port input */
421 char cx;
422
4e772f44
SG
423 while (1)
424 {
38dc5e12
SG
425 c = SERIAL_READCHAR(port_desc, 0);
426
427 if (c == SERIAL_TIMEOUT)
428 break;
429
4e772f44 430 if (c < 0)
38dc5e12
SG
431 perror_with_name("connect");
432
433 cx = c;
434
435 SERIAL_WRITE(tty_desc, &cx, 1);
4e772f44 436 }
4e772f44
SG
437 }
438 }
439}
976bb0be 440#endif /* 0 */
4e772f44 441
5c8ba017
SG
442/* VARARGS */
443void
444#ifdef ANSI_PROTOTYPES
445serial_printf (serial_t desc, const char *format, ...)
446#else
447serial_printf (va_alist)
448 va_dcl
449#endif
450{
451 va_list args;
452 char *buf;
453#ifdef ANSI_PROTOTYPES
454 va_start (args, format);
455#else
456 serial_t desc;
457 char *format;
458
459 va_start (args);
460 desc = va_arg (args, serial_t);
461 format = va_arg (args, char *);
462#endif
463
464 vasprintf (&buf, format, args);
465 SERIAL_WRITE (desc, buf, strlen (buf));
466
467 free (buf);
468 va_end (args);
469}
470
4e772f44
SG
471void
472_initialize_serial ()
473{
976bb0be 474#if 0
4e772f44
SG
475 add_com ("connect", class_obscure, connect_command,
476 "Connect the terminal directly up to the command monitor.\n\
477Use <CR>~. or <CR>~^D to break out.");
38dc5e12 478#endif /* 0 */
e8f1ad9a
FF
479
480 add_show_from_set (add_set_cmd ("remotelogfile", no_class,
481 var_filename, (char *)&serial_logfile,
482 "Set filename for remote session recording.\n\
483This file is used to record the remote session for future playback\n\
484by gdbserver.", &setlist),
485 &showlist);
486
976bb0be 487}
This page took 0.215624 seconds and 4 git commands to generate.