patch-2.1.16 linux/drivers/sbus/char/cgsix.c

Next file: linux/drivers/sbus/char/cgthree.c
Previous file: linux/drivers/sbus/char/cgfourteen.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.15/linux/drivers/sbus/char/cgsix.c linux/drivers/sbus/char/cgsix.c
@@ -0,0 +1,636 @@
+/* $Id: cgsix.c,v 1.18 1996/11/13 05:10:19 davem Exp $
+ * cgsix.c: cgsix frame buffer driver
+ *
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ */
+#include <linux/kd.h>
+#include <linux/tty.h>
+#include <linux/malloc.h>
+
+#include <asm/sbus.h>
+#include <asm/io.h>
+#include <asm/fbio.h>
+#include <asm/pgtable.h>
+
+#include "../../char/vt_kern.h"
+#include "../../char/selection.h"
+#include "../../char/console_struct.h"
+#include "fb.h"
+#include "cg_common.h"
+
+/* Offset of interesting structures in the OBIO space */
+/*
+ * Brooktree is the video dac and is funny to program on the cg6.
+ * (it's even funnier on the cg3)
+ * The FBC could be the the frame buffer control
+ * The FHC could is the frame buffer hardware control.
+ */
+#define CG6_ROM_OFFSET       0x0
+#define CG6_BROOKTREE_OFFSET 0x200000
+#define CG6_DHC_OFFSET       0x240000
+#define CG6_ALT_OFFSET       0x280000
+#define CG6_FHC_OFFSET       0x300000
+#define CG6_THC_OFFSET       0x301000
+#define CG6_FBC_OFFSET       0x700000
+#define CG6_TEC_OFFSET       0x701000
+#define CG6_RAM_OFFSET       0x800000
+
+/* FHC definitions */
+#define CG6_FHC_FBID_SHIFT           24
+#define CG6_FHC_FBID_MASK            255
+#define CG6_FHC_REV_SHIFT            20
+#define CG6_FHC_REV_MASK             15
+#define CG6_FHC_FROP_DISABLE         (1 << 19)
+#define CG6_FHC_ROW_DISABLE          (1 << 18)
+#define CG6_FHC_SRC_DISABLE          (1 << 17)
+#define CG6_FHC_DST_DISABLE          (1 << 16)
+#define CG6_FHC_RESET                (1 << 15)
+#define CG6_FHC_LITTLE_ENDIAN        (1 << 13)
+#define CG6_FHC_RES_MASK             (3 << 11)
+#define CG6_FHC_1024                 (0 << 11)
+#define CG6_FHC_1152                 (1 << 11)
+#define CG6_FHC_1280                 (2 << 11)
+#define CG6_FHC_1600                 (3 << 11)
+#define CG6_FHC_CPU_MASK             (3 << 9)
+#define CG6_FHC_CPU_SPARC            (0 << 9)
+#define CG6_FHC_CPU_68020            (1 << 9)
+#define CG6_FHC_CPU_386              (2 << 9)
+#define CG6_FHC_TEST		     (1 << 8)
+#define CG6_FHC_TEST_X_SHIFT	     4
+#define CG6_FHC_TEST_X_MASK	     15
+#define CG6_FHC_TEST_Y_SHIFT	     0
+#define CG6_FHC_TEST_Y_MASK	     15
+
+/* FBC mode definitions */
+#define CG6_FBC_BLIT_IGNORE		0x00000000
+#define CG6_FBC_BLIT_NOSRC		0x00100000
+#define CG6_FBC_BLIT_SRC		0x00200000
+#define CG6_FBC_BLIT_ILLEGAL		0x00300000
+#define CG6_FBC_BLIT_MASK		0x00300000
+
+#define CG6_FBC_VBLANK			0x00080000
+
+#define CG6_FBC_MODE_IGNORE		0x00000000
+#define CG6_FBC_MODE_COLOR8		0x00020000
+#define CG6_FBC_MODE_COLOR1		0x00040000
+#define CG6_FBC_MODE_HRMONO		0x00060000
+#define CG6_FBC_MODE_MASK		0x00060000
+
+#define CG6_FBC_DRAW_IGNORE		0x00000000
+#define CG6_FBC_DRAW_RENDER		0x00008000
+#define CG6_FBC_DRAW_PICK		0x00010000
+#define CG6_FBC_DRAW_ILLEGAL		0x00018000
+#define CG6_FBC_DRAW_MASK		0x00018000
+
+#define CG6_FBC_BWRITE0_IGNORE		0x00000000
+#define CG6_FBC_BWRITE0_ENABLE		0x00002000
+#define CG6_FBC_BWRITE0_DISABLE		0x00004000
+#define CG6_FBC_BWRITE0_ILLEGAL		0x00006000
+#define CG6_FBC_BWRITE0_MASK		0x00006000
+
+#define CG6_FBC_BWRITE1_IGNORE		0x00000000
+#define CG6_FBC_BWRITE1_ENABLE		0x00000800
+#define CG6_FBC_BWRITE1_DISABLE		0x00001000
+#define CG6_FBC_BWRITE1_ILLEGAL		0x00001800
+#define CG6_FBC_BWRITE1_MASK		0x00001800
+
+#define CG6_FBC_BREAD_IGNORE		0x00000000
+#define CG6_FBC_BREAD_0			0x00000200
+#define CG6_FBC_BREAD_1			0x00000400
+#define CG6_FBC_BREAD_ILLEGAL		0x00000600
+#define CG6_FBC_BREAD_MASK		0x00000600
+
+#define CG6_FBC_BDISP_IGNORE		0x00000000
+#define CG6_FBC_BDISP_0			0x00000080
+#define CG6_FBC_BDISP_1			0x00000100
+#define CG6_FBC_BDISP_ILLEGAL		0x00000180
+#define CG6_FBC_BDISP_MASK		0x00000180
+
+#define CG6_FBC_INDEX_MOD		0x00000040
+#define CG6_FBC_INDEX_MASK		0x00000030
+
+/* THC definitions */
+#define CG6_THC_MISC_REV_SHIFT       16
+#define CG6_THC_MISC_REV_MASK        15
+#define CG6_THC_MISC_RESET           (1 << 12)
+#define CG6_THC_MISC_VIDEO           (1 << 10)
+#define CG6_THC_MISC_SYNC            (1 << 9)
+#define CG6_THC_MISC_VSYNC           (1 << 8)
+#define CG6_THC_MISC_SYNC_ENAB       (1 << 7)
+#define CG6_THC_MISC_CURS_RES        (1 << 6)
+#define CG6_THC_MISC_INT_ENAB        (1 << 5)
+#define CG6_THC_MISC_INT             (1 << 4)
+#define CG6_THC_MISC_INIT            0x9f
+
+/* The contents are unknown */
+struct cg6_tec {
+	volatile int tec_matrix;
+	volatile int tec_clip;
+	volatile int tec_vdc;
+};
+
+struct cg6_thc {
+        uint thc_pad0[512];
+	volatile uint thc_hs;		/* hsync timing */
+	volatile uint thc_hsdvs;
+	volatile uint thc_hd;
+	volatile uint thc_vs;		/* vsync timing */
+	volatile uint thc_vd;
+	volatile uint thc_refresh;
+	volatile uint thc_misc;
+	uint thc_pad1[56];
+	volatile uint thc_cursxy;	/* cursor x,y position (16 bits each) */
+	volatile uint thc_cursmask[32];	/* cursor mask bits */
+	volatile uint thc_cursbits[32];	/* what to show where mask enabled */
+};
+
+struct cg6_fbc {
+	u32		xxx0[1];
+	volatile u32	mode;
+	volatile u32	clip;
+	u32		xxx1[1];	    
+	volatile u32	s;
+	volatile u32	draw;
+	volatile u32	blit;
+	volatile u32	font;
+	u32		xxx2[24];
+	volatile u32	x0, y0, z0, color0;
+	volatile u32	x1, y1, z1, color1;
+	volatile u32	x2, y2, z2, color2;
+	volatile u32	x3, y3, z3, color3;
+	volatile u32	offx, offy;
+	u32		xxx3[2];
+	volatile u32	incx, incy;
+	u32		xxx4[2];
+	volatile u32	clipminx, clipminy;
+	u32		xxx5[2];
+	volatile u32	clipmaxx, clipmaxy;
+	u32		xxx6[2];
+	volatile u32	fg;
+	volatile u32	bg;
+	volatile u32	alu;
+	volatile u32	pm;
+	volatile u32	pixelm;
+	u32		xxx7[2];
+	volatile u32	patalign;
+	volatile u32	pattern[8];
+	u32		xxx8[432];
+	volatile u32	apointx, apointy, apointz;
+	u32		xxx9[1];
+	volatile u32	rpointx, rpointy, rpointz;
+	u32		xxx10[5];
+	volatile u32	pointr, pointg, pointb, pointa;
+	volatile u32	alinex, aliney, alinez;
+	u32		xxx11[1];
+	volatile u32	rlinex, rliney, rlinez;
+	u32		xxx12[5];
+	volatile u32	liner, lineg, lineb, linea;
+	volatile u32	atrix, atriy, atriz;
+	u32		xxx13[1];
+	volatile u32	rtrix, rtriy, rtriz;
+	u32		xxx14[5];
+	volatile u32	trir, trig, trib, tria;
+	volatile u32	aquadx, aquady, aquadz;
+	u32		xxx15[1];
+	volatile u32	rquadx, rquady, rquadz;
+	u32		xxx16[5];
+	volatile u32	quadr, quadg, quadb, quada;
+	volatile u32	arectx, arecty, arectz;
+	u32		xxx17[1];
+	volatile u32	rrectx, rrecty, rrectz;
+	u32		xxx18[5];
+	volatile u32	rectr, rectg, rectb, recta;
+};
+
+static void
+cg6_restore_palette (fbinfo_t *fbinfo)
+{
+	volatile struct bt_regs *bt;
+
+	bt = fbinfo->info.cg6.bt;
+	bt->addr = 0;
+	bt->color_map = 0xffffffff;
+	bt->color_map = 0xffffffff;
+	bt->color_map = 0xffffffff;
+}
+
+static void cg6_blitc(unsigned short, int, int);
+static void cg6_setw(int, int, unsigned short, int);
+static void cg6_cpyw(int, int, unsigned short *, int);
+static void cg6_fill(int, int, int *);
+
+/* Ugh: X wants to mmap a bunch of cute stuff at the same time :-( */
+/* So, we just mmap the things that are being asked for */
+static int
+cg6_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma,
+	  long base, fbinfo_t *fb)
+{
+	uint size, page, r, map_size;
+	uint map_offset = 0;
+	
+	size = vma->vm_end - vma->vm_start;
+        if (vma->vm_offset & ~PAGE_MASK)
+                return -ENXIO;
+
+	/* To stop the swapper from even considering these pages */
+	vma->vm_flags |= FB_MMAP_VM_FLAGS;
+	
+	/* Each page, see which map applies */
+	for (page = 0; page < size; ){
+		switch (vma->vm_offset+page){
+		case CG6_TEC:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint)fb->info.cg6.tec);
+			break;
+		case CG6_FBC:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint)fb->info.cg6.fbc);
+			break;
+		case CG6_FHC:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint)fb->info.cg6.fhc);
+			break;
+		case CG6_THC:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint)fb->info.cg6.thc);
+			break;
+		case CG6_BTREGS:
+			map_size = PAGE_SIZE;
+			map_offset = get_phys ((uint)fb->info.cg6.bt);
+			break;
+			
+		case CG6_DHC:
+			map_size = PAGE_SIZE * 40;
+			map_offset = get_phys ((uint)fb->info.cg6.dhc);
+			break;
+			
+		case CG6_ROM:
+			map_size = PAGE_SIZE * 16;
+			map_offset = get_phys ((uint)fb->info.cg6.rom);
+			break;
+
+		case CG6_RAM:
+			map_size = size-page;
+			map_offset = get_phys ((uint) fb->base);
+			if (map_size < fb->type.fb_size)
+				map_size = fb->type.fb_size;
+			break;
+		default:
+			map_size = 0;
+			break;
+		}
+		if (!map_size){
+			page += PAGE_SIZE;
+			continue;
+		}
+		if (page + map_size > size)
+			map_size = size - page;
+		r = io_remap_page_range (vma->vm_start+page,
+					 map_offset,
+					 map_size, vma->vm_page_prot,
+					 fb->space);
+		if (r) return -EAGAIN;
+		page += map_size;
+	}
+        vma->vm_inode = inode;
+        inode->i_count++;
+        return 0;
+}
+
+static void
+cg6_loadcmap (fbinfo_t *fb, int index, int count)
+{
+	struct bt_regs *bt = fb->info.cg6.bt;
+	int i;
+	
+	bt->addr = index << 24;
+	for (i = index; count--; i++){
+		bt->color_map = fb->color_map CM(i,0) << 24;
+		bt->color_map = fb->color_map CM(i,1) << 24;
+		bt->color_map = fb->color_map CM(i,2) << 24;
+	}
+}
+
+static void
+cg6_setcursormap (fbinfo_t *fb, unsigned char *red,
+				 unsigned char *green,
+				 unsigned char *blue)
+{
+	struct bt_regs *bt = fb->info.cg6.bt;
+	
+	bt->addr = 1 << 24;
+	bt->cursor = red[0] << 24;
+	bt->cursor = green[0] << 24;
+	bt->cursor = blue[0] << 24;
+	bt->addr = 3 << 24;
+	bt->cursor = red[1] << 24;
+	bt->cursor = green[1] << 24;
+	bt->cursor = blue[1] << 24;
+}
+
+/* Load cursor information */
+static void
+cg6_setcursor (fbinfo_t *fb)
+{
+	uint v;
+	struct cg_cursor *c = &fb->cursor;
+
+	if (c->enable){
+		v = ((c->cpos.fbx - c->chot.fbx) << 16)
+		   |((c->cpos.fby - c->chot.fby) & 0xffff);
+	} else {
+		/* Magic constant to turn off the cursor */
+		v = ((65536-32) << 16) | (65536-32);
+	}
+	fb->info.cg6.thc->thc_cursxy = v;
+}
+
+/* Set cursor shape */
+static void
+cg6_setcurshape (fbinfo_t *fb)
+{
+	struct cg6_thc *thc = fb->info.cg6.thc;
+	int i;
+
+        for (i = 0; i < 32; i++){
+                thc->thc_cursmask [i] = fb->cursor.bits[0][i];
+                thc->thc_cursbits [i] = fb->cursor.bits[1][i];
+        }
+}
+
+static void
+cg6_blank (fbinfo_t *fb)
+{
+	fb->info.cg6.thc->thc_misc &= ~CG6_THC_MISC_VIDEO;
+}
+
+static void
+cg6_unblank (fbinfo_t *fb)
+{
+	fb->info.cg6.thc->thc_misc |= CG6_THC_MISC_VIDEO;
+}
+
+void
+cg6_reset (fbinfo_t *fb)
+{
+	struct cg6_info *cg6 = &(fb->info.cg6);
+	unsigned int rev, conf;
+
+	if (fb->setcursor)
+		sun_hw_hide_cursor ();
+	/* Turn off stuff in the Transform Engine. */
+	cg6->tec->tec_matrix = 0;
+	cg6->tec->tec_clip = 0;
+	cg6->tec->tec_vdc = 0;
+
+	/* Take care of bugs in old revisions. */
+	rev = (*(cg6->fhc) >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK;
+	if (rev < 5) {
+		conf = (*(cg6->fhc) & CG6_FHC_RES_MASK) |
+			CG6_FHC_CPU_68020 | CG6_FHC_TEST |
+			(11 << CG6_FHC_TEST_X_SHIFT) |
+			(11 << CG6_FHC_TEST_Y_SHIFT);
+		if (rev < 2)
+			conf |= CG6_FHC_DST_DISABLE;
+		*(cg6->fhc) = conf;
+	}
+
+	/* Set things in the FBC. */
+	cg6->fbc->mode &= ~(CG6_FBC_BLIT_MASK | CG6_FBC_MODE_MASK |
+			    CG6_FBC_DRAW_MASK | CG6_FBC_BWRITE0_MASK |
+			    CG6_FBC_BWRITE1_MASK | CG6_FBC_BREAD_MASK |
+			    CG6_FBC_BDISP_MASK);
+	cg6->fbc->mode |= (CG6_FBC_BLIT_SRC | CG6_FBC_MODE_COLOR8 |
+			   CG6_FBC_DRAW_RENDER | CG6_FBC_BWRITE0_ENABLE |
+			   CG6_FBC_BWRITE1_DISABLE | CG6_FBC_BREAD_0 |
+			   CG6_FBC_BDISP_0);
+	cg6->fbc->clip = 0;
+	cg6->fbc->offx = 0;
+	cg6->fbc->offy = 0;
+	cg6->fbc->clipminx = 0;
+	cg6->fbc->clipminy = 0;
+	cg6->fbc->clipmaxx = fb->type.fb_width - 1;
+	cg6->fbc->clipmaxy = fb->type.fb_height - 1;
+	/* Enable cursor in Brooktree DAC. */
+	cg6->bt->addr = 0x06 << 24;
+	cg6->bt->control |= 0x03 << 24;
+}
+
+__initfunc(void cg6_setup (fbinfo_t *fb, int slot, uint cg6, int cg6_io))
+{
+	struct cg6_info *cg6info;
+	unsigned int rev, cpu, conf;
+
+	printk ("cgsix%d at 0x%8.8x ", slot, (uint) cg6);
+	
+	/* Fill in parameters we left out */
+	fb->type.fb_cmsize = 256;
+	fb->mmap = cg6_mmap;
+	fb->loadcmap = cg6_loadcmap;
+	fb->reset = cg6_reset;
+	fb->blank = cg6_blank;
+	fb->unblank = cg6_unblank;
+	fb->setcursor = cg6_setcursor;
+	fb->setcursormap = cg6_setcursormap;
+	fb->setcurshape = cg6_setcurshape;
+	fb->postsetup = sun_cg_postsetup;
+	fb->blitc = cg6_blitc;
+	fb->setw = cg6_setw;
+	fb->cpyw = cg6_cpyw;
+	
+	cg6info = (struct cg6_info *) &fb->info.cg6;
+
+	/* Map the hardware registers */
+	cg6info->bt = sparc_alloc_io ((void *) cg6+CG6_BROOKTREE_OFFSET, 0,
+		 sizeof (struct bt_regs), "cgsix_dac", cg6_io, 0);
+	cg6info->fhc = sparc_alloc_io ((void *) cg6+CG6_FHC_OFFSET, 0,
+		 sizeof (int), "cgsix_fhc", cg6_io, 0);
+	cg6info->thc = sparc_alloc_io ((void *) cg6+CG6_THC_OFFSET, 0,
+		 sizeof (struct cg6_thc), "cgsix_thc", cg6_io, 0);
+	cg6info->tec = sparc_alloc_io ((void *) cg6+CG6_TEC_OFFSET, 0,
+		 sizeof (struct cg6_tec), "cgsix_tec", cg6_io, 0);
+	cg6info->dhc = sparc_alloc_io ((void *) cg6+CG6_DHC_OFFSET, 0,
+		 0x40000, "cgsix_dhc", cg6_io, 0);
+	cg6info->fbc = sparc_alloc_io ((void *) cg6+CG6_FBC_OFFSET, 0,
+		 0x1000, "cgsix_fbc", cg6_io, 0);
+	cg6info->rom = sparc_alloc_io ((void *) cg6+CG6_ROM_OFFSET, 0,
+		 0x10000, "cgsix_rom", cg6_io, 0);
+	if (!fb->base){
+		fb->base = (uint) sparc_alloc_io ((void *) cg6+CG6_RAM_OFFSET, 0,
+                    fb->type.fb_size, "cgsix_ram", cg6_io, 0);
+	}
+	if (slot == sun_prom_console_id)
+		fb_restore_palette = cg6_restore_palette;
+
+	/* Initialize Brooktree DAC */
+	cg6info->bt->addr = 0x04 << 24;		/* color planes */
+	cg6info->bt->control = 0xff << 24;
+	cg6info->bt->addr = 0x05 << 24;
+	cg6info->bt->control = 0x00 << 24;
+	cg6info->bt->addr = 0x06 << 24;		/* overlay plane */
+	cg6info->bt->control = 0x73 << 24;
+	cg6info->bt->addr = 0x07 << 24;
+	cg6info->bt->control = 0x00 << 24;
+
+	printk("TEC Rev %x ",
+		(cg6info->thc->thc_misc >> CG6_THC_MISC_REV_SHIFT) &
+		CG6_THC_MISC_REV_MASK);
+
+	/* Get FHC Revision */
+	conf = *(cg6info->fhc);
+
+	cpu = conf & CG6_FHC_CPU_MASK;
+	printk("CPU ");
+	if (cpu == CG6_FHC_CPU_SPARC)
+		printk("sparc ");
+	else if (cpu == CG6_FHC_CPU_68020)
+		printk("68020 ");
+	else
+		printk("386 ");
+
+	rev = conf >> CG6_FHC_REV_SHIFT & CG6_FHC_REV_MASK;
+	printk("Rev %x\n", rev);
+
+	if (slot && sun_prom_console_id == slot) return;
+	
+	/* Reset the cg6 */
+	cg6_reset(fb);
+	
+	if (!slot)
+	/* Enable Video */
+		cg6_unblank(fb);
+	else
+		cg6_blank(fb);
+}
+
+extern unsigned char vga_font[];
+
+#define GX_BLITC_START(attr) \
+	{ \
+		register struct cg6_fbc *gx = fbinfo[0].info.cg6.fbc; \
+		register uint i; \
+		do { \
+			i = gx->s; \
+		} while (i & 0x10000000); \
+		gx->fg = attr & 0xf; \
+		gx->bg = (attr>>4); \
+		gx->mode = 0x140000; \
+		gx->alu = 0xe880fc30; \
+		gx->pixelm = ~(0); \
+		gx->s = 0; \
+		gx->clip = 0; \
+		gx->pm = 0xff;
+#define GX_BLITC_BODY4(count,x,y,start,action) \
+		while (count >= 4) { \
+			count -= 4; \
+		    	gx->incx = 0; \
+		    	gx->incy = 1; \
+		    	gx->x0 = x; \
+		    	gx->x1 = (x += 32) - 1; \
+		    	gx->y0 = y; \
+		    	start; \
+		    	for (i = 0; i < CHAR_HEIGHT; i++) { \
+		    		action; \
+		    	} \
+		}
+#define GX_BLITC_BODY1(x,y,action) \
+		    	gx->incx = 0; \
+		    	gx->incy = 1; \
+		    	gx->x0 = x; \
+		    	gx->x1 = (x += 8) - 1; \
+		    	gx->y0 = y; \
+		    	for (i = 0; i < CHAR_HEIGHT; i++) { \
+		    		action; \
+		    	}
+#define GX_BLITC_END \
+	}
+	
+static void cg6_blitc(unsigned short charattr, int xoff, int yoff)
+{
+	unsigned char attrib = charattr >> 8;
+	unsigned char *p = &vga_font[((unsigned char)charattr) << 4];
+	GX_BLITC_START(attrib)
+	GX_BLITC_BODY1(xoff, yoff, gx->font=((*p++) << 24))
+	GX_BLITC_END
+}
+
+static void cg6_setw(int xoff, int yoff, unsigned short c, int count)
+{
+	unsigned char attrib = c >> 8;
+	unsigned char *p = &vga_font[((unsigned char)c) << 4];
+	register unsigned char *q;
+	register uint l;
+	GX_BLITC_START(attrib)
+	if (count >= 4) {
+		GX_BLITC_BODY4(count, xoff, yoff, q = p, 
+			l = *q++;
+			l |= l << 8;
+			l |= l << 16;
+			gx->font=l)
+	}
+	while (count) {
+		count--;
+		q = p;
+		GX_BLITC_BODY1(xoff, yoff, gx->font=((*q++) << 24));
+	}
+	GX_BLITC_END
+}
+
+static void cg6_cpyw(int xoff, int yoff, unsigned short *p, int count)
+{
+	unsigned char attrib = *p >> 8;
+	unsigned char *p1, *p2, *p3, *p4;
+	GX_BLITC_START(attrib)
+	if (count >= 4) {
+		GX_BLITC_BODY4(count, xoff, yoff, 
+			p1 = &vga_font[((unsigned char)*p++) << 4];
+			p2 = &vga_font[((unsigned char)*p++) << 4];
+			p3 = &vga_font[((unsigned char)*p++) << 4];
+			p4 = &vga_font[((unsigned char)*p++) << 4], 
+			gx->font=((uint)*p4++) | ((((uint)*p3++) | ((((uint)*p2++) | (((uint)*p1++) << 8)) << 8)) << 8))
+	}
+	while (count) {
+		count--;
+		p1 = &vga_font[((unsigned char)*p++) << 4];
+		GX_BLITC_BODY1(xoff, yoff, gx->font=((*p1++) << 24));
+	}
+	GX_BLITC_END
+}
+
+#define GX_FILL_START(attr) \
+	{ \
+		register struct cg6_fbc *gx = fbinfo[0].info.cg6.fbc; \
+		register uint i; \
+		do { \
+			i = gx->s; \
+		} while (i & 0x10000000); \
+		gx->fg = attr & 0xf; \
+		gx->bg = 0; \
+		gx->pixelm = ~(0); \
+		gx->s = 0; \
+		gx->alu = 0xea80ff00; \
+		gx->pm = ~(0); \
+		gx->clip = 0;
+#define GX_FILL_END \
+	}
+	
+static void cg6_fill(int attrib, int count, int *boxes)
+{
+	register int r;
+	
+	attrib = 5;
+	GX_FILL_START(attrib)
+	while (count-- > 0) {
+		gx->arecty = boxes[1];
+		gx->arectx = boxes[0];
+		gx->arecty = boxes[3];
+		gx->arecty = boxes[2];
+		boxes += 4;
+		do {
+			r = gx->draw;
+		} while (r < 0 && (r & 0x20000000) );
+	}
+	GX_FILL_END
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov