vserver 1.9.5.x5
[linux-2.6.git] / drivers / video / aty / mach64_cursor.c
index d612fc4..fbba31e 100644 (file)
@@ -1,12 +1,11 @@
-
 /*
  *  ATI Mach64 CT/VT/GT/LT Cursor Support
  */
 
 #include <linux/slab.h>
-#include <linux/console.h>
 #include <linux/fb.h>
 #include <linux/init.h>
+#include <linux/string.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <video/mach64.h>
 #include "atyfb.h"
 
+/*
+ * The hardware cursor definition requires 2 bits per pixel. The
+ * Cursor size reguardless of the visible cursor size is 64 pixels
+ * by 64 lines. The total memory required to define the cursor is
+ * 16 bytes / line for 64 lines or 1024 bytes of data. The data
+ * must be in a contigiuos format. The 2 bit cursor code values are
+ * as follows:
+ *
+ *     00 - pixel colour = CURSOR_CLR_0
+ *     01 - pixel colour = CURSOR_CLR_1
+ *     10 - pixel colour = transparent (current display pixel)
+ *     11 - pixel colour = 1's complement of current display pixel
+ *
+ *     Cursor Offset        64 pixels           Actual Displayed Area
+ *            \_________________________/
+ *           |                 |       |       |
+ *           |<--------------->|       |       |
+ *           | CURS_HORZ_OFFSET|       |       |
+ *           |                 |_______|       |  64 Lines
+ *           |                    ^    |       |
+ *           |                    |    |       |
+ *           |         CURS_VERT_OFFSET|       |
+ *           |                    |    |       |
+ *           |____________________|____|       |
+ *
+ *
+ * The Screen position of the top left corner of the displayed
+ * cursor is specificed by CURS_HORZ_VERT_POSN. Care must be taken
+ * when the cursor hot spot is not the top left corner and the
+ * physical cursor position becomes negative. It will be be displayed
+ * if either the horizontal or vertical cursor position is negative
+ *
+ * If x becomes negative the cursor manager must adjust the CURS_HORZ_OFFSET
+ * to a larger number and saturate CUR_HORZ_POSN to zero.
+ *
+ * if Y becomes negative, CUR_VERT_OFFSET must be adjusted to a larger number,
+ * CUR_OFFSET must be adjusted to a point to the appropraite line in the cursor
+ * definitation and CUR_VERT_POSN must be saturated to zero.
+ */
+
     /*
      *  Hardware Cursor support.
      */
