コード例 #1
0
ファイル: visual.c プロジェクト: antrik/libggi
static int do_cleanup(struct ggi_visual *vis)
{
        ggi_libkgi_priv *priv = LIBKGI_PRIV(vis);

        /* We may be called more than once due to the LibGG cleanup stuff */
        if (priv == NULL) return 0;

        DPRINT("display-libkgi: GGIdlcleanup start.\n");

        if (LIBGGI_FD(vis) >= 0) close(LIBGGI_FD(vis));

        if (vis->input != NULL) {
                giiClose(vis->input);
                vis->input = NULL;
        }

	free(priv);
        LIBKGI_PRIV(vis) = NULL;

        ggUnregisterCleanup((ggcleanup_func *)do_cleanup, vis);

        ggLock(_ggi_global_lock);
        refcount--;
        refcount--;
        if (refcount == 0) {
                ggLockDestroy(_ggi_libkgi_lock);
                _ggi_libkgi_lock = NULL;
        }
        ggUnlock(_ggi_global_lock);

        DPRINT("display-libkgi: GGIdlcleanup done.\n");

        return 0;
}
コード例 #2
0
ファイル: visual.c プロジェクト: Nekrofage/DoomRPi
static int do_cleanup(ggi_visual *vis)
{
	ggi_lcd823_priv *priv = LCD823_PRIV(vis);

	/* We may be called more than once due to the LibGG cleanup stuff */
	if (priv == NULL) return 0;

	DPRINT("display-lcd823: do_cleanup start.\n");

	_GGI_lcd823_free_dbs(vis);

	if (LIBGGI_FD(vis) >= 0) {
		if (priv->fb_ptr) {
			munmap(priv->fb_ptr, priv->fb_size);
		}
		ioctl(LIBGGI_FD(vis), 2); /* Disable LCD */
		close(LIBGGI_FD(vis));
		LIBGGI_FD(vis) = -1;
	}

	if (vis->input != NULL) {
		giiClose(vis->input);
		vis->input = NULL;
	}

	free(priv);
	LIBGGI_PRIVATE(vis) = NULL;

	if (LIBGGI_GC(vis)) {
		free(LIBGGI_GC(vis));
	}

	ggUnregisterCleanup((ggcleanup_func *)do_cleanup, vis);

	DPRINT("display-lcd823: do_cleanup done.\n");

	return 0;
}
コード例 #3
0
ファイル: color.c プロジェクト: Nekrofage/DoomRPi
void GGI_fbdev_color_setup(ggi_visual *vis)
{
	ggi_fbdev_priv *priv = FBDEV_PRIV(vis);
	struct fb_cmap cmap;
	int len;

	/* We rely on caller to have deallocated old storage */
	priv->orig_cmap = LIBGGI_PAL(vis)->clut.data = priv->gamma.map = NULL; 
	vis->gamma = NULL;
	priv->reds = priv->greens = priv->blues = NULL;
	priv->gamma.maxread_r = priv->gamma.maxread_g = 
	  priv->gamma.maxread_b = priv->gamma.maxread_r = 
	  priv->gamma.maxwrite_g = priv->gamma.maxwrite_b = -1;
	priv->gamma.len = priv->gamma.start = 0;

	if (!priv->var.bits_per_pixel) return;
	if (priv->fix.visual == FB_VISUAL_TRUECOLOR) return; /* No gamma. */

	if (priv->fix.visual == FB_VISUAL_DIRECTCOLOR) {

		DPRINT("display-fbdev: trying gamma.\n");

		priv->gamma.maxwrite_r = priv->gamma.maxread_r = 
			1 << priv->var.red.length;
		priv->gamma.maxwrite_g = priv->gamma.maxread_g = 
			1 << priv->var.green.length;
		priv->gamma.maxwrite_b = priv->gamma.maxread_b = 
			1 << priv->var.blue.length;
		
		len = priv->gamma.maxread_r;
		if (len < priv->gamma.maxread_g) 
			len = priv->gamma.maxread_g;
		if (len < priv->gamma.maxread_b)
			len = priv->gamma.maxread_b;
		priv->gamma.len = len;
		priv->gamma.start = 0;
		
		LIBGGI_PAL(vis)->clut.size = len * 2;
		LIBGGI_PAL(vis)->clut.data = calloc(len * 2 /* orig */, sizeof(ggi_color));
		if (LIBGGI_PAL(vis)->clut.data == NULL) return;
		priv->gamma.map = LIBGGI_PAL(vis)->clut.data;
		/* All of the above is moot until we turn it on like so: */
		vis->gamma = &(priv->gamma);
	} else {

		DPRINT("display-fbdev: trying palette.\n");

		len = 1 << priv->var.bits_per_pixel;
		LIBGGI_PAL(vis)->clut.size = len * 2;
		LIBGGI_PAL(vis)->clut.data = calloc(len * 2 /* orig */, sizeof(ggi_color));
		if (LIBGGI_PAL(vis)->clut.data == NULL) return;
	}

	cmap.start = 0;
	cmap.len   = len;
	cmap.red   = calloc(len * 3, 2);
	if (cmap.red == NULL) goto bail;
	cmap.green = cmap.red + len;
	cmap.blue  = cmap.green + len;
	cmap.transp = NULL;
	
	if (ioctl(LIBGGI_FD(vis), FBIOGETCMAP, &cmap) < 0) {
		DPRINT_COLOR("display-fbdev: GETCMAP failed.\n");
		free(cmap.red);
		goto bail;
	} 

	priv->orig_cmap = LIBGGI_PAL(vis)->clut.data + len;

	if (vis->gamma != NULL) {

		DPRINT_COLOR("display-fbdev: Saved gamma (len=%d/%d/%d).\n",
				priv->gamma.maxread_r, priv->gamma.maxread_g,
				priv->gamma.maxread_b);

		while (len--) {
			if (len < priv->gamma.maxread_r) 
				priv->orig_cmap[len].r = cmap.red[len];
			if (len < priv->gamma.maxread_g) 
				priv->orig_cmap[len].g = cmap.green[len];
			if (len < priv->gamma.maxread_b) 
				priv->orig_cmap[len].b = cmap.blue[len];
		}
		vis->opcolor->getgammamap = GGI_fbdev_getgammamap;
		vis->opcolor->setgammamap = GGI_fbdev_setgammamap;
	}
	else {
		DPRINT_COLOR("display-fbdev: Saved palette (len=%d).\n", 
				len);
		while (len--) {
			priv->orig_cmap[len].r = cmap.red[len];
			priv->orig_cmap[len].g = cmap.green[len];
			priv->orig_cmap[len].b = cmap.blue[len];
		}
		if (priv->fix.visual != FB_VISUAL_STATIC_PSEUDOCOLOR) {
			LIBGGI_PAL(vis)->setPalette  = GGI_fbdev_setPalette;
			LIBGGI_PAL(vis)->getPrivSize =  GGI_fbdev_getPrivSize;
		}
	}

	LIBGGI_PAL(vis)->priv = cmap.red;

	priv->reds = cmap.red;
	priv->greens = cmap.green;
	priv->blues = cmap.blue;
	return;

 bail:
	free(LIBGGI_PAL(vis)->clut.data);
	LIBGGI_PAL(vis)->clut.data = NULL;
	vis->gamma = NULL;
	return;

}
コード例 #4
0
ファイル: visual.c プロジェクト: Nekrofage/DoomRPi
static int GGIopen(ggi_visual *vis, struct ggi_dlhandle *dlh,
		   const char *args, void *argptr, uint32_t *dlret)
{
	ggi_lcd823_priv *priv;
	int size;

	DPRINT("display-lcd823: GGIopen start.\n");

	LIBGGI_PRIVATE(vis) = priv = malloc(sizeof(ggi_lcd823_priv));
	if (priv == NULL) {
		return GGI_ENOMEM;
	}
	
	priv->fb_ptr = NULL;

	/* Now open the framebuffer device */
	LIBGGI_FD(vis) = open(LCD_DEVNAME, O_RDWR);
	if (LIBGGI_FD(vis) < 0) {
		fprintf(stderr, "display-lcd823: Couldn't open "
			"framebuffer device %s: %s\n", LCD_DEVNAME,
			strerror(errno));
		do_cleanup(vis);
		return GGI_ENODEVICE;
	}
	if (ioctl(LIBGGI_FD(vis), 1) != 0) {
		fprintf(stderr, "display-lcd823: Unable to enable LCD: %s\n",
			strerror(errno));
		do_cleanup(vis);
		return GGI_ENODEVICE;
	}
	if (ioctl(LIBGGI_FD(vis), 5, &size) != 0) {
		fprintf(stderr, "display-lcd823: Unable to get size of LCD "
			"memory: %s\n",
			strerror(errno));
		do_cleanup(vis);
		return GGI_ENODEVICE;
	}

	priv->fb_size = size * getpagesize();
	priv->fb_ptr = mmap(NULL, priv->fb_size, PROT_READ | PROT_WRITE,
			    MAP_SHARED, LIBGGI_FD(vis), 0);
	if (priv->fb_ptr == MAP_FAILED) {
		fprintf(stderr, "display-lcd823: Unable to map LCD "
			"memory: %s\n",
			strerror(errno));
		priv->fb_ptr = NULL;
		do_cleanup(vis);
		return GGI_ENODEVICE;
	}
	priv->frame_size = priv->fb_size;

	LIBGGI_GC(vis) = malloc(sizeof(ggi_gc));
	if (LIBGGI_GC(vis) == NULL) {
		do_cleanup(vis);
		return GGI_ENOMEM;
	}

	/* Mode management */
	vis->opdisplay->getmode   = GGI_lcd823_getmode;
	vis->opdisplay->setmode   = GGI_lcd823_setmode;
	vis->opdisplay->checkmode = GGI_lcd823_checkmode;
	vis->opdisplay->getapi    = GGI_lcd823_getapi;
	vis->opdisplay->flush     = GGI_lcd823_flush;
	vis->opdisplay->setflags  = GGI_lcd823_setflags;

	/* Register cleanup handler */
	ggRegisterCleanup((ggcleanup_func *)do_cleanup, vis);

	DPRINT("display-lc823: GGIopen success.\n");

	*dlret = GGI_DL_OPDISPLAY;
	return 0;
}
コード例 #5
0
ファイル: visual.c プロジェクト: antrik/libggi
static int GGIopen(struct ggi_visual *vis, struct ggi_dlhandle *dlh,
                        const char *args, void *argptr, uint32_t *dlret)
{
        gg_option options[NUM_OPTS];
        ggi_libkgi_priv *priv;
	int err;

	/* We need LibGAlloc to be initialized.  Seems OK to do so
	 * from inside here. It would be nice to Attach it here too,
	 * but I'm less confident that that would work :-)
	 */
	ggiGAInit();

        DPRINT("display-libkgi: GGIopen start.\n");

        memcpy(options, optlist, sizeof(options));
        if (args) {
                args = ggParseOptions(args, options, NUM_OPTS);
                if (args == NULL) {
                        fprintf(stderr, "display-libkgi: error in "
                                "arguments.\n");
                        return GGI_EARGINVAL;
                }
        }

        LIBKGI_PRIV(vis) = priv = malloc(sizeof(ggi_libkgi_priv));
        if (priv == NULL) {
                return GGI_ENOMEM;
        }

        priv->have_accel = 0;
        priv->accelpriv = NULL;
        priv->flush = NULL;
        priv->idleaccel = NULL;

	snprintf(priv->suggest, sizeof(priv->suggest), "foodrv");

        DPRINT("display-libkgi: Parsing physz options.\n");
	err = _ggi_physz_parse_option(options[OPT_PHYSZ].result, 
			       &(priv->physzflags), &(priv->physz)); 
	if (err != GGI_OK) {
		do_cleanup(vis);
		return err;
	}

#if 0
	/* Don't know how this will pan out */
	err = kgiInit(&priv->ctx, &priv->client_name, &priv->client_version);
	if (err != KGI_EOK) {
		do_cleanup(vis);
		return err;
	}
	LIBGGI_FD(vis) = priv->ctx.mapper.fd;
#endif

        DPRINT("display-libkgi: Setting up locks.\n");
        ggLock(_ggi_global_lock);
        if (refcount == 0) {
                _ggi_libkgi_lock = ggLockCreate();
                if (_ggi_libkgi_lock == NULL) {
                        ggUnlock(_ggi_global_lock);
                        free(priv);
                        return GGI_ENOMEM;
                }
        }
        priv->lock = _ggi_libkgi_lock;
        priv->refcount = &refcount;
        refcount++;
        ggUnlock(_ggi_global_lock);

	priv->galloc_loaded = 0;

	LIBKGI_PRIV(vis) = priv;

        /* Mode management */
        vis->opdisplay->flush     = GGI_libkgi_flush;
	/* kgicommand obselete */
        vis->opdisplay->getapi    = GGI_libkgi_getapi;
        vis->opdisplay->setflags  = GGI_libkgi_setflags;
        vis->opdisplay->idleaccel = GGI_libkgi_idleaccel;
        vis->opdisplay->getmode   = GGI_libkgi_getmode;
        vis->opdisplay->checkmode = GGI_libkgi_checkmode;
        vis->opdisplay->setmode   = GGI_libkgi_setmode;
        vis->opdisplay->sendevent = GGI_libkgi_sendevent;

	/* GC management */
        vis->opgc->gcchanged = GGI_libkgi_gcchanged;

	/* Drawops. We don't supply _nc variants as we only do fully 
	 * implemented renderers.
	 */
	vis->opdraw->setorigin		= GGI_libkgi_setorigin;
	vis->opdraw->setdisplayframe	= GGI_libkgi_setdisplayframe;
        vis->opdraw->setreadframe	= GGI_libkgi_setreadframe;
        vis->opdraw->setwriteframe	= GGI_libkgi_setwriteframe;
        vis->opdraw->fillscreen		= GGI_libkgi_fillscreen;
        vis->opdraw->putc		= GGI_libkgi_putc;
        vis->opdraw->puts		= GGI_libkgi_puts;
        vis->opdraw->getcharsize	= GGI_libkgi_getcharsize;
        vis->opdraw->drawpixel		= GGI_libkgi_drawpixel;
        vis->opdraw->putpixel		= GGI_libkgi_putpixel;
        vis->opdraw->getpixel		= GGI_libkgi_getpixel;
        vis->opdraw->drawline		= GGI_libkgi_drawline;
        vis->opdraw->drawhline		= GGI_libkgi_drawhline;
        vis->opdraw->puthline		= GGI_libkgi_puthline;
        vis->opdraw->gethline		= GGI_libkgi_gethline;
        vis->opdraw->drawvline		= GGI_libkgi_drawvline;
        vis->opdraw->putvline		= GGI_libkgi_putvline;
        vis->opdraw->getvline		= GGI_libkgi_getvline;
        vis->opdraw->drawbox		= GGI_libkgi_drawbox;
        vis->opdraw->putbox		= GGI_libkgi_putbox;
        vis->opdraw->getbox		= GGI_libkgi_getbox;
        vis->opdraw->copybox		= GGI_libkgi_copybox;
        vis->opdraw->crossblit		= GGI_libkgi_crossblit;

	/* Color ops will use generic color libs. */

        /* Register cleanup handler */
        ggRegisterCleanup((ggcleanup_func *)do_cleanup, vis);

        DPRINT("display-libkgi: GGIopen success.\n");

        *dlret = GGI_DL_OPDISPLAY;
        return 0;
}
コード例 #6
0
ファイル: visual.c プロジェクト: Nekrofage/DoomRPi
static int GGIopen(ggi_visual *vis, struct ggi_dlhandle *dlh,
		   const char *args, void *argptr, uint32_t *dlret)
{
	struct TIhooks *priv;
	gg_option options[NUM_OPTS];
	char *term_type;
	char *term_path;
	int i, err;

        memcpy(options, optlist, sizeof(options));
	if (args != NULL) {
		args = ggParseOptions(args, options, NUM_OPTS);
		if (args == NULL) {
			fprintf(stderr, "display-x: error in arguments.\n");
			return GGI_EARGINVAL;
		}
        }
	term_path = options[OPT_PATH].result;
	term_type = options[OPT_TERM].result;
	if ((*term_type) == '\0') term_type = NULL;

	DPRINT("display-terminfo: initializing %s on %s.\n", term_type, ( ( *term_path == '\0' ) ? "stdin/stdout" : term_path ));

	priv = (struct TIhooks *)malloc(sizeof(struct TIhooks));
	if (priv == NULL) return GGI_ENOMEM;
	LIBGGI_PRIVATE(vis) = priv;

	err = _ggi_physz_parse_option(options[OPT_PHYSZ].result, 
			       &(priv->physzflags), &(priv->physz)); 
	if (err != GGI_OK) {
	  free(priv);
	  return err;
	}

	LIBGGI_GC(vis) = malloc(sizeof(ggi_gc));
	if (LIBGGI_GC(vis) == NULL) {
		free(priv);
		return GGI_ENOMEM;
	}

	priv->splitline = 0;

	priv->virgin = 1;

	if ( *term_path == '\0' ) {
		priv->f_in = fdopen(dup(fileno(stdin)), "r");
		priv->f_out = fdopen(dup(fileno(stdout)), "w");
	} else {
		priv->f_in = priv->f_out = fopen(term_path, "rw");
	}

	_terminfo_init_ncurses();

	priv->scr = _terminfo_new_screen(term_type, priv->f_out, priv->f_in);
	if (priv->scr == NULL) {
		fprintf(stderr, "display-terminfo: error creating ncurses"
				" SCREEN\n");
		fclose(priv->f_in);
		fclose(priv->f_out);
		free(LIBGGI_GC(vis));
		free(priv);
		return GGI_ENODEVICE;
	}

	LIBGGI_FD(vis) = fileno(priv->f_out);

	if ( has_colors() ) {
		static const int vga_color[8] = {
			COLOR_BLACK,
			COLOR_BLUE,
			COLOR_GREEN,
			COLOR_CYAN,
			COLOR_RED,
			COLOR_MAGENTA,
			COLOR_YELLOW,
			COLOR_WHITE
		};
		int j;
		DPRINT("display-terminfo: terminal supports %d colors\n", COLORS);
		DPRINT("display-terminfo: initializing %d - 1 color pairs\n", COLOR_PAIRS);
		for ( i = 1 ; i < COLOR_PAIRS ; i++ ) {
			if ( init_pair(i, COLORS - ( i % COLORS ) - 1, i / COLORS) == ERR ) {
				DPRINT("display-terminfo: error initializing color pair %d to %d,%d\n", i, COLORS - ( i % COLORS ) - 1, i / COLORS);
				fprintf(stderr, "display-terminfo: error initializing colors\n");
				break;
			}
		}
		for ( i = 0 ; i < 16 ; i++ ) {
			for ( j = 0 ; j < 16 ; j++ ) {
				priv->color16_table[i+(j<<4)] =
					COLOR_PAIR(((COLORS-vga_color[i&0x07]%COLORS-1)
					 +(vga_color[j&0x07]%COLORS*COLORS))%COLOR_PAIRS)
					| ( ( i > 7 ) ? A_BOLD : A_NORMAL )
					| ( ( j > 7 ) ? A_BLINK : A_NORMAL );
			}
		}

	} else {
		DPRINT("display-terminfo: terminal lacks color support\n");
	}
	construct_charmap(priv->charmap);
#if ( NCURSES_MOUSE_VERSION == 1 ) 
	DPRINT("display-terminfo: mouse support is enabled\n");
	mousemask(REPORT_MOUSE_POSITION | BUTTON1_PRESSED | BUTTON1_RELEASED |
			BUTTON2_PRESSED | BUTTON2_RELEASED | BUTTON3_PRESSED |
			BUTTON3_RELEASED | BUTTON4_PRESSED | BUTTON4_RELEASED,
			NULL);
#else
	DPRINT("display-terminfo: mouse support is disabled\n");
#endif

	/* mode management */
	vis->opdisplay->flush     = GGI_terminfo_flush;
	vis->opdisplay->getmode   = GGI_terminfo_getmode;
	vis->opdisplay->setmode   = GGI_terminfo_setmode;
	vis->opdisplay->checkmode = GGI_terminfo_checkmode;
	vis->opdisplay->getapi    = GGI_terminfo_getapi;
	vis->opdisplay->setflags  = GGI_terminfo_setflags;

	/* event management */
	{
		gii_input *inp;
		inp = _giiInputAlloc();

		if (inp == NULL) {
			fprintf(stderr, "display-terminfo: error allocating gii_input\n");
			_terminfo_destroy_screen();
			fclose(priv->f_in);
			fclose(priv->f_out);
			free(LIBGGI_GC(vis));
			free(priv);
			return GGI_ENOMEM;
		}

#if ( NCURSES_MOUSE_VERSION == 1 )
		inp->targetcan =emKey | emPtrButton | emPtrAbsolute,
#else
		inp->targetcan =emKey, /* without mouse support */
#endif
		inp->GIIseteventmask(inp,inp->targetcan);

		inp->GIIeventpoll = GII_terminfo_eventpoll;
		inp->GIIsendevent = GII_terminfo_sendevent;

		priv->vis = vis;
		inp->priv = (void *)priv;

		inp->maxfd=0;   /* This is polled. */
		inp->flags|=GII_FLAGS_HASPOLLED;

		vis->input = giiJoinInputs(vis->input, inp);
	}

	_terminfo_release_screen();
 
	*dlret = GGI_DL_OPDISPLAY;
	return 0;
}
コード例 #7
0
ファイル: visual.c プロジェクト: Nekrofage/DoomRPi
static int GGIopen(ggi_visual *vis, struct ggi_dlhandle *dlh,
		   const char *args, void *argptr, uint32_t *dlret)
{
	ggi_fbdev_priv *fbdevpriv = FBDEV_PRIV(vis);
	struct m2164w_priv *priv;
	unsigned long usedmemend;
	size_t fontlen;
	int pixbytes;
	int fd = LIBGGI_FD(vis);
	int i;

	if (GT_SIZE(LIBGGI_GT(vis)) % 8 != 0 ||
	    GT_SIZE(LIBGGI_GT(vis)) > 32 ||
	    GT_SIZE(LIBGGI_GT(vis)) < 8) {
		/* Unsupported mode */
		return GGI_ENOFUNC;
	}
	pixbytes = GT_ByPP(LIBGGI_GT(vis));

	priv = malloc(sizeof(struct m2164w_priv));
	if (priv == NULL) {
		return GGI_ENOMEM;
	}

	fbdevpriv->mmioaddr = mmap(NULL, fbdevpriv->orig_fix.mmio_len,
				   PROT_READ | PROT_WRITE, MAP_SHARED,
				   fd, (signed)fbdevpriv->orig_fix.smem_len);
	if (fbdevpriv->mmioaddr == MAP_FAILED) {
		/* Can't mmap() MMIO region - bail out */
		DPRINT_LIBS("mga-2164w: Unable to map MMIO region: %s\n"
			       "          fd: %d, len: %ld, offset: %ld\n",
			       strerror(errno), fd,
			       fbdevpriv->orig_fix.mmio_len,
			       fbdevpriv->orig_fix.smem_len);
		fbdevpriv->mmioaddr = NULL;
		free(priv);
		return GGI_ENODEVICE;
	}

	DPRINT_MISC("mga-2164w: Mapped MMIO region at %p\n",
		       fbdevpriv->mmioaddr);

	/* Set up DirectBuffers */
	for (i=0; i < LIBGGI_MODE(vis)->frames; i++) {
		ggi_directbuffer *buf = LIBGGI_APPBUFS(vis)[i];
		ggi_resource *res;
		
		res = malloc(sizeof(ggi_resource));
		if (res == NULL) {
			do_cleanup(vis);
			return GGI_ENOMEM;
		}
		buf->resource = res;
		buf->resource->acquire = m2164w_acquire;
		buf->resource->release = m2164w_release;
		buf->resource->self = buf;
		buf->resource->priv = vis;
		buf->resource->count = 0;
		buf->resource->curactype = 0;
	}

	priv->drawboxcmd
		= BOP_COPY | SHFTZERO | SGNZERO | ARZERO | SOLID | OP_TRAP;
	if (pixbytes != 3) {
		switch (fbdevpriv->orig_fix.accel) {	
		case FB_ACCEL_MATROX_MGA2064W:
		case FB_ACCEL_MATROX_MGA1064SG:
		case FB_ACCEL_MATROX_MGA2164W:
		case FB_ACCEL_MATROX_MGA2164W_AGP:
			/* Use block mode */
			priv->drawboxcmd |= ATYPE_BLK;
			break;
		default:
			/* For now - assume SDRAM for other cards */
			break;
		}
	}
	priv->dwgctl = 0;
	priv->oldfgcol = LIBGGI_GC(vis)->fg_color - 1;
	priv->oldbgcol = LIBGGI_GC(vis)->bg_color - 1;
	priv->oldtl.x = -1;
	priv->oldtl.y = -1;
	priv->oldbr.x = -1;
	priv->oldbr.y = -1;
	priv->oldyadd = -1;
	priv->curopmode = priv->origopmode = mga_in16(fbdevpriv->mmioaddr, OPMODE);
	/* Use the 7k Pseudo-DMA window */
	priv->dmaaddr = (void*)fbdevpriv->mmioaddr;
	priv->dma_len = 0x1c00;

	vis->needidleaccel = 1;
	fbdevpriv->idleaccel = m2164w_idleaccel;

	/* Accelerate fonts if possible */
	priv->font = (uint8_t *)(font);
	usedmemend = LIBGGI_MODE(vis)->frames *
		fbdevpriv->fix.line_length * LIBGGI_VIRTY(vis);
	fontlen = 256*8;
	priv->fontoffset = fbdevpriv->orig_fix.smem_len - fontlen;
	priv->fontoffset &= ~127; /* Align */
	DPRINT_MISC("mga-2164w: usedmemend: %ld, fontoffset: %ld\n",
		       usedmemend, priv->fontoffset);
	if (usedmemend <= priv->fontoffset) {
		memcpy((uint8_t*)fbdevpriv->fb_ptr + priv->fontoffset,
		       font, fontlen);
		priv->fontoffset *= 8; /* In bits */
		priv->charadd = FWIDTH*FHEIGHT;
		vis->opdraw->putc = GGI_m2164w_fastputc;
		vis->opdraw->puts = GGI_m2164w_fastputs;
		DPRINT_MISC("mga-2164w: Using fast chars\n");
	} else {
		priv->fontoffset = 0;
		vis->opdraw->putc = GGI_m2164w_putc;
		vis->opdraw->puts = GGI_m2164w_puts;
		DPRINT_MISC("mga-2164w: Using slow chars\n");
	}

	/* Save previous function pointers */
	priv->crossblit = vis->opdraw->crossblit;

	/* Initialize function pointers */
	vis->opdraw->getcharsize= GGI_m2164w_getcharsize;
	vis->opdraw->drawhline = GGI_m2164w_drawhline;
	vis->opdraw->drawvline = GGI_m2164w_drawvline;
	vis->opdraw->drawline = GGI_m2164w_drawline;
	vis->opdraw->drawbox = GGI_m2164w_drawbox;
	vis->opdraw->copybox = GGI_m2164w_copybox;
	vis->opdraw->fillscreen = GGI_m2164w_fillscreen;
	/* The crossblit in linear-* is faster on truecolor modes! */
	if (GT_SCHEME(LIBGGI_GT(vis)) == GT_PALETTE ||
	    GT_SCHEME(LIBGGI_GT(vis)) == GT_STATIC_PALETTE) {
		vis->opdraw->crossblit = GGI_m2164w_crossblit;
	}

	FBDEV_PRIV(vis)->accelpriv = priv;

	/* Register cleanup handler */
	ggRegisterCleanup((ggcleanup_func *)do_cleanup, vis);

	*dlret = GGI_DL_OPDRAW;
	return 0;
}