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