usb: device_next: rework USBD shell to take speed into account

Rework USBD shell to take speed arguments into account and revise
command help text. Rename some of the commands to better reflect what
they actually do.
Since most of the init code changes, rewrite the command to initialize
the default configuration in the shell to register all available
classes, but not to enable USB device support in a single command.
This will allow earlier notification in the future, if supported by the
controller, before the USB device controller is enabled.

Signed-off-by: Johann Fischer <johann.fischer@nordicsemi.no>
This commit is contained in:
Johann Fischer 2024-03-22 13:28:33 +01:00 committed by Carles Cufí
parent 0cfc15da2e
commit 215b4ddf98

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 Nordic Semiconductor ASA
* Copyright (c) 2022,2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -14,25 +14,46 @@
#include <zephyr/sys/byteorder.h>
#include <zephyr/sys/iterable_sections.h>
const struct shell *ctx_shell;
/* Default configurations used in the shell context. */
USBD_CONFIGURATION_DEFINE(config_1_fs, USB_SCD_REMOTE_WAKEUP, 200);
USBD_CONFIGURATION_DEFINE(config_1_hs, USB_SCD_REMOTE_WAKEUP, 200);
USBD_CONFIGURATION_DEFINE(config_2_fs, USB_SCD_SELF_POWERED, 200);
USBD_CONFIGURATION_DEFINE(config_2_hs, USB_SCD_SELF_POWERED, 200);
USBD_CONFIGURATION_DEFINE(config_baz, USB_SCD_REMOTE_WAKEUP, 200);
USBD_CONFIGURATION_DEFINE(config_foo, USB_SCD_SELF_POWERED, 200);
static struct usbd_shell_config {
struct usbd_config_node *cfg_nd;
enum usbd_speed speed;
const char *name;
} sh_configs[] = {
{.cfg_nd = &config_1_fs, .speed = USBD_SPEED_FS, .name = "FS1",},
{.cfg_nd = &config_1_hs, .speed = USBD_SPEED_HS, .name = "HS1",},
{.cfg_nd = &config_2_fs, .speed = USBD_SPEED_FS, .name = "FS2",},
{.cfg_nd = &config_2_hs, .speed = USBD_SPEED_HS, .name = "HS2",},
};
static struct usbd_shell_speed {
enum usbd_speed speed;
const char *name;
} sh_speed[] = {
{.speed = USBD_SPEED_FS, .name = "fs",},
{.speed = USBD_SPEED_HS, .name = "hs",},
};
/* Default string descriptors used in the shell context. */
USBD_DESC_LANG_DEFINE(lang);
USBD_DESC_MANUFACTURER_DEFINE(mfr, "ZEPHYR");
USBD_DESC_PRODUCT_DEFINE(product, "Zephyr USBD foobaz");
USBD_DESC_SERIAL_NUMBER_DEFINE(sn, "0123456789ABCDEF");
/* Default device descriptors and context used in the shell. */
USBD_DEVICE_DEFINE(sh_uds_ctx, DEVICE_DT_GET(DT_NODELABEL(zephyr_udc0)),
0x2fe3, 0xffff);
static struct usbd_contex *my_uds_ctx = &sh_uds_ctx;
/* TODO: Rework commands to allow specifying speed */
static enum usbd_speed speed = USBD_SPEED_FS;
static enum usbd_speed current_cmd_speed = USBD_SPEED_FS;
int cmd_wakeup_request(const struct shell *sh,
size_t argc, char **argv)
static int cmd_wakeup_request(const struct shell *sh,
size_t argc, char **argv)
{
int err;
@ -52,17 +73,16 @@ static int cmd_register(const struct shell *sh,
uint8_t cfg;
int ret;
cfg = strtol(argv[2], NULL, 10);
ret = usbd_register_class(my_uds_ctx, argv[1], speed, cfg);
cfg = strtol(argv[3], NULL, 10);
ret = usbd_register_class(my_uds_ctx, argv[1], current_cmd_speed, cfg);
if (ret) {
shell_error(sh,
"dev: failed to add USB class %s to configuration %u",
argv[1], cfg);
"dev: failed to register USB class %s to configuration %s %u",
argv[1], argv[2], cfg);
} else {
shell_print(sh,
"dev: added USB class %s to configuration %u",
argv[1], cfg);
"dev: register USB class %s to configuration %s %u",
argv[1], argv[2], cfg);
}
return ret;
@ -74,23 +94,23 @@ static int cmd_unregister(const struct shell *sh,
uint8_t cfg;
int ret;
cfg = strtol(argv[2], NULL, 10);
ret = usbd_unregister_class(my_uds_ctx, argv[1], speed, cfg);
cfg = strtol(argv[3], NULL, 10);
ret = usbd_unregister_class(my_uds_ctx, argv[1], current_cmd_speed, cfg);
if (ret) {
shell_error(sh,
"dev: failed to remove USB class %s from configuration %u",
argv[1], cfg);
"dev: failed to remove USB class %s from configuration %s %u",
argv[1], argv[2], cfg);
} else {
shell_print(sh,
"dev: removed USB class %s from configuration %u",
argv[1], cfg);
"dev: removed USB class %s from configuration %s %u",
argv[1], argv[2], cfg);
}
return ret;
}
static int cmd_usbd_magic(const struct shell *sh,
size_t argc, char **argv)
static int cmd_usbd_default_strings(const struct shell *sh,
size_t argc, char **argv)
{
int err;
@ -100,52 +120,49 @@ static int cmd_usbd_magic(const struct shell *sh,
err |= usbd_add_descriptor(my_uds_ctx, &sn);
if (err) {
shell_error(sh, "dev: Failed to initialize descriptors, %d", err);
}
err = usbd_add_configuration(my_uds_ctx, speed, &config_foo);
if (err) {
shell_error(sh, "dev: Failed to add configuration");
}
if (IS_ENABLED(CONFIG_USBD_LOOPBACK_CLASS)) {
err = usbd_register_class(my_uds_ctx, "loopback_0", speed, 1);
if (err) {
shell_error(sh, "dev: Failed to add loopback_0 class");
}
}
ctx_shell = sh;
err = usbd_init(my_uds_ctx);
if (err) {
shell_error(sh, "dev: Failed to initialize device support");
}
err = usbd_enable(my_uds_ctx);
if (err) {
shell_error(sh, "dev: Failed to enable device support");
shell_error(sh, "dev: Failed to add default string descriptors, %d", err);
} else {
shell_print(sh, "dev: added default string descriptors");
}
return err;
}
static int cmd_usbd_defaults(const struct shell *sh,
size_t argc, char **argv)
static int register_classes(const struct shell *sh)
{
int err;
err = usbd_add_descriptor(my_uds_ctx, &lang);
err |= usbd_add_descriptor(my_uds_ctx, &mfr);
err |= usbd_add_descriptor(my_uds_ctx, &product);
err |= usbd_add_descriptor(my_uds_ctx, &sn);
STRUCT_SECTION_FOREACH_ALTERNATE(usbd_class_fs, usbd_class_node, c_nd) {
err = usbd_register_class(my_uds_ctx, c_nd->c_data->name,
USBD_SPEED_FS, 1);
if (err) {
shell_error(sh,
"dev: failed to register FS %s (%d)",
c_nd->c_data->name, err);
return err;
}
if (err) {
shell_error(sh, "dev: Failed to initialize descriptors, %d", err);
} else {
shell_print(sh, "dev: USB descriptors initialized");
shell_print(sh, "dev: register FS %s", c_nd->c_data->name);
}
return err;
if (usbd_caps_speed(my_uds_ctx) != USBD_SPEED_HS) {
return 0;
}
STRUCT_SECTION_FOREACH_ALTERNATE(usbd_class_hs, usbd_class_node, c_nd) {
err = usbd_register_class(my_uds_ctx, c_nd->c_data->name,
USBD_SPEED_HS, 1);
if (err) {
shell_error(sh,
"dev: failed to register HS %s (%d)",
c_nd->c_data->name, err);
return err;
}
shell_print(sh, "dev: register HS %s", c_nd->c_data->name);
}
return 0;
}
static int cmd_usbd_init(const struct shell *sh,
@ -153,13 +170,12 @@ static int cmd_usbd_init(const struct shell *sh,
{
int err;
ctx_shell = sh;
err = usbd_init(my_uds_ctx);
if (err == -EALREADY) {
shell_error(sh, "dev: USB already initialized");
} else if (err) {
shell_error(sh, "dev: Failed to initialize %d", err);
shell_error(sh, "dev: Failed to initialize device support (%d)", err);
} else {
shell_print(sh, "dev: USB initialized");
}
@ -167,6 +183,38 @@ static int cmd_usbd_init(const struct shell *sh,
return err;
}
static int cmd_usbd_default_config(const struct shell *sh,
size_t argc, char **argv)
{
int err;
err = cmd_usbd_default_strings(sh, 0, NULL);
if (err) {
return err;
}
if (usbd_caps_speed(my_uds_ctx) == USBD_SPEED_HS) {
err = usbd_add_configuration(my_uds_ctx, USBD_SPEED_HS, &config_1_hs);
if (err) {
shell_error(sh, "dev: Failed to add HS configuration");
return err;
}
}
err = usbd_add_configuration(my_uds_ctx, USBD_SPEED_FS, &config_1_fs);
if (err) {
shell_error(sh, "dev: Failed to add FS configuration");
return err;
}
err = register_classes(sh);
if (err) {
return err;
}
return cmd_usbd_init(sh, 0, NULL);
}
static int cmd_usbd_enable(const struct shell *sh,
size_t argc, char **argv)
{
@ -243,10 +291,12 @@ static int cmd_device_bcd(const struct shell *sh, size_t argc,
uint16_t bcd;
int ret;
bcd = strtol(argv[1], NULL, 16);
ret = usbd_device_set_bcd(my_uds_ctx, speed, bcd);
bcd = strtol(argv[2], NULL, 16);
ret = usbd_device_set_bcd(my_uds_ctx, current_cmd_speed, bcd);
if (ret) {
shell_error(sh, "dev: failed to set device bcdUSB to %x", bcd);
} else {
shell_error(sh, "dev: set device bcdUSB to %x", bcd);
}
return ret;
@ -288,14 +338,17 @@ static int cmd_device_code_triple(const struct shell *sh, size_t argc,
uint8_t class, subclass, protocol;
int ret;
class = strtol(argv[1], NULL, 16);
subclass = strtol(argv[2], NULL, 16);
protocol = strtol(argv[3], NULL, 16);
ret = usbd_device_set_code_triple(my_uds_ctx, speed,
class = strtol(argv[2], NULL, 16);
subclass = strtol(argv[3], NULL, 16);
protocol = strtol(argv[4], NULL, 16);
ret = usbd_device_set_code_triple(my_uds_ctx, current_cmd_speed,
class, subclass, protocol);
if (ret) {
shell_error(sh, "dev: failed to set device code triple to %x %x %x",
class, subclass, protocol);
} else {
shell_error(sh, "dev: set device code triple to %x %x %x",
class, subclass, protocol);
}
return ret;
@ -304,93 +357,164 @@ static int cmd_device_code_triple(const struct shell *sh, size_t argc,
static int cmd_config_add(const struct shell *sh, size_t argc,
char *argv[])
{
uint8_t cfg;
int ret;
int ret = -EINVAL;
cfg = strtol(argv[1], NULL, 10);
if (cfg == 1) {
ret = usbd_add_configuration(my_uds_ctx, speed, &config_foo);
} else if (cfg == 2) {
ret = usbd_add_configuration(my_uds_ctx, speed, &config_baz);
} else {
shell_error(sh, "dev: Configuration %u not available", cfg);
return -EINVAL;
for (unsigned int i = 0; i < ARRAY_SIZE(sh_configs); i++) {
if (!strcmp(argv[1], sh_configs[i].name)) {
ret = usbd_add_configuration(my_uds_ctx,
sh_configs[i].speed,
sh_configs[i].cfg_nd);
break;
}
}
if (ret) {
shell_error(sh, "dev: failed to add configuration %u", cfg);
shell_error(sh, "dev: failed to add configuration %s", argv[1]);
}
return ret;
}
static int cmd_config_self(const struct shell *sh, size_t argc,
char *argv[])
static int cmd_config_set_selfpowered(const struct shell *sh, const bool self,
size_t argc, char *argv[])
{
bool self;
uint8_t cfg;
int ret;
cfg = strtol(argv[1], NULL, 10);
if (!strcmp(argv[2], "yes")) {
self = true;
} else {
self = false;
}
cfg = strtol(argv[2], NULL, 10);
ret = usbd_config_attrib_self(my_uds_ctx, speed, cfg, self);
ret = usbd_config_attrib_self(my_uds_ctx, current_cmd_speed, cfg, self);
if (ret) {
shell_error(sh,
"dev: failed to set attribute self powered to %u",
"dev: failed to set attribute Self-powered to %u",
cfg);
} else {
shell_print(sh,
"dev: set configuration %u attribute Self-powered to %u",
cfg, self);
}
return ret;
}
static int cmd_config_rwup(const struct shell *sh, size_t argc,
char *argv[])
static int cmd_config_selfpowered(const struct shell *sh,
size_t argc, char *argv[])
{
return cmd_config_set_selfpowered(sh, true, argc, argv);
}
static int cmd_config_buspowered(const struct shell *sh,
size_t argc, char *argv[])
{
return cmd_config_set_selfpowered(sh, false, argc, argv);
}
static int cmd_config_rwup(const struct shell *sh, const bool rwup,
size_t argc, char *argv[])
{
bool rwup;
uint8_t cfg;
int ret;
cfg = strtol(argv[1], NULL, 10);
if (!strcmp(argv[2], "yes")) {
rwup = true;
} else {
rwup = false;
}
cfg = strtol(argv[2], NULL, 10);
ret = usbd_config_attrib_rwup(my_uds_ctx, speed, cfg, rwup);
ret = usbd_config_attrib_rwup(my_uds_ctx, current_cmd_speed, cfg, rwup);
if (ret) {
shell_error(sh,
"dev: failed to set attribute remote wakeup to %x",
cfg);
"dev: failed set configuration %u Remote Wakeup to %u",
cfg, rwup);
} else {
shell_print(sh,
"dev: set configuration %u Remote Wakeup to %u",
cfg, rwup);
}
return ret;
}
static int cmd_config_set_rwup(const struct shell *sh,
size_t argc, char *argv[])
{
return cmd_config_rwup(sh, true, argc, argv);
}
static int cmd_config_clear_rwup(const struct shell *sh,
size_t argc, char *argv[])
{
return cmd_config_rwup(sh, false, argc, argv);
}
static int cmd_config_power(const struct shell *sh, size_t argc,
char *argv[])
{
uint16_t power;
uint8_t cfg;
uint8_t power;
int ret;
cfg = strtol(argv[1], NULL, 10);
power = strtol(argv[1], NULL, 10);
cfg = strtol(argv[2], NULL, 10);
power = strtol(argv[3], NULL, 10);
ret = usbd_config_maxpower(my_uds_ctx, speed, cfg, power);
if (power > UINT8_MAX) {
power = UINT8_MAX;
shell_print(sh, "dev: limit bMaxPower value to %u", power);
}
ret = usbd_config_maxpower(my_uds_ctx, current_cmd_speed, cfg, power);
if (ret) {
shell_error(sh, "dev: failed to set bMaxPower value to %u", cfg);
shell_error(sh,
"dev: failed to set configuration %u bMaxPower value to %u",
cfg, power);
} else {
shell_print(sh,
"dev: set configuration %u bMaxPower value to %u",
cfg, power);
}
return ret;
}
static void configuration_speed(size_t idx, struct shell_static_entry *entry)
{
size_t match_idx = 0;
entry->syntax = NULL;
entry->handler = NULL;
entry->help = NULL;
entry->subcmd = NULL;
for (unsigned int i = 0; i < ARRAY_SIZE(sh_speed); i++) {
if (match_idx == idx) {
entry->syntax = sh_speed[i].name;
current_cmd_speed = sh_speed[i].speed;
break;
}
++match_idx;
}
}
SHELL_DYNAMIC_CMD_CREATE(dsub_config_speed, configuration_speed);
static void configuration_lookup(size_t idx, struct shell_static_entry *entry)
{
size_t match_idx = 0;
entry->syntax = NULL;
entry->handler = NULL;
entry->help = NULL;
entry->subcmd = NULL;
for (unsigned int i = 0; i < ARRAY_SIZE(sh_configs); i++) {
if (match_idx == idx) {
entry->syntax = sh_configs[i].name;
break;
}
++match_idx;
}
}
SHELL_DYNAMIC_CMD_CREATE(dsub_config_name, configuration_lookup);
static void class_node_name_lookup(size_t idx, struct shell_static_entry *entry)
{
size_t match_idx = 0;
@ -398,7 +522,7 @@ static void class_node_name_lookup(size_t idx, struct shell_static_entry *entry)
entry->syntax = NULL;
entry->handler = NULL;
entry->help = NULL;
entry->subcmd = NULL;
entry->subcmd = &dsub_config_speed;
STRUCT_SECTION_FOREACH_ALTERNATE(usbd_class_fs, usbd_class_node, c_nd) {
if ((c_nd->c_data->name != NULL) &&
@ -438,60 +562,87 @@ SHELL_DYNAMIC_CMD_CREATE(dsub_node_name, class_node_name_lookup);
SHELL_DYNAMIC_CMD_CREATE(dsub_context_name, device_context_lookup);
SHELL_STATIC_SUBCMD_SET_CREATE(device_cmds,
SHELL_CMD_ARG(bcd, NULL, "<bcdUSB>",
cmd_device_bcd, 2, 0),
SHELL_CMD_ARG(pid, NULL, "<idProduct>",
SHELL_CMD_ARG(pid, NULL,
"<idProduct> sets device Product ID",
cmd_device_pid, 2, 0),
SHELL_CMD_ARG(vid, NULL, "<idVendor>",
SHELL_CMD_ARG(vid, NULL,
"<idVendor> sets device Vendor ID",
cmd_device_vid, 2, 0),
SHELL_CMD_ARG(triple, NULL, "<bDeviceClass> <bDeviceSubClass> <bDeviceProtocol>",
cmd_device_code_triple, 4, 0),
SHELL_CMD_ARG(bcd, &dsub_config_speed,
"<speed> <bcdUSB> sets device release number",
cmd_device_bcd, 3, 0),
SHELL_CMD_ARG(triple, &dsub_config_speed,
"<speed> <Base Class> <SubClass> <Protocol> sets device code triple",
cmd_device_code_triple, 5, 0),
SHELL_SUBCMD_SET_END
);
SHELL_STATIC_SUBCMD_SET_CREATE(config_cmds,
SHELL_CMD_ARG(add, NULL, "<configuration>",
SHELL_CMD_ARG(add, &dsub_config_name,
"<configuration name> adds one of the pre-defined configurations",
cmd_config_add, 2, 0),
SHELL_CMD_ARG(power, NULL, "<configuration> <bMaxPower>",
cmd_config_power, 3, 0),
SHELL_CMD_ARG(rwup, NULL, "<configuration> <yes, no>",
cmd_config_rwup, 3, 0),
SHELL_CMD_ARG(self, NULL, "<configuration> <yes, no>",
cmd_config_self, 3, 0),
SHELL_CMD_ARG(power, &dsub_config_speed,
"<speed> <configuration value> <bMaxPower> sets the bMaxPower",
cmd_config_power, 4, 0),
SHELL_CMD_ARG(set-rwup, &dsub_config_speed,
"<speed> <configuration value> sets Remote Wakeup bit",
cmd_config_set_rwup, 3, 0),
SHELL_CMD_ARG(clear-rwup, &dsub_config_speed,
"<speed> <configuration value> clears Remote Wakeup bit",
cmd_config_clear_rwup, 3, 0),
SHELL_CMD_ARG(selfpowered, &dsub_config_speed,
"<speed> <configuration value> sets Self-power bit",
cmd_config_selfpowered, 3, 0),
SHELL_CMD_ARG(buspowered, &dsub_config_speed,
"<speed> <configuration value> clears Self-power bit",
cmd_config_buspowered, 3, 0),
SHELL_SUBCMD_SET_END
);
SHELL_STATIC_SUBCMD_SET_CREATE(class_cmds,
SHELL_CMD_ARG(add, &dsub_node_name, "<name> <configuration>",
cmd_register, 3, 0),
SHELL_CMD_ARG(remove, &dsub_node_name, "<name> <configuration>",
cmd_unregister, 3, 0),
SHELL_CMD_ARG(register, &dsub_node_name,
"<name> <speed> <configuration value> registers class instance",
cmd_register, 4, 0),
SHELL_CMD_ARG(unregister, &dsub_node_name,
"<name> <speed> <configuration value> unregisters class instance",
cmd_unregister, 4, 0),
SHELL_SUBCMD_SET_END
);
SHELL_STATIC_SUBCMD_SET_CREATE(sub_usbd_cmds,
SHELL_CMD_ARG(wakeup, NULL, "[none]",
cmd_wakeup_request, 1, 0),
SHELL_CMD_ARG(magic, NULL, "[none]",
cmd_usbd_magic, 1, 0),
SHELL_CMD_ARG(defaults, NULL, "[none]",
cmd_usbd_defaults, 1, 0),
SHELL_CMD_ARG(init, NULL, "[none]",
SHELL_CMD_ARG(defstr, NULL,
"[none] adds default string descriptors",
cmd_usbd_default_strings, 1, 0),
SHELL_CMD_ARG(defcfg, NULL,
"[none] initializes default configuration with all available classes",
cmd_usbd_default_config, 1, 0),
SHELL_CMD_ARG(init, NULL,
"[none] initializes USB device support",
cmd_usbd_init, 1, 0),
SHELL_CMD_ARG(enable, NULL, "[none]",
SHELL_CMD_ARG(enable, NULL,
"[none] enables USB device support]",
cmd_usbd_enable, 1, 0),
SHELL_CMD_ARG(disable, NULL, "[none]",
SHELL_CMD_ARG(disable, NULL,
"[none] disables USB device support",
cmd_usbd_disable, 1, 0),
SHELL_CMD_ARG(shutdown, NULL, "[none]",
SHELL_CMD_ARG(shutdown, NULL,
"[none] shutdown USB device support",
cmd_usbd_shutdown, 1, 0),
SHELL_CMD_ARG(select, &dsub_context_name, "<USB device context name>",
SHELL_CMD_ARG(select, &dsub_context_name,
"<USB device context name> selects context used by the shell",
cmd_select, 2, 0),
SHELL_CMD_ARG(device, &device_cmds, "device commands",
SHELL_CMD_ARG(device, &device_cmds,
"device commands",
NULL, 1, 0),
SHELL_CMD_ARG(config, &config_cmds, "configuration commands",
SHELL_CMD_ARG(config, &config_cmds,
"configuration commands",
NULL, 1, 0),
SHELL_CMD_ARG(class, &class_cmds, "class commands",
SHELL_CMD_ARG(class, &class_cmds,
"class commands",
NULL, 1, 0),
SHELL_CMD_ARG(wakeup, NULL,
"[none] signals remote wakeup",
cmd_wakeup_request, 1, 0),
SHELL_SUBCMD_SET_END
);