Exemplo n.º 1
0
/**
 * rpmsg_rx_callback
 *
 * Rx callback function.
 *
 * @param vq - pointer to virtqueue on which messages is received
 *
 */
void rpmsg_rx_callback(struct virtqueue *vq) {
    struct remote_device *rdev;
    struct virtio_device *vdev;
    struct rpmsg_channel *rp_chnl;
    struct rpmsg_endpoint *rp_ept;
    struct rpmsg_hdr *rp_hdr;
    struct llist *node;
    unsigned long len;
    unsigned short idx;
    struct llist *chnl_hd;

    vdev = (struct virtio_device *) vq->vq_dev;
    rdev = (struct remote_device *) vdev;

    chnl_hd = rdev->rp_channels;
    if ((chnl_hd != RPMSG_NULL) && (rdev->role == RPMSG_MASTER)) {
        rp_chnl = (struct rpmsg_channel *) chnl_hd->data;
        if (rp_chnl->state == RPMSG_CHNL_STATE_IDLE) {
            if (rdev->support_ns) {
                rp_chnl->state = RPMSG_CHNL_STATE_NS;
                rpmsg_send_ns_message(rdev, rp_chnl, RPMSG_NS_CREATE);
            } else {
                rp_chnl->state = RPMSG_CHNL_STATE_ACTIVE;
            }
            return;
        }
    }

    env_lock_mutex(rdev->lock);

    /* Process the received data from remote node */
    rp_hdr = (struct rpmsg_hdr *) rpmsg_get_rx_buffer(rdev, &len, &idx);

    env_unlock_mutex(rdev->lock);

    while(rp_hdr) {

        /* Get the channel node from the remote device channels list. */
        node = rpmsg_rdev_get_endpoint_from_addr(rdev, rp_hdr->dst);

        if (!node)
            /* Fatal error no endpoint for the given dst addr. */
            return;

        rp_ept = (struct rpmsg_endpoint *) node->data;

        rp_chnl = rp_ept->rp_chnl;

        if ((rp_chnl) && (rp_chnl->state == RPMSG_CHNL_STATE_NS)) {
            /* First message from RPMSG Master, update channel
             * destination address and state */
            rp_chnl->dst = rp_hdr->src;
            rp_chnl->state = RPMSG_CHNL_STATE_ACTIVE;

            /* Notify channel creation to application */
            if (rdev->channel_created) {
                rdev->channel_created(rp_chnl);
            }
        } else {
            rp_ept->cb(rp_chnl, rp_hdr->data, rp_hdr->len, rp_ept->priv,
                       rp_hdr->src);
        }

        env_lock_mutex(rdev->lock);

        /* Return used buffers. */
        rpmsg_return_buffer(rdev, rp_hdr, len, idx);

        rp_hdr = (struct rpmsg_hdr *) rpmsg_get_rx_buffer(rdev, &len, &idx);
        env_unlock_mutex(rdev->lock);
    }
}
Exemplo n.º 2
0
/**
 * rpmsg_rx_callback
 *
 * Rx callback function.
 *
 * @param vq - pointer to virtqueue on which messages is received
 *
 */
void rpmsg_rx_callback(struct virtqueue *vq) {
    struct remote_device *rdev;
    struct virtio_device *vdev;
    struct rpmsg_channel *rp_chnl;
    struct rpmsg_endpoint *rp_ept;
    struct rpmsg_hdr *rp_hdr;
    struct llist *node;
    unsigned long len;
    unsigned short idx;
    struct llist *chnl_hd;

    vdev = (struct virtio_device *) vq->vq_dev;
    rdev = (struct remote_device *) vdev;

    chnl_hd = rdev->rp_channels;
    if ((chnl_hd != RPMSG_NULL) && (rdev->role == RPMSG_MASTER)) {
        rp_chnl = (struct rpmsg_channel *) chnl_hd->data;
        if (rp_chnl->state == RPMSG_CHNL_STATE_IDLE) {
            if (rdev->support_ns) {
                rp_chnl->state = RPMSG_CHNL_STATE_NS;
                rpmsg_send_ns_message(rdev, rp_chnl, RPMSG_NS_CREATE);
            } else {
                rp_chnl->state = RPMSG_CHNL_STATE_ACTIVE;
            }
            return;
        }
    }

    env_lock_mutex(rdev->lock);

    /* Process the received data from remote node */
    rp_hdr = (struct rpmsg_hdr *) rpmsg_get_rx_buffer(rdev, &len, &idx);

    env_unlock_mutex(rdev->lock);

     while(rp_hdr) {
        /* Clear 'rp_hdr->reserved' field that is used as 'callback' output */
        rp_hdr->reserved = 0;
       
        /* Get the channel node from the remote device channels list. */
        node = rpmsg_rdev_get_endpoint_from_addr(rdev, rp_hdr->dst);

        if (!node)
            /* Fatal error no endpoint for the given dst addr. */
            return;

        rp_ept = (struct rpmsg_endpoint *) node->data;

        rp_chnl = rp_ept->rp_chnl;

        if ((rp_chnl) && (rp_chnl->state == RPMSG_CHNL_STATE_NS)) {
            /* First message from RPMSG Master, update channel
             * destination address and state */
            /*
             * Only for Remote
             */
            rp_chnl->dst = rp_hdr->src;
            rp_chnl->state = RPMSG_CHNL_STATE_ACTIVE;

            /* Notify channel creation to application */
            if (rdev->channel_created) {
                rdev->channel_created(rp_chnl);
            }
        } else if(len <= 0xFFFF) {
            if (!(rp_hdr->flags & RPMSG_DROP_HDR_FLAG))
            {
                rp_ept->cb(rp_chnl, rp_hdr->data, rp_hdr->len,
                    rp_ept->priv, rp_hdr->src);
            }
        } else {
            /* Any message with totlen > 65535 are dropped, no way to notify the user about it */
        }

        env_lock_mutex(rdev->lock);
        /* Check whether callback wants to hold buffer */
        if (rp_hdr->reserved & RPMSG_BUF_HELD)
        {
            /* 'rp_hdr->reserved' field is now used as storage for
             * 'idx' and 'len' to release buffer later */
            ((struct rpmsg_hdr_reserved*)&rp_hdr->reserved)->idx = idx;
            ((struct rpmsg_hdr_reserved*)&rp_hdr->reserved)->totlen = len;
        }
        else
        {
            /* Return used buffers. */
            rpmsg_return_buffer(rdev, rp_hdr, len, idx);
        }
        rp_hdr = (struct rpmsg_hdr *) rpmsg_get_rx_buffer(rdev, &len, &idx);
        env_unlock_mutex(rdev->lock);
    }
}