Esempio n. 1
0
/*************************************************************************
 *
 *   FUNCTION
 *
 *       _open
 *
 *   DESCRIPTION
 *
 *       Open a file.  Minimal implementation
 *
 *************************************************************************/
int _open(const char * filename, int flags, int mode) {
	int filename_len = strlen(filename) + 1;
	int payload_size = sizeof(struct _sys_rpc) + filename_len;
	int retval = -1;

	if ((!filename) || (filename_len > FILE_NAME_LEN)) {
		return -1;
	}

	/* Construct rpc payload */
	rpc_data->rpc->id = OPEN_SYSCALL_ID;
	rpc_data->rpc->sys_call_args.int_field1 = flags;
	rpc_data->rpc->sys_call_args.int_field2 = mode;
	rpc_data->rpc->sys_call_args.data_len = filename_len;
	memcpy(&rpc_data->rpc->sys_call_args.data, filename, filename_len);

	/* Transmit rpc request */
	env_lock_mutex(rpc_data->rpc_lock);
	send_rpc((void*) rpc_data->rpc, payload_size);
	env_unlock_mutex(rpc_data->rpc_lock);

	/* Wait for response from proxy on master */
	env_acquire_sync_lock(rpc_data->sync_lock);

	/* Obtain return args and return to caller */
	if (rpc_data->rpc_response->id == OPEN_SYSCALL_ID) {
		retval = rpc_data->rpc_response->sys_call_args.int_field1;
	}

	return retval;
}
Esempio n. 2
0
/*************************************************************************
 *
 *   FUNCTION
 *
 *       _write
 *
 *   DESCRIPTION
 *
 *       Low level function to redirect IO to serial.
 *
 *************************************************************************/
int _write(int fd, const char * ptr, int len) {
	int retval = -1;
	int payload_size = sizeof(struct _sys_rpc) + len;
	int null_term = 0;

	if (fd == 1) {
		null_term = 1;
	}

	rpc_data->rpc->id = WRITE_SYSCALL_ID;
	rpc_data->rpc->sys_call_args.int_field1 = fd;
	rpc_data->rpc->sys_call_args.int_field2 = len;
	rpc_data->rpc->sys_call_args.data_len = len + null_term;
	memcpy(rpc_data->rpc->sys_call_args.data, ptr, len);
	if (null_term) {
		*(char*) (rpc_data->rpc->sys_call_args.data + len + null_term) = 0;
	}

	env_lock_mutex(rpc_data->rpc_lock);
	send_rpc((void*) rpc_data->rpc, payload_size);
	env_unlock_mutex(rpc_data->rpc_lock);

	env_acquire_sync_lock(rpc_data->sync_lock);

	if (rpc_data->rpc_response->id == WRITE_SYSCALL_ID) {
		retval = rpc_data->rpc_response->sys_call_args.int_field1;
	}

	return retval;

}
Esempio n. 3
0
/**
 * _rpmsg_create_channel
 *
 * Creates new rpmsg channel with the given parameters.
 *
 * @param rdev - pointer to remote device which contains the channel
 * @param name - name of the device
 * @param src  - source address for the rpmsg channel
 * @param dst  - destination address for the rpmsg channel
 *
 * @return - pointer to new rpmsg channel
 *
 */
struct rpmsg_channel *_rpmsg_create_channel(struct remote_device *rdev,
        char *name, unsigned long src, unsigned long dst) {
    struct rpmsg_channel *rp_chnl;
    struct llist *node;

    rp_chnl = env_allocate_memory(sizeof(struct rpmsg_channel));
    if (rp_chnl) {
        env_memset(rp_chnl, 0x00, sizeof(struct rpmsg_channel));
        env_strncpy(rp_chnl->name, name, sizeof(rp_chnl->name));
        rp_chnl->src = src;
        rp_chnl->dst = dst;
        rp_chnl->rdev = rdev;
        /* Place channel on channels list */
        node = env_allocate_memory(sizeof(struct llist));
        if (!node) {
            env_free_memory(rp_chnl);
            return RPMSG_NULL ;
        }
        node->data = rp_chnl;
        env_lock_mutex(rdev->lock);
        add_to_list(&rdev->rp_channels , node);
        env_unlock_mutex(rdev->lock);
    }

    return rp_chnl;
}
Esempio n. 4
0
/*************************************************************************
 *
 *   FUNCTION
 *
 *       _read
 *
 *   DESCRIPTION
 *
 *       Low level function to redirect IO to serial.
 *
 *************************************************************************/
