summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk@arm.linux.org.uk>2012-10-20 16:16:08 +0100
committerRussell King <rmk@arm.linux.org.uk>2012-10-23 11:14:47 +0100
commit3550ca2f59ae1e5f1d5f33fdfa0b56aa06f9930e (patch)
tree74dc637f9c5e5b25b127ad3c65f3b1def7789bf4
parent17b3a94e32c4b63099f7564cb9ce9d8a91174efa (diff)
Add support for /dev/vmeta miscdevice
The kernel folk don't like the uio ioctl idea, so we can't use uio for this driver. Instead, switch it to be a self-contained miscdevice. This adds support to this library for the miscdevice interface.
-rw-r--r--uio_vmeta.h56
-rw-r--r--vmeta_lib.c119
-rw-r--r--vmeta_lib.h8
3 files changed, 126 insertions, 57 deletions
diff --git a/uio_vmeta.h b/uio_vmeta.h
index d1cef5f..6f262a7 100644
--- a/uio_vmeta.h
+++ b/uio_vmeta.h
@@ -10,39 +10,60 @@
#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;
+
+struct _id_instance {
+ vmeta_instance_status status;
+ int height;
+ int width;
+ int frame_rate;
+ pid_t pid;
+ unsigned int pt; /* pthread_t */
+};
#define MAX_VMETA_INSTANCE 32
-typedef enum _VMETA_LOCK_FLAG{
+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
-{
+struct _kernel_share {
int ref_count;
- VMETA_LOCK_FLAG lock_flag;
+ enum _VMETA_LOCK_FLAG lock_flag;
int active_user_id;
- id_instance user_id_list[MAX_VMETA_INSTANCE];
-}kernel_share;
+ struct _id_instance user_id_list[MAX_VMETA_INSTANCE];
+};
+
+#ifndef __KERNEL__
+/*
+ * Needed for userspace
+ */
+typedef enum _VMETA_LOCK_FLAG VMETA_LOCK_FLAG;
+typedef struct _id_instance id_instance;
+typedef struct _kernel_share kernel_share;
+#endif
struct vmeta_lock {
unsigned long timeout;
unsigned int user_id;
};
-#define IOP_MAGIC 'v'
+struct vmeta_info {
+ uint32_t revision;
+ struct {
+ uint32_t phys;
+ uint32_t size;
+ } map[3];
+};
+
+#define VMETA_STATUS_BIT_USED 0
+#define VMETA_STATUS_BIT_REGISTED 1
+#define VMETA_STATUS_USED BIT(0)
+#define VMETA_STATUS_REGISTERED BIT(1)
+
+#define IOP_MAGIC ('v')
#define VMETA_CMD_POWER_ON _IO(IOP_MAGIC, 0)
#define VMETA_CMD_POWER_OFF _IO(IOP_MAGIC, 1)
@@ -65,5 +86,6 @@ struct vmeta_lock {
#define VMETA_CMD_UNLOCK_USER_ID _IO(IOP_MAGIC, 18)
#define VMETA_CMD_FORCE_INI _IO(IOP_MAGIC, 19)
#define VMETA_CMD_GET_USER_NUM _IOR(IOP_MAGIC, 20, unsigned)
+#define VMETA_CMD_GET_INFO _IOR(IOP_MAGIC, 21, struct vmeta_info)
#endif /* __UIO_VMETA_H */
diff --git a/vmeta_lib.c b/vmeta_lib.c
index d8e7bcf..38b0139 100644
--- a/vmeta_lib.c
+++ b/vmeta_lib.c
@@ -23,6 +23,7 @@
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
+#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -257,14 +258,14 @@ UNSG32 vdec_os_api_flush_cache(UNSG32 vaddr, UNSG32 size, enum dma_data_directio
void vdec_os_api_irq_enable(void)
{
int irq_on = 1;
- write(vdec_iface->uiofd, &irq_on, sizeof(int));
+ write(vdec_iface->fd, &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));
+ write(vdec_iface->fd, &irq_on, sizeof(int));
}
SIGN32 vdec_os_api_set_sync_timeout_isr(UNSG32 timeout)
@@ -278,7 +279,7 @@ SIGN32 vdec_os_api_sync_event()
struct pollfd ufds;
int result = 0;
- ufds.fd = vdec_iface->uiofd;
+ ufds.fd = vdec_iface->fd;
ufds.events = POLLIN;
vdec_os_api_irq_enable();
@@ -347,12 +348,17 @@ static UNSG32 get_file_unsg32(const char *fmt, ...)
static int uio_get_map(unsigned uio_num, unsigned map, unsigned size, void **rptr, unsigned *rsize, UNSG32 *rphys)
{
+ vdec_os_driver_cb_t *vdec = vdec_iface;
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 (vdec->uio) {
+ map_size = get_file_unsg32("/sys/class/uio/uio%u/maps/map%u/size",
+ uio_num, map);
+ } else {
+ map_size = vdec->map[map].size;
+ }
if (map_size == (UNSG32)-VDEC_OS_DRIVER_OPEN_FAIL)
return -VDEC_OS_DRIVER_OPEN_FAIL;
@@ -370,8 +376,12 @@ static int uio_get_map(unsigned uio_num, unsigned map, unsigned size, void **rpt
*rsize = map_size;
if (rphys) {
- phys = get_file_unsg32("/sys/class/uio/uio%u/maps/map%u/addr",
- uio_num, map);
+ if (vdec->uio) {
+ phys = get_file_unsg32("/sys/class/uio/uio%u/maps/map%u/addr",
+ uio_num, map);
+ } else {
+ phys = vdec->map[map].phys;
+ }
if (phys == (UNSG32)-VDEC_OS_DRIVER_OPEN_FAIL)
return -VDEC_OS_DRIVER_OPEN_FAIL;
if (phys == 0)
@@ -385,7 +395,7 @@ static int uio_get_map(unsigned uio_num, unsigned map, unsigned size, void **rpt
size = map_size;
addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED,
- vdec_iface->uiofd, map * getpagesize());
+ vdec->fd, map * getpagesize());
if (addr == MAP_FAILED) {
dbg_printf(VDEC_DEBUG_MEM, "Error: %s: mmap of map %u failed: %d\n",
__FUNCTION__, map, errno);
@@ -439,20 +449,51 @@ SIGN32 vdec_os_driver_init(void)
// 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;
+ // Try to open the (new) vmeta device
+ vdec_iface->fd = open("/dev/vmeta", O_RDWR);
+ if (vdec_iface->fd == -1) {
+ if (errno == ENOENT || errno == ENODEV) {
+ // Try the older uio vmeta driver
+ vdec_iface->fd = open(UIO_DEV, O_RDWR);
+ if(vdec_iface->fd < 0) {
+ ret = -VDEC_OS_DRIVER_OPEN_FAIL;
+ goto err_open_fail;
+ }
+ vdec_iface->uio = 1;
+
+ dbg_printf(VDEC_DEBUG_ALL, "%s: using UIO fd=%d\n",
+ __FUNCTION__, vdec_iface->fd);
+
+ vdec_iface->kern_ver = get_version(UIO_IO_VERSION);
+ }
+ } else {
+ struct vmeta_info info;
+ int i;
+info.revision = 1;
+ ret = ioctl(vdec_iface->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_iface->fd);
+ ret = -VDEC_OS_DRIVER_VER_FAIL;
+ goto err_open_fail;
+ }
+
+ vdec_iface->kern_ver = info.revision;
+
+ for (i = 0; i < 3; i++) {
+ vdec_iface->map[i].phys = info.map[i].phys;
+ vdec_iface->map[i].size = info.map[i].size;
+ }
}
- 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);
+ dbg_printf(VDEC_DEBUG_VER, "vdec os driver kern=%d user=%s\n", vdec_iface->kern_ver,VMETA_USER_VER);
+
if(vdec_iface->kern_ver < VMETA_KERN_MIN_VER) {
+ close(vdec_iface->fd);
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);
@@ -472,7 +513,7 @@ SIGN32 vdec_os_driver_init(void)
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);
+ close(vdec_iface->fd);
err_open_fail:
free(vdec_iface);
vdec_iface = NULL;
@@ -531,8 +572,8 @@ SIGN32 vdec_os_driver_clean(void)
}
// close fd
- if(vdec_iface->uiofd > 0) {
- close(vdec_iface->uiofd);
+ if(vdec_iface->fd > 0) {
+ close(vdec_iface->fd);
dbg_printf(VDEC_DEBUG_ALL, "uio close\n");
}
@@ -687,7 +728,7 @@ SIGN32 vdec_os_api_force_ini(void)
if (p_cb && p_cb->kern_ver >= 100) {
int ret;
- ret = ioctl(p_cb->uiofd, VMETA_CMD_FORCE_INI);
+ ret = ioctl(p_cb->fd, VMETA_CMD_FORCE_INI);
return ret < 0 ? -1 : 0;
}
@@ -703,7 +744,7 @@ SIGN32 vdec_os_api_force_ini(void)
p_ks->active_user_id = MAX_VMETA_INSTANCE;
vmeta_private_unlock();
- ioctl(vdec_iface->uiofd,VMETA_CMD_UNLOCK);
+ ioctl(vdec_iface->fd,VMETA_CMD_UNLOCK);
return 0;
}
@@ -717,7 +758,7 @@ SIGN32 vdec_os_api_get_user_id(void)
if (p_cb->kern_ver >= 100) {
unsigned id;
- ret = ioctl(p_cb->uiofd, VMETA_CMD_GET_USER_ID, &id);
+ ret = ioctl(p_cb->fd, VMETA_CMD_GET_USER_ID, &id);
return ret == 0 && id < MAX_VMETA_INSTANCE ? id :
-VDEC_OS_DRIVER_USER_ID_FAIL;
@@ -747,7 +788,7 @@ SIGN32 vdec_os_api_free_user_id(SIGN32 user_id)
if (p_cb->kern_ver >= 100) {
int ret;
- ret = ioctl(p_cb->uiofd, VMETA_CMD_FREE_USER_ID, user_id);
+ ret = ioctl(p_cb->fd, VMETA_CMD_FREE_USER_ID, user_id);
return ret == 0 ? VDEC_OS_DRIVER_OK : VDEC_OS_DRIVER_USER_ID_FAIL;
}
@@ -878,7 +919,7 @@ SIGN32 vdec_os_api_register_user_id(SIGN32 user_id)
if (p_cb->kern_ver >= 100) {
int ret;
- ret = ioctl(p_cb->uiofd, VMETA_CMD_REGISTER_USER_ID, user_id);
+ ret = ioctl(p_cb->fd, VMETA_CMD_REGISTER_USER_ID, user_id);
if (ret < 0) {
dbg_printf(VDEC_DEBUG_ALL, "%s: error %d\n",
@@ -930,7 +971,7 @@ SIGN32 vdec_os_api_unregister_user_id(SIGN32 user_id)
if (p_cb->kern_ver >= 100) {
int ret;
- ret = ioctl(p_cb->uiofd, VMETA_CMD_UNREGISTER_USER_ID, user_id);
+ ret = ioctl(p_cb->fd, VMETA_CMD_UNREGISTER_USER_ID, user_id);
if (ret < 0) {
dbg_printf(VDEC_DEBUG_ALL, "%s: error: %d\n",
__FUNCTION__, errno);
@@ -965,13 +1006,13 @@ SIGN32 vdec_os_api_unregister_user_id(SIGN32 user_id)
static SIGN32 vmeta_private_lock()
{
- ioctl(vdec_iface->uiofd,VMETA_CMD_PRIV_LOCK,(unsigned long)0xffffffff);
+ ioctl(vdec_iface->fd,VMETA_CMD_PRIV_LOCK,(unsigned long)0xffffffff);
return 0;
}
static SIGN32 vmeta_private_unlock()
{
- ioctl(vdec_iface->uiofd,VMETA_CMD_PRIV_UNLOCK);
+ ioctl(vdec_iface->fd,VMETA_CMD_PRIV_UNLOCK);
return 0;
}
@@ -989,7 +1030,7 @@ SIGN32 vdec_os_api_get_user_count(void)
unsigned num;
int ret;
- ret = ioctl(p_cb->uiofd, VMETA_CMD_GET_USER_NUM, &num);
+ ret = ioctl(p_cb->fd, VMETA_CMD_GET_USER_NUM, &num);
return ret < 0 ? -1 : num;
}
@@ -1023,7 +1064,7 @@ SIGN32 vdec_os_api_lock(SIGN32 user_id, long to_ms)
lock.user_id = user_id;
lock.timeout = to_ms;
- ret = ioctl(p_cb->uiofd, VMETA_CMD_LOCK_USER_ID, &lock);
+ ret = ioctl(p_cb->fd, VMETA_CMD_LOCK_USER_ID, &lock);
if (ret < 0) {
switch (errno) {
@@ -1048,7 +1089,7 @@ SIGN32 vdec_os_api_lock(SIGN32 user_id, long to_ms)
return LOCK_RET_ME;//just return since they are the same caller
}
- ret = ioctl(vdec_iface->uiofd,VMETA_CMD_LOCK,(unsigned long)to_ms);
+ ret = ioctl(vdec_iface->fd,VMETA_CMD_LOCK,(unsigned long)to_ms);
if(ret!=0) {
dbg_printf(VDEC_DEBUG_LOCK, "lock timeout\n");
return LOCK_RET_ERROR_TIMEOUT;
@@ -1079,7 +1120,7 @@ SIGN32 vdec_os_api_unlock(SIGN32 user_id)
}
if (p_cb->kern_ver >= 100) {
- ret = ioctl(p_cb->uiofd, VMETA_CMD_UNLOCK_USER_ID, user_id);
+ ret = ioctl(p_cb->fd, VMETA_CMD_UNLOCK_USER_ID, user_id);
if (ret < 0) {
dbg_printf(VDEC_DEBUG_LOCK, "%s: error %d\n",
@@ -1103,7 +1144,7 @@ SIGN32 vdec_os_api_unlock(SIGN32 user_id)
}
vmeta_private_unlock();
- ret = ioctl(vdec_iface->uiofd,VMETA_CMD_UNLOCK);
+ ret = ioctl(vdec_iface->fd,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");
@@ -1120,7 +1161,7 @@ SIGN32 vdec_os_api_power_on(void)
if(vdec_iface == NULL) {
return -1;
}
- ret = ioctl(vdec_iface->uiofd,VMETA_CMD_POWER_ON);
+ ret = ioctl(vdec_iface->fd,VMETA_CMD_POWER_ON);
return ret;
}
@@ -1132,7 +1173,7 @@ SIGN32 vdec_os_api_power_off(void)
if(vdec_iface == NULL) {
return -1;
}
- ret = ioctl(vdec_iface->uiofd,VMETA_CMD_POWER_OFF);
+ ret = ioctl(vdec_iface->fd,VMETA_CMD_POWER_OFF);
return ret;
}
@@ -1144,7 +1185,7 @@ SIGN32 vdec_os_api_clock_on(void)
if(vdec_iface == NULL) {
return -1;
}
- ret = ioctl(vdec_iface->uiofd,VMETA_CMD_CLK_ON);
+ ret = ioctl(vdec_iface->fd,VMETA_CMD_CLK_ON);
return ret;
}
@@ -1156,7 +1197,7 @@ SIGN32 vdec_os_api_clock_off(void)
if(vdec_iface == NULL) {
return -1;
}
- ret = ioctl(vdec_iface->uiofd,VMETA_CMD_CLK_OFF);
+ ret = ioctl(vdec_iface->fd,VMETA_CMD_CLK_OFF);
return ret;
}
@@ -1168,7 +1209,7 @@ SIGN32 vdec_os_api_clock_switch(VMETA_CLOCK_OP vco)
if(vdec_iface == NULL) {
return -1;
}
- ret = ioctl(vdec_iface->uiofd,VMETA_CMD_CLK_SWITCH,(unsigned long)vco);
+ ret = ioctl(vdec_iface->fd,VMETA_CMD_CLK_SWITCH,(unsigned long)vco);
return ret;
}
@@ -1196,7 +1237,7 @@ SIGN32 vdec_os_api_suspend_check(void) {
if(vdec_iface == NULL)
return 0;
- ioctl(vdec_iface->uiofd, VMETA_CMD_SUSPEND_CHECK, &suspend_check);
+ ioctl(vdec_iface->fd, VMETA_CMD_SUSPEND_CHECK, &suspend_check);
return suspend_check;
}
@@ -1206,7 +1247,7 @@ SIGN32 vdec_os_api_suspend_ready(void) {
if(vdec_iface == NULL)
return 0;
- ioctl(vdec_iface->uiofd, VMETA_CMD_SUSPEND_READY);
+ ioctl(vdec_iface->fd, VMETA_CMD_SUSPEND_READY);
return 0;
}
diff --git a/vmeta_lib.h b/vmeta_lib.h
index 058d9c9..6226542 100644
--- a/vmeta_lib.h
+++ b/vmeta_lib.h
@@ -173,7 +173,13 @@ typedef sem_t lock_t;
//---------------------------------------------------------------------------
typedef struct vdec_os_driver_cb_s
{
- int uiofd; // the uio file descriptor
+ int fd; // kernel file descriptor
+ int uio; // using uio driver
+ struct {
+ UNSG32 phys;
+ UNSG32 size;
+ } map[3];
+
UNSG32 io_mem_phy_addr; // the physical addr of io register base
void *io_mem_virt_addr; // the reg base addr that maped from kernel
UNSG32 io_mem_size; // the size of io mem area