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 1 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 lwkt_gettoken(&tty_token); 181 (*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color); 182 lwkt_reltoken(&tty_token); 183 } 184 185 static void 186 vga_txtdraw(scr_stat *scp, int from, int count, int flip) 187 { 188 uint16_t *p; 189 int c; 190 int a; 191 192 if (from + count > scp->xsize*scp->ysize) 193 count = scp->xsize*scp->ysize - from; 194 195 if (flip) { 196 for (p = scp->scr.vtb_buffer + from; count-- > 0; ++from) { 197 c = sc_vtb_getc(&scp->vtb, from); 198 a = sc_vtb_geta(&scp->vtb, from); 199 a = (a & 0x8800) | ((a & 0x7000) >> 4) 200 | ((a & 0x0700) << 4); 201 p = sc_vtb_putchar(&scp->scr, p, c, a); 202 } 203 } else { 204 sc_vtb_copy(&scp->vtb, from, &scp->scr, from, count); 205 } 206 } 207 208 static void 209 vga_txtcursor_shape(scr_stat *scp, int base, int height, int blink) 210 { 211 if (base < 0 || base >= scp->font_size) 212 return; 213 lwkt_gettoken(&tty_token); 214 /* the caller may set height <= 0 in order to disable the cursor */ 215 #if 0 216 scp->cursor_base = base; 217 scp->cursor_height = height; 218 #endif 219 (*vidsw[scp->sc->adapter]->set_hw_cursor_shape)(scp->sc->adp, 220 base, height, 221 scp->font_size, blink); 222 lwkt_reltoken(&tty_token); 223 } 224 225 static void 226 draw_txtcharcursor(scr_stat *scp, int at, u_short c, u_short a, int flip) 227 { 228 sc_softc_t *sc; 229 230 sc = scp->sc; 231 scp->cursor_saveunder_char = c; 232 scp->cursor_saveunder_attr = a; 233 234 //lwkt_gettoken(&tty_token); 235 #ifndef SC_NO_FONT_LOADING 236 if (sc->flags & SC_CHAR_CURSOR) { 237 unsigned char *font; 238 int h; 239 int i; 240 241 if (scp->font_size < 14) { 242 font = sc->font_8; 243 h = 8; 244 } else if (scp->font_size >= 16) { 245 font = sc->font_16; 246 h = 16; 247 } else { 248 font = sc->font_14; 249 h = 14; 250 } 251 if (scp->cursor_base >= h) { 252 lwkt_reltoken(&tty_token); 253 return; 254 } 255 if (flip) 256 a = (a & 0x8800) 257 | ((a & 0x7000) >> 4) | ((a & 0x0700) << 4); 258 bcopy(font + c*h, font + sc->cursor_char*h, h); 259 font = font + sc->cursor_char*h; 260 for (i = imax(h - scp->cursor_base - scp->cursor_height, 0); 261 i < h - scp->cursor_base; ++i) { 262 font[i] ^= 0xff; 263 } 264 sc->font_loading_in_progress = TRUE; 265 /* XXX */ 266 (*vidsw[sc->adapter]->load_font)(sc->adp, 0, h, font, 267 sc->cursor_char, 1); 268 sc->font_loading_in_progress = FALSE; 269 sc_vtb_putc(&scp->scr, at, sc->cursor_char, a); 270 } else 271 #endif /* SC_NO_FONT_LOADING */ 272 { 273 if ((a & 0x7000) == 0x7000) { 274 a &= 0x8f00; 275 if ((a & 0x0700) == 0) 276 a |= 0x0700; 277 } else { 278 a |= 0x7000; 279 if ((a & 0x0700) == 0x0700) 280 a &= 0xf000; 281 } 282 if (flip) 283 a = (a & 0x8800) 284 | ((a & 0x7000) >> 4) | ((a & 0x0700) << 4); 285 sc_vtb_putc(&scp->scr, at, c, a); 286 } 287 //lwkt_reltoken(&tty_token); 288 } 289 290 static void 291 vga_txtcursor(scr_stat *scp, int at, int blink, int on, int flip) 292 { 293 video_adapter_t *adp; 294 int cursor_attr; 295 296 if (scp->cursor_height <= 0) /* the text cursor is disabled */ 297 return; 298 299 //lwkt_gettoken(&tty_token); 300 adp = scp->sc->adp; 301 if (blink) { 302 scp->status |= VR_CURSOR_BLINK; 303 if (on) { 304 scp->status |= VR_CURSOR_ON; 305 (*vidsw[adp->va_index]->set_hw_cursor)(adp, 306 at%scp->xsize, 307 at/scp->xsize); 308 } else { 309 if (scp->status & VR_CURSOR_ON) 310 (*vidsw[adp->va_index]->set_hw_cursor)(adp, 311 -1, -1); 312 scp->status &= ~VR_CURSOR_ON; 313 } 314 } else { 315 scp->status &= ~VR_CURSOR_BLINK; 316 if (on) { 317 scp->status |= VR_CURSOR_ON; 318 draw_txtcharcursor(scp, at, 319 sc_vtb_getc(&scp->scr, at), 320 sc_vtb_geta(&scp->scr, at), 321 flip); 322 } else { 323 cursor_attr = scp->cursor_saveunder_attr; 324 if (flip) 325 cursor_attr = (cursor_attr & 0x8800) 326 | ((cursor_attr & 0x7000) >> 4) 327 | ((cursor_attr & 0x0700) << 4); 328 if (scp->status & VR_CURSOR_ON) 329 sc_vtb_putc(&scp->scr, at, 330 scp->cursor_saveunder_char, 331 cursor_attr); 332 scp->status &= ~VR_CURSOR_ON; 333 } 334 } 335 //lwkt_reltoken(&tty_token); 336 } 337 338 static void 339 vga_txtblink(scr_stat *scp, int at, int flip) 340 { 341 } 342 343 #ifndef SC_NO_CUTPASTE 344 345 static void 346 draw_txtmouse(scr_stat *scp, int x, int y) 347 { 348 #ifndef SC_ALT_MOUSE_IMAGE 349 if (ISMOUSEAVAIL(scp->sc->adp->va_flags)) { 350 u_char font_buf[128]; 351 u_short cursor[32]; 352 u_char c; 353 int pos; 354 int xoffset, yoffset; 355 int i; 356 357 lwkt_gettoken(&tty_token); 358 359 /* prepare mousepointer char's bitmaps */ 360 pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff; 361 bcopy(scp->font + sc_vtb_getc(&scp->scr, pos)*scp->font_size, 362 &font_buf[0], scp->font_size); 363 bcopy(scp->font + sc_vtb_getc(&scp->scr, pos + 1)*scp->font_size, 364 &font_buf[32], scp->font_size); 365 bcopy(scp->font 366 + sc_vtb_getc(&scp->scr, pos + scp->xsize)*scp->font_size, 367 &font_buf[64], scp->font_size); 368 bcopy(scp->font 369 + sc_vtb_getc(&scp->scr, pos + scp->xsize + 1)*scp->font_size, 370 &font_buf[96], scp->font_size); 371 for (i = 0; i < scp->font_size; ++i) { 372 cursor[i] = font_buf[i]<<8 | font_buf[i+32]; 373 cursor[i + scp->font_size] = font_buf[i+64]<<8 | font_buf[i+96]; 374 } 375 376 /* now and-or in the mousepointer image */ 377 xoffset = x%8; 378 yoffset = y%scp->font_size; 379 for (i = 0; i < 16; ++i) { 380 cursor[i + yoffset] = 381 (cursor[i + yoffset] & ~(mouse_and_mask[i] >> xoffset)) 382 | (mouse_or_mask[i] >> xoffset); 383 } 384 for (i = 0; i < scp->font_size; ++i) { 385 font_buf[i] = (cursor[i] & 0xff00) >> 8; 386 font_buf[i + 32] = cursor[i] & 0xff; 387 font_buf[i + 64] = (cursor[i + scp->font_size] & 0xff00) >> 8; 388 font_buf[i + 96] = cursor[i + scp->font_size] & 0xff; 389 } 390 391 #if 1 392 /* wait for vertical retrace to avoid jitter on some videocards */ 393 while (!(inb(CRTC + 6) & 0x08)) /* idle */ ; 394 #endif 395 c = scp->sc->mouse_char; 396 (*vidsw[scp->sc->adapter]->load_font)(scp->sc->adp, 0, 32, font_buf, 397 c, 4); 398 399 sc_vtb_putc(&scp->scr, pos, c, sc_vtb_geta(&scp->scr, pos)); 400 /* FIXME: may be out of range! */ 401 sc_vtb_putc(&scp->scr, pos + scp->xsize, c + 2, 402 sc_vtb_geta(&scp->scr, pos + scp->xsize)); 403 if (x < (scp->xsize - 1)*8) { 404 sc_vtb_putc(&scp->scr, pos + 1, c + 1, 405 sc_vtb_geta(&scp->scr, pos + 1)); 406 sc_vtb_putc(&scp->scr, pos + scp->xsize + 1, c + 3, 407 sc_vtb_geta(&scp->scr, pos + scp->xsize + 1)); 408 } 409 } else 410 #endif /* SC_ALT_MOUSE_IMAGE */ 411 { 412 /* Red, magenta and brown are mapped to green to to keep it readable */ 413 static const int col_conv[16] = { 414 6, 6, 6, 6, 2, 2, 2, 6, 14, 14, 14, 14, 10, 10, 10, 14 415 }; 416 int pos; 417 int color; 418 int a; 419 420 pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff; 421 a = sc_vtb_geta(&scp->scr, pos); 422 if (scp->sc->adp->va_flags & V_ADP_COLOR) 423 color = (col_conv[(a & 0xf000) >> 12] << 12) 424 | ((a & 0x0f00) | 0x0800); 425 else 426 color = ((a & 0xf000) >> 4) | ((a & 0x0f00) << 4); 427 sc_vtb_putc(&scp->scr, pos, sc_vtb_getc(&scp->scr, pos), color); 428 } 429 430 lwkt_reltoken(&tty_token); 431 } 432 433 static void 434 remove_txtmouse(scr_stat *scp, int x, int y) 435 { 436 } 437 438 static void 439 vga_txtmouse(scr_stat *scp, int x, int y, int on) 440 { 441 if (on) 442 draw_txtmouse(scp, x, y); 443 else 444 remove_txtmouse(scp, x, y); 445 } 446 447 #endif /* SC_NO_CUTPASTE */ 448 449 #ifdef SC_PIXEL_MODE 450 451 /* pixel (raster text) mode renderer */ 452 453 static void 454 vga_pxlborder_direct(scr_stat *scp, int color) 455 { 456 int i, x, y; 457 int line_width, pixel_size; 458 uint32_t u32 = 0; 459 vm_offset_t draw_pos, draw_end, p; 460 461 line_width = scp->sc->adp->va_line_width; 462 pixel_size = scp->sc->adp->va_info.vi_pixel_size; 463 464 for (i = 0; i < 4 / pixel_size; ++i) 465 u32 += scp->ega_palette[color] << (i * 8 * pixel_size); 466 467 if (scp->yoff > 0) { 468 draw_pos = scp->sc->adp->va_window; 469 draw_end = draw_pos + line_width * scp->yoff * scp->font_size; 470 471 for (p = draw_pos; p < draw_end; p += 4) 472 writel(p, u32); 473 } 474 475 y = (scp->yoff + scp->ysize) * scp->font_size; 476 477 if (scp->ypixel > y) { 478 draw_pos = scp->sc->adp->va_window + line_width * y; 479 draw_end = draw_pos + line_width * (scp->ypixel - y); 480 481 for (p = draw_pos; p < draw_end; p += 4) 482 writel(p, u32); 483 } 484 485 y = scp->yoff * scp->font_size; 486 x = scp->xpixel / 8 - scp->xoff - scp->xsize; 487 488 for (i = 0; i < scp->ysize * scp->font_size; ++i) { 489 if (scp->xoff > 0) { 490 draw_pos = scp->sc->adp->va_window + 491 line_width * (y + i); 492 draw_end = draw_pos + scp->xoff * 8 * pixel_size; 493 494 for (p = draw_pos; p < draw_end; p += 4) 495 writel(p, u32); 496 } 497 498 if (x > 0) { 499 draw_pos = scp->sc->adp->va_window + 500 line_width * (y + i) + 501 scp->xoff * 8 * pixel_size + 502 scp->xsize * 8 * pixel_size; 503 draw_end = draw_pos + x * 8 * pixel_size; 504 505 for (p = draw_pos; p < draw_end; p += 4) 506 writel(p, u32); 507 } 508 } 509 } 510 511 static void 512 vga_pxlborder_packed(scr_stat *scp, int color) 513 { 514 int i, x, y; 515 int line_width; 516 uint32_t u32; 517 vm_offset_t draw_pos, draw_end, p; 518 519 line_width = scp->sc->adp->va_line_width; 520 u32 = (color << 24) + (color << 16) + (color << 8) + color; 521 522 if (scp->yoff > 0) { 523 draw_pos = scp->sc->adp->va_window; 524 draw_end = draw_pos + line_width * scp->yoff * scp->font_size; 525 526 for (p = draw_pos; p < draw_end; p += 4) 527 writel(p, u32); 528 } 529 530 y = (scp->yoff + scp->ysize) * scp->font_size; 531 532 if (scp->ypixel > y) { 533 draw_pos = scp->sc->adp->va_window + line_width * y; 534 draw_end = draw_pos + line_width * (scp->ypixel - y); 535 536 for (p = draw_pos; p < draw_end; p += 4) 537 writel(p, u32); 538 } 539 540 y = scp->yoff * scp->font_size; 541 x = scp->xpixel / 8 - scp->xoff - scp->xsize; 542 543 for (i = 0; i < scp->ysize * scp->font_size; ++i) { 544 if (scp->xoff > 0) { 545 draw_pos = scp->sc->adp->va_window + 546 line_width * (y + i); 547 draw_end = draw_pos + scp->xoff * 8; 548 549 for (p = draw_pos; p < draw_end; p += 4) 550 writel(p, u32); 551 } 552 553 if (x > 0) { 554 draw_pos = scp->sc->adp->va_window + 555 line_width * (y + i) + scp->xoff * 8 + 556 scp->xsize * 8; 557 draw_end = draw_pos + x * 8; 558 559 for (p = draw_pos; p < draw_end; p += 4) 560 writel(p, u32); 561 } 562 } 563 } 564 565 static void 566 vga_pxlborder_planar(scr_stat *scp, int color) 567 { 568 vm_offset_t p; 569 int line_width; 570 int x; 571 int y; 572 int i; 573 574 lwkt_gettoken(&tty_token); 575 576 (*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color); 577 578 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 579 outw(GDCIDX, 0x0003); /* data rotate/function select */ 580 outw(GDCIDX, 0x0f01); /* set/reset enable */ 581 outw(GDCIDX, 0xff08); /* bit mask */ 582 outw(GDCIDX, (color << 8) | 0x00); /* set/reset */ 583 line_width = scp->sc->adp->va_line_width; 584 p = scp->sc->adp->va_window; 585 if (scp->yoff > 0) 586 bzero_io((void *)p, line_width*scp->yoff*scp->font_size); 587 y = (scp->yoff + scp->ysize)*scp->font_size; 588 if (scp->ypixel > y) 589 bzero_io((void *)(p + line_width*y), line_width*(scp->ypixel - y)); 590 y = scp->yoff*scp->font_size; 591 x = scp->xpixel/8 - scp->xoff - scp->xsize; 592 for (i = 0; i < scp->ysize*scp->font_size; ++i) { 593 if (scp->xoff > 0) 594 bzero_io((void *)(p + line_width*(y + i)), scp->xoff); 595 if (x > 0) 596 bzero_io((void *)(p + line_width*(y + i) 597 + scp->xoff + scp->xsize), x); 598 } 599 outw(GDCIDX, 0x0000); /* set/reset */ 600 outw(GDCIDX, 0x0001); /* set/reset enable */ 601 lwkt_reltoken(&tty_token); 602 } 603 604 static void 605 vga_vgadraw_direct(scr_stat *scp, int from, int count, int flip) 606 { 607 int line_width, pixel_size; 608 int a, i, j, k, l, pos; 609 uint32_t fg, bg, u32; 610 unsigned char *char_data; 611 vm_offset_t draw_pos, p; 612 613 line_width = scp->sc->adp->va_line_width; 614 pixel_size = scp->sc->adp->va_info.vi_pixel_size; 615 616 draw_pos = VIDEO_MEMORY_POS(scp, from, 8 * pixel_size); 617 618 if (from + count > scp->xsize * scp->ysize) 619 count = scp->xsize * scp->ysize - from; 620 621 for (i = from; count-- > 0; ++i) { 622 a = sc_vtb_geta(&scp->vtb, i); 623 624 if (flip) { 625 fg = scp->ega_palette[(((a & 0x7000) >> 4) | 626 (a & 0x0800)) >> 8]; 627 bg = scp->ega_palette[(((a & 0x8000) >> 4) | 628 (a & 0x0700)) >> 8]; 629 } else { 630 fg = scp->ega_palette[(a & 0x0f00) >> 8]; 631 bg = scp->ega_palette[(a & 0xf000) >> 12]; 632 } 633 634 p = draw_pos; 635 char_data = &(scp->font[sc_vtb_getc(&scp->vtb, i) * 636 scp->font_size]); 637 638 for (j = 0; j < scp->font_size; ++j, ++char_data) { 639 pos = 7; 640 641 for (k = 0; k < 2 * pixel_size; ++k) { 642 u32 = 0; 643 644 for (l = 0; l < 4 / pixel_size; ++l) { 645 u32 += (*char_data & (1 << pos--) ? 646 fg : bg) << (l * 8 * pixel_size); 647 } 648 649 writel(p, u32); 650 p += 4; 651 } 652 653 p += line_width - 8 * pixel_size; 654 } 655 656 draw_pos += 8 * pixel_size; 657 658 if ((i % scp->xsize) == scp->xsize - 1) 659 draw_pos += scp->xoff * 16 * pixel_size + 660 (scp->font_size - 1) * line_width; 661 } 662 } 663 664 static void 665 vga_vgadraw_packed(scr_stat *scp, int from, int count, int flip) 666 { 667 int line_width; 668 int a, i, j; 669 uint32_t fg, bg, u32; 670 unsigned char *char_data; 671 vm_offset_t draw_pos, p; 672 673 line_width = scp->sc->adp->va_line_width; 674 675 draw_pos = VIDEO_MEMORY_POS(scp, from, 8); 676 677 if (from + count > scp->xsize * scp->ysize) 678 count = scp->xsize * scp->ysize - from; 679 680 for (i = from; count-- > 0; ++i) { 681 a = sc_vtb_geta(&scp->vtb, i); 682 683 if (flip) { 684 fg = ((a & 0xf000) >> 4) >> 8; 685 bg = (a & 0x0f00) >> 8; 686 } else { 687 fg = (a & 0x0f00) >> 8; 688 bg = ((a & 0xf000) >> 4) >> 8; 689 } 690 691 p = draw_pos; 692 char_data = &(scp->font[sc_vtb_getc(&scp->vtb, i) * 693 scp->font_size]); 694 695 for (j = 0; j < scp->font_size; ++j, ++char_data) { 696 u32 = ((*char_data & 1 ? fg : bg) << 24) + 697 ((*char_data & 2 ? fg : bg) << 16) + 698 ((*char_data & 4 ? fg : bg) << 8) + 699 (*char_data & 8 ? fg : bg); 700 writel(p + 4, u32); 701 702 u32 = ((*char_data & 16 ? fg : bg) << 24) + 703 ((*char_data & 32 ? fg : bg) << 16) + 704 ((*char_data & 64 ? fg : bg) << 8) + 705 (*char_data & 128 ? fg : bg); 706 writel(p, u32); 707 708 p += line_width; 709 } 710 711 draw_pos += 8; 712 713 if ((i % scp->xsize) == scp->xsize - 1) 714 draw_pos += scp->xoff * 16 + 715 (scp->font_size - 1) * line_width; 716 } 717 } 718 719 static void 720 vga_vgadraw_planar(scr_stat *scp, int from, int count, int flip) 721 { 722 vm_offset_t d; 723 vm_offset_t e; 724 u_char *f; 725 u_short bg; 726 u_short col1, col2; 727 int line_width; 728 int i, j; 729 int a; 730 u_char c; 731 732 d = VIDEO_MEMORY_POS(scp, from, 1); 733 734 line_width = scp->sc->adp->va_line_width; 735 736 outw(GDCIDX, 0x0305); /* read mode 0, write mode 3 */ 737 outw(GDCIDX, 0x0003); /* data rotate/function select */ 738 outw(GDCIDX, 0x0f01); /* set/reset enable */ 739 outw(GDCIDX, 0xff08); /* bit mask */ 740 bg = -1; 741 if (from + count > scp->xsize*scp->ysize) 742 count = scp->xsize*scp->ysize - from; 743 for (i = from; count-- > 0; ++i) { 744 a = sc_vtb_geta(&scp->vtb, i); 745 if (flip) { 746 col1 = ((a & 0x7000) >> 4) | (a & 0x0800); 747 col2 = ((a & 0x8000) >> 4) | (a & 0x0700); 748 } else { 749 col1 = (a & 0x0f00); 750 col2 = (a & 0xf000) >> 4; 751 } 752 /* set background color in EGA/VGA latch */ 753 if (bg != col2) { 754 bg = col2; 755 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 756 outw(GDCIDX, bg | 0x00); /* set/reset */ 757 writeb(d, 0); 758 c = readb(d); /* set bg color in the latch */ 759 outw(GDCIDX, 0x0305); /* read mode 0, write mode 3 */ 760 } 761 /* foreground color */ 762 outw(GDCIDX, col1 | 0x00); /* set/reset */ 763 e = d; 764 f = &(scp->font[sc_vtb_getc(&scp->vtb, i)*scp->font_size]); 765 for (j = 0; j < scp->font_size; ++j, ++f) { 766 writeb(e, *f); 767 e += line_width; 768 } 769 ++d; 770 if ((i % scp->xsize) == scp->xsize - 1) 771 d += scp->xoff*2 772 + (scp->font_size - 1)*line_width; 773 } 774 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 775 outw(GDCIDX, 0x0000); /* set/reset */ 776 outw(GDCIDX, 0x0001); /* set/reset enable */ 777 } 778 779 static void 780 vga_pxlcursor_shape(scr_stat *scp, int base, int height, int blink) 781 { 782 if (base < 0 || base >= scp->font_size) 783 return; 784 /* the caller may set height <= 0 in order to disable the cursor */ 785 #if 0 786 scp->cursor_base = base; 787 scp->cursor_height = height; 788 #endif 789 } 790 791 static void 792 draw_pxlcursor_direct(scr_stat *scp, int at, int on, int flip) 793 { 794 int line_width, pixel_size, height; 795 int a, i, j, k, pos; 796 uint32_t fg, bg, u32; 797 unsigned char *char_data; 798 vm_offset_t draw_pos; 799 800 line_width = scp->sc->adp->va_line_width; 801 pixel_size = scp->sc->adp->va_info.vi_pixel_size; 802 803 draw_pos = VIDEO_MEMORY_POS(scp, at, 8 * pixel_size) + 804 (scp->font_size - scp->cursor_base - 1) * line_width; 805 806 a = sc_vtb_geta(&scp->vtb, at); 807 808 if (flip) { 809 fg = scp->ega_palette[((on) ? (a & 0x0f00) : 810 ((a & 0xf000) >> 4)) >> 8]; 811 bg = scp->ega_palette[((on) ? ((a & 0xf000) >> 4) : 812 (a & 0x0f00)) >> 8]; 813 } else { 814 fg = scp->ega_palette[((on) ? ((a & 0xf000) >> 4) : 815 (a & 0x0f00)) >> 8]; 816 bg = scp->ega_palette[((on) ? (a & 0x0f00) : 817 ((a & 0xf000) >> 4)) >> 8]; 818 } 819 820 char_data = &(scp->font[sc_vtb_getc(&scp->vtb, at) * scp->font_size + 821 scp->font_size - scp->cursor_base - 1]); 822 823 height = imin(scp->cursor_height, scp->font_size); 824 825 for (i = 0; i < height; ++i, --char_data) { 826 pos = 7; 827 828 for (j = 0; j < 2 * pixel_size; ++j) { 829 u32 = 0; 830 831 for (k = 0; k < 4 / pixel_size; ++k) { 832 u32 += (*char_data & (1 << pos--) ? 833 fg : bg) << (k * 8 * pixel_size); 834 } 835 836 writel(draw_pos, u32); 837 draw_pos += 4; 838 } 839 840 draw_pos -= line_width + 8 * pixel_size; 841 } 842 } 843 844 static void 845 draw_pxlcursor_packed(scr_stat *scp, int at, int on, int flip) 846 { 847 int line_width, height; 848 int a, i; 849 uint32_t fg, bg, u32; 850 unsigned char *char_data; 851 vm_offset_t draw_pos; 852 853 line_width = scp->sc->adp->va_line_width; 854 855 draw_pos = VIDEO_MEMORY_POS(scp, at, 8) + 856 (scp->font_size - scp->cursor_base - 1) * line_width; 857 858 a = sc_vtb_geta(&scp->vtb, at); 859 860 if (flip) { 861 fg = ((on) ? (a & 0x0f00) : ((a & 0xf000) >> 4)) >> 8; 862 bg = ((on) ? ((a & 0xf000) >> 4) : (a & 0x0f00)) >> 8; 863 } else { 864 fg = ((on) ? ((a & 0xf000) >> 4) : (a & 0x0f00)) >> 8; 865 bg = ((on) ? (a & 0x0f00) : ((a & 0xf000) >> 4)) >> 8; 866 } 867 868 char_data = &(scp->font[sc_vtb_getc(&scp->vtb, at) * scp->font_size + 869 scp->font_size - scp->cursor_base - 1]); 870 871 height = imin(scp->cursor_height, scp->font_size); 872 873 for (i = 0; i < height; ++i, --char_data) { 874 u32 = ((*char_data & 1 ? fg : bg) << 24) + 875 ((*char_data & 2 ? fg : bg) << 16) + 876 ((*char_data & 4 ? fg : bg) << 8) + 877 (*char_data & 8 ? fg : bg); 878 writel(draw_pos + 4, u32); 879 880 u32 = ((*char_data & 16 ? fg : bg) << 24) + 881 ((*char_data & 32 ? fg : bg) << 16) + 882 ((*char_data & 64 ? fg : bg) << 8) + 883 (*char_data & 128 ? fg : bg); 884 writel(draw_pos, u32); 885 886 draw_pos -= line_width; 887 } 888 } 889 890 static void 891 draw_pxlcursor_planar(scr_stat *scp, int at, int on, int flip) 892 { 893 vm_offset_t d; 894 u_char *f; 895 int line_width; 896 int height; 897 int col; 898 int a; 899 int i; 900 u_char c; 901 902 line_width = scp->sc->adp->va_line_width; 903 904 d = VIDEO_MEMORY_POS(scp, at, 1) + 905 (scp->font_size - scp->cursor_base - 1) * line_width; 906 907 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 908 outw(GDCIDX, 0x0003); /* data rotate/function select */ 909 outw(GDCIDX, 0x0f01); /* set/reset enable */ 910 /* set background color in EGA/VGA latch */ 911 a = sc_vtb_geta(&scp->vtb, at); 912 if (flip) 913 col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00); 914 else 915 col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4); 916 outw(GDCIDX, col | 0x00); /* set/reset */ 917 outw(GDCIDX, 0xff08); /* bit mask */ 918 writeb(d, 0); 919 c = readb(d); /* set bg color in the latch */ 920 /* foreground color */ 921 if (flip) 922 col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4); 923 else 924 col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00); 925 outw(GDCIDX, col | 0x00); /* set/reset */ 926 f = &(scp->font[sc_vtb_getc(&scp->vtb, at)*scp->font_size 927 + scp->font_size - scp->cursor_base - 1]); 928 height = imin(scp->cursor_height, scp->font_size); 929 for (i = 0; i < height; ++i, --f) { 930 outw(GDCIDX, (*f << 8) | 0x08); /* bit mask */ 931 writeb(d, 0); 932 d -= line_width; 933 } 934 outw(GDCIDX, 0x0000); /* set/reset */ 935 outw(GDCIDX, 0x0001); /* set/reset enable */ 936 outw(GDCIDX, 0xff08); /* bit mask */ 937 } 938 939 static int pxlblinkrate = 0; 940 941 static void 942 vga_pxlcursor_direct(scr_stat *scp, int at, int blink, int on, int flip) 943 { 944 if (scp->cursor_height <= 0) /* the text cursor is disabled */ 945 return; 946 947 if (on) { 948 if (!blink) { 949 scp->status |= VR_CURSOR_ON; 950 draw_pxlcursor_direct(scp, at, on, flip); 951 } else if (++pxlblinkrate & 4) { 952 pxlblinkrate = 0; 953 scp->status ^= VR_CURSOR_ON; 954 draw_pxlcursor_direct(scp, at, 955 scp->status & VR_CURSOR_ON, 956 flip); 957 } 958 } else { 959 if (scp->status & VR_CURSOR_ON) 960 draw_pxlcursor_direct(scp, at, on, flip); 961 scp->status &= ~VR_CURSOR_ON; 962 } 963 if (blink) 964 scp->status |= VR_CURSOR_BLINK; 965 else 966 scp->status &= ~VR_CURSOR_BLINK; 967 } 968 969 static void 970 vga_pxlcursor_packed(scr_stat *scp, int at, int blink, int on, int flip) 971 { 972 if (scp->cursor_height <= 0) /* the text cursor is disabled */ 973 return; 974 975 if (on) { 976 if (!blink) { 977 scp->status |= VR_CURSOR_ON; 978 draw_pxlcursor_packed(scp, at, on, flip); 979 } else if (++pxlblinkrate & 4) { 980 pxlblinkrate = 0; 981 scp->status ^= VR_CURSOR_ON; 982 draw_pxlcursor_packed(scp, at, 983 scp->status & VR_CURSOR_ON, 984 flip); 985 } 986 } else { 987 if (scp->status & VR_CURSOR_ON) 988 draw_pxlcursor_packed(scp, at, on, flip); 989 scp->status &= ~VR_CURSOR_ON; 990 } 991 if (blink) 992 scp->status |= VR_CURSOR_BLINK; 993 else 994 scp->status &= ~VR_CURSOR_BLINK; 995 } 996 997 static void 998 vga_pxlcursor_planar(scr_stat *scp, int at, int blink, int on, int flip) 999 { 1000 if (scp->cursor_height <= 0) /* the text cursor is disabled */ 1001 return; 1002 1003 if (on) { 1004 if (!blink) { 1005 scp->status |= VR_CURSOR_ON; 1006 draw_pxlcursor_planar(scp, at, on, flip); 1007 } else if (++pxlblinkrate & 4) { 1008 pxlblinkrate = 0; 1009 scp->status ^= VR_CURSOR_ON; 1010 draw_pxlcursor_planar(scp, at, 1011 scp->status & VR_CURSOR_ON, 1012 flip); 1013 } 1014 } else { 1015 if (scp->status & VR_CURSOR_ON) 1016 draw_pxlcursor_planar(scp, at, on, flip); 1017 scp->status &= ~VR_CURSOR_ON; 1018 } 1019 if (blink) 1020 scp->status |= VR_CURSOR_BLINK; 1021 else 1022 scp->status &= ~VR_CURSOR_BLINK; 1023 } 1024 1025 static void 1026 vga_pxlblink_direct(scr_stat *scp, int at, int flip) 1027 { 1028 if (!(scp->status & VR_CURSOR_BLINK)) 1029 return; 1030 if (!(++pxlblinkrate & 4)) 1031 return; 1032 pxlblinkrate = 0; 1033 scp->status ^= VR_CURSOR_ON; 1034 draw_pxlcursor_direct(scp, at, scp->status & VR_CURSOR_ON, flip); 1035 } 1036 1037 static void 1038 vga_pxlblink_packed(scr_stat *scp, int at, int flip) 1039 { 1040 if (!(scp->status & VR_CURSOR_BLINK)) 1041 return; 1042 if (!(++pxlblinkrate & 4)) 1043 return; 1044 pxlblinkrate = 0; 1045 scp->status ^= VR_CURSOR_ON; 1046 draw_pxlcursor_packed(scp, at, scp->status & VR_CURSOR_ON, flip); 1047 } 1048 1049 static void 1050 vga_pxlblink_planar(scr_stat *scp, int at, int flip) 1051 { 1052 if (!(scp->status & VR_CURSOR_BLINK)) 1053 return; 1054 if (!(++pxlblinkrate & 4)) 1055 return; 1056 pxlblinkrate = 0; 1057 scp->status ^= VR_CURSOR_ON; 1058 draw_pxlcursor_planar(scp, at, scp->status & VR_CURSOR_ON, flip); 1059 } 1060 1061 #ifndef SC_NO_CUTPASTE 1062 1063 static void 1064 draw_pxlmouse_direct(scr_stat *scp, int x, int y) 1065 { 1066 int line_width, pixel_size; 1067 int xend, yend; 1068 int i, j; 1069 vm_offset_t draw_pos; 1070 1071 line_width = scp->sc->adp->va_line_width; 1072 pixel_size = scp->sc->adp->va_info.vi_pixel_size; 1073 1074 xend = imin(x + 8, 8 * (scp->xoff + scp->xsize)); 1075 yend = imin(y + 16, scp->font_size * (scp->yoff + scp->ysize)); 1076 1077 draw_pos = scp->sc->adp->va_window + y * line_width + x * pixel_size; 1078 1079 for (i = 0; i < (yend - y); i++) { 1080 for (j = (xend - x - 1); j >= 0; j--) { 1081 switch (scp->sc->adp->va_info.vi_depth) { 1082 case 32: 1083 if (mouse_or_mask[i] & 1 << (15 - j)) 1084 writel(draw_pos + 4 * j, 1085 scp->ega_palette[15]); 1086 else if (mouse_and_mask[i] & 1 << (15 - j)) 1087 writel(draw_pos + 4 * j, 1088 scp->ega_palette[0]); 1089 break; 1090 case 16: 1091 /* FALLTHROUGH */ 1092 case 15: 1093 if (mouse_or_mask[i] & 1 << (15 - j)) 1094 writew(draw_pos + 2 * j, 1095 scp->ega_palette[15]); 1096 else if (mouse_and_mask[i] & 1 << (15 - j)) 1097 writew(draw_pos + 2 * j, 1098 scp->ega_palette[0]); 1099 break; 1100 } 1101 } 1102 1103 draw_pos += line_width; 1104 } 1105 } 1106 1107 static void 1108 draw_pxlmouse_packed(scr_stat *scp, int x, int y) 1109 { 1110 int line_width; 1111 int xend, yend; 1112 int i, j; 1113 vm_offset_t draw_pos; 1114 1115 line_width = scp->sc->adp->va_line_width; 1116 1117 xend = imin(8 * (scp->xoff + scp->xsize), imin(x + 16, scp->xpixel)); 1118 yend = imin(scp->font_size * (scp->yoff + scp->ysize), 1119 imin(y + 16, scp->ypixel)); 1120 1121 draw_pos = scp->sc->adp->va_window + y * line_width + x; 1122 1123 for (i = 0; i < (yend - y); i++) { 1124 for (j = (xend - x - 1); j >= 0; j--) { 1125 if (mouse_or_mask[i] & 1 << (15 - j)) 1126 writeb(draw_pos + j, 15); 1127 else if (mouse_and_mask[i] & 1 << (15 - j)) 1128 writeb(draw_pos + j, 0); 1129 } 1130 1131 draw_pos += line_width; 1132 } 1133 } 1134 1135 static void 1136 draw_pxlmouse_planar(scr_stat *scp, int x, int y) 1137 { 1138 vm_offset_t p; 1139 int line_width; 1140 int xoff; 1141 int ymax; 1142 u_short m; 1143 int i, j; 1144 1145 line_width = scp->sc->adp->va_line_width; 1146 xoff = (x - scp->xoff*8)%8; 1147 ymax = imin(y + 16, scp->font_size * (scp->yoff + scp->ysize)); 1148 1149 outw(GDCIDX, 0x0805); /* read mode 1, write mode 0 */ 1150 outw(GDCIDX, 0x0001); /* set/reset enable */ 1151 outw(GDCIDX, 0x0002); /* color compare */ 1152 outw(GDCIDX, 0x0007); /* color don't care */ 1153 outw(GDCIDX, 0xff08); /* bit mask */ 1154 outw(GDCIDX, 0x0803); /* data rotate/function select (and) */ 1155 p = scp->sc->adp->va_window + line_width*y + x/8; 1156 if (x < 8 * (scp->xoff + scp->xsize) - 8) { 1157 for (i = y, j = 0; i < ymax; ++i, ++j) { 1158 m = ~(mouse_and_mask[j] >> xoff); 1159 *(u_char *)p &= m >> 8; 1160 *(u_char *)(p + 1) &= m; 1161 p += line_width; 1162 } 1163 } else { 1164 xoff += 8; 1165 for (i = y, j = 0; i < ymax; ++i, ++j) { 1166 m = ~(mouse_and_mask[j] >> xoff); 1167 *(u_char *)p &= m; 1168 p += line_width; 1169 } 1170 } 1171 outw(GDCIDX, 0x1003); /* data rotate/function select (or) */ 1172 p = scp->sc->adp->va_window + line_width*y + x/8; 1173 if (x < 8 * (scp->xoff + scp->xsize) - 8) { 1174 for (i = y, j = 0; i < ymax; ++i, ++j) { 1175 m = mouse_or_mask[j] >> xoff; 1176 *(u_char *)p &= m >> 8; 1177 *(u_char *)(p + 1) &= m; 1178 p += line_width; 1179 } 1180 } else { 1181 for (i = y, j = 0; i < ymax; ++i, ++j) { 1182 m = mouse_or_mask[j] >> xoff; 1183 *(u_char *)p &= m; 1184 p += line_width; 1185 } 1186 } 1187 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 1188 outw(GDCIDX, 0x0003); /* data rotate/function select */ 1189 } 1190 1191 static void 1192 remove_pxlmouse(scr_stat *scp, int x, int y) 1193 { 1194 int col, row; 1195 int pos; 1196 int i; 1197 1198 /* erase the mouse cursor image */ 1199 col = x/8 - scp->xoff; 1200 row = y/scp->font_size - scp->yoff; 1201 pos = row*scp->xsize + col; 1202 i = (col < scp->xsize - 1) ? 2 : 1; 1203 (*scp->rndr->draw)(scp, pos, i, FALSE); 1204 if (row < scp->ysize - 1) 1205 (*scp->rndr->draw)(scp, pos + scp->xsize, i, FALSE); 1206 } 1207 1208 static void 1209 vga_pxlmouse_direct(scr_stat *scp, int x, int y, int on) 1210 { 1211 if (on) 1212 draw_pxlmouse_direct(scp, x, y); 1213 else 1214 remove_pxlmouse(scp, x, y); 1215 } 1216 1217 static void 1218 vga_pxlmouse_packed(scr_stat *scp, int x, int y, int on) 1219 { 1220 if (on) 1221 draw_pxlmouse_packed(scp, x, y); 1222 else 1223 remove_pxlmouse(scp, x, y); 1224 } 1225 1226 static void 1227 vga_pxlmouse_planar(scr_stat *scp, int x, int y, int on) 1228 { 1229 if (on) 1230 draw_pxlmouse_planar(scp, x, y); 1231 else 1232 remove_pxlmouse(scp, x, y); 1233 } 1234 1235 #endif /* SC_NO_CUTPASTE */ 1236 #endif /* SC_PIXEL_MODE */ 1237 1238 #ifndef SC_NO_MODE_CHANGE 1239 1240 /* graphics mode renderer */ 1241 1242 static void 1243 vga_grborder(scr_stat *scp, int color) 1244 { 1245 lwkt_gettoken(&tty_token); 1246 (*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color); 1247 lwkt_reltoken(&tty_token); 1248 } 1249 1250 #endif 1251