]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/rdi-share/serpardr.c
Initial creation of sourceware repository
[thirdparty/binutils-gdb.git] / gdb / rdi-share / serpardr.c
1 /*
2 * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved.
3 *
4 * This software may be freely used, copied, modified, and distributed
5 * provided that the above copyright notice is preserved in all copies of the
6 * software.
7 */
8
9 /* -*-C-*-
10 *
11 * $Revision$
12 * $Date$
13 *
14 *
15 * serpardv.c - Serial/Parallel Driver for Angel.
16 */
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20
21 #include "crc.h"
22 #include "devices.h"
23 #include "buffers.h"
24 #include "rxtx.h"
25 #include "hostchan.h"
26 #include "params.h"
27 #include "logging.h"
28 #include "hsys.h"
29
30 #ifdef COMPILING_ON_WINDOWS
31 # undef ERROR
32 # undef IGNORE
33 # include <windows.h>
34 # include "angeldll.h"
35 # include "comb_api.h"
36 #else
37 # ifdef __hpux
38 # define _TERMIOS_INCLUDED
39 # include <sys/termio.h>
40 # undef _TERMIOS_INCLUDED
41 # else
42 # include <termios.h>
43 # endif
44 # include "unixcomm.h"
45 #endif
46
47 #ifndef UNUSED
48 # define UNUSED(x) (x = x) /* Silence compiler warnings */
49 #endif
50
51 #define MAXREADSIZE 512
52 #define MAXWRITESIZE 512
53
54 #define SERPAR_FC_SET ((1 << serial_XON) | (1 << serial_XOFF))
55 #define SERPAR_CTL_SET ((1 << serial_STX) | (1 << serial_ETX) | \
56 (1 << serial_ESC))
57 #define SERPAR_ESC_SET (SERPAR_FC_SET | SERPAR_CTL_SET)
58
59 static const struct re_config config = {
60 serial_STX, serial_ETX, serial_ESC, /* self-explanatory? */
61 SERPAR_FC_SET, /* set of flow-control characters */
62 SERPAR_ESC_SET, /* set of characters to be escaped */
63 NULL, /* serial_flow_control */
64 NULL, /* what to do with FC chars */
65 angel_DD_RxEng_BufferAlloc, NULL /* how to get a buffer */
66 };
67
68 static struct re_state rxstate;
69
70 /*
71 * structure used for manipulating transmit data
72 */
73 typedef struct TxState
74 {
75 struct te_state state;
76 unsigned int index;
77 unsigned char writebuf[MAXWRITESIZE];
78 } TxState;
79
80 /*
81 * The set of parameter options supported by the device
82 */
83 static unsigned int baud_options[] =
84 {
85 #ifdef __hpux
86 115200, 57600,
87 #endif
88 38400, 19200, 9600
89 };
90
91 static ParameterList param_list[] =
92 {
93 {
94 AP_BAUD_RATE,
95 sizeof(baud_options) / sizeof(unsigned int),
96 baud_options
97 }
98 };
99
100 static const ParameterOptions serpar_options =
101 {
102 sizeof(param_list) / sizeof(ParameterList),
103 param_list
104 };
105
106 /*
107 * The default parameter config for the device
108 */
109 static Parameter param_default[] =
110 {
111 { AP_BAUD_RATE, 9600 }
112 };
113
114 static const ParameterConfig serpar_defaults =
115 {
116 sizeof(param_default)/sizeof(Parameter),
117 param_default
118 };
119
120 /*
121 * The user-modified options for the device
122 */
123 static unsigned int user_baud_options[sizeof(baud_options) /
124 sizeof(unsigned int)];
125
126 static ParameterList param_user_list[] =
127 {
128 {
129 AP_BAUD_RATE,
130 sizeof(user_baud_options) / sizeof(unsigned),
131 user_baud_options
132 }
133 };
134
135 static ParameterOptions user_options =
136 {
137 sizeof(param_user_list) / sizeof(ParameterList),
138 param_user_list
139 };
140
141 static bool user_options_set;
142
143 /* forward declarations */
144 static int serpar_reset(void);
145 static int serpar_set_params(const ParameterConfig *config);
146 static int SerparMatch(const char *name, const char *arg);
147
148 static void process_baud_rate(unsigned int target_baud_rate)
149 {
150 const ParameterList *full_list;
151 ParameterList *user_list;
152
153 /* create subset of full options */
154 full_list = Angel_FindParamList(&serpar_options, AP_BAUD_RATE);
155 user_list = Angel_FindParamList(&user_options, AP_BAUD_RATE);
156
157 if (full_list != NULL && user_list != NULL)
158 {
159 unsigned int i, j;
160 unsigned int def_baud = 0;
161
162 /* find lower or equal to */
163 for (i = 0; i < full_list->num_options; ++i)
164 if (target_baud_rate >= full_list->option[i])
165 {
166 /* copy remaining */
167 for (j = 0; j < (full_list->num_options - i); ++j)
168 user_list->option[j] = full_list->option[i+j];
169 user_list->num_options = j;
170
171 /* check this is not the default */
172 Angel_FindParam(AP_BAUD_RATE, &serpar_defaults, &def_baud);
173 if ((j == 1) && (user_list->option[0] == def_baud))
174 {
175 #ifdef DEBUG
176 printf("user selected default\n");
177 #endif
178 }
179 else
180 {
181 user_options_set = TRUE;
182 #ifdef DEBUG
183 printf("user options are: ");
184 for (j = 0; j < user_list->num_options; ++j)
185 printf("%u ", user_list->option[j]);
186 printf("\n");
187 #endif
188 }
189
190 break; /* out of i loop */
191 }
192
193 #ifdef DEBUG
194 if (i >= full_list->num_options)
195 printf("couldn't match baud rate %u\n", target_baud_rate);
196 #endif
197 }
198 #ifdef DEBUG
199 else
200 printf("failed to find lists\n");
201 #endif
202 }
203
204 static int SerparOpen(const char *name, const char *arg)
205 {
206 char *sername = NULL;
207 char *parname = NULL;
208
209 #ifdef DEBUG
210 printf("SerparOpen: name %s arg %s\n", name, arg ? arg : "<NULL>");
211 #endif
212
213 #ifdef COMPILING_ON_WINDOWS
214 if (IsOpenSerial() || IsOpenParallel()) return -1;
215 #else
216 if (Unix_IsSerialInUse() || Unix_IsParallelInUse()) return -1;
217 #endif
218
219 #ifdef COMPILING_ON_WINDOWS
220 if (SerparMatch(name, arg) == -1)
221 return -1;
222 #else
223 Unix_IsValidParallelDevice(name,&sername,&parname);
224 # ifdef DEBUG
225 printf("translated %s to serial %s and parallel %s\n",
226 name==0 ? "NULL" : name,
227 sername==0 ? "NULL" : sername,
228 parname==0 ? "NULL" : parname);
229 # endif
230 if (sername==NULL || parname==NULL) return -1;
231 #endif
232
233 user_options_set = FALSE;
234
235 /* interpret and store the arguments */
236 if (arg != NULL)
237 {
238 unsigned int target_baud_rate;
239
240 target_baud_rate = (unsigned int)strtoul(arg, NULL, 10);
241
242 if (target_baud_rate > 0)
243 {
244 #ifdef DEBUG
245 printf("user selected baud rate %u\n", target_baud_rate);
246 #endif
247 process_baud_rate(target_baud_rate);
248 }
249 #ifdef DEBUG
250 else
251 printf("could not understand baud rate %s\n", arg);
252 #endif
253 }
254
255 #ifdef COMPILING_ON_WINDOWS
256 {
257 /*
258 * The serial port number is in name[0] followed by
259 * the parallel port number in name[1]
260 */
261
262 int sport = name[0] - '0';
263 int pport = name[1] - '0';
264
265 if (OpenParallel(pport) != COM_OK)
266 return -1;
267
268 if (OpenSerial(sport, FALSE) != COM_OK)
269 {
270 CloseParallel();
271 return -1;
272 }
273 }
274 #else
275 Unix_OpenParallel(parname);
276 Unix_OpenSerial(sername);
277 #endif
278
279 serpar_reset();
280
281 #if defined(__unix) || defined(__CYGWIN32__)
282 Unix_ioctlNonBlocking();
283 #endif
284
285 Angel_RxEngineInit(&config, &rxstate);
286
287 return 0;
288 }
289
290 #ifdef COMPILING_ON_WINDOWS
291 static int SerparMatch(const char *name, const char *arg)
292 {
293 char sername[2];
294 char parname[2];
295
296 UNUSED(arg);
297
298 sername[0] = name[0];
299 parname[0] = name[1];
300 sername[1] = parname[1] = 0;
301
302 if (IsValidDevice(sername) == COM_DEVICENOTVALID ||
303 IsValidDevice(parname) == COM_DEVICENOTVALID)
304 return -1;
305 else
306 return 0;
307 }
308 #else
309 static int SerparMatch(const char *portstring, const char *arg)
310 {
311 char *sername=NULL, *parname=NULL;
312 UNUSED(arg);
313
314 Unix_IsValidParallelDevice(portstring,&sername,&parname);
315
316 /* Match failed if either sername or parname are still NULL */
317 if (sername==NULL || parname==NULL) return -1;
318 return 0;
319 }
320 #endif
321
322 static void SerparClose(void)
323 {
324 #ifdef COMPILING_ON_WINDOWS
325 CloseParallel();
326 CloseSerial();
327 #else
328 Unix_CloseParallel();
329 Unix_CloseSerial();
330 #endif
331 }
332
333 static int SerparRead(DriverCall *dc, bool block)
334 {
335 static unsigned char readbuf[MAXREADSIZE];
336 static int rbindex = 0;
337
338 int nread;
339 int read_errno;
340 int c = 0;
341 re_status restatus;
342 int ret_code = -1; /* assume bad packet or error */
343
344 /*
345 * we must not overflow buffer, and must start after
346 * the existing data
347 */
348 #ifdef COMPILING_ON_WINDOWS
349 {
350 BOOL dummy = FALSE;
351 nread = BytesInRXBufferSerial();
352
353 if (nread > MAXREADSIZE - rbindex)
354 nread = MAXREADSIZE - rbindex;
355 read_errno = ReadSerial(readbuf+rbindex, nread, &dummy);
356 if (pfnProgressCallback != NULL && read_errno == COM_OK)
357 {
358 progressInfo.nRead += nread;
359 (*pfnProgressCallback)(&progressInfo);
360 }
361 }
362 #else
363 nread = Unix_ReadSerial(readbuf+rbindex, MAXREADSIZE-rbindex, block);
364 read_errno = errno;
365 #endif
366
367 if ((nread > 0) || (rbindex > 0))
368 {
369 #ifdef DO_TRACE
370 printf("[%d@%d] ", nread, rbindex);
371 #endif
372
373 if (nread > 0)
374 rbindex = rbindex + nread;
375
376 do
377 {
378 restatus = Angel_RxEngine(readbuf[c], &(dc->dc_packet), &rxstate);
379
380 #ifdef DO_TRACE
381 printf("<%02X ",readbuf[c]);
382 #endif
383 c++;
384 } while (c < rbindex &&
385 ((restatus == RS_IN_PKT) || (restatus == RS_WAIT_PKT)));
386
387 #ifdef DO_TRACE
388 printf("\n");
389 #endif
390
391 switch(restatus)
392 {
393 case RS_GOOD_PKT:
394 ret_code = 1;
395 /* fall through to: */
396
397 case RS_BAD_PKT:
398 /*
399 * We now need to shuffle any left over data down to the
400 * beginning of our private buffer ready to be used
401 *for the next packet
402 */
403 #ifdef DO_TRACE
404 printf("SerparRead() processed %d, moving down %d\n",
405 c, rbindex - c);
406 #endif
407
408 if (c != rbindex)
409 memmove((char *) readbuf, (char *) (readbuf + c), rbindex - c);
410
411 rbindex -= c;
412
413 break;
414
415 case RS_IN_PKT:
416 case RS_WAIT_PKT:
417 rbindex = 0; /* will have processed all we had */
418 ret_code = 0;
419 break;
420
421 default:
422 #ifdef DEBUG
423 printf("Bad re_status in SerparRead()\n");
424 #endif
425 break;
426 }
427 }
428 else if (nread == 0)
429 /* nothing to read */
430 ret_code = 0;
431 else if (read_errno == ERRNO_FOR_BLOCKED_IO) /* nread < 0 */
432 ret_code = 0;
433
434 #ifdef DEBUG
435 if ((nread < 0) && (read_errno != ERRNO_FOR_BLOCKED_IO))
436 perror("read() error in SerparRead()");
437 #endif
438
439 return ret_code;
440 }
441
442 /*
443 * Function: send_packet
444 * Purpose: Send a stream of bytes to Angel through the parallel port
445 *
446 * Algorithm: We need to present the data in a form that all boards can
447 * swallow. With the PID board, this is a problem: for reasons
448 * described in the driver (angel/pid/st16c552.c), data are
449 * sent a nybble at a time on D0-D2 and D4; D3 is wired to ACK,
450 * which generates an interrupt when it goes low. This routine
451 * fills in an array of nybbles, with ACK clear in all but the
452 * last one. If, for whatever reason, the write fails, then
453 * ACK is forced high (thereby enabling the next write a chance
454 * to be noticed when the falling edge of ACK generates an
455 * interrupt (hopefully).
456 *
457 * Params:
458 * Input: txstate Contains the packet to be sent
459 *
460 * Returns: Number of *complete* bytes written
461 */
462
463 static int SerparWrite(DriverCall *dc)
464 {
465 te_status status;
466 int nwritten = 0;
467 static TxState txstate;
468
469 /*
470 * is this a new packet?
471 */
472 if (dc->dc_context == NULL)
473 {
474 /*
475 * yes - initialise TxEngine
476 */
477 Angel_TxEngineInit(&config, &dc->dc_packet, &txstate.state);
478
479 txstate.index = 0;
480 dc->dc_context = &txstate;
481 }
482
483 /*
484 * fill the buffer using the Tx Engine
485 */
486 do
487 {
488 status = Angel_TxEngine(&dc->dc_packet, &txstate.state,
489 &txstate.writebuf[txstate.index]);
490 if (status != TS_IDLE) txstate.index++;
491
492 } while (status == TS_IN_PKT && txstate.index < MAXWRITESIZE);
493
494 #ifdef DO_TRACE
495 {
496 unsigned int i = 0;
497
498 while (i < txstate.index)
499 {
500 printf(">%02X ", txstate.writebuf[i]);
501
502 if (!(++i % 16))
503 putc('\n', stdout);
504 }
505
506 if (i % 16)
507 putc('\n', stdout);
508 }
509 #endif
510
511 /*
512 * the data are ready, all we need now is to send them out
513 * in a form that Angel can swallow.
514 */
515 #ifdef COMPILING_ON_WINDOWS
516 if (WriteParallel(txstate.writebuf, txstate.index) == COM_OK)
517 {
518 nwritten = txstate.index;
519 if (pfnProgressCallback != NULL)
520 {
521 progressInfo.nWritten += nwritten;
522 (*pfnProgressCallback)(&progressInfo);
523 }
524 }
525 else
526 {
527 MessageBox(GetFocus(), "Write error\n", "Angel", MB_OK | MB_ICONSTOP);
528 return -1; /* SJ - This really needs to return a value, which is picked up in */
529 /* DevSW_Read as meaning stop debugger but don't kill. */
530 }
531 #else
532 nwritten = Unix_WriteParallel(txstate.writebuf, txstate.index);
533 #endif
534
535 if (nwritten < 0) nwritten = 0;
536
537 #ifdef DO_TRACE
538 printf("SerparWrite: wrote %d out of %d bytes\n",
539 nwritten, txstate.index);
540 #endif
541
542 /*
543 * has the whole packet gone?
544 */
545 if (nwritten == (int)txstate.index &&
546 (status == TS_DONE_PKT || status == TS_IDLE))
547 /*
548 * yes it has
549 */
550 return 1;
551 else
552 {
553 /*
554 * if some data are left, shuffle them
555 * to the start of the buffer
556 */
557 if (nwritten != (int)txstate.index && nwritten != 0)
558 {
559 txstate.index -= nwritten;
560 (void)memmove((char *) txstate.writebuf,
561 (char *) (txstate.writebuf + nwritten),
562 txstate.index);
563 }
564 else if (nwritten == (int)txstate.index)
565 txstate.index = 0;
566
567 return 0;
568 }
569 }
570
571 static int serpar_reset(void)
572 {
573 #ifdef COMPILING_ON_WINDOWS
574 FlushParallel();
575 FlushSerial();
576 #else
577 Unix_ResetParallel();
578 Unix_ResetSerial();
579 #endif
580
581 return serpar_set_params(&serpar_defaults);
582 }
583
584 static int find_baud_rate(unsigned int *speed)
585 {
586 static struct
587 {
588 unsigned int baud;
589 int termiosValue;
590 } possibleBaudRates[] =
591 {
592 #if defined(__hpux)
593 {115200, _B115200}, {57600, _B57600},
594 #endif
595 #ifdef COMPILING_ON_WINDOWS
596 {38400, CBR_38400}, {19200, CBR_19200}, {9600, CBR_9600}, {0, 0}
597 #else
598 {38400, B38400}, {19200, B19200}, {9600, B9600}, {0, 0}
599 #endif
600 };
601 unsigned int i;
602
603 /* look for lower or matching -- will always terminate at 0 end marker */
604 for (i = 0; possibleBaudRates[i].baud > *speed; ++i)
605 /* do nothing */
606 ;
607
608 if (possibleBaudRates[i].baud > 0)
609 *speed = possibleBaudRates[i].baud;
610
611 return possibleBaudRates[i].termiosValue;
612 }
613
614 static int serpar_set_params(const ParameterConfig *config)
615 {
616 unsigned int speed;
617 int termios_value;
618
619 #ifdef DEBUG
620 printf("serpar_set_params\n");
621 #endif
622
623 if (!Angel_FindParam(AP_BAUD_RATE, config, &speed))
624 {
625 #ifdef DEBUG
626 printf("speed not found in config\n");
627 #endif
628 return DE_OKAY;
629 }
630
631 termios_value = find_baud_rate(&speed);
632 if (termios_value == 0)
633 {
634 #ifdef DEBUG
635 printf("speed not valid: %u\n", speed);
636 #endif
637 return DE_OKAY;
638 }
639
640 #ifdef DEBUG
641 printf("setting speed to %u\n", speed);
642 #endif
643
644 #ifdef COMPILING_ON_WINDOWS
645 SetBaudRate((WORD)termios_value);
646 #else
647 Unix_SetSerialBaudRate(termios_value);
648 #endif
649
650 return DE_OKAY;
651 }
652
653
654 static int serpar_get_user_params(ParameterOptions **p_options)
655 {
656 #ifdef DEBUG
657 printf("serpar_get_user_params\n");
658 #endif
659
660 if (user_options_set)
661 {
662 *p_options = &user_options;
663 }
664 else
665 {
666 *p_options = NULL;
667 }
668
669 return DE_OKAY;
670 }
671
672
673 static int serial_get_default_params( const ParameterConfig **p_config )
674 {
675 #ifdef DEBUG
676 printf( "serial_get_default_params\n" );
677 #endif
678
679 *p_config = &serpar_defaults;
680 return DE_OKAY;
681 }
682
683
684 static int SerparIoctl(const int opcode, void *args)
685 {
686 int ret_code;
687
688 #ifdef DEBUG
689 printf("SerparIoctl: op %d arg %p\n", opcode, args ? args : "<NULL>");
690 #endif
691
692 switch (opcode)
693 {
694 case DC_RESET:
695 ret_code = serpar_reset();
696 break;
697
698 case DC_SET_PARAMS:
699 ret_code = serpar_set_params((const ParameterConfig *)args);
700 break;
701
702 case DC_GET_USER_PARAMS:
703 ret_code = serpar_get_user_params((ParameterOptions **)args);
704 break;
705
706 case DC_GET_DEFAULT_PARAMS:
707 ret_code =
708 serial_get_default_params((const ParameterConfig **)args);
709 break;
710
711 default:
712 ret_code = DE_BAD_OP;
713 break;
714 }
715
716 return ret_code;
717 }
718
719 DeviceDescr angel_SerparDevice =
720 {
721 "SERPAR",
722 SerparOpen,
723 SerparMatch,
724 SerparClose,
725 SerparRead,
726 SerparWrite,
727 SerparIoctl
728 };
729
730 /* EOF serpardr.c */