OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chromeos/display/output_util.h" | 5 #include "chromeos/display/output_util.h" |
6 | 6 |
7 #include <X11/Xlib.h> | 7 #include <X11/Xlib.h> |
8 #include <X11/extensions/Xrandr.h> | 8 #include <X11/extensions/Xrandr.h> |
9 #include <X11/Xatom.h> | 9 #include <X11/Xatom.h> |
10 | 10 |
| 11 #include "base/hash.h" |
11 #include "base/message_loop.h" | 12 #include "base/message_loop.h" |
12 #include "base/string_util.h" | 13 #include "base/string_util.h" |
13 #include "base/sys_byteorder.h" | 14 #include "base/sys_byteorder.h" |
14 | 15 |
15 namespace chromeos { | 16 namespace chromeos { |
16 namespace { | 17 namespace { |
17 | 18 |
18 // Prefixes for the built-in displays. | 19 // Prefixes for the built-in displays. |
19 const char kInternal_LVDS[] = "LVDS"; | 20 const char kInternal_LVDS[] = "LVDS"; |
20 const char kInternal_eDP[] = "eDP"; | 21 const char kInternal_eDP[] = "eDP"; |
21 | 22 |
22 // Returns 64-bit persistent ID for the specified manufacturer's ID and | 23 // Returns 64-bit persistent ID for the specified manufacturer's ID and |
23 // product_code, and the index of the output it is connected to. | 24 // product_code_hash, and the index of the output it is connected to. |
24 // |output_index| is used to distinguish the displays of the same type. For | 25 // |output_index| is used to distinguish the displays of the same type. For |
25 // example, swapping two identical display between two outputs will not be | 26 // example, swapping two identical display between two outputs will not be |
26 // treated as swap. The 'serial number' field in EDID isn't used here because | 27 // treated as swap. The 'serial number' field in EDID isn't used here because |
27 // it is not guaranteed to have unique number and it may have the same fixed | 28 // it is not guaranteed to have unique number and it may have the same fixed |
28 // value (like 0). | 29 // value (like 0). |
29 int64 GetID(uint16 manufacturer_id, | 30 int64 GetID(uint16 manufacturer_id, |
30 uint16 product_code, | 31 uint32 product_code_hash, |
31 uint8 output_index) { | 32 uint8 output_index) { |
32 return ((static_cast<int64>(manufacturer_id) << 24) | | 33 return ((static_cast<int64>(manufacturer_id) << 40) | |
33 (static_cast<int64>(product_code) << 8) | output_index); | 34 (static_cast<int64>(product_code_hash) << 8) | output_index); |
34 } | 35 } |
35 | 36 |
36 bool IsRandRAvailable() { | 37 bool IsRandRAvailable() { |
37 int randr_version_major = 0; | 38 int randr_version_major = 0; |
38 int randr_version_minor = 0; | 39 int randr_version_minor = 0; |
39 static bool is_randr_available = XRRQueryVersion( | 40 static bool is_randr_available = XRRQueryVersion( |
40 base::MessagePumpAuraX11::GetDefaultXDisplay(), | 41 base::MessagePumpAuraX11::GetDefaultXDisplay(), |
41 &randr_version_major, &randr_version_minor); | 42 &randr_version_major, &randr_version_minor); |
42 return is_randr_available; | 43 return is_randr_available; |
43 } | 44 } |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
90 DCHECK_EQ(8, actual_format); | 91 DCHECK_EQ(8, actual_format); |
91 return true; | 92 return true; |
92 } | 93 } |
93 | 94 |
94 // Gets some useful data from the specified output device, such like | 95 // Gets some useful data from the specified output device, such like |
95 // manufacturer's ID, product code, and human readable name. Returns false if it | 96 // manufacturer's ID, product code, and human readable name. Returns false if it |
96 // fails to get those data and doesn't touch manufacturer ID/product code/name. | 97 // fails to get those data and doesn't touch manufacturer ID/product code/name. |
97 // NULL can be passed for unwanted output parameters. | 98 // NULL can be passed for unwanted output parameters. |
98 bool GetOutputDeviceData(XID output, | 99 bool GetOutputDeviceData(XID output, |
99 uint16* manufacturer_id, | 100 uint16* manufacturer_id, |
100 uint16* product_code, | |
101 std::string* human_readable_name) { | 101 std::string* human_readable_name) { |
102 unsigned long nitems = 0; | 102 unsigned long nitems = 0; |
103 unsigned char *prop = NULL; | 103 unsigned char *prop = NULL; |
104 if (!GetEDIDProperty(output, &nitems, &prop)) | 104 if (!GetEDIDProperty(output, &nitems, &prop)) |
105 return false; | 105 return false; |
106 | 106 |
107 bool result = ParseOutputDeviceData( | 107 bool result = ParseOutputDeviceData( |
108 prop, nitems, manufacturer_id, product_code, human_readable_name); | 108 prop, nitems, manufacturer_id, human_readable_name); |
109 XFree(prop); | 109 XFree(prop); |
110 return result; | 110 return result; |
111 } | 111 } |
112 | 112 |
113 } // namespace | 113 } // namespace |
114 | 114 |
115 std::string GetDisplayName(XID output_id) { | 115 std::string GetDisplayName(XID output_id) { |
116 std::string display_name; | 116 std::string display_name; |
117 GetOutputDeviceData(output_id, NULL, NULL, &display_name); | 117 GetOutputDeviceData(output_id, NULL, &display_name); |
118 return display_name; | 118 return display_name; |
119 } | 119 } |
120 | 120 |
121 bool GetDisplayId(XID output_id, size_t output_index, int64* display_id_out) { | 121 bool GetDisplayId(XID output_id, size_t output_index, int64* display_id_out) { |
| 122 unsigned long nitems = 0; |
| 123 unsigned char* prop = NULL; |
| 124 if (!GetEDIDProperty(output_id, &nitems, &prop)) |
| 125 return false; |
| 126 |
| 127 bool result = |
| 128 GetDisplayIdFromEDID(prop, nitems, output_index, display_id_out); |
| 129 XFree(prop); |
| 130 return result; |
| 131 } |
| 132 |
| 133 bool GetDisplayIdFromEDID(const unsigned char* prop, |
| 134 unsigned long nitems, |
| 135 size_t output_index, |
| 136 int64* display_id_out) { |
122 uint16 manufacturer_id = 0; | 137 uint16 manufacturer_id = 0; |
123 uint16 product_code = 0; | 138 std::string product_name; |
124 if (GetOutputDeviceData( | 139 |
125 output_id, &manufacturer_id, &product_code, NULL) && | 140 // ParseOutputDeviceData fails if it doesn't have product_name. |
126 manufacturer_id != 0) { | 141 ParseOutputDeviceData(prop, nitems, &manufacturer_id, &product_name); |
| 142 |
| 143 // Generates product specific value from product_name instead of product code. |
| 144 // See crbug.com/240341 |
| 145 uint32 product_code_hash = product_name.empty() ? |
| 146 0 : base::Hash(product_name); |
| 147 if (manufacturer_id != 0) { |
127 // An ID based on display's index will be assigned later if this call | 148 // An ID based on display's index will be assigned later if this call |
128 // fails. | 149 // fails. |
129 *display_id_out = GetID(manufacturer_id, product_code, output_index); | 150 *display_id_out = GetID( |
| 151 manufacturer_id, product_code_hash, output_index); |
130 return true; | 152 return true; |
131 } | 153 } |
132 return false; | 154 return false; |
133 } | 155 } |
134 | 156 |
135 bool ParseOutputDeviceData(const unsigned char* prop, | 157 bool ParseOutputDeviceData(const unsigned char* prop, |
136 unsigned long nitems, | 158 unsigned long nitems, |
137 uint16* manufacturer_id, | 159 uint16* manufacturer_id, |
138 uint16* product_code, | |
139 std::string* human_readable_name) { | 160 std::string* human_readable_name) { |
140 // See http://en.wikipedia.org/wiki/Extended_display_identification_data | 161 // See http://en.wikipedia.org/wiki/Extended_display_identification_data |
141 // for the details of EDID data format. We use the following data: | 162 // for the details of EDID data format. We use the following data: |
142 // bytes 8-9: manufacturer EISA ID, in big-endian | 163 // bytes 8-9: manufacturer EISA ID, in big-endian |
143 // bytes 10-11: represents product code, in little-endian | |
144 // bytes 54-125: four descriptors (18-bytes each) which may contain | 164 // bytes 54-125: four descriptors (18-bytes each) which may contain |
145 // the display name. | 165 // the display name. |
146 const unsigned int kManufacturerOffset = 8; | 166 const unsigned int kManufacturerOffset = 8; |
147 const unsigned int kManufacturerLength = 2; | 167 const unsigned int kManufacturerLength = 2; |
148 const unsigned int kProductCodeOffset = 10; | |
149 const unsigned int kProductCodeLength = 2; | |
150 const unsigned int kDescriptorOffset = 54; | 168 const unsigned int kDescriptorOffset = 54; |
151 const unsigned int kNumDescriptors = 4; | 169 const unsigned int kNumDescriptors = 4; |
152 const unsigned int kDescriptorLength = 18; | 170 const unsigned int kDescriptorLength = 18; |
153 // The specifier types. | 171 // The specifier types. |
154 const unsigned char kMonitorNameDescriptor = 0xfc; | 172 const unsigned char kMonitorNameDescriptor = 0xfc; |
155 | 173 |
156 if (manufacturer_id) { | 174 if (manufacturer_id) { |
157 if (nitems < kManufacturerOffset + kManufacturerLength) { | 175 if (nitems < kManufacturerOffset + kManufacturerLength) { |
158 LOG(ERROR) << "too short EDID data: manifacturer id"; | 176 LOG(ERROR) << "too short EDID data: manifacturer id"; |
159 return false; | 177 return false; |
160 } | 178 } |
161 | 179 |
162 *manufacturer_id = | 180 *manufacturer_id = |
163 *reinterpret_cast<const uint16*>(prop + kManufacturerOffset); | 181 *reinterpret_cast<const uint16*>(prop + kManufacturerOffset); |
164 #if defined(ARCH_CPU_LITTLE_ENDIAN) | 182 #if defined(ARCH_CPU_LITTLE_ENDIAN) |
165 *manufacturer_id = base::ByteSwap(*manufacturer_id); | 183 *manufacturer_id = base::ByteSwap(*manufacturer_id); |
166 #endif | 184 #endif |
167 } | 185 } |
168 | 186 |
169 if (product_code) { | |
170 if (nitems < kProductCodeOffset + kProductCodeLength) { | |
171 LOG(ERROR) << "too short EDID data: product code"; | |
172 return false; | |
173 } | |
174 | |
175 *product_code = base::ByteSwapToLE16( | |
176 *reinterpret_cast<const uint16*>(prop + kProductCodeOffset)); | |
177 } | |
178 | |
179 if (!human_readable_name) | 187 if (!human_readable_name) |
180 return true; | 188 return true; |
181 | 189 |
182 human_readable_name->clear(); | 190 human_readable_name->clear(); |
183 for (unsigned int i = 0; i < kNumDescriptors; ++i) { | 191 for (unsigned int i = 0; i < kNumDescriptors; ++i) { |
184 if (nitems < kDescriptorOffset + (i + 1) * kDescriptorLength) | 192 if (nitems < kDescriptorOffset + (i + 1) * kDescriptorLength) |
185 break; | 193 break; |
186 | 194 |
187 const unsigned char* desc_buf = | 195 const unsigned char* desc_buf = |
188 prop + kDescriptorOffset + i * kDescriptorLength; | 196 prop + kDescriptorOffset + i * kDescriptorLength; |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
310 } | 318 } |
311 | 319 |
312 return false; | 320 return false; |
313 } | 321 } |
314 | 322 |
315 bool IsInternalOutputName(const std::string& name) { | 323 bool IsInternalOutputName(const std::string& name) { |
316 return name.find(kInternal_LVDS) == 0 || name.find(kInternal_eDP) == 0; | 324 return name.find(kInternal_LVDS) == 0 || name.find(kInternal_eDP) == 0; |
317 } | 325 } |
318 | 326 |
319 } // namespace chromeos | 327 } // namespace chromeos |
OLD | NEW |