1 /* ----------------------------------------------------------------------- * 2 * 3 * Copyright 2010 Intel Corporation; author: H. Peter Anvin 4 * 5 * Permission is hereby granted, free of charge, to any person 6 * obtaining a copy of this software and associated documentation 7 * files (the "Software"), to deal in the Software without 8 * restriction, including without limitation the rights to use, 9 * copy, modify, merge, publish, distribute, sublicense, and/or 10 * sell copies of the Software, and to permit persons to whom 11 * the Software is furnished to do so, subject to the following 12 * conditions: 13 * 14 * The above copyright notice and this permission notice shall 15 * be included in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 19 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 * OTHER DEALINGS IN THE SOFTWARE. 25 * 26 * ----------------------------------------------------------------------- */ 27 28 /* 29 * Based on: 30 * 31 * 915 resolution by steve tomljenovic 32 * 33 * This was tested only on Sony VGN-FS550. Use at your own risk 34 * 35 * This code is based on the techniques used in : 36 * 37 * - 855patch. Many thanks to Christian Zietz (czietz gmx net) 38 * for demonstrating how to shadow the VBIOS into system RAM 39 * and then modify it. 40 * 41 * - 1280patch by Andrew Tipton (andrewtipton null li). 42 * 43 * - 855resolution by Alain Poirier 44 * 45 * This source code is into the public domain. 46 */ 47 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <unistd.h> 51 #define __USE_GNU 52 #include <string.h> 53 #include <sys/io.h> 54 #include <sys/cpu.h> 55 #include <sys/pci.h> 56 #include <unistd.h> 57 #include <assert.h> 58 #include <stdbool.h> 59 #include "video.h" 60 #include "debug.h" 61 62 #define VBIOS_START 0xc0000 63 #define VBIOS_SIZE 0x10000 64 65 #define MODE_TABLE_OFFSET_845G 617 66 67 #define VERSION "0.5.3" 68 69 #define ATI_SIGNATURE1 "ATI MOBILITY RADEON" 70 #define ATI_SIGNATURE2 "ATI Technologies Inc" 71 #define NVIDIA_SIGNATURE "NVIDIA Corp" 72 #define INTEL_SIGNATURE "Intel Corp" 73 74 typedef unsigned char * address; 75 76 typedef enum { 77 CT_UNKWN, CT_830, CT_845G, CT_855GM, CT_865G, CT_915G, CT_915GM, 78 CT_945G, CT_945GM, CT_946GZ, CT_G965, CT_Q965, CT_945GME, 79 CHIPSET_TYPES 80 } chipset_type; 81 82 typedef enum { 83 BT_UNKWN, BT_1, BT_2, BT_3 84 } bios_type; 85 86 static int freqs[] = { 60, 75, 85 }; 87 88 typedef struct { 89 uint8_t mode; 90 uint8_t bits_per_pixel; 91 uint16_t resolution; 92 uint8_t unknown; 93 } __attribute__((packed)) vbios_mode; 94 95 typedef struct { 96 uint16_t clock; /* Clock frequency in 10 kHz */ 97 uint8_t x1; 98 uint8_t x_total; 99 uint8_t x2; 100 uint8_t y1; 101 uint8_t y_total; 102 uint8_t y2; 103 } __attribute__((packed)) vbios_resolution_type1; 104 105 typedef struct { 106 uint32_t clock; 107 108 uint16_t x1; 109 uint16_t htotal; 110 uint16_t x2; 111 uint16_t hblank; 112 uint16_t hsyncstart; 113 uint16_t hsyncend; 114 115 uint16_t y1; 116 uint16_t vtotal; 117 uint16_t y2; 118 uint16_t vblank; 119 uint16_t vsyncstart; 120 uint16_t vsyncend; 121 } __attribute__((packed)) vbios_modeline_type2; 122 123 typedef struct { 124 uint8_t xchars; 125 uint8_t ychars; 126 uint8_t unknown[4]; 127 128 vbios_modeline_type2 modelines[]; 129 } __attribute__((packed)) vbios_resolution_type2; 130 131 typedef struct { 132 uint32_t clock; 133 134 uint16_t x1; 135 uint16_t htotal; 136 uint16_t x2; 137 uint16_t hblank; 138 uint16_t hsyncstart; 139 uint16_t hsyncend; 140 141 uint16_t y1; 142 uint16_t vtotal; 143 uint16_t y2; 144 uint16_t vblank; 145 uint16_t vsyncstart; 146 uint16_t vsyncend; 147 148 uint16_t timing_h; 149 uint16_t timing_v; 150 151 uint8_t unknown[6]; 152 } __attribute__((packed)) vbios_modeline_type3; 153 154 typedef struct { 155 unsigned char unknown[6]; 156 157 vbios_modeline_type3 modelines[]; 158 } __attribute__((packed)) vbios_resolution_type3; 159 160 161 typedef struct { 162 unsigned int chipset_id; 163 chipset_type chipset; 164 bios_type bios; 165 166 address bios_ptr; 167 168 vbios_mode * mode_table; 169 unsigned int mode_table_size; 170 171 uint8_t b1, b2; 172 173 bool unlocked; 174 } vbios_map; 175 176 #if 0 /* Debugging hacks */ 177 static void good_marker(int x) 178 { 179 ((uint16_t *)0xb8000)[x] = 0x2f30 - ((x & 0xf0) << 4) + (x & 0x0f); 180 } 181 182 static void bad_marker(int x) 183 { 184 ((uint16_t *)0xb8000)[x] = 0x4f30 - ((x & 0xf0) << 4) + (x & 0x0f); 185 } 186 187 static void status(const char *fmt, ...) 188 { 189 va_list ap; 190 char msg[81], *p; 191 int i; 192 uint16_t *q; 193 194 memset(msg, 0, sizeof msg); 195 va_start(ap, fmt); 196 vsnprintf(msg, sizeof msg, fmt, ap); 197 va_end(ap); 198 p = msg; 199 q = (uint16_t *)0xb8000 + 80; 200 for (i = 0; i < 80; i++) 201 *q++ = *p++ + 0x1f00; 202 } 203 #else 204 static inline void good_marker(int x) { (void)x; } 205 static inline void bad_marker(int x) { (void)x; } 206 static inline void status(const char *fmt, ...) { (void)fmt; } 207 #endif 208 209 static unsigned int get_chipset_id(void) { 210 return pci_readl(0x80000000); 211 } 212 213 static chipset_type get_chipset(unsigned int id) { 214 chipset_type type; 215 216 switch (id) { 217 case 0x35758086: 218 type = CT_830; 219 break; 220 221 case 0x25608086: 222 type = CT_845G; 223 break; 224 225 case 0x35808086: 226 type = CT_855GM; 227 break; 228 229 case 0x25708086: 230 type = CT_865G; 231 break; 232 233 case 0x25808086: 234 type = CT_915G; 235 break; 236 237 case 0x25908086: 238 type = CT_915GM; 239 break; 240 241 case 0x27708086: 242 type = CT_945G; 243 break; 244 245 case 0x27a08086: 246 type = CT_945GM; 247 break; 248 249 case 0x29708086: 250 type = CT_946GZ; 251 break; 252 253 case 0x29a08086: 254 type = CT_G965; 255 break; 256 257 case 0x29908086: 258 type = CT_Q965; 259 break; 260 261 case 0x27ac8086: 262 type = CT_945GME; 263 break; 264 265 default: 266 type = CT_UNKWN; 267 break; 268 } 269 270 return type; 271 } 272 273 274 static vbios_resolution_type1 * map_type1_resolution(vbios_map * map, 275 uint16_t res) 276 { 277 vbios_resolution_type1 * ptr = ((vbios_resolution_type1*)(map->bios_ptr + res)); 278 return ptr; 279 } 280 281 static vbios_resolution_type2 * map_type2_resolution(vbios_map * map, 282 uint16_t res) 283 { 284 vbios_resolution_type2 * ptr = ((vbios_resolution_type2*)(map->bios_ptr + res)); 285 return ptr; 286 } 287 288 static vbios_resolution_type3 * map_type3_resolution(vbios_map * map, 289 uint16_t res) 290 { 291 vbios_resolution_type3 * ptr = ((vbios_resolution_type3*)(map->bios_ptr + res)); 292 return ptr; 293 } 294 295 296 static bool detect_bios_type(vbios_map * map, int entry_size) 297 { 298 unsigned int i; 299 uint16_t r1, r2; 300 301 r1 = r2 = 32000; 302 303 for (i = 0; i < map->mode_table_size; i++) { 304 if (map->mode_table[i].resolution <= r1) { 305 r1 = map->mode_table[i].resolution; 306 } else if (map->mode_table[i].resolution <= r2) { 307 r2 = map->mode_table[i].resolution; 308 } 309 } 310 311 return ((r2-r1-6) % entry_size) == 0; 312 } 313 314 static inline void close_vbios(vbios_map *map) 315 { 316 (void)map; 317 } 318 319 static vbios_map * open_vbios(void) 320 { 321 static vbios_map _map; 322 vbios_map * const map = &_map; 323 324 memset(&_map, 0, sizeof _map); 325 326 /* 327 * Determine chipset 328 */ 329 map->chipset_id = get_chipset_id(); 330 good_marker(0x10); 331 map->chipset = get_chipset(map->chipset_id); 332 good_marker(0x11); 333 334 /* 335 * Map the video bios to memory 336 */ 337 map->bios_ptr = (void *)VBIOS_START; 338 339 /* 340 * check if we have ATI Radeon 341 */ 342 343 if (memmem(map->bios_ptr, VBIOS_SIZE, ATI_SIGNATURE1, strlen(ATI_SIGNATURE1)) || 344 memmem(map->bios_ptr, VBIOS_SIZE, ATI_SIGNATURE2, strlen(ATI_SIGNATURE2)) ) { 345 debug("ATI chipset detected. 915resolution only works with Intel 800/900 series graphic chipsets.\r\n"); 346 return NULL; 347 } 348 349 /* 350 * check if we have NVIDIA 351 */ 352 353 if (memmem(map->bios_ptr, VBIOS_SIZE, NVIDIA_SIGNATURE, strlen(NVIDIA_SIGNATURE))) { 354 debug("NVIDIA chipset detected. 915resolution only works with Intel 800/900 series graphic chipsets.\r\n"); 355 return NULL; 356 } 357 358 /* 359 * check if we have Intel 360 */ 361 362 if (map->chipset == CT_UNKWN && memmem(map->bios_ptr, VBIOS_SIZE, INTEL_SIGNATURE, strlen(INTEL_SIGNATURE))) { 363 debug("Intel chipset detected. However, 915resolution was unable to determine the chipset type.\r\n"); 364 365 debug("Chipset Id: %x\r\n", map->chipset_id); 366 367 debug("Please report this problem to stomljen (at) yahoo.com\r\n"); 368 369 close_vbios(map); 370 return NULL; 371 } 372 373 /* 374 * check for others 375 */ 376 377 if (map->chipset == CT_UNKWN) { 378 debug("Unknown chipset type and unrecognized bios.\r\n"); 379 debug("915resolution only works with Intel 800/900 series graphic chipsets.\r\n"); 380 381 debug("Chipset Id: %x\r\n", map->chipset_id); 382 close_vbios(map); 383 return NULL; 384 } 385 386 /* 387 * Figure out where the mode table is 388 */ 389 good_marker(0x12); 390 391 { 392 address p = map->bios_ptr + 16; 393 address limit = map->bios_ptr + VBIOS_SIZE - (3 * sizeof(vbios_mode)); 394 395 while (p < limit && map->mode_table == 0) { 396 vbios_mode * mode_ptr = (vbios_mode *) p; 397 398 if (((mode_ptr[0].mode & 0xf0) == 0x30) && ((mode_ptr[1].mode & 0xf0) == 0x30) && 399 ((mode_ptr[2].mode & 0xf0) == 0x30) && ((mode_ptr[3].mode & 0xf0) == 0x30)) { 400 401 map->mode_table = mode_ptr; 402 } 403 404 p++; 405 } 406 407 if (map->mode_table == 0) { 408 debug("Unable to locate the mode table.\r\n"); 409 close_vbios(map); 410 return NULL; 411 } 412 } 413 good_marker(0x13); 414 415 /* 416 * Determine size of mode table 417 */ 418 419 { 420 vbios_mode * mode_ptr = map->mode_table; 421 422 while (mode_ptr->mode != 0xff) { 423 map->mode_table_size++; 424 mode_ptr++; 425 } 426 } 427 good_marker(0x14); 428 status("mode_table_size = %d", map->mode_table_size); 429 430 /* 431 * Figure out what type of bios we have 432 * order of detection is important 433 */ 434 435 if (detect_bios_type(map, sizeof(vbios_modeline_type3))) { 436 map->bios = BT_3; 437 } 438 else if (detect_bios_type(map, sizeof(vbios_modeline_type2))) { 439 map->bios = BT_2; 440 } 441 else if (detect_bios_type(map, sizeof(vbios_resolution_type1))) { 442 map->bios = BT_1; 443 } 444 else { 445 debug("Unable to determine bios type.\r\n"); 446 debug("Mode Table Offset: $C0000 + $%x\r\n", ((unsigned int)map->mode_table) - ((unsigned int)map->bios_ptr)); 447 debug("Mode Table Entries: %u\r\n", map->mode_table_size); 448 bad_marker(0x15); 449 return NULL; 450 } 451 good_marker(0x15); 452 453 return map; 454 } 455 456 static void unlock_vbios(vbios_map * map) 457 { 458 assert(!map->unlocked); 459 460 map->unlocked = true; 461 462 switch (map->chipset) { 463 case CT_UNKWN: 464 case CHIPSET_TYPES: /* Shut up gcc */ 465 break; 466 case CT_830: 467 case CT_855GM: 468 map->b1 = pci_readb(0x8000005a); 469 pci_writeb(0x33, 0x8000005a); 470 break; 471 case CT_845G: 472 case CT_865G: 473 case CT_915G: 474 case CT_915GM: 475 case CT_945G: 476 case CT_945GM: 477 case CT_945GME: 478 case CT_946GZ: 479 case CT_G965: 480 case CT_Q965: 481 map->b1 = pci_readb(0x80000091); 482 map->b2 = pci_readb(0x80000092); 483 pci_writeb(0x33, 0x80000091); 484 pci_writeb(0x33, 0x80000092); 485 break; 486 } 487 488 #if DEBUG 489 { 490 unsigned int t = inl(0xcfc); 491 debug("unlock PAM: (0x%08x)\r\n", t); 492 } 493 #endif 494 } 495 496 static void relock_vbios(vbios_map * map) 497 { 498 assert(map->unlocked); 499 map->unlocked = false; 500 501 switch (map->chipset) { 502 case CT_UNKWN: 503 case CHIPSET_TYPES: /* Shut up gcc */ 504 break; 505 case CT_830: 506 case CT_855GM: 507 pci_writeb(map->b1, 0x8000005a); 508 break; 509 case CT_845G: 510 case CT_865G: 511 case CT_915G: 512 case CT_915GM: 513 case CT_945G: 514 case CT_945GM: 515 case CT_945GME: 516 case CT_946GZ: 517 case CT_G965: 518 case CT_Q965: 519 pci_writeb(map->b1, 0x80000091); 520 pci_writeb(map->b2, 0x80000092); 521 break; 522 } 523 524 #if DEBUG 525 { 526 unsigned int t = inl(0xcfc); 527 debug("relock PAM: (0x%08x)\r\n", t); 528 } 529 #endif 530 } 531 532 #if 0 533 static void list_modes(vbios_map *map, unsigned int raw) 534 { 535 unsigned int i, x, y; 536 537 for (i=0; i < map->mode_table_size; i++) { 538 switch(map->bios) { 539 case BT_1: 540 { 541 vbios_resolution_type1 * res = map_type1_resolution(map, map->mode_table[i].resolution); 542 543 x = ((((unsigned int) res->x2) & 0xf0) << 4) | res->x1; 544 y = ((((unsigned int) res->y2) & 0xf0) << 4) | res->y1; 545 546 if (x != 0 && y != 0) { 547 debug("Mode %02x : %dx%d, %d bits/pixel\r\n", map->mode_table[i].mode, x, y, map->mode_table[i].bits_per_pixel); 548 } 549 550 if (raw) 551 { 552 debug("Mode %02x (raw) :\r\n\t%02x %02x\r\n\t%02x\r\n\t%02x\r\n\t%02x\r\n\t%02x\r\n\t%02x\r\n\t%02x\r\n", map->mode_table[i].mode, res->unknow1[0],res->unknow1[1], res->x1,res->x_total,res->x2,res->y1,res->y_total,res->y2); 553 } 554 555 } 556 break; 557 case BT_2: 558 { 559 vbios_resolution_type2 * res = map_type2_resolution(map, map->mode_table[i].resolution); 560 561 x = res->modelines[0].x1+1; 562 y = res->modelines[0].y1+1; 563 564 if (x != 0 && y != 0) { 565 debug("Mode %02x : %dx%d, %d bits/pixel\r\n", map->mode_table[i].mode, x, y, map->mode_table[i].bits_per_pixel); 566 } 567 } 568 break; 569 case BT_3: 570 { 571 vbios_resolution_type3 * res = map_type3_resolution(map, map->mode_table[i].resolution); 572 573 x = res->modelines[0].x1+1; 574 y = res->modelines[0].y1+1; 575 576 if (x != 0 && y != 0) { 577 debug("Mode %02x : %dx%d, %d bits/pixel\r\n", map->mode_table[i].mode, x, y, map->mode_table[i].bits_per_pixel); 578 } 579 } 580 break; 581 case BT_UNKWN: 582 break; 583 } 584 } 585 } 586 #endif 587 588 static void gtf_timings(int x, int y, int freq, uint32_t *clock, 589 uint16_t *hsyncstart, uint16_t *hsyncend, uint16_t *hblank, 590 uint16_t *vsyncstart, uint16_t *vsyncend, uint16_t *vblank) 591 { 592 int hbl, vbl, vfreq; 593 594 vbl = y + (y+1)/(20000.0/(11*freq) - 1) + 1.5; 595 vfreq = vbl * freq; 596 hbl = 16 * (int)(x * (30.0 - 300000.0 / vfreq) / 597 (70.0 + 300000.0 / vfreq) / 16.0 + 0.5); 598 599 *vsyncstart = y; 600 *vsyncend = y + 3; 601 *vblank = vbl - 1; 602 *hsyncstart = x + hbl / 2 - (x + hbl + 50) / 100 * 8 - 1; 603 *hsyncend = x + hbl / 2 - 1; 604 *hblank = x + hbl - 1; 605 *clock = (x + hbl) * vfreq / 1000; 606 } 607 608 static int set_mode(vbios_map * map, unsigned int mode, 609 unsigned int x, unsigned int y, unsigned int bp, 610 unsigned int htotal, unsigned int vtotal) 611 { 612 int xprev, yprev; 613 unsigned int i, j; 614 int rv = -1; 615 616 for (i=0; i < map->mode_table_size; i++) { 617 if (map->mode_table[i].mode == mode) { 618 switch(map->bios) { 619 case BT_1: 620 { 621 vbios_resolution_type1 * res = map_type1_resolution(map, map->mode_table[i].resolution); 622 uint32_t clock; 623 uint16_t hsyncstart, hsyncend, hblank; 624 uint16_t vsyncstart, vsyncend, vblank; 625 626 if (bp) { 627 map->mode_table[i].bits_per_pixel = bp; 628 } 629 630 gtf_timings(x, y, freqs[0], &clock, 631 &hsyncstart, &hsyncend, &hblank, 632 &vsyncstart, &vsyncend, &vblank); 633 634 status("x = %d, y = %d, clock = %lu, h = %d %d %d, v = %d %d %d\n", 635 x, y, clock, 636 hsyncstart, hsyncend, hblank, 637 vsyncstart, vsyncend, vblank); 638 639 htotal = htotal ? htotal : (unsigned int)hblank+1; 640 vtotal = vtotal ? vtotal : (unsigned int)vblank+1; 641 642 res->clock = clock/10; /* Units appear to be 10 kHz */ 643 res->x2 = (((htotal-x) >> 8) & 0x0f) | ((x >> 4) & 0xf0); 644 res->x1 = (x & 0xff); 645 646 res->y2 = (((vtotal-y) >> 8) & 0x0f) | ((y >> 4) & 0xf0); 647 res->y1 = (y & 0xff); 648 if (htotal) 649 res->x_total = ((htotal-x) & 0xff); 650 651 if (vtotal) 652 res->y_total = ((vtotal-y) & 0xff); 653 654 rv = 0; 655 } 656 break; 657 case BT_2: 658 { 659 vbios_resolution_type2 * res = map_type2_resolution(map, map->mode_table[i].resolution); 660 661 res->xchars = x / 8; 662 res->ychars = y / 16 - 1; 663 xprev = res->modelines[0].x1; 664 yprev = res->modelines[0].y1; 665 666 for(j=0; j < 3; j++) { 667 vbios_modeline_type2 * modeline = &res->modelines[j]; 668 669 if (modeline->x1 == xprev && modeline->y1 == yprev) { 670 modeline->x1 = modeline->x2 = x-1; 671 modeline->y1 = modeline->y2 = y-1; 672 673 gtf_timings(x, y, freqs[j], &modeline->clock, 674 &modeline->hsyncstart, &modeline->hsyncend, 675 &modeline->hblank, &modeline->vsyncstart, 676 &modeline->vsyncend, &modeline->vblank); 677 678 if (htotal) 679 modeline->htotal = htotal; 680 else 681 modeline->htotal = modeline->hblank; 682 683 if (vtotal) 684 modeline->vtotal = vtotal; 685 else 686 modeline->vtotal = modeline->vblank; 687 } 688 } 689 690 rv = 0; 691 } 692 break; 693 case BT_3: 694 { 695 vbios_resolution_type3 * res = map_type3_resolution(map, map->mode_table[i].resolution); 696 697 xprev = res->modelines[0].x1; 698 yprev = res->modelines[0].y1; 699 700 for (j=0; j < 3; j++) { 701 vbios_modeline_type3 * modeline = &res->modelines[j]; 702 703 if (modeline->x1 == xprev && modeline->y1 == yprev) { 704 modeline->x1 = modeline->x2 = x-1; 705 modeline->y1 = modeline->y2 = y-1; 706 707 gtf_timings(x, y, freqs[j], &modeline->clock, 708 &modeline->hsyncstart, &modeline->hsyncend, 709 &modeline->hblank, &modeline->vsyncstart, 710 &modeline->vsyncend, &modeline->vblank); 711 if (htotal) 712 modeline->htotal = htotal; 713 else 714 modeline->htotal = modeline->hblank; 715 if (vtotal) 716 modeline->vtotal = vtotal; 717 else 718 modeline->vtotal = modeline->vblank; 719 720 modeline->timing_h = y-1; 721 modeline->timing_v = x-1; 722 } 723 } 724 725 rv = 0; 726 } 727 break; 728 case BT_UNKWN: 729 break; 730 } 731 } 732 } 733 734 return rv; 735 } 736 737 static inline void display_map_info(vbios_map * map) { 738 #ifdef DEBUG 739 static const char * bios_type_names[] = 740 {"UNKNOWN", "TYPE 1", "TYPE 2", "TYPE 3"}; 741 static const char * chipset_type_names[] = { 742 "UNKNOWN", "830", "845G", "855GM", "865G", "915G", "915GM", "945G", 743 "945GM", "946GZ", "G965", "Q965", "945GME" 744 }; 745 746 debug("Chipset: %s\r\n", chipset_type_names[map->chipset]); 747 debug("BIOS: %s\r\n", bios_type_names[map->bios]); 748 749 debug("Mode Table Offset: $C0000 + $%x\r\n", 750 ((unsigned int)map->mode_table) - ((unsigned int)map->bios_ptr)); 751 debug("Mode Table Entries: %u\r\n", map->mode_table_size); 752 #endif 753 (void)map; 754 } 755 756 int __vesacon_i915resolution(int x, int y) 757 { 758 vbios_map * map; 759 unsigned int mode = 0x52; /* 800x600x32 mode in known BIOSes */ 760 unsigned int bp = 32; /* 32 bits per pixel */ 761 int rv = 0; 762 763 good_marker(0); 764 765 map = open_vbios(); 766 if (!map) 767 return -1; 768 769 good_marker(1); 770 771 display_map_info(map); 772 773 debug("\r\n"); 774 775 if (mode && x && y) { 776 good_marker(2); 777 cli(); 778 good_marker(3); 779 unlock_vbios(map); 780 good_marker(4); 781 rv = set_mode(map, mode, x, y, bp, 0, 0); 782 if (rv) 783 bad_marker(5); 784 else 785 good_marker(5); 786 relock_vbios(map); 787 good_marker(6); 788 sti(); 789 790 debug("Patch mode %02x to resolution %dx%d complete\r\n", mode, x, y); 791 } 792 close_vbios(map); 793 794 return rv; 795 } 796