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