1/* Remote serial interface using Renesas E7000 PC ISA card in a PC
2   Copyright 1994, 1996, 1997, 1998, 1999, 2000
3   Free Software Foundation, Inc.
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#if defined __GO32__ || defined _WIN32
24#include "serial.h"
25#include "gdb_string.h"
26
27#ifdef _WIN32
28#define WIN32_LEAN_AND_MEAN
29#include <windows.h>
30#endif
31
32#ifdef __GO32__
33#include <sys/dos.h>
34#endif
35
36static int e7000pc_open (struct serial *scb, const char *name);
37static void e7000pc_raw (struct serial *scb);
38static int e7000pc_readchar (struct serial *scb, int timeout);
39static int e7000pc_setbaudrate (struct serial *scb, int rate);
40static int e7000pc_write (struct serial *scb, const char *str, int len);
41static void e7000pc_close (struct serial *scb);
42static serial_ttystate e7000pc_get_tty_state (struct serial *scb);
43static int e7000pc_set_tty_state (struct serial *scb, serial_ttystate state);
44
45#define OFF_DPD 	0x0000
46#define OFF_DDP 	0x1000
47#define OFF_CPD 	0x2000
48#define OFF_CDP 	0x2400
49#define OFF_FA  	0x3000
50#define OFF_FB  	0x3002
51#define OFF_FC  	0x3004
52#define OFF_IRQTOD	0x3008
53#define OFF_IRQTOP 	0x300a
54#define OFF_READY  	0x300c
55#define OFF_PON    	0x300e
56
57#define IDLE       0x0000
58#define CMD_CI     0x4349
59#define CMD_CO     0x434f
60#define CMD_LO     0x4c4f
61#define CMD_LS     0x4c53
62#define CMD_SV     0x5356
63#define CMD_SS     0x5353
64#define CMD_OK     0x4f4b
65#define CMD_ER     0x4552
66#define CMD_NF     0x4e46
67#define CMD_AB     0x4142
68#define CMD_ED     0x4544
69#define CMD_CE     0x4345
70
71static unsigned long fa;
72static unsigned long irqtod;
73static unsigned long ready;
74static unsigned long fb;
75static unsigned long cpd;
76static unsigned long cdp;
77static unsigned long ready;
78static unsigned long pon;
79static unsigned long irqtop;
80static unsigned long board_at;
81
82#ifdef __GO32__
83
84#define SET_BYTE(x,y)   { char _buf = y;dosmemput(&_buf,1, x);}
85#define SET_WORD(x,y)   { short _buf = y;dosmemput(&_buf,2, x);}
86#define GET_BYTE(x)     ( dosmemget(x,1,&bb), bb)
87#define GET_WORD(x)     ( dosmemget(x,2,&sb), sb)
88static unsigned char bb;
89static unsigned short sb;
90
91#else /* win32 */
92
93#define SET_BYTE(x,y)   *(volatile unsigned char *)(x) = (y)
94#define SET_WORD(x,y)   *(volatile unsigned short *)(x) = (y)
95#define GET_BYTE(x)     (*(volatile unsigned char *)(x))
96#define GET_WORD(x)     (*(volatile unsigned short *)(x))
97#define dosmemget(FROM, LEN, TO) memcpy ((void *)(TO), (void *)(FROM), (LEN))
98#define dosmemput(FROM, LEN, TO) memcpy ((void *)(TO), (void *)(FROM), (LEN))
99#endif
100
101static struct sw
102  {
103    int sw;
104    int addr;
105  }
106sigs[] =
107{
108  {
109    0x14, 0xd0000
110  }
111  ,
112  {
113    0x15, 0xd4000
114  }
115  ,
116  {
117    0x16, 0xd8000
118  }
119  ,
120  {
121    0x17, 0xdc000
122  }
123  ,
124    0
125};
126
127#define get_ds_base() 0
128
129static int
130e7000pc_init (void)
131{
132  int try;
133  unsigned long dsbase;
134
135  dsbase = get_ds_base ();
136
137  /* Look around in memory for the board's signature */
138
139  for (try = 0; sigs[try].sw; try++)
140    {
141      int val;
142      board_at = sigs[try].addr - dsbase;
143      fa = board_at + OFF_FA;
144      fb = board_at + OFF_FB;
145      cpd = board_at + OFF_CPD;
146      cdp = board_at + OFF_CDP;
147      ready = board_at + OFF_READY;
148      pon = board_at + OFF_PON;
149      irqtop = board_at + OFF_IRQTOP;
150      irqtod = board_at + OFF_IRQTOD;
151
152      val = GET_WORD (ready);
153
154      if (val == (0xaaa0 | sigs[try].sw))
155	{
156	  if (GET_WORD (pon) & 0xf)
157	    {
158	      SET_WORD (fa, 0);
159	      SET_WORD (fb, 0);
160
161	      SET_WORD (irqtop, 1);	/* Disable interrupts from e7000 */
162	      SET_WORD (ready, 1);
163	      printf_filtered ("\nConnected to the E7000PC at address 0x%x\n",
164			       sigs[try].addr);
165	      return 1;
166	    }
167	  error ("The E7000 PC board is working, but the E7000 is turned off.\n");
168	  return 0;
169	}
170    }
171
172  error ("GDB cannot connect to the E7000 PC board, check that it is installed\n\
173and that the switch settings are correct.  Some other DOS programs can \n\
174stop the board from working.  Try starting from a very minimal boot, \n\
175perhaps you need to disable EMM386 over the region where the board has\n\
176its I/O space, remove other unneeded cards, etc etc\n");
177  return 0;
178
179}
180
181static int pbuf_size;
182static int pbuf_index;
183
184/* Return next byte from cdp.  If no more, then return -1.  */
185
186static int
187e7000_get (void)
188{
189  static char pbuf[1000];
190  char tmp[1000];
191  int x;
192
193  if (pbuf_index < pbuf_size)
194    {
195      x = pbuf[pbuf_index++];
196    }
197  else if ((GET_WORD (fb) & 1))
198    {
199      int i;
200      pbuf_size = GET_WORD (cdp + 2);
201
202      dosmemget (cdp + 8, pbuf_size + 1, tmp);
203
204      /* Tell the E7000 we've eaten */
205      SET_WORD (fb, 0);
206      /* Swap it around */
207      for (i = 0; i < pbuf_size; i++)
208	{
209	  pbuf[i] = tmp[i ^ 1];
210	}
211      pbuf_index = 0;
212      x = pbuf[pbuf_index++];
213    }
214  else
215    {
216      x = -1;
217    }
218  return x;
219}
220
221/* Works just like read(), except that it takes a TIMEOUT in seconds.  Note
222   that TIMEOUT == 0 is a poll, and TIMEOUT == -1 means wait forever. */
223
224static int
225dosasync_read (int fd, char *buf, int len, int timeout)
226{
227  long now;
228  long then;
229  int i = 0;
230
231  /* Then look for some more if we're still hungry */
232  time (&now);
233  then = now + timeout;
234  while (i < len)
235    {
236      int ch = e7000_get ();
237
238      /* While there's room in the buffer, and we've already
239         read the stuff in, suck it over */
240      if (ch != -1)
241	{
242	  buf[i++] = ch;
243	  while (i < len && pbuf_index < pbuf_size)
244	    {
245	      ch = e7000_get ();
246	      if (ch == -1)
247		break;
248	      buf[i++] = ch;
249	    }
250	}
251
252      time (&now);
253
254      if (timeout == 0)
255	return i;
256      if (now >= then && timeout > 0)
257	{
258	  return i;
259	}
260    }
261  return len;
262}
263
264
265static int
266dosasync_write (int fd, const char *buf, int len)
267{
268  int i;
269  char dummy[1000];
270
271  /* Construct copy locally */
272  ((short *) dummy)[0] = CMD_CI;
273  ((short *) dummy)[1] = len;
274  ((short *) dummy)[2] = 0;
275  ((short *) dummy)[3] = 0;
276  for (i = 0; i < len; i++)
277    {
278      dummy[(8 + i) ^ 1] = buf[i];
279    }
280
281  /* Wait for the card to get ready */
282  while (GET_WORD (fa) & 1);
283
284  /* Blast onto the ISA card */
285  dosmemput (dummy, 8 + len + 1, cpd);
286
287  SET_WORD (fa, 1);
288  SET_WORD (irqtod, 1);		/* Interrupt the E7000 */
289
290  return len;
291}
292
293static int
294e7000pc_open (struct serial *scb, const char *name)
295{
296  if (strncasecmp (name, "pc", 2) != 0)
297    {
298      errno = ENOENT;
299      return -1;
300    }
301
302  scb->fd = e7000pc_init ();
303
304  if (!scb->fd)
305    return -1;
306
307  return 0;
308}
309
310static int
311e7000pc_noop (struct serial *scb)
312{
313  return 0;
314}
315
316static void
317e7000pc_raw (struct serial *scb)
318{
319  /* Always in raw mode */
320}
321
322static int
323e7000pc_readchar (struct serial *scb, int timeout)
324{
325  char buf;
326
327top:
328
329  if (dosasync_read (scb->fd, &buf, 1, timeout))
330    {
331      if (buf == 0)
332	goto top;
333      return buf;
334    }
335  else
336    return SERIAL_TIMEOUT;
337}
338
339struct e7000pc_ttystate
340{
341  int dummy;
342};
343
344/* e7000pc_{get set}_tty_state() are both dummys to fill out the function
345   vector.  Someday, they may do something real... */
346
347static serial_ttystate
348e7000pc_get_tty_state (struct serial *scb)
349{
350  struct e7000pc_ttystate *state;
351
352  state = (struct e7000pc_ttystate *) xmalloc (sizeof *state);
353
354  return (serial_ttystate) state;
355}
356
357static int
358e7000pc_set_tty_state (struct serial *scb, serial_ttystate ttystate)
359{
360  return 0;
361}
362
363static int
364e7000pc_noflush_set_tty_state (struct serial *scb,
365			       serial_ttystate new_ttystate,
366			       serial_ttystate old_ttystate)
367{
368  return 0;
369}
370
371static void
372e7000pc_print_tty_state (struct serial *scb,
373			 serial_ttystate ttystate,
374			 struct ui_file *stream)
375{
376  /* Nothing to print.  */
377  return;
378}
379
380static int
381e7000pc_setbaudrate (struct serial *scb, int rate)
382{
383  return 0;
384}
385
386static int
387e7000pc_setstopbits (struct serial *scb, int rate)
388{
389  return 0;
390}
391
392static int
393e7000pc_write (struct serial *scb, const char *str, int len)
394{
395  dosasync_write (scb->fd, str, len);
396
397  return 0;
398}
399
400static void
401e7000pc_close (struct serial *scb)
402{
403}
404
405static struct serial_ops e7000pc_ops =
406{
407  "pc",
408  0,
409  e7000pc_open,
410  e7000pc_close,
411  e7000pc_readchar,
412  e7000pc_write,
413  e7000pc_noop,			/* flush output */
414  e7000pc_noop,			/* flush input */
415  e7000pc_noop,			/* send break -- currently used only for nindy */
416  e7000pc_raw,
417  e7000pc_get_tty_state,
418  e7000pc_set_tty_state,
419  e7000pc_print_tty_state,
420  e7000pc_noflush_set_tty_state,
421  e7000pc_setbaudrate,
422  e7000pc_setstopbits,
423  e7000pc_noop,			/* wait for output to drain */
424};
425
426#endif /*_WIN32 or __GO32__*/
427
428extern initialize_file_ftype _initialize_ser_e7000pc; /* -Wmissing-prototypes */
429
430void
431_initialize_ser_e7000pc (void)
432{
433#if defined __GO32__ || defined _WIN32
434  serial_add_interface (&e7000pc_ops);
435#endif
436}
437