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