1 /*
2  * Copyright (c) 2022 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief USB virtual bus service
10  */
11 
12 #ifndef ZEPHYR_INCLUDE_UVB
13 #define ZEPHYR_INCLUDE_UVB
14 
15 #include <zephyr/sys/atomic.h>
16 #include <zephyr/sys/dlist.h>
17 #include <zephyr/sys/iterable_sections.h>
18 
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
22 
23 /**
24  * @brief Virtual bus event types
25  */
26 enum uvb_event_type {
27 	/** VBUS ready event */
28 	UVB_EVT_VBUS_READY,
29 	/** VBUS removed event */
30 	UVB_EVT_VBUS_REMOVED,
31 	/** Device resume event */
32 	UVB_EVT_RESUME,
33 	/** Device suspended event */
34 	UVB_EVT_SUSPEND,
35 	/** Port reset detected */
36 	UVB_EVT_RESET,
37 	/** Endpoint request event */
38 	UVB_EVT_REQUEST,
39 	/** Endpoint request reply event */
40 	UVB_EVT_REPLY,
41 	/** Device activity event */
42 	UVB_EVT_DEVICE_ACT,
43 };
44 
45 /**
46  * @brief Virtual bus device activity type
47  */
48 enum uvb_device_act {
49 	/** Device issue remote wakeup */
50 	UVB_DEVICE_ACT_RWUP,
51 	/** Low speed connection detected */
52 	UVB_DEVICE_ACT_LS,
53 	/** Full speed connection detected */
54 	UVB_DEVICE_ACT_FS,
55 	/** High speed connection detected */
56 	UVB_DEVICE_ACT_HS,
57 	/** Super speed connection detected */
58 	UVB_DEVICE_ACT_SS,
59 	/** Connection removed, issued when a device is disabled */
60 	UVB_DEVICE_ACT_REMOVED,
61 };
62 
63 /**
64  * @brief Virtual bus host request type
65  */
66 enum uvb_request {
67 	/** Setup request */
68 	UVB_REQUEST_SETUP,
69 	/** Data request */
70 	UVB_REQUEST_DATA,
71 };
72 
73 /**
74  * @brief Virtual bus device reply type
75  */
76 enum uvb_reply {
77 	/** Default value */
78 	UVB_REPLY_TIMEOUT,
79 	/** Reply ACK handshake to a request */
80 	UVB_REPLY_ACK,
81 	/** Reply NACK handshake to a request */
82 	UVB_REPLY_NACK,
83 	/** Reply STALL handshake to a request */
84 	UVB_REPLY_STALL,
85 };
86 
87 /**
88  * USB virtual bus packet
89  */
90 struct uvb_packet {
91 	/** slist node (TBD) */
92 	sys_snode_t node;
93 	/** Consecutive packet sequence number */
94 	uint32_t seq;
95 
96 	/** Request type */
97 	enum uvb_request request: 8;
98 	/** Reply handshake */
99 	enum uvb_reply reply : 8;
100 	/** Device (peripheral) address */
101 	unsigned int addr : 8;
102 	/** Endpoint address */
103 	unsigned int ep : 8;
104 
105 	/** Pointer to a data chunk */
106 	uint8_t *data;
107 	/** Length of the data chunk */
108 	size_t length;
109 };
110 
111 /**
112  * USB virtual bus node
113  */
114 struct uvb_node {
115 	union {
116 		/** dlist device node */
117 		sys_dnode_t node;
118 		/** dlist host list */
119 		sys_dlist_t list;
120 	};
121 	/** Name of the UVB node */
122 	const char *name;
123 	/** Pointer to the notify callback of the UVB node */
124 	void (*notify)(const void *const priv,
125 		       const enum uvb_event_type type,
126 		       const void *data);
127 	/** Internally used atomic value */
128 	atomic_t subscribed;
129 	/** True for a host node */
130 	bool head;
131 	/** Pointer to the node's private data */
132 	const void *priv;
133 };
134 
135 /**
136  * @brief Allocate UVB packet for the request or reply.
137  *
138  * @param[in] request Request type
139  * @param[in] addr    Device (peripheral) address
140  * @param[in] ep      Endpoint address
141  * @param[in] data    Pointer to a chunk of the net_buf data
142  * @param[in] length  Data chunk length
143  *
144  * @return pointer to allocated packet or NULL on error.
145  */
146 struct uvb_packet *uvb_alloc_pkt(const enum uvb_request request,
147 				 const uint8_t addr, const uint8_t ep,
148 				 uint8_t *const data,
149 				 const size_t length);
150 
151 /**
152  * @brief Free UVB packet
153  *
154  * @param[in] pkt    Pointer to UVB packet
155  */
156 void uvb_free_pkt(struct uvb_packet *const pkt);
157 
158 /**
159  * @brief Advert UVB event on virtual bus
160  *
161  * All devices subscribed to a controller are advertised.
162  * Events like UVB_EVT_REQUEST are to be filtered by using device address.
163  *
164  * @param[in] host_node Pointer to host controller UVB node
165  * @param[in] type      UVB event type
166  * @param[in] pkt       Pointer to UVB packet or NULL
167  *
168  * @return 0 on success, all other values should be treated as error.
169  */
170 int uvb_advert(const struct uvb_node *const host_node,
171 	       const enum uvb_event_type type,
172 	       const struct uvb_packet *const pkt);
173 
174 /**
175  * @brief Submit UVB event to host controller node
176  *
177  * Intended for use by virtual device for the request reply
178  * UVB_EVT_REPLY and device activity event UVB_EVT_DEVICE_ACT
179  *
180  * @param[in] dev_node  Pointer to device controller UVB node
181  * @param[in] type      UVB event type
182  * @param[in] pkt       Pointer to UVB packet or NULL
183  *
184  * @return 0 on success, all other values should be treated as error.
185  */
186 int uvb_to_host(const struct uvb_node *const dev_node,
187 		const enum uvb_event_type type,
188 		const struct uvb_packet *const pkt);
189 
190 /**
191  * @brief Subscribe to the adverts of the specific host node.
192  *
193  * Intended for use by virtual device during UDC API init call.
194  *
195  * @param[in] name     Name of the host node.
196  * @param[in] dev_node Pointer to device controller UVB node
197  *
198  * @return 0 on success, all other values should be treated as error.
199  */
200 int uvb_subscribe(const char *name, struct uvb_node *const dev_node);
201 
202 /**
203  * @brief Unsubsribe from the adverts of the specific host node.
204  *
205  * Intended for use by virtual device during UDC API shutdown call.
206  *
207  * @param[in] name     Name of the host node.
208  * @param[in] dev_node Pointer to device controller UVB node
209  *
210  * @return 0 on success, all other values should be treated as error.
211  */
212 int uvb_unsubscribe(const char *name, struct uvb_node *const dev_node);
213 
214 /**
215  * @brief Advert request UVB event on virtual bus
216  *
217  * @param[in] host_node Pointer to host controller UVB node
218  * @param[in] pkt       Pointer to UVB packet
219  *
220  * @return 0 on success, all other values should be treated as error.
221  */
uvb_advert_pkt(const struct uvb_node * const host_node,const struct uvb_packet * const pkt)222 static inline int uvb_advert_pkt(const struct uvb_node *const host_node,
223 				 const struct uvb_packet *const pkt)
224 {
225 	return uvb_advert(host_node, UVB_EVT_REQUEST, pkt);
226 }
227 
228 /**
229  * @brief Reply to UVB request
230  *
231  * @param[in] dev_node Pointer to host controller UVB node
232  * @param[in] pkt      Pointer to UVB packet
233  *
234  * @return 0 on success, all other values should be treated as error.
235  */
uvb_reply_pkt(const struct uvb_node * const dev_node,const struct uvb_packet * const pkt)236 static inline int uvb_reply_pkt(const struct uvb_node *const dev_node,
237 				const struct uvb_packet *const pkt)
238 {
239 	return uvb_to_host(dev_node, UVB_EVT_REPLY, pkt);
240 }
241 
242 /** @brief Helper to define UVB host controller node
243  *
244  *  @param host        UVB host node structure name
245  *  @param host_name   UVB host node name
246  *  @param host_notify Pointer to host notify callback
247  */
248 #define UVB_HOST_NODE_DEFINE(host, host_name, host_notify)			\
249 	STRUCT_SECTION_ITERABLE(uvb_node, host) = {				\
250 		.name = host_name,						\
251 		.head = true,							\
252 		.notify = host_notify,						\
253 	}
254 
255 #ifdef __cplusplus
256 }
257 #endif
258 
259 #endif /* ZEPHYR_INCLUDE_UVB */
260