blob: a9fcfed816a4ebd67c14680c4082a4f11eb17bda [file] [log] [blame]
/*
* 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 <zephyr/sys/atomic.h>
#include <zephyr/sys/dlist.h>
#include <zephyr/sys/iterable_sections.h>
#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 */