aboutsummaryrefslogtreecommitdiff
path: root/gdb/rdi-share/rx.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/rdi-share/rx.c')
-rw-r--r--gdb/rdi-share/rx.c361
1 files changed, 361 insertions, 0 deletions
diff --git a/gdb/rdi-share/rx.c b/gdb/rdi-share/rx.c
new file mode 100644
index 0000000..4f434f0
--- /dev/null
+++ b/gdb/rdi-share/rx.c
@@ -0,0 +1,361 @@
+/*
+ * 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$
+ *
+ *
+ * Project: ANGEL
+ *
+ * Title: Character reception engine
+ */
+
+#include <stdarg.h> /* ANSI varargs support */
+#include "angel.h" /* Angel system definitions */
+#include "endian.h" /* Endian independant memory access macros */
+#include "crc.h" /* crc generation definitions and headers */
+#include "rxtx.h"
+#include "channels.h"
+#include "buffers.h"
+#ifdef TARGET
+# include "devdriv.h"
+#endif
+#include "logging.h"
+
+static re_status unexp_stx(struct re_state *rxstate);
+static re_status unexp_etx(struct re_state *rxstate);
+
+/* bitfield for the rx_engine state */
+typedef enum rx_state_flag{
+ RST_STX,
+ RST_TYP,
+ RST_LEN,
+ RST_DAT,
+ RST_CRC,
+ RST_ETX,
+ RST_ESC = (0x1 << 0x3)
+} rx_state_flag;
+
+void Angel_RxEngineInit(const struct re_config *rxconfig,
+ struct re_state *rxstate)
+{
+ rxstate->rx_state = RST_STX;
+ rxstate->field_c = 0;
+ rxstate->index = 0;
+ rxstate->crc = 0;
+ rxstate->error = RE_OKAY;
+ rxstate->config = rxconfig;
+}
+
+re_status Angel_RxEngine(unsigned char new_ch, struct data_packet *packet,
+ struct re_state *rxstate)
+{
+ /*
+ * TODO: add the flow control bits in
+ * Note: We test for the data field in a seperate case so we can
+ * completely avoid entering the switch for most chars
+ */
+
+ /* see if we're expecting a escaped char */
+ if ((rxstate->rx_state & RST_ESC) == RST_ESC)
+ {
+ /* unescape the char and unset the flag*/
+ new_ch &= ~serial_ESCAPE;
+#ifdef DO_TRACE
+ __rt_trace("rxe-echar-%2x ", new_ch);
+#endif
+ rxstate->rx_state &= ~RST_ESC;
+ }
+ else if ( (1 << new_ch) & rxstate->config->esc_set )
+ {
+ /* see if the incoming char is a special one */
+ if (new_ch == rxstate->config->esc)
+ {
+#ifdef DO_TRACE
+ __rt_trace("rxe-esc ");
+#endif
+ rxstate->rx_state |= RST_ESC;
+ return RS_IN_PKT;
+ }
+ else
+ {
+ /*
+ * must be a normal packet so do some unexpected etx/stx checking
+ * we haven't been told to escape or received an escape so unless
+ * we are expecting an stx or etx then we can take the unexpected
+ * stx/etx trap
+ */
+ if ((new_ch == (rxstate->config->stx)) && (rxstate->rx_state != RST_STX))
+ return unexp_stx(rxstate);
+ if ((new_ch == (rxstate->config->etx)) && (rxstate->rx_state != RST_ETX))
+ return unexp_etx(rxstate);
+ }
+ }
+
+ if (rxstate->rx_state == RST_DAT)
+ {
+ /*
+ * do this to speed up the common case, no real penalty for
+ * other cases
+ */
+#ifdef DO_TRACE
+ __rt_trace("rxe-dat ");
+#endif
+
+ rxstate->crc = crc32(&new_ch, 1, rxstate->crc);
+ (packet->data)[rxstate->index++] = (unsigned int)new_ch & 0xff;
+
+ if (rxstate->index == packet->len)
+ rxstate->rx_state = RST_CRC;
+
+ return RS_IN_PKT;
+ }
+
+ /*
+ * Now that the common case is out of the way we can test for everything
+ * else without worrying quite so much about the speed, changing the
+ * order to len,crc,stx,etx,typ might gain a tiny bit of speed but lets
+ * leave that for the moment
+ */
+ switch (rxstate->rx_state)
+ {
+ case RST_STX:
+ if (new_ch == rxstate->config->stx)
+ {
+ rxstate->rx_state = RST_TYP;
+ rxstate->error = RE_OKAY;
+ rxstate->crc = startCRC32;
+ rxstate->index = 0;
+ return RS_IN_PKT;
+ }
+ else
+ {
+ rxstate->error = RE_OKAY;
+ return RS_WAIT_PKT;
+ }
+
+ case RST_TYP:
+ packet->type = (DevChanID)new_ch;
+ rxstate->rx_state = RST_LEN;
+ rxstate->error = RE_OKAY;
+ rxstate->field_c = 0; /* set up here for the length that follows */
+#ifdef DO_TRACE
+ __rt_trace("rxe-type-%2x ", packet->type);
+#endif
+ rxstate->crc = crc32(&new_ch, 1, rxstate->crc);
+
+ return RS_IN_PKT;
+
+ case RST_LEN:
+ rxstate->crc = crc32(&new_ch, 1, rxstate->crc);
+
+ if (rxstate->field_c++ == 0)
+ {
+ /* first length byte */
+ packet->len = ((unsigned int)new_ch) << 8;
+ return RS_IN_PKT;
+ }
+ else
+ {
+ /* got the whole legth */
+ packet->len |= new_ch;
+#ifdef DO_TRACE
+ __rt_trace("rxe-len-%4x\n", packet->len);
+#endif
+
+ /* check that the length is ok */
+ if (packet->len == 0)
+ {
+ /* empty pkt */
+ rxstate->field_c = 0;
+ rxstate->rx_state = RST_CRC;
+ return RS_IN_PKT;
+ }
+ else
+ {
+ if (packet->data == NULL)
+ {
+ /* need to alloc the data buffer */
+ if (!rxstate->config->ba_callback(
+ packet, rxstate->config->ba_data)) {
+ rxstate->rx_state = RST_STX;
+ rxstate->error = RE_INTERNAL;
+ return RS_BAD_PKT;
+ }
+ }
+
+ if (packet->len > packet->buf_len)
+ {
+ /* pkt bigger than buffer */
+ rxstate->field_c = 0;
+ rxstate->rx_state = RST_STX;
+ rxstate->error = RE_LEN;
+ return RS_BAD_PKT;
+ }
+ else
+ {
+ /* packet ok */
+ rxstate->field_c = 0;
+ rxstate->rx_state = RST_DAT;
+ return RS_IN_PKT;
+ }
+ }
+ }
+
+ case RST_DAT:
+ /* dummy case (dealt with earlier) */
+#ifdef ASSERTIONS_ENABLED
+ __rt_warning("ERROR: hit RST_dat in switch\n");
+#endif
+ rxstate->rx_state = RST_STX;
+ rxstate->error = RE_INTERNAL;
+ return RS_BAD_PKT;
+
+ case RST_CRC:
+ if (rxstate->field_c == 0)
+ packet->crc = 0;
+
+ packet->crc |= (new_ch & 0xFF) << ((3 - rxstate->field_c) * 8);
+ rxstate->field_c++;
+
+ if (rxstate->field_c == 4)
+ {
+ /* last crc field */
+ rxstate->field_c = 0;
+ rxstate->rx_state = RST_ETX;
+#ifdef DO_TRACE
+ __rt_trace("rxe-rcrc-%8x ", packet->crc);
+#endif
+ }
+
+ return RS_IN_PKT;
+
+ case RST_ETX:
+ if (new_ch == rxstate->config->etx)
+ {
+#if defined(DEBUG) && !defined(NO_PKT_DATA)
+ {
+ int c;
+# ifdef DO_TRACE
+ __rt_trace("\n");
+# endif
+ __rt_info("RXE Data =");
+ for (c=0; c < packet->len; c++)
+ __rt_info("%02x", packet->data[c]);
+ __rt_info("\n");
+ }
+#endif
+
+ /* check crc */
+ if (rxstate->crc == packet->crc)
+ {
+ /* crc ok */
+ rxstate->rx_state = RST_STX;
+ rxstate->field_c = 0;
+ return RS_GOOD_PKT;
+ }
+ else
+ {
+#ifdef ASSERTIONS_ENABLED
+ __rt_warning("Bad crc, rx calculates it should be 0x%x\n", rxstate->crc);
+#endif
+ rxstate->rx_state = RST_STX;
+ rxstate->error = RE_CRC;
+ return RS_BAD_PKT;
+ }
+ }
+ else if (new_ch == rxstate->config->stx)
+ return unexp_stx(rxstate);
+ else
+ {
+ rxstate->rx_state = RST_STX;
+ rxstate->error = RE_NETX;
+ return RS_BAD_PKT;
+ }
+
+ default:
+#ifdef ASSERTIONS_ENABLED
+ __rt_warning("ERROR fell through rxengine\n");
+#endif
+ rxstate->rx_state = RST_STX;
+ rxstate->error = RE_INTERNAL;
+ return RS_BAD_PKT;
+ }
+}
+
+static re_status unexp_stx(struct re_state *rxstate)
+{
+#ifdef ASSERTIONS_ENABLED
+ __rt_warning("Unexpected stx\n");
+#endif
+ rxstate->crc = startCRC32;
+ rxstate->index = 0;
+ rxstate->rx_state = RST_TYP;
+ rxstate->error = RE_U_STX;
+ rxstate->field_c = 0;
+ return RS_BAD_PKT;
+}
+
+static re_status unexp_etx(struct re_state *rxstate)
+{
+#ifdef ASSERTIONS_ENABLED
+ __rt_warning("Unexpected etx, rxstate: index= 0x%2x, field_c=0x%2x, state=0x%2x\n", rxstate->index, rxstate->field_c, rxstate->rx_state);
+#endif
+ rxstate->crc = 0;
+ rxstate->index = 0;
+ rxstate->rx_state = RST_STX;
+ rxstate->error = RE_U_ETX;
+ rxstate->field_c = 0;
+ return RS_BAD_PKT;
+}
+
+/*
+ * This can be used as the buffer allocation callback for the rx engine,
+ * and makes use of angel_DD_GetBuffer() [in devdrv.h].
+ *
+ * Saves duplicating this callback function in every device driver that
+ * uses the rx engine.
+ *
+ * Note that this REQUIRES that the device id is installed as ba_data
+ * in the rx engine config structure for the driver.
+ */
+bool angel_DD_RxEng_BufferAlloc( struct data_packet *packet, void *cb_data )
+{
+#ifdef TARGET
+ DeviceID devid = (DeviceID)cb_data;
+#else
+ IGNORE(cb_data);
+#endif
+
+ if ( packet->type < DC_NUM_CHANNELS )
+ {
+ /* request a buffer down from the channels layer */
+#ifdef TARGET
+ packet->data = angel_DD_GetBuffer( devid, packet->type,
+ packet->len );
+#else
+ packet->data = malloc(packet->len);
+#endif
+ if ( packet->data == NULL )
+ return FALSE;
+ else
+ {
+ packet->buf_len = packet->len;
+ return TRUE;
+ }
+ }
+ else
+ {
+ /* bad type field */
+ return FALSE;
+ }
+}
+
+/* EOF rx.c */