diff options
Diffstat (limited to 'gdb/rdi-share/serdrv.c')
-rw-r--r-- | gdb/rdi-share/serdrv.c | 649 |
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 0000000..43fd5a0 --- /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 +}; |