xref: /netbsd/sys/dev/tc/mfb.c (revision c4a72b64)
1 /* $NetBSD: mfb.c,v 1.35 2002/10/02 16:53:04 thorpej Exp $ */
2 
3 /*
4  * Copyright (c) 1998, 1999 Tohru Nishimura.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by Tohru Nishimura
17  *	for the NetBSD Project.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: mfb.c,v 1.35 2002/10/02 16:53:04 thorpej Exp $");
35 
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39 #include <sys/device.h>
40 #include <sys/malloc.h>
41 #include <sys/buf.h>
42 #include <sys/ioctl.h>
43 
44 #include <machine/bus.h>
45 #include <machine/intr.h>
46 
47 #include <dev/wscons/wsconsio.h>
48 #include <dev/wscons/wsdisplayvar.h>
49 
50 #include <dev/rasops/rasops.h>
51 #include <dev/wsfont/wsfont.h>
52 
53 #include <dev/tc/tcvar.h>
54 #include <dev/ic/bt431reg.h>
55 
56 #include <uvm/uvm_extern.h>
57 
58 #if defined(pmax)
59 #define	machine_btop(x) mips_btop(MIPS_KSEG1_TO_PHYS(x))
60 
61 #define	BYTE(base, index)	*((u_int8_t *)(base) + ((index)<<2))
62 #define	HALF(base, index)	*((u_int16_t *)(base) + ((index)<<1))
63 #endif
64 
65 #if defined(__alpha__) || defined(alpha)
66 #define	machine_btop(x) alpha_btop(ALPHA_K0SEG_TO_PHYS(x))
67 
68 #define	BYTE(base, index)	*((u_int32_t *)(base) + (index))
69 #define	HALF(base, index)	*((u_int32_t *)(base) + (index))
70 #endif
71 
72 /* Bt455 hardware registers */
73 #define	bt_reg	0
74 #define	bt_cmap	1
75 #define	bt_clr	2
76 #define	bt_ovly	3
77 
78 /* Bt431 hardware registers */
79 #define	bt_lo	0
80 #define	bt_hi	1
81 #define	bt_ram	2
82 #define	bt_ctl	3
83 
84 #define	SELECT455(vdac, regno) do {	\
85 	BYTE(vdac, bt_reg) = (regno);	\
86 	BYTE(vdac, bt_clr) = 0;		\
87 	tc_wmb();			\
88    } while (0)
89 
90 #define	TWIN(x)    ((x)|((x) << 8))
91 #define	TWIN_LO(x) (twin = (x) & 0x00ff, twin << 8 | twin)
92 #define	TWIN_HI(x) (twin = (x) & 0xff00, twin | twin >> 8)
93 
94 #define	SELECT431(curs, regno) do {	\
95 	HALF(curs, bt_lo) = TWIN(regno);\
96 	HALF(curs, bt_hi) = 0;		\
97 	tc_wmb();			\
98    } while (0)
99 
100 struct hwcursor64 {
101 	struct wsdisplay_curpos cc_pos;
102 	struct wsdisplay_curpos cc_hot;
103 	struct wsdisplay_curpos cc_size;
104 	struct wsdisplay_curpos cc_magic;
105 #define	CURSOR_MAX_SIZE	64
106 	u_int8_t cc_color[6];
107 	u_int64_t cc_image[64 + 64];
108 };
109 
110 struct mfb_softc {
111 	struct device sc_dev;
112 	vaddr_t sc_vaddr;
113 	size_t sc_size;
114 	struct rasops_info *sc_ri;
115 	struct hwcursor64 sc_cursor;	/* software copy of cursor */
116 	int sc_blanked;
117 	int sc_curenb;			/* cursor sprite enabled */
118 	int sc_changed;			/* need update of hardware */
119 	int nscreens;
120 };
121 
122 #define	MX_MAGIC_X	360
123 #define	MX_MAGIC_Y	36
124 
125 #define	MX_FB_OFFSET	0x200000
126 #define	MX_FB_SIZE	0x200000
127 #define	MX_BT455_OFFSET	0x100000
128 #define	MX_BT431_OFFSET	0x180000
129 #define	MX_IREQ_OFFSET	0x080000	/* Interrupt req. control */
130 
131 static int  mfbmatch __P((struct device *, struct cfdata *, void *));
132 static void mfbattach __P((struct device *, struct device *, void *));
133 
134 CFATTACH_DECL(mfb, sizeof(struct mfb_softc),
135     mfbmatch, mfbattach, NULL, NULL);
136 
137 static void mfb_common_init __P((struct rasops_info *));
138 static struct rasops_info mfb_console_ri;
139 static tc_addr_t mfb_consaddr;
140 
141 static struct wsscreen_descr mfb_stdscreen = {
142 	"std", 0, 0,
143 	0, /* textops */
144 	0, 0,
145 	WSSCREEN_REVERSE
146 };
147 
148 static const struct wsscreen_descr *_mfb_scrlist[] = {
149 	&mfb_stdscreen,
150 };
151 
152 static const struct wsscreen_list mfb_screenlist = {
153 	sizeof(_mfb_scrlist) / sizeof(struct wsscreen_descr *), _mfb_scrlist
154 };
155 
156 static int	mfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
157 static paddr_t	mfbmmap __P((void *, off_t, int));
158 
159 static int	mfb_alloc_screen __P((void *, const struct wsscreen_descr *,
160 				      void **, int *, int *, long *));
161 static void	mfb_free_screen __P((void *, void *));
162 static int	mfb_show_screen __P((void *, void *, int,
163 				     void (*) (void *, int, int), void *));
164 
165 static const struct wsdisplay_accessops mfb_accessops = {
166 	mfbioctl,
167 	mfbmmap,
168 	mfb_alloc_screen,
169 	mfb_free_screen,
170 	mfb_show_screen,
171 	0 /* load_font */
172 };
173 
174 int  mfb_cnattach __P((tc_addr_t));
175 static int  mfbintr __P((void *));
176 static void mfbhwinit __P((caddr_t));
177 
178 static int  set_cursor __P((struct mfb_softc *, struct wsdisplay_cursor *));
179 static int  get_cursor __P((struct mfb_softc *, struct wsdisplay_cursor *));
180 static void set_curpos __P((struct mfb_softc *, struct wsdisplay_curpos *));
181 
182 /* bit order reverse */
183 static const u_int8_t flip[256] = {
184 	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
185 	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
186 	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
187 	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
188 	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
189 	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
190 	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
191 	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
192 	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
193 	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
194 	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
195 	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
196 	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
197 	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
198 	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
199 	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
200 	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
201 	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
202 	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
203 	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
204 	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
205 	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
206 	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
207 	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
208 	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
209 	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
210 	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
211 	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
212 	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
213 	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
214 	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
215 	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
216 };
217 
218 static int
219 mfbmatch(parent, match, aux)
220 	struct device *parent;
221 	struct cfdata *match;
222 	void *aux;
223 {
224 	struct tc_attach_args *ta = aux;
225 
226 	if (strncmp("PMAG-AA ", ta->ta_modname, TC_ROM_LLEN) != 0)
227 		return (0);
228 
229 	return (1);
230 }
231 
232 static void
233 mfbattach(parent, self, aux)
234 	struct device *parent, *self;
235 	void *aux;
236 {
237 	struct mfb_softc *sc = (struct mfb_softc *)self;
238 	struct tc_attach_args *ta = aux;
239 	struct rasops_info *ri;
240 	struct wsemuldisplaydev_attach_args waa;
241 	int console;
242 	volatile register int junk;
243 
244 	console = (ta->ta_addr == mfb_consaddr);
245 	if (console) {
246 		sc->sc_ri = ri = &mfb_console_ri;
247 		sc->nscreens = 1;
248 	}
249 	else {
250 		MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info),
251 			M_DEVBUF, M_NOWAIT);
252 		if (ri == NULL) {
253 			printf(": can't alloc memory\n");
254 			return;
255 		}
256 		memset(ri, 0, sizeof(struct rasops_info));
257 
258 		ri->ri_hw = (void *)ta->ta_addr;
259 		mfb_common_init(ri);
260 		sc->sc_ri = ri;
261 	}
262 	printf(": %dx%d, 1bpp\n", ri->ri_width, ri->ri_height);
263 
264 	sc->sc_vaddr = ta->ta_addr;
265 	sc->sc_cursor.cc_magic.x = MX_MAGIC_X;
266 	sc->sc_cursor.cc_magic.y = MX_MAGIC_Y;
267 	sc->sc_blanked = sc->sc_curenb = 0;
268 
269 	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, mfbintr, sc);
270 
271 	/* clear any pending interrupts */
272 	*(u_int8_t *)((caddr_t)ri->ri_hw + MX_IREQ_OFFSET) = 0;
273 	junk = *(u_int8_t *)((caddr_t)ri->ri_hw + MX_IREQ_OFFSET);
274 	*(u_int8_t *)((caddr_t)ri->ri_hw + MX_IREQ_OFFSET) = 1;
275 
276 	waa.console = console;
277 	waa.scrdata = &mfb_screenlist;
278 	waa.accessops = &mfb_accessops;
279 	waa.accesscookie = sc;
280 
281 	config_found(self, &waa, wsemuldisplaydevprint);
282 }
283 
284 static void
285 mfb_common_init(ri)
286 	struct rasops_info *ri;
287 {
288 	caddr_t base;
289 	int cookie;
290 
291 	base = (caddr_t)ri->ri_hw;
292 
293 	/* initialize colormap and cursor hardware */
294 	mfbhwinit(base);
295 
296 	ri->ri_flg = RI_CENTER | RI_FORCEMONO;
297 	ri->ri_depth = 8;	/* !! watch out !! */
298 	ri->ri_width = 1280;
299 	ri->ri_height = 1024;
300 	ri->ri_stride = 2048;
301 	ri->ri_bits = base + MX_FB_OFFSET;
302 
303 	/* clear the screen */
304 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
305 
306 	wsfont_init();
307 	/* prefer 12 pixel wide font */
308 	cookie = wsfont_find(NULL, 12, 0, 0, WSDISPLAY_FONTORDER_L2R,
309 	    WSDISPLAY_FONTORDER_L2R);
310 	if (cookie <= 0)
311 		cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
312 		    WSDISPLAY_FONTORDER_L2R);
313 	if (cookie <= 0) {
314 		printf("mfb: font table is empty\n");
315 		return;
316 	}
317 
318 	if (wsfont_lock(cookie, &ri->ri_font)) {
319 		printf("mfb: couldn't lock font\n");
320 		return;
321 	}
322 	ri->ri_wsfcookie = cookie;
323 
324 	rasops_init(ri, 34, 80);
325 
326 	/* XXX shouldn't be global */
327 	mfb_stdscreen.nrows = ri->ri_rows;
328 	mfb_stdscreen.ncols = ri->ri_cols;
329 	mfb_stdscreen.textops = &ri->ri_ops;
330 	mfb_stdscreen.capabilities = ri->ri_caps;
331 }
332 
333 static int
334 mfbioctl(v, cmd, data, flag, p)
335 	void *v;
336 	u_long cmd;
337 	caddr_t data;
338 	int flag;
339 	struct proc *p;
340 {
341 	struct mfb_softc *sc = v;
342 	struct rasops_info *ri = sc->sc_ri;
343 	int turnoff;
344 
345 	switch (cmd) {
346 	case WSDISPLAYIO_GTYPE:
347 		*(u_int *)data = WSDISPLAY_TYPE_MFB;
348 		return (0);
349 
350 	case WSDISPLAYIO_GINFO:
351 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
352 		wsd_fbip->height = ri->ri_height;
353 		wsd_fbip->width = ri->ri_width;
354 		wsd_fbip->depth = ri->ri_depth;
355 		wsd_fbip->cmsize = 0;
356 #undef fbt
357 		return (0);
358 
359 	case WSDISPLAYIO_GETCMAP:
360 	case WSDISPLAYIO_PUTCMAP:
361 		return (EPASSTHROUGH);
362 
363 	case WSDISPLAYIO_SVIDEO:
364 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
365 		if ((sc->sc_blanked == 0) ^ turnoff) {
366 			sc->sc_blanked = turnoff;
367 #if 0	/* XXX later XXX */
368 	To turn off,
369 	- assign Bt455 cmap[1].green with value 0 (black),
370 	- assign Bt431 register #0 with value 0x04 to hide sprite cursor.
371 #endif	/* XXX XXX XXX */
372 		}
373 		return (0);
374 
375 	case WSDISPLAYIO_GVIDEO:
376 		*(u_int *)data = sc->sc_blanked ?
377 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
378 		return (0);
379 
380 	case WSDISPLAYIO_GCURPOS:
381 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
382 		return (0);
383 
384 	case WSDISPLAYIO_SCURPOS:
385 		set_curpos(sc, (struct wsdisplay_curpos *)data);
386 		sc->sc_changed = WSDISPLAY_CURSOR_DOPOS;
387 		return (0);
388 
389 	case WSDISPLAYIO_GCURMAX:
390 		((struct wsdisplay_curpos *)data)->x =
391 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
392 		return (0);
393 
394 	case WSDISPLAYIO_GCURSOR:
395 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
396 
397 	case WSDISPLAYIO_SCURSOR:
398 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
399 	}
400 	return (EPASSTHROUGH);
401 }
402 
403 static paddr_t
404 mfbmmap(v, offset, prot)
405 	void *v;
406 	off_t offset;
407 	int prot;
408 {
409 	struct mfb_softc *sc = v;
410 
411 	if (offset >= MX_FB_SIZE || offset < 0)
412 		return (-1);
413 	return machine_btop(sc->sc_vaddr + MX_FB_OFFSET + offset);
414 }
415 
416 static int
417 mfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
418 	void *v;
419 	const struct wsscreen_descr *type;
420 	void **cookiep;
421 	int *curxp, *curyp;
422 	long *attrp;
423 {
424 	struct mfb_softc *sc = v;
425 	struct rasops_info *ri = sc->sc_ri;
426 	long defattr;
427 
428 	if (sc->nscreens > 0)
429 		return (ENOMEM);
430 
431 	*cookiep = ri;		 /* one and only for now */
432 	*curxp = 0;
433 	*curyp = 0;
434 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
435 	*attrp = defattr;
436 	sc->nscreens++;
437 	return (0);
438 }
439 
440 static void
441 mfb_free_screen(v, cookie)
442 	void *v;
443 	void *cookie;
444 {
445 	struct mfb_softc *sc = v;
446 
447 	if (sc->sc_ri == &mfb_console_ri)
448 		panic("mfb_free_screen: console");
449 
450 	sc->nscreens--;
451 }
452 
453 static int
454 mfb_show_screen(v, cookie, waitok, cb, cbarg)
455 	void *v;
456 	void *cookie;
457 	int waitok;
458 	void (*cb) __P((void *, int, int));
459 	void *cbarg;
460 {
461 
462 	return (0);
463 }
464 
465 /* EXPORT */ int
466 mfb_cnattach(addr)
467 	tc_addr_t addr;
468 {
469 	struct rasops_info *ri;
470 	long defattr;
471 
472 	ri = &mfb_console_ri;
473 	ri->ri_hw = (void *)addr;
474 	mfb_common_init(ri);
475 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
476 	wsdisplay_cnattach(&mfb_stdscreen, ri, 0, 0, defattr);
477 	mfb_consaddr = addr;
478 	return (0);
479 }
480 
481 static int
482 mfbintr(arg)
483 	void *arg;
484 {
485 	struct mfb_softc *sc = arg;
486 	caddr_t base, vdac, curs;
487 	int v;
488 	volatile register int junk;
489 
490 	base = (caddr_t)sc->sc_ri->ri_hw;
491 	junk = *(u_int8_t *)(base + MX_IREQ_OFFSET);
492 #if 0
493 	*(u_int8_t *)(base + MX_IREQ_OFFSET) = 0;
494 #endif
495 	if (sc->sc_changed == 0)
496 		goto done;
497 
498 	vdac = base + MX_BT455_OFFSET;
499 	curs = base + MX_BT431_OFFSET;
500 	v = sc->sc_changed;
501 	if (v & WSDISPLAY_CURSOR_DOCUR) {
502 		SELECT431(curs, BT431_REG_COMMAND);
503 		HALF(curs, bt_ctl) = (sc->sc_curenb) ? 0x4444 : 0x0404;
504 	}
505 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
506 		int x, y;
507 		u_int16_t twin;
508 
509 		x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
510 		y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
511 
512 		x += sc->sc_cursor.cc_magic.x;
513 		y += sc->sc_cursor.cc_magic.y;
514 
515 		SELECT431(curs, BT431_REG_CURSOR_X_LOW);
516 		HALF(curs, bt_ctl) = TWIN_LO(x);	tc_wmb();
517 		HALF(curs, bt_ctl) = TWIN_HI(x);	tc_wmb();
518 		HALF(curs, bt_ctl) = TWIN_LO(y);	tc_wmb();
519 		HALF(curs, bt_ctl) = TWIN_HI(y);	tc_wmb();
520 	}
521 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
522 		u_int8_t *cp = sc->sc_cursor.cc_color;
523 
524 		SELECT455(vdac, 8);
525 		BYTE(vdac, bt_cmap) = 0;	tc_wmb();
526 		BYTE(vdac, bt_cmap) = cp[1];	tc_wmb();
527 		BYTE(vdac, bt_cmap) = 0;	tc_wmb();
528 
529 		BYTE(vdac, bt_cmap) = 0;	tc_wmb();
530 		BYTE(vdac, bt_cmap) = cp[1];	tc_wmb();
531 		BYTE(vdac, bt_cmap) = 0;	tc_wmb();
532 
533 		BYTE(vdac, bt_ovly) = 0;	tc_wmb();
534 		BYTE(vdac, bt_ovly) = cp[0];	tc_wmb();
535 		BYTE(vdac, bt_ovly) = 0;	tc_wmb();
536 	}
537 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
538 		u_int8_t *ip, *mp, img, msk;
539 		int bcnt;
540 
541 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
542 		mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
543 		bcnt = 0;
544 		SELECT431(curs, BT431_REG_CRAM_BASE);
545 
546 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
547 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
548 			/* pad right half 32 pixel when smaller than 33 */
549 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
550 				HALF(curs, bt_ram) = 0;
551 				tc_wmb();
552 			}
553 			else {
554 				img = *ip++;
555 				msk = *mp++;
556 				img &= msk;	/* cookie off image */
557 				HALF(curs, bt_ram)
558 				    = (flip[msk] << 8) | flip[img];
559 				tc_wmb();
560 			}
561 			bcnt += 2;
562 		}
563 		/* pad unoccupied scan lines */
564 		while (bcnt < CURSOR_MAX_SIZE * 16) {
565 			HALF(curs, bt_ram) = 0;
566 			tc_wmb();
567 			bcnt += 2;
568 		}
569 	}
570 	sc->sc_changed = 0;
571 done:
572 	return (1);
573 }
574 
575 static void
576 mfbhwinit(mfbbase)
577 	caddr_t mfbbase;
578 {
579 	caddr_t vdac, curs;
580 	int i;
581 
582 	vdac = mfbbase + MX_BT455_OFFSET;
583 	curs = mfbbase + MX_BT431_OFFSET;
584 	SELECT431(curs, BT431_REG_COMMAND);
585 	HALF(curs, bt_ctl) = 0x0404;		tc_wmb();
586 	HALF(curs, bt_ctl) = 0; /* XLO */	tc_wmb();
587 	HALF(curs, bt_ctl) = 0; /* XHI */	tc_wmb();
588 	HALF(curs, bt_ctl) = 0; /* YLO */	tc_wmb();
589 	HALF(curs, bt_ctl) = 0; /* YHI */	tc_wmb();
590 	HALF(curs, bt_ctl) = 0; /* XWLO */	tc_wmb();
591 	HALF(curs, bt_ctl) = 0; /* XWHI */	tc_wmb();
592 	HALF(curs, bt_ctl) = 0; /* WYLO */	tc_wmb();
593 	HALF(curs, bt_ctl) = 0; /* WYLO */	tc_wmb();
594 	HALF(curs, bt_ctl) = 0; /* WWLO */	tc_wmb();
595 	HALF(curs, bt_ctl) = 0; /* WWHI */	tc_wmb();
596 	HALF(curs, bt_ctl) = 0; /* WHLO */	tc_wmb();
597 	HALF(curs, bt_ctl) = 0; /* WHHI */	tc_wmb();
598 
599 	/* 0: black, 1: white, 8,9: cursor mask, ovly: cursor image */
600 	SELECT455(vdac, 0);
601 	BYTE(vdac, bt_cmap) = 0; 		tc_wmb();
602 	BYTE(vdac, bt_cmap) = 0; 		tc_wmb();
603 	BYTE(vdac, bt_cmap) = 0;		tc_wmb();
604 	BYTE(vdac, bt_cmap) = 0;		tc_wmb();
605 	BYTE(vdac, bt_cmap) = 0xff;		tc_wmb();
606 	BYTE(vdac, bt_cmap) = 0;		tc_wmb();
607 	for (i = 2; i < 16; i++) {
608 		BYTE(vdac, bt_cmap) = 0;	tc_wmb();
609 		BYTE(vdac, bt_cmap) = 0;	tc_wmb();
610 		BYTE(vdac, bt_cmap) = 0;	tc_wmb();
611 	}
612 	BYTE(vdac, bt_ovly) = 0;	tc_wmb();
613 	BYTE(vdac, bt_ovly) = 0xff;	tc_wmb();
614 	BYTE(vdac, bt_ovly) = 0;	tc_wmb();
615 
616 	SELECT431(curs, BT431_REG_CRAM_BASE);
617 	for (i = 0; i < 512; i++) {
618 		HALF(curs, bt_ram) = 0;	tc_wmb();
619 	}
620 }
621 
622 static int
623 set_cursor(sc, p)
624 	struct mfb_softc *sc;
625 	struct wsdisplay_cursor *p;
626 {
627 #define	cc (&sc->sc_cursor)
628 	u_int v, count, index;
629 
630 	v = p->which;
631 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
632 		index = p->cmap.index;
633 		count = p->cmap.count;
634 		if (index >= 2 || (index + count) > 2)
635 			return (EINVAL);
636 		if (!uvm_useracc(p->cmap.red, count, B_READ))
637 			return (EFAULT);
638 	}
639 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
640 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
641 			return (EINVAL);
642 		count = ((p->size.x < 33) ? 4 : 8) * p->size.y;
643 		if (!uvm_useracc(p->image, count, B_READ) ||
644 		    !uvm_useracc(p->mask, count, B_READ))
645 			return (EFAULT);
646 	}
647 
648 	if (v & WSDISPLAY_CURSOR_DOCUR)
649 		sc->sc_curenb = p->enable;
650 	if (v & WSDISPLAY_CURSOR_DOPOS)
651 		set_curpos(sc, &p->pos);
652 	if (v & WSDISPLAY_CURSOR_DOHOT)
653 		cc->cc_hot = p->hot;
654 	if (v & WSDISPLAY_CURSOR_DOCMAP)
655 		copyin(p->cmap.red, &cc->cc_color[index], count);
656 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
657 		cc->cc_size = p->size;
658 		memset(cc->cc_image, 0, sizeof cc->cc_image);
659 		copyin(p->image, cc->cc_image, count);
660 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, count);
661 	}
662 	sc->sc_changed = v;
663 
664 	return (0);
665 #undef cc
666 }
667 
668 static int
669 get_cursor(sc, p)
670 	struct mfb_softc *sc;
671 	struct wsdisplay_cursor *p;
672 {
673 	return (EPASSTHROUGH); /* XXX */
674 }
675 
676 static void
677 set_curpos(sc, curpos)
678 	struct mfb_softc *sc;
679 	struct wsdisplay_curpos *curpos;
680 {
681 	struct rasops_info *ri = sc->sc_ri;
682 	int x = curpos->x, y = curpos->y;
683 
684 	if (y < 0)
685 		y = 0;
686 	else if (y > ri->ri_height)
687 		y = ri->ri_height;
688 	if (x < 0)
689 		x = 0;
690 	else if (x > ri->ri_width)
691 		x = ri->ri_width;
692 	sc->sc_cursor.cc_pos.x = x;
693 	sc->sc_cursor.cc_pos.y = y;
694 }
695