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