Index: libs/libmythtv/videoout_ivtv.h
===================================================================
--- libs/libmythtv/videoout_ivtv.h	(revision 13482)
+++ libs/libmythtv/videoout_ivtv.h	(working copy)
@@ -1,12 +1,22 @@
 #ifndef VIDEOOUT_IVTV_H_
 #define VIDEOOUT_IVTV_H_
 
+// Linux system headers
+#include <linux/fb.h>
+
+// Qt headers
 #include <qstring.h>
 #include <qmutex.h>
-#include <cassert>
 
+// MythTV headers
 #include "videooutbase.h"
 
+#ifdef USING_IVTV_HEADER
+#include <linux/ivtv.h>
+#else
+#include "ivtv_myth.h"
+#endif
+
 class NuppelVideoPlayer;
 
 class VideoOutputIvtv: public VideoOutput
@@ -108,6 +118,14 @@
     bool last_normal;
     int last_mask;
     eAlphaState alphaState;
+
+    bool old_ioctl;
+    struct fb_var_screeninfo ivtvfb_var;
+    struct fb_var_screeninfo ivtvfb_var_old;
+#ifdef IVTVFB_IOCTL_GET_COLORKEY
+    struct ivtvfb_ioctl_colorkey ivtvfb_colorkey;
+    struct ivtvfb_ioctl_colorkey ivtvfb_colorkey_old;
+#endif
 };
 
 #endif
Index: libs/libmythtv/videoout_ivtv.cpp
===================================================================
--- libs/libmythtv/videoout_ivtv.cpp	(revision 13482)
+++ libs/libmythtv/videoout_ivtv.cpp	(working copy)
@@ -73,7 +73,7 @@
 
     last_normal(true),        last_mask(0x2),
 
-    alphaState(kAlpha_Solid)
+    alphaState(kAlpha_Solid), old_ioctl(true)
 {
 }
 
@@ -103,23 +103,32 @@
 
     VERBOSE(VB_PLAYBACK, LOC + "ClearOSD");
 
-    struct ivtv_osd_coords osdcoords;
-    bzero(&osdcoords, sizeof(osdcoords));
+    bzero(osdbuf_aligned, osdbufsize);
 
-    if (ioctl(fbfd, IVTVFB_IOCTL_GET_ACTIVE_BUFFER, &osdcoords) < 0)
-    {
-        VERBOSE(VB_IMPORTANT, LOC_ERR +
-                "Failed to get active buffer for ClearOSD()" + ENO);
-    }
     struct ivtvfb_ioctl_dma_host_to_ivtv_args prep;
     bzero(&prep, sizeof(prep));
 
     prep.source = osdbuf_aligned;
     prep.dest_offset = 0;
-    prep.count = osdcoords.max_offset;
 
-    bzero(osdbuf_aligned, osdbufsize);
+    if (old_ioctl == true)
+    {
+        struct ivtv_osd_coords osdcoords;
+        bzero(&osdcoords, sizeof(osdcoords));
 
+        if (ioctl(fbfd, IVTVFB_IOCTL_GET_ACTIVE_BUFFER, &osdcoords) < 0)
+        {
+            VERBOSE(VB_IMPORTANT, LOC_ERR +
+                    "Failed to get active buffer for ClearOSD()" + ENO);
+        }
+        prep.count = osdcoords.max_offset;
+    }
+    else
+        prep.count = ivtvfb_var.xres_virtual * ivtvfb_var.yres * (ivtvfb_var.bits_per_pixel / 8); 
+
+    if (old_ioctl == false)
+        ioctl(fbfd, FBIOPAN_DISPLAY, &ivtvfb_var);
+
     if (ioctl(fbfd, IVTVFB_IOCTL_PREP_FRAME, &prep) < 0)
         VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to prepare frame" + ENO);
 }
@@ -140,14 +149,12 @@
         VERBOSE(VB_PLAYBACK, LOC + "SetAlpha(Embedded)");
 #endif
 
