📄 channels.c
字号:
/* adjust the pointer back to where it ought to be */ if (buffer != NULL) { buffer -= CB_CHAN_DATA_BYTE_POS; } /* pass it on to the buffer module */ Angel_BufferRelease(buffer);}/* * Function: angel_ChannelAllocDevBuffer * Purpose: allocate a buffer that is at least req_size bytes long, * alligned for use by the device driver. This routine is * used to allocate buffers when receiving new packets. * * Params: * Input: req_size the minimum size required * cb_data ignored * Output: - * In/Out: - * * Returns: pointer to allocated buffer, or * NULL if unable to allocate suitable buffer * * Reads globals: - * Modifies globals: - * * Other side effects: MUST ONLY be used by device drivers */static p_Buffer angel_ChannelAllocDevBuffer(unsigned req_size, void *cb_data){ p_Buffer ret_buffer; IGNORE(cb_data); /* commented out as the buffer code also has v. similar info calls: */ LogInfo(LOG_CHANNEL, ("angel_ChannelAllocDevBuffer: req_size %d\n", req_size)); /* make sure we get space for our overheads */ req_size += CB_CHAN_HEADER_BYTE_POS; /* * There must be at least 2 packets left here -- one we will allocate, and * one which Angel can use to send a reply back (assuming that the in-buffer * isn't freed before the out-buffer is allocated, which is common). */ if (Angel_BuffersLeft() < 2) { LogWarning(LOG_CHANNEL, ("angel_ChannelAllocDevBuffer: Not enough buffers left!\n")); return NULL; } ret_buffer = Angel_BufferAlloc(req_size); /* * Note this call can still fail, despite the check earlier! */ if (ret_buffer != NULL) { /* null the link pointer */ *CB_LINK(ret_buffer) = NULL; /* shift the returned value to the overall data area */ ret_buffer += CB_CHAN_HEADER_BYTE_POS; } /* LogInfo(LOG_CHANNEL, "angel_ChannelAllocDevBuffer: buffer 0x%x\n", ret_buffer); */ return ret_buffer;}/* * Function: write_unblock_callback * Purpose: used to signal that a blocking write has completed, and that the * write code can continue, returning to the caller. * * Params: * Input: chanid the channel on which the write occurred. * callback_data pointer to the status return (a ChanError) * * Returns: none. * * Reads globals: (via pointer) write_error * Modifies globals: - * * Other side effects: MUST ONLY be used by device drivers */static void write_unblock_callback(ChannelID chanid, void *callback_data){ ChanError *write_error = (ChanError *) callback_data; ASSERT(chanid < CI_NUM_CHANNELS, ("Channel ID %d invalid in callback\n", chanid)); ASSERT(chan_state[chanid].write_blocking == TRUE, ("Write not blocked in blocking callback!\n")); ASSERT(write_error != NULL, ("Nowhere to write error code in callback\n")); *write_error = CE_OKAY; chan_state[chanid].write_blocking = FALSE; LogInfo(LOG_CHANNEL, ( "write_unblock_callback: channel %d\n", chanid));}/* * Function: angel_ChannelSend * Purpose: blocking send of a packet via a channel * * see channels.h for full description */ChanError angel_ChannelSend(DeviceID devid, ChannelID chanid, const p_Buffer data_pkt, unsigned data_len){ ChanError chan_error; ChanError send_error = CE_PRIVATE; ASSERT(chanid < CI_NUM_CHANNELS, ("Bad channel ID %d\n", chanid)); LogInfo(LOG_CHANNEL, ( "ChannelSend: send buffer 0x%x, len %d\n", data_pkt, data_len)); /* Check that a write is not already in progress */ Angel_EnterCriticalSection(); if (chan_state[chanid].write_blocking) { Angel_LeaveCriticalSection(); LogWarning(LOG_CHANNEL, ("ChannelSend: already busy on chan %d\n", chanid)); angel_ChannelReleaseBuffer(data_pkt); return CE_BUSY; } chan_state[chanid].write_blocking = TRUE; Angel_LeaveCriticalSection(); /* Start an async write */ chan_error = angel_ChannelSendAsync(devid, chanid, data_pkt, data_len, write_unblock_callback, (void *)&send_error); if (chan_error != CE_OKAY) { chan_state[chanid].write_blocking = FALSE; return chan_error; } /* now wait for the write to complete */ while (chan_state[chanid].write_blocking) { TRACE("csb"); Angel_Yield(); } if (send_error) LogWarning(LOG_CHANNEL, ( "ChannelSend: error code %d\n", send_error)); else LogInfo(LOG_CHANNEL, ( "ChannelSend: packet 0x%x sent\n", data_pkt)); return send_error;}/* * Function: write_callback * Purpose: used to clean up after a non-blocking write has completed. The channel * state must be freed up and the buffer used to hold the packet freed up. * * Params: * Input: v_chan_pkt pointer to the packet's data buffer * v_chan_len the length of the buffer * v_status the send status -- was the write completed * v_cb_data callback data: in this case, the channel id * * Returns: none. * * Reads globals: * Modifies globals: * * Other side effects: */static void write_callback(void *v_chan_pkt, void *v_chan_len, void *v_status, void *cb_data){ DevStatus status = (DevStatus) (int)v_status; p_Buffer buffer = (p_Buffer) v_chan_pkt; ChannelID chanid; IGNORE(v_chan_len); LogInfo(LOG_CHANNEL, ("write_callback: packet %p, len %d, status %d, channel %d\n", v_chan_pkt, (int)v_chan_len, status, (ChannelID) cb_data)); if (status == DS_DONE) { /* channel id is in callback data */ chanid = (ChannelID) cb_data; ASSERT(chanid < CI_NUM_CHANNELS, ("Bad channel ID %d\n", chanid)); if (chan_state[chanid].writer != NULL) /* could have been aborted */ { /* do the callback */ chan_state[chanid].writer(chanid, chan_state[chanid].write_cb_data); chan_state[chanid].writer = NULL; chan_state[chanid].write_buff = NULL; } } else { /* * don't know which channel was being written, so must look it up in the channel * state, then free it up */ LogWarning(LOG_CHANNEL, ( "write_callback: device write error %d\n", status)); for(chanid = 0; chanid < CI_NUM_CHANNELS; chanid++) { if (chan_state[chanid].write_buff == buffer) { LogWarning(LOG_CHANNEL, ( "write_callback: releasing device for chan %d\n", chanid)); chan_state[chanid].writer = NULL; chan_state[chanid].write_buff = NULL; chan_state[chanid].write_blocking = FALSE; } } }}/* * Function: angel_ChannelSendAsync * Purpose: asynchronous send of a packet via a channel * * see channels.h for full description */ChanError angel_ChannelSendAsync(DeviceID devid, ChannelID chanid, const p_Buffer data_pkt, unsigned len, ChanTx_CB_Fn callback, void *callback_data){ DevError dev_error; p_Buffer buffer; /* adjust the device id, if required */ if (devid == CH_DEFAULT_DEV) { devid = active_device; } ASSERT(devid < DI_NUM_DEVICES, ("Bad device ID %d\n", devid)); ASSERT(chanid < CI_NUM_CHANNELS, ("Bad channel ID %d\n", chanid)); ASSERT(data_pkt != NULL, ("No data buffer\n")); ASSERT(callback != NULL, ("No callback function\n")); /* we can only service one request per channel in this version */ /* adjust buffer back to start, length to include header */ buffer = data_pkt - CB_CHAN_DATA_BYTE_POS; /* includes link ptr */ len += CF_DATA_BYTE_POS; /* excludes link ptr - just header */ Angel_EnterCriticalSection(); /* start critical region */ if (chan_state[chanid].writer != NULL) { Angel_LeaveCriticalSection(); LogWarning(LOG_CHANNEL, ( "ChannelSendAsync: already busy on chan %d\n", chanid)); angel_ChannelReleaseBuffer(data_pkt); return CE_BUSY; } INC(dev_state[devid].currentFrame); /* record what we need to know later */ chan_state[chanid].writer = callback; chan_state[chanid].write_cb_data = callback_data; chan_state[chanid].write_buff = buffer; Angel_LeaveCriticalSection(); /* end critical region */ buffer[CB_PACKET(CF_CHANNEL_BYTE_POS)] = chanid; buffer[CB_PACKET(CF_PACKET_SEQ_BYTE_POS)] = dev_state[devid].currentFrame; buffer[CB_PACKET(CF_ACK_SEQ_BYTE_POS)] = lastSEQ(dev_state[devid].frameExpected); buffer[CB_PACKET(CF_FLAGS_BYTE_POS)] = CF_RELIABLE; LogInfo(LOG_CHANNEL, ("ChannelSendAsync: packet packetseq %d ackseq %d\n", buffer[CB_PACKET(CF_PACKET_SEQ_BYTE_POS)], buffer[CB_PACKET(CF_ACK_SEQ_BYTE_POS)])); /* store the buffer in the unacked list */ adp_add_pkt(devid, dev_state[devid].currentFrame, buffer, len); do { /* attempt to queue transmission */ /* we use the channel id as callback data - simplifies write_callback */ dev_error = angel_DeviceWrite(devid, buffer + CB_CHAN_HEADER_BYTE_POS, len, write_callback, (void *)chanid, DC_DBUG); if (dev_error == DE_BUSY) { Angel_Yield(); } } while (dev_error == DE_BUSY); if (dev_error == DE_OKAY) return CE_OKAY; else return CE_DEV_ERROR;}static AdpErrs resend_packet_from(DeviceID devid, SequenceNR startpacket){ DevError chan_err = DE_OKAY; ChannelID chanid; short len; ChanError send_error = CE_PRIVATE; p_Buffer buf; register struct DevState *dev = &dev_state[devid]; register short i, j = LISTEND; SequenceNR thispacket = startpacket; Angel_EnterCriticalSection(); while (chan_err == DE_OKAY && adp_between(startpacket, thispacket, nextSEQ(dev->currentFrame))) { /* search for the requested packet in the resend list */ for (i = dev->firstUsed; i != LISTEND; i = dev->unackedBufs[i].next) { if (thispacket == dev->unackedBufs[i].packno) break; } if (i == LISTEND) { LogError(LOG_CHANNEL, ("resend_packet: packet %d not available (from %d, max %d)\n", thispacket, startpacket, dev->currentFrame)); break; } /* get the buffer details */ buf = dev_state[devid].unackedBufs[i].buf; len = dev_state[devid].unackedBufs[i].len; chanid = (ChannelID) * buf; Angel_LeaveCriticalSection(); /* * set the current frameExpected, not the value when this frame was * originally sent */ buf[CB_PACKET(CF_ACK_SEQ_BYTE_POS)] = lastSEQ(dev_state[devid].frameExpected); LogWarning(LOG_CHANNEL, ( "resend_packet: writing pkt 0x%x seq %d, chan %d, len %d\n", buf, thispacket, chanid, len)); Angel_EnterCriticalSection(); /* start critical region */ /* Check that a write is not already in progress; if so, wait... */ /* now wait for the write to complete */ while (chan_state[chanid].write_blocking && chan_state[chanid].writer != NULL) { Angel_Yield(); } chan_state[chanid].write_blocking = TRUE; chan_state[chanid].write_buff = buf; chan_state[chanid].writer = write_unblock_callback; chan_state[chanid].write_cb_data = (void *)&send_error; Angel_LeaveCriticalSection(); /* end critical region */ LogInfo(LOG_CHANNEL, ( "resend msg: writing...\n")); do { chan_err = angel_DeviceWrite(devid, buf + CB_CHAN_HEADER_BYTE_POS, len, write_callback, (void *)chanid, DC_DBUG); if (chan_err == DE_BUSY); { Angel_Yield();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -