]> err.no Git - linux-2.6/blobdiff - drivers/media/video/ivtv/ivtv-fb.c
V4L/DVB (6090): ivtv-fb: correct transparency bit reporting
[linux-2.6] / drivers / media / video / ivtv / ivtv-fb.c
index 55265bd5c2505e7ec75832bd846138177900ccea..7618cd47a35de05e85e15806572f05ea8a6f8f79 100644 (file)
 #endif
 
 #include "ivtv-driver.h"
-#include "ivtv-queue.h"
 #include "ivtv-udma.h"
-#include "ivtv-irq.h"
-#include "ivtv-fileops.h"
 #include "ivtv-mailbox.h"
-#include "ivtv-cards.h"
 #include <media/ivtv-fb.h>
 
 /* card parameters */
@@ -164,11 +160,6 @@ MODULE_LICENSE("GPL");
 #define IVTV_OSD_BPP_32     0x04
 
 struct osd_info {
-       /* Timing info for modes */
-       u32 pixclock;
-       u32 hlimit;
-       u32 vlimit;
-
        /* Physical base address */
        unsigned long video_pbase;
        /* Relative base address (relative to start of decoder memory) */
@@ -185,6 +176,9 @@ struct osd_info {
        unsigned long fb_end_aligned_physaddr;
 #endif
 
+       /* Current osd mode */
+       int osd_mode;
+
        /* Store the buffer offset */
        int set_osd_coords_x;
        int set_osd_coords_y;
@@ -350,6 +344,7 @@ static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
                              unsigned long dest_offset, int count)
 {
        DEFINE_WAIT(wait);
+       struct osd_info *oi = itv->osd_info;
 
        /* Nothing to do */
        if (count == 0) {
@@ -358,9 +353,9 @@ static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
        }
 
        /* Check Total FB Size */
-       if ((dest_offset + count) > itv->osd_info->video_buffer_size) {
+       if ((dest_offset + count) > oi->video_buffer_size) {
                IVTV_FB_WARN("ivtv_fb_prep_frame: Overflowing the framebuffer %ld, only %d available\n",
-                       dest_offset + count, itv->osd_info->video_buffer_size);
+                       dest_offset + count, oi->video_buffer_size);
                return -E2BIG;
        }
 
@@ -387,7 +382,7 @@ static int ivtv_fb_prep_frame(struct ivtv *itv, int cmd, void __user *source,
        }
 
        /* OSD Address to send DMA to */
-       dest_offset += IVTV_DEC_MEM_START + itv->osd_info->video_rbase;
+       dest_offset += IVTV_DEC_MEM_START + oi->video_rbase;
 
        /* Fill Buffers */
        return ivtv_fb_prep_dec_dma_to_device(itv, dest_offset, source, count);
@@ -420,7 +415,7 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar
 
                case FBIO_WAITFORVSYNC:
                        prepare_to_wait(&itv->vsync_waitq, &wait, TASK_INTERRUPTIBLE);
-                       if (!schedule_timeout(HZ/20)) rc = -ETIMEDOUT;
+                       if (!schedule_timeout(msecs_to_jiffies(50))) rc = -ETIMEDOUT;
                        finish_wait(&itv->vsync_waitq, &wait);
                        return rc;
 
@@ -435,7 +430,7 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar
                }
 
                default:
-                       IVTV_FB_ERR("Unknown IOCTL %d\n", cmd);
+                       IVTV_FB_DEBUG_INFO("Unknown ioctl %08x\n", cmd);
                        return -EINVAL;
        }
        return 0;
@@ -445,8 +440,10 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar
 
 static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
 {
+       struct osd_info *oi = itv->osd_info;
        struct ivtv_osd_coords ivtv_osd;
        struct v4l2_rect ivtv_window;
+       int osd_mode = -1;
 
        IVTV_FB_DEBUG_INFO("ivtvfb_set_var\n");
 
@@ -456,32 +453,24 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
        else /* RGB  */
                write_reg(read_reg(0x02a00) & ~0x0002000, 0x02a00);
 
-       /* Set the color mode
-          Although rare, occasionally things go wrong. The extra mode
-          change seems to help... */
-
+       /* Set the color mode */
        switch (var->bits_per_pixel) {
                case 8:
-                       ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
-                       ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_8);
+                       osd_mode = IVTV_OSD_BPP_8;
                        break;
                case 32:
-                       ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
-                       ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_32);
+                       osd_mode = IVTV_OSD_BPP_32;
                        break;
                case 16:
                        switch (var->green.length) {
                        case 4:
-                               ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
-                               ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_444);
+                               osd_mode = IVTV_OSD_BPP_16_444;
                                break;
                        case 5:
-                               ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
-                               ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_555);
+                               osd_mode = IVTV_OSD_BPP_16_555;
                                break;
                        case 6:
-                               ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
-                               ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, IVTV_OSD_BPP_16_565);
+                               osd_mode = IVTV_OSD_BPP_16_565;
                                break;
                        default:
                                IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
@@ -491,8 +480,17 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
                        IVTV_FB_DEBUG_WARN("ivtvfb_set_var - Invalid bpp\n");
        }
 
