Index: linux-2.6/drivers/gpu/drm/i915/intel_sdvo.c
===================================================================
--- linux-2.6.orig/drivers/gpu/drm/i915/intel_sdvo.c	2009-08-06 08:32:38.000000000 +0800
+++ linux-2.6/drivers/gpu/drm/i915/intel_sdvo.c	2009-08-06 08:36:43.000000000 +0800
@@ -38,6 +38,18 @@
 
 #undef SDVO_DEBUG
 #define I915_SDVO	"i915_sdvo"
+static char *tv_format_names[] = {
+	"NTSC_M"   , "NTSC_J"  , "NTSC_443",
+	"PAL_B"    , "PAL_D"   , "PAL_G"   ,
+	"PAL_H"    , "PAL_I"   , "PAL_M"   ,
+	"PAL_N"    , "PAL_NC"  , "PAL_60"  ,
+	"SECAM_B"  , "SECAM_D" , "SECAM_G" ,
+	"SECAM_K"  , "SECAM_K1", "SECAM_L" ,
+	"SECAM_60"
+};
+
+#define TV_FORMAT_NUM  (sizeof(tv_format_names) / sizeof(*tv_format_names))
+
 struct intel_sdvo_priv {
 	u8 slave_addr;
 
@@ -71,6 +83,15 @@
 	 */
 	bool is_tv;
 
+	/* This is for current tv format name */
+	char *tv_format_name;
+
+	/* This contains all current supported TV format */
+	char *tv_format_supported[TV_FORMAT_NUM];
+	int   format_supported_num;
+	struct drm_property *tv_format_property;
+	struct drm_property *tv_format_name_property[TV_FORMAT_NUM];
+
 	/**
 	 * This is set if we treat the device as HDMI, instead of DVI.
 	 */
@@ -97,14 +118,6 @@
 	 */
 	struct intel_sdvo_sdtv_resolution_reply sdtv_resolutions;
 
-	/**
-	 * Current selected TV format.
-	 *
-	 * This is stored in the same structure that's passed to the device, for
-	 * convenience.
-	 */
-	struct intel_sdvo_tv_format tv_format;
-
 	/*
 	 * supported encoding mode, used to determine whether HDMI is
 	 * supported
@@ -945,23 +958,28 @@
 
 static void intel_sdvo_set_tv_format(struct intel_output *output)
 {
+
+	struct intel_sdvo_tv_format format;
 	struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
-	struct intel_sdvo_tv_format *format, unset;
-	u8 status;
+	uint32_t format_map, i;
+	uint8_t status;
 
-	format = &sdvo_priv->tv_format;
-	memset(&unset, 0, sizeof(unset));
-	if (memcmp(format, &unset, sizeof(*format))) {
-		DRM_DEBUG("%s: Choosing default TV format of NTSC-M\n",
-				SDVO_NAME(sdvo_priv));
-		format->ntsc_m = 1;
-		intel_sdvo_write_cmd(output, SDVO_CMD_SET_TV_FORMAT, format,
-				sizeof(*format));
-		status = intel_sdvo_read_response(output, NULL, 0);
-		if (status != SDVO_CMD_STATUS_SUCCESS)
-			DRM_DEBUG("%s: Failed to set TV format\n",
-					SDVO_NAME(sdvo_priv));
-	}
+	for (i = 0; i < TV_FORMAT_NUM; i++)
+		if (tv_format_names[i] == sdvo_priv->tv_format_name)
+			break;
+
+	format_map = 1 << i;
+	memset(&format, 0, sizeof(format));
+	memcpy(&format, &format_map, sizeof(format_map) > sizeof(format) ?
+			sizeof(format) : sizeof(format_map));
+
+	intel_sdvo_write_cmd(output, SDVO_CMD_SET_TV_FORMAT, &format_map,
+			     sizeof(format));
+
+	status = intel_sdvo_read_response(output, NULL, 0);
+	if (status != SDVO_CMD_STATUS_SUCCESS)
+		DRM_DEBUG("%s: Failed to set TV format\n",
+			  SDVO_NAME(sdvo_priv));
 }
 
 static bool intel_sdvo_mode_fixup(struct drm_encoder *encoder,
@@ -1516,7 +1534,8 @@
 	struct intel_output *intel_output = to_intel_output(connector);
 	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
 
-	intel_sdvo_write_cmd(intel_output, SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0);
+	intel_sdvo_write_cmd(intel_output,
+			     SDVO_CMD_GET_ATTACHED_DISPLAYS, NULL, 0);
 	status = intel_sdvo_read_response(intel_output, &response, 2);
 
 	DRM_DEBUG("SDVO response %d %d\n", response & 0xff, response >> 8);
@@ -1567,25 +1586,6 @@
 #endif
 }
 
-/**
- * This function checks the current TV format, and chooses a default if
- * it hasn't been set.
- */
-static void
-intel_sdvo_check_tv_format(struct intel_output *output)
-{
-	struct intel_sdvo_priv *dev_priv = output->dev_priv;
-	struct intel_sdvo_tv_format format;
-	uint8_t status;
-
-	intel_sdvo_write_cmd(output, SDVO_CMD_GET_TV_FORMAT, NULL, 0);
-	status = intel_sdvo_read_response(output, &format, sizeof(format));
-	if (status != SDVO_CMD_STATUS_SUCCESS)
-		return;
-
-	memcpy(&dev_priv->tv_format, &format, sizeof(format));
-}
-
 /*
  * Set of SDVO TV modes.
  * Note!  This is in reply order (see loop in get_tv_modes).
@@ -1656,17 +1656,26 @@
 	struct intel_output *output = to_intel_output(connector);
 	struct intel_sdvo_priv *sdvo_priv = output->dev_priv;
 	struct intel_sdvo_sdtv_resolution_request tv_res;
-	uint32_t reply = 0;
+	uint32_t reply = 0, format_map = 0;
+	int i;
 	uint8_t status;
-	int i = 0;
 
-	intel_sdvo_check_tv_format(output);
 
 	/* Read the list of supported input resolutions for the selected TV
 	 * format.
 	 */
-	memset(&tv_res, 0, sizeof(tv_res));
-	memcpy(&tv_res, &sdvo_priv->tv_format, sizeof(tv_res));
+	for (i = 0; i < TV_FORMAT_NUM; i++)
+		if (tv_format_names[i] ==  sdvo_priv->tv_format_name)
+			break;
+
+	format_map = (1 << i);
+	memcpy(&tv_res, &format_map,
+	       sizeof(struct intel_sdvo_sdtv_resolution_request) >
+	       sizeof(format_map) ? sizeof(format_map) :
+	       sizeof(struct intel_sdvo_sdtv_resolution_request));
+
+	intel_sdvo_set_target_output(output, sdvo_priv->controlled_output);
+
 	intel_sdvo_write_cmd(output, SDVO_CMD_GET_SDTV_RESOLUTION_SUPPORT,
 			     &tv_res, sizeof(tv_res));
 	status = intel_sdvo_read_response(output, &reply, 3);
@@ -1681,6 +1690,7 @@
 			if (nmode)
 				drm_mode_probed_add(connector, nmode);
 		}
