Linux Audio

Check our new training course

Linux kernel drivers training

Mar 31-Apr 9, 2025, special US time zones
Register
Loading...
v6.8
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3   drm_edid_load.c: use a built-in EDID data set or load it via the firmware
  4		    interface
  5
  6   Copyright (C) 2012 Carsten Emde <C.Emde@osadl.org>
  7
 
 
 
 
 
 
 
 
 
 
 
 
 
  8*/
  9
 10#include <linux/firmware.h>
 11#include <linux/module.h>
 12#include <linux/platform_device.h>
 13
 14#include <drm/drm_connector.h>
 15#include <drm/drm_drv.h>
 16#include <drm/drm_edid.h>
 17#include <drm/drm_print.h>
 18
 19#include "drm_crtc_internal.h"
 20
 21static char edid_firmware[PATH_MAX];
 22module_param_string(edid_firmware, edid_firmware, sizeof(edid_firmware), 0644);
 23MODULE_PARM_DESC(edid_firmware, "Do not probe monitor, use specified EDID blob "
 24	"from built-in data or /lib/firmware instead. ");
 25
 26#define GENERIC_EDIDS 6
 27static const char * const generic_edid_name[GENERIC_EDIDS] = {
 28	"edid/800x600.bin",
 29	"edid/1024x768.bin",
 30	"edid/1280x1024.bin",
 31	"edid/1600x1200.bin",
 32	"edid/1680x1050.bin",
 33	"edid/1920x1080.bin",
 34};
 35
 36static const u8 generic_edid[GENERIC_EDIDS][128] = {
 37	{
 38	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
 39	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 40	0x05, 0x16, 0x01, 0x03, 0x6d, 0x1b, 0x14, 0x78,
 41	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
 42	0x20, 0x50, 0x54, 0x01, 0x00, 0x00, 0x45, 0x40,
 43	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 44	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0xa0, 0x0f,
 45	0x20, 0x00, 0x31, 0x58, 0x1c, 0x20, 0x28, 0x80,
 46	0x14, 0x00, 0x15, 0xd0, 0x10, 0x00, 0x00, 0x1e,
 47	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
 48	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
 49	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
 50	0x3d, 0x24, 0x26, 0x05, 0x00, 0x0a, 0x20, 0x20,
 51	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
 52	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x53,
 53	0x56, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0xc2,
 54	},
 55	{
 56	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
 57	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 58	0x05, 0x16, 0x01, 0x03, 0x6d, 0x23, 0x1a, 0x78,
 59	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
 60	0x20, 0x50, 0x54, 0x00, 0x08, 0x00, 0x61, 0x40,
 61	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 62	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x64, 0x19,
 63	0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x08, 0x90,
 64	0x36, 0x00, 0x63, 0x0a, 0x11, 0x00, 0x00, 0x18,
 65	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
 66	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
 67	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
 68	0x3d, 0x2f, 0x31, 0x07, 0x00, 0x0a, 0x20, 0x20,
 69	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
 70	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x58,
 71	0x47, 0x41, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x55,
 72	},
 73	{
 74	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
 75	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 76	0x05, 0x16, 0x01, 0x03, 0x6d, 0x2c, 0x23, 0x78,
 77	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
 78	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0x81, 0x80,
 79	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 80	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x30, 0x2a,
 81	0x00, 0x98, 0x51, 0x00, 0x2a, 0x40, 0x30, 0x70,
 82	0x13, 0x00, 0xbc, 0x63, 0x11, 0x00, 0x00, 0x1e,
 83	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
 84	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
 85	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
 86	0x3d, 0x3e, 0x40, 0x0b, 0x00, 0x0a, 0x20, 0x20,
 87	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
 88	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x53,
 89	0x58, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0xa0,
 90	},
 91	{
 92	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
 93	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 94	0x05, 0x16, 0x01, 0x03, 0x6d, 0x37, 0x29, 0x78,
 95	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
 96	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xa9, 0x40,
 97	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 98	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x48, 0x3f,
 99	0x40, 0x30, 0x62, 0xb0, 0x32, 0x40, 0x40, 0xc0,
100	0x13, 0x00, 0x2b, 0xa0, 0x21, 0x00, 0x00, 0x1e,
101	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
102	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
103	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
104	0x3d, 0x4a, 0x4c, 0x11, 0x00, 0x0a, 0x20, 0x20,
105	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
106	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x55,
107	0x58, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0x9d,
108	},
109	{
110	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
111	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
112	0x05, 0x16, 0x01, 0x03, 0x6d, 0x2b, 0x1b, 0x78,
113	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
114	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xb3, 0x00,
115	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
116	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x21, 0x39,
117	0x90, 0x30, 0x62, 0x1a, 0x27, 0x40, 0x68, 0xb0,
118	0x36, 0x00, 0xb5, 0x11, 0x11, 0x00, 0x00, 0x1e,
119	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
120	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
121	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
122	0x3d, 0x40, 0x42, 0x0f, 0x00, 0x0a, 0x20, 0x20,
123	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
124	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x57,
125	0x53, 0x58, 0x47, 0x41, 0x0a, 0x20, 0x00, 0x26,
126	},
127	{
128	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
129	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
130	0x05, 0x16, 0x01, 0x03, 0x6d, 0x32, 0x1c, 0x78,
131	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
132	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xd1, 0xc0,
133	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
134	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a,
135	0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
136	0x45, 0x00, 0xf4, 0x19, 0x11, 0x00, 0x00, 0x1e,
137	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
138	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
139	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
140	0x3d, 0x42, 0x44, 0x0f, 0x00, 0x0a, 0x20, 0x20,
141	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
142	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x46,
143	0x48, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x05,
144	},
145};
146
147static const struct drm_edid *edid_load(struct drm_connector *connector, const char *name)
 
