]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/syscons/scvgarndr.c
MFV r319951: 8311 ZFS_READONLY is a little too strict
[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
44 #include <machine/bus.h>
45
46 #include <dev/fb/fbreg.h>
47 #include <dev/fb/vgareg.h>
48 #include <dev/syscons/syscons.h>
49
50 #include <isa/isareg.h>
51
52 #ifndef SC_RENDER_DEBUG
53 #define SC_RENDER_DEBUG         0
54 #endif
55
56 static vr_clear_t               vga_txtclear;
57 static vr_draw_border_t         vga_txtborder;
58 static vr_draw_t                vga_txtdraw;
59 static vr_set_cursor_t          vga_txtcursor_shape;
60 static vr_draw_cursor_t         vga_txtcursor;
61 static vr_blink_cursor_t        vga_txtblink;
62 #ifndef SC_NO_CUTPASTE
63 static vr_draw_mouse_t          vga_txtmouse;
64 #else
65 #define vga_txtmouse            (vr_draw_mouse_t *)vga_nop
66 #endif
67
68 #ifdef SC_PIXEL_MODE
69 static vr_init_t                vga_rndrinit;
70 static vr_clear_t               vga_pxlclear_direct;
71 static vr_clear_t               vga_pxlclear_planar;
72 static vr_draw_border_t         vga_pxlborder_direct;
73 static vr_draw_border_t         vga_pxlborder_planar;
74 static vr_draw_t                vga_vgadraw_direct;
75 static vr_draw_t                vga_vgadraw_planar;
76 static vr_set_cursor_t          vga_pxlcursor_shape;
77 static vr_draw_cursor_t         vga_pxlcursor_direct;
78 static vr_draw_cursor_t         vga_pxlcursor_planar;
79 static vr_blink_cursor_t        vga_pxlblink_direct;
80 static vr_blink_cursor_t        vga_pxlblink_planar;
81 #ifndef SC_NO_CUTPASTE
82 static vr_draw_mouse_t          vga_pxlmouse_direct;
83 static vr_draw_mouse_t          vga_pxlmouse_planar;
84 #else
85 #define vga_pxlmouse_direct     (vr_draw_mouse_t *)vga_nop
86 #define vga_pxlmouse_planar     (vr_draw_mouse_t *)vga_nop
87 #endif
88 #endif /* SC_PIXEL_MODE */
89
90 #ifndef SC_NO_MODE_CHANGE
91 static vr_draw_border_t         vga_grborder;
92 #endif
93
94 static void                     vga_nop(scr_stat *scp);
95
96 static sc_rndr_sw_t txtrndrsw = {
97         (vr_init_t *)vga_nop,
98         vga_txtclear,
99         vga_txtborder,
100         vga_txtdraw,    
101         vga_txtcursor_shape,
102         vga_txtcursor,
103         vga_txtblink,
104         (vr_set_mouse_t *)vga_nop,
105         vga_txtmouse,
106 };
107 RENDERER(mda, 0, txtrndrsw, vga_set);
108 RENDERER(cga, 0, txtrndrsw, vga_set);
109 RENDERER(ega, 0, txtrndrsw, vga_set);
110 RENDERER(vga, 0, txtrndrsw, vga_set);
111
112 #ifdef SC_PIXEL_MODE
113 static sc_rndr_sw_t vgarndrsw = {
114         vga_rndrinit,
115         (vr_clear_t *)vga_nop,
116         (vr_draw_border_t *)vga_nop,
117         (vr_draw_t *)vga_nop,
118         vga_pxlcursor_shape,
119         (vr_draw_cursor_t *)vga_nop,
120         (vr_blink_cursor_t *)vga_nop,
121         (vr_set_mouse_t *)vga_nop,
122         (vr_draw_mouse_t *)vga_nop,
123 };
124 RENDERER(ega, PIXEL_MODE, vgarndrsw, vga_set);
125 RENDERER(vga, PIXEL_MODE, vgarndrsw, vga_set);
126 #endif /* SC_PIXEL_MODE */
127
128 #ifndef SC_NO_MODE_CHANGE
129 static sc_rndr_sw_t grrndrsw = {
130         (vr_init_t *)vga_nop,
131         (vr_clear_t *)vga_nop,
132         vga_grborder,
133         (vr_draw_t *)vga_nop,
134         (vr_set_cursor_t *)vga_nop,
135         (vr_draw_cursor_t *)vga_nop,
136         (vr_blink_cursor_t *)vga_nop,
137         (vr_set_mouse_t *)vga_nop,
138         (vr_draw_mouse_t *)vga_nop,
139 };
140 RENDERER(cga, GRAPHICS_MODE, grrndrsw, vga_set);
141 RENDERER(ega, GRAPHICS_MODE, grrndrsw, vga_set);
142 RENDERER(vga, GRAPHICS_MODE, grrndrsw, vga_set);
143 #endif /* SC_NO_MODE_CHANGE */
144
145 RENDERER_MODULE(vga, vga_set);
146
147 #ifndef SC_NO_CUTPASTE
148 #if !defined(SC_ALT_MOUSE_IMAGE) || defined(SC_PIXEL_MODE)
149 struct mousedata {
150         u_short md_border[16];
151         u_short md_interior[16];
152         u_short md_width;
153         u_short md_height;
154 };
155
156 static const struct mousedata mouse9x13 = { {
157         0xc000, 0xa000, 0x9000, 0x8800, 0x8400, 0x8200, 0x8100, 0x9780,
158         0xf200, 0x1200, 0x1900, 0x0900, 0x0f00, 0x0000, 0x0000, 0x0000, }, {
159         0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7c00, 0x7e00, 0x6800,
160         0x0c00, 0x0c00, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000, },
161         9, 13,
162 };
163
164 static const struct mousedata mouse10x16 = { {
165         0xc000, 0xa000, 0x9000, 0x8800, 0x8400, 0x8200, 0x8100, 0x8080,
166         0x8040, 0x83c0, 0x9200, 0xa900, 0xc900, 0x0480, 0x0480, 0x0300, }, {
167         0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7c00, 0x7e00, 0x7f00,
168         0x7f80, 0x7c00, 0x6c00, 0x4600, 0x0600, 0x0300, 0x0300, 0x0000, },
169         10, 16,
170 };
171 #endif
172 #endif
173
174 #ifdef SC_PIXEL_MODE
175 #define GET_PIXEL(scp, pos, x, w)                                       \
176 ({                                                                      \
177         (scp)->sc->adp->va_window +                                     \
178             (x) * (scp)->xoff +                                         \
179             (scp)->yoff * (scp)->font_size * (w) +                      \
180             (x) * ((pos) % (scp)->xsize) +                              \
181             (scp)->font_size * (w) * ((pos) / (scp)->xsize);            \
182 })
183
184 #define DRAW_PIXEL(scp, pos, color) do {                                \
185         switch ((scp)->sc->adp->va_info.vi_depth) {                     \
186         case 32:                                                        \
187                 writel((pos), vga_palette32[color]);                    \
188                 break;                                                  \
189         case 24:                                                        \
190                 if (((pos) & 1) == 0) {                                 \
191                         writew((pos), vga_palette32[color]);            \
192                         writeb((pos) + 2, vga_palette32[color] >> 16);  \
193                 } else {                                                \
194                         writeb((pos), vga_palette32[color]);            \
195                         writew((pos) + 1, vga_palette32[color] >> 8);   \
196                 }                                                       \
197                 break;                                                  \
198         case 16:                                                        \
199                 if ((scp)->sc->adp->va_info.vi_pixel_fsizes[1] == 5)    \
200                         writew((pos), vga_palette15[color]);            \
201                 else                                                    \
202                         writew((pos), vga_palette16[color]);            \
203                 break;                                                  \
204         case 15:                                                        \
205                 writew((pos), vga_palette15[color]);                    \
206                 break;                                                  \
207         case 8:                                                         \
208                 writeb((pos), (uint8_t)(color));                        \
209         }                                                               \
210 } while (0)
211         
212 static uint32_t vga_palette32[16] = {
213         0x000000, 0x0000ad, 0x00ad00, 0x00adad,
214         0xad0000, 0xad00ad, 0xad5200, 0xadadad,
215         0x525252, 0x5252ff, 0x52ff52, 0x52ffff,
216         0xff5252, 0xff52ff, 0xffff52, 0xffffff
217 };
218
219 static uint16_t vga_palette16[16] = {
220         0x0000, 0x0016, 0x0560, 0x0576, 0xb000, 0xb016, 0xb2a0, 0xb576,
221         0x52aa, 0x52bf, 0x57ea, 0x57ff, 0xfaaa, 0xfabf, 0xffea, 0xffff
222 };
223
224 static uint16_t vga_palette15[16] = {
225         0x0000, 0x0016, 0x02c0, 0x02d6, 0x5800, 0x5816, 0x5940, 0x5ad6,
226         0x294a, 0x295f, 0x2bea, 0x2bff, 0x7d4a, 0x7d5f, 0x7fea, 0x7fff
227 };
228 #endif
229
230 static void
231 vga_nop(scr_stat *scp)
232 {
233 }
234
235 /* text mode renderer */
236
237 static void
238 vga_txtclear(scr_stat *scp, int c, int attr)
239 {
240         sc_vtb_clear(&scp->scr, c, attr);
241 }
242
243 static void
244 vga_txtborder(scr_stat *scp, int color)
245 {
246         vidd_set_border(scp->sc->adp, color);
247 }
248
249 static void
250 vga_txtdraw(scr_stat *scp, int from, int count, int flip)
251 {
252         vm_offset_t p;
253         int c;
254         int a;
255
256         if (from + count > scp->xsize*scp->ysize)
257                 count = scp->xsize*scp->ysize - from;
258
259         if (flip) {
260                 for (p = sc_vtb_pointer(&scp->scr, from); count-- > 0; ++from) {
261                         c = sc_vtb_getc(&scp->vtb, from);
262                         a = sc_vtb_geta(&scp->vtb, from);
263                         a = (a & 0x8800) | ((a & 0x7000) >> 4) 
264                                 | ((a & 0x0700) << 4);
265                         p = sc_vtb_putchar(&scp->scr, p, c, a);
266                 }
267         } else {
268                 sc_vtb_copy(&scp->vtb, from, &scp->scr, from, count);
269         }
270 }
271
272 static void 
273 vga_txtcursor_shape(scr_stat *scp, int base, int height, int blink)
274 {
275         if (base < 0 || base >= scp->font_size)
276                 return;
277         /* the caller may set height <= 0 in order to disable the cursor */
278 #if 0
279         scp->curs_attr.base = base;
280         scp->curs_attr.height = height;
281 #endif
282         vidd_set_hw_cursor_shape(scp->sc->adp, base, height,
283             scp->font_size, blink);
284 }
285
286 static void
287 draw_txtcharcursor(scr_stat *scp, int at, u_short c, u_short a, int flip)
288 {
289         sc_softc_t *sc;
290
291         sc = scp->sc;
292
293 #ifndef SC_NO_FONT_LOADING
294         if (scp->curs_attr.flags & CONS_CHAR_CURSOR) {
295                 unsigned char *font;
296                 int h;
297                 int i;
298
299                 if (scp->font_size < 14) {
300                         font = sc->font_8;
301                         h = 8;
302                 } else if (scp->font_size >= 16) {
303                         font = sc->font_16;
304                         h = 16;
305                 } else {
306                         font = sc->font_14;
307                         h = 14;
308                 }
309                 if (scp->curs_attr.base >= h)
310                         return;
311                 if (flip)
312                         a = (a & 0x8800)
313                                 | ((a & 0x7000) >> 4) | ((a & 0x0700) << 4);
314                 bcopy(font + c*h, font + sc->cursor_char*h, h);
315                 font = font + sc->cursor_char*h;
316                 for (i = imax(h - scp->curs_attr.base - scp->curs_attr.height, 0);
317                         i < h - scp->curs_attr.base; ++i) {
318                         font[i] ^= 0xff;
319                 }
320                 /* XXX */
321                 vidd_load_font(sc->adp, 0, h, 8, font, sc->cursor_char, 1);
322                 sc_vtb_putc(&scp->scr, at, sc->cursor_char, a);
323         } else
324 #endif /* SC_NO_FONT_LOADING */
325         {
326                 if ((a & 0x7000) == 0x7000) {
327                         a &= 0x8f00;
328                         if ((a & 0x0700) == 0)
329                                 a |= 0x0700;
330                 } else {
331                         a |= 0x7000;
332                         if ((a & 0x0700) == 0x0700)
333                                 a &= 0xf000;
334                 }
335                 if (flip)
336                         a = (a & 0x8800)
337                                 | ((a & 0x7000) >> 4) | ((a & 0x0700) << 4);
338                 sc_vtb_putc(&scp->scr, at, c, a);
339         }
340 }
341
342 static void
343 vga_txtcursor(scr_stat *scp, int at, int blink, int on, int flip)
344 {
345         video_adapter_t *adp;
346         int cursor_attr;
347
348         if (scp->curs_attr.height <= 0) /* the text cursor is disabled */
349                 return;
350
351         adp = scp->sc->adp;
352         if (blink) {
353                 scp->status |= VR_CURSOR_BLINK;
354                 if (on) {
355                         scp->status |= VR_CURSOR_ON;
356                         vidd_set_hw_cursor(adp, at%scp->xsize,
357                             at/scp->xsize);
358                 } else {
359                         if (scp->status & VR_CURSOR_ON)
360                                 vidd_set_hw_cursor(adp, -1, -1);
361                         scp->status &= ~VR_CURSOR_ON;
362                 }
363         } else {
364                 scp->status &= ~VR_CURSOR_BLINK;
365                 if (on) {
366                         scp->status |= VR_CURSOR_ON;
367                         draw_txtcharcursor(scp, at,
368                                            sc_vtb_getc(&scp->vtb, at),
369                                            sc_vtb_geta(&scp->vtb, at),
370                                            flip);
371                 } else {
372                         cursor_attr = sc_vtb_geta(&scp->vtb, at);
373                         if (flip)
374                                 cursor_attr = (cursor_attr & 0x8800)
375                                         | ((cursor_attr & 0x7000) >> 4)
376                                         | ((cursor_attr & 0x0700) << 4);
377                         if (scp->status & VR_CURSOR_ON)
378                                 sc_vtb_putc(&scp->scr, at,
379                                             sc_vtb_getc(&scp->vtb, at),
380                                             cursor_attr);
381                         scp->status &= ~VR_CURSOR_ON;
382                 }
383         }
384 }
385
386 static void
387 vga_txtblink(scr_stat *scp, int at, int flip)
388 {
389 }
390
391 int sc_txtmouse_no_retrace_wait;
392
393 #ifndef SC_NO_CUTPASTE
394
395 static void
396 draw_txtmouse(scr_stat *scp, int x, int y)
397 {
398 #ifndef SC_ALT_MOUSE_IMAGE
399     if (ISMOUSEAVAIL(scp->sc->adp->va_flags)) {
400         const struct mousedata *mdp;
401         uint32_t border, interior;
402         u_char font_buf[128];
403         u_short cursor[32];
404         u_char c;
405         int pos;
406         int xoffset, yoffset;
407         int crtc_addr;
408         int i;
409
410         mdp = (scp->font_size < 14) ? &mouse9x13 : &mouse10x16;
411
412         /* prepare mousepointer char's bitmaps */
413         pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff;
414         bcopy(scp->font + sc_vtb_getc(&scp->scr, pos)*scp->font_size,
415               &font_buf[0], scp->font_size);
416         bcopy(scp->font + sc_vtb_getc(&scp->scr, pos + 1)*scp->font_size,
417               &font_buf[32], scp->font_size);
418         bcopy(scp->font 
419                  + sc_vtb_getc(&scp->scr, pos + scp->xsize)*scp->font_size,
420               &font_buf[64], scp->font_size);
421         bcopy(scp->font
422                  + sc_vtb_getc(&scp->scr, pos + scp->xsize + 1)*scp->font_size,
423               &font_buf[96], scp->font_size);
424         for (i = 0; i < scp->font_size; ++i) {
425                 cursor[i] = font_buf[i]<<8 | font_buf[i+32];
426                 cursor[i + scp->font_size] = font_buf[i+64]<<8 | font_buf[i+96];
427         }
428
429         /* now and-or in the mousepointer image */
430         xoffset = x%8;
431         yoffset = y%scp->font_size;
432         for (i = 0; i < 16; ++i) {
433                 border = mdp->md_border[i] << 8; /* avoid right shifting out */
434                 interior = mdp->md_interior[i] << 8;
435                 border >>= xoffset;             /* normalize */
436                 interior >>= xoffset;
437                 if (scp->sc->adp->va_flags & V_ADP_CWIDTH9) {
438                         /* skip gaps between characters */
439                         border = (border & 0xff0000) |
440                                  (border & 0x007f80) << 1 |
441                                  (border & 0x00003f) << 2;
442                         interior = (interior & 0xff0000) |
443                                    (interior & 0x007f80) << 1 |
444                                    (interior & 0x00003f) << 2;
445                 }
446                 border >>= 8;                   /* back to normal position */
447                 interior >>= 8;
448                 cursor[i + yoffset] = (cursor[i + yoffset]  & ~border) |
449                                       interior;
450         }
451         for (i = 0; i < scp->font_size; ++i) {
452                 font_buf[i] = (cursor[i] & 0xff00) >> 8;
453                 font_buf[i + 32] = cursor[i] & 0xff;
454                 font_buf[i + 64] = (cursor[i + scp->font_size] & 0xff00) >> 8;
455                 font_buf[i + 96] = cursor[i + scp->font_size] & 0xff;
456         }
457
458 #if 1
459         /* wait for vertical retrace to avoid jitter on some videocards */
460         crtc_addr = scp->sc->adp->va_crtc_addr;
461         while (!sc_txtmouse_no_retrace_wait &&
462             !(inb(crtc_addr + 6) & 0x08))
463                 /* idle */ ;
464 #endif
465         c = scp->sc->mouse_char;
466         vidd_load_font(scp->sc->adp, 0, 32, 8, font_buf, c, 4); 
467
468         sc_vtb_putc(&scp->scr, pos, c, sc_vtb_geta(&scp->scr, pos));
469         /* FIXME: may be out of range! */
470         sc_vtb_putc(&scp->scr, pos + scp->xsize, c + 2,
471                     sc_vtb_geta(&scp->scr, pos + scp->xsize));
472         if (x < (scp->xsize - 1)*8) {
473                 sc_vtb_putc(&scp->scr, pos + 1, c + 1,
474                             sc_vtb_geta(&scp->scr, pos + 1));
475                 sc_vtb_putc(&scp->scr, pos + scp->xsize + 1, c + 3,
476                             sc_vtb_geta(&scp->scr, pos + scp->xsize + 1));
477         }
478     } else
479 #endif /* SC_ALT_MOUSE_IMAGE */
480     {
481         /* Red, magenta and brown are mapped to green to to keep it readable */
482         static const int col_conv[16] = {
483                 6, 6, 6, 6, 2, 2, 2, 6, 14, 14, 14, 14, 10, 10, 10, 14
484         };
485         int pos;
486         int color;
487         int a;
488
489         pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff;
490         a = sc_vtb_geta(&scp->scr, pos);
491         if (scp->sc->adp->va_flags & V_ADP_COLOR)
492                 color = (col_conv[(a & 0xf000) >> 12] << 12)
493                         | ((a & 0x0f00) | 0x0800);
494         else
495                 color = ((a & 0xf000) >> 4) | ((a & 0x0f00) << 4);
496         sc_vtb_putc(&scp->scr, pos, sc_vtb_getc(&scp->scr, pos), color);
497     }
498 }
499
500 static void
501 remove_txtmouse(scr_stat *scp, int x, int y)
502 {
503 }
504
505 static void 
506 vga_txtmouse(scr_stat *scp, int x, int y, int on)
507 {
508         if (on)
509                 draw_txtmouse(scp, x, y);
510         else
511                 remove_txtmouse(scp, x, y);
512 }
513
514 #endif /* SC_NO_CUTPASTE */
515
516 #ifdef SC_PIXEL_MODE
517
518 /* pixel (raster text) mode renderer */
519
520 static void
521 vga_rndrinit(scr_stat *scp)
522 {
523         if (scp->sc->adp->va_info.vi_mem_model == V_INFO_MM_PLANAR) {
524                 scp->rndr->clear = vga_pxlclear_planar;
525                 scp->rndr->draw_border = vga_pxlborder_planar;
526                 scp->rndr->draw = vga_vgadraw_planar;
527                 scp->rndr->draw_cursor = vga_pxlcursor_planar;
528                 scp->rndr->blink_cursor = vga_pxlblink_planar;
529                 scp->rndr->draw_mouse = vga_pxlmouse_planar;
530         } else
531         if (scp->sc->adp->va_info.vi_mem_model == V_INFO_MM_DIRECT ||
532             scp->sc->adp->va_info.vi_mem_model == V_INFO_MM_PACKED) {
533                 scp->rndr->clear = vga_pxlclear_direct;
534                 scp->rndr->draw_border = vga_pxlborder_direct;
535                 scp->rndr->draw = vga_vgadraw_direct;
536                 scp->rndr->draw_cursor = vga_pxlcursor_direct;
537                 scp->rndr->blink_cursor = vga_pxlblink_direct;
538                 scp->rndr->draw_mouse = vga_pxlmouse_direct;
539         }
540 }
541
542 static void
543 vga_pxlclear_direct(scr_stat *scp, int c, int attr)
544 {
545         vm_offset_t p;
546         int line_width;
547         int pixel_size;
548         int lines;
549         int i;
550
551         line_width = scp->sc->adp->va_line_width;
552         pixel_size = scp->sc->adp->va_info.vi_pixel_size;
553         lines = scp->ysize * scp->font_size; 
554         p = scp->sc->adp->va_window +
555             line_width * scp->yoff * scp->font_size +
556             scp->xoff * 8 * pixel_size;
557
558         for (i = 0; i < lines; ++i) {
559                 bzero_io((void *)p, scp->xsize * 8 * pixel_size);
560                 p += line_width;
561         }
562 }
563
564 static void
565 vga_pxlclear_planar(scr_stat *scp, int c, int attr)
566 {
567         vm_offset_t p;
568         int line_width;
569         int lines;
570         int i;
571
572         /* XXX: we are just filling the screen with the background color... */
573         outw(GDCIDX, 0x0005);           /* read mode 0, write mode 0 */
574         outw(GDCIDX, 0x0003);           /* data rotate/function select */
575         outw(GDCIDX, 0x0f01);           /* set/reset enable */
576         outw(GDCIDX, 0xff08);           /* bit mask */
577         outw(GDCIDX, ((attr & 0xf000) >> 4) | 0x00); /* set/reset */
578         line_width = scp->sc->adp->va_line_width;
579         lines = scp->ysize*scp->font_size; 
580         p = scp->sc->adp->va_window + line_width*scp->yoff*scp->font_size
581                 + scp->xoff;
582         for (i = 0; i < lines; ++i) {
583                 bzero_io((void *)p, scp->xsize);
584                 p += line_width;
585         }
586         outw(GDCIDX, 0x0000);           /* set/reset */
587         outw(GDCIDX, 0x0001);           /* set/reset enable */
588 }
589
590 static void
591 vga_pxlborder_direct(scr_stat *scp, int color)
592 {
593         vm_offset_t s;
594         vm_offset_t e;
595         vm_offset_t f;
596         int line_width;
597         int pixel_size;
598         int x;
599         int y;
600         int i;
601
602         line_width = scp->sc->adp->va_line_width;
603         pixel_size = scp->sc->adp->va_info.vi_pixel_size;
604
605         if (scp->yoff > 0) {
606                 s = scp->sc->adp->va_window;
607                 e = s + line_width * scp->yoff * scp->font_size;
608
609                 for (f = s; f < e; f += pixel_size)
610                         DRAW_PIXEL(scp, f, color);
611         }
612
613         y = (scp->yoff + scp->ysize) * scp->font_size;
614
615         if (scp->ypixel > y) {
616                 s = scp->sc->adp->va_window + line_width * y;
617                 e = s + line_width * (scp->ypixel - y);
618
619                 for (f = s; f < e; f += pixel_size)
620                         DRAW_PIXEL(scp, f, color);
621         }
622
623         y = scp->yoff * scp->font_size;
624         x = scp->xpixel / 8 - scp->xoff - scp->xsize;
625
626         for (i = 0; i < scp->ysize * scp->font_size; ++i) {
627                 if (scp->xoff > 0) {
628                         s = scp->sc->adp->va_window + line_width * (y + i);
629                         e = s + scp->xoff * 8 * pixel_size;
630
631                         for (f = s; f < e; f += pixel_size)
632                                 DRAW_PIXEL(scp, f, color);
633                 }
634
635                 if (x > 0) {
636                         s = scp->sc->adp->va_window + line_width * (y + i) +
637                             scp->xoff * 8 * pixel_size +
638                             scp->xsize * 8 * pixel_size;
639                         e = s + x * 8 * pixel_size;
640
641                         for (f = s; f < e; f += pixel_size)
642                                 DRAW_PIXEL(scp, f, color);
643                 }
644         }
645 }
646
647 static void
648 vga_pxlborder_planar(scr_stat *scp, int color)
649 {
650         vm_offset_t p;
651         int line_width;
652         int x;
653         int y;
654         int i;
655
656         vidd_set_border(scp->sc->adp, color);
657
658         outw(GDCIDX, 0x0005);           /* read mode 0, write mode 0 */
659         outw(GDCIDX, 0x0003);           /* data rotate/function select */
660         outw(GDCIDX, 0x0f01);           /* set/reset enable */
661         outw(GDCIDX, 0xff08);           /* bit mask */
662         outw(GDCIDX, (color << 8) | 0x00);      /* set/reset */
663         line_width = scp->sc->adp->va_line_width;
664         p = scp->sc->adp->va_window;
665         if (scp->yoff > 0)
666                 bzero_io((void *)p, line_width*scp->yoff*scp->font_size);
667         y = (scp->yoff + scp->ysize)*scp->font_size;
668         if (scp->ypixel > y)
669                 bzero_io((void *)(p + line_width*y), line_width*(scp->ypixel - y));
670         y = scp->yoff*scp->font_size;
671         x = scp->xpixel/8 - scp->xoff - scp->xsize;
672         for (i = 0; i < scp->ysize*scp->font_size; ++i) {
673                 if (scp->xoff > 0)
674                         bzero_io((void *)(p + line_width*(y + i)), scp->xoff);
675                 if (x > 0)
676                         bzero_io((void *)(p + line_width*(y + i)
677                                      + scp->xoff + scp->xsize), x);
678         }
679         outw(GDCIDX, 0x0000);           /* set/reset */
680         outw(GDCIDX, 0x0001);           /* set/reset enable */
681 }
682
683 static void
684 vga_vgadraw_direct(scr_stat *scp, int from, int count, int flip)
685 {
686         vm_offset_t d;
687         vm_offset_t e;
688         u_char *f;
689         u_short col1, col2, color;
690         int line_width, pixel_size;
691         int i, j, k;
692         int a;
693
694         line_width = scp->sc->adp->va_line_width;
695         pixel_size = scp->sc->adp->va_info.vi_pixel_size;
696
697         d = GET_PIXEL(scp, from, 8 * pixel_size, line_width);
698
699         if (from + count > scp->xsize * scp->ysize)
700                 count = scp->xsize * scp->ysize - from;
701
702         for (i = from; count-- > 0; ++i) {
703                 a = sc_vtb_geta(&scp->vtb, i);
704
705                 if (flip) {
706                         col1 = (((a & 0x7000) >> 4) | (a & 0x0800)) >> 8;
707                         col2 = (((a & 0x8000) >> 4) | (a & 0x0700)) >> 8;
708                 } else {
709                         col1 = (a & 0x0f00) >> 8;
710                         col2 = (a & 0xf000) >> 12;
711                 }
712
713                 e = d;
714                 f = &(scp->font[sc_vtb_getc(&scp->vtb, i) * scp->font_size]);
715
716                 for (j = 0; j < scp->font_size; ++j, ++f) {
717                         for (k = 0; k < 8; ++k) {
718                                 color = *f & (1 << (7 - k)) ? col1 : col2;
719                                 DRAW_PIXEL(scp, e + pixel_size * k, color);
720                         }
721
722                         e += line_width;
723                 }
724
725                 d += 8 * pixel_size;
726
727                 if ((i % scp->xsize) == scp->xsize - 1)
728                         d += scp->font_size * line_width -
729                             scp->xsize * 8 * pixel_size;
730         }
731 }
732
733 static void
734 vga_vgadraw_planar(scr_stat *scp, int from, int count, int flip)
735 {
736         vm_offset_t d;
737         vm_offset_t e;
738         u_char *f;
739         u_short bg, fg;
740         u_short col1, col2;
741         int line_width;
742         int i, j;
743         int a;
744         u_char c;
745
746         line_width = scp->sc->adp->va_line_width;
747
748         d = GET_PIXEL(scp, from, 1, line_width);
749
750         if (scp->sc->adp->va_type == KD_VGA) {
751                 outw(GDCIDX, 0x0305);   /* read mode 0, write mode 3 */
752                 outw(GDCIDX, 0xff08);   /* bit mask */
753         } else
754                 outw(GDCIDX, 0x0005);   /* read mode 0, write mode 0 */
755         outw(GDCIDX, 0x0003);           /* data rotate/function select */
756         outw(GDCIDX, 0x0f01);           /* set/reset enable */
757         fg = bg = -1;
758         if (from + count > scp->xsize*scp->ysize)
759                 count = scp->xsize*scp->ysize - from;
760         for (i = from; count-- > 0; ++i) {
761                 a = sc_vtb_geta(&scp->vtb, i);
762                 if (flip) {
763                         col1 = ((a & 0x7000) >> 4) | (a & 0x0800);
764                         col2 = ((a & 0x8000) >> 4) | (a & 0x0700);
765                 } else {
766                         col1 = (a & 0x0f00);
767                         col2 = (a & 0xf000) >> 4;
768                 }
769                 /* set background color in EGA/VGA latch */
770                 if (bg != col2) {
771                         bg = col2;
772                         fg = -1;
773                         outw(GDCIDX, bg | 0x00); /* set/reset */
774                         if (scp->sc->adp->va_type != KD_VGA)
775                                 outw(GDCIDX, 0xff08); /* bit mask */
776                         writeb(d, 0xff);
777                         c = readb(d);           /* set bg color in the latch */
778                 }
779                 /* foreground color */
780                 if (fg != col1) {
781                         fg = col1;
782                         outw(GDCIDX, col1 | 0x00); /* set/reset */
783                 }
784                 e = d;
785                 f = &(scp->font[sc_vtb_getc(&scp->vtb, i)*scp->font_size]);
786                 for (j = 0; j < scp->font_size; ++j, ++f) {
787                         if (scp->sc->adp->va_type == KD_VGA)
788                                 writeb(e, *f);  
789                         else {
790                                 outw(GDCIDX, (*f << 8) | 0x08); /* bit mask */
791                                 writeb(e, 0);   
792                         }
793                         e += line_width;
794                 }
795                 ++d;
796                 if ((i % scp->xsize) == scp->xsize - 1)
797                         d += scp->font_size * line_width - scp->xsize;
798         }
799         if (scp->sc->adp->va_type == KD_VGA)
800                 outw(GDCIDX, 0x0005);   /* read mode 0, write mode 0 */
801         else
802                 outw(GDCIDX, 0xff08);   /* bit mask */
803         outw(GDCIDX, 0x0000);           /* set/reset */
804         outw(GDCIDX, 0x0001);           /* set/reset enable */
805 }
806
807 static void 
808 vga_pxlcursor_shape(scr_stat *scp, int base, int height, int blink)
809 {
810         if (base < 0 || base >= scp->font_size)
811                 return;
812         /* the caller may set height <= 0 in order to disable the cursor */
813 #if 0
814         scp->curs_attr.base = base;
815         scp->curs_attr.height = height;
816 #endif
817 }
818
819 static void 
820 draw_pxlcursor_direct(scr_stat *scp, int at, int on, int flip)
821 {
822         vm_offset_t d;
823         u_char *f;
824         int line_width, pixel_size;
825         int height;
826         int col1, col2, color;
827         int a;
828         int i, j;
829
830         line_width = scp->sc->adp->va_line_width;
831         pixel_size = scp->sc->adp->va_info.vi_pixel_size;
832
833         d = GET_PIXEL(scp, at, 8 * pixel_size, line_width) +
834             (scp->font_size - scp->curs_attr.base - 1) * line_width;
835
836         a = sc_vtb_geta(&scp->vtb, at);
837
838         if (flip) {
839                 col1 = ((on) ? (a & 0x0f00) : ((a & 0xf000) >> 4)) >> 8;
840                 col2 = ((on) ? ((a & 0xf000) >> 4) : (a & 0x0f00)) >> 8;
841         } else {
842                 col1 = ((on) ? ((a & 0xf000) >> 4) : (a & 0x0f00)) >> 8;
843                 col2 = ((on) ? (a & 0x0f00) : ((a & 0xf000) >> 4)) >> 8;
844         }
845
846         f = &(scp->font[sc_vtb_getc(&scp->vtb, at) * scp->font_size +
847               scp->font_size - scp->curs_attr.base - 1]);
848
849         height = imin(scp->curs_attr.height, scp->font_size);
850
851         for (i = 0; i < height; ++i, --f) {
852                 for (j = 0; j < 8; ++j) {
853                         color = *f & (1 << (7 - j)) ? col1 : col2;
854                         DRAW_PIXEL(scp, d + pixel_size * j, color);
855                 }
856
857                 d -= line_width;
858         }
859 }
860
861 static void 
862 draw_pxlcursor_planar(scr_stat *scp, int at, int on, int flip)
863 {
864         vm_offset_t d;
865         u_char *f;
866         int line_width;
867         int height;
868         int col;
869         int a;
870         int i;
871         u_char c;
872
873         line_width = scp->sc->adp->va_line_width;
874
875         d = GET_PIXEL(scp, at, 1, line_width) +
876             (scp->font_size - scp->curs_attr.base - 1) * line_width;
877
878         outw(GDCIDX, 0x0005);           /* read mode 0, write mode 0 */
879         outw(GDCIDX, 0x0003);           /* data rotate/function select */
880         outw(GDCIDX, 0x0f01);           /* set/reset enable */
881         /* set background color in EGA/VGA latch */
882         a = sc_vtb_geta(&scp->vtb, at);
883         if (flip)
884                 col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00);
885         else
886                 col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4);
887         outw(GDCIDX, col | 0x00);       /* set/reset */
888         outw(GDCIDX, 0xff08);           /* bit mask */
889         writeb(d, 0);
890         c = readb(d);                   /* set bg color in the latch */
891         /* foreground color */
892         if (flip)
893                 col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4);
894         else
895                 col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00);
896         outw(GDCIDX, col | 0x00);       /* set/reset */
897         f = &(scp->font[sc_vtb_getc(&scp->vtb, at)*scp->font_size
898                 + scp->font_size - scp->curs_attr.base - 1]);
899         height = imin(scp->curs_attr.height, scp->font_size);
900         for (i = 0; i < height; ++i, --f) {
901                 outw(GDCIDX, (*f << 8) | 0x08); /* bit mask */
902                 writeb(d, 0);
903                 d -= line_width;
904         }
905         outw(GDCIDX, 0x0000);           /* set/reset */
906         outw(GDCIDX, 0x0001);           /* set/reset enable */
907         outw(GDCIDX, 0xff08);           /* bit mask */
908 }
909
910 static int pxlblinkrate = 0;
911
912 static void 
913 vga_pxlcursor_direct(scr_stat *scp, int at, int blink, int on, int flip)
914 {
915         if (scp->curs_attr.height <= 0) /* the text cursor is disabled */
916                 return;
917
918         if (on) {
919                 if (!blink) {
920                         scp->status |= VR_CURSOR_ON;
921                         draw_pxlcursor_direct(scp, at, on, flip);
922                 } else if (++pxlblinkrate & 4) {
923                         pxlblinkrate = 0;
924                         scp->status ^= VR_CURSOR_ON;
925                         draw_pxlcursor_direct(scp, at,
926                                               scp->status & VR_CURSOR_ON,
927                                               flip);
928                 }
929         } else {
930                 if (scp->status & VR_CURSOR_ON)
931                         draw_pxlcursor_direct(scp, at, on, flip);
932                 scp->status &= ~VR_CURSOR_ON;
933         }
934         if (blink)
935                 scp->status |= VR_CURSOR_BLINK;
936         else
937                 scp->status &= ~VR_CURSOR_BLINK;
938 }
939
940 static void 
941 vga_pxlcursor_planar(scr_stat *scp, int at, int blink, int on, int flip)
942 {
943         if (scp->curs_attr.height <= 0) /* the text cursor is disabled */
944                 return;
945
946         if (on) {
947                 if (!blink) {
948                         scp->status |= VR_CURSOR_ON;
949                         draw_pxlcursor_planar(scp, at, on, flip);
950                 } else if (++pxlblinkrate & 4) {
951                         pxlblinkrate = 0;
952                         scp->status ^= VR_CURSOR_ON;
953                         draw_pxlcursor_planar(scp, at,
954                                               scp->status & VR_CURSOR_ON,
955                                               flip);
956                 }
957         } else {
958                 if (scp->status & VR_CURSOR_ON)
959                         draw_pxlcursor_planar(scp, at, on, flip);
960                 scp->status &= ~VR_CURSOR_ON;
961         }
962         if (blink)
963                 scp->status |= VR_CURSOR_BLINK;
964         else
965                 scp->status &= ~VR_CURSOR_BLINK;
966 }
967
968 static void
969 vga_pxlblink_direct(scr_stat *scp, int at, int flip)
970 {
971         if (!(scp->status & VR_CURSOR_BLINK))
972                 return;
973         if (!(++pxlblinkrate & 4))
974                 return;
975         pxlblinkrate = 0;
976         scp->status ^= VR_CURSOR_ON;
977         draw_pxlcursor_direct(scp, at, scp->status & VR_CURSOR_ON, flip);
978 }
979
980 static void
981 vga_pxlblink_planar(scr_stat *scp, int at, int flip)
982 {
983         if (!(scp->status & VR_CURSOR_BLINK))
984                 return;
985         if (!(++pxlblinkrate & 4))
986                 return;
987         pxlblinkrate = 0;
988         scp->status ^= VR_CURSOR_ON;
989         draw_pxlcursor_planar(scp, at, scp->status & VR_CURSOR_ON, flip);
990 }
991
992 #ifndef SC_NO_CUTPASTE
993
994 static void
995 draw_pxlmouse_planar(scr_stat *scp, int x, int y)
996 {
997         const struct mousedata *mdp;
998         vm_offset_t p;
999         int line_width;
1000         int xoff, yoff;
1001         int ymax;
1002         uint32_t m;
1003         int i, j, k;
1004         uint8_t m1;
1005
1006         mdp = (scp->font_size < 14) ? &mouse9x13 : &mouse10x16;
1007         line_width = scp->sc->adp->va_line_width;
1008         xoff = (x - scp->xoff*8)%8;
1009         yoff = y - rounddown(y, line_width);
1010         ymax = imin(y + mdp->md_height, scp->ypixel);
1011
1012         if (scp->sc->adp->va_type == KD_VGA) {
1013                 outw(GDCIDX, 0x0305);   /* read mode 0, write mode 3 */
1014                 outw(GDCIDX, 0xff08);   /* bit mask */
1015         } else
1016                 outw(GDCIDX, 0x0005);   /* read mode 0, write mode 0 */
1017         outw(GDCIDX, 0x0003);           /* data rotate/function select */
1018         outw(GDCIDX, 0x0f01);           /* set/reset enable */
1019
1020         outw(GDCIDX, (0 << 8) | 0x00); /* set/reset */
1021         p = scp->sc->adp->va_window + line_width*y + x/8;
1022         for (i = y, j = 0; i < ymax; ++i, ++j) {
1023                 m = mdp->md_border[j] << 8 >> xoff;
1024                 for (k = 0; k < 3; ++k) {
1025                         m1 = m >> (8 * (2 - k));
1026                         if (m1 != 0 && x + 8 * k < scp->xpixel) {
1027                                 readb(p + k);
1028                                 if (scp->sc->adp->va_type == KD_VGA)
1029                                         writeb(p + k, m1);
1030                                 else {
1031                                         /* bit mask: */
1032                                         outw(GDCIDX, (m1 << 8) | 0x08);
1033                                         writeb(p + k, 0);
1034                                 }
1035                         }
1036                 }
1037                 p += line_width;
1038         }
1039         outw(GDCIDX, (15 << 8) | 0x00); /* set/reset */
1040         p = scp->sc->adp->va_window + line_width*y + x/8;
1041         for (i = y, j = 0; i < ymax; ++i, ++j) {
1042                 m = mdp->md_interior[j] << 8 >> xoff;
1043                 for (k = 0; k < 3; ++k) {
1044                         m1 = m >> (8 * (2 - k));
1045                         if (m1 != 0 && x + 8 * k < scp->xpixel) {
1046                                 readb(p + k);
1047                                 if (scp->sc->adp->va_type == KD_VGA)
1048                                         writeb(p + k, m1);
1049                                 else {
1050                                         /* bit mask: */
1051                                         outw(GDCIDX, (m1 << 8) | 0x08);
1052                                         writeb(p + k, 0);
1053                                 }
1054                         }
1055                 }
1056                 p += line_width;
1057         }
1058         if (scp->sc->adp->va_type == KD_VGA)
1059                 outw(GDCIDX, 0x0005);   /* read mode 0, write mode 0 */
1060         else
1061                 outw(GDCIDX, 0xff08);   /* bit mask */
1062         outw(GDCIDX, 0x0000);           /* set/reset */
1063         outw(GDCIDX, 0x0001);           /* set/reset enable */
1064 }
1065
1066 static void
1067 remove_pxlmouse_planar(scr_stat *scp, int x, int y)
1068 {
1069         const struct mousedata *mdp;
1070         vm_offset_t p;
1071         int bx, by, i, line_width, xend, xoff, yend, yoff;
1072
1073         mdp = (scp->font_size < 14) ? &mouse9x13 : &mouse10x16;
1074
1075         /*
1076          * It is only necessary to remove the mouse image where it overlaps
1077          * the border.  Determine the overlap, and do nothing if it is empty.
1078          */
1079         bx = (scp->xoff + scp->xsize) * 8;
1080         by = (scp->yoff + scp->ysize) * scp->font_size;
1081         xend = imin(x + mdp->md_width, scp->xpixel);
1082         yend = imin(y + mdp->md_height, scp->ypixel);
1083         if (xend <= bx && yend <= by)
1084                 return;
1085
1086         /* Repaint the non-empty overlap. */
1087         line_width = scp->sc->adp->va_line_width;
1088         outw(GDCIDX, 0x0005);           /* read mode 0, write mode 0 */
1089         outw(GDCIDX, 0x0003);           /* data rotate/function select */
1090         outw(GDCIDX, 0x0f01);           /* set/reset enable */
1091         outw(GDCIDX, 0xff08);           /* bit mask */
1092         outw(GDCIDX, (scp->border << 8) | 0x00);        /* set/reset */
1093         for (i = x / 8, xoff = i * 8; xoff < xend; ++i, xoff += 8) {
1094                 yoff = (xoff >= bx) ? y : by;
1095                 p = scp->sc->adp->va_window + yoff * line_width + i;
1096                 for (; yoff < yend; ++yoff, p += line_width)
1097                         writeb(p, 0);
1098         }
1099         outw(GDCIDX, 0x0000);           /* set/reset */
1100         outw(GDCIDX, 0x0001);           /* set/reset enable */
1101 }
1102
1103 static void 
1104 vga_pxlmouse_direct(scr_stat *scp, int x, int y, int on)
1105 {
1106         const struct mousedata *mdp;
1107         vm_offset_t p;
1108         int line_width, pixel_size;
1109         int xend, yend;
1110         int i, j;
1111
1112         mdp = (scp->font_size < 14) ? &mouse9x13 : &mouse10x16;
1113
1114         /*
1115          * Determine overlap with the border and then if removing, do nothing
1116          * if the overlap is empty.
1117          */
1118         xend = imin(x + mdp->md_width, scp->xpixel);
1119         yend = imin(y + mdp->md_height, scp->ypixel);
1120         if (!on && xend <= (scp->xoff + scp->xsize) * 8 &&
1121             yend <= (scp->yoff + scp->ysize) * scp->font_size)
1122                 return;
1123
1124         line_width = scp->sc->adp->va_line_width;
1125         pixel_size = scp->sc->adp->va_info.vi_pixel_size;
1126
1127         if (on)
1128                 goto do_on;
1129
1130         /* Repaint overlap with the border (mess up the corner a little). */
1131         p = scp->sc->adp->va_window + y * line_width + x * pixel_size;
1132         for (i = 0; i < yend - y; i++, p += line_width)
1133                 for (j = xend - x - 1; j >= 0; j--)
1134                         DRAW_PIXEL(scp, p + j * pixel_size, scp->border);
1135
1136         return;
1137
1138 do_on:
1139         p = scp->sc->adp->va_window + y * line_width + x * pixel_size;
1140         for (i = 0; i < yend - y; i++, p += line_width)
1141                 for (j = xend - x - 1; j >= 0; j--)
1142                         if (mdp->md_interior[i] & (1 << (15 - j)))
1143                                 DRAW_PIXEL(scp, p + j * pixel_size, 15);
1144                         else if (mdp->md_border[i] & (1 << (15 - j)))
1145                                 DRAW_PIXEL(scp, p + j * pixel_size, 0);
1146 }
1147
1148 static void 
1149 vga_pxlmouse_planar(scr_stat *scp, int x, int y, int on)
1150 {
1151         if (on)
1152                 draw_pxlmouse_planar(scp, x, y);
1153         else
1154                 remove_pxlmouse_planar(scp, x, y);
1155 }
1156
1157 #endif /* SC_NO_CUTPASTE */
1158 #endif /* SC_PIXEL_MODE */
1159
1160 #ifndef SC_NO_MODE_CHANGE
1161
1162 /* graphics mode renderer */
1163
1164 static void
1165 vga_grborder(scr_stat *scp, int color)
1166 {
1167         vidd_set_border(scp->sc->adp, color);
1168 }
1169
1170 #endif