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 1171