+
 }
 
 static void intel_sdvo_get_lvds_modes(struct drm_connector *connector)
@@ -1753,12 +1763,55 @@
 		drm_mode_destroy(connector->dev,
 				 sdvo_priv->sdvo_lvds_fixed_mode);
 
+	if (sdvo_priv->tv_format_property)
+		drm_property_destroy(connector->dev,
+				     sdvo_priv->tv_format_property);
+
 	drm_sysfs_connector_remove(connector);
 	drm_connector_cleanup(connector);
 
 	kfree(intel_output);
 }
 
+static int
+intel_sdvo_set_property(struct drm_connector *connector,
+			struct drm_property *property,
+			uint64_t val)
+{
+	struct intel_output *intel_output = to_intel_output(connector);
+	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+	struct drm_encoder *encoder = &intel_output->enc;
+	struct drm_crtc *crtc = encoder->crtc;
+	int ret = 0;
+	bool changed = false;
+
+	ret = drm_connector_property_set_value(connector, property, val);
+	if (ret < 0)
+		goto out;
+
+	if (property == sdvo_priv->tv_format_property) {
+		if (val >= TV_FORMAT_NUM) {
+			ret = -EINVAL;
+			goto out;
+		}
+		if (sdvo_priv->tv_format_name ==
+		    sdvo_priv->tv_format_supported[val])
+			goto out;
+
+		sdvo_priv->tv_format_name = sdvo_priv->tv_format_supported[val];
+		changed = true;
+	} else {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (changed && crtc)
+		drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,
+				crtc->y, crtc->fb);
+out:
+	return ret;
+}
+
 static const struct drm_encoder_helper_funcs intel_sdvo_helper_funcs = {
 	.dpms = intel_sdvo_dpms,
 	.mode_fixup = intel_sdvo_mode_fixup,
@@ -1773,6 +1826,7 @@
 	.restore = intel_sdvo_restore,
 	.detect = intel_sdvo_detect,
 	.fill_modes = drm_helper_probe_single_connector_modes,
+	.set_property = intel_sdvo_set_property,
 	.destroy = intel_sdvo_destroy,
 };
 
