allow specifying literal values in MODULE_PNP_INFO(9)

Yuri Pankov yuripv at yuripv.net
Tue Sep 25 13:09:54 UTC 2018


Hi,

Looking at adding the MODULE_PNP_INFO() entry to iwm(4), I came up with 
the patch in https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=231625 
adding redundant and useless vendor field to iwm_devices.  While it 
works, it's unfortunate, and I have started looking into possible 
solutions and the result is a small patch for kldxref(8) allowing 
specifying literal values in descriptor_string like the following:

MODULE_PNP_INFO("U16=8086:vendor;U16:device;P:#", pci, iwm_pci_driver,
     iwm_devices, sizeof(iwm_devices[0]), nitems(iwm_devices));

...so that we always have vendor 0x8086 and only consume the device field.

If it makes at least some sense, I'll put it for review.
-------------- next part --------------
diff --git a/usr.sbin/kldxref/kldxref.c b/usr.sbin/kldxref/kldxref.c
index f0d699369dbd..e494e8a9f039 100644
--- a/usr.sbin/kldxref/kldxref.c
+++ b/usr.sbin/kldxref/kldxref.c
@@ -168,7 +168,7 @@ pnp_eisaformat(uint32_t id)
 
 struct pnp_elt
 {
-	int	pe_kind;	/* What kind of entry */
+	int		pe_kind;	/* What kind of entry */
 #define TYPE_SZ_MASK	0x0f
 #define TYPE_FLAGGED	0x10	/* all f's is a wildcard */
 #define	TYPE_INT	0x20	/* Is a number */
@@ -191,8 +191,9 @@ struct pnp_elt
 #define TYPE_P		9
 #define TYPE_E		10
 #define TYPE_T		11
-	int	pe_offset;	/* Offset within the element */
-	char *	pe_key;		/* pnp key name */
+	int		pe_offset;	/* Offset within the element */
+	char		*pe_key;	/* pnp key name */
+	uint32_t	pe_value;	/* literal value, if any */
 	TAILQ_ENTRY(pnp_elt) next; /* Link */
 };
 typedef TAILQ_HEAD(pnp_head, pnp_elt) pnp_list;
