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 *);