-
-static const u8 cursor_pixel_map[2] = { 0, 15 };
-static const u8 cursor_color_map[2] = { 0, 0xff };
-
 static const u8 cursor_bits_lookup[16] = {
        0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
        0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
@@ -36,89 +71,25 @@ static const u8 cursor_mask_lookup[16] = {
        0xa8, 0x28, 0x88, 0x08, 0xa0, 0x20, 0x80, 0x00
 };
 
-void aty_set_cursor_color(struct fb_info *info)
-{
-       struct atyfb_par *par = (struct atyfb_par *) info->par;
-       struct aty_cursor *c = par->cursor;
-       const u8 *pixel = cursor_pixel_map;     /* ++Geert: Why?? */
-       const u8 *red = cursor_color_map;
-       const u8 *green = cursor_color_map;
-       const u8 *blue = cursor_color_map;
-       u32 fg_color, bg_color;
-
-       if (!c)
-               return;
-
-#ifdef __sparc__
-       if (par->mmaped)
-               return;
-#endif
-       fg_color = (u32) red[0] << 24;
-       fg_color |= (u32) green[0] << 16;
-       fg_color |= (u32) blue[0] << 8;
-       fg_color |= (u32) pixel[0];
-
-       bg_color = (u32) red[1] << 24;
-       bg_color |= (u32) green[1] << 16;
-       bg_color |= (u32) blue[1] << 8;
-       bg_color |= (u32) pixel[1];
-
-       wait_for_fifo(2, par);
-       aty_st_le32(CUR_CLR0, fg_color, par);
-       aty_st_le32(CUR_CLR1, bg_color, par);
-}
-
-void aty_set_cursor_shape(struct fb_info *info)
-{
-       struct atyfb_par *par = (struct atyfb_par *) info->par;
-       struct fb_cursor *cursor = &info->cursor;
-       struct aty_cursor *c = par->cursor;
-       u8 *ram, m, b;
-       int x, y;
-
-       if (!c)
-               return;
-#ifdef __sparc__
-       if (par->mmaped)
-               return;
-#endif
-
-       ram = c->ram;
-       for (y = 0; y < cursor->image.height; y++) {
-               for (x = 0; x < cursor->image.width >> 2; x++) {
-                       m = c->mask[x][y];
-                       b = c->bits[x][y];
-                       fb_writeb(cursor_mask_lookup[m >> 4] |
-                                 cursor_bits_lookup[(b & m) >> 4], ram++);
-                       fb_writeb(cursor_mask_lookup[m & 0x0f] |
-                                 cursor_bits_lookup[(b & m) & 0x0f],
-                                 ram++);
-               }
-               for (; x < 8; x++) {
-                       fb_writeb(0xaa, ram++);
-                       fb_writeb(0xaa, ram++);
-               }
-       }
-       fb_memset(ram, 0xaa, (64 - cursor->image.height) * 16);
-}
-
-static void aty_set_cursor(struct fb_info *info)
+int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 {
        struct atyfb_par *par = (struct atyfb_par *) info->par;
-       struct fb_cursor *cursor = &info->cursor;
-       struct aty_cursor *c = par->cursor;
        u16 xoff, yoff;
-       int x, y;
-
-       if (!c)
-               return;
+       int x, y, h;
 
 #ifdef __sparc__
        if (par->mmaped)
-               return;
+               return -EPERM;
 #endif
+       if (par->asleep)
+               return -EPERM;
 
-       if (cursor->enable) {
+       /* Hide cursor */
+       wait_for_fifo(1, par);
+       aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par) & ~HWCURSOR_ENABLE, par);
+
+       /* set position */
+       if (cursor->set & FB_CUR_SETPOS) {
                x = cursor->image.dx - cursor->hot.x - info->var.xoffset;
                if (x < 0) {
                        xoff = -x;
@@ -135,107 +106,121 @@ static void aty_set_cursor(struct fb_info *info)
                        yoff = 0;
                }
 
+               h = cursor->image.height;
+
+               /*
+                * In doublescan mode, the cursor location
+                * and heigh also needs to be doubled.
+                */
+                if (par->crtc.gen_cntl & CRTC_DBL_SCAN_EN) {
+                       y<<=1;
+                       h<<=1;
+               }
                wait_for_fifo(4, par);
-               aty_st_le32(CUR_OFFSET, (info->fix.smem_len >> 3) + (yoff << 1),
-                           par);
+               aty_st_le32(CUR_OFFSET, (info->fix.smem_len >> 3) + (yoff << 1), par);
                aty_st_le32(CUR_HORZ_VERT_OFF,
-                           ((u32) (64 - cursor->image.height + yoff) << 16) | xoff,
-                           par);
+                           ((u32) (64 - h + yoff) << 16) | xoff, par);
                aty_st_le32(CUR_HORZ_VERT_POSN, ((u32) y << 16) | x, par);
-               aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par)
-                           | HWCURSOR_ENABLE, par);
-       } else {
-               wait_for_fifo(1, par);
-               aty_st_le32(GEN_TEST_CNTL,
-                           aty_ld_le32(GEN_TEST_CNTL,
-                                       par) & ~HWCURSOR_ENABLE, par);
        }
-       if (par->blitter_may_be_busy)
-               wait_for_idle(par);
-}
 
-int atyfb_cursor(struct fb_info *info, struct fb_cursor *cursor)
-{
-       struct atyfb_par *par = (struct atyfb_par *) info->par;
-       struct aty_cursor *c = par->cursor;
+       /* Set color map */
+       if (cursor->set & FB_CUR_SETCMAP) {
+               u32 fg_idx, bg_idx, fg, bg;
 
-       if (!c)
-               return -1;
+               fg_idx = cursor->image.fg_color;
+               bg_idx = cursor->image.bg_color;
 
-#ifdef __sparc__
-       if (par->mmaped)
-               return 0;
-#endif
+               fg = (info->cmap.red[fg_idx] << 24) |
+                    (info->cmap.green[fg_idx] << 16) |
+                    (info->cmap.blue[fg_idx] << 8) | 15;
+
+               bg = (info->cmap.red[bg_idx] << 24) |
+                    (info->cmap.green[bg_idx] << 16) |
+                    (info->cmap.blue[bg_idx] << 8);
+
+               wait_for_fifo(2, par);
+               aty_st_le32(CUR_CLR0, bg, par);
+               aty_st_le32(CUR_CLR1, fg, par);
+       }
 
-       aty_set_cursor(info);
-       cursor->image.dx = info->cursor.image.dx;
-       cursor->image.dy = info->cursor.image.dy;
+       if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
+           u8 *src = (u8 *)cursor->image.data;
+           u8 *msk = (u8 *)cursor->mask;
+           u8 __iomem *dst = (u8 __iomem *)info->sprite.addr;
+           unsigned int width = (cursor->image.width + 7) >> 3;
+           unsigned int height = cursor->image.height;
+           unsigned int align = info->sprite.scan_align;
+
+           unsigned int i, j, offset;
+           u8 m, b;
+
+           // Clear cursor image with 1010101010...
+           fb_memset(dst, 0xaa, 1024);
+
+           offset = align - width*2;
+
+           for (i = 0; i < height; i++) {
+               for (j = 0; j < width; j++) {
+                       b = *src++;
+                       m = *msk++;
+                       switch (cursor->rop) {
+                       case ROP_XOR:
+                           // Upper 4 bits of mask data
+                           fb_writeb(cursor_mask_lookup[m >> 4 ] |
+                               cursor_bits_lookup[(b ^ m) >> 4], dst++);
+                           // Lower 4 bits of mask
+                           fb_writeb(cursor_mask_lookup[m & 0x0f ] |
+                               cursor_bits_lookup[(b ^ m) & 0x0f], dst++);
+                           break;
+                       case ROP_COPY:
+                           // Upper 4 bits of mask data
+                           fb_writeb(cursor_mask_lookup[m >> 4 ] |
+                               cursor_bits_lookup[(b & m) >> 4], dst++);
+                           // Lower 4 bits of mask
+                           fb_writeb(cursor_mask_lookup[m & 0x0f ] |
+                               cursor_bits_lookup[(b & m) & 0x0f], dst++);
+                           break;
+                       }
+               }
+               dst += offset;
+           }
+       }
 
