vidcvideo.c revision 1.19 1 /* $NetBSD: vidcvideo.c,v 1.19 2003/11/07 18:29:30 he Exp $ */
2
3 /*
4 * Copyright (c) 2001 Reinoud Zandijk
5 * Copyright (c) 1998, 1999 Tohru Nishimura. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Tohru Nishimura
18 * and Reinoud Zandijk for the NetBSD Project.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 * Created vidcvideo.c from /dev/tc/cfb.c to fit the Acorn/ARM VIDC1 and VIDC20 chips
34 *
35 */
36
37 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
38
39 __KERNEL_RCSID(0, "$NetBSD: vidcvideo.c,v 1.19 2003/11/07 18:29:30 he Exp $");
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/kernel.h>
44 #include <sys/device.h>
45 #include <sys/malloc.h>
46 #include <sys/buf.h>
47 #include <sys/ioctl.h>
48
49 #include <arm/mainbus/mainbus.h>
50 #include <machine/bus.h>
51 #include <machine/intr.h>
52
53 #include <dev/wscons/wsconsio.h>
54 #include <dev/wscons/wsdisplayvar.h>
55
56 #include <dev/rasops/rasops.h>
57 #include <dev/wsfont/wsfont.h>
58
59 #include <uvm/uvm_extern.h>
60 #include <arm/arm32/pmap.h>
61 #include <arm/cpufunc.h>
62 #include <machine/intr.h>
63
64 /* for vidc_mode ... needs to be MI indepenent one day */
65 #include <arm/iomd/vidc.h>
66 #include <arm/iomd/vidc20config.h>
67 #include <arm/iomd/vidcvideo.h>
68 #include <machine/bootconfig.h>
69
70 /* FOR DEBUG */
71 extern videomemory_t videomemory;
72
73 struct hwcmap256 {
74 #define CMAP_SIZE 256 /* 256 R/G/B entries */
75 u_int8_t r[CMAP_SIZE];
76 u_int8_t g[CMAP_SIZE];
77 u_int8_t b[CMAP_SIZE];
78 };
79
80
81 /* XXX for CURSOR_MAX_WIDTH = 32 */
82 struct hwcursor32 {
83 struct wsdisplay_curpos cc_pos;
84 struct wsdisplay_curpos cc_hot;
85 struct wsdisplay_curpos cc_size;
86 struct wsdisplay_curpos cc_magic;
87 u_int8_t cc_color[6]; /* how many? */
88 u_int32_t cc_image[(CURSOR_MAX_WIDTH/4) * CURSOR_MAX_HEIGHT];
89 u_int32_t cc_mask[(CURSOR_MAX_WIDTH/4) * CURSOR_MAX_HEIGHT];
90 };
91
92
93 struct fb_devconfig {
94 vaddr_t dc_vaddr; /* memory space virtual base address */
95 paddr_t dc_paddr; /* memory space physical base address */
96 vsize_t dc_size; /* size of slot memory */
97 int dc_wid; /* width of frame buffer */
98 int dc_ht; /* height of frame buffer */
99 int dc_log2_depth; /* log2 of bits per pixel */
100 int dc_depth; /* depth, bits per pixel */
101 int dc_rowbytes; /* bytes in a FB scan line */
102 vaddr_t dc_videobase; /* base of flat frame buffer */
103 int dc_blanked; /* currently has video disabled */
104 void *dc_hwscroll_cookie; /* cookie for hardware scroll */
105
106 int dc_curenb; /* is cursor sprite enabled ? */
107 int dc_changed; /* need update of hardware */
108 int dc_writeback_delay; /* Screenarea write back vsync counter */
109 #define WSDISPLAY_CMAP_DOLUT 0x20
110 #define WSDISPLAY_VIDEO_ONOFF 0x40
111 #define WSDISPLAY_WB_COUNTER 0x80
112
113 struct hwcmap256 dc_cmap;/* software copy of colormap */
114 struct hwcursor32 dc_cursor;/* software copy of cursor */
115
116 struct vidc_mode mode_info;
117 struct rasops_info rinfo;
118
119 struct wsdisplay_emulops orig_ri_ops; /* Rasops functions for deligation */
120 };
121
122
123 struct vidcvideo_softc {
124 struct device sc_dev;
125 struct fb_devconfig *sc_dc; /* device configuration */
126 int nscreens; /* number of screens configured */
127 };
128
129
130 /* XXX has to go XXX */
131 #define CX_MAGIC_X 220
132 #define CX_MAGIC_Y 35
133 #define CX_FB_OFFSET 0x000000
134 #define CX_FB_SIZE 0x100000
135 #define CX_BT459_OFFSET 0x200000
136 #define CX_OFFSET_IREQ 0x300000 /* Interrupt req. control */
137 /* XXX till here XXX */
138
139
140 /* Function prototypes for glue */
141 static int vidcvideo_match __P((struct device *, struct cfdata *, void *));
142 static void vidcvideo_attach __P((struct device *, struct device *, void *));
143
144
145 /* config glue */
146 CFATTACH_DECL(vidcvideo, sizeof(struct vidcvideo_softc),
147 vidcvideo_match, vidcvideo_attach, NULL, NULL);
148
149 static struct fb_devconfig vidcvideo_console_dc;
150 static int vidcvideo_is_console;
151
152
153 static struct wsscreen_descr vidcvideo_stdscreen = {
154 "std", 0, 0,
155 0, /* textops */
156 0, 0,
157 WSSCREEN_REVERSE
158 };
159
160 static const struct wsscreen_descr *_vidcvideo_scrlist[] = {
161 &vidcvideo_stdscreen,
162 };
163
164 static const struct wsscreen_list vidcvideo_screenlist = {
165 sizeof(_vidcvideo_scrlist) / sizeof(struct wsscreen_descr *), _vidcvideo_scrlist
166 };
167
168 static int vidcvideoioctl __P((void *, u_long, caddr_t, int, struct proc *));
169 static paddr_t vidcvideommap __P((void *, off_t, int));
170
171 static int vidcvideo_alloc_screen __P((void *, const struct wsscreen_descr *,
172 void **, int *, int *, long *));
173 static void vidcvideo_free_screen __P((void *, void *));
174 static int vidcvideo_show_screen __P((void *, void *, int,
175 void (*) (void *, int, int), void *));
176
177 static const struct wsdisplay_accessops vidcvideo_accessops = {
178 vidcvideoioctl,
179 vidcvideommap,
180 vidcvideo_alloc_screen,
181 vidcvideo_free_screen,
182 vidcvideo_show_screen,
183 NULL, /* load_font */
184 NULL, /* pollc */
185 NULL, /* getwschar */
186 NULL /* putwschar */
187 };
188
189
190 /* Function prototypes */
191 int vidcvideo_cnattach __P((vaddr_t));
192 static void vidcvideo_colourmap_and_cursor_init __P((struct fb_devconfig *));
193
194 static int get_cmap __P((struct vidcvideo_softc *, struct wsdisplay_cmap *));
195 static int set_cmap __P((struct vidcvideo_softc *, struct wsdisplay_cmap *));
196 static int set_cursor __P((struct vidcvideo_softc *, struct wsdisplay_cursor *));
197 static int get_cursor __P((struct vidcvideo_softc *, struct wsdisplay_cursor *));
198 static void set_curpos __P((struct vidcvideo_softc *, struct wsdisplay_curpos *));
199 static void vidcvideo_getdevconfig __P((vaddr_t, struct fb_devconfig *));
200
201 static int vidcvideointr __P((void *));
202 static void vidcvideo_config_wscons __P((struct fb_devconfig *));
203
204
205 /* Acceleration function prototypes */
206 static void vv_copyrows __P((void *, int, int, int));
207 static void vv_eraserows __P((void *, int, int, long));
208 static void vv_putchar __P((void *c, int row, int col, u_int uc, long attr));
209
210
211 static int
212 vidcvideo_match(parent, match, aux)
213 struct device *parent;
214 struct cfdata *match;
215 void *aux;
216 {
217 /* Can't probe AFAIK ; how ? */
218 return (1);
219 }
220
221
222 static void
223 vidcvideo_getdevconfig(dense_addr, dc)
224 vaddr_t dense_addr;
225 struct fb_devconfig *dc;
226 {
227 dc->dc_vaddr = dense_addr;
228 (void) pmap_extract(pmap_kernel(), dc->dc_vaddr, &(dc->dc_paddr));
229
230 vidcvideo_getmode(&dc->mode_info);
231
232 dc->dc_wid = dc->mode_info.hder;
233 dc->dc_ht = dc->mode_info.vder;
234 dc->dc_log2_depth = dc->mode_info.log2_bpp;
235 dc->dc_depth = 1 << dc->dc_log2_depth;
236 dc->dc_videobase = dc->dc_vaddr;
237 dc->dc_blanked = 0;
238
239 /* this should/could be done somewhat more elegant! */
240 switch (dc->dc_depth) {
241 case 1:
242 dc->dc_rowbytes = dc->dc_wid / 8;
243 break;
244 case 2:
245 dc->dc_rowbytes = dc->dc_wid / 4;
246 break;
247 case 4:
248 dc->dc_rowbytes = dc->dc_wid / 2;
249 break;
250 case 8:
251 dc->dc_rowbytes = dc->dc_wid;
252 break;
253 case 16:
254 dc->dc_rowbytes = dc->dc_wid * 2;
255 break;
256 case 32:
257 dc->dc_rowbytes = dc->dc_wid * 4;
258 break;
259 default:
260 printf("Unknown colour depth %d ... what to do ?", dc->dc_depth);
261 break;
262 };
263
264 /* euhm... correct ? i.e. not complete VIDC memory */
265 dc->dc_size = dc->mode_info.vder * dc->dc_rowbytes;
266
267 /* initialize colormap and cursor resource */
268 vidcvideo_colourmap_and_cursor_init(dc);
269
270 dc->rinfo.ri_flg = 0; /* RI_CENTER; */
271 dc->rinfo.ri_depth = dc->dc_depth;
272 dc->rinfo.ri_bits = (void *) dc->dc_videobase;
273 dc->rinfo.ri_width = dc->dc_wid;
274 dc->rinfo.ri_height = dc->dc_ht;
275 dc->rinfo.ri_stride = dc->dc_rowbytes;
276 dc->rinfo.ri_hw = dc; /* link back */
277
278 /* intitialise miscelanious */
279 dc->dc_writeback_delay = 0;
280 }
281
282
283 static void
284 vidcvideo_config_wscons(dc)
285 struct fb_devconfig *dc;
286 {
287 int i, cookie, font_not_locked;
288
289 /* clear the screen ; why not a memset ? - it was this way so keep it for now */
290 for (i = 0; i < dc->dc_ht * dc->dc_rowbytes; i += sizeof(u_int32_t))
291 *(u_int32_t *)(dc->dc_videobase + i) = 0x0;
292
293 wsfont_init();
294
295 /* prefer 8 pixel wide font */
296 cookie = wsfont_find(NULL, 8, 0, 0, WSDISPLAY_FONTORDER_L2R,
297 WSDISPLAY_FONTORDER_L2R);
298 if (cookie <= 0)
299 cookie = wsfont_find(NULL, 0, 0, 0, WSDISPLAY_FONTORDER_L2R,
300 WSDISPLAY_FONTORDER_L2R);
301
302 if (cookie < 0) {
303 /* Can I even print here ? */
304 printf("Font table empty! exiting\n");
305 return;
306 };
307
308 font_not_locked = wsfont_lock(cookie, &dc->rinfo.ri_font);
309
310 dc->rinfo.ri_wsfcookie = cookie;
311
312 rasops_init(&dc->rinfo,
313 dc->rinfo.ri_height / dc->rinfo.ri_font->fontheight,
314 dc->rinfo.ri_width / dc->rinfo.ri_font->fontwidth
315 );
316
317 /*
318 * Provide a hook for the acceleration functions and make a copy of the
319 * original rasops functions for passing on calls
320 */
321 dc->rinfo.ri_hw = dc;
322 memcpy(&(dc->orig_ri_ops), &(dc->rinfo.ri_ops), sizeof(struct wsdisplay_emulops));
323
324 /* add our accelerated functions */
325 dc->rinfo.ri_ops.eraserows = vv_eraserows;
326 dc->rinfo.ri_ops.copyrows = vv_copyrows;
327
328 /* add the extra activity measuring functions; they just delegate on */
329 dc->rinfo.ri_ops.putchar = vv_putchar;
330
331 /* XXX shouldn't be global */
332 vidcvideo_stdscreen.nrows = dc->rinfo.ri_rows;
333 vidcvideo_stdscreen.ncols = dc->rinfo.ri_cols;
334 vidcvideo_stdscreen.textops = &dc->rinfo.ri_ops;
335 vidcvideo_stdscreen.capabilities = dc->rinfo.ri_caps;
336
337 if (font_not_locked) {
338 printf(" warning ... couldn't lock font! ");
339 };
340 }
341
342
343 static void
344 vidcvideo_attach(parent, self, aux)
345 struct device *parent, *self;
346 void *aux;
347 {
348 struct vidcvideo_softc *sc = (struct vidcvideo_softc *)self;
349 struct fb_devconfig *dc;
350 struct wsemuldisplaydev_attach_args waa;
351 struct hwcmap256 *cm;
352 const u_int8_t *p;
353 long defattr;
354 int index;
355
356 vidcvideo_init();
357 if (sc->nscreens == 0) {
358 sc->sc_dc = &vidcvideo_console_dc;
359 if (!vidcvideo_is_console) {
360 printf(" : non console (no kbd yet) ");
361 vidcvideo_getdevconfig(videomemory.vidm_vbase, sc->sc_dc);
362 vidcvideo_config_wscons(sc->sc_dc);
363 (*sc->sc_dc->rinfo.ri_ops.allocattr)(&sc->sc_dc->rinfo, 0, 0, 0, &defattr);
364 };
365 sc->nscreens = 1;
366 } else {
367 printf(": allready attached ... can't cope with this\n");
368 return;
369 };
370
371 dc = sc->sc_dc;
372
373 vidcvideo_printdetails();
374 printf(": using %d x %d, %dbpp\n", dc->dc_wid, dc->dc_ht,
375 dc->dc_depth);
376
377 /* initialise rasops */
378 cm = &dc->dc_cmap;
379 p = rasops_cmap;
380 for (index = 0; index < CMAP_SIZE; index++, p += 3) {
381 cm->r[index] = p[0];
382 cm->g[index] = p[1];
383 cm->b[index] = p[2];
384 }
385
386 /* what does these do ? */
387 dc->dc_cursor.cc_magic.x = CX_MAGIC_X;
388 dc->dc_cursor.cc_magic.y = CX_MAGIC_Y;
389
390 /* set up interrupt flags */
391 dc->dc_changed |= WSDISPLAY_CMAP_DOLUT;
392
393 /*
394 * Set up a link in the rasops structure to our device config
395 * for acceleration stuff
396 */
397 dc->rinfo.ri_hw = sc->sc_dc;
398
399 /* Establish an interrupt handler, and clear any pending interrupts */
400 intr_claim(IRQ_FLYBACK, IPL_TTY, "vblank", vidcvideointr, dc);
401
402 waa.console = (vidcvideo_is_console ? 1 : 0);
403 waa.scrdata = &vidcvideo_screenlist;
404 waa.accessops = &vidcvideo_accessops;
405 waa.accesscookie = sc;
406
407 config_found(self, &waa, wsemuldisplaydevprint);
408 }
409
410
411 static int
412 vidcvideoioctl(v, cmd, data, flag, p)
413 void *v;
414 u_long cmd;
415 caddr_t data;
416 int flag;
417 struct proc *p;
418 {
419 struct vidcvideo_softc *sc = v;
420 struct fb_devconfig *dc = sc->sc_dc;
421 int state;
422
423 switch (cmd) {
424 case WSDISPLAYIO_GTYPE:
425 *(u_int *)data = WSDISPLAY_TYPE_VIDC;
426 return (0);
427
428 case WSDISPLAYIO_GINFO:
429 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
430 wsd_fbip->height = dc->dc_ht;
431 wsd_fbip->width = dc->dc_wid;
432 wsd_fbip->depth = dc->dc_depth;
433 wsd_fbip->cmsize = CMAP_SIZE;
434 #undef fbt
435 return (0);
436
437 case WSDISPLAYIO_GETCMAP:
438 return get_cmap(sc, (struct wsdisplay_cmap *)data);
439
440 case WSDISPLAYIO_PUTCMAP:
441 return set_cmap(sc, (struct wsdisplay_cmap *)data);
442
443 case WSDISPLAYIO_SVIDEO:
444 state = *(int *)data;
445 dc->dc_blanked = (state == WSDISPLAYIO_VIDEO_OFF);
446 dc->dc_changed |= WSDISPLAY_VIDEO_ONOFF;
447 /* done on video blank */
448 return (0);
449
450 case WSDISPLAYIO_GVIDEO:
451 *(u_int *)data = dc->dc_blanked ?
452 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
453 return (0);
454
455 case WSDISPLAYIO_GCURPOS:
456 *(struct wsdisplay_curpos *)data = dc->dc_cursor.cc_pos;
457 return (0);
458
459 case WSDISPLAYIO_SCURPOS:
460 set_curpos(sc, (struct wsdisplay_curpos *)data);
461 dc->dc_changed |= WSDISPLAY_CURSOR_DOPOS;
462 return (0);
463
464 case WSDISPLAYIO_GCURMAX:
465 ((struct wsdisplay_curpos *)data)->x = CURSOR_MAX_WIDTH;
466 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_HEIGHT;
467 return (0);
468
469 case WSDISPLAYIO_GCURSOR:
470 return get_cursor(sc, (struct wsdisplay_cursor *)data);
471
472 case WSDISPLAYIO_SCURSOR:
473 return set_cursor(sc, (struct wsdisplay_cursor *)data);
474
475 case WSDISPLAYIO_SMODE:
476 state = *(int *)data;
477 if (state == WSDISPLAYIO_MODE_MAPPED) {
478 dc->dc_hwscroll_cookie = vidcvideo_hwscroll_reset();
479 };
480 if (state == WSDISPLAYIO_MODE_EMUL) {
481 vidcvideo_hwscroll_back(dc->dc_hwscroll_cookie);
482 };
483 vidcvideo_progr_scroll();
484
485 return (0);
486 }
487 return EPASSTHROUGH;
488 }
489
490
491 paddr_t
492 vidcvideommap(v, offset, prot)
493 void *v;
494 off_t offset;
495 int prot;
496 {
497 struct vidcvideo_softc *sc = v;
498
499 if (offset >= sc->sc_dc->dc_size || offset < 0)
500 return (-1);
501
502 return arm_btop(sc->sc_dc->dc_paddr + offset);
503 }
504
505
506 static int
507 vidcvideo_alloc_screen(v, type, cookiep, curxp, curyp, attrp)
508 void *v;
509 const struct wsscreen_descr *type;
510 void **cookiep;
511 int *curxp, *curyp;
512 long *attrp;
513 {
514 struct vidcvideo_softc *sc = v;
515 struct fb_devconfig *dc = sc->sc_dc;
516 long defattr;
517
518 /*
519 * One and just only one for now :( ... if the vidcconsole is not the
520 * console then this makes one wsconsole screen free for use !
521 */
522 if ((sc->nscreens > 1) || vidcvideo_is_console)
523 return (ENOMEM);
524
525 /* Add the screen to wscons to control */
526 *cookiep = &dc->rinfo;
527 *curxp = 0;
528 *curyp = 0;
529 vidcvideo_getdevconfig(videomemory.vidm_vbase, dc);
530 vidcvideo_config_wscons(dc);
531 (*dc->rinfo.ri_ops.allocattr)(&dc->rinfo, 0, 0, 0, &defattr);
532 *attrp = defattr;
533 sc->nscreens++;
534
535 return (0);
536 }
537
538
539 static void
540 vidcvideo_free_screen(v, cookie)
541 void *v;
542 void *cookie;
543 {
544 struct vidcvideo_softc *sc = v;
545
546 if (sc->sc_dc == &vidcvideo_console_dc)
547 panic("vidcvideo_free_screen: console");
548
549 sc->nscreens--;
550 }
551
552
553 static int
554 vidcvideo_show_screen(v, cookie, waitok, cb, cbarg)
555 void *v;
556 void *cookie;
557 int waitok;
558 void (*cb) __P((void *, int, int));
559 void *cbarg;
560 {
561
562 return (0);
563 }
564
565
566 /* EXPORT */ int
567 vidcvideo_cnattach(addr)
568 vaddr_t addr;
569 {
570 struct fb_devconfig *dcp = &vidcvideo_console_dc;
571 long defattr;
572
573 vidcvideo_init();
574 vidcvideo_getdevconfig(addr, dcp);
575 vidcvideo_config_wscons(dcp);
576 (*dcp->rinfo.ri_ops.allocattr)(&dcp->rinfo, 0, 0, 0, &defattr);
577 wsdisplay_cnattach(&vidcvideo_stdscreen, &dcp->rinfo, 0, 0, defattr);
578
579 vidcvideo_is_console = 1;
580 return(0);
581 }
582
583
584 static int
585 vidcvideointr(arg)
586 void *arg;
587 {
588 struct fb_devconfig *dc = arg;
589 int v, cleared = 0;
590
591 v = dc->dc_changed;
592 if (v == 0)
593 return (1);
594
595 if (v & WSDISPLAY_WB_COUNTER) {
596 dc->dc_writeback_delay--;
597 if (dc->dc_writeback_delay == 0) {
598 cpu_dcache_wb_range(dc->dc_vaddr, dc->dc_size);
599 cleared |= WSDISPLAY_WB_COUNTER;
600 };
601 }
602
603 if (v & WSDISPLAY_CMAP_DOLUT) {
604 struct hwcmap256 *cm = &dc->dc_cmap;
605 int index;
606
607 if (dc->dc_depth == 4) {
608 /* palette for 4 bpp is different from 8bpp */
609 vidcvideo_write(VIDC_PALREG, 0x00000000);
610 for (index=0; index < (1 << dc->dc_depth); index++)
611 vidcvideo_write(VIDC_PALETTE,
612 VIDC_COL(cm->r[index],
613 cm->g[index],
614 cm->b[index]));
615 ;
616 };
617
618 if (dc->dc_depth == 8) {
619 /* dunno what to do in more than 8bpp */
620 /* palettes only make sense in 8bpp and less modes on VIDC */
621 vidcvideo_write(VIDC_PALREG, 0x00000000);
622 for (index = 0; index < CMAP_SIZE; index++) {
623 vidcvideo_write(VIDC_PALETTE,
624 VIDC_COL(cm->r[index], cm->g[index], cm->b[index])
625 );
626 };
627 };
628 cleared |= WSDISPLAY_CMAP_DOLUT;
629 }
630
631 if (v & WSDISPLAY_VIDEO_ONOFF) {
632 vidcvideo_blank(dc->dc_blanked);
633 cleared |= WSDISPLAY_VIDEO_ONOFF;
634 };
635
636 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
637 int x, y;
638 x = dc->dc_cursor.cc_pos.x - dc->dc_cursor.cc_hot.x;
639 y = dc->dc_cursor.cc_pos.y - dc->dc_cursor.cc_hot.y;
640
641 vidcvideo_updatecursor(x, y);
642 cleared |= WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT;
643 };
644
645 if (v & WSDISPLAY_CURSOR_DOCUR) {
646 vidcvideo_enablecursor(dc->dc_curenb);
647 cleared |= WSDISPLAY_CURSOR_DOCUR;
648 };
649
650
651 #if 0 /* XXX snip XXX */
652 /* XXX kept here as an archive for now XXX */
653
654 vdac = vidcvideobase + CX_BT459_OFFSET;
655 v = sc->sc_changed;
656 if (v & WSDISPLAY_CURSOR_DOCUR) {
657 SELECT(vdac, BT459_IREG_CCR);
658 REG(vdac, bt_reg) = (sc->sc_curenb) ? 0xc0 : 0x00;
659 }
660 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
661 int x, y;
662
663 x = sc->sc_cursor.cc_pos.x - sc->sc_cursor.cc_hot.x;
664 y = sc->sc_cursor.cc_pos.y - sc->sc_cursor.cc_hot.y;
665
666 x += sc->sc_cursor.cc_magic.x;
667 y += sc->sc_cursor.cc_magic.y;
668
669 SELECT(vdac, BT459_IREG_CURSOR_X_LOW);
670 REG(vdac, bt_reg) = x; tc_wmb();
671 REG(vdac, bt_reg) = x >> 8; tc_wmb();
672 REG(vdac, bt_reg) = y; tc_wmb();
673 REG(vdac, bt_reg) = y >> 8; tc_wmb();
674 }
675 if (v & WSDISPLAY_CURSOR_DOCMAP) {
676 u_int8_t *cp = sc->sc_cursor.cc_color;
677
678 SELECT(vdac, BT459_IREG_CCOLOR_2);
679 REG(vdac, bt_reg) = cp[1]; tc_wmb();
680 REG(vdac, bt_reg) = cp[3]; tc_wmb();
681 REG(vdac, bt_reg) = cp[5]; tc_wmb();
682
683 REG(vdac, bt_reg) = cp[0]; tc_wmb();
684 REG(vdac, bt_reg) = cp[2]; tc_wmb();
685 REG(vdac, bt_reg) = cp[4]; tc_wmb();
686 }
687 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
688 u_int8_t *ip, *mp, img, msk;
689 u_int8_t u;
690 int bcnt;
691
692 ip = (u_int8_t *)sc->sc_cursor.cc_image;
693 mp = (u_int8_t *)(sc->sc_cursor.cc_image + CURSOR_MAX_HEIGHT);
694
695 bcnt = 0;
696 SELECT(vdac, BT459_IREG_CRAM_BASE+0);
697 /* 64 pixel scan line is consisted with 16 byte cursor ram */
698 while (bcnt < sc->sc_cursor.cc_size.y * 16) {
699 /* pad right half 32 pixel when smaller than 33 */
700 if ((bcnt & 0x8) && sc->sc_cursor.cc_size.x < 33) {
701 REG(vdac, bt_reg) = 0; tc_wmb();
702 REG(vdac, bt_reg) = 0; tc_wmb();
703 }
704 else {
705 img = *ip++;
706 msk = *mp++;
707 img &= msk; /* cookie off image */
708 u = (msk & 0x0f) << 4 | (img & 0x0f);
709 REG(vdac, bt_reg) = shuffle[u]; tc_wmb();
710 u = (msk & 0xf0) | (img & 0xf0) >> 4;
711 REG(vdac, bt_reg) = shuffle[u]; tc_wmb();
712 }
713 bcnt += 2;
714 }
715 /* pad unoccupied scan lines */
716 while (bcnt < CURSOR_MAX_HEIGHT * 16) {
717 REG(vdac, bt_reg) = 0; tc_wmb();
718 REG(vdac, bt_reg) = 0; tc_wmb();
719 bcnt += 2;
720 }
721 }
722 #endif /* XXX snip XXX */
723
724 dc->dc_changed ^= cleared;
725
726 return (1);
727 }
728
729
730 static u_char ri_col_data[6][6] = {
731 { 0, 0, 0, 0, 0, 0}, /* 1 bpp */
732 { 0, 0, 0, 0, 0, 0}, /* 2 bpp */
733 { 0, 0, 0, 0, 0, 0}, /* 4 bpp */
734 { 0, 0, 0, 0, 0, 0}, /* 8 bpp */
735 { 6, 5, 5, 0, 6, 11}, /* 16 bpp */
736 { 8, 8, 8, 0, 8, 16}, /* 32 bpp */
737 };
738
739 static void
740 vidcvideo_colourmap_and_cursor_init(dc)
741 struct fb_devconfig *dc;
742 {
743 struct rasops_info *ri = &dc->rinfo;
744 u_char *rgbdat;
745
746 /* Whatever we do later... just make sure we have a
747 * sane palette to start with
748 */
749 vidcvideo_stdpalette();
750
751 /* set up rgb bit pattern values for rasops_init */
752 rgbdat = ri_col_data[dc->dc_log2_depth];
753 ri->ri_rnum = rgbdat[0];
754 ri->ri_gnum = rgbdat[1];
755 ri->ri_bnum = rgbdat[2];
756 ri->ri_rpos = rgbdat[3];
757 ri->ri_gpos = rgbdat[4];
758 ri->ri_bpos = rgbdat[5];
759
760 }
761
762
763 static int
764 get_cmap(sc, p)
765 struct vidcvideo_softc *sc;
766 struct wsdisplay_cmap *p;
767 {
768 u_int index = p->index, count = p->count;
769
770 if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
771 return (EINVAL);
772
773 if (!uvm_useracc(p->red, count, B_WRITE) ||
774 !uvm_useracc(p->green, count, B_WRITE) ||
775 !uvm_useracc(p->blue, count, B_WRITE))
776 return (EFAULT);
777
778 copyout(&sc->sc_dc->dc_cmap.r[index], p->red, count);
779 copyout(&sc->sc_dc->dc_cmap.g[index], p->green, count);
780 copyout(&sc->sc_dc->dc_cmap.b[index], p->blue, count);
781
782 return (0);
783 }
784
785
786 static int
787 set_cmap(sc, p)
788 struct vidcvideo_softc *sc;
789 struct wsdisplay_cmap *p;
790 {
791 struct fb_devconfig *dc = sc->sc_dc;
792 u_int index = p->index, count = p->count;
793
794 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
795 return (EINVAL);
796
797 if (!uvm_useracc(p->red, count, B_READ) ||
798 !uvm_useracc(p->green, count, B_READ) ||
799 !uvm_useracc(p->blue, count, B_READ))
800 return (EFAULT);
801
802 copyin(p->red, &dc->dc_cmap.r[index], count);
803 copyin(p->green, &dc->dc_cmap.g[index], count);
804 copyin(p->blue, &dc->dc_cmap.b[index], count);
805 dc->dc_changed |= WSDISPLAY_CMAP_DOLUT;
806 return (0);
807 }
808
809
810 static int
811 set_cursor(sc, p)
812 struct vidcvideo_softc *sc;
813 struct wsdisplay_cursor *p;
814 {
815 #define cc (&dc->dc_cursor)
816 struct fb_devconfig *dc = sc->sc_dc;
817 u_int v, index, count, icount;
818
819 /* XXX gcc does not detect identical conditions */
820 index = count = icount = 0;
821
822 v = p->which;
823 if (v & WSDISPLAY_CURSOR_DOCMAP) {
824 index = p->cmap.index;
825 count = p->cmap.count;
826 if (index >= CURSOR_MAX_COLOURS || (index + count) > CURSOR_MAX_COLOURS)
827 return (EINVAL);
828 if (!uvm_useracc(p->cmap.red, count, B_READ) ||
829 !uvm_useracc(p->cmap.green, count, B_READ) ||
830 !uvm_useracc(p->cmap.blue, count, B_READ))
831 return (EFAULT);
832 }
833 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
834 if (p->size.x > CURSOR_MAX_WIDTH || p->size.y > CURSOR_MAX_HEIGHT)
835 return (EINVAL);
836 icount = sizeof(u_int32_t) * p->size.y;
837 if (!uvm_useracc(p->image, icount, B_READ) ||
838 !uvm_useracc(p->mask, icount, B_READ))
839 return (EFAULT);
840 }
841
842 if (v & WSDISPLAY_CURSOR_DOCUR)
843 dc->dc_curenb = p->enable;
844 if (v & WSDISPLAY_CURSOR_DOPOS)
845 set_curpos(sc, &p->pos);
846 if (v & WSDISPLAY_CURSOR_DOHOT)
847 cc->cc_hot = p->hot;
848 if (v & WSDISPLAY_CURSOR_DOCMAP) {
849 copyin(p->cmap.red, &cc->cc_color[index], count);
850 copyin(p->cmap.green, &cc->cc_color[index + 2], count);
851 copyin(p->cmap.blue, &cc->cc_color[index + 4], count);
852 }
853 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
854 cc->cc_size = p->size;
855 memset(cc->cc_image, 0, sizeof cc->cc_image);
856 memset(cc->cc_mask, 0, sizeof cc->cc_mask);
857 copyin(p->image, cc->cc_image, icount);
858 copyin(p->mask, cc->cc_mask, icount);
859 }
860 dc->dc_changed |= v;
861
862 return (0);
863 #undef cc
864 }
865
866
867 static int
868 get_cursor(sc, p)
869 struct vidcvideo_softc *sc;
870 struct wsdisplay_cursor *p;
871 {
872 return (EPASSTHROUGH); /* XXX */
873 }
874
875
876 static void
877 set_curpos(sc, curpos)
878 struct vidcvideo_softc *sc;
879 struct wsdisplay_curpos *curpos;
880 {
881 struct fb_devconfig *dc = sc->sc_dc;
882 int x = curpos->x, y = curpos->y;
883
884 if (y < 0)
885 y = 0;
886 else if (y > dc->dc_ht)
887 y = dc->dc_ht;
888 if (x < 0)
889 x = 0;
890 else if (x > dc->dc_wid)
891 x = dc->dc_wid;
892 dc->dc_cursor.cc_pos.x = x;
893 dc->dc_cursor.cc_pos.y = y;
894 }
895
896
897 static void vv_copyrows(id, srcrow, dstrow, nrows)
898 void *id;
899 int srcrow, dstrow, nrows;
900 {
901 struct rasops_info *ri = id;
902 int height, offset, size;
903 int scrollup, scrolldown;
904 unsigned char *src, *dst;
905
906 /* All movements are done in multiples of character heigths */
907 height = ri->ri_font->fontheight * nrows;
908 offset = (srcrow - dstrow) * ri->ri_yscale;
909 size = height * ri->ri_stride;
910
911 /* check if we are full screen scrolling */
912 scrollup = (srcrow + nrows >= ri->ri_rows);
913 scrolldown = (dstrow + nrows >= ri->ri_rows);
914
915 if ((scrollup || scrolldown) && (videomemory.vidm_type == VIDEOMEM_TYPE_VRAM)) {
916 ri->ri_bits = vidcvideo_hwscroll(offset);
917 vidcvideo_progr_scroll(); /* sadistic ; shouldnt this be on vsync? */
918
919 /* wipe out remains of the screen if nessisary */
920 if (ri->ri_emuheight != ri->ri_height) vv_eraserows(id, ri->ri_rows, 1, 0);
921 return;
922 };
923
924 /* Else we just copy the area : we're braindead for now
925 * Note: we can't use hardware scrolling when the softc isnt known yet...
926 * if its not known we dont have interrupts and we can't change the display
927 * address reliable other than in a Vsync
928 */
929
930 src = ri->ri_bits + srcrow * ri->ri_font->fontheight * ri->ri_stride;
931 dst = ri->ri_bits + dstrow * ri->ri_font->fontheight * ri->ri_stride;
932
933 bcopy(src, dst, size);
934 }
935
936
937 static void vv_eraserows(id, startrow, nrows, attr)
938 void *id;
939 int startrow, nrows;
940 long attr;
941 {
942 struct rasops_info *ri = id;
943 int height;
944 unsigned char *src;
945
946 /* we're braindead for now */
947 height = ri->ri_font->fontheight * nrows * ri->ri_stride;
948
949 src = ri->ri_bits + startrow * ri->ri_font->fontheight * ri->ri_stride;
950
951 bzero(src, height);
952 }
953
954
955 static void vv_putchar(id, row, col, uc, attr)
956 void *id;
957 int row, col;
958 u_int uc;
959 long attr;
960 {
961 struct rasops_info *ri = id;
962 struct fb_devconfig *dc = (struct fb_devconfig *) (ri->ri_hw);
963
964 /* delay the write back operation of the screen area */
965 dc->dc_writeback_delay = SCREEN_WRITE_BACK_DELAY;
966 dc->dc_changed |= WSDISPLAY_WB_COUNTER;
967
968 /* just delegate */
969 dc->orig_ri_ops.putchar(id, row, col, uc, attr);
970 }
971