aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/video.c
diff options
context:
space:
mode:
authorMatthew Garrett <mjg@redhat.com>2010-01-12 14:17:03 -0500
committerLen Brown <len.brown@intel.com>2010-04-19 15:56:32 -0400
commite92a716240258989f19c7345e8b135e6d214431a (patch)
treec36d681616cd41dd76220760c93ddfa651c7a28f /drivers/acpi/video.c
parent76e506a754c9519ba0a948b475a62f31fac8b599 (diff)
ACPI: Export EDID blocks to the kernel
The ACPI spec includes a provision for hardware to provide EDID via the ACPI video extension. In the KMS world it's necessary for a way to obtain this from within the kernel. Add a function that either returns the EDID for the provided ACPI display ID or the first display of the provided type. Also add support for ensuring that devices with legacy IDs are supported. Signed-off-by: Matthew Garrett <mjg@redhat.com> Acked-by: Zhang Rui <rui.zhang@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/video.c')
-rw-r--r--drivers/acpi/video.c110
1 files changed, 102 insertions, 8 deletions
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index a0c93b321482..4b8bda1154db 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -45,6 +45,7 @@
45#include <acpi/acpi_bus.h> 45#include <acpi/acpi_bus.h>
46#include <acpi/acpi_drivers.h> 46#include <acpi/acpi_drivers.h>
47#include <linux/suspend.h> 47#include <linux/suspend.h>
48#include <acpi/video.h>
48 49
49#define PREFIX "ACPI: " 50#define PREFIX "ACPI: "
50 51
@@ -65,11 +66,6 @@
65 66
66#define MAX_NAME_LEN 20 67#define MAX_NAME_LEN 20
67 68
68#define ACPI_VIDEO_DISPLAY_CRT 1
69#define ACPI_VIDEO_DISPLAY_TV 2
70#define ACPI_VIDEO_DISPLAY_DVI 3
71#define ACPI_VIDEO_DISPLAY_LCD 4
72
73#define _COMPONENT ACPI_VIDEO_COMPONENT 69#define _COMPONENT ACPI_VIDEO_COMPONENT
74ACPI_MODULE_NAME("video"); 70ACPI_MODULE_NAME("video");
75 71
@@ -1748,11 +1744,27 @@ acpi_video_get_device_attr(struct acpi_video_bus *video, unsigned long device_id
1748} 1744}
1749 1745
1750static int 1746static int
1747acpi_video_get_device_type(struct acpi_video_bus *video,
1748 unsigned long device_id)
1749{
1750 struct acpi_video_enumerated_device *ids;
1751 int i;
1752
1753 for (i = 0; i < video->attached_count; i++) {
1754 ids = &video->attached_array[i];
1755 if ((ids->value.int_val & 0xffff) == device_id)
1756 return ids->value.int_val;
1757 }
1758
1759 return 0;
1760}
1761
1762static int
1751acpi_video_bus_get_one_device(struct acpi_device *device, 1763acpi_video_bus_get_one_device(struct acpi_device *device,
1752 struct acpi_video_bus *video) 1764 struct acpi_video_bus *video)
1753{ 1765{
1754 unsigned long long device_id; 1766 unsigned long long device_id;
1755 int status; 1767 int status, device_type;
1756 struct acpi_video_device *data; 1768 struct acpi_video_device *data;
1757 struct acpi_video_device_attrib* attribute; 1769 struct acpi_video_device_attrib* attribute;
1758 1770
@@ -1797,8 +1809,25 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
1797 } 1809 }
1798 if(attribute->bios_can_detect) 1810 if(attribute->bios_can_detect)
1799 data->flags.bios = 1; 1811 data->flags.bios = 1;
1800 } else 1812 } else {
1801 data->flags.unknown = 1; 1813 /* Check for legacy IDs */
1814 device_type = acpi_video_get_device_type(video,
1815 device_id);
1816 /* Ignore bits 16 and 18-20 */
1817 switch (device_type & 0xffe2ffff) {
1818 case ACPI_VIDEO_DISPLAY_LEGACY_MONITOR:
1819 data->flags.crt = 1;
1820 break;
1821 case ACPI_VIDEO_DISPLAY_LEGACY_PANEL:
1822 data->flags.lcd = 1;
1823 break;
1824 case ACPI_VIDEO_DISPLAY_LEGACY_TV:
1825 data->flags.tvout = 1;
1826 break;
1827 default:
1828 data->flags.unknown = 1;
1829 }
1830 }
1802 1831
1803 acpi_video_device_bind(video, data); 1832 acpi_video_device_bind(video, data);
1804 acpi_video_device_find_cap(data); 1833 acpi_video_device_find_cap(data);
@@ -2032,6 +2061,71 @@ out:
2032 return result; 2061 return result;
2033} 2062}
2034 2063
2064int acpi_video_get_edid(struct acpi_device *device, int type, int device_id,
2065 void **edid)
2066{
2067 struct acpi_video_bus *video;
2068 struct acpi_video_device *video_device;
2069 union acpi_object *buffer = NULL;
2070 acpi_status status;
2071 int i, length;
2072
2073 if (!device || !acpi_driver_data(device))
2074 return -EINVAL;
2075
2076 video = acpi_driver_data(device);
2077
2078 for (i = 0; i < video->attached_count; i++) {
2079 video_device = video->attached_array[i].bind_info;
2080 length = 256;
2081
2082 if (!video_device)
2083 continue;
2084
2085 if (type) {
2086 switch (type) {
2087 case ACPI_VIDEO_DISPLAY_CRT:
2088 if (!video_device->flags.crt)
2089 continue;
2090 break;
2091 case ACPI_VIDEO_DISPLAY_TV:
2092 if (!video_device->flags.tvout)
2093 continue;
2094 break;
2095 case ACPI_VIDEO_DISPLAY_DVI:
2096 if (!video_device->flags.dvi)
2097 continue;
2098 break;
2099 case ACPI_VIDEO_DISPLAY_LCD:
2100 if (!video_device->flags.lcd)
2101 continue;
2102 break;
2103 }
2104 } else if (video_device->device_id != device_id) {
2105 continue;
2106 }
2107
2108 status = acpi_video_device_EDID(video_device, &buffer, length);
2109
2110 if (ACPI_FAILURE(status) || !buffer ||
2111 buffer->type != ACPI_TYPE_BUFFER) {
2112 length = 128;
2113 status = acpi_video_device_EDID(video_device, &buffer,
2114 length);
2115 if (ACPI_FAILURE(status) || !buffer ||
2116 buffer->type != ACPI_TYPE_BUFFER) {
2117 continue;
2118 }
2119 }
2120
2121 *edid = buffer->buffer.pointer;
2122 return length;
2123 }
2124
2125 return -ENODEV;
2126}
2127EXPORT_SYMBOL(acpi_video_get_edid);
2128
2035static int 2129static int
2036acpi_video_bus_get_devices(struct acpi_video_bus *video, 2130acpi_video_bus_get_devices(struct acpi_video_bus *video,
2037 struct acpi_device *device) 2131 struct acpi_device *device)