Thread (2 messages) 2 messages, 2 authors, 2003-03-19

[PATCH] Port amifb to new fbdev API

STALE8600d

From: Geert Uytterhoeven <geert@linux-m68k.org>
Date: 2003-03-19 12:34:29

Amiga frame buffer device: Port to the new fbdev API
--- linux-2.5.x/drivers/video/Makefile	Mon Feb 17 17:38:49 2003
+++ linux-m68k-2.5.x/drivers/video/Makefile	Mon Feb 10 22:30:27 2003
@@ -13,7 +13,7 @@
 endif
 
 obj-$(CONFIG_FB_ACORN)            += acornfb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o
-obj-$(CONFIG_FB_AMIGA)            += amifb.o
+obj-$(CONFIG_FB_AMIGA)            += amifb.o c2p.o
 obj-$(CONFIG_FB_PM2)              += pm2fb.o
 obj-$(CONFIG_FB_PM3)		  += pm3fb.o
 obj-$(CONFIG_FB_APOLLO)           += dnfb.o cfbfillrect.o cfbimgblt.o
--- linux-2.5.x/drivers/video/amifb.c	Tue Dec 10 13:41:40 2002
+++ linux-m68k-2.5.x/drivers/video/amifb.c	Sat Jan 25 19:58:10 2003
@@ -1,7 +1,7 @@
 /*
  * linux/drivers/video/amifb.c -- Amiga builtin chipset frame buffer device
  *
- *    Copyright (C) 1995 Geert Uytterhoeven
+ *    Copyright (C) 1995-2003 Geert Uytterhoeven
  *
  *          with work by Roman Zippel
  *
@@ -62,10 +62,7 @@
 #include <asm/amigaints.h>
 #include <asm/setup.h>
 
-#include <video/fbcon.h>
-#include <video/fbcon-afb.h>
-#include <video/fbcon-ilbm.h>
-#include <video/fbcon-mfb.h>
+#include "c2p.h"
 
 
 #define DEBUG
@@ -613,12 +610,11 @@
 
 #define SPRITEMEMSIZE		(64*64/4) /* max 64*64*4 */
 #define DUMMYSPRITEMEMSIZE	(8)
+static u_long spritememory;
 
 #define CHIPRAM_SAFETY_LIMIT	(16384)
 
-static u_long videomemory, spritememory;
-static u_long videomemorysize;
-static u_long videomemory_phys;
+static u_long videomemory;
 
 	/*
 	 * This is the earliest allowed start of fetching display data.
@@ -660,6 +656,47 @@
 static u_short currentcop = 0;
 
 	/*
+	 * Hardware Cursor API Definitions
+	 * These used to be in linux/fb.h, but were preliminary and used by
+	 * amifb only anyway
+	 */
+
+#define FBIOGET_FCURSORINFO     0x4607
+#define FBIOGET_VCURSORINFO     0x4608
+#define FBIOPUT_VCURSORINFO     0x4609
+#define FBIOGET_CURSORSTATE     0x460A
+#define FBIOPUT_CURSORSTATE     0x460B
+
+
+struct fb_fix_cursorinfo {
+	__u16 crsr_width;		/* width and height of the cursor in */
+	__u16 crsr_height;		/* pixels (zero if no cursor)	*/
+	__u16 crsr_xsize;		/* cursor size in display pixels */
+	__u16 crsr_ysize;
+	__u16 crsr_color1;		/* colormap entry for cursor color1 */
+	__u16 crsr_color2;		/* colormap entry for cursor color2 */
+};
+
+struct fb_var_cursorinfo {
+	__u16 width;
+	__u16 height;
+	__u16 xspot;
+	__u16 yspot;
+	__u8 data[1];			/* field with [height][width]        */
+};
+
+struct fb_cursorstate {
+	__s16 xoffset;
+	__s16 yoffset;
+	__u16 mode;
+};
+
+#define FB_CURSOR_OFF		0
+#define FB_CURSOR_ON		1
+#define FB_CURSOR_FLASH		2
+
+
+	/*
 	 * Hardware Cursor
 	 */
 
@@ -738,28 +775,28 @@
 	u_short fmode;		/* vmode */
 } currentpar;
 
-static struct display disp;
 
-static struct fb_info fb_info;
+static struct fb_info fb_info = {
+    .fix = {
+	.id		= "Amiga ",
+	.visual		= FB_VISUAL_PSEUDOCOLOR,
+	.accel		= FB_ACCEL_AMIGABLITT
+    }
+};
 
 
 	/*
-	 * Since we can't read the palette on OCS/ECS, and since reading one
-	 * single color palette entry requires 5 expensive custom chip bus accesses
-	 * on AGA, we keep a copy of the current palette.
-	 * Note that the entries are always 24 bit!
+	 *  Saved color entry 0 so we can restore it when unblanking
 	 */
 
-#if defined(CONFIG_FB_AMIGA_AGA)
-static struct { u_char red, green, blue, pad; } palette[256];
-#else
-static struct { u_char red, green, blue, pad; } palette[32];
-#endif
+static u_char red0, green0, blue0;
+
 
 #if defined(CONFIG_FB_AMIGA_ECS)
 static u_short ecs_palette[32];
 #endif
 
+
 	/*
 	 * Latches for Display Changes during VBlank
 	 */
@@ -778,15 +815,6 @@
 static u_short is_lace = 0;		/* Screen is laced */
 
 	/*
-	 * Frame Buffer Name
-	 *
-	 * The rest of the name is filled in during initialization
-	 */
-
-static char amifb_name[16] = "Amiga ";
-
-
-	/*
 	 * Predefined Video Modes
 	 *
 	 */
@@ -1087,29 +1115,22 @@
 
 int amifb_setup(char*);
 
-static int amifb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			 struct fb_info *info);
-static int amifb_get_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info);
-static int amifb_set_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info);
-static int amifb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
-                           u_int transp, struct fb_info *info);
+static int amifb_check_var(struct fb_var_screeninfo *var,
+			   struct fb_info *info);
+static int amifb_set_par(struct fb_info *info);
+static int amifb_setcolreg(unsigned regno, unsigned red, unsigned green,
+			   unsigned blue, unsigned transp,
+			   struct fb_info *info);
 static int amifb_blank(int blank, struct fb_info *info);
-static int amifb_pan_display(struct fb_var_screeninfo *var, int con,
+static int amifb_pan_display(struct fb_var_screeninfo *var,
 			     struct fb_info *info);
-static int amifb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			  struct fb_info *info);
-static int amifb_ioctl(struct inode *inode, struct file *file, u_int cmd,
-		       u_long arg, int con, struct fb_info *info);
-
-static int amifb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con);
-static int amifb_get_var_cursorinfo(struct fb_var_cursorinfo *var,
-				       u_char *data, int con);
-static int amifb_set_var_cursorinfo(struct fb_var_cursorinfo *var,
-				       u_char *data, int con);
-static int amifb_get_cursorstate(struct fb_cursorstate *state, int con);
-static int amifb_set_cursorstate(struct fb_cursorstate *state, int con);
+static void amifb_fillrect(struct fb_info *info, struct fb_fillrect *rect);
+static void amifb_copyarea(struct fb_info *info, struct fb_copyarea *region);
+static void amifb_imageblit(struct fb_info *info, struct fb_image *image);
+static int amifb_ioctl(struct inode *inode, struct file *file,
+		       unsigned int cmd, unsigned long arg,
+		       struct fb_info *info);
+
 
 	/*
 	 * Interface to the low level console driver
@@ -1117,8 +1138,6 @@
 
 int amifb_init(void);
 static void amifb_deinit(void);
-static int amifbcon_switch(int con, struct fb_info *info);
-static int amifbcon_updatevar(int con, struct fb_info *info);
 
 	/*
 	 * Internal routines
@@ -1133,29 +1152,20 @@
 	 * Hardware routines
 	 */
 
-static int ami_encode_fix(struct fb_fix_screeninfo *fix,
-                          struct amifb_par *par);
 static int ami_decode_var(struct fb_var_screeninfo *var,
                           struct amifb_par *par);
 static int ami_encode_var(struct fb_var_screeninfo *var,
                           struct amifb_par *par);
-static void ami_get_par(struct amifb_par *par);
-static void ami_set_var(struct fb_var_screeninfo *var);
-#ifdef DEBUG
-static void ami_set_par(struct amifb_par *par);
-#endif
 static void ami_pan_var(struct fb_var_screeninfo *var);
 static int ami_update_par(void);
-static int ami_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-                         u_int *transp, struct fb_info *info);
 static void ami_update_display(void);
 static void ami_init_display(void);
 static void ami_do_blank(void);
-static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con);
-static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con);
-static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con);
-static int ami_get_cursorstate(struct fb_cursorstate *state, int con);
-static int ami_set_cursorstate(struct fb_cursorstate *state, int con);
+static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix);
+static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data);
+static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data);
+static int ami_get_cursorstate(struct fb_cursorstate *state);
+static int ami_set_cursorstate(struct fb_cursorstate *state);
 static void ami_set_sprite(void);
 static void ami_init_copper(void);
 static void ami_reinit_copper(void);
