]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/syscons/scvgarndr.c
Add many bitmaps (now there are 13) for mouse cursors and logic to try
[FreeBSD/FreeBSD.git] / sys / dev / syscons / scvgarndr.c
1 /*-
2  * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to The DragonFly Project
6  * by Sascha Wildner <saw@online.de>
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer as
13  *    the first lines of this file unmodified.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include "opt_syscons.h"
35 #include "opt_vga.h"
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/module.h>
41 #include <sys/fbio.h>
42 #include <sys/consio.h>
43 #include <sys/sysctl.h>
44
45 #include <machine/bus.h>
46
47 #include <dev/fb/fbreg.h>
48 #include <dev/fb/vgareg.h>
49 #include <dev/syscons/syscons.h>
50
51 #include <isa/isareg.h>
52
53 #ifndef SC_RENDER_DEBUG
54 #define SC_RENDER_DEBUG         0
55 #endif
56
57 static vr_clear_t               vga_txtclear;
58 static vr_draw_border_t         vga_txtborder;
59 static vr_draw_t                vga_txtdraw;
60 static vr_set_cursor_t          vga_txtcursor_shape;
61 static vr_draw_cursor_t         vga_txtcursor;
62 static vr_blink_cursor_t        vga_txtblink;
63 #ifndef SC_NO_CUTPASTE
64 static vr_draw_mouse_t          vga_txtmouse;
65 #else
66 #define vga_txtmouse            (vr_draw_mouse_t *)vga_nop
67 #endif
68
69 #ifdef SC_PIXEL_MODE
70 static vr_init_t                vga_rndrinit;
71 static vr_clear_t               vga_pxlclear_direct;
72 static vr_clear_t               vga_pxlclear_planar;
73 static vr_draw_border_t         vga_pxlborder_direct;
74 static vr_draw_border_t         vga_pxlborder_planar;
75 static vr_draw_t                vga_vgadraw_direct;
76 static vr_draw_t                vga_vgadraw_planar;
77 static vr_set_cursor_t          vga_pxlcursor_shape;
78 static vr_draw_cursor_t         vga_pxlcursor_direct;
79 static vr_draw_cursor_t         vga_pxlcursor_planar;
80 static vr_blink_cursor_t        vga_pxlblink_direct;
81 static vr_blink_cursor_t        vga_pxlblink_planar;
82 #ifndef SC_NO_CUTPASTE
83 static vr_draw_mouse_t          vga_pxlmouse_direct;
84 static vr_draw_mouse_t          vga_pxlmouse_planar;
85 #else
86 #define vga_pxlmouse_direct     (vr_draw_mouse_t *)vga_nop
87 #define vga_pxlmouse_planar     (vr_draw_mouse_t *)vga_nop
88 #endif
89 #endif /* SC_PIXEL_MODE */
90
91 #ifndef SC_NO_MODE_CHANGE
92 static vr_draw_border_t         vga_grborder;
93 #endif
94
95 static void                     vga_nop(scr_stat *scp);
96
97 static sc_rndr_sw_t txtrndrsw = {
98         (vr_init_t *)vga_nop,
99         vga_txtclear,
100         vga_txtborder,
101         vga_txtdraw,    
102         vga_txtcursor_shape,
103         vga_txtcursor,
104         vga_txtblink,
105         (vr_set_mouse_t *)vga_nop,
106         vga_txtmouse,
107 };
108 RENDERER(mda, 0, txtrndrsw, vga_set);
109 RENDERER(cga, 0, txtrndrsw, vga_set);
110 RENDERER(ega, 0, txtrndrsw, vga_set);
111 RENDERER(vga, 0, txtrndrsw, vga_set);
112
113 #ifdef SC_PIXEL_MODE
114 static sc_rndr_sw_t vgarndrsw = {
115         vga_rndrinit,
116         (vr_clear_t *)vga_nop,
117         (vr_draw_border_t *)vga_nop,
118         (vr_draw_t *)vga_nop,
119         vga_pxlcursor_shape,
120         (vr_draw_cursor_t *)vga_nop,
121         (vr_blink_cursor_t *)vga_nop,
122         (vr_set_mouse_t *)vga_nop,
123         (vr_draw_mouse_t *)vga_nop,
124 };
125 RENDERER(ega, PIXEL_MODE, vgarndrsw, vga_set);
126 RENDERER(vga, PIXEL_MODE, vgarndrsw, vga_set);
127 #endif /* SC_PIXEL_MODE */
128
129 #ifndef SC_NO_MODE_CHANGE
130 static sc_rndr_sw_t grrndrsw = {
131         (vr_init_t *)vga_nop,
132         (vr_clear_t *)vga_nop,
133         vga_grborder,
134         (vr_draw_t *)vga_nop,
135         (vr_set_cursor_t *)vga_nop,
136         (vr_draw_cursor_t *)vga_nop,
137         (vr_blink_cursor_t *)vga_nop,
138         (vr_set_mouse_t *)vga_nop,
139         (vr_draw_mouse_t *)vga_nop,
140 };
141 RENDERER(cga, GRAPHICS_MODE, grrndrsw, vga_set);
142 RENDERER(ega, GRAPHICS_MODE, grrndrsw, vga_set);
143 RENDERER(vga, GRAPHICS_MODE, grrndrsw, vga_set);
144 #endif /* SC_NO_MODE_CHANGE */
145
146 RENDERER_MODULE(vga, vga_set);
147
148 #ifndef SC_NO_CUTPASTE
149 #if !defined(SC_ALT_MOUSE_IMAGE) || defined(SC_PIXEL_MODE)
150 struct mousedata {
151         u_short md_border[16];
152         u_short md_interior[16];
153         u_char  md_width;
154         u_char  md_height;
155         u_char  md_baspect;
156         u_char  md_iaspect;
157         const char *md_name;
158 };
159
160 static const struct mousedata mouse10x16_50 = { {
161         0xC000, 0xA000, 0x9000, 0x8800, 0x8400, 0x8200, 0x8100, 0x8200,
162         0x8400, 0x8400, 0x8400, 0x9200, 0xB200, 0xA900, 0xC900, 0x8600, }, {
163         0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7C00, 0x7E00, 0x7C00,
164         0x7800, 0x7800, 0x7800, 0x6C00, 0x4C00, 0x4600, 0x0600, 0x0000, },
165         10, 16, 49, 52, "mouse10x16_50",
166 };
167
168 static const struct mousedata mouse8x14_67 = { {
169         0xC000, 0xA000, 0x9000, 0x8800, 0x8400, 0x8200, 0x8100, 0x8700,
170         0x8400, 0x9200, 0xB200, 0xA900, 0xC900, 0x0600, 0x0000, 0x0000, }, {
171         0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7C00, 0x7E00, 0x7800,
172         0x7800, 0x6C00, 0x4C00, 0x4600, 0x0600, 0x0000, 0x0000, 0x0000, },
173         8, 14, 64, 65, "mouse8x14_67",
174 };
175
176 static const struct mousedata mouse8x13_75 = { {
177         0xC000, 0xA000, 0x9000, 0x8800, 0x8400, 0x8200, 0x8600, 0x8400,
178         0xB200, 0xD200, 0x0900, 0x0900, 0x0600, 0x0000, 0x0000, 0x0000, }, {
179         0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7C00, 0x7800, 0x7800,
180         0x4C00, 0x0C00, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000, },
181         8, 13, 75, 80, "mouse8x13_75",
182 };
183
184 static const struct mousedata mouse10x16_75 = { {
185         0xC000, 0xA000, 0x9000, 0x8800, 0x8400, 0x8200, 0x8100, 0x8700,
186         0x8400, 0x9200, 0xB200, 0xC900, 0x0900, 0x0480, 0x0480, 0x0300, }, {
187         0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7C00, 0x7E00, 0x7800,
188         0x7800, 0x6C00, 0x4C00, 0x0600, 0x0600, 0x0300, 0x0300, 0x0000, },
189         10, 16, 72, 75, "mouse10x16_75",
190 };
191
192 static const struct mousedata mouse9x13_90 = { {
193         0xC000, 0xA000, 0x9000, 0x8800, 0x8400, 0x8200, 0x8100, 0x8780,
194         0x9200, 0xB200, 0xD900, 0x8900, 0x0600, 0x0000, 0x0000, 0x0000, }, {
195         0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7C00, 0x7E00, 0x7800,
196         0x6C00, 0x4C00, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000, },
197         9, 13, 89, 89, "mouse9x13_90",
198 };
199
200 static const struct mousedata mouse10x16_90 = { {
201         0xC000, 0xA000, 0x9000, 0x8800, 0x8400, 0x8200, 0x8100, 0x8080,
202         0x8040, 0x83E0, 0x8200, 0x9900, 0xA900, 0xC480, 0x8480, 0x0300, }, {
203         0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7C00, 0x7E00, 0x7F00,
204         0x7F80, 0x7C00, 0x7C00, 0x6600, 0x4600, 0x0300, 0x0300, 0x0000, },
205         10, 16, 89, 89, "mouse10x16_90",
206 };
207
208 static const struct mousedata mouse9x13_100 = { {
209         0xC000, 0xA000, 0x9000, 0x8800, 0x8400, 0x8200, 0x8100, 0x8780,
210         0xB200, 0xD200, 0x8900, 0x0900, 0x0600, 0x0000, 0x0000, 0x0000, }, {
211         0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7C00, 0x7E00, 0x7800,
212         0x4C00, 0x0C00, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000, },
213         9, 13, 106, 113, "mouse9x13_100",
214 };
215
216 static const struct mousedata mouse10x16_100 = { {
217         0xC000, 0xA000, 0x9000, 0x8800, 0x8400, 0x8200, 0x8100, 0x8080,
218         0x8040, 0x83C0, 0x9200, 0xA900, 0xC900, 0x0480, 0x0480, 0x0300, }, {
219         0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7C00, 0x7E00, 0x7F00,
220         0x7F80, 0x7C00, 0x6C00, 0x4600, 0x0600, 0x0300, 0x0300, 0x0000, },
221         10, 16, 96, 106, "mouse10x16_100",
222 };
223
224 static const struct mousedata mouse10x14_120 = { {
225         0xC000, 0xA000, 0x9000, 0x8800, 0x8400, 0x8200, 0x8100, 0x8080,
226         0x97C0, 0xB200, 0xF200, 0xC900, 0x8900, 0x0600, 0x0000, 0x0000, }, {
227         0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7C00, 0x7E00, 0x7F00,
228         0x6800, 0x4C00, 0x0C00, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, },
229         10, 14, 120, 124, "mouse10x14_120",
230 };
231
232 static const struct mousedata mouse10x16_120 = { {
233         0xC000, 0xA000, 0x9000, 0x8800, 0x8400, 0x8200, 0x8100, 0x8080,
234         0x97C0, 0xB200, 0xF200, 0xC900, 0x8900, 0x0480, 0x0480, 0x0300, }, {
235         0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7C00, 0x7E00, 0x7F00,
236         0x6800, 0x4C00, 0x0C00, 0x0600, 0x0600, 0x0300, 0x0300, 0x0000, },
237         10, 16, 120, 124, "mouse10x16_120",
238 };
239
240 static const struct mousedata mouse9x13_133 = { {
241         0xC000, 0xA000, 0x9000, 0x8800, 0x8400, 0x8200, 0x8100, 0x8080,
242         0x9780, 0xB200, 0xC900, 0x0900, 0x0600, 0x0000, 0x0000, 0x0000, }, {
243         0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7C00, 0x7E00, 0x7F00,
244         0x6800, 0x4C00, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000, },
245         9, 13, 142, 124, "mouse9x13_133",
246 };
247
248 static const struct mousedata mouse10x16_133 = { {
249         0xC000, 0xA000, 0x9000, 0x8800, 0x8400, 0x8200, 0x8100, 0x8080,
250         0x8040, 0x93E0, 0xB200, 0xC900, 0x8900, 0x0480, 0x0480, 0x0300, }, {
251         0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7C00, 0x7E00, 0x7F00,
252         0x7F80, 0x6C00, 0x4C00, 0x0600, 0x0600, 0x0300, 0x0300, 0x0000, },
253         10, 16, 120, 133, "mouse10x16_133",
254 };
255
256 static const struct mousedata mouse14x10_240 = { {
257         0xF800, 0xCE00, 0xC380, 0xC0E0, 0xC038, 0xC1FC, 0xDCC0, 0xF660,
258         0xC330, 0x01E0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, }, {
259         0x0000, 0x3000, 0x3C00, 0x3F00, 0x3FC0, 0x3E00, 0x2300, 0x0180,
260         0x00C0, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, },
261         14, 10, 189, 189, "mouse14x10_240",
262 };
263
264 static const struct mousedata * const mouselarge[] = {
265         &mouse10x16_50,
266         &mouse8x14_67,
267         &mouse10x16_75,
268         &mouse10x16_90,
269         &mouse10x16_100,
270         &mouse10x16_120,
271         &mouse10x16_133,
272         &mouse14x10_240,
273 };
274
275 static const struct mousedata * const mousesmall[] = {
276         &mouse8x14_67,
277         &mouse8x13_75,
278         &mouse9x13_90,
279         &mouse9x13_100,
280         &mouse10x14_120,
281         &mouse9x13_133,
282         &mouse14x10_240,
283 };
284 #endif
285 #endif
286
287 #ifdef SC_PIXEL_MODE
288 #define GET_PIXEL(scp, pos, x, w)                                       \
289 ({                                                                      \
290         (scp)->sc->adp->va_window +                                     \
291             (x) * (scp)->xoff +                                         \
292             (scp)->yoff * (scp)->font_size * (w) +                      \
293             (x) * ((pos) % (scp)->xsize) +                              \
294             (scp)->font_size * (w) * ((pos) / (scp)->xsize);            \
295 })
296
297 #define DRAW_PIXEL(scp, pos, color) do {                                \
298         switch ((scp)->sc->adp->va_info.vi_depth) {                     \
299         case 32:                                                        \
300                 writel((pos), vga_palette32[color]);                    \
301                 break;                                                  \
302         case 24:                                                        \
303                 if (((pos) & 1) == 0) {                                 \
304                         writew((pos), vga_palette32[color]);            \
305                         writeb((pos) + 2, vga_palette32[color] >> 16);  \
306                 } else {                                                \
307                         writeb((pos), vga_palette32[color]);            \
308                         writew((pos) + 1, vga_palette32[color] >> 8);   \
309                 }                                                       \
310                 break;                                                  \
311         case 16:                                                        \
312                 if ((scp)->sc->adp->va_info.vi_pixel_fsizes[1] == 5)    \
313                         writew((pos), vga_palette15[color]);            \
314                 else                                                    \
315                         writew((pos), vga_palette16[color]);            \
316                 break;                                                  \
317         case 15:                                                        \
318                 writew((pos), vga_palette15[color]);                    \
319                 break;                                                  \
320         case 8:                                                         \
321                 writeb((pos), (uint8_t)(color));                        \
322         }                                                               \
323 } while (0)
324         
325 static uint32_t vga_palette32[16] = {
326         0x000000, 0x0000ad, 0x00ad00, 0x00adad,
327         0xad0000, 0xad00ad, 0xad5200, 0xadadad,
328         0x525252, 0x5252ff, 0x52ff52, 0x52ffff,
329         0xff5252, 0xff52ff, 0xffff52, 0xffffff
330 };
331
332 static uint16_t vga_palette16[16] = {
333         0x0000, 0x0016, 0x0560, 0x0576, 0xb000, 0xb016, 0xb2a0, 0xb576,
334         0x52aa, 0x52bf, 0x57ea, 0x57ff, 0xfaaa, 0xfabf, 0xffea, 0xffff
335 };
336
337 static uint16_t vga_palette15[16] = {
338         0x0000, 0x0016, 0x02c0, 0x02d6, 0x5800, 0x5816, 0x5940, 0x5ad6,
339         0x294a, 0x295f, 0x2bea, 0x2bff, 0x7d4a, 0x7d5f, 0x7fea, 0x7fff
340 };
341 #endif
342
343 static int vga_aspect_scale= 100;
344 SYSCTL_INT(_machdep, OID_AUTO, vga_aspect_scale, CTLFLAG_RW,
345     &vga_aspect_scale, 0, "Aspect scale ratio (3:4):actual times 100");
346
347 static void
348 vga_setmdp(scr_stat *scp)
349 {
350 #if !defined(SC_NO_CUTPASTE) && \
351    (!defined(SC_ALT_MOUSE_IMAGE) || defined(SC_PIXEL_MODE))
352         const struct mousedata *mdp;
353         const struct mousedata * const *mdpp;
354         int aspect, best_i, best_v, i, n, v, wb, wi, xpixel, ypixel;
355
356         xpixel = scp->xpixel;
357         ypixel = scp->ypixel;
358         if (scp->sc->adp->va_flags & V_ADP_CWIDTH9)
359                 xpixel = xpixel * 9 / 8;
360
361         /* If 16:9 +-1%, assume square pixels, else scale to 4:3 or full. */
362         aspect = xpixel * 900 / ypixel / 16;
363         if (aspect < 99 || aspect > 100)
364                 aspect = xpixel * 300 / ypixel / 4 * vga_aspect_scale / 100;
365
366         /*
367          * Use 10x16 cursors except even with 8x8 fonts except in ~200-
368          * line modes where pixels are very large and in text mode where
369          * even 13 pixels high is really 4 too many.  Clipping a 16-high
370          * cursor at 9-high gives a variable tail which looks better than
371          * a smaller cursor with a constant tail.
372          *
373          * XXX: the IS*SC() macros don't work when this is called at the
374          * end of a mode switch since UNKNOWN_SC is still set.
375          */
376         if (scp->font_size <= 8 &&
377             (ypixel < 300 || !(scp->status & PIXEL_MODE))) {
378                 mdpp = &mousesmall[0];
379                 n = nitems(mousesmall);
380         } else {
381                 mdpp = &mouselarge[0];
382                 n = nitems(mouselarge);
383         }
384         if (scp->status & PIXEL_MODE) {
385                 wb = 1024;
386                 wi = 256;
387         } else {
388                 wb = 256;
389                 wi = 1024;
390         }
391         best_i = 0;
392         best_v = 0x7fffffff;
393         for (i = 0; i < n; i++) {
394                 v = (wb * abs(mdpp[i]->md_baspect - aspect) +
395                      wi * abs(mdpp[i]->md_iaspect - aspect)) / aspect;
396                 if (best_v > v) {
397                         best_v = v;
398                         best_i = i;
399                 }
400         }
401         mdp = mdpp[best_i];
402         scp->mouse_data = mdp;
403 #endif /* !SC_NO_CUTPASTE && (!SC_ALT_MOUSE_IMAGE || SC_PIXEL_MODE) */
404 }
405
406 static void
407 vga_nop(scr_stat *scp)
408 {
409 }
410
411 /* text mode renderer */
412
413 static void
414 vga_txtclear(scr_stat *scp, int c, int attr)
415 {
416         sc_vtb_clear(&scp->scr, c, attr);
417 }
418
419 static void
420 vga_txtborder(scr_stat *scp, int color)
421 {
422         vidd_set_border(scp->sc->adp, color);
423 }
424
425 static void
426 vga_txtdraw(scr_stat *scp, int from, int count, int flip)
427 {
428         vm_offset_t p;
429         int c;
430         int a;
431
432         if (from + count > scp->xsize*scp->ysize)
433                 count = scp->xsize*scp->ysize - from;
434
435         if (flip) {
436                 for (p = sc_vtb_pointer(&scp->scr, from); count-- > 0; ++from) {
437                         c = sc_vtb_getc(&scp->vtb, from);
438                         a = sc_vtb_geta(&scp->vtb, from);
439                         a = (a & 0x8800) | ((a & 0x7000) >> 4) 
440                                 | ((a & 0x0700) << 4);
441                         p = sc_vtb_putchar(&scp->scr, p, c, a);
442                 }
443         } else {
444                 sc_vtb_copy(&scp->vtb, from, &scp->scr, from, count);
445         }
446 }
447
448 static void 
449 vga_txtcursor_shape(scr_stat *scp, int base, int height, int blink)
450 {
451         vga_setmdp(scp);
452         if (base < 0 || base >= scp->font_size)
453                 return;
454         /* the caller may set height <= 0 in order to disable the cursor */
455         vidd_set_hw_cursor_shape(scp->sc->adp, base, height,
456             scp->font_size, blink);
457 }
458
459 static void
460 draw_txtcharcursor(scr_stat *scp, int at, u_short c, u_short a, int flip)
461 {
462         sc_softc_t *sc;
463
464         sc = scp->sc;
465
466 #ifndef SC_NO_FONT_LOADING
467         if (scp->curs_attr.flags & CONS_CHAR_CURSOR) {
468                 unsigned char *font;
469                 int h;
470                 int i;
471
472                 if (scp->font_size < 14) {
473                         font = sc->font_8;
474                         h = 8;
475                 } else if (scp->font_size >= 16) {
476                         font = sc->font_16;
477                         h = 16;
478                 } else {
479                         font = sc->font_14;
480                         h = 14;
481                 }
482                 if (scp->curs_attr.base >= h)
483                         return;
484                 if (flip)
485                         a = (a & 0x8800)
486                                 | ((a & 0x7000) >> 4) | ((a & 0x0700) << 4);
487                 bcopy(font + c*h, font + sc->cursor_char*h, h);
488                 font = font + sc->cursor_char*h;
489                 for (i = imax(h - scp->curs_attr.base - scp->curs_attr.height, 0);
490                         i < h - scp->curs_attr.base; ++i) {
491                         font[i] ^= 0xff;
492                 }
493                 /* XXX */
494                 vidd_load_font(sc->adp, 0, h, 8, font, sc->cursor_char, 1);
495                 sc_vtb_putc(&scp->scr, at, sc->cursor_char, a);
496         } else
497 #endif /* SC_NO_FONT_LOADING */
498         {
499                 if ((a & 0x7000) == 0x7000) {
500                         a &= 0x8f00;
501                         if ((a & 0x0700) == 0)
502                                 a |= 0x0700;
503                 } else {
504                         a |= 0x7000;
505                         if ((a & 0x0700) == 0x0700)
506                                 a &= 0xf000;
507                 }
508                 if (flip)
509                         a = (a & 0x8800)
510                                 | ((a & 0x7000) >> 4) | ((a & 0x0700) << 4);
511                 sc_vtb_putc(&scp->scr, at, c, a);
512         }
513 }
514
515 static void
516 vga_txtcursor(scr_stat *scp, int at, int blink, int on, int flip)
517 {
518         video_adapter_t *adp;
519         int cursor_attr;
520
521         if (scp->curs_attr.height <= 0) /* the text cursor is disabled */
522                 return;
523
524         adp = scp->sc->adp;
525         if (blink) {
526                 scp->status |= VR_CURSOR_BLINK;
527                 if (on) {
528                         scp->status |= VR_CURSOR_ON;
529                         vidd_set_hw_cursor(adp, at%scp->xsize,
530                             at/scp->xsize);
531                 } else {
532                         if (scp->status & VR_CURSOR_ON)
533                                 vidd_set_hw_cursor(adp, -1, -1);
534                         scp->status &= ~VR_CURSOR_ON;
535                 }
536         } else {
537                 scp->status &= ~VR_CURSOR_BLINK;
538                 if (on) {
539                         scp->status |= VR_CURSOR_ON;
540                         draw_txtcharcursor(scp, at,
541                                            sc_vtb_getc(&scp->vtb, at),
542                                            sc_vtb_geta(&scp->vtb, at),
543                                            flip);
544                 } else {
545                         cursor_attr = sc_vtb_geta(&scp->vtb, at);
546                         if (flip)
547                                 cursor_attr = (cursor_attr & 0x8800)
548                                         | ((cursor_attr & 0x7000) >> 4)
549                                         | ((cursor_attr & 0x0700) << 4);
550                         if (scp->status & VR_CURSOR_ON)
551                                 sc_vtb_putc(&scp->scr, at,
552                                             sc_vtb_getc(&scp->vtb, at),
553                                             cursor_attr);
554                         scp->status &= ~VR_CURSOR_ON;
555                 }
556         }
557 }
558
559 static void
560 vga_txtblink(scr_stat *scp, int at, int flip)
561 {
562 }
563
564 int sc_txtmouse_no_retrace_wait;
565
566 #ifndef SC_NO_CUTPASTE
567
568 static void
569 draw_txtmouse(scr_stat *scp, int x, int y)
570 {
571 #ifndef SC_ALT_MOUSE_IMAGE
572     if (ISMOUSEAVAIL(scp->sc->adp->va_flags)) {
573         const struct mousedata *mdp;
574         uint32_t border, interior;
575         u_char font_buf[128];
576         u_short cursor[32];
577         u_char c;
578         int pos;
579         int xoffset, yoffset;
580         int crtc_addr;
581         int i;
582
583         mdp = scp->mouse_data;
584
585         /* prepare mousepointer char's bitmaps */
586         pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff;
587         bcopy(scp->font + sc_vtb_getc(&scp->scr, pos)*scp->font_size,
588               &font_buf[0], scp->font_size);
589         bcopy(scp->font + sc_vtb_getc(&scp->scr, pos + 1)*scp->font_size,
590               &font_buf[32], scp->font_size);
591         bcopy(scp->font 
592                  + sc_vtb_getc(&scp->scr, pos + scp->xsize)*scp->font_size,
593               &font_buf[64], scp->font_size);
594         bcopy(scp->font
595                  + sc_vtb_getc(&scp->scr, pos + scp->xsize + 1)*scp->font_size,
596               &font_buf[96], scp->font_size);
597         for (i = 0; i < scp->font_size; ++i) {
598                 cursor[i] = font_buf[i]<<8 | font_buf[i+32];
599                 cursor[i + scp->font_size] = font_buf[i+64]<<8 | font_buf[i+96];
600         }
601
602         /* now and-or in the mousepointer image */
603         xoffset = x%8;
604         yoffset = y%scp->font_size;
605         for (i = 0; i < 16; ++i) {
606                 border = mdp->md_border[i] << 8; /* avoid right shifting out */
607                 interior = mdp->md_interior[i] << 8;
608                 border >>= xoffset;             /* normalize */
609                 interior >>= xoffset;
610                 if (scp->sc->adp->va_flags & V_ADP_CWIDTH9) {
611                         /* skip gaps between characters */
612                         border = (border & 0xff0000) |
613                                  (border & 0x007f80) << 1 |
614                                  (border & 0x00003f) << 2;
615                         interior = (interior & 0xff0000) |
616                                    (interior & 0x007f80) << 1 |
617                                    (interior & 0x00003f) << 2;
618                 }
619                 border >>= 8;                   /* back to normal position */
620                 interior >>= 8;
621                 cursor[i + yoffset] = (cursor[i + yoffset]  & ~border) |
622                                       interior;
623         }
624         for (i = 0; i < scp->font_size; ++i) {
625                 font_buf[i] = (cursor[i] & 0xff00) >> 8;
626                 font_buf[i + 32] = cursor[i] & 0xff;
627                 font_buf[i + 64] = (cursor[i + scp->font_size] & 0xff00) >> 8;
628                 font_buf[i + 96] = cursor[i + scp->font_size] & 0xff;
629         }
630
631 #if 1
632         /* wait for vertical retrace to avoid jitter on some videocards */
633         crtc_addr = scp->sc->adp->va_crtc_addr;
634         while (!sc_txtmouse_no_retrace_wait &&
635             !(inb(crtc_addr + 6) & 0x08))
636                 /* idle */ ;
637 #endif
638         c = scp->sc->mouse_char;
639         vidd_load_font(scp->sc->adp, 0, 32, 8, font_buf, c, 4); 
640
641         sc_vtb_putc(&scp->scr, pos, c, sc_vtb_geta(&scp->scr, pos));
642         /* FIXME: may be out of range! */
643         sc_vtb_putc(&scp->scr, pos + scp->xsize, c + 2,
644                     sc_vtb_geta(&scp->scr, pos + scp->xsize));
645         if (x < (scp->xsize - 1)*8) {
646                 sc_vtb_putc(&scp->scr, pos + 1, c + 1,
647                             sc_vtb_geta(&scp->scr, pos + 1));
648                 sc_vtb_putc(&scp->scr, pos + scp->xsize + 1, c + 3,
649                             sc_vtb_geta(&scp->scr, pos + scp->xsize + 1));
650         }
651     } else
652 #endif /* SC_ALT_MOUSE_IMAGE */
653     {
654         /* Red, magenta and brown are mapped to green to to keep it readable */
655         static const int col_conv[16] = {
656                 6, 6, 6, 6, 2, 2, 2, 6, 14, 14, 14, 14, 10, 10, 10, 14
657         };
658         int pos;
659         int color;
660         int a;
661
662         pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff;
663         a = sc_vtb_geta(&scp->scr, pos);
664         if (scp->sc->adp->va_flags & V_ADP_COLOR)
665                 color = (col_conv[(a & 0xf000) >> 12] << 12)
666                         | ((a & 0x0f00) | 0x0800);
667         else
668                 color = ((a & 0xf000) >> 4) | ((a & 0x0f00) << 4);
669         sc_vtb_putc(&scp->scr, pos, sc_vtb_getc(&scp->scr, pos), color);
670     }
671 }
672
673 static void
674 remove_txtmouse(scr_stat *scp, int x, int y)
675 {
676 }
677
678 static void 
679 vga_txtmouse(scr_stat *scp, int x, int y, int on)
680 {
681         if (on)
682                 draw_txtmouse(scp, x, y);
683         else
684                 remove_txtmouse(scp, x, y);
685 }
686
687 #endif /* SC_NO_CUTPASTE */
688
689 #ifdef SC_PIXEL_MODE
690
691 /* pixel (raster text) mode renderer */
692
693 static void
694 vga_rndrinit(scr_stat *scp)
695 {
696         if (scp->sc->adp->va_info.vi_mem_model == V_INFO_MM_PLANAR) {
697                 scp->rndr->clear = vga_pxlclear_planar;
698                 scp->rndr->draw_border = vga_pxlborder_planar;
699                 scp->rndr->draw = vga_vgadraw_planar;
700                 scp->rndr->draw_cursor = vga_pxlcursor_planar;
701                 scp->rndr->blink_cursor = vga_pxlblink_planar;
702                 scp->rndr->draw_mouse = vga_pxlmouse_planar;
703         } else
704         if (scp->sc->adp->va_info.vi_mem_model == V_INFO_MM_DIRECT ||
705             scp->sc->adp->va_info.vi_mem_model == V_INFO_MM_PACKED) {
706                 scp->rndr->clear = vga_pxlclear_direct;
707                 scp->rndr->draw_border = vga_pxlborder_direct;
708                 scp->rndr->draw = vga_vgadraw_direct;
709                 scp->rndr->draw_cursor = vga_pxlcursor_direct;
710                 scp->rndr->blink_cursor = vga_pxlblink_direct;
711                 scp->rndr->draw_mouse = vga_pxlmouse_direct;
712         }
713 }
714
715 static void
716 vga_pxlclear_direct(scr_stat *scp, int c, int attr)
717 {
718         vm_offset_t p;
719         int line_width;
720         int pixel_size;
721         int lines;
722         int i;
723
724         line_width = scp->sc->adp->va_line_width;
725         pixel_size = scp->sc->adp->va_info.vi_pixel_size;
726         lines = scp->ysize * scp->font_size; 
727         p = scp->sc->adp->va_window +
728             line_width * scp->yoff * scp->font_size +
729             scp->xoff * 8 * pixel_size;
730
731         for (i = 0; i < lines; ++i) {
732                 bzero_io((void *)p, scp->xsize * 8 * pixel_size);
733                 p += line_width;
734         }
735 }
736
737 static void
738 vga_pxlclear_planar(scr_stat *scp, int c, int attr)
739 {
740         vm_offset_t p;
741         int line_width;
742         int lines;
743         int i;
744
745         /* XXX: we are just filling the screen with the background color... */
746         outw(GDCIDX, 0x0005);           /* read mode 0, write mode 0 */
747         outw(GDCIDX, 0x0003);           /* data rotate/function select */
748         outw(GDCIDX, 0x0f01);           /* set/reset enable */
749         outw(GDCIDX, 0xff08);           /* bit mask */
750         outw(GDCIDX, ((attr & 0xf000) >> 4) | 0x00); /* set/reset */
751         line_width = scp->sc->adp->va_line_width;
752         lines = scp->ysize*scp->font_size; 
753         p = scp->sc->adp->va_window + line_width*scp->yoff*scp->font_size
754                 + scp->xoff;
755         for (i = 0; i < lines; ++i) {
756                 bzero_io((void *)p, scp->xsize);
757                 p += line_width;
758         }
759         outw(GDCIDX, 0x0000);           /* set/reset */
760         outw(GDCIDX, 0x0001);           /* set/reset enable */
761 }
762
763 static void
764 vga_pxlborder_direct(scr_stat *scp, int color)
765 {
766         vm_offset_t s;
767         vm_offset_t e;
768         vm_offset_t f;
769         int line_width;
770         int pixel_size;
771         int x;
772         int y;
773         int i;
774
775         line_width = scp->sc->adp->va_line_width;
776         pixel_size = scp->sc->adp->va_info.vi_pixel_size;
777
778         if (scp->yoff > 0) {
779                 s = scp->sc->adp->va_window;
780                 e = s + line_width * scp->yoff * scp->font_size;
781
782                 for (f = s; f < e; f += pixel_size)
783                         DRAW_PIXEL(scp, f, color);
784         }
785
786         y = (scp->yoff + scp->ysize) * scp->font_size;
787
788         if (scp->ypixel > y) {
789                 s = scp->sc->adp->va_window + line_width * y;
790                 e = s + line_width * (scp->ypixel - y);
791
792                 for (f = s; f < e; f += pixel_size)
793                         DRAW_PIXEL(scp, f, color);
794         }
795
796         y = scp->yoff * scp->font_size;
797         x = scp->xpixel / 8 - scp->xoff - scp->xsize;
798
799         for (i = 0; i < scp->ysize * scp->font_size; ++i) {
800                 if (scp->xoff > 0) {
801                         s = scp->sc->adp->va_window + line_width * (y + i);
802                         e = s + scp->xoff * 8 * pixel_size;
803
804                         for (f = s; f < e; f += pixel_size)
805                                 DRAW_PIXEL(scp, f, color);
806                 }
807
808                 if (x > 0) {
809                         s = scp->sc->adp->va_window + line_width * (y + i) +
810                             scp->xoff * 8 * pixel_size +
811                             scp->xsize * 8 * pixel_size;
812                         e = s + x * 8 * pixel_size;
813
814                         for (f = s; f < e; f += pixel_size)
815                                 DRAW_PIXEL(scp, f, color);
816                 }
817         }
818 }
819
820 static void
821 vga_pxlborder_planar(scr_stat *scp, int color)
822 {
823         vm_offset_t p;
824         int line_width;
825         int x;
826         int y;
827         int i;
828
829         vidd_set_border(scp->sc->adp, color);
830
831         outw(GDCIDX, 0x0005);           /* read mode 0, write mode 0 */
832         outw(GDCIDX, 0x0003);           /* data rotate/function select */
833         outw(GDCIDX, 0x0f01);           /* set/reset enable */
834         outw(GDCIDX, 0xff08);           /* bit mask */
835         outw(GDCIDX, (color << 8) | 0x00);      /* set/reset */
836         line_width = scp->sc->adp->va_line_width;
837         p = scp->sc->adp->va_window;
838         if (scp->yoff > 0)
839                 bzero_io((void *)p, line_width*scp->yoff*scp->font_size);
840         y = (scp->yoff + scp->ysize)*scp->font_size;
841         if (scp->ypixel > y)
842                 bzero_io((void *)(p + line_width*y), line_width*(scp->ypixel - y));
843         y = scp->yoff*scp->font_size;
844         x = scp->xpixel/8 - scp->xoff - scp->xsize;
845         for (i = 0; i < scp->ysize*scp->font_size; ++i) {
846                 if (scp->xoff > 0)
847                         bzero_io((void *)(p + line_width*(y + i)), scp->xoff);
848                 if (x > 0)
849                         bzero_io((void *)(p + line_width*(y + i)
850                                      + scp->xoff + scp->xsize), x);
851         }
852         outw(GDCIDX, 0x0000);           /* set/reset */
853         outw(GDCIDX, 0x0001);           /* set/reset enable */
854 }
855
856 static void
857 vga_vgadraw_direct(scr_stat *scp, int from, int count, int flip)
858 {
859         vm_offset_t d;
860         vm_offset_t e;
861         u_char *f;
862         u_short col1, col2, color;
863         int line_width, pixel_size;
864         int i, j, k;
865         int a;
866
867         line_width = scp->sc->adp->va_line_width;
868         pixel_size = scp->sc->adp->va_info.vi_pixel_size;
869
870         d = GET_PIXEL(scp, from, 8 * pixel_size, line_width);
871
872         if (from + count > scp->xsize * scp->ysize)
873                 count = scp->xsize * scp->ysize - from;
874
875         for (i = from; count-- > 0; ++i) {
876                 a = sc_vtb_geta(&scp->vtb, i);
877
878                 if (flip) {
879                         col1 = (((a & 0x7000) >> 4) | (a & 0x0800)) >> 8;
880                         col2 = (((a & 0x8000) >> 4) | (a & 0x0700)) >> 8;
881                 } else {
882                         col1 = (a & 0x0f00) >> 8;
883                         col2 = (a & 0xf000) >> 12;
884                 }
885
886                 e = d;
887                 f = &(scp->font[sc_vtb_getc(&scp->vtb, i) * scp->font_size]);
888
889                 for (j = 0; j < scp->font_size; ++j, ++f) {
890                         for (k = 0; k < 8; ++k) {
891                                 color = *f & (1 << (7 - k)) ? col1 : col2;
892                                 DRAW_PIXEL(scp, e + pixel_size * k, color);
893                         }
894
895                         e += line_width;
896                 }
897
898                 d += 8 * pixel_size;
899
900                 if ((i % scp->xsize) == scp->xsize - 1)
901                         d += scp->font_size * line_width -
902                             scp->xsize * 8 * pixel_size;
903         }
904 }
905
906 static void
907 vga_vgadraw_planar(scr_stat *scp, int from, int count, int flip)
908 {
909         vm_offset_t d;
910         vm_offset_t e;
911         u_char *f;
912         u_short bg, fg;
913         u_short col1, col2;
914         int line_width;
915         int i, j;
916         int a;
917         u_char c;
918
919         line_width = scp->sc->adp->va_line_width;
920
921         d = GET_PIXEL(scp, from, 1, line_width);
922
923         if (scp->sc->adp->va_type == KD_VGA) {
924                 outw(GDCIDX, 0x0305);   /* read mode 0, write mode 3 */
925                 outw(GDCIDX, 0xff08);   /* bit mask */
926         } else
927                 outw(GDCIDX, 0x0005);   /* read mode 0, write mode 0 */
928         outw(GDCIDX, 0x0003);           /* data rotate/function select */
929         outw(GDCIDX, 0x0f01);           /* set/reset enable */
930         fg = bg = -1;
931         if (from + count > scp->xsize*scp->ysize)
932                 count = scp->xsize*scp->ysize - from;
933         for (i = from; count-- > 0; ++i) {
934                 a = sc_vtb_geta(&scp->vtb, i);
935                 if (flip) {
936                         col1 = ((a & 0x7000) >> 4) | (a & 0x0800);
937                         col2 = ((a & 0x8000) >> 4) | (a & 0x0700);
938                 } else {
939                         col1 = (a & 0x0f00);
940                         col2 = (a & 0xf000) >> 4;
941                 }
942                 /* set background color in EGA/VGA latch */
943                 if (bg != col2) {
944                         bg = col2;
945                         fg = -1;
946                         outw(GDCIDX, bg | 0x00); /* set/reset */
947                         if (scp->sc->adp->va_type != KD_VGA)
948                                 outw(GDCIDX, 0xff08); /* bit mask */
949                         writeb(d, 0xff);
950                         c = readb(d);           /* set bg color in the latch */
951                 }
952                 /* foreground color */
953                 if (fg != col1) {
954                         fg = col1;
955                         outw(GDCIDX, col1 | 0x00); /* set/reset */
956                 }
957                 e = d;
958                 f = &(scp->font[sc_vtb_getc(&scp->vtb, i)*scp->font_size]);
959                 for (j = 0; j < scp->font_size; ++j, ++f) {
960                         if (scp->sc->adp->va_type == KD_VGA)
961                                 writeb(e, *f);  
962                         else {
963                                 outw(GDCIDX, (*f << 8) | 0x08); /* bit mask */
964                                 writeb(e, 0);   
965                         }
966                         e += line_width;
967                 }
968                 ++d;
969                 if ((i % scp->xsize) == scp->xsize - 1)
970                         d += scp->font_size * line_width - scp->xsize;
971         }
972         if (scp->sc->adp->va_type == KD_VGA)
973                 outw(GDCIDX, 0x0005);   /* read mode 0, write mode 0 */
974         else
975                 outw(GDCIDX, 0xff08);   /* bit mask */
976         outw(GDCIDX, 0x0000);           /* set/reset */
977         outw(GDCIDX, 0x0001);           /* set/reset enable */
978 }
979
980 static void 
981 vga_pxlcursor_shape(scr_stat *scp, int base, int height, int blink)
982 {
983         vga_setmdp(scp);
984 }
985
986 static void 
987 draw_pxlcursor_direct(scr_stat *scp, int at, int on, int flip)
988 {
989         vm_offset_t d;
990         u_char *f;
991         int line_width, pixel_size;
992         int height;
993         int col1, col2, color;
994         int a;
995         int i, j;
996
997         line_width = scp->sc->adp->va_line_width;
998         pixel_size = scp->sc->adp->va_info.vi_pixel_size;
999
1000         d = GET_PIXEL(scp, at, 8 * pixel_size, line_width) +
1001             (scp->font_size - scp->curs_attr.base - 1) * line_width;
1002
1003         a = sc_vtb_geta(&scp->vtb, at);
1004
1005         if (flip) {
1006                 col1 = ((on) ? (a & 0x0f00) : ((a & 0xf000) >> 4)) >> 8;
1007                 col2 = ((on) ? ((a & 0xf000) >> 4) : (a & 0x0f00)) >> 8;
1008         } else {
1009                 col1 = ((on) ? ((a & 0xf000) >> 4) : (a & 0x0f00)) >> 8;
1010                 col2 = ((on) ? (a & 0x0f00) : ((a & 0xf000) >> 4)) >> 8;
1011         }
1012
1013         f = &(scp->font[sc_vtb_getc(&scp->vtb, at) * scp->font_size +
1014               scp->font_size - scp->curs_attr.base - 1]);
1015
1016         height = imin(scp->curs_attr.height, scp->font_size);
1017
1018         for (i = 0; i < height; ++i, --f) {
1019                 for (j = 0; j < 8; ++j) {
1020                         color = *f & (1 << (7 - j)) ? col1 : col2;
1021                         DRAW_PIXEL(scp, d + pixel_size * j, color);
1022                 }
1023
1024                 d -= line_width;
1025         }
1026 }
1027
1028 static void 
1029 draw_pxlcursor_planar(scr_stat *scp, int at, int on, int flip)
1030 {
1031         vm_offset_t d;
1032         u_char *f;
1033         int line_width;
1034         int height;
1035         int col;
1036         int a;
1037         int i;
1038         u_char c;
1039
1040         line_width = scp->sc->adp->va_line_width;
1041
1042         d = GET_PIXEL(scp, at, 1, line_width) +
1043             (scp->font_size - scp->curs_attr.base - 1) * line_width;
1044
1045         outw(GDCIDX, 0x0005);           /* read mode 0, write mode 0 */
1046         outw(GDCIDX, 0x0003);           /* data rotate/function select */
1047         outw(GDCIDX, 0x0f01);           /* set/reset enable */
1048         /* set background color in EGA/VGA latch */
1049         a = sc_vtb_geta(&scp->vtb, at);
1050         if (flip)
1051                 col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00);
1052         else
1053                 col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4);
1054         outw(GDCIDX, col | 0x00);       /* set/reset */
1055         outw(GDCIDX, 0xff08);           /* bit mask */
1056         writeb(d, 0);
1057         c = readb(d);                   /* set bg color in the latch */
1058         /* foreground color */
1059         if (flip)
1060                 col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4);
1061         else
1062                 col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00);
1063         outw(GDCIDX, col | 0x00);       /* set/reset */
1064         f = &(scp->font[sc_vtb_getc(&scp->vtb, at)*scp->font_size
1065                 + scp->font_size - scp->curs_attr.base - 1]);
1066         height = imin(scp->curs_attr.height, scp->font_size);
1067         for (i = 0; i < height; ++i, --f) {
1068                 outw(GDCIDX, (*f << 8) | 0x08); /* bit mask */
1069                 writeb(d, 0);
1070                 d -= line_width;
1071         }
1072         outw(GDCIDX, 0x0000);           /* set/reset */
1073         outw(GDCIDX, 0x0001);           /* set/reset enable */
1074         outw(GDCIDX, 0xff08);           /* bit mask */
1075 }
1076
1077 static int pxlblinkrate = 0;
1078
1079 static void 
1080 vga_pxlcursor_direct(scr_stat *scp, int at, int blink, int on, int flip)
1081 {
1082         if (scp->curs_attr.height <= 0) /* the text cursor is disabled */
1083                 return;
1084
1085         if (on) {
1086                 if (!blink) {
1087                         scp->status |= VR_CURSOR_ON;
1088                         draw_pxlcursor_direct(scp, at, on, flip);
1089                 } else if (++pxlblinkrate & 4) {
1090                         pxlblinkrate = 0;
1091                         scp->status ^= VR_CURSOR_ON;
1092                         draw_pxlcursor_direct(scp, at,
1093                                               scp->status & VR_CURSOR_ON,
1094                                               flip);
1095                 }
1096         } else {
1097                 if (scp->status & VR_CURSOR_ON)
1098                         draw_pxlcursor_direct(scp, at, on, flip);
1099                 scp->status &= ~VR_CURSOR_ON;
1100         }
1101         if (blink)
1102                 scp->status |= VR_CURSOR_BLINK;
1103         else
1104                 scp->status &= ~VR_CURSOR_BLINK;
1105 }
1106
1107 static void 
1108 vga_pxlcursor_planar(scr_stat *scp, int at, int blink, int on, int flip)
1109 {
1110         if (scp->curs_attr.height <= 0) /* the text cursor is disabled */
1111                 return;
1112
1113         if (on) {
1114                 if (!blink) {
1115                         scp->status |= VR_CURSOR_ON;
1116                         draw_pxlcursor_planar(scp, at, on, flip);
1117                 } else if (++pxlblinkrate & 4) {
1118                         pxlblinkrate = 0;
1119                         scp->status ^= VR_CURSOR_ON;
1120                         draw_pxlcursor_planar(scp, at,
1121                                               scp->status & VR_CURSOR_ON,
1122                                               flip);
1123                 }
1124         } else {
1125                 if (scp->status & VR_CURSOR_ON)
1126                         draw_pxlcursor_planar(scp, at, on, flip);
1127                 scp->status &= ~VR_CURSOR_ON;
1128         }
1129         if (blink)
1130                 scp->status |= VR_CURSOR_BLINK;
1131         else
1132                 scp->status &= ~VR_CURSOR_BLINK;
1133 }
1134
1135 static void
1136 vga_pxlblink_direct(scr_stat *scp, int at, int flip)
1137 {
1138         if (!(scp->status & VR_CURSOR_BLINK))
1139                 return;
1140         if (!(++pxlblinkrate & 4))
1141                 return;
1142         pxlblinkrate = 0;
1143         scp->status ^= VR_CURSOR_ON;
1144         draw_pxlcursor_direct(scp, at, scp->status & VR_CURSOR_ON, flip);
1145 }
1146
1147 static void
1148 vga_pxlblink_planar(scr_stat *scp, int at, int flip)
1149 {
1150         if (!(scp->status & VR_CURSOR_BLINK))
1151                 return;
1152         if (!(++pxlblinkrate & 4))
1153                 return;
1154         pxlblinkrate = 0;
1155         scp->status ^= VR_CURSOR_ON;
1156         draw_pxlcursor_planar(scp, at, scp->status & VR_CURSOR_ON, flip);
1157 }
1158
1159 #ifndef SC_NO_CUTPASTE
1160
1161 static void
1162 draw_pxlmouse_planar(scr_stat *scp, int x, int y)
1163 {
1164         const struct mousedata *mdp;
1165         vm_offset_t p;
1166         int line_width;
1167         int xoff, yoff;
1168         int ymax;
1169         uint32_t m;
1170         int i, j, k;
1171         uint8_t m1;
1172
1173         mdp = scp->mouse_data;
1174         line_width = scp->sc->adp->va_line_width;
1175         xoff = (x - scp->xoff*8)%8;
1176         yoff = y - rounddown(y, line_width);
1177         ymax = imin(y + mdp->md_height, scp->ypixel);
1178
1179         if (scp->sc->adp->va_type == KD_VGA) {
1180                 outw(GDCIDX, 0x0305);   /* read mode 0, write mode 3 */
1181                 outw(GDCIDX, 0xff08);   /* bit mask */
1182         } else
1183                 outw(GDCIDX, 0x0005);   /* read mode 0, write mode 0 */
1184         outw(GDCIDX, 0x0003);           /* data rotate/function select */
1185         outw(GDCIDX, 0x0f01);           /* set/reset enable */
1186
1187         outw(GDCIDX, (0 << 8) | 0x00); /* set/reset */
1188         p = scp->sc->adp->va_window + line_width*y + x/8;
1189         for (i = y, j = 0; i < ymax; ++i, ++j) {
1190                 m = mdp->md_border[j] << 8 >> xoff;
1191                 for (k = 0; k < 3; ++k) {
1192                         m1 = m >> (8 * (2 - k));
1193                         if (m1 != 0 && x + 8 * k < scp->xpixel) {
1194                                 readb(p + k);
1195                                 if (scp->sc->adp->va_type == KD_VGA)
1196                                         writeb(p + k, m1);
1197                                 else {
1198                                         /* bit mask: */
1199                                         outw(GDCIDX, (m1 << 8) | 0x08);
1200                                         writeb(p + k, 0);
1201                                 }
1202                         }
1203                 }
1204                 p += line_width;
1205         }
1206         outw(GDCIDX, (15 << 8) | 0x00); /* set/reset */
1207         p = scp->sc->adp->va_window + line_width*y + x/8;
1208         for (i = y, j = 0; i < ymax; ++i, ++j) {
1209                 m = mdp->md_interior[j] << 8 >> xoff;
1210                 for (k = 0; k < 3; ++k) {
1211                         m1 = m >> (8 * (2 - k));
1212                         if (m1 != 0 && x + 8 * k < scp->xpixel) {
1213                                 readb(p + k);
1214                                 if (scp->sc->adp->va_type == KD_VGA)
1215                                         writeb(p + k, m1);
1216                                 else {
1217                                         /* bit mask: */
1218                                         outw(GDCIDX, (m1 << 8) | 0x08);
1219                                         writeb(p + k, 0);
1220                                 }
1221                         }
1222                 }
1223                 p += line_width;
1224         }
1225         if (scp->sc->adp->va_type == KD_VGA)
1226                 outw(GDCIDX, 0x0005);   /* read mode 0, write mode 0 */
1227         else
1228                 outw(GDCIDX, 0xff08);   /* bit mask */
1229         outw(GDCIDX, 0x0000);           /* set/reset */
1230         outw(GDCIDX, 0x0001);           /* set/reset enable */
1231 }
1232
1233 static void
1234 remove_pxlmouse_planar(scr_stat *scp, int x, int y)
1235 {
1236         const struct mousedata *mdp;
1237         vm_offset_t p;
1238         int bx, by, i, line_width, xend, xoff, yend, yoff;
1239
1240         mdp = scp->mouse_data;
1241
1242         /*
1243          * It is only necessary to remove the mouse image where it overlaps
1244          * the border.  Determine the overlap, and do nothing if it is empty.
1245          */
1246         bx = (scp->xoff + scp->xsize) * 8;
1247         by = (scp->yoff + scp->ysize) * scp->font_size;
1248         xend = imin(x + mdp->md_width, scp->xpixel);
1249         yend = imin(y + mdp->md_height, scp->ypixel);
1250         if (xend <= bx && yend <= by)
1251                 return;
1252
1253         /* Repaint the non-empty overlap. */
1254         line_width = scp->sc->adp->va_line_width;
1255         outw(GDCIDX, 0x0005);           /* read mode 0, write mode 0 */
1256         outw(GDCIDX, 0x0003);           /* data rotate/function select */
1257         outw(GDCIDX, 0x0f01);           /* set/reset enable */
1258         outw(GDCIDX, 0xff08);           /* bit mask */
1259         outw(GDCIDX, (scp->border << 8) | 0x00);        /* set/reset */
1260         for (i = x / 8, xoff = i * 8; xoff < xend; ++i, xoff += 8) {
1261                 yoff = (xoff >= bx) ? y : by;
1262                 p = scp->sc->adp->va_window + yoff * line_width + i;
1263                 for (; yoff < yend; ++yoff, p += line_width)
1264                         writeb(p, 0);
1265         }
1266         outw(GDCIDX, 0x0000);           /* set/reset */
1267         outw(GDCIDX, 0x0001);           /* set/reset enable */
1268 }
1269
1270 static void 
1271 vga_pxlmouse_direct(scr_stat *scp, int x, int y, int on)
1272 {
1273         const struct mousedata *mdp;
1274         vm_offset_t p;
1275         int line_width, pixel_size;
1276         int xend, yend;
1277         int i, j;
1278
1279         mdp = scp->mouse_data;
1280
1281         /*
1282          * Determine overlap with the border and then if removing, do nothing
1283          * if the overlap is empty.
1284          */
1285         xend = imin(x + mdp->md_width, scp->xpixel);
1286         yend = imin(y + mdp->md_height, scp->ypixel);
1287         if (!on && xend <= (scp->xoff + scp->xsize) * 8 &&
1288             yend <= (scp->yoff + scp->ysize) * scp->font_size)
1289                 return;
1290
1291         line_width = scp->sc->adp->va_line_width;
1292         pixel_size = scp->sc->adp->va_info.vi_pixel_size;
1293
1294         if (on)
1295                 goto do_on;
1296
1297         /* Repaint overlap with the border (mess up the corner a little). */
1298         p = scp->sc->adp->va_window + y * line_width + x * pixel_size;
1299         for (i = 0; i < yend - y; i++, p += line_width)
1300                 for (j = xend - x - 1; j >= 0; j--)
1301                         DRAW_PIXEL(scp, p + j * pixel_size, scp->border);
1302
1303         return;
1304
1305 do_on:
1306         p = scp->sc->adp->va_window + y * line_width + x * pixel_size;
1307         for (i = 0; i < yend - y; i++, p += line_width)
1308                 for (j = xend - x - 1; j >= 0; j--)
1309                         if (mdp->md_interior[i] & (1 << (15 - j)))
1310                                 DRAW_PIXEL(scp, p + j * pixel_size, 15);
1311                         else if (mdp->md_border[i] & (1 << (15 - j)))
1312                                 DRAW_PIXEL(scp, p + j * pixel_size, 0);
1313 }
1314
1315 static void 
1316 vga_pxlmouse_planar(scr_stat *scp, int x, int y, int on)
1317 {
1318         if (on)
1319                 draw_pxlmouse_planar(scp, x, y);
1320         else
1321                 remove_pxlmouse_planar(scp, x, y);
1322 }
1323
1324 #endif /* SC_NO_CUTPASTE */
1325 #endif /* SC_PIXEL_MODE */
1326
1327 #ifndef SC_NO_MODE_CHANGE
1328
1329 /* graphics mode renderer */
1330
1331 static void
1332 vga_grborder(scr_stat *scp, int color)
1333 {
1334         vidd_set_border(scp->sc->adp, color);
1335 }
1336
1337 #endif