@@ -232,10 +233,10 @@ static int
 parse_pnp_list(const char *desc, char **new_desc, pnp_list *list)
 {
 	const char *walker, *ep;
-	const char *colon, *semi;
+	const char *assign, *colon, *semi;
 	struct pnp_elt *elt;
 	char *nd;
-	char type[8], key[32];
+	char type[8], value[9], key[32];
 	int off;
 
 	walker = desc;
@@ -245,14 +246,28 @@ parse_pnp_list(const char *desc, char **new_desc, pnp_list *list)
 	if (verbose > 1)
 		printf("Converting %s into a list\n", desc);
 	while (walker < ep) {
+		assign = strchr(walker, '=');
 		colon = strchr(walker, ':');
 		semi = strchr(walker, ';');
+		if (colon == NULL)
+			goto err;
+		if (assign != NULL && assign > colon)
+			assign = NULL;
 		if (semi != NULL && semi < colon)
 			goto err;
 		if (colon - walker > sizeof(type))
 			goto err;
-		strncpy(type, walker, colon - walker);
-		type[colon - walker] = '\0';
+		if (assign != NULL) {
+			strncpy(type, walker, assign - walker);
+			type[assign - walker] = '\0';
+			if (colon - assign >= sizeof(value))
+				goto err;
+			strncpy(value, assign + 1, colon - assign - 1);
+			value[colon - assign - 1] = '\0';
+		} else {
+			strncpy(type, walker, colon - walker);
+			type[colon - walker] = '\0';
+		}
 		if (semi != NULL) {
 			if (semi - colon >= sizeof(key))
 				goto err;
@@ -265,8 +280,15 @@ parse_pnp_list(const char *desc, char **new_desc, pnp_list *list)
 			strcpy(key, colon + 1);
 			walker = ep;
 		}
-		if (verbose > 1)
-			printf("Found type %s for name %s\n", type, key);
+		if (verbose > 1) {
+			if (assign != NULL) {
+				printf("Found type %s for name %s "
+				    "with value %s\n", type, key, value);
+			} else {
+				printf("Found type %s for name %s\n",
+				    type, key);
+			}
+		}
 		/* Skip pointer place holders */
 		if (strcmp(type, "P") == 0) {
 			off += sizeof(void *);
@@ -318,7 +340,14 @@ parse_pnp_list(const char *desc, char **new_desc, pnp_list *list)
 		 * have sane ordering of types.
 		 */
 		if (elt->pe_kind & TYPE_INT) {
-			elt->pe_offset = roundup2(elt->pe_offset, elt->pe_kind & TYPE_SZ_MASK);
+			/*
+			 * Literal values (assign != NULL) don't consume space
+			 * in the table.
+			 */
+			if (assign == NULL) {
+				elt->pe_offset = roundup2(elt->pe_offset,
+				    elt->pe_kind & TYPE_SZ_MASK);
+			}
 			off = elt->pe_offset + (elt->pe_kind & TYPE_SZ_MASK);
 		} else if (elt->pe_kind == TYPE_E) {
 			/* Type E stored as Int, displays as string */
@@ -340,9 +369,7 @@ parse_pnp_list(const char *desc, char **new_desc, pnp_list *list)
 				    word);
 				nd += strlen(nd);
 			}
-			
-		}
-		else {
+		} else {
 			if (elt->pe_kind & TYPE_FLAGGED)
 				*nd++ = 'J';
 			else if (elt->pe_kind & TYPE_GE)
@@ -351,9 +378,18 @@ parse_pnp_list(const char *desc, char **new_desc, pnp_list *list)
 				*nd++ = 'L';
 			else if (elt->pe_kind & TYPE_MASK)
 				*nd++ = 'M';
-			else if (elt->pe_kind & TYPE_INT)
+			else if (elt->pe_kind & TYPE_INT) {
 				*nd++ = 'I';
-			else if (elt->pe_kind == TYPE_D)
+				if (assign != NULL) {
+					char *cep;
+
+					errno = 0;
+					elt->pe_value = strtoul(value, &cep,
+					    16);
+					if (errno != 0 || *ep != '\0')
+						goto err;
+				}
+			} else if (elt->pe_kind == TYPE_D)
 				*nd++ = 'D';
 			else if (elt->pe_kind == TYPE_Z || elt->pe_kind == TYPE_E)
 				*nd++ = 'Z';
@@ -470,23 +506,27 @@ parse_entry(struct mod_metadata *md, const char *cval,
 						if (verbose > 1)
 							printf(":%#x;", value);
 					} else if (elt->pe_kind & TYPE_INT) {
+						char *val = elt->pe_value != 0 ?
+						    (char *)&elt->pe_value :
+						    walker + elt->pe_offset;
+
 						switch (elt->pe_kind & TYPE_SZ_MASK) {
 						case 1:
-							memcpy(&v1, walker + elt->pe_offset, sizeof(v1));
+							memcpy(&v1, val, sizeof(v1));
 							if ((elt->pe_kind & TYPE_FLAGGED) && v1 == 0xff)
 								value = -1;
 							else
 								value = v1;
 							break;
 						case 2:
-							memcpy(&v2, walker + elt->pe_offset, sizeof(v2));
+							memcpy(&v2, val, sizeof(v2));
 							if ((elt->pe_kind & TYPE_FLAGGED) && v2 == 0xffff)
 								value = -1;
 							else
 								value = v2;
 							break;
 						case 4:
-							memcpy(&v4, walker + elt->pe_offset, sizeof(v4));
+							memcpy(&v4, val, sizeof(v4));
 							if ((elt->pe_kind & TYPE_FLAGGED) && v4 == 0xffffffff)
 								value = -1;
 							else


More information about the freebsd-hackers mailing list