mosys: Add regex pattern support for ARM DT

Adding support so that regex patterns can be used from cros_config to
generically match patterns from the source compatible device tree on ARM
devices.  This will support SKU-specific matching and config options
going forward.

BUG=b:115771305
TEST=Permuted over scarlet YAML and tested mosys

Change-Id: I27a842ef633216e55b483e5fe30a5cd564bfdcd0
Reviewed-on: https://chromium-review.googlesource.com/1230593
Commit-Ready: C Shapiro <shapiroc@google.com>
Tested-by: C Shapiro <shapiroc@google.com>
Reviewed-by: Justin TerAvest <teravest@chromium.org>
diff --git a/include/lib/probe.h b/include/lib/probe.h
index 4f35e09..c583452 100644
--- a/include/lib/probe.h
+++ b/include/lib/probe.h
@@ -129,12 +129,13 @@
  * @id_list:		Known platform IDs to compare with
  * @num_ids:		Number of known platform IDs
  * @allow_partial:	Allow partial match (0=no, 1=yes)
+ * @allow_regex:	Allow regex match (0=no, 1=yes)
  *
  * returns the index of the platform ID if found
  * returns <0 to indicate error
  */
 extern int probe_fdt_compatible(const char * const id_list[],
-				int num_ids, int allow_partial);
+				int num_ids, int allow_partial, int allow_regex);
 
 
 /*
diff --git a/lib/cros_config/cros_config.c b/lib/cros_config/cros_config.c
index 1f95fe3..96ba351 100644
--- a/lib/cros_config/cros_config.c
+++ b/lib/cros_config/cros_config.c
@@ -412,6 +412,7 @@
 #ifdef CONFIG_PLATFORM_ARCH_ARMEL
 	static const int MAX_NAME_LEN = 256;
 	static const int NO_PARTIAL_MATCHES = 0;
+	static const int NO_REGEX_MATCHES = 0;
 	// probe_fdt_compatible() returns an index of the matching name
 	// found in the find_platform_names list. Success is an index
 	// that is greater than or equal zero.
@@ -430,7 +431,7 @@
 		// as the first parameter, we are only passing one name
 		// to check at a time requiring full name matches.
 		int found = probe_fdt_compatible(&compat_names, 1,
-						 NO_PARTIAL_MATCHES);
+						 NO_PARTIAL_MATCHES, NO_REGEX_MATCHES);
 		if (found >= 0) {
 			// Platform is compatible, now read the sku info to see
 			// if we can find a device match.
diff --git a/lib/cros_config/cros_config_struct.c b/lib/cros_config/cros_config_struct.c
index cad1c8a..4ecdeca 100644
--- a/lib/cros_config/cros_config_struct.c
+++ b/lib/cros_config/cros_config_struct.c
@@ -84,8 +84,9 @@
 	    cros_config_get_config_map(&config_map_size);
 	for (int i = 0; i < config_map_size; i++) {
 		const struct config_map *config = &configs[i];
-		bool device_match = probe_fdt_compatible(
-			&config->device_tree_compatible_match, 1, 1) == 0;
+		bool device_match =
+		    probe_fdt_compatible(&config->device_tree_compatible_match,
+					 1, 1, 1) == 0;
 		bool whitelabel_match =
 		    !strcmp("", config->whitelabel_tag) ||
 		    !strcmp(whitelabel_tag, config->whitelabel_tag);
diff --git a/lib/misc/probe.c b/lib/misc/probe.c
index 3a5ff58..23399c4 100644
--- a/lib/misc/probe.c
+++ b/lib/misc/probe.c
@@ -35,6 +35,7 @@
 #include <ctype.h>
 #include <string.h>
 #include <limits.h>
+#include <regex.h>
 #include <unistd.h>
 
 #include "mosys/alloc.h"
@@ -308,7 +309,7 @@
 
 #define FDT_COMPATIBLE	"/proc/device-tree/compatible"
 int probe_fdt_compatible(const char * const id_list[], int num_ids,
-			 int allow_partial)
+			 int allow_partial, int allow_regex)
 {
 	int ret = -1, i, fd;
 	char path[PATH_MAX];
@@ -355,6 +356,25 @@
 				cmp = strcmp(&compat[0], id_list[i]);
 			}
 
+			if (cmp && allow_regex) {
+				regex_t regex;
+				if (regcomp(&regex, id_list[i],
+					    REG_EXTENDED | REG_ICASE |
+						REG_NOSUB) == 0) {
+					cmp = regexec(&regex, &compat[0], 0,
+						      NULL, 0);
+					regfree(&regex);
+				} else {
+					/* This is not necessarily an error
+					 since it may just be a partial match
+					 that's not a valid regex pattern. */
+					lprintf(LOG_DEBUG,
+						"Failed compiling regex "
+						"pattern: \"%s\"\n",
+						id_list[i]);
+				}
+			}
+
 			if (!cmp) {
 				lprintf(LOG_DEBUG, "yes\n");
 				ret = i;
diff --git a/platform/cyclone/cyclone.c b/platform/cyclone/cyclone.c
index 9bcfcdf..7cf8ea2 100644
--- a/platform/cyclone/cyclone.c
+++ b/platform/cyclone/cyclone.c
@@ -67,7 +67,7 @@
 {
 	int index;
 
-	index = probe_fdt_compatible(&id_list[0], ARRAY_SIZE(id_list), 1);
+	index = probe_fdt_compatible(&id_list[0], ARRAY_SIZE(id_list), 1, 0);
 	if (index >= 0) {
 		lprintf(LOG_DEBUG, "Found platform \"%s\" via FDT compatible "
 				"node.\n", id_list[index]);
diff --git a/platform/daisy/daisy.c b/platform/daisy/daisy.c
index 85f0463..f89f0eb 100644
--- a/platform/daisy/daisy.c
+++ b/platform/daisy/daisy.c
@@ -84,7 +84,7 @@
 		return status;
 
 	index = probe_fdt_compatible(&snow_id_list[0],
-				ARRAY_SIZE(snow_id_list), 0);
+				ARRAY_SIZE(snow_id_list), 0, 0);
 	if (index >= 0) {
 		lprintf(LOG_DEBUG, "Found platform \"%s\" via FDT compatible "
 				"node.\n", snow_id_list[index]);
@@ -96,7 +96,7 @@
 	}
 
 	index = probe_fdt_compatible(&daisy_id_list[0],
-				ARRAY_SIZE(daisy_id_list), 0);
+				ARRAY_SIZE(daisy_id_list), 0, 0);
 	if (index >= 0) {
 		lprintf(LOG_DEBUG, "Found platform \"%s\" via FDT compatible "
 				"node.\n", daisy_id_list[index]);
diff --git a/platform/gru/gru.c b/platform/gru/gru.c
index dd89dc0..8e08e4b 100644
--- a/platform/gru/gru.c
+++ b/platform/gru/gru.c
@@ -105,7 +105,7 @@
 	for (i = 0; i < ARRAY_SIZE(gru_id_list); i++) {
 		const char **compat = &gru_id_list[i].fdt_compat;
 
-		if (probe_fdt_compatible(compat, 1, 1) == 0) {
+		if (probe_fdt_compatible(compat, 1, 1, 0) == 0) {
 			lprintf(LOG_DEBUG, "Found platform \"%s\" via FDT "
 				"compatible node.\n", gru_id_list[i].name);
 			intf->name = gru_id_list[i].name;
diff --git a/platform/nyan/nyan.c b/platform/nyan/nyan.c
index f7a874d..d0c1d72 100644
--- a/platform/nyan/nyan.c
+++ b/platform/nyan/nyan.c
@@ -95,7 +95,7 @@
 
 	/* nyan-big is listed before google,nyan, so search for it first */
 	index = probe_fdt_compatible(&nyan_big_id_list[0],
-					ARRAY_SIZE(nyan_big_id_list), 0);
+					ARRAY_SIZE(nyan_big_id_list), 0, 0);
 	if (index >= 0) {
 		gpio_t gpio[] = {GPIO(Q3), GPIO(T1), GPIO(X1), GPIO(X4)};
 		int value;
@@ -116,7 +116,7 @@
 
 	/* nyan-blaze is listed before google,nyan, so search for it first */
 	index = probe_fdt_compatible(&nyan_blaze_id_list[0],
-					ARRAY_SIZE(nyan_blaze_id_list), 0);
+					ARRAY_SIZE(nyan_blaze_id_list), 0, 0);
 	if (index >= 0) {
 		lprintf(LOG_DEBUG, "Found platform \"%s\" via FDT compatible "
 				"node.\n", nyan_blaze_id_list[index]);
@@ -126,7 +126,7 @@
 
 	/* nyan-kitty is listed before google,nyan, so search for it first */
 	index = probe_fdt_compatible(&nyan_kitty_id_list[0],
-					ARRAY_SIZE(nyan_kitty_id_list), 0);
+					ARRAY_SIZE(nyan_kitty_id_list), 0, 0);
 	if (index >= 0) {
 		lprintf(LOG_DEBUG, "Found platform \"%s\" via FDT compatible "
 				"node.\n", nyan_kitty_id_list[index]);
@@ -135,7 +135,7 @@
 	}
 
 	index = probe_fdt_compatible(&nyan_id_list[0],
-					ARRAY_SIZE(nyan_id_list), 0);
+					ARRAY_SIZE(nyan_id_list), 0, 0);
 	if (index >= 0) {
 		lprintf(LOG_DEBUG, "Found platform \"%s\" via FDT compatible "
 				"node.\n", nyan_id_list[index]);
diff --git a/platform/oak/oak.c b/platform/oak/oak.c
index 0d50b08..eed26ba 100644
--- a/platform/oak/oak.c
+++ b/platform/oak/oak.c
@@ -85,7 +85,7 @@
 	for (i = 0; i < ARRAY_SIZE(oak_id_list); i++) {
 		const char **compat = &oak_id_list[i].fdt_compat;
 
-		if (probe_fdt_compatible(compat, 1, 1) == 0) {
+		if (probe_fdt_compatible(compat, 1, 1, 0) == 0) {
 			lprintf(LOG_DEBUG, "Found platform \"%s\" via FDT "
 				"compatible node.\n", oak_id_list[i].name);
 			intf->name = oak_id_list[i].name;
diff --git a/platform/pinky/pinky.c b/platform/pinky/pinky.c
index fbad567..d656828 100644
--- a/platform/pinky/pinky.c
+++ b/platform/pinky/pinky.c
@@ -110,7 +110,7 @@
 	for (i = 0; i < ARRAY_SIZE(veyron_id_list); i++) {
 		const char **compat = &veyron_id_list[i].fdt_compat;
 
-		if (probe_fdt_compatible(compat, 1, 1) == 0) {
+		if (probe_fdt_compatible(compat, 1, 1, 0) == 0) {
 			lprintf(LOG_DEBUG, "Found platform \"%s\" via FDT "
 				"compatible node.\n", veyron_id_list[i].name);
 			intf->name = veyron_id_list[i].name;
diff --git a/platform/smaug/smaug.c b/platform/smaug/smaug.c
index 9202e8f..2dbbd37 100644
--- a/platform/smaug/smaug.c
+++ b/platform/smaug/smaug.c
@@ -73,7 +73,7 @@
 	int index;
 
 	index = probe_fdt_compatible(&id_list[0],
-					ARRAY_SIZE(id_list), 0);
+					ARRAY_SIZE(id_list), 0, 0);
 	if (index >= 0) {
 		lprintf(LOG_DEBUG, "Found platform \"%s\" via FDT compatible "
 				"node.\n", id_list[index]);
diff --git a/platform/storm/storm.c b/platform/storm/storm.c
index 250d936..197b996 100644
--- a/platform/storm/storm.c
+++ b/platform/storm/storm.c
@@ -70,7 +70,7 @@
 {
 	int index;
 
-	index = probe_fdt_compatible(&id_list[0], ARRAY_SIZE(id_list), 1);
+	index = probe_fdt_compatible(&id_list[0], ARRAY_SIZE(id_list), 1, 0);
 	if (index >= 0) {
 		lprintf(LOG_DEBUG, "Found platform \"%s\" via FDT compatible "
 				"node.\n", id_list[index]);