1 /*- 2 * (MPSAFE) 3 * 4 * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The DragonFly Project 8 * by Sascha Wildner <saw@online.de> 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer as 15 * the first lines of this file unmodified. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 * 31 * $FreeBSD: src/sys/dev/syscons/scvgarndr.c,v 1.5.2.3 2001/07/28 12:51:47 yokota Exp $ 32 * $DragonFly: src/sys/dev/misc/syscons/scvgarndr.c,v 1.17 2008/08/10 19:45:01 swildner Exp $ 33 */ 34 35 #include "opt_syscons.h" 36 #include "opt_vga.h" 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/kernel.h> 41 #include <sys/thread.h> 42 #include <sys/thread2.h> 43 44 #include <machine/console.h> 45 46 #include <dev/video/fb/fbreg.h> 47 #include <dev/video/fb/vgareg.h> 48 #include "syscons.h" 49 50 #include <bus/isa/isareg.h> 51 52 /* 53 * XXX: this still doesn't quite work with tokens (mainly vga_txtcursor*), 54 * so temporarily disable tokens here. 55 */ 56 #if 0 57 #define lwkt_gettoken(x) 58 #define lwkt_reltoken(x) 59 #endif 60 61 static vr_draw_border_t vga_txtborder; 62 static vr_draw_t vga_txtdraw; 63 static vr_set_cursor_t vga_txtcursor_shape; 64 static vr_draw_cursor_t vga_txtcursor; 65 static vr_blink_cursor_t vga_txtblink; 66 #ifndef SC_NO_CUTPASTE 67 static vr_draw_mouse_t vga_txtmouse; 68 #else 69 #define vga_txtmouse (vr_draw_mouse_t *)vga_nop 70 #endif 71 72 #ifdef SC_PIXEL_MODE 73 static vr_draw_border_t vga_pxlborder_direct; 74 static vr_draw_border_t vga_pxlborder_packed; 75 static vr_draw_border_t vga_pxlborder_planar; 76 static vr_draw_t vga_vgadraw_direct; 77 static vr_draw_t vga_vgadraw_packed; 78 static vr_draw_t vga_vgadraw_planar; 79 static vr_set_cursor_t vga_pxlcursor_shape; 80 static vr_draw_cursor_t vga_pxlcursor_direct; 81 static vr_draw_cursor_t vga_pxlcursor_packed; 82 static vr_draw_cursor_t vga_pxlcursor_planar; 83 static vr_blink_cursor_t vga_pxlblink_direct; 84 static vr_blink_cursor_t vga_pxlblink_packed; 85 static vr_blink_cursor_t vga_pxlblink_planar; 86 #ifndef SC_NO_CUTPASTE 87 static vr_draw_mouse_t vga_pxlmouse_direct; 88 static vr_draw_mouse_t vga_pxlmouse_packed; 89 static vr_draw_mouse_t vga_pxlmouse_planar; 90 #else 91 #define vga_pxlmouse_direct (vr_draw_mouse_t *)vga_nop 92 #define vga_pxlmouse_packed (vr_draw_mouse_t *)vga_nop 93 #define vga_pxlmouse_planar (vr_draw_mouse_t *)vga_nop 94 #endif 95 #endif /* SC_PIXEL_MODE */ 96 97 #ifndef SC_NO_MODE_CHANGE 98 static vr_draw_border_t vga_grborder; 99 #endif 100 101 static void vga_nop(scr_stat *scp, ...); 102 103 static sc_rndr_sw_t txtrndrsw = { 104 vga_txtborder, 105 vga_txtdraw, 106 vga_txtcursor_shape, 107 vga_txtcursor, 108 vga_txtblink, 109 vga_txtmouse, 110 }; 111 RENDERER(vga, V_INFO_MM_TEXT, txtrndrsw, vga_set); 112 113 #ifdef SC_PIXEL_MODE 114 static sc_rndr_sw_t directrndrsw = { 115 vga_pxlborder_direct, 116 vga_vgadraw_direct, 117 vga_pxlcursor_shape, 118 vga_pxlcursor_direct, 119 vga_pxlblink_direct, 120 vga_pxlmouse_direct, 121 }; 122 RENDERER(vga, V_INFO_MM_DIRECT, directrndrsw, vga_set); 123 124 static sc_rndr_sw_t packedrndrsw = { 125 vga_pxlborder_packed, 126 vga_vgadraw_packed, 127 vga_pxlcursor_shape, 128 vga_pxlcursor_packed, 129 vga_pxlblink_packed, 130 vga_pxlmouse_packed, 131 }; 132 RENDERER(vga, V_INFO_MM_PACKED, packedrndrsw, vga_set); 133 134 static sc_rndr_sw_t planarrndrsw = { 135 vga_pxlborder_planar, 136 vga_vgadraw_planar, 137 vga_pxlcursor_shape, 138 vga_pxlcursor_planar, 139 vga_pxlblink_planar, 140 vga_pxlmouse_planar, 141 }; 142 RENDERER(vga, V_INFO_MM_PLANAR, planarrndrsw, vga_set); 143 #endif /* SC_PIXEL_MODE */ 144 145 #ifndef SC_NO_MODE_CHANGE 146 static sc_rndr_sw_t grrndrsw = { 147 vga_grborder, 148 (vr_draw_t *)vga_nop, 149 (vr_set_cursor_t *)vga_nop, 150 (vr_draw_cursor_t *)vga_nop, 151 (vr_blink_cursor_t *)vga_nop, 152 (vr_draw_mouse_t *)vga_nop, 153 }; 154 RENDERER(vga, V_INFO_MM_OTHER, grrndrsw, vga_set); 155 #endif /* SC_NO_MODE_CHANGE */ 156 157 RENDERER_MODULE(vga, vga_set); 158 159 #ifndef SC_NO_CUTPASTE 160 static u_short mouse_and_mask[16] = { 161 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00, 0xff80, 162 0xfe00, 0x1e00, 0x1f00, 0x0f00, 0x0f00, 0x0000, 0x0000, 0x0000 163 }; 164 static u_short mouse_or_mask[16] = { 165 0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7c00, 0x7e00, 0x6800, 166 0x0c00, 0x0c00, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000 167 }; 168 #endif 169 170 static void 171 vga_nop(scr_stat *scp, ...) 172 { 173 } 174 175 /* text mode renderer */ 176 177 static void 178 vga_txtborder(scr_stat *scp, int color) 179 { 180 (*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color); 181 } 182 183 static void 184 vga_txtdraw(scr_stat *scp, int from, int count, int flip) 185 { 186 uint16_t *p; 187 int c; 188 int a; 189 190 if (from + count > scp->xsize*scp->ysize) 191 count = scp->xsize*scp->ysize - from; 192 193 if (flip) { 194 for (p = scp->scr.vtb_buffer + from; count-- > 0; ++from) { 195 c = sc_vtb_getc(&scp->vtb, from); 196 a = sc_vtb_geta(&scp->vtb, from); 197 a = (a & 0x8800) | ((a & 0x7000) >> 4) 198 | ((a & 0x0700) << 4); 199 p = sc_vtb_putchar(&scp->scr, p, c, a); 200 } 201 } else { 202 sc_vtb_copy(&scp->vtb, from, &scp->scr, from, count); 203 } 204 } 205 206 static void 207 vga_txtcursor_shape(scr_stat *scp, int base, int height, int blink) 208 { 209 if (base < 0 || base >= scp->font_size) 210 return; 211 212 /* the caller may set height <= 0 in order to disable the cursor */ 213 #if 0 214 scp->cursor_base = base; 215 scp->cursor_height = height; 216 #endif 217 (*vidsw[scp->sc->adapter]->set_hw_cursor_shape)(scp->sc->adp, 218 base, height, 219 scp->font_size, blink); 220 221 } 222 223 static void 224 draw_txtcharcursor(scr_stat *scp, int at, u_short c, u_short a, int flip) 225 { 226 sc_softc_t *sc; 227 228 sc = scp->sc; 229 scp->cursor_saveunder_char = c; 230 scp->cursor_saveunder_attr = a; 231 232 #ifndef SC_NO_FONT_LOADING 233 if (sc->flags & SC_CHAR_CURSOR) { 234 unsigned char *font; 235 int h; 236 int i; 237 238 if (scp->font_size < 14) { 239 font = sc->font_8; 240 h = 8; 241 } else if (scp->font_size >= 16) { 242 font = sc->font_16; 243 h = 16; 244 } else { 245 font = sc->font_14; 246 h = 14; 247 } 248 if (scp->cursor_base >= h) { 249 lwkt_reltoken(&tty_token); 250 return; 251 } 252 if (flip) 253 a = (a & 0x8800) 254 | ((a & 0x7000) >> 4) | ((a & 0x0700) << 4); 255 bcopy(font + c*h, font + sc->cursor_char*h, h); 256 font = font + sc->cursor_char*h; 257 for (i = imax(h - scp->cursor_base - scp->cursor_height, 0); 258 i < h - scp->cursor_base; ++i) { 259 font[i] ^= 0xff; 260 } 261 sc->font_loading_in_progress = TRUE; 262 /* XXX */ 263 (*vidsw[sc->adapter]->load_font)(sc->adp, 0, h, font, 264 sc->cursor_char, 1); 265 sc->font_loading_in_progress = FALSE; 266 sc_vtb_putc(&scp->scr, at, sc->cursor_char, a); 267 } else 268 #endif /* SC_NO_FONT_LOADING */ 269 { 270 if ((a & 0x7000) == 0x7000) { 271 a &= 0x8f00; 272 if ((a & 0x0700) == 0) 273 a |= 0x0700; 274 } else { 275 a |= 0x7000; 276 if ((a & 0x0700) == 0x0700) 277 a &= 0xf000; 278 } 279 if (flip) 280 a = (a & 0x8800) 281 | ((a & 0x7000) >> 4) | ((a & 0x0700) << 4); 282 sc_vtb_putc(&scp->scr, at, c, a); 283 } 284 } 285 286 static void 287 vga_txtcursor(scr_stat *scp, int at, int blink, int on, int flip) 288 { 289 video_adapter_t *adp; 290 int cursor_attr; 291 292 if (scp->cursor_height <= 0) /* the text cursor is disabled */ 293 return; 294 295 adp = scp->sc->adp; 296 if (blink) { 297 scp->status |= VR_CURSOR_BLINK; 298 if (on) { 299 scp->status |= VR_CURSOR_ON; 300 (*vidsw[adp->va_index]->set_hw_cursor)(adp, 301 at%scp->xsize, 302 at/scp->xsize); 303 } else { 304 if (scp->status & VR_CURSOR_ON) 305 (*vidsw[adp->va_index]->set_hw_cursor)(adp, 306 -1, -1); 307 scp->status &= ~VR_CURSOR_ON; 308 } 309 } else { 310 scp->status &= ~VR_CURSOR_BLINK; 311 if (on) { 312 scp->status |= VR_CURSOR_ON; 313 draw_txtcharcursor(scp, at, 314 sc_vtb_getc(&scp->scr, at), 315 sc_vtb_geta(&scp->scr, at), 316 flip); 317 } else { 318 cursor_attr = scp->cursor_saveunder_attr; 319 if (flip) 320 cursor_attr = (cursor_attr & 0x8800) 321 | ((cursor_attr & 0x7000) >> 4) 322 | ((cursor_attr & 0x0700) << 4); 323 if (scp->status & VR_CURSOR_ON) 324 sc_vtb_putc(&scp->scr, at, 325 scp->cursor_saveunder_char, 326 cursor_attr); 327 scp->status &= ~VR_CURSOR_ON; 328 } 329 } 330 } 331 332 static void 333 vga_txtblink(scr_stat *scp, int at, int flip) 334 { 335 } 336 337 #ifndef SC_NO_CUTPASTE 338 339 static void 340 draw_txtmouse(scr_stat *scp, int x, int y) 341 { 342 #ifndef SC_ALT_MOUSE_IMAGE 343 if (ISMOUSEAVAIL(scp->sc->adp->va_flags)) { 344 u_char font_buf[128]; 345 u_short cursor[32]; 346 u_char c; 347 int pos; 348 int xoffset, yoffset; 349 int i; 350 351 /* prepare mousepointer char's bitmaps */ 352 pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff; 353 bcopy(scp->font + sc_vtb_getc(&scp->scr, pos)*scp->font_size, 354 &font_buf[0], scp->font_size); 355 bcopy(scp->font + sc_vtb_getc(&scp->scr, pos + 1)*scp->font_size, 356 &font_buf[32], scp->font_size); 357 bcopy(scp->font 358 + sc_vtb_getc(&scp->scr, pos + scp->xsize)*scp->font_size, 359 &font_buf[64], scp->font_size); 360 bcopy(scp->font 361 + sc_vtb_getc(&scp->scr, pos + scp->xsize + 1)*scp->font_size, 362 &font_buf[96], scp->font_size); 363 for (i = 0; i < scp->font_size; ++i) { 364 cursor[i] = font_buf[i]<<8 | font_buf[i+32]; 365 cursor[i + scp->font_size] = font_buf[i+64]<<8 | font_buf[i+96]; 366 } 367 368 /* now and-or in the mousepointer image */ 369 xoffset = x%8; 370 yoffset = y%scp->font_size; 371 for (i = 0; i < 16; ++i) { 372 cursor[i + yoffset] = 373 (cursor[i + yoffset] & ~(mouse_and_mask[i] >> xoffset)) 374 | (mouse_or_mask[i] >> xoffset); 375 } 376 for (i = 0; i < scp->font_size; ++i) { 377 font_buf[i] = (cursor[i] & 0xff00) >> 8; 378 font_buf[i + 32] = cursor[i] & 0xff; 379 font_buf[i + 64] = (cursor[i + scp->font_size] & 0xff00) >> 8; 380 font_buf[i + 96] = cursor[i + scp->font_size] & 0xff; 381 } 382 383 #if 1 384 /* wait for vertical retrace to avoid jitter on some videocards */ 385 while (!(inb(CRTC + 6) & 0x08)) /* idle */ ; 386 #endif 387 c = scp->sc->mouse_char; 388 (*vidsw[scp->sc->adapter]->load_font)(scp->sc->adp, 0, 32, font_buf, 389 c, 4); 390 391 sc_vtb_putc(&scp->scr, pos, c, sc_vtb_geta(&scp->scr, pos)); 392 /* FIXME: may be out of range! */ 393 sc_vtb_putc(&scp->scr, pos + scp->xsize, c + 2, 394 sc_vtb_geta(&scp->scr, pos + scp->xsize)); 395 if (x < (scp->xsize - 1)*8) { 396 sc_vtb_putc(&scp->scr, pos + 1, c + 1, 397 sc_vtb_geta(&scp->scr, pos + 1)); 398 sc_vtb_putc(&scp->scr, pos + scp->xsize + 1, c + 3, 399 sc_vtb_geta(&scp->scr, pos + scp->xsize + 1)); 400 } 401 } else 402 #endif /* SC_ALT_MOUSE_IMAGE */ 403 { 404 /* Red, magenta and brown are mapped to green to to keep it readable */ 405 static const int col_conv[16] = { 406 6, 6, 6, 6, 2, 2, 2, 6, 14, 14, 14, 14, 10, 10, 10, 14 407 }; 408 int pos; 409 int color; 410 int a; 411 412 pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff; 413 a = sc_vtb_geta(&scp->scr, pos); 414 if (scp->sc->adp->va_flags & V_ADP_COLOR) 415 color = (col_conv[(a & 0xf000) >> 12] << 12) 416 | ((a & 0x0f00) | 0x0800); 417 else 418 color = ((a & 0xf000) >> 4) | ((a & 0x0f00) << 4); 419 sc_vtb_putc(&scp->scr, pos, sc_vtb_getc(&scp->scr, pos), color); 420 } 421 422 } 423 424 static void 425 remove_txtmouse(scr_stat *scp, int x, int y) 426 { 427 } 428 429 static void 430 vga_txtmouse(scr_stat *scp, int x, int y, int on) 431 { 432 if (on) 433 draw_txtmouse(scp, x, y); 434 else 435 remove_txtmouse(scp, x, y); 436 } 437 438 #endif /* SC_NO_CUTPASTE */ 439 440 #ifdef SC_PIXEL_MODE 441 442 /* pixel (raster text) mode renderer */ 443 444 static void 445 vga_pxlborder_direct(scr_stat *scp, int color) 446 { 447 int i, x, y; 448 int line_width, pixel_size; 449 uint32_t u32 = 0; 450 vm_offset_t draw_pos, draw_end, p; 451 452 line_width = scp->sc->adp->va_line_width; 453 pixel_size = scp->sc->adp->va_info.vi_pixel_size; 454 455 for (i = 0; i < 4 / pixel_size; ++i) 456 u32 += scp->ega_palette[color] << (i * 8 * pixel_size); 457 458 if (scp->yoff > 0) { 459 draw_pos = scp->sc->adp->va_window; 460 draw_end = draw_pos + line_width * scp->yoff * scp->font_size; 461 462 for (p = draw_pos; p < draw_end; p += 4) 463 writel(p, u32); 464 } 465 466 y = (scp->yoff + scp->ysize) * scp->font_size; 467 468 if (scp->ypixel > y) { 469 draw_pos = scp->sc->adp->va_window + line_width * y; 470 draw_end = draw_pos + line_width * (scp->ypixel - y); 471 472 for (p = draw_pos; p < draw_end; p += 4) 473 writel(p, u32); 474 } 475 476 y = scp->yoff * scp->font_size; 477 x = scp->xpixel / 8 - scp->xoff - scp->xsize; 478 479 for (i = 0; i < scp->ysize * scp->font_size; ++i) { 480 if (scp->xoff > 0) { 481 draw_pos = scp->sc->adp->va_window + 482 line_width * (y + i); 483 draw_end = draw_pos + scp->xoff * 8 * pixel_size; 484 485 for (p = draw_pos; p < draw_end; p += 4) 486 writel(p, u32); 487 } 488 489 if (x > 0) { 490 draw_pos = scp->sc->adp->va_window + 491 line_width * (y + i) + 492 scp->xoff * 8 * pixel_size + 493 scp->xsize * 8 * pixel_size; 494 draw_end = draw_pos + x * 8 * pixel_size; 495 496 for (p = draw_pos; p < draw_end; p += 4) 497 writel(p, u32); 498 } 499 } 500 } 501 502 static void 503 vga_pxlborder_packed(scr_stat *scp, int color) 504 { 505 int i, x, y; 506 int line_width; 507 uint32_t u32; 508 vm_offset_t draw_pos, draw_end, p; 509 510 line_width = scp->sc->adp->va_line_width; 511 u32 = (color << 24) + (color << 16) + (color << 8) + color; 512 513 if (scp->yoff > 0) { 514 draw_pos = scp->sc->adp->va_window; 515 draw_end = draw_pos + line_width * scp->yoff * scp->font_size; 516 517 for (p = draw_pos; p < draw_end; p += 4) 518 writel(p, u32); 519 } 520 521 y = (scp->yoff + scp->ysize) * scp->font_size; 522 523 if (scp->ypixel > y) { 524 draw_pos = scp->sc->adp->va_window + line_width * y; 525 draw_end = draw_pos + line_width * (scp->ypixel - y); 526 527 for (p = draw_pos; p < draw_end; p += 4) 528 writel(p, u32); 529 } 530 531 y = scp->yoff * scp->font_size; 532 x = scp->xpixel / 8 - scp->xoff - scp->xsize; 533 534 for (i = 0; i < scp->ysize * scp->font_size; ++i) { 535 if (scp->xoff > 0) { 536 draw_pos = scp->sc->adp->va_window + 537 line_width * (y + i); 538 draw_end = draw_pos + scp->xoff * 8; 539 540 for (p = draw_pos; p < draw_end; p += 4) 541 writel(p, u32); 542 } 543 544 if (x > 0) { 545 draw_pos = scp->sc->adp->va_window + 546 line_width * (y + i) + scp->xoff * 8 + 547 scp->xsize * 8; 548 draw_end = draw_pos + x * 8; 549 550 for (p = draw_pos; p < draw_end; p += 4) 551 writel(p, u32); 552 } 553 } 554 } 555 556 static void 557 vga_pxlborder_planar(scr_stat *scp, int color) 558 { 559 vm_offset_t p; 560 int line_width; 561 int x; 562 int y; 563 int i; 564 565 lwkt_gettoken(&tty_token); 566 567 (*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color); 568 569 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 570 outw(GDCIDX, 0x0003); /* data rotate/function select */ 571 outw(GDCIDX, 0x0f01); /* set/reset enable */ 572 outw(GDCIDX, 0xff08); /* bit mask */ 573 outw(GDCIDX, (color << 8) | 0x00); /* set/reset */ 574 line_width = scp->sc->adp->va_line_width; 575 p = scp->sc->adp->va_window; 576 if (scp->yoff > 0) 577 bzero_io((void *)p, line_width*scp->yoff*scp->font_size); 578 y = (scp->yoff + scp->ysize)*scp->font_size; 579 if (scp->ypixel > y) 580 bzero_io((void *)(p + line_width*y), line_width*(scp->ypixel - y)); 581 y = scp->yoff*scp->font_size; 582 x = scp->xpixel/8 - scp->xoff - scp->xsize; 583 for (i = 0; i < scp->ysize*scp->font_size; ++i) { 584 if (scp->xoff > 0) 585 bzero_io((void *)(p + line_width*(y + i)), scp->xoff); 586 if (x > 0) 587 bzero_io((void *)(p + line_width*(y + i) 588 + scp->xoff + scp->xsize), x); 589 } 590 outw(GDCIDX, 0x0000); /* set/reset */ 591 outw(GDCIDX, 0x0001); /* set/reset enable */ 592 lwkt_reltoken(&tty_token); 593 } 594 595 static void 596 vga_vgadraw_direct(scr_stat *scp, int from, int count, int flip) 597 { 598 int line_width, pixel_size; 599 int a, i, j, k, l, pos; 600 uint32_t fg, bg, u32; 601 unsigned char *char_data; 602 vm_offset_t draw_pos, p; 603 604 line_width = scp->sc->adp->va_line_width; 605 pixel_size = scp->sc->adp->va_info.vi_pixel_size; 606 607 draw_pos = VIDEO_MEMORY_POS(scp, from, 8 * pixel_size); 608 609 if (from + count > scp->xsize * scp->ysize) 610 count = scp->xsize * scp->ysize - from; 611 612 for (i = from; count-- > 0; ++i) { 613 a = sc_vtb_geta(&scp->vtb, i); 614 615 if (flip) { 616 fg = scp->ega_palette[(((a & 0x7000) >> 4) | 617 (a & 0x0800)) >> 8]; 618 bg = scp->ega_palette[(((a & 0x8000) >> 4) | 619 (a & 0x0700)) >> 8]; 620 } else { 621 fg = scp->ega_palette[(a & 0x0f00) >> 8]; 622 bg = scp->ega_palette[(a & 0xf000) >> 12]; 623 } 624 625 p = draw_pos; 626 char_data = &(scp->font[sc_vtb_getc(&scp->vtb, i) * 627 scp->font_size]); 628 629 for (j = 0; j < scp->font_size; ++j, ++char_data) { 630 pos = 7; 631 632 for (k = 0; k < 2 * pixel_size; ++k) { 633 u32 = 0; 634 635 for (l = 0; l < 4 / pixel_size; ++l) { 636 u32 += (*char_data & (1 << pos--) ? 637 fg : bg) << (l * 8 * pixel_size); 638 } 639 640 writel(p, u32); 641 p += 4; 642 } 643 644 p += line_width - 8 * pixel_size; 645 } 646 647 draw_pos += 8 * pixel_size; 648 649 if ((i % scp->xsize) == scp->xsize - 1) 650 draw_pos += scp->xoff * 16 * pixel_size + 651 (scp->font_size - 1) * line_width; 652 } 653 } 654 655 static void 656 vga_vgadraw_packed(scr_stat *scp, int from, int count, int flip) 657 { 658 int line_width; 659 int a, i, j; 660 uint32_t fg, bg, u32; 661 unsigned char *char_data; 662 vm_offset_t draw_pos, p; 663 664 line_width = scp->sc->adp->va_line_width; 665 666 draw_pos = VIDEO_MEMORY_POS(scp, from, 8); 667 668 if (from + count > scp->xsize * scp->ysize) 669 count = scp->xsize * scp->ysize - from; 670 671 for (i = from; count-- > 0; ++i) { 672 a = sc_vtb_geta(&scp->vtb, i); 673 674 if (flip) { 675 fg = ((a & 0xf000) >> 4) >> 8; 676 bg = (a & 0x0f00) >> 8; 677 } else { 678 fg = (a & 0x0f00) >> 8; 679 bg = ((a & 0xf000) >> 4) >> 8; 680 } 681 682 p = draw_pos; 683 char_data = &(scp->font[sc_vtb_getc(&scp->vtb, i) * 684 scp->font_size]); 685 686 for (j = 0; j < scp->font_size; ++j, ++char_data) { 687 u32 = ((*char_data & 1 ? fg : bg) << 24) + 688 ((*char_data & 2 ? fg : bg) << 16) + 689 ((*char_data & 4 ? fg : bg) << 8) + 690 (*char_data & 8 ? fg : bg); 691 writel(p + 4, u32); 692 693 u32 = ((*char_data & 16 ? fg : bg) << 24) + 694 ((*char_data & 32 ? fg : bg) << 16) + 695 ((*char_data & 64 ? fg : bg) << 8) + 696 (*char_data & 128 ? fg : bg); 697 writel(p, u32); 698 699 p += line_width; 700 } 701 702 draw_pos += 8; 703 704 if ((i % scp->xsize) == scp->xsize - 1) 705 draw_pos += scp->xoff * 16 + 706 (scp->font_size - 1) * line_width; 707 } 708 } 709 710 static void 711 vga_vgadraw_planar(scr_stat *scp, int from, int count, int flip) 712 { 713 vm_offset_t d; 714 vm_offset_t e; 715 u_char *f; 716 u_short bg; 717 u_short col1, col2; 718 int line_width; 719 int i, j; 720 int a; 721 u_char c; 722 723 d = VIDEO_MEMORY_POS(scp, from, 1); 724 725 line_width = scp->sc->adp->va_line_width; 726 727 outw(GDCIDX, 0x0305); /* read mode 0, write mode 3 */ 728 outw(GDCIDX, 0x0003); /* data rotate/function select */ 729 outw(GDCIDX, 0x0f01); /* set/reset enable */ 730 outw(GDCIDX, 0xff08); /* bit mask */ 731 bg = -1; 732 if (from + count > scp->xsize*scp->ysize) 733 count = scp->xsize*scp->ysize - from; 734 for (i = from; count-- > 0; ++i) { 735 a = sc_vtb_geta(&scp->vtb, i); 736 if (flip) { 737 col1 = ((a & 0x7000) >> 4) | (a & 0x0800); 738 col2 = ((a & 0x8000) >> 4) | (a & 0x0700); 739 } else { 740 col1 = (a & 0x0f00); 741 col2 = (a & 0xf000) >> 4; 742 } 743 /* set background color in EGA/VGA latch */ 744 if (bg != col2) { 745 bg = col2; 746 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 747 outw(GDCIDX, bg | 0x00); /* set/reset */ 748 writeb(d, 0); 749 c = readb(d); /* set bg color in the latch */ 750 outw(GDCIDX, 0x0305); /* read mode 0, write mode 3 */ 751 } 752 /* foreground color */ 753 outw(GDCIDX, col1 | 0x00); /* set/reset */ 754 e = d; 755 f = &(scp->font[sc_vtb_getc(&scp->vtb, i)*scp->font_size]); 756 for (j = 0; j < scp->font_size; ++j, ++f) { 757 writeb(e, *f); 758 e += line_width; 759 } 760 ++d; 761 if ((i % scp->xsize) == scp->xsize - 1) 762 d += scp->xoff*2 763 + (scp->font_size - 1)*line_width; 764 } 765 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 766 outw(GDCIDX, 0x0000); /* set/reset */ 767 outw(GDCIDX, 0x0001); /* set/reset enable */ 768 } 769 770 static void 771 vga_pxlcursor_shape(scr_stat *scp, int base, int height, int blink) 772 { 773 if (base < 0 || base >= scp->font_size) 774 return; 775 /* the caller may set height <= 0 in order to disable the cursor */ 776 #if 0 777 scp->cursor_base = base; 778 scp->cursor_height = height; 779 #endif 780 } 781 782 static void 783 draw_pxlcursor_direct(scr_stat *scp, int at, int on, int flip) 784 { 785 int line_width, pixel_size, height; 786 int a, i, j, k, pos; 787 uint32_t fg, bg, u32; 788 unsigned char *char_data; 789 vm_offset_t draw_pos; 790 791 line_width = scp->sc->adp->va_line_width; 792 pixel_size = scp->sc->adp->va_info.vi_pixel_size; 793 794 draw_pos = VIDEO_MEMORY_POS(scp, at, 8 * pixel_size) + 795 (scp->font_size - scp->cursor_base - 1) * line_width; 796 797 a = sc_vtb_geta(&scp->vtb, at); 798 799 if (flip) { 800 fg = scp->ega_palette[((on) ? (a & 0x0f00) : 801 ((a & 0xf000) >> 4)) >> 8]; 802 bg = scp->ega_palette[((on) ? ((a & 0xf000) >> 4) : 803 (a & 0x0f00)) >> 8]; 804 } else { 805 fg = scp->ega_palette[((on) ? ((a & 0xf000) >> 4) : 806 (a & 0x0f00)) >> 8]; 807 bg = scp->ega_palette[((on) ? (a & 0x0f00) : 808 ((a & 0xf000) >> 4)) >> 8]; 809 } 810 811 char_data = &(scp->font[sc_vtb_getc(&scp->vtb, at) * scp->font_size + 812 scp->font_size - scp->cursor_base - 1]); 813 814 height = imin(scp->cursor_height, scp->font_size); 815 816 for (i = 0; i < height; ++i, --char_data) { 817 pos = 7; 818 819 for (j = 0; j < 2 * pixel_size; ++j) { 820 u32 = 0; 821 822 for (k = 0; k < 4 / pixel_size; ++k) { 823 u32 += (*char_data & (1 << pos--) ? 824 fg : bg) << (k * 8 * pixel_size); 825 } 826 827 writel(draw_pos, u32); 828 draw_pos += 4; 829 } 830 831 draw_pos -= line_width + 8 * pixel_size; 832 } 833 } 834 835 static void 836 draw_pxlcursor_packed(scr_stat *scp, int at, int on, int flip) 837 { 838 int line_width, height; 839 int a, i; 840 uint32_t fg, bg, u32; 841 unsigned char *char_data; 842 vm_offset_t draw_pos; 843 844 line_width = scp->sc->adp->va_line_width; 845 846 draw_pos = VIDEO_MEMORY_POS(scp, at, 8) + 847 (scp->font_size - scp->cursor_base - 1) * line_width; 848 849 a = sc_vtb_geta(&scp->vtb, at); 850 851 if (flip) { 852 fg = ((on) ? (a & 0x0f00) : ((a & 0xf000) >> 4)) >> 8; 853 bg = ((on) ? ((a & 0xf000) >> 4) : (a & 0x0f00)) >> 8; 854 } else { 855 fg = ((on) ? ((a & 0xf000) >> 4) : (a & 0x0f00)) >> 8; 856 bg = ((on) ? (a & 0x0f00) : ((a & 0xf000) >> 4)) >> 8; 857 } 858 859 char_data = &(scp->font[sc_vtb_getc(&scp->vtb, at) * scp->font_size + 860 scp->font_size - scp->cursor_base - 1]); 861 862 height = imin(scp->cursor_height, scp->font_size); 863 864 for (i = 0; i < height; ++i, --char_data) { 865 u32 = ((*char_data & 1 ? fg : bg) << 24) + 866 ((*char_data & 2 ? fg : bg) << 16) + 867 ((*char_data & 4 ? fg : bg) << 8) + 868 (*char_data & 8 ? fg : bg); 869 writel(draw_pos + 4, u32); 870 871 u32 = ((*char_data & 16 ? fg : bg) << 24) + 872 ((*char_data & 32 ? fg : bg) << 16) + 873 ((*char_data & 64 ? fg : bg) << 8) + 874 (*char_data & 128 ? fg : bg); 875 writel(draw_pos, u32); 876 877 draw_pos -= line_width; 878 } 879 } 880 881 static void 882 draw_pxlcursor_planar(scr_stat *scp, int at, int on, int flip) 883 { 884 vm_offset_t d; 885 u_char *f; 886 int line_width; 887 int height; 888 int col; 889 int a; 890 int i; 891 u_char c; 892 893 line_width = scp->sc->adp->va_line_width; 894 895 d = VIDEO_MEMORY_POS(scp, at, 1) + 896 (scp->font_size - scp->cursor_base - 1) * line_width; 897 898 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 899 outw(GDCIDX, 0x0003); /* data rotate/function select */ 900 outw(GDCIDX, 0x0f01); /* set/reset enable */ 901 /* set background color in EGA/VGA latch */ 902 a = sc_vtb_geta(&scp->vtb, at); 903 if (flip) 904 col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00); 905 else 906 col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4); 907 outw(GDCIDX, col | 0x00); /* set/reset */ 908 outw(GDCIDX, 0xff08); /* bit mask */ 909 writeb(d, 0); 910 c = readb(d); /* set bg color in the latch */ 911 /* foreground color */ 912 if (flip) 913 col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4); 914 else 915 col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00); 916 outw(GDCIDX, col | 0x00); /* set/reset */ 917 f = &(scp->font[sc_vtb_getc(&scp->vtb, at)*scp->font_size 918 + scp->font_size - scp->cursor_base - 1]); 919 height = imin(scp->cursor_height, scp->font_size); 920 for (i = 0; i < height; ++i, --f) { 921 outw(GDCIDX, (*f << 8) | 0x08); /* bit mask */ 922 writeb(d, 0); 923 d -= line_width; 924 } 925 outw(GDCIDX, 0x0000); /* set/reset */ 926 outw(GDCIDX, 0x0001); /* set/reset enable */ 927 outw(GDCIDX, 0xff08); /* bit mask */ 928 } 929 930 static int pxlblinkrate = 0; 931 932 static void 933 vga_pxlcursor_direct(scr_stat *scp, int at, int blink, int on, int flip) 934 { 935 if (scp->cursor_height <= 0) /* the text cursor is disabled */ 936 return; 937 938 if (on) { 939 if (!blink) { 940 scp->status |= VR_CURSOR_ON; 941 draw_pxlcursor_direct(scp, at, on, flip); 942 } else if (++pxlblinkrate & 4) { 943 pxlblinkrate = 0; 944 scp->status ^= VR_CURSOR_ON; 945 draw_pxlcursor_direct(scp, at, 946 scp->status & VR_CURSOR_ON, 947 flip); 948 } 949 } else { 950 if (scp->status & VR_CURSOR_ON) 951 draw_pxlcursor_direct(scp, at, on, flip); 952 scp->status &= ~VR_CURSOR_ON; 953 } 954 if (blink) 955 scp->status |= VR_CURSOR_BLINK; 956 else 957 scp->status &= ~VR_CURSOR_BLINK; 958 } 959 960 static void 961 vga_pxlcursor_packed(scr_stat *scp, int at, int blink, int on, int flip) 962 { 963 if (scp->cursor_height <= 0) /* the text cursor is disabled */ 964 return; 965 966 if (on) { 967 if (!blink) { 968 scp->status |= VR_CURSOR_ON; 969 draw_pxlcursor_packed(scp, at, on, flip); 970 } else if (++pxlblinkrate & 4) { 971 pxlblinkrate = 0; 972 scp->status ^= VR_CURSOR_ON; 973 draw_pxlcursor_packed(scp, at, 974 scp->status & VR_CURSOR_ON, 975 flip); 976 } 977 } else { 978 if (scp->status & VR_CURSOR_ON) 979 draw_pxlcursor_packed(scp, at, on, flip); 980 scp->status &= ~VR_CURSOR_ON; 981 } 982 if (blink) 983 scp->status |= VR_CURSOR_BLINK; 984 else 985 scp->status &= ~VR_CURSOR_BLINK; 986 } 987 988 static void 989 vga_pxlcursor_planar(scr_stat *scp, int at, int blink, int on, int flip) 990 { 991 if (scp->cursor_height <= 0) /* the text cursor is disabled */ 992 return; 993 994 if (on) { 995 if (!blink) { 996 scp->status |= VR_CURSOR_ON; 997 draw_pxlcursor_planar(scp, at, on, flip); 998 } else if (++pxlblinkrate & 4) { 999 pxlblinkrate = 0; 1000 scp->status ^= VR_CURSOR_ON; 1001 draw_pxlcursor_planar(scp, at, 1002 scp->status & VR_CURSOR_ON, 1003 flip); 1004 } 1005 } else { 1006 if (scp->status & VR_CURSOR_ON) 1007 draw_pxlcursor_planar(scp, at, on, flip); 1008 scp->status &= ~VR_CURSOR_ON; 1009 } 1010 if (blink) 1011 scp->status |= VR_CURSOR_BLINK; 1012 else 1013 scp->status &= ~VR_CURSOR_BLINK; 1014 } 1015 1016 static void 1017 vga_pxlblink_direct(scr_stat *scp, int at, int flip) 1018 { 1019 if (!(scp->status & VR_CURSOR_BLINK)) 1020 return; 1021 if (!(++pxlblinkrate & 4)) 1022 return; 1023 pxlblinkrate = 0; 1024 scp->status ^= VR_CURSOR_ON; 1025 draw_pxlcursor_direct(scp, at, scp->status & VR_CURSOR_ON, flip); 1026 } 1027 1028 static void 1029 vga_pxlblink_packed(scr_stat *scp, int at, int flip) 1030 { 1031 if (!(scp->status & VR_CURSOR_BLINK)) 1032 return; 1033 if (!(++pxlblinkrate & 4)) 1034 return; 1035 pxlblinkrate = 0; 1036 scp->status ^= VR_CURSOR_ON; 1037 draw_pxlcursor_packed(scp, at, scp->status & VR_CURSOR_ON, flip); 1038 } 1039 1040 static void 1041 vga_pxlblink_planar(scr_stat *scp, int at, int flip) 1042 { 1043 if (!(scp->status & VR_CURSOR_BLINK)) 1044 return; 1045 if (!(++pxlblinkrate & 4)) 1046 return; 1047 pxlblinkrate = 0; 1048 scp->status ^= VR_CURSOR_ON; 1049 draw_pxlcursor_planar(scp, at, scp->status & VR_CURSOR_ON, flip); 1050 } 1051 1052 #ifndef SC_NO_CUTPASTE 1053 1054 static void 1055 draw_pxlmouse_direct(scr_stat *scp, int x, int y) 1056 { 1057 int line_width, pixel_size; 1058 int xend, yend; 1059 int i, j; 1060 vm_offset_t draw_pos; 1061 1062 line_width = scp->sc->adp->va_line_width; 1063 pixel_size = scp->sc->adp->va_info.vi_pixel_size; 1064 1065 xend = imin(x + 8, 8 * (scp->xoff + scp->xsize)); 1066 yend = imin(y + 16, scp->font_size * (scp->yoff + scp->ysize)); 1067 1068 draw_pos = scp->sc->adp->va_window + y * line_width + x * pixel_size; 1069 1070 for (i = 0; i < (yend - y); i++) { 1071 for (j = (xend - x - 1); j >= 0; j--) { 1072 switch (scp->sc->adp->va_info.vi_depth) { 1073 case 32: 1074 if (mouse_or_mask[i] & 1 << (15 - j)) 1075 writel(draw_pos + 4 * j, 1076 scp->ega_palette[15]); 1077 else if (mouse_and_mask[i] & 1 << (15 - j)) 1078 writel(draw_pos + 4 * j, 1079 scp->ega_palette[0]); 1080 break; 1081 case 16: 1082 /* FALLTHROUGH */ 1083 case 15: 1084 if (mouse_or_mask[i] & 1 << (15 - j)) 1085 writew(draw_pos + 2 * j, 1086 scp->ega_palette[15]); 1087 else if (mouse_and_mask[i] & 1 << (15 - j)) 1088 writew(draw_pos + 2 * j, 1089 scp->ega_palette[0]); 1090 break; 1091 } 1092 } 1093 1094 draw_pos += line_width; 1095 } 1096 } 1097 1098 static void 1099 draw_pxlmouse_packed(scr_stat *scp, int x, int y) 1100 { 1101 int line_width; 1102 int xend, yend; 1103 int i, j; 1104 vm_offset_t draw_pos; 1105 1106 line_width = scp->sc->adp->va_line_width; 1107 1108 xend = imin(8 * (scp->xoff + scp->xsize), imin(x + 16, scp->xpixel)); 1109 yend = imin(scp->font_size * (scp->yoff + scp->ysize), 1110 imin(y + 16, scp->ypixel)); 1111 1112 draw_pos = scp->sc->adp->va_window + y * line_width + x; 1113 1114 for (i = 0; i < (yend - y); i++) { 1115 for (j = (xend - x - 1); j >= 0; j--) { 1116 if (mouse_or_mask[i] & 1 << (15 - j)) 1117 writeb(draw_pos + j, 15); 1118 else if (mouse_and_mask[i] & 1 << (15 - j)) 1119 writeb(draw_pos + j, 0); 1120 } 1121 1122 draw_pos += line_width; 1123 } 1124 } 1125 1126 static void 1127 draw_pxlmouse_planar(scr_stat *scp, int x, int y) 1128 { 1129 vm_offset_t p; 1130 int line_width; 1131 int xoff; 1132 int ymax; 1133 u_short m; 1134 int i, j; 1135 1136 line_width = scp->sc->adp->va_line_width; 1137 xoff = (x - scp->xoff*8)%8; 1138 ymax = imin(y + 16, scp->font_size * (scp->yoff + scp->ysize)); 1139 1140 outw(GDCIDX, 0x0805); /* read mode 1, write mode 0 */ 1141 outw(GDCIDX, 0x0001); /* set/reset enable */ 1142 outw(GDCIDX, 0x0002); /* color compare */ 1143 outw(GDCIDX, 0x0007); /* color don't care */ 1144 outw(GDCIDX, 0xff08); /* bit mask */ 1145 outw(GDCIDX, 0x0803); /* data rotate/function select (and) */ 1146 p = scp->sc->adp->va_window + line_width*y + x/8; 1147 if (x < 8 * (scp->xoff + scp->xsize) - 8) { 1148 for (i = y, j = 0; i < ymax; ++i, ++j) { 1149 m = ~(mouse_and_mask[j] >> xoff); 1150 *(u_char *)p &= m >> 8; 1151 *(u_char *)(p + 1) &= m; 1152 p += line_width; 1153 } 1154 } else { 1155 xoff += 8; 1156 for (i = y, j = 0; i < ymax; ++i, ++j) { 1157 m = ~(mouse_and_mask[j] >> xoff); 1158 *(u_char *)p &= m; 1159 p += line_width; 1160 } 1161 } 1162 outw(GDCIDX, 0x1003); /* data rotate/function select (or) */ 1163 p = scp->sc->adp->va_window + line_width*y + x/8; 1164 if (x < 8 * (scp->xoff + scp->xsize) - 8) { 1165 for (i = y, j = 0; i < ymax; ++i, ++j) { 1166 m = mouse_or_mask[j] >> xoff; 1167 *(u_char *)p &= m >> 8; 1168 *(u_char *)(p + 1) &= m; 1169 p += line_width; 1170 } 1171 } else { 1172 for (i = y, j = 0; i < ymax; ++i, ++j) { 1173 m = mouse_or_mask[j] >> xoff; 1174 *(u_char *)p &= m; 1175 p += line_width; 1176 } 1177 } 1178 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 1179 outw(GDCIDX, 0x0003); /* data rotate/function select */ 1180 } 1181 1182 static void 1183 remove_pxlmouse(scr_stat *scp, int x, int y) 1184 { 1185 int col, row; 1186 int pos; 1187 int i; 1188 1189 /* erase the mouse cursor image */ 1190 col = x/8 - scp->xoff; 1191 row = y/scp->font_size - scp->yoff; 1192 pos = row*scp->xsize + col; 1193 i = (col < scp->xsize - 1) ? 2 : 1; 1194 (*scp->rndr->draw)(scp, pos, i, FALSE); 1195 if (row < scp->ysize - 1) 1196 (*scp->rndr->draw)(scp, pos + scp->xsize, i, FALSE); 1197 } 1198 1199 static void 1200 vga_pxlmouse_direct(scr_stat *scp, int x, int y, int on) 1201 { 1202 if (on) 1203 draw_pxlmouse_direct(scp, x, y); 1204 else 1205 remove_pxlmouse(scp, x, y); 1206 } 1207 1208 static void 1209 vga_pxlmouse_packed(scr_stat *scp, int x, int y, int on) 1210 { 1211 if (on) 1212 draw_pxlmouse_packed(scp, x, y); 1213 else 1214 remove_pxlmouse(scp, x, y); 1215 } 1216 1217 static void 1218 vga_pxlmouse_planar(scr_stat *scp, int x, int y, int on) 1219 { 1220 if (on) 1221 draw_pxlmouse_planar(scp, x, y); 1222 else 1223 remove_pxlmouse(scp, x, y); 1224 } 1225 1226 #endif /* SC_NO_CUTPASTE */ 1227 #endif /* SC_PIXEL_MODE */ 1228 1229 #ifndef SC_NO_MODE_CHANGE 1230 1231 /* graphics mode renderer */ 1232 1233 static void 1234 vga_grborder(scr_stat *scp, int color) 1235 { 1236 lwkt_gettoken(&tty_token); 1237 (*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color); 1238 lwkt_reltoken(&tty_token); 1239 } 1240 1241 #endif 1242