* Declare vtb_buffer as a pointer to uint16_t and get rid of
[dragonfly.git] / sys / dev / misc / syscons / scvgarndr.c
1 /*-
2  * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
3  * All rights reserved.
4  *
5  * 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  * $FreeBSD: src/sys/dev/syscons/scvgarndr.c,v 1.5.2.3 2001/07/28 12:51:47 yokota Exp $
30  * $DragonFly: src/sys/dev/misc/syscons/scvgarndr.c,v 1.14 2005/05/26 16:24:33 swildner Exp $
31  */
32
33 #include "opt_syscons.h"
34 #include "opt_vga.h"
35
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/kernel.h>
39
40 #include <machine/console.h>
41
42 #include <dev/video/fb/fbreg.h>
43 #include <dev/video/fb/vgareg.h>
44 #include "syscons.h"
45
46 #include <bus/isa/isareg.h>
47
48 #ifndef SC_RENDER_DEBUG
49 #define SC_RENDER_DEBUG         0
50 #endif
51
52 static vr_draw_border_t         vga_txtborder;
53 static vr_draw_t                vga_txtdraw;
54 static vr_set_cursor_t          vga_txtcursor_shape;
55 static vr_draw_cursor_t         vga_txtcursor;
56 static vr_blink_cursor_t        vga_txtblink;
57 #ifndef SC_NO_CUTPASTE
58 static vr_draw_mouse_t          vga_txtmouse;
59 #else
60 #define vga_txtmouse            (vr_draw_mouse_t *)vga_nop
61 #endif
62
63 #ifdef SC_PIXEL_MODE
64 static vr_init_t                vga_rndrinit;
65 static vr_draw_border_t         vga_pxlborder_direct;
66 static vr_draw_border_t         vga_pxlborder_planar;
67 static vr_draw_t                vga_vgadraw_direct;
68 static vr_draw_t                vga_vgadraw_planar;
69 static vr_set_cursor_t          vga_pxlcursor_shape;
70 static vr_draw_cursor_t         vga_pxlcursor_direct;
71 static vr_draw_cursor_t         vga_pxlcursor_planar;
72 static vr_blink_cursor_t        vga_pxlblink_direct;
73 static vr_blink_cursor_t        vga_pxlblink_planar;
74 #ifndef SC_NO_CUTPASTE
75 static vr_draw_mouse_t          vga_pxlmouse_direct;
76 static vr_draw_mouse_t          vga_pxlmouse_planar;
77 #else
78 #define vga_pxlmouse_direct     (vr_draw_mouse_t *)vga_nop
79 #define vga_pxlmouse_planar     (vr_draw_mouse_t *)vga_nop
80 #endif
81 #endif /* SC_PIXEL_MODE */
82
83 #ifndef SC_NO_MODE_CHANGE
84 static vr_draw_border_t         vga_grborder;
85 #endif
86
87 static void                     vga_nop(scr_stat *scp, ...);
88
89 static sc_rndr_sw_t txtrndrsw = {
90         (vr_init_t *)vga_nop,
91         vga_txtborder,
92         vga_txtdraw,    
93         vga_txtcursor_shape,
94         vga_txtcursor,
95         vga_txtblink,
96         (vr_set_mouse_t *)vga_nop,
97         vga_txtmouse,
98 };
99 RENDERER(vga, 0, txtrndrsw, vga_set);
100
101 #ifdef SC_PIXEL_MODE
102 static sc_rndr_sw_t vgarndrsw = {
103         vga_rndrinit,
104         (vr_draw_border_t *)vga_nop,
105         (vr_draw_t *)vga_nop,
106         vga_pxlcursor_shape,
107         (vr_draw_cursor_t *)vga_nop,
108         (vr_blink_cursor_t *)vga_nop,
109         (vr_set_mouse_t *)vga_nop,
110         (vr_draw_mouse_t *)vga_nop,
111 };
112 RENDERER(vga, PIXEL_MODE, vgarndrsw, vga_set);
113 #endif /* SC_PIXEL_MODE */
114
115 #ifndef SC_NO_MODE_CHANGE
116 static sc_rndr_sw_t grrndrsw = {
117         (vr_init_t *)vga_nop,
118         vga_grborder,
119         (vr_draw_t *)vga_nop,
120         (vr_set_cursor_t *)vga_nop,
121         (vr_draw_cursor_t *)vga_nop,
122         (vr_blink_cursor_t *)vga_nop,
123         (vr_set_mouse_t *)vga_nop,
124         (vr_draw_mouse_t *)vga_nop,
125 };
126 RENDERER(vga, GRAPHICS_MODE, grrndrsw, vga_set);
127 #endif /* SC_NO_MODE_CHANGE */
128
129 RENDERER_MODULE(vga, vga_set);
130
131 #ifndef SC_NO_CUTPASTE
132 static u_short mouse_and_mask[16] = {
133         0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00, 0xff80,
134         0xfe00, 0x1e00, 0x1f00, 0x0f00, 0x0f00, 0x0000, 0x0000, 0x0000
135 };
136 static u_short mouse_or_mask[16] = {
137         0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7c00, 0x7e00, 0x6800,
138         0x0c00, 0x0c00, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000
139 };
140 #endif
141
142 static void
143 vga_nop(scr_stat *scp, ...)
144 {
145 }
146
147 /* text mode renderer */
148
149 static void
150 vga_txtborder(scr_stat *scp, int color)
151 {
152         (*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color);
153 }
154
155 static void
156 vga_txtdraw(scr_stat *scp, int from, int count, int flip)
157 {
158         uint16_t *p;
159         int c;
160         int a;
161
162         if (from + count > scp->xsize*scp->ysize)
163                 count = scp->xsize*scp->ysize - from;
164
165         if (flip) {
166                 for (p = scp->scr.vtb_buffer + from; count-- > 0; ++from) {
167                         c = sc_vtb_getc(&scp->vtb, from);
168                         a = sc_vtb_geta(&scp->vtb, from);
169                         a = (a & 0x8800) | ((a & 0x7000) >> 4) 
170                                 | ((a & 0x0700) << 4);
171                         p = sc_vtb_putchar(&scp->scr, p, c, a);
172                 }
173         } else {
174                 sc_vtb_copy(&scp->vtb, from, &scp->scr, from, count);
175         }
176 }
177
178 static void 
179 vga_txtcursor_shape(scr_stat *scp, int base, int height, int blink)
180 {
181         if (base < 0 || base >= scp->font_size)
182                 return;
183         /* the caller may set height <= 0 in order to disable the cursor */
184 #if 0
185         scp->cursor_base = base;
186         scp->cursor_height = height;
187 #endif
188         (*vidsw[scp->sc->adapter]->set_hw_cursor_shape)(scp->sc->adp,
189                                                         base, height,
190                                                         scp->font_size, blink);
191 }
192
193 static void
194 draw_txtcharcursor(scr_stat *scp, int at, u_short c, u_short a, int flip)
195 {
196         sc_softc_t *sc;
197
198         sc = scp->sc;
199         scp->cursor_saveunder_char = c;
200         scp->cursor_saveunder_attr = a;
201
202 #ifndef SC_NO_FONT_LOADING
203         if (sc->flags & SC_CHAR_CURSOR) {
204                 unsigned char *font;
205                 int h;
206                 int i;
207
208                 if (scp->font_size < 14) {
209                         font = sc->font_8;
210                         h = 8;
211                 } else if (scp->font_size >= 16) {
212                         font = sc->font_16;
213                         h = 16;
214                 } else {
215                         font = sc->font_14;
216                         h = 14;
217                 }
218                 if (scp->cursor_base >= h)
219                         return;
220                 if (flip)
221                         a = (a & 0x8800)
222                                 | ((a & 0x7000) >> 4) | ((a & 0x0700) << 4);
223                 bcopy(font + c*h, font + sc->cursor_char*h, h);
224                 font = font + sc->cursor_char*h;
225                 for (i = imax(h - scp->cursor_base - scp->cursor_height, 0);
226                         i < h - scp->cursor_base; ++i) {
227                         font[i] ^= 0xff;
228                 }
229                 sc->font_loading_in_progress = TRUE;
230                 /* XXX */
231                 (*vidsw[sc->adapter]->load_font)(sc->adp, 0, h, font,
232                                                  sc->cursor_char, 1);
233                 sc->font_loading_in_progress = FALSE;
234                 sc_vtb_putc(&scp->scr, at, sc->cursor_char, a);
235         } else
236 #endif /* SC_NO_FONT_LOADING */
237         {
238                 if ((a & 0x7000) == 0x7000) {
239                         a &= 0x8f00;
240                         if ((a & 0x0700) == 0)
241                                 a |= 0x0700;
242                 } else {
243                         a |= 0x7000;
244                         if ((a & 0x0700) == 0x0700)
245                                 a &= 0xf000;
246                 }
247                 if (flip)
248                         a = (a & 0x8800)
249                                 | ((a & 0x7000) >> 4) | ((a & 0x0700) << 4);
250                 sc_vtb_putc(&scp->scr, at, c, a);
251         }
252 }
253
254 static void
255 vga_txtcursor(scr_stat *scp, int at, int blink, int on, int flip)
256 {
257         video_adapter_t *adp;
258         int cursor_attr;
259
260         if (scp->cursor_height <= 0)    /* the text cursor is disabled */
261                 return;
262
263         adp = scp->sc->adp;
264         if (blink) {
265                 scp->status |= VR_CURSOR_BLINK;
266                 if (on) {
267                         scp->status |= VR_CURSOR_ON;
268                         (*vidsw[adp->va_index]->set_hw_cursor)(adp,
269                                                                at%scp->xsize,
270                                                                at/scp->xsize); 
271                 } else {
272                         if (scp->status & VR_CURSOR_ON)
273                                 (*vidsw[adp->va_index]->set_hw_cursor)(adp,
274                                                                        -1, -1);
275                         scp->status &= ~VR_CURSOR_ON;
276                 }
277         } else {
278                 scp->status &= ~VR_CURSOR_BLINK;
279                 if (on) {
280                         scp->status |= VR_CURSOR_ON;
281                         draw_txtcharcursor(scp, at,
282                                            sc_vtb_getc(&scp->scr, at),
283                                            sc_vtb_geta(&scp->scr, at),
284                                            flip);
285                 } else {
286                         cursor_attr = scp->cursor_saveunder_attr;
287                         if (flip)
288                                 cursor_attr = (cursor_attr & 0x8800)
289                                         | ((cursor_attr & 0x7000) >> 4)
290                                         | ((cursor_attr & 0x0700) << 4);
291                         if (scp->status & VR_CURSOR_ON)
292                                 sc_vtb_putc(&scp->scr, at,
293                                             scp->cursor_saveunder_char,
294                                             cursor_attr);
295                         scp->status &= ~VR_CURSOR_ON;
296                 }
297         }
298 }
299
300 static void
301 vga_txtblink(scr_stat *scp, int at, int flip)
302 {
303 }
304
305 #ifndef SC_NO_CUTPASTE
306
307 static void
308 draw_txtmouse(scr_stat *scp, int x, int y)
309 {
310 #ifndef SC_ALT_MOUSE_IMAGE
311     if (ISMOUSEAVAIL(scp->sc->adp->va_flags)) {
312         u_char font_buf[128];
313         u_short cursor[32];
314         u_char c;
315         int pos;
316         int xoffset, yoffset;
317         int crtc_addr;
318         int i;
319
320         /* prepare mousepointer char's bitmaps */
321         pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff;
322         bcopy(scp->font + sc_vtb_getc(&scp->scr, pos)*scp->font_size,
323               &font_buf[0], scp->font_size);
324         bcopy(scp->font + sc_vtb_getc(&scp->scr, pos + 1)*scp->font_size,
325               &font_buf[32], scp->font_size);
326         bcopy(scp->font 
327                  + sc_vtb_getc(&scp->scr, pos + scp->xsize)*scp->font_size,
328               &font_buf[64], scp->font_size);
329         bcopy(scp->font
330                  + sc_vtb_getc(&scp->scr, pos + scp->xsize + 1)*scp->font_size,
331               &font_buf[96], scp->font_size);
332         for (i = 0; i < scp->font_size; ++i) {
333                 cursor[i] = font_buf[i]<<8 | font_buf[i+32];
334                 cursor[i + scp->font_size] = font_buf[i+64]<<8 | font_buf[i+96];
335         }
336
337         /* now and-or in the mousepointer image */
338         xoffset = x%8;
339         yoffset = y%scp->font_size;
340         for (i = 0; i < 16; ++i) {
341                 cursor[i + yoffset] =
342                         (cursor[i + yoffset] & ~(mouse_and_mask[i] >> xoffset))
343                         | (mouse_or_mask[i] >> xoffset);
344         }
345         for (i = 0; i < scp->font_size; ++i) {
346                 font_buf[i] = (cursor[i] & 0xff00) >> 8;
347                 font_buf[i + 32] = cursor[i] & 0xff;
348                 font_buf[i + 64] = (cursor[i + scp->font_size] & 0xff00) >> 8;
349                 font_buf[i + 96] = cursor[i + scp->font_size] & 0xff;
350         }
351
352 #if 1
353         /* wait for vertical retrace to avoid jitter on some videocards */
354         crtc_addr = scp->sc->adp->va_crtc_addr;
355         while (!(inb(crtc_addr + 6) & 0x08)) /* idle */ ;
356 #endif
357         c = scp->sc->mouse_char;
358         (*vidsw[scp->sc->adapter]->load_font)(scp->sc->adp, 0, 32, font_buf,
359                                               c, 4); 
360
361         sc_vtb_putc(&scp->scr, pos, c, sc_vtb_geta(&scp->scr, pos));
362         /* FIXME: may be out of range! */
363         sc_vtb_putc(&scp->scr, pos + scp->xsize, c + 2,
364                     sc_vtb_geta(&scp->scr, pos + scp->xsize));
365         if (x < (scp->xsize - 1)*8) {
366                 sc_vtb_putc(&scp->scr, pos + 1, c + 1,
367                             sc_vtb_geta(&scp->scr, pos + 1));
368                 sc_vtb_putc(&scp->scr, pos + scp->xsize + 1, c + 3,
369                             sc_vtb_geta(&scp->scr, pos + scp->xsize + 1));
370         }
371     } else
372 #endif /* SC_ALT_MOUSE_IMAGE */
373     {
374         /* Red, magenta and brown are mapped to green to to keep it readable */
375         static const int col_conv[16] = {
376                 6, 6, 6, 6, 2, 2, 2, 6, 14, 14, 14, 14, 10, 10, 10, 14
377         };
378         int pos;
379         int color;
380         int a;
381
382         pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff;
383         a = sc_vtb_geta(&scp->scr, pos);
384         if (scp->sc->adp->va_flags & V_ADP_COLOR)
385                 color = (col_conv[(a & 0xf000) >> 12] << 12)
386                         | ((a & 0x0f00) | 0x0800);
387         else
388                 color = ((a & 0xf000) >> 4) | ((a & 0x0f00) << 4);
389         sc_vtb_putc(&scp->scr, pos, sc_vtb_getc(&scp->scr, pos), color);
390     }
391 }
392
393 static void
394 remove_txtmouse(scr_stat *scp, int x, int y)
395 {
396 }
397
398 static void 
399 vga_txtmouse(scr_stat *scp, int x, int y, int on)
400 {
401         if (on)
402                 draw_txtmouse(scp, x, y);
403         else
404                 remove_txtmouse(scp, x, y);
405 }
406
407 #endif /* SC_NO_CUTPASTE */
408
409 #ifdef SC_PIXEL_MODE
410
411 /* pixel (raster text) mode renderer */
412
413 static void
414 vga_rndrinit(scr_stat *scp)
415 {
416         if (scp->sc->adp->va_info.vi_mem_model == V_INFO_MM_PLANAR) {
417                 scp->rndr->draw_border = vga_pxlborder_planar;
418                 scp->rndr->draw = vga_vgadraw_planar;
419                 scp->rndr->draw_cursor = vga_pxlcursor_planar;
420                 scp->rndr->blink_cursor = vga_pxlblink_planar;
421                 scp->rndr->draw_mouse = vga_pxlmouse_planar;
422         } else if (scp->sc->adp->va_info.vi_mem_model == V_INFO_MM_DIRECT) {
423                 scp->rndr->draw_border = vga_pxlborder_direct;
424                 scp->rndr->draw = vga_vgadraw_direct;
425                 scp->rndr->draw_cursor = vga_pxlcursor_direct;
426                 scp->rndr->blink_cursor = vga_pxlblink_direct;
427                 scp->rndr->draw_mouse = vga_pxlmouse_direct;
428         }
429 }
430
431 static void
432 vga_pxlborder_direct(scr_stat *scp, int color)
433 {
434         int i, x, y;
435         int line_width, pixel_size;
436         uint32_t u32 = 0;
437         vm_offset_t draw_pos, draw_end, p;
438
439         line_width = scp->sc->adp->va_line_width;
440         pixel_size = scp->sc->adp->va_info.vi_pixel_size;
441
442         for (i = 0; i < 4 / pixel_size; ++i)
443                 u32 += scp->ega_palette[color] << (i * 8 * pixel_size);
444
445         if (scp->yoff > 0) {
446                 draw_pos = scp->sc->adp->va_window;
447                 draw_end = draw_pos +
448                     line_width * scp->yoff * scp->font_size;
449
450                 for (p = draw_pos; p < draw_end; p += 4)
451                         writel(p, u32);
452         }
453
454         y = (scp->yoff + scp->ysize) * scp->font_size;
455
456         if (scp->ypixel > y) {
457                 draw_pos = scp->sc->adp->va_window + line_width * y;
458                 draw_end = draw_pos + line_width * (scp->ypixel - y);
459
460                 for (p = draw_pos; p < draw_end; p += 4)
461                         writel(p, u32); 
462         }
463
464         y = scp->yoff * scp->font_size;
465         x = scp->xpixel / 8 - scp->xoff - scp->xsize;
466
467         for (i = 0; i < scp->ysize * scp->font_size; ++i) {
468                 if (scp->xoff > 0) {
469                         draw_pos = scp->sc->adp->va_window +
470                             line_width * (y + i);
471                         draw_end = draw_pos + scp->xoff * 8 * pixel_size;
472
473                         for (p = draw_pos; p < draw_end; p += 4)
474                                 writel(p, u32);
475                 }
476
477                 if (x > 0) {
478                         draw_pos = scp->sc->adp->va_window +
479                             line_width * (y + i) +
480                             scp->xoff * 8 * pixel_size +
481                             scp->xsize * 8 * pixel_size;
482                         draw_end = draw_pos + x * 8 * pixel_size;
483
484                         for (p = draw_pos; p < draw_end; p += 4)
485                                 writel(p, u32);
486                 }
487         }
488 }
489
490 static void
491 vga_pxlborder_planar(scr_stat *scp, int color)
492 {
493         vm_offset_t p;
494         int line_width;
495         int x;
496         int y;
497         int i;
498
499         (*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color);
500
501         outw(GDCIDX, 0x0005);           /* read mode 0, write mode 0 */
502         outw(GDCIDX, 0x0003);           /* data rotate/function select */
503         outw(GDCIDX, 0x0f01);           /* set/reset enable */
504         outw(GDCIDX, 0xff08);           /* bit mask */
505         outw(GDCIDX, (color << 8) | 0x00);      /* set/reset */
506         line_width = scp->sc->adp->va_line_width;
507         p = scp->sc->adp->va_window;
508         if (scp->yoff > 0)
509                 bzero_io((void *)p, line_width*scp->yoff*scp->font_size);
510         y = (scp->yoff + scp->ysize)*scp->font_size;
511         if (scp->ypixel > y)
512                 bzero_io((void *)(p + line_width*y), line_width*(scp->ypixel - y));
513         y = scp->yoff*scp->font_size;
514         x = scp->xpixel/8 - scp->xoff - scp->xsize;
515         for (i = 0; i < scp->ysize*scp->font_size; ++i) {
516                 if (scp->xoff > 0)
517                         bzero_io((void *)(p + line_width*(y + i)), scp->xoff);
518                 if (x > 0)
519                         bzero_io((void *)(p + line_width*(y + i)
520                                      + scp->xoff + scp->xsize), x);
521         }
522         outw(GDCIDX, 0x0000);           /* set/reset */
523         outw(GDCIDX, 0x0001);           /* set/reset enable */
524 }
525
526 static void
527 vga_vgadraw_direct(scr_stat *scp, int from, int count, int flip)
528 {
529         int line_width, pixel_size;
530         int a, i, j, k, l, pos;
531         uint32_t fg, bg, u32;
532         unsigned char *char_data;
533         vm_offset_t draw_pos, p;
534
535         line_width = scp->sc->adp->va_line_width;
536         pixel_size = scp->sc->adp->va_info.vi_pixel_size;
537
538         draw_pos = VIDEO_MEMORY_POS(scp, from, 8 * pixel_size);
539
540         if (from + count > scp->xsize * scp->ysize)
541                 count = scp->xsize * scp->ysize - from;
542
543         for (i = from; count-- > 0; ++i) {
544                 a = sc_vtb_geta(&scp->vtb, i);
545
546                 if (flip) {
547                         fg = scp->ega_palette[(((a & 0x7000) >> 4) |
548                             (a & 0x0800)) >> 8];
549                         bg = scp->ega_palette[(((a & 0x8000) >> 4) |
550                             (a & 0x0700)) >> 8];
551                 } else {
552                         fg = scp->ega_palette[(a & 0x0f00) >> 8];
553                         bg = scp->ega_palette[(a & 0xf000) >> 12];
554                 }
555
556                 p = draw_pos;
557                 char_data = &(scp->font[sc_vtb_getc(&scp->vtb, i) *
558                     scp->font_size]);
559
560                 for (j = 0; j < scp->font_size; ++j, ++char_data) {
561                         pos = 7;
562
563                         for (k = 0; k < 2 * pixel_size; ++k) {
564                                 u32 = 0;
565
566                                 for (l = 0; l < 4 / pixel_size; ++l) {
567                                         u32 += (*char_data & (1 << pos--) ?
568                                             fg : bg) << (l * 8 * pixel_size);
569                                 }
570
571                                 writel(p, u32);
572                                 p += 4;
573                         }
574
575                         p += line_width - 8 * pixel_size;
576                 }
577
578                 draw_pos += 8 * pixel_size;
579
580                 if ((i % scp->xsize) == scp->xsize - 1)
581                         draw_pos += scp->xoff * 16 * pixel_size +
582                              (scp->font_size - 1) * line_width;
583         }
584 }
585
586 static void
587 vga_vgadraw_planar(scr_stat *scp, int from, int count, int flip)
588 {
589         vm_offset_t d;
590         vm_offset_t e;
591         u_char *f;
592         u_short bg;
593         u_short col1, col2;
594         int line_width;
595         int i, j;
596         int a;
597         u_char c;
598
599         d = VIDEO_MEMORY_POS(scp, from, 1);
600
601         line_width = scp->sc->adp->va_line_width;
602
603         outw(GDCIDX, 0x0305);           /* read mode 0, write mode 3 */
604         outw(GDCIDX, 0x0003);           /* data rotate/function select */
605         outw(GDCIDX, 0x0f01);           /* set/reset enable */
606         outw(GDCIDX, 0xff08);           /* bit mask */
607         bg = -1;
608         if (from + count > scp->xsize*scp->ysize)
609                 count = scp->xsize*scp->ysize - from;
610         for (i = from; count-- > 0; ++i) {
611                 a = sc_vtb_geta(&scp->vtb, i);
612                 if (flip) {
613                         col1 = ((a & 0x7000) >> 4) | (a & 0x0800);
614                         col2 = ((a & 0x8000) >> 4) | (a & 0x0700);
615                 } else {
616                         col1 = (a & 0x0f00);
617                         col2 = (a & 0xf000) >> 4;
618                 }
619                 /* set background color in EGA/VGA latch */
620                 if (bg != col2) {
621                         bg = col2;
622                         outw(GDCIDX, 0x0005);   /* read mode 0, write mode 0 */
623                         outw(GDCIDX, bg | 0x00); /* set/reset */
624                         writeb(d, 0);
625                         c = readb(d);           /* set bg color in the latch */
626                         outw(GDCIDX, 0x0305);   /* read mode 0, write mode 3 */
627                 }
628                 /* foreground color */
629                 outw(GDCIDX, col1 | 0x00);      /* set/reset */
630                 e = d;
631                 f = &(scp->font[sc_vtb_getc(&scp->vtb, i)*scp->font_size]);
632                 for (j = 0; j < scp->font_size; ++j, ++f) {
633                         writeb(e, *f);
634                         e += line_width;
635                 }
636                 ++d;
637                 if ((i % scp->xsize) == scp->xsize - 1)
638                         d += scp->xoff*2 
639                                  + (scp->font_size - 1)*line_width;
640         }
641         outw(GDCIDX, 0x0005);           /* read mode 0, write mode 0 */
642         outw(GDCIDX, 0x0000);           /* set/reset */
643         outw(GDCIDX, 0x0001);           /* set/reset enable */
644 }
645
646 static void 
647 vga_pxlcursor_shape(scr_stat *scp, int base, int height, int blink)
648 {
649         if (base < 0 || base >= scp->font_size)
650                 return;
651         /* the caller may set height <= 0 in order to disable the cursor */
652 #if 0
653         scp->cursor_base = base;
654         scp->cursor_height = height;
655 #endif
656 }
657
658 static void 
659 draw_pxlcursor_direct(scr_stat *scp, int at, int on, int flip)
660 {
661         int line_width, pixel_size, height;
662         int a, i, j, k, pos;
663         uint32_t fg, bg, u32;
664         unsigned char *char_data;
665         vm_offset_t draw_pos;
666
667         line_width = scp->sc->adp->va_line_width;
668         pixel_size = scp->sc->adp->va_info.vi_pixel_size;
669
670         draw_pos = VIDEO_MEMORY_POS(scp, at, 8 * pixel_size) +
671             (scp->font_size - scp->cursor_base - 1) * line_width;
672
673         a = sc_vtb_geta(&scp->vtb, at);
674
675         if (flip) {
676                 fg = scp->ega_palette[((on) ? (a & 0x0f00) :
677                     ((a & 0xf000) >> 4)) >> 8];
678                 bg = scp->ega_palette[((on) ? ((a & 0xf000) >> 4) :
679                     (a & 0x0f00)) >> 8];
680         } else {
681                 fg = scp->ega_palette[((on) ? ((a & 0xf000) >> 4) :
682                     (a & 0x0f00)) >> 8];
683                 bg = scp->ega_palette[((on) ? (a & 0x0f00) :
684                     ((a & 0xf000) >> 4)) >> 8];
685         }
686
687         char_data = &(scp->font[sc_vtb_getc(&scp->vtb, at) * scp->font_size +
688             scp->font_size - scp->cursor_base - 1]);
689
690         height = imin(scp->cursor_height, scp->font_size);
691
692         for (i = 0; i < height; ++i, --char_data) {
693                 pos = 7;
694
695                 for (j = 0; j < 2 * pixel_size; ++j) {
696                         u32 = 0;
697
698                         for (k = 0; k < 4 / pixel_size; ++k) {
699                                 u32 += (*char_data & (1 << pos--) ?
700                                     fg : bg) << (k * 8 * pixel_size);
701                         }
702
703                         writel(draw_pos, u32);
704                         draw_pos += 4;
705                 }
706
707                 draw_pos -= line_width + 8 * pixel_size;
708         }
709 }
710
711 static void 
712 draw_pxlcursor_planar(scr_stat *scp, int at, int on, int flip)
713 {
714         vm_offset_t d;
715         u_char *f;
716         int line_width;
717         int height;
718         int col;
719         int a;
720         int i;
721         u_char c;
722
723         line_width = scp->sc->adp->va_line_width;
724
725         d = VIDEO_MEMORY_POS(scp, at, 1) +
726             (scp->font_size - scp->cursor_base - 1) * line_width;
727
728         outw(GDCIDX, 0x0005);           /* read mode 0, write mode 0 */
729         outw(GDCIDX, 0x0003);           /* data rotate/function select */
730         outw(GDCIDX, 0x0f01);           /* set/reset enable */
731         /* set background color in EGA/VGA latch */
732         a = sc_vtb_geta(&scp->vtb, at);
733         if (flip)
734                 col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00);
735         else
736                 col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4);
737         outw(GDCIDX, col | 0x00);       /* set/reset */
738         outw(GDCIDX, 0xff08);           /* bit mask */
739         writeb(d, 0);
740         c = readb(d);                   /* set bg color in the latch */
741         /* foreground color */
742         if (flip)
743                 col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4);
744         else
745                 col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00);
746         outw(GDCIDX, col | 0x00);       /* set/reset */
747         f = &(scp->font[sc_vtb_getc(&scp->vtb, at)*scp->font_size
748                 + scp->font_size - scp->cursor_base - 1]);
749         height = imin(scp->cursor_height, scp->font_size);
750         for (i = 0; i < height; ++i, --f) {
751                 outw(GDCIDX, (*f << 8) | 0x08); /* bit mask */
752                 writeb(d, 0);
753                 d -= line_width;
754         }
755         outw(GDCIDX, 0x0000);           /* set/reset */
756         outw(GDCIDX, 0x0001);           /* set/reset enable */
757         outw(GDCIDX, 0xff08);           /* bit mask */
758 }
759
760 static int pxlblinkrate = 0;
761
762 static void 
763 vga_pxlcursor_direct(scr_stat *scp, int at, int blink, int on, int flip)
764 {
765         if (scp->cursor_height <= 0)    /* the text cursor is disabled */
766                 return;
767
768         if (on) {
769                 if (!blink) {
770                         scp->status |= VR_CURSOR_ON;
771                         draw_pxlcursor_direct(scp, at, on, flip);
772                 } else if (++pxlblinkrate & 4) {
773                         pxlblinkrate = 0;
774                         scp->status ^= VR_CURSOR_ON;
775                         draw_pxlcursor_direct(scp, at,
776                                               scp->status & VR_CURSOR_ON,
777                                               flip);
778                 }
779         } else {
780                 if (scp->status & VR_CURSOR_ON)
781                         draw_pxlcursor_direct(scp, at, on, flip);
782                 scp->status &= ~VR_CURSOR_ON;
783         }
784         if (blink)
785                 scp->status |= VR_CURSOR_BLINK;
786         else
787                 scp->status &= ~VR_CURSOR_BLINK;
788 }
789
790 static void 
791 vga_pxlcursor_planar(scr_stat *scp, int at, int blink, int on, int flip)
792 {
793         if (scp->cursor_height <= 0)    /* the text cursor is disabled */
794                 return;
795
796         if (on) {
797                 if (!blink) {
798                         scp->status |= VR_CURSOR_ON;
799                         draw_pxlcursor_planar(scp, at, on, flip);
800                 } else if (++pxlblinkrate & 4) {
801                         pxlblinkrate = 0;
802                         scp->status ^= VR_CURSOR_ON;
803                         draw_pxlcursor_planar(scp, at,
804                                               scp->status & VR_CURSOR_ON,
805                                               flip);
806                 }
807         } else {
808                 if (scp->status & VR_CURSOR_ON)
809                         draw_pxlcursor_planar(scp, at, on, flip);
810                 scp->status &= ~VR_CURSOR_ON;
811         }
812         if (blink)
813                 scp->status |= VR_CURSOR_BLINK;
814         else
815                 scp->status &= ~VR_CURSOR_BLINK;
816 }
817
818 static void
819 vga_pxlblink_direct(scr_stat *scp, int at, int flip)
820 {
821         if (!(scp->status & VR_CURSOR_BLINK))
822                 return;
823         if (!(++pxlblinkrate & 4))
824                 return;
825         pxlblinkrate = 0;
826         scp->status ^= VR_CURSOR_ON;
827         draw_pxlcursor_direct(scp, at, scp->status & VR_CURSOR_ON, flip);
828 }
829
830 static void
831 vga_pxlblink_planar(scr_stat *scp, int at, int flip)
832 {
833         if (!(scp->status & VR_CURSOR_BLINK))
834                 return;
835         if (!(++pxlblinkrate & 4))
836                 return;
837         pxlblinkrate = 0;
838         scp->status ^= VR_CURSOR_ON;
839         draw_pxlcursor_planar(scp, at, scp->status & VR_CURSOR_ON, flip);
840 }
841
842 #ifndef SC_NO_CUTPASTE
843
844 static void 
845 draw_pxlmouse_direct(scr_stat *scp, int x, int y)
846 {
847         int line_width, pixel_size;
848         int xend, yend;
849         int i, j;
850         vm_offset_t draw_pos;
851
852         line_width = scp->sc->adp->va_line_width;
853         pixel_size = scp->sc->adp->va_info.vi_pixel_size;
854
855         xend = imin(x + 8, 8 * (scp->xoff + scp->xsize));
856         yend = imin(y + 16, scp->font_size * (scp->yoff + scp->ysize));
857
858         draw_pos = scp->sc->adp->va_window + y * line_width + x * pixel_size;
859
860         for (i = 0; i < (yend - y); i++) {
861                 for (j = (xend - x - 1); j >= 0; j--) {
862                         switch (scp->sc->adp->va_info.vi_depth) {
863                         case 32:
864                                 if (mouse_or_mask[i] & 1 << (15 - j))
865                                         writel(draw_pos + 4 * j,
866                                             scp->ega_palette[15]);
867                                 else if (mouse_and_mask[i] & 1 << (15 - j))
868                                         writel(draw_pos + 4 * j,
869                                             scp->ega_palette[0]);
870                                 break;
871                         case 16:
872                                 /* FALLTHROUGH */
873                         case 15:
874                                 if (mouse_or_mask[i] & 1 << (15 - j))
875                                         writew(draw_pos + 2 * j,
876                                             scp->ega_palette[15]);
877                                 else if (mouse_and_mask[i] & 1 << (15 - j))
878                                         writew(draw_pos + 2 * j,
879                                             scp->ega_palette[0]);
880                                 break;
881                         }
882                 }
883
884                 draw_pos += line_width;
885         }
886 }
887
888 static void
889 draw_pxlmouse_planar(scr_stat *scp, int x, int y)
890 {
891         vm_offset_t p;
892         int line_width;
893         int xoff, yoff;
894         int ymax;
895         u_short m;
896         int i, j;
897
898         line_width = scp->sc->adp->va_line_width;
899         xoff = (x - scp->xoff*8)%8;
900         yoff = y - (y/line_width)*line_width;
901         ymax = imin(y + 16, scp->font_size * (scp->yoff + scp->ysize));
902
903         outw(GDCIDX, 0x0805);           /* read mode 1, write mode 0 */
904         outw(GDCIDX, 0x0001);           /* set/reset enable */
905         outw(GDCIDX, 0x0002);           /* color compare */
906         outw(GDCIDX, 0x0007);           /* color don't care */
907         outw(GDCIDX, 0xff08);           /* bit mask */
908         outw(GDCIDX, 0x0803);           /* data rotate/function select (and) */
909         p = scp->sc->adp->va_window + line_width*y + x/8;
910         if (x < 8 * (scp->xoff + scp->xsize) - 8) {
911                 for (i = y, j = 0; i < ymax; ++i, ++j) {
912                         m = ~(mouse_and_mask[j] >> xoff);
913                         *(u_char *)p &= m >> 8;
914                         *(u_char *)(p + 1) &= m;
915                         p += line_width;
916                 }
917         } else {
918                 xoff += 8;
919                 for (i = y, j = 0; i < ymax; ++i, ++j) {
920                         m = ~(mouse_and_mask[j] >> xoff);
921                         *(u_char *)p &= m;
922                         p += line_width;
923                 }
924         }
925         outw(GDCIDX, 0x1003);           /* data rotate/function select (or) */
926         p = scp->sc->adp->va_window + line_width*y + x/8;
927         if (x < 8 * (scp->xoff + scp->xsize) - 8) {
928                 for (i = y, j = 0; i < ymax; ++i, ++j) {
929                         m = mouse_or_mask[j] >> xoff;
930                         *(u_char *)p &= m >> 8;
931                         *(u_char *)(p + 1) &= m;
932                         p += line_width;
933                 }
934         } else {
935                 for (i = y, j = 0; i < ymax; ++i, ++j) {
936                         m = mouse_or_mask[j] >> xoff;
937                         *(u_char *)p &= m;
938                         p += line_width;
939                 }
940         }
941         outw(GDCIDX, 0x0005);           /* read mode 0, write mode 0 */
942         outw(GDCIDX, 0x0003);           /* data rotate/function select */
943 }
944
945 static void
946 remove_pxlmouse(scr_stat *scp, int x, int y)
947 {
948         int col, row;
949         int pos;
950         int i;
951
952         /* erase the mouse cursor image */
953         col = x/8 - scp->xoff;
954         row = y/scp->font_size - scp->yoff;
955         pos = row*scp->xsize + col;
956         i = (col < scp->xsize - 1) ? 2 : 1;
957         (*scp->rndr->draw)(scp, pos, i, FALSE);
958         if (row < scp->ysize - 1)
959                 (*scp->rndr->draw)(scp, pos + scp->xsize, i, FALSE);
960 }
961
962 static void 
963 vga_pxlmouse_direct(scr_stat *scp, int x, int y, int on)
964 {
965         if (on)
966                 draw_pxlmouse_direct(scp, x, y);
967         else
968                 remove_pxlmouse(scp, x, y);
969 }
970
971 static void 
972 vga_pxlmouse_planar(scr_stat *scp, int x, int y, int on)
973 {
974         if (on)
975                 draw_pxlmouse_planar(scp, x, y);
976         else
977                 remove_pxlmouse(scp, x, y);
978 }
979
980 #endif /* SC_NO_CUTPASTE */
981 #endif /* SC_PIXEL_MODE */
982
983 #ifndef SC_NO_MODE_CHANGE
984
985 /* graphics mode renderer */
986
987 static void
988 vga_grborder(scr_stat *scp, int color)
989 {
990         (*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color);
991 }
992
993 #endif