usb: device_next: allow reuse of string descriptor nodes

If we try to reuse a string descriptor node, the content will
be corrupted because the device stack assumes it is still ASCII7
encoded. Add a flag to indicate that a descriptor node contains
UTF16LE encoded content.

And while we are at it, add a flag to indicate that the SN string
should not be obtained from the hwinfo API.

Signed-off-by: Johann Fischer <johann.fischer@nordicsemi.no>
diff --git a/include/zephyr/usb/usbd.h b/include/zephyr/usb/usbd.h
index 34b1c64..410fdf9 100644
--- a/include/zephyr/usb/usbd.h
+++ b/include/zephyr/usb/usbd.h
@@ -58,13 +58,17 @@
  * Descriptor node
  *
  * Descriptor node is used to manage descriptors that are not
- * directly part of a structure string, and bos descriptors.
+ * directly part of a structure, such as string or bos descriptors.
  */
 struct usbd_desc_node {
 	/** slist node struct */
 	sys_snode_t node;
-	/** Optional descriptor index, required for string descriptors */
-	uint32_t idx;
+	/** Descriptor index, required for string descriptors */
+	unsigned int idx : 8;
+	/** If not set, string descriptor must be converted to UTF16LE */
+	unsigned int utf16le : 1;
+	/** If not set, device stack obtains SN using the hwinfo API */
+	unsigned int custom_sn : 1;
 	/** Pointer to a descriptor */
 	void *desc;
 };
diff --git a/subsys/usb/device_next/usbd_desc.c b/subsys/usb/device_next/usbd_desc.c
index 89a1a1a..bea3b05 100644
--- a/subsys/usb/device_next/usbd_desc.c
+++ b/subsys/usb/device_next/usbd_desc.c
@@ -61,6 +61,8 @@
 		buf[i] = 0U;
 		buf[i - 1] = buf[ascii_idx_max--];
 	}
+
+	dn->utf16le = true;
 }
 
 /**
@@ -163,16 +165,18 @@
 			dev_desc->iProduct = desc_nd->idx;
 			break;
 		case USBD_DESC_SERIAL_NUMBER_IDX:
-			/* FIXME, should we force the use of hwid here? */
-			ret = usbd_get_sn_from_hwid(desc_nd);
+			if (!desc_nd->custom_sn) {
+				ret = usbd_get_sn_from_hwid(desc_nd);
+				desc_nd->utf16le = false;
+			}
+
 			dev_desc->iSerialNumber = desc_nd->idx;
 			break;
 		default:
 			break;
 		}
 
-		if (desc_nd->idx) {
-			/* FIXME, should we force ascii7 -> utf16le? */
+		if (desc_nd->idx && !desc_nd->utf16le) {
 			usbd_ascii7_to_utf16le(desc_nd);
 		}
 	}