cfb.c revision 1.17
1/* $NetBSD: cfb.c,v 1.17 1999/12/15 15:09:37 ad 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: cfb.c,v 1.17 1999/12/15 15:09:37 ad 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#include <vm/vm.h>
45
46#include <machine/bus.h>
47#include <machine/intr.h>
48
49#include <dev/rcons/raster.h>
50#include <dev/wscons/wsconsio.h>
51#include <dev/wscons/wscons_raster.h>
52#include <dev/wscons/wsdisplayvar.h>
53
54#include <dev/tc/tcvar.h>
55#include <dev/ic/bt459reg.h>
56
57#include <uvm/uvm_extern.h>
58
59#if defined(pmax)
60#define	machine_btop(x) mips_btop(x)
61#define	MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG1_TO_PHYS(x)
62#endif
63
64#if defined(__alpha__) || defined(alpha)
65/*
66 * Digital UNIX never supports PMAG-BA
67 */
68#define machine_btop(x) alpha_btop(x)
69#define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x)
70#endif
71
72/*
73 * N.B., Bt459 registers are 8bit width.  Some of TC framebuffers have
74 * obscure register layout such as 2nd and 3rd Bt459 registers are
75 * adjacent each other in a word, i.e.,
76 *	struct bt459triplet {
77 * 		struct {
78 *			u_int8_t u0;
79 *			u_int8_t u1;
80 *			u_int8_t u2;
81 *			unsigned :8;
82 *		} bt_lo;
83 *		...
84 * Although CX has single Bt459, 32bit R/W can be done w/o any trouble.
85 *
86 * struct bt459reg {
87 *         u_int32_t       bt_lo;
88 *         u_int32_t       bt_hi;
89 *         u_int32_t       bt_reg;
90 *         u_int32_t       bt_cmap;
91 * };
92 *
93 */
94
95/* Bt459 hardware registers */
96#define bt_lo	0
97#define bt_hi	1
98#define bt_reg	2
99#define bt_cmap 3
100
101#define REG(base, index)	*((u_int32_t *)(base) + (index))
102#define SELECT(vdac, regno) do {			\
103	REG(vdac, bt_lo) = ((regno) & 0x00ff);		\
104	REG(vdac, bt_hi) = ((regno) & 0x0f00) >> 8;	\
105	tc_wmb();					\
106   } while (0)
107
108struct fb_devconfig {
109	vaddr_t dc_vaddr;		/* memory space virtual base address */
110	paddr_t dc_paddr;		/* memory space physical base address */
111	vsize_t	dc_size;		/* size of slot memory */
112	int	dc_wid;			/* width of frame buffer */
113	int	dc_ht;			/* height of frame buffer */
114	int	dc_depth;		/* depth, bits per pixel */
115	int	dc_rowbytes;		/* bytes in a FB scan line */
116	vaddr_t dc_videobase;		/* base of flat frame buffer */
117	struct raster	dc_raster;	/* raster description */
118	struct rcons	dc_rcons;	/* raster blitter control info */
119	int	    dc_blanked;		/* currently has video disabled */
120};
121
122struct hwcmap256 {
123#define	CMAP_SIZE	256	/* 256 R/G/B entries */
124	u_int8_t r[CMAP_SIZE];
125	u_int8_t g[CMAP_SIZE];
126	u_int8_t b[CMAP_SIZE];
127};
128
129struct hwcursor64 {
130	struct wsdisplay_curpos cc_pos;
131	struct wsdisplay_curpos cc_hot;
132	struct wsdisplay_curpos cc_size;
133	struct wsdisplay_curpos cc_magic;
134#define	CURSOR_MAX_SIZE	64
135	u_int8_t cc_color[6];
136	u_int64_t cc_image[64 + 64];
137};
138
139struct cfb_softc {
140	struct device sc_dev;
141	struct fb_devconfig *sc_dc;	/* device configuration */
142	struct hwcmap256 sc_cmap;	/* software copy of colormap */
143	struct hwcursor64 sc_cursor;	/* software copy of cursor */
144	int sc_curenb;			/* cursor sprite enabled */
145	int sc_changed;			/* need update of colormap */
146#define	DATA_ENB_CHANGED	0x01	/* cursor enable changed */
147#define	DATA_CURCMAP_CHANGED	0x02	/* cursor colormap changed */
148#define	DATA_CURSHAPE_CHANGED	0x04	/* cursor size, image, mask changed */
149#define	DATA_CMAP_CHANGED	0x08	/* colormap changed */
150#define	DATA_ALL_CHANGED	0x0f
151	int nscreens;
152};
153
154#define	CX_MAGIC_X	220
155#define	CX_MAGIC_Y 	35
156
157#define	CX_FB_OFFSET	0x000000
158#define	CX_FB_SIZE	0x100000
159#define	CX_BT459_OFFSET	0x200000
160#define	CX_OFFSET_IREQ	0x300000	/* Interrupt req. control */
161
162static int  cfbmatch __P((struct device *, struct cfdata *, void *));
163static void cfbattach __P((struct device *, struct device *, void *));
164
165const struct cfattach cfb_ca = {
166	sizeof(struct cfb_softc), cfbmatch, cfbattach,
167};
168
169static void cfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
170static struct fb_devconfig cfb_console_dc;
171static tc_addr_t cfb_consaddr;
172
173static const struct wsdisplay_emulops cfb_emulops = {
174	rcons_cursor,			/* could use hardware cursor; punt */
175	rcons_mapchar,
176	rcons_putchar,
177	rcons_copycols,
178	rcons_erasecols,
179	rcons_copyrows,
180	rcons_eraserows,
181	rcons_alloc_attr
182};
183
184static struct wsscreen_descr cfb_stdscreen = {
185	"std", 0, 0,
186	&cfb_emulops,
187	0, 0,
188	WSSCREEN_REVERSE
189};
190
191static const struct wsscreen_descr *_cfb_scrlist[] = {
192	&cfb_stdscreen,
193};
194
195static const struct wsscreen_list cfb_screenlist = {
196	sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist
197};
198
199static int  cfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
200static int  cfbmmap __P((void *, off_t, int));
201
202static int  cfb_alloc_screen __P((void *, const struct wsscreen_descr *,
203				      void **, int *, int *, long *));
204static void cfb_free_screen __P((void *, void *));
205static int cfb_show_screen __P((void *, void *, int,
206				void (*) (void *, int, int), void *));
207
208static const struct wsdisplay_accessops cfb_accessops = {
209	cfbioctl,
210	cfbmmap,
211	cfb_alloc_screen,
212	cfb_free_screen,
213	cfb_show_screen,
214	0 /* load_font */
215};
216
217int  cfb_cnattach __P((tc_addr_t));
218static int  cfbintr __P((void *));
219static void cfbinit __P((struct fb_devconfig *));
220
221static int  get_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
222static int  set_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
223static int  set_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
224static int  get_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
225static void set_curpos __P((struct cfb_softc *, struct wsdisplay_curpos *));
226static void bt459_set_curpos __P((struct cfb_softc *));
227
228/*
229 * Compose 2 bit/pixel cursor image.  Bit order will be reversed.
230 *   M M M M I I I I		M I M I M I M I
231 *	[ before ]		   [ after ]
232 *   3 2 1 0 3 2 1 0		0 0 1 1 2 2 3 3
233 *   7 6 5 4 7 6 5 4		4 4 5 5 6 6 7 7
234 */
235static const u_int8_t shuffle[256] = {
236	0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
237	0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
238	0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
239	0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
240	0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
241	0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
242	0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
243	0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
244	0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
245	0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
246	0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
247	0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
248	0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
249	0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
250	0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
251	0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
252	0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
253	0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
254	0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
255	0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
256	0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
257	0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
258	0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
259	0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
260	0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
261	0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
262	0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
263	0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
264	0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
265	0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
266	0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
267	0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
268};
269
270static int
271cfbmatch(parent, match, aux)
272	struct device *parent;
273	struct cfdata *match;
274	void *aux;
275{
276	struct tc_attach_args *ta = aux;
277
278	if (strncmp("PMAG-BA ", ta->ta_modname, TC_ROM_LLEN) != 0)
279		return (0);
280
281	return (1);
282}
283
284static void
285cfb_getdevconfig(dense_addr, dc)
286	tc_addr_t dense_addr;
287	struct fb_devconfig *dc;
288{
289	struct raster *rap;
290	struct rcons *rcp;
291	int i;
292
293	dc->dc_vaddr = dense_addr;
294	dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr + CX_FB_OFFSET);
295
296	dc->dc_wid = 1024;
297	dc->dc_ht = 864;
298	dc->dc_depth = 8;
299	dc->dc_rowbytes = 1024;
300	dc->dc_videobase = dc->dc_vaddr + CX_FB_OFFSET;
301	dc->dc_blanked = 0;
302
303	/* initialize colormap and cursor resource */
304	cfbinit(dc);
305
306	/* clear the screen */
307	for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
308		*(u_int32_t *)(dc->dc_videobase + i) = 0x0;
309
310	/* initialize the raster */
311	rap = &dc->dc_raster;
312	rap->width = dc->dc_wid;
313	rap->height = dc->dc_ht;
314	rap->depth = dc->dc_depth;
315	rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
316	rap->pixels = (u_int32_t *)dc->dc_videobase;
317
318	/* initialize the raster console blitter */
319	rcp = &dc->dc_rcons;
320	rcp->rc_sp = rap;
321	rcp->rc_crow = rcp->rc_ccol = -1;
322	rcp->rc_crowp = &rcp->rc_crow;
323	rcp->rc_ccolp = &rcp->rc_ccol;
324	rcons_init(rcp, 34, 80);
325
326	cfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
327	cfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
328}
329
330static void
331cfbattach(parent, self, aux)
332	struct device *parent, *self;
333	void *aux;
334{
335	struct cfb_softc *sc = (struct cfb_softc *)self;
336	struct tc_attach_args *ta = aux;
337	struct wsemuldisplaydev_attach_args waa;
338	struct hwcmap256 *cm;
339	int console;
340
341	console = (ta->ta_addr == cfb_consaddr);
342	if (console) {
343		sc->sc_dc = &cfb_console_dc;
344		sc->nscreens = 1;
345	}
346	else {
347		sc->sc_dc = (struct fb_devconfig *)
348		    malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
349		cfb_getdevconfig(ta->ta_addr, sc->sc_dc);
350	}
351	printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
352	    sc->sc_dc->dc_depth);
353
354	cm = &sc->sc_cmap;
355	memset(cm, 255, sizeof(struct hwcmap256));	/* XXX */
356	cm->r[0] = cm->g[0] = cm->b[0] = 0;		/* XXX */
357
358	sc->sc_cursor.cc_magic.x = CX_MAGIC_X;
359	sc->sc_cursor.cc_magic.y = CX_MAGIC_Y;
360
361	/* Establish an interrupt handler, and clear any pending interrupts */
362	tc_intr_establish(parent, ta->ta_cookie, IPL_TTY, cfbintr, sc);
363	*(u_int8_t *)(sc->sc_dc->dc_vaddr + CX_OFFSET_IREQ) = 0;
364
365	waa.console = console;
366	waa.scrdata = &cfb_screenlist;
367	waa.accessops = &cfb_accessops;
368	waa.accesscookie = sc;
369
370	config_found(self, &waa, wsemuldisplaydevprint);
371}
372
373static int
374cfbioctl(v, cmd, data, flag, p)
375	void *v;
376	u_long cmd;
377	caddr_t data;
378	int flag;
379	struct proc *p;
380{
381	struct cfb_softc *sc = v;
382	struct fb_devconfig *dc = sc->sc_dc;
383	int turnoff;
384
385	switch (cmd) {
386	case WSDISPLAYIO_GTYPE:
387		*(u_int *)data = WSDISPLAY_TYPE_CFB;
388		return (0);
389
390	case WSDISPLAYIO_GINFO:
391#define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
392		wsd_fbip->height = sc->sc_dc->dc_ht;
393		wsd_fbip->width = sc->sc_dc->dc_wid;
394		wsd_fbip->depth = sc->sc_dc->dc_depth;
395		wsd_fbip->cmsize = CMAP_SIZE;
396#undef fbt
397		return (0);
398
399	case WSDISPLAYIO_GETCMAP:
400		return get_cmap(sc, (struct wsdisplay_cmap *)data);
401
402	case WSDISPLAYIO_PUTCMAP:
403		return set_cmap(sc, (struct wsdisplay_cmap *)data);
404
405	case WSDISPLAYIO_SVIDEO:
406		turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
407		if ((dc->dc_blanked == 0) ^ turnoff) {
408			dc->dc_blanked = turnoff;
409			/* XXX later XXX */
410		}
411		return (0);
412
413	case WSDISPLAYIO_GVIDEO:
414		*(u_int *)data = dc->dc_blanked ?
415		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
416		return (0);
417
418	case WSDISPLAYIO_GCURPOS:
419		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
420		return (0);
421
422	case WSDISPLAYIO_SCURPOS:
423		set_curpos(sc, (struct wsdisplay_curpos *)data);
424		bt459_set_curpos(sc);
425		return (0);
426
427	case WSDISPLAYIO_GCURMAX:
428		((struct wsdisplay_curpos *)data)->x =
429		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
430		return (0);
431
432	case WSDISPLAYIO_GCURSOR:
433		return get_cursor(sc, (struct wsdisplay_cursor *)data);
434
435	case WSDISPLAYIO_SCURSOR:
436		return set_cursor(sc, (struct wsdisplay_cursor *)data);
437	}
438	return ENOTTY;
439}
440
441int
442cfbmmap(v, offset, prot)
443	void *v;
444	off_t offset;
445	int prot;
446{
447	struct cfb_softc *sc = v;
448
449	if (offset >= CX_FB_SIZE || offset < 0)
450		return (-1);
451	return machine_btop(sc->sc_dc->dc_paddr + offset);
452}
453
454static int
455cfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
456	void *v;
457	const struct wsscreen_descr *type;
458	void **cookiep;
459	int *curxp, *curyp;
460	long *attrp;
461{
462	struct cfb_softc *sc = v;
463	long defattr;
464
465	if (sc->nscreens > 0)
466		return (ENOMEM);
467
468	*cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
469	*curxp = 0;
470	*curyp = 0;
471	rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
472	*attrp = defattr;
473	sc->nscreens++;
474	return (0);
475}
476
477static void
478cfb_free_screen(v, cookie)
479	void *v;
480	void *cookie;
481{
482	struct cfb_softc *sc = v;
483
484	if (sc->sc_dc == &cfb_console_dc)
485		panic("cfb_free_screen: console");
486
487	sc->nscreens--;
488}
489
490static int
491cfb_show_screen(v, cookie, waitok, cb, cbarg)
492	void *v;
493	void *cookie;
494	int waitok;
495	void (*cb) __P((void *, int, int));
496	void *cbarg;
497{
498
499	return (0);
500}
501
502/* EXPORT */ int
503cfb_cnattach(addr)
504        tc_addr_t addr;
505{
506        struct fb_devconfig *dcp = &cfb_console_dc;
507        long defattr;
508
509        cfb_getdevconfig(addr, dcp);
510
511        rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
512
513        wsdisplay_cnattach(&cfb_stdscreen, &dcp->dc_rcons,
514                           0, 0, defattr);
515        cfb_consaddr = addr;
516        return(0);
517}
518
519
520static int
521cfbintr(arg)
522	void *arg;
523{
524	struct cfb_softc *sc = arg;
525	caddr_t cfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
526	struct bt459reg *vdac;
527	int v;
528
529	*(u_int8_t *)(cfbbase + CX_OFFSET_IREQ) = 0;
530	if (sc->sc_changed == 0)
531		return (1);
532
533	vdac = (void *)(cfbbase + CX_BT459_OFFSET);
534	v = sc->sc_changed;
535	sc->sc_changed = 0;
536	if (v & DATA_ENB_CHANGED) {
537		SELECT(vdac, BT459_IREG_CCR);
538		REG(vdac, bt_reg) = (sc->sc_curenb) ? 0xc0 : 0x00;
539	}
540	if (v & DATA_CURCMAP_CHANGED) {
541		u_int8_t *cp = sc->sc_cursor.cc_color;
542
543		SELECT(vdac, BT459_IREG_CCOLOR_2);
544		REG(vdac, bt_reg) = cp[1];	tc_wmb();
545		REG(vdac, bt_reg) = cp[3];	tc_wmb();
546		REG(vdac, bt_reg) = cp[5];	tc_wmb();
547
548		REG(vdac, bt_reg) = cp[0];	tc_wmb();
549		REG(vdac, bt_reg) = cp[2];	tc_wmb();
550		REG(vdac, bt_reg) = cp[4];	tc_wmb();
551	}
552	if (v & DATA_CURSHAPE_CHANGED) {
553		u_int8_t *ip, *mp, img, msk;
554		u_int8_t u;
555		int bcnt;
556
557		ip = (u_int8_t *)sc->sc_cursor.cc_image;
558		mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
559
560		bcnt = 0;
561		SELECT(vdac, BT459_IREG_CRAM_BASE+0);
562		/* 64 pixel scan line is consisted with 16 byte cursor ram */
563		while (bcnt < sc->sc_cursor.cc_size.y * 16) {
564			/* pad right half 32 pixel when smaller than 33 */
565			if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
566				REG(vdac, bt_reg) = 0; tc_wmb();
567				REG(vdac, bt_reg) = 0; tc_wmb();
568			}
569			else {
570				img = *ip++;
571				msk = *mp++;
572				img &= msk;	/* cookie off image */
573				u = (msk & 0x0f) << 4 | (img & 0x0f);
574				REG(vdac, bt_reg) = shuffle[u];	tc_wmb();
575				u = (msk & 0xf0) | (img & 0xf0) >> 4;
576				REG(vdac, bt_reg) = shuffle[u];	tc_wmb();
577			}
578			bcnt += 2;
579		}
580		/* pad unoccupied scan lines */
581		while (bcnt < CURSOR_MAX_SIZE * 16) {
582			REG(vdac, bt_reg) = 0; tc_wmb();
583			REG(vdac, bt_reg) = 0; tc_wmb();
584			bcnt += 2;
585		}
586	}
587	if (v & DATA_CMAP_CHANGED) {
588		struct hwcmap256 *cm = &sc->sc_cmap;
589		int index;
590
591		SELECT(vdac, 0);
592		for (index = 0; index < CMAP_SIZE; index++) {
593			REG(vdac, bt_cmap) = cm->r[index];	tc_wmb();
594			REG(vdac, bt_cmap) = cm->g[index];	tc_wmb();
595			REG(vdac, bt_cmap) = cm->b[index];	tc_wmb();
596		}
597	}
598	return (1);
599}
600
601static void
602cfbinit(dc)
603	struct fb_devconfig *dc;
604{
605	caddr_t cfbbase = (caddr_t)dc->dc_vaddr;
606	struct bt459reg *vdac = (void *)(cfbbase + CX_BT459_OFFSET);
607	int i;
608
609	SELECT(vdac, BT459_IREG_COMMAND_0);
610	REG(vdac, bt_reg) = 0x40; /* CMD0 */	tc_wmb();
611	REG(vdac, bt_reg) = 0x0;  /* CMD1 */	tc_wmb();
612	REG(vdac, bt_reg) = 0xc0; /* CMD2 */	tc_wmb();
613	REG(vdac, bt_reg) = 0xff; /* PRM */	tc_wmb();
614	REG(vdac, bt_reg) = 0;    /* 205 */	tc_wmb();
615	REG(vdac, bt_reg) = 0x0;  /* PBM */	tc_wmb();
616	REG(vdac, bt_reg) = 0;    /* 207 */	tc_wmb();
617	REG(vdac, bt_reg) = 0x0;  /* ORM */	tc_wmb();
618	REG(vdac, bt_reg) = 0x0;  /* OBM */	tc_wmb();
619	REG(vdac, bt_reg) = 0x0;  /* ILV */	tc_wmb();
620	REG(vdac, bt_reg) = 0x0;  /* TEST */	tc_wmb();
621
622	SELECT(vdac, BT459_IREG_CCR);
623	REG(vdac, bt_reg) = 0x0;	tc_wmb();
624	REG(vdac, bt_reg) = 0x0;	tc_wmb();
625	REG(vdac, bt_reg) = 0x0;	tc_wmb();
626	REG(vdac, bt_reg) = 0x0;	tc_wmb();
627	REG(vdac, bt_reg) = 0x0;	tc_wmb();
628	REG(vdac, bt_reg) = 0x0;	tc_wmb();
629	REG(vdac, bt_reg) = 0x0;	tc_wmb();
630	REG(vdac, bt_reg) = 0x0;	tc_wmb();
631	REG(vdac, bt_reg) = 0x0;	tc_wmb();
632	REG(vdac, bt_reg) = 0x0;	tc_wmb();
633	REG(vdac, bt_reg) = 0x0;	tc_wmb();
634	REG(vdac, bt_reg) = 0x0;	tc_wmb();
635	REG(vdac, bt_reg) = 0x0;	tc_wmb();
636
637	/* build sane colormap */
638	SELECT(vdac, 0);
639	REG(vdac, bt_cmap) = 0;	 tc_wmb();
640	REG(vdac, bt_cmap) = 0;	 tc_wmb();
641	REG(vdac, bt_cmap) = 0;	 tc_wmb();
642	for (i = 1; i < CMAP_SIZE; i++) {
643		REG(vdac, bt_cmap) = 0xff;	tc_wmb();
644		REG(vdac, bt_cmap) = 0xff;	tc_wmb();
645		REG(vdac, bt_cmap) = 0xff;	tc_wmb();
646	}
647
648	/* clear out cursor image */
649	SELECT(vdac, BT459_IREG_CRAM_BASE);
650	for (i = 0; i < 1024; i++)
651		REG(vdac, bt_reg) = 0xff;	tc_wmb();
652
653	/*
654	 * 2 bit/pixel cursor.  Assign MSB for cursor mask and LSB for
655	 * cursor image.  CCOLOR_2 for mask color, while CCOLOR_3 for
656	 * image color.  CCOLOR_1 will be never used.
657	 */
658	SELECT(vdac, BT459_IREG_CCOLOR_1);
659	REG(vdac, bt_reg) = 0xff;	tc_wmb();
660	REG(vdac, bt_reg) = 0xff;	tc_wmb();
661	REG(vdac, bt_reg) = 0xff;	tc_wmb();
662
663	REG(vdac, bt_reg) = 0;	tc_wmb();
664	REG(vdac, bt_reg) = 0;	tc_wmb();
665	REG(vdac, bt_reg) = 0;	tc_wmb();
666
667	REG(vdac, bt_reg) = 0xff;	tc_wmb();
668	REG(vdac, bt_reg) = 0xff;	tc_wmb();
669	REG(vdac, bt_reg) = 0xff;	tc_wmb();
670}
671
672static int
673get_cmap(sc, p)
674	struct cfb_softc *sc;
675	struct wsdisplay_cmap *p;
676{
677	u_int index = p->index, count = p->count;
678
679	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
680		return (EINVAL);
681
682	if (!uvm_useracc(p->red, count, B_WRITE) ||
683	    !uvm_useracc(p->green, count, B_WRITE) ||
684	    !uvm_useracc(p->blue, count, B_WRITE))
685		return (EFAULT);
686
687	copyout(&sc->sc_cmap.r[index], p->red, count);
688	copyout(&sc->sc_cmap.g[index], p->green, count);
689	copyout(&sc->sc_cmap.b[index], p->blue, count);
690
691	return (0);
692}
693
694static int
695set_cmap(sc, p)
696	struct cfb_softc *sc;
697	struct wsdisplay_cmap *p;
698{
699	u_int index = p->index, count = p->count;
700
701	if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
702		return (EINVAL);
703
704	if (!uvm_useracc(p->red, count, B_READ) ||
705	    !uvm_useracc(p->green, count, B_READ) ||
706	    !uvm_useracc(p->blue, count, B_READ))
707		return (EFAULT);
708
709	copyin(p->red, &sc->sc_cmap.r[index], count);
710	copyin(p->green, &sc->sc_cmap.g[index], count);
711	copyin(p->blue, &sc->sc_cmap.b[index], count);
712
713	sc->sc_changed |= DATA_CMAP_CHANGED;
714
715	return (0);
716}
717
718static int
719set_cursor(sc, p)
720	struct cfb_softc *sc;
721	struct wsdisplay_cursor *p;
722{
723#define	cc (&sc->sc_cursor)
724	int v, index, count, icount;
725
726	v = p->which;
727	if (v & WSDISPLAY_CURSOR_DOCMAP) {
728		index = p->cmap.index;
729		count = p->cmap.count;
730		if (index >= 2 || (index + count) > 2)
731			return (EINVAL);
732		if (!uvm_useracc(p->cmap.red, count, B_READ) ||
733		    !uvm_useracc(p->cmap.green, count, B_READ) ||
734		    !uvm_useracc(p->cmap.blue, count, B_READ))
735			return (EFAULT);
736	}
737	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
738		if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
739			return (EINVAL);
740		icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
741		if (!uvm_useracc(p->image, icount, B_READ) ||
742		    !uvm_useracc(p->mask, icount, B_READ))
743			return (EFAULT);
744	}
745	if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
746		if (v & WSDISPLAY_CURSOR_DOCUR)
747			cc->cc_hot = p->hot;
748		if (v & WSDISPLAY_CURSOR_DOPOS)
749			set_curpos(sc, &p->pos);
750		bt459_set_curpos(sc);
751	}
752
753	sc->sc_changed = 0;
754	if (v & WSDISPLAY_CURSOR_DOCUR) {
755		sc->sc_curenb = p->enable;
756		sc->sc_changed |= DATA_ENB_CHANGED;
757	}
758	if (v & WSDISPLAY_CURSOR_DOCMAP) {
759		copyin(p->cmap.red, &cc->cc_color[index], count);
760		copyin(p->cmap.green, &cc->cc_color[index + 2], count);
761		copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
762		sc->sc_changed |= DATA_CURCMAP_CHANGED;
763	}
764	if (v & WSDISPLAY_CURSOR_DOSHAPE) {
765		cc->cc_size = p->size;
766		memset(cc->cc_image, 0, sizeof cc->cc_image);
767		copyin(p->image, cc->cc_image, icount);
768		copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
769		sc->sc_changed |= DATA_CURSHAPE_CHANGED;
770	}
771
772	return (0);
773#undef cc
774}
775
776static int
777get_cursor(sc, p)
778	struct cfb_softc *sc;
779	struct wsdisplay_cursor *p;
780{
781	return (ENOTTY); /* XXX */
782}
783
784static void
785set_curpos(sc, curpos)
786	struct cfb_softc *sc;
787	struct wsdisplay_curpos *curpos;
788{
789	struct fb_devconfig *dc = sc->sc_dc;
790	int x = curpos->x, y = curpos->y;
791
792	if (y < 0)
793		y = 0;
794	else if (y > dc->dc_ht)
795		y = dc->dc_ht;
796	if (x < 0)
797		x = 0;
798	else if (x > dc->dc_wid)
799		x = dc->dc_wid;
800	sc->sc_cursor.cc_pos.x = x;
801	sc->sc_cursor.cc_pos.y = y;
802}
803
804void
805bt459_set_curpos(sc)
806	struct cfb_softc *sc;
807{
808	caddr_t cfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
809	struct bt459reg *vdac = (void *)(cfbbase + CX_BT459_OFFSET);
810	int x, y, s;
811
812	x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
813	y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
814
815	x += sc->sc_cursor.cc_magic.x;
816	y += sc->sc_cursor.cc_magic.y;
817
818	s = spltty();
819
820	SELECT(vdac, BT459_IREG_CURSOR_X_LOW);
821	REG(vdac, bt_reg) = x;		tc_wmb();
822	REG(vdac, bt_reg) = x >> 8;	tc_wmb();
823	REG(vdac, bt_reg) = y;		tc_wmb();
824	REG(vdac, bt_reg) = y >> 8;	tc_wmb();
825
826	splx(s);
827}
828