⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 channels.c

📁 ARM入门的好帮手.包含了从简单到相对较复杂的程序.
💻 C
📖 第 1 页 / 共 5 页
字号:
/* -*-C-*- * * $Revision: 1.13.2.11 $ *   $Author: rivimey $ *     $Date: 1998/03/11 10:38:37 $ * * Copyright (c) 1996 Advanced RISC Machines Limited. * All Rights Reserved. * *   Project: ANGEL * *     Title: Implementation of channels layer */#include <stdlib.h>             /* for NULL macro */#include "channels.h"#include "chandefs.h"#include "chanpriv.h"#include "devclnt.h"#include "devconf.h"#include "logging.h"#include "serlock.h"#include "adp.h"#include "adperr.h"#include "endian.h"#include "msgbuild.h"/* General purpose constants, macros, enums, typedefs *//* * The number of packets which can be outstanding at once -- normally * called the window size. In this case, though, the window size is * in a sense 1 as each channel is stop-and-wait. However, theoretically * all channels could have sent a packet and none received an ack, so * the number of outstanding packets possible is the number of configured * channels. */#define MAX_UNACKED   CI_NUM_CHANNELS/********************************************************************** *                      T Y P E    D E F I N I T I O N S **********************************************************************/enum ChanPrivateErrors{    CE_BLOCKING = CE_PRIVATE,   /* used for blocking reads and sends */    CE_UNBLOCK_BASE,    CE_UNBLOCK_OKAY = CE_UNBLOCK_BASE + CE_OKAY};/* state per channel */struct ChanState{    ChanRx_CB_Fn reader;               /* the read callback, or NULL */    void        *read_cb_data;         /* the read callback data */    p_Buffer     read_buffer;          /* for blocking reads */    unsigned int read_len;             /* for blocking reads */    bool         read_blocking;        /* for blocking reads */    ChanTx_CB_Fn writer;               /* the write callback, or NULL */    void        *write_cb_data;        /* the write callback data */    bool         write_blocking;       /* for blocking sends */    p_Buffer     write_buff;           /* buffer being written */};/* state per device *//* * ackExpected and currentFrame form the lower and upper edges of the sender's * window. * * frameExpected is the lower and upper edges of the receiver's * window. */struct DevState{    SequenceNR currentFrame;      /* seq number of last frame sent */    SequenceNR ackExpected;       /* seq number of successfully-received frame */    SequenceNR frameExpected;     /* seq number of last received frame from host */    SequenceNR lastReceived;      /* distinguish heartbeat(8) from data(8) */        /*     * The following is used to implement a list of buffers which have yet to     * be acknowledged.     */    struct _unacked    {        p_Buffer        buf;    /* the list of un-acked packets */        unsigned short  len;    /* the length of data in this packet */        int             packno; /* packet sequence number for this packet */        short           next;   /* next buffer in this list, LISTEND => none */    } unackedBufs[MAX_UNACKED];    short firstFree;            /* first free buffer, LISTEND => none */    short lastUsed;             /* last (most recently pushed) buffer, LISTEND => none */    short firstUsed;            /* first (oldest) buffer, LISTEND => none */};#define LISTEND  (-1)extern int booted_flow_controlled;/********************************************************************** *                      M O D U L E   D A T A **********************************************************************//* Publically-accessible globals *//* do we acknowledge heartbeats; TRUE by default. */unsigned Angel_AckedHeartbeats = 1;/* the default size of a channel buffer, for global use */unsigned Angel_ChanBuffSize = 0;/* the size of a long buffer, for global use */unsigned Angel_ChanLongSize = 0;/* Private globals *//* the state of each channel */static volatile struct ChanState chan_state[CI_NUM_CHANNELS];/* the state of each device */static struct DevState dev_state[DI_NUM_DEVICES];/* the active device */static DeviceID active_device = DE_DEFAULT_ACTIVE;/* the reader-of-all-devices */static ChannelID read_all_channel;static ChanRx_CB_Fn read_all_callback = NULL;static void *read_all_cb_data = NULL;/********************************************************************** *          P R O T O T Y P E   D E C L A R A T I O N S **********************************************************************//* forward declarations */static p_Buffer angel_ChannelAllocDevBuffer(unsigned req_size, void *cb_data);static AdpErrs resend_packet_from(DeviceID devid, SequenceNR packet_no);static void angel_ChannelQuerySizes(unsigned *default_size, unsigned *max_size);/********************************************************************** *              I N T E R N A L   F U N C T I O N S **********************************************************************//* *  Function: adp_between *   Purpose: To return TRUE if a <= b < c circularly. * *    Params:  *       Input: none * *   Returns: TRUE/FALSE */static intadp_between(SequenceNR a, SequenceNR b, SequenceNR c){    return (((a <= b) && (b < c)) || ((c < a) && (a <= b)) || ((b < c) && (c < a)));}/* *  Function: angel_InitResendList *   Purpose: To initialise the resend list - link all elements onto *            the free list, and setting the used list to empty * *    Params:  *       Input: dev - the device to initialise. * *   Returns: none */static voidangel_InitResendList(register struct DevState *dev){    register int i;        dev->firstFree = 0;    dev->firstUsed = LISTEND;    dev->lastUsed = LISTEND;        for(i = 0; i < MAX_UNACKED; i++)    {        dev->unackedBufs[i].buf = NULL;        dev->unackedBufs[i].len = 0;        dev->unackedBufs[i].packno = 0;        dev->unackedBufs[i].next = i + 1;    }    dev->unackedBufs[i - 1].next = LISTEND;        return;}/* *  Function: Angel_InitChannels *   Purpose: To Initialise the sequence numbers, and resend list. *            This should be called only when the state of memory *            is unknown (i.e. the data structures are random). * *    Params:  *       Input: none * *   Returns: adp_ok */AdpErrsAngel_InitChannels(void){    int j;    LogInfo(LOG_CHANNEL, ( "Angel_InitChannels: resetting...\n"));    Angel_EnterCriticalSection();    for (j = 0; j < DI_NUM_DEVICES; j++)    {        register struct DevState *dev = &dev_state[j];        dev->currentFrame = 0;        dev->ackExpected = 0;        dev->lastReceived = 0;        dev->frameExpected = 1;                angel_InitResendList(dev);    }    Angel_LeaveCriticalSection();        LogInfo(LOG_CHANNEL, ( "Angel_InitChannels: reset channels.\n"));    return adp_ok;}/* *  Function: Angel_ReinitChannels *   Purpose: To re initialise the device; very similar to the *            initialise, but assumes the device state is "sensible", *            freeing any buffers allocated on the resend list. * *    Params:  *       Input: none * *   Returns: adp_ok */AdpErrsAngel_ReinitChannels(void){    int i, j;        LogInfo(LOG_CHANNEL, ( "Angel_ReinitChannels: resetting...\n"));    Angel_EnterCriticalSection();    for (j = 0; j < DI_NUM_DEVICES; j++)    {        register struct DevState *dev = &dev_state[j];        dev->currentFrame = 0;        dev->ackExpected = 0;        dev->lastReceived = 0;        dev->frameExpected = 1;        /* free all packets on the used list */        i = dev->firstUsed;        while ( i != LISTEND )        {            if (dev->unackedBufs[i].buf)            {                Angel_BufferRelease(dev->unackedBufs[i].buf);            }                        i = dev->unackedBufs[i].next;        }        /* then reinitialise the free list. */        angel_InitResendList(dev);    }    Angel_LeaveCriticalSection();        LogInfo(LOG_CHANNEL, ( "Angel_ReinitChannels: reset channels.\n"));        return adp_ok;}/* *  Function: adp_get_unack_bufno *   Purpose: To search the resend list for a given packet and return the buffer *            number in which it is located. Additionally, return the previous *            buffer number, if any, for the purposes of list pointer changes. * *    Params:  *       Input: devid    - the device ID of the driver  *              pkt_no   - the packet number required *              startbuf - the initial buffer index (use to select btw. free *                         and used buffer lists) * *      Output: prev     - if non-null, a pointer to a value holding the previous *                         buffer, whose next pointer points at the wanted one, or *                         LISTEND signifying this was the first buffer. * *   Returns: OK:    the buffer index of the required buffer *            Error: LISTEND if packet number not found */static int adp_get_unack_bufno(DeviceID devid, SequenceNR pkt_no,                               short startbuf, short *prev){    register struct DevState *dev = &dev_state[devid];    register short i, j = LISTEND;    for (i = startbuf; i != LISTEND; i = dev->unackedBufs[i].next)    {        if (dev->unackedBufs[i].packno == pkt_no)        {            if (prev != NULL)                *prev = j;            return i;        }        j = i;    }    return LISTEND;}/* *  Function: Angel_show_unacked_list *   Purpose: To display the used and free resend lists for a given device. * *    Params:  *       Input: devid - the device ID of the driver  * *   Returns: none */#if DEBUG == 1static void Angel_show_unacked_list(DeviceID devid){    register struct DevState *dev = &dev_state[devid];    register int i;    LogInfo(LOG_CHANNEL, ("Resend list for Device %d\n", devid));    for (i = dev->firstUsed; i != LISTEND; i = dev->unackedBufs[i].next)    {        LogInfo(LOG_CHANNEL, ("    Buffer %d: Packet %d unacked (@%x, len %d)\n", i,                              dev->unackedBufs[i].packno, dev->unackedBufs[i].buf,                              dev->unackedBufs[i].len));    }}#else#define Angel_show_unacked_list(d)#endif/* *  Function: adp_add_pkt *   Purpose: To add the given packet to the resend list. * *    Params:  *       Input: devid - the device ID of the driver  *              pkt_no - the packet number required *              buffer - the buffer pointer for this packet *              len - the length of this packet in bytes * *   Returns: adp_ok */static AdpErrs adp_add_pkt(DeviceID devid, SequenceNR pkt_no, p_Buffer buffer, int len){    int b; /* the list reference number of the packet to add */    register struct DevState *dev = &dev_state[devid];    Angel_EnterCriticalSection();        if (dev->firstFree != LISTEND)    {        /* remove this buffer from the free list */        b = dev->firstFree;        dev->firstFree = dev->unackedBufs[b].next;        /* set it up... */        dev->unackedBufs[b].buf = buffer;        dev->unackedBufs[b].len = len;        dev->unackedBufs[b].packno = pkt_no;        /* now add it onto the unacked buffer list. firstUsed is the head -- set         * this if the list was initially empty. lastUsed is the tail; set this         * to the current buffer after modifying the old 'next' pointer.         */        dev->unackedBufs[b].next = LISTEND;        if (dev->lastUsed != LISTEND)            dev->unackedBufs[dev->lastUsed].next = b;        else            dev->firstUsed = b;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -