xref: /openbsd/sys/dev/pcmcia/cfxga.c (revision 4bdff4be)
1 /*	$OpenBSD: cfxga.c,v 1.33 2022/07/15 17:57:26 kettenis Exp $	*/
2 
3 /*
4  * Copyright (c) 2005, 2006, Matthieu Herrb and Miodrag Vallat
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /*
20  * Display driver for the Colorgraphic CompactFlash ``VoyagerVGA'' card.
21  * based upon the Epson S1D13806 graphics chip.
22  *
23  * Our goals are:
24  * - to provide a somewhat usable emulation mode for extra text display.
25  * - to let an application (such as an X server) map the controller registers
26  *   in order to do its own display game.
27  *
28  * Driving this card is somewhat a challenge since:
29  * - its video memory is not directly accessible.
30  * - no operation can make use of DMA.
31  */
32 
33 #include <sys/param.h>
34 #include <sys/kernel.h>
35 #include <sys/device.h>
36 #include <sys/systm.h>
37 #include <sys/malloc.h>
38 #include <sys/conf.h>
39 
40 #include <dev/pcmcia/pcmciavar.h>
41 #include <dev/pcmcia/pcmciareg.h>
42 
43 #include <dev/wscons/wsconsio.h>
44 #include <dev/wscons/wsdisplayvar.h>
45 #include <dev/rasops/rasops.h>
46 
47 #include <dev/pcmcia/cfxgareg.h>
48 
49 /*
50 #define CFXGADEBUG
51 #define ENABLE_8BIT_MODES
52 */
53 
54 #ifdef CFXGADEBUG
55 #define	DPRINTF(arg) printf arg
56 #else
57 #define	DPRINTF(arg)
58 #endif
59 
60 struct cfxga_screen;
61 
62 #define	CFXGA_MODE_640x480x16	0
63 #define	CFXGA_MODE_800x600x16	1
64 #ifdef ENABLE_8BIT_MODES
65 #define	CFXGA_MODE_640x480x8	2
66 #define	CFXGA_MODE_800x600x8	3
67 #define	CFXGA_NMODES		4
68 #else
69 #define	CFXGA_NMODES		2
70 #endif
71 
72 struct cfxga_softc {
73 	struct device sc_dev;
74 	struct pcmcia_function *sc_pf;
75 	int	sc_state;
76 #define	CS_MAPPED	0x0001
77 #define	CS_RESET	0x0002
78 
79 	struct pcmcia_mem_handle sc_pmemh;
80 	int sc_memwin;
81 	bus_addr_t sc_offset;
82 
83 	int sc_mode;
84 
85 	int sc_nscreens;
86 	LIST_HEAD(, cfxga_screen) sc_scr;
87 	struct cfxga_screen *sc_active;
88 
89 	/* wsdisplay glue */
90 	struct wsscreen_descr sc_wsd[CFXGA_NMODES];
91 	struct wsscreen_list sc_wsl;
92 	struct wsscreen_descr *sc_scrlist[CFXGA_NMODES];
93 	struct wsdisplay_emulops sc_ops;
94 	struct device *sc_wsdisplay;
95 };
96 
97 int	cfxga_match(struct device *, void *,  void *);
98 void	cfxga_attach(struct device *, struct device *, void *);
99 int	cfxga_detach(struct device *, int);
100 int	cfxga_activate(struct device *, int);
101 
102 const struct cfattach cfxga_ca = {
103 	sizeof(struct cfxga_softc), cfxga_match, cfxga_attach,
104 	cfxga_detach, cfxga_activate
105 };
106 
107 struct cfdriver cfxga_cd = {
108 	NULL, "cfxga", DV_DULL
109 };
110 
111 int	cfxga_alloc_screen(void *, const struct wsscreen_descr *, void **,
112 	    int *, int *, uint32_t *);
113 void	cfxga_burner(void *, u_int, u_int);
114 void	cfxga_free_screen(void *, void *);
115 int	cfxga_ioctl(void *, u_long, caddr_t, int, struct proc *);
116 paddr_t	cfxga_mmap(void *, off_t, int);
117 int	cfxga_load_font(void *, void *, struct wsdisplay_font *);
118 int	cfxga_list_font(void *, struct wsdisplay_font *);
119 int	cfxga_show_screen(void *, void *, int, void (*)(void *, int, int),
120 	    void *);
121 
122 struct wsdisplay_accessops cfxga_accessops = {
123 	.ioctl = cfxga_ioctl,
124 	.mmap = cfxga_mmap,
125 	.alloc_screen = cfxga_alloc_screen,
126 	.free_screen = cfxga_free_screen,
127 	.show_screen = cfxga_show_screen,
128 	.load_font = cfxga_load_font,
129 	.list_font = cfxga_list_font,
130 	.burn_screen = cfxga_burner
131 };
132 
133 /*
134  * Per-screen structure
135  */
136 
137 struct cfxga_screen {
138 	LIST_ENTRY(cfxga_screen) scr_link;
139 	struct cfxga_softc *scr_sc;	/* parent reference */
140 	struct rasops_info scr_ri;	/* raster op glue */
141 	struct wsdisplay_charcell *scr_mem;	/* backing memory */
142 };
143 
144 int	cfxga_copycols(void *, int, int, int, int);
145 int	cfxga_copyrows(void *, int, int, int);
146 int	cfxga_do_cursor(struct rasops_info *);
147 int	cfxga_erasecols(void *, int, int, int, uint32_t);
148 int	cfxga_eraserows(void *, int, int, uint32_t);
149 int	cfxga_putchar(void *, int, int, u_int, uint32_t);
150 
151 int	cfxga_install_function(struct pcmcia_function *);
152 void	cfxga_remove_function(struct pcmcia_function *);
153 
154 int	cfxga_expand_char(struct cfxga_screen *, u_int, int, int, uint32_t);
155 int	cfxga_repaint_screen(struct cfxga_screen *);
156 void	cfxga_reset_video(struct cfxga_softc *);
157 void	cfxga_reset_and_repaint(struct cfxga_softc *);
158 int	cfxga_solid_fill(struct cfxga_screen *, int, int, int, int, int32_t);
159 int	cfxga_standalone_rop(struct cfxga_screen *, u_int,
160 	    int, int, int, int, int, int);
161 int	cfxga_synchronize(struct cfxga_softc *);
162 u_int	cfxga_wait(struct cfxga_softc *, u_int, u_int);
163 
164 #define	cfxga_clear_screen(scr) \
165 	cfxga_solid_fill(scr, 0, 0, scr->scr_ri.ri_width, \
166 	    scr->scr_ri.ri_height, scr->scr_ri.ri_devcmap[WSCOL_BLACK])
167 
168 #define	cfxga_read_1(sc, addr) \
169 	bus_space_read_1((sc)->sc_pmemh.memt, (sc)->sc_pmemh.memh, \
170 	    (sc)->sc_offset + (addr))
171 #define	cfxga_read_2(sc, addr) \
172 	bus_space_read_2((sc)->sc_pmemh.memt, (sc)->sc_pmemh.memh, \
173 	    (sc)->sc_offset + (addr))
174 #define	cfxga_write_1(sc, addr, val) \
175 	bus_space_write_1((sc)->sc_pmemh.memt, (sc)->sc_pmemh.memh, \
176 	    (sc)->sc_offset + (addr), (val))
177 #define	cfxga_write_2(sc, addr, val) \
178 	bus_space_write_2((sc)->sc_pmemh.memt, (sc)->sc_pmemh.memh, \
179 	    (sc)->sc_offset + (addr), (val))
180 
181 #define	cfxga_stop_memory_blt(sc) \
182 	(void)cfxga_read_2(sc, CFREG_BITBLT_DATA)
183 
184 const char *cfxga_modenames[CFXGA_NMODES] = {
185 	"640x480x16",
186 	"800x600x16",
187 #ifdef ENABLE_8BIT_MODES
188 	"640x480x8",
189 	"800x600x8"
190 #endif
191 };
192 
193 /*
194  * This card is very poorly engineered, specificationwise. It does not
195  * provide any CIS information, and has no vendor/product numbers as
196  * well: as such, there is no easy way to differentiate it from any
197  * other cheapo PCMCIA card.
198  *
199  * The best we can do is probe for a chip ID. This is not perfect but better
200  * than matching blindly. Of course this requires us to play some nasty games
201  * behind the PCMCIA framework to be able to do this probe, and correctly fail
202  * if this is not the card we are looking for.
203  *
204  * In shorter words: some card designers ought to be shot, as a service
205  * to the community.
206  */
207 
208 /*
209  * Create the necessary pcmcia function structures to alleviate the lack
210  * of any CIS information on this device.
211  * Actually, we hijack the fake function created by the pcmcia framework.
212  */
213 int
214 cfxga_install_function(struct pcmcia_function *pf)
215 {
216 	struct pcmcia_config_entry *cfe;
217 
218 	/* Get real. */
219 	pf->pf_flags &= ~PFF_FAKE;
220 
221 	/* Tell the pcmcia framework where the CCR is. */
222 	pf->ccr_base = 0x800;
223 	pf->ccr_mask = 0x67;
224 
225 	/* Create a simple cfe. */
226 	cfe = (struct pcmcia_config_entry *)malloc(sizeof *cfe,
227 	    M_DEVBUF, M_NOWAIT | M_ZERO);
228 	if (cfe == NULL) {
229 		DPRINTF(("%s: cfe allocation failed\n", __func__));
230 		return (ENOMEM);
231 	}
232 
233 	cfe->number = 42;	/* have to put some value... */
234 	cfe->flags = PCMCIA_CFE_IO16;
235 	cfe->iftype = PCMCIA_IFTYPE_MEMORY;
236 
237 	SIMPLEQ_INSERT_TAIL(&pf->cfe_head, cfe, cfe_list);
238 
239 	pcmcia_function_init(pf, cfe);
240 	return (0);
241 }
242 
243 /*
244  * Undo the changes done above.
245  * Such a function is necessary since we need a full-blown pcmcia world
246  * set up in order to do the device probe, but if we don't match the card,
247  * leaving this state will cause trouble during other probes.
248  */
249 void
250 cfxga_remove_function(struct pcmcia_function *pf)
251 {
252 	struct pcmcia_config_entry *cfe;
253 
254 	/* we are the first and only entry... */
255 	cfe = SIMPLEQ_FIRST(&pf->cfe_head);
256 	SIMPLEQ_REMOVE_HEAD(&pf->cfe_head, cfe_list);
257 	free(cfe, M_DEVBUF, 0);
258 
259 	/* And we're a figment of the kernel's imagination again. */
260 	pf->pf_flags |= PFF_FAKE;
261 }
262 
263 int
264 cfxga_match(struct device *parent, void *match, void *aux)
265 {
266 	struct pcmcia_attach_args *pa = aux;
267 	struct pcmcia_function *pf = pa->pf;
268 	struct pcmcia_mem_handle h;
269 	int rc;
270 	int win;
271 	bus_addr_t ptr;
272 	u_int8_t id = 0;
273 
274 	if (pa->product != PCMCIA_PRODUCT_INVALID ||
275 	    pa->manufacturer != PCMCIA_VENDOR_INVALID)
276 		return (0);
277 
278 	/* Only a card with no CIS will have a fake function... */
279 	if ((pf->pf_flags & PFF_FAKE) == 0)
280 		return (0);
281 
282 	if (cfxga_install_function(pf) != 0)
283 		return (0);
284 
285 	if (pcmcia_function_enable(pf) != 0) {
286 		DPRINTF(("%s: function enable failed\n", __func__));
287 		return (0);
288 	}
289 
290 	rc = pcmcia_mem_alloc(pf, CFXGA_MEM_RANGE, &h);
291 	if (rc != 0)
292 		goto out;
293 
294 	rc = pcmcia_mem_map(pf, PCMCIA_MEM_ATTR, 0, CFXGA_MEM_RANGE,
295 	    &h, &ptr, &win);
296 	if (rc != 0)
297 		goto out2;
298 
299 	id = (bus_space_read_1(h.memt, h.memh, ptr + CFREG_REV) &
300 	    CR_PRODUCT_MASK) >> CR_PRODUCT_SHIFT;
301 
302 	pcmcia_mem_unmap(pa->pf, win);
303 out2:
304 	pcmcia_mem_free(pa->pf, &h);
305 out:
306 	pcmcia_function_disable(pf);
307 	cfxga_remove_function(pf);
308 
309 	/*
310 	 * Be sure to return a value greater than com's if we match,
311 	 * otherwise it can win due to the way config(8) will order devices...
312 	 */
313 	return (id == PRODUCT_S1D13806 ? 10 : 0);
314 }
315 
316 int
317 cfxga_activate(struct device *dev, int act)
318 {
319 	struct cfxga_softc *sc = (void *)dev;
320 	int rv = 0;
321 
322 	switch (act) {
323 	case DVACT_DEACTIVATE:
324 		pcmcia_function_disable(sc->sc_pf);
325 		break;
326 	default:
327 		rv = config_activate_children(self, act);
328 		break;
329 	}
330 	return (rv);
331 }
332 
333 void
334 cfxga_attach(struct device *parent, struct device *self, void *aux)
335 {
336 	struct cfxga_softc *sc = (void *)self;
337 	struct pcmcia_attach_args *pa = aux;
338 	struct pcmcia_function *pf = pa->pf;
339 	struct wsemuldisplaydev_attach_args waa;
340 	struct wsscreen_descr *wsd;
341 	u_int i;
342 
343 	LIST_INIT(&sc->sc_scr);
344 	sc->sc_nscreens = 0;
345 	sc->sc_pf = pf;
346 
347 	if (cfxga_install_function(pf) != 0) {
348 		printf(": pcmcia function setup failed\n");
349 		return;
350 	}
351 
352 	if (pcmcia_function_enable(pf)) {
353 		printf(": function enable failed\n");
354 		return;
355 	}
356 
357 	if (pcmcia_mem_alloc(pf, CFXGA_MEM_RANGE, &sc->sc_pmemh) != 0) {
358 		printf(": can't allocate memory space\n");
359 		return;
360 	}
361 
362 	if (pcmcia_mem_map(pf, PCMCIA_MEM_ATTR, 0, CFXGA_MEM_RANGE,
363 	    &sc->sc_pmemh, &sc->sc_offset, &sc->sc_memwin) != 0) {
364 		printf(": can't map frame buffer registers\n");
365 		pcmcia_mem_free(pf, &sc->sc_pmemh);
366 		return;
367 	}
368 
369 	SET(sc->sc_state, CS_MAPPED);
370 
371 	printf("\n");
372 
373 	sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
374 
375 	/*
376 	 * We actually defer real initialization to the creation of the
377 	 * first wsdisplay screen, since we do not know which mode to pick
378 	 * yet.
379 	 */
380 
381 	for (wsd = sc->sc_wsd, i = 0; i < CFXGA_NMODES; wsd++, i++) {
382 		strlcpy(wsd->name, cfxga_modenames[i], sizeof(wsd->name));
383 		wsd->textops = &sc->sc_ops;
384 		sc->sc_scrlist[i] = wsd;
385 	}
386 	sc->sc_wsl.nscreens = CFXGA_NMODES;
387 	sc->sc_wsl.screens = (const struct wsscreen_descr **)sc->sc_scrlist;
388 
389 	waa.console = 0;
390 	waa.scrdata = &sc->sc_wsl;
391 	waa.accessops = &cfxga_accessops;
392 	waa.accesscookie = sc;
393 	waa.defaultscreens = 1;
394 
395 	if ((sc->sc_wsdisplay =
396 	    config_found(self, &waa, wsemuldisplaydevprint)) == NULL) {
397 		/* otherwise wscons will do this */
398 		if (sc->sc_active != NULL)
399 			cfxga_clear_screen(sc->sc_active);
400 		else
401 			cfxga_burner(sc, 0, 0);
402 	}
403 }
404 
405 int
406 cfxga_detach(struct device *dev, int flags)
407 {
408 	struct cfxga_softc *sc = (void *)dev;
409 
410 	/*
411 	 * Detach all children, and hope wsdisplay detach code is correct...
412 	 */
413 	if (sc->sc_wsdisplay != NULL) {
414 		config_detach(sc->sc_wsdisplay, DETACH_FORCE);
415 		/* sc->sc_wsdisplay = NULL; */
416 	}
417 
418 	if (ISSET(sc->sc_state, CS_MAPPED)) {
419 		pcmcia_mem_unmap(sc->sc_pf, sc->sc_memwin);
420 		pcmcia_mem_free(sc->sc_pf, &sc->sc_pmemh);
421 		/* CLR(sc->sc_state, CS_MAPPED); */
422 	}
423 
424 	return (0);
425 }
426 
427 /*
428  * Wscons operations
429  */
430 
431 int
432 cfxga_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
433     int *curxp, int *curyp, uint32_t *attrp)
434 {
435 	struct cfxga_softc *sc = v;
436 	struct cfxga_screen *scr;
437 	struct rasops_info *ri;
438 	u_int mode, width, height, depth, scrsize;
439 
440 	scr = malloc(sizeof *scr, M_DEVBUF,
441 	    (cold ? M_NOWAIT : M_WAITOK) | M_ZERO);
442 	if (scr == NULL)
443 		return (ENOMEM);
444 
445 	mode = type - sc->sc_wsd;
446 #ifdef DIAGNOSTIC
447 	if (mode >= CFXGA_NMODES)
448 		mode = CFXGA_MODE_640x480x16;
449 #endif
450 	switch (mode) {
451 	default:
452 	case CFXGA_MODE_640x480x16:
453 		width = 640;
454 		height = 480;
455 		depth = 16;
456 		break;
457 	case CFXGA_MODE_800x600x16:
458 		width = 800;
459 		height = 600;
460 		depth = 16;
461 		break;
462 #ifdef ENABLE_8BIT_MODES
463 	case CFXGA_MODE_640x480x8:
464 		width = 640;
465 		height = 480;
466 		depth = 8;
467 		break;
468 	case CFXGA_MODE_800x600x8:
469 		width = 800;
470 		height = 600;
471 		depth = 8;
472 		break;
473 #endif
474 	}
475 
476 	ri = &scr->scr_ri;
477 	ri->ri_hw = (void *)scr;
478 	ri->ri_bits = NULL;
479 	ri->ri_depth = depth;
480 	ri->ri_width = width;
481 	ri->ri_height = height;
482 	ri->ri_stride = width * depth / 8;
483 	ri->ri_flg = 0;
484 
485 	/* swap B and R at 16 bpp */
486 	if (depth == 16) {
487 		ri->ri_rnum = 5;
488 		ri->ri_rpos = 11;
489 		ri->ri_gnum = 6;
490 		ri->ri_gpos = 5;
491 		ri->ri_bnum = 5;
492 		ri->ri_bpos = 0;
493 	}
494 
495 	if (type->nrows == 0)	/* first screen creation */
496 		rasops_init(ri, 100, 100);
497 	else
498 		rasops_init(ri, type->nrows, type->ncols);
499 
500 	/*
501 	 * Allocate backing store to remember non-visible screen contents in
502 	 * emulation mode.
503 	 */
504 	scr->scr_mem = mallocarray(ri->ri_rows,
505 	    ri->ri_cols * sizeof(struct wsdisplay_charcell), M_DEVBUF,
506 	    (cold ? M_NOWAIT : M_WAITOK) | M_ZERO);
507 	if (scr->scr_mem == NULL) {
508 		free(scr, M_DEVBUF, 0);
509 		return (ENOMEM);
510 	}
511 	scrsize = ri->ri_rows * ri->ri_cols * sizeof(struct wsdisplay_charcell);
512 
513 	ri->ri_ops.copycols = cfxga_copycols;
514 	ri->ri_ops.copyrows = cfxga_copyrows;
515 	ri->ri_ops.erasecols = cfxga_erasecols;
516 	ri->ri_ops.eraserows = cfxga_eraserows;
517 	ri->ri_ops.putchar = cfxga_putchar;
518 	ri->ri_do_cursor = cfxga_do_cursor;
519 
520 	/*
521 	 * Finish initializing our screen descriptions, now that we know
522 	 * the actual console emulation parameters.
523 	 */
524 	if (type->nrows == 0) {
525 		struct wsscreen_descr *wsd = (struct wsscreen_descr *)type;
526 
527 		wsd->nrows = ri->ri_rows;
528 		wsd->ncols = ri->ri_cols;
529 		bcopy(&ri->ri_ops, &sc->sc_ops, sizeof(sc->sc_ops));
530 		wsd->fontwidth = ri->ri_font->fontwidth;
531 		wsd->fontheight = ri->ri_font->fontheight;
532 		wsd->capabilities = ri->ri_caps;
533 	}
534 
535 	scr->scr_sc = sc;
536 	LIST_INSERT_HEAD(&sc->sc_scr, scr, scr_link);
537 	sc->sc_nscreens++;
538 
539 	ri->ri_ops.pack_attr(ri, 0, 0, 0, attrp);
540 
541 	*cookiep = ri;
542 	*curxp = *curyp = 0;
543 
544 	return (0);
545 }
546 
547 void
548 cfxga_burner(void *v, u_int on, u_int flags)
549 {
550 	struct cfxga_softc *sc = (void *)v;
551 	u_int8_t mode;
552 
553 	mode = cfxga_read_1(sc, CFREG_MODE) & LCD_MODE_SWIVEL_BIT_0;
554 
555 	if (on)
556 		cfxga_write_1(sc, CFREG_MODE, mode | MODE_CRT);
557 	else
558 		cfxga_write_1(sc, CFREG_MODE, mode | MODE_NO_DISPLAY);
559 }
560 
561 void
562 cfxga_free_screen(void *v, void *cookie)
563 {
564 	struct cfxga_softc *sc = v;
565 	struct rasops_info *ri = cookie;
566 	struct cfxga_screen *scr = ri->ri_hw;
567 
568 	LIST_REMOVE(scr, scr_link);
569 	sc->sc_nscreens--;
570 
571 	if (scr == sc->sc_active) {
572 		sc->sc_active = NULL;
573 		cfxga_burner(sc, 0, 0);
574 	}
575 
576 	free(scr->scr_mem, M_DEVBUF, 0);
577 	free(scr, M_DEVBUF, 0);
578 }
579 
580 int
581 cfxga_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
582 {
583 	struct cfxga_softc *sc = v;
584 	struct cfxga_screen *scr;
585 	struct wsdisplay_fbinfo *wdf;
586 	int mode;
587 
588 	switch (cmd) {
589 	case WSDISPLAYIO_GTYPE:
590 		*(u_int *)data = WSDISPLAY_TYPE_CFXGA;
591 		break;
592 
593 	case WSDISPLAYIO_GINFO:
594 		wdf = (struct wsdisplay_fbinfo *)data;
595 		scr = sc->sc_active;
596 		if (scr == NULL) {
597 			/* try later...after running wsconscfg to add screens */
598 			wdf->height = wdf->width = wdf->depth = 0;
599 			wdf->stride = wdf->offset = wdf->cmsize = 0;
600 		} else {
601 			wdf->height = scr->scr_ri.ri_height;
602 			wdf->width = scr->scr_ri.ri_width;
603 			wdf->depth = scr->scr_ri.ri_depth;
604 			wdf->stride = scr->scr_ri.ri_stride;
605 			wdf->offset = 0;
606 			wdf->cmsize = scr->scr_ri.ri_depth <= 8 ?
607 			    (1 << scr->scr_ri.ri_depth) : 0;
608 		}
609 		break;
610 
611 	case WSDISPLAYIO_SMODE:
612 		mode = *(u_int *)data;
613 		if (mode == sc->sc_mode)
614 			break;
615 		switch (mode) {
616 		case WSDISPLAYIO_MODE_EMUL:
617 			cfxga_reset_and_repaint(sc);
618 			break;
619 		case WSDISPLAYIO_MODE_MAPPED:
620 			break;
621 		default:
622 			return (EINVAL);
623 		}
624 		sc->sc_mode = mode;
625 		break;
626 
627 	/* these operations are handled by the wscons code... */
628 	case WSDISPLAYIO_GVIDEO:
629 	case WSDISPLAYIO_SVIDEO:
630 		break;
631 
632 	/* these operations are not supported... */
633 	case WSDISPLAYIO_GETCMAP:
634 	case WSDISPLAYIO_PUTCMAP:
635 	case WSDISPLAYIO_LINEBYTES:
636 	case WSDISPLAYIO_GCURPOS:
637 	case WSDISPLAYIO_SCURPOS:
638 	case WSDISPLAYIO_GCURMAX:
639 	case WSDISPLAYIO_GCURSOR:
640 	case WSDISPLAYIO_SCURSOR:
641 	default:
642 		return (-1);
643 	}
644 
645 	return (0);
646 }
647 
648 paddr_t
649 cfxga_mmap(void *v, off_t off, int prot)
650 {
651 	return (-1);
652 }
653 
654 int
655 cfxga_show_screen(void *v, void *cookie, int waitok,
656     void (*cb)(void *, int, int), void *cbarg)
657 {
658 	struct cfxga_softc *sc = v;
659 	struct rasops_info *ri = cookie;
660 	struct cfxga_screen *scr = ri->ri_hw, *old;
661 
662 	old = sc->sc_active;
663 	if (old == scr)
664 		return (0);
665 
666 	sc->sc_active = scr;
667 	cfxga_reset_and_repaint(sc);	/* will turn video on if scr != NULL */
668 
669 	return (0);
670 }
671 
672 int
673 cfxga_load_font(void *v, void *emulcookie, struct wsdisplay_font *font)
674 {
675 	struct cfxga_softc *sc = v;
676 	struct cfxga_screen *scr = sc->sc_active;
677 
678 	if (scr == NULL)
679 		return ENXIO;
680 
681 	return rasops_load_font(&scr->scr_ri, emulcookie, font);
682 }
683 
684 int
685 cfxga_list_font(void *v, struct wsdisplay_font *font)
686 {
687 	struct cfxga_softc *sc = v;
688 	struct cfxga_screen *scr = sc->sc_active;
689 
690 	if (scr == NULL)
691 		return ENXIO;
692 
693 	return rasops_list_font(&scr->scr_ri, font);
694 }
695 
696 /*
697  * Real frame buffer operations
698  */
699 
700 void
701 cfxga_reset_video(struct cfxga_softc *sc)
702 {
703 	struct cfxga_screen *scr = sc->sc_active;
704 	struct rasops_info *ri;
705 #ifdef ENABLE_8BIT_MODES
706 	const u_int8_t *cmap;
707 	u_int i;
708 #endif
709 
710 	/*
711 	 * Reset controller
712 	 */
713 
714 	/* need to write to both REV and MISC at the same time */
715 	cfxga_write_2(sc, CFREG_REV, 0x80 | (CM_REGSEL << 8));
716 	delay(25000);	/* maintain reset for a short while */
717 	/* need to write to both REV and MISC at the same time */
718 	cfxga_write_2(sc, CFREG_REV, 0 | (CM_MEMSEL << 8));
719 	delay(25000);
720 	/* stop any pending blt operation */
721 	cfxga_write_2(sc, CFREG_BITBLT_CONTROL, 0);
722 	cfxga_stop_memory_blt(sc);
723 	cfxga_write_1(sc, CFREG_MODE, 0);	/* disable all displays */
724 
725 	/*
726 	 * Setup common video mode parameters.
727 	 */
728 
729 	cfxga_write_2(sc, CFREG_MEMCLK, MEMCLK_SRC_CLK3);
730 #if 0
731 	cfxga_write_1(sc, CFREG_LCD_PCLK, LCD_PCLK_SRC_CLKI | LCD_PCLK_DIV_1);
732 	cfxga_write_1(sc, CFREG_MPLUG_CLK,
733 	    MPLUG_PCLK_SRC_CLKI2 | MPLUG_PCLK_DIV_1);
734 #endif
735 	cfxga_write_2(sc, CFREG_CRTTV_PCLK, CRT_PCLK_SRC_CLKI | CRT_PCLK_DIV_1);
736 	cfxga_write_2(sc, CFREG_WSTATE, WSTATE_MCLK);
737 
738 	/* MEMCNF and DRAM_RFRSH need to be programmed at the same time */
739 	cfxga_write_2(sc, CFREG_MEMCNF,
740 	    MEMCNF_SDRAM_INIT | (DRAM_RFRSH_50MHZ << 8));
741 	delay(250);
742 	cfxga_write_2(sc, CFREG_DRAM_TIMING, DRAM_TIMING_50MHZ);
743 
744 	/*
745 	 * Setup mode-dependent parameters.
746 	 */
747 	if (scr == NULL)
748 		return;
749 
750 	ri = &scr->scr_ri;
751 	switch (scr->scr_ri.ri_width) {
752 	default:
753 	case 640:
754 		cfxga_write_1(sc, CFREG_CRT_HWIDTH, (640 / 8) - 1);
755 		/* HNDISP and HSTART need to be programmed at the same time */
756 		cfxga_write_2(sc, CFREG_CRT_HNDISP, 23 | (2 << 8));
757 		cfxga_write_1(sc, CFREG_CRT_HPULSE, 4);
758 		cfxga_write_2(sc, CFREG_CRT_VHEIGHT, 480 - 1);
759 		/* VNDISP and VSTART need to be programmed at the same time */
760 		cfxga_write_2(sc, CFREG_CRT_VNDISP, 39 | (8 << 8));
761 		cfxga_write_1(sc, CFREG_CRT_VPULSE, 2);
762 		break;
763 	case 800:
764 		cfxga_write_1(sc, CFREG_CRT_HWIDTH, (800 / 8) - 1);
765 		/* HNDISP and HSTART need to be programmed at the same time */
766 		cfxga_write_2(sc, CFREG_CRT_HNDISP, 27 | (2 << 8));
767 		cfxga_write_1(sc, CFREG_CRT_HPULSE, 4);
768 		cfxga_write_2(sc, CFREG_CRT_VHEIGHT, 600 - 1);
769 		/* VNDISP and VSTART need to be programmed at the same time */
770 		cfxga_write_2(sc, CFREG_CRT_VNDISP, 25 | (8 << 8));
771 		cfxga_write_1(sc, CFREG_CRT_VPULSE, 2);
772 		break;
773 	}
774 	cfxga_write_1(sc, CFREG_CRT_MODE,
775 	    ri->ri_depth == 16 ? CRT_MODE_16BPP : CRT_MODE_8BPP);
776 	cfxga_write_2(sc, CFREG_CRT_START_LOW, 0);
777 	cfxga_write_1(sc, CFREG_CRT_START_HIGH, 0);
778 	cfxga_write_2(sc, CFREG_CRT_MEMORY, ri->ri_width * ri->ri_depth / 16);
779 	cfxga_write_1(sc, CFREG_CRT_PANNING, 0);
780 	cfxga_write_1(sc, CFREG_CRT_FIFO_THRESHOLD_HIGH, 0);
781 	cfxga_write_1(sc, CFREG_CRT_FIFO_THRESHOLD_LOW, 0);
782 	cfxga_write_1(sc, CFREG_CRT_CURSOR_CONTROL, CURSOR_INACTIVE);
783 
784 #ifdef ENABLE_8BIT_MODES
785 	/*
786 	 * On 8bpp video modes, program the LUT
787 	 */
788 	if (ri->ri_depth == 8) {
789 #if 0
790 		/* Wait for retrace */
791 		while ((cfxga_read_1(sc, CFREG_CRT_VNDISP) &
792 		    CRT_VNDISP_STATUS) == 0)
793 			delay(1);
794 #endif
795 		cfxga_write_1(sc, CFREG_LUT_MODE, LUT_CRT);
796 		cfxga_write_1(sc, CFREG_LUT_ADDRESS, 0); /* autoincrements */
797 		cmap = rasops_cmap;
798 		for (i = 256 * 3; i != 0; i--)
799 			cfxga_write_1(sc, CFREG_LUT_DATA, *cmap++ & 0xf0);
800 	}
801 #endif
802 
803 	cfxga_write_1(sc, CFREG_TV_CONTROL,
804 	    TV_LUMINANCE_FILTER | TV_SVIDEO_OUTPUT | TV_NTSC_OUTPUT);
805 
806 	cfxga_write_1(sc, CFREG_POWER_CONF, POWERSAVE_MBO);
807 	cfxga_write_1(sc, CFREG_WATCHDOG, 0);
808 
809 	cfxga_write_1(sc, CFREG_MODE, MODE_CRT);
810 	delay(25000);
811 }
812 
813 void
814 cfxga_reset_and_repaint(struct cfxga_softc *sc)
815 {
816 	cfxga_reset_video(sc);
817 
818 	if (sc->sc_active != NULL)
819 		cfxga_repaint_screen(sc->sc_active);
820 	else
821 		cfxga_burner(sc, 0, 0);
822 }
823 
824 /*
825  * Wait for the blitter to be in a given state.
826  */
827 u_int
828 cfxga_wait(struct cfxga_softc *sc, u_int mask, u_int result)
829 {
830 	u_int tries;
831 
832 	for (tries = 10000; tries != 0; tries--) {
833 		if ((cfxga_read_1(sc, CFREG_BITBLT_CONTROL) & mask) == result)
834 			break;
835 		delay(10);
836 	}
837 
838 	return (tries);
839 }
840 
841 /*
842  * Wait for all pending blitter operations to be complete.
843  * Returns non-zero if the blitter got stuck.
844  */
845 int
846 cfxga_synchronize(struct cfxga_softc *sc)
847 {
848 	/* Wait for previous operations to complete */
849 	if (cfxga_wait(sc, BITBLT_ACTIVE, 0) == 0) {
850 		DPRINTF(("%s: not ready\n", __func__));
851 		if (ISSET(sc->sc_state, CS_RESET))
852 			return (EAGAIN);
853 		else {
854 			DPRINTF(("%s: resetting...\n", sc->sc_dev.dv_xname));
855 			SET(sc->sc_state, CS_RESET);
856 			cfxga_reset_and_repaint(sc);
857 			CLR(sc->sc_state, CS_RESET);
858 		}
859 	}
860 	cfxga_stop_memory_blt(sc);
861 	return (0);
862 }
863 
864 /*
865  * Display a character.
866  */
867 int
868 cfxga_expand_char(struct cfxga_screen *scr, u_int uc, int x, int y,
869     uint32_t attr)
870 {
871 	struct cfxga_softc *sc = scr->scr_sc;
872 	struct rasops_info *ri = &scr->scr_ri;
873 	struct wsdisplay_font *font = ri->ri_font;
874 	u_int pos, sts, fifo_avail, chunk;
875 	u_int8_t *fontbits;
876 	int bg, fg, ul;
877 	u_int i;
878 	int rc;
879 
880 	pos = (y * ri->ri_width + x) * ri->ri_depth / 8;
881 	fontbits = (u_int8_t *)(font->data + (uc - font->firstchar) *
882 	    ri->ri_fontscale);
883 	ri->ri_ops.unpack_attr(ri, attr, &fg, &bg, &ul);
884 
885 	/* Wait for previous operations to complete */
886 	if ((rc = cfxga_synchronize(sc)) != 0)
887 		return (rc);
888 
889 	cfxga_write_2(sc, CFREG_COLOR_EXPANSION,
890 	    ((font->fontwidth - 1) & 7) | (OP_COLOR_EXPANSION << 8));
891 	cfxga_write_2(sc, CFREG_BITBLT_SRC_LOW, font->fontwidth <= 8 ? 0 : 1);
892 	cfxga_write_2(sc, CFREG_BITBLT_SRC_HIGH, 0);
893 	cfxga_write_2(sc, CFREG_BITBLT_DST_LOW, pos);
894 	cfxga_write_2(sc, CFREG_BITBLT_DST_HIGH, pos >> 16);
895 	cfxga_write_2(sc, CFREG_BITBLT_OFFSET,
896 	    ri->ri_width * ri->ri_depth / 16);
897 	cfxga_write_2(sc, CFREG_BITBLT_WIDTH, font->fontwidth - 1);
898 	cfxga_write_2(sc, CFREG_BITBLT_HEIGHT, font->fontheight - 1);
899 	cfxga_write_2(sc, CFREG_BITBLT_FG, ri->ri_devcmap[fg]);
900 	cfxga_write_2(sc, CFREG_BITBLT_BG, ri->ri_devcmap[bg]);
901 	cfxga_write_2(sc, CFREG_BITBLT_CONTROL, BITBLT_ACTIVE |
902 	    (ri->ri_depth > 8 ? BITBLT_COLOR_16 : BITBLT_COLOR_8));
903 
904 	if (cfxga_wait(sc, BITBLT_ACTIVE, BITBLT_ACTIVE) == 0)
905 		goto fail;	/* unlikely */
906 	fifo_avail = 0;
907 
908 	for (i = font->fontheight; i != 0; i--) {
909 		/*
910 		 * Find out how much words we can feed before
911 		 * a FIFO check is needed.
912 		 */
913 		if (fifo_avail == 0) {
914 			sts = cfxga_read_1(sc, CFREG_BITBLT_CONTROL);
915 			if ((sts & BITBLT_FIFO_NOT_EMPTY) == 0)
916 				fifo_avail = font->fontwidth <= 8 ? 2 : 1;
917 			else if ((sts & BITBLT_FIFO_HALF_FULL) == 0)
918 				fifo_avail = font->fontwidth <= 8 ? 1 : 0;
919 			else {
920 				/*
921 				 * Let the cheap breathe for a short while.
922 				 * If this is not enough to free some FIFO
923 				 * entries, abort the operation.
924 				 */
925 				if (cfxga_wait(sc, BITBLT_FIFO_FULL, 0) == 0)
926 					goto fail;
927 			}
928 		}
929 
930 		if (font->fontwidth <= 8) {
931 			chunk = *fontbits;
932 			if (ul && i == 1)
933 				chunk = 0xff;
934 		} else {
935 			chunk = *(u_int16_t *)fontbits;
936 			if (ul && i == 1)
937 				chunk = 0xffff;
938 		}
939 		cfxga_write_2(sc, CFREG_BITBLT_DATA, chunk);
940 		fontbits += font->stride;
941 		fifo_avail--;
942 	}
943 
944 	return (0);
945 
946 fail:
947 	DPRINTF(("%s: abort\n", __func__));
948 	cfxga_write_2(sc, CFREG_BITBLT_CONTROL, 0);
949 	cfxga_stop_memory_blt(sc);
950 	return (EINTR);
951 }
952 
953 /*
954  * Copy a memory bitmap to the frame buffer.
955  *
956  * This is slow - we only use this to repaint the whole frame buffer on
957  * screen switches.
958  */
959 int
960 cfxga_repaint_screen(struct cfxga_screen *scr)
961 {
962 	struct wsdisplay_charcell *cell = scr->scr_mem;
963 	struct rasops_info *ri = &scr->scr_ri;
964 	int x, y, cx, cy, lx, ly;
965 	int fg, bg;
966 	int rc;
967 
968 	cfxga_clear_screen(scr);
969 
970 	cx = ri->ri_font->fontwidth;
971 	cy = ri->ri_font->fontheight;
972 
973 	for (ly = 0, y = ri->ri_yorigin; ly < ri->ri_rows; ly++, y += cy) {
974 		for (lx = 0, x = ri->ri_xorigin; lx < ri->ri_cols;
975 		    lx++, x += cx) {
976 			if (cell->uc == 0 || cell->uc == ' ') {
977 				ri->ri_ops.unpack_attr(ri, cell->attr,
978 				    &fg, &bg, NULL);
979 				rc = cfxga_solid_fill(scr, x, y, cx, cy,
980 				    ri->ri_devcmap[bg]);
981 			} else {
982 				rc = cfxga_expand_char(scr, cell->uc,
983 				    x, y, cell->attr);
984 			}
985 			cell++;
986 			if (rc != 0)
987 				return (rc);
988 		}
989 	}
990 
991 	return (0);
992 }
993 
994 /*
995  * Perform a solid fill operation.
996  */
997 int
998 cfxga_solid_fill(struct cfxga_screen *scr, int x, int y, int cx, int cy,
999     int32_t srccolor)
1000 {
1001 	struct cfxga_softc *sc = scr->scr_sc;
1002 	struct rasops_info *ri = &scr->scr_ri;
1003 	u_int pos;
1004 	int rc;
1005 
1006 	pos = (y * ri->ri_width + x) * ri->ri_depth / 8;
1007 
1008 	/* Wait for previous operations to complete */
1009 	if ((rc = cfxga_synchronize(sc)) != 0)
1010 		return (rc);
1011 
1012 	cfxga_write_2(sc, CFREG_BITBLT_ROP, 0 | (OP_SOLID_FILL << 8));
1013 	cfxga_write_2(sc, CFREG_BITBLT_SRC_LOW, pos);
1014 	cfxga_write_2(sc, CFREG_BITBLT_SRC_HIGH, pos >> 16);
1015 	cfxga_write_2(sc, CFREG_BITBLT_DST_LOW, pos);
1016 	cfxga_write_2(sc, CFREG_BITBLT_DST_HIGH, pos >> 16);
1017 	cfxga_write_2(sc, CFREG_BITBLT_OFFSET,
1018 	    ri->ri_width * ri->ri_depth / 16);
1019 	cfxga_write_2(sc, CFREG_BITBLT_WIDTH, cx - 1);
1020 	cfxga_write_2(sc, CFREG_BITBLT_HEIGHT, cy - 1);
1021 	cfxga_write_2(sc, CFREG_BITBLT_FG, (u_int16_t)srccolor);
1022 	cfxga_write_2(sc, CFREG_BITBLT_CONTROL, BITBLT_ACTIVE |
1023 	    (ri->ri_depth > 8 ? BITBLT_COLOR_16 : BITBLT_COLOR_8));
1024 
1025 	return (0);
1026 }
1027 
1028 /*
1029  * Perform an internal frame buffer operation.
1030  */
1031 int
1032 cfxga_standalone_rop(struct cfxga_screen *scr, u_int rop, int sx, int sy,
1033     int dx, int dy, int cx, int cy)
1034 {
1035 	struct cfxga_softc *sc = scr->scr_sc;
1036 	struct rasops_info *ri = &scr->scr_ri;
1037 	u_int srcpos, dstpos;
1038 	u_int opcode;
1039 	int rc;
1040 
1041 	srcpos = (sy * ri->ri_width + sx) * ri->ri_depth / 8;
1042 	dstpos = (dy * ri->ri_width + dx) * ri->ri_depth / 8;
1043 
1044 	if (dstpos <= srcpos)
1045 		opcode = (OP_MOVE_POSITIVE_ROP << 8) | rop;
1046 	else
1047 		opcode = (OP_MOVE_NEGATIVE_ROP << 8) | rop;
1048 
1049 	/* Wait for previous operations to complete */
1050 	if ((rc = cfxga_synchronize(sc)) != 0)
1051 		return (rc);
1052 
1053 	cfxga_write_2(sc, CFREG_BITBLT_ROP, opcode);
1054 	cfxga_write_2(sc, CFREG_BITBLT_SRC_LOW, srcpos);
1055 	cfxga_write_2(sc, CFREG_BITBLT_SRC_HIGH, srcpos >> 16);
1056 	cfxga_write_2(sc, CFREG_BITBLT_DST_LOW, dstpos);
1057 	cfxga_write_2(sc, CFREG_BITBLT_DST_HIGH, dstpos >> 16);
1058 	cfxga_write_2(sc, CFREG_BITBLT_OFFSET,
1059 	    ri->ri_width * ri->ri_depth / 16);
1060 	cfxga_write_2(sc, CFREG_BITBLT_WIDTH, cx - 1);
1061 	cfxga_write_2(sc, CFREG_BITBLT_HEIGHT, cy - 1);
1062 	cfxga_write_2(sc, CFREG_BITBLT_CONTROL, BITBLT_ACTIVE |
1063 	    (ri->ri_depth > 8 ? BITBLT_COLOR_16 : BITBLT_COLOR_8));
1064 
1065 	return (0);
1066 }
1067 
1068 /*
1069  * Text console raster operations.
1070  *
1071  * We shadow all these operations on a memory copy of the frame buffer.
1072  * Since we are running in emulation mode only, this could be optimized
1073  * by only storing actual character cell values (a la mda).
1074  */
1075 
1076 int
1077 cfxga_copycols(void *cookie, int row, int src, int dst, int num)
1078 {
1079 	struct rasops_info *ri = cookie;
1080 	struct cfxga_screen *scr = ri->ri_hw;
1081 	int sx, dx, y, cx, cy;
1082 
1083 	/* Copy columns in backing store. */
1084 	memmove(scr->scr_mem + row * ri->ri_cols + dst,
1085 	    scr->scr_mem + row * ri->ri_cols + src,
1086 	    num * sizeof(struct wsdisplay_charcell));
1087 
1088 	if (scr != scr->scr_sc->sc_active)
1089 		return 0;
1090 
1091 	sx = src * ri->ri_font->fontwidth + ri->ri_xorigin;
1092 	dx = dst * ri->ri_font->fontwidth + ri->ri_xorigin;
1093 	y = row * ri->ri_font->fontheight + ri->ri_yorigin;
1094 	cx = num * ri->ri_font->fontwidth;
1095 	cy = ri->ri_font->fontheight;
1096 	return cfxga_standalone_rop(scr, ROP_SRC, sx, y, dx, y, cx, cy);
1097 }
1098 
1099 int
1100 cfxga_copyrows(void *cookie, int src, int dst, int num)
1101 {
1102 	struct rasops_info *ri = cookie;
1103 	struct cfxga_screen *scr = ri->ri_hw;
1104 	int x, sy, dy, cx, cy;
1105 
1106 	/* Copy rows in backing store. */
1107 	memmove(scr->scr_mem + dst * ri->ri_cols,
1108 	    scr->scr_mem + src * ri->ri_cols,
1109 	    num * ri->ri_cols * sizeof(struct wsdisplay_charcell));
1110 
1111 	if (scr != scr->scr_sc->sc_active)
1112 		return 0;
1113 
1114 	x = ri->ri_xorigin;
1115 	sy = src * ri->ri_font->fontheight + ri->ri_yorigin;
1116 	dy = dst * ri->ri_font->fontheight + ri->ri_yorigin;
1117 	cx = ri->ri_emuwidth;
1118 	cy = num * ri->ri_font->fontheight;
1119 	return cfxga_standalone_rop(scr, ROP_SRC, x, sy, x, dy, cx, cy);
1120 }
1121 
1122 int
1123 cfxga_do_cursor(struct rasops_info *ri)
1124 {
1125 	struct cfxga_screen *scr = ri->ri_hw;
1126 	int x, y, cx, cy;
1127 
1128 	if (scr != scr->scr_sc->sc_active)
1129 		return 0;
1130 
1131 	x = ri->ri_ccol * ri->ri_font->fontwidth + ri->ri_xorigin;
1132 	y = ri->ri_crow * ri->ri_font->fontheight + ri->ri_yorigin;
1133 	cx = ri->ri_font->fontwidth;
1134 	cy = ri->ri_font->fontheight;
1135 	return cfxga_standalone_rop(scr, ROP_ONES ^ ROP_SRC /* i.e. not SRC */,
1136 	    x, y, x, y, cx, cy);
1137 }
1138 
1139 int
1140 cfxga_erasecols(void *cookie, int row, int col, int num, uint32_t attr)
1141 {
1142 	struct rasops_info *ri = cookie;
1143 	struct cfxga_screen *scr = ri->ri_hw;
1144 	int fg, bg;
1145 	int x, y, cx, cy;
1146 
1147 	/* Erase columns in backing store. */
1148 	for (x = col; x < col + num; x++) {
1149 		scr->scr_mem[row * ri->ri_cols + x].uc = 0;
1150 		scr->scr_mem[row * ri->ri_cols + x].attr = attr;
1151 	}
1152 
1153 	if (scr != scr->scr_sc->sc_active)
1154 		return 0;
1155 
1156 	ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
1157 	x = col * ri->ri_font->fontwidth + ri->ri_xorigin;
1158 	y = row * ri->ri_font->fontheight + ri->ri_yorigin;
1159 	cx = num * ri->ri_font->fontwidth;
1160 	cy = ri->ri_font->fontheight;
1161 	return cfxga_solid_fill(scr, x, y, cx, cy, ri->ri_devcmap[bg]);
1162 }
1163 
1164 int
1165 cfxga_eraserows(void *cookie, int row, int num, uint32_t attr)
1166 {
1167 	struct rasops_info *ri = cookie;
1168 	struct cfxga_screen *scr = ri->ri_hw;
1169 	int fg, bg;
1170 	int x, y, cx, cy;
1171 
1172 	/* Erase rows in backing store. */
1173 	for (x = 0; x < ri->ri_cols; x++) {
1174 		scr->scr_mem[row * ri->ri_cols + x].uc = 0;
1175 		scr->scr_mem[row * ri->ri_cols + x].attr = attr;
1176 	}
1177 	for (y = 1; y < num; y++)
1178 		memmove(scr->scr_mem + (row + y) * ri->ri_cols,
1179 		    scr->scr_mem + row * ri->ri_cols,
1180 		    ri->ri_cols * sizeof(struct wsdisplay_charcell));
1181 
1182 	if (scr != scr->scr_sc->sc_active)
1183 		return 0;
1184 
1185 	ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
1186 	x = ri->ri_xorigin;
1187 	y = row * ri->ri_font->fontheight + ri->ri_yorigin;
1188 	cx = ri->ri_emuwidth;
1189 	cy = num * ri->ri_font->fontheight;
1190 	return cfxga_solid_fill(scr, x, y, cx, cy, ri->ri_devcmap[bg]);
1191 }
1192 
1193 int
1194 cfxga_putchar(void *cookie, int row, int col, u_int uc, uint32_t attr)
1195 {
1196 	struct rasops_info *ri = cookie;
1197 	struct cfxga_screen *scr = ri->ri_hw;
1198 	int x, y;
1199 
1200 	scr->scr_mem[row * ri->ri_cols + col].uc = uc;
1201 	scr->scr_mem[row * ri->ri_cols + col].attr = attr;
1202 
1203 	if (scr != scr->scr_sc->sc_active)
1204 		return 0;
1205 
1206 	x = col * ri->ri_font->fontwidth + ri->ri_xorigin;
1207 	y = row * ri->ri_font->fontheight + ri->ri_yorigin;
1208 
1209 	if (uc == ' ') {
1210 		int cx, cy, fg, bg;
1211 
1212 		ri->ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
1213 		cx = ri->ri_font->fontwidth;
1214 		cy = ri->ri_font->fontheight;
1215 		return cfxga_solid_fill(scr, x, y, cx, cy, ri->ri_devcmap[bg]);
1216 	} else {
1217 		return cfxga_expand_char(scr, uc, x, y, attr);
1218 	}
1219 }
1220