Index: linux-2.6/drivers/gpu/drm/i915/i915_drv.h
===================================================================
--- linux-2.6.orig/drivers/gpu/drm/i915/i915_drv.h	2009-07-20 15:00:01.000000000 +0800
+++ linux-2.6/drivers/gpu/drm/i915/i915_drv.h	2009-07-20 17:24:22.000000000 +0800
@@ -437,6 +437,8 @@
 		struct drm_i915_gem_phys_object *phys_objs[I915_MAX_PHYS_OBJECT];
 	} mm;
 	struct sdvo_device_mapping sdvo_mappings[2];
+	int child_dev_num;
+	struct child_device_config *child_dev;
 } drm_i915_private_t;
 
 /** driver private structure attached to each drm_gem_object */
Index: linux-2.6/drivers/gpu/drm/i915/intel_bios.c
===================================================================
--- linux-2.6.orig/drivers/gpu/drm/i915/intel_bios.c	2009-07-13 08:49:30.000000000 +0800
+++ linux-2.6/drivers/gpu/drm/i915/intel_bios.c	2009-07-20 16:52:51.000000000 +0800
@@ -295,6 +295,70 @@
 	}
 	return;
 }
+static void
+parse_device_mapping_from_vbt(struct drm_i915_private *dev_priv,
+		       struct bdb_header *bdb)
+{
+	struct bdb_general_definitions *p_defs;
+	struct child_device_config *p_child, *child_dev_ptr;
+	int i, child_device_num, count;
+	u16	block_size, *block_ptr;
+
+	p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS);
+	if (!p_defs) {
+		DRM_DEBUG("No general definition block is found\n");
+		return;
+	}
+	/* judge whether the size of child device meets the requirements.
+	 * If the child device size obtained from general definition block
+	 * is different with sizeof(struct child_device_config), skip the
+	 * parsing of sdvo device info
+	 */
+	if (p_defs->child_dev_size != sizeof(*p_child)) {
+		/* different child dev size . Ignore it */
+		DRM_DEBUG("different child size is found. Invalid.\n");
+		return;
+	}
+	/* get the block size of general definitions */
+	block_ptr = (u16 *)((char *)p_defs - 2);
+	block_size = *block_ptr;
+	/* get the number of child device */
+	child_device_num = (block_size - sizeof(*p_defs)) /
+				sizeof(*p_child);
+	count = 0;
+	/* get the number of child device that is present */
+	for (i = 0; i < child_device_num; i++) {
+		p_child = &(p_defs->devices[i]);
+		if (!p_child->device_type) {
+			/* skip the device block if device type is invalid */
+			continue;
+		}
+		count++;
+	}
+	if (!count) {
+		DRM_DEBUG("no child dev is parsed from VBT \n");
+		return;
+	}
+	dev_priv->child_dev = kzalloc(sizeof(*p_child) * count, GFP_KERNEL);
+	if (!dev_priv->child_dev) {
+		DRM_DEBUG("Can't allocate memory space for child device\n");
+	}
+	dev_priv->child_dev_num = count;
+	count = 0;
+	for (i = 0; i < child_device_num; i++) {
+		p_child = &(p_defs->devices[i]);
+		if (!p_child->device_type) {
+			/* skip the device block if device type is invalid */
+			continue;
+		}
+		child_dev_ptr = dev_priv->child_dev + count;
+		printk(KERN_DEBUG "initial %p, result %p, size %d\n",
+				dev_priv->child_dev, child_dev_ptr, sizeof(*p_child) * count);
+		count++;
+		memcpy((void *)child_dev_ptr, (void *)p_child, sizeof(*p_child));
+	}
+	return;
+}
 /**
  * intel_init_bios - initialize VBIOS settings & find VBT
  * @dev: DRM device
@@ -345,6 +409,7 @@
 	parse_lfp_panel_data(dev_priv, bdb);
 	parse_sdvo_panel_data(dev_priv, bdb);
 	parse_sdvo_device_mapping(dev_priv, bdb);
+	parse_device_mapping_from_vbt(dev_priv, bdb);
 	pci_unmap_rom(pdev, bios);
 
 	return 0;
Index: linux-2.6/drivers/gpu/drm/i915/i915_dma.c
===================================================================
--- linux-2.6.orig/drivers/gpu/drm/i915/i915_dma.c	2009-07-20 15:26:30.000000000 +0800
+++ linux-2.6/drivers/gpu/drm/i915/i915_dma.c	2009-07-20 15:29:54.000000000 +0800
@@ -1242,6 +1242,8 @@
 	}
 	
 	if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+		dev_priv->child_dev = NULL;
+		dev_priv->child_dev_num = 0;
 		ret = i915_load_modeset_init(dev, prealloc_size, agp_size);
 		if (ret < 0) {
 			DRM_ERROR("failed to init modeset\n");
@@ -1299,6 +1301,15 @@
 		mutex_unlock(&dev->struct_mutex);
 		drm_mm_takedown(&dev_priv->vram);
 		i915_gem_lastclose(dev);
+		/*
+		 * free the memory space allocated for the child device
+		 * config parsed from VBT
+		 */
+		if (dev_priv->child_dev_num && dev_priv->child_dev) {
+			kfree(dev_priv->child_dev);
+			dev_priv->child_dev = NULL;
+			dev_priv->child_dev_num = 0;
+		}
 	}
 
 	kfree(dev->dev_private);
