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