-       aty_set_cursor(info);
+       if (cursor->enable) {
+               wait_for_fifo(1, par);
+               aty_st_le32(GEN_TEST_CNTL, aty_ld_le32(GEN_TEST_CNTL, par)
+                           | HWCURSOR_ENABLE, par);
+       }
        return 0;
 }
 
-struct aty_cursor *__init aty_init_cursor(struct fb_info *info)
+int __init aty_init_cursor(struct fb_info *info)
 {
-       struct aty_cursor *cursor;
        unsigned long addr;
 
-       cursor = kmalloc(sizeof(struct aty_cursor), GFP_ATOMIC);
-       if (!cursor)
-               return NULL;
-       memset(cursor, 0, sizeof(*cursor));
-
        info->fix.smem_len -= PAGE_SIZE;
 
 #ifdef __sparc__
        addr = (unsigned long) info->screen_base - 0x800000 + info->fix.smem_len;
-       cursor->ram = (u8 *) addr;
+       info->sprite.addr = (u8 *) addr;
 #else
 #ifdef __BIG_ENDIAN
        addr = info->fix.smem_start - 0x800000 + info->fix.smem_len;
-       cursor->ram = (u8 *) ioremap(addr, 1024);
+       info->sprite.addr = (u8 *) ioremap(addr, 1024);
 #else
        addr = (unsigned long) info->screen_base + info->fix.smem_len;
-       cursor->ram = (u8 *) addr;
+       info->sprite.addr = (u8 *) addr;
 #endif
 #endif
-       if (!cursor->ram) {
-               kfree(cursor);
-               return NULL;
-       }
-       return cursor;
-}
-
-int atyfb_set_font(struct fb_info *info, int width, int height)
-{
-       struct atyfb_par *par = (struct atyfb_par *) info->par;
-       struct fb_cursor *cursor = &info->cursor;
-       struct aty_cursor *c = par->cursor;
-       int i, j;
-
-       if (c) {
-               if (!width || !height) {
-                       width = 8;
-                       height = 16;
-               }
-
-               cursor->hot.x = 0;
-               cursor->hot.y = 0;
-               cursor->image.width = width;
-               cursor->image.height = height;
-
-               memset(c->bits, 0xff, sizeof(c->bits));
-               memset(c->mask, 0, sizeof(c->mask));
+       if (!info->sprite.addr)
+               return -ENXIO;
+       info->sprite.size = PAGE_SIZE;
+       info->sprite.scan_align = 16;   /* Scratch pad 64 bytes wide */
+       info->sprite.buf_align = 16;    /* and 64 lines tall. */
+       info->sprite.flags = FB_PIXMAP_IO;
 
-               for (i = 0, j = width; j >= 0; j -= 8, i++) {
-                       c->mask[i][height - 2] =
-                           (j >= 8) ? 0xff : (0xff << (8 - j));
-                       c->mask[i][height - 1] =
-                           (j >= 8) ? 0xff : (0xff << (8 - j));
-               }
+       info->fbops->fb_cursor = atyfb_cursor;
 
-               aty_set_cursor_color(info);
-               aty_set_cursor_shape(info);
-       }
-       return 1;
+       return 0;
 }
+