diff options
Diffstat (limited to 'gdb/rdi-share/serpardr.c')
-rw-r--r-- | gdb/rdi-share/serpardr.c | 730 |
1 files changed, 730 insertions, 0 deletions
diff --git a/gdb/rdi-share/serpardr.c b/gdb/rdi-share/serpardr.c new file mode 100644 index 0000000..604d048 --- /dev/null +++ b/gdb/rdi-share/serpardr.c @@ -0,0 +1,730 @@ +/* + * 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$ + * + * + * serpardv.c - Serial/Parallel Driver for Angel. + */ +#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" +#include "hsys.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 SERPAR_FC_SET ((1 << serial_XON) | (1 << serial_XOFF)) +#define SERPAR_CTL_SET ((1 << serial_STX) | (1 << serial_ETX) | \ + (1 << serial_ESC)) +#define SERPAR_ESC_SET (SERPAR_FC_SET | SERPAR_CTL_SET) + +static const struct re_config config = { + serial_STX, serial_ETX, serial_ESC, /* self-explanatory? */ + SERPAR_FC_SET, /* set of flow-control characters */ + SERPAR_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; + +/* + * structure used for manipulating transmit data + */ +typedef struct TxState +{ + struct te_state state; + unsigned int index; + unsigned char writebuf[MAXWRITESIZE]; +} TxState; + +/* + * 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 serpar_options = +{ + sizeof(param_list) / sizeof(ParameterList), + param_list +}; + +/* + * The default parameter config for the device + */ +static Parameter param_default[] = +{ + { AP_BAUD_RATE, 9600 } +}; + +static const ParameterConfig serpar_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 int)]; + +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 serpar_reset(void); +static int serpar_set_params(const ParameterConfig *config); +static int SerparMatch(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(&serpar_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, &serpar_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 SerparOpen(const char *name, const char *arg) +{ + char *sername = NULL; + char *parname = NULL; + +#ifdef DEBUG + printf("SerparOpen: name %s arg %s\n", name, arg ? arg : "<NULL>"); +#endif + +#ifdef COMPILING_ON_WINDOWS + if (IsOpenSerial() || IsOpenParallel()) return -1; +#else + if (Unix_IsSerialInUse() || Unix_IsParallelInUse()) return -1; +#endif + +#ifdef COMPILING_ON_WINDOWS + if (SerparMatch(name, arg) == -1) + return -1; +#else + Unix_IsValidParallelDevice(name,&sername,&parname); +# ifdef DEBUG + printf("translated %s to serial %s and parallel %s\n", + name==0 ? "NULL" : name, + sername==0 ? "NULL" : sername, + parname==0 ? "NULL" : parname); +# endif + if (sername==NULL || parname==NULL) return -1; +#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 + { + /* + * The serial port number is in name[0] followed by + * the parallel port number in name[1] + */ + + int sport = name[0] - '0'; + int pport = name[1] - '0'; + + if (OpenParallel(pport) != COM_OK) + return -1; + + if (OpenSerial(sport, FALSE) != COM_OK) + { + CloseParallel(); + return -1; + } + } +#else + Unix_OpenParallel(parname); + Unix_OpenSerial(sername); +#endif + + serpar_reset(); + +#if defined(__unix) || defined(__CYGWIN32__) + Unix_ioctlNonBlocking(); +#endif + + Angel_RxEngineInit(&config, &rxstate); + + return 0; +} + +#ifdef COMPILING_ON_WINDOWS +static int SerparMatch(const char *name, const char *arg) +{ + char sername[2]; + char parname[2]; + + UNUSED(arg); + + sername[0] = name[0]; + parname[0] = name[1]; + sername[1] = parname[1] = 0; + + if (IsValidDevice(sername) == COM_DEVICENOTVALID || + IsValidDevice(parname) == COM_DEVICENOTVALID) + return -1; + else + return 0; +} +#else +static int SerparMatch(const char *portstring, const char *arg) +{ + char *sername=NULL, *parname=NULL; + UNUSED(arg); + + Unix_IsValidParallelDevice(portstring,&sername,&parname); + + /* Match failed if either sername or parname are still NULL */ + if (sername==NULL || parname==NULL) return -1; + return 0; +} +#endif + +static void SerparClose(void) +{ +#ifdef COMPILING_ON_WINDOWS + CloseParallel(); + CloseSerial(); +#else + Unix_CloseParallel(); + Unix_CloseSerial(); +#endif +} + +static int SerparRead(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 */ + + /* + * we 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; + read_errno = ReadSerial(readbuf+rbindex, nread, &dummy); + 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]); +#endif + c++; + } while (c < rbindex && + ((restatus == RS_IN_PKT) || (restatus == RS_WAIT_PKT))); + +#ifdef DO_TRACE + 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("SerparRead() 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 SerparRead()\n"); +#endif + break; + } + } + else if (nread == 0) + /* nothing to read */ + ret_code = 0; + 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 SerparRead()"); +#endif + + return ret_code; +} + +/* + * Function: send_packet + * Purpose: Send a stream of bytes to Angel through the parallel port + * + * Algorithm: We need to present the data in a form that all boards can + * swallow. With the PID board, this is a problem: for reasons + * described in the driver (angel/pid/st16c552.c), data are + * sent a nybble at a time on D0-D2 and D4; D3 is wired to ACK, + * which generates an interrupt when it goes low. This routine + * fills in an array of nybbles, with ACK clear in all but the + * last one. If, for whatever reason, the write fails, then + * ACK is forced high (thereby enabling the next write a chance + * to be noticed when the falling edge of ACK generates an + * interrupt (hopefully). + * + * Params: + * Input: txstate Contains the packet to be sent + * + * Returns: Number of *complete* bytes written + */ + +static int SerparWrite(DriverCall *dc) +{ + te_status status; + int nwritten = 0; + static TxState txstate; + + /* + * is this a new packet? + */ + if (dc->dc_context == NULL) + { + /* + * yes - initialise TxEngine + */ + Angel_TxEngineInit(&config, &dc->dc_packet, &txstate.state); + + txstate.index = 0; + dc->dc_context = &txstate; + } + + /* + * fill the buffer using the Tx Engine + */ + do + { + status = Angel_TxEngine(&dc->dc_packet, &txstate.state, + &txstate.writebuf[txstate.index]); + if (status != TS_IDLE) txstate.index++; + + } while (status == TS_IN_PKT && txstate.index < MAXWRITESIZE); + +#ifdef DO_TRACE + { + unsigned int i = 0; + + while (i < txstate.index) + { + printf(">%02X ", txstate.writebuf[i]); + + if (!(++i % 16)) + putc('\n', stdout); + } + + if (i % 16) + putc('\n', stdout); + } +#endif + + /* + * the data are ready, all we need now is to send them out + * in a form that Angel can swallow. + */ +#ifdef COMPILING_ON_WINDOWS + if (WriteParallel(txstate.writebuf, txstate.index) == COM_OK) + { + nwritten = txstate.index; + 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_WriteParallel(txstate.writebuf, txstate.index); +#endif + + if (nwritten < 0) nwritten = 0; + +#ifdef DO_TRACE + printf("SerparWrite: wrote %d out of %d bytes\n", + nwritten, txstate.index); +#endif + + /* + * has the whole packet gone? + */ + if (nwritten == (int)txstate.index && + (status == TS_DONE_PKT || status == TS_IDLE)) + /* + * yes it has + */ + return 1; + else + { + /* + * if some data are left, shuffle them + * to the start of the buffer + */ + if (nwritten != (int)txstate.index && nwritten != 0) + { + txstate.index -= nwritten; + (void)memmove((char *) txstate.writebuf, + (char *) (txstate.writebuf + nwritten), + txstate.index); + } + else if (nwritten == (int)txstate.index) + txstate.index = 0; + + return 0; + } +} + +static int serpar_reset(void) +{ +#ifdef COMPILING_ON_WINDOWS + FlushParallel(); + FlushSerial(); +#else + Unix_ResetParallel(); + Unix_ResetSerial(); +#endif + + return serpar_set_params(&serpar_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 serpar_set_params(const ParameterConfig *config) +{ + unsigned int speed; + int termios_value; + +#ifdef DEBUG + printf("serpar_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 serpar_get_user_params(ParameterOptions **p_options) +{ +#ifdef DEBUG + printf("serpar_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( const ParameterConfig **p_config ) +{ +#ifdef DEBUG + printf( "serial_get_default_params\n" ); +#endif + + *p_config = &serpar_defaults; + return DE_OKAY; +} + + +static int SerparIoctl(const int opcode, void *args) +{ + int ret_code; + +#ifdef DEBUG + printf("SerparIoctl: op %d arg %p\n", opcode, args ? args : "<NULL>"); +#endif + + switch (opcode) + { + case DC_RESET: + ret_code = serpar_reset(); + break; + + case DC_SET_PARAMS: + ret_code = serpar_set_params((const ParameterConfig *)args); + break; + + case DC_GET_USER_PARAMS: + ret_code = serpar_get_user_params((ParameterOptions **)args); + break; + + case DC_GET_DEFAULT_PARAMS: + ret_code = + serial_get_default_params((const ParameterConfig **)args); + break; + + default: + ret_code = DE_BAD_OP; + break; + } + + return ret_code; +} + +DeviceDescr angel_SerparDevice = +{ + "SERPAR", + SerparOpen, + SerparMatch, + SerparClose, + SerparRead, + SerparWrite, + SerparIoctl +}; + +/* EOF serpardr.c */ |