summaryrefslogtreecommitdiff
path: root/src/setres.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/setres.c')
-rw-r--r--src/setres.c400
1 files changed, 400 insertions, 0 deletions
diff --git a/src/setres.c b/src/setres.c
new file mode 100644
index 0000000..1bf566f
--- /dev/null
+++ b/src/setres.c
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ * Author: Per Persson per.xb.persson@stericsson.com for
+ * ST-Ericsson.
+ * License terms: <FOSS license>.
+ */
+
+#include <unistd.h> /* Symbolic Constants */
+#include <sys/types.h> /* Primitive System Data Types */
+#include <errno.h> /* Errors */
+#include <stdarg.h>
+#include <stdio.h> /* Input/Output */
+#include <stdlib.h> /* General Utilities */
+#include <string.h> /* String handling */
+#include <fcntl.h>
+#include <time.h>
+#include <ctype.h>
+#include "linux/fb.h"
+#include <utils/Log.h>
+#include "../include/hdmi_service_api.h"
+#include "../include/hdmi_service_local.h"
+
+/* List of cea numbers. First ceanr has highest priority */
+struct vesacea vesaceaprio[CEAPRIO_MAX_SIZE];
+
+/*
+ * During edid_parse, sink_support will be filled in.
+ * The first format in this list with sink_support set will be chosen.
+ */
+int video_formats_nr;
+struct video_format video_formats[FORMATS_MAX];
+
+int video_formats_clear(void)
+{
+ memset(video_formats, 0, sizeof(video_formats));
+ return 0;
+}
+
+int vesacea_supported(int *nr, struct vesacea vesacea[])
+{
+ int index;
+
+ *nr = 0;
+ LOGHDMILIB2("%s begin", __func__);
+ for (index = 0; index < FORMATS_MAX; index++) {
+ if (video_formats[index].sink_support) {
+ vesacea[*nr].cea = video_formats[index].cea;
+ vesacea[*nr].nr = video_formats[index].vesaceanr;
+ LOGHDMILIB2("cea:%d nr:%d", vesacea[*nr].cea, vesacea[*nr].nr);
+ (*nr)++;
+ }
+ }
+ LOGHDMILIB2("%s end", __func__);
+ return 0;
+}
+
+int video_formats_supported_hw(void)
+{
+ int res;
+ int index;
+ int vesacea;
+ char buf[FORMATS_MAX * 2 + 1];
+
+ /* Get hw supported formats */
+ vesacea = open(VESACEAFORMATS_FILE, O_RDONLY);
+ if (vesacea < 0) {
+ LOGHDMILIB("***** Failed to open %s *****",
+ VESACEAFORMATS_FILE);
+ return -1;
+ }
+
+ res = read(vesacea, buf, sizeof(buf));
+ close(vesacea);
+ if (res <= 0) {
+ LOGHDMILIB("***** Failed to read %s *****",
+ VESACEAFORMATS_FILE);
+ return -1;
+ }
+
+ for (index = 0; index < FORMATS_MAX; index++) {
+ if ((index * 2 + 2) > res) {
+ /* No more to read */
+ video_formats[index].cea = 0;
+ video_formats[index].vesaceanr = 0;
+ video_formats[index].sink_support = 0;
+ video_formats[index].prio = VESACEAPRIO_DEFAULT;
+ break;
+ }
+ video_formats[index].cea = *(buf + index * 2);
+ video_formats[index].vesaceanr = *(buf + index * 2 + 1);
+ video_formats[index].sink_support = 0;
+ video_formats[index].prio = VESACEAPRIO_DEFAULT;
+ }
+ video_formats_nr = index;
+ return 0;
+}
+
+int nr_formats_get(void)
+{
+ return video_formats_nr;
+}
+
+struct video_format *video_formats_get(void)
+{
+ return video_formats;
+}
+
+static int vesaceanrtovar(struct fb_var_screeninfo *var, __u8 cea,
+ __u8 vesaceanr, __u8 num_buffers)
+{
+ int timing;
+ int res;
+ unsigned int index;
+ char buf[128];
+ int interlaced;
+
+ /* Request timing info */
+ timing = open(TIMING_FILE, O_RDWR);
+ if (timing < 0) {
+ LOGHDMILIB("***** Failed to open %s *****", TIMING_FILE);
+ return -1;
+ }
+ buf[0] = cea;
+ buf[1] = vesaceanr;
+ res = write(timing, buf, 2);
+ if (res <= 0) {
+ LOGHDMILIB("***** Failed to write %s *****", TIMING_FILE);
+ close(timing);
+ return -1;
+ }
+
+ lseek(timing, 0, SEEK_SET);
+ res = read(timing, buf, sizeof(buf));
+ close(timing);
+ if (res <= 0) {
+ LOGHDMILIB("***** Failed to read %s *****", TIMING_FILE);
+ return -1;
+ }
+
+ /* Read timing info */
+ if (res == TIMING_SIZE) {
+ index = 0;
+ memcpy(&var->xres, buf + index, 4);
+ LOGHDMILIB3("xres:%d", var->xres);
+ index += 4;
+ memcpy(&var->yres, buf + index, 4);
+ LOGHDMILIB3("yres:%d", var->yres);
+ index += 4;
+ var->xres_virtual = var->xres;
+ var->yres_virtual = var->yres * num_buffers;
+ memcpy(&var->pixclock, buf + index, 4);
+ LOGHDMILIB3("pixclock:%d", var->pixclock);
+ index += 4;
+ memcpy(&var->left_margin, buf + index, 4);
+ LOGHDMILIB3("left_margin:%d", var->left_margin);
+ index += 4;
+ memcpy(&var->right_margin, buf + index, 4);
+ LOGHDMILIB3("right_margin:%d", var->right_margin);
+ index += 4;
+ memcpy(&var->upper_margin, buf + index, 4);
+ LOGHDMILIB3("upper_margin:%d", var->upper_margin);
+ index += 4;
+ memcpy(&var->lower_margin, buf + index, 4);
+ LOGHDMILIB3("lower_margin:%d", var->lower_margin);
+ index += 4;
+ var->vmode &= ~FB_VMODE_INTERLACED;
+ memcpy(&interlaced, buf + index, 4);
+ LOGHDMILIB3("vmode:%x", var->vmode);
+ var->vmode |= interlaced ? FB_VMODE_INTERLACED :
+ FB_VMODE_NONINTERLACED;
+ LOGHDMILIB("CEA %d nr %d found\n", cea, vesaceanr);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static void vesacea_prio_default(void)
+{
+ /* 1920x1080P@30 */
+ vesaceaprio[0].cea = 1;
+ vesaceaprio[0].nr = 34;
+
+ /* 1920x1080P@25 */
+ vesaceaprio[1].cea = 1;
+ vesaceaprio[1].nr = 33;
+
+ /* 1920x1080P@24 */
+ vesaceaprio[2].cea = 1;
+ vesaceaprio[2].nr = 32;
+
+ /* 1920x1080I@60 */
+ vesaceaprio[3].cea = 1;
+ vesaceaprio[3].nr = 5;
+
+ /* 1920x1080I@30 */
+ vesaceaprio[4].cea = 1;
+ vesaceaprio[4].nr = 20;
+
+ /* 1280x720P@60 */
+ vesaceaprio[5].cea = 1;
+ vesaceaprio[5].nr = 4;
+
+ /* 1280x720P@50 */
+ vesaceaprio[6].cea = 1;
+ vesaceaprio[6].nr = 19;
+
+ /* 720x480P@60 */
+ vesaceaprio[7].cea = 1;
+ vesaceaprio[7].nr = 3;
+
+ /* end of list */
+ vesaceaprio[8].cea = 0;
+ vesaceaprio[8].nr = 0;
+}
+
+static void set_vesacea_prio(__u8 cea, __u8 vesaceanr, __u8 prio)
+{
+ int nr_formats = sizeof(video_formats)/sizeof(video_formats[0]);
+ int index;
+
+ for (index = 0; index < nr_formats; index++) {
+ if ((video_formats[index].cea == cea) &
+ (video_formats[index].vesaceanr == vesaceanr)) {
+ video_formats[index].prio = prio;
+ LOGHDMILIB("set_cea_prio %d %d", index, prio);
+ break;
+ }
+ }
+}
+
+void set_vesacea_prio_all(void)
+{
+ int index;
+
+ vesacea_prio_default();
+
+ /* Set cea prio. Continue until prio = 0 or maxsize */
+ for (index = 0; index < CEAPRIO_MAX_SIZE; index++) {
+ LOGHDMILIB("index:%d cea:%d prio:%d",
+ index,
+ vesaceaprio[index].cea,
+ vesaceaprio[index].nr);
+ if (vesaceaprio[index].nr == 0)
+ break;
+
+ set_vesacea_prio(vesaceaprio[index].cea,
+ vesaceaprio[index].nr,
+ index + 1);
+ }
+}
+
+int get_best_videoformat(__u8 *cea, __u8 *vesaceanr)
+{
+ int index;
+ int nr_formats;
+ struct video_format *video_formats;
+ __u8 best_prio;
+ int best_ceanr;
+ int best_vesanr;
+
+ *cea = 1;
+ *vesaceanr = VIDEO_FORMAT_DEFAULT;
+
+ nr_formats = nr_formats_get();
+ video_formats = video_formats_get();
+ best_prio = VESACEAPRIO_DEFAULT + 1;
+ best_ceanr = 0;
+ best_vesanr = 0;
+
+ /* Choose best video format */
+ for (index = 0; index < nr_formats; index++) {
+ LOGHDMILIB("test cea:%d nr:%d prio:%d",
+ video_formats[index].cea,
+ video_formats[index].vesaceanr,
+ video_formats[index].prio);
+ if (video_formats[index].sink_support == 0)
+ /* No sink support, check next format */
+ continue;
+
+ if (video_formats[index].prio < best_prio) {
+ /* Prio is best */
+ *cea = video_formats[index].cea;
+ *vesaceanr = video_formats[index].vesaceanr;
+ best_prio = video_formats[index].prio;
+ } else if (best_prio >= VESACEAPRIO_DEFAULT) {
+ /* Prio is not set; check ceanr */
+ if (video_formats[index].cea &&
+ (video_formats[index].vesaceanr >
+ best_ceanr)) {
+ /* It is the highest ceanr */
+ *cea = 1;
+ *vesaceanr = video_formats[index].vesaceanr;
+ best_ceanr = *vesaceanr;
+ }
+
+ /* If no cea has been chosen, check vesa */
+ if ((best_ceanr == 0) &
+ (!video_formats[index].cea &&
+ (video_formats[index].vesaceanr >
+ best_vesanr))) {
+ /* It is the highest veasanr */
+ *cea = 0;
+ *vesaceanr = video_formats[index].vesaceanr;
+ best_vesanr = *vesaceanr;
+ }
+ }
+ LOGHDMILIB("cea:%d nr:%d best_prio:%d",
+ *cea, *vesaceanr, best_prio);
+ }
+
+ return 0;
+}
+
+int hdmi_fb_chres(__u8 cea, __u8 vesaceanr)
+{
+ struct fb_var_screeninfo var;
+ int fd;
+ char fbname[128];
+ char buf[128];
+ int read_res;
+ int disponoff;
+ __u8 num_buffers;
+
+ /* Get fb dev name */
+ disponoff = open(DISPONOFF_FILE, O_RDONLY);
+ if (disponoff < 0) {
+ LOGHDMILIB("***** Failed to open %s *****", DISPONOFF_FILE);
+ return -1;
+ }
+
+ read_res = read(disponoff, buf, sizeof(buf));
+ close(disponoff);
+ if (read_res <= 0) {
+ LOGHDMILIB("***** Failed to read %s *****", DISPONOFF_FILE);
+ return -1;
+ }
+
+ /* Open fb */
+ sprintf(fbname, "%s%s", FBPATH, buf);
+ LOGHDMILIB("fbname:%s", fbname);
+ fd = open(fbname, O_RDONLY);
+ if (fd <= 0) {
+ LOGHDMILIB("%s", "***** Open fb failed *****");
+ return -2;
+ }
+
+ /* Get screen info */
+ if (ioctl(fd, FBIOGET_VSCREENINFO, &var)) {
+ LOGHDMILIB("%s", "***** FBIOGET_VSCREENINFO failed *****");
+ close(fd);
+ return -3;
+ }
+
+ num_buffers = var.yres_virtual / var.yres;
+ /* Convert ceanr to screeninfo */
+ vesaceanrtovar(&var, cea, vesaceanr, num_buffers);
+
+ /* Set screen info */
+ if (ioctl(fd, FBIOPUT_VSCREENINFO, &var)) {
+ LOGHDMILIB("%s", "***** FBIOPUT_VSCREENINFO failed *****");
+ close(fd);
+ return -4;
+ }
+
+ /* Close fb */
+ close(fd);
+ return 0;
+}
+
+int vesaceaprio_set(__u8 len, __u8 *data)
+{
+ int index;
+ int index_last;
+ int cnt = 0;
+
+ LOGHDMILIB("%s begin", __func__);
+
+ if (len < CEAPRIO_MAX_SIZE)
+ index_last = len;
+ else
+ index_last = CEAPRIO_MAX_SIZE;
+
+ for (index = 0; index < CEAPRIO_MAX_SIZE; index++) {
+ if (index < index_last) {
+ vesaceaprio[index].cea = data[index * 2];
+ vesaceaprio[index].nr = data[index * 2 + 1];
+ LOGHDMILIB("prio:%d cea:%d nr:%d", cnt,
+ vesaceaprio[index].cea,
+ vesaceaprio[index].nr);
+ } else {
+ vesaceaprio[index].cea = 0;
+ vesaceaprio[index].nr = 0;
+ break;
+ }
+ cnt++;
+ }
+
+ LOGHDMILIB("%s end", __func__);
+ return 0;
+}