cfb.c revision 1.2 1 /* $NetBSD: cfb.c,v 1.2 1998/10/30 00:53:12 nisimura Exp $ */
2
3 /*
4 * Copyright (c) 1996, 1998 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.2 1998/10/30 00:53:12 nisimura 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 #include <machine/autoconf.h>
54
55 #include <dev/tc/tcvar.h>
56 #include <dev/ic/bt459reg.h>
57
58 #include "opt_uvm.h"
59 #if defined(UVM)
60 #include <uvm/uvm_extern.h>
61 #define useracc uvm_useracc
62 #endif
63
64 /* XXX BUS'IFYING XXX */
65
66 #if defined(__pmax__)
67 #define machine_btop(x) mips_btop(x)
68 #define MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG1_TO_PHYS(x)
69 #endif
70
71 #if defined(__alpha__) || defined(alpha)
72 /*
73 * Digital UNIX never supports PMAG-BA
74 */
75 #define machine_btop(x) alpha_btop(x)
76 #define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x)
77 #endif
78
79 /*
80 * N.B., Bt459 registers are 8bit width. Some of TC framebuffers have
81 * weird register layout such as each of 2nd and 3rd Bt459 registers
82 * is adjacent each other in a word, i.e.,
83 *
84 * struct bt459triplet {
85 * struct {
86 * u_int8_t u0;
87 * u_int8_t u1;
88 * u_int8_t u2;
89 * unsigned :8;
90 * } bt_lo;
91 * ...
92 *
93 * Although CX has single Bt459, 32bit R/W can be done w/o any trouble.
94 */
95 struct bt459reg {
96 u_int32_t bt_lo;
97 u_int32_t bt_hi;
98 u_int32_t bt_reg;
99 u_int32_t bt_cmap;
100 };
101
102 /* XXX XXX XXX */
103
104 struct fb_devconfig {
105 vaddr_t dc_vaddr; /* memory space virtual base address */
106 paddr_t dc_paddr; /* memory space physical base address */
107 vsize_t dc_size; /* size of slot memory */
108 int dc_wid; /* width of frame buffer */
109 int dc_ht; /* height of frame buffer */
110 int dc_depth; /* depth, bits per pixel */
111 int dc_rowbytes; /* bytes in a FB scan line */
112 vaddr_t dc_videobase; /* base of flat frame buffer */
113 struct raster dc_raster; /* raster description */
114 struct rcons dc_rcons; /* raster blitter control info */
115 int dc_blanked; /* currently has video disabled */
116 };
117
118 struct hwcmap {
119 #define CMAP_SIZE 256 /* 256 R/G/B entries */
120 u_int8_t r[CMAP_SIZE];
121 u_int8_t g[CMAP_SIZE];
122 u_int8_t b[CMAP_SIZE];
123 };
124
125 struct hwcursor {
126 struct wsdisplay_curpos cc_pos;
127 struct wsdisplay_curpos cc_hot;
128 struct wsdisplay_curpos cc_size;
129 #define CURSOR_MAX_SIZE 64
130 u_int8_t cc_color[6];
131 u_int64_t cc_image[64 + 64];
132 };
133
134 struct cfb_softc {
135 struct device sc_dev;
136 struct fb_devconfig *sc_dc; /* device configuration */
137 struct hwcmap sc_cmap; /* software copy of colormap */
138 struct hwcursor sc_cursor; /* software copy of cursor */
139 int sc_curenb; /* cursor sprite enabled */
140 int sc_changed; /* need update of colormap */
141 #define DATA_ENB_CHANGED 0x01 /* cursor enable changed */
142 #define DATA_CURCMAP_CHANGED 0x02 /* cursor colormap changed */
143 #define DATA_CURSHAPE_CHANGED 0x04 /* cursor size, image, mask changed */
144 #define DATA_CMAP_CHANGED 0x08 /* colormap changed */
145 #define DATA_ALL_CHANGED 0x0f
146 int nscreens;
147 };
148
149 int cfbmatch __P((struct device *, struct cfdata *, void *));
150 void cfbattach __P((struct device *, struct device *, void *));
151
152 struct cfattach cfb_ca = {
153 sizeof(struct cfb_softc), cfbmatch, cfbattach,
154 };
155
156 void cfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
157 struct fb_devconfig cfb_console_dc;
158 tc_addr_t cfb_consaddr;
159
160 struct wsdisplay_emulops cfb_emulops = {
161 rcons_cursor, /* could use hardware cursor; punt */
162 rcons_mapchar,
163 rcons_putchar,
164 rcons_copycols,
165 rcons_erasecols,
166 rcons_copyrows,
167 rcons_eraserows,
168 rcons_alloc_attr
169 };
170
171 struct wsscreen_descr cfb_stdscreen = {
172 "std", 0, 0,
173 &cfb_emulops,
174 0, 0,
175 0
176 };
177
178 const struct wsscreen_descr *_cfb_scrlist[] = {
179 &cfb_stdscreen,
180 };
181
182 struct wsscreen_list cfb_screenlist = {
183 sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist
184 };
185
186 int cfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
187 int cfbmmap __P((void *, off_t, int));
188
189 int cfb_alloc_screen __P((void *, const struct wsscreen_descr *,
190 void **, int *, int *, long *));
191 void cfb_free_screen __P((void *, void *));
192 void cfb_show_screen __P((void *, void *));
193 int cfb_load_font __P((void *, void *, int, int, int, void *));
194
195 struct wsdisplay_accessops cfb_accessops = {
196 cfbioctl,
197 cfbmmap,
198 cfb_alloc_screen,
199 cfb_free_screen,
200 cfb_show_screen,
201 cfb_load_font
202 };
203
204 int cfb_cnattach __P((tc_addr_t));
205 int cfbintr __P((void *));
206 void cfbinit __P((struct fb_devconfig *));
207
208 static int get_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
209 static int set_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
210 static int set_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
211 static int get_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
212 static void set_curpos __P((struct cfb_softc *, struct wsdisplay_curpos *));
213 static void bt459_set_curpos __P((struct cfb_softc *));
214
215 /* XXX XXX XXX */
216 #define BT459_SELECT(vdac, regno) do { \
217 vdac->bt_lo = (regno) & 0x00ff; \
218 vdac->bt_hi = ((regno)& 0xff00) >> 8; \
219 tc_wmb(); \
220 } while (0)
221 /* XXX XXX XXX */
222
223 #define CFB_FB_OFFSET 0x000000
224 #define CFB_FB_SIZE 0x100000
225 #define CFB_BT459_OFFSET 0x200000
226 #define CFB_OFFSET_IREQ 0x300000 /* Interrupt req. control */
227
228 int
229 cfbmatch(parent, match, aux)
230 struct device *parent;
231 struct cfdata *match;
232 void *aux;
233 {
234 struct tc_attach_args *ta = aux;
235
236 if (strncmp("PMAG-BA ", ta->ta_modname, TC_ROM_LLEN) != 0)
237 return (0);
238
239 return (1);
240 }
241
242 void
243 cfb_getdevconfig(dense_addr, dc)
244 tc_addr_t dense_addr;
245 struct fb_devconfig *dc;
246 {
247 struct raster *rap;
248 struct rcons *rcp;
249 int i;
250
251 dc->dc_vaddr = dense_addr;
252 dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr + CFB_FB_OFFSET);
253
254 dc->dc_wid = 1024;
255 dc->dc_ht = 864;
256 dc->dc_depth = 8;
257 dc->dc_rowbytes = 1024;
258 dc->dc_videobase = dc->dc_vaddr + CFB_FB_OFFSET;
259 dc->dc_blanked = 0;
260
261 /* initialize colormap and cursor resource */
262 cfbinit(dc);
263
264 /* clear the screen */
265 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
266 *(u_int32_t *)(dc->dc_videobase + i) = 0x0;
267
268 /* initialize the raster */
269 rap = &dc->dc_raster;
270 rap->width = dc->dc_wid;
271 rap->height = dc->dc_ht;
272 rap->depth = dc->dc_depth;
273 rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
274 rap->pixels = (u_int32_t *)dc->dc_videobase;
275
276 /* initialize the raster console blitter */
277 rcp = &dc->dc_rcons;
278 rcp->rc_sp = rap;
279 rcp->rc_crow = rcp->rc_ccol = -1;
280 rcp->rc_crowp = &rcp->rc_crow;
281 rcp->rc_ccolp = &rcp->rc_ccol;
282 rcons_init(rcp, 34, 80);
283
284 cfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
285 cfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
286 }
287
288 void
289 cfbattach(parent, self, aux)
290 struct device *parent, *self;
291 void *aux;
292 {
293 struct cfb_softc *sc = (struct cfb_softc *)self;
294 struct tc_attach_args *ta = aux;
295 struct wsemuldisplaydev_attach_args waa;
296 struct hwcmap *cm;
297 int console, i;
298
299 console = (ta->ta_addr == cfb_consaddr);
300 if (console) {
301 sc->sc_dc = &cfb_console_dc;
302 sc->nscreens = 1;
303 }
304 else {
305 sc->sc_dc = (struct fb_devconfig *)
306 malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
307 cfb_getdevconfig(ta->ta_addr, sc->sc_dc);
308 }
309 printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
310 sc->sc_dc->dc_depth);
311
312 cm = &sc->sc_cmap;
313 cm->r[0] = cm->g[0] = cm->b[0] = 0;
314 for (i = 1; i < CMAP_SIZE; i++) {
315 cm->r[i] = cm->g[i] = cm->b[i] = 0xff;
316 }
317
318 /* Establish an interrupt handler, and clear any pending interrupts */
319 tc_intr_establish(parent, ta->ta_cookie, TC_IPL_TTY, cfbintr, sc);
320 *(u_int8_t *)(sc->sc_dc->dc_vaddr + CFB_OFFSET_IREQ) = 0;
321
322 waa.console = console;
323 waa.scrdata = &cfb_screenlist;
324 waa.accessops = &cfb_accessops;
325 waa.accesscookie = sc;
326
327 config_found(self, &waa, wsemuldisplaydevprint);
328 }
329
330 int
331 cfbioctl(v, cmd, data, flag, p)
332 void *v;
333 u_long cmd;
334 caddr_t data;
335 int flag;
336 struct proc *p;
337 {
338 struct cfb_softc *sc = v;
339 struct fb_devconfig *dc = sc->sc_dc;
340 int turnoff;
341
342 switch (cmd) {
343 case WSDISPLAYIO_GTYPE:
344 *(u_int *)data = WSDISPLAY_TYPE_CFB;
345 return (0);
346
347 case WSDISPLAYIO_GINFO:
348 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
349 wsd_fbip->height = sc->sc_dc->dc_ht;
350 wsd_fbip->width = sc->sc_dc->dc_wid;
351 wsd_fbip->depth = sc->sc_dc->dc_depth;
352 wsd_fbip->cmsize = CMAP_SIZE;
353 #undef fbt
354 return (0);
355
356 case WSDISPLAYIO_GETCMAP:
357 return get_cmap(sc, (struct wsdisplay_cmap *)data);
358
359 case WSDISPLAYIO_PUTCMAP:
360 return set_cmap(sc, (struct wsdisplay_cmap *)data);
361
362 case WSDISPLAYIO_SVIDEO:
363 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
364 if ((dc->dc_blanked == 0) ^ turnoff) {
365 /* sc->sc_changed |= DATA_ALL_CHANGED; */
366 dc->dc_blanked = turnoff;
367 }
368 return (0);
369
370 case WSDISPLAYIO_GVIDEO:
371 *(u_int *)data = dc->dc_blanked ?
372 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
373 return (0);
374
375 case WSDISPLAYIO_GCURPOS:
376 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
377 return (0);
378
379 case WSDISPLAYIO_SCURPOS:
380 set_curpos(sc, (struct wsdisplay_curpos *)data);
381 bt459_set_curpos(sc);
382 return (0);
383
384 case WSDISPLAYIO_GCURMAX:
385 ((struct wsdisplay_curpos *)data)->x =
386 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
387 return (0);
388
389 case WSDISPLAYIO_GCURSOR:
390 return get_cursor(sc, (struct wsdisplay_cursor *)data);
391
392 case WSDISPLAYIO_SCURSOR:
393 return set_cursor(sc, (struct wsdisplay_cursor *)data);
394 }
395 return ENOTTY;
396 }
397
398 int
399 cfbmmap(v, offset, prot)
400 void *v;
401 off_t offset;
402 int prot;
403 {
404 struct cfb_softc *sc = v;
405
406 if (offset > CFB_FB_SIZE)
407 return (-1);
408 return machine_btop(sc->sc_dc->dc_paddr + offset);
409 }
410
411 int
412 cfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
413 void *v;
414 const struct wsscreen_descr *type;
415 void **cookiep;
416 int *curxp, *curyp;
417 long *attrp;
418 {
419 struct cfb_softc *sc = v;
420 long defattr;
421
422 if (sc->nscreens > 0)
423 return (ENOMEM);
424
425 *cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
426 *curxp = 0;
427 *curyp = 0;
428 rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
429 *attrp = defattr;
430 sc->nscreens++;
431 return (0);
432 }
433
434 void
435 cfb_free_screen(v, cookie)
436 void *v;
437 void *cookie;
438 {
439 struct cfb_softc *sc = v;
440
441 if (sc->sc_dc == &cfb_console_dc)
442 panic("cfb_free_screen: console");
443
444 sc->nscreens--;
445 }
446
447 void
448 cfb_show_screen(v, cookie)
449 void *v;
450 void *cookie;
451 {
452 }
453
454 int
455 cfb_load_font(v, cookie, first, num, stride, data)
456 void *v;
457 void *cookie;
458 int first, num, stride;
459 void *data;
460 {
461 return (EINVAL);
462 }
463
464 int
465 cfb_cnattach(addr)
466 tc_addr_t addr;
467 {
468 struct fb_devconfig *dcp = &cfb_console_dc;
469 long defattr;
470
471 cfb_getdevconfig(addr, dcp);
472
473 rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
474
475 wsdisplay_cnattach(&cfb_stdscreen, &dcp->dc_rcons,
476 0, 0, defattr);
477 cfb_consaddr = addr;
478 return(0);
479 }
480
481
482 int
483 cfbintr(arg)
484 void *arg;
485 {
486 struct cfb_softc *sc = arg;
487 caddr_t cfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
488 struct bt459reg *vdac;
489 int v;
490
491 *(u_int8_t *)(cfbbase + CFB_OFFSET_IREQ) = 0;
492 if (sc->sc_changed == 0)
493 return (1);
494
495 vdac = (void *)(cfbbase + CFB_BT459_OFFSET);
496 v = sc->sc_changed;
497 sc->sc_changed = 0;
498 if (v & DATA_ENB_CHANGED) {
499 BT459_SELECT(vdac, BT459_REG_CCR);
500 vdac->bt_reg = (sc->sc_curenb) ? 0xc0 : 0x00;
501 }
502 if (v & DATA_CURCMAP_CHANGED) {
503 u_int8_t *cp = sc->sc_cursor.cc_color;
504
505 BT459_SELECT(vdac, BT459_REG_CCOLOR_2);
506 vdac->bt_cmap = cp[1]; tc_wmb();
507 vdac->bt_cmap = cp[3]; tc_wmb();
508 vdac->bt_cmap = cp[5]; tc_wmb();
509
510 BT459_SELECT(vdac, BT459_REG_CCOLOR_3);
511 vdac->bt_cmap = cp[0]; tc_wmb();
512 vdac->bt_cmap = cp[2]; tc_wmb();
513 vdac->bt_cmap = cp[4]; tc_wmb();
514 }
515 if (v & DATA_CURSHAPE_CHANGED) {
516 u_int8_t *bp;
517 int i;
518
519 bp = (u_int8_t *)&sc->sc_cursor.cc_image;
520 BT459_SELECT(vdac, BT459_REG_CRAM_BASE);
521 for (i = 0; i < sizeof(sc->sc_cursor.cc_image); i++) {
522 vdac->bt_reg = *bp++;
523 tc_wmb();
524 }
525 }
526 if (v & DATA_CMAP_CHANGED) {
527 struct hwcmap *cm = &sc->sc_cmap;
528 int index;
529
530 BT459_SELECT(vdac, 0);
531 for (index = 0; index < CMAP_SIZE; index++) {
532 vdac->bt_cmap = cm->r[index];
533 vdac->bt_cmap = cm->g[index];
534 vdac->bt_cmap = cm->b[index];
535 }
536 }
537 return (1);
538 }
539
540 void
541 cfbinit(dc)
542 struct fb_devconfig *dc;
543 {
544 caddr_t cfbbase = (caddr_t)dc->dc_vaddr;
545 struct bt459reg *vdac = (void *)(cfbbase + CFB_BT459_OFFSET);
546 int i;
547
548 BT459_SELECT(vdac, 0);
549 vdac->bt_cmap = 0; tc_wmb();
550 vdac->bt_cmap = 0; tc_wmb();
551 vdac->bt_cmap = 0; tc_wmb();
552 for (i = 1; i < CMAP_SIZE; i++) {
553 vdac->bt_cmap = 0xff; tc_wmb();
554 vdac->bt_cmap = 0xff; tc_wmb();
555 vdac->bt_cmap = 0xff; tc_wmb();
556 }
557
558 BT459_SELECT(vdac, BT459_REG_COMMAND_0);
559 vdac->bt_reg = 0x40; /* CMD0 */ tc_wmb();
560 vdac->bt_reg = 0x0; /* CMD1 */ tc_wmb();
561 vdac->bt_reg = 0xc0; /* CMD2 */ tc_wmb();
562 vdac->bt_reg = 0xff; /* PRM */ tc_wmb();
563 vdac->bt_reg = 0; /* 205 */ tc_wmb();
564 vdac->bt_reg = 0x0; /* PBM */ tc_wmb();
565 vdac->bt_reg = 0; /* 207 */ tc_wmb();
566 vdac->bt_reg = 0x0; /* ORM */ tc_wmb();
567 vdac->bt_reg = 0x0; /* OBM */ tc_wmb();
568 vdac->bt_reg = 0x0; /* ILV */ tc_wmb();
569 vdac->bt_reg = 0x0; /* TEST */ tc_wmb();
570
571 BT459_SELECT(vdac, BT459_REG_CCR);
572 vdac->bt_reg = 0x0; tc_wmb();
573 vdac->bt_reg = 0x0; tc_wmb();
574 vdac->bt_reg = 0x0; tc_wmb();
575 vdac->bt_reg = 0x0; tc_wmb();
576 vdac->bt_reg = 0x0; tc_wmb();
577 vdac->bt_reg = 0x0; tc_wmb();
578 vdac->bt_reg = 0x0; tc_wmb();
579 vdac->bt_reg = 0x0; tc_wmb();
580 vdac->bt_reg = 0x0; tc_wmb();
581 vdac->bt_reg = 0x0; tc_wmb();
582 vdac->bt_reg = 0x0; tc_wmb();
583 vdac->bt_reg = 0x0; tc_wmb();
584 vdac->bt_reg = 0x0; tc_wmb();
585 }
586
587 static int
588 get_cmap(sc, p)
589 struct cfb_softc *sc;
590 struct wsdisplay_cmap *p;
591 {
592 u_int index = p->index, count = p->count;
593
594 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
595 return (EINVAL);
596
597 if (!useracc(p->red, count, B_WRITE) ||
598 !useracc(p->green, count, B_WRITE) ||
599 !useracc(p->blue, count, B_WRITE))
600 return (EFAULT);
601
602 copyout(&sc->sc_cmap.r[index], p->red, count);
603 copyout(&sc->sc_cmap.g[index], p->green, count);
604 copyout(&sc->sc_cmap.b[index], p->blue, count);
605
606 return (0);
607 }
608
609 static int
610 set_cmap(sc, p)
611 struct cfb_softc *sc;
612 struct wsdisplay_cmap *p;
613 {
614 u_int index = p->index, count = p->count;
615
616 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
617 return (EINVAL);
618
619 if (!useracc(p->red, count, B_READ) ||
620 !useracc(p->green, count, B_READ) ||
621 !useracc(p->blue, count, B_READ))
622 return (EFAULT);
623
624 copyin(p->red, &sc->sc_cmap.r[index], count);
625 copyin(p->green, &sc->sc_cmap.g[index], count);
626 copyin(p->blue, &sc->sc_cmap.b[index], count);
627
628 sc->sc_changed |= DATA_CMAP_CHANGED;
629
630 return (0);
631 }
632
633 static int
634 set_cursor(sc, p)
635 struct cfb_softc *sc;
636 struct wsdisplay_cursor *p;
637 {
638 #define cc (&sc->sc_cursor)
639 int v, index, count;
640
641 v = p->which;
642 if (v & WSDISPLAY_CURSOR_DOCMAP) {
643 index = p->cmap.index;
644 count = p->cmap.count;
645 if (index >= 2 || (index + count) > 2)
646 return (EINVAL);
647 if (!useracc(p->cmap.red, count, B_READ) ||
648 !useracc(p->cmap.green, count, B_READ) ||
649 !useracc(p->cmap.blue, count, B_READ))
650 return (EFAULT);
651 }
652 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
653 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
654 return (EINVAL);
655 count = (CURSOR_MAX_SIZE / NBBY) * p->size.y;
656 if (!useracc(p->image, count, B_READ) ||
657 !useracc(p->mask, count, B_READ))
658 return (EFAULT);
659 }
660 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
661 if (v & WSDISPLAY_CURSOR_DOCUR)
662 cc->cc_hot = p->hot;
663 if (v & WSDISPLAY_CURSOR_DOPOS)
664 set_curpos(sc, &p->pos);
665 bt459_set_curpos(sc);
666 }
667
668 sc->sc_changed = 0;
669 if (v & WSDISPLAY_CURSOR_DOCUR) {
670 sc->sc_curenb = p->enable;
671 sc->sc_changed |= DATA_ENB_CHANGED;
672 }
673 if (v & WSDISPLAY_CURSOR_DOCMAP) {
674 count = p->cmap.count;
675 copyin(p->cmap.red, &cc->cc_color[index], count);
676 copyin(p->cmap.green, &cc->cc_color[index + 2], count);
677 copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
678 sc->sc_changed |= DATA_CURCMAP_CHANGED;
679 }
680 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
681 cc->cc_size = p->size;
682 memset(cc->cc_image, 0, sizeof cc->cc_image);
683 copyin(p->image, (caddr_t)cc->cc_image, count);
684 copyin(p->mask, (caddr_t)(cc->cc_image+CURSOR_MAX_SIZE), count);
685 sc->sc_changed |= DATA_CURSHAPE_CHANGED;
686 }
687
688 return (0);
689 #undef cc
690 }
691
692 static int
693 get_cursor(sc, p)
694 struct cfb_softc *sc;
695 struct wsdisplay_cursor *p;
696 {
697 return (ENOTTY); /* XXX */
698 }
699
700 static void
701 set_curpos(sc, curpos)
702 struct cfb_softc *sc;
703 struct wsdisplay_curpos *curpos;
704 {
705 struct fb_devconfig *dc = sc->sc_dc;
706 int x = curpos->x, y = curpos->y;
707
708 if (y < 0)
709 y = 0;
710 else if (y > dc->dc_ht - sc->sc_cursor.cc_size.y - 1)
711 y = dc->dc_ht - sc->sc_cursor.cc_size.y - 1;
712 if (x < 0)
713 x = 0;
714 else if (x > dc->dc_wid - sc->sc_cursor.cc_size.x - 1)
715 x = dc->dc_wid - sc->sc_cursor.cc_size.x - 1;
716 sc->sc_cursor.cc_pos.x = x;
717 sc->sc_cursor.cc_pos.y = y;
718 }
719
720 void
721 bt459_set_curpos(sc)
722 struct cfb_softc *sc;
723 {
724 caddr_t cfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
725 struct bt459reg *vdac = (void *)(cfbbase + CFB_BT459_OFFSET);
726 int x = 220, y = 35; /* magic offset of CX coordinate */
727 int s;
728
729 x += sc->sc_cursor.cc_pos.x;
730 y += sc->sc_cursor.cc_pos.y;
731
732 s = spltty();
733
734 BT459_SELECT(vdac, BT459_REG_CURSOR_X_LOW);
735 vdac->bt_reg = x; tc_wmb();
736 vdac->bt_reg = x >> 8; tc_wmb();
737 vdac->bt_reg = y; tc_wmb();
738 vdac->bt_reg = y >> 8; tc_wmb();
739
740 splx(s);
741 }
742