📄 monitor_detection.c
字号:
snooze( 4000 ); OUTREG( regs, RADEON_TV_DAC_CNTL, RADEON_TV_DAC_CNTL_NBLANK | RADEON_TV_DAC_CNTL_NHOLD | RADEON_TV_DAC_CNTL_DETECT | RADEON_TV_DAC_CNTL_STD_NTSC | (8 << RADEON_TV_DAC_CNTL_BGADJ_SHIFT) | (6 << RADEON_TV_DAC_CNTL_DACADJ_SHIFT )); (void)INREG( regs, RADEON_TV_DAC_CNTL ); snooze( 6000 ); // now see which wires are connected tmp = INREG( regs, RADEON_TV_DAC_CNTL ); if( (tmp & RADEON_TV_DAC_CNTL_GDACDET) != 0 ) { displays |= dd_stv; SHOW_INFO0( 2, "S-Video TV-Out is connected" ); } if( (tmp & RADEON_TV_DAC_CNTL_BDACDET) != 0 ) { displays |= dd_ctv; SHOW_INFO0( 2, "Composite TV-Out is connected" ); } // clean up the mess we did OUTREG( regs, RADEON_TV_DAC_CNTL, old_tv_dac_cntl ); OUTREG( regs, RADEON_DAC_EXT_CNTL, old_dac_ext_cntl ); OUTREG( regs, RADEON_CRTC2_GEN_CNTL, old_crtc2_gen_cntl ); OUTREG( regs, RADEON_DAC_CNTL2, old_dac_cntl2 ); OUTREGP( regs, RADEON_GPIOPAD_A, old_radeon_gpiopad_a, ~1 ); return displays;}// save readout of TV detection comparatorsstatic bool readTVDetect( accelerator_info *ai ){ uint32 tmp; int i; bigtime_t start_time; bool detect; // make output constant Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, RADEON_TV_DAC_CNTL_STD_NTSC | RADEON_TV_DAC_CNTL_DETECT | RADEON_TV_DAC_CNTL_NBLANK ); // check detection result Radeon_VIPRead( ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, &tmp ); detect = (tmp & RADEON_TV_DAC_CNTL_CMPOUT) != 0; //SHOW_FLOW( 2, "detect=%d", detect ); start_time = system_time(); do { // wait for stable detect signal for( i = 0; i < 5; ++i ) { bool cur_detect; Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, RADEON_TV_DAC_CNTL_STD_NTSC | RADEON_TV_DAC_CNTL_DETECT | RADEON_TV_DAC_CNTL_NBLANK | RADEON_TV_DAC_CNTL_NHOLD ); Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, RADEON_TV_DAC_CNTL_STD_NTSC | RADEON_TV_DAC_CNTL_DETECT | RADEON_TV_DAC_CNTL_NBLANK ); Radeon_VIPRead( ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, &tmp ); cur_detect = (tmp & RADEON_TV_DAC_CNTL_CMPOUT) != 0; //SHOW_FLOW( 2, "cur_detect=%d", cur_detect ); if( cur_detect != detect ) break; detect = cur_detect; } if( i == 5 ) { //SHOW_FLOW( 2, "return %d", detect ); return detect; } // don't wait forever - give up after 1 second } while( system_time() - start_time < 1000000 ); SHOW_FLOW0( 2, "timeout" ); return false;}// detect TV connected to external Theatre-Outstatic display_device_e Radeon_DetectTV_Theatre( accelerator_info *ai ){ uint32 old_tv_dac_cntl, old_pre_dac_mux_cntl, old_modulator_cntl1, old_master_cntl; uint32 uv_adr, old_last_fifo_entry, old_mid_fifo_entry, last_fifo_addr; display_device_e displays = dd_none; if( ai->si->tv_chip != tc_external_rt1 ) return dd_none; // save previous values (TV-Out may be running) Radeon_VIPRead( ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, &old_tv_dac_cntl ); // enable DAC and comparators Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, RADEON_TV_DAC_CNTL_STD_NTSC | RADEON_TV_DAC_CNTL_DETECT | RADEON_TV_DAC_CNTL_NHOLD | RADEON_TV_DAC_CNTL_NBLANK ); Radeon_VIPRead( ai, ai->si->theatre_channel, THEATRE_VIP_PRE_DAC_MUX_CNTL, &old_pre_dac_mux_cntl ); Radeon_VIPRead( ai, ai->si->theatre_channel, THEATRE_VIP_MODULATOR_CNTL1, &old_modulator_cntl1 ); Radeon_VIPRead( ai, ai->si->theatre_channel, THEATRE_VIP_MASTER_CNTL, &old_master_cntl ); // save output timing Radeon_VIPRead( ai, ai->si->theatre_channel, THEATRE_VIP_UV_ADR, &uv_adr ); last_fifo_addr = (uv_adr & RADEON_TV_UV_ADR_MAX_UV_ADR_MASK) * 2 + 1; old_last_fifo_entry = Radeon_TheatreReadFIFO( ai, last_fifo_addr ); old_mid_fifo_entry = Radeon_TheatreReadFIFO( ai, 0x18f ); Radeon_TheatreWriteFIFO( ai, last_fifo_addr, 0x20208 ); Radeon_TheatreWriteFIFO( ai, 0x18f, 0x3ff2608 ); // stop TV-Out to savely program it Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_MASTER_CNTL, RADEON_TV_MASTER_CNTL_TV_FIFO_ASYNC_RST | RADEON_TV_MASTER_CNTL_TV_ASYNC_RST ); // set constant base level Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_MODULATOR_CNTL1, (0x2c << RADEON_TV_MODULATOR_CNTL1_SET_UP_LEVEL_SHIFT) | (0x2c << RADEON_TV_MODULATOR_CNTL1_BLANK_LEVEL_SHIFT) ); // enable output Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_MASTER_CNTL, RADEON_TV_MASTER_CNTL_TV_ASYNC_RST ); Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_MASTER_CNTL, 0 ); // set constant Composite output Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_PRE_DAC_MUX_CNTL, RADEON_TV_PRE_DAC_MUX_CNTL_CMP_BLU_EN | RADEON_TV_PRE_DAC_MUX_CNTL_DAC_DITHER_EN | (9 << RADEON_TV_PRE_DAC_MUX_CNTL_BLU_MX_SHIFT) | (0xa8 << RADEON_TV_PRE_DAC_MUX_CNTL_FORCE_DAC_DATA_SHIFT) ); // check for S-Video connection if( readTVDetect( ai )) { SHOW_FLOW0( 2, "Composite-Out of Rage Theatre is connected" ); displays |= dd_ctv; } // enable output changes Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, RADEON_TV_DAC_CNTL_STD_NTSC | RADEON_TV_DAC_CNTL_DETECT | RADEON_TV_DAC_CNTL_NBLANK | RADEON_TV_DAC_CNTL_NHOLD ); // set constant Y-output of S-Video adapter Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_PRE_DAC_MUX_CNTL, RADEON_TV_PRE_DAC_MUX_CNTL_Y_RED_EN | RADEON_TV_PRE_DAC_MUX_CNTL_DAC_DITHER_EN | (9 << RADEON_TV_PRE_DAC_MUX_CNTL_RED_MX_SHIFT) | (0xa8 << RADEON_TV_PRE_DAC_MUX_CNTL_FORCE_DAC_DATA_SHIFT) ); // check for composite connection if( readTVDetect( ai )) { SHOW_FLOW0( 2, "S-Video-Out of Rage Theatre is connected" ); displays |= dd_stv; } // restore everything Radeon_TheatreWriteFIFO( ai, last_fifo_addr, old_last_fifo_entry ); Radeon_TheatreWriteFIFO( ai, 0x18f, old_mid_fifo_entry ); Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_MASTER_CNTL, old_master_cntl ); Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_MODULATOR_CNTL1, old_modulator_cntl1 ); Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_PRE_DAC_MUX_CNTL, old_pre_dac_mux_cntl ); Radeon_VIPWrite( ai, ai->si->theatre_channel, THEATRE_VIP_TV_DAC_CNTL, old_tv_dac_cntl ); return displays;}// check whether there is a TV connected to TV-DAC// returns bit set, i.e. there can be S-Video or composite or bothstatic display_device_e Radeon_DetectTV( accelerator_info *ai, bool tv_crt_found ){ switch( ai->si->asic ) { case rt_r100: case rt_r200: return Radeon_DetectTV_Theatre( ai ); case rt_ve: case rt_m6: case rt_rv200: case rt_m7: case rt_rv250: case rt_m9: case rt_rv280: case rt_m9plus: // IGP method is guessed case rt_rs100: case rt_rs200: return Radeon_DetectTV_RV200( ai, tv_crt_found ); case rt_r300: case rt_r300_4p: case rt_rv350: case rt_rv360: case rt_m10: case rt_r350: case rt_r360: return Radeon_DetectTV_R300( ai ); } return dd_none;}// get native monitor timing, using Detailed Monitor Descriptionstatic void Radeon_FindFPTiming_DetailedMonitorDesc( const edid1_info *edid, fp_info *fp, uint32 *max_hsize, uint32 *max_vsize ){ int i; for( i = 0; i < EDID1_NUM_DETAILED_MONITOR_DESC; ++i ) { if( edid->detailed_monitor[i].monitor_desc_type == edid1_is_detailed_timing ) { const edid1_detailed_timing *timing = &edid->detailed_monitor[i].data.detailed_timing; SHOW_FLOW( 2, "Found detailed timing for mode %dx%d in DDC data", (int)timing->h_active, (int)timing->v_active ); if( timing->h_active > *max_hsize && timing->v_active > *max_vsize ) { *max_hsize = timing->h_active; *max_vsize = timing->v_active; // copy it to timing specification fp->panel_xres = timing->h_active; fp->h_blank = timing->h_blank; fp->h_over_plus = timing->h_sync_off; fp->h_sync_width = timing->h_sync_width; fp->panel_yres = timing->v_active; fp->v_blank = timing->v_blank; fp->v_over_plus = timing->v_sync_off; fp->v_sync_width = timing->v_sync_width; // BeOS uses kHz, but the timing is in 10 kHz fp->dot_clock = timing->pixel_clock * 10; } } }}// get native monitor timing, using Standard Timing table;// this table doesn't contain the actual timing, so we try to find a// appropriate VESA modes for the resolutions given in the tablestatic void Radeon_FindFPTiming_StandardTiming( const edid1_info *edid, fp_info *fp, uint32 *max_hsize, uint32 *max_vsize ){ int i; for( i = 0; i < EDID1_NUM_STD_TIMING; ++i ) { const edid1_std_timing *std_timing = &edid->std_timing[i]; int best_fit = -1; int best_refresh_deviation = 10000; int j; if( std_timing->h_size <= 256 ) continue; for( j = 0; j < (int)vesa_mode_list_count; ++j ) { int refresh_rate, cur_refresh_deviation; if( vesa_mode_list[j].h_display != std_timing->h_size || vesa_mode_list[j].v_display != std_timing->v_size ) continue; // take pixel_clock times 1000 because is is in kHz // further, take it times 1000 again, to get 1/1000 frames // as refresh rate refresh_rate = (int64)vesa_mode_list[j].pixel_clock * 1000*1000 / (vesa_mode_list[j].h_total * vesa_mode_list[j].v_total); // standard timing is in frames, so multiple by it to get 1/1000 frames // result is scaled by 100 to get difference in percentage; cur_refresh_deviation = (100 * (refresh_rate - std_timing->refresh * 1000)) / refresh_rate; if( cur_refresh_deviation < 0 ) cur_refresh_deviation = -cur_refresh_deviation; // less then 1 percent difference is (hopefully) OK, // if there are multiple, we take best one // (if the screen is that picky, it should have defined an enhanced timing) if( cur_refresh_deviation < 1 && cur_refresh_deviation < best_refresh_deviation ) { best_fit = j; best_refresh_deviation = cur_refresh_deviation; } } if( best_fit < 0 ) { SHOW_FLOW( 2, "Unsupported standard mode %dx%d@%dHz (not VESA)", std_timing->h_size, std_timing->v_size, std_timing->refresh ); continue; } if( std_timing->h_size > *max_hsize && std_timing->h_size > *max_vsize ) { const display_timing *timing = &vesa_mode_list[best_fit]; SHOW_FLOW( 2, "Found DDC data for standard mode %dx%d", (int)timing->h_display, (int)timing->v_display ); *max_hsize = timing->h_display; *max_vsize = timing->h_display; // copy it to timing specification fp->panel_xres = timing->h_display; fp->h_blank = timing->h_total - timing->h_display; fp->h_over_plus = timing->h_sync_start - timing->h_display; fp->h_sync_width = timing->h_sync_end - timing->h_sync_start; fp->panel_yres = timing->v_display; fp->v_blank = timing->v_total - timing->v_display; fp->v_over_plus = timing->v_sync_start - timing->v_display; fp->v_sync_width = timing->v_sync_end - timing->v_sync_start; fp->dot_clock = timing->pixel_clock; } }} // read edid data of flat panel and setup its timing accordinglystatic status_t Radeon_StoreFPEDID( accelerator_info *ai, const edid1_info *edid ){ fp_info *fp = &ai->si->flatpanels[0]; uint32 max_hsize, max_vsize; SHOW_FLOW0( 2, "EDID data read from DVI port via DDC2:" ); edid_dump( edid ); // find detailed timing with maximum resolution max_hsize = max_vsize = 0; Radeon_FindFPTiming_DetailedMonitorDesc( edid, fp, &max_hsize, &max_vsize ); if( max_hsize == 0 ) { SHOW_FLOW0( 2, "Timing is not explicitely defined in DDC - checking standard modes" ); Radeon_FindFPTiming_StandardTiming( edid, fp, &max_hsize, &max_vsize ); if( max_hsize == 0 ) { SHOW_FLOW0( 2, "Still found no valid native mode, disabling DVI" ); return B_ERROR; } } SHOW_INFO( 2, "h_disp=%d, h_blank=%d, h_over_plus=%d, h_sync_width=%d", fp->panel_xres, fp->h_blank, fp->h_over_plus, fp->h_sync_width ); SHOW_INFO( 2, "v_disp=%d, v_blank=%d, v_over_plus=%d, v_sync_width=%d", fp->panel_yres, fp->v_blank, fp->v_over_plus, fp->v_sync_width ); SHOW_INFO( 2, "pixel_clock=%d kHz", fp->dot_clock ); return B_OK;}// detect connected displays devices// whished_num_heads - how many heads the requested display mode needsvoid Radeon_DetectDisplays( accelerator_info *ai ){ shared_info *si = ai->si; display_device_e displays = 0; display_device_e controlled_displays = ai->vc->controlled_displays; edid1_info edid; // lock hardware so noone bothers us Radeon_WaitForIdle( ai, true ); // mobile chips are for use in laptops - there must be a laptop panel if( si->is_mobility ) displays |= dd_lvds; // use DDC to detect monitors - if we can read DDC, there must be a monitor // all non-mobility versions have a DVI port if( (displays & dd_lvds) == 0 && Radeon_ReadEDID( ai, RADEON_GPIO_DVI_DDC, &edid )) { SHOW_FLOW0( 2, "Found monitor on DVI DDC port" ); // there may be an analog monitor connected to DVI-I; // we must check EDID to see whether it's really a digital monitor if( edid.display.input_type == 1 ) { SHOW_FLOW0( 2, "Must be a DVI monitor" ); // store info about DVI-connected flat-panel if( Radeon_StoreFPEDID( ai, &edid ) == B_OK ) { displays |= dd_dvi; } else { SHOW_ERROR0( 2, "Disabled DVI - invalid EDID" ); } } else { // must be the analog portion of DVI // I'm not sure about Radeons with one CRTC - do they have DVI-I or DVI-D? // anyway - if there are two CRTC, analog portion must be connected // to TV-DAC; if there is one CRTC, it must be the normal VGA-DAC if( si->num_crtc > 1 ) { SHOW_FLOW0( 2, "Must be an analog monitor on DVI port" ); displays |= dd_tv_crt; } else { SHOW_FLOW0( 2, "Seems to be a CRT on VGA port!?" ); displays |= dd_crt; } } } // all chips have a standard VGA port if( Radeon_ReadEDID( ai, RADEON_GPIO_VGA_DDC, &edid )) displays |= dd_crt; // we may have overseen monitors if they don't support DDC or // have broken DDC data (like mine); // time to do a physical wire test; this test is more reliable, but it // leads to distortions on screen, which is not very nice to look at // for DVI, there is no mercy if no DDC data is there - we wouldn't // even know the native resolution of the panel! // all versions have a standard VGA port if( (displays & dd_crt) == 0 && (controlled_displays && dd_crt) != 0 && Radeon_DetectCRT( ai )) displays |= dd_crt; // check VGA signal routed to DVI port // (the detection code checks whether there is hardware for that) if( (displays & dd_tv_crt) == 0 && (controlled_displays && dd_tv_crt) != 0 && Radeon_DetectTVCRT( ai )) displays |= dd_tv_crt; // check TV-out connector if( (controlled_displays && (dd_ctv | dd_stv)) != 0 ) displays |= Radeon_DetectTV( ai, (displays & dd_tv_crt) != 0 ); SHOW_INFO( 0, "Detected monitors: 0x%x", displays ); displays &= controlled_displays; // if no monitor found, we define to have a CRT connected to CRT-DAC if( displays == 0 ) displays = dd_crt; ai->vc->connected_displays = displays; RELEASE_BEN( si->cp.lock );}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -