brintos

brintos / linux-shallow public Read only

0
0
Text · 2.6 KiB · d1c7e82 Raw
108 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3   drm_edid_load.c: use a built-in EDID data set or load it via the firmware4		    interface5 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,24		 "Do not probe monitor, use specified EDID blob from /lib/firmware instead.");25 26static const struct drm_edid *edid_load(struct drm_connector *connector, const char *name)27{28	const struct firmware *fw = NULL;29	const struct drm_edid *drm_edid;30	int err;31 32	err = request_firmware(&fw, name, connector->dev->dev);33	if (err) {34		drm_err(connector->dev,35			"[CONNECTOR:%d:%s] Requesting EDID firmware \"%s\" failed (err=%d)\n",36			connector->base.id, connector->name,37			name, err);38		return ERR_PTR(err);39	}40 41	drm_dbg_kms(connector->dev, "[CONNECTOR:%d:%s] Loaded external firmware EDID \"%s\"\n",42		    connector->base.id, connector->name, name);43 44	drm_edid = drm_edid_alloc(fw->data, fw->size);45	if (!drm_edid_valid(drm_edid)) {46		drm_err(connector->dev, "Invalid firmware EDID \"%s\"\n", name);47		drm_edid_free(drm_edid);48		drm_edid = ERR_PTR(-EINVAL);49	}50 51	release_firmware(fw);52 53	return drm_edid;54}55 56const struct drm_edid *drm_edid_load_firmware(struct drm_connector *connector)57{58	char *edidname, *last, *colon, *fwstr, *edidstr, *fallback = NULL;59	const struct drm_edid *drm_edid;60 61	if (edid_firmware[0] == '\0')62		return ERR_PTR(-ENOENT);63 64	/*65	 * If there are multiple edid files specified and separated66	 * by commas, search through the list looking for one that67	 * matches the connector.68	 *69	 * If there's one or more that doesn't specify a connector, keep70	 * the last one found one as a fallback.71	 */72	fwstr = kstrdup(edid_firmware, GFP_KERNEL);73	if (!fwstr)74		return ERR_PTR(-ENOMEM);75	edidstr = fwstr;76 77	while ((edidname = strsep(&edidstr, ","))) {78		colon = strchr(edidname, ':');79		if (colon != NULL) {80			if (strncmp(connector->name, edidname, colon - edidname))81				continue;82			edidname = colon + 1;83			break;84		}85 86		if (*edidname != '\0') /* corner case: multiple ',' */87			fallback = edidname;88	}89 90	if (!edidname) {91		if (!fallback) {92			kfree(fwstr);93			return ERR_PTR(-ENOENT);94		}95		edidname = fallback;96	}97 98	last = edidname + strlen(edidname) - 1;99	if (*last == '\n')100		*last = '\0';101 102	drm_edid = edid_load(connector, edidname);103 104	kfree(fwstr);105 106	return drm_edid;107}108