/** * 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); } }
/** * 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); } }