1 /* 2 Copyright 1999, Be Incorporated. All Rights Reserved. 3 This file may be used under the terms of the Be Sample Code License. 4 5 Other authors: 6 Mark Watson, 7 Apsed, 8 Rudolf Cornelissen 11/2002-1/2004 9 */ 10 11 #define MODULE_BIT 0x00200000 12 13 #include "acc_std.h" 14 15 /* 16 Enable/Disable interrupts. Just a wrapper around the 17 ioctl() to the kernel driver. 18 */ 19 static void interrupt_enable(bool flag) { 20 status_t result; 21 gx00_set_bool_state sbs; 22 23 /* set the magic number so the driver knows we're for real */ 24 sbs.magic = GX00_PRIVATE_DATA_MAGIC; 25 sbs.do_it = flag; 26 /* contact driver and get a pointer to the registers and shared data */ 27 result = ioctl(fd, GX00_RUN_INTERRUPTS, &sbs, sizeof(sbs)); 28 } 29 30 /* First validate the mode, then call lots of bit banging stuff to set the mode(s)! */ 31 status_t SET_DISPLAY_MODE(display_mode *mode_to_set) 32 { 33 /* BOUNDS WARNING: 34 * It's impossible to deviate whatever small amount in a display_mode if the lower 35 * and upper limits are the same! 36 * Besides: 37 * BeOS (tested R5.0.3PE) is failing BWindowScreen::SetFrameBuffer() if PROPOSEMODE 38 * returns B_BAD_VALUE! 39 * Which means PROPOSEMODE should not return that on anything except on 40 * deviations for: 41 * display_mode.virtual_width; 42 * display_mode.virtual_height; 43 * display_mode.timing.h_display; 44 * display_mode.timing.v_display; 45 * So: 46 * We don't use bounds here by making sure bounds and target are the same struct! 47 * (See the call to PROPOSE_DISPLAY_MODE below) */ 48 display_mode /*bounds,*/ target; 49 50 uint8 colour_depth1 = 32; 51 status_t result; 52 uint32 startadd,startadd_right; 53 bool display, h, v; 54 55 /* Adjust mode to valid one and fail if invalid */ 56 target /*= bounds*/ = *mode_to_set; 57 /* show the mode bits */ 58 LOG(1, ("SETMODE: (ENTER) initial modeflags: $%08x\n", target.flags)); 59 LOG(1, ("SETMODE: requested target pixelclock %dkHz\n", target.timing.pixel_clock)); 60 LOG(1, ("SETMODE: requested virtual_width %d, virtual_height %d\n", 61 target.virtual_width, target.virtual_height)); 62 63 /* See BOUNDS WARNING above... */ 64 if (PROPOSE_DISPLAY_MODE(&target, &target, &target) == B_ERROR) return B_ERROR; 65 66 /* if not dualhead capable card clear dualhead flags */ 67 if (!(target.flags & DUALHEAD_CAPABLE)) 68 { 69 target.flags &= ~DUALHEAD_BITS; 70 } 71 /* if not TVout capable card clear TVout flags */ 72 if (!(target.flags & TV_CAPABLE)) 73 { 74 target.flags &= ~TV_BITS; 75 } 76 LOG(1, ("SETMODE: (CONT.) validated command modeflags: $%08x\n", target.flags)); 77 78 /* overlay engine, cursor and MOVE_DISPLAY need to know the status even when 79 * in singlehead mode */ 80 si->switched_crtcs = false; 81 82 /* disable interrupts using the kernel driver */ 83 interrupt_enable(false); 84 85 /* find current DPMS state, then turn off screen(s) */ 86 gx00_crtc_dpms_fetch(&display, &h, &v); 87 gx00_crtc_dpms(false, false, false); 88 if (si->ps.secondary_head) g400_crtc2_dpms(false, false, false); 89 90 /*where in framebuffer the screen is (should this be dependant on previous MOVEDISPLAY?)*/ 91 startadd = (uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer; 92 93 /* calculate and set new mode bytes_per_row */ 94 gx00_general_validate_pic_size (&target, &si->fbc.bytes_per_row, &si->acc_mode); 95 96 /*Perform the very long mode switch!*/ 97 if (target.flags & DUALHEAD_BITS) /*if some dualhead mode*/ 98 { 99 uint8 colour_depth2 = colour_depth1; 100 101 /* init display mode for secondary head */ 102 display_mode target2 = target; 103 104 LOG(1,("SETMODE: setting DUALHEAD mode\n")); 105 106 /* validate flags for secondary TVout */ 107 if ((i2c_sec_tv_adapter() != B_OK) && (target2.flags & TV_BITS)) 108 { 109 target.flags &= ~TV_BITS;//still needed for some routines... 110 target2.flags &= ~TV_BITS; 111 LOG(1,("SETMODE: blocking TVout: no TVout cable connected!\n")); 112 } 113 114 /* set the pixel clock PLL(s) */ 115 LOG(8,("SETMODE: target clock %dkHz\n",target.timing.pixel_clock)); 116 if (gx00_dac_set_pix_pll(target) == B_ERROR) 117 LOG(8,("SETMODE: error setting pixel clock (internal DAC)\n")); 118 119 /* we do not need to set the pixelclock here for a head that's in TVout mode */ 120 if (!(target2.flags & TV_BITS)) 121 { 122 LOG(8,("SETMODE: target2 clock %dkHz\n",target2.timing.pixel_clock)); 123 if (gx00_maven_set_vid_pll(target2) == B_ERROR) 124 LOG(8,("SETMODE: error setting pixel clock (MAVEN)\n")); 125 } 126 127 /*set the colour depth for CRTC1 and the DAC */ 128 switch(target.space) 129 { 130 case B_RGB16_LITTLE: 131 colour_depth1 = 16; 132 gx00_dac_mode(BPP16, 1.0); 133 gx00_crtc_depth(BPP16); 134 break; 135 case B_RGB32_LITTLE: 136 colour_depth1 = 32; 137 gx00_dac_mode(BPP32, 1.0); 138 gx00_crtc_depth(BPP32); 139 break; 140 } 141 /*set the colour depth for CRTC2 and the MAVEN */ 142 switch(target2.space) 143 { 144 case B_RGB16_LITTLE: 145 colour_depth2 = 16; 146 gx00_maven_mode(BPP16, 1.0); 147 g400_crtc2_depth(BPP16); 148 break; 149 case B_RGB32_LITTLE: 150 colour_depth2 = 32; 151 gx00_maven_mode(BPP32DIR, 1.0); 152 g400_crtc2_depth(BPP32DIR); 153 break; 154 } 155 156 /* check if we are doing interlaced TVout mode */ 157 si->interlaced_tv_mode = false; 158 if ((target2.flags & TV_BITS) && (si->ps.card_type >= G450)) 159 si->interlaced_tv_mode = true; 160 161 /*set the display(s) pitches*/ 162 gx00_crtc_set_display_pitch (); 163 //fixme: seperate for real dualhead modes: 164 //we need a secondary si->fbc! 165 g400_crtc2_set_display_pitch (); 166 167 /*work out where the "right" screen starts*/ 168 startadd_right=startadd+(target.timing.h_display * (colour_depth1 >> 3)); 169 170 /* calculate needed MAVEN-CRTC delay: formula valid for straight-through CRTC's */ 171 si->crtc_delay = 44 + 0 * (colour_depth2 == 16); 172 173 /* set the outputs */ 174 switch (si->ps.card_type) 175 { 176 case G400: 177 case G400MAX: 178 /* setup vertical timing adjust for crtc connected to the MAVEN: 179 * assuming connected straight through. */ 180 /* (extra "blanking" line for MAVEN hardware design fault) */ 181 target2.timing.v_display++; 182 183 switch (target.flags & DUALHEAD_BITS) 184 { 185 case DUALHEAD_ON: 186 case DUALHEAD_CLONE: 187 gx00_general_dac_select(DS_CRTC1DAC_CRTC2MAVEN); 188 si->switched_crtcs = false; 189 break; 190 case DUALHEAD_SWITCH: 191 if (i2c_sec_tv_adapter() == B_OK) 192 { 193 /* Don't switch CRTC's because MAVEN YUV is impossible then, 194 * and primary head output will be limited to 135Mhz pixelclock. */ 195 LOG(4,("SETMODE: secondary TV-adapter detected, switching buffers\n")); 196 gx00_general_dac_select(DS_CRTC1DAC_CRTC2MAVEN); 197 si->switched_crtcs = true; 198 } 199 else 200 { 201 /* This limits the pixelclocks on both heads to 135Mhz, 202 * but you can use overlay on the other output now. */ 203 LOG(4,("SETMODE: no secondary TV-adapter detected, switching CRTCs\n")); 204 gx00_general_dac_select(DS_CRTC1MAVEN_CRTC2DAC); 205 si->switched_crtcs = false; 206 /* re-calculate MAVEN-CRTC delay: formula valid for crossed CRTC's */ 207 si->crtc_delay = 17 + 4 * (colour_depth1 == 16); 208 /* re-setup vertical timing adjust for crtc connected to the MAVEN: 209 * cross connected. */ 210 /* (extra "blanking" line for MAVEN hardware design fault) */ 211 target.timing.v_display++; 212 target2.timing.v_display--; 213 } 214 break; 215 } 216 break; 217 case G450: 218 case G550: 219 if (!si->ps.primary_dvi) 220 /* output connector use is always 'straight-through' */ 221 //fixme: re-evaluate when DVI is setup... 222 { 223 switch (target.flags & DUALHEAD_BITS) 224 { 225 case DUALHEAD_ON: 226 case DUALHEAD_CLONE: 227 gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2); 228 si->switched_crtcs = false; 229 break; 230 case DUALHEAD_SWITCH: 231 if (i2c_sec_tv_adapter() == B_OK) 232 { 233 /* Don't switch CRTC's because MAVEN YUV and TVout is impossible then, 234 * and primary head output will be limited to 235Mhz pixelclock. */ 235 LOG(4,("SETMODE: secondary TV-adapter detected, switching buffers\n")); 236 gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2); 237 si->switched_crtcs = true; 238 } 239 else 240 { 241 /* This limits the pixelclocks on both heads to 235Mhz, 242 * but you can use overlay on the other output now. */ 243 LOG(4,("SETMODE: no secondary TV-adapter detected, switching CRTCs\n")); 244 gx00_general_dac_select(DS_CRTC1CON2_CRTC2CON1); 245 si->switched_crtcs = false; 246 } 247 break; 248 } 249 } 250 else 251 /* output connector use is cross-linked if no TV cable connected! */ 252 //fixme: re-evaluate when DVI is setup... 253 { 254 switch (target.flags & DUALHEAD_BITS) 255 { 256 case DUALHEAD_ON: 257 case DUALHEAD_CLONE: 258 if (i2c_sec_tv_adapter() == B_OK) 259 { 260 gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2); 261 si->switched_crtcs = false; 262 } 263 else 264 { 265 /* This limits the pixelclocks on both heads to 235Mhz, 266 * but you can use overlay on the other output now. */ 267 gx00_general_dac_select(DS_CRTC1CON2_CRTC2CON1); 268 si->switched_crtcs = false; 269 } 270 break; 271 case DUALHEAD_SWITCH: 272 if (i2c_sec_tv_adapter() == B_OK) 273 { 274 /* Don't switch CRTC's because MAVEN YUV and TVout is impossible then, 275 * and primary head output will be limited to 235Mhz pixelclock. */ 276 LOG(4,("SETMODE: secondary TV-adapter detected, switching buffers\n")); 277 gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2); 278 si->switched_crtcs = true; 279 } 280 else 281 { 282 LOG(4,("SETMODE: no secondary TV-adapter detected, switching CRTCs\n")); 283 gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2); 284 si->switched_crtcs = false; 285 } 286 break; 287 } 288 } 289 break; 290 default: 291 break; 292 } 293 294 if (si->switched_crtcs) 295 { 296 uint32 temp = startadd; 297 startadd = startadd_right; 298 startadd_right = temp; 299 } 300 301 /*Tell card what memory to display*/ 302 switch (target.flags & DUALHEAD_BITS) 303 { 304 case DUALHEAD_ON: 305 case DUALHEAD_SWITCH: 306 gx00_crtc_set_display_start(startadd,colour_depth1); 307 g400_crtc2_set_display_start(startadd_right,colour_depth2); 308 break; 309 case DUALHEAD_CLONE: 310 gx00_crtc_set_display_start(startadd,colour_depth1); 311 g400_crtc2_set_display_start(startadd,colour_depth2); 312 break; 313 } 314 315 /* set the timing */ 316 gx00_crtc_set_timing(target); 317 /* we do not need to setup CRTC2 here for a head that's in TVout mode */ 318 if (!(target2.flags & TV_BITS)) result = g400_crtc2_set_timing(target2); 319 320 /* TVout support: setup CRTC2 and it's pixelclock */ 321 if (si->ps.secondary_tvout && (target2.flags & TV_BITS)) maventv_init(target2); 322 } 323 else /* single head mode */ 324 { 325 status_t status; 326 int colour_mode = BPP32; 327 328 switch(target.space) 329 { 330 case B_CMAP8: colour_depth1 = 8; colour_mode = BPP8; break; 331 case B_RGB15_LITTLE: colour_depth1 = 16; colour_mode = BPP15; break; 332 case B_RGB16_LITTLE: colour_depth1 = 16; colour_mode = BPP16; break; 333 case B_RGB32_LITTLE: colour_depth1 = 32; colour_mode = BPP32; break; 334 default: 335 LOG(8,("SETMODE: Invalid singlehead colour depth 0x%08x\n", target.space)); 336 return B_ERROR; 337 } 338 339 /* set the pixel clock PLL */ 340 if (si->ps.card_type >= G100) 341 status = gx00_dac_set_pix_pll(target); 342 else 343 { 344 status = mil2_dac_set_pix_pll((target.timing.pixel_clock)/1000.0, colour_depth1); 345 } 346 if (status==B_ERROR) 347 LOG(8,("CRTC: error setting pixel clock (internal DAC)\n")); 348 349 /* set the colour depth for CRTC1 and the DAC */ 350 gx00_dac_mode(colour_mode,1.0); 351 gx00_crtc_depth(colour_mode); 352 353 /* set the display pitch */ 354 gx00_crtc_set_display_pitch(); 355 356 /* tell the card what memory to display */ 357 gx00_crtc_set_display_start(startadd,colour_depth1); 358 359 /* enable primary analog output */ 360 switch (si->ps.card_type) 361 { 362 case G100: 363 case G200: 364 case G400: 365 case G400MAX: 366 gx00_general_dac_select(DS_CRTC1DAC_CRTC2MAVEN); 367 break; 368 case G450: 369 case G550: 370 gx00_general_dac_select(DS_CRTC1CON1_CRTC2CON2); 371 gx50_general_output_select(); 372 break; 373 default: 374 break; 375 } 376 377 /* set the timing */ 378 gx00_crtc_set_timing(target); 379 380 //fixme: shut-off the videoPLL if it exists... 381 } 382 383 /* update driver's mode store */ 384 si->dm = target; 385 386 /* turn screen one on */ 387 gx00_crtc_dpms(display, h, v); 388 /* turn screen two on if a dualhead mode is active */ 389 if (target.flags & DUALHEAD_BITS) g400_crtc2_dpms(display, h, v); 390 391 /* set up acceleration for this mode */ 392 gx00_acc_init(); 393 394 /* clear line at bottom of screen if dualhead mode: 395 * MAVEN hardware design fault 'fix'. */ 396 if ((target.flags & DUALHEAD_BITS) && (si->ps.card_type <= G400MAX)) 397 gx00_maven_clrline(); 398 399 LOG(1,("SETMODE: booted since %f mS\n", system_time()/1000.0)); 400 401 /* enable interrupts using the kernel driver */ 402 interrupt_enable(true); 403 404 /* optimize memory-access if needed */ 405 gx00_crtc_mem_priority(colour_depth1); 406 407 /* Tune RAM CAS-latency if needed. Must be done *here*! */ 408 mga_set_cas_latency(); 409 410 return B_OK; 411 } 412 413 /* 414 Set which pixel of the virtual frame buffer will show up in the 415 top left corner of the display device. Used for page-flipping 416 games and virtual desktops. 417 */ 418 status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start) { 419 uint8 colour_depth; 420 uint32 startadd,startadd_right; 421 422 LOG(4,("MOVE_DISPLAY: h %d, v %d\n", h_display_start, v_display_start)); 423 424 /* G400 CRTC1 handles multiples of 8 for 8bit, 4 for 16bit, 2 for 32 bit 425 G400 CRTC2 handles multiples of 32 for 16-bit and 16 for 32-bit - must stoop to this in dualhead 426 */ 427 428 /* reset lower bits, don't return an error! */ 429 if (si->dm.flags & DUALHEAD_BITS) 430 { 431 switch(si->dm.space) 432 { 433 case B_RGB16_LITTLE: 434 colour_depth=16; 435 h_display_start &= ~0x1f; 436 break; 437 case B_RGB32_LITTLE: 438 colour_depth=32; 439 h_display_start &= ~0x0f; 440 break; 441 default: 442 LOG(8,("SET:Invalid DH colour depth 0x%08x, should never happen\n", si->dm.space)); 443 return B_ERROR; 444 } 445 } 446 else 447 { 448 switch(si->dm.space) 449 { 450 case B_CMAP8: 451 colour_depth=8; 452 h_display_start &= ~0x07; 453 break; 454 case B_RGB15_LITTLE: case B_RGB16_LITTLE: 455 colour_depth=16; 456 h_display_start &= ~0x03; 457 break; 458 case B_RGB32_LITTLE: 459 colour_depth=32; 460 h_display_start &= ~0x01; 461 break; 462 default: 463 return B_ERROR; 464 } 465 } 466 467 /* do not run past end of display */ 468 switch (si->dm.flags & DUALHEAD_BITS) 469 { 470 case DUALHEAD_ON: 471 case DUALHEAD_SWITCH: 472 if (((si->dm.timing.h_display * 2) + h_display_start) > si->dm.virtual_width) 473 return B_ERROR; 474 break; 475 default: 476 if ((si->dm.timing.h_display + h_display_start) > si->dm.virtual_width) 477 return B_ERROR; 478 break; 479 } 480 if ((si->dm.timing.v_display + v_display_start) > si->dm.virtual_height) 481 return B_ERROR; 482 483 /* everybody remember where we parked... */ 484 si->dm.h_display_start = h_display_start; 485 si->dm.v_display_start = v_display_start; 486 487 /* actually set the registers */ 488 //fixme: seperate both heads: we need a secondary si->fbc! 489 startadd = v_display_start * si->fbc.bytes_per_row; 490 startadd += h_display_start * (colour_depth >> 3); 491 startadd += (uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer; 492 startadd_right = startadd + si->dm.timing.h_display * (colour_depth >> 3); 493 494 /* account for switched CRTC's */ 495 if (si->switched_crtcs) 496 { 497 uint32 temp = startadd; 498 startadd = startadd_right; 499 startadd_right = temp; 500 } 501 502 interrupt_enable(false); 503 504 switch (si->dm.flags&DUALHEAD_BITS) 505 { 506 case DUALHEAD_ON: 507 case DUALHEAD_SWITCH: 508 gx00_crtc_set_display_start(startadd,colour_depth); 509 g400_crtc2_set_display_start(startadd_right,colour_depth); 510 break; 511 case DUALHEAD_OFF: 512 gx00_crtc_set_display_start(startadd,colour_depth); 513 break; 514 case DUALHEAD_CLONE: 515 gx00_crtc_set_display_start(startadd,colour_depth); 516 g400_crtc2_set_display_start(startadd,colour_depth); 517 break; 518 } 519 520 interrupt_enable(true); 521 return B_OK; 522 } 523 524 /* 525 Set the indexed color palette. 526 */ 527 void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags) { 528 int i; 529 uint8 *r,*g,*b; 530 531 /* Protect gamma correction when not in CMAP8 */ 532 if (si->dm.space != B_CMAP8) return; 533 534 r=si->color_data; 535 g=r+256; 536 b=g+256; 537 538 i=first; 539 while (count--) 540 { 541 r[i]=*color_data++; 542 g[i]=*color_data++; 543 b[i]=*color_data++; 544 i++; 545 } 546 gx00_dac_palette(r,g,b); 547 } 548 549 /* Put the display into one of the Display Power Management modes. */ 550 status_t SET_DPMS_MODE(uint32 dpms_flags) { 551 interrupt_enable(false); 552 553 LOG(4,("SET_DPMS_MODE: 0x%08x\n", dpms_flags)); 554 555 if (si->dm.flags & DUALHEAD_BITS) /* dualhead */ 556 { 557 switch(dpms_flags) 558 { 559 case B_DPMS_ON: /* H: on, V: on */ 560 gx00_crtc_dpms(true, true, true); 561 if (si->ps.secondary_head) g400_crtc2_dpms(true, true, true); 562 break; 563 case B_DPMS_STAND_BY: 564 if (si->settings.greensync) 565 { 566 /* blank screen, but keep sync running */ 567 gx00_crtc_dpms(false, true, true); 568 } 569 else 570 { 571 gx00_crtc_dpms(false, false, true); 572 } 573 if (si->ps.secondary_head) 574 { 575 if ((si->dm.flags & TV_BITS) && (si->ps.card_type > G400MAX)) 576 { 577 /* keep display enabled in TVout modes for G450 and G550! */ 578 g400_crtc2_dpms(true, false, true); 579 } 580 else 581 { 582 g400_crtc2_dpms(false, false, true); 583 } 584 } 585 break; 586 case B_DPMS_SUSPEND: 587 if (si->settings.greensync) 588 { 589 /* blank screen, but keep sync running */ 590 gx00_crtc_dpms(false, true, true); 591 } 592 else 593 { 594 gx00_crtc_dpms(false, true, false); 595 } 596 if (si->ps.secondary_head) 597 { 598 if ((si->dm.flags & TV_BITS) && (si->ps.card_type > G400MAX)) 599 { 600 /* keep display enabled in TVout modes for G450 and G550! */ 601 g400_crtc2_dpms(true, true, false); 602 } 603 else 604 { 605 g400_crtc2_dpms(false, true, false); 606 } 607 } 608 break; 609 case B_DPMS_OFF: /* H: off, V: off, display off */ 610 if (si->settings.greensync) 611 { 612 /* blank screen, but keep sync running */ 613 gx00_crtc_dpms(false, true, true); 614 } 615 else 616 { 617 gx00_crtc_dpms(false, false, false); 618 } 619 if (si->ps.secondary_head) 620 { 621 if ((si->dm.flags & TV_BITS) && (si->ps.card_type > G400MAX)) 622 { 623 /* keep display enabled in TVout modes for G450 and G550! */ 624 g400_crtc2_dpms(true, false, false); 625 } 626 else 627 { 628 g400_crtc2_dpms(false, false, false); 629 } 630 } 631 break; 632 default: 633 LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags)); 634 interrupt_enable(true); 635 return B_ERROR; 636 } 637 } 638 else /* singlehead */ 639 { 640 switch(dpms_flags) 641 { 642 case B_DPMS_ON: /* H: on, V: on */ 643 gx00_crtc_dpms(true, true, true); 644 break; 645 case B_DPMS_STAND_BY: 646 if (si->settings.greensync) 647 { 648 /* blank screen, but keep sync running */ 649 gx00_crtc_dpms(false, true, true); 650 } 651 else 652 { 653 gx00_crtc_dpms(false, false, true); 654 } 655 break; 656 case B_DPMS_SUSPEND: 657 if (si->settings.greensync) 658 { 659 /* blank screen, but keep sync running */ 660 gx00_crtc_dpms(false, true, true); 661 } 662 else 663 { 664 gx00_crtc_dpms(false, true, false); 665 } 666 break; 667 case B_DPMS_OFF: /* H: off, V: off, display off */ 668 if (si->settings.greensync) 669 { 670 /* blank screen, but keep sync running */ 671 gx00_crtc_dpms(false, true, true); 672 } 673 else 674 { 675 gx00_crtc_dpms(false, false, false); 676 } 677 break; 678 default: 679 LOG(8,("SET: Invalid DPMS settings (SH) 0x%08x\n", dpms_flags)); 680 interrupt_enable(true); 681 return B_ERROR; 682 } 683 } 684 interrupt_enable(true); 685 return B_OK; 686 } 687 688 /* Report device DPMS capabilities. */ 689 uint32 DPMS_CAPABILITIES(void) 690 { 691 if (si->settings.greensync) 692 /* we can blank the screen on CRTC1, G400 CRTC2 does not support intermediate 693 * modes anyway. */ 694 //fixme: G450/G550 support full DPMS on CRTC2... 695 return B_DPMS_ON | B_DPMS_OFF; 696 else 697 /* normally CRTC1 supports full DPMS (and on G450/G550 CRTC2 also).. */ 698 return B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF; 699 } 700 701 /* Return the current DPMS mode. */ 702 uint32 DPMS_MODE(void) { 703 bool display, h, v; 704 705 interrupt_enable(false); 706 gx00_crtc_dpms_fetch(&display, &h, &v); 707 interrupt_enable(true); 708 709 if (display && h && v) 710 return B_DPMS_ON; 711 else if (si->settings.greensync) 712 return B_DPMS_OFF; 713 else if (v) 714 return B_DPMS_STAND_BY; 715 else if (h) 716 return B_DPMS_SUSPEND; 717 else 718 return B_DPMS_OFF; 719 } 720