From 9014dc8b10cda10477cfae228979b12f2fa92132 Mon Sep 17 00:00:00 2001 From: Joseph Lo Date: Tue, 26 Oct 2010 12:12:56 +0800 Subject: update libvmeta to "build-004" version --- uio_vmeta.h | 56 ++++ vmeta_lib.c | 856 ++++++++++++++++++++++++++++++++++++++++++++++++++---------- vmeta_lib.h | 105 ++++++-- 3 files changed, 851 insertions(+), 166 deletions(-) create mode 100755 uio_vmeta.h diff --git a/uio_vmeta.h b/uio_vmeta.h new file mode 100755 index 0000000..bab40dd --- /dev/null +++ b/uio_vmeta.h @@ -0,0 +1,56 @@ +/* + * This software program is licensed subject to the GNU General Public License + * (GPL).Version 2,June 1991, available at http://www.fsf.org/copyleft/gpl.html + + * (C) Copyright 2010 Marvell International Ltd. + * All Rights Reserved + */ + +#ifndef __UIO_VMETA_H +#define __UIO_VMETA_H + +typedef unsigned int vmeta_instance_status; +typedef struct _id_instance +{ + vmeta_instance_status status; + int height; + int width; + int frame_rate; + pid_t pid; + unsigned int pt;//pthread_t +}id_instance; + +#define MAX_VMETA_INSTANCE 32 + +typedef enum _VMETA_LOCK_FLAG{ + VMETA_LOCK_OFF = 0, + VMETA_LOCK_ON, + VMETA_LOCK_FORCE_INIT +}VMETA_LOCK_FLAG; + +/* This struct should be aligned with user space API */ +typedef struct _kernel_share +{ + int ref_count; + VMETA_LOCK_FLAG lock_flag; + int active_user_id; + id_instance user_id_list[MAX_VMETA_INSTANCE]; +}kernel_share; + +#define IOP_MAGIC 'v' + +#define VMETA_CMD_POWER_ON _IO(IOP_MAGIC, 0) +#define VMETA_CMD_POWER_OFF _IO(IOP_MAGIC, 1) +#define VMETA_CMD_CLK_ON _IO(IOP_MAGIC, 2) +#define VMETA_CMD_CLK_OFF _IO(IOP_MAGIC, 3) +#define VMETA_CMD_CLK_SWITCH _IO(IOP_MAGIC, 4) +#define VMETA_CMD_LOCK _IO(IOP_MAGIC, 5) +#define VMETA_CMD_UNLOCK _IO(IOP_MAGIC, 6) +#define VMETA_CMD_PRIV_LOCK _IO(IOP_MAGIC, 7) +#define VMETA_CMD_PRIV_UNLOCK _IO(IOP_MAGIC, 8) +#define VMETA_CMD_SUSPEND_CHECK _IOR(IOP_MAGIC, 9, int) +#define VMETA_CMD_SUSPEND_READY _IO(IOP_MAGIC, 10) +#define VMETA_CMD_SUSPEND_SET _IO(IOP_MAGIC, 11) +#define VMETA_CMD_SUSPEND_UNSET _IO(IOP_MAGIC, 12) + +#endif /* __UIO_VMETA_H */ diff --git a/vmeta_lib.c b/vmeta_lib.c index 15b3820..023a128 100755 --- a/vmeta_lib.c +++ b/vmeta_lib.c @@ -29,19 +29,58 @@ #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 vdec_os_driver_cb_t *vdec_iface = NULL; UNSG32 globalDbgLevel = VDEC_DEBUG_NONE; -struct timeval vdec_timer; +UNSG32 syncTimeout = 500; + +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) @@ -167,80 +206,91 @@ void * vdec_os_api_dma_alloc(UNSG32 size, UNSG32 align, UNSG32 * pPhysical) return ptr; } -void * vdec_os_api_dma_alloc_writecombine(UNSG32 size, UNSG32 align, UNSG32 * pPhysical) +void * vdec_os_api_dma_alloc_cached(UNSG32 size, UNSG32 align, UNSG32 * pPhysical) { - unsigned int *ptr = NULL; - unsigned int tmp = 0; + unsigned int *ptr = NULL; + unsigned int tmp = 0; - if(size <= 0) - return NULL; + if(size <= 0) + return NULL; - dbg_printf(VDEC_DEBUG_MEM, "vdec_os_api_dma_alloc -> size: 0x%x\n", size); + 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) { - printf("\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 ptr: 0x%x\n", ptr); - //memset(ptr, 0, size); - - return ptr; + size += align; + ptr = bmm_malloc(size, BMM_ATTR_DEFAULT); + if (!ptr) { + printf("\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); + //memset(ptr, 0, size); + return ptr; } -void * vdec_os_api_dma_alloc_cached(UNSG32 size, UNSG32 align, UNSG32 * pPhysical) +void * vdec_os_api_dma_alloc_writecombine(UNSG32 size, UNSG32 align, UNSG32 * pPhysical) { - unsigned int *ptr = NULL; - unsigned int tmp = 0; + unsigned int *ptr = NULL; + unsigned int tmp = 0; - if(size <= 0) - return NULL; + if(size <= 0) + return NULL; - dbg_printf(VDEC_DEBUG_MEM, "vdec_os_api_dma_alloc -> size: 0x%x\n", size); + 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) { - printf("\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 ptr: 0x%x\n", ptr); - //memset(ptr, 0, size); - - return ptr; + size += align; + ptr = bmm_malloc(size, BMM_ATTR_WRITECOMBINE); + if (!ptr) { + printf("\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); + //memset(ptr, 0, size); + return ptr; } UNSG32 vdec_os_api_flush_cache(UNSG32 vaddr, UNSG32 size, enum dma_data_direction direction) { - switch (direction) { - case DMA_FROM_DEVICE: - bmm_flush_cache_range((void *)vaddr, size, BMM_DMA_FROM_DEVICE); - break; - case DMA_TO_DEVICE: - bmm_flush_cache_range((void *)vaddr, size, BMM_DMA_TO_DEVICE); - break; - case DMA_BIDIRECTIONAL: - bmm_flush_cache_range((void *)vaddr, size, BMM_DMA_BIDIRECTIONAL); - break; + if (0 < size) { + switch (direction) { + case DMA_FROM_DEVICE: + bmm_flush_cache_range((void *)vaddr, size, BMM_DMA_FROM_DEVICE); + break; + case DMA_TO_DEVICE: + bmm_flush_cache_range((void *)vaddr, size, BMM_DMA_TO_DEVICE); + break; + case DMA_BIDIRECTIONAL: + bmm_flush_cache_range((void *)vaddr, size, BMM_DMA_BIDIRECTIONAL); + break; + } + } else { + switch (direction) { + case DMA_FROM_DEVICE: + bmm_flush_cache((void *)vaddr, BMM_DMA_FROM_DEVICE); + break; + case DMA_TO_DEVICE: + bmm_flush_cache((void *)vaddr, BMM_DMA_TO_DEVICE); + break; + case DMA_BIDIRECTIONAL: + bmm_flush_cache((void *)vaddr, BMM_DMA_BIDIRECTIONAL); + break; + } } return 0; } @@ -248,69 +298,62 @@ UNSG32 vdec_os_api_flush_cache(UNSG32 vaddr, UNSG32 size, enum dma_data_directio // enable vmeta interrupt void vdec_os_api_irq_enable(void) { - if(vdec_iface == NULL) - return; - - ioctl(vdec_iface->uiofd, UIO_VPRO_IRQ_ENABLE); + int irq_on = 1; + write(vdec_iface->uiofd, &irq_on, sizeof(int)); } // disable vmeta interrupt void vdec_os_api_irq_disable(void) { - if(vdec_iface == NULL) - return; - - ioctl(vdec_iface->uiofd, UIO_VPRO_IRQ_DISABLE); + int irq_on = 0; + write(vdec_iface->uiofd, &irq_on, sizeof(int)); } SIGN32 vdec_os_api_set_sync_timeout_isr(UNSG32 timeout) { - vdec_timer.tv_sec = 0; - vdec_timer.tv_usec = timeout * 1000; - - return 0; + syncTimeout = timeout; + return syncTimeout; } SIGN32 vdec_os_api_sync_event() { - SIGN32 ret = VDEC_OS_DRIVER_OK; - fd_set rd_fds, tmp_fds; - struct timeval timeout; - - if(vdec_iface == NULL) + 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-" - FD_ZERO(&rd_fds); - FD_SET(vdec_iface->uiofd, &rd_fds); - - timeout.tv_sec = vdec_timer.tv_sec; - timeout.tv_usec = vdec_timer.tv_usec; - - while(1) { - int ret = 0; - - tmp_fds = rd_fds; +int get_version(char *msg) +{ + int ret; + int version; - // enable interrupt - vdec_os_api_irq_enable(); + FILE *file = fopen(msg, "r"); - ret = select(vdec_iface->uiofd + 1, &tmp_fds, NULL, NULL, &timeout); - if(FD_ISSET(vdec_iface->uiofd, &tmp_fds)) { - int irq_num; - read(vdec_iface->uiofd, &irq_num, sizeof(int)); - // Or handle userspace ISR here - break; - } - - // timeout - ret = -VDEC_OS_DRIVER_SYNC_TIMEOUT_FAIL; + if(!file) { + dbg_printf(VDEC_DEBUG_ALL, "Error: get_mem_size -> fopen failed\n"); + return -1; + } - break; + ret = fscanf(file, VMETA_VERSION_PREFIX"%d", &version); + if(ret<0) { + dbg_printf(VDEC_DEBUG_ALL, "Error: get_version -> fscanf failed\n"); + version = -1; } - - return ret; + + fclose(file); + return version; } -//End of mem mmap UNSG32 get_mem_size(char *msg) { @@ -354,48 +397,13 @@ UNSG32 get_mem_addr(char *msg) return result; } -// VMeta power on -void vdec_os_api_power_on(void) { - if(vdec_iface == NULL) - return; - - ioctl(vdec_iface->uiofd, UIO_VMETA_POWER_ON); - } - -// VMeta power off -void vdec_os_api_power_off(void) { - if(vdec_iface == NULL) - return; - - ioctl(vdec_iface->uiofd, UIO_VMETA_POWER_OFF); -} - -// 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, UIO_VMETA_SUSPEND_CHECK, &suspend_check); - - return suspend_check; -} - -// VMeta is ready to suspend -void vdec_os_api_suspend_ready(void) { - if(vdec_iface == NULL) - return; - - ioctl(vdec_iface->uiofd, UIO_VMETA_SUSPEND_READY); -} - // init vdec os driver SIGN32 vdec_os_driver_init(void) { int ret = 0; + int rv; - if(vdec_iface != NULL) { // already been initiated + if(vdec_iface != NULL) { // already been initiated in this process vdec_iface->refcount++; return ret; } @@ -417,6 +425,13 @@ SIGN32 vdec_os_driver_init(void) } dbg_printf(VDEC_DEBUG_ALL, "vdec os driver open: %s\n", UIO_DEV); + 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 size of vPro's register vdec_iface->io_mem_size = get_mem_size(UIO_IO_MEM_SIZE); if(vdec_iface->io_mem_size <= 0) { @@ -465,23 +480,31 @@ SIGN32 vdec_os_driver_clean(void) // decrease the refcount vdec_iface->refcount--; - if(vdec_iface->refcount != 0) + if(vdec_iface->refcount != 0) { + dbg_printf(VDEC_DEBUG_ALL, "refcount = %d\n", vdec_iface->refcount); return 0; + } // unmap memory area - if(vdec_iface->io_mem_virt_addr > 0) + if(vdec_iface->io_mem_virt_addr > 0) { munmap((void*)vdec_iface->io_mem_virt_addr, vdec_iface->io_mem_size); + dbg_printf(VDEC_DEBUG_MEM, "munmap with io_mem_virt_addr = 0x%x\n", vdec_iface->io_mem_virt_addr); + } // close fd - if(vdec_iface->uiofd > 0) + 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((void*)vdec_iface); + dbg_printf(VDEC_DEBUG_ALL, "free vdec_iface\n"); vdec_iface = NULL; } + dbg_printf(VDEC_DEBUG_ALL, "vmeta clean done\n"); return 0; } @@ -501,6 +524,10 @@ int dbg_printf(UNSG32 dbglevel, const char* format, ...) { printf(dbgBuf); else if((VDEC_DEBUG_MEM & globalDbgLevel) && (dbglevel == VDEC_DEBUG_MEM)) printf(dbgBuf); + else if((VDEC_DEBUG_LOCK & globalDbgLevel) && (dbglevel == VDEC_DEBUG_LOCK)) + printf(dbgBuf); + else if((VDEC_DEBUG_VER & globalDbgLevel) && (dbglevel == VDEC_DEBUG_VER)) + printf(dbgBuf); else return 0; } @@ -512,3 +539,546 @@ int dbg_printf(UNSG32 dbglevel, const char* format, ...) { 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) +{ + UNSG32 io_mem_size; + UNSG32 io_mem_addr; + UNSG32 io_mem_virt_addr; + UNSG32 ret = VDEC_OS_DRIVER_OK; + + if(vdec_iface->vdec_obj_va != 0) + { + dbg_printf(VDEC_DEBUG_MEM, "Already get vdec obj\n"); + } + + io_mem_size = get_mem_size(UIO_IO_VMETA_OBJ_SIZE); + if(io_mem_size <= 0 || io_mem_size < size) { + ret = -VDEC_OS_DRIVER_MMAP_FAIL; + dbg_printf(VDEC_DEBUG_MEM, "vdec_os_api_get_hw_obj_addr error: get_mem_size io_mem_size=%d, requested size=%d!!!\n", \ + io_mem_size, size); + goto get_vdec_obj_fail; + } + dbg_printf(VDEC_DEBUG_MEM, "vdec_os_api_get_hw_obj_addr: get_mem_size io_mem_size=%d, requested size=%d\n", \ + io_mem_size,size); + + io_mem_virt_addr = (SIGN32)mmap(NULL, size, + PROT_READ|PROT_WRITE, MAP_SHARED, vdec_iface->uiofd, UIO_IO_VMETA_OBJ_INDEX*getpagesize()); + if(io_mem_virt_addr == -1) { + ret = -VDEC_OS_DRIVER_MMAP_FAIL; + dbg_printf(VDEC_DEBUG_MEM, "vdec_os_api_get_hw_obj_addr: mmap hw obj error\n"); + goto get_vdec_obj_fail; + } + + dbg_printf(VDEC_DEBUG_MEM, "UIO_IO_VMETA_OBJ_ADDR virtual 0x%x\n", io_mem_virt_addr); + + *vaddr = io_mem_virt_addr; + vdec_iface->vdec_obj_va = (UNSG32)io_mem_virt_addr; + +get_vdec_obj_fail: + return ret; +} + +SIGN32 vdec_os_api_get_hw_context_addr(UNSG32* paddr, UNSG32* vaddr, UNSG32 size, SIGN32 flag) +{ + UNSG32 io_mem_size; + UNSG32 io_mem_addr; + UNSG32 io_mem_virt_addr; + + UNSG32 ret = VDEC_OS_DRIVER_OK; + + if(vdec_iface->hw_context_pa != 0) + { + dbg_printf(VDEC_DEBUG_MEM, "Already get hw context\n"); + } + io_mem_size = get_mem_size(UIO_IO_HW_CONTEXT_SIZE); + if(io_mem_size <= 0 || io_mem_size < size) { + ret = -VDEC_OS_DRIVER_MMAP_FAIL; + dbg_printf(VDEC_DEBUG_MEM, "vdec_os_api_get_hw_context_addr error: get_mem_size io_mem_size=%d, requested size=%d!!!\n", \ + io_mem_size,size); + goto get_hw_context_fail; + } + dbg_printf(VDEC_DEBUG_MEM, "vdec_os_api_get_hw_context_addr: get_mem_size io_mem_size=%d, requested size=%d\n", \ + io_mem_size,size); + + io_mem_addr = get_mem_addr(UIO_IO_HW_CONTEXT_ADDR); + if(io_mem_addr <= 0) { + ret = -VDEC_OS_DRIVER_MMAP_FAIL; + dbg_printf(VDEC_DEBUG_MEM, "vdec_os_api_get_hw_context_addr: get_mem_addr error\n"); + goto get_hw_context_fail; + } + + *((UNSG32*) paddr) = io_mem_addr; + vdec_iface->hw_context_pa = io_mem_addr; + + dbg_printf(VDEC_DEBUG_MEM, "UIO_IO_HW_CONTEXT_ADDR: 0x%08x\n", *((UNSG32*) paddr)); + + +get_hw_context_fail: + return ret; +} + +SIGN32 vdec_os_api_get_ks(kernel_share** pp_ks) +{ + UNSG32 io_mem_size; + UNSG32 io_mem_addr; + UNSG32 io_mem_virt_addr; + + UNSG32 ret = VDEC_OS_DRIVER_OK; + + if(vdec_iface->kernel_share_va != 0) + { + dbg_printf(VDEC_DEBUG_MEM, "Already get kernel share\n"); + return 0; + } + + io_mem_size = get_mem_size(UIO_IO_KERNEL_SHARE_SIZE); + if(io_mem_size <= 0 ) { + ret = -VDEC_OS_DRIVER_MMAP_FAIL; + dbg_printf(VDEC_DEBUG_MEM, "vdec_os_api_get_ks: get_mem_size error\n"); + goto get_vos_fail; + } + dbg_printf(VDEC_DEBUG_MEM, "vdec_os_api_get_ks: get_mem_size io_mem_size=%d\n",io_mem_size); + + io_mem_virt_addr = (UNSG32)mmap(NULL, io_mem_size, \ + PROT_READ|PROT_WRITE, MAP_SHARED, vdec_iface->uiofd, \ + UIO_IO_KERNEL_SHARE_INDEX*getpagesize()); + if(io_mem_virt_addr == -1) { + ret = -VDEC_OS_DRIVER_MMAP_FAIL; + dbg_printf(VDEC_DEBUG_MEM, "vdec_os_api_get_ks: mmap ks error\n"); + goto get_vos_fail; + } + + dbg_printf(VDEC_DEBUG_MEM, "kernel share virtual address: 0x%x\n", io_mem_virt_addr); + + *pp_ks = (kernel_share *)io_mem_virt_addr; + vdec_iface->kernel_share_va = io_mem_virt_addr; + +get_vos_fail: + return ret; +} + +int find_user_id(id_instance *list)//return unoccupied id +{ + int i; + for(i=0; ikernel_share_va==0) + { + vdec_os_api_get_ks(&p_ks); + } + else + { + p_ks = (kernel_share *)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==0) + { + vdec_os_api_get_ks(&p_ks); + } + else + { + p_ks = (kernel_share *)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==0) + { + printf("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) { + printf("vdec_os_api_free_user_id error: exceeds max user_id\n"); + return VDEC_OS_DRIVER_USER_ID_FAIL; + } + p_ks = (kernel_share *)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; + } + +int vmeta_thread_monitor(struct monitor_data * p_md) +{ + kernel_share *p_ks; + unsigned int *ret; + vdec_os_driver_cb_t *p_cb = vdec_driver_get_cb(); + pthread_attr_t pat; + int detach_attr; + + if(p_cb->kernel_share_va==0 || p_md == NULL) + { + printf("vdec_os_api_free_user_id error: not init yet\n"); + return -1; + } + p_ks = (kernel_share *)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_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); + + if( (p_ks->lock_flag==VMETA_LOCK_ON) && (p_md->user_id==p_ks->active_user_id)) + { + vdec_os_api_unlock(p_md->user_id); + + vmeta_private_lock(); + p_ks->lock_flag = VMETA_LOCK_FORCE_INIT; + p_ks->ref_count--; + memset(&(p_ks->user_id_list[p_ks->active_user_id]),0x0,sizeof(id_instance)); + vmeta_private_unlock(); + } + + free(p_md);//This is malloced in register function + pthread_attr_destroy(&pat); + return 0; + +tag_monitor_fail: + free(p_md); + pthread_attr_destroy(&pat); + return -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) { + printf("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==0) + { + vdec_os_api_get_ks(&p_ks); + } + else + { + p_ks = (kernel_share *)p_cb->kernel_share_va; + } + + if(set_bit(VMETA_STATUS_BIT_REGISTED, &(p_ks->user_id_list[user_id].status)) == 1) { + printf("vdec_os_api_register_user_id error: user id has already been registered\n"); + return VDEC_OS_DRIVER_USER_ID_FAIL; + } + + p_md = (struct monitor_data*) malloc(sizeof(struct monitor_data));//This is freed monitor function + if(p_md == NULL) { + printf("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=0x%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) { + printf("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==0) + { + printf("vdec_os_api_unregister_user_id error: not init yet\n"); + return VDEC_OS_DRIVER_USER_ID_FAIL; + } + else + { + p_ks = (kernel_share *)p_cb->kernel_share_va; + } + + if(clear_bit(VMETA_STATUS_BIT_REGISTED,&(p_ks->user_id_list[user_id].status)) == 0) { + printf("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; + } + + + SIGN32 vmeta_private_lock() + { + ioctl(vdec_iface->uiofd,VMETA_CMD_PRIV_LOCK,(unsigned long)0xffffffff); + return 0; + } + + 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) { + printf("vdec_os_api_get_user_count error: point is NULL\n"); + return -1; + } + p_ks = (kernel_share*)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; + struct timespec ts; + SIGN32 ret; + SIGN32 sem_val; + + if(p_cb == NULL) { + printf("vdec_os_api_lock error: point is NULL\n"); + return LOCK_RET_ERROR_UNKNOWN; + } + p_ks = (kernel_share*)p_cb->kernel_share_va; + + if(p_ks->active_user_id == user_id) { + dbg_printf(VDEC_DEBUG_LOCK,"lock same user\n"); + 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) { + printf("vdec_os_api_unlock error: point is NULL\n"); + return LOCK_RET_ERROR_UNKNOWN; + } + + p_ks = (kernel_share*)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 + { + printf("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) { + printf("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) { + printf("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; + + ioctl(vdec_iface->uiofd, VMETA_CMD_SUSPEND_READY); + + return 0; +} + + diff --git a/vmeta_lib.h b/vmeta_lib.h index 3c44412..dd9a262 100755 --- a/vmeta_lib.h +++ b/vmeta_lib.h @@ -1,6 +1,8 @@ #ifndef VDEC_OS_DRIVER_H #define VDEC_OS_DRIVER_H #include +#include +#include "uio_vmeta.h" #ifdef __cplusplus extern "C" @@ -9,12 +11,30 @@ extern "C" #define VDEC_DEBUG_ALL 0x1 #define VDEC_DEBUG_MEM 0x2 -#define VDEC_DEBUG_NONE 0x80 +#define VDEC_DEBUG_LOCK 0x4 +#define VDEC_DEBUG_VER 0x8 +#define VDEC_DEBUG_NONE 0x0 #define UIO_DEV "/dev/uio0" #define UIO_IO_MEM_SIZE "/sys/class/uio/uio0/maps/map0/size" #define UIO_IO_MEM_ADDR "/sys/class/uio/uio0/maps/map0/addr" +#define UIO_IO_VERSION "/sys/class/uio/uio0/version" +#define UIO_IO_HW_CONTEXT_SIZE "/sys/class/uio/uio0/maps/map1/size" +#define UIO_IO_HW_CONTEXT_ADDR "/sys/class/uio/uio0/maps/map1/addr" + +#define UIO_IO_VMETA_OBJ_SIZE "/sys/class/uio/uio0/maps/map2/size" +#define UIO_IO_VMETA_OBJ_ADDR "/sys/class/uio/uio0/maps/map2/addr" +#define UIO_IO_VMETA_OBJ_INDEX 2 + +#define UIO_IO_KERNEL_SHARE_SIZE "/sys/class/uio/uio0/maps/map3/size" +#define UIO_IO_KERNEL_SHARE_ADDR "/sys/class/uio/uio0/maps/map3/addr" +#define UIO_IO_KERNEL_SHARE_INDEX 3 + +#define VMETA_SHARED_LOCK_HANDLE "vmeta_shared_lock" + +#define VMETA_KERN_MIN_VER 4 +#define VMETA_USER_VER "build-004" //--------------------------------------------------------------------------- // Macros //--------------------------------------------------------------------------- @@ -38,6 +58,10 @@ extern "C" #define UNSG8 unsigned char #endif +#ifndef SIGN8 +#define SIGN8 char +#endif + enum dma_data_direction { DMA_BIDIRECTIONAL = 0, DMA_TO_DEVICE = 1, @@ -45,11 +69,15 @@ enum dma_data_direction { DMA_NONE = 3, }; +#define VMETA_STATUS_BIT_USED 0 +#define VMETA_STATUS_BIT_REGISTED 1 + //--------------------------------------------------------------------------- // Driver initialization API //--------------------------------------------------------------------------- SIGN32 vdec_os_driver_init(void); SIGN32 vdec_os_driver_clean(void); +SIGN32 vdec_os_driver_version(SIGN8 *ver_str); //--------------------------------------------------------------------------- // Memory operation API @@ -66,6 +94,9 @@ UNSG32 vdec_os_api_get_pa(UNSG32 vaddr); UNSG32 vdec_os_api_flush_cache(UNSG32 vaddr, UNSG32 size, enum dma_data_direction direction); +SIGN32 vdec_os_api_get_hw_obj_addr(UNSG32* vaddr, UNSG32 size); +SIGN32 vdec_os_api_get_hw_context_addr(UNSG32* paddr, UNSG32* vaddr, UNSG32 size, SIGN32 flag); + //--------------------------------------------------------------------------- // Mem/IO R/W API //--------------------------------------------------------------------------- @@ -84,12 +115,36 @@ SIGN32 vdec_os_api_set_sync_timeout_isr(UNSG32 timeout); SIGN32 vdec_os_api_sync_event(); //--------------------------------------------------------------------------- -// Power Management API +// multi-instance operation APIs //--------------------------------------------------------------------------- -void vdec_os_api_power_on(void); -void vdec_os_api_power_off(void); +SIGN32 vdec_os_api_get_user_id(void); +SIGN32 vdec_os_api_free_user_id(SIGN32 user_id); +SIGN32 vdec_os_api_register_user_id(SIGN32 user_id); +SIGN32 vdec_os_api_unregister_user_id(SIGN32 user_id); + +SIGN32 vdec_os_api_update_user_info(SIGN32 user_id, void* info); +SIGN32 vdec_os_api_get_user_count(void); + +//return: Former user unlock vmeta normally/abnormally/forced +SIGN32 vdec_os_api_lock(SIGN32 user_id, long to_ms); +SIGN32 vdec_os_api_unlock(SIGN32 user_id); + +//--------------------------------------------------------------------------- +// Power operation APIs +//--------------------------------------------------------------------------- +SIGN32 vdec_os_api_power_on(void); +SIGN32 vdec_os_api_power_off(void); SIGN32 vdec_os_api_suspend_check(void); -void vdec_os_api_suspend_ready(void); +SIGN32 vdec_os_api_suspend_ready(void); +SIGN32 vdec_os_api_clock_on(void); +SIGN32 vdec_os_api_clock_off(void); + +typedef enum _VMETA_CLOCK_OP{ + VMETA_CLOCK_L0 = 0, + VMETA_CLOCK_L1 +}VMETA_CLOCK_OP; + +SIGN32 vdec_os_api_clock_switch(VMETA_CLOCK_OP vco); typedef enum _VPRO_CODEC_ERROR_CODE_ { VDEC_OS_DRIVER_OK = 0, @@ -101,29 +156,24 @@ typedef enum _VPRO_CODEC_ERROR_CODE_ { VDEC_OS_DRIVER_SYNC_TIMEOUT_FAIL, VDEC_OS_DRIVER_IO_CONTROL_FAIL, VDEC_OS_DRIVER_ALREADY_INIT_FAIL, - VDEC_OS_DRIVER_CLEAN_FAIL + VDEC_OS_DRIVER_CLEAN_FAIL, + VDEC_OS_DRIVER_USER_ID_FAIL, + VDEC_OS_DRIVER_VER_FAIL }VPRO_DEC_ERROR_CODE; -/************************* - * Vmeta ioctl Define * - *************************/ -#define IOP_MAGIC 'v' - -#define UIO_VPRO_IRQ_ENABLE _IO(IOP_MAGIC, 2) -#define UIO_VPRO_IRQ_DISABLE _IO(IOP_MAGIC, 3) -#define UIO_VPRO_XV_IN_QUEUE _IOW(IOP_MAGIC, 4, struct vpro_xv_frame) // used for vpro decoder to put a video frame in queue -#define UIO_VPRO_XV_DQUEUE _IOR(IOP_MAGIC, 5, struct vpro_xv_frame) // used for vpro decoder to free a video frame in queue -#define UIO_VPRO_XV_QUERY_VIDEO _IOR(IOP_MAGIC, 6, struct vpro_xv_frame) // used for vo xv interface to query a video frame that from vpro -#define UIO_VPRO_XV_FREE_VIDEO _IOW(IOP_MAGIC, 7, struct vpro_xv_frame) // used for vo xv interface to free a video frame -#define UIO_VPRO_XV_INIT_QUEUE _IO(IOP_MAGIC, 8) -#define UIO_VMETA_POWER_ON _IO(IOP_MAGIC, 9) -#define UIO_VMETA_POWER_OFF _IO(IOP_MAGIC, 10) -#define UIO_VMETA_SUSPEND_CHECK _IOR(IOP_MAGIC, 11, int) -#define UIO_VMETA_SUSPEND_READY _IO(IOP_MAGIC, 12) +typedef enum _LOCK_RET_CODE { + LOCK_RET_ERROR_TIMEOUT = -9999, + LOCK_RET_ERROR_UNKNOWN, + LOCK_RET_OHTERS_NORM = 0, + LOCK_RET_NULL, + LOCK_RET_ME, + LOCK_RET_FORCE_INIT, +}LOCK_RET_CODE; /* display debug message */ int dbg_printf(UNSG32 dbglevel, const char* format, ...); +typedef sem_t lock_t; //--------------------------------------------------------------------------- // the control block of vdec os driver //--------------------------------------------------------------------------- @@ -133,9 +183,18 @@ typedef struct vdec_os_driver_cb_s UNSG32 io_mem_phy_addr; // the physical addr of io register base SIGN32 io_mem_virt_addr; // the reg base addr that maped from kernel UNSG32 io_mem_size; // the size of io mem area - int refcount; // reference count + int refcount; // reference count in current process + UNSG32 vdec_obj_va; + UNSG32 hw_context_pa; + UNSG32 kernel_share_va; + int kern_ver; //vmeta kernel version } vdec_os_driver_cb_t; +struct monitor_data{ + pthread_t pt; + SIGN32 user_id; +}; + /* vdec driver get cb */ vdec_os_driver_cb_t *vdec_driver_get_cb(void); -- cgit