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