/* * 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 #include #include "vmeta_lib.h" #include "bmm_lib.h" #include "rb.h" #include "uio_vmeta.h" #define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1) #define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) #define VDEC_DEBUG_ALL 0x1 #define VDEC_DEBUG_MEM 0x2 #define VDEC_DEBUG_LOCK 0x4 #define VDEC_DEBUG_VER 0x8 #define VDEC_DEBUG_NONE 0x0 #define MAP_IO_MEM 0 #define MAP_IO_HW_CONTEXT 1 #define VMETA_KERN_MIN_VER 104 #define VMETA_USER_VER "build-004" // debug message #define VMETA_LOG_ON 0 #define VMETA_LOG_FILE "/data/vmeta_dbg.log" static void dbg_printf(UNSG32 dbglevel, const char *format, ...); // our private data structure typedef struct vdec_os_driver_cb_s { int fd; // kernel file descriptor int refcount; // reference count in current process int kern_ver; // vmeta kernel version struct { UNSG32 phys; UNSG32 size; } map[2]; void *regs; // the vmeta registers void *vdec_obj_va; UNSG32 vdec_obj_size; } vdec_os_driver_cb_t; // global variable static vdec_os_driver_cb_t *vdec_iface = NULL; static int vmeta_fd = -1; static UNSG32 globalDbgLevel = VDEC_DEBUG_NONE; static UNSG32 syncTimeout = 500; static pthread_mutex_t pmt = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t rb_mutex = PTHREAD_MUTEX_INITIALIZER; static Rb_node phys_rb, virt_rb; typedef unsigned long phys_t; struct v2p { void *vaddr; size_t size; phys_t paddr; int32_t fd; int32_t id; }; static int cmp_phys(const void *key, const void *val) { const struct v2p *v2p = val; phys_t k = *(const phys_t *)key; return (k < v2p->paddr) ? -1 : (k - v2p->paddr < v2p->size) ? 0 : 1; } static struct v2p *find_phys(phys_t paddr) { int found = 0; Rb_node node = rb_find_key_n(phys_rb, &paddr, cmp_phys, &found); return found ? rb_val(node) : NULL; } static struct v2p *find_remove_phys(phys_t paddr) { struct v2p *v2p = NULL; int found = 0; Rb_node node = rb_find_key_n(phys_rb, &paddr, cmp_phys, &found); if (found) { v2p = rb_val(node); rb_delete_node(node); } return v2p; } static int cmp_virt(const void *key, const void *val) { const struct v2p *v2p = val; void *k = (void *)key; return (k < v2p->vaddr) ? -1 : (k - v2p->vaddr < v2p->size) ? 0 : 1; } static struct v2p *find_virt(void *vaddr) { int found = 0; Rb_node node = rb_find_key_n(virt_rb, vaddr, cmp_virt, &found); return found ? rb_val(node) : NULL; } 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 = vdec_iface; return (UNSG32) vdec->regs; } static void __attribute__((destructor)) vdec_os_api_exit(void) { if (phys_rb) { Rb_node node; /* * Release all resources on the virtual rb tree, but leave * the v2p structs in place, as these will also be on the * phys rb tree. */ rb_traverse(node, virt_rb) { struct v2p *v2p = rb_val(node); ioctl(vmeta_fd, VMETA_CMD_DMABUF_RELEASE, v2p->id); bmm_dmabuf_unmap(v2p->vaddr); bmm_dmabuf_free(v2p->fd); v2p->id = -1; } rb_free_tree(virt_rb); rb_traverse(node, phys_rb) { struct v2p *v2p = rb_val(node); if (v2p->id != -1) { ioctl(vmeta_fd, VMETA_CMD_DMABUF_RELEASE, v2p->id); v2p->id = -1; } free(v2p); } rb_free_tree(phys_rb); } if (vmeta_fd >= 0) close(vmeta_fd); bmm_exit(); } static int vdec_os_api_init(void) { int fd; if (!virt_rb) { virt_rb = make_rb(); phys_rb = make_rb(); if (!virt_rb || !phys_rb) goto rb; fd = open("/dev/vmeta", O_RDWR | O_CLOEXEC); if (fd == -1) goto rb; if (bmm_init() < 0) goto vmeta; vmeta_fd = fd; } return 0; vmeta: close(fd); rb: if (virt_rb) rb_free_tree(virt_rb); if (phys_rb) rb_free_tree(phys_rb); phys_rb = virt_rb = NULL; return 1; } static int vdec_os_api_add_mapping(void *ptr, size_t size, phys_t paddr, int fd, int id) { struct v2p *v2p; Rb_node node; int found = 0; v2p = malloc(sizeof(*v2p)); if (!v2p) return -1; v2p->vaddr = ptr; v2p->size = size; v2p->paddr = paddr; v2p->fd = fd; v2p->id = id; pthread_mutex_lock(&rb_mutex); node = rb_find_key_n(phys_rb, &paddr, cmp_phys, &found); assert(found == 0); rb_insert_b(node, v2p); if (ptr) { node = rb_find_key_n(virt_rb, ptr, cmp_virt, &found); assert(found == 0); rb_insert_b(node, v2p); } pthread_mutex_unlock(&rb_mutex); return 0; } /** * vdec_os_api_dmabuf_import - import a DMA buffer into vmeta * @fd: dmabuf file descriptor * @phys: pointer to unsigned long for physical address of buffer * @size: pointer ti size_t for size of buffer * * Returns: ID of buffer, physical address in *phys and size in *size, * or -1 on error. */ int vdec_os_api_dmabuf_import(int fd, unsigned long *phys, size_t *size) { struct vmeta_dmabuf_import arg; int ret; if (vdec_os_api_init()) return -1; arg.fd = fd; ret = ioctl(vmeta_fd, VMETA_CMD_DMABUF_IMPORT, &arg); if (ret == -1) return ret; if ((phys_t)arg.phys != arg.phys) { ret = -1; goto release; } ret = vdec_os_api_add_mapping(NULL, arg.size, arg.phys, arg.fd, arg.id); if (ret) goto release; return arg.id; release: ioctl(vmeta_fd, VMETA_CMD_DMABUF_RELEASE, arg.id); return ret; } void vdec_os_api_dmabuf_release(unsigned long phys) { struct v2p *v2p; pthread_mutex_lock(&rb_mutex); v2p = find_remove_phys(phys); pthread_mutex_unlock(&rb_mutex); ioctl(vmeta_fd, VMETA_CMD_DMABUF_RELEASE, v2p->id); free(v2p); } //Mem map to bmm_lib UNSG32 vdec_os_api_get_pa(UNSG32 virt) { unsigned long paddr; struct v2p *v2p; void *vaddr = (void *)virt; pthread_mutex_lock(&rb_mutex); v2p = find_virt(vaddr); pthread_mutex_unlock(&rb_mutex); assert(v2p); paddr = v2p->paddr + vaddr - v2p->vaddr; return paddr; } UNSG32 vdec_os_api_get_va(UNSG32 paddr) { struct v2p *v2p; void *vaddr; pthread_mutex_lock(&rb_mutex); v2p = find_phys(paddr); pthread_mutex_unlock(&rb_mutex); assert(v2p); if (v2p->vaddr) vaddr = v2p->vaddr + paddr - v2p->paddr; else vaddr = NULL; return (UNSG32)vaddr; } 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) { struct v2p *v2p; Rb_node node; int found = 0; dbg_printf(VDEC_DEBUG_MEM, "vdec_os_api_free: 0x%p\n", ptr); pthread_mutex_lock(&rb_mutex); node = rb_find_key_n(virt_rb, ptr, cmp_virt, &found); if (!found) { pthread_mutex_unlock(&rb_mutex); dbg_printf(VDEC_DEBUG_MEM, "vdec_os_api_free: not found\n"); assert(0); return; } rb_delete_node(node); v2p = rb_val(node); assert(find_remove_phys(v2p->paddr) == v2p); pthread_mutex_unlock(&rb_mutex); bmm_dmabuf_unmap(v2p->vaddr); if (v2p->id != -1) ioctl(vmeta_fd, VMETA_CMD_DMABUF_RELEASE, v2p->id); bmm_dmabuf_free(v2p->fd); free(v2p); } static void *vmeta_bmm_malloc_aligned(UNSG32 size, UNSG32 align, UNSG32 *phys, int attr) { struct vmeta_dmabuf_import arg; unsigned long paddr; void *ptr; int fd; dbg_printf(VDEC_DEBUG_MEM, "%s: size 0x%x attr %u align %u\n", __FUNCTION__, size, attr, align); if (size == 0) return NULL; if (vdec_os_api_init()) return NULL; fd = bmm_dmabuf_alloc(size, attr, align); if (fd < 0) { dbg_printf(VDEC_DEBUG_MEM, "%s: %s\n", __FUNCTION__, strerror(errno)); return NULL; } ptr = bmm_dmabuf_map(fd, 0, size); if (ptr == NULL) goto free; arg.fd = fd; if (ioctl(vmeta_fd, VMETA_CMD_DMABUF_IMPORT, &arg) == -1) goto unmap; paddr = arg.phys; dbg_printf(VDEC_DEBUG_MEM, "%s: virt=%p phys=0x%08lx fd %d id %d\n", __FUNCTION__, ptr, paddr, fd, arg.id); if (vdec_os_api_add_mapping(ptr, size, paddr, fd, arg.id)) goto release; *phys = paddr; return ptr; release: ioctl(vmeta_fd, VMETA_CMD_DMABUF_RELEASE, arg.id); unmap: bmm_dmabuf_unmap(ptr); free: bmm_dmabuf_free(fd); return NULL; } void *vdec_os_api_dma_alloc(UNSG32 size, UNSG32 align, UNSG32 *phys) { return vmeta_bmm_malloc_aligned(size, align, phys, BMM_ATTR_NONCACHED); } void *vdec_os_api_dma_alloc_cached(UNSG32 size, UNSG32 align, UNSG32 *phys) { return vmeta_bmm_malloc_aligned(size, align, phys, BMM_ATTR_DEFAULT); } void *vdec_os_api_dma_alloc_writecombine(UNSG32 size, UNSG32 align, UNSG32 *phys) { return vmeta_bmm_malloc_aligned(size, align, phys, BMM_ATTR_WRITECOMBINE); } UNSG32 vdec_os_api_flush_cache(UNSG32 vaddr, UNSG32 size, enum dma_data_direction direction) { struct v2p *v2p; unsigned bmm_direction, offset; switch (direction) { case DMA_NONE: 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; default: assert(0); } if (bmm_direction == BMM_DMA_NONE) return 0; pthread_mutex_lock(&rb_mutex); v2p = find_virt((void *)vaddr); pthread_mutex_unlock(&rb_mutex); assert(v2p); offset = (void *)vaddr - v2p->vaddr; bmm_dmabuf_flush(v2p->fd, v2p->vaddr, offset, size - offset, direction); return 0; } static int vmeta_ioctl(unsigned cmd) { vdec_os_driver_cb_t *vdec = vdec_iface; if (vdec == NULL) { errno = EBADF; return -1; } return ioctl(vdec->fd, cmd); } static int vmeta_ioctl_ulong(unsigned cmd, unsigned long arg) { vdec_os_driver_cb_t *vdec = vdec_iface; if (vdec == NULL) { errno = EBADF; return -1; } return ioctl(vdec->fd, cmd, arg); } // control vmeta interrupt static void vdec_os_api_irq_ctrl(int state) { vdec_os_driver_cb_t *vdec = vdec_iface; write(vdec->fd, &state, sizeof(state)); } SIGN32 vdec_os_api_set_sync_timeout_isr(UNSG32 timeout) { syncTimeout = timeout; return syncTimeout; } SIGN32 vdec_os_api_sync_event() { vdec_os_driver_cb_t *vdec = vdec_iface; struct pollfd ufds; int result = 0; ufds.fd = vdec->fd; ufds.events = POLLIN; vdec_os_api_irq_ctrl(1); result = poll(&ufds, 1, syncTimeout); if(result > 0) return VDEC_OS_DRIVER_OK; else return -VDEC_OS_DRIVER_SYNC_TIMEOUT_FAIL; } static int vmeta_get_map(vdec_os_driver_cb_t *vdec, unsigned map, unsigned size, void **rptr, unsigned *rsize) { UNSG32 map_size; void *addr; map_size = vdec->map[map].size; 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 (size == 0) size = map_size; addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, vdec->fd, map * getpagesize()); if (addr == MAP_FAILED) { dbg_printf(VDEC_DEBUG_MEM, "Error: %s: mmap of map %u failed: %s\n", __FUNCTION__, map, strerror(errno)); return -VDEC_OS_DRIVER_MMAP_FAIL; } *rptr = addr; return VDEC_OS_DRIVER_OK; } // init vdec os driver SIGN32 vdec_os_driver_init(void) { vdec_os_driver_cb_t *vdec; struct vmeta_info info; unsigned size; void *addr; int i, ret; #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 VDEC_OS_DRIVER_OK; } if (vdec_os_api_init()) { pthread_mutex_unlock(&pmt); return -VDEC_OS_DRIVER_INIT_FAIL; } #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 = malloc(sizeof(vdec_os_driver_cb_t)); if (vdec == NULL) { pthread_mutex_unlock(&pmt); return -VDEC_OS_DRIVER_INIT_FAIL; } memset(vdec, 0, sizeof(*vdec)); // initialize reference count vdec->refcount++; vdec->fd = vmeta_fd; ret = ioctl(vdec->fd, VMETA_CMD_GET_INFO, &info); if (ret == -1) { dbg_printf(VDEC_DEBUG_ALL, "%s: unable to get info: %s\n", __FUNCTION__, strerror(errno)); close(vdec->fd); ret = -VDEC_OS_DRIVER_VER_FAIL; goto err_open_fail; } dbg_printf(VDEC_DEBUG_VER, "%s: version: kernel=%u user=%s\n", __FUNCTION__, info.revision, VMETA_USER_VER); vdec->kern_ver = info.revision; if (vdec->kern_ver < VMETA_KERN_MIN_VER) { close(vdec->fd); ret = -VDEC_OS_DRIVER_VER_FAIL; goto err_open_fail; } for (i = 0; i < 2; i++) { vdec->map[i].phys = info.map[i].phys; vdec->map[i].size = info.map[i].size; } // Get the IO mem phy addr and size of vPro's register ret = vmeta_get_map(vdec, MAP_IO_MEM, 0, &addr, &size); 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, vdec->map[0].phys, addr); vdec->regs = addr; vdec_iface = vdec; pthread_mutex_unlock(&pmt); return VDEC_OS_DRIVER_OK; err_mmap_fail: err_open_fail: free(vdec); pthread_mutex_unlock(&pmt); return ret; } // clean vdec os driver SIGN32 vdec_os_driver_clean(void) { vdec_os_driver_cb_t *vdec; pthread_mutex_lock(&pmt); vdec = vdec_iface; if (vdec == NULL){ pthread_mutex_unlock(&pmt); return -VDEC_OS_DRIVER_CLEAN_FAIL; } // decrease the refcount vdec->refcount--; if (vdec->refcount != 0) { dbg_printf(VDEC_DEBUG_ALL, "refcount = %d\n", vdec->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->regs) { dbg_printf(VDEC_DEBUG_MEM, "munmap registers at 0x%x\n", vdec->regs); munmap(vdec->regs, vdec->map[MAP_IO_MEM].size); } if (vdec->vdec_obj_va != NULL) { dbg_printf(VDEC_DEBUG_MEM, "munmap with vdec_obj_va = 0x%x size=%d\n", vdec->vdec_obj_va, vdec->vdec_obj_size); munmap(vdec->vdec_obj_va, vdec->vdec_obj_size); } // free vdec_iface free(vdec); 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 void dbg_printf(UNSG32 dbglevel, const char* format, ...) { /* Fast exit path */ if (globalDbgLevel == VDEC_DEBUG_NONE) return; if (globalDbgLevel & (dbglevel | VDEC_DEBUG_ALL)) { FILE *f; char buf[256]; va_list ap; int ret; va_start(ap, format); ret = vsnprintf(buf, sizeof(buf), format, ap); va_end(ap); #if VMETA_LOG_ON f = fopen(VMETA_LOG_FILE, "a+"); if (f == NULL) return; #else f = stderr; #endif fputs(buf, f); if (ret >= sizeof(buf)) fputs("... (output truncated)\n", f); #if VMETA_LOG_ON fclose(f); #endif } } SIGN32 vdec_os_api_get_hw_obj_addr(UNSG32* vaddr,UNSG32 size) { vdec_os_driver_cb_t *vdec = vdec_iface; struct vmeta_mmap arg; void *addr; int ret; if (vdec->vdec_obj_va != NULL) { dbg_printf(VDEC_DEBUG_MEM, "Already get vdec obj\n"); *vaddr = (UNSG32)vdec->vdec_obj_va; return VDEC_OS_DRIVER_OK; } memset(&arg, 0, sizeof(arg)); arg.size = size; ret = ioctl(vdec->fd, VMETA_CMD_MAP_SW_CONTEXT, &arg); if (ret < 0) return ret; addr = (void *)(uintptr_t)arg.addr; dbg_printf(VDEC_DEBUG_MEM, "%s: virtual %p size=%d\n", __FUNCTION__, addr, size); *vaddr = (UNSG32)addr; vdec->vdec_obj_va = addr; vdec->vdec_obj_size = size; return VDEC_OS_DRIVER_OK; } SIGN32 vdec_os_api_get_hw_context_addr(UNSG32* paddr, UNSG32* vaddr, UNSG32 size, SIGN32 flag) { vdec_os_driver_cb_t *vdec = vdec_iface; if (vdec->map[MAP_IO_HW_CONTEXT].size < size) { dbg_printf(VDEC_DEBUG_MEM, "Error: %s: requested %u bytes but only %u bytes available\n", __FUNCTION__, size, vdec->map[MAP_IO_HW_CONTEXT].size); return -VDEC_OS_DRIVER_MMAP_FAIL; } *paddr = vdec->map[MAP_IO_HW_CONTEXT].phys; dbg_printf(VDEC_DEBUG_MEM, "MAP_IO_HW_CONTEXT: 0x%08x\n", *paddr); return VDEC_OS_DRIVER_OK; } SIGN32 vdec_os_api_force_ini(void) { return vmeta_ioctl(VMETA_CMD_FORCE_INI); } SIGN32 vdec_os_api_get_user_id(void) { vdec_os_driver_cb_t *vdec = vdec_iface; unsigned id; int ret; ret = ioctl(vdec->fd, VMETA_CMD_GET_USER_ID, &id); return ret == 0 && id < MAX_VMETA_INSTANCE ? id : -VDEC_OS_DRIVER_USER_ID_FAIL; } SIGN32 vdec_os_api_free_user_id(SIGN32 user_id) { int ret = vmeta_ioctl_ulong(VMETA_CMD_FREE_USER_ID, user_id); return ret == 0 ? VDEC_OS_DRIVER_OK : VDEC_OS_DRIVER_USER_ID_FAIL; } SIGN32 vdec_os_api_register_user_id(SIGN32 user_id) { int ret = vmeta_ioctl_ulong(VMETA_CMD_REGISTER_USER_ID, user_id); if (ret < 0) { dbg_printf(VDEC_DEBUG_ALL, "%s: error: %s\n", __FUNCTION__, strerror(errno)); return VDEC_OS_DRIVER_USER_ID_FAIL; } return VDEC_OS_DRIVER_OK; } SIGN32 vdec_os_api_unregister_user_id(SIGN32 user_id) { int ret = vmeta_ioctl_ulong(VMETA_CMD_UNREGISTER_USER_ID, user_id); if (ret < 0) { dbg_printf(VDEC_DEBUG_ALL, "%s: error: %s\n", __FUNCTION__, strerror(errno)); return VDEC_OS_DRIVER_USER_ID_FAIL; } return VDEC_OS_DRIVER_OK; } SIGN32 vdec_os_api_get_user_count(void) { vdec_os_driver_cb_t *vdec = vdec_iface; unsigned num; int ret; if (vdec == NULL) { dbg_printf(VDEC_DEBUG_ALL,"vdec_os_api_get_user_count error: point is NULL\n"); return -1; } ret = ioctl(vdec->fd, VMETA_CMD_GET_USER_NUM, &num); return ret < 0 ? -1 : num; } SIGN32 vdec_os_api_lock(SIGN32 user_id, long to_ms) { vdec_os_driver_cb_t *vdec = vdec_iface; struct vmeta_lock lock; int ret; if (vdec == NULL) { dbg_printf(VDEC_DEBUG_ALL,"vdec_os_api_lock error: point is NULL\n"); return LOCK_RET_ERROR_UNKNOWN; } lock.user_id = user_id; lock.timeout = to_ms; ret = ioctl(vdec->fd, VMETA_CMD_LOCK_USER_ID, &lock); if (ret < 0) { switch (errno) { case ETIME: return LOCK_RET_ERROR_TIMEOUT; case EDEADLOCK: return LOCK_RET_ME; case EUCLEAN: return LOCK_RET_FORCE_INIT; default: return LOCK_RET_ERROR_UNKNOWN; } } return LOCK_RET_OHTERS_NORM; } SIGN32 vdec_os_api_unlock(SIGN32 user_id) { int ret = vmeta_ioctl_ulong(VMETA_CMD_UNLOCK_USER_ID, user_id); if (ret < 0) { dbg_printf(VDEC_DEBUG_LOCK, "%s: error: %s\n", __FUNCTION__, strerror(errno)); return LOCK_RET_ERROR_UNKNOWN; } return LOCK_RET_OHTERS_NORM; } SIGN32 vdec_os_api_power_on(void) { return vmeta_ioctl(VMETA_CMD_POWER_ON); } SIGN32 vdec_os_api_power_off(void) { return vmeta_ioctl(VMETA_CMD_POWER_OFF); } SIGN32 vdec_os_api_clock_on(void) { return vmeta_ioctl(VMETA_CMD_CLK_ON); } SIGN32 vdec_os_api_clock_off(void) { return vmeta_ioctl(VMETA_CMD_CLK_OFF); } SIGN32 vdec_os_api_clock_switch(VMETA_CLOCK_OP vco) { return vmeta_ioctl_ulong(VMETA_CMD_CLK_SWITCH, (unsigned long)vco); } SIGN32 vdec_os_driver_version(SIGN8 *ver_str) { vdec_os_driver_cb_t *vdec = vdec_iface; if (vdec == 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) { vdec_os_driver_cb_t *vdec = vdec_iface; SIGN32 suspend_check; if (vdec == NULL) return 0; ioctl(vdec->fd, VMETA_CMD_SUSPEND_CHECK, &suspend_check); return suspend_check; } // VMeta is ready to suspend SIGN32 vdec_os_api_suspend_ready(void) { vmeta_ioctl(VMETA_CMD_SUSPEND_READY); return 0; }