xref: /netbsd-src/sys/dev/tc/mfb.c (revision 1ca5c1b28139779176bd5c13ad7c5f25c0bcd5f8)
1 /* $NetBSD: mfb.c,v 1.29 2001/11/13 06:26:10 lukem 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.29 2001/11/13 06:26:10 lukem 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 const struct cfattach mfb_ca = {
135 	sizeof(struct mfb_softc), mfbmatch, mfbattach,
136 };
137 
138 static void mfb_common_init __P((struct rasops_info *));
139 static struct rasops_info mfb_console_ri;
140 static tc_addr_t mfb_consaddr;
141 
142 static struct wsscreen_descr mfb_stdscreen = {
143 	"std", 0, 0,
144 	0, /* textops */
145 	0, 0,
146 	WSSCREEN_REVERSE
147 };
148 
149 static const struct wsscreen_descr *_mfb_scrlist[] = {
150 	&mfb_stdscreen,
151 };
152 
153 static const struct wsscreen_list mfb_screenlist = {
154 	sizeof(_mfb_scrlist) / sizeof(struct wsscreen_descr *), _mfb_scrlist
155 };
156 
157 static int	mfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
158 static paddr_t	mfbmmap __P((void *, off_t, int));
159 
160 static int	mfb_alloc_screen __P((void *, const struct wsscreen_descr *,
161 				      void **, int *, int *, long *));
162 static void	mfb_free_screen __P((void *, void *));
163 static int	mfb_show_screen __P((void *, void *, int,
164 				     void (*) (void *, int, int), void *));
165 
166 static const struct wsdisplay_accessops mfb_accessops = {
167 	mfbioctl,
168 	mfbmmap,
169 	mfb_alloc_screen,
170 	mfb_free_screen,
171 	mfb_show_screen,
172 	0 /* load_font */
173 };
174 
175 int  mfb_cnattach __P((tc_addr_t));
176 static int  mfbintr __P((void *));
177 static void mfbhwinit __P((caddr_t));
178 
179 static int  set_cursor __P((struct mfb_softc *, struct wsdisplay_cursor *));
180 static int  get_cursor __P((struct mfb_softc *, struct wsdisplay_cursor *));
181 static void set_curpos __P((struct mfb_softc *, struct wsdisplay_curpos *));
182 
183 /* bit order reverse */
184 static const u_int8_t flip[256] = {
185 	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
186 	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
187 	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
188 	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
189 	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
190 	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
191 	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
192 	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
193 	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
194 	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
195 	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
196 	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
197 	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
198 	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
199 	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
200 	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
201 	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
202 	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
203 	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
204 	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
205 	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
206 	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
207 	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
208 	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
209 	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
210 	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
211 	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
212 	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
213 	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
214 	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
215 	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
216 	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
217 };
218 
219 static int
220 mfbmatch(parent, match, aux)
221 	struct device *parent;
222 	struct cfdata *match;
223 	void *aux;
224 {
225 	struct tc_attach_args *ta = aux;
226 
227 	if (strncmp("PMAG-AA ", ta->ta_modname, TC_ROM_LLEN) != 0)
228 		return (0);
229 
230 	return (1);
231 }
232 
233 static void
234 mfbattach(parent, self, aux)
235 	struct device *parent, *self;
236 	void *aux;
237 {
238 	struct mfb_softc *sc = (struct mfb_softc *)self;
239 	struct tc_attach_args *ta = aux;
240 	struct rasops_info *ri;
241 	struct wsemuldisplaydev_attach_args waa;
242 	int console;
243 	volatile register int junk;
244 
245 	console = (ta->ta_addr == mfb_consaddr);
246 	if (console) {
247 		sc->sc_ri = ri = &mfb_console_ri;
248 		sc->nscreens = 1;
249 	}
250 	else {
251 		MALLOC(ri, struct rasops_info *, sizeof(struct rasops_info),
252 			M_DEVBUF, M_NOWAIT);
253 		if (ri == NULL) {
254 			printf(": can't alloc memory\n");
255 			return;
256 		}
257 		memset(ri, 0, sizeof(struct rasops_info));
258 
259 		ri->ri_hw = (void *)ta->ta_addr;
260 		mfb_common_init(ri);
261 		sc->sc_ri = ri;
262 	}
263 	printf(": %dx%d, 1bpp\n", ri->ri_width, ri->ri_height);
264 
265 	sc->sc_vaddr = ta->ta_addr;
266 	sc->sc_cursor.cc_magic.x = MX_MAGIC_X;
267 	sc->sc_cursor.cc_magic.y = MX_MAGIC_Y;
268 	sc->sc_blanked = sc->sc_curenb = 0;
269 
270 	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, mfbintr, sc);
271 
272 	/* clear any pending interrupts */
273 	*(u_int8_t *)((caddr_t)ri->ri_hw + MX_IREQ_OFFSET) = 0;
274 	junk = *(u_int8_t *)((caddr_t)ri->ri_hw + MX_IREQ_OFFSET);
275 	*(u_int8_t *)((caddr_t)ri->ri_hw + MX_IREQ_OFFSET) = 1;
276 
277 	waa.console = console;
278 	waa.scrdata = &mfb_screenlist;
279 	waa.accessops = &mfb_accessops;
280 	waa.accesscookie = sc;
281 
282 	config_found(self, &waa, wsemuldisplaydevprint);
283 }
284 
285 static void
286 mfb_common_init(ri)
287 	struct rasops_info *ri;
288 {
289 	caddr_t base;
290 	int cookie;
291 
292 	base = (caddr_t)ri->ri_hw;
293 
294 	/* initialize colormap and cursor hardware */
295 	mfbhwinit(base);
296 
297 	ri->ri_flg = RI_CENTER;
298 	ri->ri_depth = 8;	/* !! watch out !! */
299 	ri->ri_width = 1280;
300 	ri->ri_height = 1024;
301 	ri->ri_stride = 2048;
302 	ri->ri_bits = base + MX_FB_OFFSET;
303 
304 	/* clear the screen */
305 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
306 
307 	wsfont_init();
308 	/* prefer 12 pixel wide font */
309 	if ((cookie = wsfont_find(NULL, 12, 0, 0)) <= 0)
310 		cookie = wsfont_find(NULL, 0, 0, 0);
311 	if (cookie <= 0) {
312 		printf("mfb: font table is empty\n");
313 		return;
314 	}
315 
316 	if (wsfont_lock(cookie, &ri->ri_font,
317 	    WSDISPLAY_FONTORDER_L2R, WSDISPLAY_FONTORDER_L2R) <= 0) {
318 		printf("mfb: couldn't lock font\n");
319 		return;
320 	}
321 	ri->ri_wsfcookie = cookie;
322 
323 	rasops_init(ri, 34, 80);
324 
325 	/* XXX shouldn't be global */
326 	mfb_stdscreen.nrows = ri->ri_rows;
327 	mfb_stdscreen.ncols = ri->ri_cols;
328 	mfb_stdscreen.textops = &ri->ri_ops;
329 	mfb_stdscreen.capabilities = ri->ri_caps;
330 }
331 
332 static int
333 mfbioctl(v, cmd, data, flag, p)
334 	void *v;
335 	u_long cmd;
336 	caddr_t data;
337 	int flag;
338 	struct proc *p;
339 {
340 	struct mfb_softc *sc = v;
341 	struct rasops_info *ri = sc->sc_ri;
342 	int turnoff;
343 
344 	switch (cmd) {
345 	case WSDISPLAYIO_GTYPE:
346 		*(u_int *)data = WSDISPLAY_TYPE_MFB;
347 		return (0);
348 
349 	case WSDISPLAYIO_GINFO:
350 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
351 		wsd_fbip->height = ri->ri_height;
352 		wsd_fbip->width = ri->ri_width;
353 		wsd_fbip->depth = ri->ri_depth;
354 		wsd_fbip->cmsize = 0;
355 #undef fbt
356 		return (0);
357 
358 	case WSDISPLAYIO_GETCMAP:
359 	case WSDISPLAYIO_PUTCMAP:
360 		return (ENOTTY);
361 
362 	case WSDISPLAYIO_SVIDEO:
363 		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
364 		if ((sc->sc_blanked == 0) ^ turnoff) {
365 			sc->sc_blanked = turnoff;
366 #if 0	/* XXX later XXX */
367 	To turn off,
368 	- assign Bt455 cmap[1].green with value 0 (black),
369 	- assign Bt431 register #0 with value 0x04 to hide sprite cursor.
370 #endif	/* XXX XXX XXX */
371 		}
372 		return (0);
373 
374 	case WSDISPLAYIO_GVIDEO:
375 		*(u_int *)data = sc->sc_blanked ?
376 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
377 		return (0);
378 
379 	case WSDISPLAYIO_GCURPOS:
380 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
381 		return (0);
382 
383 	case WSDISPLAYIO_SCURPOS:
384 		set_curpos(sc, (struct wsdisplay_curpos *)data);
385 		sc->sc_changed = WSDISPLAY_CURSOR_DOPOS;
386 		return (0);
387 
388 	case WSDISPLAYIO_GCURMAX:
389 		((struct wsdisplay_curpos *)data)->x =
390 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
391 		return (0);
392 
393 	case WSDISPLAYIO_GCURSOR:
394 		return get_cursor(sc, (struct wsdisplay_cursor *)data);
395 
396 	case WSDISPLAYIO_SCURSOR:
397 		return set_cursor(sc, (struct wsdisplay_cursor *)data);
398 	}
399 	return (ENOTTY);
400 }
401 
402 static paddr_t
403 mfbmmap(v, offset, prot)
404 	void *v;
405 	off_t offset;
406 	int prot;
407 {
408 	struct mfb_softc *sc = v;
409 
410 	if (offset >= MX_FB_SIZE || offset < 0)
411 		return (-1);
412 	return machine_btop(sc->sc_vaddr + MX_FB_OFFSET + offset);
413 }
414 
415 static int
416 mfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
417 	void *v;
418 	const struct wsscreen_descr *type;
419 	void **cookiep;
420 	int *curxp, *curyp;
421 	long *attrp;
422 {
423 	struct mfb_softc *sc = v;
424 	struct rasops_info *ri = sc->sc_ri;
425 	long defattr;
426 
427 	if (sc->nscreens > 0)
428 		return (ENOMEM);
429 
430 	*cookiep = ri;		 /* one and only for now */
431 	*curxp = 0;
432 	*curyp = 0;
433 	(*ri->ri_ops.alloc_attr)(ri, 0, 0, 0, &defattr);
434 	*attrp = defattr;
435 	sc->nscreens++;
436 	return (0);
437 }
438 
439 static void
440 mfb_free_screen(v, cookie)
441 	void *v;
442 	void *cookie;
443 {
444 	struct mfb_softc *sc = v;
445 
446 	if (sc->sc_ri == &mfb_console_ri)
447 		panic("mfb_free_screen: console");
448 
449 	sc->nscreens--;
450 }
451 
452 static int
453 mfb_show_screen(v, cookie, waitok, cb, cbarg)
454 	void *v;
455 	void *cookie;
456 	int waitok;
457 	void (*cb) __P((void *, int, int));
458 	void *cbarg;
459 {
460 
461 	return (0);
462 }
463 
464 /* EXPORT */ int
465 mfb_cnattach(addr)
466 	tc_addr_t addr;
467 {
468 	struct rasops_info *ri;
469 	long defattr;
470 
471 	ri = &mfb_console_ri;
472 	ri->ri_hw = (void *)addr;
473 	mfb_common_init(ri);
474 	(*ri->ri_ops.alloc_attr)(ri, 0, 0, 0, &defattr);
475 	wsdisplay_cnattach(&mfb_stdscreen, ri, 0, 0, defattr);
476 	mfb_consaddr = addr;
477 	return (0);
478 }
479 
480 static int
481 mfbintr(arg)
482 	void *arg;
483 {
484 	struct mfb_softc *sc = arg;
485 	caddr_t base, vdac, curs;
486 	int v;
487 	volatile register int junk;
488 
489 	base = (caddr_t)sc->sc_ri->ri_hw;
490 	junk = *(u_int8_t *)(base + MX_IREQ_OFFSET);
491 #if 0
492 	*(u_int8_t *)(base + MX_IREQ_OFFSET) = 0;
493 #endif
494 	if (sc->sc_changed == 0)
495 		goto done;
496 
497 	vdac = base + MX_BT455_OFFSET;
498 	curs = base + MX_BT431_OFFSET;
499 	v = sc->sc_changed;
500 	if (v & WSDISPLAY_CURSOR_DOCUR) {
501 		SELECT431(curs, BT431_REG_COMMAND);
502 		HALF(curs, bt_ctl) = (sc->sc_curenb) ? 0x4444 : 0x0404;
503 	}
504 	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
505 		int x, y;
506 		u_int16_t twin;
507 
508 		x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
509 		y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
510 
511 		x += sc->sc_cursor.cc_magic.x;
512 		y += sc->sc_cursor.cc_magic.y;
513 
514 		SELECT431(curs, BT431_REG_CURSOR_X_LOW);
515 		HALF(curs, bt_ctl) = TWIN_LO(x);	tc_wmb();
516 		HALF(curs, bt_ctl) = TWIN_HI(x);	tc_wmb();
517 		HALF(curs, bt_ctl) = TWIN_LO(y);	tc_wmb();
518 		HALF(curs, bt_ctl) = TWIN_HI(y);	tc_wmb();
519 	}
520 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
521 		u_int8_t *cp = sc->sc_cursor.cc_color;
522 
523 		SELECT455(vdac, 8);
524 		BYTE(vdac, bt_cmap) = 0;	tc_wmb();
525 		BYTE(vdac, bt_cmap) = cp[1];	tc_wmb();
526 		BYTE(vdac, bt_cmap) = 0;	tc_wmb();
527 
528 		BYTE(vdac, bt_cmap) = 0;	tc_wmb();
529 		BYTE(vdac, bt_cmap) = cp[1];	tc_wmb();
530 		BYTE(vdac, bt_cmap) = 0;	tc_wmb();
531 
532 		BYTE(vdac, bt_ovly) = 0;	tc_wmb();
533 		BYTE(vdac, bt_ovly) = cp[0];	tc_wmb();
534 		BYTE(vdac, bt_ovly) = 0;	tc_wmb();
535 	}
536 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
537 		u_int8_t *ip, *mp, img, msk;
538 		int bcnt;
539 
540 		ip = (u_int8_t *)sc->sc_cursor.cc_image;
541 		mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
542 		bcnt = 0;
543 		SELECT431(curs, BT431_REG_CRAM_BASE);
544 
545 		/* 64 pixel scan line is consisted with 16 byte cursor ram */
546 		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
547 			/* pad right half 32 pixel when smaller than 33 */
548 			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
549 				HALF(curs, bt_ram) = 0;
550 				tc_wmb();
551 			}
552 			else {
553 				img = *ip++;
554 				msk = *mp++;
555 				img &= msk;	/* cookie off image */
556 				HALF(curs, bt_ram)
557 				    = (flip[msk] << 8) | flip[img];
558 				tc_wmb();
559 			}
560 			bcnt += 2;
561 		}
562 		/* pad unoccupied scan lines */
563 		while (bcnt < CURSOR_MAX_SIZE * 16) {
564 			HALF(curs, bt_ram) = 0;
565 			tc_wmb();
566 			bcnt += 2;
567 		}
568 	}
569 	sc->sc_changed = 0;
570 done:
571 	return (1);
572 }
573 
574 static void
575 mfbhwinit(mfbbase)
576 	caddr_t mfbbase;
577 {
578 	caddr_t vdac, curs;
579 	int i;
580 
581 	vdac = mfbbase + MX_BT455_OFFSET;
582 	curs = mfbbase + MX_BT431_OFFSET;
583 	SELECT431(curs, BT431_REG_COMMAND);
584 	HALF(curs, bt_ctl) = 0x0404;		tc_wmb();
585 	HALF(curs, bt_ctl) = 0; /* XLO */	tc_wmb();
586 	HALF(curs, bt_ctl) = 0; /* XHI */	tc_wmb();
587 	HALF(curs, bt_ctl) = 0; /* YLO */	tc_wmb();
588 	HALF(curs, bt_ctl) = 0; /* YHI */	tc_wmb();
589 	HALF(curs, bt_ctl) = 0; /* XWLO */	tc_wmb();
590 	HALF(curs, bt_ctl) = 0; /* XWHI */	tc_wmb();
591 	HALF(curs, bt_ctl) = 0; /* WYLO */	tc_wmb();
592 	HALF(curs, bt_ctl) = 0; /* WYLO */	tc_wmb();
593 	HALF(curs, bt_ctl) = 0; /* WWLO */	tc_wmb();
594 	HALF(curs, bt_ctl) = 0; /* WWHI */	tc_wmb();
595 	HALF(curs, bt_ctl) = 0; /* WHLO */	tc_wmb();
596 	HALF(curs, bt_ctl) = 0; /* WHHI */	tc_wmb();
597 
598 	/* 0: black, 1: white, 8,9: cursor mask, ovly: cursor image */
599 	SELECT455(vdac, 0);
600 	BYTE(vdac, bt_cmap) = 0; 		tc_wmb();
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) = 0xff;		tc_wmb();
605 	BYTE(vdac, bt_cmap) = 0;		tc_wmb();
606 	for (i = 2; i < 16; i++) {
607 		BYTE(vdac, bt_cmap) = 0;	tc_wmb();
608 		BYTE(vdac, bt_cmap) = 0;	tc_wmb();
609 		BYTE(vdac, bt_cmap) = 0;	tc_wmb();
610 	}
611 	BYTE(vdac, bt_ovly) = 0;	tc_wmb();
612 	BYTE(vdac, bt_ovly) = 0xff;	tc_wmb();
613 	BYTE(vdac, bt_ovly) = 0;	tc_wmb();
614 
615 	SELECT431(curs, BT431_REG_CRAM_BASE);
616 	for (i = 0; i < 512; i++) {
617 		HALF(curs, bt_ram) = 0;	tc_wmb();
618 	}
619 }
620 
621 static int
622 set_cursor(sc, p)
623 	struct mfb_softc *sc;
624 	struct wsdisplay_cursor *p;
625 {
626 #define	cc (&sc->sc_cursor)
627 	u_int v, count, index;
628 
629 	v = p->which;
630 	if (v & WSDISPLAY_CURSOR_DOCMAP) {
631 		index = p->cmap.index;
632 		count = p->cmap.count;
633 		if (index >= 2 || (index + count) > 2)
634 			return (EINVAL);
635 		if (!uvm_useracc(p->cmap.red, count, B_READ))
636 			return (EFAULT);
637 	}
638 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
639 		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
640 			return (EINVAL);
641 		count = ((p->size.x < 33) ? 4 : 8) * p->size.y;
642 		if (!uvm_useracc(p->image, count, B_READ) ||
643 		    !uvm_useracc(p->mask, count, B_READ))
644 			return (EFAULT);
645 	}
646 
647 	if (v & WSDISPLAY_CURSOR_DOCUR)
648 		sc->sc_curenb = p->enable;
649 	if (v & WSDISPLAY_CURSOR_DOPOS)
650 		set_curpos(sc, &p->pos);
651 	if (v & WSDISPLAY_CURSOR_DOHOT)
652 		cc->cc_hot = p->hot;
653 	if (v & WSDISPLAY_CURSOR_DOCMAP)
654 		copyin(p->cmap.red, &cc->cc_color[index], count);
655 	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
656 		cc->cc_size = p->size;
657 		memset(cc->cc_image, 0, sizeof cc->cc_image);
658 		copyin(p->image, cc->cc_image, count);
659 		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, count);
660 	}
661 	sc->sc_changed = v;
662 
663 	return (0);
664 #undef cc
665 }
666 
667 static int
668 get_cursor(sc, p)
669 	struct mfb_softc *sc;
670 	struct wsdisplay_cursor *p;
671 {
672 	return (ENOTTY); /* XXX */
673 }
674 
675 static void
676 set_curpos(sc, curpos)
677 	struct mfb_softc *sc;
678 	struct wsdisplay_curpos *curpos;
679 {
680 	struct rasops_info *ri = sc->sc_ri;
681 	int x = curpos->x, y = curpos->y;
682 
683 	if (y < 0)
684 		y = 0;
685 	else if (y > ri->ri_height)
686 		y = ri->ri_height;
687 	if (x < 0)
688 		x = 0;
689 	else if (x > ri->ri_width)
690 		x = ri->ri_width;
691 	sc->sc_cursor.cc_pos.x = x;
692 	sc->sc_cursor.cc_pos.y = y;
693 }
694