summaryrefslogtreecommitdiffstats
path: root/bltsville/gcbv/gcmain.c
diff options
context:
space:
mode:
Diffstat (limited to 'bltsville/gcbv/gcmain.c')
-rw-r--r--bltsville/gcbv/gcmain.c531
1 files changed, 531 insertions, 0 deletions
diff --git a/bltsville/gcbv/gcmain.c b/bltsville/gcbv/gcmain.c
new file mode 100644
index 0000000..7d8b0bd
--- /dev/null
+++ b/bltsville/gcbv/gcmain.c
@@ -0,0 +1,531 @@
+/*
+ * Copyright (c) 2012,
+ * Texas Instruments, Inc. and Vivante Corporation
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Texas Instruments, Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL TEXAS INSTRUMENTS, INC. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "gcmain.h"
+#include "gcbv.h"
+#include <semaphore.h>
+
+#if ANDROID
+#include <cutils/log.h>
+#include <cutils/process_name.h>
+#endif
+
+#define GCZONE_NONE 0
+#define GCZONE_ALL (~0U)
+#define GCZONE_INIT (1 << 0)
+#define GCZONE_CALLBACK (1 << 1)
+
+GCDBG_FILTERDEF(gcmain, GCZONE_NONE,
+ "init",
+ "callback")
+
+
+static int g_handle;
+
+
+/*******************************************************************************
+ * Callback manager.
+ */
+enum gccallbackinfo_status {
+ UNINIT,
+ SUPPORTED,
+ UNSUPPORTED
+};
+
+static const char * const g_statusNames[] = {
+ "UNINIT",
+ "SUPPORTED",
+ "UNSUPPORTED"
+};
+
+struct gccallbackinfo {
+ /* Callback status */
+ enum gccallbackinfo_status status;
+
+ /* Callback handle. */
+ unsigned long handle;
+
+ /* Termination semaphore. */
+ sem_t stop;
+
+ /* Callback thread handle. */
+ pthread_t thread;
+
+ /* Start/stop mutex */
+ pthread_mutex_t mutex;
+};
+
+struct gccallbackinfo g_callbackinfo = {
+ .status = UNINIT
+};
+
+static void *callbackthread(void *_gccallbackinfo)
+{
+ struct gccallbackinfo *gccallbackinfo;
+ struct gcicallbackwait gccmdcallbackwait;
+ int result;
+
+ /* Get callback info. */
+ gccallbackinfo = (struct gccallbackinfo *) _gccallbackinfo;
+
+ /* Initialize the command. */
+ gccmdcallbackwait.handle = gccallbackinfo->handle;
+ gccmdcallbackwait.timeoutms = 2000;
+
+ /* Enter wait loop. */
+ while (1) {
+ /* Call the kernel to wait for callback event. */
+ result = ioctl(g_handle, GCIOCTL_CALLBACK_WAIT,
+ &gccmdcallbackwait);
+ if (result == 0) {
+ if (gccmdcallbackwait.gcerror == GCERR_NONE) {
+ /* Work completed. */
+ GCDBG(GCZONE_CALLBACK,
+ "callback 0x%08X(0x%08X).\n",
+ (unsigned int)
+ gccmdcallbackwait.callback,
+ (unsigned int)
+ gccmdcallbackwait.callbackparam);
+
+ /* Invoke the callback. */
+ gccmdcallbackwait.callback(
+ gccmdcallbackwait.callbackparam);
+ } else if (gccmdcallbackwait.gcerror == GCERR_TIMEOUT) {
+ /* Timeout. */
+ GCDBG(GCZONE_CALLBACK,
+ "callback wait timeout.\n");
+ } else {
+ /* Error occurred. */
+ GCERR("callback wait failed (0x%08X).\n",
+ gccmdcallbackwait.gcerror);
+ break;
+ }
+ } else if (result != -EINTR) {
+ GCERR("callback wait ioctl failed (%d).\n", result);
+ break;
+ }
+
+ /* Stop requested? */
+ if (sem_trywait(&gccallbackinfo->stop) == 0) {
+ GCDBG(GCZONE_CALLBACK, "terminating.\n");
+ break;
+ }
+ }
+
+ return NULL;
+}
+
+static int callback_start(struct gccallbackinfo *gccallbackinfo)
+{
+ int result = 0;
+ struct gcicallback gccmdcallback;
+
+ GCENTER(GCZONE_CALLBACK);
+
+ pthread_mutex_lock(&gccallbackinfo->mutex);
+
+ if (gccallbackinfo->status != UNINIT) {
+ pthread_mutex_unlock(&gccallbackinfo->mutex);
+ return 0;
+ }
+
+ gccmdcallback.handle = 0;
+
+ gccallbackinfo->status =
+#if ANDROID
+ /* The Android zygote process refuses to fork if there is
+ * more than one thread present. */
+ (strcmp(get_process_name(), "zygote") == 0) ? UNSUPPORTED :
+#endif
+ SUPPORTED;
+
+ GCDBG(GCZONE_CALLBACK, "callback status: %s\n",
+ g_statusNames[gccallbackinfo->status]);
+
+ if (gccallbackinfo->status == SUPPORTED) {
+ /* Initialize callback. */
+ result = ioctl(g_handle,
+ GCIOCTL_CALLBACK_ALLOC,
+ &gccmdcallback);
+ if (result != 0) {
+ GCERR("callback ioctl failed (%d).\n", result);
+ goto fail;
+ }
+
+ if (gccmdcallback.gcerror != GCERR_NONE) {
+ GCERR("failed to initialize callback "
+ "mechanism (0x%08X).\n",
+ gccmdcallback.gcerror);
+ goto fail;
+ }
+
+ gccallbackinfo->handle = gccmdcallback.handle;
+
+ /* Initialize the termination semaphore. */
+ result = sem_init(&gccallbackinfo->stop, 0, 0);
+ if (result != 0) {
+ GCERR("callback semaphore init failed (%d).\n", result);
+ goto fail;
+ }
+
+ /* Start the thread. */
+ result = pthread_create(&gccallbackinfo->thread, NULL,
+ callbackthread, gccallbackinfo);
+ if (result != 0) {
+ GCERR("failed to start callback thread.\n");
+ goto fail;
+ }
+
+ gccmdcallback.handle = 0;
+ }
+
+fail:
+ if (gccmdcallback.handle != 0) {
+ ioctl(g_handle, GCIOCTL_CALLBACK_FREE, &gccmdcallback);
+ gccallbackinfo->handle = 0;
+ }
+
+ pthread_mutex_unlock(&gccallbackinfo->mutex);
+
+ GCEXITARG(GCZONE_CALLBACK, "result=%d", result);
+ return result;
+}
+
+static void callback_stop(struct gccallbackinfo *gccallbackinfo)
+{
+ struct gcicallback gccmdcallback;
+
+ GCENTER(GCZONE_CALLBACK);
+
+ pthread_mutex_lock(&gccallbackinfo->mutex);
+
+ if (gccallbackinfo->status == SUPPORTED) {
+ if (gccallbackinfo->thread) {
+ sem_post(&gccallbackinfo->stop);
+ pthread_kill(gccallbackinfo->thread, SIGINT);
+
+ GCDBG(GCZONE_CALLBACK,
+ "waiting to join callback thread...\n");
+
+ pthread_join(gccallbackinfo->thread, NULL);
+ gccallbackinfo->thread = 0;
+ }
+
+ /* Free kernel resources. */
+ gccmdcallback.handle = gccallbackinfo->handle;
+ ioctl(g_handle, GCIOCTL_CALLBACK_FREE, &gccmdcallback);
+ gccallbackinfo->handle = 0;
+ }
+
+ gccallbackinfo->status == UNINIT;
+
+ pthread_mutex_unlock(&gccallbackinfo->mutex);
+
+ GCEXIT(GCZONE_CALLBACK);
+}
+
+
+/*******************************************************************************
+ * IOCTL wrappers.
+ */
+
+#if GCDEBUG_ENABLE && 0
+#define GCPRINTDELAY() sleep(1)
+#else
+#define GCPRINTDELAY()
+#endif
+
+void gc_getcaps_wrapper(struct gcicaps *gcicaps)
+{
+ int result;
+
+ GCPRINTDELAY();
+
+ result = ioctl(g_handle, GCIOCTL_GETCAPS, gcicaps);
+ if (result != 0) {
+ GCERR("ioctl failed (%d).\n", result);
+ gcicaps->gcerror = GCERR_IOCTL;
+ }
+}
+
+void gc_map_wrapper(struct gcimap *gcmap)
+{
+ int result;
+
+ GCPRINTDELAY();
+ result = ioctl(g_handle, GCIOCTL_MAP, gcmap);
+
+ if (result != 0) {
+ GCERR("ioctl failed (%d).\n", result);
+ gcmap->gcerror = GCERR_IOCTL;
+ }
+}
+
+void gc_unmap_wrapper(struct gcimap *gcmap)
+{
+ int result;
+
+ GCPRINTDELAY();
+ result = ioctl(g_handle, GCIOCTL_UNMAP, gcmap);
+
+ if (result != 0) {
+ GCERR("ioctl failed (%d).\n", result);
+ gcmap->gcerror = GCERR_IOCTL;
+ }
+}
+
+void gc_commit_wrapper(struct gcicommit *gccommit)
+{
+ int result;
+
+ GCPRINTDELAY();
+
+ /* Callback start is delayed until needed to handle a case
+ * where it's unsupported on Android. */
+ if (gccommit->callback)
+ callback_start(&g_callbackinfo);
+
+ gccommit->handle = g_callbackinfo.handle;
+ result = ioctl(g_handle, GCIOCTL_COMMIT, gccommit);
+
+ if (result != 0) {
+ GCERR("ioctl failed (%d).\n", result);
+ gccommit->gcerror = GCERR_IOCTL;
+ }
+}
+
+void gc_callback_wrapper(struct gcicallbackarm *gcicallbackarm)
+{
+ int result;
+
+ GCPRINTDELAY();
+
+ callback_start(&g_callbackinfo);
+
+ gcicallbackarm->handle = g_callbackinfo.handle;
+ result = ioctl(g_handle, GCIOCTL_CALLBACK_ARM, gcicallbackarm);
+ if (result != 0) {
+ GCERR("ioctl failed (%d).\n", result);
+ gcicallbackarm->gcerror = GCERR_IOCTL;
+ }
+}
+
+
+/*******************************************************************************
+ * Convert floating point in 0..1 range to an 8-bit value in range 0..255.
+ */
+
+union gcfp {
+ struct {
+ unsigned int mantissa:23;
+ unsigned int exponent:8;
+ unsigned int sign:1;
+ } comp;
+
+ float value;
+};
+
+unsigned char gcfp2norm8(float value)
+{
+ union gcfp gcfp;
+ int exponent;
+ unsigned int mantissa;
+ int shift;
+
+ /* Get access to components. */
+ gcfp.value = value;
+
+ /* Clamp negatives. */
+ if (gcfp.comp.sign)
+ return 0;
+
+ /* Get unbiased exponent. */
+ exponent = (int) gcfp.comp.exponent - 127;
+
+ /* Clamp if too large. */
+ if (exponent >= 0)
+ return 255;
+
+ /* Clamp if too small. */
+ if (exponent < -8)
+ return 0;
+
+ /* Determine the shift value. */
+ shift = (23 - 8) - exponent;
+
+ /* Compute the mantissa. */
+ mantissa = (gcfp.comp.mantissa | 0x00800000) >> shift;
+
+ /* Normalize. */
+ mantissa = (mantissa * 255) >> 8;
+
+ return (unsigned char) mantissa;
+}
+
+
+/*******************************************************************************
+ * Surface allocation.
+ */
+
+enum bverror allocate_surface(struct bvbuffdesc **bvbuffdesc,
+ void **buffer,
+ unsigned int size)
+{
+ enum bverror bverror = BVERR_NONE;
+ struct bvbuffdesc *tempbuffdesc = NULL;
+ void *tempbuff = NULL;
+ unsigned long base;
+
+ /* Allocate surface buffer descriptor. */
+ tempbuffdesc = gcalloc(struct bvbuffdesc, sizeof(struct bvbuffdesc));
+ if (tempbuffdesc == NULL) {
+ BVSETERROR(BVERR_OOM, "failed to allocate surface");
+ goto exit;
+ }
+
+ /* Initialize buffer descriptor. */
+ tempbuffdesc->structsize = sizeof(struct bvbuffdesc);
+ tempbuffdesc->virtaddr = NULL;
+ tempbuffdesc->length = size;
+ tempbuffdesc->map = NULL;
+ tempbuffdesc->auxtype = BVAT_NONE;
+ tempbuffdesc->auxptr = NULL;
+
+ /* Allocate the surface. */
+ tempbuff = gcalloc(void, size + GC_MAX_BASE_ALIGN);
+ if (tempbuff == NULL) {
+ BVSETERROR(BVERR_OOM, "failed to allocate surface");
+ goto exit;
+ }
+
+ /* Align the base address. */
+ tempbuffdesc->virtaddr
+ = (void *) (((unsigned long) tempbuff + GC_MAX_BASE_ALIGN - 1)
+ & ~(GC_MAX_BASE_ALIGN - 1));
+
+ /* Set return pointers. */
+ *bvbuffdesc = tempbuffdesc;
+ *buffer = tempbuff;
+ return BVERR_NONE;
+
+exit:
+ free_surface(tempbuffdesc, tempbuff);
+ return bverror;
+}
+
+void free_surface(struct bvbuffdesc *bvbuffdesc,
+ void *buffer)
+{
+ gcfree(buffer);
+ gcfree(bvbuffdesc);
+}
+
+
+/*******************************************************************************
+ * Cache operation wrapper.
+ */
+
+enum bverror gcbvcacheop(int count, struct c2dmrgn rgn[],
+ enum bvcacheop cacheop)
+{
+ int result;
+ struct gcicache xfer;
+
+ if ((count < 0) || (count > 3))
+ return BVERR_CACHEOP;
+
+ xfer.count = count;
+ xfer.dir = cacheop;
+ memcpy(xfer.rgn, rgn, count * sizeof(struct c2dmrgn));
+
+ GCPRINTDELAY();
+ result = ioctl(g_handle, GCIOCTL_CACHE, &xfer);
+
+ if (result != 0)
+ GCERR("ioctl failed (%d).\n", result);
+
+ return BVERR_NONE;
+}
+
+
+/*******************************************************************************
+ * Device init/cleanup.
+ */
+
+void __attribute__((constructor)) dev_init(void)
+{
+ char *env;
+
+ env = getenv("GCBV_DEBUG");
+ if (env && (atol(env) != 0))
+ GCDBG_ENABLEDUMP();
+
+ GCDBG_INIT();
+ GCDBG_REGISTER(gcmain);
+
+ GCENTER(GCZONE_INIT);
+
+ g_handle = open("/dev/gcioctl", O_RDWR);
+ if (g_handle == -1) {
+ GCERR("failed to open device (%d).\n", errno);
+ goto fail;
+ }
+
+ bv_init();
+
+ pthread_mutex_init(&g_callbackinfo.mutex, 0);
+
+ GCEXIT(GCZONE_INIT);
+ return;
+
+fail:
+ if (g_handle > 0) {
+ close(g_handle);
+ g_handle = 0;
+ }
+
+ GCEXIT(GCZONE_INIT);
+}
+
+void __attribute__((destructor)) dev_exit(void)
+{
+ GCENTER(GCZONE_INIT);
+
+ bv_exit();
+ callback_stop(&g_callbackinfo);
+
+ if (g_handle != 0) {
+ close(g_handle);
+ g_handle = 0;
+ }
+
+ GCEXIT(GCZONE_INIT);
+ GCDBG_EXIT();
+}
+