1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1991-1997 Søren Schmidt 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer 12 * in this position and unchanged. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include <signal.h> 35 #include <sys/fbio.h> 36 #include "vgl.h" 37 38 static byte VGLSavePaletteRed[256]; 39 static byte VGLSavePaletteGreen[256]; 40 static byte VGLSavePaletteBlue[256]; 41 42 #define ABS(a) (((a)<0) ? -(a) : (a)) 43 #define SGN(a) (((a)<0) ? -1 : 1) 44 #define min(x, y) (((x) < (y)) ? (x) : (y)) 45 #define max(x, y) (((x) > (y)) ? (x) : (y)) 46 47 static void 48 color2mem(u_long color, byte *b, int len) 49 { 50 switch (len) { 51 case 4: 52 b[3] = (color >> 24) & 0xff; 53 /* fallthrough */ 54 case 3: 55 b[2] = (color >> 16) & 0xff; 56 /* fallthrough */ 57 case 2: 58 b[1] = (color >> 8) & 0xff; 59 /* fallthrough */ 60 case 1: 61 default: 62 b[0] = color & 0xff; 63 break; 64 } 65 66 return; 67 } 68 69 static u_long 70 mem2color(byte *b, int len) 71 { 72 u_long color = 0; 73 74 switch (len) { 75 case 4: 76 color |= (b[3] & 0xff) << 24; 77 /* fallthrough */ 78 case 3: 79 color |= (b[2] & 0xff) << 16; 80 /* fallthrough */ 81 case 2: 82 color |= (b[1] & 0xff) << 8; 83 /* fallthrough */ 84 case 1: 85 default: 86 color |= (b[0] & 0xff); 87 break; 88 } 89 90 return color; 91 } 92 93 void 94 VGLSetXY(VGLBitmap *object, int x, int y, u_long color) 95 { 96 int offset; 97 byte b[4]; 98 99 VGLCheckSwitch(); 100 if (x>=0 && x<object->VXsize && y>=0 && y<object->VYsize) { 101 if (!VGLMouseFreeze(x, y, 1, 1, color)) { 102 switch (object->Type) { 103 case MEMBUF: 104 case VIDBUF8: 105 object->Bitmap[y*object->VXsize+x]=((byte)color); 106 break; 107 case VIDBUF8S: 108 object->Bitmap[VGLSetSegment(y*object->VXsize+x)]=((byte)color); 109 break; 110 case VIDBUF16: 111 case VIDBUF24: 112 case VIDBUF32: 113 color2mem(color, b, object->PixelBytes); 114 bcopy(b, &object->Bitmap[(y*object->VXsize+x) * object->PixelBytes], 115 object->PixelBytes); 116 break; 117 case VIDBUF16S: 118 case VIDBUF24S: 119 case VIDBUF32S: 120 color2mem(color, b, object->PixelBytes); 121 offset = VGLSetSegment((y*object->VXsize+x) * object->PixelBytes); 122 bcopy(b, &object->Bitmap[offset], object->PixelBytes); 123 break; 124 case VIDBUF8X: 125 outb(0x3c4, 0x02); 126 outb(0x3c5, 0x01 << (x&0x3)); 127 object->Bitmap[(unsigned)(VGLAdpInfo.va_line_width*y)+(x/4)] = ((byte)color); 128 break; 129 case VIDBUF4S: 130 offset = VGLSetSegment(y*VGLAdpInfo.va_line_width + x/8); 131 goto set_planar; 132 case VIDBUF4: 133 offset = y*VGLAdpInfo.va_line_width + x/8; 134 set_planar: 135 outb(0x3c4, 0x02); outb(0x3c5, 0x0f); 136 outb(0x3ce, 0x00); outb(0x3cf, (byte)color & 0x0f); /* set/reset */ 137 outb(0x3ce, 0x01); outb(0x3cf, 0x0f); /* set/reset enable */ 138 outb(0x3ce, 0x08); outb(0x3cf, 0x80 >> (x%8)); /* bit mask */ 139 object->Bitmap[offset] |= (byte)color; 140 } 141 } 142 VGLMouseUnFreeze(); 143 } 144 } 145 146 u_long 147 VGLGetXY(VGLBitmap *object, int x, int y) 148 { 149 int offset; 150 byte b[4]; 151 int i; 152 u_long color; 153 byte mask; 154 155 VGLCheckSwitch(); 156 if (x<0 || x>=object->VXsize || y<0 || y>=object->VYsize) 157 return 0; 158 switch (object->Type) { 159 case MEMBUF: 160 case VIDBUF8: 161 return object->Bitmap[((y*object->VXsize)+x)]; 162 case VIDBUF8S: 163 return object->Bitmap[VGLSetSegment(y*object->VXsize+x)]; 164 case VIDBUF16: 165 case VIDBUF24: 166 case VIDBUF32: 167 bcopy(&object->Bitmap[(y*object->VXsize+x) * object->PixelBytes], 168 b, object->PixelBytes); 169 return (mem2color(b, object->PixelBytes)); 170 case VIDBUF16S: 171 case VIDBUF24S: 172 case VIDBUF32S: 173 offset = VGLSetSegment((y*object->VXsize+x) * object->PixelBytes); 174 bcopy(&object->Bitmap[offset], b, object->PixelBytes); 175 176 return (mem2color(b, object->PixelBytes)); 177 case VIDBUF8X: 178 outb(0x3ce, 0x04); outb(0x3cf, x & 0x3); 179 return object->Bitmap[(unsigned)(VGLAdpInfo.va_line_width*y)+(x/4)]; 180 case VIDBUF4S: 181 offset = VGLSetSegment(y*VGLAdpInfo.va_line_width + x/8); 182 goto get_planar; 183 case VIDBUF4: 184 offset = y*VGLAdpInfo.va_line_width + x/8; 185 get_planar: 186 color = 0; 187 mask = 0x80 >> (x%8); 188 for (i = 0; i < VGLModeInfo.vi_planes; i++) { 189 outb(0x3ce, 0x04); outb(0x3cf, i); 190 color |= (((volatile VGLBitmap *)object)->Bitmap[offset] & mask) ? 191 (1 << i) : 0; 192 } 193 return color; 194 } 195 return 0; /* XXX black? */ 196 } 197 198 /* 199 * Symmetric Double Step Line Algorithm by Brian Wyvill from 200 * "Graphics Gems", Academic Press, 1990. 201 */ 202 203 #define SL_SWAP(a,b) {a^=b; b^=a; a^=b;} 204 #define SL_ABSOLUTE(i,j,k) ( (i-j)*(k = ( (i-j)<0 ? -1 : 1))) 205 206 void 207 plot(VGLBitmap * object, int x, int y, int flag, byte color) 208 { 209 /* non-zero flag indicates the pixels need swapping back. */ 210 if (flag) 211 VGLSetXY(object, y, x, color); 212 else 213 VGLSetXY(object, x, y, color); 214 } 215 216 217 void 218 VGLLine(VGLBitmap *object, int x1, int y1, int x2, int y2, u_long color) 219 { 220 int dx, dy, incr1, incr2, D, x, y, xend, c, pixels_left; 221 int sign_x, sign_y, step, reverse, i; 222 223 dx = SL_ABSOLUTE(x2, x1, sign_x); 224 dy = SL_ABSOLUTE(y2, y1, sign_y); 225 /* decide increment sign by the slope sign */ 226 if (sign_x == sign_y) 227 step = 1; 228 else 229 step = -1; 230 231 if (dy > dx) { /* chooses axis of greatest movement (make dx) */ 232 SL_SWAP(x1, y1); 233 SL_SWAP(x2, y2); 234 SL_SWAP(dx, dy); 235 reverse = 1; 236 } else 237 reverse = 0; 238 /* note error check for dx==0 should be included here */ 239 if (x1 > x2) { /* start from the smaller coordinate */ 240 x = x2; 241 y = y2; 242 /* x1 = x1; 243 y1 = y1; */ 244 } else { 245 x = x1; 246 y = y1; 247 x1 = x2; 248 y1 = y2; 249 } 250 251 252 /* Note dx=n implies 0 - n or (dx+1) pixels to be set */ 253 /* Go round loop dx/4 times then plot last 0,1,2 or 3 pixels */ 254 /* In fact (dx-1)/4 as 2 pixels are already plotted */ 255 xend = (dx - 1) / 4; 256 pixels_left = (dx - 1) % 4; /* number of pixels left over at the 257 * end */ 258 plot(object, x, y, reverse, color); 259 if (pixels_left < 0) 260 return; /* plot only one pixel for zero length 261 * vectors */ 262 plot(object, x1, y1, reverse, color); /* plot first two points */ 263 incr2 = 4 * dy - 2 * dx; 264 if (incr2 < 0) { /* slope less than 1/2 */ 265 c = 2 * dy; 266 incr1 = 2 * c; 267 D = incr1 - dx; 268 269 for (i = 0; i < xend; i++) { /* plotting loop */ 270 ++x; 271 --x1; 272 if (D < 0) { 273 /* pattern 1 forwards */ 274 plot(object, x, y, reverse, color); 275 plot(object, ++x, y, reverse, color); 276 /* pattern 1 backwards */ 277 plot(object, x1, y1, reverse, color); 278 plot(object, --x1, y1, reverse, color); 279 D += incr1; 280 } else { 281 if (D < c) { 282 /* pattern 2 forwards */ 283 plot(object, x, y, reverse, color); 284 plot(object, ++x, y += step, reverse, 285 color); 286 /* pattern 2 backwards */ 287 plot(object, x1, y1, reverse, color); 288 plot(object, --x1, y1 -= step, reverse, 289 color); 290 } else { 291 /* pattern 3 forwards */ 292 plot(object, x, y += step, reverse, color); 293 plot(object, ++x, y, reverse, color); 294 /* pattern 3 backwards */ 295 plot(object, x1, y1 -= step, reverse, 296 color); 297 plot(object, --x1, y1, reverse, color); 298 } 299 D += incr2; 300 } 301 } /* end for */ 302 303 /* plot last pattern */ 304 if (pixels_left) { 305 if (D < 0) { 306 plot(object, ++x, y, reverse, color); /* pattern 1 */ 307 if (pixels_left > 1) 308 plot(object, ++x, y, reverse, color); 309 if (pixels_left > 2) 310 plot(object, --x1, y1, reverse, color); 311 } else { 312 if (D < c) { 313 plot(object, ++x, y, reverse, color); /* pattern 2 */ 314 if (pixels_left > 1) 315 plot(object, ++x, y += step, reverse, color); 316 if (pixels_left > 2) 317 plot(object, --x1, y1, reverse, color); 318 } else { 319 /* pattern 3 */ 320 plot(object, ++x, y += step, reverse, color); 321 if (pixels_left > 1) 322 plot(object, ++x, y, reverse, color); 323 if (pixels_left > 2) 324 plot(object, --x1, y1 -= step, reverse, color); 325 } 326 } 327 } /* end if pixels_left */ 328 } 329 /* end slope < 1/2 */ 330 else { /* slope greater than 1/2 */ 331 c = 2 * (dy - dx); 332 incr1 = 2 * c; 333 D = incr1 + dx; 334 for (i = 0; i < xend; i++) { 335 ++x; 336 --x1; 337 if (D > 0) { 338 /* pattern 4 forwards */ 339 plot(object, x, y += step, reverse, color); 340 plot(object, ++x, y += step, reverse, color); 341 /* pattern 4 backwards */ 342 plot(object, x1, y1 -= step, reverse, color); 343 plot(object, --x1, y1 -= step, reverse, color); 344 D += incr1; 345 } else { 346 if (D < c) { 347 /* pattern 2 forwards */ 348 plot(object, x, y, reverse, color); 349 plot(object, ++x, y += step, reverse, 350 color); 351 352 /* pattern 2 backwards */ 353 plot(object, x1, y1, reverse, color); 354 plot(object, --x1, y1 -= step, reverse, 355 color); 356 } else { 357 /* pattern 3 forwards */ 358 plot(object, x, y += step, reverse, color); 359 plot(object, ++x, y, reverse, color); 360 /* pattern 3 backwards */ 361 plot(object, x1, y1 -= step, reverse, color); 362 plot(object, --x1, y1, reverse, color); 363 } 364 D += incr2; 365 } 366 } /* end for */ 367 /* plot last pattern */ 368 if (pixels_left) { 369 if (D > 0) { 370 plot(object, ++x, y += step, reverse, color); /* pattern 4 */ 371 if (pixels_left > 1) 372 plot(object, ++x, y += step, reverse, 373 color); 374 if (pixels_left > 2) 375 plot(object, --x1, y1 -= step, reverse, 376 color); 377 } else { 378 if (D < c) { 379 plot(object, ++x, y, reverse, color); /* pattern 2 */ 380 if (pixels_left > 1) 381 plot(object, ++x, y += step, reverse, color); 382 if (pixels_left > 2) 383 plot(object, --x1, y1, reverse, color); 384 } else { 385 /* pattern 3 */ 386 plot(object, ++x, y += step, reverse, color); 387 if (pixels_left > 1) 388 plot(object, ++x, y, reverse, color); 389 if (pixels_left > 2) { 390 if (D > c) /* step 3 */ 391 plot(object, --x1, y1 -= step, reverse, color); 392 else /* step 2 */ 393 plot(object, --x1, y1, reverse, color); 394 } 395 } 396 } 397 } 398 } 399 } 400 401 void 402 VGLBox(VGLBitmap *object, int x1, int y1, int x2, int y2, u_long color) 403 { 404 VGLLine(object, x1, y1, x2, y1, color); 405 VGLLine(object, x2, y1, x2, y2, color); 406 VGLLine(object, x2, y2, x1, y2, color); 407 VGLLine(object, x1, y2, x1, y1, color); 408 } 409 410 void 411 VGLFilledBox(VGLBitmap *object, int x1, int y1, int x2, int y2, u_long color) 412 { 413 int y; 414 415 for (y=y1; y<=y2; y++) VGLLine(object, x1, y, x2, y, color); 416 } 417 418 static inline void 419 set4pixels(VGLBitmap *object, int x, int y, int xc, int yc, u_long color) 420 { 421 if (x!=0) { 422 VGLSetXY(object, xc+x, yc+y, color); 423 VGLSetXY(object, xc-x, yc+y, color); 424 if (y!=0) { 425 VGLSetXY(object, xc+x, yc-y, color); 426 VGLSetXY(object, xc-x, yc-y, color); 427 } 428 } 429 else { 430 VGLSetXY(object, xc, yc+y, color); 431 if (y!=0) 432 VGLSetXY(object, xc, yc-y, color); 433 } 434 } 435 436 void 437 VGLEllipse(VGLBitmap *object, int xc, int yc, int a, int b, u_long color) 438 { 439 int x = 0, y = b, asq = a*a, asq2 = a*a*2, bsq = b*b; 440 int bsq2 = b*b*2, d = bsq-asq*b+asq/4, dx = 0, dy = asq2*b; 441 442 while (dx<dy) { 443 set4pixels(object, x, y, xc, yc, color); 444 if (d>0) { 445 y--; dy-=asq2; d-=dy; 446 } 447 x++; dx+=bsq2; d+=bsq+dx; 448 } 449 d+=(3*(asq-bsq)/2-(dx+dy))/2; 450 while (y>=0) { 451 set4pixels(object, x, y, xc, yc, color); 452 if (d<0) { 453 x++; dx+=bsq2; d+=dx; 454 } 455 y--; dy-=asq2; d+=asq-dy; 456 } 457 } 458 459 static inline void 460 set2lines(VGLBitmap *object, int x, int y, int xc, int yc, u_long color) 461 { 462 if (x!=0) { 463 VGLLine(object, xc+x, yc+y, xc-x, yc+y, color); 464 if (y!=0) 465 VGLLine(object, xc+x, yc-y, xc-x, yc-y, color); 466 } 467 else { 468 VGLLine(object, xc, yc+y, xc, yc-y, color); 469 } 470 } 471 472 void 473 VGLFilledEllipse(VGLBitmap *object, int xc, int yc, int a, int b, u_long color) 474 { 475 int x = 0, y = b, asq = a*a, asq2 = a*a*2, bsq = b*b; 476 int bsq2 = b*b*2, d = bsq-asq*b+asq/4, dx = 0, dy = asq2*b; 477 478 while (dx<dy) { 479 set2lines(object, x, y, xc, yc, color); 480 if (d>0) { 481 y--; dy-=asq2; d-=dy; 482 } 483 x++; dx+=bsq2; d+=bsq+dx; 484 } 485 d+=(3*(asq-bsq)/2-(dx+dy))/2; 486 while (y>=0) { 487 set2lines(object, x, y, xc, yc, color); 488 if (d<0) { 489 x++; dx+=bsq2; d+=dx; 490 } 491 y--; dy-=asq2; d+=asq-dy; 492 } 493 } 494 495 void 496 VGLClear(VGLBitmap *object, u_long color) 497 { 498 int offset; 499 int len; 500 int i, total = 0; 501 byte b[4]; 502 503 VGLCheckSwitch(); 504 VGLMouseFreeze(0, 0, object->Xsize, object->Ysize, color); /* XXX */ 505 switch (object->Type) { 506 case MEMBUF: 507 case VIDBUF8: 508 memset(object->Bitmap, (byte)color, object->VXsize*object->VYsize); 509 break; 510 511 case VIDBUF8S: 512 for (offset = 0; offset < object->VXsize*object->VYsize; ) { 513 VGLSetSegment(offset); 514 len = min(object->VXsize*object->VYsize - offset, 515 VGLAdpInfo.va_window_size); 516 memset(object->Bitmap, (byte)color, len); 517 offset += len; 518 } 519 break; 520 case VIDBUF16: 521 case VIDBUF24: 522 case VIDBUF32: 523 color2mem(color, b, object->PixelBytes); 524 total = object->VXsize*object->VYsize*object->PixelBytes; 525 for (i = 0; i < total; i += object->PixelBytes) 526 bcopy(b, object->Bitmap + i, object->PixelBytes); 527 break; 528 529 case VIDBUF16S: 530 case VIDBUF24S: 531 case VIDBUF32S: 532 color2mem(color, b, object->PixelBytes); 533 total = object->VXsize*object->VYsize*object->PixelBytes; 534 for (offset = 0; offset < total; ) { 535 VGLSetSegment(offset); 536 len = min(total - offset, VGLAdpInfo.va_window_size); 537 for (i = 0; i < len; i += object->PixelBytes) 538 bcopy(object->Bitmap + (offset + i) % VGLAdpInfo.va_window_size, b, 539 object->PixelBytes); 540 offset += len; 541 } 542 break; 543 544 case VIDBUF8X: 545 /* XXX works only for Xsize % 4 = 0 */ 546 outb(0x3c6, 0xff); 547 outb(0x3c4, 0x02); outb(0x3c5, 0x0f); 548 memset(object->Bitmap, (byte)color, VGLAdpInfo.va_line_width*object->VYsize); 549 break; 550 551 case VIDBUF4: 552 case VIDBUF4S: 553 /* XXX works only for Xsize % 8 = 0 */ 554 outb(0x3c4, 0x02); outb(0x3c5, 0x0f); 555 outb(0x3ce, 0x05); outb(0x3cf, 0x02); /* mode 2 */ 556 outb(0x3ce, 0x01); outb(0x3cf, 0x00); /* set/reset enable */ 557 outb(0x3ce, 0x08); outb(0x3cf, 0xff); /* bit mask */ 558 for (offset = 0; offset < VGLAdpInfo.va_line_width*object->VYsize; ) { 559 VGLSetSegment(offset); 560 len = min(object->VXsize*object->VYsize - offset, 561 VGLAdpInfo.va_window_size); 562 memset(object->Bitmap, (byte)color, len); 563 offset += len; 564 } 565 outb(0x3ce, 0x05); outb(0x3cf, 0x00); 566 break; 567 } 568 VGLMouseUnFreeze(); 569 } 570 571 void 572 VGLRestorePalette() 573 { 574 int i; 575 576 outb(0x3C6, 0xFF); 577 inb(0x3DA); 578 outb(0x3C8, 0x00); 579 for (i=0; i<256; i++) { 580 outb(0x3C9, VGLSavePaletteRed[i]); 581 inb(0x84); 582 outb(0x3C9, VGLSavePaletteGreen[i]); 583 inb(0x84); 584 outb(0x3C9, VGLSavePaletteBlue[i]); 585 inb(0x84); 586 } 587 inb(0x3DA); 588 outb(0x3C0, 0x20); 589 } 590 591 void 592 VGLSavePalette() 593 { 594 int i; 595 596 outb(0x3C6, 0xFF); 597 inb(0x3DA); 598 outb(0x3C7, 0x00); 599 for (i=0; i<256; i++) { 600 VGLSavePaletteRed[i] = inb(0x3C9); 601 inb(0x84); 602 VGLSavePaletteGreen[i] = inb(0x3C9); 603 inb(0x84); 604 VGLSavePaletteBlue[i] = inb(0x3C9); 605 inb(0x84); 606 } 607 inb(0x3DA); 608 outb(0x3C0, 0x20); 609 } 610 611 void 612 VGLSetPalette(byte *red, byte *green, byte *blue) 613 { 614 int i; 615 616 for (i=0; i<256; i++) { 617 VGLSavePaletteRed[i] = red[i]; 618 VGLSavePaletteGreen[i] = green[i]; 619 VGLSavePaletteBlue[i] = blue[i]; 620 } 621 VGLCheckSwitch(); 622 outb(0x3C6, 0xFF); 623 inb(0x3DA); 624 outb(0x3C8, 0x00); 625 for (i=0; i<256; i++) { 626 outb(0x3C9, VGLSavePaletteRed[i]); 627 inb(0x84); 628 outb(0x3C9, VGLSavePaletteGreen[i]); 629 inb(0x84); 630 outb(0x3C9, VGLSavePaletteBlue[i]); 631 inb(0x84); 632 } 633 inb(0x3DA); 634 outb(0x3C0, 0x20); 635 } 636 637 void 638 VGLSetPaletteIndex(byte color, byte red, byte green, byte blue) 639 { 640 VGLSavePaletteRed[color] = red; 641 VGLSavePaletteGreen[color] = green; 642 VGLSavePaletteBlue[color] = blue; 643 VGLCheckSwitch(); 644 outb(0x3C6, 0xFF); 645 inb(0x3DA); 646 outb(0x3C8, color); 647 outb(0x3C9, red); outb(0x3C9, green); outb(0x3C9, blue); 648 inb(0x3DA); 649 outb(0x3C0, 0x20); 650 } 651 652 void 653 VGLSetBorder(byte color) 654 { 655 VGLCheckSwitch(); 656 inb(0x3DA); 657 outb(0x3C0,0x11); outb(0x3C0, color); 658 inb(0x3DA); 659 outb(0x3C0, 0x20); 660 } 661 662 void 663 VGLBlankDisplay(int blank) 664 { 665 byte val; 666 667 VGLCheckSwitch(); 668 outb(0x3C4, 0x01); val = inb(0x3C5); outb(0x3C4, 0x01); 669 outb(0x3C5, ((blank) ? (val |= 0x20) : (val &= 0xDF))); 670 } 671