usb: device_next: do a little more cleanup on shutdown

At the shutdown of USB device stack we have to cleanup and
remove all registered class instances and string descriptors
from a configuration.

Signed-off-by: Johann Fischer <johann.fischer@nordicsemi.no>
diff --git a/subsys/usb/device_next/usbd_class.c b/subsys/usb/device_next/usbd_class.c
index 7470acc..1464d84 100644
--- a/subsys/usb/device_next/usbd_class.c
+++ b/subsys/usb/device_next/usbd_class.c
@@ -257,6 +257,27 @@
 	return 0;
 }
 
+int usbd_class_remove_all(struct usbd_contex *const uds_ctx,
+			  const uint8_t cfg)
+{
+	struct usbd_config_node *cfg_nd;
+	struct usbd_class_node *c_nd;
+	sys_snode_t *node;
+
+	cfg_nd = usbd_config_get(uds_ctx, cfg);
+	if (cfg_nd == NULL) {
+		return -ENODATA;
+	}
+
+	while ((node = sys_slist_get(&cfg_nd->class_list))) {
+		c_nd = CONTAINER_OF(node, struct usbd_class_node, node);
+		atomic_clear_bit(&c_nd->data->state, USBD_CCTX_REGISTERED);
+		LOG_DBG("Remove class node %p from configuration %u", c_nd, cfg);
+	}
+
+	return 0;
+}
+
 /*
  * All the functions below are part of public USB device support API.
  */
diff --git a/subsys/usb/device_next/usbd_class.h b/subsys/usb/device_next/usbd_class.h
index caa4262..a4d6793 100644
--- a/subsys/usb/device_next/usbd_class.h
+++ b/subsys/usb/device_next/usbd_class.h
@@ -93,4 +93,15 @@
 struct usbd_class_node *usbd_class_get_by_req(struct usbd_contex *uds_ctx,
 					      uint8_t request);
 
+/**
+ * @brief Remove all registered class instances from a configuration
+ *
+ * @param[in] uds_ctx Pointer to device context
+ * @param[in] cfg     Configuration number (bConfigurationValue)
+ *
+ * @return 0 on success, other values on fail.
+ */
+int usbd_class_remove_all(struct usbd_contex *const uds_ctx,
+			  const uint8_t cfg);
+
 #endif /* ZEPHYR_INCLUDE_USBD_CLASS_H */
diff --git a/subsys/usb/device_next/usbd_core.c b/subsys/usb/device_next/usbd_core.c
index 48cc0a6..c8ca933 100644
--- a/subsys/usb/device_next/usbd_core.c
+++ b/subsys/usb/device_next/usbd_core.c
@@ -13,6 +13,7 @@
 #include <zephyr/usb/usbd.h>
 
 #include "usbd_device.h"
+#include "usbd_desc.h"
 #include "usbd_config.h"
 #include "usbd_init.h"
 #include "usbd_ch9.h"
@@ -199,6 +200,23 @@
 
 int usbd_device_shutdown_core(struct usbd_contex *const uds_ctx)
 {
+	struct usbd_config_node *cfg_nd;
+	int ret;
+
+	SYS_SLIST_FOR_EACH_CONTAINER(&uds_ctx->configs, cfg_nd, node) {
+		uint8_t cfg_value = usbd_config_get_value(cfg_nd);
+
+		ret = usbd_class_remove_all(uds_ctx, cfg_value);
+		if (ret) {
+			LOG_ERR("Failed to cleanup registered classes, %d", ret);
+		}
+	}
+
+	ret = usbd_desc_remove_all(uds_ctx);
+	if (ret) {
+		LOG_ERR("Failed to cleanup descriptors, %d", ret);
+	}
+
 	return udc_shutdown(uds_ctx->dev);
 }
 
diff --git a/subsys/usb/device_next/usbd_desc.c b/subsys/usb/device_next/usbd_desc.c
index 9390fa1..89a1a1a 100644
--- a/subsys/usb/device_next/usbd_desc.c
+++ b/subsys/usb/device_next/usbd_desc.c
@@ -11,6 +11,7 @@
 #include <zephyr/usb/usbd.h>
 #include <zephyr/drivers/hwinfo.h>
 
+#include "usbd_desc.h"
 #include "usbd_device.h"
 
 #include <zephyr/logging/log.h>
@@ -117,6 +118,19 @@
 	return NULL;
 }
 
+int usbd_desc_remove_all(struct usbd_contex *const uds_ctx)
+{
+	struct usbd_desc_node *tmp;
+	sys_snode_t *node;
+
+	while ((node = sys_slist_get(&uds_ctx->descriptors))) {
+		tmp = CONTAINER_OF(node, struct usbd_desc_node, node);
+		LOG_DBG("Remove descriptor node %p", tmp);
+	}
+
+	return 0;
+}
+
 int usbd_add_descriptor(struct usbd_contex *const uds_ctx,
 			struct usbd_desc_node *const desc_nd)
 {
diff --git a/subsys/usb/device_next/usbd_desc.h b/subsys/usb/device_next/usbd_desc.h
index e52d22f..ab796ef 100644
--- a/subsys/usb/device_next/usbd_desc.h
+++ b/subsys/usb/device_next/usbd_desc.h
@@ -23,4 +23,17 @@
 void *usbd_get_descriptor(struct usbd_contex *uds_ctx,
 			  const uint8_t type, const uint8_t idx);
 
+/**
+ * @brief Remove all descriptors from an USB device context
+ *
+ * This removes all loose descriptors like string descriptors.
+ * Descriptors like configuration, or interface are not touched
+ * by this.
+ *
+ * @param[in] uds_ctx Pointer to device context
+ *
+ * @return 0 on success, other values on fail.
+ */
+int usbd_desc_remove_all(struct usbd_contex *const uds_ctx);
+
 #endif /* ZEPHYR_INCLUDE_USBD_DESC_H */