fbdev: move FBIO_WAITFORVSYNC to linux/fb.h
[safe/jmp/linux-2.6] / drivers / video / tgafb.c
index 5345fe0..1b3b1c7 100644 (file)
@@ -5,7 +5,7 @@
  *     Copyright (C) 1997 Geert Uytterhoeven
  *     Copyright (C) 1999,2000 Martin Lucina, Tom Zerucha
  *     Copyright (C) 2002 Richard Henderson
- *     Copyright (C) 2006 Maciej W. Rozycki
+ *     Copyright (C) 2006, 2007  Maciej W. Rozycki
  *
  *  This file is subject to the terms and conditions of the GNU General Public
  *  License. See the file COPYING in the main directory of this archive for
@@ -13,6 +13,7 @@
  */
 
 #include <linux/bitrev.h>
+#include <linux/compiler.h>
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/errno.h>
@@ -24,7 +25,6 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/selection.h>
-#include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/tc.h>
 
@@ -59,6 +59,7 @@ static void tgafb_init_fix(struct fb_info *);
 static void tgafb_imageblit(struct fb_info *, const struct fb_image *);
 static void tgafb_fillrect(struct fb_info *, const struct fb_fillrect *);
 static void tgafb_copyarea(struct fb_info *, const struct fb_copyarea *);
+static int tgafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);
 
 static int __devinit tgafb_register(struct device *dev);
 static void __devexit tgafb_unregister(struct device *dev);
