cfb.c revision 1.4 1 /* $NetBSD: cfb.c,v 1.4 1998/11/18 12:26:31 nisimura Exp $ */
2
3 /*
4 * Copyright (c) 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.4 1998/11/18 12:26:31 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 * obscure register layout such as 2nd and 3rd Bt459 registers are
82 * adjacent each other in a word, i.e.,
83 * struct bt459triplet {
84 * struct {
85 * u_int8_t u0;
86 * u_int8_t u1;
87 * u_int8_t u2;
88 * unsigned :8;
89 * } bt_lo;
90 * ...
91 * Although CX has single Bt459, 32bit R/W can be done w/o any trouble.
92 */
93 struct bt459reg {
94 u_int32_t bt_lo;
95 u_int32_t bt_hi;
96 u_int32_t bt_reg;
97 u_int32_t bt_cmap;
98 };
99
100 /* XXX XXX XXX */
101
102 struct fb_devconfig {
103 vaddr_t dc_vaddr; /* memory space virtual base address */
104 paddr_t dc_paddr; /* memory space physical base address */
105 vsize_t dc_size; /* size of slot memory */
106 int dc_wid; /* width of frame buffer */
107 int dc_ht; /* height of frame buffer */
108 int dc_depth; /* depth, bits per pixel */
109 int dc_rowbytes; /* bytes in a FB scan line */
110 vaddr_t dc_videobase; /* base of flat frame buffer */
111 struct raster dc_raster; /* raster description */
112 struct rcons dc_rcons; /* raster blitter control info */
113 int dc_blanked; /* currently has video disabled */
114 };
115
116 struct hwcmap {
117 #define CMAP_SIZE 256 /* 256 R/G/B entries */
118 u_int8_t r[CMAP_SIZE];
119 u_int8_t g[CMAP_SIZE];
120 u_int8_t b[CMAP_SIZE];
121 };
122
123 struct hwcursor {
124 struct wsdisplay_curpos cc_pos;
125 struct wsdisplay_curpos cc_hot;
126 struct wsdisplay_curpos cc_size;
127 #define CURSOR_MAX_SIZE 64
128 u_int8_t cc_color[6];
129 u_int64_t cc_image[64 + 64];
130 };
131
132 struct cfb_softc {
133 struct device sc_dev;
134 struct fb_devconfig *sc_dc; /* device configuration */
135 struct hwcmap sc_cmap; /* software copy of colormap */
136 struct hwcursor sc_cursor; /* software copy of cursor */
137 int sc_curenb; /* cursor sprite enabled */
138 int sc_changed; /* need update of colormap */
139 #define DATA_ENB_CHANGED 0x01 /* cursor enable changed */
140 #define DATA_CURCMAP_CHANGED 0x02 /* cursor colormap changed */
141 #define DATA_CURSHAPE_CHANGED 0x04 /* cursor size, image, mask changed */
142 #define DATA_CMAP_CHANGED 0x08 /* colormap changed */
143 #define DATA_ALL_CHANGED 0x0f
144 int nscreens;
145 short magic_x, magic_y; /* CX cursor location offset */
146 #define CX_MAGIC_X 220
147 #define CX_MAGIC_Y 35
148 };
149
150 #define CX_FB_OFFSET 0x000000
151 #define CX_FB_SIZE 0x100000
152 #define CX_BT459_OFFSET 0x200000
153 #define CX_OFFSET_IREQ 0x300000 /* Interrupt req. control */
154
155 int cfbmatch __P((struct device *, struct cfdata *, void *));
156 void cfbattach __P((struct device *, struct device *, void *));
157
158 struct cfattach cfb_ca = {
159 sizeof(struct cfb_softc), cfbmatch, cfbattach,
160 };
161
162 void cfb_getdevconfig __P((tc_addr_t, struct fb_devconfig *));
163 struct fb_devconfig cfb_console_dc;
164 tc_addr_t cfb_consaddr;
165
166 struct wsdisplay_emulops cfb_emulops = {
167 rcons_cursor, /* could use hardware cursor; punt */
168 rcons_mapchar,
169 rcons_putchar,
170 rcons_copycols,
171 rcons_erasecols,
172 rcons_copyrows,
173 rcons_eraserows,
174 rcons_alloc_attr
175 };
176
177 struct wsscreen_descr cfb_stdscreen = {
178 "std", 0, 0,
179 &cfb_emulops,
180 0, 0,
181 0
182 };
183
184 const struct wsscreen_descr *_cfb_scrlist[] = {
185 &cfb_stdscreen,
186 };
187
188 struct wsscreen_list cfb_screenlist = {
189 sizeof(_cfb_scrlist) / sizeof(struct wsscreen_descr *), _cfb_scrlist
190 };
191
192 int cfbioctl __P((void *, u_long, caddr_t, int, struct proc *));
193 int cfbmmap __P((void *, off_t, int));
194
195 int cfb_alloc_screen __P((void *, const struct wsscreen_descr *,
196 void **, int *, int *, long *));
197 void cfb_free_screen __P((void *, void *));
198 void cfb_show_screen __P((void *, void *));
199 int cfb_load_font __P((void *, void *, int, int, int, void *));
200
201 struct wsdisplay_accessops cfb_accessops = {
202 cfbioctl,
203 cfbmmap,
204 cfb_alloc_screen,
205 cfb_free_screen,
206 cfb_show_screen,
207 cfb_load_font
208 };
209
210 int cfb_cnattach __P((tc_addr_t));
211 int cfbintr __P((void *));
212 void cfbinit __P((struct fb_devconfig *));
213
214 static int get_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
215 static int set_cmap __P((struct cfb_softc *, struct wsdisplay_cmap *));
216 static int set_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
217 static int get_cursor __P((struct cfb_softc *, struct wsdisplay_cursor *));
218 static void set_curpos __P((struct cfb_softc *, struct wsdisplay_curpos *));
219 static void bt459_set_curpos __P((struct cfb_softc *));
220
221 /* XXX XXX XXX */
222 #define BT459_SELECT(vdac, regno) do { \
223 vdac->bt_lo = (regno) & 0x00ff; \
224 vdac->bt_hi = ((regno)& 0x0f00) >> 8; \
225 tc_wmb(); \
226 } while (0)
227 /* XXX XXX XXX */
228
229 /*
230 * Compose 2 bit/pixel cursor image. Bit order will be reversed.
231 * M M M M I I I I M I M I M I M I
232 * [ before ] [ after ]
233 * 3 2 1 0 3 2 1 0 0 0 1 1 2 2 3 3
234 * 7 6 5 4 7 6 5 4 4 4 5 5 6 6 7 7
235 */
236 const static u_int8_t shuffle[256] = {
237 0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
238 0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55,
239 0x80, 0xc0, 0x90, 0xd0, 0x84, 0xc4, 0x94, 0xd4,
240 0x81, 0xc1, 0x91, 0xd1, 0x85, 0xc5, 0x95, 0xd5,
241 0x20, 0x60, 0x30, 0x70, 0x24, 0x64, 0x34, 0x74,
242 0x21, 0x61, 0x31, 0x71, 0x25, 0x65, 0x35, 0x75,
243 0xa0, 0xe0, 0xb0, 0xf0, 0xa4, 0xe4, 0xb4, 0xf4,
244 0xa1, 0xe1, 0xb1, 0xf1, 0xa5, 0xe5, 0xb5, 0xf5,
245 0x08, 0x48, 0x18, 0x58, 0x0c, 0x4c, 0x1c, 0x5c,
246 0x09, 0x49, 0x19, 0x59, 0x0d, 0x4d, 0x1d, 0x5d,
247 0x88, 0xc8, 0x98, 0xd8, 0x8c, 0xcc, 0x9c, 0xdc,
248 0x89, 0xc9, 0x99, 0xd9, 0x8d, 0xcd, 0x9d, 0xdd,
249 0x28, 0x68, 0x38, 0x78, 0x2c, 0x6c, 0x3c, 0x7c,
250 0x29, 0x69, 0x39, 0x79, 0x2d, 0x6d, 0x3d, 0x7d,
251 0xa8, 0xe8, 0xb8, 0xf8, 0xac, 0xec, 0xbc, 0xfc,
252 0xa9, 0xe9, 0xb9, 0xf9, 0xad, 0xed, 0xbd, 0xfd,
253 0x02, 0x42, 0x12, 0x52, 0x06, 0x46, 0x16, 0x56,
254 0x03, 0x43, 0x13, 0x53, 0x07, 0x47, 0x17, 0x57,
255 0x82, 0xc2, 0x92, 0xd2, 0x86, 0xc6, 0x96, 0xd6,
256 0x83, 0xc3, 0x93, 0xd3, 0x87, 0xc7, 0x97, 0xd7,
257 0x22, 0x62, 0x32, 0x72, 0x26, 0x66, 0x36, 0x76,
258 0x23, 0x63, 0x33, 0x73, 0x27, 0x67, 0x37, 0x77,
259 0xa2, 0xe2, 0xb2, 0xf2, 0xa6, 0xe6, 0xb6, 0xf6,
260 0xa3, 0xe3, 0xb3, 0xf3, 0xa7, 0xe7, 0xb7, 0xf7,
261 0x0a, 0x4a, 0x1a, 0x5a, 0x0e, 0x4e, 0x1e, 0x5e,
262 0x0b, 0x4b, 0x1b, 0x5b, 0x0f, 0x4f, 0x1f, 0x5f,
263 0x8a, 0xca, 0x9a, 0xda, 0x8e, 0xce, 0x9e, 0xde,
264 0x8b, 0xcb, 0x9b, 0xdb, 0x8f, 0xcf, 0x9f, 0xdf,
265 0x2a, 0x6a, 0x3a, 0x7a, 0x2e, 0x6e, 0x3e, 0x7e,
266 0x2b, 0x6b, 0x3b, 0x7b, 0x2f, 0x6f, 0x3f, 0x7f,
267 0xaa, 0xea, 0xba, 0xfa, 0xae, 0xee, 0xbe, 0xfe,
268 0xab, 0xeb, 0xbb, 0xfb, 0xaf, 0xef, 0xbf, 0xff,
269 };
270
271 int
272 cfbmatch(parent, match, aux)
273 struct device *parent;
274 struct cfdata *match;
275 void *aux;
276 {
277 struct tc_attach_args *ta = aux;
278
279 if (strncmp("PMAG-BA ", ta->ta_modname, TC_ROM_LLEN) != 0)
280 return (0);
281
282 return (1);
283 }
284
285 void
286 cfb_getdevconfig(dense_addr, dc)
287 tc_addr_t dense_addr;
288 struct fb_devconfig *dc;
289 {
290 struct raster *rap;
291 struct rcons *rcp;
292 int i;
293
294 dc->dc_vaddr = dense_addr;
295 dc->dc_paddr = MACHINE_KSEG0_TO_PHYS(dc->dc_vaddr + CX_FB_OFFSET);
296
297 dc->dc_wid = 1024;
298 dc->dc_ht = 864;
299 dc->dc_depth = 8;
300 dc->dc_rowbytes = 1024;
301 dc->dc_videobase = dc->dc_vaddr + CX_FB_OFFSET;
302 dc->dc_blanked = 0;
303
304 /* initialize colormap and cursor resource */
305 cfbinit(dc);
306
307 /* clear the screen */
308 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
309 *(u_int32_t *)(dc->dc_videobase + i) = 0x0;
310
311 /* initialize the raster */
312 rap = &dc->dc_raster;
313 rap->width = dc->dc_wid;
314 rap->height = dc->dc_ht;
315 rap->depth = dc->dc_depth;
316 rap->linelongs = dc->dc_rowbytes / sizeof(u_int32_t);
317 rap->pixels = (u_int32_t *)dc->dc_videobase;
318
319 /* initialize the raster console blitter */
320 rcp = &dc->dc_rcons;
321 rcp->rc_sp = rap;
322 rcp->rc_crow = rcp->rc_ccol = -1;
323 rcp->rc_crowp = &rcp->rc_crow;
324 rcp->rc_ccolp = &rcp->rc_ccol;
325 rcons_init(rcp, 34, 80);
326
327 cfb_stdscreen.nrows = dc->dc_rcons.rc_maxrow;
328 cfb_stdscreen.ncols = dc->dc_rcons.rc_maxcol;
329 }
330
331 void
332 cfbattach(parent, self, aux)
333 struct device *parent, *self;
334 void *aux;
335 {
336 struct cfb_softc *sc = (struct cfb_softc *)self;
337 struct tc_attach_args *ta = aux;
338 struct wsemuldisplaydev_attach_args waa;
339 struct hwcmap *cm;
340 int console, i;
341
342 console = (ta->ta_addr == cfb_consaddr);
343 if (console) {
344 sc->sc_dc = &cfb_console_dc;
345 sc->nscreens = 1;
346 }
347 else {
348 sc->sc_dc = (struct fb_devconfig *)
349 malloc(sizeof(struct fb_devconfig), M_DEVBUF, M_WAITOK);
350 cfb_getdevconfig(ta->ta_addr, sc->sc_dc);
351 }
352 printf(": %d x %d, %dbpp\n", sc->sc_dc->dc_wid, sc->sc_dc->dc_ht,
353 sc->sc_dc->dc_depth);
354
355 cm = &sc->sc_cmap;
356 cm->r[0] = cm->g[0] = cm->b[0] = 0;
357 for (i = 1; i < CMAP_SIZE; i++) {
358 cm->r[i] = cm->g[i] = cm->b[i] = 0xff;
359 }
360 sc->magic_x = CX_MAGIC_X;
361 sc->magic_y = CX_MAGIC_Y;
362
363 /* Establish an interrupt handler, and clear any pending interrupts */
364 tc_intr_establish(parent, ta->ta_cookie, TC_IPL_TTY, cfbintr, sc);
365 *(u_int8_t *)(sc->sc_dc->dc_vaddr + CX_OFFSET_IREQ) = 0;
366
367 waa.console = console;
368 waa.scrdata = &cfb_screenlist;
369 waa.accessops = &cfb_accessops;
370 waa.accesscookie = sc;
371
372 config_found(self, &waa, wsemuldisplaydevprint);
373 }
374
375 int
376 cfbioctl(v, cmd, data, flag, p)
377 void *v;
378 u_long cmd;
379 caddr_t data;
380 int flag;
381 struct proc *p;
382 {
383 struct cfb_softc *sc = v;
384 struct fb_devconfig *dc = sc->sc_dc;
385 int turnoff;
386
387 switch (cmd) {
388 case WSDISPLAYIO_GTYPE:
389 *(u_int *)data = WSDISPLAY_TYPE_CFB;
390 return (0);
391
392 case WSDISPLAYIO_GINFO:
393 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
394 wsd_fbip->height = sc->sc_dc->dc_ht;
395 wsd_fbip->width = sc->sc_dc->dc_wid;
396 wsd_fbip->depth = sc->sc_dc->dc_depth;
397 wsd_fbip->cmsize = CMAP_SIZE;
398 #undef fbt
399 return (0);
400
401 case WSDISPLAYIO_GETCMAP:
402 return get_cmap(sc, (struct wsdisplay_cmap *)data);
403
404 case WSDISPLAYIO_PUTCMAP:
405 return set_cmap(sc, (struct wsdisplay_cmap *)data);
406
407 case WSDISPLAYIO_SVIDEO:
408 turnoff = *(int *)data == WSDISPLAYIO_VIDEO_OFF;
409 if ((dc->dc_blanked == 0) ^ turnoff) {
410 dc->dc_blanked = turnoff;
411 /* XXX later XXX */
412 }
413 return (0);
414
415 case WSDISPLAYIO_GVIDEO:
416 *(u_int *)data = dc->dc_blanked ?
417 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
418 return (0);
419
420 case WSDISPLAYIO_GCURPOS:
421 *(struct wsdisplay_curpos *)data = sc->sc_cursor.cc_pos;
422 return (0);
423
424 case WSDISPLAYIO_SCURPOS:
425 set_curpos(sc, (struct wsdisplay_curpos *)data);
426 bt459_set_curpos(sc);
427 return (0);
428
429 case WSDISPLAYIO_GCURMAX:
430 ((struct wsdisplay_curpos *)data)->x =
431 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_SIZE;
432 return (0);
433
434 case WSDISPLAYIO_GCURSOR:
435 return get_cursor(sc, (struct wsdisplay_cursor *)data);
436
437 case WSDISPLAYIO_SCURSOR:
438 return set_cursor(sc, (struct wsdisplay_cursor *)data);
439 }
440 return ENOTTY;
441 }
442
443 int
444 cfbmmap(v, offset, prot)
445 void *v;
446 off_t offset;
447 int prot;
448 {
449 struct cfb_softc *sc = v;
450
451 if (offset > CX_FB_SIZE)
452 return (-1);
453 return machine_btop(sc->sc_dc->dc_paddr + offset);
454 }
455
456 int
457 cfb_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
458 void *v;
459 const struct wsscreen_descr *type;
460 void **cookiep;
461 int *curxp, *curyp;
462 long *attrp;
463 {
464 struct cfb_softc *sc = v;
465 long defattr;
466
467 if (sc->nscreens > 0)
468 return (ENOMEM);
469
470 *cookiep = &sc->sc_dc->dc_rcons; /* one and only for now */
471 *curxp = 0;
472 *curyp = 0;
473 rcons_alloc_attr(&sc->sc_dc->dc_rcons, 0, 0, 0, &defattr);
474 *attrp = defattr;
475 sc->nscreens++;
476 return (0);
477 }
478
479 void
480 cfb_free_screen(v, cookie)
481 void *v;
482 void *cookie;
483 {
484 struct cfb_softc *sc = v;
485
486 if (sc->sc_dc == &cfb_console_dc)
487 panic("cfb_free_screen: console");
488
489 sc->nscreens--;
490 }
491
492 void
493 cfb_show_screen(v, cookie)
494 void *v;
495 void *cookie;
496 {
497 }
498
499 int
500 cfb_load_font(v, cookie, first, num, stride, data)
501 void *v;
502 void *cookie;
503 int first, num, stride;
504 void *data;
505 {
506 return (EINVAL);
507 }
508
509 int
510 cfb_cnattach(addr)
511 tc_addr_t addr;
512 {
513 struct fb_devconfig *dcp = &cfb_console_dc;
514 long defattr;
515
516 cfb_getdevconfig(addr, dcp);
517
518 rcons_alloc_attr(&dcp->dc_rcons, 0, 0, 0, &defattr);
519
520 wsdisplay_cnattach(&cfb_stdscreen, &dcp->dc_rcons,
521 0, 0, defattr);
522 cfb_consaddr = addr;
523 return(0);
524 }
525
526
527 int
528 cfbintr(arg)
529 void *arg;
530 {
531 struct cfb_softc *sc = arg;
532 caddr_t cfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
533 struct bt459reg *vdac;
534 int v;
535
536 *(u_int8_t *)(cfbbase + CX_OFFSET_IREQ) = 0;
537 if (sc->sc_changed == 0)
538 return (1);
539
540 vdac = (void *)(cfbbase + CX_BT459_OFFSET);
541 v = sc->sc_changed;
542 sc->sc_changed = 0;
543 if (v & DATA_ENB_CHANGED) {
544 BT459_SELECT(vdac, BT459_REG_CCR);
545 vdac->bt_reg = (sc->sc_curenb) ? 0xc0 : 0x00;
546 }
547 if (v & DATA_CURCMAP_CHANGED) {
548 u_int8_t *cp = sc->sc_cursor.cc_color;
549
550 BT459_SELECT(vdac, BT459_REG_CCOLOR_2);
551 vdac->bt_reg = cp[1]; tc_wmb();
552 vdac->bt_reg = cp[3]; tc_wmb();
553 vdac->bt_reg = cp[5]; tc_wmb();
554
555 vdac->bt_reg = cp[0]; tc_wmb();
556 vdac->bt_reg = cp[2]; tc_wmb();
557 vdac->bt_reg = cp[4]; tc_wmb();
558 }
559 if (v & DATA_CURSHAPE_CHANGED) {
560 u_int8_t *ip, *mp, img, msk;
561 u_int8_t u;
562 int bcnt;
563
564 ip = (u_int8_t *)sc->sc_cursor.cc_image;
565 mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_SIZE);
566
567 bcnt = 0;
568 BT459_SELECT(vdac, BT459_REG_CRAM_BASE+0);
569 /* 64 pixel scan line is consisted with 16 byte cursor ram */
570 while (bcnt < sc->sc_cursor.cc_size.y * 16) {
571 /* pad right half 32 pixel when smaller than 33 */
572 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
573 vdac->bt_reg = 0; tc_wmb();
574 vdac->bt_reg = 0; tc_wmb();
575 }
576 else {
577 img = *ip++;
578 msk = *mp++;
579 img &= msk; /* cookie off image */
580 u = (msk & 0x0f) << 4 | (img & 0x0f);
581 vdac->bt_reg = shuffle[u]; tc_wmb();
582 u = (msk & 0xf0) | (img & 0xf0) >> 4;
583 vdac->bt_reg = shuffle[u]; tc_wmb();
584 }
585 bcnt += 2;
586 }
587 /* pad unoccupied scan lines */
588 while (bcnt < CURSOR_MAX_SIZE * 16) {
589 vdac->bt_reg = 0; tc_wmb();
590 vdac->bt_reg = 0; tc_wmb();
591 bcnt += 2;
592 }
593 }
594 if (v & DATA_CMAP_CHANGED) {
595 struct hwcmap *cm = &sc->sc_cmap;
596 int index;
597
598 BT459_SELECT(vdac, 0);
599 for (index = 0; index < CMAP_SIZE; index++) {
600 vdac->bt_cmap = cm->r[index]; tc_wmb();
601 vdac->bt_cmap = cm->g[index]; tc_wmb();
602 vdac->bt_cmap = cm->b[index]; tc_wmb();
603 }
604 }
605 return (1);
606 }
607
608 void
609 cfbinit(dc)
610 struct fb_devconfig *dc;
611 {
612 caddr_t cfbbase = (caddr_t)dc->dc_vaddr;
613 struct bt459reg *vdac = (void *)(cfbbase + CX_BT459_OFFSET);
614 int i;
615
616 BT459_SELECT(vdac, BT459_REG_COMMAND_0);
617 vdac->bt_reg = 0x40; /* CMD0 */ tc_wmb();
618 vdac->bt_reg = 0x0; /* CMD1 */ tc_wmb();
619 vdac->bt_reg = 0xc0; /* CMD2 */ tc_wmb();
620 vdac->bt_reg = 0xff; /* PRM */ tc_wmb();
621 vdac->bt_reg = 0; /* 205 */ tc_wmb();
622 vdac->bt_reg = 0x0; /* PBM */ tc_wmb();
623 vdac->bt_reg = 0; /* 207 */ tc_wmb();
624 vdac->bt_reg = 0x0; /* ORM */ tc_wmb();
625 vdac->bt_reg = 0x0; /* OBM */ tc_wmb();
626 vdac->bt_reg = 0x0; /* ILV */ tc_wmb();
627 vdac->bt_reg = 0x0; /* TEST */ tc_wmb();
628
629 BT459_SELECT(vdac, BT459_REG_CCR);
630 vdac->bt_reg = 0x0; tc_wmb();
631 vdac->bt_reg = 0x0; tc_wmb();
632 vdac->bt_reg = 0x0; tc_wmb();
633 vdac->bt_reg = 0x0; tc_wmb();
634 vdac->bt_reg = 0x0; tc_wmb();
635 vdac->bt_reg = 0x0; tc_wmb();
636 vdac->bt_reg = 0x0; tc_wmb();
637 vdac->bt_reg = 0x0; tc_wmb();
638 vdac->bt_reg = 0x0; tc_wmb();
639 vdac->bt_reg = 0x0; tc_wmb();
640 vdac->bt_reg = 0x0; tc_wmb();
641 vdac->bt_reg = 0x0; tc_wmb();
642 vdac->bt_reg = 0x0; tc_wmb();
643
644 /* build sane colormap */
645 BT459_SELECT(vdac, 0);
646 vdac->bt_cmap = 0; tc_wmb();
647 vdac->bt_cmap = 0; tc_wmb();
648 vdac->bt_cmap = 0; tc_wmb();
649 for (i = 1; i < CMAP_SIZE; i++) {
650 vdac->bt_cmap = 0xff; tc_wmb();
651 vdac->bt_cmap = 0xff; tc_wmb();
652 vdac->bt_cmap = 0xff; tc_wmb();
653 }
654
655 /* clear out cursor image */
656 BT459_SELECT(vdac, BT459_REG_CRAM_BASE);
657 for (i = 0; i < 1024; i++)
658 vdac->bt_reg = 0xff; tc_wmb();
659
660 /*
661 * 2 bit/pixel cursor. Assign MSB for cursor mask and LSB for
662 * cursor image. CCOLOR_2 for mask color, while CCOLOR_3 for
663 * image color. CCOLOR_1 will be never used.
664 */
665 BT459_SELECT(vdac, BT459_REG_CCOLOR_1);
666 vdac->bt_reg = 0xff; tc_wmb();
667 vdac->bt_reg = 0xff; tc_wmb();
668 vdac->bt_reg = 0xff; tc_wmb();
669
670 vdac->bt_reg = 0; tc_wmb();
671 vdac->bt_reg = 0; tc_wmb();
672 vdac->bt_reg = 0; tc_wmb();
673
674 vdac->bt_reg = 0xff; tc_wmb();
675 vdac->bt_reg = 0xff; tc_wmb();
676 vdac->bt_reg = 0xff; tc_wmb();
677 }
678
679 static int
680 get_cmap(sc, p)
681 struct cfb_softc *sc;
682 struct wsdisplay_cmap *p;
683 {
684 u_int index = p->index, count = p->count;
685
686 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
687 return (EINVAL);
688
689 if (!useracc(p->red, count, B_WRITE) ||
690 !useracc(p->green, count, B_WRITE) ||
691 !useracc(p->blue, count, B_WRITE))
692 return (EFAULT);
693
694 copyout(&sc->sc_cmap.r[index], p->red, count);
695 copyout(&sc->sc_cmap.g[index], p->green, count);
696 copyout(&sc->sc_cmap.b[index], p->blue, count);
697
698 return (0);
699 }
700
701 static int
702 set_cmap(sc, p)
703 struct cfb_softc *sc;
704 struct wsdisplay_cmap *p;
705 {
706 u_int index = p->index, count = p->count;
707
708 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
709 return (EINVAL);
710
711 if (!useracc(p->red, count, B_READ) ||
712 !useracc(p->green, count, B_READ) ||
713 !useracc(p->blue, count, B_READ))
714 return (EFAULT);
715
716 copyin(p->red, &sc->sc_cmap.r[index], count);
717 copyin(p->green, &sc->sc_cmap.g[index], count);
718 copyin(p->blue, &sc->sc_cmap.b[index], count);
719
720 sc->sc_changed |= DATA_CMAP_CHANGED;
721
722 return (0);
723 }
724
725 static int
726 set_cursor(sc, p)
727 struct cfb_softc *sc;
728 struct wsdisplay_cursor *p;
729 {
730 #define cc (&sc->sc_cursor)
731 int v, index, count, icount;
732
733 v = p->which;
734 if (v & WSDISPLAY_CURSOR_DOCMAP) {
735 index = p->cmap.index;
736 count = p->cmap.count;
737 if (index >= 2 || (index + count) > 2)
738 return (EINVAL);
739 if (!useracc(p->cmap.red, count, B_READ) ||
740 !useracc(p->cmap.green, count, B_READ) ||
741 !useracc(p->cmap.blue, count, B_READ))
742 return (EFAULT);
743 }
744 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
745 if (p->size.x > CURSOR_MAX_SIZE || p->size.y > CURSOR_MAX_SIZE)
746 return (EINVAL);
747 icount = ((p->size.x < 33) ? 4 : 8) * p->size.y;
748 if (!useracc(p->image, count, B_READ) ||
749 !useracc(p->mask, count, B_READ))
750 return (EFAULT);
751 }
752 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOCUR)) {
753 if (v & WSDISPLAY_CURSOR_DOCUR)
754 cc->cc_hot = p->hot;
755 if (v & WSDISPLAY_CURSOR_DOPOS)
756 set_curpos(sc, &p->pos);
757 bt459_set_curpos(sc);
758 }
759
760 sc->sc_changed = 0;
761 if (v & WSDISPLAY_CURSOR_DOCUR) {
762 sc->sc_curenb = p->enable;
763 sc->sc_changed |= DATA_ENB_CHANGED;
764 }
765 if (v & WSDISPLAY_CURSOR_DOCMAP) {
766 copyin(p->cmap.red, &cc->cc_color[index], count);
767 copyin(p->cmap.green, &cc->cc_color[index + 2], count);
768 copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
769 sc->sc_changed |= DATA_CURCMAP_CHANGED;
770 }
771 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
772 cc->cc_size = p->size;
773 memset(cc->cc_image, 0, sizeof cc->cc_image);
774 copyin(p->image, cc->cc_image, icount);
775 copyin(p->mask, cc->cc_image+CURSOR_MAX_SIZE, icount);
776 sc->sc_changed |= DATA_CURSHAPE_CHANGED;
777 }
778
779 return (0);
780 #undef cc
781 }
782
783 static int
784 get_cursor(sc, p)
785 struct cfb_softc *sc;
786 struct wsdisplay_cursor *p;
787 {
788 return (ENOTTY); /* XXX */
789 }
790
791 static void
792 set_curpos(sc, curpos)
793 struct cfb_softc *sc;
794 struct wsdisplay_curpos *curpos;
795 {
796 struct fb_devconfig *dc = sc->sc_dc;
797 int x = curpos->x, y = curpos->y;
798
799 if (y < 0)
800 y = 0;
801 else if (y > dc->dc_ht)
802 y = dc->dc_ht;
803 if (x < 0)
804 x = 0;
805 else if (x > dc->dc_wid)
806 x = dc->dc_wid;
807 sc->sc_cursor.cc_pos.x = x;
808 sc->sc_cursor.cc_pos.y = y;
809 }
810
811 void
812 bt459_set_curpos(sc)
813 struct cfb_softc *sc;
814 {
815 caddr_t cfbbase = (caddr_t)sc->sc_dc->dc_vaddr;
816 struct bt459reg *vdac = (void *)(cfbbase + CX_BT459_OFFSET);
817 int x, y, s;
818
819 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
820 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
821 x += sc->magic_x; y += sc->magic_y; /* magic offset of CX coordinate */
822
823 s = spltty();
824
825 BT459_SELECT(vdac, BT459_REG_CURSOR_X_LOW);
826 vdac->bt_reg = x; tc_wmb();
827 vdac->bt_reg = x >> 8; tc_wmb();
828 vdac->bt_reg = y; tc_wmb();
829 vdac->bt_reg = y >> 8; tc_wmb();
830
831 splx(s);
832 }
833