URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [trunk/] [gdb-5.0/] [gdb/] [rdi-share/] [serdrv.c] - Rev 1765
Compare with Previous | Blame | View Log
/* * 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: 1.1.1.1 $ * $Date: 2001-05-18 11:16:45 $ * * * 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" extern int baud_rate; /* From gdb/top.c */ #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[] = { #if defined(B115200) || defined(__hpux) 115200, #endif #if defined(B57600) || defined(__hpux) 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 } else if (baud_rate > 0) { /* If the user specified a baud rate on the command line "-b" or via the "set remotebaud" command then try to use that one */ process_baud_rate( baud_rate ); } #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}, #else #ifdef B115200 {115200,B115200}, #endif #ifdef B57600 {57600,B57600}, #endif #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 };