-       itv->osd_info->bits_per_pixel = var->bits_per_pixel;
-       itv->osd_info->bytes_per_pixel = var->bits_per_pixel / 8;
+       /* Change osd mode if needed.
+          Although rare, things can go wrong. The extra mode
+          change seems to help... */
+       if (osd_mode != -1 && osd_mode != oi->osd_mode) {
+               ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, 0);
+               ivtv_vapi(itv, CX2341X_OSD_SET_PIXEL_FORMAT, 1, osd_mode);
+               oi->osd_mode = osd_mode;
+       }
+
+       oi->bits_per_pixel = var->bits_per_pixel;
+       oi->bytes_per_pixel = var->bits_per_pixel / 8;
 
        /* Set the flicker filter */
        switch (var->vmode & FB_VMODE_MASK) {
@@ -572,10 +570,25 @@ static int ivtvfb_get_fix(struct ivtv *itv, struct fb_fix_screeninfo *fix)
 static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
 {
        struct osd_info *oi = itv->osd_info;
-       int osd_height_limit = itv->is_50hz ? 576 : 480;
+       int osd_height_limit;
+       u32 pixclock, hlimit, vlimit;
 
        IVTV_FB_DEBUG_INFO("ivtvfb_check_var\n");
 
+       /* Set base references for mode calcs. */
+       if (itv->is_50hz) {
+               pixclock = 84316;
+               hlimit = 776;
+               vlimit = 591;
+               osd_height_limit = 576;
+       }
+       else {
+               pixclock = 83926;
+               hlimit = 776;
+               vlimit = 495;
+               osd_height_limit = 480;
+       }
+
        /* Check the bits per pixel */
        if (osd_compat) {
                if (var->bits_per_pixel != 32) {
@@ -595,9 +608,6 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
                var->blue.length = 8;
        }
        else if (var->bits_per_pixel == 16) {
-               var->transp.offset = 0;
-               var->transp.length = 0;
-
                /* To find out the true mode, check green length */
                switch (var->green.length) {
                        case 4:
@@ -607,6 +617,8 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
                                var->green.length = 4;
                                var->blue.offset = 0;
                                var->blue.length = 4;
+                               var->transp.offset = 12;
+                               var->transp.length = 1;
                                break;
                        case 5:
                                var->red.offset = 10;
@@ -615,6 +627,8 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
                                var->green.length = 5;
                                var->blue.offset = 0;
                                var->blue.length = 5;
+                               var->transp.offset = 15;
+                               var->transp.length = 1;
                                break;
                        default:
                                var->red.offset = 11;
@@ -623,6 +637,8 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
                                var->green.length = 6;
                                var->blue.offset = 0;
                                var->blue.length = 5;
+                               var->transp.offset = 0;
+                               var->transp.length = 0;
                                break;
                }
        }
@@ -716,8 +732,8 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
        }
 
        /* Maintain overall 'size' for a constant refresh rate */
-       var->right_margin = oi->hlimit - var->left_margin - var->xres;
-       var->lower_margin = oi->vlimit - var->upper_margin - var->yres;
+       var->right_margin = hlimit - var->left_margin - var->xres;
+       var->lower_margin = vlimit - var->upper_margin - var->yres;
 
        /* Fixed sync times */
        var->hsync_len = 24;
@@ -726,9 +742,10 @@ static int _ivtvfb_check_var(struct fb_var_screeninfo *var, struct ivtv *itv)
        /* Non-interlaced / interlaced mode is used to switch the OSD filter
           on or off. Adjust the clock timings to maintain a constant
           vertical refresh rate. */
-       var->pixclock = oi->pixclock;
        if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_NONINTERLACED)
-               var->pixclock /= 2;
+               var->pixclock = pixclock / 2;
+       else
+               var->pixclock = pixclock;
 
        IVTV_FB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
                      var->xres, var->yres,
@@ -868,18 +885,6 @@ static int ivtvfb_init_vidmode(struct ivtv *itv)
        struct v4l2_rect start_window;
        int max_height;
 
-       /* Set base references for mode calcs. */
-       if (itv->is_50hz) {
-               oi->pixclock = 84316;
-               oi->hlimit = 776;
-               oi->vlimit = 591;
-       }
-       else {
-               oi->pixclock = 83926;
-               oi->hlimit = 776;
-               oi->vlimit = 495;
-       }
-
        /* Color mode */
 
        if (osd_compat) osd_depth = 32;
@@ -887,6 +892,9 @@ static int ivtvfb_init_vidmode(struct ivtv *itv)
        oi->bits_per_pixel = osd_depth;
        oi->bytes_per_pixel = oi->bits_per_pixel / 8;
 
+       /* Invalidate current osd mode to force a mode switch later */
+       oi->osd_mode = -1;
+
        /* Horizontal size & position */
 
        if (osd_xres > 720) osd_xres = 720;
@@ -1003,6 +1011,11 @@ static int ivtvfb_init_io(struct ivtv *itv)
 {
        struct osd_info *oi = itv->osd_info;
 
+       if (ivtv_init_on_first_open(itv)) {
+               IVTV_FB_ERR("Failed to initialize ivtv\n");
+               return -ENXIO;
+       }
+
        ivtv_fb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size);
 
        /* The osd buffer size depends on the number of video buffers allocated