Fri Dec 3 09:55:17 1993 Pete Hoogenboom (hoogen@cs.utah.edu)
[external/binutils.git] / gdb / serial.c
1 /* Generic serial interface routines
2    Copyright 1992, 1993 Free Software Foundation, Inc.
3
4 This file is part of GDB.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
19
20 #include "defs.h"
21 #include "serial.h"
22
23 /* Linked list of serial I/O handlers */
24
25 static struct serial_ops *serial_ops_list = NULL;
26
27 /* This is the last serial stream opened.  Used by connect command. */
28
29 static serial_t last_serial_opened = NULL;
30
31 static struct serial_ops *
32 serial_interface_lookup (name)
33      char *name;
34 {
35   struct serial_ops *ops;
36
37   for (ops = serial_ops_list; ops; ops = ops->next)
38     if (strcmp (name, ops->name) == 0)
39       return ops;
40
41   return NULL;
42 }
43
44 void
45 serial_add_interface(optable)
46      struct serial_ops *optable;
47 {
48   optable->next = serial_ops_list;
49   serial_ops_list = optable;
50 }
51
52 /* Open up a device or a network socket, depending upon the syntax of NAME. */
53
54 serial_t
55 serial_open(name)
56      const char *name;
57 {
58   serial_t scb;
59   struct serial_ops *ops;
60
61   if (strchr (name, ':'))
62     ops = serial_interface_lookup ("tcp");
63   else
64     ops = serial_interface_lookup ("hardwire");
65
66   if (!ops)
67     return NULL;
68
69   scb = (serial_t)xmalloc (sizeof (struct _serial_t));
70
71   scb->ops = ops;
72
73   scb->bufcnt = 0;
74   scb->bufp = scb->buf;
75
76   if (scb->ops->open(scb, name))
77     {
78       free (scb);
79       return NULL;
80     }
81
82   last_serial_opened = scb;
83
84   return scb;
85 }
86
87 serial_t
88 serial_fdopen(fd)
89      const int fd;
90 {
91   serial_t scb;
92   struct serial_ops *ops;
93
94   ops = serial_interface_lookup ("hardwire");
95
96   if (!ops)
97     return NULL;
98
99   scb = (serial_t)xmalloc (sizeof (struct _serial_t));
100
101   scb->ops = ops;
102
103   scb->bufcnt = 0;
104   scb->bufp = scb->buf;
105
106   scb->fd = fd;
107
108   last_serial_opened = scb;
109
110   return scb;
111 }
112
113 void
114 serial_close(scb)
115      serial_t scb;
116 {
117   last_serial_opened = NULL;
118
119 /* This is bogus.  It's not our fault if you pass us a bad scb...!  Rob, you
120    should fix your code instead.  */
121
122   if (!scb)
123     return;
124
125   scb->ops->close(scb);
126   free(scb);
127 }
128
129 #if 0
130 /*
131 The connect command is #if 0 because I hadn't thought of an elegant
132 way to wait for I/O on two serial_t's simultaneously.  Two solutions
133 came to mind:
134
135         1) Fork, and have have one fork handle the to user direction,
136            and have the other hand the to target direction.  This
137            obviously won't cut it for MSDOS.
138
139         2) Use something like select.  This assumes that stdin and
140            the target side can both be waited on via the same
141            mechanism.  This may not be true for DOS, if GDB is
142            talking to the target via a TCP socket.
143 -grossman, 8 Jun 93
144 */
145
146 /* Connect the user directly to the remote system.  This command acts just like
147    the 'cu' or 'tip' command.  Use <CR>~. or <CR>~^D to break out.  */
148
149 static serial_t tty_desc;               /* Controlling terminal */
150
151 static void
152 cleanup_tty(ttystate)
153      serial_ttystate ttystate;
154 {
155   printf_unfiltered ("\r\n[Exiting connect mode]\r\n");
156   SERIAL_SET_TTY_STATE (tty_desc, ttystate);
157   free (ttystate);
158   SERIAL_CLOSE (tty_desc);
159 }
160
161 static void
162 connect_command (args, fromtty)
163      char       *args;
164      int        fromtty;
165 {
166   int c;
167   char cur_esc = 0;
168   serial_ttystate ttystate;
169   serial_t port_desc;           /* TTY port */
170
171   dont_repeat();
172
173   if (args)
174     fprintf_unfiltered(gdb_stderr, "This command takes no args.  They have been ignored.\n");
175         
176   printf_unfiltered("[Entering connect mode.  Use ~. or ~^D to escape]\n");
177
178   tty_desc = SERIAL_FDOPEN (0);
179   port_desc = last_serial_opened;
180
181   ttystate = SERIAL_GET_TTY_STATE (tty_desc);
182
183   SERIAL_RAW (tty_desc);
184   SERIAL_RAW (port_desc);
185
186   make_cleanup (cleanup_tty, ttystate);
187
188   while (1)
189     {
190       int mask;
191
192       mask = SERIAL_WAIT_2 (tty_desc, port_desc, -1);
193
194       if (mask & 2)
195         {                       /* tty input */
196           char cx;
197
198           while (1)
199             {
200               c = SERIAL_READCHAR(tty_desc, 0);
201
202               if (c == SERIAL_TIMEOUT)
203                   break;
204
205               if (c < 0)
206                 perror_with_name("connect");
207
208               cx = c;
209               SERIAL_WRITE(port_desc, &cx, 1);
210
211               switch (cur_esc)
212                 {
213                 case 0:
214                   if (c == '\r')
215                     cur_esc = c;
216                   break;
217                 case '\r':
218                   if (c == '~')
219                     cur_esc = c;
220                   else
221                     cur_esc = 0;
222                   break;
223                 case '~':
224                   if (c == '.' || c == '\004')
225                     return;
226                   else
227                     cur_esc = 0;
228                 }
229             }
230         }
231
232       if (mask & 1)
233         {                       /* Port input */
234           char cx;
235
236           while (1)
237             {
238               c = SERIAL_READCHAR(port_desc, 0);
239
240               if (c == SERIAL_TIMEOUT)
241                   break;
242
243               if (c < 0)
244                 perror_with_name("connect");
245
246               cx = c;
247
248               SERIAL_WRITE(tty_desc, &cx, 1);
249             }
250         }
251     }
252 }
253 #endif /* 0 */
254
255 void
256 _initialize_serial ()
257 {
258 #if 0
259   add_com ("connect", class_obscure, connect_command,
260            "Connect the terminal directly up to the command monitor.\n\
261 Use <CR>~. or <CR>~^D to break out.");
262 #endif /* 0 */
263 }