📄 hostchan.c
字号:
/* * 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.8 $ * $Date: 1999/11/01 15:32:59 $ * * * 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 8static 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 defined(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;}void Adp_SetLogEnable(int logEnableFlag){ DevSW_SetLogEnable(logEnableFlag);}void Adp_SetLogfile(const char *filename){ DevSW_SetLogfile(filename);}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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -