633 lines
15 KiB
C
633 lines
15 KiB
C
![]() |
// Copyright 2020-2021 Beken
|
||
|
//
|
||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
// you may not use this file except in compliance with the License.
|
||
|
// You may obtain a copy of the License at
|
||
|
//
|
||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||
|
//
|
||
|
// Unless required by applicable law or agreed to in writing, software
|
||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
// See the License for the specific language governing permissions and
|
||
|
// limitations under the License.
|
||
|
//
|
||
|
|
||
|
#pragma once
|
||
|
|
||
|
#include <common/bk_include.h>
|
||
|
#include <driver/dma_types.h>
|
||
|
|
||
|
#ifdef __cplusplus
|
||
|
extern "C" {
|
||
|
#endif
|
||
|
|
||
|
/**
|
||
|
* @brief Init the DMA driver
|
||
|
*
|
||
|
* This API init the resoure common to all dma channels:
|
||
|
* - Init dma driver control memory
|
||
|
*
|
||
|
* This API should be called before any other dma APIs.
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*/
|
||
|
bk_err_t bk_dma_driver_init(void);
|
||
|
|
||
|
/**
|
||
|
* @brief Deinit the DMA driver
|
||
|
*
|
||
|
* This API free all resource related to dma and power down all dma channels.
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*/
|
||
|
bk_err_t bk_dma_driver_deinit(void);
|
||
|
|
||
|
/**
|
||
|
* @brief Allocate a DMA channel
|
||
|
*
|
||
|
* @attention: This API can only be called in task context,
|
||
|
* - and can't be called in context that interrupt is disabled.
|
||
|
*
|
||
|
* This API should be called before any other dma channel APIs.
|
||
|
*
|
||
|
* @param user_id DMA channel applicant
|
||
|
*
|
||
|
* @return DMA channel id.
|
||
|
* - > DMA_ID_MAX: no free DMA channel.
|
||
|
*/
|
||
|
dma_id_t bk_dma_alloc(u16 user_id);
|
||
|
|
||
|
#if CONFIG_GDMA_HW_V2PX
|
||
|
/**
|
||
|
* @brief Allocate a fixed DMA channel.Maybe some APP needs to have a
|
||
|
* fixed channel forever, then it can use this API.
|
||
|
*
|
||
|
* @attention: This API is just for CONFIG_GDMA_HW_V2PX
|
||
|
* And CONFIG_GDMA_HW_V1PX doesn't support it.
|
||
|
*
|
||
|
* This API should be called before any other dma channel APIs.
|
||
|
*
|
||
|
* @param user_id DMA channel applicant
|
||
|
* @param fixed_chnl_id application wants to get which fixed channel
|
||
|
*
|
||
|
* @return DMA channel id.
|
||
|
* - > DMA_ID_MAX: if the fixed_chnl_id has been allocated, it will
|
||
|
* return DMA_ID_MAX which means error.
|
||
|
* - > fixed_chnl_id: the fixed_chnl_id is allocated suc.
|
||
|
*/
|
||
|
dma_id_t bk_fixed_dma_alloc(u16 user_id, dma_id_t fixed_chnl_id);
|
||
|
#endif
|
||
|
|
||
|
/**
|
||
|
* @brief Free the DMA channel
|
||
|
*
|
||
|
* @attention: This API can only be called in task context,
|
||
|
* - and can't be called in context that interrupt is disabled.
|
||
|
*
|
||
|
* @param user_id DMA channel applicant, the same as in bk_dma_alloc.
|
||
|
* @param id DMA channel
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*/
|
||
|
bk_err_t bk_dma_free(u16 user_id, dma_id_t id);
|
||
|
|
||
|
/**
|
||
|
* @brief get the user of DMA channel
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
*
|
||
|
* @return DMA channel user_id.
|
||
|
* - u32: high u16 is the CPU_ID, low 16 bits is the applicant_id.
|
||
|
*/
|
||
|
uint32_t bk_dma_user(dma_id_t id);
|
||
|
|
||
|
/**
|
||
|
* @brief Init the DMA channel
|
||
|
*
|
||
|
* @attention 1. the higher channel priority value, the higher the priority
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
* @param config DMA configuration
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - BK_ERR_DMA_NOT_INIT: DMA driver not init
|
||
|
* - BK_ERR_NULL_PARAM: config is NULL
|
||
|
* - BK_ERR_DMA_ID: invalid DMA channel
|
||
|
* - BK_ERR_DMA_INVALID_ADDR: invalid DMA address
|
||
|
* - others: other errors.
|
||
|
*/
|
||
|
bk_err_t bk_dma_init(dma_id_t id, const dma_config_t *config);
|
||
|
|
||
|
/**
|
||
|
* @brief Deinit a DMA channel
|
||
|
*
|
||
|
* This API deinit the DMA channel:
|
||
|
* - Stop the DMA channel
|
||
|
* - Reset all configuration of DMA channel to default value
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*/
|
||
|
bk_err_t bk_dma_deinit(dma_id_t id);
|
||
|
|
||
|
/**
|
||
|
* @brief Start a DMA channel
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*/
|
||
|
bk_err_t bk_dma_start(dma_id_t id);
|
||
|
|
||
|
/**
|
||
|
* @brief Stop a DMA channel
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*/
|
||
|
bk_err_t bk_dma_stop(dma_id_t id);
|
||
|
|
||
|
/**
|
||
|
* @brief Transfer data from memory to peripheral
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
* @param data DMA transfer data
|
||
|
* @param size data size
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*/
|
||
|
bk_err_t bk_dma_write(dma_id_t id, const uint8_t *data, uint32_t size);
|
||
|
|
||
|
/**
|
||
|
* @brief Transfer data from peripheral to memory
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
* @param data DMA transfer data
|
||
|
* @param size data size
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*/
|
||
|
bk_err_t bk_dma_read(dma_id_t id, uint8_t *data, uint32_t size);
|
||
|
|
||
|
/**
|
||
|
* @brief Enable DMA finish intterrup
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*
|
||
|
* @NOTES before enable interrupt, please confirm have called bk_dma_register_isr.
|
||
|
*/
|
||
|
bk_err_t bk_dma_enable_finish_interrupt(dma_id_t id);
|
||
|
|
||
|
/**
|
||
|
* @brief Disable DMA finish intterrup
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*/
|
||
|
bk_err_t bk_dma_disable_finish_interrupt(dma_id_t id);
|
||
|
|
||
|
/**
|
||
|
* @brief Enable DMA half finish intterrup
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*
|
||
|
* @NOTES before enable interrupt, please confirm have called bk_dma_register_isr.
|
||
|
*/
|
||
|
bk_err_t bk_dma_enable_half_finish_interrupt(dma_id_t id);
|
||
|
|
||
|
/**
|
||
|
* @brief Disable DMA half finish intterrup
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*/
|
||
|
bk_err_t bk_dma_disable_half_finish_interrupt(dma_id_t id);
|
||
|
|
||
|
/**
|
||
|
* @brief Register the interrupt service routine for DMA channel
|
||
|
*
|
||
|
* This API regist dma isr callback function.
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
* @param half_finish_isr DMA half finish callback
|
||
|
* @param finish_isr DMA finish callback
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*/
|
||
|
bk_err_t bk_dma_register_isr(dma_id_t id, dma_isr_t half_finish_isr, dma_isr_t finish_isr);
|
||
|
|
||
|
#if CONFIG_GDMA_HW_V2PX
|
||
|
/**
|
||
|
* @brief Register the interrupt service routine for DMA channel
|
||
|
*
|
||
|
* This API regist dma isr callback function.
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
* @param half_finish_isr DMA half finish callback
|
||
|
* @param finish_isr DMA finish callback
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*/
|
||
|
bk_err_t bk_dma_register_bus_err_isr(dma_id_t id, dma_isr_t bus_err_isr);
|
||
|
#endif
|
||
|
|
||
|
/**
|
||
|
* @brief get DMA transfer max length in one round, default value is 65536 bytes.
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
*
|
||
|
* @return
|
||
|
* - max len: how many bytes can be copy by DMA in one round.
|
||
|
*/
|
||
|
uint32_t bk_dma_get_transfer_len_max(dma_id_t id);
|
||
|
|
||
|
/**
|
||
|
* @brief Set DMA transfer length
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
* @param tran_len DMA transfer length, the tran_len should be <= bk_dma_get_transfer_len_max() bytes.
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*/
|
||
|
bk_err_t bk_dma_set_transfer_len(dma_id_t id, uint32_t tran_len);
|
||
|
|
||
|
/**
|
||
|
* @brief Set DMA source address
|
||
|
*
|
||
|
* @attention 1. address should be zero when there is no value, e.g. bk_dma_set_src_addr(1, 0x80210C, 0)
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
* @param start_addr DMA source start address
|
||
|
* @param end_addr DMA source end address
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*/
|
||
|
bk_err_t bk_dma_set_src_addr(dma_id_t id, uint32_t start_addr, uint32_t end_addr);
|
||
|
|
||
|
/**
|
||
|
* @brief Set DMA source start address
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
* @param start_addr DMA source start address
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*/
|
||
|
bk_err_t bk_dma_set_src_start_addr(dma_id_t id, uint32_t start_addr);
|
||
|
|
||
|
/**
|
||
|
* @brief Set DMA dest address
|
||
|
*
|
||
|
* @attention 1. address should be zero when there is no value, e.g. bk_dma_set_dest_addr(1, 0x80210C, 0)
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
* @param start_addr DMA dest start address
|
||
|
* @param end_addr DMA dest end address
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*/
|
||
|
bk_err_t bk_dma_set_dest_addr(dma_id_t id, uint32_t start_addr, uint32_t end_addr);
|
||
|
|
||
|
/**
|
||
|
* @brief Set DMA dest start address
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
* @param start_addr DMA dest start address
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*/
|
||
|
bk_err_t bk_dma_set_dest_start_addr(dma_id_t id, uint32_t start_addr);
|
||
|
|
||
|
/**
|
||
|
* @brief Enable DMA source address increase
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*/
|
||
|
bk_err_t bk_dma_enable_src_addr_increase(dma_id_t id);
|
||
|
|
||
|
/**
|
||
|
* @brief Disable DMA source address increase
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*/
|
||
|
bk_err_t bk_dma_disable_src_addr_increase(dma_id_t id);
|
||
|
|
||
|
/**
|
||
|
* @brief Enable DMA source address loop
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*/
|
||
|
bk_err_t bk_dma_enable_src_addr_loop(dma_id_t id);
|
||
|
|
||
|
/**
|
||
|
* @brief Disable DMA source address loop
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*/
|
||
|
bk_err_t bk_dma_disable_src_addr_loop(dma_id_t id);
|
||
|
|
||
|
/**
|
||
|
* @brief Enable DMA dest address increase
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*/
|
||
|
bk_err_t bk_dma_enable_dest_addr_increase(dma_id_t id);
|
||
|
|
||
|
/**
|
||
|
* @brief Disable DMA dest address increase
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*/
|
||
|
bk_err_t bk_dma_disable_dest_addr_increase(dma_id_t id);
|
||
|
|
||
|
/**
|
||
|
* @brief Enable DMA dest address loop
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*/
|
||
|
bk_err_t bk_dma_enable_dest_addr_loop(dma_id_t id);
|
||
|
|
||
|
/**
|
||
|
* @brief Disable DMA dest address loop
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*/
|
||
|
bk_err_t bk_dma_disable_dest_addr_loop(dma_id_t id);
|
||
|
|
||
|
/**
|
||
|
* @brief Get DMA transfer remain length
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
*
|
||
|
* @return DMA transfer remain length
|
||
|
*/
|
||
|
uint32_t bk_dma_get_remain_len(dma_id_t id);
|
||
|
|
||
|
/**
|
||
|
* @brief Gets the current DMA channel working status
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
*
|
||
|
* @return
|
||
|
* - 0: Channel idle state
|
||
|
* - others: Channel busy state.
|
||
|
*/
|
||
|
uint32_t bk_dma_get_enable_status(dma_id_t id);
|
||
|
|
||
|
/**
|
||
|
* @brief flush reserved data in dma internal buffer
|
||
|
* I.E:If source data width is not 4bytes, and data size isn't 4bytes align,
|
||
|
* but dest data width is 4bytes, then maybe 1~3 bytes data reserved in
|
||
|
* dma internal buffer, then the left 1~3 bytes data not copy to dest address.
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
* @param attr DMA privileged attr
|
||
|
*
|
||
|
* @return
|
||
|
* - 0: Channel idle state
|
||
|
* - others: Channel busy state.
|
||
|
*/
|
||
|
bk_err_t bk_dma_flush_src_buffer(dma_id_t id);
|
||
|
|
||
|
#ifdef CONFIG_SPE
|
||
|
/**
|
||
|
* @brief To configure the beat length,
|
||
|
* DMA actually applies for the bus one at a time and divides the total
|
||
|
* amount of data to be transmitted into small data blocks. For example, if
|
||
|
* you want to transfer 64 bytes, then dma may be divided into 2 times internally.
|
||
|
* 64/2=32 bytes are transferred at one time.This 2(a) times is called burst.
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
* @param len DMA dest burst len
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*/
|
||
|
bk_err_t bk_dma_set_dest_burst_len(dma_id_t id, dma_burst_len_t len);
|
||
|
|
||
|
/**
|
||
|
* @brief Get the configured length of burst
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
*
|
||
|
* @return DMA dest burst length
|
||
|
*/
|
||
|
uint32_t bk_dma_get_dest_burst_len(dma_id_t id);
|
||
|
|
||
|
/**
|
||
|
* @brief To configure the beat length,
|
||
|
* DMA actually applies for the bus one at a time and divides the total
|
||
|
* amount of data to be transmitted into small data blocks. For example, if
|
||
|
* you want to transfer 64 bytes, then dma may be divided into 2 times internally.
|
||
|
* 64/2=32 bytes are transferred at one time.This 2(a) times is called burst.
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
* @param len DMA dest burst len
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*/
|
||
|
bk_err_t bk_dma_set_src_burst_len(dma_id_t id, dma_burst_len_t len);
|
||
|
|
||
|
/**
|
||
|
* @brief Get the configured length of burst
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
*
|
||
|
* @return DMA dest burst length
|
||
|
*/
|
||
|
uint32_t bk_dma_get_src_burst_len(dma_id_t id);
|
||
|
|
||
|
/**
|
||
|
* @brief Select the conversion mode that needs to be configured for DMA conversion of
|
||
|
* video formats during data transfer.
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
* @param type DMA Select conversion mode
|
||
|
*
|
||
|
* @return
|
||
|
* - BK_OK: succeed
|
||
|
* - others: other errors.
|
||
|
*/
|
||
|
bk_err_t bk_dma_set_pixel_trans_type(dma_id_t id, dma_pixel_trans_type_t type);
|
||
|
|
||
|
/**
|
||
|
* @brief Get the conversion mode
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
*
|
||
|
* @return DMA conversion mode
|
||
|
*/
|
||
|
uint32_t bk_dma_get_pixel_trans_type(dma_id_t id);
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @brief Enable the current DMA channel bus err interrupt
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
*
|
||
|
* @return
|
||
|
* - 0: enable success state
|
||
|
* - others: Channel busy state.
|
||
|
*/
|
||
|
bk_err_t bk_dma_bus_err_int_enable(dma_id_t id);
|
||
|
|
||
|
/**
|
||
|
* @brief Disable the current DMA channel bus err interrupt
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
*
|
||
|
* @return
|
||
|
* - 0: disable success state
|
||
|
* - others: Channel busy state.
|
||
|
*/
|
||
|
bk_err_t bk_dma_bus_err_int_disable(dma_id_t id);
|
||
|
|
||
|
/**
|
||
|
* @brief Set the current DMA channel dest secure attr
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
* @param attr DMA secure attr
|
||
|
*
|
||
|
* @return
|
||
|
* - 0: Channel idle state
|
||
|
* - others: Channel busy state.
|
||
|
*/
|
||
|
bk_err_t bk_dma_set_dest_sec_attr(dma_id_t id, dma_sec_attr_t attr);
|
||
|
|
||
|
/**
|
||
|
* @brief Set the current DMA channel src secure attr
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
* @param attr DMA secure attr
|
||
|
*
|
||
|
* @return
|
||
|
* - 0: Channel idle state
|
||
|
* - others: Channel busy state.
|
||
|
*/
|
||
|
bk_err_t bk_dma_set_src_sec_attr(dma_id_t id, dma_sec_attr_t attr);
|
||
|
#endif
|
||
|
|
||
|
#if (CONFIG_SPE)
|
||
|
/**
|
||
|
* @brief Set the all DMA channel secure attr
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
* @param attr DMA secure attr
|
||
|
*
|
||
|
* @return
|
||
|
* - 0: Channel idle state
|
||
|
* - others: Channel busy state.
|
||
|
*/
|
||
|
bk_err_t bk_dma_set_sec_attr(dma_id_t id, dma_sec_attr_t attr);
|
||
|
|
||
|
/**
|
||
|
* @brief Set the all DMA channel privileded attr
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
* @param attr DMA privileged attr
|
||
|
*
|
||
|
* @return
|
||
|
* - 0: Channel idle state
|
||
|
* - others: Channel busy state.
|
||
|
*/
|
||
|
bk_err_t bk_dma_set_privileged_attr(dma_id_t id, dma_sec_attr_t attr);
|
||
|
|
||
|
/**
|
||
|
* @brief Configure the same DMA channel to trigger the interrupt state on a fixed core
|
||
|
*
|
||
|
* @param id DMA channel
|
||
|
* @param DMA interrupt id
|
||
|
*
|
||
|
* @return
|
||
|
* - 0: Channel idle state
|
||
|
* - others: Channel busy state.
|
||
|
*/
|
||
|
bk_err_t bk_dma_set_int_allocate(dma_id_t id,dma_int_id_t int_id);
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#ifdef __cplusplus
|
||
|
}
|
||
|
#endif
|
||
|
|