Merge "ARM: dts: msm: add audio ion vm dev on msm8996 vplatform"

This commit is contained in:
Linux Build Service Account 2017-10-21 02:30:25 -07:00 committed by Gerrit - the friendly Code Review server
commit 164f8dcb96
8 changed files with 2011 additions and 2 deletions

View file

@ -1096,6 +1096,26 @@ qcom,msm-audio-ion {
qcom,smmu-enabled;
};
* msm-audio-ion-vm
Required properties:
- compatible : "qcom,msm-audio-ion-vm"
Optional properties:
- qcom,smmu-enabled:
It is possible that some MSM have SMMU in ADSP. While other
MSM use no SMMU. Audio lib introduce wrapper for ION APIs.
The wrapper needs presence of SMMU in ADSP to handle ION
APIs differently. Presence of this property means ADSP has
SMMU in it.
Example:
qcom,msm-audio-ion-vm {
compatible = "qcom,msm-audio-ion-vm;
qcom,smmu-enabled;
};
* MSM8994 ASoC Machine driver
Required properties:

View file

@ -184,6 +184,11 @@
iommus = <&lpass_q6_smmu 1>;
};
qcom,msm-audio-ion-vm {
compatible = "qcom,msm-audio-ion-vm";
qcom,smmu-enabled;
};
pcm0: qcom,msm-pcm {
compatible = "qcom,msm-pcm-dsp";
qcom,msm-pcm-dsp-id = <0>;

View file

@ -616,6 +616,15 @@ config MSM_QDSP6_APRV2
used by audio driver to configure QDSP6's
ASM, ADM and AFE.
config MSM_QDSP6_APRV2_VM
bool "Audio QDSP6 APRv2 virtualization support"
depends on MSM_HAB
help
Enable APRv2 IPC protocol support over
HAB between application processor and
QDSP6. APR is used by audio driver to
configure QDSP6's ASM, ADM and AFE.
config MSM_QDSP6_APRV3
bool "Audio QDSP6 APRv3 support"
depends on MSM_SMD
@ -800,7 +809,8 @@ config MSM_EVENT_TIMER
config MSM_AVTIMER
tristate "Avtimer Driver"
depends on MSM_QDSP6_APRV2 || MSM_QDSP6_APRV3 || MSM_QDSP6_APRV2_GLINK
depends on MSM_QDSP6_APRV2 || MSM_QDSP6_APRV3 || MSM_QDSP6_APRV2_GLINK || \
MSM_QDSP6_APRV2_VM
help
This driver gets the Q6 out of power collapsed state and
exposes ioctl control to read avtimer tick.

View file

@ -2,7 +2,9 @@ obj-$(CONFIG_MSM_QDSP6_APRV2) += apr.o apr_v2.o apr_tal.o voice_svc.o
obj-$(CONFIG_MSM_QDSP6_APRV3) += apr.o apr_v3.o apr_tal.o voice_svc.o
obj-$(CONFIG_MSM_QDSP6_APRV2_GLINK) += apr.o apr_v2.o apr_tal_glink.o voice_svc.o
obj-$(CONFIG_MSM_QDSP6_APRV3_GLINK) += apr.o apr_v3.o apr_tal_glink.o voice_svc.o
obj-$(CONFIG_MSM_QDSP6_APRV2_VM) += apr_vm.o apr_v2.o voice_svc.o
obj-$(CONFIG_SND_SOC_MSM_QDSP6V2_INTF) += msm_audio_ion.o
obj-$(CONFIG_SND_SOC_QDSP6V2_VM) += msm_audio_ion_vm.o
obj-$(CONFIG_MSM_ADSP_LOADER) += adsp-loader.o
obj-$(CONFIG_MSM_QDSP6_SSR) += audio_ssr.o
obj-$(CONFIG_MSM_QDSP6_PDR) += audio_pdr.o

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,582 @@
/*
* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/err.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
#include <linux/msm_audio_ion.h>
#include "../../../staging/android/ion/ion_priv.h"
#include "../../../staging/android/ion/ion_hvenv_driver.h"
#define MSM_AUDIO_ION_PROBED (1 << 0)
struct msm_audio_ion_private {
bool smmu_enabled;
bool audioheap_enabled;
u8 device_status;
};
static struct msm_audio_ion_private msm_audio_ion_data = {0,};
static int msm_audio_ion_get_phys(struct ion_client *client,
struct ion_handle *handle,
ion_phys_addr_t *addr, size_t *len);
int msm_audio_ion_alloc(const char *name, struct ion_client **client,
struct ion_handle **handle, size_t bufsz,
ion_phys_addr_t *paddr, size_t *pa_len, void **vaddr)
{
int rc = -EINVAL;
unsigned long err_ion_ptr = 0;
if ((msm_audio_ion_data.smmu_enabled == true) &&
!(msm_audio_ion_data.device_status & MSM_AUDIO_ION_PROBED)) {
pr_debug("%s:probe is not done, deferred\n", __func__);
return -EPROBE_DEFER;
}
if (!name || !client || !handle || !paddr || !vaddr
|| !bufsz || !pa_len) {
pr_err("%s: Invalid params\n", __func__);
return -EINVAL;
}
*client = msm_audio_ion_client_create(name);
if (IS_ERR_OR_NULL((void *)(*client))) {
pr_err("%s: ION create client for AUDIO failed\n", __func__);
goto err;
}
*handle = ion_alloc(*client, bufsz, SZ_4K,
ION_HEAP(ION_AUDIO_HEAP_ID), 0);
if (IS_ERR_OR_NULL((void *) (*handle))) {
if (msm_audio_ion_data.smmu_enabled == true) {
pr_debug("system heap is used");
msm_audio_ion_data.audioheap_enabled = 0;
*handle = ion_alloc(*client, bufsz, SZ_4K,
ION_HEAP(ION_SYSTEM_HEAP_ID), 0);
}
if (IS_ERR_OR_NULL((void *) (*handle))) {
if (IS_ERR((void *)(*handle)))
err_ion_ptr = PTR_ERR((int *)(*handle));
pr_err("%s:ION alloc fail err ptr=%ld, smmu_enabled=%d\n",
__func__, err_ion_ptr, msm_audio_ion_data.smmu_enabled);
rc = -ENOMEM;
goto err_ion_client;
}
} else {
pr_debug("audio heap is used");
msm_audio_ion_data.audioheap_enabled = 1;
}
rc = msm_audio_ion_get_phys(*client, *handle, paddr, pa_len);
if (rc) {
pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n",
__func__, rc);
goto err_ion_handle;
}
*vaddr = ion_map_kernel(*client, *handle);
if (IS_ERR_OR_NULL((void *)*vaddr)) {
pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
goto err_ion_handle;
}
pr_debug("%s: mapped address = %pK, size=%zd\n", __func__,
*vaddr, bufsz);
if (bufsz != 0) {
pr_debug("%s: memset to 0 %pK %zd\n", __func__, *vaddr, bufsz);
memset((void *)*vaddr, 0, bufsz);
}
return rc;
err_ion_handle:
ion_free(*client, *handle);
err_ion_client:
msm_audio_ion_client_destroy(*client);
*handle = NULL;
*client = NULL;
err:
return rc;
}
EXPORT_SYMBOL(msm_audio_ion_alloc);
int msm_audio_ion_phys_free(struct ion_client *client,
struct ion_handle *handle,
ion_phys_addr_t *paddr,
size_t *pa_len, u8 assign_type)
{
if (!(msm_audio_ion_data.device_status & MSM_AUDIO_ION_PROBED)) {
pr_debug("%s:probe is not done, deferred\n", __func__);
return -EPROBE_DEFER;
}
if (!client || !handle || !paddr || !pa_len) {
pr_err("%s: Invalid params\n", __func__);
return -EINVAL;
}
/* hyp assign is not supported in VM */
ion_free(client, handle);
ion_client_destroy(client);
return 0;
}
int msm_audio_ion_phys_assign(const char *name, struct ion_client **client,
struct ion_handle **handle, int fd,
ion_phys_addr_t *paddr,
size_t *pa_len, u8 assign_type)
{
int ret;
if (!(msm_audio_ion_data.device_status & MSM_AUDIO_ION_PROBED)) {
pr_debug("%s:probe is not done, deferred\n", __func__);
return -EPROBE_DEFER;
}
if (!name || !client || !handle || !paddr || !pa_len) {
pr_err("%s: Invalid params\n", __func__);
return -EINVAL;
}
*client = msm_audio_ion_client_create(name);
if (IS_ERR_OR_NULL((void *)(*client))) {
pr_err("%s: ION create client failed\n", __func__);
return -EINVAL;
}
*handle = ion_import_dma_buf(*client, fd);
if (IS_ERR_OR_NULL((void *) (*handle))) {
pr_err("%s: ion import dma buffer failed\n",
__func__);
ret = -EINVAL;
goto err_destroy_client;
}
ret = ion_phys(*client, *handle, paddr, pa_len);
if (ret) {
pr_err("%s: could not get physical address for handle, ret = %d\n",
__func__, ret);
goto err_ion_handle;
}
/* hyp assign is not supported in VM */
return ret;
err_ion_handle:
ion_free(*client, *handle);
err_destroy_client:
ion_client_destroy(*client);
*client = NULL;
*handle = NULL;
return ret;
}
int msm_audio_ion_import(const char *name, struct ion_client **client,
struct ion_handle **handle, int fd,
unsigned long *ionflag, size_t bufsz,
ion_phys_addr_t *paddr, size_t *pa_len, void **vaddr)
{
int rc = 0;
if ((msm_audio_ion_data.smmu_enabled == true) &&
!(msm_audio_ion_data.device_status & MSM_AUDIO_ION_PROBED)) {
pr_debug("%s:probe is not done, deferred\n", __func__);
return -EPROBE_DEFER;
}
if (!name || !client || !handle || !paddr || !vaddr || !pa_len) {
pr_err("%s: Invalid params\n", __func__);
rc = -EINVAL;
goto err;
}
*client = msm_audio_ion_client_create(name);
if (IS_ERR_OR_NULL((void *)(*client))) {
pr_err("%s: ION create client for AUDIO failed\n", __func__);
rc = -EINVAL;
goto err;
}
/* name should be audio_acdb_client or Audio_Dec_Client,
* bufsz should be 0 and fd shouldn't be 0 as of now
*/
*handle = ion_import_dma_buf(*client, fd);
pr_debug("%s: DMA Buf name=%s, fd=%d handle=%pK\n", __func__,
name, fd, *handle);
if (IS_ERR_OR_NULL((void *) (*handle))) {
pr_err("%s: ion import dma buffer failed\n",
__func__);
rc = -EINVAL;
goto err_destroy_client;
}
if (ionflag != NULL) {
rc = ion_handle_get_flags(*client, *handle, ionflag);
if (rc) {
pr_err("%s: could not get flags for the handle\n",
__func__);
goto err_ion_handle;
}
}
rc = msm_audio_ion_get_phys(*client, *handle, paddr, pa_len);
if (rc) {
pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n",
__func__, rc);
goto err_ion_handle;
}
*vaddr = ion_map_kernel(*client, *handle);
if (IS_ERR_OR_NULL((void *)*vaddr)) {
pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
rc = -ENOMEM;
goto err_ion_handle;
}
pr_debug("%s: mapped address = %pK, size=%zd\n", __func__,
*vaddr, bufsz);
return 0;
err_ion_handle:
ion_free(*client, *handle);
err_destroy_client:
msm_audio_ion_client_destroy(*client);
*client = NULL;
*handle = NULL;
err:
return rc;
}
int msm_audio_ion_free(struct ion_client *client, struct ion_handle *handle)
{
if (!client || !handle) {
pr_err("%s Invalid params\n", __func__);
return -EINVAL;
}
ion_unmap_kernel(client, handle);
ion_free(client, handle);
msm_audio_ion_client_destroy(client);
return 0;
}
EXPORT_SYMBOL(msm_audio_ion_free);
int msm_audio_ion_mmap(struct audio_buffer *ab,
struct vm_area_struct *vma)
{
struct sg_table *table;
unsigned long addr = vma->vm_start;
unsigned long offset = vma->vm_pgoff * PAGE_SIZE;
struct scatterlist *sg;
unsigned int i;
struct page *page;
int ret;
pr_debug("%s\n", __func__);
table = ion_sg_table(ab->client, ab->handle);
if (IS_ERR(table)) {
pr_err("%s: Unable to get sg_table from ion: %ld\n",
__func__, PTR_ERR(table));
return PTR_ERR(table);
} else if (!table) {
pr_err("%s: sg_list is NULL\n", __func__);
return -EINVAL;
}
/* uncached */
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
/* We need to check if a page is associated with this sg list because:
* If the allocation came from a carveout we currently don't have
* pages associated with carved out memory. This might change in the
* future and we can remove this check and the else statement.
*/
page = sg_page(table->sgl);
if (page) {
pr_debug("%s: page is NOT null\n", __func__);
for_each_sg(table->sgl, sg, table->nents, i) {
unsigned long remainder = vma->vm_end - addr;
unsigned long len = sg->length;
page = sg_page(sg);
if (offset >= len) {
offset -= len;
continue;
} else if (offset) {
page += offset / PAGE_SIZE;
len -= offset;
offset = 0;
}
len = min(len, remainder);
pr_debug("vma=%pK, addr=%x len=%ld vm_start=%x vm_end=%x vm_page_prot=%ld\n",
vma, (unsigned int)addr, len,
(unsigned int)vma->vm_start,
(unsigned int)vma->vm_end,
(unsigned long int)vma->vm_page_prot);
remap_pfn_range(vma, addr, page_to_pfn(page), len,
vma->vm_page_prot);
addr += len;
if (addr >= vma->vm_end)
return 0;
}
} else {
ion_phys_addr_t phys_addr;
size_t phys_len;
size_t va_len = 0;
pr_debug("%s: page is NULL\n", __func__);
ret = ion_phys(ab->client, ab->handle, &phys_addr, &phys_len);
if (ret) {
pr_err("%s: Unable to get phys address from ION buffer: %d\n",
__func__, ret);
return ret;
}
pr_debug("phys=%pK len=%zd\n", &phys_addr, phys_len);
pr_debug("vma=%pK, vm_start=%x vm_end=%x vm_pgoff=%ld vm_page_prot=%ld\n",
vma, (unsigned int)vma->vm_start,
(unsigned int)vma->vm_end, vma->vm_pgoff,
(unsigned long int)vma->vm_page_prot);
va_len = vma->vm_end - vma->vm_start;
if ((offset > phys_len) || (va_len > phys_len-offset)) {
pr_err("wrong offset size %ld, lens= %zd, va_len=%zd\n",
offset, phys_len, va_len);
return -EINVAL;
}
ret = remap_pfn_range(vma, vma->vm_start,
__phys_to_pfn(phys_addr) + vma->vm_pgoff,
vma->vm_end - vma->vm_start,
vma->vm_page_prot);
}
return 0;
}
bool msm_audio_ion_is_smmu_available(void)
{
return msm_audio_ion_data.smmu_enabled;
}
/* move to static section again */
struct ion_client *msm_audio_ion_client_create(const char *name)
{
struct ion_client *pclient = NULL;
pclient = hvenv_ion_client_create(name);
return pclient;
}
void msm_audio_ion_client_destroy(struct ion_client *client)
{
pr_debug("%s: client = %pK smmu_enabled = %d\n", __func__,
client, msm_audio_ion_data.smmu_enabled);
ion_client_destroy(client);
}
int msm_audio_ion_import_legacy(const char *name, struct ion_client *client,
struct ion_handle **handle, int fd,
unsigned long *ionflag, size_t bufsz,
ion_phys_addr_t *paddr, size_t *pa_len, void **vaddr)
{
int rc = 0;
if (!name || !client || !handle || !paddr || !vaddr || !pa_len) {
pr_err("%s: Invalid params\n", __func__);
rc = -EINVAL;
goto err;
}
/* client is already created for legacy and given*/
/* name should be audio_acdb_client or Audio_Dec_Client,
* bufsz should be 0 and fd shouldn't be 0 as of now
*/
*handle = ion_import_dma_buf(client, fd);
pr_debug("%s: DMA Buf name=%s, fd=%d handle=%pK\n", __func__,
name, fd, *handle);
if (IS_ERR_OR_NULL((void *)(*handle))) {
pr_err("%s: ion import dma buffer failed\n",
__func__);
rc = -EINVAL;
goto err;
}
if (ionflag != NULL) {
rc = ion_handle_get_flags(client, *handle, ionflag);
if (rc) {
pr_err("%s: could not get flags for the handle\n",
__func__);
rc = -EINVAL;
goto err_ion_handle;
}
}
rc = msm_audio_ion_get_phys(client, *handle, paddr, pa_len);
if (rc) {
pr_err("%s: ION Get Physical for AUDIO failed, rc = %d\n",
__func__, rc);
rc = -EINVAL;
goto err_ion_handle;
}
/*Need to add condition SMMU enable or not */
*vaddr = ion_map_kernel(client, *handle);
if (IS_ERR_OR_NULL((void *)*vaddr)) {
pr_err("%s: ION memory mapping for AUDIO failed\n", __func__);
rc = -EINVAL;
goto err_ion_handle;
}
if (bufsz != 0)
memset((void *)*vaddr, 0, bufsz);
return 0;
err_ion_handle:
ion_free(client, *handle);
err:
return rc;
}
int msm_audio_ion_free_legacy(struct ion_client *client,
struct ion_handle *handle)
{
ion_unmap_kernel(client, handle);
ion_free(client, handle);
/* no client_destrody in legacy*/
return 0;
}
static int msm_audio_ion_get_phys(struct ion_client *client,
struct ion_handle *handle,
ion_phys_addr_t *addr, size_t *len)
{
int rc = 0;
pr_debug("%s: smmu_enabled = %d\n", __func__,
msm_audio_ion_data.smmu_enabled);
if (msm_audio_ion_data.smmu_enabled) {
rc = ion_phys(client, handle, addr, len);
if (rc) {
pr_err("%s: ion_phys failed, err = %d\n",
__func__, rc);
goto err;
}
/* Append the SMMU SID information to the IOVA address */
*addr |= (1 << 32);
} else {
rc = ion_phys(client, handle, addr, len);
}
pr_debug("%s: phys=%pK, len=%zd, rc=%d\n",
__func__, &(*addr), *len, rc);
err:
return rc;
}
static const struct of_device_id msm_audio_ion_dt_match[] = {
{ .compatible = "qcom,msm-audio-ion-vm" },
{ }
};
MODULE_DEVICE_TABLE(of, msm_audio_ion_dt_match);
u32 msm_audio_ion_get_smmu_sid_mode32(void)
{
if (msm_audio_ion_data.smmu_enabled)
return 1;
else
return 0;
}
u32 msm_audio_populate_upper_32_bits(ion_phys_addr_t pa)
{
if (sizeof(ion_phys_addr_t) == sizeof(u32))
return msm_audio_ion_get_smmu_sid_mode32();
else
return upper_32_bits(pa);
}
static int msm_audio_ion_probe(struct platform_device *pdev)
{
int rc = 0;
const char *msm_audio_ion_dt = "qcom,smmu-enabled";
bool smmu_enabled;
struct device *dev = &pdev->dev;
if (dev->of_node == NULL) {
pr_err("%s: device tree is not found\n",
__func__);
msm_audio_ion_data.smmu_enabled = 0;
return 0;
}
smmu_enabled = of_property_read_bool(dev->of_node,
msm_audio_ion_dt);
msm_audio_ion_data.smmu_enabled = smmu_enabled;
pr_info("%s: SMMU is %s\n", __func__,
(smmu_enabled) ? "Enabled" : "Disabled");
if (!rc)
msm_audio_ion_data.device_status |= MSM_AUDIO_ION_PROBED;
return rc;
}
static int msm_audio_ion_remove(struct platform_device *pdev)
{
msm_audio_ion_data.smmu_enabled = 0;
msm_audio_ion_data.device_status = 0;
return 0;
}
static struct platform_driver msm_audio_ion_driver = {
.driver = {
.name = "msm-audio-ion-vm",
.owner = THIS_MODULE,
.of_match_table = msm_audio_ion_dt_match,
},
.probe = msm_audio_ion_probe,
.remove = msm_audio_ion_remove,
};
static int __init msm_audio_ion_init(void)
{
return platform_driver_register(&msm_audio_ion_driver);
}
module_init(msm_audio_ion_init);
static void __exit msm_audio_ion_exit(void)
{
platform_driver_unregister(&msm_audio_ion_driver);
}
module_exit(msm_audio_ion_exit);
MODULE_DESCRIPTION("MSM Audio ION VM module");
MODULE_LICENSE("GPL v2");

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2010-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2010-2017, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -137,6 +137,10 @@ struct apr_svc {
struct mutex m_lock;
spinlock_t w_lock;
uint8_t pkt_owner;
#ifdef CONFIG_MSM_QDSP6_APRV2_VM
uint16_t vm_dest_svc;
uint32_t vm_handle;
#endif
};
struct apr_client {

View file

@ -0,0 +1,116 @@
/* Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef __APRV2_VM_H__
#define __APRV2_VM_H__
#define APRV2_VM_MAX_DNS_SIZE (31)
/* Includes NULL character. */
#define APRV2_VM_PKT_SERVICE_ID_MASK (0x00FF)
/* Bitmask of the service ID field. */
/* Packet Structure Definition */
struct aprv2_vm_packet_t {
uint32_t header;
uint16_t src_addr;
uint16_t src_port;
uint16_t dst_addr;
uint16_t dst_port;
uint32_t token;
uint32_t opcode;
};
/**
* In order to send command/event via MM HAB, the following buffer
* format shall be followed, where the buffer is provided to the
* HAB send API.
* |-----cmd_id or evt_id -----| <- 32 bit, e.g. APRV2_VM_CMDID_REGISTER
* |-----cmd payload ----------| e.g. aprv2_vm_cmd_register_t
* | ... |
*
* In order to receive a command response or event ack, the following
* buffer format shall be followed, where the buffer is provided to
* the HAB receive API.
* |-----cmd response ---------| e.g. aprv2_vm_cmd_register_rsp_t
* | ... |
*/
/* Registers a service with the backend APR driver. */
#define APRV2_VM_CMDID_REGISTER (0x00000001)
struct aprv2_vm_cmd_register_t {
uint32_t name_size;
/**< The service name string size in bytes. */
char name[APRV2_VM_MAX_DNS_SIZE];
/**<
* The service name string to register.
*
* A NULL name means the service does not have a name.
*/
uint16_t addr;
/**<
* The address to register.
*
* A zero value means to auto-generate a free dynamic address.
* A non-zero value means to directly use the statically assigned address.
*/
};
struct aprv2_vm_cmd_register_rsp_t {
int32_t status;
/**< The status of registration. */
uint32_t handle;
/**< The registered service handle. */
uint16_t addr;
/**< The actual registered address. */
};
#define APRV2_VM_CMDID_DEREGISTER (0x00000002)
struct aprv2_vm_cmd_deregister_t {
uint32_t handle;
/**< The registered service handle. */
};
struct aprv2_vm_cmd_deregister_rsp_t {
int32_t status;
/**< The status of de-registration. */
};
#define APRV2_VM_CMDID_ASYNC_SEND (0x00000003)
struct aprv2_vm_cmd_async_send_t {
uint32_t handle;
/**< The registered service handle. */
struct aprv2_vm_packet_t pkt_header;
/**< The packet header. */
/* The apr packet payload follows */
};
struct aprv2_vm_cmd_async_send_rsp_t {
int32_t status;
/**< The status of send. */
};
#define APRV2_VM_EVT_RX_PKT_AVAILABLE (0x00000004)
struct aprv2_vm_evt_rx_pkt_available_t {
struct aprv2_vm_packet_t pkt_header;
/**< The packet header. */
/* The apr packet payload follows */
};
struct aprv2_vm_ack_rx_pkt_available_t {
int32_t status;
};
#endif /* __APRV2_VM_H__ */