@@ -1165,14 +1175,15 @@
 
 static struct fb_ops amifb_ops = {
 	.owner		= THIS_MODULE,
-	.fb_get_fix	= amifb_get_fix,
-	.fb_get_var	= amifb_get_var,
-	.fb_set_var	= amifb_set_var,
-	.fb_get_cmap	= amifb_get_cmap,
-	.fb_set_cmap	= gen_set_cmap,
+	.fb_check_var	= amifb_check_var,
+	.fb_set_par	= amifb_set_par,
 	.fb_setcolreg	= amifb_setcolreg,
-	.fb_pan_display	= amifb_pan_display,
 	.fb_blank	= amifb_blank,
+	.fb_pan_display	= amifb_pan_display,
+	.fb_fillrect	= amifb_fillrect,
+	.fb_copyarea	= amifb_copyarea,
+	.fb_imageblit	= amifb_imageblit,
+	.fb_cursor	= soft_cursor,
 	.fb_ioctl	= amifb_ioctl,
 };
 
@@ -1217,8 +1228,6 @@
 {
 	char *this_opt;
 
-	fb_info.fontname[0] = '\0';
-
 	if (!options || !*options)
 		return 0;
 
@@ -1234,8 +1243,6 @@
 			amifb_ilbm = 1;
 		else if (!strncmp(this_opt, "monitorcap:", 11))
 			amifb_setup_mcap(this_opt+11);
-		else if (!strncmp(this_opt, "font:", 5))
-			strcpy(fb_info.fontname, this_opt+5);
 		else if (!strncmp(this_opt, "fstart:", 7))
 			min_fstrt = simple_strtoul(this_opt+7, NULL, 0);
 		else
@@ -1248,293 +1255,975 @@
 	return 0;
 }
 
-	/*
-	 * Get the Fixed Part of the Display
-	 */
 
-static int amifb_get_fix(struct fb_fix_screeninfo *fix, int con,
-			 struct fb_info *info)
+static int amifb_check_var(struct fb_var_screeninfo *var,
+			   struct fb_info *info)
 {
+	int err;
 	struct amifb_par par;
 
-	if (con == -1)
-		ami_get_par(&par);
-	else {
-		int err;
+	/* Validate wanted screen parameters */
+	if ((err = ami_decode_var(var, &par)))
+		return err;
 
-		if ((err = ami_decode_var(&fb_display[con].var, &par)))
-			return err;
-	}
-	return ami_encode_fix(fix, &par);
+	/* Encode (possibly rounded) screen parameters */
+	ami_encode_var(var, &par);
+	return 0;
 }
 
-	/*
-	 * Get the User Defined Part of the Display
-	 */
 
-static int amifb_get_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info)
+static int amifb_set_par(struct fb_info *info)
 {
-	int err = 0;
-
-	if (con == -1) {
-		struct amifb_par par;
+	struct amifb_par *par = (struct amifb_par *)info->par;
 
-		ami_get_par(&par);
-		err = ami_encode_var(var, &par);
-	} else
-		*var = fb_display[con].var;
-	return err;
-}
-
-	/*
-	 * Set the User Defined Part of the Display
-	 */
+	do_vmode_pan = 0;
+	do_vmode_full = 0;
 
