xref: /netbsd-src/sys/arch/pmax/ibus/pm.c (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
1 /*	$NetBSD: pm.c,v 1.2 2003/12/13 23:04:38 ad Exp $	*/
2 
3 /*-
4  * Copyright (c) 2002, 2003 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Andrew Doran.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * Copyright (c) 1998, 1999 Tohru Nishimura.  All rights reserved.
41  *
42  * Redistribution and use in source and binary forms, with or without
43  * modification, are permitted provided that the following conditions
44  * are met:
45  * 1. Redistributions of source code must retain the above copyright
46  *    notice, this list of conditions and the following disclaimer.
47  * 2. Redistributions in binary form must reproduce the above copyright
48  *    notice, this list of conditions and the following disclaimer in the
49  *    documentation and/or other materials provided with the distribution.
50  * 3. All advertising materials mentioning features or use of this software
51  *    must display the following acknowledgement:
52  *      This product includes software developed by Tohru Nishimura
53  *	for the NetBSD Project.
54  * 4. The name of the author may not be used to endorse or promote products
55  *    derived from this software without specific prior written permission
56  *
57  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
58  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
59  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
60  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
61  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
62  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
63  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
64  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
65  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
66  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
67  */
68 
69 #include <sys/cdefs.h>
70 __KERNEL_RCSID(0, "$NetBSD: pm.c,v 1.2 2003/12/13 23:04:38 ad Exp $");
71 
72 #include <sys/param.h>
73 #include <sys/systm.h>
74 #include <sys/kernel.h>
75 #include <sys/device.h>
76 #include <sys/buf.h>
77 #include <sys/ioctl.h>
78 
79 #include <machine/bus.h>
80 #include <machine/intr.h>
81 
82 #include <dev/wscons/wsconsio.h>
83 #include <dev/wscons/wsdisplayvar.h>
84 #include <dev/rasops/rasops.h>
85 #include <dev/wsfont/wsfont.h>
86 
87 #include <pmax/pmax/kn01.h>
88 
89 #include <pmax/ibus/ibusvar.h>
90 #include <pmax/ibus/pmreg.h>
91 
92 #include <uvm/uvm_extern.h>
93 
94 #define	CURSOR_MAX_SIZE	16
95 
96 struct hwcmap256 {
97 	uint8_t r[256];
98 	uint8_t g[256];
99 	uint8_t b[256];
100 };
101 
102 struct hwcursor64 {
103 	struct wsdisplay_curpos cc_pos;
104 	struct wsdisplay_curpos cc_hot;
105 	struct wsdisplay_curpos cc_size;
106 	uint8_t cc_color[6];
107 
108 	/*
109 	 * Max cursor size is 16x16.  The X server pads bitmap scanlines to
110 	 * a word boundary.  We take the easy route and waste some space.
111 	 */
112 	u_short cc_image[32 + 32];
113 };
114 
115 struct pm_softc {
116 	struct device		sc_dev;
117 	size_t			sc_cmap_size;
118 	size_t			sc_fb_size;
119 	int			sc_type;
120 	int			sc_blanked;
121 	int			sc_curenb;
122 	int			sc_changed;
123 	int			sc_nscreens;
124 	struct hwcursor64	sc_cursor;
125 	struct hwcmap256	sc_cmap;
126 };
127 #define	WSDISPLAY_CMAP_DOLUT	0x20
128 
129 int	pm_match(struct device *, struct cfdata *, void *);
130 void	pm_attach(struct device *, struct device *, void *);
131 int	pm_ioctl(void *, u_long, caddr_t, int, struct proc *);
132 paddr_t	pm_mmap(void *, off_t, int);
133 int	pm_alloc_screen(void *, const struct wsscreen_descr *,
134 				void **, int *, int *, long *);
135 void	pm_free_screen(void *, void *);
136 int	pm_show_screen(void *, void *, int,
137 			       void (*) (void *, int, int), void *);
138 void	pm_cursor_off(void);
139 void	pm_cursor_on(struct pm_softc *);
140 int	pm_cnattach(void);
141 void	pm_common_init(void);
142 int	pm_flush(struct pm_softc *);
143 int	pm_get_cmap(struct pm_softc *, struct wsdisplay_cmap *);
144 int	pm_set_cmap(struct pm_softc *, struct wsdisplay_cmap *);
145 int	pm_set_cursor(struct pm_softc *, struct wsdisplay_cursor *);
146 int	pm_get_cursor(struct pm_softc *, struct wsdisplay_cursor *);
147 void	pm_set_curpos(struct pm_softc *, struct wsdisplay_curpos *);
148 void	pm_init_cmap(struct pm_softc *);
149 
150 CFATTACH_DECL(pm, sizeof(struct pm_softc),
151    pm_match, pm_attach, NULL, NULL);
152 
153 struct rasops_info pm_ri;
154 
155 struct wsscreen_descr pm_stdscreen = {
156 	"std", 0, 0,
157 	0, /* textops */
158 	0, 0,
159 	WSSCREEN_REVERSE
160 };
161 
162 const struct wsscreen_descr *_pm_scrlist[] = {
163 	&pm_stdscreen,
164 };
165 
166 const struct wsscreen_list pm_screenlist = {
167 	sizeof(_pm_scrlist) / sizeof(struct wsscreen_descr *), _pm_scrlist
168 };
169 
170 const struct wsdisplay_accessops pm_accessops = {
171 	pm_ioctl,
172 	pm_mmap,
173 	pm_alloc_screen,
174 	pm_free_screen,
175 	pm_show_screen,
176 	0 /* load_font */
177 };
178 
179 u_int	pm_creg;
180 
181 int
182 pm_match(struct device *parent, struct cfdata *match, void *aux)
183 {
184 	struct ibus_attach_args *ia;
185 	caddr_t pmaddr;
186 
187 	ia = aux;
188 	pmaddr = (caddr_t)ia->ia_addr;
189 
190 	if (strcmp(ia->ia_name, "pm") != 0)
191 		return (0);
192 
193 	if (badaddr(pmaddr, 4))
194 		return (0);
195 
196 	return (1);
197 }
198 
199 void
200 pm_attach(struct device *parent, struct device *self, void *aux)
201 {
202 	struct pm_softc *sc;
203 	struct rasops_info *ri;
204 	struct wsemuldisplaydev_attach_args waa;
205 	int console;
206 
207 	sc = (struct pm_softc *)self;
208 	ri = &pm_ri;
209 	console = (ri->ri_bits != NULL);
210 
211 	if (console)
212 		sc->sc_nscreens = 1;
213 	else
214 		pm_common_init();
215 
216 	printf(": %dx%d, %dbpp\n", ri->ri_width, ri->ri_height, ri->ri_depth);
217 
218 	pm_init_cmap(sc);
219 
220 	sc->sc_blanked = 0;
221 	sc->sc_curenb = 0;
222 
223 	waa.console = console;
224 	waa.scrdata = &pm_screenlist;
225 	waa.accessops = &pm_accessops;
226 	waa.accesscookie = sc;
227 
228 	config_found(self, &waa, wsemuldisplaydevprint);
229 }
230 
231 void
232 pm_init_cmap(struct pm_softc *sc)
233 {
234 	struct hwcmap256 *cm;
235 	struct rasops_info *ri;
236 	const uint8_t *p;
237 	int index;
238 
239 	cm = &sc->sc_cmap;
240 	ri = &pm_ri;
241 
242 	if (ri->ri_depth == 8) {
243 		p = rasops_cmap;
244 		for (index = 0; index < 256; index++, p += 3) {
245 			cm->r[index] = p[0];
246 			cm->g[index] = p[1];
247 			cm->b[index] = p[2];
248 		}
249 
250 		sc->sc_type = WSDISPLAY_TYPE_PM_COLOR;
251 		sc->sc_cmap_size = 256;
252 		sc->sc_fb_size = 0x100000;
253 	} else {
254 		cm->r[0] = 0x00;
255 		cm->g[0] = 0x00;
256 		cm->b[0] = 0x00;
257 
258 		cm->r[1] = 0x00;
259 		cm->g[1] = 0xff;
260 		cm->b[1] = 0x00;
261 
262 		sc->sc_type = WSDISPLAY_TYPE_PM_MONO;
263 		sc->sc_cmap_size = 2;
264 		sc->sc_fb_size = 0x40000;
265 	}
266 }
267 
268 void
269 pm_common_init(void)
270 {
271 	struct rasops_info *ri;
272 	int cookie, bior, i;
273 	PCCRegs *pcc;
274 	VDACRegs *vdac;
275 	uint16_t kn01csr;
276 
277 	kn01csr = *(volatile uint16_t *)MIPS_PHYS_TO_KSEG1(KN01_SYS_CSR);
278 	pcc = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_PCC);
279 	vdac = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_VDAC);
280 	ri = &pm_ri;
281 
282 	ri->ri_flg = RI_CENTER;
283 	ri->ri_depth = ((kn01csr & KN01_CSR_MONO) != 0 ? 1 : 8);
284 	ri->ri_width = 1024;
285 	ri->ri_height = 864;
286 	ri->ri_stride = (ri->ri_depth == 8 ? 1024 : 2048 / 8);
287 	ri->ri_bits = (void *)MIPS_PHYS_TO_KSEG1(KN01_PHYS_FBUF_START);
288 
289 	/*
290 	 * Clear the screen.
291 	 */
292 	memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
293 
294 	/*
295 	 * Get a font to use.
296 	 */
297 	bior = (ri->ri_depth == 8 ? WSDISPLAY_FONTORDER_L2R :
298 	    WSDISPLAY_FONTORDER_R2L);
299 
300 	wsfont_init();
301 	if (ri->ri_depth == 8)
302 		cookie = wsfont_find(NULL, 12, 0, 0, bior,
303 		    WSDISPLAY_FONTORDER_L2R);
304 	else
305 		cookie = wsfont_find(NULL, 8, 0, 0, bior,
306 		    WSDISPLAY_FONTORDER_L2R);
307 	if (cookie <= 0)
308 		cookie = wsfont_find(NULL, 0, 0, 0, bior,
309 		    WSDISPLAY_FONTORDER_L2R);
310 	if (cookie <= 0) {
311 		printf("pm: font table is empty\n");
312 		return;
313 	}
314 
315 	if (wsfont_lock(cookie, &ri->ri_font)) {
316 		printf("pm: couldn't lock font\n");
317 		return;
318 	}
319 	ri->ri_wsfcookie = cookie;
320 
321 	/*
322 	 * Set up the raster operations set.
323 	 */
324 	rasops_init(ri, 1000, 1000);
325 
326 	pm_stdscreen.nrows = ri->ri_rows;
327 	pm_stdscreen.ncols = ri->ri_cols;
328 	pm_stdscreen.textops = &ri->ri_ops;
329 	pm_stdscreen.capabilities = ri->ri_caps;
330 
331 	/*
332 	 * Initalize the VDAC.
333 	 */
334 	*(uint8_t *)MIPS_PHYS_TO_KSEG1(KN01_PHYS_COLMASK_START) = 0xff;
335 	wbflush();
336 
337 	vdac->overWA = 0x04; wbflush();
338 	vdac->over = 0x00; wbflush();
339 	vdac->over = 0x00; wbflush();
340 	vdac->over = 0x00; wbflush();
341 	vdac->overWA = 0x08; wbflush();
342 	vdac->over = 0x00; wbflush();
343 	vdac->over = 0x00; wbflush();
344 	vdac->over = 0x7f; wbflush();
345 	vdac->overWA = 0x0c; wbflush();
346 	vdac->over = 0xff; wbflush();
347 	vdac->over = 0xff; wbflush();
348 	vdac->over = 0xff; wbflush();
349 
350 	/*
351 	 * Set in the initial colormap.
352 	 */
353 	if (ri->ri_depth == 8) {
354 		vdac->mapWA = 0;
355 		wbflush();
356 
357 		for (i = 0; i < 256 * 3; i += 3) {
358 			vdac->map = rasops_cmap[i];
359 			wbflush();
360 			vdac->map = rasops_cmap[i + 1];
361 			wbflush();
362 			vdac->map = rasops_cmap[i + 2];
363 			wbflush();
364 		}
365 	} else {
366 		vdac->mapWA = 0;
367 		wbflush();
368 
369 		for (i = 0; i < 256; i++) {
370 			vdac->map = 0x00;
371 			wbflush();
372 			vdac->map = (i < 128 ? 0x00 : 0xff);
373 			wbflush();
374 			vdac->map = 0x00;
375 			wbflush();
376 		}
377 	}
378 
379 	/*
380 	 * Turn off the hardware cursor sprite for text mode.
381 	 */
382 	pcc->cmdr = PCC_FOPB | PCC_VBHI;
383 	wbflush();
384 	pm_creg = 0;
385 	pm_cursor_off();
386 }
387 
388 void
389 pm_cursor_off(void)
390 {
391 	PCCRegs *pcc;
392 
393 	pcc = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_PCC);
394 	pcc->cmdr = (pm_creg &= ~(PCC_ENPA | PCC_ENPB));
395 	wbflush();
396 }
397 
398 void
399 pm_cursor_on(struct pm_softc *sc)
400 {
401 	PCCRegs *pcc;
402 
403 	if (sc->sc_curenb) {
404 		pcc = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_PCC);
405 		pcc->cmdr = (pm_creg |= (PCC_ENPA | PCC_ENPB));
406 		wbflush();
407 	}
408 }
409 
410 int
411 pm_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
412 {
413 	struct pm_softc *sc;
414 	struct rasops_info *ri;
415 	int turnoff, rv, i;
416 	PCCRegs *pcc;
417 	VDACRegs *vdac;
418 
419 	sc = v;
420 	ri = &pm_ri;
421 	rv = 0;
422 	pcc = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_PCC);
423 	vdac = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_VDAC);
424 
425 	switch (cmd) {
426 	case WSDISPLAYIO_GTYPE:
427 		*(u_int *)data = sc->sc_type;
428 		break;
429 
430 	case WSDISPLAYIO_SMODE:
431 		if (*(u_int *)data == WSDISPLAYIO_MODE_EMUL) {
432 			pm_cursor_off();
433 			pm_init_cmap(sc);
434 			memset(ri->ri_bits, 0, ri->ri_stride * ri->ri_height);
435 			sc->sc_curenb = 0;
436 			sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
437 		}
438 		break;
439 
440 	case WSDISPLAYIO_GINFO:
441 #define	wsd_fbip ((struct wsdisplay_fbinfo *)data)
442 		wsd_fbip->height = ri->ri_height;
443 		wsd_fbip->width = ri->ri_width;
444 		wsd_fbip->depth = ri->ri_depth;
445 		wsd_fbip->cmsize = sc->sc_cmap_size;
446 #undef fbt
447 		break;
448 
449 	case WSDISPLAYIO_GETCMAP:
450 		rv = pm_get_cmap(sc, (struct wsdisplay_cmap *)data);
451 		break;
452 
453 	case WSDISPLAYIO_PUTCMAP:
454 		rv = pm_set_cmap(sc, (struct wsdisplay_cmap *)data);
455 		break;
456 
457 	case WSDISPLAYIO_SVIDEO:
458 		turnoff = (*(int *)data == WSDISPLAYIO_VIDEO_OFF);
459 		if ((sc->sc_blanked == 0) ^ turnoff) {
460 			sc->sc_blanked = turnoff;
461 			if (turnoff == 0) {
462 				pcc->cmdr =
463 				    (pm_creg &= ~(PCC_FOPA | PCC_FOPB));
464 				wbflush();
465 				pm_cursor_on(sc);
466 				sc->sc_changed |= WSDISPLAY_CURSOR_DOCMAP;
467 			} else {
468 				pm_cursor_off();
469 				pcc->cmdr =
470 				    (pm_creg |= (PCC_FOPA | PCC_FOPB));
471 				wbflush();
472 				vdac->overWA = 0x0c;
473 				wbflush();
474 				for (i = 0; i < 3; i++) {
475 					vdac->over = 0;
476 					wbflush();
477 				}
478 			}
479 		}
480 		break;
481 
482 	case WSDISPLAYIO_GVIDEO:
483 		*(u_int *)data = (sc->sc_blanked ?
484 		    WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON);
485 		break;
486 
487 	case WSDISPLAYIO_GCURPOS:
488 		*(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
489 		break;
490 
491 	case WSDISPLAYIO_SCURPOS:
492 		pm_set_curpos(sc, (struct wsdisplay_curpos *)data);
493 		sc->sc_changed |= WSDISPLAY_CURSOR_DOPOS;
494 		break;
495 
496 	case WSDISPLAYIO_GCURMAX:
497 		((struct wsdisplay_curpos *)data)->x =
498 		((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
499 		break;
500 
501 	case WSDISPLAYIO_GCURSOR:
502 		rv = pm_get_cursor(sc, (struct wsdisplay_cursor *)data);
503 		break;
504 
505 	case WSDISPLAYIO_SCURSOR:
506 		rv = pm_set_cursor(sc, (struct wsdisplay_cursor *)data);
507 		break;
508 
509 	default:
510 		rv = ENOTTY;
511 		break;
512 	}
513 
514 	pm_flush(sc);
515 	return (rv);
516 }
517 
518 paddr_t
519 pm_mmap(void *v, off_t offset, int prot)
520 {
521 	struct pm_softc *sc;
522 
523 	sc = v;
524 
525 	if (offset >= sc->sc_fb_size || offset < 0)
526 		return (-1);
527 
528 	return (mips_btop(KN01_PHYS_FBUF_START + offset));
529 }
530 
531 int
532 pm_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
533 		int *curxp, int *curyp, long *attrp)
534 {
535 	struct pm_softc *sc;
536 	struct rasops_info *ri;
537 	long defattr;
538 
539 	sc = v;
540 	ri = &pm_ri;
541 
542 	if (sc->sc_nscreens > 0)
543 		return (ENOMEM);
544 
545 	*cookiep = ri;	 /* one and only for now */
546 	*curxp = 0;
547 	*curyp = 0;
548 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
549 	*attrp = defattr;
550 	sc->sc_nscreens++;
551 	return (0);
552 }
553 
554 void
555 pm_free_screen(void *v, void *cookie)
556 {
557 
558 	panic("pm_free_screen: console");
559 }
560 
561 int
562 pm_show_screen(void *v, void *cookie, int waitok,
563 	       void (*cb)(void *, int, int), void *cbarg)
564 {
565 
566 	return (0);
567 }
568 
569 /* EXPORT */ int
570 pm_cnattach(void)
571 {
572 	struct rasops_info *ri;
573 	long defattr;
574 
575 	ri = &pm_ri;
576 
577 	pm_common_init();
578 	(*ri->ri_ops.allocattr)(ri, 0, 0, 0, &defattr);
579 	wsdisplay_cnattach(&pm_stdscreen, ri, 0, 0, defattr);
580 	return (1);
581 }
582 
583 int
584 pm_flush(struct pm_softc *sc)
585 {
586 	VDACRegs *vdac;
587 	PCCRegs *pcc;
588 	uint8_t *cp;
589 	int v, i, x, y;
590 	u_short *p, *pe;
591 	struct hwcmap256 *cm;
592 	struct rasops_info *ri;
593 
594 	if (sc->sc_changed == 0)
595 		return (1);
596 
597 	vdac = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_VDAC);
598 	pcc = (void *)MIPS_PHYS_TO_KSEG1(KN01_SYS_PCC);
599 	ri = &pm_ri;
600 	v = sc->sc_changed;
601 
602 	if ((v & WSDISPLAY_CURSOR_DOCUR) != 0) {
603 		if (sc->sc_curenb)
604 			pm_cursor_on(sc);
605 		else
606 			pm_cursor_off();
607 	}
608 
609 	if ((v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) != 0) {
610 		x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
611 		y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
612 		pcc->xpos = x + PCC_X_OFFSET;
613 		pcc->ypos = y + PCC_Y_OFFSET;
614 		wbflush();
615 	}
616 	if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) {
617 		cp = sc->sc_cursor.cc_color;
618 
619 		vdac->overWA = 0x04;
620 		wbflush();
621 		for (i = 1; i < 6; i += 2) {
622 			vdac->over = cp[i];
623 			wbflush();
624 		}
625 
626 		vdac->overWA = 0x08;
627 		wbflush();
628 		vdac->over = 0x00;
629 		wbflush();
630 		vdac->over = 0x00;
631 		wbflush();
632 		vdac->over = 0x7f;
633 		wbflush();
634 
635 		vdac->overWA = 0x0c;
636 		wbflush();
637 		for (i = 0; i < 6; i += 2) {
638 			vdac->over = cp[i];
639 			wbflush();
640 		}
641 	}
642 	if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) {
643 		pcc->cmdr = (pm_creg | PCC_LODSA);
644 		wbflush();
645 
646 		p = sc->sc_cursor.cc_image;
647 		x = 0xffff >> (16 - sc->sc_cursor.cc_size.x);
648 		for (pe = p + 64; p < pe; p += 2) {
649 			pcc->memory = *p & x;
650 			wbflush();
651 		}
652 
653 		pcc->cmdr = (pm_creg &= ~PCC_LODSA);
654 		wbflush();
655 	}
656 
657 	if ((v & WSDISPLAY_CMAP_DOLUT) != 0) {
658 		cm = &sc->sc_cmap;
659 
660 		vdac->mapWA = 0;
661 		wbflush();
662 
663 		if (sc->sc_cmap_size == 2) {
664 			for (i = 0; i < 128; i++) {
665 				vdac->map = 0;
666 				wbflush();
667 				vdac->map = cm->g[0];
668 				wbflush();
669 				vdac->map = 0;
670 				wbflush();
671 			}
672 			for (; i < 256; i++) {
673 				vdac->map = 0;
674 				wbflush();
675 				vdac->map = cm->g[1];
676 				wbflush();
677 				vdac->map = 0;
678 				wbflush();
679 			}
680 		} else {
681 			for (i = 0; i < sc->sc_cmap_size; i++) {
682 				vdac->map = cm->r[i];
683 				wbflush();
684 				vdac->map = cm->g[i];
685 				wbflush();
686 				vdac->map = cm->b[i];
687 				wbflush();
688 			}
689 		}
690 	}
691 
692 	sc->sc_changed = 0;
693 	return (1);
694 }
695 
696 int
697 pm_get_cmap(struct pm_softc *sc, struct wsdisplay_cmap *p)
698 {
699 	u_int index, count;
700 	int rv;
701 
702 	index = p->index;
703 	count = p->count;
704 
705 	if (index >= sc->sc_cmap_size || (index + count) > sc->sc_cmap_size)
706 		return (EINVAL);
707 
708 	if ((rv = copyout(&sc->sc_cmap.r[index], p->red, count)) != 0)
709 		return (rv);
710 	if ((rv = copyout(&sc->sc_cmap.g[index], p->green, count)) != 0)
711 		return (rv);
712 	return (copyout(&sc->sc_cmap.b[index], p->blue, count));
713 }
714 
715 int
716 pm_set_cmap(struct pm_softc *sc, struct wsdisplay_cmap *p)
717 {
718 	u_int index, count;
719 	int rv;
720 
721 	index = p->index;
722 	count = p->count;
723 
724 	if (index >= sc->sc_cmap_size || (index + count) > sc->sc_cmap_size)
725 		return (EINVAL);
726 
727 	if ((rv = copyin(p->red, &sc->sc_cmap.r[index], count)) != 0)
728 		return (rv);
729 	if ((rv = copyin(p->green, &sc->sc_cmap.g[index], count)) != 0)
730 		return (rv);
731 	if ((rv = copyin(p->blue, &sc->sc_cmap.b[index], count)) != 0)
732 		return (rv);
733 	sc->sc_changed |= WSDISPLAY_CMAP_DOLUT;
734 	return (0);
735 }
736 
737 int
738 pm_set_cursor(struct pm_softc *sc, struct wsdisplay_cursor *p)
739 {
740 	u_int v, index, count;
741 	struct hwcursor64 *cc;
742 	int rv;
743 
744 	v = p->which;
745 	cc = &sc->sc_cursor;
746 
747 	if ((v & WSDISPLAY_CURSOR_DOCUR) != 0)
748 		sc->sc_curenb = p->enable;
749 	if ((v & WSDISPLAY_CURSOR_DOPOS) != 0)
750 		pm_set_curpos(sc, &p->pos);
751 	if ((v & WSDISPLAY_CURSOR_DOHOT) != 0)
752 		cc->cc_hot = p->hot;
753 	if ((v & WSDISPLAY_CURSOR_DOCMAP) != 0) {
754 		index = p->cmap.index;
755 		count = p->cmap.count;
756 		if (index >= 2 || (index + count) > 2)
757 			return (EINVAL);
758 
759 		rv = copyin(p->cmap.red, &cc->cc_color[index], count);
760 		if (rv != 0)
761 			return (rv);
762 		rv = copyin(p->cmap.green, &cc->cc_color[index + 2], count);
763 		if (rv != 0)
764 			return (rv);
765 		rv = copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
766 		if (rv != 0)
767 			return (rv);
768 	}
769 	if ((v & WSDISPLAY_CURSOR_DOSHAPE) != 0) {
770 		if (p->size.x > CURSOR_MAX_SIZE ||
771 		    p->size.y > CURSOR_MAX_SIZE)
772 			return (EINVAL);
773 
774 		cc->cc_size = p->size;
775 		memset(cc->cc_image, 0, sizeof(cc->cc_image));
776 		rv = copyin(p->image, cc->cc_image, p->size.y * 4);
777 		if (rv != 0)
778 			return (rv);
779 		rv = copyin(p->mask, cc->cc_image+32, p->size.y * 4);
780 		if (rv != 0)
781 			return (rv);
782 	}
783 
784 	sc->sc_changed |= v;
785 	return (0);
786 }
787 
788 int
789 pm_get_cursor(struct pm_softc *sc, struct wsdisplay_cursor *p)
790 {
791 
792 	return (ENOTTY); /* XXX */
793 }
794 
795 void
796 pm_set_curpos(struct pm_softc *sc, struct wsdisplay_curpos *curpos)
797 {
798 	struct rasops_info *ri;
799 	int x, y;
800 
801 	ri = &pm_ri;
802 	x = curpos->x;
803 	y = curpos->y;
804 
805 	if (y < 0)
806 		y = 0;
807 	else if (y > ri->ri_height)
808 		y = ri->ri_height;
809 	if (x < 0)
810 		x = 0;
811 	else if (x > ri->ri_width)
812 		x = ri->ri_width;
813 	sc->sc_cursor.cc_pos.x = x;
814 	sc->sc_cursor.cc_pos.y = y;
815 }
816