kernel tree reorganization stage 1: Major cvs repository work (not logged as
[dragonfly.git] / sys / dev / misc / syscons / scvgarndr.c
1 /*-
2  * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer as
10  *    the first lines of this file unmodified.
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  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * $FreeBSD: src/sys/dev/syscons/scvgarndr.c,v 1.5.2.3 2001/07/28 12:51:47 yokota Exp $
27  * $DragonFly: src/sys/dev/misc/syscons/scvgarndr.c,v 1.3 2003/08/07 21:16:59 dillon Exp $
28  */
29
30 #include "opt_syscons.h"
31 #include "opt_vga.h"
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
36
37 #include <machine/console.h>
38
39 #include <dev/video/fb/fbreg.h>
40 #include <dev/video/fb/vgareg.h>
41 #include "syscons.h"
42
43 #include <bus/isa/isareg.h>
44
45 #ifndef SC_RENDER_DEBUG
46 #define SC_RENDER_DEBUG         0
47 #endif
48
49 static vr_clear_t               vga_txtclear;
50 static vr_draw_border_t         vga_txtborder;
51 static vr_draw_t                vga_txtdraw;
52 static vr_set_cursor_t          vga_txtcursor_shape;
53 static vr_draw_cursor_t         vga_txtcursor;
54 static vr_blink_cursor_t        vga_txtblink;
55 #ifndef SC_NO_CUTPASTE
56 static vr_draw_mouse_t          vga_txtmouse;
57 #else
58 #define vga_txtmouse            (vr_draw_mouse_t *)vga_nop
59 #endif
60
61 #ifdef SC_PIXEL_MODE
62 static vr_clear_t               vga_pxlclear;
63 static vr_draw_border_t         vga_pxlborder;
64 static vr_draw_t                vga_egadraw;
65 static vr_draw_t                vga_vgadraw;
66 static vr_set_cursor_t          vga_pxlcursor_shape;
67 static vr_draw_cursor_t         vga_pxlcursor;
68 static vr_blink_cursor_t        vga_pxlblink;
69 #ifndef SC_NO_CUTPASTE
70 static vr_draw_mouse_t          vga_pxlmouse;
71 #else
72 #define vga_pxlmouse            (vr_draw_mouse_t *)vga_nop
73 #endif
74 #endif /* SC_PIXEL_MODE */
75
76 #ifndef SC_NO_MODE_CHANGE
77 static vr_draw_border_t         vga_grborder;
78 #endif
79
80 static void                     vga_nop(scr_stat *scp, ...);
81
82 static struct linker_set        vga_set;
83
84 static sc_rndr_sw_t txtrndrsw = {
85         vga_txtclear,
86         vga_txtborder,
87         vga_txtdraw,    
88         vga_txtcursor_shape,
89         vga_txtcursor,
90         vga_txtblink,
91         (vr_set_mouse_t *)vga_nop,
92         vga_txtmouse,
93 };
94 RENDERER(mda, 0, txtrndrsw, vga_set);
95 RENDERER(cga, 0, txtrndrsw, vga_set);
96 RENDERER(ega, 0, txtrndrsw, vga_set);
97 RENDERER(vga, 0, txtrndrsw, vga_set);
98
99 #ifdef SC_PIXEL_MODE
100 static sc_rndr_sw_t egarndrsw = {
101         vga_pxlclear,
102         vga_pxlborder,
103         vga_egadraw,
104         vga_pxlcursor_shape,
105         vga_pxlcursor,
106         vga_pxlblink,
107         (vr_set_mouse_t *)vga_nop,
108         vga_pxlmouse,
109 };
110 RENDERER(ega, PIXEL_MODE, egarndrsw, vga_set);
111
112 static sc_rndr_sw_t vgarndrsw = {
113         vga_pxlclear,
114         vga_pxlborder,
115         vga_vgadraw,
116         vga_pxlcursor_shape,
117         vga_pxlcursor,
118         vga_pxlblink,
119         (vr_set_mouse_t *)vga_nop,
120         vga_pxlmouse,
121 };
122 RENDERER(vga, PIXEL_MODE, vgarndrsw, vga_set);
123 #endif /* SC_PIXEL_MODE */
124
125 #ifndef SC_NO_MODE_CHANGE
126 static sc_rndr_sw_t grrndrsw = {
127         (vr_clear_t *)vga_nop,
128         vga_grborder,
129         (vr_draw_t *)vga_nop,
130         (vr_set_cursor_t *)vga_nop,
131         (vr_draw_cursor_t *)vga_nop,
132         (vr_blink_cursor_t *)vga_nop,
133         (vr_set_mouse_t *)vga_nop,
134         (vr_draw_mouse_t *)vga_nop,
135 };
136 RENDERER(cga, GRAPHICS_MODE, grrndrsw, vga_set);
137 RENDERER(ega, GRAPHICS_MODE, grrndrsw, vga_set);
138 RENDERER(vga, GRAPHICS_MODE, grrndrsw, vga_set);
139 #endif /* SC_NO_MODE_CHANGE */
140
141 RENDERER_MODULE(vga, vga_set);
142
143 #ifndef SC_NO_CUTPASTE
144 static u_short mouse_and_mask[16] = {
145         0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00, 0xff80,
146         0xfe00, 0x1e00, 0x1f00, 0x0f00, 0x0f00, 0x0000, 0x0000, 0x0000
147 };
148 static u_short mouse_or_mask[16] = {
149         0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7c00, 0x7e00, 0x6800,
150         0x0c00, 0x0c00, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000
151 };
152 #endif
153
154 static void
155 vga_nop(scr_stat *scp, ...)
156 {
157 }
158
159 /* text mode renderer */
160
161 static void
162 vga_txtclear(scr_stat *scp, int c, int attr)
163 {
164         sc_vtb_clear(&scp->scr, c, attr);
165 }
166
167 static void
168 vga_txtborder(scr_stat *scp, int color)
169 {
170         (*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color);
171 }
172
173 static void
174 vga_txtdraw(scr_stat *scp, int from, int count, int flip)
175 {
176         vm_offset_t p;
177         int c;
178         int a;
179
180         if (from + count > scp->xsize*scp->ysize)
181                 count = scp->xsize*scp->ysize - from;
182
183         if (flip) {
184                 for (p = sc_vtb_pointer(&scp->scr, from); count-- > 0; ++from) {
185                         c = sc_vtb_getc(&scp->vtb, from);
186                         a = sc_vtb_geta(&scp->vtb, from);
187                         a = (a & 0x8800) | ((a & 0x7000) >> 4) 
188                                 | ((a & 0x0700) << 4);
189                         p = sc_vtb_putchar(&scp->scr, p, c, a);
190                 }
191         } else {
192                 sc_vtb_copy(&scp->vtb, from, &scp->scr, from, count);
193         }
194 }
195
196 static void 
197 vga_txtcursor_shape(scr_stat *scp, int base, int height, int blink)
198 {
199         if (base < 0 || base >= scp->font_size)
200                 return;
201         /* the caller may set height <= 0 in order to disable the cursor */
202 #if 0
203         scp->cursor_base = base;
204         scp->cursor_height = height;
205 #endif
206         (*vidsw[scp->sc->adapter]->set_hw_cursor_shape)(scp->sc->adp,
207                                                         base, height,
208                                                         scp->font_size, blink);
209 }
210
211 static void
212 draw_txtcharcursor(scr_stat *scp, int at, u_short c, u_short a, int flip)
213 {
214         sc_softc_t *sc;
215
216         sc = scp->sc;
217         scp->cursor_saveunder_char = c;
218         scp->cursor_saveunder_attr = a;
219
220 #ifndef SC_NO_FONT_LOADING
221         if (sc->flags & SC_CHAR_CURSOR) {
222                 unsigned char *font;
223                 int h;
224                 int i;
225
226                 if (scp->font_size < 14) {
227                         font = sc->font_8;
228                         h = 8;
229                 } else if (scp->font_size >= 16) {
230                         font = sc->font_16;
231                         h = 16;
232                 } else {
233                         font = sc->font_14;
234                         h = 14;
235                 }
236                 if (scp->cursor_base >= h)
237                         return;
238                 if (flip)
239                         a = (a & 0x8800)
240                                 | ((a & 0x7000) >> 4) | ((a & 0x0700) << 4);
241                 bcopy(font + c*h, font + sc->cursor_char*h, h);
242                 font = font + sc->cursor_char*h;
243                 for (i = imax(h - scp->cursor_base - scp->cursor_height, 0);
244                         i < h - scp->cursor_base; ++i) {
245                         font[i] ^= 0xff;
246                 }
247                 sc->font_loading_in_progress = TRUE;
248                 /* XXX */
249                 (*vidsw[sc->adapter]->load_font)(sc->adp, 0, h, font,
250                                                  sc->cursor_char, 1);
251                 sc->font_loading_in_progress = FALSE;
252                 sc_vtb_putc(&scp->scr, at, sc->cursor_char, a);
253         } else
254 #endif /* SC_NO_FONT_LOADING */
255         {
256                 if ((a & 0x7000) == 0x7000) {
257                         a &= 0x8f00;
258                         if ((a & 0x0700) == 0)
259                                 a |= 0x0700;
260                 } else {
261                         a |= 0x7000;
262                         if ((a & 0x0700) == 0x0700)
263                                 a &= 0xf000;
264                 }
265                 if (flip)
266                         a = (a & 0x8800)
267                                 | ((a & 0x7000) >> 4) | ((a & 0x0700) << 4);
268                 sc_vtb_putc(&scp->scr, at, c, a);
269         }
270 }
271
272 static void
273 vga_txtcursor(scr_stat *scp, int at, int blink, int on, int flip)
274 {
275         video_adapter_t *adp;
276         int cursor_attr;
277
278         if (scp->cursor_height <= 0)    /* the text cursor is disabled */
279                 return;
280
281         adp = scp->sc->adp;
282         if (blink) {
283                 scp->status |= VR_CURSOR_BLINK;
284                 if (on) {
285                         scp->status |= VR_CURSOR_ON;
286                         (*vidsw[adp->va_index]->set_hw_cursor)(adp,
287                                                                at%scp->xsize,
288                                                                at/scp->xsize); 
289                 } else {
290                         if (scp->status & VR_CURSOR_ON)
291                                 (*vidsw[adp->va_index]->set_hw_cursor)(adp,
292                                                                        -1, -1);
293                         scp->status &= ~VR_CURSOR_ON;
294                 }
295         } else {
296                 scp->status &= ~VR_CURSOR_BLINK;
297                 if (on) {
298                         scp->status |= VR_CURSOR_ON;
299                         draw_txtcharcursor(scp, at,
300                                            sc_vtb_getc(&scp->scr, at),
301                                            sc_vtb_geta(&scp->scr, at),
302                                            flip);
303                 } else {
304                         cursor_attr = scp->cursor_saveunder_attr;
305                         if (flip)
306                                 cursor_attr = (cursor_attr & 0x8800)
307                                         | ((cursor_attr & 0x7000) >> 4)
308                                         | ((cursor_attr & 0x0700) << 4);
309                         if (scp->status & VR_CURSOR_ON)
310                                 sc_vtb_putc(&scp->scr, at,
311                                             scp->cursor_saveunder_char,
312                                             cursor_attr);
313                         scp->status &= ~VR_CURSOR_ON;
314                 }
315         }
316 }
317
318 static void
319 vga_txtblink(scr_stat *scp, int at, int flip)
320 {
321 }
322
323 #ifndef SC_NO_CUTPASTE
324
325 static void
326 draw_txtmouse(scr_stat *scp, int x, int y)
327 {
328 #ifndef SC_ALT_MOUSE_IMAGE
329     if (ISMOUSEAVAIL(scp->sc->adp->va_flags)) {
330         u_char font_buf[128];
331         u_short cursor[32];
332         u_char c;
333         int pos;
334         int xoffset, yoffset;
335         int crtc_addr;
336         int i;
337
338         /* prepare mousepointer char's bitmaps */
339         pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff;
340         bcopy(scp->font + sc_vtb_getc(&scp->scr, pos)*scp->font_size,
341               &font_buf[0], scp->font_size);
342         bcopy(scp->font + sc_vtb_getc(&scp->scr, pos + 1)*scp->font_size,
343               &font_buf[32], scp->font_size);
344         bcopy(scp->font 
345                  + sc_vtb_getc(&scp->scr, pos + scp->xsize)*scp->font_size,
346               &font_buf[64], scp->font_size);
347         bcopy(scp->font
348                  + sc_vtb_getc(&scp->scr, pos + scp->xsize + 1)*scp->font_size,
349               &font_buf[96], scp->font_size);
350         for (i = 0; i < scp->font_size; ++i) {
351                 cursor[i] = font_buf[i]<<8 | font_buf[i+32];
352                 cursor[i + scp->font_size] = font_buf[i+64]<<8 | font_buf[i+96];
353         }
354
355         /* now and-or in the mousepointer image */
356         xoffset = x%8;
357         yoffset = y%scp->font_size;
358         for (i = 0; i < 16; ++i) {
359                 cursor[i + yoffset] =
360                         (cursor[i + yoffset] & ~(mouse_and_mask[i] >> xoffset))
361                         | (mouse_or_mask[i] >> xoffset);
362         }
363         for (i = 0; i < scp->font_size; ++i) {
364                 font_buf[i] = (cursor[i] & 0xff00) >> 8;
365                 font_buf[i + 32] = cursor[i] & 0xff;
366                 font_buf[i + 64] = (cursor[i + scp->font_size] & 0xff00) >> 8;
367                 font_buf[i + 96] = cursor[i + scp->font_size] & 0xff;
368         }
369
370 #if 1
371         /* wait for vertical retrace to avoid jitter on some videocards */
372         crtc_addr = scp->sc->adp->va_crtc_addr;
373         while (!(inb(crtc_addr + 6) & 0x08)) /* idle */ ;
374 #endif
375         c = scp->sc->mouse_char;
376         (*vidsw[scp->sc->adapter]->load_font)(scp->sc->adp, 0, 32, font_buf,
377                                               c, 4); 
378
379         sc_vtb_putc(&scp->scr, pos, c, sc_vtb_geta(&scp->scr, pos));
380         /* FIXME: may be out of range! */
381         sc_vtb_putc(&scp->scr, pos + scp->xsize, c + 2,
382                     sc_vtb_geta(&scp->scr, pos + scp->xsize));
383         if (x < (scp->xsize - 1)*8) {
384                 sc_vtb_putc(&scp->scr, pos + 1, c + 1,
385                             sc_vtb_geta(&scp->scr, pos + 1));
386                 sc_vtb_putc(&scp->scr, pos + scp->xsize + 1, c + 3,
387                             sc_vtb_geta(&scp->scr, pos + scp->xsize + 1));
388         }
389     } else
390 #endif /* SC_ALT_MOUSE_IMAGE */
391     {
392         /* Red, magenta and brown are mapped to green to to keep it readable */
393         static const int col_conv[16] = {
394                 6, 6, 6, 6, 2, 2, 2, 6, 14, 14, 14, 14, 10, 10, 10, 14
395         };
396         int pos;
397         int color;
398         int a;
399
400         pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff;
401         a = sc_vtb_geta(&scp->scr, pos);
402         if (scp->sc->adp->va_flags & V_ADP_COLOR)
403                 color = (col_conv[(a & 0xf000) >> 12] << 12)
404                         | ((a & 0x0f00) | 0x0800);
405         else
406                 color = ((a & 0xf000) >> 4) | ((a & 0x0f00) << 4);
407         sc_vtb_putc(&scp->scr, pos, sc_vtb_getc(&scp->scr, pos), color);
408     }
409 }
410
411 static void
412 remove_txtmouse(scr_stat *scp, int x, int y)
413 {
414 }
415
416 static void 
417 vga_txtmouse(scr_stat *scp, int x, int y, int on)
418 {
419         if (on)
420                 draw_txtmouse(scp, x, y);
421         else
422                 remove_txtmouse(scp, x, y);
423 }
424
425 #endif /* SC_NO_CUTPASTE */
426
427 #ifdef SC_PIXEL_MODE
428
429 /* pixel (raster text) mode renderer */
430
431 static void
432 vga_pxlclear(scr_stat *scp, int c, int attr)
433 {
434         vm_offset_t p;
435         int line_width;
436         int lines;
437         int i;
438
439         /* XXX: we are just filling the screen with the background color... */
440         outw(GDCIDX, 0x0005);           /* read mode 0, write mode 0 */
441         outw(GDCIDX, 0x0003);           /* data rotate/function select */
442         outw(GDCIDX, 0x0f01);           /* set/reset enable */
443         outw(GDCIDX, 0xff08);           /* bit mask */
444         outw(GDCIDX, ((attr & 0xf000) >> 4) | 0x00); /* set/reset */
445         line_width = scp->sc->adp->va_line_width;
446         lines = scp->ysize*scp->font_size; 
447         p = scp->sc->adp->va_window + line_width*scp->yoff*scp->font_size
448                 + scp->xoff;
449         for (i = 0; i < lines; ++i) {
450                 bzero_io((void *)p, scp->xsize);
451                 p += line_width;
452         }
453         outw(GDCIDX, 0x0000);           /* set/reset */
454         outw(GDCIDX, 0x0001);           /* set/reset enable */
455 }
456
457 static void
458 vga_pxlborder(scr_stat *scp, int color)
459 {
460         vm_offset_t p;
461         int line_width;
462         int x;
463         int y;
464         int i;
465
466         (*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color);
467
468         outw(GDCIDX, 0x0005);           /* read mode 0, write mode 0 */
469         outw(GDCIDX, 0x0003);           /* data rotate/function select */
470         outw(GDCIDX, 0x0f01);           /* set/reset enable */
471         outw(GDCIDX, 0xff08);           /* bit mask */
472         outw(GDCIDX, (color << 8) | 0x00);      /* set/reset */
473         line_width = scp->sc->adp->va_line_width;
474         p = scp->sc->adp->va_window;
475         if (scp->yoff > 0)
476                 bzero_io((void *)p, line_width*scp->yoff*scp->font_size);
477         y = (scp->yoff + scp->ysize)*scp->font_size;
478         if (scp->ypixel > y)
479                 bzero_io((void *)(p + line_width*y), line_width*(scp->ypixel - y));
480         y = scp->yoff*scp->font_size;
481         x = scp->xpixel/8 - scp->xoff - scp->xsize;
482         for (i = 0; i < scp->ysize*scp->font_size; ++i) {
483                 if (scp->xoff > 0)
484                         bzero_io((void *)(p + line_width*(y + i)), scp->xoff);
485                 if (x > 0)
486                         bzero_io((void *)(p + line_width*(y + i)
487                                      + scp->xoff + scp->xsize), x);
488         }
489         outw(GDCIDX, 0x0000);           /* set/reset */
490         outw(GDCIDX, 0x0001);           /* set/reset enable */
491 }
492
493 static void 
494 vga_egadraw(scr_stat *scp, int from, int count, int flip)
495 {
496         vm_offset_t d;
497         vm_offset_t e;
498         u_char *f;
499         u_short bg;
500         u_short col1, col2;
501         int line_width;
502         int i, j;
503         int a;
504         u_char c;
505
506         line_width = scp->sc->adp->va_line_width;
507         d = scp->sc->adp->va_window
508                 + scp->xoff 
509                 + scp->yoff*scp->font_size*line_width 
510                 + (from%scp->xsize) 
511                 + scp->font_size*line_width*(from/scp->xsize);
512
513         outw(GDCIDX, 0x0005);           /* read mode 0, write mode 0 */
514         outw(GDCIDX, 0x0003);           /* data rotate/function select */
515         outw(GDCIDX, 0x0f01);           /* set/reset enable */
516         bg = -1;
517         if (from + count > scp->xsize*scp->ysize)
518                 count = scp->xsize*scp->ysize - from;
519         for (i = from; count-- > 0; ++i) {
520                 a = sc_vtb_geta(&scp->vtb, i);
521                 if (flip) {
522                         col1 = ((a & 0x7000) >> 4) | (a & 0x0800);
523                         col2 = ((a & 0x8000) >> 4) | (a & 0x0700);
524                 } else {
525                         col1 = (a & 0x0f00);
526                         col2 = (a & 0xf000) >> 4;
527                 }
528                 /* set background color in EGA/VGA latch */
529                 if (bg != col2) {
530                         bg = col2;
531                         outw(GDCIDX, bg | 0x00);        /* set/reset */
532                         outw(GDCIDX, 0xff08);           /* bit mask */
533                         writeb(d, 0);
534                         c = readb(d);   /* set bg color in the latch */
535                 }
536                 /* foreground color */
537                 outw(GDCIDX, col1 | 0x00);              /* set/reset */
538                 e = d;
539                 f = &(scp->font[sc_vtb_getc(&scp->vtb, i)*scp->font_size]);
540                 for (j = 0; j < scp->font_size; ++j, ++f) {
541                         outw(GDCIDX, (*f << 8) | 0x08); /* bit mask */
542                         writeb(e, 0);
543                         e += line_width;
544                 }
545                 ++d;
546                 if ((i % scp->xsize) == scp->xsize - 1)
547                         d += scp->xoff*2 
548                                  + (scp->font_size - 1)*line_width;
549         }
550         outw(GDCIDX, 0x0000);           /* set/reset */
551         outw(GDCIDX, 0x0001);           /* set/reset enable */
552         outw(GDCIDX, 0xff08);           /* bit mask */
553 }
554
555 static void 
556 vga_vgadraw(scr_stat *scp, int from, int count, int flip)
557 {
558         vm_offset_t d;
559         vm_offset_t e;
560         u_char *f;
561         u_short bg;
562         u_short col1, col2;
563         int line_width;
564         int i, j;
565         int a;
566         u_char c;
567
568         line_width = scp->sc->adp->va_line_width;
569         d = scp->sc->adp->va_window
570                 + scp->xoff 
571                 + scp->yoff*scp->font_size*line_width 
572                 + (from%scp->xsize) 
573                 + scp->font_size*line_width*(from/scp->xsize);
574
575         outw(GDCIDX, 0x0305);           /* read mode 0, write mode 3 */
576         outw(GDCIDX, 0x0003);           /* data rotate/function select */
577         outw(GDCIDX, 0x0f01);           /* set/reset enable */
578         outw(GDCIDX, 0xff08);           /* bit mask */
579         bg = -1;
580         if (from + count > scp->xsize*scp->ysize)
581                 count = scp->xsize*scp->ysize - from;
582         for (i = from; count-- > 0; ++i) {
583                 a = sc_vtb_geta(&scp->vtb, i);
584                 if (flip) {
585                         col1 = ((a & 0x7000) >> 4) | (a & 0x0800);
586                         col2 = ((a & 0x8000) >> 4) | (a & 0x0700);
587                 } else {
588                         col1 = (a & 0x0f00);
589                         col2 = (a & 0xf000) >> 4;
590                 }
591                 /* set background color in EGA/VGA latch */
592                 if (bg != col2) {
593                         bg = col2;
594                         outw(GDCIDX, 0x0005);   /* read mode 0, write mode 0 */
595                         outw(GDCIDX, bg | 0x00); /* set/reset */
596                         writeb(d, 0);
597                         c = readb(d);           /* set bg color in the latch */
598                         outw(GDCIDX, 0x0305);   /* read mode 0, write mode 3 */
599                 }
600                 /* foreground color */
601                 outw(GDCIDX, col1 | 0x00);      /* set/reset */
602                 e = d;
603                 f = &(scp->font[sc_vtb_getc(&scp->vtb, i)*scp->font_size]);
604                 for (j = 0; j < scp->font_size; ++j, ++f) {
605                         writeb(e, *f);
606                         e += line_width;
607                 }
608                 ++d;
609                 if ((i % scp->xsize) == scp->xsize - 1)
610                         d += scp->xoff*2 
611                                  + (scp->font_size - 1)*line_width;
612         }
613         outw(GDCIDX, 0x0005);           /* read mode 0, write mode 0 */
614         outw(GDCIDX, 0x0000);           /* set/reset */
615         outw(GDCIDX, 0x0001);           /* set/reset enable */
616 }
617
618 static void 
619 vga_pxlcursor_shape(scr_stat *scp, int base, int height, int blink)
620 {
621         if (base < 0 || base >= scp->font_size)
622                 return;
623         /* the caller may set height <= 0 in order to disable the cursor */
624 #if 0
625         scp->cursor_base = base;
626         scp->cursor_height = height;
627 #endif
628 }
629
630 static void 
631 draw_pxlcursor(scr_stat *scp, int at, int on, int flip)
632 {
633         vm_offset_t d;
634         u_char *f;
635         int line_width;
636         int height;
637         int col;
638         int a;
639         int i;
640         u_char c;
641
642         line_width = scp->sc->adp->va_line_width;
643         d = scp->sc->adp->va_window
644                 + scp->xoff 
645                 + scp->yoff*scp->font_size*line_width 
646                 + (at%scp->xsize) 
647                 + scp->font_size*line_width*(at/scp->xsize)
648                 + (scp->font_size - scp->cursor_base - 1)*line_width;
649
650         outw(GDCIDX, 0x0005);           /* read mode 0, write mode 0 */
651         outw(GDCIDX, 0x0003);           /* data rotate/function select */
652         outw(GDCIDX, 0x0f01);           /* set/reset enable */
653         /* set background color in EGA/VGA latch */
654         a = sc_vtb_geta(&scp->vtb, at);
655         if (flip)
656                 col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00);
657         else
658                 col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4);
659         outw(GDCIDX, col | 0x00);       /* set/reset */
660         outw(GDCIDX, 0xff08);           /* bit mask */
661         writeb(d, 0);
662         c = readb(d);                   /* set bg color in the latch */
663         /* foreground color */
664         if (flip)
665                 col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4);
666         else
667                 col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00);
668         outw(GDCIDX, col | 0x00);       /* set/reset */
669         f = &(scp->font[sc_vtb_getc(&scp->vtb, at)*scp->font_size
670                 + scp->font_size - scp->cursor_base - 1]);
671         height = imin(scp->cursor_height, scp->font_size);
672         for (i = 0; i < height; ++i, --f) {
673                 outw(GDCIDX, (*f << 8) | 0x08); /* bit mask */
674                 writeb(d, 0);
675                 d -= line_width;
676         }
677         outw(GDCIDX, 0x0000);           /* set/reset */
678         outw(GDCIDX, 0x0001);           /* set/reset enable */
679         outw(GDCIDX, 0xff08);           /* bit mask */
680 }
681
682 static int pxlblinkrate = 0;
683
684 static void 
685 vga_pxlcursor(scr_stat *scp, int at, int blink, int on, int flip)
686 {
687         if (scp->cursor_height <= 0)    /* the text cursor is disabled */
688                 return;
689
690         if (on) {
691                 if (!blink) {
692                         scp->status |= VR_CURSOR_ON;
693                         draw_pxlcursor(scp, at, on, flip);
694                 } else if (++pxlblinkrate & 4) {
695                         pxlblinkrate = 0;
696                         scp->status ^= VR_CURSOR_ON;
697                         draw_pxlcursor(scp, at,
698                                        scp->status & VR_CURSOR_ON,
699                                        flip);
700                 }
701         } else {
702                 if (scp->status & VR_CURSOR_ON)
703                         draw_pxlcursor(scp, at, on, flip);
704                 scp->status &= ~VR_CURSOR_ON;
705         }
706         if (blink)
707                 scp->status |= VR_CURSOR_BLINK;
708         else
709                 scp->status &= ~VR_CURSOR_BLINK;
710 }
711
712 static void
713 vga_pxlblink(scr_stat *scp, int at, int flip)
714 {
715         if (!(scp->status & VR_CURSOR_BLINK))
716                 return;
717         if (!(++pxlblinkrate & 4))
718                 return;
719         pxlblinkrate = 0;
720         scp->status ^= VR_CURSOR_ON;
721         draw_pxlcursor(scp, at, scp->status & VR_CURSOR_ON, flip);
722 }
723
724 #ifndef SC_NO_CUTPASTE
725
726 static void
727 draw_pxlmouse(scr_stat *scp, int x, int y)
728 {
729         vm_offset_t p;
730         int line_width;
731         int xoff, yoff;
732         int ymax;
733         u_short m;
734         int i, j;
735
736         line_width = scp->sc->adp->va_line_width;
737         xoff = (x - scp->xoff*8)%8;
738         yoff = y - (y/line_width)*line_width;
739         ymax = imin(y + 16, scp->ypixel);
740
741         outw(GDCIDX, 0x0805);           /* read mode 1, write mode 0 */
742         outw(GDCIDX, 0x0001);           /* set/reset enable */
743         outw(GDCIDX, 0x0002);           /* color compare */
744         outw(GDCIDX, 0x0007);           /* color don't care */
745         outw(GDCIDX, 0xff08);           /* bit mask */
746         outw(GDCIDX, 0x0803);           /* data rotate/function select (and) */
747         p = scp->sc->adp->va_window + line_width*y + x/8;
748         if (x < scp->xpixel - 8) {
749                 for (i = y, j = 0; i < ymax; ++i, ++j) {
750                         m = ~(mouse_and_mask[j] >> xoff);
751 #ifdef __i386__
752                         *(u_char *)p &= m >> 8;
753                         *(u_char *)(p + 1) &= m;
754 #elif defined(__alpha__)
755                         writeb(p, readb(p) & (m >> 8));
756                         writeb(p + 1, readb(p + 1) & (m >> 8));
757 #endif
758                         p += line_width;
759                 }
760         } else {
761                 xoff += 8;
762                 for (i = y, j = 0; i < ymax; ++i, ++j) {
763                         m = ~(mouse_and_mask[j] >> xoff);
764 #ifdef __i386__
765                         *(u_char *)p &= m;
766 #elif defined(__alpha__)
767                         writeb(p, readb(p) & (m >> 8));
768 #endif
769                         p += line_width;
770                 }
771         }
772         outw(GDCIDX, 0x1003);           /* data rotate/function select (or) */
773         p = scp->sc->adp->va_window + line_width*y + x/8;
774         if (x < scp->xpixel - 8) {
775                 for (i = y, j = 0; i < ymax; ++i, ++j) {
776                         m = mouse_or_mask[j] >> xoff;
777 #ifdef __i386__
778                         *(u_char *)p &= m >> 8;
779                         *(u_char *)(p + 1) &= m;
780 #elif defined(__alpha__)
781                         writeb(p, readb(p) & (m >> 8));
782                         writeb(p + 1, readb(p + 1) & (m >> 8));
783 #endif
784                         p += line_width;
785                 }
786         } else {
787                 for (i = y, j = 0; i < ymax; ++i, ++j) {
788                         m = mouse_or_mask[j] >> xoff;
789 #ifdef __i386__
790                         *(u_char *)p &= m;
791 #elif defined(__alpha__)
792                         writeb(p, readb(p) & (m >> 8));
793 #endif
794                         p += line_width;
795                 }
796         }
797         outw(GDCIDX, 0x0005);           /* read mode 0, write mode 0 */
798         outw(GDCIDX, 0x0003);           /* data rotate/function select */
799 }
800
801 static void
802 remove_pxlmouse(scr_stat *scp, int x, int y)
803 {
804         vm_offset_t p;
805         int col, row;
806         int pos;
807         int line_width;
808         int ymax;
809         int i;
810
811         /* erase the mouse cursor image */
812         col = x/8 - scp->xoff;
813         row = y/scp->font_size - scp->yoff;
814         pos = row*scp->xsize + col;
815         i = (col < scp->xsize - 1) ? 2 : 1;
816         (*scp->rndr->draw)(scp, pos, i, FALSE);
817         if (row < scp->ysize - 1)
818                 (*scp->rndr->draw)(scp, pos + scp->xsize, i, FALSE);
819
820         /* paint border if necessary */
821         line_width = scp->sc->adp->va_line_width;
822         outw(GDCIDX, 0x0005);           /* read mode 0, write mode 0 */
823         outw(GDCIDX, 0x0003);           /* data rotate/function select */
824         outw(GDCIDX, 0x0f01);           /* set/reset enable */
825         outw(GDCIDX, 0xff08);           /* bit mask */
826         outw(GDCIDX, (scp->border << 8) | 0x00);        /* set/reset */
827         if (row == scp->ysize - 1) {
828                 i = (scp->ysize + scp->yoff)*scp->font_size;
829                 ymax = imin(i + scp->font_size, scp->ypixel);
830                 p = scp->sc->adp->va_window + i*line_width + scp->xoff + col;
831                 if (col < scp->xsize - 1) {
832                         for (; i < ymax; ++i) {
833                                 writeb(p, 0);
834                                 writeb(p + 1, 0);
835                                 p += line_width;
836                         }
837                 } else {
838                         for (; i < ymax; ++i) {
839                                 writeb(p, 0);
840                                 p += line_width;
841                         }
842                 }
843         }
844         if ((col == scp->xsize - 1) && (scp->xoff > 0)) {
845                 i = (row + scp->yoff)*scp->font_size;
846                 ymax = imin(i + scp->font_size*2, scp->ypixel);
847                 p = scp->sc->adp->va_window + i*line_width
848                         + scp->xoff + scp->xsize;
849                 for (; i < ymax; ++i) {
850                         writeb(p, 0);
851                         p += line_width;
852                 }
853         }
854         outw(GDCIDX, 0x0000);           /* set/reset */
855         outw(GDCIDX, 0x0001);           /* set/reset enable */
856 }
857
858 static void 
859 vga_pxlmouse(scr_stat *scp, int x, int y, int on)
860 {
861         if (on)
862                 draw_pxlmouse(scp, x, y);
863         else
864                 remove_pxlmouse(scp, x, y);
865 }
866
867 #endif /* SC_NO_CUTPASTE */
868 #endif /* SC_PIXEL_MODE */
869
870 #ifndef SC_NO_MODE_CHANGE
871
872 /* graphics mode renderer */
873
874 static void
875 vga_grborder(scr_stat *scp, int color)
876 {
877         (*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color);
878 }
879
880 #endif