1 /*
2 * Copyright (c) 2021-2022 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @file
9 * @brief Private API for USB device controller (UDC) drivers
10 */
11
12 #ifndef ZEPHYR_INCLUDE_UDC_COMMON_H
13 #define ZEPHYR_INCLUDE_UDC_COMMON_H
14
15 #include <zephyr/drivers/usb/udc.h>
16 #include <zephyr/sys/byteorder.h>
17
18 #define CTRL_PIPE_STAGE_SETUP 0
19 #define CTRL_PIPE_STAGE_DATA_OUT 1
20 #define CTRL_PIPE_STAGE_DATA_IN 2
21 #define CTRL_PIPE_STAGE_NO_DATA 3
22 #define CTRL_PIPE_STAGE_STATUS_OUT 4
23 #define CTRL_PIPE_STAGE_STATUS_IN 5
24 #define CTRL_PIPE_STAGE_ERROR 6
25
26 /**
27 * @brief Get driver's private data
28 *
29 * @param[in] dev Pointer to device struct of the driver instance
30 *
31 * @return pointer to driver's private data
32 */
udc_get_private(const struct device * dev)33 static inline void *udc_get_private(const struct device *dev)
34 {
35 struct udc_data *data = dev->data;
36
37 return data->priv;
38 }
39
40 /**
41 * @brief Helper function to set suspended status
42 *
43 * This function can be used by the driver to set suspended status
44 *
45 * @param[in] dev Pointer to device struct of the driver instance
46 * @param[in] values True to set suspended status
47 */
48 void udc_set_suspended(const struct device *dev, const bool value);
49
50 /**
51 * @brief Get pointer to endpoint configuration structure.
52 *
53 * @param[in] dev Pointer to device struct of the driver instance
54 * @param[in] ep Endpoint address
55 *
56 * @return pointer to endpoint configuration or NULL on error.
57 */
58 struct udc_ep_config *udc_get_ep_cfg(const struct device *dev,
59 const uint8_t ep);
60
61 /**
62 * @brief Checks if the endpoint is busy
63 *
64 * @param[in] dev Pointer to device struct of the driver instance
65 * @param[in] ep Endpoint address
66 *
67 * @return true if endpoint is busy
68 */
69 bool udc_ep_is_busy(const struct device *dev, const uint8_t ep);
70
71 /**
72 * @brief Helper function to set endpoint busy state
73 *
74 * @param[in] dev Pointer to device struct of the driver instance
75 * @param[in] ep Endpoint address
76 * @param[in] busy Busy state
77 */
78 void udc_ep_set_busy(const struct device *dev, const uint8_t ep,
79 const bool busy);
80
81 /**
82 * @brief Get UDC request from endpoint FIFO.
83 *
84 * This function removes request from endpoint FIFO.
85 * Use it when transfer is finished and request should
86 * be passed to the higher level.
87 *
88 * @param[in] dev Pointer to device struct of the driver instance
89 * @param[in] ep Endpoint address
90 *
91 * @return pointer to UDC request or NULL on error.
92 */
93 struct net_buf *udc_buf_get(const struct device *dev,
94 const uint8_t ep);
95
96 /**
97 * @brief Get all UDC request from endpoint FIFO.
98 *
99 * Get all UDC request from endpoint FIFO as single-linked list.
100 * This function removes all request from endpoint FIFO and
101 * is typically used to dequeue endpoint FIFO.
102 *
103 * @param[in] dev Pointer to device struct of the driver instance
104 * @param[in] ep Endpoint address
105 *
106 * @return pointer to UDC request or NULL on error.
107 */
108 struct net_buf *udc_buf_get_all(const struct device *dev,
109 const uint8_t ep);
110
111 /**
112 * @brief Peek request at the head of endpoint FIFO.
113 *
114 * Return request from the head of endpoint FIFO without removing.
115 * Use it when request buffer is required for a transfer.
116 *
117 * @param[in] dev Pointer to device struct of the driver instance
118 * @param[in] ep Endpoint address
119 *
120 * @return pointer to request or NULL on error.
121 */
122 struct net_buf *udc_buf_peek(const struct device *dev,
123 const uint8_t ep);
124
125 /**
126 * @brief Put request at the tail of endpoint FIFO.
127 *
128 * @param[in] ep_cfg Pointer to endpoint configuration
129 * @param[in] buf Pointer to UDC request buffer
130 *
131 * @return pointer to request or NULL on error.
132 */
133 void udc_buf_put(struct udc_ep_config *const ep_cfg,
134 struct net_buf *const buf);
135 /**
136 * @brief Helper function to send UDC event to a higher level.
137 *
138 * The callback would typically sends UDC even to a message queue (k_msgq).
139 *
140 * @param[in] dev Pointer to device struct of the driver instance
141 * @param[in] type Event type
142 * @param[in] status Event status
143 *
144 * @return 0 on success, all other values should be treated as error.
145 * @retval -EPERM controller is not initialized
146 */
147 int udc_submit_event(const struct device *dev,
148 const enum udc_event_type type,
149 const int status);
150
151 /**
152 * @brief Helper function to send UDC endpoint event to a higher level.
153 *
154 * Type of this event is hardcoded to UDC_EVT_EP_REQUEST.
155 * The callback would typically sends UDC even to a message queue (k_msgq).
156 *
157 * @param[in] dev Pointer to device struct of the driver instance
158 * @param[in] buf Pointer to UDC request buffer
159 * @param[in] err Request result
160 *
161 * @return 0 on success, all other values should be treated as error.
162 * @retval -EPERM controller is not initialized
163 */
164 int udc_submit_ep_event(const struct device *dev,
165 struct net_buf *const buf,
166 const int err);
167 /**
168 * @brief Helper function to enable endpoint.
169 *
170 * This function can be used by the driver to enable control IN/OUT endpoint.
171 *
172 * @param[in] dev Pointer to device struct of the driver instance
173 * @param[in] ep Endpoint address (same as bEndpointAddress)
174 * @param[in] attributes Endpoint attributes (same as bmAttributes)
175 * @param[in] mps Maximum packet size (same as wMaxPacketSize)
176 * @param[in] interval Polling interval (same as bInterval)
177 *
178 * @return 0 on success, all other values should be treated as error.
179 * @retval -ENODEV endpoint is not assigned or no configuration found
180 * @retval -EALREADY endpoint is already enabled
181 */
182 int udc_ep_enable_internal(const struct device *dev,
183 const uint8_t ep,
184 const uint8_t attributes,
185 const uint16_t mps,
186 const uint8_t interval);
187
188 /**
189 * @brief Helper function to disable endpoint.
190 *
191 * This function can be used by the driver to disable control IN/OUT endpoint.
192 *
193 * @param[in] dev Pointer to device struct of the driver instance
194 * @param[in] ep Endpoint address
195 *
196 * @return 0 on success, all other values should be treated as error.
197 * @retval -ENODEV endpoint is not assigned or no configuration found
198 * @retval -EALREADY endpoint is already enabled
199 */
200 int udc_ep_disable_internal(const struct device *dev,
201 const uint8_t ep);
202
203 /**
204 * @brief Helper function to register endpoint configuration.
205 *
206 * This function initializes endpoint FIFO and
207 * appends endpoint configuration to drivers endpoint list.
208 *
209 * @param[in] dev Pointer to device struct of the driver instance
210 * @param[in] cfg Pointer to endpoint configuration structure
211 *
212 * @return 0 on success, all other values should be treated as error.
213 * @retval -EACCES controller is initialized or enabled
214 */
215 int udc_register_ep(const struct device *dev,
216 struct udc_ep_config *const cfg);
217
218 /**
219 * @brief Set setup flag in requests metadata.
220 *
221 * A control transfer can be either setup or data OUT,
222 * use this function to mark request as setup packet.
223 *
224 * @param[in] buf Pointer to UDC request buffer
225 */
226 void udc_ep_buf_set_setup(struct net_buf *const buf);
227
228 /**
229 * @brief Checks whether the driver must finish transfer with a ZLP
230 *
231 * @param[in] buf Pointer to UDC request buffer
232 *
233 * @return true if ZLP is requested
234 */
235 bool udc_ep_buf_has_zlp(const struct net_buf *const buf);
236
237 /**
238 * @brief Clear ZLP flag
239 *
240 * @param[in] buf Pointer to UDC request buffer
241 */
242 void udc_ep_buf_clear_zlp(const struct net_buf *const buf);
243
244 /**
245 * @brief Locking function for the drivers.
246 *
247 * @param[in] dev Pointer to device struct of the driver instance
248 * @param[in] timeout Timeout
249 *
250 * @return values provided by k_mutex_lock()
251 */
udc_lock_internal(const struct device * dev,k_timeout_t timeout)252 static inline int udc_lock_internal(const struct device *dev,
253 k_timeout_t timeout)
254 {
255 struct udc_data *data = dev->data;
256
257 return k_mutex_lock(&data->mutex, timeout);
258 }
259
260 /**
261 * @brief Unlocking function for the drivers.
262 *
263 * @param[in] dev Pointer to device struct of the driver instance
264 *
265 * @return values provided by k_mutex_lock()
266 */
udc_unlock_internal(const struct device * dev)267 static inline int udc_unlock_internal(const struct device *dev)
268 {
269 struct udc_data *data = dev->data;
270
271 return k_mutex_unlock(&data->mutex);
272 }
273
274 /**
275 * @brief Allocate UDC control transfer buffer
276 *
277 * Allocate a new buffer from common control transfer buffer pool.
278 *
279 * @param[in] dev Pointer to device struct of the driver instance
280 * @param[in] ep Endpoint address
281 * @param[in] size Size of the request buffer
282 *
283 * @return pointer to allocated request or NULL on error.
284 */
285 struct net_buf *udc_ctrl_alloc(const struct device *dev,
286 const uint8_t ep,
287 const size_t size);
288
udc_data_stage_length(const struct net_buf * const buf)289 static inline uint16_t udc_data_stage_length(const struct net_buf *const buf)
290 {
291 struct usb_setup_packet *setup = (void *)buf->data;
292
293 return sys_le16_to_cpu(setup->wLength);
294 }
295
296 /**
297 * @brief Checks whether the current control transfer stage is Data Stage OUT
298 *
299 * @param[in] dev Pointer to device struct of the driver instance
300 *
301 * @return true if stage is Data Stage OUT
302 */
303 bool udc_ctrl_stage_is_data_out(const struct device *dev);
304
305 /**
306 * @brief Checks whether the current control transfer stage is Data Stage IN
307 *
308 * @param[in] dev Pointer to device struct of the driver instance
309 *
310 * @return true if stage is Data Stage IN
311 */
312 bool udc_ctrl_stage_is_data_in(const struct device *dev);
313
314 /**
315 * @brief Checks whether the current control transfer stage is Status IN
316 *
317 * @param[in] dev Pointer to device struct of the driver instance
318 *
319 * @return true if stage is Data Stage IN
320 */
321 bool udc_ctrl_stage_is_status_in(const struct device *dev);
322
323 /**
324 * @brief Checks whether the current control transfer stage is Status OUT
325 *
326 * @param[in] dev Pointer to device struct of the driver instance
327 *
328 * @return true if stage is Data Stage OUT
329 */
330 bool udc_ctrl_stage_is_status_out(const struct device *dev);
331
332 /**
333 * @brief Checks whether the current control transfer stage is Status no-data
334 *
335 * @param[in] dev Pointer to device struct of the driver instance
336 *
337 * @return true if stage is Status no-data
338 */
339 bool udc_ctrl_stage_is_no_data(const struct device *dev);
340
341 /**
342 * @brief Submit Control Write (s-out-status) transfer
343 *
344 * Allocate buffer for data stage IN,
345 * submit both setup and data buffer to upper layer.
346 *
347 * @param[in] dev Pointer to device struct of the driver instance
348 * @param[in] dout Pointer to UDC buffer containing data transaction
349 *
350 * @return 0 on success, all other values should be treated as error.
351 */
352 int udc_ctrl_submit_s_out_status(const struct device *dev,
353 struct net_buf *const dout);
354
355 /**
356 * @brief Prepare control data IN stage
357 *
358 * Allocate buffer for data stage IN,
359 * submit both setup and data buffer to upper layer.
360 *
361 * @param[in] dev Pointer to device struct of the driver instance
362 *
363 * @return 0 on success, all other values should be treated as error.
364 */
365 int udc_ctrl_submit_s_in_status(const struct device *dev);
366
367 /**
368 * @brief Prepare control (no-data) status stage
369 *
370 * Allocate buffer for status stage IN,
371 * submit both setup and status buffer to upper layer.
372 *
373 * @param[in] dev Pointer to device struct of the driver instance
374 *
375 * @return 0 on success, all other values should be treated as error.
376 */
377 int udc_ctrl_submit_s_status(const struct device *dev);
378
379 /**
380 * @brief Submit status transaction
381 *
382 * Submit both status transaction to upper layer.
383 *
384 * @param[in] dev Pointer to device struct of the driver instance
385 * @param[in] dout Pointer to UDC buffer containing data transaction
386 *
387 * @return 0 on success, all other values should be treated as error.
388 */
389 int udc_ctrl_submit_status(const struct device *dev,
390 struct net_buf *const buf);
391
392 /**
393 * @brief Update internal control stage status based on the net_buf metadata
394 *
395 * Use it in the driver to update the stage, typically there are
396 * three places where this function should be called:
397 * - when a setup packet is received
398 * - when a data stage is completed (all data stage transactions)
399 * - when a status stage transaction is finished
400 *
401 * The functions of type udc_ctrl_stage_is_*() can be called before or
402 * after this function, depending on the desired action.
403 * To keep protocol processing running the following should be taken
404 * into account:
405 *
406 * - Upper layer may not allocate buffers but remove or release buffers
407 * from the chain that are no longer needed. Only control IN transfers may
408 * be enqueued by the upper layer.
409 *
410 * - For "Control Write" (s-out-status), the driver should allocate the buffer,
411 * insert it as a fragment to setup buffer and perform the Data Stage
412 * transaction. Allocate and insert a fragment for the status (IN) stage to
413 * setup buffer, and then pass setup packet with the chain of s-out-status to
414 * upper layer. Upper layer should either halt control endpoint or
415 * enqueue status buffer for status stage. There should be second
416 * notification to upper layer when the status transaction is finished.
417 *
418 * ->driver_foo_setup_rcvd(dev)
419 * ->udc_ctrl_update_stage(dev, buf)
420 * ->udc_ctrl_alloc(dev, USB_CONTROL_EP_OUT, wLength)
421 * ->driver_foo_xfer_start(dev, USB_CONTROL_EP_OUT)
422 *
423 * ->driver_foo_dout_rcvd(dev)
424 * -...
425 * ->driver_foo_feed_next_dout(dev, ....)
426 * -...
427 * ->udc_ctrl_update_stage(dev, dout_buf)
428 * -...
429 * ->udc_ctrl_submit_s_out_status(dev, dout_buf);
430 *
431 * ->driver_foo_din_rcvd(dev)
432 * -...
433 * ->udc_ctrl_submit_status(dev, status_buf);
434 * -...
435 * ->udc_ctrl_update_stage(dev, status_buf)
436 *
437 * - For "Control Read" (s-in-status), depending on the controller,
438 * the driver should reserve the buffers for subsequent status stage and
439 * setup packet and prepare everything. The driver should allocate the buffer
440 * for IN transaction insert it as a fragment to setup buffer, and pass
441 * the chain of s-in to upper layer. Upper layer should either halt control
442 * endpoint or enqueue (in) buffer. There should be second
443 * notification to upper layer when the status transaction is finished.
444 *
445 * ->driver_foo_setup_rcvd(dev)
446 * ->udc_ctrl_update_stage(dev, buf)
447 * ->driver_foo_feed_next_dout(dev, ....)
448 * -...
449 * ->udc_ctrl_submit_s_in_status(dev);
450 *
451 * ->driver_foo_din_rcvd(dev)
452 * -...
453 * ->udc_ctrl_update_stage(dev, dout_buf)
454 * -...
455 *
456 * ->driver_foo_dout_rcvd(dev)
457 * -...
458 * ->udc_ctrl_submit_status(dev, status_buf);
459 * -...
460 * ->udc_ctrl_update_stage(dev, dout_buf)
461 *
462 * - For "No-data Control" (s-status), the driver should allocate the buffer
463 * for the status (IN) stage, insert it as a fragment to setup buffer,
464 * and then pass setup packet with the chain of s-status to
465 * upper layer. Upper layer should either halt control endpoint or
466 * enqueue status buffer for status stage. There should be second
467 * notification to upper layer when the status transaction is finished.
468 *
469 * ->driver_foo_setup_rcvd(dev)
470 * ->udc_ctrl_update_stage(dev, buf)
471 * ->driver_foo_feed_next_dout(dev, ....)
472 * -...
473 * ->udc_ctrl_submit_s_status(dev);
474 *
475 * ->driver_foo_din_rcvd(dev)
476 * -...
477 * ->udc_ctrl_submit_status(dev, status_buf);
478 * -...
479 * ->udc_ctrl_update_stage(dev, status_buf)
480 *
481 * Please refer to Chapter 8.5.3 Control Transfers USB 2.0 spec.
482 *
483 * @param[in] dev Pointer to device struct of the driver instance
484 * @param[in] buf Buffer containing setup packet
485 *
486 * @return 0 on success, all other values should be treated as error.
487 */
488 void udc_ctrl_update_stage(const struct device *dev,
489 struct net_buf *const buf);
490
491 #if defined(CONFIG_UDC_WORKQUEUE)
492 extern struct k_work_q udc_work_q;
493
udc_get_work_q(void)494 static inline struct k_work_q *udc_get_work_q(void)
495 {
496 return &udc_work_q;
497 }
498 #else
udc_get_work_q(void)499 static inline struct k_work_q *udc_get_work_q(void)
500 {
501 return &k_sys_work_q;
502 }
503 #endif
504
505 #endif /* ZEPHYR_INCLUDE_UDC_COMMON_H */
506