-static int amifb_set_var(struct fb_var_screeninfo *var, int con,
-			 struct fb_info *info)
-{
-	int err, activate = var->activate;
-	int oldxres, oldyres, oldvxres, oldvyres, oldbpp;
-	struct amifb_par par;
+	/* Decode wanted screen parameters */
+	ami_decode_var(&info->var, par);
 
-	struct display *display;
-	if (con >= 0)
-		display = &fb_display[con];
-	else
-		display = &disp;	/* used during initialization */
+	/* Set new videomode */
+	ami_build_copper();
 
-	/*
-	 * FB_VMODE_CONUPDATE and FB_VMODE_SMOOTH_XPAN are equal!
-	 * as FB_VMODE_SMOOTH_XPAN is only used internally
-	 */
+	/* Set VBlank trigger */
+	do_vmode_full = 1;
 
-	if (var->vmode & FB_VMODE_CONUPDATE) {
-		var->vmode |= FB_VMODE_YWRAP;
-		var->xoffset = display->var.xoffset;
-		var->yoffset = display->var.yoffset;
+	/* Update fix for new screen parameters */
+	if (par->bpp == 1) {
+		info->fix.type = FB_TYPE_PACKED_PIXELS;
+		info->fix.type_aux = 0;
+	} else if (amifb_ilbm) {
+		info->fix.type = FB_TYPE_INTERLEAVED_PLANES;
+		info->fix.type_aux = par->next_line;
+	} else {
+		info->fix.type = FB_TYPE_PLANES;
+		info->fix.type_aux = 0;
 	}
-	if ((err = ami_decode_var(var, &par)))
-		return err;
-	ami_encode_var(var, &par);
-	if ((activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
-		oldxres = display->var.xres;
-		oldyres = display->var.yres;
-		oldvxres = display->var.xres_virtual;
-		oldvyres = display->var.yres_virtual;
-		oldbpp = display->var.bits_per_pixel;
-		display->var = *var;
-		if (oldxres != var->xres || oldyres != var->yres ||
-		    oldvxres != var->xres_virtual || oldvyres != var->yres_virtual ||
-		    oldbpp != var->bits_per_pixel) {
-			struct fb_fix_screeninfo fix;
-
-			ami_encode_fix(&fix, &par);
-			display->visual = fix.visual;
-			display->type = fix.type;
-			display->type_aux = fix.type_aux;
-			display->ypanstep = fix.ypanstep;
-			display->ywrapstep = fix.ywrapstep;
-			display->line_length = fix.line_length;
-			display->can_soft_blank = 1;
-			display->inverse = amifb_inverse;
-			switch (fix.type) {
-#ifdef FBCON_HAS_ILBM
-			    case FB_TYPE_INTERLEAVED_PLANES:
-				display->dispsw = &fbcon_ilbm;
-				break;
-#endif
-#ifdef FBCON_HAS_AFB
-			    case FB_TYPE_PLANES:
-				display->dispsw = &fbcon_afb;
-				break;
-#endif
-#ifdef FBCON_HAS_MFB
-			    case FB_TYPE_PACKED_PIXELS:	/* depth == 1 */
-				display->dispsw = &fbcon_mfb;
-				break;
-#endif
-			    default:
-				display->dispsw = &fbcon_dummy;
-			}
-			if (fb_info.changevar)
-				(*fb_info.changevar)(con);
-		}
-		if (oldbpp != var->bits_per_pixel) {
-			if ((err = fb_alloc_cmap(&display->cmap, 0, 0)))
-				return err;
-			do_install_cmap(con, info);
-		}
-		if (con == info->currcon)
-			ami_set_var(&display->var);
+	info->fix.line_length = div8(upx(16<<maxfmode, par->vxres));
+
+	if (par->vmode & FB_VMODE_YWRAP) {
+		info->fix.ywrapstep = 1;
+		info->fix.xpanstep = 0;
+		info->fix.ypanstep = 0;
+	} else {
+		info->fix.ywrapstep = 0;
+		if (par->vmode &= FB_VMODE_SMOOTH_XPAN)
+			info->fix.xpanstep = 1;
+		else
+			info->fix.xpanstep = 16<<maxfmode;
+		info->fix.ypanstep = 1;
 	}
 	return 0;
 }
 
+
 	/*
 	 * Pan or Wrap the Display
 	 *
 	 * This call looks only at xoffset, yoffset and the FB_VMODE_YWRAP flag
 	 */
 
-static int amifb_pan_display(struct fb_var_screeninfo *var, int con,
-				struct fb_info *info)
+static int amifb_pan_display(struct fb_var_screeninfo *var,
+			     struct fb_info *info)
 {
 	if (var->vmode & FB_VMODE_YWRAP) {
-		if (var->yoffset<0 || var->yoffset >= fb_display[con].var.yres_virtual || var->xoffset)
+		if (var->yoffset < 0 ||
+		    var->yoffset >= info->var.yres_virtual || var->xoffset)
 			return -EINVAL;
 	} else {
 		/*
 		 * TODO: There will be problems when xpan!=1, so some columns
 		 * on the right side will never be seen
 		 */
-		if (var->xoffset+fb_display[con].var.xres > upx(16<<maxfmode, fb_display[con].var.xres_virtual) ||
-		    var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual)
+		if (var->xoffset+info->var.xres > upx(16<<maxfmode, info->var.xres_virtual) ||
+		    var->yoffset+info->var.yres > info->var.yres_virtual)
 			return -EINVAL;
 	}
-	if (con == info->currcon)
-		ami_pan_var(var);
-	fb_display[con].var.xoffset = var->xoffset;
-	fb_display[con].var.yoffset = var->yoffset;
+	ami_pan_var(var);
+	info->var.xoffset = var->xoffset;
+	info->var.yoffset = var->yoffset;
 	if (var->vmode & FB_VMODE_YWRAP)
-		fb_display[con].var.vmode |= FB_VMODE_YWRAP;
+		info->var.vmode |= FB_VMODE_YWRAP;
 	else
-		fb_display[con].var.vmode &= ~FB_VMODE_YWRAP;
+		info->var.vmode &= ~FB_VMODE_YWRAP;
 	return 0;
 }
 
-	/*
-	 * Get the Colormap
-	 */
 
-static int amifb_get_cmap(struct fb_cmap *cmap, int kspc, int con,
-			  struct fb_info *info)
+#if BITS_PER_LONG == 32
+#define BYTES_PER_LONG	4
+#define SHIFT_PER_LONG	5
+#elif BITS_PER_LONG == 64
+#define BYTES_PER_LONG	8
+#define SHIFT_PER_LONG	6
+#else
+#define Please update me
+#endif
+
+
+    /*
+     *  Compose two values, using a bitmask as decision value
+     *  This is equivalent to (a & mask) | (b & ~mask)
+     */
+
+static inline unsigned long comp(unsigned long a, unsigned long b,
+				 unsigned long mask)
 {
-	if (con == info->currcon) /* current console? */
-		return fb_get_cmap(cmap, kspc, ami_getcolreg, info);
-	else if (fb_display[con].cmap.len) /* non default colormap? */
-		fb_copy_cmap(&fb_display[con].cmap, cmap, kspc ? 0 : 2);
-	else
-		fb_copy_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel),
-			     cmap, kspc ? 0 : 2);
-	return 0;
+	return ((a ^ b) & mask) ^ b;
 }
-	
-	/*
-	 * Amiga Frame Buffer Specific ioctls
-	 */
 
-static int amifb_ioctl(struct inode *inode, struct file *file,
-                       u_int cmd, u_long arg, int con, struct fb_info *info)
+
+static inline unsigned long xor(unsigned long a, unsigned long b,
+				unsigned long mask)
 {
-	int i;
+	return (a & mask) ^ b;
+}
 
-	switch (cmd) {
-		case FBIOGET_FCURSORINFO : {
-			struct fb_fix_cursorinfo crsrfix;
-			
-			i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrfix));
-			if (!i) {
-				i = amifb_get_fix_cursorinfo(&crsrfix, con);
-				copy_to_user((void *)arg, &crsrfix, sizeof(crsrfix));
-			}
-			return i;
-		}
-		case FBIOGET_VCURSORINFO : {
-			struct fb_var_cursorinfo crsrvar;
 
-			i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrvar));
-			if (!i) {
-				i = amifb_get_var_cursorinfo(&crsrvar,
-					((struct fb_var_cursorinfo *)arg)->data, con);
-				copy_to_user((void *)arg, &crsrvar, sizeof(crsrvar));
-			}
-			return i;
+    /*
+     *  Unaligned forward bit copy using 32-bit or 64-bit memory accesses
+     */
+
+static void bitcpy(unsigned long *dst, int dst_idx, const unsigned long *src,
+		   int src_idx, u32 n)
+{
+	unsigned long first, last;
+	int shift = dst_idx-src_idx, left, right;
+	unsigned long d0, d1;
+	int m;
+
+	if (!n)
+		return;
+
+	shift = dst_idx-src_idx;
+	first = ~0UL >> dst_idx;
+	last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
+
+	if (!shift) {
+		// Same alignment for source and dest
+
+		if (dst_idx+n <= BITS_PER_LONG) {
+			// Single word
+			if (last)
+				first &= last;
+			*dst = comp(*src, *dst, first);
+		} else {
+			// Multiple destination words
+			// Leading bits
+			if (first) {
+				*dst = comp(*src, *dst, first);
+				dst++;
+				src++;
+				n -= BITS_PER_LONG-dst_idx;
+			}
+
+			// Main chunk
+			n /= BITS_PER_LONG;
+			while (n >= 8) {
+				*dst++ = *src++;
+				*dst++ = *src++;
+				*dst++ = *src++;
+				*dst++ = *src++;
+				*dst++ = *src++;
+				*dst++ = *src++;
+				*dst++ = *src++;
+				*dst++ = *src++;
+				n -= 8;
+			}
+			while (n--)
+				*dst++ = *src++;
+
+			// Trailing bits
+			if (last)
+				*dst = comp(*src, *dst, last);
 		}
-		case FBIOPUT_VCURSORINFO : {
-			struct fb_var_cursorinfo crsrvar;
+	} else {
+		// Different alignment for source and dest
+
+		right = shift & (BITS_PER_LONG-1);
+		left = -shift & (BITS_PER_LONG-1);
 
-			i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrvar));
-			if (!i) {
-				copy_from_user(&crsrvar, (void *)arg, sizeof(crsrvar));
-				i = amifb_set_var_cursorinfo(&crsrvar,
-					((struct fb_var_cursorinfo *)arg)->data, con);
+		if (dst_idx+n <= BITS_PER_LONG) {
+			// Single destination word
+			if (last)
+				first &= last;
+			if (shift > 0) {
+				// Single source word
+				*dst = comp(*src >> right, *dst, first);
+			} else if (src_idx+n <= BITS_PER_LONG) {
+				// Single source word
+				*dst = comp(*src << left, *dst, first);
+			} else {
+				// 2 source words
+				d0 = *src++;
+				d1 = *src;
+				*dst = comp(d0 << left | d1 >> right, *dst,
+					    first);
+			}
+		} else {
+			// Multiple destination words
+			d0 = *src++;
+			// Leading bits
+			if (shift > 0) {
+				// Single source word
+				*dst = comp(d0 >> right, *dst, first);
+				dst++;
+				n -= BITS_PER_LONG-dst_idx;
+			} else {
+				// 2 source words
+				d1 = *src++;
+				*dst = comp(d0 << left | d1 >> right, *dst,
+					    first);
+				d0 = d1;
+				dst++;
+				n -= BITS_PER_LONG-dst_idx;
+			}
+
+			// Main chunk
+			m = n % BITS_PER_LONG;
+			n /= BITS_PER_LONG;
+			while (n >= 4) {
+				d1 = *src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+				d1 = *src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+				d1 = *src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+				d1 = *src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+				n -= 4;
+			}
+			while (n--) {
+				d1 = *src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+			}
+
+			// Trailing bits
+			if (last) {
+				if (m <= right) {
+					// Single source word
+					*dst = comp(d0 << left, *dst, last);
+				} else {
+					// 2 source words
+					d1 = *src;
+					*dst = comp(d0 << left | d1 >> right,
+						    *dst, last);
+				}
 			}
-			return i;
 		}
-		case FBIOGET_CURSORSTATE : {
-			struct fb_cursorstate crsrstate;
+	}
+}
 
-			i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(crsrstate));
-			if (!i) {
-				i = amifb_get_cursorstate(&crsrstate, con);
-				copy_to_user((void *)arg, &crsrstate, sizeof(crsrstate));
-			}
-			return i;
+
+    /*
+     *  Unaligned reverse bit copy using 32-bit or 64-bit memory accesses
+     */
+
+static void bitcpy_rev(unsigned long *dst, int dst_idx,
+		       const unsigned long *src, int src_idx, u32 n)
+{
+	unsigned long first, last;
+	int shift = dst_idx-src_idx, left, right;
+	unsigned long d0, d1;
+	int m;
+
+	if (!n)
+		return;
+
+	dst += (n-1)/BITS_PER_LONG;
+	src += (n-1)/BITS_PER_LONG;
+	if ((n-1) % BITS_PER_LONG) {
+		dst_idx += (n-1) % BITS_PER_LONG;
+		dst += dst_idx >> SHIFT_PER_LONG;
+		dst_idx &= BITS_PER_LONG-1;
+		src_idx += (n-1) % BITS_PER_LONG;
+		src += src_idx >> SHIFT_PER_LONG;
+		src_idx &= BITS_PER_LONG-1;
+	}
+
+	shift = dst_idx-src_idx;
+	first = ~0UL << (BITS_PER_LONG-1-dst_idx);
+	last = ~(~0UL << (BITS_PER_LONG-1-((dst_idx-n) % BITS_PER_LONG)));
+
+	if (!shift) {
+		// Same alignment for source and dest
+
+		if ((unsigned long)dst_idx+1 >= n) {
+			// Single word
+			if (last)
+				first &= last;
+			*dst = comp(*src, *dst, first);
+		} else {
+			// Multiple destination words
+			// Leading bits
+			if (first) {
+				*dst = comp(*src, *dst, first);
+				dst--;
+				src--;
+				n -= dst_idx+1;
+			}
+
+			// Main chunk
+			n /= BITS_PER_LONG;
+			while (n >= 8) {
+				*dst-- = *src--;
+				*dst-- = *src--;
+				*dst-- = *src--;
+				*dst-- = *src--;
+				*dst-- = *src--;
+				*dst-- = *src--;
+				*dst-- = *src--;
+				*dst-- = *src--;
+				n -= 8;
+			}
+			while (n--)
+				*dst-- = *src--;
+
+			// Trailing bits
+			if (last)
+				*dst = comp(*src, *dst, last);
 		}
-		case FBIOPUT_CURSORSTATE : {
-			struct fb_cursorstate crsrstate;
+	} else {
+		// Different alignment for source and dest
+
+		right = shift & (BITS_PER_LONG-1);
+		left = -shift & (BITS_PER_LONG-1);
 
-			i = verify_area(VERIFY_READ, (void *)arg, sizeof(crsrstate));
-			if (!i) {
-				copy_from_user(&crsrstate, (void *)arg, sizeof(crsrstate));
-				i = amifb_set_cursorstate(&crsrstate, con);
+		if ((unsigned long)dst_idx+1 >= n) {
+			// Single destination word
+			if (last)
+				first &= last;
+			if (shift < 0) {
+				// Single source word
+				*dst = comp(*src << left, *dst, first);
+			} else if (1+(unsigned long)src_idx >= n) {
+				// Single source word
+				*dst = comp(*src >> right, *dst, first);
+			} else {
+				// 2 source words
+				d0 = *src--;
+				d1 = *src;
+				*dst = comp(d0 >> right | d1 << left, *dst,
+					    first);
+			}
+		} else {
+			// Multiple destination words
+			d0 = *src--;
+			// Leading bits
+			if (shift < 0) {
+				// Single source word
+				*dst = comp(d0 << left, *dst, first);
+				dst--;
+				n -= dst_idx+1;
+			} else {
+				// 2 source words
+				d1 = *src--;
+				*dst = comp(d0 >> right | d1 << left, *dst,
+					    first);
+				d0 = d1;
+				dst--;
+				n -= dst_idx+1;
+			}
+
+			// Main chunk
+			m = n % BITS_PER_LONG;
+			n /= BITS_PER_LONG;
+			while (n >= 4) {
+				d1 = *src--;
+				*dst-- = d0 >> right | d1 << left;
+				d0 = d1;
+				d1 = *src--;
+				*dst-- = d0 >> right | d1 << left;
+				d0 = d1;
+				d1 = *src--;
+				*dst-- = d0 >> right | d1 << left;
+				d0 = d1;
+				d1 = *src--;
+				*dst-- = d0 >> right | d1 << left;
+				d0 = d1;
+				n -= 4;
+			}
+			while (n--) {
+				d1 = *src--;
+				*dst-- = d0 >> right | d1 << left;
+				d0 = d1;
+			}
+
+			// Trailing bits
+			if (last) {
+				if (m <= left) {
+					// Single source word
+					*dst = comp(d0 >> right, *dst, last);
+				} else {
+					// 2 source words
+					d1 = *src;
+					*dst = comp(d0 >> right | d1 << left,
+						    *dst, last);
+				}
 			}
-			return i;
 		}
-#ifdef DEBUG
-		case FBCMD_GET_CURRENTPAR : {
-			struct amifb_par par;
+	}
+}
 
-			i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct amifb_par));
-			if (!i) {
-				ami_get_par(&par);
-				copy_to_user((void *)arg, &par, sizeof(struct amifb_par));
-			}
-			return i;
+
+    /*
+     *  Unaligned forward inverting bit copy using 32-bit or 64-bit memory
+     *  accesses
+     */
+
+static void bitcpy_not(unsigned long *dst, int dst_idx,
+		       const unsigned long *src, int src_idx, u32 n)
+{
+	unsigned long first, last;
+	int shift = dst_idx-src_idx, left, right;
+	unsigned long d0, d1;
+	int m;
+
+	if (!n)
+		return;
+
+	shift = dst_idx-src_idx;
+	first = ~0UL >> dst_idx;
+	last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
+
+	if (!shift) {
+		// Same alignment for source and dest
+
+		if (dst_idx+n <= BITS_PER_LONG) {
+			// Single word
+			if (last)
+				first &= last;
+			*dst = comp(~*src, *dst, first);
+		} else {
+			// Multiple destination words
+			// Leading bits
+			if (first) {
+				*dst = comp(~*src, *dst, first);
+				dst++;
+				src++;
+				n -= BITS_PER_LONG-dst_idx;
+			}
+
+			// Main chunk
+			n /= BITS_PER_LONG;
+			while (n >= 8) {
+				*dst++ = ~*src++;
+				*dst++ = ~*src++;
+				*dst++ = ~*src++;
+				*dst++ = ~*src++;
+				*dst++ = ~*src++;
+				*dst++ = ~*src++;
+				*dst++ = ~*src++;
+				*dst++ = ~*src++;
+				n -= 8;
+			}
+			while (n--)
+				*dst++ = ~*src++;
+
+			// Trailing bits
+			if (last)
+				*dst = comp(~*src, *dst, last);
 		}
-		case FBCMD_SET_CURRENTPAR : {
-			struct amifb_par par;
+	} else {
+		// Different alignment for source and dest
+
+		right = shift & (BITS_PER_LONG-1);
+		left = -shift & (BITS_PER_LONG-1);
 
-			i = verify_area(VERIFY_READ, (void *)arg, sizeof(struct amifb_par));
-			if (!i) {
-				copy_from_user(&par, (void *)arg, sizeof(struct amifb_par));
-				ami_set_par(&par);
+		if (dst_idx+n <= BITS_PER_LONG) {
+			// Single destination word
+			if (last)
+				first &= last;
+			if (shift > 0) {
+				// Single source word
+				*dst = comp(~*src >> right, *dst, first);
+			} else if (src_idx+n <= BITS_PER_LONG) {
+				// Single source word
+				*dst = comp(~*src << left, *dst, first);
+			} else {
+				// 2 source words
+				d0 = ~*src++;
+				d1 = ~*src;
+				*dst = comp(d0 << left | d1 >> right, *dst,
+					    first);
+			}
+		} else {
+			// Multiple destination words
+			d0 = ~*src++;
+			// Leading bits
+			if (shift > 0) {
+				// Single source word
+				*dst = comp(d0 >> right, *dst, first);
+				dst++;
+				n -= BITS_PER_LONG-dst_idx;
+			} else {
+				// 2 source words
+				d1 = ~*src++;
+				*dst = comp(d0 << left | d1 >> right, *dst,
+					    first);
+				d0 = d1;
+				dst++;
+				n -= BITS_PER_LONG-dst_idx;
+			}
+
+			// Main chunk
+			m = n % BITS_PER_LONG;
+			n /= BITS_PER_LONG;
+			while (n >= 4) {
+				d1 = ~*src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+				d1 = ~*src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+				d1 = ~*src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+				d1 = ~*src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+				n -= 4;
+			}
+			while (n--) {
+				d1 = ~*src++;
+				*dst++ = d0 << left | d1 >> right;
+				d0 = d1;
+			}
+
+			// Trailing bits
+			if (last) {
+				if (m <= right) {
+					// Single source word
+					*dst = comp(d0 << left, *dst, last);
+				} else {
+					// 2 source words
+					d1 = ~*src;
+					*dst = comp(d0 << left | d1 >> right,
+						    *dst, last);
+				}
 			}
-			return i;
 		}
-#endif	/* DEBUG */
 	}
-	return -EINVAL;
 }
 
-	/*
-	 * Hardware Cursor
-	 */
 
-static int amifb_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con)
+    /*
+     *  Unaligned 32-bit pattern fill using 32/64-bit memory accesses
+     */
+
+static void bitfill32(unsigned long *dst, int dst_idx, u32 pat, u32 n)
 {
-	return ami_get_fix_cursorinfo(fix, con);
+	unsigned long val = pat;
+	unsigned long first, last;
+
+	if (!n)
+		return;
+
+#if BITS_PER_LONG == 64
+	val |= val << 32;
+#endif
+
+	first = ~0UL >> dst_idx;
+	last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
+
+	if (dst_idx+n <= BITS_PER_LONG) {
+		// Single word
+		if (last)
+			first &= last;
+		*dst = comp(val, *dst, first);
+	} else {
+		// Multiple destination words
+		// Leading bits
+		if (first) {
+			*dst = comp(val, *dst, first);
+			dst++;
+			n -= BITS_PER_LONG-dst_idx;
+		}
+
+		// Main chunk
+		n /= BITS_PER_LONG;
+		while (n >= 8) {
+			*dst++ = val;
+			*dst++ = val;
+			*dst++ = val;
+			*dst++ = val;
+			*dst++ = val;
+			*dst++ = val;
+			*dst++ = val;
+			*dst++ = val;
+			n -= 8;
+		}
+		while (n--)
+			*dst++ = val;
+
+		// Trailing bits
+		if (last)
+			*dst = comp(val, *dst, last);
+	}
 }
 
-static int amifb_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
+
+    /*
+     *  Unaligned 32-bit pattern xor using 32/64-bit memory accesses
+     */
+
+static void bitxor32(unsigned long *dst, int dst_idx, u32 pat, u32 n)
 {
-	return ami_get_var_cursorinfo(var, data, con);
+	unsigned long val = pat;
+	unsigned long first, last;
+
+	if (!n)
+		return;
+
+#if BITS_PER_LONG == 64
+	val |= val << 32;
+#endif
+
+	first = ~0UL >> dst_idx;
+	last = ~(~0UL >> ((dst_idx+n) % BITS_PER_LONG));
+
+	if (dst_idx+n <= BITS_PER_LONG) {
+		// Single word
+		if (last)
+			first &= last;
+		*dst = xor(val, *dst, first);
+	} else {
+		// Multiple destination words
+		// Leading bits
+		if (first) {
+			*dst = xor(val, *dst, first);
+			dst++;
+			n -= BITS_PER_LONG-dst_idx;
+		}
+
+		// Main chunk
+		n /= BITS_PER_LONG;
+		while (n >= 4) {
+			*dst++ ^= val;
+			*dst++ ^= val;
+			*dst++ ^= val;
+			*dst++ ^= val;
+			n -= 4;
+		}
+		while (n--)
+			*dst++ ^= val;
+
+		// Trailing bits
+		if (last)
+			*dst = xor(val, *dst, last);
+	}
+}
+
+static inline void fill_one_line(int bpp, unsigned long next_plane,
+				 unsigned long *dst, int dst_idx, u32 n,
+				 u32 color)
+{
+	while (1) {
+		dst += dst_idx >> SHIFT_PER_LONG;
+		dst_idx &= (BITS_PER_LONG-1);
+		bitfill32(dst, dst_idx, color & 1 ? ~0 : 0, n);
+		if (!--bpp)
+			break;
+		color >>= 1;
+		dst_idx += next_plane*8;
+	}
+}
+
+static inline void xor_one_line(int bpp, unsigned long next_plane,
+				unsigned long *dst, int dst_idx, u32 n,
+				u32 color)
+{
+	while (color) {
+		dst += dst_idx >> SHIFT_PER_LONG;
+		dst_idx &= (BITS_PER_LONG-1);
+		bitxor32(dst, dst_idx, color & 1 ? ~0 : 0, n);
+		if (!--bpp)
+			break;
+		color >>= 1;
+		dst_idx += next_plane*8;
+	}
+}
+
+
+static void amifb_fillrect(struct fb_info *info, struct fb_fillrect *rect)
+{
+	struct amifb_par *par = (struct amifb_par *)info->par;
+	int dst_idx, x2, y2;
+	unsigned long *dst;
+
+	if (!rect->width || !rect->height)
+		return;
+
+	/*
+	 * We could use hardware clipping but on many cards you get around
+	 * hardware clipping by writing to framebuffer directly.
+	 * */
+	x2 = rect->dx + rect->width;
+	y2 = rect->dy + rect->height;
+	x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
+	y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
+	rect->width = x2 - rect->dx;
+	rect->height = y2 - rect->dy;
+
+	dst = (unsigned long *)
+		((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1));
+	dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8;
+	dst_idx += rect->dy*par->next_line*8+rect->dx;
+	while (rect->height--) {
+		switch (rect->rop) {
+		    case ROP_COPY:
+			fill_one_line(info->var.bits_per_pixel,
+				      par->next_plane, dst, dst_idx,
+				      rect->width, rect->color);
+			break;
+
+		    case ROP_XOR:
+			xor_one_line(info->var.bits_per_pixel,
+				     par->next_plane, dst, dst_idx,
+				     rect->width, rect->color);
+			break;
+		}
+		dst_idx += par->next_line*8;
+	}
 }
 
-static int amifb_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
+static inline void copy_one_line(int bpp, unsigned long next_plane,
+				 unsigned long *dst, int dst_idx,
+				 unsigned long *src, int src_idx, u32 n)
+{
+	while (1) {
+		dst += dst_idx >> SHIFT_PER_LONG;
+		dst_idx &= (BITS_PER_LONG-1);
+		src += src_idx >> SHIFT_PER_LONG;
+		src_idx &= (BITS_PER_LONG-1);
+		bitcpy(dst, dst_idx, src, src_idx, n);
+		if (!--bpp)
+			break;
+		dst_idx += next_plane*8;
+		src_idx += next_plane*8;
+	}
+}
+
+static inline void copy_one_line_rev(int bpp, unsigned long next_plane,
+				     unsigned long *dst, int dst_idx,
+				     unsigned long *src, int src_idx, u32 n)
+{
+	while (1) {
+		dst += dst_idx >> SHIFT_PER_LONG;
+		dst_idx &= (BITS_PER_LONG-1);
+		src += src_idx >> SHIFT_PER_LONG;
+		src_idx &= (BITS_PER_LONG-1);
+		bitcpy_rev(dst, dst_idx, src, src_idx, n);
+		if (!--bpp)
+			break;
+		dst_idx += next_plane*8;
+		src_idx += next_plane*8;
+	}
+}
+
+
+static void amifb_copyarea(struct fb_info *info, struct fb_copyarea *area)
 {
-	return ami_set_var_cursorinfo(var, data, con);
+	struct amifb_par *par = (struct amifb_par *)info->par;
+	int x2, y2, old_dx, old_dy;
+	unsigned long *dst, *src;
+	int dst_idx, src_idx, height;
+	int rev_copy = 0;
+
+	/* clip the destination */
+	old_dx = area->dx;
+	old_dy = area->dy;
+
+	/*
+	 * We could use hardware clipping but on many cards you get around
+	 * hardware clipping by writing to framebuffer directly.
+	 */
+	x2 = area->dx + area->width;
+	y2 = area->dy + area->height;
+	area->dx = area->dx > 0 ? area->dx : 0;
+	area->dy = area->dy > 0 ? area->dy : 0;
+	x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
+	y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
+	area->width = x2 - area->dx;
+	area->height = y2 - area->dy;
+
+	/* update sx1,sy1 */
+	area->sx += (area->dx - old_dx);
+	area->sy += (area->dy - old_dy);
+
+	height = area->height;
+
+	/* the source must be completely inside the virtual screen */
+	if (area->sx < 0 || area->sy < 0 ||
+	    (area->sx + area->width) > info->var.xres_virtual ||
+	    (area->sy + area->height) > info->var.yres_virtual)
+		return;
+
+	if (area->dy > area->sy ||
+	    (area->dy == area->sy && area->dx > area->sx)) {
+		area->dy += area->height;
+		area->sy += area->height;
+		rev_copy = 1;
+	}
+	dst = (unsigned long *)
+		((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1));
+	src = dst;
+	dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8;
+	src_idx = dst_idx;
+	dst_idx += area->dy*par->next_line*8+area->dx;
+	src_idx += area->sy*par->next_line*8+area->sx;
+	if (rev_copy) {
+		while (height--) {
+			dst_idx -= par->next_line*8;
+			src_idx -= par->next_line*8;
+			copy_one_line_rev(info->var.bits_per_pixel,
+					  par->next_plane, dst, dst_idx, src,
+					  src_idx, area->width);
+		}
+	} else {
+		while (height--) {
+			copy_one_line(info->var.bits_per_pixel,
+				      par->next_plane, dst, dst_idx, src,
+				      src_idx, area->width);
+			dst_idx += par->next_line*8;
+			src_idx += par->next_line*8;
+		}
+	}
+}
+
+
+static inline void expand_one_line(int bpp, unsigned long next_plane,
+				   unsigned long *dst, int dst_idx, u32 n,
+				   const u8 *data, u32 bgcolor, u32 fgcolor)
+{
+    const unsigned long *src;
+    int src_idx;
+
+    while (1) {
+	dst += dst_idx >> SHIFT_PER_LONG;
+	dst_idx &= (BITS_PER_LONG-1);
+	if ((bgcolor ^ fgcolor) & 1) {
+	    src = (unsigned long *)((unsigned long)data & ~(BYTES_PER_LONG-1));
+	    src_idx = ((unsigned long)data & (BYTES_PER_LONG-1))*8;
+	    if (fgcolor & 1)
+		bitcpy(dst, dst_idx, src, src_idx, n);
+	    else
+		bitcpy_not(dst, dst_idx, src, src_idx, n);
+	    /* set or clear */
+	} else
+	    bitfill32(dst, dst_idx, fgcolor & 1 ? ~0 : 0, n);
+	if (!--bpp)
+	    break;
+	bgcolor >>= 1;
+	fgcolor >>= 1;
+	dst_idx += next_plane*8;
+    }
 }
 
-static int amifb_get_cursorstate(struct fb_cursorstate *state, int con)
+
+static void amifb_imageblit(struct fb_info *info, struct fb_image *image)
 {
-	return ami_get_cursorstate(state, con);
+	struct amifb_par *par = (struct amifb_par *)info->par;
+	int x2, y2;
+	unsigned long *dst;
+	int dst_idx;
+	const char *src;
+	u32 dx, dy, width, height, pitch;
+
+	/*
+	 * We could use hardware clipping but on many cards you get around
+	 * hardware clipping by writing to framebuffer directly like we are
+	 * doing here.
+	 */
+	x2 = image->dx + image->width;
+	y2 = image->dy + image->height;
+	dx = image->dx;
+	dy = image->dy;
+	x2 = x2 < info->var.xres_virtual ? x2 : info->var.xres_virtual;
+	y2 = y2 < info->var.yres_virtual ? y2 : info->var.yres_virtual;
+	width  = x2 - dx;
+	height = y2 - dy;
+
+	if (image->depth == 1) {
+		dst = (unsigned long *)
+			((unsigned long)info->screen_base & ~(BYTES_PER_LONG-1));
+		dst_idx = ((unsigned long)info->screen_base & (BYTES_PER_LONG-1))*8;
+		dst_idx += dy*par->next_line*8+dx;
+		src = image->data;
+		pitch = (image->width+7)/8;
+		while (height--) {
+			expand_one_line(info->var.bits_per_pixel,
+					par->next_plane, dst, dst_idx, width,
+					src, image->bg_color,
+					image->fg_color);
+			dst_idx += par->next_line*8;
+			src += pitch;
+		}
+	} else {
+		c2p(info->screen_base, image->data, dx, dy, width, height,
+		    par->next_line, par->next_plane, image->width,
+		    info->var.bits_per_pixel);
+	}
 }
 
-static int amifb_set_cursorstate(struct fb_cursorstate *state, int con)
+
+	/*
+	 * Amiga Frame Buffer Specific ioctls
+	 */
+
+static int amifb_ioctl(struct inode *inode, struct file *file,
+		       unsigned int cmd, unsigned long arg,
+		       struct fb_info *info)
 {
-	return ami_set_cursorstate(state, con);
+	union {
+		struct fb_fix_cursorinfo fix;
+		struct fb_var_cursorinfo var;
+		struct fb_cursorstate state;
+	} crsr;
+	int i;
+
+	switch (cmd) {
+		case FBIOGET_FCURSORINFO:
+			i = ami_get_fix_cursorinfo(&crsr.fix);
+			if (i)
+				return i;
+			return copy_to_user((void *)arg, &crsr.fix,
+					    sizeof(crsr.fix)) ? -EFAULT : 0;
+
+		case FBIOGET_VCURSORINFO:
+			i = ami_get_var_cursorinfo(&crsr.var,
+				((struct fb_var_cursorinfo *)arg)->data);
+			if (i)
+				return i;
+			return copy_to_user((void *)arg, &crsr.var,
+					    sizeof(crsr.var)) ? -EFAULT : 0;
+
+		case FBIOPUT_VCURSORINFO:
+			if (copy_from_user(&crsr.var, (void *)arg,
+					   sizeof(crsr.var)))
+				return -EFAULT;
+			return ami_set_var_cursorinfo(&crsr.var,
+				((struct fb_var_cursorinfo *)arg)->data);
+
+		case FBIOGET_CURSORSTATE:
+			i = ami_get_cursorstate(&crsr.state);
+			if (i)
+				return i;
+			return copy_to_user((void *)arg, &crsr.state,
+					    sizeof(crsr.state)) ? -EFAULT : 0;
+
+		case FBIOPUT_CURSORSTATE:
+			if (copy_from_user(&crsr.state, (void *)arg,
+					   sizeof(crsr.state)))
+				return -EFAULT;
+			return ami_set_cursorstate(&crsr.state);
+	}
+	return -EINVAL;
 }
 
 
@@ -1570,7 +2259,6 @@
 	int tag, i, err = 0;
 	u_long chipptr;
 	u_int defmode;
-	struct fb_var_screeninfo var;
 
 	if (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(AMI_VIDEO))
 		return -ENXIO;
@@ -1600,7 +2288,7 @@
 	switch (amiga_chipset) {
 #ifdef CONFIG_FB_AMIGA_OCS
 		case CS_OCS:
-			strcat(amifb_name, "OCS");
+			strcat(fb_info.fix.id, "OCS");
 default_chipset:
 			chipset = TAG_OCS;
 			maxdepth[TAG_SHRES] = 0;	/* OCS means no SHRES */
@@ -1609,13 +2297,13 @@
 			maxfmode = TAG_FMODE_1;
 			defmode = amiga_vblank == 50 ? DEFMODE_PAL
 						     : DEFMODE_NTSC;
-			videomemorysize = VIDEOMEMSIZE_OCS;
+			fb_info.fix.smem_len = VIDEOMEMSIZE_OCS;
 			break;
 #endif /* CONFIG_FB_AMIGA_OCS */
 
 #ifdef CONFIG_FB_AMIGA_ECS
 		case CS_ECS:
-			strcat(amifb_name, "ECS");
+			strcat(fb_info.fix.id, "ECS");
 			chipset = TAG_ECS;
 			maxdepth[TAG_SHRES] = 2;
 			maxdepth[TAG_HIRES] = 4;
@@ -1629,15 +2317,15 @@
 							 : DEFMODE_NTSC;
 			if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT >
 			    VIDEOMEMSIZE_ECS_1M)
-				videomemorysize = VIDEOMEMSIZE_ECS_2M;
+				fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_2M;
 			else
-				videomemorysize = VIDEOMEMSIZE_ECS_1M;
+				fb_info.fix.smem_len = VIDEOMEMSIZE_ECS_1M;
 			break;
 #endif /* CONFIG_FB_AMIGA_ECS */
 
 #ifdef CONFIG_FB_AMIGA_AGA
 		case CS_AGA:
-			strcat(amifb_name, "AGA");
+			strcat(fb_info.fix.id, "AGA");
 			chipset = TAG_AGA;
 			maxdepth[TAG_SHRES] = 8;
 			maxdepth[TAG_HIRES] = 8;
@@ -1646,16 +2334,16 @@
 			defmode = DEFMODE_AGA;
 			if (amiga_chip_avail()-CHIPRAM_SAFETY_LIMIT >
 			    VIDEOMEMSIZE_AGA_1M)
-				videomemorysize = VIDEOMEMSIZE_AGA_2M;
+				fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_2M;
 			else
-				videomemorysize = VIDEOMEMSIZE_AGA_1M;
+				fb_info.fix.smem_len = VIDEOMEMSIZE_AGA_1M;
 			break;
 #endif /* CONFIG_FB_AMIGA_AGA */
 
 		default:
 #ifdef CONFIG_FB_AMIGA_OCS
 			printk("Unknown graphics chipset, defaulting to OCS\n");
-			strcat(amifb_name, "Unknown");
+			strcat(fb_info.fix.id, "Unknown");
 			goto default_chipset;
 #else /* CONFIG_FB_AMIGA_OCS */
 			err = -ENXIO;
@@ -1698,31 +2386,25 @@
 	    fb_info.monspecs.vfmax = 90;
 	}
 
-	strcpy(fb_info.modename, amifb_name);
-	fb_info.changevar = NULL;
 	fb_info.node = NODEV;
 	fb_info.fbops = &amifb_ops;
-	fb_info.disp = &disp;
-	fb_info.currcon = 1;
-	fb_info.switch_con = &amifbcon_switch;
-	fb_info.updatevar = &amifbcon_updatevar;
+	fb_info.par = &currentpar;
 	fb_info.flags = FBINFO_FLAG_DEFAULT;
-	memset(&var, 0, sizeof(var));
 
-	if (!fb_find_mode(&var, &fb_info, mode_option, ami_modedb,
+	if (!fb_find_mode(&fb_info.var, &fb_info, mode_option, ami_modedb,
 			  NUM_TOTAL_MODES, &ami_modedb[defmode], 4)) {
 		err = -EINVAL;
 		goto amifb_error;
 	}
 
 	round_down_bpp = 0;
-	chipptr = chipalloc(videomemorysize+
+	chipptr = chipalloc(fb_info.fix.smem_len+
 	                    SPRITEMEMSIZE+
 	                    DUMMYSPRITEMEMSIZE+
 	                    COPINITSIZE+
 	                    4*COPLISTSIZE);
 
-	assignchunk(videomemory, u_long, chipptr, videomemorysize);
+	assignchunk(videomemory, u_long, chipptr, fb_info.fix.smem_len);
 	assignchunk(spritememory, u_long, chipptr, SPRITEMEMSIZE);
 	assignchunk(dummysprite, u_short *, chipptr, DUMMYSPRITEMEMSIZE);
 	assignchunk(copdisplay.init, copins *, chipptr, COPINITSIZE);
@@ -1734,11 +2416,12 @@
 	/*
 	 * access the videomem with writethrough cache
 	 */
-	videomemory_phys = (u_long)ZTWO_PADDR(videomemory);
-	videomemory = (u_long)ioremap_writethrough(videomemory_phys, videomemorysize);
+	fb_info.fix.smem_start = (u_long)ZTWO_PADDR(videomemory);
+	videomemory = (u_long)ioremap_writethrough(fb_info.fix.smem_start,
+						   fb_info.fix.smem_len);
 	if (!videomemory) {
 		printk("amifb: WARNING! unable to map videomem cached writethrough\n");
-		videomemory = ZTWO_VADDR(videomemory_phys);
+		videomemory = ZTWO_VADDR(fb_info.fix.smem_start);
 	}
 
 	fb_info.screen_base = (char *)videomemory;
@@ -1763,19 +2446,18 @@
 		goto amifb_error;
 	}
 
-	amifb_set_var(&var, -1, &fb_info);
+	fb_alloc_cmap(&fb_info.cmap, 1<<fb_info.var.bits_per_pixel, 0);
 
 	if (register_framebuffer(&fb_info) < 0) {
 		err = -EINVAL;
 		goto amifb_error;
 	}
 
-	printk("fb%d: %s frame buffer device, using %ldK of video memory\n",
-	       minor(fb_info.node), fb_info.modename,
-	       videomemorysize>>10);
+	printk("fb%d: %s frame buffer device, using %dK of video memory\n",
+	       minor(fb_info.node), fb_info.fix.id, fb_info.fix.smem_len>>10);
 
 	return 0;
-	
+
 amifb_error:
 	amifb_deinit();
 	return err;
@@ -1783,33 +2465,12 @@
 
 static void amifb_deinit(void)
 {
-	chipfree();    
+	fb_dealloc_cmap(&fb_info.cmap);
+	chipfree();
 	release_mem_region(CUSTOM_PHYSADDR+0xe0, 0x120);
 	custom.dmacon = DMAF_ALL | DMAF_MASTER;
 }
 
-static int amifbcon_switch(int con, struct fb_info *info)
-{
-	/* Do we have to save the colormap? */
-	if (fb_display[info->currcon].cmap.len)
-		fb_get_cmap(&fb_display[info->currcon].cmap, 1, ami_getcolreg, info);
-
-	info->currcon = con;
-	ami_set_var(&fb_display[con].var);
-	/* Install new colormap */
-	do_install_cmap(con, info);
-	return 0;
-}
-
-	/*
-	 * Update the `var' structure (called by fbcon.c)
-	 */
-
-static int amifbcon_updatevar(int con, struct fb_info *info)
-{
-	ami_pan_var(&fb_display[con].var);
-	return 0;
-}
 
 	/*
 	 * Blank the display.
@@ -1821,6 +2482,10 @@
 	return 0;
 }
 
+	/*
+	 * Flash the cursor (called by VBlank interrupt)
+	 */
+
 static int flash_cursor(void)
 {
 	static int cursorcount = 1;
@@ -1875,50 +2540,6 @@
 /* --------------------------- Hardware routines --------------------------- */
 
 	/*
-	 * This function should fill in the `fix' structure based on the
-	 * values in the `par' structure.
-	 */
-
-static int ami_encode_fix(struct fb_fix_screeninfo *fix,
-                          struct amifb_par *par)
-{
-	memset(fix, 0, sizeof(struct fb_fix_screeninfo));
-	strcpy(fix->id, amifb_name);
-	fix->smem_start = videomemory_phys;
-	fix->smem_len = videomemorysize;
-
-#ifdef FBCON_HAS_MFB
-	if (par->bpp == 1) {
-		fix->type = FB_TYPE_PACKED_PIXELS;
-		fix->type_aux = 0;
-	} else
-#endif
-	if (amifb_ilbm) {
-		fix->type = FB_TYPE_INTERLEAVED_PLANES;
-		fix->type_aux = par->next_line;
-	} else {
-		fix->type = FB_TYPE_PLANES;
-		fix->type_aux = 0;
-	}
-	fix->line_length = div8(upx(16<<maxfmode, par->vxres));
-	fix->visual = FB_VISUAL_PSEUDOCOLOR;
-
-	if (par->vmode & FB_VMODE_YWRAP) {
-		fix->ywrapstep = 1;
-		fix->xpanstep = fix->ypanstep = 0;
-	} else {
-		fix->ywrapstep = 0;
-		if (par->vmode &= FB_VMODE_SMOOTH_XPAN)
-			fix->xpanstep = 1;
-		else
-			fix->xpanstep = 16<<maxfmode;
-		fix->ypanstep = 1;
-	}
-	fix->accel = FB_ACCEL_AMIGABLITT;
-	return 0;
-}
-
-	/*
 	 * Get the video params out of `var'. If a value doesn't fit, round
 	 * it up, if it's too big, return -EINVAL.
 	 */
@@ -2074,7 +2695,7 @@
 			if (!IS_OCS) {
 				par->beamcon0 = BMC0_PAL;
 				par->bplcon3 |= BPC3_BRDRBLNK;
-			} else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || 
+			} else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) ||
 			           AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {
 				par->beamcon0 = BMC0_PAL;
 				par->hsstop = 1;
@@ -2104,7 +2725,7 @@
 			if (!IS_OCS) {
 				par->beamcon0 = 0;
 				par->bplcon3 |= BPC3_BRDRBLNK;
-			} else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) || 
+			} else if (AMIGAHW_PRESENT(AGNUS_HR_PAL) ||
 			           AMIGAHW_PRESENT(AGNUS_HR_NTSC)) {
 				par->beamcon0 = 0;
 				par->hsstop = 1;
@@ -2235,14 +2856,14 @@
 	if (amifb_ilbm) {
 		par->next_plane = div8(upx(16<<maxfmode, par->vxres));
 		par->next_line = par->bpp*par->next_plane;
-		if (par->next_line * par->vyres > videomemorysize) {
+		if (par->next_line * par->vyres > fb_info.fix.smem_len) {
 			DPRINTK("too few video mem\n");
 			return -EINVAL;
 		}
 	} else {
 		par->next_line = div8(upx(16<<maxfmode, par->vxres));
 		par->next_plane = par->vyres*par->next_line;
-		if (par->next_plane * par->bpp > videomemorysize) {
+		if (par->next_plane * par->bpp > fb_info.fix.smem_len) {
 			DPRINTK("too few video mem\n");
 			return -EINVAL;
 		}
@@ -2402,38 +3023,6 @@
 	return 0;
 }
 
-	/*
-	 * Get current hardware setting
-	 */
-
-static void ami_get_par(struct amifb_par *par)
-{
-	*par = currentpar;
-}
-
-	/*
-	 * Set new videomode
-	 */
-
-static void ami_set_var(struct fb_var_screeninfo *var)
-{
-	do_vmode_pan = 0;
-	do_vmode_full = 0;
-	ami_decode_var(var, &currentpar);
-	ami_build_copper();
-	do_vmode_full = 1;
-}
-
-#ifdef DEBUG
-static void ami_set_par(struct amifb_par *par)
-{
-	do_vmode_pan = 0;
-	do_vmode_full = 0;
-	currentpar = *par;
-	ami_build_copper();
-	do_vmode_full = 1;
-}
-#endif
 
 	/*
 	 * Pan or Wrap the Display
@@ -2506,16 +3095,16 @@
 		par->bpl1mod = par->bpl2mod;
 
 	if (par->yoffset) {
-		par->bplpt0 = videomemory_phys + par->next_line*par->yoffset + move;
+		par->bplpt0 = fb_info.fix.smem_start + par->next_line*par->yoffset + move;
 		if (par->vmode & FB_VMODE_YWRAP) {
 			if (par->yoffset > par->vyres-par->yres) {
-				par->bplpt0wrap = videomemory_phys + move;
+				par->bplpt0wrap = fb_info.fix.smem_start + move;
 				if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v+par->vyres-par->yoffset))
 					par->bplpt0wrap += par->next_line;
 			}
 		}
 	} else
-		par->bplpt0 = videomemory_phys + move;
+		par->bplpt0 = fb_info.fix.smem_start + move;
 
 	if (par->bplcon0 & BPC0_LACE && mod2(par->diwstrt_v))
 		par->bplpt0 += par->next_line;
@@ -2523,45 +3112,6 @@
 	return 0;
 }
 
-	/*
-	 * Read a single color register and split it into
-	 * colors/transparent. Return != 0 for invalid regno.
-	 */
-
-static int ami_getcolreg(u_int regno, u_int *red, u_int *green, u_int *blue,
-                         u_int *transp, struct fb_info *info)
-{
-	int len, tr, tg, tb;
-
-	if (IS_AGA) {
-		if (regno > 255)
-			return 1;
-		len = 8;
-	} else if (currentpar.bplcon0 & BPC0_SHRES) {
-		if (regno > 3)
-			return 1;
-		len = 2;
-	} else {
-		if (regno > 31)
-			return 1;
-		len = 4;
-	}
-	tr = palette[regno].red>>(8-len);
-	tg = palette[regno].green>>(8-len);
-	tb = palette[regno].blue>>(8-len);
-	while (len < 16) {
-		tr |= tr<<len;
-		tg |= tg<<len;
-		tb |= tb<<len;
-		len <<= 1;
-	}
-	*red = tr;
-	*green = tg;
-	*blue = tb;
-	*transp = 0;
-	return 0;
-}
-
 
 	/*
 	 * Set a single color register. The values supplied are already
@@ -2585,9 +3135,11 @@
 	red >>= 8;
 	green >>= 8;
 	blue >>= 8;
-	palette[regno].red = red;
-	palette[regno].green = green;
-	palette[regno].blue = blue;
+	if (!regno) {
+		red0 = red;
+		green0 = green;
+		blue0 = blue;
+	}
 
 	/*
 	 * Update the corresponding Hardware Color Register, unless it's Color
@@ -2650,6 +3202,7 @@
 static void ami_init_display(void)
 {
 	struct amifb_par *par = &currentpar;
+	int i;
 
 	custom.bplcon0 = par->bplcon0 & ~BPC0_LACE;
 	custom.bplcon2 = (IS_OCS ? 0 : BPC2_KILLEHB) | BPC2_PF2P2 | BPC2_PF1P2;
@@ -2685,18 +3238,16 @@
 	is_lace = par->bplcon0 & BPC0_LACE ? 1 : 0;
 #if 1
 	if (is_lace) {
-		if (custom.vposr & 0x8000)
-			custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][1]);
-		else
-			custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][0]);
+		i = custom.vposr >> 15;
 	} else {
 		custom.vposw = custom.vposr | 0x8000;
-		custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][1]);
+		i = 1;
 	}
 #else
+	i = 1;
 	custom.vposw = custom.vposr | 0x8000;
-	custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][1]);
 #endif
+	custom.cop2lc = (u_short *)ZTWO_PADDR(copdisplay.list[currentcop][i]);
 }
 
 	/*
@@ -2744,9 +3295,9 @@
 		}
 	} else {
 		custom.dmacon = DMAF_SETCLR | DMAF_RASTER | DMAF_SPRITE;
-		red = palette[0].red;
-		green = palette[0].green;
-		blue = palette[0].blue;
+		red = red0;
+		green = green0;
+		blue = blue0;
 		if (!IS_OCS) {
 			custom.hsstrt = hsstrt2hw(par->hsstrt);
 			custom.hsstop = hsstop2hw(par->hsstop);
@@ -2782,11 +3333,7 @@
 	is_blanked = do_blank > 0 ? do_blank : 0;
 }
 
-	/*
-	 * Flash the cursor (called by VBlank interrupt)
-	 */
-
-static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix, int con)
+static int ami_get_fix_cursorinfo(struct fb_fix_cursorinfo *fix)
 {
 	struct amifb_par *par = &currentpar;
 
@@ -2797,7 +3344,7 @@
 	return 0;
 }
 
-static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
+static int ami_get_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data)
 {
 	struct amifb_par *par = &currentpar;
 	register u_short *lspr, *sspr;
@@ -2846,7 +3393,7 @@
 				"swap %1 ; lslw #1,%1 ; roxlb #1,%0"
 				: "=d" (color), "=d" (datawords) : "1" (datawords));
 #else
-			color = (((datawords >> 30) & 2) 
+			color = (((datawords >> 30) & 2)
 				 | ((datawords >> 15) & 1));
 			datawords <<= 1;
 #endif
@@ -2872,7 +3419,7 @@
 	return 0;
 }
 
-static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data, int con)
+static int ami_set_var_cursorinfo(struct fb_var_cursorinfo *var, u_char *data)
 {
 	struct amifb_par *par = &currentpar;
 	register u_short *lspr, *sspr;
@@ -2991,7 +3538,7 @@
 	return 0;
 }
 
-static int ami_get_cursorstate(struct fb_cursorstate *state, int con)
+static int ami_get_cursorstate(struct fb_cursorstate *state)
 {
 	struct amifb_par *par = &currentpar;
 
@@ -3001,7 +3548,7 @@
 	return 0;
 }
 
-static int ami_set_cursorstate(struct fb_cursorstate *state, int con)
+static int ami_set_cursorstate(struct fb_cursorstate *state)
 {
 	struct amifb_par *par = &currentpar;
 
@@ -3061,6 +3608,7 @@
 		cops[cop_spr0ptrl].w[1] = loww(ps);
 	}
 }