int _read(int fd, char * buffer, int buflen) {
	int payload_size = sizeof(struct _sys_rpc);
	int retval = -1;

	if (!buffer || !buflen)
		return retval;

	/* Construct rpc payload */
	rpc_data->rpc->id = READ_SYSCALL_ID;
	rpc_data->rpc->sys_call_args.int_field1 = fd;
	rpc_data->rpc->sys_call_args.int_field2 = buflen;
	rpc_data->rpc->sys_call_args.data_len = 0; /*not used*/

	/* Transmit rpc request */
	env_lock_mutex(rpc_data->rpc_lock);
	get_response=0;
	send_rpc((void*) rpc_data->rpc, payload_size);
	env_unlock_mutex(rpc_data->rpc_lock);

	/* Wait for response from proxy on master */
	env_acquire_sync_lock(rpc_data->sync_lock);

	/* Obtain return args and return to caller */
	if (rpc_data->rpc_response->id == READ_SYSCALL_ID) {
		if (rpc_data->rpc_response->sys_call_args.int_field1 > 0) {
			memcpy(buffer, rpc_data->rpc_response->sys_call_args.data,
					rpc_data->rpc_response->sys_call_args.data_len);
		}

	    retval = rpc_data->rpc_response->sys_call_args.int_field1;
	}

	return retval;
}
Esempio n. 5
0
/**
 * rpmsg_send_ns_message
 *
 * Sends name service announcement to remote device
 *
 * @param rdev    - pointer to remote device
 * @param rp_chnl - pointer to rpmsg channel
 * @param flags   - Channel creation/deletion flags
 *
 */
void rpmsg_send_ns_message(struct remote_device *rdev,
                           struct rpmsg_channel *rp_chnl, unsigned long flags) {

    struct rpmsg_hdr *rp_hdr;
    struct rpmsg_ns_msg *ns_msg;
    unsigned short idx;
    int len;

    env_lock_mutex(rdev->lock);

    /* Get Tx buffer. */
    rp_hdr = (struct rpmsg_hdr *) rpmsg_get_tx_buffer(rdev, &len, &idx);
    if (!rp_hdr)
        return;

    /* Fill out name service data. */
    rp_hdr->dst = RPMSG_NS_EPT_ADDR;
    rp_hdr->len = sizeof(struct rpmsg_ns_msg);
    ns_msg = (struct rpmsg_ns_msg *) rp_hdr->data;
    env_strncpy(ns_msg->name, rp_chnl->name, sizeof(rp_chnl->name));
    ns_msg->flags = flags;
    ns_msg->addr = rp_chnl->src;

    /* Place the buffer on virtqueue. */
    rpmsg_enqueue_buffer(rdev, rp_hdr, len, idx);

    /* Notify the other side that it has data to process. */
    virtqueue_kick(rdev->tvq);

    env_unlock_mutex(rdev->lock);
}
Esempio n. 6
0
/**
 * _create_endpoint
 *
 * This function creates rpmsg endpoint.
 *
 * @param rdev    - pointer to remote device
 * @param cb      - Rx completion call back
 * @param priv    - private data
 * @param addr    - endpoint src address
 *
 * @return - pointer to endpoint control block
 *
 */
