xref: /netbsd-src/sys/dev/tc/mfb.c (revision 27578b9aac214cc7796ead81dcc5427e79d5f2a0)
1 /* $NetBSD: mfb.c,v 1.28 2001/08/22 02:24:29 nisimura 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>			/* RCS ID & Copyright macro defns */
34 
35 __KERNEL_RCSID(0, "$NetBSD: mfb.c,v 1.28 2001/08/22 02:24:29 nisimura Exp $");
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/device.h>
41 #include <sys/malloc.h>
42 #include <sys/buf.h>
43 #include <sys/ioctl.h>
44 
45 #include <machine/bus.h>
46 #include <machine/intr.h>
47 
48 #include <dev/wscons/wsconsio.h>
49 #include <dev/wscons/wsdisplayvar.h>
50 
51 #include <dev/rasops/rasops.h>
52 #include <dev/wsfont/wsfont.h>
53 
54 #include <dev/tc/tcvar.h>
55 #include <dev/ic/bt431reg.h>
56 
57 #include <uvm/uvm_extern.h>
58 
59 #if defined(pmax)
60 #define	machine_btop(x) mips_btop(MIPS_KSEG1_TO_PHYS(x))
61 
62 #define	BYTE(base, index)	*((u_int8_t *)(base) + ((index)<<2))
63 #define	HALF(base, index)	*((u_int16_t *)(base) + ((index)<<1))
64 #endif
65 
66 #if defined(__alpha__) || defined(alpha)
67 #define	machine_btop(x) alpha_btop(ALPHA_K0SEG_TO_PHYS(x))
68 
69 #define	BYTE(base, index)	*((u_int32_t *)(base) + (index))
70 #define	HALF(base, index)	*((u_int32_t *)(base) + (index))
71 #endif
72 
73 /* Bt455 hardware registers */
74 #define	bt_reg	0
75 #define	bt_cmap	1
76 #define	bt_clr	2
77 #define	bt_ovly	3
78 
79 /* Bt431 hardware registers */
80 #define	bt_lo	0
81 #define	bt_hi	1
82 #define	bt_ram	2
83 #define	bt_ctl	3
84 
85 #define	SELECT455(vdac, regno) do {	\
86 	BYTE(vdac, bt_reg) = (regno);	\
87 	BYTE(vdac, bt_clr) = 0;		\
88 	tc_wmb();			\
89    } while (0)
90 
91 #define	TWIN(x)    ((x)|((x) << 8))
92 #define	TWIN_LO(x) (twin = (x) & 0x00ff, twin << 8 | twin)
93 #define	TWIN_HI(x) (twin = (x) & 0xff00, twin | twin >> 8)
94 
95 #define	SELECT431(curs, regno) do {	\
96 	HALF(curs, bt_lo) = TWIN(regno);\
97 	HALF(curs, bt_hi) = 0;		\
98 	tc_wmb();			\
99    } while (0)
100 
101 struct hwcursor64 {
102 	struct wsdisplay_curpos cc_pos;
103 	struct wsdisplay_curpos cc_hot;
104 	struct wsdisplay_curpos cc_size;
105 	struct wsdisplay_curpos cc_magic;
106 #define	CURSOR_MAX_SIZE	64
107 	u_int8_t cc_color[6];
108 	u_int64_t cc_image[64 + 64];
109 };
110 
111 struct mfb_softc {
112 	struct device sc_dev;
113 	vaddr_t sc_vaddr;
114 	size_t sc_size;
115 	struct rasops_info *sc_ri;
116 	struct hwcursor64 sc_cursor;	/* software copy of cursor */
117 	int sc_blanked;
118 	int sc_curenb;			/* cursor sprite enabled */
119 	int sc_changed;			/* need update of hardware */
120 	int nscreens;
121 };
122 
123 #define	MX_MAGIC_X	360
124 #define	MX_MAGIC_Y	36
125 
126 #define	MX_FB_OFFSET	0x200000
127 #define	MX_FB_SIZE	0x200000
128 #define	MX_BT455_OFFSET	0x100000
129 #define	MX_BT431_OFFSET	0x180000
130 #define	MX_IREQ_OFFSET	0x080000	/* Interrupt req. control */
131 
132 static int  mfbmatch __P((struct device *, struct cfdata *, void *));
133 static void mfbattach __P((struct device *, struct device *, void *));
134 
135 const struct cfattach mfb_ca = {
136 	sizeof(struct mfb_softc), mfbmatch, mfbattach,
137 };
138 
139 static void mfb_common_init __P((struct rasops_info *));
140 static struct rasops_info mfb_console_ri;
141 static tc_addr_t mfb_consaddr;
142 
143 static struct wsscreen_descr mfb_stdscreen = {
144 	"std", 0, 0,
145 	0, /* textops */
146 	0, 0,
147 	WSSCREEN_REVERSE
148 };
149 
150 static const struct wsscreen_descr *_mfb_scrlist[] = {
151 	&mfb_stdscreen,
152 };
153 
154 static const struct wsscreen_list mfb_screenlist = {
155 	sizeof(_mfb_scrlist) / sizeof(struct wsscreen_descr *), _mfb_scrlist
156 };
157 
158 static int	mfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
159 static paddr_t	mfbmmap __P((void *, off_t, int));
160 
161 static int	mfb_alloc_screen __P((void *, const struct wsscreen_descr *,
162 				      void **, int *, int *, long *));
163 static void	mfb_free_screen __P((void *, void *));
164 static int	mfb_show_screen __P((void *, void *, int,
165 				     void (*) (void *, int, int), void *));
166 
167 static const struct wsdisplay_accessops mfb_accessops = {
168 	mfbioctl,
169 	mfbmmap,
170 	mfb_alloc_screen,
171 	mfb_free_screen,
172 	mfb_show_screen,
173 	0 /* load_font */
174 };
175 
176 int  mfb_cnattach __P((tc_addr_t));
177 static int  mfbintr __P((void *));
178 static void mfbhwinit __P((caddr_t));
179 
180 static int  set_cursor __P((struct mfb_softc *, struct wsdisplay_cursor *));
181 static int  get_cursor __P((struct mfb_softc *, struct wsdisplay_cursor *));
182 static void set_curpos __P((struct mfb_softc *, struct wsdisplay_curpos *));
183 
184 /* bit order reverse */
185 static const u_int8_t flip[256] = {
186 	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
187 	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
188 	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
189 	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
190 	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
191 	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
192 	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
193 	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
194 	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
195 	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
196 	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
197 	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
198 	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
199 	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
200 	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
201 	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
202 	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
203 	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
204 	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
205 	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
206 	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
207 	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
208 	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
209 	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
210 	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
211 	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
212 	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
213 	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
214 	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
215 	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
216 	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
217 	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
218 };
219 
220 static int
221 mfbmatch(parent, match, aux)
222 	struct device *parent;
223 	struct cfdata *match;
224 	void *aux;
225 {
226 	struct tc_attach_args *ta = aux;
227 
228 	if (strncmp("PMAG-AA ", ta->ta_modname, TC_ROM_LLEN) != 0)
229 		return (0);
230 
231 	return (1);
232 }
233 
234 static void
235 mfbattach(parent, self, aux)
236 	struct device *parent, *self;
237 	void *aux;
238 {
239 	struct mfb_softc *sc = (struct mfb_softc *)self;
240 	struct tc_attach_args *ta = aux;
241 	struct rasops_info *ri;
242 	struct wsemuldisplaydev_attach_args waa;
243 	int console;
244 	volatile register int junk;
245 
246 	console = (ta->ta_addr == mfb_consaddr);
247 	if (console) {
248 		sc->sc_ri = ri = &mfb_console_ri;
249 		sc->nscreens = 1;
250 	}
251 	else {
252 		MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info),
253 			M_DEVBUF, M_NOWAIT);
254 		if (ri == NULL) {
255 			printf(": can't alloc memory\n");
256 			return;
257 		}
258 		memset(ri, 0, sizeof(struct rasops_info));
259 
260 		ri->ri_hw = (void *)ta->ta_addr;
261 		mfb_common_init(ri);
262 		sc->sc_ri = ri;
263 	}
264 	printf(": %dx%d, 1bpp\n", ri->ri_width, ri->ri_height);
265 
266 	sc->sc_vaddr = ta->ta_addr;
267 	sc->sc_cursor.cc_magic.x = MX_MAGIC_X;
268 	sc->sc_cursor.cc_magic.y = MX_MAGIC_Y;
269 	sc->sc_blanked = sc->sc_curenb = 0;
270 
271 	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, mfbintr, sc);
272 
273 	/* clear any pending interrupts */
274 	*(u_int8_t *)((caddr_t)ri->ri_hw + MX_IREQ_OFFSET) = 0;
275 	junk = *(u_int8_t *)((caddr_t)ri->ri_hw + MX_IREQ_OFFSET);
276 	*(u_int8_t *)((caddr_t)ri->ri_hw + MX_IREQ_OFFSET) = 1;
277 
278 	waa.console = console;
279 	waa.scrdata = &mfb_screenlist;
280 	waa.accessops = &mfb_accessops;
281 	waa.accesscookie = sc;
282 
283 	config_found(self, &waa, wsemuldisplaydevprint);
284 }
285 
286 static void
287 mfb_common_init(ri)
288 	struct rasops_info *ri;
289 {
290 	caddr_t base;
291 	int cookie;
292 
293 	base = (caddr_t)ri->ri_hw;
294 
295 	/* initialize colormap and cursor hardware */
296 	mfbhwinit(base);
297 
298 	ri->ri_flg = RI_CENTER;
299 	ri->ri_depth = 8;	/* !! watch out !! */
300 	ri->ri_width = 1280;
301 	ri->ri_height = 1024;
302 	ri->ri_stride = 2048;
303 	ri->ri_bits = base + MX_FB_OFFSET;
304 
305 	/* clear the screen */
306 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
307 
308 	wsfont_init();
309 	/* prefer 12 pixel wide font */
310 	if ((cookie = wsfont_find(NULL, 12, 0, 0)) <= 0)
311 		cookie = wsfont_find(NULL, 0, 0, 0);
312 	if (cookie <= 0) {
313 		printf("mfb: font table is empty\n");
314 		return;
315 	}
316 
317 	if (wsfont_lock(cookie, &ri->ri_font,
318 	    WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R) <= 0) {
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 (ENOTTY);
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 (ENOTTY);
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.alloc_attr)(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.alloc_attr)(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 (ENOTTY); /* 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