samples: usb: add common USB device instantiation and initialization

There is common code for the new USB device support in the samples to
instantiate USB device, descriptors, configuration and initialize USB
device. Add common code that can be used for the simple usecase with a
single USB device and single configuration.

Signed-off-by: Johann Fischer <johann.fischer@nordicsemi.no>
This commit is contained in:
Johann Fischer 2023-11-17 16:05:37 +01:00 committed by Carles Cufí
parent 52686a8308
commit b00a998cf1
4 changed files with 191 additions and 0 deletions

View File

@ -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

View File

@ -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
)

View File

@ -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 <stdint.h>
#include <zephyr/usb/usbd.h>
/*
* 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 */

View File

@ -0,0 +1,102 @@
/*
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <zephyr/device.h>
#include <zephyr/usb/usbd.h>
#include <zephyr/sys/iterable_sections.h>
#include <zephyr/logging/log.h>
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;
}