struct rpmsg_endpoint *_create_endpoint(struct remote_device *rdev,
                rpmsg_rx_cb_t cb, void *priv, unsigned long addr) {

    struct rpmsg_endpoint *rp_ept;
    struct llist *node;
    int status = RPMSG_SUCCESS;

    rp_ept = env_allocate_memory(sizeof(struct rpmsg_endpoint));
    if (!rp_ept) {
        return RPMSG_NULL ;
    }
    env_memset(rp_ept, 0x00, sizeof(struct rpmsg_endpoint));

    node = env_allocate_memory(sizeof(struct llist));
    if (!node) {
        env_free_memory(rp_ept);
        return RPMSG_NULL;
    }

    env_lock_mutex(rdev->lock);

    if (addr != RPMSG_ADDR_ANY) {
        /*
         * Application has requested a particular src address for endpoint,
         * first check if address is available.
         */
        if (!rpmsg_is_address_set(rdev->bitmap, RPMSG_ADDR_BMP_SIZE, addr)) {
            /* Mark the address as used in the address bitmap. */
            rpmsg_set_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE, addr);

        } else {
            status = RPMSG_ERR_DEV_ADDR;
        }
    } else {
        addr = rpmsg_get_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE);
        if (addr < 0) {
            status = RPMSG_ERR_DEV_ADDR;
        }
    }

    /* Do cleanup in case of error and return */
    if (status) {
        env_free_memory(node);
        env_free_memory(rp_ept);
        env_unlock_mutex(rdev->lock);
        return RPMSG_NULL;
    }

    rp_ept->addr = addr;
    rp_ept->cb = cb;
    rp_ept->priv = priv;

    node->data = rp_ept;
    add_to_list(&rdev->rp_endpoints, node);

    env_unlock_mutex(rdev->lock);

    return rp_ept;
}
Esempio n. 7
0
/**
 * rpmsg_destroy_ept
 *
 * This function deletes rpmsg endpoint and performs cleanup.
 *
 * @param rdev   - pointer to remote device
 * @param rp_ept - pointer to endpoint to destroy
 *
 */
void _destroy_endpoint(struct remote_device *rdev,
                       struct rpmsg_endpoint *rp_ept) {
    struct llist *node;
    node = rpmsg_rdev_get_endpoint_from_addr(rdev, rp_ept->addr);
    if (node) {
        env_lock_mutex(rdev->lock);
        rpmsg_release_address(rdev->bitmap, RPMSG_ADDR_BMP_SIZE, rp_ept->addr);
        remove_from_list(&rdev->rp_endpoints, node);
        env_unlock_mutex(rdev->lock);
        env_free_memory(node);
    }
    env_free_memory(rp_ept);
}
Esempio n. 8
0
/**
 * _rpmsg_delete_channel
 *
 * Deletes given rpmsg channel.
 *
 * @param rp_chnl -  pointer to rpmsg channel to delete
 *
 * return - none
 */
void _rpmsg_delete_channel(struct rpmsg_channel * rp_chnl) {
    struct llist *node;
    if (rp_chnl) {
        node = rpmsg_rdev_get_chnl_node_from_id(rp_chnl->rdev, rp_chnl->name);
        if (node) {
            env_lock_mutex(rp_chnl->rdev->lock);
            remove_from_list(&rp_chnl->rdev->rp_channels, node);
            env_unlock_mutex(rp_chnl->rdev->lock);
            env_free_memory(node);
        }
        env_free_memory(rp_chnl);
    }
}
Esempio n. 9
0
/**
 * rpmsg_rdev_get_endpoint_from_addr
 *
 * This function returns endpoint node based on src address.
 *
 * @param rdev - pointer remote device control block
 * @param addr - src address
 *
 * @return - endpoint node
 *
 */
struct llist *rpmsg_rdev_get_endpoint_from_addr(struct remote_device *rdev,
						unsigned long addr)
{
	struct llist *rp_ept_lut_head;

	rp_ept_lut_head = rdev->rp_endpoints;

	env_lock_mutex(rdev->lock);
	while (rp_ept_lut_head) {
		struct rpmsg_endpoint *rp_ept =
		    (struct rpmsg_endpoint *)rp_ept_lut_head->data;
		if (rp_ept->addr == addr) {
			env_unlock_mutex(rdev->lock);
			return rp_ept_lut_head;
		}
		rp_ept_lut_head = rp_ept_lut_head->next;
	}
	env_unlock_mutex(rdev->lock);

	return RPMSG_NULL;
}
Esempio n. 10
0
/**
 * rpmsg_rdev_get_chnl_from_addr
 *
 * This function returns channel node based on src/dst address.
 *
 * @param rdev - pointer remote device control block
 * @param addr - src/dst address
 *
 * @return - channel node
 *
 */