-    alphaState = newAlphaState;
-
     struct ivtvfb_ioctl_state_info fbstate;
     bzero(&fbstate, sizeof(fbstate));
     if (ioctl(fbfd, IVTVFB_IOCTL_GET_STATE, &fbstate) < 0)
         VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to query alpha state" + ENO);
 
-    if (alphaState == kAlpha_Local)
+    if (newAlphaState == kAlpha_Local)
     {
         fbstate.status &= ~IVTVFB_STATUS_GLOBAL_ALPHA;
         fbstate.status |= IVTVFB_STATUS_LOCAL_ALPHA;
@@ -158,16 +165,60 @@
         fbstate.status &= ~IVTVFB_STATUS_LOCAL_ALPHA;
     }
 
-    if (alphaState == kAlpha_Solid)
+    if (newAlphaState == kAlpha_Solid)
         fbstate.alpha = 255;
-    else if (alphaState == kAlpha_Clear)
+    else if (newAlphaState == kAlpha_Clear)
         fbstate.alpha = 0;
-    else if (alphaState == kAlpha_Embedded)
+    else if (newAlphaState == kAlpha_Embedded)
         fbstate.alpha = gContext->GetNumSetting("PVR350EPGAlphaValue", 164);
 
+    // If using the new ioctl we need to check the fb mode
+    if (old_ioctl == false)
+    {
+        struct fb_var_screeninfo *tmpfb_var = NULL;
+
+        // If EPG switched on, select old fb mode
+        if (newAlphaState == kAlpha_Embedded)
+            tmpfb_var = &ivtvfb_var_old;
+        // If EPG switched off, select new fb mode
+        else if (newAlphaState != kAlpha_Embedded && alphaState == kAlpha_Embedded)
+            tmpfb_var = &ivtvfb_var;
+
+        // Change fb mode if required
+        if (tmpfb_var)
+        {
+            if ((ivtvfb_var_old.bits_per_pixel != 32) &&
+                 (ivtvfb_var_old.bits_per_pixel != 8))
+            {
+                // Hide osd during mode change
+#ifdef FB_BLANK_NORMAL
+                ioctl(fbfd, FBIOBLANK, FB_BLANK_NORMAL);
+#else
+                ioctl(fbfd, FBIOBLANK, VESA_VSYNC_SUSPEND);
+#endif
+                tmpfb_var->activate = FB_ACTIVATE_NOW;
+                if (ioctl(fbfd, FBIOPUT_VSCREENINFO, tmpfb_var) < 0)
+                    VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to switch framebuffer settings for EPG" + ENO);
+
+                // Restore osd
+#ifdef FB_BLANK_UNBLANK
+                ioctl(fbfd, FBIOBLANK, FB_BLANK_UNBLANK);
+#else
+                ioctl(fbfd, FBIOBLANK, VESA_NO_BLANKING);
+#endif
+            }
+            // Reset display pan
+            ivtvfb_var.xoffset = 0;
+            ivtvfb_var.yoffset = 0;
+            ioctl(fbfd, FBIOPAN_DISPLAY, &ivtvfb_var);
+        }
+    }
+
     if (ioctl(fbfd, IVTVFB_IOCTL_SET_STATE, &fbstate) < 0)
         VERBOSE(VB_IMPORTANT, LOC_ERR +
                 "Failed to set ivtv alpha values." + ENO);