+
 
 	/*
 	 * Initialise the Copper Initialisation List
--- linux-2.5.x/drivers/video/c2p.c	Thu Jan  1 01:00:00 1970
+++ linux-m68k-2.5.x/drivers/video/c2p.c	Fri Jan 24 18:23:15 2003
@@ -0,0 +1,229 @@
+/*
+ *  Fast C2P (Chunky-to-Planar) Conversion
+ *
+ *  Copyright (C) 2003 Geert Uytterhoeven
+ *
+ *  NOTES:
+ *    - This code was inspired by Scout's C2P tutorial
+ *    - It assumes to run on a big endian system
+ *
+ *  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 more details.
+ */
+
+#include <linux/string.h>
+#include "c2p.h"
+
+
+    /*
+     *  Basic transpose step
+     */
+
+#define _transp(d, i1, i2, shift, mask)			\
+    do {						\
+	u32 t = (d[i1] ^ (d[i2] >> shift)) & mask;	\
+	d[i1] ^= t;					\
+	d[i2] ^= t << shift;				\
+    } while (0)
+
+static inline u32 get_mask(int n)
+{
+    switch (n) {
+	case 1:
+	    return 0x55555555;
+	    break;
+
+	case 2:
+	    return 0x33333333;
+	    break;
+
+	case 4:
+	    return 0x0f0f0f0f;
+	    break;
+
+	case 8:
+	    return 0x00ff00ff;
+	    break;
+
+	case 16:
+	    return 0x0000ffff;
+	    break;
+    }
+    return 0;
+}
+
+#define transp_nx1(d, n)				\
+    do {						\
+	u32 mask = get_mask(n);				\
+	/* First block */				\
+	_transp(d, 0, 1, n, mask);			\
+	/* Second block */				\
+	_transp(d, 2, 3, n, mask);			\
+	/* Third block */				\
+	_transp(d, 4, 5, n, mask);			\
+	/* Fourth block */				\
+	_transp(d, 6, 7, n, mask);			\
+    } while (0)
+
+#define transp_nx2(d, n)				\
+    do {						\
+	u32 mask = get_mask(n);				\
+	/* First block */				\
+	_transp(d, 0, 2, n, mask);			\
+	_transp(d, 1, 3, n, mask);			\
+	/* Second block */				\
+	_transp(d, 4, 6, n, mask);			\
+	_transp(d, 5, 7, n, mask);			\
+    } while (0)
+
+#define transp_nx4(d, n)				\
+    do {						\
+	u32 mask = get_mask(n);				\
+	_transp(d, 0, 4, n, mask);			\
+	_transp(d, 1, 5, n, mask);			\
+	_transp(d, 2, 6, n, mask);			\
+	_transp(d, 3, 7, n, mask);			\
+    } while (0)
+
+#define transp(d, n, m)	transp_nx ## m(d, n)
+
+
+    /*
+     *  Perform a full C2P step on 32 8-bit pixels, stored in 8 32-bit words
+     *  containing
+     *    - 32 8-bit chunky pixels on input
+     *    - permuted planar data on output
+     */
+
+static void c2p_8bpp(u32 d[8])
+{
+    transp(d, 16, 4);
+    transp(d, 8, 2);
+    transp(d, 4, 1);
+    transp(d, 2, 4);
+    transp(d, 1, 2);
+}
+
+
+    /*
+     *  Array containing the permution indices of the planar data after c2p
+     */
+
+static const int perm_c2p_8bpp[8] = { 7, 5, 3, 1, 6, 4, 2, 0 };
+
+
+    /*
+     *  Compose two values, using a bitmask as decision value
+     *  This is equivalent to (a & mask) | (b & ~mask)
+     */
+
+static inline unsigned long comp(unsigned long a, unsigned long b,
+				 unsigned long mask)
+{
+	return ((a ^ b) & mask) ^ b;
+}
+
+
+    /*
+     *  Store a full block of planar data after c2p conversion
+     */
+
+static inline void store_planar(char *dst, u32 dst_inc, u32 bpp, u32 d[8])
+{
+    int i;
+
+    for (i = 0; i < bpp; i++, dst += dst_inc)
+	*(u32 *)dst = d[perm_c2p_8bpp[i]];
+}
+
+
+    /*
+     *  Store a partial block of planar data after c2p conversion
+     */
+
+static inline void store_planar_masked(char *dst, u32 dst_inc, u32 bpp,
+				       u32 d[8], u32 mask)
+{
+    int i;
+
+    for (i = 0; i < bpp; i++, dst += dst_inc)
+	*(u32 *)dst = comp(d[perm_c2p_8bpp[i]], *(u32 *)dst, mask);
+}
+
+
+    /*
+     *  c2p - Copy 8-bit chunky image data to a planar frame buffer
+     *  @dst: Starting address of the planar frame buffer
+     *  @dx: Horizontal destination offset (in pixels)
+     *  @dy: Vertical destination offset (in pixels)
+     *  @width: Image width (in pixels)
+     *  @height: Image height (in pixels)
+     *  @dst_nextline: Frame buffer offset to the next line (in bytes)
+     *  @dst_nextplane: Frame buffer offset to the next plane (in bytes)
+     *  @src_nextline: Image offset to the next line (in bytes)
+     *  @bpp: Bits per pixel of the planar frame buffer (1-8)
+     */
+
+void c2p(u8 *dst, const u8 *src, u32 dx, u32 dy, u32 width, u32 height,
+	 u32 dst_nextline, u32 dst_nextplane, u32 src_nextline, u32 bpp)
+{
+    int dst_idx;
+    u32 d[8], first, last, w;
+    const u8 *c;
+    u8 *p;
+
+    dst += dy*dst_nextline+(dx & ~31);
+    dst_idx = dx % 32;
+    first = ~0UL >> dst_idx;
+    last = ~(~0UL >> ((dst_idx+width) % 32));
+    while (height--) {
+	c = src;
+	p = dst;
+	w = width;
+	if (dst_idx+width <= 32) {
+	    /* Single destination word */
+	    first &= last;
+	    memset(d, 0, sizeof(d));
+	    memcpy((u8 *)d+dst_idx, c, width);
+	    c += width;
+	    c2p_8bpp(d);
+	    store_planar_masked(p, dst_nextplane, bpp, d, first);
+	    p += 4;
+	} else {
+	    /* Multiple destination words */
+	    w = width;
+	    /* Leading bits */
+	    if (dst_idx) {
+		w = 32 - dst_idx;
+		memset(d, 0, dst_idx);
+		memcpy((u8 *)d+dst_idx, c, w);
+		c += w;
+		c2p_8bpp(d);
+		store_planar_masked(p, dst_nextplane, bpp, d, first);
+		p += 4;
+		w = width-w;
+	    }
+	    /* Main chunk */
+	    while (w >= 32) {
+		memcpy(d, c, 32);
+		c += 32;
+		c2p_8bpp(d);
+		store_planar(p, dst_nextplane, bpp, d);
+		p += 4;
+		w -= 32;
+	    }
+	    /* Trailing bits */
+	    w %= 32;
+	    if (w > 0) {
+		memcpy(d, c, w);
+		memset((u8 *)d+w, 0, 32-w);
+		c2p_8bpp(d);
+		store_planar_masked(p, dst_nextplane, bpp, d, last);
+	    }
+	}
+	src += src_nextline;
+	dst += dst_nextline;
+    }
+}
+
--- linux-2.5.x/drivers/video/c2p.h	Thu Jan  1 01:00:00 1970
+++ linux-m68k-2.5.x/drivers/video/c2p.h	Fri Jan 24 18:23:04 2003
@@ -0,0 +1,16 @@
+/*
+ *  Fast C2P (Chunky-to-Planar) Conversion
+ *
+ *  Copyright (C) 2003 Geert Uytterhoeven
+ *
+ *  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 more details.
+ */
+
+#include <linux/types.h>
+
+extern void c2p(u8 *dst, const u8 *src, u32 dx, u32 dy, u32 width, u32 height,
+		u32 dst_nextline, u32 dst_nextplane, u32 src_nextline,
+		u32 bpp);
+
Gr{oetje,eeting}s,

						Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
							    -- Linus Torvalds


-------------------------------------------------------
This SF.net email is sponsored by: Does your code think in ink? 
You could win a Tablet PC. Get a free Tablet PC hat just for playing. 
What are you waiting for?
http://ads.sourceforge.net/cgi-bin/redirect.pl?micr5043en
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help