Home | History | Annotate | Download | only in android
      1 /*
      2  * Copyright (c) 2011 Intel Corporation. All Rights Reserved.
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the
      6  * "Software"), to deal in the Software without restriction, including
      7  * without limitation the rights to use, copy, modify, merge, publish,
      8  * distribute, sub license, and/or sell copies of the Software, and to
      9  * permit persons to whom the Software is furnished to do so, subject to
     10  * the following conditions:
     11  *
     12  * The above copyright notice and this permission notice (including the
     13  * next paragraph) shall be included in all copies or substantial portions
     14  * of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     19  * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
     20  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     21  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     22  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     23  *
     24  */
     25 
     26 #include <sys/mman.h>
     27 #include <va/va_tpi.h>
     28 #include "psb_drv_video.h"
     29 #include "psb_drv_debug.h"
     30 #include "psb_surface.h"
     31 #include "psb_surface_attrib.h"
     32 
     33 #include <gralloc.h>
     34 #include "android/psb_gralloc.h"
     35 #include "android/psb_android_glue.h"
     36 #ifndef BAYTRAIL
     37 #include <hal/hal_public.h>
     38 #endif
     39 #include <wsbm/wsbm_manager.h>
     40 
     41 #define INIT_DRIVER_DATA    psb_driver_data_p driver_data = (psb_driver_data_p) ctx->pDriverData;
     42 #define CONFIG(id)  ((object_config_p) object_heap_lookup( &driver_data->config_heap, id ))
     43 #define CONTEXT(id) ((object_context_p) object_heap_lookup( &driver_data->context_heap, id ))
     44 #define SURFACE(id)    ((object_surface_p) object_heap_lookup( &driver_data->surface_heap, id ))
     45 #define BUFFER(id)  ((object_buffer_p) object_heap_lookup( &driver_data->buffer_heap, id ))
     46 #define SHARE_INFO_INIT_VALUE   0x12345678
     47 
     48 static pthread_mutex_t gralloc_mutex = PTHREAD_MUTEX_INITIALIZER;
     49 
     50 /*FIXME: include hal_public.h instead of define it here*/
     51 enum {
     52     GRALLOC_SUB_BUFFER0 = 0,
     53     GRALLOC_SUB_BUFFER1,
     54     GRALLOC_SUB_BUFFER2,
     55     GRALLOC_SUB_BUFFER_MAX,
     56 };
     57 
     58 VAStatus psb_DestroySurfaceGralloc(object_surface_p obj_surface)
     59 {
     60     void *vaddr[GRALLOC_SUB_BUFFER_MAX];
     61     int usage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER;
     62     buffer_handle_t handle = obj_surface->psb_surface->buf.handle;
     63     VAStatus vaStatus = VA_STATUS_SUCCESS;
     64 
     65 #ifdef PSBVIDEO_MRFL
     66     usage |= GRALLOC_USAGE_SW_WRITE_OFTEN;
     67 #endif
     68 
     69     pthread_mutex_lock(&gralloc_mutex);
     70     if (!gralloc_lock(handle, usage, 0, 0,
     71                       obj_surface->width, obj_surface->height, (void **)&vaddr[GRALLOC_SUB_BUFFER0])){
     72         if (obj_surface->share_info && vaddr[GRALLOC_SUB_BUFFER1] == obj_surface->share_info) {
     73             int metadata_rotate = obj_surface->share_info->metadata_rotate;
     74             int surface_protected = obj_surface->share_info->surface_protected;
     75             int force_output_method = obj_surface->share_info->force_output_method;
     76             int bob_deinterlace = obj_surface->share_info->bob_deinterlace;
     77 
     78             memset(obj_surface->share_info, 0, sizeof(struct psb_surface_share_info_s));
     79             /* Still need to keep these info so that hwc can get them after suspend/resume cycle */
     80             obj_surface->share_info->metadata_rotate = metadata_rotate;
     81             obj_surface->share_info->surface_protected = surface_protected;
     82             obj_surface->share_info->force_output_method = force_output_method;
     83             obj_surface->share_info->bob_deinterlace = bob_deinterlace;
     84         }
     85         gralloc_unlock(handle);
     86 
     87         if (gralloc_unregister(handle))
     88             vaStatus = VA_STATUS_ERROR_UNKNOWN;
     89     }
     90     pthread_mutex_unlock(&gralloc_mutex);
     91 
     92     return vaStatus;
     93 }
     94 
     95 #ifdef BAYTRAIL
     96 VAStatus psb_CreateSurfacesFromGralloc(
     97     VADriverContextP ctx,
     98     int width,
     99     int height,
    100     int format,
    101     int num_surfaces,
    102     VASurfaceID *surface_list,        /* out */
    103     PsbSurfaceAttributeTPI *attribute_tpi
    104 )
    105 {
    106     INIT_DRIVER_DATA
    107     VAStatus vaStatus = VA_STATUS_SUCCESS;
    108     int i, height_origin, usage, buffer_stride = 0;
    109     int protected = (VA_RT_FORMAT_PROTECTED & format);
    110     unsigned long fourcc;
    111     VASurfaceAttributeTPI *external_buffers = NULL;
    112     unsigned long handle;
    113     int size = num_surfaces * sizeof(unsigned int);
    114     void *vaddr;
    115 
    116 
    117     /* follow are gralloc-buffers */
    118     format = format & (~VA_RT_FORMAT_PROTECTED);
    119     driver_data->protected = protected;
    120 
    121     CHECK_INVALID_PARAM(num_surfaces <= 0);
    122     CHECK_SURFACE(surface_list);
    123 
    124     external_buffers = attribute_tpi;
    125 
    126     ALOGD("format is 0x%x, width is %d, height is %d, num_surfaces is %d.\n", format, width, height, num_surfaces);
    127     /* We only support one format */
    128     if ((VA_RT_FORMAT_YUV420 != format)
    129         && (VA_RT_FORMAT_YUV422 != format)) {
    130         vaStatus = VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT;
    131         DEBUG_FAILURE;
    132         return vaStatus;
    133     }
    134 
    135     CHECK_INVALID_PARAM(external_buffers == NULL);
    136 
    137     /*
    138     vaStatus = psb__checkSurfaceDimensions(driver_data, width, height);
    139     CHECK_VASTATUS();
    140     */
    141     /* Adjust height to be a multiple of 32 (height of macroblock in interlaced mode) */
    142     height_origin = height;
    143     height = (height + 0x1f) & ~0x1f;
    144     ALOGD("external_buffers->pixel_format is 0x%x.\n", external_buffers->pixel_format);
    145     /* get native window from the reserved field */
    146     driver_data->native_window = (void *)external_buffers->reserved[0];
    147 
    148     for (i = 0; i < num_surfaces; i++) {
    149         int surfaceID;
    150         object_surface_p obj_surface;
    151         psb_surface_p psb_surface;
    152 
    153         surfaceID = object_heap_allocate(&driver_data->surface_heap);
    154         obj_surface = SURFACE(surfaceID);
    155         if (NULL == obj_surface) {
    156             vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
    157             DEBUG_FAILURE;
    158             break;
    159         }
    160         MEMSET_OBJECT(obj_surface, struct object_surface_s);
    161 
    162         obj_surface->surface_id = surfaceID;
    163         surface_list[i] = surfaceID;
    164         obj_surface->context_id = -1;
    165         obj_surface->width = width;
    166         obj_surface->height = height;
    167         obj_surface->width_r = width;
    168         obj_surface->height_r = height;
    169         obj_surface->height_origin = height_origin;
    170         obj_surface->is_ref_surface = 0;
    171 
    172         psb_surface = (psb_surface_p) calloc(1, sizeof(struct psb_surface_s));
    173         if (NULL == psb_surface) {
    174             object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface);
    175             obj_surface->surface_id = VA_INVALID_SURFACE;
    176 
    177             vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
    178 
    179             DEBUG_FAILURE;
    180             break;
    181         }
    182 
    183         switch (format) {
    184         case VA_RT_FORMAT_YUV422:
    185             fourcc = VA_FOURCC_YV16;
    186             break;
    187         case VA_RT_FORMAT_YUV420:
    188         default:
    189             fourcc = VA_FOURCC_NV12;
    190             break;
    191         }
    192 
    193         /*hard code the gralloc buffer usage*/
    194         usage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER;
    195 
    196         /* usage hack for byt */
    197         usage |= GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
    198         /* usage hack to force pages alloc and CPU/GPU cache flush */
    199         usage |= GRALLOC_USAGE_HW_VIDEO_ENCODER;
    200 
    201         handle = (unsigned long)external_buffers->buffers[i];
    202         pthread_mutex_lock(&gralloc_mutex);
    203         if (gralloc_lock(handle, usage, 0, 0, width, height, (void **)&vaddr)) {
    204             vaStatus = VA_STATUS_ERROR_UNKNOWN;
    205         } else {
    206             int cache_flag = PSB_USER_BUFFER_UNCACHED;
    207             int buf_fd = gralloc_getbuffd(handle);
    208 
    209             vaStatus = psb_surface_create_from_ub(driver_data, width, height, fourcc,
    210                     external_buffers, psb_surface, vaddr, buf_fd,
    211                     cache_flag);
    212 
    213             psb_surface->buf.handle = handle;
    214             obj_surface->share_info = NULL;
    215             gralloc_unlock(handle);
    216         }
    217         pthread_mutex_unlock(&gralloc_mutex);
    218 
    219         if (VA_STATUS_SUCCESS != vaStatus) {
    220             free(psb_surface);
    221             object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface);
    222             obj_surface->surface_id = VA_INVALID_SURFACE;
    223 
    224             DEBUG_FAILURE;
    225             break;
    226         }
    227         buffer_stride = psb_surface->stride;
    228 #ifdef PSBVIDEO_MSVDX_DEC_TILING
    229         psb_surface->extra_info[7] = external_buffers->tiling;
    230 #endif
    231         /* by default, surface fourcc is NV12 */
    232         psb_surface->extra_info[4] = fourcc;
    233         obj_surface->psb_surface = psb_surface;
    234     }
    235 
    236     /* Error recovery */
    237     if (VA_STATUS_SUCCESS != vaStatus) {
    238         /* surface_list[i-1] was the last successful allocation */
    239         for (; i--;) {
    240             object_surface_p obj_surface = SURFACE(surface_list[i]);
    241             psb__destroy_surface(driver_data, obj_surface);
    242             surface_list[i] = VA_INVALID_SURFACE;
    243         }
    244         drv_debug_msg(VIDEO_DEBUG_ERROR, "CreateSurfaces failed\n");
    245 
    246         return vaStatus;
    247     }
    248 
    249     return vaStatus;
    250 }
    251 #else
    252 VAStatus psb_CreateSurfacesFromGralloc(
    253     VADriverContextP ctx,
    254     int width,
    255     int height,
    256     int format,
    257     int num_surfaces,
    258     VASurfaceID *surface_list,        /* out */
    259     PsbSurfaceAttributeTPI *attribute_tpi
    260 )
    261 {
    262     INIT_DRIVER_DATA
    263     VAStatus vaStatus = VA_STATUS_SUCCESS;
    264     int i, height_origin, usage, buffer_stride = 0;
    265     int protected = (VA_RT_FORMAT_PROTECTED & format);
    266     unsigned long fourcc;
    267     PsbSurfaceAttributeTPI *external_buffers = NULL;
    268     unsigned long handle;
    269     int size = num_surfaces * sizeof(unsigned int);
    270     void *vaddr[GRALLOC_SUB_BUFFER_MAX];
    271 
    272     /* follow are gralloc-buffers */
    273     format = format & (~VA_RT_FORMAT_PROTECTED);
    274     driver_data->protected = protected;
    275 
    276     CHECK_INVALID_PARAM(num_surfaces <= 0);
    277     CHECK_SURFACE(surface_list);
    278 
    279     external_buffers = attribute_tpi;
    280 
    281     /* We only support one format */
    282     if ((VA_RT_FORMAT_YUV420 != format)
    283         && (VA_RT_FORMAT_YUV422 != format)
    284         && (VA_RT_FORMAT_RGB32 != format)) {
    285         vaStatus = VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT;
    286         DEBUG_FAILURE;
    287         return vaStatus;
    288     }
    289 
    290     CHECK_INVALID_PARAM(external_buffers == NULL);
    291 
    292     /*
    293     vaStatus = psb__checkSurfaceDimensions(driver_data, width, height);
    294     CHECK_VASTATUS();
    295     */
    296     /* Adjust height to be a multiple of 32 (height of macroblock in interlaced mode) */
    297     height_origin = height;
    298 
    299     IMG_native_handle_t* h = (IMG_native_handle_t*)external_buffers->buffers[0];
    300     int gfx_colorformat = h->iFormat;
    301 
    302     if (gfx_colorformat != HAL_PIXEL_FORMAT_NV12 && format != VA_RT_FORMAT_RGB32)
    303         height = (height + 0x1f) & ~0x1f;
    304 
    305     /* get native window from the reserved field */
    306     driver_data->native_window = (void *)external_buffers->reserved[0];
    307 
    308     for (i = 0; i < num_surfaces; i++) {
    309         int surfaceID;
    310         object_surface_p obj_surface;
    311         psb_surface_p psb_surface;
    312 
    313         surfaceID = object_heap_allocate(&driver_data->surface_heap);
    314         obj_surface = SURFACE(surfaceID);
    315         if (NULL == obj_surface) {
    316             vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
    317             DEBUG_FAILURE;
    318             break;
    319         }
    320         MEMSET_OBJECT(obj_surface, struct object_surface_s);
    321 
    322         obj_surface->surface_id = surfaceID;
    323         surface_list[i] = surfaceID;
    324         obj_surface->context_id = -1;
    325         obj_surface->width = width;
    326         obj_surface->height = height;
    327         obj_surface->width_r = width;
    328         obj_surface->height_r = height;
    329         obj_surface->height_origin = height_origin;
    330 
    331         psb_surface = (psb_surface_p) calloc(1, sizeof(struct psb_surface_s));
    332         if (NULL == psb_surface) {
    333             object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface);
    334             obj_surface->surface_id = VA_INVALID_SURFACE;
    335 
    336             vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
    337 
    338             DEBUG_FAILURE;
    339             break;
    340         }
    341 
    342         switch (format) {
    343         case VA_RT_FORMAT_YUV422:
    344             fourcc = VA_FOURCC_YV16;
    345             break;
    346         case VA_RT_FORMAT_RGB32:
    347             fourcc = VA_FOURCC_RGBA;
    348             break;
    349         case VA_RT_FORMAT_YUV420:
    350         default:
    351             fourcc = VA_FOURCC_NV12;
    352             break;
    353         }
    354 
    355 #ifndef PSBVIDEO_MSVDX_DEC_TILING
    356         external_buffers->tiling = 0;
    357 #endif
    358         /*hard code the gralloc buffer usage*/
    359         usage = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER;
    360 
    361         if (gfx_colorformat == HAL_PIXEL_FORMAT_NV12)
    362             usage |= GRALLOC_USAGE_SW_READ_OFTEN;
    363         else {
    364             // video decoder allows app to read/write the buffer
    365             usage |= GRALLOC_USAGE_SW_WRITE_RARELY | GRALLOC_USAGE_SW_READ_RARELY;
    366         }
    367 
    368         handle = (unsigned long)external_buffers->buffers[i];
    369         pthread_mutex_lock(&gralloc_mutex);
    370 
    371         if (gralloc_register((buffer_handle_t)handle)) {
    372             vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
    373         } else {
    374             if (gralloc_lock((buffer_handle_t)handle, usage, 0, 0, width, height, (void **)&vaddr[GRALLOC_SUB_BUFFER0])) {
    375                 vaStatus = VA_STATUS_ERROR_UNKNOWN;
    376                 gralloc_unregister((buffer_handle_t)handle);
    377             } else {
    378                 int cache_flag = PSB_USER_BUFFER_UNCACHED;
    379                 int buf_fd = gralloc_getbuffd((buffer_handle_t)handle);
    380 #ifdef PSBVIDEO_MRFL
    381                 //cache_flag = 0;
    382 #endif
    383                 vaStatus = psb_surface_create_from_ub(driver_data, width, height, fourcc,
    384                         (VASurfaceAttributeTPI *)external_buffers, psb_surface,
    385                         vaddr[GRALLOC_SUB_BUFFER0], buf_fd, cache_flag);
    386                 psb_surface->buf.handle = (void *)handle;
    387                 obj_surface->share_info = NULL;
    388 
    389                 if ((gfx_colorformat != HAL_PIXEL_FORMAT_NV12) &&
    390                         (gfx_colorformat != HAL_PIXEL_FORMAT_YV12) &&
    391                         (format != VA_RT_FORMAT_RGB32)) {
    392                     unsigned int decoder_share_info = (unsigned int)external_buffers->reserved[2];
    393                     drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s : Create graphic buffer initialized share info %d", __FUNCTION__, decoder_share_info);
    394                     obj_surface->share_info = (psb_surface_share_info_t *)vaddr[GRALLOC_SUB_BUFFER1];
    395 
    396                     if (obj_surface->share_info->initialized != SHARE_INFO_INIT_VALUE) {
    397                         memset(obj_surface->share_info, 0, sizeof(struct psb_surface_share_info_s));
    398                         // Set clear video the default output method as OUTPUT_FORCE_OVERLAY_FOR_SW_DECODE
    399                         // if the video can be decoded by HW, will reset the output method as 0 in psb_BeginPicture
    400 #ifdef PSBVIDEO_MSVDX_DEC_TILING
    401                         obj_surface->share_info->tiling = external_buffers->tiling;
    402 #endif
    403                         obj_surface->share_info->width = obj_surface->width;
    404                         obj_surface->share_info->height = obj_surface->height_origin;
    405 
    406                         obj_surface->share_info->luma_stride = psb_surface->stride;
    407                         obj_surface->share_info->chroma_u_stride = psb_surface->stride;
    408                         obj_surface->share_info->chroma_v_stride = psb_surface->stride;
    409                         obj_surface->share_info->format = VA_FOURCC_NV12;
    410 
    411                         obj_surface->share_info->khandle = (uint32_t)(wsbmKBufHandle(wsbmKBuf(psb_surface->buf.drm_buf)));
    412 
    413                         obj_surface->share_info->initialized = SHARE_INFO_INIT_VALUE;
    414                     }
    415 
    416                     if (decoder_share_info) {
    417                         obj_surface->share_info->force_output_method = protected ? OUTPUT_FORCE_OVERLAY : OUTPUT_FORCE_OVERLAY_FOR_SW_DECODE;
    418                         obj_surface->share_info->native_window = (void *)external_buffers->reserved[0];
    419 
    420                         attribute_tpi->reserved[1] = (unsigned long)obj_surface->share_info;
    421 
    422                         if (vaddr[GRALLOC_SUB_BUFFER0] == NULL) {
    423                             drv_debug_msg(VIDEO_DEBUG_ERROR, "Failed to lock graphic buffer in psb_video");
    424                         } else {
    425                             size = psb_surface->chroma_offset;
    426                             // the following memset was used to work-around Bug 19197299 on L.
    427                             // on DDK-1.5 we didn't observe the problem so comment it out.
    428                             // memset((char *)vaddr[GRALLOC_SUB_BUFFER0], 0, size);
    429                             // memset((char *)vaddr[GRALLOC_SUB_BUFFER0] + size, 0x80, psb_surface->size - size);
    430                         }
    431                         // overlay only support BT.601 and BT.709
    432                         if (driver_data->load_csc_matrix == 1) {
    433                             obj_surface->share_info->csc_mode = (driver_data->is_BT601 == 1) ? 0 : 1;
    434                         } else {
    435                             // if csc matrix is not set, use BT601 by default
    436                             obj_surface->share_info->csc_mode = 0;
    437                         }
    438 
    439                         if (driver_data->set_video_range == 1) {
    440                             obj_surface->share_info->video_range = driver_data->video_range;
    441                         } else {
    442                             // if video range is not set, use limited range by default
    443                             obj_surface->share_info->video_range = 0;
    444                         }
    445 
    446                         obj_surface->share_info->surface_protected = driver_data->protected;
    447                         if (driver_data->render_rect.width == 0 || driver_data->render_rect.height == 0) {
    448                             obj_surface->share_info->crop_width = obj_surface->share_info->width;
    449                             obj_surface->share_info->crop_height = obj_surface->share_info->height;
    450                         } else {
    451                             obj_surface->share_info->crop_width = driver_data->render_rect.width;
    452                             obj_surface->share_info->crop_height = driver_data->render_rect.height;
    453                         }
    454 
    455                         if (obj_surface->share_info->coded_width == 0 || obj_surface->share_info->coded_height == 0) {
    456                             obj_surface->share_info->coded_width = (obj_surface->share_info->width + 0xf) & ~0xf;
    457                             obj_surface->share_info->coded_height = (obj_surface->share_info->height + 0xf) & ~0xf;
    458                         }
    459 
    460                         drv_debug_msg(VIDEO_DEBUG_GENERAL, "%s : Create graphic buffer success"
    461                                 "surface_id= 0x%x, vaddr[0] (0x%x), vaddr[1] (0x%x)\n",
    462                                 __FUNCTION__, surfaceID, vaddr[GRALLOC_SUB_BUFFER0], vaddr[GRALLOC_SUB_BUFFER1]);
    463                     }
    464                 }
    465                 gralloc_unlock((buffer_handle_t)handle);
    466                 psb_surface->buf.user_ptr = NULL;
    467             }
    468         }
    469         pthread_mutex_unlock(&gralloc_mutex);
    470 
    471         if (VA_STATUS_SUCCESS != vaStatus) {
    472             free(psb_surface);
    473             object_heap_free(&driver_data->surface_heap, (object_base_p) obj_surface);
    474             obj_surface->surface_id = VA_INVALID_SURFACE;
    475 
    476             DEBUG_FAILURE;
    477             break;
    478         }
    479         buffer_stride = psb_surface->stride;
    480         /* by default, surface fourcc is NV12 */
    481         psb_surface->extra_info[4] = fourcc;
    482         /* save the pixel format set by application */
    483         psb_surface->extra_info[8] = external_buffers->pixel_format;
    484 #ifdef PSBVIDEO_MSVDX_DEC_TILING
    485         psb_surface->extra_info[7] = external_buffers->tiling;
    486 #endif
    487         obj_surface->psb_surface = psb_surface;
    488     }
    489 
    490     /* Error recovery */
    491     if (VA_STATUS_SUCCESS != vaStatus) {
    492         /* surface_list[i-1] was the last successful allocation */
    493         for (; i--;) {
    494             object_surface_p obj_surface = SURFACE(surface_list[i]);
    495             psb__destroy_surface(driver_data, obj_surface);
    496             surface_list[i] = VA_INVALID_SURFACE;
    497         }
    498         drv_debug_msg(VIDEO_DEBUG_ERROR, "CreateSurfaces failed\n");
    499 
    500         return vaStatus;
    501     }
    502 
    503     return vaStatus;
    504 }
    505 
    506 #endif
    507