+
+    alphaState = newAlphaState;
 }
 
 void VideoOutputIvtv::InputChanged(int width, int height, float aspect,
@@ -244,10 +295,22 @@
         bzero(&igfb, sizeof(igfb));
 
         if (ioctl(fbfd, IVTVFB_IOCTL_GET_FRAME_BUFFER, &igfb) < 0)
-            VERBOSE(VB_IMPORTANT, LOC_ERR + "Getting frame buffer" + ENO);
+        {
+            if (errno == EINVAL)
+            {
+                struct fb_fix_screeninfo ivtvfb_fix;
+                if (ioctl(fbfd, FBIOGET_FSCREENINFO, &ivtvfb_fix) < 0)
+                    VERBOSE(VB_IMPORTANT, LOC_ERR + "Getting frame buffer" + ENO);
+                else
+                {
+                    old_ioctl = false;
+                    ioctl(fbfd, FBIOGET_VSCREENINFO, &ivtvfb_var_old);
+                }
+            }
+            else
+                VERBOSE(VB_IMPORTANT, LOC_ERR + "Getting frame buffer" + ENO);
+        }
 
-        stride = igfb.sizex * 4;
-
         long pagesize = sysconf(_SC_PAGE_SIZE);
         long pagemask = ~(pagesize-1);
         osdbuffer = new char[osdbufsize + pagesize];
@@ -256,17 +319,59 @@
 
         bzero(osdbuf_aligned, osdbufsize);
 
-        ClearOSD();
+        if (old_ioctl == true)
+        {
+            struct ivtv_osd_coords osdcoords;
+            stride = igfb.sizex * 4;
+            bzero(&osdcoords, sizeof(osdcoords));
+            osdcoords.lines = video_dim.height();
+            osdcoords.offset = 0;
+            osdcoords.pixel_stride = video_dim.width() * 2;
+            if (ioctl(fbfd, IVTVFB_IOCTL_SET_ACTIVE_BUFFER, &osdcoords) < 0)
+                VERBOSE(VB_IMPORTANT, LOC_ERR + "Setting active buffer" + ENO);
+        }
+        else
+        {
+            bzero (&ivtvfb_var, sizeof(ivtvfb_var));
 
-        struct ivtv_osd_coords osdcoords;
-        bzero(&osdcoords, sizeof(osdcoords));
-        osdcoords.lines = video_dim.height();
-        osdcoords.offset = 0;
-        osdcoords.pixel_stride = video_dim.width() * 2;
+            // Switch dimensions to match the framebuffer
+            video_dim = QSize(ivtvfb_var_old.xres, ivtvfb_var_old.yres);
 
-        if (ioctl(fbfd, IVTVFB_IOCTL_SET_ACTIVE_BUFFER, &osdcoords) < 0)
-            VERBOSE(VB_IMPORTANT, LOC_ERR + "Setting active buffer" + ENO);
+            memcpy(&ivtvfb_var,&ivtvfb_var_old,sizeof ivtvfb_var);
 
+            // The OSD only supports 32bpp, so only change mode if needed
+            if (ivtvfb_var_old.bits_per_pixel != 32)
+            {
+                ivtvfb_var.xres_virtual = ivtvfb_var.xres;
+                ivtvfb_var.yres_virtual = ivtvfb_var.yres;
+                ivtvfb_var.xoffset = 0;
+                ivtvfb_var.yoffset = 0;
+                ivtvfb_var.bits_per_pixel = 32;
+                ivtvfb_var.nonstd = 0;
+                ivtvfb_var.activate = FB_ACTIVATE_NOW;
+
+                if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &ivtvfb_var) < 0)
+                    VERBOSE(VB_IMPORTANT, LOC_ERR + "Setting frame buffer" + ENO);
+            }
+            else
+            {
+                ivtvfb_var.xoffset = 0;
+                ivtvfb_var.yoffset = 0;
+                ioctl(fbfd, FBIOPAN_DISPLAY, &ivtvfb_var);
+            }
+
+            stride = ivtvfb_var.xres_virtual * 4;
+        }
+
+#ifdef IVTVFB_IOCTL_GET_COLORKEY
+        // Setup color-key. This helps when X isn't running on the PVR350
+        ioctl(fbfd,IVTVFB_IOCTL_GET_COLORKEY, &ivtvfb_colorkey_old);
+        ivtvfb_colorkey.state = 1;
+        ivtvfb_colorkey.colorKey = 0x00010001;
+        ioctl(fbfd,IVTVFB_IOCTL_SET_COLORKEY, &ivtvfb_colorkey);
+#endif
+        ClearOSD();
+
         SetAlpha(kAlpha_Clear);
     }
 
