* config/m68k/tm-m68kv4.h (DWARF_REG_TO_REGNUM): Define to
[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 /* Pointer to list of scb's. */
32
33 static serial_t scb_base;
34
35 static struct serial_ops *
36 serial_interface_lookup (name)
37      char *name;
38 {
39   struct serial_ops *ops;
40
41   for (ops = serial_ops_list; ops; ops = ops->next)
42     if (strcmp (name, ops->name) == 0)
43       return ops;
44
45   return NULL;
46 }
47
48 void
49 serial_add_interface(optable)
50      struct serial_ops *optable;
51 {
52   optable->next = serial_ops_list;
53   serial_ops_list = optable;
54 }
55
56 /* Open up a device or a network socket, depending upon the syntax of NAME. */
57
58 serial_t
59 serial_open (name)
60      const char *name;
61 {
62   serial_t scb;
63   struct serial_ops *ops;
64
65   for (scb = scb_base; scb; scb = scb->next)
66     if (scb->name && strcmp (scb->name, name) == 0)
67       {
68         scb->refcnt++;
69         return scb;
70       }
71
72   if (strcmp (name, "pc") == 0)
73     ops = serial_interface_lookup ("pc");
74   else if (strchr (name, ':'))
75     ops = serial_interface_lookup ("tcp");
76   else
77     ops = serial_interface_lookup ("hardwire");
78
79   if (!ops)
80     return NULL;
81
82   scb = (serial_t)xmalloc (sizeof (struct _serial_t));
83
84   scb->ops = ops;
85
86   scb->bufcnt = 0;
87   scb->bufp = scb->buf;
88
89   if (scb->ops->open(scb, name))
90     {
91       free (scb);
92       return NULL;
93     }
94
95   scb->name = strsave (name);
96   scb->next = scb_base;
97   scb->refcnt = 1;
98   scb_base = scb;
99
100   last_serial_opened = scb;
101
102   return scb;
103 }
104
105 serial_t
106 serial_fdopen (fd)
107      const int fd;
108 {
109   serial_t scb;
110   struct serial_ops *ops;
111
112   for (scb = scb_base; scb; scb = scb->next)
113     if (scb->fd == fd)
114       {
115         scb->refcnt++;
116         return scb;
117       }
118
119   ops = serial_interface_lookup ("hardwire");
120
121   if (!ops)
122     return NULL;
123
124   scb = (serial_t)xmalloc (sizeof (struct _serial_t));
125
126   scb->ops = ops;
127
128   scb->bufcnt = 0;
129   scb->bufp = scb->buf;
130
131   scb->fd = fd;
132
133   scb->name = NULL;
134   scb->next = scb_base;
135   scb->refcnt = 1;
136   scb_base = scb;
137
138   last_serial_opened = scb;
139
140   return scb;
141 }
142
143 void
144 serial_close(scb, really_close)
145      serial_t scb;
146      int really_close;
147 {
148   serial_t tmp_scb;
149
150   last_serial_opened = NULL;
151
152 /* This is bogus.  It's not our fault if you pass us a bad scb...!  Rob, you
153    should fix your code instead.  */
154
155   if (!scb)
156     return;
157
158   scb->refcnt--;
159   if (scb->refcnt > 0)
160     return;
161
162   if (really_close)
163     scb->ops->close (scb);
164
165   if (scb->name)
166     free (scb->name);
167
168   if (scb_base == scb)
169     scb_base = scb_base->next;
170   else
171     for (tmp_scb = scb_base; tmp_scb; tmp_scb = tmp_scb->next)
172       {
173         if (tmp_scb->next != scb)
174           continue;
175
176         tmp_scb->next = tmp_scb->next->next;
177         break;
178       }
179
180   free(scb);
181 }
182
183 #if 0
184 /*
185 The connect command is #if 0 because I hadn't thought of an elegant
186 way to wait for I/O on two serial_t's simultaneously.  Two solutions
187 came to mind:
188
189         1) Fork, and have have one fork handle the to user direction,
190            and have the other hand the to target direction.  This
191            obviously won't cut it for MSDOS.
192
193         2) Use something like select.  This assumes that stdin and
194            the target side can both be waited on via the same
195            mechanism.  This may not be true for DOS, if GDB is
196            talking to the target via a TCP socket.
197 -grossman, 8 Jun 93
198 */
199
200 /* Connect the user directly to the remote system.  This command acts just like
201    the 'cu' or 'tip' command.  Use <CR>~. or <CR>~^D to break out.  */
202
203 static serial_t tty_desc;               /* Controlling terminal */
204
205 static void
206 cleanup_tty(ttystate)
207      serial_ttystate ttystate;
208 {
209   printf_unfiltered ("\r\n[Exiting connect mode]\r\n");
210   SERIAL_SET_TTY_STATE (tty_desc, ttystate);
211   free (ttystate);
212   SERIAL_CLOSE (tty_desc);
213 }
214
215 static void
216 connect_command (args, fromtty)
217      char       *args;
218      int        fromtty;
219 {
220   int c;
221   char cur_esc = 0;
222   serial_ttystate ttystate;
223   serial_t port_desc;           /* TTY port */
224
225   dont_repeat();
226
227   if (args)
228     fprintf_unfiltered(gdb_stderr, "This command takes no args.  They have been ignored.\n");
229         
230   printf_unfiltered("[Entering connect mode.  Use ~. or ~^D to escape]\n");
231
232   tty_desc = SERIAL_FDOPEN (0);
233   port_desc = last_serial_opened;
234
235   ttystate = SERIAL_GET_TTY_STATE (tty_desc);
236
237   SERIAL_RAW (tty_desc);
238   SERIAL_RAW (port_desc);
239
240   make_cleanup (cleanup_tty, ttystate);
241
242   while (1)
243     {
244       int mask;
245
246       mask = SERIAL_WAIT_2 (tty_desc, port_desc, -1);
247
248       if (mask & 2)
249         {                       /* tty input */
250           char cx;
251
252           while (1)
253             {
254               c = SERIAL_READCHAR(tty_desc, 0);
255
256               if (c == SERIAL_TIMEOUT)
257                   break;
258
259               if (c < 0)
260                 perror_with_name("connect");
261
262               cx = c;
263               SERIAL_WRITE(port_desc, &cx, 1);
264
265               switch (cur_esc)
266                 {
267                 case 0:
268                   if (c == '\r')
269                     cur_esc = c;
270                   break;
271                 case '\r':
272                   if (c == '~')
273                     cur_esc = c;
274                   else
275                     cur_esc = 0;
276                   break;
277                 case '~':
278                   if (c == '.' || c == '\004')
279                     return;
280                   else
281                     cur_esc = 0;
282                 }
283             }
284         }
285
286       if (mask & 1)
287         {                       /* Port input */
288           char cx;
289
290           while (1)
291             {
292               c = SERIAL_READCHAR(port_desc, 0);
293
294               if (c == SERIAL_TIMEOUT)
295                   break;
296
297               if (c < 0)
298                 perror_with_name("connect");
299
300               cx = c;
301
302               SERIAL_WRITE(tty_desc, &cx, 1);
303             }
304         }
305     }
306 }
307 #endif /* 0 */
308
309 void
310 _initialize_serial ()
311 {
312 #if 0
313   add_com ("connect", class_obscure, connect_command,
314            "Connect the terminal directly up to the command monitor.\n\
315 Use <CR>~. or <CR>~^D to break out.");
316 #endif /* 0 */
317 }