/* * vmeta_lib.c * * * Copyright (C) 2009 Marvell International Ltd. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "vmeta_lib.h" #include "bmm_lib.h" #include "sys/poll.h" #define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1) #define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) // these APIs are used for vmeta driver only, not for export purpose. #define VMETA_PRIVATE_LOCK_HANDLE "vmeta_private_lock" static SIGN32 vmeta_private_lock(); static SIGN32 vmeta_private_unlock(); static SIGN32 vdec_os_api_get_ks(kernel_share **pp_ks);//get kernel shared resources // global variable static vdec_os_driver_cb_t *vdec_iface = NULL; static UNSG32 globalDbgLevel = VDEC_DEBUG_NONE; static UNSG32 syncTimeout = 500; static pthread_mutex_t pmt = PTHREAD_MUTEX_INITIALIZER; static inline int get_bit(int nr, unsigned int *addr) { unsigned int mask = 1 << nr; return ((*addr) & mask) != 0; } static inline int set_bit(int nr, unsigned int *addr) { unsigned int mask = 1 << nr; unsigned int old; old = *addr; *addr = old | mask; return (old & mask) != 0; } static inline int clear_bit(int nr, unsigned int *addr) { unsigned int mask = 1 << nr; unsigned int old; old = *addr; *addr = old & ~mask; return (old & mask) != 0; } //Add for hal mmap UNSG8 vdec_os_api_rd8(UNSG32 addr) { return *((volatile UNSG8*)addr); } UNSG16 vdec_os_api_rd16(UNSG32 addr) { return *((volatile UNSG16*)addr); } UNSG32 vdec_os_api_rd32(UNSG32 addr) { return *((volatile UNSG32*)addr); } void vdec_os_api_wr8(UNSG32 addr, UNSG8 data) { *((volatile UNSG8*)addr) = data; } void vdec_os_api_wr16(UNSG32 addr, UNSG16 data) { *((volatile UNSG16*)addr) = data; } void vdec_os_api_wr32(UNSG32 addr, UNSG32 data) { *((volatile UNSG32*)addr) = data; } UNSG32 vdec_os_api_get_regbase_addr(void) { vdec_os_driver_cb_t *vdec_iface = vdec_driver_get_cb(); return (UNSG32) vdec_iface->io_mem_virt_addr; } //End of hal mmap //Mem map to bmm_lib UNSG32 vdec_os_api_get_pa(UNSG32 vaddr) { return ((UNSG32)bmm_get_paddr((void *)vaddr)); } UNSG32 vdec_os_api_get_va(UNSG32 paddr) { return ((UNSG32)bmm_get_vaddr((void *)paddr)); } void vdec_os_api_vfree(void *ptr) { unsigned int offset; unsigned int *paddr; paddr = ptr; offset = *(paddr - 1); paddr = (unsigned int *)((unsigned int)paddr - offset); free(paddr); } void *vdec_os_api_vmalloc(UNSG32 size, UNSG32 align) { unsigned int *ptr; unsigned int tmp; align = ALIGN(align, sizeof(int)); size += align; ptr = malloc(size); if (!ptr) { dbg_printf(VDEC_DEBUG_MEM, "vdec_os_api_vmalloc not enough memory \n"); return NULL; } tmp = (unsigned int)((unsigned int)(ptr) & (align - 1)); tmp = (unsigned int)(align - tmp); ptr = (unsigned int *)((unsigned int)ptr + tmp); *(ptr - 1) = tmp; dbg_printf(VDEC_DEBUG_MEM, "vdec_os_api_vmalloc ptr: 0x%x\n", ptr); return ptr; } void vdec_os_api_dma_free(void *ptr) { unsigned int offset; unsigned int *paddr; paddr = ptr; offset = *(paddr - 1); paddr = (unsigned int *)((unsigned int)paddr - offset); bmm_free((void *)paddr); } void * vdec_os_api_dma_alloc(UNSG32 size, UNSG32 align, UNSG32 * pPhysical) { unsigned int *ptr; unsigned int tmp; if(size <= 0) return NULL; dbg_printf(VDEC_DEBUG_MEM, "vdec_os_api_dma_alloc -> size: 0x%x\n", size); align = ALIGN(align, sizeof(int)); size += align; ptr = bmm_malloc(size, BMM_ATTR_NONCACHED); if (!ptr) { dbg_printf(VDEC_DEBUG_MEM, "vdec_os_api_vmalloc not enough memory \n"); return NULL; } tmp = (unsigned int)((unsigned int)(ptr) & (align - 1)); tmp = (unsigned int)(align - tmp); ptr = (unsigned int *)((unsigned int)ptr + tmp); *(ptr - 1) = tmp; *pPhysical = (unsigned long)bmm_get_paddr(ptr); dbg_printf(VDEC_DEBUG_MEM, "vdec_os_api_dma_alloc ptr: 0x%x\n", ptr); return ptr; } void * vdec_os_api_dma_alloc_cached(UNSG32 size, UNSG32 align, UNSG32 * pPhysical) { unsigned int *ptr; unsigned int tmp; if(size <= 0) return NULL; dbg_printf(VDEC_DEBUG_MEM, "vdec_os_api_dma_alloc_cached -> size: 0x%x\n", size); align = ALIGN(align, sizeof(int)); size += align; ptr = bmm_malloc(size, BMM_ATTR_DEFAULT); if (!ptr) { dbg_printf(VDEC_DEBUG_MEM,"\tno enough memory\n"); return NULL; } tmp = (unsigned int)((unsigned int)(ptr) & (align - 1)); tmp = (unsigned int)(align - tmp); ptr = (unsigned int *)((unsigned int)ptr + tmp); *(ptr - 1) = tmp; *pPhysical = (unsigned long)bmm_get_paddr(ptr); dbg_printf(VDEC_DEBUG_MEM, "vdec_os_api_dma_alloc_cached ptr: 0x%x\n", ptr); return ptr; } void * vdec_os_api_dma_alloc_writecombine(UNSG32 size, UNSG32 align, UNSG32 * pPhysical) { unsigned int *ptr; unsigned int tmp; if(size <= 0) return NULL; dbg_printf(VDEC_DEBUG_MEM, "vdec_os_api_dma_alloc_cached -> size: 0x%x\n", size); align = ALIGN(align, sizeof(int)); size += align; ptr = bmm_malloc(size, BMM_ATTR_WRITECOMBINE); if (!ptr) { dbg_printf(VDEC_DEBUG_MEM, "\tno enough memory\n"); return NULL; } tmp = (unsigned int)((unsigned int)(ptr) & (align - 1)); tmp = (unsigned int)(align - tmp); ptr = (unsigned int *)((unsigned int)ptr + tmp); *(ptr - 1) = tmp; *pPhysical = (unsigned long)bmm_get_paddr(ptr); dbg_printf(VDEC_DEBUG_MEM, "vdec_os_api_dma_alloc_writecombine ptr: 0x%x\n", ptr); return ptr; } UNSG32 vdec_os_api_flush_cache(UNSG32 vaddr, UNSG32 size, enum dma_data_direction direction) { int bmm_direction; switch (direction) { case DMA_NONE: default: bmm_direction = BMM_DMA_NONE; break; case DMA_FROM_DEVICE: bmm_direction = BMM_DMA_FROM_DEVICE; break; case DMA_TO_DEVICE: bmm_direction = BMM_DMA_TO_DEVICE; break; case DMA_BIDIRECTIONAL: bmm_direction = BMM_DMA_BIDIRECTIONAL; break; } if (bmm_direction == BMM_DMA_NONE) return 0; if (0 < size) { bmm_flush_cache_range((void *)vaddr, size, bmm_direction); } else { bmm_flush_cache((void *)vaddr, bmm_direction); } return 0; } // enable vmeta interrupt void vdec_os_api_irq_enable(void) { int irq_on = 1; write(vdec_iface->uiofd, &irq_on, sizeof(int)); } // disable vmeta interrupt void vdec_os_api_irq_disable(void) { int irq_on = 0; write(vdec_iface->uiofd, &irq_on, sizeof(int)); } SIGN32 vdec_os_api_set_sync_timeout_isr(UNSG32 timeout) { syncTimeout = timeout; return syncTimeout; } SIGN32 vdec_os_api_sync_event() { struct pollfd ufds; int result = 0; ufds.fd = vdec_iface->uiofd; ufds.events = POLLIN; vdec_os_api_irq_enable(); result = poll(&ufds, 1, syncTimeout); if(result > 0) return VDEC_OS_DRIVER_OK; else return -VDEC_OS_DRIVER_SYNC_TIMEOUT_FAIL; } //End of mem mmap #define VMETA_VERSION_PREFIX "build-" static int get_version(const char *filename) { int ret; int version; FILE *file = fopen(filename, "r"); if(!file) { dbg_printf(VDEC_DEBUG_ALL, "Error: %s -> fopen failed\n", __FUNCTION__); return -1; } ret = fscanf(file, VMETA_VERSION_PREFIX"%d", &version); if(ret<0) { dbg_printf(VDEC_DEBUG_ALL, "Error: get_version -> fscanf failed\n"); version = -1; } fclose(file); return version; } static UNSG32 get_file_unsg32(const char *fmt, ...) { char buf[80]; va_list ap; FILE *file; UNSG32 result; int ret; va_start(ap, fmt); ret = vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); if (ret >= sizeof(buf)) return -VDEC_OS_DRIVER_OPEN_FAIL; file = fopen(buf, "r"); if(!file) { dbg_printf(VDEC_DEBUG_ALL, "Error: %s: fopen %s failed\n", __FUNCTION__, buf); return -VDEC_OS_DRIVER_OPEN_FAIL; } ret = fscanf(file, "0x%x", &result); if (ret != 1) { dbg_printf(VDEC_DEBUG_ALL, "Error: %s: fscanf %s failed\n", __FUNCTION__, buf); result = 0; } fclose(file); return result; } static int uio_get_map(unsigned uio_num, unsigned map, unsigned size, void **rptr, unsigned *rsize, UNSG32 *rphys) { UNSG32 phys; UNSG32 map_size; void *addr; map_size = get_file_unsg32("/sys/class/uio/uio%u/maps/map%u/size", uio_num, map); if (map_size == (UNSG32)-VDEC_OS_DRIVER_OPEN_FAIL) return -VDEC_OS_DRIVER_OPEN_FAIL; if (map_size == 0) return -VDEC_OS_DRIVER_MMAP_FAIL; if (size && map_size < size) { dbg_printf(VDEC_DEBUG_MEM, "Error: %s: requested mmap of %u bytes but map %u only has %u bytes available\n", __FUNCTION__, size, map, map_size); return -VDEC_OS_DRIVER_MMAP_FAIL; } if (rsize) *rsize = map_size; if (rphys) { phys = get_file_unsg32("/sys/class/uio/uio%u/maps/map%u/addr", uio_num, map); if (phys == (UNSG32)-VDEC_OS_DRIVER_OPEN_FAIL) return -VDEC_OS_DRIVER_OPEN_FAIL; if (phys == 0) return -VDEC_OS_DRIVER_MMAP_FAIL; *rphys = phys; } if (rptr) { if (size == 0) size = map_size; addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, vdec_iface->uiofd, map * getpagesize()); if (addr == MAP_FAILED) { dbg_printf(VDEC_DEBUG_MEM, "Error: %s: mmap of map %u failed: %d\n", __FUNCTION__, map, errno); return -VDEC_OS_DRIVER_MMAP_FAIL; } *rptr = addr; } return VDEC_OS_DRIVER_OK; } // init vdec os driver SIGN32 vdec_os_driver_init(void) { unsigned size; void *addr; UNSG32 phys; int ret = 0; #if VMETA_LOG_ON FILE *fp_log; #endif pthread_mutex_lock(&pmt); if(vdec_iface != NULL) { // already been initiated in this process vdec_iface->refcount++; pthread_mutex_unlock(&pmt); return ret; } #if (VMETA_LOG_ON && 0) fp_log = fopen(VMETA_LOG_FILE,"w"); if(fp_log == NULL) { pthread_mutex_unlock(&pmt); return -1; } fclose(fp_log); #endif // Prepare the vdec os driver control interface vdec_iface = malloc(sizeof(vdec_os_driver_cb_t)); if(vdec_iface == NULL) { pthread_mutex_unlock(&pmt); return -VDEC_OS_DRIVER_INIT_FAIL; } memset(vdec_iface, 0, sizeof(vdec_os_driver_cb_t)); // initialize reference count vdec_iface->refcount++; // Open the vdec uio driver vdec_iface->uiofd = open(UIO_DEV, O_RDWR); if(vdec_iface->uiofd < 0) { ret = -VDEC_OS_DRIVER_OPEN_FAIL; goto err_open_fail; } dbg_printf(VDEC_DEBUG_ALL, "vdec os driver open: %s uiofd=%d\n", UIO_DEV,vdec_iface->uiofd); vdec_iface->kern_ver = get_version(UIO_IO_VERSION); if(vdec_iface->kern_ver < VMETA_KERN_MIN_VER) { ret = -VDEC_OS_DRIVER_VER_FAIL; goto err_open_fail; } dbg_printf(VDEC_DEBUG_VER, "vdec os driver kern=%d user=%s\n", vdec_iface->kern_ver,VMETA_USER_VER); // Get the IO mem phy addr and size of vPro's register ret = uio_get_map(0, UIO_IO_MEM_INDEX, 0, &addr, &size, &phys); if (ret < 0) goto err_mmap_fail; dbg_printf(VDEC_DEBUG_MEM, "vdec os driver io mem size: 0x%x, phy addr 0x%x, virt 0x%p\n", size, phys, addr); vdec_iface->io_mem_phy_addr = phys; vdec_iface->io_mem_size = size; vdec_iface->io_mem_virt_addr = addr; pthread_mutex_unlock(&pmt); return ret; err_mmap_fail: if(vdec_iface->io_mem_virt_addr > 0) munmap(vdec_iface->io_mem_virt_addr, vdec_iface->io_mem_size); close(vdec_iface->uiofd); err_open_fail: free(vdec_iface); vdec_iface = NULL; pthread_mutex_unlock(&pmt); return ret; } // clean vdec os driver SIGN32 vdec_os_driver_clean(void) { pthread_mutex_lock(&pmt); if(vdec_iface == NULL){ pthread_mutex_unlock(&pmt); return -VDEC_OS_DRIVER_CLEAN_FAIL; } // decrease the refcount vdec_iface->refcount--; if(vdec_iface->refcount != 0) { dbg_printf(VDEC_DEBUG_ALL, "refcount = %d\n", vdec_iface->refcount); pthread_mutex_unlock(&pmt); return 0; } // close clock and power if(vdec_os_api_get_user_count() <=0) { vdec_os_api_clock_off(); vdec_os_api_power_off(); dbg_printf(VDEC_DEBUG_ALL, "close vmeta power and clock in case app doesn't close\n"); } // unmap memory area if(vdec_iface->io_mem_virt_addr != NULL) { dbg_printf(VDEC_DEBUG_MEM, "munmap with io_mem_virt_addr = 0x%x\n", vdec_iface->io_mem_virt_addr); munmap(vdec_iface->io_mem_virt_addr, vdec_iface->io_mem_size); vdec_iface->io_mem_virt_addr = NULL; vdec_iface->io_mem_size = 0; } if(vdec_iface->kernel_share_va != NULL) { dbg_printf(VDEC_DEBUG_MEM, "munmap with kernel_share_va = 0x%p size=%d\n", vdec_iface->kernel_share_va,vdec_iface->kernel_share_size); munmap(vdec_iface->kernel_share_va, vdec_iface->kernel_share_size); vdec_iface->kernel_share_va = NULL; vdec_iface->kernel_share_size = 0; } if(vdec_iface->vdec_obj_va != NULL) { dbg_printf(VDEC_DEBUG_MEM, "munmap with vdec_obj_va = 0x%x size=%d\n", vdec_iface->vdec_obj_va, vdec_iface->vdec_obj_size); munmap(vdec_iface->vdec_obj_va,vdec_iface->vdec_obj_size ); vdec_iface->vdec_obj_va = NULL; vdec_iface->vdec_obj_size = 0; } // close fd if(vdec_iface->uiofd > 0) { close(vdec_iface->uiofd); dbg_printf(VDEC_DEBUG_ALL, "uio close\n"); } // free vdec_iface if(vdec_iface != NULL) { free(vdec_iface); dbg_printf(VDEC_DEBUG_ALL, "free vdec_iface\n"); vdec_iface = NULL; } dbg_printf(VDEC_DEBUG_ALL, "vmeta clean done\n"); pthread_mutex_unlock(&pmt); return 0; } /* display debug message */ static int dbg_printf(UNSG32 dbglevel, const char* format, ...) { char dbgBuf[256] = {'\0'}; va_list var; #if VMETA_LOG_ON FILE *fp_log = fopen(VMETA_LOG_FILE,"a+"); if(fp_log == NULL) { return -1; } #endif if(VDEC_DEBUG_NONE == globalDbgLevel) goto DBG_EXIT; else { va_start(var, format); vsprintf(dbgBuf, format, var); va_end(var); if(VDEC_DEBUG_ALL & globalDbgLevel) goto DBG_PRINT; else if((VDEC_DEBUG_MEM & globalDbgLevel) && (dbglevel == VDEC_DEBUG_MEM)) goto DBG_PRINT; else if((VDEC_DEBUG_LOCK & globalDbgLevel) && (dbglevel == VDEC_DEBUG_LOCK)) goto DBG_PRINT; else if((VDEC_DEBUG_VER & globalDbgLevel) && (dbglevel == VDEC_DEBUG_VER)) goto DBG_PRINT; else goto DBG_EXIT; } DBG_PRINT: #if VMETA_LOG_ON fprintf(fp_log,dbgBuf); #else printf("%s", dbgBuf); #endif DBG_EXIT: #if VMETA_LOG_ON fclose(fp_log); #endif return 0; } /* vdec driver get cb */ vdec_os_driver_cb_t *vdec_driver_get_cb(void) { return vdec_iface; } SIGN32 vdec_os_api_get_hw_obj_addr(UNSG32* vaddr,UNSG32 size) { void *addr; int ret; if(vdec_iface->vdec_obj_va != NULL) { dbg_printf(VDEC_DEBUG_MEM, "Already get vdec obj\n"); *vaddr = (UNSG32)vdec_iface->vdec_obj_va; return VDEC_OS_DRIVER_OK; } ret = uio_get_map(0, UIO_IO_VMETA_OBJ_INDEX, size, &addr, NULL, NULL); if (ret < 0) goto get_vdec_obj_fail; dbg_printf(VDEC_DEBUG_MEM, "UIO_IO_VMETA_OBJ virtual 0x%p size=%d\n", addr, size); *vaddr = (UNSG32)addr; vdec_iface->vdec_obj_va = addr; vdec_iface->vdec_obj_size = size; get_vdec_obj_fail: return ret; } SIGN32 vdec_os_api_get_hw_context_addr(UNSG32* paddr, UNSG32* vaddr, UNSG32 size, SIGN32 flag) { UNSG32 phys; int ret; if(vdec_iface->hw_context_pa != 0) { dbg_printf(VDEC_DEBUG_MEM, "Already get hw context\n"); *paddr = vdec_iface->hw_context_pa; return VDEC_OS_DRIVER_OK; } ret = uio_get_map(0, UIO_IO_HW_CONTEXT_INDEX, size, NULL, NULL, &phys); if (ret < 0) goto get_hw_context_fail; *paddr = phys; vdec_iface->hw_context_pa = phys; dbg_printf(VDEC_DEBUG_MEM, "UIO_IO_HW_CONTEXT: 0x%08x\n", *paddr); get_hw_context_fail: return ret; } SIGN32 vdec_os_api_get_ks(kernel_share** pp_ks) { unsigned size; void *addr; int ret; if(vdec_iface->kernel_share_va != NULL) { dbg_printf(VDEC_DEBUG_MEM, "Already get kernel share\n"); return 0; } ret = uio_get_map(0, UIO_IO_KERNEL_SHARE_INDEX, 0, &addr, &size, NULL); if (ret < 0) goto get_vos_fail; dbg_printf(VDEC_DEBUG_MEM, "kernel share virtual address: 0x%p size=%d \n", addr, size); *pp_ks = addr; vdec_iface->kernel_share_va = addr; vdec_iface->kernel_share_size = size; get_vos_fail: return ret; } static int find_user_id(id_instance *list)//return unoccupied id { int i; for(i=0; ikernel_share_va == NULL) { vdec_os_api_get_ks(&p_ks); } else { p_ks = p_cb->kernel_share_va; } vmeta_private_lock(); memset(p_ks, 0, sizeof(kernel_share)); p_ks->active_user_id = MAX_VMETA_INSTANCE; vmeta_private_unlock(); ioctl(vdec_iface->uiofd,VMETA_CMD_UNLOCK); return 0; } SIGN32 vdec_os_api_get_user_id(void) { kernel_share *p_ks; SIGN32 ret = -1; vdec_os_driver_cb_t *p_cb = vdec_driver_get_cb(); if(p_cb->kernel_share_va == NULL) { vdec_os_api_get_ks(&p_ks); } else { p_ks = p_cb->kernel_share_va; } vmeta_private_lock(); ret = find_user_id(p_ks->user_id_list); if( ret < 0) { dbg_printf(VDEC_DEBUG_ALL, "vdec_os_api_get_user_id: find_user_id error\n"); } vmeta_private_unlock(); return ret; } SIGN32 vdec_os_api_free_user_id(SIGN32 user_id) { kernel_share *p_ks; vdec_os_driver_cb_t *p_cb = vdec_driver_get_cb(); if(p_cb->kernel_share_va == NULL) { dbg_printf(VDEC_DEBUG_ALL,"vdec_os_api_free_user_id error: not init yet\n"); return VDEC_OS_DRIVER_USER_ID_FAIL; } if(user_id >= MAX_VMETA_INSTANCE || user_id < 0) { dbg_printf(VDEC_DEBUG_ALL,"vdec_os_api_free_user_id error: exceeds max user_id\n"); return VDEC_OS_DRIVER_USER_ID_FAIL; } p_ks = p_cb->kernel_share_va; vmeta_private_lock(); clear_bit(VMETA_STATUS_BIT_REGISTED,&(p_ks->user_id_list[user_id].status)); clear_bit(VMETA_STATUS_BIT_USED,&(p_ks->user_id_list[user_id].status)); vmeta_private_unlock(); return VDEC_OS_DRIVER_OK; } static void *vmeta_thread_monitor(void *_data) { struct monitor_data *pmd = _data; kernel_share *p_ks; vdec_os_driver_cb_t *p_cb = vdec_driver_get_cb(); pthread_attr_t pat; int detach_attr; struct monitor_data *p_md = NULL; pthread_mutex_lock(&pmt); if(p_cb->kernel_share_va == NULL || pmd == NULL) { dbg_printf(VDEC_DEBUG_ALL,"vdec_os_api_free_user_id error: not init yet\n"); free(pmd); pthread_detach(pthread_self()); pthread_mutex_unlock(&pmt); return (void *)-1; } p_md = malloc(sizeof(struct monitor_data)); if(p_md == NULL) { free(pmd); pthread_detach(pthread_self()); pthread_mutex_unlock(&pmt); return (void *)-1; } memcpy(p_md,pmd,sizeof(struct monitor_data)); dbg_printf(VDEC_DEBUG_LOCK,"ori 0x%x 0x%x pt=0x%x user_id=0x%x \n",pmd->pt, pmd->user_id, p_md->pt,p_md->user_id); p_ks = p_cb->kernel_share_va; if(pthread_getattr_np(p_md->pt,&pat) != 0) { dbg_printf(VDEC_DEBUG_LOCK,"get thread attr failed \n"); goto tag_monitor_fail; } if( pthread_attr_getdetachstate(&pat,&detach_attr) != 0) { dbg_printf(VDEC_DEBUG_LOCK,"get detach attr failed \n"); goto tag_monitor_fail; } if( detach_attr == PTHREAD_CREATE_DETACHED) { dbg_printf(VDEC_DEBUG_LOCK,"The thread is a detached thread, cannot join \nexit monitor! \n"); goto tag_monitor_fail; } dbg_printf(VDEC_DEBUG_LOCK,"wait for pt=0x%x \n",p_md->pt); pthread_mutex_unlock(&pmt); pthread_join(p_md->pt,NULL); dbg_printf(VDEC_DEBUG_LOCK,"pt=0x%x is killed user_id(%d)\n",p_md->pt,p_md->user_id); pthread_mutex_lock(&pmt); p_cb = vdec_driver_get_cb(); if(p_cb) { if(p_cb->kernel_share_va) { p_ks = p_cb->kernel_share_va; if(p_md->user_id==p_ks->active_user_id) { dbg_printf(VDEC_DEBUG_LOCK,"vmeta thread exit abnormally, instance id=%d lock flag=%d\n",p_md->user_id,p_ks->lock_flag); if( p_ks->lock_flag==VMETA_LOCK_ON ) { vdec_os_api_unlock(p_md->user_id); p_ks->lock_flag = VMETA_LOCK_FORCE_INIT; } p_ks->active_user_id = MAX_VMETA_INSTANCE; } if(p_ks->user_id_list[p_md->user_id].status != 0) { dbg_printf(VDEC_DEBUG_LOCK,"vmeta thread exit abnormally, clear instance(%d)\n",p_md->user_id); memset(&(p_ks->user_id_list[p_md->user_id]),0x0,sizeof(id_instance)); p_ks->ref_count--; } } } free(p_md); free(pmd); pthread_attr_destroy(&pat); dbg_printf(VDEC_DEBUG_MEM,"thread monitor exit\n"); pthread_detach(pthread_self()); pthread_mutex_unlock(&pmt); return NULL; tag_monitor_fail: pthread_mutex_unlock(&pmt); free(p_md); free(pmd); pthread_detach(pthread_self()); pthread_attr_destroy(&pat); return (void *)-1; } SIGN32 vdec_os_api_register_user_id(SIGN32 user_id) { kernel_share *p_ks; vdec_os_driver_cb_t *p_cb = vdec_driver_get_cb(); pthread_t tmp; struct monitor_data *p_md; if(user_id>=MAX_VMETA_INSTANCE || user_id<0) { dbg_printf(VDEC_DEBUG_ALL,"vdec_os_api_register_user_id error: exceeds max user_id\n"); return VDEC_OS_DRIVER_USER_ID_FAIL; } if(p_cb->kernel_share_va == NULL) { vdec_os_api_get_ks(&p_ks); } else { p_ks = p_cb->kernel_share_va; } if(set_bit(VMETA_STATUS_BIT_REGISTED, &(p_ks->user_id_list[user_id].status)) == 1) { dbg_printf(VDEC_DEBUG_ALL, "vdec_os_api_register_user_id error: user id has already been registered\n"); return VDEC_OS_DRIVER_USER_ID_FAIL; } p_md = malloc(sizeof(struct monitor_data));//This is freed monitor function if(p_md == NULL) { dbg_printf(VDEC_DEBUG_ALL,"vdec_os_api_register_user_id error: OOM\n"); return VDEC_OS_DRIVER_USER_ID_FAIL; } p_ks->ref_count++; p_ks->user_id_list[user_id].pid = getpid(); p_md->pt = pthread_self(); p_ks->user_id_list[user_id].pt = (unsigned int) p_md->pt; p_md->user_id = user_id; pthread_create(&tmp,NULL,vmeta_thread_monitor,p_md); dbg_printf(VDEC_DEBUG_LOCK,"pid=%x,pt=0x%x are monitored user_id(%d)\n",p_ks->user_id_list[user_id].pid,p_ks->user_id_list[user_id].pt,user_id); return VDEC_OS_DRIVER_OK; } SIGN32 vdec_os_api_unregister_user_id(SIGN32 user_id) { kernel_share *p_ks; vdec_os_driver_cb_t *p_cb = vdec_driver_get_cb(); if(user_id>=MAX_VMETA_INSTANCE || user_id<0) { dbg_printf(VDEC_DEBUG_ALL,"vdec_os_api_unregister_user_id error: exceeds max user_id\n"); return VDEC_OS_DRIVER_USER_ID_FAIL; } if(p_cb->kernel_share_va == NULL) { dbg_printf(VDEC_DEBUG_ALL,"vdec_os_api_unregister_user_id error: not init yet\n"); return VDEC_OS_DRIVER_USER_ID_FAIL; } else { p_ks = p_cb->kernel_share_va; } if(clear_bit(VMETA_STATUS_BIT_REGISTED,&(p_ks->user_id_list[user_id].status)) == 0) { dbg_printf(VDEC_DEBUG_ALL,"vdec_os_api_unregister_user_id error: user id[%d] has not been registered\n",user_id); return VDEC_OS_DRIVER_USER_ID_FAIL; } p_ks->ref_count--; return VDEC_OS_DRIVER_OK; } static SIGN32 vmeta_private_lock() { ioctl(vdec_iface->uiofd,VMETA_CMD_PRIV_LOCK,(unsigned long)0xffffffff); return 0; } static SIGN32 vmeta_private_unlock() { ioctl(vdec_iface->uiofd,VMETA_CMD_PRIV_UNLOCK); return 0; } SIGN32 vdec_os_api_get_user_count(void) { vdec_os_driver_cb_t *p_cb = vdec_driver_get_cb(); kernel_share *p_ks; if(p_cb == NULL) { dbg_printf(VDEC_DEBUG_ALL,"vdec_os_api_get_user_count error: point is NULL\n"); return -1; } if(p_cb->kernel_share_va == NULL) { vdec_os_api_get_ks(&p_ks); } else { p_ks = p_cb->kernel_share_va; } dbg_printf(VDEC_DEBUG_ALL, "get_user_count=%d \n",p_ks->ref_count); return p_ks->ref_count; } SIGN32 vdec_os_api_lock(SIGN32 user_id, long to_ms) { vdec_os_driver_cb_t *p_cb = vdec_driver_get_cb(); kernel_share* p_ks; SIGN32 ret; if(p_cb == NULL) { dbg_printf(VDEC_DEBUG_ALL,"vdec_os_api_lock error: point is NULL\n"); return LOCK_RET_ERROR_UNKNOWN; } p_ks = p_cb->kernel_share_va; if(p_ks->active_user_id == user_id) { dbg_printf(VDEC_DEBUG_LOCK,"lock same user=%d, lock_flag=%d,ref_count=%d\n",\ user_id,p_ks->lock_flag,p_ks->ref_count); return LOCK_RET_ME;//just return since they are the same caller } ret = ioctl(vdec_iface->uiofd,VMETA_CMD_LOCK,(unsigned long)to_ms); if(ret!=0) { dbg_printf(VDEC_DEBUG_LOCK, "lock timeout \n"); return LOCK_RET_ERROR_TIMEOUT; } vmeta_private_lock(); p_ks->active_user_id = user_id; if(p_ks->lock_flag == VMETA_LOCK_FORCE_INIT){ p_ks->lock_flag = VMETA_LOCK_ON; vmeta_private_unlock(); return LOCK_RET_FORCE_INIT; } p_ks->lock_flag = VMETA_LOCK_ON; vmeta_private_unlock(); return LOCK_RET_OHTERS_NORM; } SIGN32 vdec_os_api_unlock(SIGN32 user_id) { vdec_os_driver_cb_t *p_cb = vdec_driver_get_cb(); kernel_share* p_ks; int ret; if(p_cb == NULL) { dbg_printf(VDEC_DEBUG_LOCK,"vdec_os_api_unlock error: point is NULL\n"); return LOCK_RET_ERROR_UNKNOWN; } p_ks = p_cb->kernel_share_va; vmeta_private_lock(); if(p_ks->active_user_id == user_id) { p_ks->active_user_id = MAX_VMETA_INSTANCE; p_ks->lock_flag = VMETA_LOCK_OFF; } else { dbg_printf(VDEC_DEBUG_LOCK,"vdec_os_api_unlock error: unlock other user id %d; active_user_id is %d\n", user_id, p_ks->active_user_id); vmeta_private_unlock(); return LOCK_RET_ERROR_UNKNOWN; } vmeta_private_unlock(); ret = ioctl(vdec_iface->uiofd,VMETA_CMD_UNLOCK); dbg_printf(VDEC_DEBUG_LOCK, "ID: %d after unlock\n", user_id); if(ret != 0) { dbg_printf(VDEC_DEBUG_LOCK,"vdec_os_api_unlock ioctl error\n"); return LOCK_RET_ERROR_UNKNOWN; } return LOCK_RET_OHTERS_NORM; } SIGN32 vdec_os_api_power_on(void) { SIGN32 ret = 0; if(vdec_iface == NULL) { return -1; } ret = ioctl(vdec_iface->uiofd,VMETA_CMD_POWER_ON); return ret; } SIGN32 vdec_os_api_power_off(void) { SIGN32 ret = 0; if(vdec_iface == NULL) { return -1; } ret = ioctl(vdec_iface->uiofd,VMETA_CMD_POWER_OFF); return ret; } SIGN32 vdec_os_api_clock_on(void) { SIGN32 ret = 0; if(vdec_iface == NULL) { return -1; } ret = ioctl(vdec_iface->uiofd,VMETA_CMD_CLK_ON); return ret; } SIGN32 vdec_os_api_clock_off(void) { SIGN32 ret = 0; if(vdec_iface == NULL) { return -1; } ret = ioctl(vdec_iface->uiofd,VMETA_CMD_CLK_OFF); return ret; } SIGN32 vdec_os_api_clock_switch(VMETA_CLOCK_OP vco) { SIGN32 ret = 0; if(vdec_iface == NULL) { return -1; } ret = ioctl(vdec_iface->uiofd,VMETA_CMD_CLK_SWITCH,(unsigned long)vco); return ret; } SIGN32 vdec_os_driver_version(SIGN8 *ver_str) { vdec_os_driver_cb_t *p_cb = vdec_driver_get_cb(); if(p_cb==NULL || ver_str==NULL) { dbg_printf(VDEC_DEBUG_VER,"vdec_os_driver_version error: point is NULL\n"); return -VDEC_OS_DRIVER_VER_FAIL; } //ver_str = (UNSG8 *)VMETA_USER_VER; strcpy(ver_str,VMETA_USER_VER); dbg_printf(VDEC_DEBUG_VER, "vmeta user lib ver=%s\n", ver_str); return VDEC_OS_DRIVER_OK; } // check VMeta is ready to suspend SIGN32 vdec_os_api_suspend_check(void) { SIGN32 suspend_check; if(vdec_iface == NULL) return 0; ioctl(vdec_iface->uiofd, VMETA_CMD_SUSPEND_CHECK, &suspend_check); return suspend_check; } // VMeta is ready to suspend SIGN32 vdec_os_api_suspend_ready(void) { if(vdec_iface == NULL) return 0; ioctl(vdec_iface->uiofd, VMETA_CMD_SUSPEND_READY); return 0; }