summaryrefslogtreecommitdiff
path: root/gdb/rdi-share/serdrv.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/rdi-share/serdrv.c')
-rw-r--r--gdb/rdi-share/serdrv.c649
1 files changed, 649 insertions, 0 deletions
diff --git a/gdb/rdi-share/serdrv.c b/gdb/rdi-share/serdrv.c
new file mode 100644
index 00000000000..43fd5a00f22
--- /dev/null
+++ b/gdb/rdi-share/serdrv.c
@@ -0,0 +1,649 @@
+/*
+ * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved.
+ *
+ * This software may be freely used, copied, modified, and distributed
+ * provided that the above copyright notice is preserved in all copies of the
+ * software.
+ */
+
+/* -*-C-*-
+ *
+ * $Revision$
+ * $Date$
+ *
+ *
+ * serdrv.c - Synchronous Serial Driver for Angel.
+ * This is nice and simple just to get something going.
+ */
+
+#ifdef __hpux
+# define _POSIX_SOURCE 1
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "crc.h"
+#include "devices.h"
+#include "buffers.h"
+#include "rxtx.h"
+#include "hostchan.h"
+#include "params.h"
+#include "logging.h"
+
+#ifdef COMPILING_ON_WINDOWS
+# undef ERROR
+# undef IGNORE
+# include <windows.h>
+# include "angeldll.h"
+# include "comb_api.h"
+#else
+# ifdef __hpux
+# define _TERMIOS_INCLUDED
+# include <sys/termio.h>
+# undef _TERMIOS_INCLUDED
+# else
+# include <termios.h>
+# endif
+# include "unixcomm.h"
+#endif
+
+#ifndef UNUSED
+# define UNUSED(x) (x = x) /* Silence compiler warnings */
+#endif
+
+#define MAXREADSIZE 512
+#define MAXWRITESIZE 512
+
+#define SERIAL_FC_SET ((1<<serial_XON)|(1<<serial_XOFF))
+#define SERIAL_CTL_SET ((1<<serial_STX)|(1<<serial_ETX)|(1<<serial_ESC))
+#define SERIAL_ESC_SET (SERIAL_FC_SET|SERIAL_CTL_SET)
+
+static const struct re_config config = {
+ serial_STX, serial_ETX, serial_ESC, /* self-explanatory? */
+ SERIAL_FC_SET, /* set of flow-control characters */
+ SERIAL_ESC_SET, /* set of characters to be escaped */
+ NULL /* serial_flow_control */, NULL , /* what to do with FC chars */
+ angel_DD_RxEng_BufferAlloc, NULL /* how to get a buffer */
+};
+
+static struct re_state rxstate;
+
+typedef struct writestate {
+ unsigned int wbindex;
+ /* static te_status testatus;*/
+ unsigned char writebuf[MAXWRITESIZE];
+ struct te_state txstate;
+} writestate;
+
+static struct writestate wstate;
+
+/*
+ * The set of parameter options supported by the device
+ */
+static unsigned int baud_options[] = {
+#ifdef __hpux
+ 115200, 57600,
+#endif
+ 38400, 19200, 9600
+};
+
+static ParameterList param_list[] = {
+ { AP_BAUD_RATE,
+ sizeof(baud_options)/sizeof(unsigned int),
+ baud_options }
+};
+
+static const ParameterOptions serial_options = {
+ sizeof(param_list)/sizeof(ParameterList), param_list };
+
+/*
+ * The default parameter config for the device
+ */
+static Parameter param_default[] = {
+ { AP_BAUD_RATE, 9600 }
+};
+
+static ParameterConfig serial_defaults = {
+ sizeof(param_default)/sizeof(Parameter), param_default };
+
+/*
+ * The user-modified options for the device
+ */
+static unsigned int user_baud_options[sizeof(baud_options)/sizeof(unsigned)];
+
+static ParameterList param_user_list[] = {
+ { AP_BAUD_RATE,
+ sizeof(user_baud_options)/sizeof(unsigned),
+ user_baud_options }
+};
+
+static ParameterOptions user_options = {
+ sizeof(param_user_list)/sizeof(ParameterList), param_user_list };
+
+static bool user_options_set;
+
+/* forward declarations */
+static int serial_reset( void );
+static int serial_set_params( const ParameterConfig *config );
+static int SerialMatch(const char *name, const char *arg);
+
+static void process_baud_rate( unsigned int target_baud_rate )
+{
+ const ParameterList *full_list;
+ ParameterList *user_list;
+
+ /* create subset of full options */
+ full_list = Angel_FindParamList( &serial_options, AP_BAUD_RATE );
+ user_list = Angel_FindParamList( &user_options, AP_BAUD_RATE );
+
+ if ( full_list != NULL && user_list != NULL )
+ {
+ unsigned int i, j;
+ unsigned int def_baud = 0;
+
+ /* find lower or equal to */
+ for ( i = 0; i < full_list->num_options; ++i )
+ if ( target_baud_rate >= full_list->option[i] )
+ {
+ /* copy remaining */
+ for ( j = 0; j < (full_list->num_options - i); ++j )
+ user_list->option[j] = full_list->option[i+j];
+ user_list->num_options = j;
+
+ /* check this is not the default */
+ Angel_FindParam( AP_BAUD_RATE, &serial_defaults, &def_baud );
+ if ( (j == 1) && (user_list->option[0] == def_baud) )
+ {
+#ifdef DEBUG
+ printf( "user selected default\n" );
+#endif
+ }
+ else
+ {
+ user_options_set = TRUE;
+#ifdef DEBUG
+ printf( "user options are: " );
+ for ( j = 0; j < user_list->num_options; ++j )
+ printf( "%u ", user_list->option[j] );
+ printf( "\n" );
+#endif
+ }
+
+ break; /* out of i loop */
+ }
+
+#ifdef DEBUG
+ if ( i >= full_list->num_options )
+ printf( "couldn't match baud rate %u\n", target_baud_rate );
+#endif
+ }
+#ifdef DEBUG
+ else
+ printf( "failed to find lists\n" );
+#endif
+}
+
+static int SerialOpen(const char *name, const char *arg)
+{
+ const char *port_name = name;
+
+#ifdef DEBUG
+ printf("SerialOpen: name %s arg %s\n", name, arg ? arg : "<NULL>");
+#endif
+
+#ifdef COMPILING_ON_WINDOWS
+ if (IsOpenSerial()) return -1;
+#else
+ if (Unix_IsSerialInUse()) return -1;
+#endif
+
+#ifdef COMPILING_ON_WINDOWS
+ if (SerialMatch(name, arg) != adp_ok)
+ return adp_failed;
+#else
+ port_name = Unix_MatchValidSerialDevice(port_name);
+# ifdef DEBUG
+ printf("translated port to %s\n", port_name == 0 ? "NULL" : port_name);
+# endif
+ if (port_name == 0) return adp_failed;
+#endif
+
+ user_options_set = FALSE;
+
+ /* interpret and store the arguments */
+ if ( arg != NULL )
+ {
+ unsigned int target_baud_rate;
+ target_baud_rate = (unsigned int)strtoul(arg, NULL, 10);
+ if (target_baud_rate > 0)
+ {
+#ifdef DEBUG
+ printf( "user selected baud rate %u\n", target_baud_rate );
+#endif
+ process_baud_rate( target_baud_rate );
+ }
+#ifdef DEBUG
+ else
+ printf( "could not understand baud rate %s\n", arg );
+#endif
+ }
+
+#ifdef COMPILING_ON_WINDOWS
+ {
+ int port = IsValidDevice(name);
+ if (OpenSerial(port, FALSE) != COM_OK)
+ return -1;
+ }
+#else
+ if (Unix_OpenSerial(port_name) < 0)
+ return -1;
+#endif
+
+ serial_reset();
+
+#if defined(__unix) || defined(__CYGWIN32__)
+ Unix_ioctlNonBlocking();
+#endif
+
+ Angel_RxEngineInit(&config, &rxstate);
+ /*
+ * DANGER!: passing in NULL as the packet is ok for now as it is just
+ * IGNOREd but this may well change
+ */
+ Angel_TxEngineInit(&config, NULL, &wstate.txstate);
+ return 0;
+}
+
+static int SerialMatch(const char *name, const char *arg)
+{
+ UNUSED(arg);
+#ifdef COMPILING_ON_WINDOWS
+ if (IsValidDevice(name) == COM_DEVICENOTVALID)
+ return -1;
+ else
+ return 0;
+#else
+ return Unix_MatchValidSerialDevice(name) == 0 ? -1 : 0;
+#endif
+}
+
+static void SerialClose(void)
+{
+#ifdef DO_TRACE
+ printf("SerialClose()\n");
+#endif
+
+#ifdef COMPILING_ON_WINDOWS
+ CloseSerial();
+#else
+ Unix_CloseSerial();
+#endif
+}
+
+static int SerialRead(DriverCall *dc, bool block) {
+ static unsigned char readbuf[MAXREADSIZE];
+ static int rbindex=0;
+
+ int nread;
+ int read_errno;
+ int c=0;
+ re_status restatus;
+ int ret_code = -1; /* assume bad packet or error */
+
+ /* must not overflow buffer and must start after the existing data */
+#ifdef COMPILING_ON_WINDOWS
+ {
+ BOOL dummy = FALSE;
+ nread = BytesInRXBufferSerial();
+
+ if (nread > MAXREADSIZE - rbindex)
+ nread = MAXREADSIZE - rbindex;
+
+ if ((read_errno = ReadSerial(readbuf+rbindex, nread, &dummy)) == COM_READFAIL)
+ {
+ MessageBox(GetFocus(), "Read error\n", "Angel", MB_OK | MB_ICONSTOP);
+ return -1; /* SJ - This really needs to return a value, which is picked up in */
+ /* DevSW_Read as meaning stop debugger but don't kill. */
+ }
+ else if (pfnProgressCallback != NULL && read_errno == COM_OK)
+ {
+ progressInfo.nRead += nread;
+ (*pfnProgressCallback)(&progressInfo);
+ }
+ }
+#else
+ nread = Unix_ReadSerial(readbuf+rbindex, MAXREADSIZE-rbindex, block);
+ read_errno = errno;
+#endif
+
+ if ((nread > 0) || (rbindex > 0)) {
+
+#ifdef DO_TRACE
+ printf("[%d@%d] ", nread, rbindex);
+#endif
+
+ if (nread>0)
+ rbindex = rbindex+nread;
+
+ do {
+ restatus = Angel_RxEngine(readbuf[c], &(dc->dc_packet), &rxstate);
+#ifdef DO_TRACE
+ printf("<%02X ",readbuf[c]);
+ if (!(++c % 16))
+ printf("\n");
+#else
+ c++;
+#endif
+ } while (c<rbindex &&
+ ((restatus == RS_IN_PKT) || (restatus == RS_WAIT_PKT)));
+
+#ifdef DO_TRACE
+ if (c % 16)
+ printf("\n");
+#endif
+
+ switch(restatus) {
+
+ case RS_GOOD_PKT:
+ ret_code = 1;
+ /* fall through to: */
+
+ case RS_BAD_PKT:
+ /*
+ * We now need to shuffle any left over data down to the
+ * beginning of our private buffer ready to be used
+ *for the next packet
+ */
+#ifdef DO_TRACE
+ printf("SerialRead() processed %d, moving down %d\n", c, rbindex-c);
+#endif
+ if (c != rbindex) memmove((char *) readbuf, (char *) (readbuf+c),
+ rbindex-c);
+ rbindex -= c;
+ break;
+
+ case RS_IN_PKT:
+ case RS_WAIT_PKT:
+ rbindex = 0; /* will have processed all we had */
+ ret_code = 0;
+ break;
+
+ default:
+#ifdef DEBUG
+ printf("Bad re_status in serialRead()\n");
+#endif
+ break;
+ }
+ } else if (nread == 0)
+ ret_code = 0; /* nothing to read */
+ else if (read_errno == ERRNO_FOR_BLOCKED_IO) /* nread < 0 */
+ ret_code = 0;
+
+#ifdef DEBUG
+ if ((nread<0) && (read_errno!=ERRNO_FOR_BLOCKED_IO))
+ perror("read() error in serialRead()");
+#endif
+
+ return ret_code;
+}
+
+
+static int SerialWrite(DriverCall *dc) {
+ int nwritten = 0;
+ te_status testatus = TS_IN_PKT;
+
+ if (dc->dc_context == NULL) {
+ Angel_TxEngineInit(&config, &(dc->dc_packet), &(wstate.txstate));
+ wstate.wbindex = 0;
+ dc->dc_context = &wstate;
+ }
+
+ while ((testatus == TS_IN_PKT) && (wstate.wbindex < MAXWRITESIZE))
+ {
+ /* send the raw data through the tx engine to escape and encapsulate */
+ testatus = Angel_TxEngine(&(dc->dc_packet), &(wstate.txstate),
+ &(wstate.writebuf)[wstate.wbindex]);
+ if (testatus != TS_IDLE) wstate.wbindex++;
+ }
+
+ if (testatus == TS_IDLE) {
+#ifdef DEBUG
+ printf("SerialWrite: testatus is TS_IDLE during preprocessing\n");
+#endif
+ }
+
+#ifdef DO_TRACE
+ {
+ int i = 0;
+
+ while (i<wstate.wbindex)
+ {
+ printf(">%02X ",wstate.writebuf[i]);
+
+ if (!(++i % 16))
+ printf("\n");
+ }
+ if (i % 16)
+ printf("\n");
+ }
+#endif
+
+#ifdef COMPILING_ON_WINDOWS
+ if (WriteSerial(wstate.writebuf, wstate.wbindex) == COM_OK)
+ {
+ nwritten = wstate.wbindex;
+ if (pfnProgressCallback != NULL)
+ {
+ progressInfo.nWritten += nwritten;
+ (*pfnProgressCallback)(&progressInfo);
+ }
+ }
+ else
+ {
+ MessageBox(GetFocus(), "Write error\n", "Angel", MB_OK | MB_ICONSTOP);
+ return -1; /* SJ - This really needs to return a value, which is picked up in */
+ /* DevSW_Read as meaning stop debugger but don't kill. */
+ }
+#else
+ nwritten = Unix_WriteSerial(wstate.writebuf, wstate.wbindex);
+
+ if (nwritten < 0) {
+ nwritten=0;
+ }
+#endif
+
+#ifdef DEBUG
+ if (nwritten > 0)
+ printf("Wrote %#04x bytes\n", nwritten);
+#endif
+
+ if ((unsigned) nwritten == wstate.wbindex &&
+ (testatus == TS_DONE_PKT || testatus == TS_IDLE)) {
+
+ /* finished sending the packet */
+
+#ifdef DEBUG
+ printf("SerialWrite: calling Angel_TxEngineInit after sending packet (len=%i)\n",wstate.wbindex);
+#endif
+ testatus = TS_IN_PKT;
+ wstate.wbindex = 0;
+ return 1;
+ }
+ else {
+#ifdef DEBUG
+ printf("SerialWrite: Wrote part of packet wbindex=%i, nwritten=%i\n",
+ wstate.wbindex, nwritten);
+#endif
+
+ /*
+ * still some data left to send shuffle whats left down and reset
+ * the ptr
+ */
+ memmove((char *) wstate.writebuf, (char *) (wstate.writebuf+nwritten),
+ wstate.wbindex-nwritten);
+ wstate.wbindex -= nwritten;
+ return 0;
+ }
+ return -1;
+}
+
+
+static int serial_reset( void )
+{
+#ifdef DEBUG
+ printf( "serial_reset\n" );
+#endif
+
+#ifdef COMPILING_ON_WINDOWS
+ FlushSerial();
+#else
+ Unix_ResetSerial();
+#endif
+
+ return serial_set_params( &serial_defaults );
+}
+
+
+static int find_baud_rate( unsigned int *speed )
+{
+ static struct {
+ unsigned int baud;
+ int termiosValue;
+ } possibleBaudRates[] = {
+#if defined(__hpux)
+ {115200,_B115200}, {57600,_B57600},
+#endif
+#ifdef COMPILING_ON_WINDOWS
+ {38400,CBR_38400}, {19200,CBR_19200}, {9600, CBR_9600}, {0,0}
+#else
+ {38400,B38400}, {19200,B19200}, {9600, B9600}, {0,0}
+#endif
+ };
+ unsigned int i;
+
+ /* look for lower or matching -- will always terminate at 0 end marker */
+ for ( i = 0; possibleBaudRates[i].baud > *speed; ++i )
+ /* do nothing */ ;
+
+ if ( possibleBaudRates[i].baud > 0 )
+ *speed = possibleBaudRates[i].baud;
+
+ return possibleBaudRates[i].termiosValue;
+}
+
+
+static int serial_set_params( const ParameterConfig *config )
+{
+ unsigned int speed;
+ int termios_value;
+
+#ifdef DEBUG
+ printf( "serial_set_params\n" );
+#endif
+
+ if ( ! Angel_FindParam( AP_BAUD_RATE, config, &speed ) )
+ {
+#ifdef DEBUG
+ printf( "speed not found in config\n" );
+#endif
+ return DE_OKAY;
+ }
+
+ termios_value = find_baud_rate( &speed );
+ if ( termios_value == 0 )
+ {
+#ifdef DEBUG
+ printf( "speed not valid: %u\n", speed );
+#endif
+ return DE_OKAY;
+ }
+
+#ifdef DEBUG
+ printf( "setting speed to %u\n", speed );
+#endif
+
+#ifdef COMPILING_ON_WINDOWS
+ SetBaudRate((WORD)termios_value);
+#else
+ Unix_SetSerialBaudRate(termios_value);
+#endif
+
+ return DE_OKAY;
+}
+
+
+static int serial_get_user_params( ParameterOptions **p_options )
+{
+#ifdef DEBUG
+ printf( "serial_get_user_params\n" );
+#endif
+
+ if ( user_options_set )
+ {
+ *p_options = &user_options;
+ }
+ else
+ {
+ *p_options = NULL;
+ }
+
+ return DE_OKAY;
+}
+
+
+static int serial_get_default_params( ParameterConfig **p_config )
+{
+#ifdef DEBUG
+ printf( "serial_get_default_params\n" );
+#endif
+
+ *p_config = (ParameterConfig *) &serial_defaults;
+ return DE_OKAY;
+}
+
+
+static int SerialIoctl(const int opcode, void *args) {
+
+ int ret_code;
+
+#ifdef DEBUG
+ printf( "SerialIoctl: op %d arg %p\n", opcode, args ? args : "<NULL>");
+#endif
+
+ switch (opcode)
+ {
+ case DC_RESET:
+ ret_code = serial_reset();
+ break;
+
+ case DC_SET_PARAMS:
+ ret_code = serial_set_params((const ParameterConfig *)args);
+ break;
+
+ case DC_GET_USER_PARAMS:
+ ret_code = serial_get_user_params((ParameterOptions **)args);
+ break;
+
+ case DC_GET_DEFAULT_PARAMS:
+ ret_code = serial_get_default_params((ParameterConfig **)args);
+ break;
+
+ default:
+ ret_code = DE_BAD_OP;
+ break;
+ }
+
+ return ret_code;
+}
+
+DeviceDescr angel_SerialDevice = {
+ "SERIAL",
+ SerialOpen,
+ SerialMatch,
+ SerialClose,
+ SerialRead,
+ SerialWrite,
+ SerialIoctl
+};