Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 113 additions & 2 deletions include/zephyr/usb/usbd.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@
*/
#define USB_STRING_DESCRIPTOR_LENGTH(s) (sizeof(s) * 2)

struct usbd_context;

/** Used internally to keep descriptors in order
* @cond INTERNAL_HIDDEN
*/
Expand All @@ -72,6 +74,7 @@

enum usbd_bos_desc_utype {
USBD_DUT_BOS_NONE,
USBD_DUT_BOS_VREQ,
};
/** @endcond */

Expand All @@ -89,12 +92,63 @@
unsigned int use_hwinfo : 1;
};

/**
* USBD vendor request node
*
* Vendor request node is identified by the vendor code and is used to register
* callbacks to handle the vendor request with the receiving device.
* When the device stack receives a request with type Vendor and recipient
* Device, and bRequest value equal to the vendor request code, it will call
* the vendor callbacks depending on the direction of the request.
*
* Example callback code fragment:
*
* @code{.c}
* static int foo_to_host_cb(const struct usbd_context *const ctx,
* const struct usb_setup_packet *const setup,
* struct net_buf *const buf)
* {
* if (setup->wIndex == WEBUSB_REQ_GET_URL) {
* uint8_t index = USB_GET_DESCRIPTOR_INDEX(setup->wValue);
*
* if (index != SAMPLE_WEBUSB_LANDING_PAGE) {
* return -ENOTSUP;
* }
*
* net_buf_add_mem(buf, &webusb_origin_url,
* MIN(net_buf_tailroom(buf), sizeof(webusb_origin_url)));
*
* return 0;
* }
*
* return -ENOTSUP;
* }
* @endcode
*/
struct usbd_vreq_node {
/** Node information for the dlist */
sys_dnode_t node;
/** Vendor code (bRequest value) */
const uint8_t code;
/** Vendor request callback for device-to-host direction */
int (*to_host)(const struct usbd_context *const ctx,
const struct usb_setup_packet *const setup,
struct net_buf *const buf);
/** Vendor request callback for host-to-device direction */
int (*to_dev)(const struct usbd_context *const ctx,
const struct usb_setup_packet *const setup,
const struct net_buf *const buf);
};

Check notice on line 142 in include/zephyr/usb/usbd.h

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

include/zephyr/usb/usbd.h:142 - const struct usb_setup_packet *const setup, - struct net_buf *const buf); + const struct usb_setup_packet *const setup, struct net_buf *const buf); /** Vendor request callback for host-to-device direction */ int (*to_dev)(const struct usbd_context *const ctx, - const struct usb_setup_packet *const setup, - const struct net_buf *const buf); + const struct usb_setup_packet *const setup, const struct net_buf *const buf);
/**
* USBD BOS Device Capability descriptor data
*/
struct usbd_bos_desc_data {
/** Descriptor usage type (not bDescriptorType) */
enum usbd_bos_desc_utype utype : 8;
union {
struct usbd_vreq_node *const vreq_nd;
};
};

/**
Expand Down Expand Up @@ -199,8 +253,6 @@
enum usbd_speed speed : 2;
};

struct usbd_context;

/**
* @brief Callback type definition for USB device message delivery
*
Expand Down Expand Up @@ -238,6 +290,8 @@
sys_slist_t fs_configs;
/** slist to manage High-Speed device configurations */
sys_slist_t hs_configs;
/** dlist to manage vendor requests with recipient device */
sys_dlist_t vreqs;
/** Status of the USB device support */
struct usbd_status status;
/** Pointer to Full-Speed device descriptor */
Expand Down Expand Up @@ -597,6 +651,49 @@
.bDescriptorType = USB_DESC_BOS, \
}

