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