@@ -2029,6 +2083,55 @@
 
 }
 
+static void intel_sdvo_tv_create_property(struct drm_connector *connector)
+{
+      struct intel_output *intel_output = to_intel_output(connector);
+	struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv;
+	struct intel_sdvo_tv_format format;
+	uint32_t format_map, i;
+	uint8_t status;
+
+	intel_sdvo_set_target_output(intel_output,
+				     sdvo_priv->controlled_output);
+
+	intel_sdvo_write_cmd(intel_output,
+			     SDVO_CMD_GET_SUPPORTED_TV_FORMATS, NULL, 0);
+	status = intel_sdvo_read_response(intel_output,
+					  &format, sizeof(format));
+	if (status != SDVO_CMD_STATUS_SUCCESS)
+		return;
+
+	memcpy(&format_map, &format, sizeof(format) > sizeof(format_map) ?
+	       sizeof(format_map) : sizeof(format));
+
+	if (format_map == 0)
+		return;
+
+	sdvo_priv->format_supported_num = 0;
+	for (i = 0 ; i < TV_FORMAT_NUM; i++)
+		if (format_map & (1 << i)) {
+			sdvo_priv->tv_format_supported
+			[sdvo_priv->format_supported_num++] =
+			tv_format_names[i];
+		}
+
+
+	sdvo_priv->tv_format_property =
+			drm_property_create(
+				connector->dev, DRM_MODE_PROP_ENUM,
+				"mode", sdvo_priv->format_supported_num);
+
+	for (i = 0; i < sdvo_priv->format_supported_num; i++)
+		drm_property_add_enum(
+				sdvo_priv->tv_format_property, i,
+				i, sdvo_priv->tv_format_supported[i]);
+
+	sdvo_priv->tv_format_name = sdvo_priv->tv_format_supported[0];
+	drm_connector_attach_property(
+			connector, sdvo_priv->tv_format_property, 0);
+
+}
+
 bool intel_sdvo_init(struct drm_device *dev, int output_device)
 {
 	struct drm_connector *connector;
@@ -2111,6 +2214,8 @@
 	drm_encoder_helper_add(&intel_output->enc, &intel_sdvo_helper_funcs);
 
 	drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc);
+	if (sdvo_priv->is_tv)
+		intel_sdvo_tv_create_property(connector);
 	drm_sysfs_connector_add(connector);
 
 	intel_sdvo_select_ddc_bus(sdvo_priv);
