comparison src/video/fbcon/SDL_fbvideo.c @ 4256:ba587a51f899 SDL-1.2

Vitaly Minko to slouken Hi all, I wrote a patch, which allows user to rotate the screen in case of fbcon driver. The rotation angle is controlled by SDL_VIDEO_FBCON_ROTATION environment variable and possible values are: not set - Not rotating, no shadow. "NONE" - Not rotating, but still using shadow. "CW" - Rotating screen clockwise. "UD" - Rotating screen upside down. "CCW" - Rotating screen counter clockwise. The patch is based on wscons driver, written by Staffan Ulfberg. I tested it on Device: Sharp Zaurus SL-C1000 SDL version: 1.2.13 Kernel version: 2.6.24.4 Best regards, Vitaly.
author Sam Lantinga <slouken@libsdl.org>
date Mon, 28 Sep 2009 06:23:22 +0000
parents bec67d0b6645
children ca02f877d055
comparison
equal deleted inserted replaced
4255:5a203e2b0162 4256:ba587a51f899
124 { 1280, 1024, 9369, 224, 32, 32, 4, 136, 4, 0, 0 }, /* 60 Hz */ 124 { 1280, 1024, 9369, 224, 32, 32, 4, 136, 4, 0, 0 }, /* 60 Hz */
125 { 1408, 1056, 8214, 256, 40, 32, 5, 144, 5, 0, 0 }, /* 60 Hz */ 125 { 1408, 1056, 8214, 256, 40, 32, 5, 144, 5, 0, 0 }, /* 60 Hz */
126 { 1600, 1200,/*?*/0, 272, 48, 32, 5, 152, 5, 0, 0 }, /* 60 Hz */ 126 { 1600, 1200,/*?*/0, 272, 48, 32, 5, 152, 5, 0, 0 }, /* 60 Hz */
127 #endif 127 #endif
128 }; 128 };
129 enum {
130 FBCON_ROTATE_NONE = 0,
131 FBCON_ROTATE_CCW = 90,
132 FBCON_ROTATE_UD = 180,
133 FBCON_ROTATE_CW = 270
134 };
135
136 #define min(a,b) ((a)<(b)?(a):(b))
129 137
130 /* Initialization/Query functions */ 138 /* Initialization/Query functions */
131 static int FB_VideoInit(_THIS, SDL_PixelFormat *vformat); 139 static int FB_VideoInit(_THIS, SDL_PixelFormat *vformat);
132 static SDL_Rect **FB_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags); 140 static SDL_Rect **FB_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
133 static SDL_Surface *FB_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags); 141 static SDL_Surface *FB_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
150 158
151 /* Internal palette functions */ 159 /* Internal palette functions */
152 static void FB_SavePalette(_THIS, struct fb_fix_screeninfo *finfo, 160 static void FB_SavePalette(_THIS, struct fb_fix_screeninfo *finfo,
153 struct fb_var_screeninfo *vinfo); 161 struct fb_var_screeninfo *vinfo);
154 static void FB_RestorePalette(_THIS); 162 static void FB_RestorePalette(_THIS);
163
164 /* Shadow buffer functions */
165 static FB_bitBlit FB_blit16;
166 static FB_bitBlit FB_blit16blocked;
155 167
156 static int SDL_getpagesize(void) 168 static int SDL_getpagesize(void)
157 { 169 {
158 #ifdef HAVE_GETPAGESIZE 170 #ifdef HAVE_GETPAGESIZE
159 return getpagesize(); 171 return getpagesize();
489 int i, j; 501 int i, j;
490 int current_index; 502 int current_index;
491 unsigned int current_w; 503 unsigned int current_w;
492 unsigned int current_h; 504 unsigned int current_h;
493 const char *SDL_fbdev; 505 const char *SDL_fbdev;
506 const char *rotation;
494 FILE *modesdb; 507 FILE *modesdb;
495 508
496 /* Initialize the library */ 509 /* Initialize the library */
497 SDL_fbdev = SDL_getenv("SDL_FBDEV"); 510 SDL_fbdev = SDL_getenv("SDL_FBDEV");
498 if ( SDL_fbdev == NULL ) { 511 if ( SDL_fbdev == NULL ) {
617 /* Hmm, failed to memory map I/O registers */ 630 /* Hmm, failed to memory map I/O registers */
618 mapped_io = NULL; 631 mapped_io = NULL;
619 } 632 }
620 } 633 }
621 634
635 rotate = FBCON_ROTATE_NONE;
636 rotation = SDL_getenv("SDL_VIDEO_FBCON_ROTATION");
637 if (rotation != NULL) {
638 if (SDL_strlen(rotation) == 0) {
639 shadow_fb = 0;
640 rotate = FBCON_ROTATE_NONE;
641 #ifdef FBCON_DEBUG
642 printf("Not rotating, no shadow\n");
643 #endif
644 } else if (!SDL_strcmp(rotation, "NONE")) {
645 shadow_fb = 1;
646 rotate = FBCON_ROTATE_NONE;
647 #ifdef FBCON_DEBUG
648 printf("Not rotating, but still using shadow\n");
649 #endif
650 } else if (!SDL_strcmp(rotation, "CW")) {
651 shadow_fb = 1;
652 rotate = FBCON_ROTATE_CW;
653 #ifdef FBCON_DEBUG
654 printf("Rotating screen clockwise\n");
655 #endif
656 } else if (!SDL_strcmp(rotation, "CCW")) {
657 shadow_fb = 1;
658 rotate = FBCON_ROTATE_CCW;
659 #ifdef FBCON_DEBUG
660 printf("Rotating screen counter clockwise\n");
661 #endif
662 } else if (!SDL_strcmp(rotation, "UD")) {
663 shadow_fb = 1;
664 rotate = FBCON_ROTATE_UD;
665 #ifdef FBCON_DEBUG
666 printf("Rotating screen upside down\n");
667 #endif
668 } else {
669 SDL_SetError("\"%s\" is not a valid value for "
670 "SDL_VIDEO_FBCON_ROTATION", rotation);
671 return(-1);
672 }
673 }
674
675 if (rotate == FBCON_ROTATE_CW || rotate == FBCON_ROTATE_CCW) {
676 current_w = vinfo.yres;
677 current_h = vinfo.xres;
678 } else {
679 current_w = vinfo.xres;
680 current_h = vinfo.yres;
681 }
682
622 /* Query for the list of available video modes */ 683 /* Query for the list of available video modes */
623 current_w = vinfo.xres;
624 current_h = vinfo.yres;
625 current_index = ((vinfo.bits_per_pixel+7)/8)-1; 684 current_index = ((vinfo.bits_per_pixel+7)/8)-1;
626 modesdb = fopen(FB_MODES_DB, "r"); 685 modesdb = fopen(FB_MODES_DB, "r");
627 for ( i=0; i<NUM_MODELISTS; ++i ) { 686 for ( i=0; i<NUM_MODELISTS; ++i ) {
628 SDL_nummodes[i] = 0; 687 SDL_nummodes[i] = 0;
629 SDL_modelist[i] = NULL; 688 SDL_modelist[i] = NULL;
633 } else if(modesdb) { 692 } else if(modesdb) {
634 while ( read_fbmodes_mode(modesdb, &vinfo) ) { 693 while ( read_fbmodes_mode(modesdb, &vinfo) ) {
635 for ( i=0; i<NUM_MODELISTS; ++i ) { 694 for ( i=0; i<NUM_MODELISTS; ++i ) {
636 unsigned int w, h; 695 unsigned int w, h;
637 696
697 if (rotate == FBCON_ROTATE_CW || rotate == FBCON_ROTATE_CCW) {
698 w = vinfo.yres;
699 h = vinfo.xres;
700 } else {
701 w = vinfo.xres;
702 h = vinfo.yres;
703 }
638 /* See if we are querying for the current mode */ 704 /* See if we are querying for the current mode */
639 w = vinfo.xres;
640 h = vinfo.yres;
641 if ( i == current_index ) { 705 if ( i == current_index ) {
642 if ( (current_w > w) || (current_h > h) ) { 706 if ( (current_w > w) || (current_h > h) ) {
643 /* Only check once */ 707 /* Only check once */
644 FB_AddMode(this, i, current_w, current_h, 0); 708 FB_AddMode(this, i, current_w, current_h, 0);
645 current_index = -1; 709 current_index = -1;
655 } else { 719 } else {
656 for ( i=0; i<NUM_MODELISTS; ++i ) { 720 for ( i=0; i<NUM_MODELISTS; ++i ) {
657 for ( j=0; j<(sizeof(checkres)/sizeof(checkres[0])); ++j ) { 721 for ( j=0; j<(sizeof(checkres)/sizeof(checkres[0])); ++j ) {
658 unsigned int w, h; 722 unsigned int w, h;
659 723
724 if (rotate == FBCON_ROTATE_CW || rotate == FBCON_ROTATE_CCW) {
725 w = checkres[j].h;
726 h = checkres[j].w;
727 } else {
728 w = checkres[j].w;
729 h = checkres[j].h;
730 }
660 /* See if we are querying for the current mode */ 731 /* See if we are querying for the current mode */
661 w = checkres[j].w;
662 h = checkres[j].h;
663 if ( i == current_index ) { 732 if ( i == current_index ) {
664 if ( (current_w > w) || (current_h > h) ) { 733 if ( (current_w > w) || (current_h > h) ) {
665 /* Only check once */ 734 /* Only check once */
666 FB_AddMode(this, i, current_w, current_h, 0); 735 FB_AddMode(this, i, current_w, current_h, 0);
667 current_index = -1; 736 current_index = -1;
672 } 741 }
673 } 742 }
674 } 743 }
675 } 744 }
676 745
677 /* Fill in our hardware acceleration capabilities */
678 this->info.current_w = current_w; 746 this->info.current_w = current_w;
679 this->info.current_h = current_h; 747 this->info.current_h = current_h;
680 this->info.wm_available = 0; 748 this->info.wm_available = 0;
681 this->info.hw_available = 1; 749 this->info.hw_available = !shadow_fb;
682 this->info.video_mem = finfo.smem_len/1024; 750 this->info.video_mem = shadow_fb ? 0 : finfo.smem_len/1024;
751 /* Fill in our hardware acceleration capabilities */
683 if ( mapped_io ) { 752 if ( mapped_io ) {
684 switch (finfo.accel) { 753 switch (finfo.accel) {
685 case FB_ACCEL_MATROX_MGA2064W: 754 case FB_ACCEL_MATROX_MGA2064W:
686 case FB_ACCEL_MATROX_MGA1064SG: 755 case FB_ACCEL_MATROX_MGA1064SG:
687 case FB_ACCEL_MATROX_MGA2164W: 756 case FB_ACCEL_MATROX_MGA2164W:
711 #ifdef FBACCEL_DEBUG 780 #ifdef FBACCEL_DEBUG
712 printf("Unknown hardware accelerator.\n"); 781 printf("Unknown hardware accelerator.\n");
713 #endif 782 #endif
714 break; 783 break;
715 } 784 }
785 }
786
787 if (shadow_fb) {
788 shadow_mem = (char *)SDL_malloc(mapped_memlen);
789 if (shadow_mem == NULL) {
790 SDL_SetError("No memory for shadow");
791 return (-1);
792 }
716 } 793 }
717 794
718 /* Enable mouse and keyboard support */ 795 /* Enable mouse and keyboard support */
719 if ( FB_OpenKeyboard(this) < 0 ) { 796 if ( FB_OpenKeyboard(this) < 0 ) {
720 FB_VideoQuit(this); 797 FB_VideoQuit(this);
945 } 1022 }
946 #ifdef FBCON_DEBUG 1023 #ifdef FBCON_DEBUG
947 fprintf(stderr, "Printing original vinfo:\n"); 1024 fprintf(stderr, "Printing original vinfo:\n");
948 print_vinfo(&vinfo); 1025 print_vinfo(&vinfo);
949 #endif 1026 #endif
1027 /* Do not use double buffering with shadow buffer */
1028 if (shadow_fb) {
1029 flags &= ~SDL_DOUBLEBUF;
1030 }
1031
950 if ( (vinfo.xres != width) || (vinfo.yres != height) || 1032 if ( (vinfo.xres != width) || (vinfo.yres != height) ||
951 (vinfo.bits_per_pixel != bpp) || (flags & SDL_DOUBLEBUF) ) { 1033 (vinfo.bits_per_pixel != bpp) || (flags & SDL_DOUBLEBUF) ) {
952 vinfo.activate = FB_ACTIVATE_NOW; 1034 vinfo.activate = FB_ACTIVATE_NOW;
953 vinfo.accel_flags = 0; 1035 vinfo.accel_flags = 0;
954 vinfo.bits_per_pixel = bpp; 1036 vinfo.bits_per_pixel = bpp;
971 } 1053 }
972 #ifdef FBCON_DEBUG 1054 #ifdef FBCON_DEBUG
973 fprintf(stderr, "Printing wanted vinfo:\n"); 1055 fprintf(stderr, "Printing wanted vinfo:\n");
974 print_vinfo(&vinfo); 1056 print_vinfo(&vinfo);
975 #endif 1057 #endif
976 if ( ioctl(console_fd, FBIOPUT_VSCREENINFO, &vinfo) < 0 ) { 1058 if ( !shadow_fb &&
1059 ioctl(console_fd, FBIOPUT_VSCREENINFO, &vinfo) < 0 ) {
977 vinfo.yres_virtual = height; 1060 vinfo.yres_virtual = height;
978 if ( ioctl(console_fd, FBIOPUT_VSCREENINFO, &vinfo) < 0 ) { 1061 if ( ioctl(console_fd, FBIOPUT_VSCREENINFO, &vinfo) < 0 ) {
979 SDL_SetError("Couldn't set console screen info"); 1062 SDL_SetError("Couldn't set console screen info");
980 return(NULL); 1063 return(NULL);
981 } 1064 }
1027 } 1110 }
1028 1111
1029 /* Save hardware palette, if needed */ 1112 /* Save hardware palette, if needed */
1030 FB_SavePalette(this, &finfo, &vinfo); 1113 FB_SavePalette(this, &finfo, &vinfo);
1031 1114
1115 if (shadow_fb) {
1116 if (vinfo.bits_per_pixel == 16) {
1117 blitFunc = (rotate == FBCON_ROTATE_NONE ||
1118 rotate == FBCON_ROTATE_UD) ?
1119 FB_blit16 : FB_blit16blocked;
1120 } else {
1121 fprintf(stderr, "Init vinfo:\n");
1122 print_vinfo(&vinfo);
1123 SDL_SetError("Using software buffer, but no blitter "
1124 "function is available for %d bpp.",
1125 vinfo.bits_per_pixel);
1126 return(NULL);
1127 }
1128 }
1129
1032 /* Set up the new mode framebuffer */ 1130 /* Set up the new mode framebuffer */
1033 current->flags = (SDL_FULLSCREEN|SDL_HWSURFACE); 1131 current->flags &= SDL_FULLSCREEN;
1132 if (shadow_fb) {
1133 current->flags |= SDL_SWSURFACE;
1134 } else {
1135 current->flags |= SDL_HWSURFACE;
1136 }
1034 current->w = vinfo.xres; 1137 current->w = vinfo.xres;
1035 current->h = vinfo.yres; 1138 current->h = vinfo.yres;
1036 current->pitch = finfo.line_length; 1139 if (shadow_fb) {
1037 current->pixels = mapped_mem+mapped_offset; 1140 current->pitch = current->w * ((vinfo.bits_per_pixel + 7) / 8);
1141 current->pixels = shadow_mem;
1142 physlinebytes = finfo.line_length;
1143 } else {
1144 current->pitch = finfo.line_length;
1145 current->pixels = mapped_mem+mapped_offset;
1146 }
1038 1147
1039 /* Set up the information for hardware surfaces */ 1148 /* Set up the information for hardware surfaces */
1040 surfaces_mem = (char *)current->pixels + 1149 surfaces_mem = (char *)current->pixels +
1041 vinfo.yres_virtual*current->pitch; 1150 vinfo.yres_virtual*current->pitch;
1042 surfaces_len = (mapped_memlen-(surfaces_mem-mapped_mem)); 1151 surfaces_len = (shadow_fb) ?
1152 0 : (mapped_memlen-(surfaces_mem-mapped_mem));
1153
1043 FB_FreeHWSurfaces(this); 1154 FB_FreeHWSurfaces(this);
1044 FB_InitHWSurfaces(this, current, surfaces_mem, surfaces_len); 1155 FB_InitHWSurfaces(this, current, surfaces_mem, surfaces_len);
1045 1156
1046 /* Let the application know we have a hardware palette */ 1157 /* Let the application know we have a hardware palette */
1047 switch (finfo.visual) { 1158 switch (finfo.visual) {
1048 case FB_VISUAL_PSEUDOCOLOR: 1159 case FB_VISUAL_PSEUDOCOLOR:
1049 current->flags |= SDL_HWPALETTE; 1160 current->flags |= SDL_HWPALETTE;
1050 break; 1161 break;
1051 default: 1162 default:
1052 break; 1163 break;
1053 } 1164 }
1054 1165
1055 /* Update for double-buffering, if we can */ 1166 /* Update for double-buffering, if we can */
1056 if ( flags & SDL_DOUBLEBUF ) { 1167 if ( flags & SDL_DOUBLEBUF ) {
1057 if ( vinfo.yres_virtual == (height*2) ) { 1168 if ( vinfo.yres_virtual == (height*2) ) {
1058 current->flags |= SDL_DOUBLEBUF; 1169 current->flags |= SDL_DOUBLEBUF;
1059 flip_page = 0; 1170 flip_page = 0;
1060 flip_address[0] = (char *)current->pixels; 1171 flip_address[0] = (char *)current->pixels;
1061 flip_address[1] = (char *)current->pixels+ 1172 flip_address[1] = (char *)current->pixels+
1062 current->h*current->pitch; 1173 current->h*current->pitch;
1063 this->screen = current; 1174 this->screen = current;
1064 FB_FlipHWSurface(this, current); 1175 FB_FlipHWSurface(this, current);
1065 this->screen = NULL; 1176 this->screen = NULL;
1066 } 1177 }
1067 } 1178 }
1327 1438
1328 surface->pixels = flip_address[flip_page]; 1439 surface->pixels = flip_address[flip_page];
1329 return(0); 1440 return(0);
1330 } 1441 }
1331 1442
1443 static void FB_blit16(Uint8 *byte_src_pos, int src_right_delta, int src_down_delta,
1444 Uint8 *byte_dst_pos, int dst_linebytes, int width, int height)
1445 {
1446 int w;
1447 Uint16 *src_pos = (Uint16 *)byte_src_pos;
1448 Uint16 *dst_pos = (Uint16 *)byte_dst_pos;
1449
1450 while (height) {
1451 Uint16 *src = src_pos;
1452 Uint16 *dst = dst_pos;
1453 for (w = width; w != 0; w--) {
1454 *dst = *src;
1455 src += src_right_delta;
1456 dst++;
1457 }
1458 dst_pos = (Uint16 *)((Uint8 *)dst_pos + dst_linebytes);
1459 src_pos += src_down_delta;
1460 height--;
1461 }
1462 }
1463
1464 #define BLOCKSIZE_W 32
1465 #define BLOCKSIZE_H 32
1466
1467 static void FB_blit16blocked(Uint8 *byte_src_pos, int src_right_delta, int src_down_delta,
1468 Uint8 *byte_dst_pos, int dst_linebytes, int width, int height)
1469 {
1470 int w;
1471 Uint16 *src_pos = (Uint16 *)byte_src_pos;
1472 Uint16 *dst_pos = (Uint16 *)byte_dst_pos;
1473
1474 while (height > 0) {
1475 Uint16 *src = src_pos;
1476 Uint16 *dst = dst_pos;
1477 for (w = width; w > 0; w -= BLOCKSIZE_W) {
1478 FB_blit16((Uint8 *)src,
1479 src_right_delta,
1480 src_down_delta,
1481 (Uint8 *)dst,
1482 dst_linebytes,
1483 min(w, BLOCKSIZE_W),
1484 min(height, BLOCKSIZE_H));
1485 src += src_right_delta * BLOCKSIZE_W;
1486 dst += BLOCKSIZE_W;
1487 }
1488 dst_pos = (Uint16 *)((Uint8 *)dst_pos + dst_linebytes * BLOCKSIZE_H);
1489 src_pos += src_down_delta * BLOCKSIZE_H;
1490 height -= BLOCKSIZE_H;
1491 }
1492 }
1493
1332 static void FB_DirectUpdate(_THIS, int numrects, SDL_Rect *rects) 1494 static void FB_DirectUpdate(_THIS, int numrects, SDL_Rect *rects)
1333 { 1495 {
1334 /* The application is already updating the visible video memory */ 1496 int width = cache_vinfo.xres;
1335 return; 1497 int height = cache_vinfo.yres;
1498 int bytes_per_pixel = (cache_vinfo.bits_per_pixel + 7) / 8;
1499 int i;
1500
1501 if (!shadow_fb) {
1502 /* The application is already updating the visible video memory */
1503 return;
1504 }
1505
1506 if (cache_vinfo.bits_per_pixel != 16) {
1507 SDL_SetError("Shadow copy only implemented for 16 bpp");
1508 return;
1509 }
1510
1511 for (i = 0; i < numrects; i++) {
1512 int x1, y1, x2, y2;
1513 int scr_x1, scr_y1, scr_x2, scr_y2;
1514 int sha_x1, sha_y1;
1515 int shadow_right_delta; /* Address change when moving right in dest */
1516 int shadow_down_delta; /* Address change when moving down in dest */
1517 char *src_start;
1518 char *dst_start;
1519
1520 x1 = rects[i].x;
1521 y1 = rects[i].y;
1522 x2 = x1 + rects[i].w;
1523 y2 = y1 + rects[i].h;
1524
1525 if (x1 < 0) {
1526 x1 = 0;
1527 } else if (x1 > width) {
1528 x1 = width;
1529 }
1530 if (x2 < 0) {
1531 x2 = 0;
1532 } else if (x2 > width) {
1533 x2 = width;
1534 }
1535 if (y1 < 0) {
1536 y1 = 0;
1537 } else if (y1 > height) {
1538 y1 = height;
1539 }
1540 if (y2 < 0) {
1541 y2 = 0;
1542 } else if (y2 > height) {
1543 y2 = height;
1544 }
1545 if (x2 <= x1 || y2 <= y1) {
1546 continue;
1547 }
1548
1549 switch (rotate) {
1550 case FBCON_ROTATE_NONE:
1551 sha_x1 = scr_x1 = x1;
1552 sha_y1 = scr_y1 = y1;
1553 scr_x2 = x2;
1554 scr_y2 = y2;
1555 shadow_right_delta = 1;
1556 shadow_down_delta = width;
1557 break;
1558 case FBCON_ROTATE_CCW:
1559 scr_x1 = y1;
1560 scr_y1 = width - x2;
1561 scr_x2 = y2;
1562 scr_y2 = width - x1;
1563 sha_x1 = x2 - 1;
1564 sha_y1 = y1;
1565 shadow_right_delta = width;
1566 shadow_down_delta = -1;
1567 break;
1568 case FBCON_ROTATE_UD:
1569 scr_x1 = width - x2;
1570 scr_y1 = height - y2;
1571 scr_x2 = width - x1;
1572 scr_y2 = height - y1;
1573 sha_x1 = x2 - 1;
1574 sha_y1 = y2 - 1;
1575 shadow_right_delta = -1;
1576 shadow_down_delta = -width;
1577 break;
1578 case FBCON_ROTATE_CW:
1579 scr_x1 = height - y2;
1580 scr_y1 = x1;
1581 scr_x2 = height - y1;
1582 scr_y2 = x2;
1583 sha_x1 = x1;
1584 sha_y1 = y2 - 1;
1585 shadow_right_delta = -width;
1586 shadow_down_delta = 1;
1587 break;
1588 default:
1589 SDL_SetError("Unknown rotation");
1590 return;
1591 }
1592
1593 src_start = shadow_mem +
1594 (sha_y1 * width + sha_x1) * bytes_per_pixel;
1595 dst_start = mapped_mem + mapped_offset + scr_y1 * physlinebytes +
1596 scr_x1 * bytes_per_pixel;
1597
1598 blitFunc((Uint8 *) src_start,
1599 shadow_right_delta,
1600 shadow_down_delta,
1601 (Uint8 *) dst_start,
1602 physlinebytes,
1603 scr_x2 - scr_x1,
1604 scr_y2 - scr_y1);
1605 }
1336 } 1606 }
1337 1607
1338 #ifdef VGA16_FBCON_SUPPORT 1608 #ifdef VGA16_FBCON_SUPPORT
1339 /* Code adapted with thanks from the XFree86 VGA16 driver! :) */ 1609 /* Code adapted with thanks from the XFree86 VGA16 driver! :) */
1340 #define writeGr(index, value) \ 1610 #define writeGr(index, value) \