2000-03-21 J.T. Conklin <jtc@redback.com>
[platform/upstream/binutils.git] / gdb / ser-mac.c
1 /* Remote serial interface for local (hardwired) serial ports for Macintosh.
2    Copyright 1994, 2000 Free Software Foundation, Inc.
3    Contributed by Cygnus Support.  Written by Stan Shebs.
4
5    This file is part of GDB.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 59 Temple Place - Suite 330,
20    Boston, MA 02111-1307, USA.  */
21
22 #include "defs.h"
23 #include "serial.h"
24
25 #include <Types.h>
26 #include <Devices.h>
27 /* This is the regular Mac Serial.h, but copied to a different name
28    so as not to get confused with the GDB serial.h above.  */
29 #include "MacSerial.h"
30
31 /* This is unused for now.  We just return a placeholder. */
32
33 struct mac_ttystate
34   {
35     int bogus;
36   };
37
38 static int mac_open PARAMS ((serial_t scb, const char *name));
39 static void mac_raw PARAMS ((serial_t scb));
40 static int mac_readchar PARAMS ((serial_t scb, int timeout));
41 static int mac_setbaudrate PARAMS ((serial_t scb, int rate));
42 static int mac_write PARAMS ((serial_t scb, const char *str, int len));
43 static void mac_close PARAMS ((serial_t scb));
44 static serial_ttystate mac_get_tty_state PARAMS ((serial_t scb));
45 static int mac_set_tty_state PARAMS ((serial_t scb, serial_ttystate state));
46 static char *aptr PARAMS ((short p));
47
48 short input_refnum;
49 short output_refnum;
50
51 char *mac_input_buffer;
52 char *mac_output_buffer;
53
54 static int
55 mac_open (scb, name)
56      serial_t scb;
57      const char *name;
58 {
59   OSErr err;
60
61   /* Alloc buffer space first - that way any allocation failures are
62      intercepted before the serial driver gets involved. */
63   if (mac_input_buffer == NULL)
64     mac_input_buffer = (char *) xmalloc (4096);
65   /* Match on a name and open a port. */
66   if (strcmp (name, "modem") == 0)
67     {
68       err = OpenDriver ("\p.AIn", &input_refnum);
69       if (err != 0)
70         {
71           return (-1);
72         }
73       err = OpenDriver ("\p.AOut", &output_refnum);
74       if (err != 0)
75         {
76           CloseDriver (input_refnum);
77           return (-1);
78         }
79     }
80   else if (strcmp (name, "printer") == 0)
81     {
82       err = OpenDriver ("\p.BIn", &input_refnum);
83       if (err != 0)
84         {
85           return (-1);
86         }
87       err = OpenDriver ("\p.BOut", &output_refnum);
88       if (err != 0)
89         {
90           CloseDriver (input_refnum);
91           return (-1);
92         }
93       /* fake */
94       scb->fd = 1;
95       return 0;
96     }
97   else
98     {
99       error ("You must specify a valid serial port name; your choices are `modem' or `printer'.");
100       errno = ENOENT;
101       return (-1);
102     }
103   /* We got something open. */
104   if (1 /* using custom buffer */ )
105     SerSetBuf (input_refnum, mac_input_buffer, 4096);
106   /* Set to a GDB-preferred state. */
107   SerReset (input_refnum, stop10 | noParity | data8 | baud9600);
108   SerReset (output_refnum, stop10 | noParity | data8 | baud9600);
109   {
110     CntrlParam cb;
111     struct SerShk *handshake;
112
113     cb.ioCRefNum = output_refnum;
114     cb.csCode = 14;
115     handshake = (struct SerShk *) &cb.csParam[0];
116     handshake->fXOn = 0;
117     handshake->fCTS = 0;
118     handshake->xOn = 0;
119     handshake->xOff = 0;
120     handshake->errs = 0;
121     handshake->evts = 0;
122     handshake->fInX = 0;
123     handshake->fDTR = 0;
124     err = PBControl ((ParmBlkPtr) & cb, 0);
125     if (err < 0)
126       return (-1);
127   }
128   /* fake */
129   scb->fd = 1;
130   return 0;
131 }
132
133 static int
134 mac_noop (scb)
135      serial_t scb;
136 {
137   return 0;
138 }
139
140 static void
141 mac_raw (scb)
142      serial_t scb;
143 {
144   /* Always effectively in raw mode. */
145 }
146
147 /* Read a character with user-specified timeout.  TIMEOUT is number of seconds
148    to wait, or -1 to wait forever.  Use timeout of 0 to effect a poll.  Returns
149    char if successful.  Returns -2 if timeout expired, EOF if line dropped
150    dead, or -3 for any other error (see errno in that case). */
151
152 static int
153 mac_readchar (scb, timeout)
154      serial_t scb;
155      int timeout;
156 {
157   int status, n;
158   /* time_t */ unsigned long start_time, now;
159   OSErr err;
160   CntrlParam cb;
161   IOParam pb;
162
163   if (scb->bufcnt-- > 0)
164     return *scb->bufp++;
165
166   time (&start_time);
167
168   while (1)
169     {
170       cb.ioCRefNum = input_refnum;
171       cb.csCode = 2;
172       err = PBStatus ((ParmBlkPtr) & cb, 0);
173       if (err < 0)
174         return SERIAL_ERROR;
175       n = *((long *) &cb.csParam[0]);
176       if (n > 0)
177         {
178           pb.ioRefNum = input_refnum;
179           pb.ioBuffer = (Ptr) (scb->buf);
180           pb.ioReqCount = (n > 64 ? 64 : n);
181           err = PBRead ((ParmBlkPtr) & pb, 0);
182           if (err < 0)
183             return SERIAL_ERROR;
184           scb->bufcnt = pb.ioReqCount;
185           scb->bufcnt--;
186           scb->bufp = scb->buf;
187           return *scb->bufp++;
188         }
189       else if (timeout == 0)
190         return SERIAL_TIMEOUT;
191       else if (timeout == -1)
192         ;
193       else
194         {
195           time (&now);
196           if (now > start_time + timeout)
197             return SERIAL_TIMEOUT;
198         }
199       PROGRESS (1);
200     }
201 }
202
203 /* mac_{get set}_tty_state() are both dummys to fill out the function
204    vector.  Someday, they may do something real... */
205
206 static serial_ttystate
207 mac_get_tty_state (scb)
208      serial_t scb;
209 {
210   struct mac_ttystate *state;
211
212   state = (struct mac_ttystate *) xmalloc (sizeof *state);
213
214   return (serial_ttystate) state;
215 }
216
217 static int
218 mac_set_tty_state (scb, ttystate)
219      serial_t scb;
220      serial_ttystate ttystate;
221 {
222   return 0;
223 }
224
225 static int
226 mac_noflush_set_tty_state (scb, new_ttystate, old_ttystate)
227      serial_t scb;
228      serial_ttystate new_ttystate;
229      serial_ttystate old_ttystate;
230 {
231   return 0;
232 }
233
234 static void
235 mac_print_tty_state (serial_t scb,
236                      serial_ttystate ttystate,
237                      struct ui_file *stream)
238 {
239   /* Nothing to print.  */
240   return;
241 }
242
243 /* If there is a tricky formula to relate real baud rates
244    to what the serial driver wants, we should use it.  Until
245    we get one, this table will have to do.  */
246
247 static struct
248 {
249   int real_rate;
250   int bits;
251 }
252 mac_baud_rate_table[] =
253 {
254   {
255     57600, baud57600
256   }
257   ,
258   {
259     38400, 1
260   }
261   ,
262   {
263     19200, baud19200
264   }
265   ,
266   {
267     9600, baud9600
268   }
269   ,
270   {
271     7200, baud7200
272   }
273   ,
274   {
275     4800, baud4800
276   }
277   ,
278   {
279     3600, baud3600
280   }
281   ,
282   {
283     2400, baud2400
284   }
285   ,
286   {
287     1800, baud1800
288   }
289   ,
290   {
291     1200, baud1200
292   }
293   ,
294   {
295     600, baud600
296   }
297   ,
298   {
299     300, baud300
300   }
301   ,
302   {
303     0, 0
304   }
305 };
306
307 static int
308 mac_set_baud_rate (scb, rate)
309      serial_t scb;
310      int rate;
311 {
312   int i, bits;
313
314   for (i = 0; mac_baud_rate_table[i].real_rate != 0; ++i)
315     {
316       if (mac_baud_rate_table[i].real_rate == rate)
317         {
318           bits = mac_baud_rate_table[i].bits;
319           break;
320         }
321     }
322   SerReset (input_refnum, stop10 | noParity | data8 | bits);
323   SerReset (output_refnum, stop10 | noParity | data8 | bits);
324 }
325
326 static int
327 mac_set_stop_bits (scb, num)
328      serial_t scb;
329      int num;
330 {
331   return 0;
332 }
333
334 int first_mac_write = 0;
335
336 static int
337 mac_write (scb, str, len)
338      serial_t scb;
339      const char *str;
340      int len;
341 {
342   OSErr err;
343   IOParam pb;
344
345   if (first_mac_write++ < 4)
346     {
347       sleep (1);
348     }
349   pb.ioRefNum = output_refnum;
350   pb.ioBuffer = (Ptr) str;
351   pb.ioReqCount = len;
352   err = PBWrite ((ParmBlkPtr) & pb, 0);
353   if (err < 0)
354     {
355       return 1;
356     }
357   return 0;
358 }
359
360 static void
361 mac_close (serial_t scb)
362 {
363   if (input_refnum)
364     {
365       if (1 /* custom buffer */ )
366         SerSetBuf (input_refnum, mac_input_buffer, 0);
367       CloseDriver (input_refnum);
368       input_refnum = 0;
369     }
370   if (output_refnum)
371     {
372       if (0 /* custom buffer */ )
373         SerSetBuf (input_refnum, mac_output_buffer, 0);
374       CloseDriver (output_refnum);
375       output_refnum = 0;
376     }
377 }
378
379 static struct serial_ops mac_ops =
380 {
381   "hardwire",
382   0,
383   mac_open,
384   mac_close,
385   mac_readchar,
386   mac_write,
387   mac_noop,                     /* flush output */
388   mac_noop,                     /* flush input */
389   mac_noop,                     /* send break -- currently only for nindy */
390   mac_raw,
391   mac_get_tty_state,
392   mac_set_tty_state,
393   mac_print_tty_state,
394   mac_noflush_set_tty_state,
395   mac_set_baud_rate,
396   mac_set_stop_bits,
397   mac_noop,                     /* wait for output to drain */
398 };
399
400 void
401 _initialize_ser_mac ()
402 {
403   serial_add_interface (&mac_ops);
404 }