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