148{
149	const struct firmware *fw = NULL;
150	const u8 *fwdata;
151	const struct drm_edid *drm_edid;
152	int fwsize, builtin;
153
154	builtin = match_string(generic_edid_name, GENERIC_EDIDS, name);
155	if (builtin >= 0) {
156		fwdata = generic_edid[builtin];
157		fwsize = sizeof(generic_edid[builtin]);
158	} else {
159		int err;
160
161		err = request_firmware(&fw, name, connector->dev->dev);
162		if (err) {
163			drm_err(connector->dev,
164				"[CONNECTOR:%d:%s] Requesting EDID firmware \"%s\" failed (err=%d)\n",
165				connector->base.id, connector->name,
166				name, err);
167			return ERR_PTR(err);
 
 
 
 
 
 
 
 
168		}
 
169
170		fwdata = fw->data;
171		fwsize = fw->size;
 
 
172	}
173
174	drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] Loaded %s firmware EDID \"%s\"\n",
175		    connector->base.id, connector->name,
176		    builtin >= 0 ? "built-in" : "external", name);
177
178	drm_edid = drm_edid_alloc(fwdata, fwsize);
179	if (!drm_edid_valid(drm_edid)) {
180		drm_err(connector->dev, "Invalid firmware EDID \"%s\"\n", name);
181		drm_edid_free(drm_edid);
182		drm_edid = ERR_PTR(-EINVAL);
183	}
184
185	release_firmware(fw);
 
 
 
 
 
 
186
187	return drm_edid;
188}
 
 
 
 
189
190const struct drm_edid *drm_edid_load_firmware(struct drm_connector *connector)
191{
192	char *edidname, *last, *colon, *fwstr, *edidstr, *fallback = NULL;
193	const struct drm_edid *drm_edid;
 
 
 
194
195	if (edid_firmware[0] == '\0')
196		return ERR_PTR(-ENOENT);
 
 
 
 
 
197
198	/*
199	 * If there are multiple edid files specified and separated
200	 * by commas, search through the list looking for one that
201	 * matches the connector.
202	 *
203	 * If there's one or more that doesn't specify a connector, keep
204	 * the last one found one as a fallback.
205	 */
206	fwstr = kstrdup(edid_firmware, GFP_KERNEL);
207	if (!fwstr)
208		return ERR_PTR(-ENOMEM);
209	edidstr = fwstr;
210
211	while ((edidname = strsep(&edidstr, ","))) {
212		colon = strchr(edidname, ':');
213		if (colon != NULL) {
214			if (strncmp(connector->name, edidname, colon - edidname))
215				continue;
216			edidname = colon + 1;
217			break;
218		}
219
220		if (*edidname != '\0') /* corner case: multiple ',' */
221			fallback = edidname;
222	}
223
224	if (!edidname) {
225		if (!fallback) {
226			kfree(fwstr);
227			return ERR_PTR(-ENOENT);
228		}
229		edidname = fallback;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230	}
231
232	last = edidname + strlen(edidname) - 1;
233	if (*last == '\n')
234		*last = '\0';
235
236	drm_edid = edid_load(connector, edidname);
 
 
237
238	kfree(fwstr);
 
239
240	return drm_edid;
 
241}
v3.5.6
 
  1/*
  2   drm_edid_load.c: use a built-in EDID data set or load it via the firmware
  3		    interface
  4
  5   Copyright (C) 2012 Carsten Emde <C.Emde@osadl.org>
  6
  7   This program is free software; you can redistribute it and/or
  8   modify it under the terms of the GNU General Public License
  9   as published by the Free Software Foundation; either version 2
 10   of the License, or (at your option) any later version.
 11
 12   This program is distributed in the hope that it will be useful,
 13   but WITHOUT ANY WARRANTY; without even the implied warranty of
 14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15   GNU General Public License for more details.
 16
 17   You should have received a copy of the GNU General Public License
 18   along with this program; if not, write to the Free Software
 19   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
 20*/
 21
 
 22#include <linux/module.h>
 23#include <linux/firmware.h>
 24#include "drmP.h"
 25#include "drm_crtc.h"
 26#include "drm_crtc_helper.h"
 27#include "drm_edid.h"
 
 
 
 28
 29static char edid_firmware[PATH_MAX];
 30module_param_string(edid_firmware, edid_firmware, sizeof(edid_firmware), 0644);
 31MODULE_PARM_DESC(edid_firmware, "Do not probe monitor, use specified EDID blob "
 32	"from built-in data or /lib/firmware instead. ");
 33
 34#define GENERIC_EDIDS 4
 35static char *generic_edid_name[GENERIC_EDIDS] = {
 
 36	"edid/1024x768.bin",
 37	"edid/1280x1024.bin",
 
 38	"edid/1680x1050.bin",
 39	"edid/1920x1080.bin",
 40};
 41
 42static u8 generic_edid[GENERIC_EDIDS][128] = {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 43	{
 44	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
 45	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 46	0x05, 0x16, 0x01, 0x03, 0x6d, 0x23, 0x1a, 0x78,
 47	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
 48	0x20, 0x50, 0x54, 0x00, 0x08, 0x00, 0x61, 0x40,
 49	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 50	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x64, 0x19,
 51	0x00, 0x40, 0x41, 0x00, 0x26, 0x30, 0x08, 0x90,
 52	0x36, 0x00, 0x63, 0x0a, 0x11, 0x00, 0x00, 0x18,
 53	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
 54	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
 55	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
 56	0x3d, 0x2f, 0x31, 0x07, 0x00, 0x0a, 0x20, 0x20,
 57	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
 58	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x58,
 59	0x47, 0x41, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x55,
 60	},
 61	{
 62	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
 63	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 64	0x05, 0x16, 0x01, 0x03, 0x6d, 0x2c, 0x23, 0x78,
 65	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
 66	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0x81, 0x80,
 67	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 68	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x30, 0x2a,
 69	0x00, 0x98, 0x51, 0x00, 0x2a, 0x40, 0x30, 0x70,
 70	0x13, 0x00, 0xbc, 0x63, 0x11, 0x00, 0x00, 0x1e,
 71	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
 72	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
 73	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
 74	0x3d, 0x3e, 0x40, 0x0b, 0x00, 0x0a, 0x20, 0x20,
 75	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
 76	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x53,
 77	0x58, 0x47, 0x41, 0x0a, 0x20, 0x20, 0x00, 0xa0,
 78	},
 79	{
 80	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
 81	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 82	0x05, 0x16, 0x01, 0x03, 0x6d, 0x2b, 0x1b, 0x78,
 83	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
 84	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xb3, 0x00,
 85	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
 86	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x21, 0x39,
 87	0x90, 0x30, 0x62, 0x1a, 0x27, 0x40, 0x68, 0xb0,
 88	0x36, 0x00, 0xb5, 0x11, 0x11, 0x00, 0x00, 0x1e,
 89	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
 90	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
 91	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
 92	0x3d, 0x40, 0x42, 0x0f, 0x00, 0x0a, 0x20, 0x20,
 93	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
 94	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x57,
 95	0x53, 0x58, 0x47, 0x41, 0x0a, 0x20, 0x00, 0x26,
 96	},
 97	{
 98	0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
 99	0x31, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
100	0x05, 0x16, 0x01, 0x03, 0x6d, 0x32, 0x1c, 0x78,
101	0xea, 0x5e, 0xc0, 0xa4, 0x59, 0x4a, 0x98, 0x25,
102	0x20, 0x50, 0x54, 0x00, 0x00, 0x00, 0xd1, 0xc0,
103	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
104	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x3a,
105	0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
106	0x45, 0x00, 0xf4, 0x19, 0x11, 0x00, 0x00, 0x1e,
107	0x00, 0x00, 0x00, 0xff, 0x00, 0x4c, 0x69, 0x6e,
108	0x75, 0x78, 0x20, 0x23, 0x30, 0x0a, 0x20, 0x20,
109	0x20, 0x20, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x3b,
110	0x3d, 0x42, 0x44, 0x0f, 0x00, 0x0a, 0x20, 0x20,
111	0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc,
112	0x00, 0x4c, 0x69, 0x6e, 0x75, 0x78, 0x20, 0x46,
113	0x48, 0x44, 0x0a, 0x20, 0x20, 0x20, 0x00, 0x05,
114	},
115};
116
117static int edid_load(struct drm_connector *connector, char *name,
118		     char *connector_name)
119{
120	const struct firmware *fw;
121	struct platform_device *pdev;
122	u8 *fwdata = NULL, *edid;
123	int fwsize, expected;
124	int builtin = 0, err = 0;
125	int i, valid_extensions = 0;
126
127	pdev = platform_device_register_simple(connector_name, -1, NULL, 0);
128	if (IS_ERR(pdev)) {
129		DRM_ERROR("Failed to register EDID firmware platform device "
130		    "for connector \"%s\"\n", connector_name);
131		err = -EINVAL;
132		goto out;
133	}
134
135	err = request_firmware(&fw, name, &pdev->dev);
136	platform_device_unregister(pdev);
137
138	if (err) {
139		i = 0;
140		while (i < GENERIC_EDIDS && strcmp(name, generic_edid_name[i]))
141			i++;
142		if (i < GENERIC_EDIDS) {
143			err = 0;
144			builtin = 1;
145			fwdata = generic_edid[i];
146			fwsize = sizeof(generic_edid[i]);
147		}
148	}
149
150	if (err) {
151		DRM_ERROR("Requesting EDID firmware \"%s\" failed (err=%d)\n",
152		    name, err);
153		goto out;
154	}
155
156	if (fwdata == NULL) {
157		fwdata = (u8 *) fw->data;
158		fwsize = fw->size;
 
 
 
 
 
 
159	}
160
161	expected = (fwdata[0x7e] + 1) * EDID_LENGTH;
162	if (expected != fwsize) {
163		DRM_ERROR("Size of EDID firmware \"%s\" is invalid "
164		    "(expected %d, got %d)\n", name, expected, (int) fwsize);
165		err = -EINVAL;
166		goto relfw_out;
167	}
168
169	edid = kmalloc(fwsize, GFP_KERNEL);
170	if (edid == NULL) {
171		err = -ENOMEM;
172		goto relfw_out;
173	}
174	memcpy(edid, fwdata, fwsize);
175
176	if (!drm_edid_block_valid(edid, 0)) {
177		DRM_ERROR("Base block of EDID firmware \"%s\" is invalid ",
178		    name);
179		kfree(edid);
180		err = -EINVAL;
181		goto relfw_out;
182	}
183
184	for (i = 1; i <= edid[0x7e]; i++) {
185		if (i != valid_extensions + 1)
186			memcpy(edid + (valid_extensions + 1) * EDID_LENGTH,
187			    edid + i * EDID_LENGTH, EDID_LENGTH);
188		if (drm_edid_block_valid(edid + i * EDID_LENGTH, i))
189			valid_extensions++;
190	}
191
192	if (valid_extensions != edid[0x7e]) {
193		edid[EDID_LENGTH-1] += edid[0x7e] - valid_extensions;
194		DRM_INFO("Found %d valid extensions instead of %d in EDID data "
195		    "\"%s\" for connector \"%s\"\n", valid_extensions,
196		    edid[0x7e], name, connector_name);
197		edid[0x7e] = valid_extensions;
198		edid = krealloc(edid, (valid_extensions + 1) * EDID_LENGTH,
199		    GFP_KERNEL);
200		if (edid == NULL) {
201			err = -ENOMEM;
202			goto relfw_out;
 
 
 
 
 
 
 
 
 
203		}
 
 
 
204	}
205
206	connector->display_info.raw_edid = edid;
207	DRM_INFO("Got %s EDID base block and %d extension%s from "
208	    "\"%s\" for connector \"%s\"\n", builtin ? "built-in" :
209	    "external", valid_extensions, valid_extensions == 1 ? "" : "s",
210	    name, connector_name);
211
212relfw_out:
213	release_firmware(fw);
214
215out:
216	return err;
217}
218
219int drm_load_edid_firmware(struct drm_connector *connector)
220{
221	char *connector_name = drm_get_connector_name(connector);
222	char *edidname = edid_firmware, *last, *colon;
223	int ret;
224
225	if (*edidname == '\0')
226		return 0;
227
228	colon = strchr(edidname, ':');
229	if (colon != NULL) {
230		if (strncmp(connector_name, edidname, colon - edidname))
231			return 0;
232		edidname = colon + 1;
233		if (*edidname == '\0')
234			return 0;
235	}
236
237	last = edidname + strlen(edidname) - 1;
238	if (*last == '\n')
239		*last = '\0';
240
241	ret = edid_load(connector, edidname, connector_name);
242	if (ret)
243		return 0;
244
245	drm_mode_connector_update_edid_property(connector,
246	    (struct edid *) connector->display_info.raw_edid);
247
248	return drm_add_edid_modes(connector, (struct edid *)
249	    connector->display_info.raw_edid);
250}