aboutsummaryrefslogtreecommitdiff
path: root/gdb/rdi-share/hostchan.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/rdi-share/hostchan.c')
-rw-r--r--gdb/rdi-share/hostchan.c1057
1 files changed, 1057 insertions, 0 deletions
diff --git a/gdb/rdi-share/hostchan.c b/gdb/rdi-share/hostchan.c
new file mode 100644
index 0000000..8e41da4
--- /dev/null
+++ b/gdb/rdi-share/hostchan.c
@@ -0,0 +1,1057 @@
+/*
+ * 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$
+ *
+ *
+ * hostchan.c - Semi Synchronous Host side channel interface for Angel.
+ */
+
+#include <stdio.h>
+
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#else
+# include "winsock.h"
+# include "time.h"
+#endif
+#include "hsys.h"
+#include "host.h"
+#include "logging.h"
+#include "chandefs.h"
+#include "chanpriv.h"
+#include "devclnt.h"
+#include "buffers.h"
+#include "drivers.h"
+#include "adperr.h"
+#include "devsw.h"
+#include "hostchan.h"
+
+#ifndef UNUSED
+#define UNUSED(x) (x = x) /* Silence compiler warnings for unused arguments */
+#endif
+
+#define HEARTRATE 5000000
+
+/*
+ * list of available drivers, declared in drivers.c
+ */
+extern DeviceDescr *devices[];
+
+static DeviceDescr *deviceToUse = NULL;
+
+static struct Channel {
+ ChannelCallback callback;
+ void *callback_state;
+} channels[CI_NUM_CHANNELS];
+
+static unsigned char HomeSeq;
+static unsigned char OppoSeq;
+
+/*
+ * Handler for DC_APPL packets
+ */
+static DC_Appl_Handler dc_appl_handler = NULL;
+
+/*
+ * slots for registered asynchronous processing callback procedures
+ */
+#define MAX_ASYNC_CALLBACKS 8
+static unsigned int num_async_callbacks = 0;
+static Adp_Async_Callback async_callbacks[MAX_ASYNC_CALLBACKS];
+
+/*
+ * writeQueueRoot is the queue of write requests pending acknowledgement
+ * writeQueueSend is the queue of pending write requests which will
+ * be a subset of the list writeQueueRoot
+ */
+static Packet *writeQueueRoot = NULL;
+static Packet *writeQueueSend = NULL;
+static Packet *resend_pkt = NULL;
+static int resending = FALSE;
+
+/* heartbeat_enabled is a flag used to indicate whether the heartbeat is
+ * currently turned on, heartbeat_enabled will be false in situations
+ * where even though a heartbeat is being used it is problematical or
+ * dis-advantageous to have it turned on, for instance during the
+ * initial stages of boot up
+ */
+unsigned int heartbeat_enabled = FALSE;
+/* heartbeat_configured is set up by the device driver to indicate whether
+ * the heartbeat is being used during this debug session. In contrast to
+ * heartbeat_enabled it must not be changed during a session. The logic for
+ * deciding whether to send a heartbeat is: Is heartbeat_configured for this
+ * session? if and only if it is then if heartbeat[is currently]_enabled and
+ * we are due to send a pulse then send it
+ */
+unsigned int heartbeat_configured = TRUE;
+
+void Adp_initSeq( void ) {
+ Packet *tmp_pkt = writeQueueSend;
+
+ HomeSeq = 0;
+ OppoSeq = 0;
+ if ( writeQueueSend != NULL) {
+ while (writeQueueSend->pk_next !=NULL) {
+ tmp_pkt = writeQueueSend;
+ writeQueueSend = tmp_pkt->pk_next;
+ DevSW_FreePacket(tmp_pkt);
+ }
+ }
+ tmp_pkt = writeQueueRoot;
+ if ( writeQueueRoot == NULL)
+ return;
+
+ while (writeQueueRoot->pk_next !=NULL) {
+ tmp_pkt = writeQueueRoot;
+ writeQueueRoot = tmp_pkt->pk_next;
+ DevSW_FreePacket(tmp_pkt);
+ }
+ return;
+}
+
+/**********************************************************************/
+
+/*
+ * Function: DummyCallback
+ * Purpose: Default callback routine to handle unexpected input
+ * on a channel
+ *
+ * Params:
+ * Input: packet The received packet
+ *
+ * state Contains nothing of significance
+ *
+ * Returns: Nothing
+ */
+static void DummyCallback(Packet *packet, void *state)
+{
+ ChannelID chan;
+ const char fmt[] = "Unexpected read on channel %u, length %d\n";
+ char fmtbuf[sizeof(fmt) + 24];
+
+ UNUSED(state);
+
+ chan = *(packet->pk_buffer);
+ sprintf(fmtbuf, fmt, chan, packet->pk_length);
+ printf(fmtbuf);
+
+ /*
+ * junk this packet
+ */
+ DevSW_FreePacket(packet);
+}
+
+/*
+ * Function: BlockingCallback
+ * Purpose: Callback routine used to implement a blocking read call
+ *
+ * Params:
+ * Input: packet The received packet.
+ *
+ * Output: state Address of higher level's pointer to the received
+ * packet.
+ *
+ * Returns: Nothing
+ */
+static void BlockingCallback(Packet *packet, void *state)
+{
+ /*
+ * Pass the packet back to the caller which requested a packet
+ * from this channel. This also flags the completion of the I/O
+ * request to the blocking read call.
+ */
+ *((Packet **)state) = packet;
+}
+
+/*
+ * Function: FireCallback
+ * Purpose: Pass received packet along to the callback routine for
+ * the appropriate channel
+ *
+ * Params:
+ * Input: packet The received packet.
+ *
+ * Returns: Nothing
+ *
+ * Post-conditions: The Target-to-Host sequence number for the channel
+ * will have been incremented.
+ */
+static void FireCallback(Packet *packet)
+{
+ ChannelID chan;
+ struct Channel *ch;
+
+ /*
+ * is this a sensible channel number?
+ */
+ chan = *(packet->pk_buffer);
+ if (invalidChannelID(chan))
+ {
+ printf("ERROR: invalid ChannelID received from target\n");
+
+ /*
+ * free the packet's resources, 'cause no-one else will
+ */
+ DevSW_FreePacket(packet);
+ return;
+ }
+
+ /*
+ * looks OK - increment sequence number, and pass packet to callback
+ */
+ ch = channels + chan;
+ (ch->callback)(packet, ch->callback_state);
+}
+
+/**********************************************************************/
+
+/*
+ * These are the externally visible functions. They are documented
+ * in hostchan.h
+ */
+void Adp_addToQueue(Packet **head, Packet *newpkt)
+{
+ /*
+ * this is a bit of a hack
+ */
+ Packet *pk;
+
+ /*
+ * make sure that the hack we are about to use will work as expected
+ */
+ ASSERT(&(((Packet *)0)->pk_next) == 0, "bad struct Packet layout");
+
+#if DEBUG && 0
+ printf("Adp_addToQueue(%p, %p)\n", head, newpkt);
+#endif
+
+ /*
+ * here's the hack - it relies upon the next
+ * pointer being at the start of Packet.
+ */
+ pk = (Packet *)(head);
+
+ /*
+ * skip to the end of the queue
+ */
+ while (pk->pk_next != NULL)
+ pk = pk->pk_next;
+
+ /*
+ * now add the new element
+ */
+ newpkt->pk_next = NULL;
+ pk->pk_next = newpkt;
+}
+
+Packet *Adp_removeFromQueue(Packet **head)
+{
+ struct Packet *pk;
+
+ pk = *head;
+
+ if (pk != NULL)
+ *head = pk->pk_next;
+
+ return pk;
+}
+
+AdpErrs Adp_OpenDevice(const char *name, const char *arg,
+ unsigned int heartbeat_on)
+{
+ int i;
+ AdpErrs retc;
+ ChannelID chan;
+
+#ifdef DEBUG
+ printf("Adp_OpenDevice(%s, %s)\n", name, arg ? arg : "<NULL>");
+#endif
+
+ heartbeat_configured = heartbeat_on;
+ if (deviceToUse != NULL)
+ return adp_device_already_open;
+
+ for (i = 0; (deviceToUse = devices[i]) != NULL; ++i)
+ if (DevSW_Match(deviceToUse, name, arg) == adp_ok)
+ break;
+
+ if (deviceToUse == NULL)
+ return adp_device_not_found;
+
+ /*
+ * we seem to have found a suitable device driver, so try to open it
+ */
+ if ((retc = DevSW_Open(deviceToUse, name, arg, DC_DBUG)) != adp_ok)
+ {
+ /* we don't have a device to use */
+ deviceToUse = NULL;
+ return retc;
+ }
+
+ /*
+ * there is no explicit open on channels any more, so
+ * initialise state for all channels.
+ */
+ for (chan = 0; chan < CI_NUM_CHANNELS; ++chan)
+ {
+ struct Channel *ch = channels + chan;
+
+ ch->callback = DummyCallback;
+ ch->callback_state = NULL;
+ OppoSeq = 0;
+ HomeSeq = 0;
+ }
+
+ return adp_ok;
+}
+
+AdpErrs Adp_CloseDevice(void)
+{
+ AdpErrs retc;
+
+#ifdef DEBUG
+ printf("Adp_CloseDevice\n");
+#endif
+
+ if (deviceToUse == NULL)
+ return adp_device_not_open;
+
+ heartbeat_enabled = FALSE;
+
+ retc = DevSW_Close(deviceToUse, DC_DBUG);
+
+ /*
+ * we have to clear deviceToUse, even when the lower layers
+ * faulted the close, otherwise the condition will never clear
+ */
+ if (retc != adp_ok)
+ WARN("DevSW_Close faulted the call");
+
+ deviceToUse = NULL;
+ return retc;
+}
+
+AdpErrs Adp_Ioctl(int opcode, void *args)
+{
+#ifdef DEBUG
+ printf("Adp_Ioctl\n");
+#endif
+
+ if (deviceToUse == NULL)
+ return adp_device_not_open;
+
+ return DevSW_Ioctl(deviceToUse, opcode, args);
+}
+
+AdpErrs Adp_ChannelRegisterRead(const ChannelID chan,
+ const ChannelCallback cbfunc,
+ void *cbstate)
+{
+#ifdef DEBUG
+ printf("Adp_ChannelRegisterRead(%d, %p, %x)\n", chan, cbfunc, cbstate);
+#endif
+
+ if (deviceToUse == NULL)
+ return adp_device_not_open;
+
+ if (invalidChannelID(chan))
+ return adp_bad_channel_id;
+
+ if (cbfunc == NULL)
+ {
+ channels[chan].callback = DummyCallback;
+ channels[chan].callback_state = NULL;
+ }
+ else
+ {
+ channels[chan].callback = cbfunc;
+ channels[chan].callback_state = cbstate;
+ }
+
+ return adp_ok;
+}
+
+AdpErrs Adp_ChannelRead(const ChannelID chan, Packet **packet)
+{
+ struct Channel *ch;
+
+#ifdef DEBUG
+ printf("Adp_ChannelRead(%d, %x)\n", chan, *packet);
+#endif
+
+ if (deviceToUse == NULL)
+ return adp_device_not_open;
+
+ if (invalidChannelID(chan))
+ return adp_bad_channel_id;
+
+ /*
+ * if a callback has already been registered for this
+ * channel, then we do not allow this blocking read.
+ */
+ ch = channels + chan;
+ if (ch->callback != DummyCallback)
+ return adp_callback_already_registered;
+
+ /*
+ * OK, use our own callback to wait for a packet to arrive
+ * on this channel
+ */
+ ch->callback = BlockingCallback;
+ ch->callback_state = packet;
+ *packet = NULL;
+
+ /*
+ * keep polling until a packet appears for this channel
+ */
+ while (((volatile Packet *)(*packet)) == NULL)
+ /*
+ * this call will block until a packet is read on any channel
+ */
+ Adp_AsynchronousProcessing(async_block_on_read);
+
+ /*
+ * OK, the packet has arrived: clear the callback
+ */
+ ch->callback = DummyCallback;
+ ch->callback_state = NULL;
+
+ return adp_ok;
+}
+
+static AdpErrs ChannelWrite(
+ const ChannelID chan, Packet *packet, AsyncMode mode)
+{
+ struct Channel *ch;
+ unsigned char *cptr;
+
+#ifdef DEBUG
+ printf( "Adp_ChannelWrite(%d, %x)\n", chan, packet );
+#endif
+
+ if (deviceToUse == NULL)
+ return adp_device_not_open;
+
+ if (invalidChannelID(chan))
+ return adp_bad_channel_id;
+
+ /*
+ * fill in the channels header at the start of this buffer
+ */
+ ch = channels + chan;
+ cptr = packet->pk_buffer;
+ *cptr++ = chan;
+ *cptr = 0;
+ packet->pk_length += CHAN_HEADER_SIZE;
+
+ /*
+ * OK, add this packet to the write queue, and try to flush it out
+ */
+
+ Adp_addToQueue(&writeQueueSend, packet);
+ Adp_AsynchronousProcessing(mode);
+
+ return adp_ok;
+}
+
+AdpErrs Adp_ChannelWrite(const ChannelID chan, Packet *packet) {
+ return ChannelWrite(chan, packet, async_block_on_write);
+}
+
+AdpErrs Adp_ChannelWriteAsync(const ChannelID chan, Packet *packet) {
+ return ChannelWrite(chan, packet, async_block_on_nothing);
+}
+
+static AdpErrs send_resend_msg(DeviceID devid) {
+
+ /*
+ * Send a resend message, usually in response to a bad packet or
+ * a resend request */
+ Packet * packet;
+ packet = DevSW_AllocatePacket(CF_DATA_BYTE_POS);
+ packet->pk_buffer[CF_CHANNEL_BYTE_POS] = CI_PRIVATE;
+ packet->pk_buffer[CF_HOME_SEQ_BYTE_POS] = HomeSeq;
+ packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS] = OppoSeq;
+ packet->pk_buffer[CF_FLAGS_BYTE_POS] = CF_RELIABLE | CF_RESEND;
+ packet->pk_length = CF_DATA_BYTE_POS;
+ return DevSW_Write(deviceToUse, packet, devid);
+}
+
+static AdpErrs check_seq(unsigned char msg_home, unsigned char msg_oppo) {
+ Packet *tmp_pkt;
+
+ UNUSED(msg_oppo);
+ /*
+ * check if we have got an ack for anything and if so remove it from the
+ * queue
+ */
+ if (msg_home == (unsigned char)(OppoSeq+1)) {
+ /*
+ * arrived in sequence can increment our opposing seq number and remove
+ * the relevant packet from our queue
+ * check that the packet we're going to remove really is the right one
+ */
+ tmp_pkt = writeQueueRoot;
+ while ((tmp_pkt->pk_next != NULL) &&
+ (tmp_pkt->pk_next->pk_buffer[CF_HOME_SEQ_BYTE_POS]
+ != OppoSeq)){
+ tmp_pkt = tmp_pkt->pk_next;
+ }
+ OppoSeq++;
+ if (tmp_pkt->pk_next == NULL) {
+#ifdef DEBUG
+ printf("trying to remove a non existant packet\n");
+#endif
+ return adp_bad_packet;
+ }
+ else {
+ Packet *tmp = tmp_pkt->pk_next;
+#ifdef RET_DEBUG
+ printf("removing a packet from the root queue\n");
+#endif
+ tmp_pkt->pk_next = tmp_pkt->pk_next->pk_next;
+ /* remove the appropriate packet */
+ DevSW_FreePacket(tmp);
+ return adp_ok;
+ }
+ }
+ else if (msg_home < (unsigned char) (OppoSeq+1)){
+ /* already received this message */
+#ifdef RET_DEBUG
+ printf("sequence numbers low\n");
+#endif
+ return adp_seq_low;
+ }
+ else { /* we've missed something */
+#ifdef RET_DEBUG
+ printf("sequence numbers high\n");
+#endif
+ return adp_seq_high;
+ }
+}
+
+static unsigned long tv_diff(const struct timeval *time_now,
+ const struct timeval *time_was)
+{
+ return ( ((time_now->tv_sec * 1000000) + time_now->tv_usec)
+ - ((time_was->tv_sec * 1000000) + time_was->tv_usec) );
+}
+
+#if !defined(__unix) && !defined(__CYGWIN32__)
+static void gettimeofday( struct timeval *time_now, void *dummy )
+{
+ time_t t = clock();
+ UNUSED(dummy);
+ time_now->tv_sec = t/CLOCKS_PER_SEC;
+ time_now->tv_usec = (t%CLOCKS_PER_SEC)*(1000000/CLOCKS_PER_SEC);
+}
+#endif
+
+static AdpErrs pacemaker(void)
+{
+ Packet *packet;
+
+ packet = DevSW_AllocatePacket(CF_DATA_BYTE_POS);
+ if (packet == NULL) {
+ printf("ERROR: could not allocate a packet in pacemaker()\n");
+ return adp_malloc_failure;
+ }
+ packet->pk_buffer[CF_CHANNEL_BYTE_POS] = CI_PRIVATE;
+ packet->pk_buffer[CF_HOME_SEQ_BYTE_POS] = HomeSeq;
+ packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS] = OppoSeq;
+ packet->pk_buffer[CF_FLAGS_BYTE_POS] = CF_RELIABLE | CF_HEARTBEAT;
+ packet->pk_length = CF_DATA_BYTE_POS;
+ return DevSW_Write(deviceToUse, packet, DC_DBUG);
+}
+
+#ifdef FAKE_BAD_LINE_RX
+static AdpErrs fake_bad_line_rx( const Packet *const packet, AdpErrs adp_err )
+{
+ static unsigned int bl_num = 0;
+
+ if ( (packet != NULL)
+ && (bl_num++ >= 20 )
+ && ((bl_num % FAKE_BAD_LINE_RX) == 0))
+ {
+ printf("DEBUG: faking a bad packet\n");
+ return adp_bad_packet;
+ }
+ return adp_err;
+}
+#endif /* def FAKE_BAD_LINE_RX */
+
+#ifdef FAKE_BAD_LINE_TX
+static unsigned char tmp_ch;
+
+static void fake_bad_line_tx( void )
+{
+ static unsigned int bl_num = 0;
+
+ /* give the thing a chance to boot then try corrupting stuff */
+ if ( (bl_num++ >= 20) && ((bl_num % FAKE_BAD_LINE_TX) == 0))
+ {
+ printf("DEBUG: faking a bad packet for tx\n");
+ tmp_ch = writeQueueSend->pk_buffer[CF_FLAGS_BYTE_POS];
+ writeQueueSend->pk_buffer[CF_FLAGS_BYTE_POS] = 77;
+ }
+}
+
+static void unfake_bad_line_tx( void )
+{
+ static unsigned int bl_num = 0;
+
+ /*
+ * must reset the packet so that its not corrupted when we
+ * resend it
+ */
+ if ( (bl_num >= 20) && ((bl_num % FAKE_BAD_LINE_TX) != 0))
+ {
+ writeQueueSend->pk_buffer[CF_FLAGS_BYTE_POS] = tmp_ch;
+ }
+}
+#endif /* def FAKE_BAD_LINE_TX */
+
+/*
+ * NOTE: we are assuming that a resolution of microseconds will
+ * be good enough for the purporses of the heartbeat. If this proves
+ * not to be the case then we may need a rethink, possibly using
+ * [get,set]itimer
+ */
+static struct timeval time_now;
+static struct timeval time_lastalive;
+
+static void async_process_dbug_read( const AsyncMode mode,
+ bool *const finished )
+{
+ Packet *packet;
+ unsigned int msg_home, msg_oppo;
+ AdpErrs adp_err;
+
+ adp_err = DevSW_Read(deviceToUse, DC_DBUG, &packet,
+ mode == async_block_on_read );
+
+#ifdef FAKE_BAD_LINE_RX
+ adp_err = fake_bad_line_rx( packet, adp_err );
+#endif
+
+ if (adp_err == adp_bad_packet) {
+ /* We got a bad packet, ask for a resend, send a resend message */
+#ifdef DEBUG
+ printf("received a bad packet\n");
+#endif
+ send_resend_msg(DC_DBUG);
+ }
+ else if (packet != NULL)
+ {
+ /* update the heartbeat clock */
+ gettimeofday(&time_lastalive, NULL);
+
+ /*
+ * we got a live one here - were we waiting for it?
+ */
+ if (mode == async_block_on_read)
+ /* not any more */
+ *finished = TRUE;
+#ifdef RETRANS
+
+ if (packet->pk_length < CF_DATA_BYTE_POS) {
+ /* we've got a packet with no header information! */
+ printf("ERROR: packet with no transport header\n");
+ send_resend_msg(DC_DBUG);
+ }
+ else {
+#ifdef RET_DEBUG
+ unsigned int c;
+#endif
+ /*
+ * TODO: Check to see if its acknowledgeing anything, remove
+ * those packets it is from the queue. If its a retrans add the
+ * packets to the queue
+ */
+ msg_home = packet->pk_buffer[CF_HOME_SEQ_BYTE_POS];
+ msg_oppo = packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS];
+#ifdef RET_DEBUG
+ printf("msg seq numbers are hseq 0x%x oseq 0x%x\n",
+ msg_home, msg_oppo);
+ for (c=0;c<packet->pk_length;c++)
+ printf("%02.2x", packet->pk_buffer[c]);
+ printf("\n");
+#endif
+ /* now was it a resend request? */
+ if ((packet->pk_buffer[CF_FLAGS_BYTE_POS])
+ & CF_RESEND) {
+ /* we've been asked for a resend so we had better resend */
+ /*
+ * I don't think we can use a resend as acknowledgement for
+ * anything so lets not do this for the moment
+ * check_seq(msg_home, msg_oppo);
+ */
+#ifdef RET_DEBUG
+ printf("received a resend request\n");
+#endif
+ if (HomeSeq != msg_oppo) {
+ int found = FALSE;
+ /* need to resend from msg_oppo +1 upwards */
+ DevSW_FreePacket(packet);
+ resending = TRUE;
+ /* find the correct packet to resend from */
+ packet = writeQueueRoot;
+ while (((packet->pk_next) != NULL) && !found) {
+ if ((packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS])
+ != msg_oppo+1) {
+ resend_pkt = packet;
+ found = TRUE;
+ }
+ packet = packet->pk_next;
+ }
+ if (!found) {
+ panic("trying to resend non-existent packets\n");
+ }
+ }
+ else if (OppoSeq != msg_home) {
+ /*
+ * send a resend request telling the target where we think
+ * the world is at
+ */
+ DevSW_FreePacket(packet);
+ send_resend_msg(DC_DBUG);
+ }
+ }
+ else {
+ /* not a resend request, lets check the sequence numbers */
+
+ if ((packet->pk_buffer[CF_CHANNEL_BYTE_POS] != CI_HBOOT) &&
+ (packet->pk_buffer[CF_CHANNEL_BYTE_POS] != CI_TBOOT)) {
+ adp_err = check_seq(msg_home, msg_oppo);
+ if (adp_err == adp_seq_low) {
+ /* we have already received this packet so discard */
+ DevSW_FreePacket(packet);
+ }
+ else if (adp_err == adp_seq_high) {
+ /*
+ * we must have missed a packet somewhere, discard this
+ * packet and tell the target where we are
+ */
+ DevSW_FreePacket(packet);
+ send_resend_msg(DC_DBUG);
+ }
+ else
+ /*
+ * now pass the packet to whoever is waiting for it
+ */
+ FireCallback(packet);
+ }
+ else
+ FireCallback(packet);
+ }
+ }
+#else
+ /*
+ * now pass the packet to whoever is waiting for it
+ */
+ FireCallback(packet);
+#endif
+ }
+}
+
+static void async_process_appl_read(void)
+{
+ Packet *packet;
+ AdpErrs adp_err;
+
+ /* see if there is anything for the DC_APPL channel */
+ adp_err = DevSW_Read(deviceToUse, DC_APPL, &packet, FALSE);
+
+ if (adp_err == adp_ok && packet != NULL)
+ {
+ /* got an application packet on a shared device */
+
+#ifdef DEBUG
+ printf("GOT DC_APPL PACKET: len %d\nData: ", packet->pk_length);
+ {
+ unsigned int c;
+ for ( c = 0; c < packet->pk_length; ++c )
+ printf( "%02X ", packet->pk_buffer[c] );
+ }
+ printf("\n");
+#endif
+
+ if (dc_appl_handler != NULL)
+ {
+ dc_appl_handler( deviceToUse, packet );
+ }
+ else
+ {
+ /* for now, just free it!! */
+#ifdef DEBUG
+ printf("no handler - dropping DC_APPL packet\n");
+#endif
+ DevSW_FreePacket( packet );
+ }
+ }
+}
+
+static void async_process_write( const AsyncMode mode,
+ bool *const finished )
+{
+ Packet *packet;
+
+#ifdef DEBUG
+ static unsigned int num_written = 0;
+#endif
+
+ /*
+ * NOTE: here we rely in the fact that any packet in the writeQueueSend
+ * section of the queue will need its sequence number setting up while
+ * and packet in the writeQueueRoot section will have its sequence
+ * numbers set up from when it was first sent so we can easily look
+ * up the packet numbers when(if) we want to resend the packet.
+ */
+
+#ifdef DEBUG
+ if (writeQueueSend!=NULL)
+ printf("written 0x%x\n",num_written += writeQueueSend->pk_length);
+#endif
+ /*
+ * give the switcher a chance to complete any partial writes
+ */
+ if (DevSW_FlushPendingWrite(deviceToUse) == adp_write_busy)
+ {
+ /* no point trying a new write */
+ return;
+ }
+
+ /*
+ * now see whether there is anything to write
+ */
+ packet = NULL;
+ if (resending) {
+ packet = resend_pkt;
+#ifdef RET_DEBUG
+ printf("resending hseq 0x%x oseq 0x%x\n",
+ packet->pk_buffer[CF_HOME_SEQ_BYTE_POS],
+ packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS]);
+#endif
+ }
+ else if (writeQueueSend != NULL) {
+#ifdef RETRANS
+ /* set up the sequence number on the packet */
+ packet = writeQueueSend;
+ HomeSeq++;
+ (writeQueueSend->pk_buffer[CF_OPPO_SEQ_BYTE_POS])
+ = OppoSeq;
+ (writeQueueSend->pk_buffer[CF_HOME_SEQ_BYTE_POS])
+ = HomeSeq;
+ (writeQueueSend->pk_buffer[CF_FLAGS_BYTE_POS])
+ = CF_RELIABLE;
+# ifdef RET_DEBUG
+ printf("sending packet with hseq 0x%x oseq 0x%x\n",
+ writeQueueSend->pk_buffer[CF_HOME_SEQ_BYTE_POS],
+ writeQueueSend->pk_buffer[CF_OPPO_SEQ_BYTE_POS]);
+# endif
+#endif /* RETRANS */
+ }
+
+ if (packet != NULL) {
+ AdpErrs dev_err;
+
+#ifdef FAKE_BAD_LINE_TX
+ fake_bad_line_tx();
+#endif
+
+ dev_err = DevSW_Write(deviceToUse, packet, DC_DBUG);
+ if (dev_err == adp_ok) {
+#ifdef RETRANS
+ if (resending) {
+ /* check to see if we've recovered yet */
+ if ((packet->pk_next) == NULL){
+# ifdef RET_DEBUG
+ printf("we have recovered\n");
+# endif
+ resending = FALSE;
+ }
+ else {
+ resend_pkt = resend_pkt->pk_next;
+ }
+ }
+ else {
+ /*
+ * move the packet we just sent from the send queue to the root
+ */
+ Packet *tmp_pkt, *tmp;
+
+# ifdef FAKE_BAD_LINE_TX
+ unfake_bad_line_tx();
+# endif
+
+ tmp_pkt = writeQueueSend;
+ writeQueueSend = writeQueueSend->pk_next;
+ tmp_pkt->pk_next = NULL;
+ if (writeQueueRoot == NULL)
+ writeQueueRoot = tmp_pkt;
+ else {
+ tmp = writeQueueRoot;
+ while (tmp->pk_next != NULL) {
+ tmp = tmp->pk_next;
+ }
+ tmp->pk_next = tmp_pkt;
+ }
+ }
+#else /* not RETRANS */
+ /*
+ * switcher has taken the write, so remove it from the
+ * queue, and free its resources
+ */
+ DevSW_FreePacket(Adp_removeFromQueue(&writeQueueSend));
+#endif /* if RETRANS ... else ... */
+
+ if (mode == async_block_on_write)
+ *finished = DevSW_WriteFinished(deviceToUse);
+
+ } /* endif write ok */
+ }
+ else /* packet == NULL */
+ {
+ if (mode == async_block_on_write)
+ *finished = DevSW_WriteFinished(deviceToUse);
+ }
+}
+
+static void async_process_heartbeat( void )
+{
+ /* check to see whether we need to send a heartbeat */
+ gettimeofday(&time_now, NULL);
+
+ if (tv_diff(&time_now, &time_lastalive) >= HEARTRATE)
+ {
+ /*
+ * if we've not booted then don't do send a heartrate the link
+ * must be reliable enough for us to boot without any clever stuff,
+ * if we can't do this then theres little chance of the link staying
+ * together even with the resends etc
+ */
+ if (heartbeat_enabled) {
+ gettimeofday(&time_lastalive, NULL);
+ pacemaker();
+ }
+ }
+}
+
+static void async_process_callbacks( void )
+{
+ /* call any registered asynchronous callbacks */
+ unsigned int i;
+ for ( i = 0; i < num_async_callbacks; ++i )
+ async_callbacks[i]( deviceToUse, &time_now );
+}
+
+void Adp_AsynchronousProcessing(const AsyncMode mode)
+{
+ bool finished = FALSE;
+#ifdef DEBUG
+ unsigned int wc = 0, dc = 0, ac = 0, hc = 0;
+# define INC_COUNT(x) ((x)++)
+#else
+# define INC_COUNT(x)
+#endif
+
+ if ((time_lastalive.tv_sec == 0) && (time_lastalive.tv_usec == 0)) {
+ /* first time through, needs initing */
+ gettimeofday(&time_lastalive, NULL);
+ }
+
+ /* main loop */
+ do
+ {
+ async_process_write( mode, &finished );
+ INC_COUNT(wc);
+
+ if ( ! finished && mode != async_block_on_write )
+ {
+ async_process_dbug_read( mode, &finished );
+ INC_COUNT(dc);
+ }
+
+ if ( ! finished && mode != async_block_on_write )
+ {
+ async_process_appl_read();
+ INC_COUNT(ac);
+ }
+
+ if ( ! finished )
+ {
+ if (heartbeat_configured)
+ async_process_heartbeat();
+ async_process_callbacks();
+ INC_COUNT(hc);
+ }
+
+ } while (!finished && mode != async_block_on_nothing);
+
+#ifdef DEBUG
+ if ( mode != async_block_on_nothing )
+ printf( "Async: %s - w %d, d %d, a %d, h %d\n",
+ mode == async_block_on_write ? "blk_write" : "blk_read",
+ wc, dc, ac, hc );
+#endif
+}
+
+/*
+ * install a handler for DC_APPL packets (can be NULL), returning old one.
+ */
+DC_Appl_Handler Adp_Install_DC_Appl_Handler(const DC_Appl_Handler handler)
+{
+ DC_Appl_Handler old_handler = dc_appl_handler;
+
+#ifdef DEBUG
+ printf( "Installing DC_APPL handler %x (old %x)\n", handler, old_handler );
+#endif
+
+ dc_appl_handler = handler;
+ return old_handler;
+}
+
+
+/*
+ * add an asynchronous processing callback to the list
+ * TRUE == okay, FALSE == no more async processing slots
+ */
+bool Adp_Install_Async_Callback( const Adp_Async_Callback callback_proc )
+{
+ if ( num_async_callbacks < MAX_ASYNC_CALLBACKS && callback_proc != NULL )
+ {
+ async_callbacks[num_async_callbacks] = callback_proc;
+ ++num_async_callbacks;
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+
+/*
+ * delay for a given period (in microseconds)
+ */
+void Adp_delay(unsigned int period)
+{
+ struct timeval tv;
+
+#ifdef DEBUG
+ printf("delaying for %d microseconds\n", period);
+#endif
+ tv.tv_sec = (period / 1000000);
+ tv.tv_usec = (period % 1000000);
+
+ (void)select(0, NULL, NULL, NULL, &tv);
+}
+
+/* EOF hostchan.c */