Module Name: src
Committed By: thorpej
Date: Sun Jan 24 17:42:37 UTC 2021
Modified Files:
src/sys/kern: subr_autoconf.c
src/sys/sys: device.h
Log Message:
Refactor and simplify device_compatible_match(), and also provide
device_compatible_p{match,lookup}() which treats the strings in the
driver compatible data as pmatch(9) patterns.
Add device_compatible_{,p}{match,lookup}_strlist(), which are the same, but
take an OpenFirmware-style string list rather than an array of strings
for the device data.
To generate a diff of this commit:
cvs rdiff -u -r1.275 -r1.276 src/sys/kern/subr_autoconf.c
cvs rdiff -u -r1.161 -r1.162 src/sys/sys/device.h
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/kern/subr_autoconf.c
diff -u src/sys/kern/subr_autoconf.c:1.275 src/sys/kern/subr_autoconf.c:1.276
--- src/sys/kern/subr_autoconf.c:1.275 Mon Jan 18 15:28:21 2021
+++ src/sys/kern/subr_autoconf.c Sun Jan 24 17:42:36 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: subr_autoconf.c,v 1.275 2021/01/18 15:28:21 thorpej Exp $ */
+/* $NetBSD: subr_autoconf.c,v 1.276 2021/01/24 17:42:36 thorpej Exp $ */
/*
* Copyright (c) 1996, 2000 Christopher G. Demetriou
@@ -77,7 +77,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.275 2021/01/18 15:28:21 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.276 2021/01/24 17:42:36 thorpej Exp $");
#ifdef _KERNEL_OPT
#include "opt_ddb.h"
@@ -2324,52 +2324,179 @@ device_find_by_driver_unit(const char *n
return device_lookup(cd, unit);
}
+static bool
+match_strcmp(const char * const s1, const char * const s2)
+{
+ return strcmp(s1, s2) == 0;
+}
+
+static bool
+match_pmatch(const char * const s1, const char * const s2)
+{
+ return pmatch(s1, s2, NULL) == 2;
+}
+
+static bool
+strarray_match_internal(const char ** const strings,
+ unsigned int const nstrings, const char * const str,
+ unsigned int * const indexp,
+ bool (*match_fn)(const char *, const char *))
+{
+ unsigned int i;
+
+ if (strings == NULL || nstrings == 0) {
+ return 0;
+ }
+
+ for (i = 0; i < nstrings; i++) {
+ if ((*match_fn)(strings[i], str)) {
+ *indexp = i;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static int
+strarray_match(const char ** const strings, unsigned int const nstrings,
+ const char * const str)
+{
+ unsigned int idx;
+
+ if (strarray_match_internal(strings, nstrings, str, &idx,
+ match_strcmp)) {
+ return (int)(nstrings - idx);
+ }
+ return 0;
+}
+
+static int
+strarray_pmatch(const char ** const strings, unsigned int const nstrings,
+ const char * const pattern)
+{
+ unsigned int idx;
+
+ if (strarray_match_internal(strings, nstrings, pattern, &idx,
+ match_pmatch)) {
+ return (int)(nstrings - idx);
+ }
+ return 0;
+}
+
+static int
+device_compatible_match_strarray_internal(
+ const char **device_compats, int ndevice_compats,
+ const struct device_compatible_entry *driver_compats,
+ const struct device_compatible_entry **matching_entryp,
+ int (*match_fn)(const char **, unsigned int, const char *))
+{
+ const struct device_compatible_entry *dce = NULL;
+ int rv;
+
+ if (ndevice_compats == 0 || device_compats == NULL ||
+ driver_compats == NULL)
+ return 0;
+
+ for (dce = driver_compats; dce->compat != NULL; dce++) {
+ rv = (*match_fn)(device_compats, ndevice_compats, dce->compat);
+ if (rv != 0) {
+ if (matching_entryp != NULL) {
+ *matching_entryp = dce;
+ }
+ return rv;
+ }
+ }
+ return 0;
+}
+
/*
* device_compatible_match:
*
* Match a driver's "compatible" data against a device's
- * "compatible" strings. If a match is found, we return
- * a weighted match result, and optionally the matching
- * entry.
+ * "compatible" strings. Returns resulted weighted by
+ * which device "compatible" string was matched.
+ */
+int
+device_compatible_match(const char **device_compats, int ndevice_compats,
+ const struct device_compatible_entry *driver_compats)
+{
+ return device_compatible_match_strarray_internal(device_compats,
+ ndevice_compats, driver_compats, NULL, strarray_match);
+}
+
+/*
+ * device_compatible_pmatch:
+ *
+ * Like device_compatible_match(), but uses pmatch(9) to compare
+ * the device "compatible" strings against patterns in the
+ * driver's "compatible" data.
*/
+int
+device_compatible_pmatch(const char **device_compats, int ndevice_compats,
+ const struct device_compatible_entry *driver_compats)
+{
+ return device_compatible_match_strarray_internal(device_compats,
+ ndevice_compats, driver_compats, NULL, strarray_pmatch);
+}
+
static int
-device_compatible_match_internal(const char **device_compats,
- int ndevice_compats,
+device_compatible_match_strlist_internal(
+ const char * const device_compats, size_t const device_compatsize,
const struct device_compatible_entry *driver_compats,
- const struct device_compatible_entry **matching_entryp)
+ const struct device_compatible_entry **matching_entryp,
+ int (*match_fn)(const char *, size_t, const char *))
{
const struct device_compatible_entry *dce = NULL;
- int i, match_weight;
+ int rv;
- if (ndevice_compats == 0 || device_compats == NULL ||
+ if (device_compats == NULL || device_compatsize == 0 ||
driver_compats == NULL)
return 0;
-
- /*
- * We take the first match because we start with the most-specific
- * device compatible string.
- */
- for (i = 0, match_weight = ndevice_compats - 1;
- i < ndevice_compats;
- i++, match_weight--) {
- for (dce = driver_compats; dce->compat != NULL; dce++) {
- if (strcmp(dce->compat, device_compats[i]) == 0) {
- KASSERT(match_weight >= 0);
- if (matching_entryp)
- *matching_entryp = dce;
- return 1 + match_weight;
+
+ for (dce = driver_compats; dce->compat != NULL; dce++) {
+ rv = (*match_fn)(device_compats, device_compatsize,
+ dce->compat);
+ if (rv != 0) {
+ if (matching_entryp != NULL) {
+ *matching_entryp = dce;
}
+ return rv;
}
}
return 0;
}
+/*
+ * device_compatible_match_strlist:
+ *
+ * Like device_compatible_match(), but take the device
+ * "compatible" strings as an OpenFirmware-style string
+ * list.
+ */
int
-device_compatible_match(const char **device_compats, int ndevice_compats,
- const struct device_compatible_entry *driver_compats)
+device_compatible_match_strlist(
+ const char * const device_compats, size_t const device_compatsize,
+ const struct device_compatible_entry *driver_compats)
{
- return device_compatible_match_internal(device_compats, ndevice_compats,
- driver_compats, NULL);
+ return device_compatible_match_strlist_internal(device_compats,
+ device_compatsize, driver_compats, NULL, strlist_match);
+}
+
+/*
+ * device_compatible_pmatch_strlist:
+ *
+ * Like device_compatible_pmatch(), but take the device
+ * "compatible" strings as an OpenFirmware-style string
+ * list.
+ */
+int
+device_compatible_pmatch_strlist(
+ const char * const device_compats, size_t const device_compatsize,
+ const struct device_compatible_entry *driver_compats)
+{
+ return device_compatible_match_strlist_internal(device_compats,
+ device_compatsize, driver_compats, NULL, strlist_pmatch);
}
/*
@@ -2384,8 +2511,69 @@ device_compatible_lookup(const char **de
{
const struct device_compatible_entry *dce;
- if (device_compatible_match_internal(device_compats, ndevice_compats,
- driver_compats, &dce)) {
+ if (device_compatible_match_strarray_internal(device_compats,
+ ndevice_compats, driver_compats, &dce, strarray_match)) {
+ return dce;
+ }
+ return NULL;
+}
+
+/*
+ * device_compatible_plookup:
+ *
+ * Look up and return the device_compatible_entry, using the
+ * same matching criteria used by device_compatible_pmatch().
+ */
+const struct device_compatible_entry *
+device_compatible_plookup(const char **device_compats, int ndevice_compats,
+ const struct device_compatible_entry *driver_compats)
+{
+ const struct device_compatible_entry *dce;
+
+ if (device_compatible_match_strarray_internal(device_compats,
+ ndevice_compats, driver_compats, &dce, strarray_pmatch)) {
+ return dce;
+ }
+ return NULL;
+}
+
+/*
+ * device_compatible_lookup_strlist:
+ *
+ * Like device_compatible_lookup(), but take the device
+ * "compatible" strings as an OpenFirmware-style string
+ * list.
+ */
+const struct device_compatible_entry *
+device_compatible_lookup_strlist(
+ const char * const device_compats, size_t const device_compatsize,
+ const struct device_compatible_entry *driver_compats)
+{
+ const struct device_compatible_entry *dce;
+
+ if (device_compatible_match_strlist_internal(device_compats,
+ device_compatsize, driver_compats, &dce, strlist_match)) {
+ return dce;
+ }
+ return NULL;
+}
+
+/*
+ * device_compatible_plookup_strlist:
+ *
+ * Like device_compatible_plookup(), but take the device
+ * "compatible" strings as an OpenFirmware-style string
+ * list.
+ */
+const struct device_compatible_entry *
+device_compatible_plookup_strlist(
+ const char * const device_compats, size_t const device_compatsize,
+ const struct device_compatible_entry *driver_compats)
+{
+ const struct device_compatible_entry *dce;
+
+ if (device_compatible_match_strlist_internal(device_compats,
+ device_compatsize, driver_compats, &dce, strlist_pmatch)) {
return dce;
}
return NULL;
Index: src/sys/sys/device.h
diff -u src/sys/sys/device.h:1.161 src/sys/sys/device.h:1.162
--- src/sys/sys/device.h:1.161 Mon Jan 18 15:28:21 2021
+++ src/sys/sys/device.h Sun Jan 24 17:42:37 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: device.h,v 1.161 2021/01/18 15:28:21 thorpej Exp $ */
+/* $NetBSD: device.h,v 1.162 2021/01/24 17:42:37 thorpej Exp $ */
/*
* Copyright (c) 1996, 2000 Christopher G. Demetriou
@@ -545,10 +545,27 @@ device_t device_find_by_driver_unit(cons
int device_compatible_match(const char **, int,
const struct device_compatible_entry *);
+int device_compatible_pmatch(const char **, int,
+ const struct device_compatible_entry *);
const struct device_compatible_entry *
device_compatible_lookup(const char **, int,
const struct device_compatible_entry *);
+const struct device_compatible_entry *
+ device_compatible_plookup(const char **, int,
+ const struct device_compatible_entry *);
+int device_compatible_match_strlist(const char *, size_t,
+ const struct device_compatible_entry *);
+int device_compatible_pmatch_strlist(const char *, size_t,
+ const struct device_compatible_entry *);
+const struct device_compatible_entry *
+ device_compatible_lookup_strlist(const char *, size_t,
+ const struct device_compatible_entry *);
+const struct device_compatible_entry *
+ device_compatible_plookup_strlist(const char *, size_t,
+ const struct device_compatible_entry *);
+
+bool device_pmf_is_registered(device_t);
bool device_pmf_is_registered(device_t);
bool device_pmf_driver_suspend(device_t, const pmf_qual_t *);