diff --git a/src/i830_sdvo.c b/src/i830_sdvo.c index 254b866..5606222 100644 --- a/src/i830_sdvo.c +++ b/src/i830_sdvo.c @@ -119,6 +119,25 @@ struct i830_sdvo_priv { struct i830_sdvo_dtd save_output_dtd[16]; uint32_t save_SDVOX; /** @} */ + + /** Position and overscan properties */ + /** @{ */ + int16_t position_h; + int16_t position_v; + int8_t overscan_h; + int8_t overscan_v; + /** @} */ + + /** Picture parameters */ + /** @{ */ + int16_t saturation; + int16_t hue; + int16_t brightness; + int16_t contrast; + int16_t sharpness; + int16_t tv_chroma; + int16_t tv_luma; + /** @} */ }; /** @@ -991,6 +1010,107 @@ i830_sdvo_set_tv_format(xf86OutputPtr output) } static Bool +i830_sdvo_run_set_command(xf86OutputPtr output, uint8_t command, + void *val, size_t size) +{ + uint8_t status; + + i830_sdvo_write_cmd(output, command, val, size); + status = i830_sdvo_read_response(output, NULL, 0); + if (status != SDVO_CMD_STATUS_SUCCESS) + return FALSE; + + return TRUE; +} + +static Bool +i830_sdvo_run_get_command(xf86OutputPtr output, uint8_t command, + void *result, size_t size) +{ + uint8_t status; + + i830_sdvo_write_cmd(output, command, NULL, 0); + status = i830_sdvo_read_response(output, result, size); + + return (status == SDVO_CMD_STATUS_SUCCESS); +} + +static void +i830_sdvo_set_position_and_overscan(xf86OutputPtr output) +{ + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_sdvo_priv *dev_priv = intel_output->dev_priv; + int16_t pos_h = 512 + dev_priv->position_h; + int16_t pos_v = 512 + dev_priv->position_v; + int8_t ovscn_h = 32 + dev_priv->overscan_h; + int8_t ovscn_v = 32 + dev_priv->overscan_v; + + int16_t max_pos; + if (i830_sdvo_run_get_command(output, SDVO_CMD_GET_MAX_POSITION_H, &max_pos, sizeof(max_pos))) + if (pos_h > max_pos) + pos_h = max_pos; + if (i830_sdvo_run_get_command(output, SDVO_CMD_GET_MAX_POSITION_V, &max_pos, sizeof(max_pos))) + if (pos_v > max_pos) + pos_v = max_pos; + int8_t max_ovscn; + if (i830_sdvo_run_get_command(output, SDVO_CMD_GET_MAX_OVERSCAN_H, &max_ovscn, sizeof(max_ovscn))) + if (ovscn_h > max_ovscn) + ovscn_h = max_ovscn; + if (i830_sdvo_run_get_command(output, SDVO_CMD_GET_MAX_OVERSCAN_V, &max_ovscn, sizeof(max_ovscn))) + if (ovscn_v > max_ovscn) + ovscn_v = max_ovscn; + + //xf86DrvMsg(output->scrn->scrnIndex, X_INFO, + // "Position H: %d, Position V: %d, Overscan H: %d, Overscan V %d\n", + // pos_h, pos_v, ovscn_h, ovscn_v); + + i830_sdvo_run_set_command(output, SDVO_CMD_SET_POSITION_H, + &pos_h, sizeof(pos_h)); + i830_sdvo_run_set_command(output, SDVO_CMD_SET_POSITION_V, + &pos_v, sizeof(pos_v)); + i830_sdvo_run_set_command(output, SDVO_CMD_SET_OVERSCAN_H, + &ovscn_h, sizeof(ovscn_h)); + i830_sdvo_run_set_command(output, SDVO_CMD_SET_OVERSCAN_V, + &ovscn_v, sizeof(ovscn_v)); +} + +static void +i830_sdvo_set_picture_param(xf86OutputPtr output, uint8_t set_cmd, + uint8_t get_max_cmd, int16_t param) +{ + uint8_t val; + uint8_t max; + if (param < 0) + return; + val = (uint8_t)param; + if (i830_sdvo_run_get_command(output, get_max_cmd, &max, sizeof(max))) + if (val > max) + val = max; +} + +static void +i830_sdvo_set_picture_params(xf86OutputPtr output) +{ + I830OutputPrivatePtr intel_output = output->driver_private; + struct i830_sdvo_priv *dev_priv = intel_output->dev_priv; + + i830_sdvo_set_picture_param(output, SDVO_CMD_SET_HUE, + SDVO_CMD_GET_MAX_HUE, dev_priv->hue); + i830_sdvo_set_picture_param(output, SDVO_CMD_SET_SATURATION, + SDVO_CMD_GET_MAX_SATURATION, dev_priv->saturation); + i830_sdvo_set_picture_param(output, SDVO_CMD_SET_BRIGHTNESS, + SDVO_CMD_GET_MAX_BRIGHTNESS, dev_priv->brightness); + i830_sdvo_set_picture_param(output, SDVO_CMD_SET_CONTRAST, + SDVO_CMD_GET_MAX_CONTRAST, dev_priv->contrast); + i830_sdvo_set_picture_param(output, SDVO_CMD_SET_SHARPNESS, + SDVO_CMD_GET_MAX_SHARPNESS_V, dev_priv->sharpness); + i830_sdvo_set_picture_param(output, SDVO_CMD_SET_TV_CHROMA, + SDVO_CMD_GET_MAX_TV_CHROMA, dev_priv->tv_chroma); + i830_sdvo_set_picture_param(output, SDVO_CMD_SET_TV_LUMA, + SDVO_CMD_GET_MAX_TV_LUMA, dev_priv->tv_luma); +} + +static Bool i830_sdvo_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, DisplayModePtr adjusted_mode) { @@ -1024,6 +1144,9 @@ i830_sdvo_mode_fixup(xf86OutputPtr output, DisplayModePtr mode, i830_sdvo_set_target_input(output, TRUE, FALSE); + /* Since this affects prefered timings let it go before creating them */ + i830_sdvo_set_position_and_overscan(output); + success = i830_sdvo_create_preferred_input_timing(output, mode->Clock / 10, mode->HDisplay, @@ -1173,6 +1296,8 @@ i830_sdvo_mode_set(xf86OutputPtr output, DisplayModePtr mode, } i830_sdvo_write_sdvox(output, sdvox); + + i830_sdvo_set_picture_params(output); } static void @@ -1680,13 +1805,20 @@ i830_sdvo_detect(xf86OutputPtr output) struct i830_sdvo_priv *dev_priv = intel_output->dev_priv; uint16_t response; uint8_t status; + int attempts = 5; - i830_sdvo_write_cmd(output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0); - status = i830_sdvo_read_response(output, &response, 2); - - if (status != SDVO_CMD_STATUS_SUCCESS) - return XF86OutputStatusUnknown; + /* Detecting attached TV is not 100% reliable so lets make several attempts */ + while(attempts--) + { + i830_sdvo_write_cmd(output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0); + status = i830_sdvo_read_response(output, &response, 2); + if (status != SDVO_CMD_STATUS_SUCCESS) + return XF86OutputStatusUnknown; + + if (response != 0) + break; + } if (response == 0) return XF86OutputStatusDisconnected; @@ -1990,7 +2122,6 @@ i830_sdvo_select_ddc_bus(struct i830_sdvo_priv *dev_priv) dev_priv->ddc_bus = 1 << num_bits; } - Bool i830_sdvo_init(ScrnInfoPtr pScrn, int output_device) { @@ -2000,6 +2131,7 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device) int i; unsigned char ch[0x40]; I2CBusPtr i2cbus = NULL, ddcbus; + XF86OptionPtr mon_option_lst = NULL; output = xf86OutputCreate (pScrn, &i830_sdvo_output_funcs,NULL); if (!output) @@ -2134,6 +2266,20 @@ i830_sdvo_init(ScrnInfoPtr pScrn, int output_device) SDVO_NAME(dev_priv), dev_priv->caps.sdvo_input_count, dev_priv->caps.sdvo_input_count >= 2 ? "s" : ""); + if (output->conf_monitor) + mon_option_lst = output->conf_monitor->mon_option_lst; + dev_priv->position_h = xf86SetIntOption(mon_option_lst, "Position H", 0); + dev_priv->position_v = xf86SetIntOption(mon_option_lst, "Position V", 0); + dev_priv->overscan_h = xf86SetIntOption(mon_option_lst, "Overscan H", 0); + dev_priv->overscan_v = xf86SetIntOption(mon_option_lst, "Overscan V", 0); + dev_priv->saturation = xf86SetIntOption(mon_option_lst, "Saturation", -1); + dev_priv->hue = xf86SetIntOption(mon_option_lst, "Hue", -1); + dev_priv->brightness = xf86SetIntOption(mon_option_lst, "Brightness", -1); + dev_priv->contrast = xf86SetIntOption(mon_option_lst, "Contrast", -1); + dev_priv->sharpness = xf86SetIntOption(mon_option_lst, "Sharpness", -1); + dev_priv->tv_chroma = xf86SetIntOption(mon_option_lst, "TV Chroma", -1); + dev_priv->tv_luma = xf86SetIntOption(mon_option_lst, "TV Luma", -1); + #define REPORT_OUTPUT_FLAG(flag, name) do { \ if (dev_priv->caps.output_flags & flag) { \ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s: %s output reported\n", \