struct llist *rpmsg_rdev_get_chnl_from_addr(struct remote_device *rdev,
					    unsigned long addr)
{
	struct rpmsg_channel *rp_chnl;
	struct llist *rp_chnl_head;

	rp_chnl_head = rdev->rp_channels;

	env_lock_mutex(rdev->lock);
	while (rp_chnl_head) {
		rp_chnl = (struct rpmsg_channel *)rp_chnl_head->data;
		if ((rp_chnl->src == addr) || (rp_chnl->dst == addr)) {
			env_unlock_mutex(rdev->lock);
			return rp_chnl_head;
		}
		rp_chnl_head = rp_chnl_head->next;
	}
	env_unlock_mutex(rdev->lock);

	return RPMSG_NULL;
}
Esempio n. 11
0
/*************************************************************************
 *
 *   FUNCTION
 *
 *       _close
 *
 *   DESCRIPTION
 *
 *       Close a file.  Minimal implementation
 *
 *************************************************************************/
int _close(int fd) {
	int payload_size = sizeof(struct _sys_rpc);
	int retval = -1;

	rpc_data->rpc->id = CLOSE_SYSCALL_ID;
	rpc_data->rpc->sys_call_args.int_field1 = fd;
	rpc_data->rpc->sys_call_args.int_field2 = 0; /*not used*/
	rpc_data->rpc->sys_call_args.data_len = 0; /*not used*/

	env_lock_mutex(rpc_data->rpc_lock);
	send_rpc((void*) rpc_data->rpc, payload_size);
	env_unlock_mutex(rpc_data->rpc_lock);

	/* Wait for response from proxy on master */
	env_acquire_sync_lock(rpc_data->sync_lock);

	if (rpc_data->rpc_response->id == CLOSE_SYSCALL_ID) {
		retval = rpc_data->rpc_response->sys_call_args.int_field1;
	}

	return retval;
}
Esempio n. 12
0
/**
 * rpmsg_rdev_get_chnl_node_from_id
 *
 * This function returns channel node based on channel name.
 *
 * @param stack      - pointer to remote device
 * @param rp_chnl_id - rpmsg channel name
 *
 * @return - channel node
 *
 */
struct llist *rpmsg_rdev_get_chnl_node_from_id(struct remote_device *rdev,
					       char *rp_chnl_id)
{
	struct rpmsg_channel *rp_chnl;
	struct llist *rp_chnl_head;

	rp_chnl_head = rdev->rp_channels;

	env_lock_mutex(rdev->lock);
	while (rp_chnl_head) {
		rp_chnl = (struct rpmsg_channel *)rp_chnl_head->data;
		if (env_strncmp
		    (rp_chnl->name, rp_chnl_id, sizeof(rp_chnl->name))
		    == 0) {
			env_unlock_mutex(rdev->lock);
			return rp_chnl_head;
		}
		rp_chnl_head = rp_chnl_head->next;
	}
	env_unlock_mutex(rdev->lock);

	return RPMSG_NULL;
}
Esempio n. 13
0
/**
 * rpmsg_get_buffer_size
 *
 * Returns buffer size available for sending messages.
 *
 * @param channel - pointer to rpmsg channel
 *
 * @return - buffer size
 *
 */