/**
* @brief Define a vendor request with recipient device
*
* @param name Vendor request identifier
* @param vcode Vendor request code
* @param vto_host Vendor callback for to-host direction request
* @param vto_dev Vendor callback for to-device direction request
*/
#define USBD_VREQUEST_DEFINE(name, vcode, vto_host, vto_dev) \
static struct usbd_vreq_node name = { \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer some prefix on the node, e.g.

Suggested change
static struct usbd_vreq_node name = { \
static struct usbd_vreq_node usbd_vreq_node_##name = { \

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then the user does not know the real structure name. This makes sense for more abstract macros, but not here.

.code = vcode, \
.to_host = vto_host, \
.to_dev = vto_dev, \
}

/**
* @brief Define BOS Device Capability descriptor node with vendor request
*
* This macro defines a BOS descriptor, usually a platform capability, with a
* vendor request node.
*
* USBD_DESC_BOS_VREQ_DEFINE(bos_vreq_webusb, sizeof(bos_cap_webusb), &bos_cap_webusb,
* SAMPLE_WEBUSB_VENDOR_CODE, webusb_to_host_cb, NULL);
*
* @param name Descriptor node identifier
* @param len Device Capability descriptor length
* @param subset Pointer to a Device Capability descriptor
* @param vcode Vendor request code
* @param vto_host Vendor callback for to-host direction request
* @param vto_dev Vendor callback for to-device direction request
*/
#define USBD_DESC_BOS_VREQ_DEFINE(name, len, subset, vcode, vto_host, vto_dev) \
USBD_VREQUEST_DEFINE(vreq_nd_##name, vcode, vto_host, vto_dev); \

Check notice on line 686 in include/zephyr/usb/usbd.h

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

include/zephyr/usb/usbd.h:686 -#define USBD_VREQUEST_DEFINE(name, vcode, vto_host, vto_dev) \ - static struct usbd_vreq_node name = { \ - .code = vcode, \ - .to_host = vto_host, \ - .to_dev = vto_dev, \ +#define USBD_VREQUEST_DEFINE(name, vcode, vto_host, vto_dev) \ + static struct usbd_vreq_node name = { \ + .code = vcode, \ + .to_host = vto_host, \ + .to_dev = vto_dev, \
static struct usbd_desc_node name = { \
.bos = { \
.utype = USBD_DUT_BOS_VREQ, \
.vreq_nd = &vreq_nd_##name, \
}, \
.ptr = subset, \
.bLength = len, \
.bDescriptorType = USB_DESC_BOS, \
}

/**
* @brief Define USB device support class data
*
Expand All @@ -614,7 +711,7 @@
.api = class_api, \
.v_reqs = class_v_reqs, \
.priv = class_priv, \
}; \

Check notice on line 714 in include/zephyr/usb/usbd.h

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

include/zephyr/usb/usbd.h:714 -#define USBD_DESC_BOS_VREQ_DEFINE(name, len, subset, vcode, vto_host, vto_dev) \ - USBD_VREQUEST_DEFINE(vreq_nd_##name, vcode, vto_host, vto_dev); \ - static struct usbd_desc_node name = { \ - .bos = { \ - .utype = USBD_DUT_BOS_VREQ, \ - .vreq_nd = &vreq_nd_##name, \ - }, \ - .ptr = subset, \ - .bLength = len, \ - .bDescriptorType = USB_DESC_BOS, \ +#define USBD_DESC_BOS_VREQ_DEFINE(name, len, subset, vcode, vto_host, vto_dev) \ + USBD_VREQUEST_DEFINE(vreq_nd_##name, vcode, vto_host, vto_dev); \ + static struct usbd_desc_node name = { \ + .bos = \ + { \ + .utype = USBD_DUT_BOS_VREQ, \ + .vreq_nd = &vreq_nd_##name, \ + }, \ + .ptr = subset, \ + .bLength = len, \ + .bDescriptorType = USB_DESC_BOS, \
static STRUCT_SECTION_ITERABLE_ALTERNATE( \
usbd_class_fs, usbd_class_node, class_name##_fs) = { \
.c_data = &class_name, \
Expand Down Expand Up @@ -1056,6 +1153,20 @@
*/
bool usbd_can_detect_vbus(struct usbd_context *const uds_ctx);

/**
* @brief Register an USB vendor request with recipient device
*
* The vendor request with the recipient device applies to all configurations
* within the device.
*
* @param[in] uds_ctx Pointer to USB device support context
* @param[in] vreq_nd Pointer to vendor request node
*
* @return 0 on success, other values on fail.
*/
int usbd_device_register_vreq(struct usbd_context *const uds_ctx,
struct usbd_vreq_node *const vreq_nd);

/**
* @}
*/
Expand Down
7 changes: 7 additions & 0 deletions samples/subsys/usb/common/sample_usbd.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,11 @@
*/
struct usbd_context *sample_usbd_init_device(usbd_msg_cb_t msg_cb);

/*
* This function is similar to sample_usbd_init_device(), but does not
* initialize the device. It allows the application to set additional features,
* such as additional descriptors.
*/
struct usbd_context *sample_usbd_setup_device(usbd_msg_cb_t msg_cb);

#endif /* ZEPHYR_SAMPLES_SUBSYS_USB_COMMON_SAMPLE_USBD_H */
13 changes: 12 additions & 1 deletion samples/subsys/usb/common/sample_usbd_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ static void sample_fix_code_triple(struct usbd_context *uds_ctx,
}
}

struct usbd_context *sample_usbd_init_device(usbd_msg_cb_t msg_cb)
struct usbd_context *sample_usbd_setup_device(usbd_msg_cb_t msg_cb)
{
int err;

Expand Down Expand Up @@ -169,6 +169,17 @@ struct usbd_context *sample_usbd_init_device(usbd_msg_cb_t msg_cb)
}
}

