/* * Copyright (c) 2022 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ /** * @file * @brief USB virtual bus service */ #ifndef ZEPHYR_INCLUDE_UVB #define ZEPHYR_INCLUDE_UVB #include #include #include #ifdef __cplusplus extern "C" { #endif /** * @brief Virtual bus event types */ enum uvb_event_type { /** VBUS ready event */ UVB_EVT_VBUS_READY, /** VBUS removed event */ UVB_EVT_VBUS_REMOVED, /** Device resume event */ UVB_EVT_RESUME, /** Device suspended event */ UVB_EVT_SUSPEND, /** Port reset detected */ UVB_EVT_RESET, /** Endpoint request event */ UVB_EVT_REQUEST, /** Endpoint request reply event */ UVB_EVT_REPLY, /** Device activity event */ UVB_EVT_DEVICE_ACT, }; /** * @brief Virtual bus device activity type */ enum uvb_device_act { /** Device issue remote wakeup */ UVB_DEVICE_ACT_RWUP, /** Low speed connection detected */ UVB_DEVICE_ACT_LS, /** Full speed connection detected */ UVB_DEVICE_ACT_FS, /** High speed connection detected */ UVB_DEVICE_ACT_HS, /** Super speed connection detected */ UVB_DEVICE_ACT_SS, /** Connection removed, issued when a device is disabled */ UVB_DEVICE_ACT_REMOVED, }; /** * @brief Virtual bus host request type */ enum uvb_request { /** Setup request */ UVB_REQUEST_SETUP, /** Data request */ UVB_REQUEST_DATA, }; /** * @brief Virtual bus device reply type */ enum uvb_reply { /** Default value */ UVB_REPLY_TIMEOUT, /** Reply ACK handshake to a request */ UVB_REPLY_ACK, /** Reply NACK handshake to a request */ UVB_REPLY_NACK, /** Reply STALL handshake to a request */ UVB_REPLY_STALL, }; /** * USB virtual bus packet */ struct uvb_packet { /** slist node (TBD) */ sys_snode_t node; /** Consecutive packet sequence number */ uint32_t seq; /** Request type */ enum uvb_request request: 8; /** Reply handshake */ enum uvb_reply reply : 8; /** Device (peripheral) address */ unsigned int addr : 8; /** Endpoint address */ unsigned int ep : 8; /** Pointer to a data chunk */ uint8_t *data; /** Length of the data chunk */ size_t length; }; /** * USB virtual bus node */ struct uvb_node { union { /** dlist device node */ sys_dnode_t node; /** dlist host list */ sys_dlist_t list; }; /** Name of the UVB node */ const char *name; /** Pointer to the notify callback of the UVB node */ void (*notify)(const void *const priv, const enum uvb_event_type type, const void *data); /** Internally used atomic value */ atomic_t subscribed; /** True for a host node */ bool head; /** Pointer to the node's private data */ const void *priv; }; /** * @brief Allocate UVB packet for the request or reply. * * @param[in] request Request type * @param[in] addr Device (peripheral) address * @param[in] ep Endpoint address * @param[in] data Pointer to a chunk of the net_buf data * @param[in] length Data chunk length * * @return pointer to allocated packet or NULL on error. */ struct uvb_packet *uvb_alloc_pkt(const enum uvb_request request, const uint8_t addr, const uint8_t ep, uint8_t *const data, const size_t length); /** * @brief Free UVB packet * * @param[in] pkt Pointer to UVB packet */ void uvb_free_pkt(struct uvb_packet *const pkt); /** * @brief Advert UVB event on virtual bus * * All devices subscribed to a controller are advertised. * Events like UVB_EVT_REQUEST are to be filtered by using device address. * * @param[in] host_node Pointer to host controller UVB node * @param[in] type UVB event type * @param[in] pkt Pointer to UVB packet or NULL * * @return 0 on success, all other values should be treated as error. */ int uvb_advert(const struct uvb_node *const host_node, const enum uvb_event_type type, const struct uvb_packet *const pkt); /** * @brief Submit UVB event to host controller node * * Intended for use by virtual device for the request reply * UVB_EVT_REPLY and device activity event UVB_EVT_DEVICE_ACT * * @param[in] dev_node Pointer to device controller UVB node * @param[in] type UVB event type * @param[in] pkt Pointer to UVB packet or NULL * * @return 0 on success, all other values should be treated as error. */ int uvb_to_host(const struct uvb_node *const dev_node, const enum uvb_event_type type, const struct uvb_packet *const pkt); /** * @brief Subscribe to the adverts of the specific host node. * * Intended for use by virtual device during UDC API init call. * * @param[in] name Name of the host node. * @param[in] dev_node Pointer to device controller UVB node * * @return 0 on success, all other values should be treated as error. */ int uvb_subscribe(const char *name, struct uvb_node *const dev_node); /** * @brief Unsubsribe from the adverts of the specific host node. * * Intended for use by virtual device during UDC API shutdown call. * * @param[in] name Name of the host node. * @param[in] dev_node Pointer to device controller UVB node * * @return 0 on success, all other values should be treated as error. */ int uvb_unsubscribe(const char *name, struct uvb_node *const dev_node); /** * @brief Advert request UVB event on virtual bus * * @param[in] host_node Pointer to host controller UVB node * @param[in] pkt Pointer to UVB packet * * @return 0 on success, all other values should be treated as error. */ static inline int uvb_advert_pkt(const struct uvb_node *const host_node, const struct uvb_packet *const pkt) { return uvb_advert(host_node, UVB_EVT_REQUEST, pkt); } /** * @brief Reply to UVB request * * @param[in] dev_node Pointer to host controller UVB node * @param[in] pkt Pointer to UVB packet * * @return 0 on success, all other values should be treated as error. */ static inline int uvb_reply_pkt(const struct uvb_node *const dev_node, const struct uvb_packet *const pkt) { return uvb_to_host(dev_node, UVB_EVT_REPLY, pkt); } /** @brief Helper to define UVB host controller node * * @param host UVB host node structure name * @param host_name UVB host node name * @param host_notify Pointer to host notify callback */ #define UVB_HOST_NODE_DEFINE(host, host_name, host_notify) \ STRUCT_SECTION_ITERABLE(uvb_node, host) = { \ .name = host_name, \ .head = true, \ .notify = host_notify, \ } #ifdef __cplusplus } #endif #endif /* ZEPHYR_INCLUDE_UVB */