diff --git a/samples/subsys/usb/common/Kconfig.sample_usbd b/samples/subsys/usb/common/Kconfig.sample_usbd new file mode 100644 index 00000000000..1d330c2ad08 --- /dev/null +++ b/samples/subsys/usb/common/Kconfig.sample_usbd @@ -0,0 +1,48 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +# This file contains Kconfig options and defaults for configuring USB devices +# using the new experimental USB device support. The scope of these options is +# limited to USB samples in project tree, you cannot use them in your own +# application. + +menu "USB sample options" + depends on USB_DEVICE_STACK_NEXT + +config SAMPLE_USBD_MANUFACTURER + string "USB device sample manufacturer string" + default "Zephyr Project" + help + USB device sample manufacturer string. + +config SAMPLE_USBD_PRODUCT + string "USB device sample product string" + default "USBD sample" + help + USB device sample product stringa. + +config SAMPLE_USBD_PID + hex "USB device sample Product ID" + default 0x0001 + help + USB device sample Product ID. + +config SAMPLE_USBD_SELF_POWERED + bool "USB device sample Self-powered attribute" + default y + help + Set the Self-powered attribute in the sample configuration. + +config SAMPLE_USBD_REMOTE_WAKEUP + bool "USB device sample Remote Wakeup attribute" + help + Set the Remote Wakeup attribute in the sample configuration. + +config SAMPLE_USBD_MAX_POWER + int "USB device sample bMaxPower value" + default 125 + range 0 250 + help + bMaxPower value in the sample configuration in 2 mA units. + +endmenu diff --git a/samples/subsys/usb/common/common.cmake b/samples/subsys/usb/common/common.cmake new file mode 100644 index 00000000000..08d90a86612 --- /dev/null +++ b/samples/subsys/usb/common/common.cmake @@ -0,0 +1,9 @@ +# Copyright (c) 2023 Nordic Semiconductor ASA +# SPDX-License-Identifier: Apache-2.0 + +set(SAMPLE_USBD_DIR ${ZEPHYR_BASE}/samples/subsys/usb/common) + +target_include_directories(app PRIVATE ${SAMPLE_USBD_DIR}) +target_sources_ifdef(CONFIG_USB_DEVICE_STACK_NEXT app PRIVATE + ${SAMPLE_USBD_DIR}/sample_usbd_init.c +) diff --git a/samples/subsys/usb/common/sample_usbd.h b/samples/subsys/usb/common/sample_usbd.h new file mode 100644 index 00000000000..95880f02b0a --- /dev/null +++ b/samples/subsys/usb/common/sample_usbd.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SAMPLES_SUBSYS_USB_COMMON_SAMPLE_USBD_H +#define ZEPHYR_SAMPLES_SUBSYS_USB_COMMON_SAMPLE_USBD_H + +#include +#include + +/* + * The scope of this header is limited to use in USB samples together with the + * new experimental USB device stack, you should not use it in your own + * application. However, you can use the code as a template. + */ + +/* + * This function uses Kconfig.sample_usbd options to configure and initialize a + * USB device. It configures sample's device context, default string descriptors, + * USB device configuration, registers any available class instances, and + * finally initializes USB device. It is limited to a single device with a + * single configuration instantiated in sample_usbd_init.c, which should be + * enough for a simple USB device sample. + * + * It returns the configured and initialized USB device context on success, + * otherwise it returns NULL. + */ +struct usbd_contex *sample_usbd_init_device(void); + +#endif /* ZEPHYR_SAMPLES_SUBSYS_USB_COMMON_SAMPLE_USBD_H */ diff --git a/samples/subsys/usb/common/sample_usbd_init.c b/samples/subsys/usb/common/sample_usbd_init.c new file mode 100644 index 00000000000..ce4d5ce7fc9 --- /dev/null +++ b/samples/subsys/usb/common/sample_usbd_init.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2023 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#include +#include +#include + +#include +LOG_MODULE_REGISTER(usbd_sample_config); + +#define ZEPHYR_PROJECT_USB_VID 0x2fe3 + +USBD_DEVICE_DEFINE(sample_usbd, + DEVICE_DT_GET(DT_NODELABEL(zephyr_udc0)), + ZEPHYR_PROJECT_USB_VID, CONFIG_SAMPLE_USBD_PID); + +USBD_DESC_LANG_DEFINE(sample_lang); +USBD_DESC_MANUFACTURER_DEFINE(sample_mfr, CONFIG_SAMPLE_USBD_MANUFACTURER); +USBD_DESC_PRODUCT_DEFINE(sample_product, CONFIG_SAMPLE_USBD_PRODUCT); +USBD_DESC_SERIAL_NUMBER_DEFINE(sample_sn, "0123456789ABCDEF"); + +static const uint8_t attributes = (IS_ENABLED(CONFIG_SAMPLE_USBD_SELF_POWERED) ? + USB_SCD_SELF_POWERED : 0) | + (IS_ENABLED(CONFIG_SAMPLE_USBD_REMOTE_WAKEUP) ? + USB_SCD_REMOTE_WAKEUP : 0); + +USBD_CONFIGURATION_DEFINE(sample_config, + attributes, + CONFIG_SAMPLE_USBD_MAX_POWER); + +struct usbd_contex *sample_usbd_init_device(void) +{ + int err; + + err = usbd_add_descriptor(&sample_usbd, &sample_lang); + if (err) { + LOG_ERR("Failed to initialize language descriptor (%d)", err); + return NULL; + } + + err = usbd_add_descriptor(&sample_usbd, &sample_mfr); + if (err) { + LOG_ERR("Failed to initialize manufacturer descriptor (%d)", err); + return NULL; + } + + err = usbd_add_descriptor(&sample_usbd, &sample_product); + if (err) { + LOG_ERR("Failed to initialize product descriptor (%d)", err); + return NULL; + } + + err = usbd_add_descriptor(&sample_usbd, &sample_sn); + if (err) { + LOG_ERR("Failed to initialize SN descriptor (%d)", err); + return NULL; + } + + err = usbd_add_configuration(&sample_usbd, &sample_config); + if (err) { + LOG_ERR("Failed to add configuration (%d)", err); + return NULL; + } + + STRUCT_SECTION_FOREACH(usbd_class_node, node) { + /* Pull everything that is enabled in our configuration. */ + err = usbd_register_class(&sample_usbd, node->name, 1); + if (err) { + LOG_ERR("Failed to register %s (%d)", node->name, err); + return NULL; + } + + LOG_DBG("Register %s", node->name); + } + + /* Always use class code information from Interface Descriptors */ + if (IS_ENABLED(CONFIG_USBD_CDC_ACM_CLASS) || + IS_ENABLED(CONFIG_USBD_CDC_ECM_CLASS)) { + /* + * Class with multiple interfaces have an Interface + * Association Descriptor available, use an appropriate triple + * to indicate it. + */ + usbd_device_set_code_triple(&sample_usbd, + USB_BCC_MISCELLANEOUS, 0x02, 0x01); + } else { + usbd_device_set_code_triple(&sample_usbd, 0, 0, 0); + } + + err = usbd_init(&sample_usbd); + if (err) { + LOG_ERR("Failed to initialize device support"); + return NULL; + } + + return &sample_usbd; +}