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