summary refs log tree commit diff
path: root/drivers/of/device.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/of/device.c')
-rw-r--r--drivers/of/device.c48
1 files changed, 48 insertions, 0 deletions
diff --git a/drivers/of/device.c b/drivers/of/device.c
index 8fbfeee53c1e..8a1d93a2bb81 100644
--- a/drivers/of/device.c
+++ b/drivers/of/device.c
@@ -104,3 +104,51 @@ void of_device_unregister(struct of_device *ofdev)
 	device_unregister(&ofdev->dev);
 }
 EXPORT_SYMBOL(of_device_unregister);
+
+ssize_t of_device_get_modalias(struct of_device *ofdev,
+				char *str, ssize_t len)
+{
+	const char *compat;
+	int cplen, i;
+	ssize_t tsize, csize, repend;
+
+	/* Name & Type */
+	csize = snprintf(str, len, "of:N%sT%s",
+				ofdev->node->name, ofdev->node->type);
+
+	/* Get compatible property if any */
+	compat = of_get_property(ofdev->node, "compatible", &cplen);
+	if (!compat)
+		return csize;
+
+	/* Find true end (we tolerate multiple \0 at the end */
+	for (i = (cplen - 1); i >= 0 && !compat[i]; i--)
+		cplen--;
+	if (!cplen)
+		return csize;
+	cplen++;
+
+	/* Check space (need cplen+1 chars including final \0) */
+	tsize = csize + cplen;
+	repend = tsize;
+
+	if (csize >= len)		/* @ the limit, all is already filled */
+		return tsize;
+
+	if (tsize >= len) {		/* limit compat list */
+		cplen = len - csize - 1;
+		repend = len;
+	}
+
+	/* Copy and do char replacement */
+	memcpy(&str[csize + 1], compat, cplen);
+	for (i = csize; i < repend; i++) {
+		char c = str[i];
+		if (c == '\0')
+			str[i] = 'C';
+		else if (c == ' ')
+			str[i] = '_';
+	}
+
+	return tsize;
+}