int rpmsg_get_buffer_size(struct rpmsg_channel *rp_chnl) {
    struct remote_device *rdev;
    int length;

    if (!rp_chnl) {
        return RPMSG_ERR_PARAM;
    }

    /* Get associated remote device for channel. */
    rdev = rp_chnl->rdev;

    /* Validate device state */
    if (rp_chnl->state != RPMSG_CHNL_STATE_ACTIVE
                    || rdev->state != RPMSG_DEV_STATE_ACTIVE) {
        return RPMSG_ERR_DEV_STATE;
    }

    env_lock_mutex(rdev->lock);

    if (rdev->role == RPMSG_REMOTE) {
        /*
         * If device role is Remote then buffers are provided by us
         * (RPMSG Master), so just provide the macro.
         */
        length = RPMSG_BUFFER_SIZE - sizeof(struct rpmsg_hdr);
    } else {
        /*
         * If other core is Master then buffers are provided by it,
         * so get the buffer size from the virtqueue.
         */
        length = (int) virtqueue_get_desc_size(rdev->tvq) - sizeof(struct rpmsg_hdr);
    }

    env_unlock_mutex(rdev->lock);

    return length;
}
Esempio n. 14
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);
    }
}
Esempio n. 15
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);
    }
}
Esempio n. 16
0
int rpmsg_send_offchannel_raw(struct rpmsg_channel *rp_chnl, unsigned long src,
                unsigned long dst, char *data, int size, int wait) {
    struct remote_device *rdev;
    struct rpmsg_hdr *rp_hdr;
    void *buffer;
    int status = RPMSG_SUCCESS;
    unsigned short idx;
    int tick_count = 0;
    int buff_len;

    if (!rp_chnl) {
        return RPMSG_ERR_PARAM;
    }

    /* Get the associated remote device for channel. */
    rdev = rp_chnl->rdev;

    /* Validate device state */
    if (rp_chnl->state != RPMSG_CHNL_STATE_ACTIVE
                    || rdev->state != RPMSG_DEV_STATE_ACTIVE) {
        return RPMSG_ERR_DEV_STATE;
    }

    /* Lock the device to enable exclusive access to virtqueues */
    env_lock_mutex(rdev->lock);
    /* Get rpmsg buffer for sending message. */
    buffer = rpmsg_get_tx_buffer(rdev, &buff_len, &idx);
    if (!buffer && !wait) {
        status = RPMSG_ERR_NO_MEM;
    }
    env_unlock_mutex(rdev->lock);

    if (status == RPMSG_SUCCESS) {

        while (!buffer) {
            /*
             * Wait parameter is true - pool the buffer for
             * 15 secs as defined by the APIs.
             */
            env_sleep_msec(RPMSG_TICKS_PER_INTERVAL);
            env_lock_mutex(rdev->lock);
            buffer = rpmsg_get_tx_buffer(rdev, &buff_len, &idx);
            env_unlock_mutex(rdev->lock);
            tick_count += RPMSG_TICKS_PER_INTERVAL;
            if (tick_count >= (RPMSG_TICK_COUNT / RPMSG_TICKS_PER_INTERVAL)) {
                status = RPMSG_ERR_NO_BUFF;
                break;
            }
        }

        if (status == RPMSG_SUCCESS) {
            //FIXME : may be just copy the data size equal to buffer length and Tx it.
            if (size > (buff_len - sizeof(struct rpmsg_hdr)))
                status = RPMSG_ERR_BUFF_SIZE;

            if (status == RPMSG_SUCCESS) {
                rp_hdr = (struct rpmsg_hdr *) buffer;

                /* Initialize RPMSG header. */
                rp_hdr->dst = dst;
                rp_hdr->src = src;
                rp_hdr->len = size;

                /* Copy data to rpmsg buffer. */
                env_memcpy(rp_hdr->data, data, size);

                env_lock_mutex(rdev->lock);
                /* Enqueue buffer on virtqueue. */
                status = rpmsg_enqueue_buffer(rdev, buffer, buff_len, idx);
                if (status == RPMSG_SUCCESS) {
                    /* Let the other side know that there is a job to process. */
                    virtqueue_kick(rdev->tvq);
                }
                env_unlock_mutex(rdev->lock);
            }

        }
    }

    /* Do cleanup in case of error.*/
    if (status != RPMSG_SUCCESS) {
        rpmsg_free_buffer(rdev, buffer);
    }

    return status;
}