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