tfb.c revision 1.2 1 /* $NetBSD: tfb.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: tfb.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/bt463reg.h>
57 #include <dev/ic/bt431reg.h>
58
59 #include "opt_uvm.h"
60 #if defined(UVM)
61 #include <uvm/uvm_extern.h>
62 #define useracc uvm_useracc
63 #endif
64
65 /* XXX BUS'IFYING XXX */
66
67 #if defined(__pmax__)
68 #define machine_btop(x) mips_btop(x)
69 #define MACHINE_KSEG0_TO_PHYS(x) MIPS_KSEG0_TO_PHYS(x)
70
71 struct bt463reg {
72 u_int8_t bt_lo;
73 unsigned : 24;
74 u_int8_t bt_hi;
75 unsigned : 24;
76 u_int8_t bt_reg;
77 unsigned : 24;
78 u_int8_t bt_cmap;
79 };
80
81 /* it's really painful to manipulate 'twined' registers... */
82 struct bt431reg {
83 u_int16_t bt_lo;
84 unsigned : 16;
85 u_int16_t bt_hi;
86 unsigned : 16;
87 u_int16_t bt_ram;
88 unsigned : 16;
89 u_int16_t bt_ctl;
90 };
91 #endif
92
93 #if defined(__alpha__) || defined(alpha)
94 #define machine_btop(x) alpha_btop(x)
95 #define MACHINE_KSEG0_TO_PHYS(x) ALPHA_K0SEG_TO_PHYS(x)
96
97 struct bt463reg {
98 u_int32_t bt_lo;
99 u_int32_t bt_hi;
100 u_int32_t bt_reg;
101 u_int32_t bt_cmap;
102 };
103
104 /* it's really painful to manipulate 'twined' registers... */
105 struct bt431reg {
106 u_int32_t bt_lo;
107 u_int32_t bt_hi;
108 u_int32_t bt_ram;
109 u_int32_t bt_ctl;
110 };
111 #endif
112
113 /* XXX XXX XXX */
114
115 struct fb_devconfig {
116 vaddr_t dc_vaddr; /* memory space virtual base address */
117 paddr_t dc_paddr; /* memory space physical base address */
118 vsize_t dc_size; /* size of slot memory */
119 int dc_wid; /* width of frame buffer */
120 int dc_ht; /* height of frame buffer */
121 int dc_depth; /* depth, bits per pixel */
122 int dc_rowbytes; /* bytes in a FB scan line */
123 vaddr_t dc_videobase; /* base of flat frame buffer */
124 struct raster dc_raster; /* raster description */
125 struct rcons dc_rcons; /* raster blitter control info */
126 int dc_blanked; /* currently has video disabled */
127 };
128
129 struct hwcmap {
130 #define CMAP_SIZE 256 /* R/G/B entries */
131 u_int8_t r[CMAP_SIZE];
132 u_int8_t g[CMAP_SIZE];
133 u_int8_t b[CMAP_SIZE];
134 };
135
136 struct hwcursor {
137 struct wsdisplay_curpos cc_pos;
138 struct wsdisplay_curpos cc_hot;
139 struct wsdisplay_curpos cc_size;
140 #define CURSOR_MAX_SIZE 64
141 u_int8_t cc_color[6];
142 u_int64_t cc_image[64 + 64];
143 };
144
145 struct tfb_softc {
146 struct device sc_dev;
147 struct fb_devconfig *sc_dc; /* device configuration */
148 struct hwcmap sc_cmap; /* software copy of colormap */
149 struct hwcursor sc_cursor; /* software copy of cursor */
150 int sc_curenb; /* cursor sprite enabled */
151 int sc_changed; /* need update of colormap */
152 #define DATA_ENB_CHANGED 0x01 /* cursor enable changed */
153 #define DATA_CURCMAP_CHANGED 0x02 /* cursor colormap changed */
154 #define DATA_CURSHAPE_CHANGED 0x04 /* cursor size, image, mask changed */
155 #define DATA_CMAP_CHANGED 0x08 /* colormap changed */
156 #define DATA_ALL_CHANGED 0x0f
157 int nscreens;
158 };
159
160 int tfbmatch __P((struct device *, struct cfdata *, void *));
161 void tfbattach __P((struct device *, struct device *, void *));
162
163 struct cfattach tfb_ca = {
164 sizeof(struct tfb_softc), tfbmatch, tfbattach,
165 };
166
167 void tfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
168 struct fb_devconfig tfb_console_dc;
169 tc_addr_t tfb_consaddr;
170
171 struct wsdisplay_emulops tfb_emulops = {
172 rcons_cursor, /* could use hardware cursor; punt */
173 rcons_mapchar,
174 rcons_putchar,
175 rcons_copycols,
176 rcons_erasecols,
177 rcons_copyrows,
178 rcons_eraserows,
179 rcons_alloc_attr
180 };
181
182 struct wsscreen_descr tfb_stdscreen = {
183 "std", 0, 0,
184 &tfb_emulops,
185 0, 0,
186 0
187 };
188
189 const struct wsscreen_descr *_tfb_scrlist[] = {
190 &tfb_stdscreen,
191 };
192
193 struct wsscreen_list tfb_screenlist = {
194 sizeof(_tfb_scrlist) / sizeof(struct wsscreen_descr *), _tfb_scrlist
195 };
196
197 int tfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
198 int tfbmmap __P((void *, off_t, int));
199
200 int tfb_alloc_screen __P((void *, const struct wsscreen_descr *,
201 void **, int *, int *, long *));
202 void tfb_free_screen __P((void *, void *));
203 void tfb_show_screen __P((void *, void *));
204 int tfb_load_font __P((void *, void *, int, int, int, void *));
205
206 struct wsdisplay_accessops tfb_accessops = {
207 tfbioctl,
208 tfbmmap,
209 tfb_alloc_screen,
210 tfb_free_screen,
211 tfb_show_screen,
212 tfb_load_font
213 };
214
215 int tfb_cnattach __P((tc_addr_t));
216 int tfbintr __P((void *));
217 void tfbinit __P((struct fb_devconfig *));
218
219 static int get_cmap __P((struct tfb_softc *, struct wsdisplay_cmap *));
220 static int set_cmap __P((struct tfb_softc *, struct wsdisplay_cmap *));
221 static int set_cursor __P((struct tfb_softc *, struct wsdisplay_cursor *));
222 static int get_cursor __P((struct tfb_softc *, struct wsdisplay_cursor *));
223 static void set_curpos __P((struct tfb_softc *, struct wsdisplay_curpos *));
224 static void bt431_set_curpos __P((struct tfb_softc *));
225
226 #define TWIN_LO(x) (twin = (x) & 0x00ff, twin << 8 | twin)
227 #define TWIN_HI(x) (twin = (x) & 0xff00, twin | twin >> 8)
228
229 /* XXX XXX XXX */
230 #define BT431_SELECT(curs, regno) do { \
231 u_int16_t twin; \
232 curs->bt_lo = TWIN_LO(regno); \
233 curs->bt_hi = TWIN_HI(regno); \
234 tc_wmb(); \
235 } while (0)
236
237 #define BT463_SELECT(vdac, regno) do { \
238 vdac->bt_lo = (regno) & 0x00ff; \
239 vdac->bt_hi = ((regno)& 0xff00) >> 8; \
240 tc_wmb(); \
241 } while (0)
242 /* XXX XXX XXX */
243
244 #define TX_BT463_OFFSET 0x040000
245 #define TX_BT431_OFFSET 0x040010
246 #define TX_CONTROL 0x040030
247 #define TX_MAP_REGISTER 0x040030
248 #define TX_PIP_OFFSET 0x0800c0
249 #define TX_SELECTION 0x100000
250 #define TX_8FB_OFFSET 0x200000
251 #define TX_8FB_SIZE 0x100000
252 #define TX_24FB_OFFSET 0x400000
253 #define TX_24FB_SIZE 0x400000
254 #define TX_VIDEO_ENABLE 0xa00000
255
256 #define TX_CTL_VIDEO_ON 0x80
257 #define TX_CTL_INT_ENA 0x40
258 #define TX_CTL_INT_PEND 0x20
259 #define TX_CTL_SEG_ENA 0x10
260 #define TX_CTL_SEG 0x0f
261
262
263 int
264 tfbmatch(parent, match, aux)
265 struct device *parent;
266 struct cfdata *match;
267 void *aux;
268 {
269 struct tc_attach_args *ta = aux;
270
271 if (strncmp("PMAG-RO ", ta->ta_modname, TC_ROM_LLEN) != 0
272 && strncmp("PMAG-JA ", ta->ta_modname, TC_ROM_LLEN) != 0)
273 return (0);
274
275 return (1);
276 }
277
278 void
279 tfb_getdevconfig(dense_addr, dc)
280 tc_addr_t dense_addr;
281 struct fb_devconfig *dc;
282 {
283 struct raster *rap;
284 struct rcons *rcp;
285 int i;
286
287 dc->dc_vaddr = dense_addr;
288 dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr);
289
290 dc->dc_wid = 1280;
291 dc->dc_ht = 1024;
292 dc->dc_depth = 8;
293 dc->dc_rowbytes = 1280;
294 dc->dc_videobase = dc->dc_vaddr + TX_8FB_OFFSET;
295 dc->dc_blanked = 0;
296
297 /* initialize colormap and cursor resource */
298 tfbinit(dc);
299
300 /* clear the screen */
301 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
302 *(u_int32_t *)(dc->dc_videobase + i) = 0x0;
303
304 /* initialize the raster */
305 rap = &dc->dc_raster;
306 rap->width = dc->dc_wid;
307 rap->height = dc->dc_ht;
308 rap->depth = dc->dc_depth;
309 rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
310 rap->pixels = (u_int32_t *)dc->dc_videobase;
311
312 /* initialize the raster console blitter */
313 rcp = &dc->dc_rcons;
314 rcp->rc_sp = rap;
315 rcp->rc_crow = rcp->rc_ccol = -1;
316 rcp->rc_crowp = &rcp->rc_crow;
317 rcp->rc_ccolp = &rcp->rc_ccol;
318 rcons_init(rcp, 34, 80);
319
320 tfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
321 tfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
322 }
323
324 void
325 tfbattach(parent, self, aux)
326 struct device *parent, *self;
327 void *aux;
328 {
329 struct tfb_softc *sc = (struct tfb_softc *)self;
330 struct tc_attach_args *ta = aux;
331 struct wsemuldisplaydev_attach_args waa;
332 struct hwcmap *cm;
333 int console, i;
334
335 console = (ta->ta_addr == tfb_consaddr);
336 if (console) {
337 sc->sc_dc = &tfb_console_dc;
338 sc->nscreens = 1;
339 }
340 else {
341 sc->sc_dc = (struct fb_devconfig *)
342 malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
343 tfb_getdevconfig(ta->ta_addr, sc->sc_dc);
344 }
345 printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
346 sc->sc_dc->dc_depth);
347
348 cm = &sc->sc_cmap;
349 cm->r[0] = cm->g[0] = cm->b[0] = 0;
350 for (i = 1; i < CMAP_SIZE; i++) {
351 cm->r[i] = cm->g[i] = cm->b[i] = 0xff;
352 }
353
354 tc_intr_establish(parent, ta->ta_cookie, TC_IPL_TTY, tfbintr, sc);
355 *(u_int8_t *)(sc->sc_dc->dc_vaddr + TX_CONTROL) &= ~0x40;
356 *(u_int8_t *)(sc->sc_dc->dc_vaddr + TX_CONTROL) |= 0x40;
357
358 waa.console = console;
359 waa.scrdata = &tfb_screenlist;
360 waa.accessops = &tfb_accessops;
361 waa.accesscookie = sc;
362
363 config_found(self, &waa, wsemuldisplaydevprint);
364 }
365
366 int
367 tfbioctl(v, cmd, data, flag, p)
368 void *v;
369 u_long cmd;
370 caddr_t data;
371 int flag;
372 struct proc *p;
373 {
374 struct tfb_softc *sc = v;
375 struct fb_devconfig *dc = sc->sc_dc;
376 int turnoff;
377
378 switch (cmd) {
379 case WSDISPLAYIO_GTYPE:
380 *(u_int *)data = /* WSDISPLAY_TYPE_TX */ 0x19980910;
381 return (0);
382
383 case WSDISPLAYIO_GINFO:
384 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
385 wsd_fbip->height = sc->sc_dc->dc_ht;
386 wsd_fbip->width = sc->sc_dc->dc_wid;
387 wsd_fbip->depth = sc->sc_dc->dc_depth;
388 wsd_fbip->cmsize = CMAP_SIZE;
389 #undef fbt
390 return (0);
391
392 case WSDISPLAYIO_GETCMAP:
393 return get_cmap(sc, (struct wsdisplay_cmap *)data);
394
395 case WSDISPLAYIO_PUTCMAP:
396 return set_cmap(sc, (struct wsdisplay_cmap *)data);
397
398 case WSDISPLAYIO_SVIDEO:
399 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
400 if ((dc->dc_blanked == 0) ^ turnoff) {
401 /* sc->sc_changed |= DATA_ALL_CHANGED; */
402 dc->dc_blanked = turnoff;
403 }
404 return (0);
405
406 case WSDISPLAYIO_GVIDEO:
407 *(u_int *)data = dc->dc_blanked ?
408 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
409 return (0);
410
411 case WSDISPLAYIO_GCURPOS:
412 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
413 return (0);
414
415 case WSDISPLAYIO_SCURPOS:
416 set_curpos(sc, (struct wsdisplay_curpos *)data);
417 bt431_set_curpos(sc);
418 return (0);
419
420 case WSDISPLAYIO_GCURMAX:
421 ((struct wsdisplay_curpos *)data)->x =
422 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
423 return (0);
424
425 case WSDISPLAYIO_GCURSOR:
426 return get_cursor(sc, (struct wsdisplay_cursor *)data);
427
428 case WSDISPLAYIO_SCURSOR:
429 return set_cursor(sc, (struct wsdisplay_cursor *)data);
430 }
431 return ENOTTY;
432 }
433
434 int
435 tfbmmap(v, offset, prot)
436 void *v;
437 off_t offset;
438 int prot;
439 {
440 struct tfb_softc *sc = v;
441
442 if (offset > TX_8FB_SIZE) /* XXX */
443 return (-1);
444 return machine_btop(sc->sc_dc->dc_paddr + TX_8FB_OFFSET + offset);
445 }
446
447 int
448 tfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
449 void *v;
450 const struct wsscreen_descr *type;
451 void **cookiep;
452 int *curxp, *curyp;
453 long *attrp;
454 {
455 struct tfb_softc *sc = v;
456 long defattr;
457
458 if (sc->nscreens > 0)
459 return (ENOMEM);
460
461 *cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
462 *curxp = 0;
463 *curyp = 0;
464 rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
465 *attrp = defattr;
466 sc->nscreens++;
467 return (0);
468 }
469
470 void
471 tfb_free_screen(v, cookie)
472 void *v;
473 void *cookie;
474 {
475 struct tfb_softc *sc = v;
476
477 if (sc->sc_dc == &tfb_console_dc)
478 panic("tfb_free_screen: console");
479
480 sc->nscreens--;
481 }
482
483 void
484 tfb_show_screen(v, cookie)
485 void *v;
486 void *cookie;
487 {
488 }
489
490 int
491 tfb_load_font(v, cookie, first, num, stride, data)
492 void *v;
493 void *cookie;
494 int first, num, stride;
495 void *data;
496 {
497 return (EINVAL);
498 }
499
500 int
501 tfb_cnattach(addr)
502 tc_addr_t addr;
503 {
504 struct fb_devconfig *dcp = &tfb_console_dc;
505 long defattr;
506
507 tfb_getdevconfig(addr, dcp);
508
509 rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
510
511 wsdisplay_cnattach(&tfb_stdscreen, &dcp->dc_rcons,
512 0, 0, defattr);
513 tfb_consaddr = addr;
514 return(0);
515 }
516
517
518 int
519 tfbintr(arg)
520 void *arg;
521 {
522 struct tfb_softc *sc = arg;
523 caddr_t tfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
524 struct bt463reg *vdac;
525 struct bt431reg *curs;
526 int v;
527
528 *(u_int8_t *)(tfbbase + TX_CONTROL) &= ~0x40;
529 *(u_int8_t *)(tfbbase + TX_CONTROL) |= 0x40;
530 if (sc->sc_changed == 0)
531 return (1);
532
533 vdac = (void *)(tfbbase + TX_BT463_OFFSET);
534 curs = (void *)(tfbbase + TX_BT431_OFFSET);
535 v = sc->sc_changed;
536 sc->sc_changed = 0;
537 if (v & DATA_ENB_CHANGED) {
538 BT431_SELECT(curs, BT431_REG_COMMAND);
539 curs->bt_ctl = (sc->sc_curenb) ? 0x4444 : 0x0404;
540 }
541 if (v & DATA_CURCMAP_CHANGED) {
542 u_int8_t *cp = sc->sc_cursor.cc_color;
543
544 BT463_SELECT(vdac, BT463_IREG_CURSOR_COLOR_0);
545 vdac->bt_reg = cp[1]; tc_wmb();
546 vdac->bt_reg = cp[3]; tc_wmb();
547 vdac->bt_reg = cp[5]; tc_wmb();
548
549 vdac->bt_reg = cp[0]; tc_wmb();
550 vdac->bt_reg = cp[2]; tc_wmb();
551 vdac->bt_reg = cp[4]; tc_wmb();
552
553 vdac->bt_reg = cp[1]; tc_wmb();
554 vdac->bt_reg = cp[3]; tc_wmb();
555 vdac->bt_reg = cp[5]; tc_wmb();
556
557 vdac->bt_reg = cp[1]; tc_wmb();
558 vdac->bt_reg = cp[3]; tc_wmb();
559 vdac->bt_reg = cp[5]; tc_wmb();
560 }
561 if (v & DATA_CURSHAPE_CHANGED) {
562 u_int8_t *bp1, *bp2;
563 u_int16_t twin;
564 int index;
565
566 bp1 = (u_int8_t *)&sc->sc_cursor.cc_image;
567 bp2 = (u_int8_t *)(&sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
568
569 BT431_SELECT(curs, BT431_REG_CRAM_BASE+0);
570 for (index = 0;
571 index < sizeof(sc->sc_cursor.cc_image)/sizeof(u_int16_t);
572 index++) {
573 twin = *bp1++ | (*bp2++ << 8);
574 curs->bt_ram = twin;
575 tc_wmb();
576 }
577 }
578 if (v & DATA_CMAP_CHANGED) {
579 struct hwcmap *cm = &sc->sc_cmap;
580 int index;
581
582 BT463_SELECT(vdac, BT463_IREG_CPALETTE_RAM);
583 for (index = 0; index < CMAP_SIZE; index++) {
584 vdac->bt_cmap = cm->r[index];
585 vdac->bt_cmap = cm->g[index];
586 vdac->bt_cmap = cm->b[index];
587 }
588 }
589 return (1);
590 }
591
592 void
593 tfbinit(dc)
594 struct fb_devconfig *dc;
595 {
596 caddr_t tfbbase = (caddr_t)dc->dc_vaddr;
597 struct bt463reg *vdac = (void *)(tfbbase + TX_BT463_OFFSET);
598 struct bt431reg *curs = (void *)(tfbbase + TX_BT431_OFFSET);
599 int i;
600
601 BT463_SELECT(vdac, BT463_IREG_COMMAND_0);
602 vdac->bt_reg = 0x40; tc_wmb();
603 vdac->bt_reg = 0x46; tc_wmb();
604 vdac->bt_reg = 0xc0; tc_wmb();
605 vdac->bt_reg = 0; tc_wmb(); /* !? 204 !? */
606 vdac->bt_reg = 0xff; tc_wmb(); /* plane 0:7 */
607 vdac->bt_reg = 0xff; tc_wmb(); /* plane 8:15 */
608 vdac->bt_reg = 0xff; tc_wmb(); /* plane 16:23 */
609 vdac->bt_reg = 0xff; tc_wmb(); /* plane 24:27 */
610 vdac->bt_reg = 0x00; tc_wmb(); /* blink 0:7 */
611 vdac->bt_reg = 0x00; tc_wmb(); /* blink 8:15 */
612 vdac->bt_reg = 0x00; tc_wmb(); /* blink 16:23 */
613 vdac->bt_reg = 0x00; tc_wmb(); /* blink 24:27 */
614 vdac->bt_reg = 0x00; tc_wmb();
615
616 /* bt463_load_wid(vdac, 0, 16, -1); */
617
618 BT463_SELECT(vdac, BT463_IREG_CPALETTE_RAM);
619 vdac->bt_cmap = 0; tc_wmb();
620 vdac->bt_cmap = 0; tc_wmb();
621 vdac->bt_cmap = 0; tc_wmb();
622 for (i = 1; i < CMAP_SIZE; i++) {
623 vdac->bt_cmap = 0xff; tc_wmb();
624 vdac->bt_cmap = 0xff; tc_wmb();
625 vdac->bt_cmap = 0xff; tc_wmb();
626 }
627
628 BT463_SELECT(vdac, BT463_IREG_CPALETTE_RAM+0x100);
629 for (i = 0; i < CMAP_SIZE; i++) {
630 vdac->bt_cmap = 0; tc_wmb();
631 vdac->bt_cmap = 0; tc_wmb();
632 vdac->bt_cmap = 0; tc_wmb();
633 }
634
635 BT431_SELECT(curs, BT431_REG_COMMAND);
636 curs->bt_ctl = 0x0404; tc_wmb();
637 curs->bt_ctl = 0; tc_wmb();
638 curs->bt_ctl = 0; tc_wmb();
639 curs->bt_ctl = 0; tc_wmb();
640 curs->bt_ctl = 0; tc_wmb();
641 curs->bt_ctl = 0; tc_wmb();
642 curs->bt_ctl = 0; tc_wmb();
643 curs->bt_ctl = 0; tc_wmb();
644 curs->bt_ctl = 0; tc_wmb();
645 curs->bt_ctl = 0; tc_wmb();
646 curs->bt_ctl = 0; tc_wmb();
647 curs->bt_ctl = 0; tc_wmb();
648 curs->bt_ctl = 0; tc_wmb();
649 }
650
651 static int
652 get_cmap(sc, p)
653 struct tfb_softc *sc;
654 struct wsdisplay_cmap *p;
655 {
656 u_int index = p->index, count = p->count;
657
658 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
659 return (EINVAL);
660
661 if (!useracc(p->red, count, B_WRITE) ||
662 !useracc(p->green, count, B_WRITE) ||
663 !useracc(p->blue, count, B_WRITE))
664 return (EFAULT);
665
666 copyout(&sc->sc_cmap.r[index], p->red, count);
667 copyout(&sc->sc_cmap.g[index], p->green, count);
668 copyout(&sc->sc_cmap.b[index], p->blue, count);
669
670 return (0);
671 }
672
673 static int
674 set_cmap(sc, p)
675 struct tfb_softc *sc;
676 struct wsdisplay_cmap *p;
677 {
678 u_int index = p->index, count = p->count;
679
680 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
681 return (EINVAL);
682
683 if (!useracc(p->red, count, B_READ) ||
684 !useracc(p->green, count, B_READ) ||
685 !useracc(p->blue, count, B_READ))
686 return (EFAULT);
687
688 copyin(p->red, &sc->sc_cmap.r[index], count);
689 copyin(p->green, &sc->sc_cmap.g[index], count);
690 copyin(p->blue, &sc->sc_cmap.b[index], count);
691
692 sc->sc_changed |= DATA_CMAP_CHANGED;
693
694 return (0);
695 }
696
697 static int
698 set_cursor(sc, p)
699 struct tfb_softc *sc;
700 struct wsdisplay_cursor *p;
701 {
702 #define cc (&sc->sc_cursor)
703 int v, index, count;
704
705 v = p->which;
706 if (v & WSDISPLAY_CURSOR_DOCMAP) {
707 index = p->cmap.index;
708 count = p->cmap.count;
709 if (index >= 2 || (index + count) > 2)
710 return (EINVAL);
711 if (!useracc(p->cmap.red, count, B_READ) ||
712 !useracc(p->cmap.green, count, B_READ) ||
713 !useracc(p->cmap.blue, count, B_READ))
714 return (EFAULT);
715 }
716 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
717 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
718 return (EINVAL);
719 count = (CURSOR_MAX_SIZE / NBBY) * p->size.y;
720 if (!useracc(p->image, count, B_READ) ||
721 !useracc(p->mask, count, B_READ))
722 return (EFAULT);
723 }
724 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
725 if (v & WSDISPLAY_CURSOR_DOCUR)
726 cc->cc_hot = p->hot;
727 if (v & WSDISPLAY_CURSOR_DOPOS)
728 set_curpos(sc, &p->pos);
729 bt431_set_curpos(sc);
730 }
731
732 sc->sc_changed = 0;
733 if (v & WSDISPLAY_CURSOR_DOCUR) {
734 sc->sc_curenb = p->enable;
735 sc->sc_changed |= DATA_ENB_CHANGED;
736 }
737 if (v & WSDISPLAY_CURSOR_DOCMAP) {
738 count = p->cmap.count;
739 copyin(p->cmap.red, &cc->cc_color[index], count);
740 copyin(p->cmap.green, &cc->cc_color[index + 2], count);
741 copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
742 sc->sc_changed |= DATA_CURCMAP_CHANGED;
743 }
744 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
745 cc->cc_size = p->size;
746 memset(cc->cc_image, 0, sizeof cc->cc_image);
747 copyin(p->image, (caddr_t)cc->cc_image, count);
748 copyin(p->mask, (caddr_t)(cc->cc_image+CURSOR_MAX_SIZE), count);
749 sc->sc_changed |= DATA_CURSHAPE_CHANGED;
750 }
751
752 return (0);
753 #undef cc
754 }
755
756 static int
757 get_cursor(sc, p)
758 struct tfb_softc *sc;
759 struct wsdisplay_cursor *p;
760 {
761 return (ENOTTY); /* XXX */
762 }
763
764 static void
765 set_curpos(sc, curpos)
766 struct tfb_softc *sc;
767 struct wsdisplay_curpos *curpos;
768 {
769 struct fb_devconfig *dc = sc->sc_dc;
770 int x = curpos->x, y = curpos->y;
771
772 if (y < 0)
773 y = 0;
774 else if (y > dc->dc_ht - sc->sc_cursor.cc_size.y - 1)
775 y = dc->dc_ht - sc->sc_cursor.cc_size.y - 1;
776 if (x < 0)
777 x = 0;
778 else if (x > dc->dc_wid - sc->sc_cursor.cc_size.x - 1)
779 x = dc->dc_wid - sc->sc_cursor.cc_size.x - 1;
780 sc->sc_cursor.cc_pos.x = x;
781 sc->sc_cursor.cc_pos.y = y;
782 }
783
784 static void
785 bt431_set_curpos(sc)
786 struct tfb_softc *sc;
787 {
788 caddr_t tfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
789 struct bt431reg *curs = (void *)(tfbbase + TX_BT431_OFFSET);
790 int x = 220, y = 35; /* magic offset of TX coordinate */
791 u_int16_t twin;
792 int s;
793
794 x += sc->sc_cursor.cc_pos.x;
795 y += sc->sc_cursor.cc_pos.y;
796
797 s = spltty();
798
799 BT431_SELECT(curs, BT431_REG_CURSOR_X_LOW);
800 curs->bt_ctl = TWIN_LO(x);
801 curs->bt_ctl = TWIN_HI(x);
802 curs->bt_ctl = TWIN_LO(y);
803 curs->bt_ctl = TWIN_HI(y);
804
805 splx(s);
806 }
807