650 lines
15 KiB
C
650 lines
15 KiB
C
/*
|
|
* Copyright (c) 2022 Nordic Semiconductor ASA
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <zephyr/sys/util.h>
|
|
#include <zephyr/shell/shell.h>
|
|
#include <zephyr/sys/byteorder.h>
|
|
#include <zephyr/usb/usbh.h>
|
|
|
|
#include "usbh_internal.h"
|
|
#include "usbh_ch9.h"
|
|
|
|
#include <zephyr/logging/log.h>
|
|
LOG_MODULE_REGISTER(usbh_shell, CONFIG_USBH_LOG_LEVEL);
|
|
|
|
#define FOOBAZ_VREQ_OUT 0x5b
|
|
#define FOOBAZ_VREQ_IN 0x5c
|
|
|
|
USBH_CONTROLLER_DEFINE(uhs_ctx, DEVICE_DT_GET(DT_NODELABEL(zephyr_uhc0)));
|
|
|
|
const static struct shell *ctx_shell;
|
|
|
|
static void print_dev_desc(const struct shell *sh,
|
|
const struct usb_device_descriptor *const desc)
|
|
{
|
|
shell_print(sh, "bLength\t\t\t%u", desc->bLength);
|
|
shell_print(sh, "bDescriptorType\t\t%u", desc->bDescriptorType);
|
|
shell_print(sh, "bcdUSB\t\t\t%x", desc->bcdUSB);
|
|
shell_print(sh, "bDeviceClass\t\t%u", desc->bDeviceClass);
|
|
shell_print(sh, "bDeviceSubClass\t\t%u", desc->bDeviceSubClass);
|
|
shell_print(sh, "bDeviceProtocol\t\t%u", desc->bDeviceProtocol);
|
|
shell_print(sh, "bMaxPacketSize0\t\t%u", desc->bMaxPacketSize0);
|
|
shell_print(sh, "idVendor\t\t%x", desc->idVendor);
|
|
shell_print(sh, "idProduct\t\t%x", desc->idProduct);
|
|
shell_print(sh, "bcdDevice\t\t%x", desc->bcdDevice);
|
|
shell_print(sh, "iManufacturer\t\t%u", desc->iManufacturer);
|
|
shell_print(sh, "iProduct\t\t%u", desc->iProduct);
|
|
shell_print(sh, "iSerial\t\t\t%u", desc->iSerialNumber);
|
|
shell_print(sh, "bNumConfigurations\t%u", desc->bNumConfigurations);
|
|
}
|
|
|
|
static void print_cfg_desc(const struct shell *sh,
|
|
const struct usb_cfg_descriptor *const desc)
|
|
{
|
|
shell_print(sh, "bLength\t\t\t%u", desc->bLength);
|
|
shell_print(sh, "bDescriptorType\t\t%u", desc->bDescriptorType);
|
|
shell_print(sh, "wTotalLength\t\t%x", desc->wTotalLength);
|
|
shell_print(sh, "bNumInterfaces\t\t%u", desc->bNumInterfaces);
|
|
shell_print(sh, "bConfigurationValue\t%u", desc->bConfigurationValue);
|
|
shell_print(sh, "iConfiguration\t\t%u", desc->iConfiguration);
|
|
shell_print(sh, "bmAttributes\t\t%02x", desc->bmAttributes);
|
|
shell_print(sh, "bMaxPower\t\t%u mA", desc->bMaxPower * 2);
|
|
}
|
|
|
|
static void print_desc(const struct shell *sh, const struct net_buf *const buf)
|
|
{
|
|
struct usb_desc_header *head = (void *)buf->data;
|
|
|
|
if (buf->len < sizeof(struct usb_desc_header)) {
|
|
return;
|
|
}
|
|
|
|
switch (head->bDescriptorType) {
|
|
case USB_DESC_DEVICE: {
|
|
struct usb_device_descriptor *desc = (void *)buf->data;
|
|
|
|
if (buf->len < sizeof(struct usb_device_descriptor)) {
|
|
shell_hexdump(ctx_shell, buf->data, buf->len);
|
|
break;
|
|
}
|
|
|
|
desc->bcdUSB = sys_le16_to_cpu(desc->bcdUSB);
|
|
desc->idVendor = sys_le16_to_cpu(desc->idVendor);
|
|
desc->idProduct = sys_le16_to_cpu(desc->idProduct);
|
|
desc->bcdDevice = sys_le16_to_cpu(desc->bcdDevice);
|
|
print_dev_desc(sh, desc);
|
|
break;
|
|
}
|
|
case USB_DESC_CONFIGURATION: {
|
|
struct usb_cfg_descriptor *desc = (void *)buf->data;
|
|
|
|
if (buf->len < sizeof(struct usb_cfg_descriptor)) {
|
|
shell_hexdump(ctx_shell, buf->data, buf->len);
|
|
break;
|
|
}
|
|
|
|
desc->wTotalLength = sys_le16_to_cpu(desc->wTotalLength);
|
|
print_cfg_desc(sh, desc);
|
|
break;
|
|
}
|
|
default:
|
|
shell_hexdump(ctx_shell, buf->data, buf->len);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int bazfoo_request(struct usbh_contex *const ctx,
|
|
struct uhc_transfer *const xfer,
|
|
int err)
|
|
{
|
|
const struct device *dev = ctx->dev;
|
|
|
|
shell_info(ctx_shell, "host: transfer finished %p, err %d", xfer, err);
|
|
|
|
while (!k_fifo_is_empty(&xfer->done)) {
|
|
struct net_buf *buf;
|
|
|
|
buf = net_buf_get(&xfer->done, K_NO_WAIT);
|
|
if (buf) {
|
|
/*
|
|
* FIXME: We don not distinguish the context
|
|
* of the request and always try to print it
|
|
* as descriptor first. If it is not a known descriptor,
|
|
* we show a hexdump in any case.
|
|
* This is just simple enough for first steps and will
|
|
* be revised with coming peripheral device management.
|
|
*/
|
|
if (xfer->ep == USB_CONTROL_EP_IN) {
|
|
print_desc(ctx_shell, buf);
|
|
} else {
|
|
shell_hexdump(ctx_shell, buf->data, buf->len);
|
|
}
|
|
|
|
uhc_xfer_buf_free(dev, buf);
|
|
}
|
|
}
|
|
|
|
return uhc_xfer_free(dev, xfer);
|
|
}
|
|
|
|
static int bazfoo_connected(struct usbh_contex *const ctx)
|
|
{
|
|
shell_info(ctx_shell, "host: USB device connected");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int bazfoo_removed(struct usbh_contex *const ctx)
|
|
{
|
|
shell_info(ctx_shell, "host: USB device removed");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int bazfoo_rwup(struct usbh_contex *const ctx)
|
|
{
|
|
shell_info(ctx_shell, "host: Bus remote wakeup event");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int bazfoo_suspended(struct usbh_contex *const ctx)
|
|
{
|
|
shell_info(ctx_shell, "host: Bus suspended");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int bazfoo_resumed(struct usbh_contex *const ctx)
|
|
{
|
|
shell_info(ctx_shell, "host: Bus resumed");
|
|
|
|
return 0;
|
|
}
|
|
|
|
USBH_DEFINE_CLASS(bazfoo) = {
|
|
.request = bazfoo_request,
|
|
.connected = bazfoo_connected,
|
|
.removed = bazfoo_removed,
|
|
.rwup = bazfoo_rwup,
|
|
.suspended = bazfoo_suspended,
|
|
.resumed = bazfoo_resumed,
|
|
};
|
|
|
|
static uint8_t vreq_test_buf[1024];
|
|
|
|
static int cmd_bulk(const struct shell *sh, size_t argc, char **argv)
|
|
{
|
|
struct uhc_transfer *xfer;
|
|
struct net_buf *buf;
|
|
uint8_t addr;
|
|
uint8_t ep;
|
|
size_t len;
|
|
|
|
addr = strtol(argv[1], NULL, 10);
|
|
ep = strtol(argv[2], NULL, 16);
|
|
len = MIN(sizeof(vreq_test_buf), strtol(argv[3], NULL, 10));
|
|
|
|
xfer = uhc_xfer_alloc(uhs_ctx.dev, addr, ep, 0, 512, 10, NULL);
|
|
if (!xfer) {
|
|
return -ENOMEM;
|
|
}
|
|
|
|
buf = uhc_xfer_buf_alloc(uhs_ctx.dev, xfer, len);
|
|
if (!buf) {
|
|
return -ENOMEM;
|
|
}
|
|
|
|
if (USB_EP_DIR_IS_OUT(ep)) {
|
|
net_buf_add_mem(buf, vreq_test_buf, len);
|
|
}
|
|
|
|
return uhc_ep_enqueue(uhs_ctx.dev, xfer);
|
|
}
|
|
|
|
static int cmd_vendor_in(const struct shell *sh,
|
|
size_t argc, char **argv)
|
|
{
|
|
const uint8_t bmRequestType = (USB_REQTYPE_DIR_TO_HOST << 7) |
|
|
(USB_REQTYPE_TYPE_VENDOR << 5);
|
|
const uint8_t bRequest = FOOBAZ_VREQ_IN;
|
|
const uint16_t wValue = 0x0000;
|
|
uint16_t wLength;
|
|
uint8_t addr;
|
|
|
|
addr = strtol(argv[1], NULL, 10);
|
|
wLength = MIN(sizeof(vreq_test_buf), strtol(argv[2], NULL, 10));
|
|
|
|
return usbh_req_setup(uhs_ctx.dev, addr,
|
|
bmRequestType, bRequest, wValue, 0, wLength,
|
|
NULL);
|
|
}
|
|
|
|
static int cmd_vendor_out(const struct shell *sh,
|
|
size_t argc, char **argv)
|
|
{
|
|
const uint8_t bmRequestType = (USB_REQTYPE_DIR_TO_DEVICE << 7) |
|
|
(USB_REQTYPE_TYPE_VENDOR << 5);
|
|
const uint8_t bRequest = FOOBAZ_VREQ_OUT;
|
|
const uint16_t wValue = 0x0000;
|
|
uint16_t wLength;
|
|
uint8_t addr;
|
|
|
|
addr = strtol(argv[1], NULL, 10);
|
|
wLength = MIN(sizeof(vreq_test_buf), strtol(argv[2], NULL, 10));
|
|
|
|
for (int i = 0; i < wLength; i++) {
|
|
vreq_test_buf[i] = i;
|
|
}
|
|
|
|
return usbh_req_setup(uhs_ctx.dev, addr,
|
|
bmRequestType, bRequest, wValue, 0, wLength,
|
|
vreq_test_buf);
|
|
}
|
|
|
|
static int cmd_desc_device(const struct shell *sh,
|
|
size_t argc, char **argv)
|
|
{
|
|
uint8_t addr;
|
|
int err;
|
|
|
|
addr = strtol(argv[1], NULL, 10);
|
|
|
|
err = usbh_req_desc_dev(uhs_ctx.dev, addr);
|
|
if (err) {
|
|
shell_print(sh, "host: Failed to request device descriptor");
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static int cmd_desc_config(const struct shell *sh,
|
|
size_t argc, char **argv)
|
|
{
|
|
uint8_t addr;
|
|
uint8_t cfg;
|
|
int err;
|
|
|
|
addr = strtol(argv[1], NULL, 10);
|
|
cfg = strtol(argv[2], NULL, 10);
|
|
|
|
/* TODO: cfg is ignored, add to usbh_req_desc_cfg */
|
|
err = usbh_req_desc_cfg(uhs_ctx.dev, addr, cfg, 128);
|
|
if (err) {
|
|
shell_print(sh, "host: Failed to request configuration descriptor");
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static int cmd_desc_string(const struct shell *sh,
|
|
size_t argc, char **argv)
|
|
{
|
|
const uint8_t type = USB_DESC_STRING;
|
|
uint8_t addr;
|
|
uint8_t id;
|
|
uint8_t idx;
|
|
int err;
|
|
|
|
addr = strtol(argv[1], NULL, 10);
|
|
id = strtol(argv[2], NULL, 10);
|
|
idx = strtol(argv[3], NULL, 10);
|
|
|
|
err = usbh_req_desc(uhs_ctx.dev, addr, type, idx, id, 128);
|
|
if (err) {
|
|
shell_print(sh, "host: Failed to request configuration descriptor");
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static int cmd_feature_set_halt(const struct shell *sh,
|
|
size_t argc, char **argv)
|
|
{
|
|
uint8_t addr;
|
|
uint8_t ep;
|
|
int err;
|
|
|
|
addr = strtol(argv[1], NULL, 10);
|
|
ep = strtol(argv[2], NULL, 16);
|
|
|
|
/* TODO: add usbh_req_set_sfs_halt(uhs_ctx.dev, 0); */
|
|
err = usbh_req_set_sfs_rwup(uhs_ctx.dev, addr);
|
|
if (err) {
|
|
shell_error(sh, "host: Failed to set halt feature");
|
|
} else {
|
|
shell_print(sh, "host: Device 0x%02x, ep 0x%02x halt feature set",
|
|
addr, ep);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static int cmd_feature_clear_rwup(const struct shell *sh,
|
|
size_t argc, char **argv)
|
|
{
|
|
uint8_t addr;
|
|
int err;
|
|
|
|
addr = strtol(argv[1], NULL, 10);
|
|
|
|
err = usbh_req_clear_sfs_rwup(uhs_ctx.dev, addr);
|
|
if (err) {
|
|
shell_error(sh, "host: Failed to clear rwup feature");
|
|
} else {
|
|
shell_print(sh, "host: Device 0x%02x, rwup feature cleared", addr);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static int cmd_feature_set_rwup(const struct shell *sh,
|
|
size_t argc, char **argv)
|
|
{
|
|
uint8_t addr;
|
|
int err;
|
|
|
|
addr = strtol(argv[1], NULL, 10);
|
|
|
|
err = usbh_req_set_sfs_rwup(uhs_ctx.dev, addr);
|
|
if (err) {
|
|
shell_error(sh, "host: Failed to set rwup feature");
|
|
} else {
|
|
shell_print(sh, "host: Device 0x%02x, rwup feature set", addr);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static int cmd_feature_set_ppwr(const struct shell *sh,
|
|
size_t argc, char **argv)
|
|
{
|
|
uint8_t addr;
|
|
uint8_t port;
|
|
int err;
|
|
|
|
addr = strtol(argv[1], NULL, 10);
|
|
port = strtol(argv[2], NULL, 10);
|
|
|
|
err = usbh_req_set_hcfs_ppwr(uhs_ctx.dev, addr, port);
|
|
if (err) {
|
|
shell_error(sh, "host: Failed to set ppwr feature");
|
|
} else {
|
|
shell_print(sh, "host: Device 0x%02x, port %d, ppwr feature set",
|
|
addr, port);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static int cmd_feature_set_prst(const struct shell *sh,
|
|
size_t argc, char **argv)
|
|
{
|
|
uint8_t addr;
|
|
uint8_t port;
|
|
int err;
|
|
|
|
addr = strtol(argv[1], NULL, 10);
|
|
port = strtol(argv[2], NULL, 10);
|
|
|
|
err = usbh_req_set_hcfs_prst(uhs_ctx.dev, addr, port);
|
|
if (err) {
|
|
shell_error(sh, "host: Failed to set prst feature");
|
|
} else {
|
|
shell_print(sh, "host: Device 0x%02x, port %d, prst feature set",
|
|
addr, port);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static int cmd_device_config(const struct shell *sh,
|
|
size_t argc, char **argv)
|
|
{
|
|
uint8_t addr;
|
|
uint8_t cfg;
|
|
int err;
|
|
|
|
addr = strtol(argv[1], NULL, 10);
|
|
cfg = strtol(argv[2], NULL, 10);
|
|
|
|
err = usbh_req_set_cfg(uhs_ctx.dev, addr, cfg);
|
|
if (err) {
|
|
shell_error(sh, "host: Failed to set configuration");
|
|
} else {
|
|
shell_print(sh, "host: Device 0x%02x, new configuration %u",
|
|
addr, cfg);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static int cmd_device_interface(const struct shell *sh,
|
|
size_t argc, char **argv)
|
|
{
|
|
uint8_t addr;
|
|
uint8_t iface;
|
|
uint8_t alt;
|
|
int err;
|
|
|
|
addr = strtol(argv[1], NULL, 10);
|
|
iface = strtol(argv[2], NULL, 10);
|
|
alt = strtol(argv[3], NULL, 10);
|
|
|
|
err = usbh_req_set_alt(uhs_ctx.dev, addr, iface, alt);
|
|
if (err) {
|
|
shell_error(sh, "host: Failed to set interface alternate");
|
|
} else {
|
|
shell_print(sh, "host: Device 0x%02x, new %u alternate %u",
|
|
addr, iface, alt);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static int cmd_device_address(const struct shell *sh,
|
|
size_t argc, char **argv)
|
|
{
|
|
uint8_t addr;
|
|
int err;
|
|
|
|
addr = strtol(argv[1], NULL, 10);
|
|
|
|
err = usbh_req_set_address(uhs_ctx.dev, 0, addr);
|
|
if (err) {
|
|
shell_error(sh, "host: Failed to set address");
|
|
} else {
|
|
shell_print(sh, "host: New device address is 0x%02x", addr);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static int cmd_bus_suspend(const struct shell *sh,
|
|
size_t argc, char **argv)
|
|
{
|
|
int err;
|
|
|
|
err = uhc_bus_suspend(uhs_ctx.dev);
|
|
if (err) {
|
|
shell_error(sh, "host: Failed to perform bus suspend %d", err);
|
|
} else {
|
|
shell_print(sh, "host: USB bus suspended");
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static int cmd_bus_resume(const struct shell *sh,
|
|
size_t argc, char **argv)
|
|
{
|
|
int err;
|
|
|
|
err = uhc_bus_resume(uhs_ctx.dev);
|
|
if (err) {
|
|
shell_error(sh, "host: Failed to perform bus resume %d", err);
|
|
} else {
|
|
shell_print(sh, "host: USB bus resumed");
|
|
}
|
|
|
|
err = uhc_sof_enable(uhs_ctx.dev);
|
|
if (err) {
|
|
shell_error(sh, "host: Failed to start SoF generator %d", err);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static int cmd_bus_reset(const struct shell *sh,
|
|
size_t argc, char **argv)
|
|
{
|
|
int err;
|
|
|
|
err = uhc_bus_reset(uhs_ctx.dev);
|
|
if (err) {
|
|
shell_error(sh, "host: Failed to perform bus reset %d", err);
|
|
} else {
|
|
shell_print(sh, "host: USB bus reset");
|
|
}
|
|
|
|
err = uhc_sof_enable(uhs_ctx.dev);
|
|
if (err) {
|
|
shell_error(sh, "host: Failed to start SoF generator %d", err);
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static int cmd_usbh_init(const struct shell *sh,
|
|
size_t argc, char **argv)
|
|
{
|
|
int err;
|
|
|
|
ctx_shell = sh;
|
|
|
|
err = usbh_init(&uhs_ctx);
|
|
if (err == -EALREADY) {
|
|
shell_error(sh, "host: USB host already initialized");
|
|
} else if (err) {
|
|
shell_error(sh, "host: Failed to initialize %d", err);
|
|
} else {
|
|
shell_print(sh, "host: USB host initialized");
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static int cmd_usbh_enable(const struct shell *sh,
|
|
size_t argc, char **argv)
|
|
{
|
|
int err;
|
|
|
|
err = usbh_enable(&uhs_ctx);
|
|
if (err) {
|
|
shell_error(sh, "host: Failed to enable USB host support");
|
|
} else {
|
|
shell_print(sh, "host: USB host enabled");
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
static int cmd_usbh_disable(const struct shell *sh,
|
|
size_t argc, char **argv)
|
|
{
|
|
int err;
|
|
|
|
err = usbh_disable(&uhs_ctx);
|
|
if (err) {
|
|
shell_error(sh, "host: Failed to disable USB host support");
|
|
} else {
|
|
shell_print(sh, "host: USB host disabled");
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
SHELL_STATIC_SUBCMD_SET_CREATE(desc_cmds,
|
|
SHELL_CMD_ARG(device, NULL, "<address>",
|
|
cmd_desc_device, 2, 0),
|
|
SHELL_CMD_ARG(configuration, NULL, "<address> <index>",
|
|
cmd_desc_config, 3, 0),
|
|
SHELL_CMD_ARG(string, NULL, "<address> <id> <index>",
|
|
cmd_desc_string, 4, 0),
|
|
SHELL_SUBCMD_SET_END
|
|
);
|
|
|
|
SHELL_STATIC_SUBCMD_SET_CREATE(feature_set_cmds,
|
|
SHELL_CMD_ARG(rwup, NULL, "<address>",
|
|
cmd_feature_set_rwup, 2, 0),
|
|
SHELL_CMD_ARG(ppwr, NULL, "<address> <port>",
|
|
cmd_feature_set_ppwr, 3, 0),
|
|
SHELL_CMD_ARG(prst, NULL, "<address> <port>",
|
|
cmd_feature_set_prst, 3, 0),
|
|
SHELL_CMD_ARG(halt, NULL, "<address> <endpoint>",
|
|
cmd_feature_set_halt, 3, 0),
|
|
SHELL_SUBCMD_SET_END
|
|
);
|
|
|
|
SHELL_STATIC_SUBCMD_SET_CREATE(feature_clear_cmds,
|
|
SHELL_CMD_ARG(rwup, NULL, "<address>",
|
|
cmd_feature_clear_rwup, 2, 0),
|
|
SHELL_CMD_ARG(halt, NULL, "<address> <endpoint>",
|
|
cmd_feature_set_halt, 3, 0),
|
|
SHELL_SUBCMD_SET_END
|
|
);
|
|
|
|
SHELL_STATIC_SUBCMD_SET_CREATE(device_cmds,
|
|
SHELL_CMD_ARG(address, NULL, "<address>",
|
|
cmd_device_address, 2, 0),
|
|
SHELL_CMD_ARG(config, NULL, "<address> <config>",
|
|
cmd_device_config, 3, 0),
|
|
SHELL_CMD_ARG(interface, NULL, "<address> <interface> <alternate>",
|
|
cmd_device_interface, 4, 0),
|
|
SHELL_CMD_ARG(descriptor, &desc_cmds, "descriptor request",
|
|
NULL, 1, 0),
|
|
SHELL_CMD_ARG(feature-set, &feature_set_cmds, "feature selector",
|
|
NULL, 1, 0),
|
|
SHELL_CMD_ARG(feature-clear, &feature_clear_cmds, "feature selector",
|
|
NULL, 1, 0),
|
|
SHELL_CMD_ARG(vendor_in, NULL, "<address> <length>",
|
|
cmd_vendor_in, 3, 0),
|
|
SHELL_CMD_ARG(vendor_out, NULL, "<address> <length>",
|
|
cmd_vendor_out, 3, 0),
|
|
SHELL_CMD_ARG(bulk, NULL, "<address> <endpoint> <length>",
|
|
cmd_bulk, 4, 0),
|
|
SHELL_SUBCMD_SET_END
|
|
);
|
|
|
|
SHELL_STATIC_SUBCMD_SET_CREATE(bus_cmds,
|
|
SHELL_CMD_ARG(suspend, NULL, "[nono]",
|
|
cmd_bus_suspend, 1, 0),
|
|
SHELL_CMD_ARG(resume, NULL, "[nono]",
|
|
cmd_bus_resume, 1, 0),
|
|
SHELL_CMD_ARG(reset, NULL, "[nono]",
|
|
cmd_bus_reset, 1, 0),
|
|
SHELL_SUBCMD_SET_END
|
|
);
|
|
|
|
SHELL_STATIC_SUBCMD_SET_CREATE(sub_usbh_cmds,
|
|
SHELL_CMD_ARG(init, NULL, "[none]",
|
|
cmd_usbh_init, 1, 0),
|
|
SHELL_CMD_ARG(enable, NULL, "[none]",
|
|
cmd_usbh_enable, 1, 0),
|
|
SHELL_CMD_ARG(disable, NULL, "[none]",
|
|
cmd_usbh_disable, 1, 0),
|
|
SHELL_CMD_ARG(bus, &bus_cmds, "bus commands",
|
|
NULL, 1, 0),
|
|
SHELL_CMD_ARG(device, &device_cmds, "device commands",
|
|
NULL, 1, 0),
|
|
SHELL_SUBCMD_SET_END
|
|
);
|
|
|
|
SHELL_CMD_REGISTER(usbh, &sub_usbh_cmds, "USBH commands", NULL);
|