ffb_dac.c revision dbbd9e4b
1/* 2 * Acceleration for the Creator and Creator3D framebuffer - DAC programming. 3 * 4 * Copyright (C) 2000 David S. Miller (davem@redhat.com) 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * DAVID MILLER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 * 23 */ 24/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/sunffb/ffb_dac.c,v 1.3tsi Exp $ */ 25 26#ifdef HAVE_CONFIG_H 27#include "config.h" 28#endif 29 30#include "ffb.h" 31#include "ffb_rcache.h" 32#include "ffb_fifo.h" 33 34#include "xf86.h" 35#include "xf86_OSproc.h" 36 37#include "xf86DDC.h" 38 39/* 40 * Used for stabilize time after playing with power management on the display 41 */ 42 43#ifndef DPMS_SPIN_COUNT 44#define DPMS_SPIN_COUNT 100 45#endif /* DPMS_SPIN_COUNT */ 46 47/* Cursor programming */ 48 49void 50FFBDacLoadCursorPos(FFBPtr pFfb, int x, int y) 51{ 52 ffb_dacPtr dac = pFfb->dac; 53 int posval; 54 55 posval = ((y & 0xffff) << 16) | (x & 0xffff); 56 posval &= (FFBDAC_CUR_POS_Y_SIGN | 57 FFBDAC_CUR_POS_Y | 58 FFBDAC_CUR_POS_X_SIGN | 59 FFBDAC_CUR_POS_X); 60 61 DACCUR_WRITE(dac, FFBDAC_CUR_POS, posval); 62} 63 64void 65FFBDacLoadCursorColor(FFBPtr pFfb, int fg, int bg) 66{ 67 ffb_dacPtr dac = pFfb->dac; 68 69 dac->cur = FFBDAC_CUR_COLOR1; 70 dac->curdata = bg; 71 dac->curdata = fg; 72} 73 74void 75FFBDacCursorEnableDisable(FFBPtr pFfb, int enable) 76{ 77 ffb_dac_info_t *p = &pFfb->dac_info; 78 ffb_dacPtr dac = pFfb->dac; 79 int val; 80 81 val = 0; 82 if (!enable) 83 val = (FFBDAC_CUR_CTRL_P0 | FFBDAC_CUR_CTRL_P1); 84 85 /* PAC1 ramdacs with manufacturing revision less than 86 * '3' invert these control bits, wheee... 87 */ 88 if (p->flags & FFB_DAC_ICURCTL) 89 val ^= (FFBDAC_CUR_CTRL_P0 | FFBDAC_CUR_CTRL_P1); 90 91 DACCUR_WRITE(dac, FFBDAC_CUR_CTRL, val); 92} 93 94void 95FFBDacCursorLoadBitmap(FFBPtr pFfb, int xshift, int yshift, unsigned int *bitmap) 96{ 97 ffb_dacPtr dac = pFfb->dac; 98 int i, j; 99 100 dac->cur = FFBDAC_CUR_BITMAP_P0; 101 for (j = 0; j < 2; j++) { 102 bitmap += yshift * 2; 103 if (!xshift) { 104 for (i = yshift * 2; i < 128; i++) 105 dac->curdata = *bitmap++; 106 } else if (xshift < 32) { 107 for (i = yshift; i < 64; i++, bitmap += 2) { 108 dac->curdata = (bitmap[0] << xshift) | 109 (bitmap[1] >> (32 - xshift)); 110 dac->curdata = bitmap[1] << xshift; 111 } 112 } else { 113 for (i = yshift; i < 64; i++, bitmap += 2) { 114 dac->curdata = bitmap[1] << (xshift - 32); 115 dac->curdata = 0; 116 } 117 } 118 119 for (i = 0; i < yshift * 2; i++) 120 dac->curdata = 0; 121 } 122} 123 124/* Config space programming */ 125 126/* XF86 LoadPalette callback. */ 127 128void 129FFBDacLoadPalette(ScrnInfoPtr pScrn, int ncolors, int *indices, LOCO *colors, VisualPtr pVisual) 130{ 131 FFBPtr pFfb = GET_FFB_FROM_SCRN(pScrn); 132 ffb_dac_info_t *p = &pFfb->dac_info; 133 ffb_dacPtr dac = pFfb->dac; 134 unsigned int *cluts; 135 int i, index, palette; 136 137 if ((pVisual->nplanes != 8 && pVisual->class != DirectColor) || 138 (pVisual->nplanes == 8 && pVisual->class == StaticGray)) 139 return; 140 141 palette = 0; 142 if (p->flags & FFB_DAC_PAC2) { 143 if (pVisual->class == PseudoColor) 144 palette = 0; 145 if (pVisual->class == GrayScale) 146 palette = 1; 147 if (pVisual->class == DirectColor) 148 palette = 2; 149 } 150 151 cluts = &p->x_dac_state.clut[256 * palette]; 152 for (i = 0; i < ncolors; i++) { 153 unsigned int regval; 154 155 index = indices[i]; 156 if (pVisual->class == GrayScale) { 157 regval = cluts[index] = 158 ((colors[index].red << FFBDAC_COLOR_RED_SHFT) | 159 (colors[index].red << FFBDAC_COLOR_GREEN_SHFT) | 160 (colors[index].red << FFBDAC_COLOR_BLUE_SHFT)); 161 } else { 162 regval = cluts[index] = 163 ((colors[index].red << FFBDAC_COLOR_RED_SHFT) | 164 (colors[index].green << FFBDAC_COLOR_GREEN_SHFT) | 165 (colors[index].blue << FFBDAC_COLOR_BLUE_SHFT)); 166 } 167 168 FFBLOG(("FFBDacLoadPalette: visclass(%d) index(%d) val[%08x]\n", 169 pVisual->class, index, regval)); 170 171 /* Now update the hardware copy. */ 172 dac->cfg = FFBDAC_CFG_CLUP(palette) + index; 173 dac->cfgdata = regval; 174 } 175} 176 177/* WARNING: Very dangerous function, use with extreme care. */ 178static void 179dac_stop(FFBPtr pFfb) 180{ 181 ffb_dacPtr dac = pFfb->dac; 182 unsigned int tgctrl; 183 184 tgctrl = DACCFG_READ(dac, FFBDAC_CFG_TGEN); 185 if (tgctrl & FFBDAC_CFG_TGEN_TGE) { 186 long limit = 1000000; 187 188 /* We try to shut off the timing generation 189 * precisely at the beginning of a vertical 190 * retrace. This is really just to make it 191 * look nice, it's not a functional necessity. 192 * 193 * The limit is so that malfunctioning hardware 194 * does not end up hanging the server. 195 */ 196 while (limit--) { 197 unsigned int vctr = DACCFG_READ(dac, FFBDAC_CFG_TGVC); 198 199 if (vctr == 0) 200 break; 201 } 202 203 DACCFG_WRITE(dac, FFBDAC_CFG_TGEN, 0); 204 } 205} 206 207/* This is made slightly complex because the ordering matters 208 * between several operations. We have to stop the DAC while 209 * restoring the timing registers so that some intermediate 210 * state does not emit wild retrace signals to the monitor. 211 * 212 * Another further complication is that we need to mess with 213 * some portions of the FFB framebuffer config registers to 214 * do this all properly. 215 */ 216static void 217dac_state_restore(FFBPtr pFfb, ffb_dac_hwstate_t *state) 218{ 219 ffb_dac_info_t *p = &pFfb->dac_info; 220 ffb_dacPtr dac = pFfb->dac; 221 ffb_fbcPtr ffb = pFfb->regs; 222 int i, nluts; 223 224 /* Step 1: Shut off all pixel timing generation. */ 225 dac_stop(pFfb); 226 ffb->fbcfg0 = 0; 227 228 /* Step 2: Restore timing settings. */ 229 DACCFG_WRITE(dac, FFBDAC_CFG_VBNP, state->vbnp); 230 DACCFG_WRITE(dac, FFBDAC_CFG_VBAP, state->vbap); 231 DACCFG_WRITE(dac, FFBDAC_CFG_VSNP, state->vsnp); 232 DACCFG_WRITE(dac, FFBDAC_CFG_VSAP, state->vsap); 233 DACCFG_WRITE(dac, FFBDAC_CFG_HSNP, state->hsnp); 234 DACCFG_WRITE(dac, FFBDAC_CFG_HBNP, state->hbnp); 235 DACCFG_WRITE(dac, FFBDAC_CFG_HBAP, state->hbap); 236 DACCFG_WRITE(dac, FFBDAC_CFG_HSYNCNP, state->hsyncnp); 237 DACCFG_WRITE(dac, FFBDAC_CFG_HSYNCAP, state->hsyncap); 238 DACCFG_WRITE(dac, FFBDAC_CFG_HSCENNP, state->hscennp); 239 DACCFG_WRITE(dac, FFBDAC_CFG_HSCENAP, state->hscenap); 240 DACCFG_WRITE(dac, FFBDAC_CFG_EPNP, state->epnp); 241 DACCFG_WRITE(dac, FFBDAC_CFG_EINP, state->einp); 242 DACCFG_WRITE(dac, FFBDAC_CFG_EIAP, state->eiap); 243 244 /* Step 3: Restore rest of DAC hw state. */ 245 DACCFG_WRITE(dac, FFBDAC_CFG_PPLLCTRL, state->ppllctrl); 246 DACCFG_WRITE(dac, FFBDAC_CFG_GPLLCTRL, state->gpllctrl); 247 DACCFG_WRITE(dac, FFBDAC_CFG_PFCTRL, state->pfctrl); 248 DACCFG_WRITE(dac, FFBDAC_CFG_UCTRL, state->uctrl); 249 250 nluts = (p->flags & FFB_DAC_PAC1) ? 256 : (4 * 256); 251 dac->cfg = FFBDAC_CFG_CLUP_BASE; 252 for (i = 0; i < nluts; i++) 253 dac->cfgdata = state->clut[i]; 254 255 if (p->flags & FFB_DAC_PAC2) { 256 dac->cfg = FFBDAC_PAC2_AOVWLUT0; 257 for (i = 0; i < 4; i++) 258 dac->cfgdata = state->ovluts[i]; 259 } 260 261 DACCFG_WRITE(dac, FFBDAC_CFG_WTCTRL, state->wtctrl); 262 DACCFG_WRITE(dac, FFBDAC_CFG_TMCTRL, state->tmctrl); 263 DACCFG_WRITE(dac, FFBDAC_CFG_TCOLORKEY, state->tcolorkey); 264 if (p->flags & FFB_DAC_PAC2) 265 DACCFG_WRITE(dac, FFBDAC_CFG_WAMASK, state->wamask); 266 267 if (p->flags & FFB_DAC_PAC1) { 268 dac->cfg = FFBDAC_PAC1_APWLUT_BASE; 269 for (i = 0; i < 32; i++) 270 dac->cfgdata = state->pwluts[i]; 271 } else { 272 dac->cfg = FFBDAC_PAC2_APWLUT_BASE; 273 for (i = 0; i < 64; i++) 274 dac->cfgdata = state->pwluts[i]; 275 } 276 277 DACCFG_WRITE(dac, FFBDAC_CFG_DACCTRL, state->dacctrl); 278 279 /* Step 4: Restore FFB framebuffer config state. */ 280 if (pFfb->ffb_type == ffb2_vertical_plus || 281 pFfb->ffb_type == ffb2_horizontal_plus || 282 pFfb->ffb_type == afb_m3 || 283 pFfb->ffb_type == afb_m6) 284 ffb->passin = p->ffb_passin_ctrl; 285 ffb->fbcfg0 = p->ffbcfg0; 286 ffb->fbcfg2 = p->ffbcfg2; 287 288 /* Step 5: Restore the timing generator control reg. */ 289 DACCFG_WRITE(dac, FFBDAC_CFG_TGEN, state->tgen); 290 291 /* Step 6: Pause for a bit. */ 292 for (i = 0; i < 100; i++) 293 (void) DACCFG_READ(dac, FFBDAC_CFG_TGVC); 294} 295 296static void 297dac_state_save(FFBPtr pFfb, ffb_dac_hwstate_t *state) 298{ 299 ffb_dac_info_t *p = &pFfb->dac_info; 300 ffb_dacPtr dac = pFfb->dac; 301 int i, nluts; 302 303 state->ppllctrl = DACCFG_READ(dac, FFBDAC_CFG_PPLLCTRL); 304 state->gpllctrl = DACCFG_READ(dac, FFBDAC_CFG_GPLLCTRL); 305 state->pfctrl = DACCFG_READ(dac, FFBDAC_CFG_PFCTRL); 306 state->uctrl = DACCFG_READ(dac, FFBDAC_CFG_UCTRL); 307 308 nluts = (p->flags & FFB_DAC_PAC1) ? 256 : (4 * 256); 309 dac->cfg = FFBDAC_CFG_CLUP_BASE; 310 for (i = 0; i < nluts; i++) 311 state->clut[i] = dac->cfgdata; 312 313 if (p->flags & FFB_DAC_PAC2) { 314 dac->cfg = FFBDAC_PAC2_AOVWLUT0; 315 for (i = 0; i < 4; i++) 316 state->ovluts[i] = dac->cfgdata; 317 } 318 319 state->wtctrl = DACCFG_READ(dac, FFBDAC_CFG_WTCTRL); 320 state->tmctrl = DACCFG_READ(dac, FFBDAC_CFG_TMCTRL); 321 state->tcolorkey = DACCFG_READ(dac, FFBDAC_CFG_TCOLORKEY); 322 if (p->flags & FFB_DAC_PAC2) 323 state->wamask = DACCFG_READ(dac, FFBDAC_CFG_WAMASK); 324 325 if (p->flags & FFB_DAC_PAC1) { 326 dac->cfg = FFBDAC_PAC1_APWLUT_BASE; 327 for (i = 0; i < 32; i++) 328 state->pwluts[i] = dac->cfgdata; 329 } else { 330 dac->cfg = FFBDAC_PAC2_APWLUT_BASE; 331 for (i = 0; i < 64; i++) 332 state->pwluts[i] = dac->cfgdata; 333 } 334 335 state->dacctrl = DACCFG_READ(dac, FFBDAC_CFG_DACCTRL); 336 337 state->tgen = DACCFG_READ(dac, FFBDAC_CFG_TGEN); 338 state->vbnp = DACCFG_READ(dac, FFBDAC_CFG_VBNP); 339 state->vbap = DACCFG_READ(dac, FFBDAC_CFG_VBAP); 340 state->vsnp = DACCFG_READ(dac, FFBDAC_CFG_VSNP); 341 state->vsap = DACCFG_READ(dac, FFBDAC_CFG_VSAP); 342 state->hsnp = DACCFG_READ(dac, FFBDAC_CFG_HSNP); 343 state->hbnp = DACCFG_READ(dac, FFBDAC_CFG_HBNP); 344 state->hbap = DACCFG_READ(dac, FFBDAC_CFG_HBAP); 345 state->hsyncnp = DACCFG_READ(dac, FFBDAC_CFG_HSYNCNP); 346 state->hsyncap = DACCFG_READ(dac, FFBDAC_CFG_HSYNCAP); 347 state->hscennp = DACCFG_READ(dac, FFBDAC_CFG_HSCENNP); 348 state->hscenap = DACCFG_READ(dac, FFBDAC_CFG_HSCENAP); 349 state->epnp = DACCFG_READ(dac, FFBDAC_CFG_EPNP); 350 state->einp = DACCFG_READ(dac, FFBDAC_CFG_EINP); 351 state->eiap = DACCFG_READ(dac, FFBDAC_CFG_EIAP); 352} 353 354static void 355init_dac_flags(FFBPtr pFfb) 356{ 357 ffb_dac_info_t *p = &pFfb->dac_info; 358 ffb_dacPtr dac = pFfb->dac; 359 unsigned int did, manuf_rev, partnum; 360 char *device; 361 362 /* Fetch kernel WID. */ 363 p->kernel_wid = *((volatile unsigned char *)pFfb->dfb8x); 364 365 /* For AFB, assume it is PAC2 which also implies not having 366 * the inverted cursor control attribute. 367 */ 368 if (pFfb->ffb_type == afb_m3 || pFfb->ffb_type == afb_m6) { 369 p->flags = FFB_DAC_PAC2; 370 manuf_rev = 4; 371 } else { 372 p->flags = 0; 373 374 did = DACCFG_READ(dac, FFBDAC_CFG_DID); 375 376 manuf_rev = DACCFG_READ(dac, FFBDAC_CFG_UCTRL); 377 manuf_rev = (manuf_rev & FFBDAC_UCTRL_MANREV) >> 8; 378 379 partnum = ((did & FFBDAC_CFG_DID_PNUM) >> 12); 380 if (partnum == 0x236e) 381 p->flags |= FFB_DAC_PAC2; 382 else 383 p->flags |= FFB_DAC_PAC1; 384 } 385 386 device = pFfb->psdp->device; 387 if ((p->flags & FFB_DAC_PAC1) != 0) { 388 if (manuf_rev < 3) { 389 p->flags |= FFB_DAC_ICURCTL; 390 xf86Msg(X_INFO, "%s: BT9068 (PAC1) ramdac detected (with " 391 "inverted cursor control)\n", device); 392 } else { 393 xf86Msg(X_INFO, "%s: BT9068 (PAC1) ramdac detected (with " 394 "normal cursor control)\n", device); 395 } 396 } else { 397 xf86Msg(X_INFO, "%s: BT498 (PAC2) ramdac detected\n", device); 398 } 399} 400 401/* The registers of the chip must be mapped, and the FFB/AFB 402 * board type must be probed before this is invoked. 403 */ 404Bool 405FFBDacInit(FFBPtr pFfb) 406{ 407 ffb_dac_info_t *p = &pFfb->dac_info; 408 ffb_fbcPtr ffb = pFfb->regs; 409 410 init_dac_flags(pFfb); 411 412 p->ffbcfg0 = ffb->fbcfg0; 413 p->ffbcfg2 = ffb->fbcfg2; 414 if (pFfb->ffb_type == ffb2_vertical_plus || 415 pFfb->ffb_type == ffb2_horizontal_plus || 416 pFfb->ffb_type == afb_m3 || 417 pFfb->ffb_type == afb_m6) 418 p->ffb_passin_ctrl = ffb->passin; 419 420 /* Save the kernel DAC state. We also save to the 421 * X server state here as well even though we have 422 * not modified anything yet. 423 */ 424 dac_state_save(pFfb, &p->kern_dac_state); 425 dac_state_save(pFfb, &p->x_dac_state); 426 427 /* Fire up the WID layer. */ 428 FFBWidPoolInit(pFfb); 429 430 return TRUE; 431} 432 433/* We need to reset the A buffer X planes to the value 0xff 434 * when giving the hardware back to the kernel too, thus... 435 * Also need to do this for the B buffer X planes when double 436 * buffering is available. 437 */ 438static void 439restore_kernel_xchannel(FFBPtr pFfb) 440{ 441 ffb_fbcPtr ffb = pFfb->regs; 442 unsigned int fbc, ppc, ppc_mask, drawop, wid; 443 444 wid = pFfb->dac_info.kernel_wid; 445 446 if (pFfb->has_double_buffer) 447 fbc = FFB_FBC_WB_AB; 448 else 449 fbc = FFB_FBC_WB_A; 450 451 fbc |= (FFB_FBC_WM_COMBINED | FFB_FBC_RB_A | FFB_FBC_SB_BOTH | 452 FFB_FBC_ZE_OFF | FFB_FBC_YE_OFF | 453 FFB_FBC_XE_ON | FFB_FBC_RGBE_MASK); 454 455 ppc = (FFB_PPC_APE_DISABLE | FFB_PPC_CS_CONST | FFB_PPC_XS_WID); 456 ppc_mask = (FFB_PPC_APE_MASK | FFB_PPC_CS_MASK | FFB_PPC_XS_MASK); 457 458 drawop = FFB_DRAWOP_RECTANGLE; 459 460 FFB_ATTR_RAW(pFfb, ppc, ppc_mask, ~0, 461 (FFB_ROP_EDIT_BIT | GXcopy)|(FFB_ROP_NEW<<8), 462 drawop, 0x0, fbc, wid); 463 464 FFBFifo(pFfb, 4); 465 FFB_WRITE64(&ffb->by, 0, 0); 466 FFB_WRITE64_2(&ffb->bh, pFfb->psdp->height, pFfb->psdp->width); 467 pFfb->rp_active = 1; 468 FFBWait(pFfb, ffb); 469} 470 471void 472FFBDacFini(FFBPtr pFfb) 473{ 474 ffb_dac_info_t *p = &pFfb->dac_info; 475 476 /* Just restore the kernel ramdac/x-channel state. */ 477 dac_state_restore(pFfb, &p->kern_dac_state); 478 restore_kernel_xchannel(pFfb); 479} 480 481 482/* Restore X server DAC state. */ 483void 484FFBDacEnterVT(FFBPtr pFfb) 485{ 486 ffb_dac_info_t *p = &pFfb->dac_info; 487 488 /* Save kernel DAC state. */ 489 dac_state_save(pFfb, &p->kern_dac_state); 490 491 /* Restore X DAC state. */ 492 dac_state_restore(pFfb, &p->x_dac_state); 493} 494 495/* Restore kernel DAC state. */ 496void 497FFBDacLeaveVT(FFBPtr pFfb) 498{ 499 ffb_dac_info_t *p = &pFfb->dac_info; 500 501 /* Save X DAC state. */ 502 dac_state_save(pFfb, &p->x_dac_state); 503 504 /* Restore kernel DAC and x-channel state. */ 505 dac_state_restore(pFfb, &p->kern_dac_state); 506 restore_kernel_xchannel(pFfb); 507} 508 509/* DPMS stuff, courtesy of a hint from David S. Miller. 510 * 05.xii.01, FEM 511 */ 512 513/* 514 * I don't know why, if at all, this is needed, but JJ or DSM do it 515 * on restore. I observe that when just blanking/unblanking, everything 516 * works fine without it, but that sometimes DPMS -> Standby actually 517 * results in Off. Maybe related? 518 */ 519static void 520SPIN(ffb_dacPtr d, int count) { 521 while(count-- > 0) { 522 (void) DACCFG_READ(d, FFBDAC_CFG_TGVC); 523 } 524 return; 525} 526 527/* Screen save (blank) restore */ 528Bool 529FFBDacSaveScreen(FFBPtr pFfb, int mode) { 530 int tmp; 531 ffb_dacPtr dac; 532 if(!pFfb) return FALSE; /* Is there any way at all this could happen? */ 533 else dac = pFfb -> dac; 534 535 tmp = DACCFG_READ(dac, FFBDAC_CFG_TGEN); /* Get the timing information */ 536 537 switch(mode) { 538 case SCREEN_SAVER_ON: 539 case SCREEN_SAVER_CYCLE: 540 tmp &= ~FFBDAC_CFG_TGEN_VIDE; /* Kill the video */ 541 break; 542 543 case SCREEN_SAVER_OFF: 544 case SCREEN_SAVER_FORCER: 545 tmp |= FFBDAC_CFG_TGEN_VIDE; /* Turn the video on */ 546 break; 547 548 default: 549 return FALSE; /* Don't know what to do; gently fail. */ 550 } 551 DACCFG_WRITE(dac, FFBDAC_CFG_TGEN, tmp); /* Restore timing register, video set as asked */ 552 SPIN(dac, DPMS_SPIN_COUNT/10); 553 return TRUE; 554} 555 556/* DPMS Control, also hinted at by David Miller. 557 558 The rule seems to be: 559 560 StandBy = -HSYNC +VSYNC -VIDEO 561 Suspend = +HSYNC -VSYNC -VIDEO 562 Off = -HSYNC -VSYNC -VIDEO 563 On = +HSYNC +VSINC +VIDEO 564 565 If you don't force video off, someone periodically tries to turn the 566 monitor on for some reason. I don't know who or why, so I kill the video 567 when trying to go into some sort of energy saving mode. (In real life, 568 'xset s blank s xx' could well have taken care of this.) 569 570 Also, on MY monitor, StandBy as above defined (-H+V-Vid) in fact 571 gives the same as Off, which I don't want. Hence, I just do (-Vid) 572 573 05.xii.01, FEM 574 08.xii.01, FEM 575*/ 576void 577FFBDacDPMSMode(FFBPtr pFfb, int DPMSMode, int flags) { 578 int tmp; 579 ffb_dacPtr dac = pFfb -> dac; 580 581 tmp = DACCFG_READ(dac, FFBDAC_CFG_TGEN); /* Get timing control */ 582 583 switch(DPMSMode) { 584 585 case DPMSModeOn: 586 tmp &= ~(FFBDAC_CFG_TGEN_VSD | FFBDAC_CFG_TGEN_HSD); /* Turn off VSYNC, HSYNC 587 disable bits */ 588 tmp |= FFBDAC_CFG_TGEN_VIDE; /* Turn the video on */ 589 break; 590 591 case DPMSModeStandby: 592#ifdef DPMS_TRUE_STANDBY 593 tmp |= FFBDAC_CFG_TGEN_HSD; /* HSYNC = OFF */ 594#endif /* DPMS_TRUE_STANDBY */ 595 tmp &= ~FFBDAC_CFG_TGEN_VSD; /* VSYNC = ON */ 596 tmp &= ~FFBDAC_CFG_TGEN_VIDE; /* Kill the video */ 597 break; 598 599 case DPMSModeSuspend: 600 tmp |= FFBDAC_CFG_TGEN_VSD; /* VSYNC = OFF */ 601 tmp &= ~FFBDAC_CFG_TGEN_HSD; /* HSYNC = ON */ 602 tmp &= ~FFBDAC_CFG_TGEN_VIDE; /* Kill the video */ 603 break; 604 605 case DPMSModeOff: 606 tmp |= (FFBDAC_CFG_TGEN_VSD | FFBDAC_CFG_TGEN_HSD); /* Kill HSYNC, VSYNC both */ 607 tmp &= ~FFBDAC_CFG_TGEN_VIDE; /* Kill the video */ 608 break; 609 610 default: 611 return; /* If we get here, we really should log an error */ 612 } 613 DACCFG_WRITE(dac, FFBDAC_CFG_TGEN,tmp); /* Restore timing register, video set as asked */ 614 SPIN(dac, DPMS_SPIN_COUNT); /* Is this necessary? Why? */ 615} 616