xref: /haiku/src/add-ons/accelerants/nvidia/SetDisplayMode.c (revision 01b25646004ff628ecad0281a9795e5e90f71746)
1 
2 /*
3 	Copyright 1999, Be Incorporated.   All Rights Reserved.
4 	This file may be used under the terms of the Be Sample Code License.
5 
6 	Other authors:
7 	Mark Watson,
8 	Apsed,
9 	Rudolf Cornelissen 11/2002-12/2003
10 */
11 
12 #define MODULE_BIT 0x00200000
13 
14 #include "acc_std.h"
15 
16 /*
17 	Enable/Disable interrupts.  Just a wrapper around the
18 	ioctl() to the kernel driver.
19 */
20 static void interrupt_enable(bool flag) {
21 	status_t result;
22 	nv_set_bool_state sbs;
23 
24 	/* set the magic number so the driver knows we're for real */
25 	sbs.magic = NV_PRIVATE_DATA_MAGIC;
26 	sbs.do_it = flag;
27 	/* contact driver and get a pointer to the registers and shared data */
28 	result = ioctl(fd, NV_RUN_INTERRUPTS, &sbs, sizeof(sbs));
29 }
30 
31 /* First validate the mode, then call lots of bit banging stuff to set the mode(s)! */
32 status_t SET_DISPLAY_MODE(display_mode *mode_to_set)
33 {
34 	/* BOUNDS WARNING:
35 	 * It's impossible to deviate whatever small amount in a display_mode if the lower
36 	 * and upper limits are the same!
37 	 * Besides:
38 	 * BeOS (tested R5.0.3PE) is failing BWindowScreen::SetFrameBuffer() if PROPOSEMODE
39 	 * returns B_BAD_VALUE!
40 	 * Which means PROPOSEMODE should not return that on anything except on
41 	 * deviations for:
42 	 * display_mode.virtual_width;
43 	 * display_mode.virtual_height;
44 	 * display_mode.timing.h_display;
45 	 * display_mode.timing.v_display;
46 	 * So:
47 	 * We don't use bounds here by making sure bounds and target are the same struct!
48 	 * (See the call to PROPOSE_DISPLAY_MODE below) */
49 	display_mode /*bounds,*/ target;
50 
51 	uint8 colour_depth1 = 32;
52 	status_t result;
53 	uint32 startadd,startadd_right;
54 // apsed TODO startadd is 19 bits if < g200
55 
56 	bool display, h, v;
57 	si->switched_crtcs = false;
58 
59 	/* Adjust mode to valid one and fail if invalid */
60 	target /*= bounds*/ = *mode_to_set;
61 	/* show the mode bits */
62 	LOG(1, ("SETMODE: (ENTER) initial modeflags: $%08x\n", target.flags));
63 	LOG(1, ("SETMODE: requested target pixelclock %dkHz\n",  target.timing.pixel_clock));
64 	LOG(1, ("SETMODE: requested virtual_width %d, virtual_height %d\n",
65 										target.virtual_width, target.virtual_height));
66 
67 	/* See BOUNDS WARNING above... */
68 	if (PROPOSE_DISPLAY_MODE(&target, &target, &target) == B_ERROR)	return B_ERROR;
69 
70 	/* if not dualhead capable card clear dualhead flags */
71 	if (!(target.flags & DUALHEAD_CAPABLE))
72 	{
73 		target.flags &= ~DUALHEAD_BITS;
74 	}
75 	/* if not TVout capable card clear TVout flags */
76 	if (!(target.flags & TV_CAPABLE))
77 	{
78 		target.flags &= ~TV_BITS;
79 	}
80 	LOG(1, ("SETMODE: (CONT.) validated command modeflags: $%08x\n", target.flags));
81 
82 	/* disable interrupts using the kernel driver */
83 	interrupt_enable(false);
84 
85 	/* find current DPMS state, then turn off screen(s) */
86 	nv_crtc_dpms_fetch(&display, &h, &v);
87 	nv_crtc_dpms(false, false, false);
88 //	if (si->ps.secondary_head) g400_crtc2_dpms(0,0,0);
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 	nv_general_validate_pic_size (&target, &si->fbc.bytes_per_row);
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 (nv_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 (nv_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 			nv_dac_mode(BPP16, 1.0);
133 			nv_crtc_depth(BPP16);
134 			break;
135 		case B_RGB32_LITTLE:
136 			colour_depth1 = 32;
137 			nv_dac_mode(BPP32, 1.0);
138 			nv_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 			nv_maven_mode(BPP16, 1.0);
147 			g400_crtc2_depth(BPP16);
148 			break;
149 		case B_RGB32_LITTLE:
150 			colour_depth2 = 32;
151 			nv_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 		nv_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 		/* setup vertical timing adjust for crtc1 and crtc2 for straight-through CRTC's */
174 		/* (extra "blanking" line for MAVEN) */
175 		target2.timing.v_display++;
176 
177 		/* set the outputs */
178 		switch (si->ps.card_type)
179 		{
180 		case NV11:
181 			switch (target.flags & DUALHEAD_BITS)
182 			{
183 			case DUALHEAD_ON:
184 			case DUALHEAD_CLONE:
185 				nv_general_dac_select(DS_CRTC1DAC_CRTC2MAVEN);
186 				si->switched_crtcs = false;
187 				break;
188 			case DUALHEAD_SWITCH:
189 				if (i2c_sec_tv_adapter() == B_OK)
190 				{
191 					/* Don't switch CRTC's because MAVEN YUV is impossible then,
192 					 * and primary head output will be limited to 135Mhz pixelclock. */
193 					LOG(4,("SETMODE: secondary TV-adapter detected, switching buffers\n"));
194 					nv_general_dac_select(DS_CRTC1DAC_CRTC2MAVEN);
195 					si->switched_crtcs = true;
196 				}
197 				else
198 				{
199 					/* This limits the pixelclocks on both heads to 135Mhz,
200 					 * but you can use overlay on the other output now. */
201 					LOG(4,("SETMODE: no secondary TV-adapter detected, switching CRTCs\n"));
202 					nv_general_dac_select(DS_CRTC1MAVEN_CRTC2DAC);
203 					si->switched_crtcs = false;
204 					/* re-calculate MAVEN-CRTC delay: formula valid for crossed CRTC's */
205 					si->crtc_delay = 17 + 4 * (colour_depth1 == 16);
206 					/* re-setup vertical timing adjust for crtc1 and crtc2 for crossed CRTC's */
207 					/* (extra "blanking" line for MAVEN) */
208 					target.timing.v_display++;
209 					target2.timing.v_display--;
210 				}
211 				break;
212 			}
213 			break;
214 		//fixme:
215 		//setup crtc_delay and vertical timing adjust for G450(?)/G550,
216 		//and remove the '+1' in crtc2 vertical timing(?)
217 		case NV17:
218 			if (!si->ps.primary_dvi)
219 			/* output connector use is always 'straight-through' */
220 			//fixme: re-evaluate when DVI is setup...
221 			{
222 				switch (target.flags & DUALHEAD_BITS)
223 				{
224 				case DUALHEAD_ON:
225 				case DUALHEAD_CLONE:
226 					nv_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
227 					si->switched_crtcs = false;
228 					break;
229 				case DUALHEAD_SWITCH:
230 					if (i2c_sec_tv_adapter() == B_OK)
231 					{
232 						/* Don't switch CRTC's because MAVEN YUV and TVout is impossible then,
233 						 * and primary head output will be limited to 235Mhz pixelclock. */
234 						LOG(4,("SETMODE: secondary TV-adapter detected, switching buffers\n"));
235 						nv_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
236 						si->switched_crtcs = true;
237 					}
238 					else
239 					{
240 						/* This limits the pixelclocks on both heads to 235Mhz,
241 						 * but you can use overlay on the other output now. */
242 						LOG(4,("SETMODE: no secondary TV-adapter detected, switching CRTCs\n"));
243 						nv_general_dac_select(DS_CRTC1CON2_CRTC2CON1);
244 						si->switched_crtcs = false;
245 					}
246 					break;
247 				}
248 			}
249 			else
250 			/* output connector use is cross-linked if no TV cable connected! */
251 			//fixme: re-evaluate when DVI is setup...
252 			{
253 				switch (target.flags & DUALHEAD_BITS)
254 				{
255 				case DUALHEAD_ON:
256 				case DUALHEAD_CLONE:
257 					if (i2c_sec_tv_adapter() == B_OK)
258 					{
259 						nv_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
260 						si->switched_crtcs = false;
261 					}
262 					else
263 					{
264 						/* This limits the pixelclocks on both heads to 235Mhz,
265 						 * but you can use overlay on the other output now. */
266 						nv_general_dac_select(DS_CRTC1CON2_CRTC2CON1);
267 						si->switched_crtcs = false;
268 					}
269 					break;
270 				case DUALHEAD_SWITCH:
271 					if (i2c_sec_tv_adapter() == B_OK)
272 					{
273 						/* Don't switch CRTC's because MAVEN YUV and TVout is impossible then,
274 						 * and primary head output will be limited to 235Mhz pixelclock. */
275 						LOG(4,("SETMODE: secondary TV-adapter detected, switching buffers\n"));
276 						nv_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
277 						si->switched_crtcs = true;
278 					}
279 					else
280 					{
281 						LOG(4,("SETMODE: no secondary TV-adapter detected, switching CRTCs\n"));
282 						nv_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
283 						si->switched_crtcs = false;
284 					}
285 					break;
286 				}
287 			}
288 			break;
289 		default:
290 			break;
291 		}
292 
293 		if (si->switched_crtcs)
294 		{
295 				uint32 temp = startadd;
296 				startadd = startadd_right;
297 				startadd_right = temp;
298 		}
299 
300 		/*Tell card what memory to display*/
301 		switch (target.flags & DUALHEAD_BITS)
302 		{
303 		case DUALHEAD_ON:
304 		case DUALHEAD_SWITCH:
305 			nv_crtc_set_display_start(startadd,colour_depth1);
306 			g400_crtc2_set_display_start(startadd_right,colour_depth2);
307 			break;
308 		case DUALHEAD_CLONE:
309 			nv_crtc_set_display_start(startadd,colour_depth1);
310 			g400_crtc2_set_display_start(startadd,colour_depth2);
311 			break;
312 		}
313 
314 		/* set the timing */
315 		nv_crtc_set_timing(target);
316 		/* we do not need to setup CRTC2 here for a head that's in TVout mode */
317 		if (!(target2.flags & TV_BITS))	result = g400_crtc2_set_timing(target2);
318 
319 		/* TVout support: setup CRTC2 and it's pixelclock */
320 		if (si->ps.tvout && (target2.flags & TV_BITS))
321 		{
322 			si->crtc_delay += 5;
323 			maventv_init(target2);
324 		}
325 	}
326 	else /* single head mode */
327 	{
328 		status_t status;
329 		int colour_mode = BPP32;
330 
331 		switch(target.space)
332 		{
333 		case B_CMAP8:        colour_depth1 =  8; colour_mode = BPP8;  break;
334 		case B_RGB15_LITTLE: colour_depth1 = 16; colour_mode = BPP15; break;
335 		case B_RGB16_LITTLE: colour_depth1 = 16; colour_mode = BPP16; break;
336 		case B_RGB32_LITTLE: colour_depth1 = 32; colour_mode = BPP32; break;
337 		default:
338 			LOG(8,("SETMODE: Invalid singlehead colour depth 0x%08x\n", target.space));
339 			return B_ERROR;
340 		}
341 
342 		/* set the pixel clock PLL */
343 		status = nv_dac_set_pix_pll(target);
344 
345 		if (status==B_ERROR)
346 			LOG(8,("CRTC: error setting pixel clock (internal DAC)\n"));
347 
348 		/* set the colour depth for CRTC1 and the DAC */
349 		/* first set the colordepth */
350 		nv_crtc_depth(colour_mode);
351 		/* then(!) program the PAL (<8bit colordepth does not support 8bit PAL) */
352 		nv_dac_mode(colour_mode,1.0);
353 
354 		/* set the display pitch */
355 		nv_crtc_set_display_pitch();
356 
357 		/* tell the card what memory to display */
358 		nv_crtc_set_display_start(startadd,colour_depth1);
359 
360 		/* enable primary analog output */
361 		switch (si->ps.card_type)
362 		{
363 		case NV11:
364 //			nv_general_dac_select(DS_CRTC1DAC_CRTC2MAVEN);
365 			break;
366 		case NV17:
367 //			nv_general_dac_select(DS_CRTC1CON1_CRTC2CON2);
368 //			gx50_general_output_select();
369 			break;
370 		default:
371 			break;
372 		}
373 
374 		/* set the timing */
375 		nv_crtc_set_timing(target);
376 
377 		//fixme: shut-off the videoPLL if it exists...
378 	}
379 
380 	/* update driver's mode store */
381 	si->dm = target;
382 
383 	/* turn screen one on */
384 	nv_crtc_dpms(display, h, v);
385 	/* turn screen two on if a dualhead mode is active */
386 //	if (target.flags & DUALHEAD_BITS) g400_crtc2_dpms(display,h,v);
387 
388 	/* set up acceleration for this mode */
389 	nv_acc_init();
390 	/* set up overlay unit for this mode */
391 	nv_bes_init();
392 
393 	MSG(("SETMODE: booted since %f mS\n", system_time()/1000.0));
394 
395 	/* enable interrupts using the kernel driver */
396 	interrupt_enable(true);
397 
398 	/* optimize memory-access if needed */
399 //	nv_crtc_mem_priority(colour_depth1);
400 
401 	/* Tune RAM CAS-latency if needed. Must be done *here*! */
402 	nv_set_cas_latency();
403 
404 	return B_OK;
405 }
406 
407 /*
408 	Set which pixel of the virtual frame buffer will show up in the
409 	top left corner of the display device.  Used for page-flipping
410 	games and virtual desktops.
411 */
412 status_t MOVE_DISPLAY(uint16 h_display_start, uint16 v_display_start) {
413 	uint8 colour_depth;
414 	uint32 startadd,startadd_right;
415 
416 	LOG(4,("MOVE_DISPLAY: h %d, v %d\n", h_display_start, v_display_start));
417 
418 	/* reset lower bits, don't return an error! */
419 //fixme: not needed in dualhead on Nvidia??? (pixelprecise panning on sec. head??)
420 	if (si->dm.flags & DUALHEAD_BITS)
421 	{
422 		switch(si->dm.space)
423 		{
424 		case B_RGB16_LITTLE:
425 			colour_depth=16;
426 			h_display_start &= ~0x1f;
427 			break;
428 		case B_RGB32_LITTLE:
429 			colour_depth=32;
430 			h_display_start &= ~0x0f;
431 			break;
432 		default:
433 			LOG(8,("SET:Invalid DH colour depth 0x%08x, should never happen\n", si->dm.space));
434 			return B_ERROR;
435 		}
436 	}
437 	else
438 	{
439 		/* Nvidia always does pixelprecise panning on primary head */
440 		switch(si->dm.space)
441 		{
442 		case B_CMAP8:
443 			colour_depth=8;
444 //			h_display_start &= ~0x07;
445 			break;
446 		case B_RGB15_LITTLE: case B_RGB16_LITTLE:
447 			colour_depth=16;
448 //			h_display_start &= ~0x03;
449 			break;
450 		case B_RGB32_LITTLE:
451 			colour_depth=32;
452 //			h_display_start &= ~0x01;
453 			break;
454 		default:
455 			return B_ERROR;
456 		}
457 	}
458 
459 	/* do not run past end of display */
460 	switch (si->dm.flags & DUALHEAD_BITS)
461 	{
462 	case DUALHEAD_ON:
463 	case DUALHEAD_SWITCH:
464 		if (((si->dm.timing.h_display * 2) + h_display_start) > si->dm.virtual_width)
465 			return B_ERROR;
466 		break;
467 	default:
468 		if ((si->dm.timing.h_display + h_display_start) > si->dm.virtual_width)
469 			return B_ERROR;
470 		break;
471 	}
472 	if ((si->dm.timing.v_display + v_display_start) > si->dm.virtual_height)
473 		return B_ERROR;
474 
475 	/* everybody remember where we parked... */
476 	si->dm.h_display_start = h_display_start;
477 	si->dm.v_display_start = v_display_start;
478 
479 	/* actually set the registers */
480 	//fixme: seperate both heads: we need a secondary si->fbc!
481 	startadd = v_display_start * si->fbc.bytes_per_row;
482 	startadd += h_display_start * (colour_depth >> 3);
483 	startadd += (uint8*)si->fbc.frame_buffer - (uint8*)si->framebuffer;
484 	startadd_right = startadd + si->dm.timing.h_display * (colour_depth >> 3);
485 
486 	/* account for switched CRTC's */
487 	if (si->switched_crtcs)
488 	{
489 		uint32 temp = startadd;
490 		startadd = startadd_right;
491 		startadd_right = temp;
492 	}
493 
494 	interrupt_enable(false);
495 
496 	switch (si->dm.flags&DUALHEAD_BITS)
497 	{
498 		case DUALHEAD_ON:
499 		case DUALHEAD_SWITCH:
500 			nv_crtc_set_display_start(startadd,colour_depth);
501 			g400_crtc2_set_display_start(startadd_right,colour_depth);
502 			break;
503 		case DUALHEAD_OFF:
504 			nv_crtc_set_display_start(startadd,colour_depth);
505 			break;
506 		case DUALHEAD_CLONE:
507 			nv_crtc_set_display_start(startadd,colour_depth);
508 			g400_crtc2_set_display_start(startadd,colour_depth);
509 			break;
510 	}
511 
512 	interrupt_enable(true);
513 	return B_OK;
514 }
515 
516 /*
517 	Set the indexed color palette.
518 */
519 void SET_INDEXED_COLORS(uint count, uint8 first, uint8 *color_data, uint32 flags) {
520 	int i;
521 	uint8 *r,*g,*b;
522 
523 	/* Protect gamma correction when not in CMAP8 */
524 	if (si->dm.space != B_CMAP8) return;
525 
526 	r=si->color_data;
527 	g=r+256;
528 	b=g+256;
529 
530 	i=first;
531 	while (count--)
532 	{
533 		r[i]=*color_data++;
534 		g[i]=*color_data++;
535 		b[i]=*color_data++;
536 		i++;
537 	}
538 	nv_dac_palette(r,g,b);
539 }
540 
541 
542 /* masks for DPMS control bits */
543 enum {
544 	H_SYNC_OFF = 0x01,
545 	V_SYNC_OFF = 0x02,
546 	DISPLAY_OFF = 0x04,
547 	BITSMASK = (H_SYNC_OFF | V_SYNC_OFF | DISPLAY_OFF)
548 };
549 
550 /* Put the display into one of the Display Power Management modes. */
551 status_t SET_DPMS_MODE(uint32 dpms_flags) {
552 	interrupt_enable(false);
553 
554 	LOG(4,("SET_DPMS_MODE: 0x%08x\n", dpms_flags));
555 
556 	if (si->dm.flags & DUALHEAD_BITS) /*dualhead*/
557 	{
558 		switch(dpms_flags)
559 		{
560 		case B_DPMS_ON:	/* H: on, V: on, display on */
561 			nv_crtc_dpms(true, true, true);
562 			if (si->ps.secondary_head) g400_crtc2_dpms(1,1,1);
563 			break;
564 		case B_DPMS_STAND_BY:
565 			nv_crtc_dpms(false, false, true);
566 			if (si->ps.secondary_head) g400_crtc2_dpms(0,0,1);
567 			break;
568 		case B_DPMS_SUSPEND:
569 			nv_crtc_dpms(false, true, false);
570 			if (si->ps.secondary_head) g400_crtc2_dpms(0,1,0);
571 			break;
572 		case B_DPMS_OFF: /* H: off, V: off, display off */
573 			nv_crtc_dpms(false, false, false);
574 			if (si->ps.secondary_head) g400_crtc2_dpms(0,0,0);
575 			break;
576 		default:
577 			LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags));
578 			interrupt_enable(true);
579 			return B_ERROR;
580 		}
581 	}
582 	else /* singlehead */
583 	{
584 		switch(dpms_flags)
585 		{
586 		case B_DPMS_ON:	/* H: on, V: on, display on */
587 			nv_crtc_dpms(true, true, true);
588 			break;
589 		case B_DPMS_STAND_BY:
590 			nv_crtc_dpms(false, false, true);
591 			break;
592 		case B_DPMS_SUSPEND:
593 			nv_crtc_dpms(false, true, false);
594 			break;
595 		case B_DPMS_OFF: /* H: off, V: off, display off */
596 			nv_crtc_dpms(false, false, false);
597 			break;
598 		default:
599 			LOG(8,("SET: Invalid DPMS settings (DH) 0x%08x\n", dpms_flags));
600 			interrupt_enable(true);
601 			return B_ERROR;
602 		}
603 	}
604 	interrupt_enable(true);
605 	return B_OK;
606 }
607 
608 /* Report device DPMS capabilities */
609 uint32 DPMS_CAPABILITIES(void) {
610 	return 	(B_DPMS_ON | B_DPMS_STAND_BY | B_DPMS_SUSPEND | B_DPMS_OFF);
611 }
612 
613 
614 /* Return the current DPMS mode */
615 uint32 DPMS_MODE(void) {
616 	bool display, h, v;
617 
618 	interrupt_enable(false);
619 	nv_crtc_dpms_fetch(&display, &h, &v);
620 	interrupt_enable(true);
621 
622 	if (display && h && v)
623 		return B_DPMS_ON;
624 	else if(v)
625 		return B_DPMS_STAND_BY;
626 	else if(h)
627 		return B_DPMS_SUSPEND;
628 	else
629 		return B_DPMS_OFF;
630 }
631