return &sample_usbd;
}

struct usbd_context *sample_usbd_init_device(usbd_msg_cb_t msg_cb)
{
int err;

if (sample_usbd_setup_device(msg_cb) == NULL) {
return NULL;
}

/* doc device init start */
err = usbd_init(&sample_usbd);
if (err) {
Expand Down
9 changes: 9 additions & 0 deletions samples/subsys/usb/webusb-next/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# SPDX-License-Identifier: Apache-2.0

cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(webusb)

include(${ZEPHYR_BASE}/samples/subsys/usb/common/common.cmake)
FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources})
9 changes: 9 additions & 0 deletions samples/subsys/usb/webusb-next/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Copyright (c) 2023 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0

# Source common USB sample options used to initialize new experimental USB
# device stack. The scope of these options is limited to USB samples in project
# tree, you cannot use them in your own application.
source "samples/subsys/usb/common/Kconfig.sample_usbd"

source "Kconfig.zephyr"
73 changes: 73 additions & 0 deletions samples/subsys/usb/webusb-next/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
.. zephyr:code-sample:: webusb-next
:name: WebUSB-next
:relevant-api: usbd_api

Receive and echo data from a web page using WebUSB API.

Overview
********

This sample demonstrates how to use the Binary Device Object Store (BOS),
Microsoft OS 2.0 descriptors, and WebUSB descriptors to implement a WebUSB
sample application. The sample USB function receives the data and echoes back
to the WebUSB API based application running in the browser on your local host.
This sample can be found at :zephyr_file:`samples/subsys/usb/webusb-next` in the
Zephyr project tree.

Requirements
************

This project requires a USB device controller driver using the UDC API.
On your host computer, this project requires a web browser that supports the
WebUSB API, such as Chromium or a Chromium-based browser.

Building and Running
********************

Build and flash webusb sample with:

.. zephyr-app-commands::
:zephyr-app: samples/subsys/usb/webusb-next
:board: <board to use>
:goals: flash
:compact:

Demonstration
*************

The sample includes a simple WebUSB API application and can be found in the
sample directory: :zephyr_file:`samples/subsys/usb/webusb-next/index.html`.

There are two ways to access this sample page:

* Using browser go to :doc:`demo`

* Start a web server in the sample directory:

.. code-block:: console

$ python -m http.server

Then follow these steps:

#. Connect the board to your host.

#. Once the device has booted, you may see a notification from the browser: "Go
to localhost to connect". Click on the notification to open the demo page. If
there is no notification from the browser, open the URL http://localhost:8001/
in your browser.

#. Click on the :guilabel:`Connect` button to connect to the device.

#. Send some text to the device by clicking on the :guilabel:`Send` button.
The demo application will receive the same text from the device and display
it in the text area.

References
***********

WebUSB API Specification:
https://wicg.github.io/webusb/

Chrome for Developers, "Access USB Devices on the Web":
https://developer.chrome.com/docs/capabilities/usb
7 changes: 7 additions & 0 deletions samples/subsys/usb/webusb-next/demo.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
:orphan:

WebUSB HTML Demo App
====================

.. raw:: html
:file: index.html
Loading
Loading