@@ -81,6 +82,7 @@ static struct fb_ops tgafb_ops = {
        .fb_set_par             = tgafb_set_par,
        .fb_setcolreg           = tgafb_setcolreg,
        .fb_blank               = tgafb_blank,
+       .fb_pan_display         = tgafb_pan_display,
        .fb_fillrect            = tgafb_fillrect,
        .fb_copyarea            = tgafb_copyarea,
        .fb_imageblit           = tgafb_imageblit,
@@ -319,21 +321,7 @@ tgafb_set_par(struct fb_info *info)
                BT485_WRITE(par, 0x00, BT485_ADDR_PAL_WRITE);
                TGA_WRITE_REG(par, BT485_DATA_PAL, TGA_RAMDAC_SETUP_REG);
 
-#ifdef CONFIG_HW_CONSOLE
-               for (i = 0; i < 16; i++) {
-                       int j = color_table[i];
-
-                       TGA_WRITE_REG(par, default_red[j]|(BT485_DATA_PAL<<8),
-                                     TGA_RAMDAC_REG);
-                       TGA_WRITE_REG(par, default_grn[j]|(BT485_DATA_PAL<<8),
-                                     TGA_RAMDAC_REG);
-                       TGA_WRITE_REG(par, default_blu[j]|(BT485_DATA_PAL<<8),
-                                     TGA_RAMDAC_REG);
-               }
-               for (i = 0; i < 240 * 3; i += 4) {
-#else
                for (i = 0; i < 256 * 3; i += 4) {
-#endif
                        TGA_WRITE_REG(par, 0x55 | (BT485_DATA_PAL << 8),
                                      TGA_RAMDAC_REG);
                        TGA_WRITE_REG(par, 0x00 | (BT485_DATA_PAL << 8),
@@ -358,18 +346,7 @@ tgafb_set_par(struct fb_info *info)
                BT459_LOAD_ADDR(par, 0x0000);
                TGA_WRITE_REG(par, BT459_PALETTE << 2, TGA_RAMDAC_SETUP_REG);
 
-#ifdef CONFIG_HW_CONSOLE
-               for (i = 0; i < 16; i++) {
-                       int j = color_table[i];
-
-                       TGA_WRITE_REG(par, default_red[j], TGA_RAMDAC_REG);
-                       TGA_WRITE_REG(par, default_grn[j], TGA_RAMDAC_REG);
-                       TGA_WRITE_REG(par, default_blu[j], TGA_RAMDAC_REG);
-               }
-               for (i = 0; i < 240 * 3; i += 4) {
-#else
                for (i = 0; i < 256 * 3; i += 4) {
-#endif
                        TGA_WRITE_REG(par, 0x55, TGA_RAMDAC_REG);
                        TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);
                        TGA_WRITE_REG(par, 0x00, TGA_RAMDAC_REG);
@@ -646,16 +623,8 @@ tgafb_blank(int blank, struct fb_info *info)
  *  Acceleration.
  */
 
-/**
- *      tgafb_imageblit - REQUIRED function. Can use generic routines if
- *                        non acclerated hardware and packed pixel based.
- *                        Copies a image from system memory to the screen. 
- *
- *      @info: frame buffer structure that represents a single frame buffer
- *      @image: structure defining the image.
- */
 static void
-tgafb_imageblit(struct fb_info *info, const struct fb_image *image)
+tgafb_mono_imageblit(struct fb_info *info, const struct fb_image *image)
 {
        struct tga_par *par = (struct tga_par *) info->par;
        u32 fgcolor, bgcolor, dx, dy, width, height, vxres, vyres, pixelmask;
@@ -665,6 +634,8 @@ tgafb_imageblit(struct fb_info *info, const struct fb_image *image)
        void __iomem *regs_base;
        void __iomem *fb_base;
 
+       is8bpp = info->var.bits_per_pixel == 8;
+
        dx = image->dx;
        dy = image->dy;
        width = image->width;
@@ -674,6 +645,9 @@ tgafb_imageblit(struct fb_info *info, const struct fb_image *image)
        line_length = info->fix.line_length;
        rincr = (width + 7) / 8;
 
+       /* A shift below cannot cope with.  */
+       if (unlikely(width == 0))
+               return;
        /* Crop the image to the screen.  */
        if (dx > vxres || dy > vyres)
                return;
@@ -682,18 +656,8 @@ tgafb_imageblit(struct fb_info *info, const struct fb_image *image)
        if (dy + height > vyres)
                height = vyres - dy;
 
-       /* For copies that aren't pixel expansion, there's little we
-          can do better than the generic code.  */
-       /* ??? There is a DMA write mode; I wonder if that could be
-          made to pull the data from the image buffer...  */
-       if (image->depth > 1) {
-               cfb_imageblit(info, image);
-               return;
-       }
-
        regs_base = par->tga_regs_base;
        fb_base = par->tga_fb_base;
-       is8bpp = info->var.bits_per_pixel == 8;
 
        /* Expand the color values to fill 32-bits.  */
        /* ??? Would be nice to notice colour changes elsewhere, so
@@ -739,9 +703,10 @@ tgafb_imageblit(struct fb_info *info, const struct fb_image *image)
                unsigned long bwidth;
 
                /* Handle common case of imaging a single character, in
-                  a font less than 32 pixels wide.  */
+                  a font less than or 32 pixels wide.  */
 
-               pixelmask = (1 << width) - 1;
+               /* Avoid a shift by 32; width > 0 implied.  */
+               pixelmask = (2ul << (width - 1)) - 1;
                pixelmask <<= shift;
                __raw_writel(pixelmask, regs_base + TGA_PIXELMASK_REG);
                wmb();
@@ -871,6 +836,85 @@ tgafb_imageblit(struct fb_info *info, const struct fb_image *image)
                     regs_base + TGA_MODE_REG);
 }
 
+static void
+tgafb_clut_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+       struct tga_par *par = (struct tga_par *) info->par;
+       u32 color, dx, dy, width, height, vxres, vyres;
+       u32 *palette = ((u32 *)info->pseudo_palette);
+       unsigned long pos, line_length, i, j;
+       const unsigned char *data;
+       void __iomem *regs_base, *fb_base;
+
+       dx = image->dx;
+       dy = image->dy;
+       width = image->width;
+       height = image->height;
+       vxres = info->var.xres_virtual;
+       vyres = info->var.yres_virtual;
+       line_length = info->fix.line_length;
+
+       /* Crop the image to the screen.  */
+       if (dx > vxres || dy > vyres)
+               return;
+       if (dx + width > vxres)
+               width = vxres - dx;
+       if (dy + height > vyres)
+               height = vyres - dy;
+
+       regs_base = par->tga_regs_base;
+       fb_base = par->tga_fb_base;
+
+       pos = dy * line_length + (dx * 4);
+       data = image->data;
+
+       /* Now copy the image, color_expanding via the palette. */
+       for (i = 0; i < height; i++) {
+               for (j = 0; j < width; j++) {
+                       color = palette[*data++];
+                       __raw_writel(color, fb_base + pos + j*4);
+               }
+               pos += line_length;
+       }
+}
+
+/**
+ *      tgafb_imageblit - REQUIRED function. Can use generic routines if
+ *                        non acclerated hardware and packed pixel based.
+ *                        Copies a image from system memory to the screen.
+ *
+ *      @info: frame buffer structure that represents a single frame buffer
+ *      @image: structure defining the image.
+ */
+static void
+tgafb_imageblit(struct fb_info *info, const struct fb_image *image)
+{
+       unsigned int is8bpp = info->var.bits_per_pixel == 8;
+
+       /* If a mono image, regardless of FB depth, go do it. */
+       if (image->depth == 1) {
+               tgafb_mono_imageblit(info, image);
+               return;
+       }
+
+       /* For copies that aren't pixel expansion, there's little we
+          can do better than the generic code.  */
+       /* ??? There is a DMA write mode; I wonder if that could be
+          made to pull the data from the image buffer...  */
+       if (image->depth == info->var.bits_per_pixel) {
+               cfb_imageblit(info, image);
+               return;
+       }
+
+       /* If 24-plane FB and the image is 8-plane with CLUT, we can do it. */
+       if (!is8bpp && image->depth == 8) {
+               tgafb_clut_imageblit(info, image);
+               return;
+       }
+
+       /* Silently return... */
+}
+
 /**
  *      tgafb_fillrect - REQUIRED function. Can use generic routines if 
  *                       non acclerated hardware and packed pixel based.
@@ -1480,6 +1524,26 @@ tgafb_init_fix(struct fb_info *info)
        info->fix.ywrapstep = 0;
 
        info->fix.accel = FB_ACCEL_DEC_TGA;
+
+       /*
+        * These are needed by fb_set_logo_truepalette(), so we
+        * set them here for 24-plane cards.
+        */
+       if (tga_type != TGA_TYPE_8PLANE) {
+               info->var.red.length = 8;
+               info->var.green.length = 8;
+               info->var.blue.length = 8;
+               info->var.red.offset = 16;
+               info->var.green.offset = 8;
+               info->var.blue.offset = 0;
+       }
+}
+
+static int tgafb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+       /* We just use this to catch switches out of graphics mode. */
+       tgafb_set_par(info); /* A bit of overkill for BASE_ADDR reset. */
+       return 0;
 }
 
 static int __devinit
@@ -1556,8 +1620,7 @@ tgafb_register(struct device *dev)
        par->tga_regs_base = mem_base + TGA_REGS_OFFSET;
        par->tga_type = tga_type;
        if (tga_bus_pci)
-               pci_read_config_byte(to_pci_dev(dev), PCI_REVISION_ID,
-                                    &par->tga_chip_rev);
+               par->tga_chip_rev = (to_pci_dev(dev))->revision;
        if (tga_bus_tc)
                par->tga_chip_rev = TGA_READ_REG(par, TGA_START_REG) & 0xff;
 
@@ -1566,7 +1629,7 @@ tgafb_register(struct device *dev)
                      FBINFO_HWACCEL_IMAGEBLIT | FBINFO_HWACCEL_FILLRECT;
        info->fbops = &tgafb_ops;
        info->screen_base = par->tga_fb_base;
-       info->pseudo_palette = (void *)(par + 1);
+       info->pseudo_palette = par->palette;
 
        /* This should give a reasonable default video mode.  */
        if (tga_bus_pci) {
@@ -1599,7 +1662,7 @@ tgafb_register(struct device *dev)
        if (register_framebuffer(info) < 0) {
                printk(KERN_ERR "tgafb: Could not register framebuffer\n");
                ret = -EINVAL;
-               goto err1;
+               goto err2;
        }
 
        if (tga_bus_pci) {
@@ -1618,6 +1681,8 @@ tgafb_register(struct device *dev)
 
        return 0;
 
+ err2:
+       fb_dealloc_cmap(&info->cmap);
  err1:
        if (mem_base)
                iounmap(mem_base);