vidcvideo.c revision 1.36 1 /* $NetBSD: vidcvideo.c,v 1.36 2009/03/14 15:36:02 dsl 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.36 2009/03/14 15:36:02 dsl 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 <dev/wscons/wsdisplay_vconsvar.h>
60
61 #include <uvm/uvm_extern.h>
62 #include <arm/arm32/pmap.h>
63 #include <arm/cpufunc.h>
64
65 /* for vidc_mode ... needs to be MI indepenent one day */
66 #include <arm/iomd/vidc.h>
67 #include <arm/iomd/vidc20config.h>
68 #include <arm/iomd/vidcvideo.h>
69 #include <machine/bootconfig.h>
70
71 /* FOR DEBUG */
72 extern videomemory_t videomemory;
73
74 struct hwcmap256 {
75 #define CMAP_SIZE 256 /* 256 R/G/B entries */
76 uint8_t r[CMAP_SIZE];
77 uint8_t g[CMAP_SIZE];
78 uint8_t b[CMAP_SIZE];
79 };
80
81
82 /* XXX for CURSOR_MAX_WIDTH = 32 */
83 struct hwcursor32 {
84 struct wsdisplay_curpos cc_pos;
85 struct wsdisplay_curpos cc_hot;
86 struct wsdisplay_curpos cc_size;
87 uint8_t cc_color[6]; /* how many? */
88 uint32_t cc_image[(CURSOR_MAX_WIDTH/4) * CURSOR_MAX_HEIGHT];
89 uint32_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_width; /* width of frame buffer */
98 int dc_height; /* 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 void *dc_ih; /* interrupt handler for dc */
106
107 int dc_curenb; /* is cursor sprite enabled ? */
108 int _internal_dc_changed; /* need update of hardware */
109 int dc_writeback_delay; /* Screenarea write back vsync counter */
110 #define WSDISPLAY_CMAP_DOLUT 0x20
111 #define WSDISPLAY_VIDEO_ONOFF 0x40
112 #define WSDISPLAY_WB_COUNTER 0x80
113
114 struct hwcmap256 dc_cmap; /* software copy of colormap */
115 struct hwcursor32 dc_cursor; /* software copy of cursor */
116
117 struct vidc_mode mode_info;
118
119 struct wsdisplay_emulops orig_ri_ops; /* Rasops functions for deligation */
120
121 /* virtual console support */
122 struct vcons_data dc_vd;
123 struct vcons_screen dc_console;
124 };
125
126
127 struct vidcvideo_softc {
128 struct device sc_dev;
129 struct fb_devconfig *sc_dc; /* device configuration */
130 };
131
132
133 /* Function prototypes for glue */
134 static int vidcvideo_match(struct device *, struct cfdata *, void *);
135 static void vidcvideo_attach(struct device *, struct device *, void *);
136
137
138 /* config glue */
139 CFATTACH_DECL(vidcvideo, sizeof(struct vidcvideo_softc),
140 vidcvideo_match, vidcvideo_attach, NULL, NULL);
141
142 static struct fb_devconfig vidcvideo_console_dc;
143 static bool vidcvideo_is_console = false;
144
145
146 static struct wsscreen_descr vidcvideo_stdscreen = {
147 "std", 0, 0,
148 NULL, /* textops */
149 8, 16,
150 WSSCREEN_WSCOLORS | WSSCREEN_HILIT,
151 NULL
152 };
153
154 static const struct wsscreen_descr *_vidcvideo_scrlist[] = {
155 &vidcvideo_stdscreen,
156 };
157
158 static const struct wsscreen_list vidcvideo_screenlist = {
159 sizeof(_vidcvideo_scrlist) / sizeof(struct wsscreen_descr *),
160 _vidcvideo_scrlist
161 };
162
163 static int vidcvideoioctl(void *, void *, u_long, void *, int,
164 struct lwp *);
165 static paddr_t vidcvideommap(void *, void *, off_t, int);
166 static void vidcvideoinit_screen(void *, struct vcons_screen *, int, long *);
167
168 static void vidcvideo_queue_dc_change(struct fb_devconfig*, int);
169 static int flush_dc_changes_to_screen(struct fb_devconfig*);
170
171 static struct wsdisplay_accessops vidcvideo_accessops = {
172 vidcvideoioctl,
173 vidcvideommap,
174 NULL, /* alloc_screen */
175 NULL, /* free_screen */
176 NULL, /* show_screen */
177 NULL, /* load_font */
178 NULL, /* pollc */
179 NULL /* scroll */
180 };
181
182
183 /* Function prototypes */
184 int vidcvideo_cnattach(vaddr_t);
185 static void vidcvideo_colourmap_and_cursor_init(struct fb_devconfig *);
186
187 static int get_cmap(struct vidcvideo_softc *, struct wsdisplay_cmap *);
188 static int set_cmap(struct vidcvideo_softc *, struct wsdisplay_cmap *);
189 static int set_cursor(struct vidcvideo_softc *, struct wsdisplay_cursor *);
190 static int get_cursor(struct vidcvideo_softc *, struct wsdisplay_cursor *);
191 static void set_curpos(struct vidcvideo_softc *, struct wsdisplay_curpos *);
192 static void vidcvideo_getdevconfig(vaddr_t, u_int, struct fb_devconfig *);
193
194 static int vidcvideointr(void *);
195
196 /* Acceleration function prototypes */
197 static void vv_copyrows(void *, int, int, int);
198 static void vv_eraserows(void *, int, int, long);
199 static void vv_putchar(void *c, int row, int col, u_int uc, long attr);
200
201
202 static int
203 vidcvideo_match(struct device *parent, struct cfdata *match, void *aux)
204 {
205
206 /* Can't probe AFAIK ; how ? */
207 return 1;
208 }
209
210
211 static void
212 vidcvideo_getdevconfig(vaddr_t dense_addr, u_int mem_size,
213 struct fb_devconfig *dc)
214 {
215
216 dc->dc_vaddr = dense_addr;
217 (void) pmap_extract(pmap_kernel(), dc->dc_vaddr, &(dc->dc_paddr));
218
219 vidcvideo_getmode(&dc->mode_info);
220
221 dc->dc_width = dc->mode_info.timings.hdisplay;
222 dc->dc_height = dc->mode_info.timings.vdisplay;
223 dc->dc_log2_depth = dc->mode_info.log2_bpp;
224 dc->dc_depth = 1 << dc->dc_log2_depth;
225 dc->dc_videobase = dc->dc_vaddr;
226 dc->dc_blanked = 0;
227
228 /* this should/could be done somewhat more elegant! */
229 switch (dc->dc_depth) {
230 case 1:
231 dc->dc_rowbytes = dc->dc_width / 8;
232 break;
233 case 2:
234 dc->dc_rowbytes = dc->dc_width / 4;
235 break;
236 case 4:
237 dc->dc_rowbytes = dc->dc_width / 2;
238 break;
239 case 8:
240 dc->dc_rowbytes = dc->dc_width;
241 break;
242 case 16:
243 dc->dc_rowbytes = dc->dc_width * 2;
244 break;
245 case 32:
246 dc->dc_rowbytes = dc->dc_width * 4;
247 break;
248 default:
249 printf("Unknown colour depth %d ... what to do ?", dc->dc_depth);
250 break;
251 }
252
253 /* setup the correct size */
254 dc->dc_size = mem_size;
255
256 /* initialize colormap and cursor resource */
257 vidcvideo_colourmap_and_cursor_init(dc);
258
259 /* blank the memory */
260 bzero((void*)dc->dc_vaddr, dc->dc_size);
261
262 /* intitialise miscelanious */
263 dc->dc_writeback_delay = 0;
264 }
265
266 static void
267 vidcvideoinit_screen(void *cookie, struct vcons_screen *scr,
268 int existing, long *defattr)
269 {
270 struct rasops_info *ri = &scr->scr_ri;
271 struct fb_devconfig *dc = cookie;
272
273 if ((scr == &dc->dc_console) && (dc->dc_vd.active != NULL))
274 return;
275
276 ri->ri_flg = 0; /* RI_CENTER | RI_FULLCLEAR; */
277 ri->ri_depth = dc->dc_depth;
278 ri->ri_bits = (void *) dc->dc_videobase;
279 ri->ri_width = dc->dc_width;
280 ri->ri_height = dc->dc_height;
281 ri->ri_stride = dc->dc_rowbytes;
282 ri->ri_hw = &dc->dc_console; /* link back */
283
284 rasops_init(ri,
285 ri->ri_height / 8,
286 ri->ri_width / 8);
287
288 ri->ri_caps = WSSCREEN_WSCOLORS;
289
290 rasops_reconfig(ri,
291 ri->ri_height / ri->ri_font->fontheight,
292 ri->ri_width / ri->ri_font->fontwidth);
293
294 /*
295 * Provide a hook for the acceleration functions and make a copy of the
296 * original rasops functions for passing on calls
297 */
298 memcpy(&(dc->orig_ri_ops), &(ri->ri_ops),
299 sizeof(struct wsdisplay_emulops));
300
301 /* add our accelerated functions */
302 ri->ri_ops.eraserows = vv_eraserows;
303 ri->ri_ops.copyrows = vv_copyrows;
304
305 /* add the extra activity measuring functions; they just delegate on */
306 ri->ri_ops.putchar = vv_putchar;
307
308 vidcvideo_stdscreen.nrows = ri->ri_rows;
309 vidcvideo_stdscreen.ncols = ri->ri_cols;
310 vidcvideo_stdscreen.textops = &ri->ri_ops;
311 vidcvideo_stdscreen.capabilities = ri->ri_caps;
312 }
313
314 static void
315 vidcvideo_attach(struct device *parent, struct device *self, void *aux)
316 {
317 struct vidcvideo_softc *sc = (struct vidcvideo_softc *)self;
318 struct fb_devconfig *dc;
319 struct wsemuldisplaydev_attach_args waa;
320 long defattr;
321
322 dc = sc->sc_dc = &vidcvideo_console_dc;
323
324 /*
325 * for reasons which are crazy we init vidcvideo twice,
326 * the second time sets up the cursor
327 */
328 vidcvideo_init();
329 if (!vidcvideo_is_console) {
330 vidcvideo_getdevconfig(videomemory.vidm_vbase,
331 videomemory.vidm_size,
332 sc->sc_dc);
333 }
334
335 vcons_init(&dc->dc_vd, dc, &vidcvideo_stdscreen, &vidcvideo_accessops);
336 dc->dc_vd.init_screen = vidcvideoinit_screen;
337
338 vcons_init_screen(&dc->dc_vd, &dc->dc_console, 1, &defattr);
339
340 dc->dc_console.scr_flags |= VCONS_SCREEN_IS_STATIC;
341
342 vidcvideo_printdetails();
343 printf(": mode %s, %dbpp\n", dc->mode_info.timings.name,
344 dc->dc_depth);
345
346 /* set up interrupt flags */
347 vidcvideo_queue_dc_change(dc, WSDISPLAY_CMAP_DOLUT);
348
349 /* Establish an interrupt handler, and clear any pending interrupts */
350 dc->dc_ih = intr_claim(IRQ_FLYBACK, IPL_TTY, "vblank", vidcvideointr, dc);
351
352 waa.console = (vidcvideo_is_console ? 1 : 0);
353 waa.scrdata = &vidcvideo_screenlist;
354 waa.accessops = &vidcvideo_accessops;
355 waa.accesscookie = &dc->dc_vd;
356
357 config_found(self, &waa, wsemuldisplaydevprint);
358 }
359
360
361 static int
362 vidcvideoioctl(void *v, void *vs, u_long cmd, void *data, int flag,
363 struct lwp *l)
364 {
365 struct vcons_data *vd = v;
366 struct vidcvideo_softc *sc = vd->cookie;
367 struct fb_devconfig *dc = sc->sc_dc;
368 struct vcons_screen *ms = vd->active;
369 int state;
370
371 switch (cmd) {
372 case WSDISPLAYIO_GTYPE:
373 *(u_int *)data = WSDISPLAY_TYPE_VIDC;
374 return 0;
375
376 case WSDISPLAYIO_GINFO:
377 if (ms == NULL)
378 return ENODEV;
379 #define wsd_fbip ((struct wsdisplay_fbinfo *)data)
380 wsd_fbip->height = dc->dc_height;
381 wsd_fbip->width = dc->dc_width;
382 wsd_fbip->depth = dc->dc_depth;
383 wsd_fbip->cmsize = CMAP_SIZE;
384 #undef fbt
385 return 0;
386
387 case WSDISPLAYIO_GETCMAP:
388 return get_cmap(sc, (struct wsdisplay_cmap *)data);
389
390 case WSDISPLAYIO_PUTCMAP:
391 return set_cmap(sc, (struct wsdisplay_cmap *)data);
392
393 case WSDISPLAYIO_LINEBYTES:
394 *(u_int *)data = dc->dc_rowbytes;
395 return 0;
396
397 case WSDISPLAYIO_SVIDEO:
398 state = *(int *)data;
399 dc->dc_blanked = (state == WSDISPLAYIO_VIDEO_OFF);
400 vidcvideo_queue_dc_change(dc, WSDISPLAY_VIDEO_ONOFF);
401 /* done on video blank */
402 return 0;
403
404 case WSDISPLAYIO_GVIDEO:
405 *(u_int *)data = dc->dc_blanked ?
406 WSDISPLAYIO_VIDEO_OFF : WSDISPLAYIO_VIDEO_ON;
407 return 0;
408
409 case WSDISPLAYIO_GCURPOS:
410 *(struct wsdisplay_curpos *)data = dc->dc_cursor.cc_pos;
411 return 0;
412
413 case WSDISPLAYIO_SCURPOS:
414 set_curpos(sc, (struct wsdisplay_curpos *)data);
415 vidcvideo_queue_dc_change(dc, WSDISPLAY_CURSOR_DOPOS);
416 return 0;
417
418 case WSDISPLAYIO_GCURMAX:
419 ((struct wsdisplay_curpos *)data)->x = CURSOR_MAX_WIDTH;
420 ((struct wsdisplay_curpos *)data)->y = CURSOR_MAX_HEIGHT;
421 return 0;
422
423 case WSDISPLAYIO_GCURSOR:
424 return get_cursor(sc, (struct wsdisplay_cursor *)data);
425
426 case WSDISPLAYIO_SCURSOR:
427 return set_cursor(sc, (struct wsdisplay_cursor *)data);
428
429 case WSDISPLAYIO_SMODE:
430 state = *(int *)data;
431 if (state == WSDISPLAYIO_MODE_MAPPED)
432 dc->dc_hwscroll_cookie = vidcvideo_hwscroll_reset();
433 if (state == WSDISPLAYIO_MODE_EMUL)
434 vidcvideo_hwscroll_back(dc->dc_hwscroll_cookie);
435 vidcvideo_progr_scroll();
436
437 return 0;
438 }
439 return EPASSTHROUGH;
440 }
441
442
443 paddr_t
444 vidcvideommap(void *v, void *vs, off_t offset, int prot)
445 {
446 struct vcons_data *vd = v;
447 struct vidcvideo_softc *sc = vd->cookie;
448
449 if (offset >= sc->sc_dc->dc_size || offset < 0)
450 return -1;
451
452 return arm_btop(sc->sc_dc->dc_paddr + offset);
453 }
454
455
456 /* EXPORT */ int
457 vidcvideo_cnattach(vaddr_t addr)
458 {
459 struct fb_devconfig *dc = &vidcvideo_console_dc;
460 struct rasops_info *ri;
461 long defattr;
462
463 vidcvideo_init();
464
465 /* fetch current framebuffer config */
466 vidcvideo_getdevconfig(videomemory.vidm_vbase,
467 videomemory.vidm_size,
468 dc);
469
470 dc->dc_vd.active = NULL;
471 vidcvideoinit_screen(dc, &dc->dc_console, 1, &defattr);
472
473 ri = &(dc->dc_console.scr_ri);
474 ri->ri_hw = &dc->dc_console;
475 dc->dc_console.scr_cookie = dc;
476
477 (*ri->ri_ops.allocattr)(ri,
478 WS_DEFAULT_FG, /* fg */
479 WS_DEFAULT_BG, /* bg */
480 0, /* wsattrs */
481 &defattr);
482
483 wsdisplay_cnattach(&vidcvideo_stdscreen,
484 ri, /* emulcookie */
485 0, 0, /* cursor position */
486 defattr);
487
488 vidcvideo_is_console = true;
489
490 return 0;
491 }
492
493
494 static int
495 vidcvideointr(void *arg)
496 {
497 struct fb_devconfig *dc = arg;
498
499 return flush_dc_changes_to_screen(dc);
500 }
501
502 static int
503 flush_dc_changes_to_screen(struct fb_devconfig *dc)
504 {
505 int v, cleared = 0;
506
507 v = dc->_internal_dc_changed;
508
509 if (v == 0) {
510 disable_irq(IRQ_FLYBACK);
511 return 1;
512 }
513
514 if (v & WSDISPLAY_WB_COUNTER) {
515 dc->dc_writeback_delay--;
516 if (dc->dc_writeback_delay == 0) {
517 cpu_dcache_wb_range(dc->dc_vaddr, dc->dc_size);
518 cleared |= WSDISPLAY_WB_COUNTER;
519 }
520 }
521
522 if (v & WSDISPLAY_CMAP_DOLUT) {
523 struct hwcmap256 *cm = &dc->dc_cmap;
524 int index;
525
526 if (dc->dc_depth == 4) {
527 /* palette for 4 bpp is different from 8bpp */
528 vidcvideo_write(VIDC_PALREG, 0x00000000);
529 for (index=0; index < (1 << dc->dc_depth); index++)
530 vidcvideo_write(VIDC_PALETTE,
531 VIDC_COL(cm->r[index],
532 cm->g[index],
533 cm->b[index]));
534 }
535
536 if (dc->dc_depth == 8) {
537 /*
538 * dunno what to do in more than 8bpp
539 * palettes only make sense in 8bpp and less modes
540 * on VIDC
541 */
542 vidcvideo_write(VIDC_PALREG, 0x00000000);
543 for (index = 0; index < CMAP_SIZE; index++) {
544 vidcvideo_write(VIDC_PALETTE,
545 VIDC_COL(cm->r[index], cm->g[index],
546 cm->b[index]));
547 }
548 }
549 cleared |= WSDISPLAY_CMAP_DOLUT;
550 }
551
552 if (v & WSDISPLAY_VIDEO_ONOFF) {
553 vidcvideo_blank(dc->dc_blanked);
554 cleared |= WSDISPLAY_VIDEO_ONOFF;
555 }
556
557 if (v & (WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT)) {
558 int x, y;
559 x = dc->dc_cursor.cc_pos.x - dc->dc_cursor.cc_hot.x;
560 y = dc->dc_cursor.cc_pos.y - dc->dc_cursor.cc_hot.y;
561
562 vidcvideo_updatecursor(x, y);
563 cleared |= WSDISPLAY_CURSOR_DOPOS | WSDISPLAY_CURSOR_DOHOT;
564 }
565
566 if (v & WSDISPLAY_CURSOR_DOCUR) {
567 vidcvideo_enablecursor(dc->dc_curenb);
568 cleared |= WSDISPLAY_CURSOR_DOCUR;
569 }
570
571 dc->_internal_dc_changed ^= cleared;
572
573 if (dc->_internal_dc_changed == 0) {
574 disable_irq(IRQ_FLYBACK);
575 }
576
577 return 1;
578 }
579
580
581 static void vidcvideo_queue_dc_change(struct fb_devconfig *dc, int dc_change)
582 {
583 dc->_internal_dc_changed |= dc_change;
584
585 if (curcpl() == IPL_HIGH) {
586 /* running in ddb or without interrupts */
587 dc->dc_writeback_delay = 1;
588 flush_dc_changes_to_screen(dc);
589 } else {
590 /*
591 * running with interrupts so handle this in the next
592 * vsync
593 */
594 if (dc->dc_ih) {
595 enable_irq(IRQ_FLYBACK);
596 }
597 }
598 }
599
600
601 static const u_char ri_col_data[6][6] = {
602 { 0, 0, 0, 0, 0, 0}, /* 1 bpp */
603 { 0, 0, 0, 0, 0, 0}, /* 2 bpp */
604 { 0, 0, 0, 0, 0, 0}, /* 4 bpp */
605 { 0, 0, 0, 0, 0, 0}, /* 8 bpp */
606 { 6, 5, 5, 0, 6, 11}, /* 16 bpp */
607 { 8, 8, 8, 0, 8, 16}, /* 32 bpp */
608 };
609
610 static void
611 vidcvideo_colourmap_and_cursor_init(struct fb_devconfig *dc)
612 {
613 struct rasops_info *ri = &dc->dc_console.scr_ri;
614 const u_char *rgbdat;
615 struct hwcmap256 *cm;
616 const u_int8_t *p;
617 int index;
618
619 /* Whatever we do later... just make sure we have a
620 * sane palette to start with
621 */
622 vidcvideo_stdpalette();
623
624 /* set up rgb bit pattern values for rasops_init */
625 rgbdat = ri_col_data[dc->dc_log2_depth];
626 ri->ri_rnum = rgbdat[0];
627 ri->ri_gnum = rgbdat[1];
628 ri->ri_bnum = rgbdat[2];
629 ri->ri_rpos = rgbdat[3];
630 ri->ri_gpos = rgbdat[4];
631 ri->ri_bpos = rgbdat[5];
632
633 /* initialise color map */
634 cm = &dc->dc_cmap;
635 p = rasops_cmap;
636 for (index = 0; index < CMAP_SIZE; index++, p += 3) {
637 cm->r[index] = p[0];
638 cm->g[index] = p[1];
639 cm->b[index] = p[2];
640 }
641 /* flush to hardware */
642 vidcvideo_queue_dc_change(dc, WSDISPLAY_CMAP_DOLUT);
643 }
644
645
646 static int
647 get_cmap(struct vidcvideo_softc *sc, struct wsdisplay_cmap *p)
648 {
649 u_int index = p->index, count = p->count;
650 int error;
651
652 if (index >= CMAP_SIZE || count > CMAP_SIZE - index)
653 return EINVAL;
654
655 error = copyout(&sc->sc_dc->dc_cmap.r[index], p->red, count);
656 if (error)
657 return error;
658 error = copyout(&sc->sc_dc->dc_cmap.g[index], p->green, count);
659 if (error)
660 return error;
661 error = copyout(&sc->sc_dc->dc_cmap.b[index], p->blue, count);
662 return error;
663 }
664
665
666 static int
667 set_cmap(struct vidcvideo_softc *sc, struct wsdisplay_cmap *p)
668 {
669 struct fb_devconfig *dc = sc->sc_dc;
670 struct hwcmap256 cmap;
671 u_int index = p->index, count = p->count;
672 int error;
673
674 if (index >= CMAP_SIZE || (index + count) > CMAP_SIZE)
675 return EINVAL;
676
677 error = copyin(p->red, &cmap.r[index], count);
678 if (error)
679 return error;
680 error = copyin(p->green, &cmap.g[index], count);
681 if (error)
682 return error;
683 error = copyin(p->blue, &cmap.b[index], count);
684 if (error)
685 return error;
686 memcpy(&dc->dc_cmap.r[index], &cmap.r[index], count);
687 memcpy(&dc->dc_cmap.g[index], &cmap.g[index], count);
688 memcpy(&dc->dc_cmap.b[index], &cmap.b[index], count);
689 vidcvideo_queue_dc_change(dc, WSDISPLAY_CMAP_DOLUT);
690 return 0;
691 }
692
693
694 static int
695 set_cursor(struct vidcvideo_softc *sc, struct wsdisplay_cursor *p)
696 {
697 #define cc (&dc->dc_cursor)
698 struct fb_devconfig *dc = sc->sc_dc;
699 u_int v, index = 0, count = 0, icount = 0;
700 uint8_t r[2], g[2], b[2], image[512], mask[512];
701 int error;
702
703 /* XXX gcc does not detect identical conditions */
704 index = count = icount = 0;
705
706 v = p->which;
707 if (v & WSDISPLAY_CURSOR_DOCMAP) {
708 index = p->cmap.index;
709 count = p->cmap.count;
710 if (index >= CURSOR_MAX_COLOURS ||
711 (index + count) > CURSOR_MAX_COLOURS)
712 return EINVAL;
713 error = copyin(p->cmap.red, &r[index], count);
714 if (error)
715 return error;
716 error = copyin(p->cmap.green, &g[index], count);
717 if (error)
718 return error;
719 error = copyin(p->cmap.blue, &b[index], count);
720 if (error)
721 return error;
722 }
723 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
724 if (p->size.x > CURSOR_MAX_WIDTH ||
725 p->size.y > CURSOR_MAX_HEIGHT)
726 return EINVAL;
727 icount = sizeof(u_int32_t) * p->size.y;
728 error = copyin(p->image, &image, icount);
729 if (error)
730 return error;
731 error = copyin(p->mask, &mask, icount);
732 if (error)
733 return error;
734 }
735
736 if (v & WSDISPLAY_CURSOR_DOCUR)
737 dc->dc_curenb = p->enable;
738 if (v & WSDISPLAY_CURSOR_DOPOS)
739 set_curpos(sc, &p->pos);
740 if (v & WSDISPLAY_CURSOR_DOHOT)
741 cc->cc_hot = p->hot;
742 if (v & WSDISPLAY_CURSOR_DOCMAP) {
743 memcpy(&cc->cc_color[index], &r[index], count);
744 memcpy(&cc->cc_color[index + 2], &g[index], count);
745 memcpy(&cc->cc_color[index + 4], &b[index], count);
746 }
747 if (v & WSDISPLAY_CURSOR_DOSHAPE) {
748 cc->cc_size = p->size;
749 memset(cc->cc_image, 0, sizeof cc->cc_image);
750 memcpy(cc->cc_image, image, icount);
751 memset(cc->cc_mask, 0, sizeof cc->cc_mask);
752 memcpy(cc->cc_mask, mask, icount);
753 }
754 vidcvideo_queue_dc_change(dc, v);
755
756 return 0;
757 #undef cc
758 }
759
760
761 static int
762 get_cursor(struct vidcvideo_softc *sc, struct wsdisplay_cursor *p)
763 {
764
765 return EPASSTHROUGH; /* XXX */
766 }
767
768
769 static void
770 set_curpos(struct vidcvideo_softc *sc, struct wsdisplay_curpos *curpos)
771 {
772 struct fb_devconfig *dc = sc->sc_dc;
773 int x = curpos->x, y = curpos->y;
774
775 if (y < 0)
776 y = 0;
777 else if (y > dc->dc_height)
778 y = dc->dc_height;
779 if (x < 0)
780 x = 0;
781 else if (x > dc->dc_width)
782 x = dc->dc_width;
783 dc->dc_cursor.cc_pos.x = x;
784 dc->dc_cursor.cc_pos.y = y;
785 }
786
787
788 static void vv_copyrows(void *id, int srcrow, int dstrow, int nrows)
789 {
790 struct rasops_info *ri = id;
791 int height, offset, size;
792 int scrollup, scrolldown;
793 unsigned char *src, *dst;
794 struct vcons_screen *scr = ri->ri_hw;
795 struct fb_devconfig *dc = (struct fb_devconfig *) (scr->scr_cookie);
796
797 /* All movements are done in multiples of character heigths */
798 height = ri->ri_font->fontheight * nrows;
799 offset = (srcrow - dstrow) * ri->ri_yscale;
800 size = height * ri->ri_stride;
801
802 /* check if we are full screen scrolling */
803 scrollup = (srcrow + nrows >= ri->ri_rows);
804 scrolldown = (dstrow + nrows >= ri->ri_rows);
805
806 #if 0
807 if ((scrollup || scrolldown) &&
808 (videomemory.vidm_type == VIDEOMEM_TYPE_VRAM)) {
809 ri->ri_bits = vidcvideo_hwscroll(offset);
810 vidcvideo_progr_scroll(); /* sadistic ; shouldnt this be on vsync? */
811
812 /* wipe out remains of the screen if nessisary */
813 if (ri->ri_emuheight != ri->ri_height)
814 vv_eraserows(id, ri->ri_rows, 1, 0);
815 return;
816 }
817 #endif
818
819 /*
820 * Else we just copy the area : we're braindead for now
821 * Note: we can't use hardware scrolling when the softc isnt
822 * known yet... if its not known we dont have interrupts and
823 * we can't change the display address reliable other than in
824 * a Vsync
825 */
826
827 src = ri->ri_bits + srcrow * ri->ri_font->fontheight * ri->ri_stride;
828 dst = ri->ri_bits + dstrow * ri->ri_font->fontheight * ri->ri_stride;
829
830 memmove(dst, src, size);
831
832 /* delay the write back operation of the screen area */
833 dc->dc_writeback_delay = SCREEN_WRITE_BACK_DELAY;
834 vidcvideo_queue_dc_change(dc, WSDISPLAY_WB_COUNTER);
835 }
836
837
838 static void vv_eraserows(void *id, int startrow, int nrows, long attr)
839 {
840 struct rasops_info *ri = id;
841 int height;
842 unsigned char *src;
843 struct vcons_screen *scr = ri->ri_hw;
844 struct fb_devconfig *dc = (struct fb_devconfig *) (scr->scr_cookie);
845
846 /* we're braindead for now */
847 height = ri->ri_font->fontheight * nrows * ri->ri_stride;
848
849 src = ri->ri_bits + startrow * ri->ri_font->fontheight * ri->ri_stride;
850
851 memset(src, 0, height);
852
853 /* delay the write back operation of the screen area */
854 dc->dc_writeback_delay = SCREEN_WRITE_BACK_DELAY;
855 vidcvideo_queue_dc_change(dc, WSDISPLAY_WB_COUNTER);
856 }
857
858
859 static void vv_putchar(void *id, int row, int col, u_int uc, long attr)
860 {
861 struct rasops_info *ri = id;
862 struct vcons_screen *scr = ri->ri_hw;
863 struct fb_devconfig *dc = (struct fb_devconfig *) (scr->scr_cookie);
864
865 /* just delegate */
866 dc->orig_ri_ops.putchar(id, row, col, uc, attr);
867
868 /* delay the write back operation of the screen area */
869 dc->dc_writeback_delay = SCREEN_WRITE_BACK_DELAY;
870 vidcvideo_queue_dc_change(dc, WSDISPLAY_WB_COUNTER);
871 }
872