@@ -286,6 +391,18 @@
     {
         Stop(true /* hide */);
 
+        if (old_ioctl == false)
+        {
+            ivtvfb_var_old.activate = FB_ACTIVATE_NOW;
+
+            if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &ivtvfb_var_old) < 0)
+                VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to restore framebuffer settings" + ENO);
+        }
+
+#ifdef IVTVFB_IOCTL_GET_COLORKEY
+        // Restore old colorkey
+        ioctl(fbfd,IVTVFB_IOCTL_SET_COLORKEY, &ivtvfb_colorkey_old);
+#endif
         close(videofd);
         videofd = -1;
     }
@@ -450,7 +567,7 @@
 
     VideoFrame tmpframe;
     init(&tmpframe, FMT_ARGB32, (unsigned char *)osdbuf_aligned,
-         stride, video_dim.height(), 32, 4 * stride * video_dim.height());
+         stride, video_dim.height(), 32, stride * video_dim.height());
 
     OSDSurface *surface = NULL;
     if (osd)
@@ -506,22 +623,28 @@
     pipon = (bool) pipPlayer;
 
     // If there is an OSD, make sure we draw OSD surface
-    lastcleared &= !osd;
+    lastcleared &= !osdon;
 
-#if 0
-// These optimizations have been disabled until someone with a real PVR-350
-// setup can test them Feb 7th, 2006 -- dtk
     // If nothing on OSD surface, just set the alpha to zero
-    if (lastcleared && drawanyway)
+    if (!osdon && !pipon)
     {
+        if (lastcleared == true)
+            return;
+
+        lastcleared = true;
         SetAlpha(kAlpha_Clear);
-        return;
+#ifdef IVTVFB_IOCTL_GET_COLORKEY
+#ifdef WORDS_BIGENDIAN
+        wmemset((wchar_t *)osdbuf_aligned, 0x01000100, osdbufsize/4);
+#else
+        wmemset((wchar_t *)osdbuf_aligned, 0x00010001, osdbufsize/4);
+#endif 
+#endif
     }
 
     // If there has been no OSD change and no draw has been forced we're done
     if (ret <= 0 && !drawanyway)
         return;
-#endif
 
     // The OSD surface needs to be updated...
     struct ivtvfb_ioctl_dma_host_to_ivtv_args prep;
@@ -529,10 +652,34 @@
     prep.source = osdbuf_aligned;
     prep.count  = video_dim.height() * stride;
 
+    // This shouldn't be here. OSD should be rendered correctly to start with
+#ifdef WORDS_BIGENDIAN
+    int b_index, i_index;
+    unsigned int *osd_int = (unsigned int *)osdbuf_aligned;
+    if (lastcleared != true)
+    {
+        for (b_index = 0, i_index = 0; b_index < prep.count; b_index += 4, i_index ++)
+        {
+            if (osd_int[i_index])
+            {
+                osd_int[i_index] =
+                        ((unsigned char)osdbuf_aligned[b_index+0]) |
+                        ((unsigned char)osdbuf_aligned[b_index+1] << 8) |
+                        ((unsigned char)osdbuf_aligned[b_index+2] << 16) |
+                        ((unsigned char)osdbuf_aligned[b_index+3] << 24);
+            }
+        }
+    }
+#endif
+
+    if (old_ioctl == false)
+        ioctl(fbfd, FBIOPAN_DISPLAY, &ivtvfb_var);
+
     if (ioctl(fbfd, IVTVFB_IOCTL_PREP_FRAME, &prep) < 0)
         VERBOSE(VB_IMPORTANT, LOC_ERR + "Failed to process frame" + ENO);
 
-    SetAlpha(kAlpha_Local);
+    if (lastcleared != true)
+        SetAlpha(kAlpha_Local);
 }
 
 /** \fn VideoOutputIvtv::Start(int,int)
