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 * $DragonFly: src/sys/dev/misc/syscons/scvgarndr.c,v 1.17 2008/08/10 19:45:01 swildner Exp $ 31 */ 32 33 #include "opt_syscons.h" 34 #include "opt_vga.h" 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/kernel.h> 39 40 #include <machine/console.h> 41 42 #include <dev/video/fb/fbreg.h> 43 #include <dev/video/fb/vgareg.h> 44 #include "syscons.h" 45 46 #include <bus/isa/isareg.h> 47 48 static vr_draw_border_t vga_txtborder; 49 static vr_draw_t vga_txtdraw; 50 static vr_set_cursor_t vga_txtcursor_shape; 51 static vr_draw_cursor_t vga_txtcursor; 52 static vr_blink_cursor_t vga_txtblink; 53 #ifndef SC_NO_CUTPASTE 54 static vr_draw_mouse_t vga_txtmouse; 55 #else 56 #define vga_txtmouse (vr_draw_mouse_t *)vga_nop 57 #endif 58 59 #ifdef SC_PIXEL_MODE 60 static vr_draw_border_t vga_pxlborder_direct; 61 static vr_draw_border_t vga_pxlborder_planar; 62 static vr_draw_t vga_vgadraw_direct; 63 static vr_draw_t vga_vgadraw_planar; 64 static vr_set_cursor_t vga_pxlcursor_shape; 65 static vr_draw_cursor_t vga_pxlcursor_direct; 66 static vr_draw_cursor_t vga_pxlcursor_planar; 67 static vr_blink_cursor_t vga_pxlblink_direct; 68 static vr_blink_cursor_t vga_pxlblink_planar; 69 #ifndef SC_NO_CUTPASTE 70 static vr_draw_mouse_t vga_pxlmouse_direct; 71 static vr_draw_mouse_t vga_pxlmouse_planar; 72 #else 73 #define vga_pxlmouse_direct (vr_draw_mouse_t *)vga_nop 74 #define vga_pxlmouse_planar (vr_draw_mouse_t *)vga_nop 75 #endif 76 #endif /* SC_PIXEL_MODE */ 77 78 #ifndef SC_NO_MODE_CHANGE 79 static vr_draw_border_t vga_grborder; 80 #endif 81 82 static void vga_nop(scr_stat *scp, ...); 83 84 static sc_rndr_sw_t txtrndrsw = { 85 vga_txtborder, 86 vga_txtdraw, 87 vga_txtcursor_shape, 88 vga_txtcursor, 89 vga_txtblink, 90 vga_txtmouse, 91 }; 92 RENDERER(vga, V_INFO_MM_TEXT, txtrndrsw, vga_set); 93 94 #ifdef SC_PIXEL_MODE 95 static sc_rndr_sw_t planarrndrsw = { 96 vga_pxlborder_planar, 97 vga_vgadraw_planar, 98 vga_pxlcursor_shape, 99 vga_pxlcursor_planar, 100 vga_pxlblink_planar, 101 vga_pxlmouse_planar, 102 }; 103 RENDERER(vga, V_INFO_MM_PLANAR, planarrndrsw, vga_set); 104 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 #endif /* SC_PIXEL_MODE */ 115 116 #ifndef SC_NO_MODE_CHANGE 117 static sc_rndr_sw_t grrndrsw = { 118 vga_grborder, 119 (vr_draw_t *)vga_nop, 120 (vr_set_cursor_t *)vga_nop, 121 (vr_draw_cursor_t *)vga_nop, 122 (vr_blink_cursor_t *)vga_nop, 123 (vr_draw_mouse_t *)vga_nop, 124 }; 125 RENDERER(vga, V_INFO_MM_OTHER, grrndrsw, vga_set); 126 #endif /* SC_NO_MODE_CHANGE */ 127 128 RENDERER_MODULE(vga, vga_set); 129 130 #ifndef SC_NO_CUTPASTE 131 static u_short mouse_and_mask[16] = { 132 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00, 0xff80, 133 0xfe00, 0x1e00, 0x1f00, 0x0f00, 0x0f00, 0x0000, 0x0000, 0x0000 134 }; 135 static u_short mouse_or_mask[16] = { 136 0x0000, 0x4000, 0x6000, 0x7000, 0x7800, 0x7c00, 0x7e00, 0x6800, 137 0x0c00, 0x0c00, 0x0600, 0x0600, 0x0000, 0x0000, 0x0000, 0x0000 138 }; 139 #endif 140 141 static void 142 vga_nop(scr_stat *scp, ...) 143 { 144 } 145 146 /* text mode renderer */ 147 148 static void 149 vga_txtborder(scr_stat *scp, int color) 150 { 151 (*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color); 152 } 153 154 static void 155 vga_txtdraw(scr_stat *scp, int from, int count, int flip) 156 { 157 uint16_t *p; 158 int c; 159 int a; 160 161 if (from + count > scp->xsize*scp->ysize) 162 count = scp->xsize*scp->ysize - from; 163 164 if (flip) { 165 for (p = scp->scr.vtb_buffer + from; count-- > 0; ++from) { 166 c = sc_vtb_getc(&scp->vtb, from); 167 a = sc_vtb_geta(&scp->vtb, from); 168 a = (a & 0x8800) | ((a & 0x7000) >> 4) 169 | ((a & 0x0700) << 4); 170 p = sc_vtb_putchar(&scp->scr, p, c, a); 171 } 172 } else { 173 sc_vtb_copy(&scp->vtb, from, &scp->scr, from, count); 174 } 175 } 176 177 static void 178 vga_txtcursor_shape(scr_stat *scp, int base, int height, int blink) 179 { 180 if (base < 0 || base >= scp->font_size) 181 return; 182 /* the caller may set height <= 0 in order to disable the cursor */ 183 #if 0 184 scp->cursor_base = base; 185 scp->cursor_height = height; 186 #endif 187 (*vidsw[scp->sc->adapter]->set_hw_cursor_shape)(scp->sc->adp, 188 base, height, 189 scp->font_size, blink); 190 } 191 192 static void 193 draw_txtcharcursor(scr_stat *scp, int at, u_short c, u_short a, int flip) 194 { 195 sc_softc_t *sc; 196 197 sc = scp->sc; 198 scp->cursor_saveunder_char = c; 199 scp->cursor_saveunder_attr = a; 200 201 #ifndef SC_NO_FONT_LOADING 202 if (sc->flags & SC_CHAR_CURSOR) { 203 unsigned char *font; 204 int h; 205 int i; 206 207 if (scp->font_size < 14) { 208 font = sc->font_8; 209 h = 8; 210 } else if (scp->font_size >= 16) { 211 font = sc->font_16; 212 h = 16; 213 } else { 214 font = sc->font_14; 215 h = 14; 216 } 217 if (scp->cursor_base >= h) 218 return; 219 if (flip) 220 a = (a & 0x8800) 221 | ((a & 0x7000) >> 4) | ((a & 0x0700) << 4); 222 bcopy(font + c*h, font + sc->cursor_char*h, h); 223 font = font + sc->cursor_char*h; 224 for (i = imax(h - scp->cursor_base - scp->cursor_height, 0); 225 i < h - scp->cursor_base; ++i) { 226 font[i] ^= 0xff; 227 } 228 sc->font_loading_in_progress = TRUE; 229 /* XXX */ 230 (*vidsw[sc->adapter]->load_font)(sc->adp, 0, h, font, 231 sc->cursor_char, 1); 232 sc->font_loading_in_progress = FALSE; 233 sc_vtb_putc(&scp->scr, at, sc->cursor_char, a); 234 } else 235 #endif /* SC_NO_FONT_LOADING */ 236 { 237 if ((a & 0x7000) == 0x7000) { 238 a &= 0x8f00; 239 if ((a & 0x0700) == 0) 240 a |= 0x0700; 241 } else { 242 a |= 0x7000; 243 if ((a & 0x0700) == 0x0700) 244 a &= 0xf000; 245 } 246 if (flip) 247 a = (a & 0x8800) 248 | ((a & 0x7000) >> 4) | ((a & 0x0700) << 4); 249 sc_vtb_putc(&scp->scr, at, c, a); 250 } 251 } 252 253 static void 254 vga_txtcursor(scr_stat *scp, int at, int blink, int on, int flip) 255 { 256 video_adapter_t *adp; 257 int cursor_attr; 258 259 if (scp->cursor_height <= 0) /* the text cursor is disabled */ 260 return; 261 262 adp = scp->sc->adp; 263 if (blink) { 264 scp->status |= VR_CURSOR_BLINK; 265 if (on) { 266 scp->status |= VR_CURSOR_ON; 267 (*vidsw[adp->va_index]->set_hw_cursor)(adp, 268 at%scp->xsize, 269 at/scp->xsize); 270 } else { 271 if (scp->status & VR_CURSOR_ON) 272 (*vidsw[adp->va_index]->set_hw_cursor)(adp, 273 -1, -1); 274 scp->status &= ~VR_CURSOR_ON; 275 } 276 } else { 277 scp->status &= ~VR_CURSOR_BLINK; 278 if (on) { 279 scp->status |= VR_CURSOR_ON; 280 draw_txtcharcursor(scp, at, 281 sc_vtb_getc(&scp->scr, at), 282 sc_vtb_geta(&scp->scr, at), 283 flip); 284 } else { 285 cursor_attr = scp->cursor_saveunder_attr; 286 if (flip) 287 cursor_attr = (cursor_attr & 0x8800) 288 | ((cursor_attr & 0x7000) >> 4) 289 | ((cursor_attr & 0x0700) << 4); 290 if (scp->status & VR_CURSOR_ON) 291 sc_vtb_putc(&scp->scr, at, 292 scp->cursor_saveunder_char, 293 cursor_attr); 294 scp->status &= ~VR_CURSOR_ON; 295 } 296 } 297 } 298 299 static void 300 vga_txtblink(scr_stat *scp, int at, int flip) 301 { 302 } 303 304 #ifndef SC_NO_CUTPASTE 305 306 static void 307 draw_txtmouse(scr_stat *scp, int x, int y) 308 { 309 #ifndef SC_ALT_MOUSE_IMAGE 310 if (ISMOUSEAVAIL(scp->sc->adp->va_flags)) { 311 u_char font_buf[128]; 312 u_short cursor[32]; 313 u_char c; 314 int pos; 315 int xoffset, yoffset; 316 int i; 317 318 /* prepare mousepointer char's bitmaps */ 319 pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff; 320 bcopy(scp->font + sc_vtb_getc(&scp->scr, pos)*scp->font_size, 321 &font_buf[0], scp->font_size); 322 bcopy(scp->font + sc_vtb_getc(&scp->scr, pos + 1)*scp->font_size, 323 &font_buf[32], scp->font_size); 324 bcopy(scp->font 325 + sc_vtb_getc(&scp->scr, pos + scp->xsize)*scp->font_size, 326 &font_buf[64], scp->font_size); 327 bcopy(scp->font 328 + sc_vtb_getc(&scp->scr, pos + scp->xsize + 1)*scp->font_size, 329 &font_buf[96], scp->font_size); 330 for (i = 0; i < scp->font_size; ++i) { 331 cursor[i] = font_buf[i]<<8 | font_buf[i+32]; 332 cursor[i + scp->font_size] = font_buf[i+64]<<8 | font_buf[i+96]; 333 } 334 335 /* now and-or in the mousepointer image */ 336 xoffset = x%8; 337 yoffset = y%scp->font_size; 338 for (i = 0; i < 16; ++i) { 339 cursor[i + yoffset] = 340 (cursor[i + yoffset] & ~(mouse_and_mask[i] >> xoffset)) 341 | (mouse_or_mask[i] >> xoffset); 342 } 343 for (i = 0; i < scp->font_size; ++i) { 344 font_buf[i] = (cursor[i] & 0xff00) >> 8; 345 font_buf[i + 32] = cursor[i] & 0xff; 346 font_buf[i + 64] = (cursor[i + scp->font_size] & 0xff00) >> 8; 347 font_buf[i + 96] = cursor[i + scp->font_size] & 0xff; 348 } 349 350 #if 1 351 /* wait for vertical retrace to avoid jitter on some videocards */ 352 while (!(inb(CRTC + 6) & 0x08)) /* idle */ ; 353 #endif 354 c = scp->sc->mouse_char; 355 (*vidsw[scp->sc->adapter]->load_font)(scp->sc->adp, 0, 32, font_buf, 356 c, 4); 357 358 sc_vtb_putc(&scp->scr, pos, c, sc_vtb_geta(&scp->scr, pos)); 359 /* FIXME: may be out of range! */ 360 sc_vtb_putc(&scp->scr, pos + scp->xsize, c + 2, 361 sc_vtb_geta(&scp->scr, pos + scp->xsize)); 362 if (x < (scp->xsize - 1)*8) { 363 sc_vtb_putc(&scp->scr, pos + 1, c + 1, 364 sc_vtb_geta(&scp->scr, pos + 1)); 365 sc_vtb_putc(&scp->scr, pos + scp->xsize + 1, c + 3, 366 sc_vtb_geta(&scp->scr, pos + scp->xsize + 1)); 367 } 368 } else 369 #endif /* SC_ALT_MOUSE_IMAGE */ 370 { 371 /* Red, magenta and brown are mapped to green to to keep it readable */ 372 static const int col_conv[16] = { 373 6, 6, 6, 6, 2, 2, 2, 6, 14, 14, 14, 14, 10, 10, 10, 14 374 }; 375 int pos; 376 int color; 377 int a; 378 379 pos = (y/scp->font_size - scp->yoff)*scp->xsize + x/8 - scp->xoff; 380 a = sc_vtb_geta(&scp->scr, pos); 381 if (scp->sc->adp->va_flags & V_ADP_COLOR) 382 color = (col_conv[(a & 0xf000) >> 12] << 12) 383 | ((a & 0x0f00) | 0x0800); 384 else 385 color = ((a & 0xf000) >> 4) | ((a & 0x0f00) << 4); 386 sc_vtb_putc(&scp->scr, pos, sc_vtb_getc(&scp->scr, pos), color); 387 } 388 } 389 390 static void 391 remove_txtmouse(scr_stat *scp, int x, int y) 392 { 393 } 394 395 static void 396 vga_txtmouse(scr_stat *scp, int x, int y, int on) 397 { 398 if (on) 399 draw_txtmouse(scp, x, y); 400 else 401 remove_txtmouse(scp, x, y); 402 } 403 404 #endif /* SC_NO_CUTPASTE */ 405 406 #ifdef SC_PIXEL_MODE 407 408 /* pixel (raster text) mode renderer */ 409 410 static void 411 vga_pxlborder_direct(scr_stat *scp, int color) 412 { 413 int i, x, y; 414 int line_width, pixel_size; 415 uint32_t u32 = 0; 416 vm_offset_t draw_pos, draw_end, p; 417 418 line_width = scp->sc->adp->va_line_width; 419 pixel_size = scp->sc->adp->va_info.vi_pixel_size; 420 421 for (i = 0; i < 4 / pixel_size; ++i) 422 u32 += scp->ega_palette[color] << (i * 8 * pixel_size); 423 424 if (scp->yoff > 0) { 425 draw_pos = scp->sc->adp->va_window; 426 draw_end = draw_pos + 427 line_width * scp->yoff * scp->font_size; 428 429 for (p = draw_pos; p < draw_end; p += 4) 430 writel(p, u32); 431 } 432 433 y = (scp->yoff + scp->ysize) * scp->font_size; 434 435 if (scp->ypixel > y) { 436 draw_pos = scp->sc->adp->va_window + line_width * y; 437 draw_end = draw_pos + line_width * (scp->ypixel - y); 438 439 for (p = draw_pos; p < draw_end; p += 4) 440 writel(p, u32); 441 } 442 443 y = scp->yoff * scp->font_size; 444 x = scp->xpixel / 8 - scp->xoff - scp->xsize; 445 446 for (i = 0; i < scp->ysize * scp->font_size; ++i) { 447 if (scp->xoff > 0) { 448 draw_pos = scp->sc->adp->va_window + 449 line_width * (y + i); 450 draw_end = draw_pos + scp->xoff * 8 * pixel_size; 451 452 for (p = draw_pos; p < draw_end; p += 4) 453 writel(p, u32); 454 } 455 456 if (x > 0) { 457 draw_pos = scp->sc->adp->va_window + 458 line_width * (y + i) + 459 scp->xoff * 8 * pixel_size + 460 scp->xsize * 8 * pixel_size; 461 draw_end = draw_pos + x * 8 * pixel_size; 462 463 for (p = draw_pos; p < draw_end; p += 4) 464 writel(p, u32); 465 } 466 } 467 } 468 469 static void 470 vga_pxlborder_planar(scr_stat *scp, int color) 471 { 472 vm_offset_t p; 473 int line_width; 474 int x; 475 int y; 476 int i; 477 478 (*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color); 479 480 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 481 outw(GDCIDX, 0x0003); /* data rotate/function select */ 482 outw(GDCIDX, 0x0f01); /* set/reset enable */ 483 outw(GDCIDX, 0xff08); /* bit mask */ 484 outw(GDCIDX, (color << 8) | 0x00); /* set/reset */ 485 line_width = scp->sc->adp->va_line_width; 486 p = scp->sc->adp->va_window; 487 if (scp->yoff > 0) 488 bzero_io((void *)p, line_width*scp->yoff*scp->font_size); 489 y = (scp->yoff + scp->ysize)*scp->font_size; 490 if (scp->ypixel > y) 491 bzero_io((void *)(p + line_width*y), line_width*(scp->ypixel - y)); 492 y = scp->yoff*scp->font_size; 493 x = scp->xpixel/8 - scp->xoff - scp->xsize; 494 for (i = 0; i < scp->ysize*scp->font_size; ++i) { 495 if (scp->xoff > 0) 496 bzero_io((void *)(p + line_width*(y + i)), scp->xoff); 497 if (x > 0) 498 bzero_io((void *)(p + line_width*(y + i) 499 + scp->xoff + scp->xsize), x); 500 } 501 outw(GDCIDX, 0x0000); /* set/reset */ 502 outw(GDCIDX, 0x0001); /* set/reset enable */ 503 } 504 505 static void 506 vga_vgadraw_direct(scr_stat *scp, int from, int count, int flip) 507 { 508 int line_width, pixel_size; 509 int a, i, j, k, l, pos; 510 uint32_t fg, bg, u32; 511 unsigned char *char_data; 512 vm_offset_t draw_pos, p; 513 514 line_width = scp->sc->adp->va_line_width; 515 pixel_size = scp->sc->adp->va_info.vi_pixel_size; 516 517 draw_pos = VIDEO_MEMORY_POS(scp, from, 8 * pixel_size); 518 519 if (from + count > scp->xsize * scp->ysize) 520 count = scp->xsize * scp->ysize - from; 521 522 for (i = from; count-- > 0; ++i) { 523 a = sc_vtb_geta(&scp->vtb, i); 524 525 if (flip) { 526 fg = scp->ega_palette[(((a & 0x7000) >> 4) | 527 (a & 0x0800)) >> 8]; 528 bg = scp->ega_palette[(((a & 0x8000) >> 4) | 529 (a & 0x0700)) >> 8]; 530 } else { 531 fg = scp->ega_palette[(a & 0x0f00) >> 8]; 532 bg = scp->ega_palette[(a & 0xf000) >> 12]; 533 } 534 535 p = draw_pos; 536 char_data = &(scp->font[sc_vtb_getc(&scp->vtb, i) * 537 scp->font_size]); 538 539 for (j = 0; j < scp->font_size; ++j, ++char_data) { 540 pos = 7; 541 542 for (k = 0; k < 2 * pixel_size; ++k) { 543 u32 = 0; 544 545 for (l = 0; l < 4 / pixel_size; ++l) { 546 u32 += (*char_data & (1 << pos--) ? 547 fg : bg) << (l * 8 * pixel_size); 548 } 549 550 writel(p, u32); 551 p += 4; 552 } 553 554 p += line_width - 8 * pixel_size; 555 } 556 557 draw_pos += 8 * pixel_size; 558 559 if ((i % scp->xsize) == scp->xsize - 1) 560 draw_pos += scp->xoff * 16 * pixel_size + 561 (scp->font_size - 1) * line_width; 562 } 563 } 564 565 static void 566 vga_vgadraw_planar(scr_stat *scp, int from, int count, int flip) 567 { 568 vm_offset_t d; 569 vm_offset_t e; 570 u_char *f; 571 u_short bg; 572 u_short col1, col2; 573 int line_width; 574 int i, j; 575 int a; 576 u_char c; 577 578 d = VIDEO_MEMORY_POS(scp, from, 1); 579 580 line_width = scp->sc->adp->va_line_width; 581 582 outw(GDCIDX, 0x0305); /* read mode 0, write mode 3 */ 583 outw(GDCIDX, 0x0003); /* data rotate/function select */ 584 outw(GDCIDX, 0x0f01); /* set/reset enable */ 585 outw(GDCIDX, 0xff08); /* bit mask */ 586 bg = -1; 587 if (from + count > scp->xsize*scp->ysize) 588 count = scp->xsize*scp->ysize - from; 589 for (i = from; count-- > 0; ++i) { 590 a = sc_vtb_geta(&scp->vtb, i); 591 if (flip) { 592 col1 = ((a & 0x7000) >> 4) | (a & 0x0800); 593 col2 = ((a & 0x8000) >> 4) | (a & 0x0700); 594 } else { 595 col1 = (a & 0x0f00); 596 col2 = (a & 0xf000) >> 4; 597 } 598 /* set background color in EGA/VGA latch */ 599 if (bg != col2) { 600 bg = col2; 601 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 602 outw(GDCIDX, bg | 0x00); /* set/reset */ 603 writeb(d, 0); 604 c = readb(d); /* set bg color in the latch */ 605 outw(GDCIDX, 0x0305); /* read mode 0, write mode 3 */ 606 } 607 /* foreground color */ 608 outw(GDCIDX, col1 | 0x00); /* set/reset */ 609 e = d; 610 f = &(scp->font[sc_vtb_getc(&scp->vtb, i)*scp->font_size]); 611 for (j = 0; j < scp->font_size; ++j, ++f) { 612 writeb(e, *f); 613 e += line_width; 614 } 615 ++d; 616 if ((i % scp->xsize) == scp->xsize - 1) 617 d += scp->xoff*2 618 + (scp->font_size - 1)*line_width; 619 } 620 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 621 outw(GDCIDX, 0x0000); /* set/reset */ 622 outw(GDCIDX, 0x0001); /* set/reset enable */ 623 } 624 625 static void 626 vga_pxlcursor_shape(scr_stat *scp, int base, int height, int blink) 627 { 628 if (base < 0 || base >= scp->font_size) 629 return; 630 /* the caller may set height <= 0 in order to disable the cursor */ 631 #if 0 632 scp->cursor_base = base; 633 scp->cursor_height = height; 634 #endif 635 } 636 637 static void 638 draw_pxlcursor_direct(scr_stat *scp, int at, int on, int flip) 639 { 640 int line_width, pixel_size, height; 641 int a, i, j, k, pos; 642 uint32_t fg, bg, u32; 643 unsigned char *char_data; 644 vm_offset_t draw_pos; 645 646 line_width = scp->sc->adp->va_line_width; 647 pixel_size = scp->sc->adp->va_info.vi_pixel_size; 648 649 draw_pos = VIDEO_MEMORY_POS(scp, at, 8 * pixel_size) + 650 (scp->font_size - scp->cursor_base - 1) * line_width; 651 652 a = sc_vtb_geta(&scp->vtb, at); 653 654 if (flip) { 655 fg = scp->ega_palette[((on) ? (a & 0x0f00) : 656 ((a & 0xf000) >> 4)) >> 8]; 657 bg = scp->ega_palette[((on) ? ((a & 0xf000) >> 4) : 658 (a & 0x0f00)) >> 8]; 659 } else { 660 fg = scp->ega_palette[((on) ? ((a & 0xf000) >> 4) : 661 (a & 0x0f00)) >> 8]; 662 bg = scp->ega_palette[((on) ? (a & 0x0f00) : 663 ((a & 0xf000) >> 4)) >> 8]; 664 } 665 666 char_data = &(scp->font[sc_vtb_getc(&scp->vtb, at) * scp->font_size + 667 scp->font_size - scp->cursor_base - 1]); 668 669 height = imin(scp->cursor_height, scp->font_size); 670 671 for (i = 0; i < height; ++i, --char_data) { 672 pos = 7; 673 674 for (j = 0; j < 2 * pixel_size; ++j) { 675 u32 = 0; 676 677 for (k = 0; k < 4 / pixel_size; ++k) { 678 u32 += (*char_data & (1 << pos--) ? 679 fg : bg) << (k * 8 * pixel_size); 680 } 681 682 writel(draw_pos, u32); 683 draw_pos += 4; 684 } 685 686 draw_pos -= line_width + 8 * pixel_size; 687 } 688 } 689 690 static void 691 draw_pxlcursor_planar(scr_stat *scp, int at, int on, int flip) 692 { 693 vm_offset_t d; 694 u_char *f; 695 int line_width; 696 int height; 697 int col; 698 int a; 699 int i; 700 u_char c; 701 702 line_width = scp->sc->adp->va_line_width; 703 704 d = VIDEO_MEMORY_POS(scp, at, 1) + 705 (scp->font_size - scp->cursor_base - 1) * line_width; 706 707 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 708 outw(GDCIDX, 0x0003); /* data rotate/function select */ 709 outw(GDCIDX, 0x0f01); /* set/reset enable */ 710 /* set background color in EGA/VGA latch */ 711 a = sc_vtb_geta(&scp->vtb, at); 712 if (flip) 713 col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00); 714 else 715 col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4); 716 outw(GDCIDX, col | 0x00); /* set/reset */ 717 outw(GDCIDX, 0xff08); /* bit mask */ 718 writeb(d, 0); 719 c = readb(d); /* set bg color in the latch */ 720 /* foreground color */ 721 if (flip) 722 col = (on) ? (a & 0x0f00) : ((a & 0xf000) >> 4); 723 else 724 col = (on) ? ((a & 0xf000) >> 4) : (a & 0x0f00); 725 outw(GDCIDX, col | 0x00); /* set/reset */ 726 f = &(scp->font[sc_vtb_getc(&scp->vtb, at)*scp->font_size 727 + scp->font_size - scp->cursor_base - 1]); 728 height = imin(scp->cursor_height, scp->font_size); 729 for (i = 0; i < height; ++i, --f) { 730 outw(GDCIDX, (*f << 8) | 0x08); /* bit mask */ 731 writeb(d, 0); 732 d -= line_width; 733 } 734 outw(GDCIDX, 0x0000); /* set/reset */ 735 outw(GDCIDX, 0x0001); /* set/reset enable */ 736 outw(GDCIDX, 0xff08); /* bit mask */ 737 } 738 739 static int pxlblinkrate = 0; 740 741 static void 742 vga_pxlcursor_direct(scr_stat *scp, int at, int blink, int on, int flip) 743 { 744 if (scp->cursor_height <= 0) /* the text cursor is disabled */ 745 return; 746 747 if (on) { 748 if (!blink) { 749 scp->status |= VR_CURSOR_ON; 750 draw_pxlcursor_direct(scp, at, on, flip); 751 } else if (++pxlblinkrate & 4) { 752 pxlblinkrate = 0; 753 scp->status ^= VR_CURSOR_ON; 754 draw_pxlcursor_direct(scp, at, 755 scp->status & VR_CURSOR_ON, 756 flip); 757 } 758 } else { 759 if (scp->status & VR_CURSOR_ON) 760 draw_pxlcursor_direct(scp, at, on, flip); 761 scp->status &= ~VR_CURSOR_ON; 762 } 763 if (blink) 764 scp->status |= VR_CURSOR_BLINK; 765 else 766 scp->status &= ~VR_CURSOR_BLINK; 767 } 768 769 static void 770 vga_pxlcursor_planar(scr_stat *scp, int at, int blink, int on, int flip) 771 { 772 if (scp->cursor_height <= 0) /* the text cursor is disabled */ 773 return; 774 775 if (on) { 776 if (!blink) { 777 scp->status |= VR_CURSOR_ON; 778 draw_pxlcursor_planar(scp, at, on, flip); 779 } else if (++pxlblinkrate & 4) { 780 pxlblinkrate = 0; 781 scp->status ^= VR_CURSOR_ON; 782 draw_pxlcursor_planar(scp, at, 783 scp->status & VR_CURSOR_ON, 784 flip); 785 } 786 } else { 787 if (scp->status & VR_CURSOR_ON) 788 draw_pxlcursor_planar(scp, at, on, flip); 789 scp->status &= ~VR_CURSOR_ON; 790 } 791 if (blink) 792 scp->status |= VR_CURSOR_BLINK; 793 else 794 scp->status &= ~VR_CURSOR_BLINK; 795 } 796 797 static void 798 vga_pxlblink_direct(scr_stat *scp, int at, int flip) 799 { 800 if (!(scp->status & VR_CURSOR_BLINK)) 801 return; 802 if (!(++pxlblinkrate & 4)) 803 return; 804 pxlblinkrate = 0; 805 scp->status ^= VR_CURSOR_ON; 806 draw_pxlcursor_direct(scp, at, scp->status & VR_CURSOR_ON, flip); 807 } 808 809 static void 810 vga_pxlblink_planar(scr_stat *scp, int at, int flip) 811 { 812 if (!(scp->status & VR_CURSOR_BLINK)) 813 return; 814 if (!(++pxlblinkrate & 4)) 815 return; 816 pxlblinkrate = 0; 817 scp->status ^= VR_CURSOR_ON; 818 draw_pxlcursor_planar(scp, at, scp->status & VR_CURSOR_ON, flip); 819 } 820 821 #ifndef SC_NO_CUTPASTE 822 823 static void 824 draw_pxlmouse_direct(scr_stat *scp, int x, int y) 825 { 826 int line_width, pixel_size; 827 int xend, yend; 828 int i, j; 829 vm_offset_t draw_pos; 830 831 line_width = scp->sc->adp->va_line_width; 832 pixel_size = scp->sc->adp->va_info.vi_pixel_size; 833 834 xend = imin(x + 8, 8 * (scp->xoff + scp->xsize)); 835 yend = imin(y + 16, scp->font_size * (scp->yoff + scp->ysize)); 836 837 draw_pos = scp->sc->adp->va_window + y * line_width + x * pixel_size; 838 839 for (i = 0; i < (yend - y); i++) { 840 for (j = (xend - x - 1); j >= 0; j--) { 841 switch (scp->sc->adp->va_info.vi_depth) { 842 case 32: 843 if (mouse_or_mask[i] & 1 << (15 - j)) 844 writel(draw_pos + 4 * j, 845 scp->ega_palette[15]); 846 else if (mouse_and_mask[i] & 1 << (15 - j)) 847 writel(draw_pos + 4 * j, 848 scp->ega_palette[0]); 849 break; 850 case 16: 851 /* FALLTHROUGH */ 852 case 15: 853 if (mouse_or_mask[i] & 1 << (15 - j)) 854 writew(draw_pos + 2 * j, 855 scp->ega_palette[15]); 856 else if (mouse_and_mask[i] & 1 << (15 - j)) 857 writew(draw_pos + 2 * j, 858 scp->ega_palette[0]); 859 break; 860 } 861 } 862 863 draw_pos += line_width; 864 } 865 } 866 867 static void 868 draw_pxlmouse_planar(scr_stat *scp, int x, int y) 869 { 870 vm_offset_t p; 871 int line_width; 872 int xoff; 873 int ymax; 874 u_short m; 875 int i, j; 876 877 line_width = scp->sc->adp->va_line_width; 878 xoff = (x - scp->xoff*8)%8; 879 ymax = imin(y + 16, scp->font_size * (scp->yoff + scp->ysize)); 880 881 outw(GDCIDX, 0x0805); /* read mode 1, write mode 0 */ 882 outw(GDCIDX, 0x0001); /* set/reset enable */ 883 outw(GDCIDX, 0x0002); /* color compare */ 884 outw(GDCIDX, 0x0007); /* color don't care */ 885 outw(GDCIDX, 0xff08); /* bit mask */ 886 outw(GDCIDX, 0x0803); /* data rotate/function select (and) */ 887 p = scp->sc->adp->va_window + line_width*y + x/8; 888 if (x < 8 * (scp->xoff + scp->xsize) - 8) { 889 for (i = y, j = 0; i < ymax; ++i, ++j) { 890 m = ~(mouse_and_mask[j] >> xoff); 891 *(u_char *)p &= m >> 8; 892 *(u_char *)(p + 1) &= m; 893 p += line_width; 894 } 895 } else { 896 xoff += 8; 897 for (i = y, j = 0; i < ymax; ++i, ++j) { 898 m = ~(mouse_and_mask[j] >> xoff); 899 *(u_char *)p &= m; 900 p += line_width; 901 } 902 } 903 outw(GDCIDX, 0x1003); /* data rotate/function select (or) */ 904 p = scp->sc->adp->va_window + line_width*y + x/8; 905 if (x < 8 * (scp->xoff + scp->xsize) - 8) { 906 for (i = y, j = 0; i < ymax; ++i, ++j) { 907 m = mouse_or_mask[j] >> xoff; 908 *(u_char *)p &= m >> 8; 909 *(u_char *)(p + 1) &= m; 910 p += line_width; 911 } 912 } else { 913 for (i = y, j = 0; i < ymax; ++i, ++j) { 914 m = mouse_or_mask[j] >> xoff; 915 *(u_char *)p &= m; 916 p += line_width; 917 } 918 } 919 outw(GDCIDX, 0x0005); /* read mode 0, write mode 0 */ 920 outw(GDCIDX, 0x0003); /* data rotate/function select */ 921 } 922 923 static void 924 remove_pxlmouse(scr_stat *scp, int x, int y) 925 { 926 int col, row; 927 int pos; 928 int i; 929 930 /* erase the mouse cursor image */ 931 col = x/8 - scp->xoff; 932 row = y/scp->font_size - scp->yoff; 933 pos = row*scp->xsize + col; 934 i = (col < scp->xsize - 1) ? 2 : 1; 935 (*scp->rndr->draw)(scp, pos, i, FALSE); 936 if (row < scp->ysize - 1) 937 (*scp->rndr->draw)(scp, pos + scp->xsize, i, FALSE); 938 } 939 940 static void 941 vga_pxlmouse_direct(scr_stat *scp, int x, int y, int on) 942 { 943 if (on) 944 draw_pxlmouse_direct(scp, x, y); 945 else 946 remove_pxlmouse(scp, x, y); 947 } 948 949 static void 950 vga_pxlmouse_planar(scr_stat *scp, int x, int y, int on) 951 { 952 if (on) 953 draw_pxlmouse_planar(scp, x, y); 954 else 955 remove_pxlmouse(scp, x, y); 956 } 957 958 #endif /* SC_NO_CUTPASTE */ 959 #endif /* SC_PIXEL_MODE */ 960 961 #ifndef SC_NO_MODE_CHANGE 962 963 /* graphics mode renderer */ 964 965 static void 966 vga_grborder(scr_stat *scp, int color) 967 { 968 (*vidsw[scp->sc->adapter]->set_border)(scp->sc->adp, color); 969 } 970 971 #endif 972