1 /*
2  * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #pragma once
8 
9 #include <stdint.h>
10 #include <sys/queue.h>
11 #include "freertos/FreeRTOS.h"
12 #include "freertos/task.h"
13 #include "hcd.h"
14 #include "usb/usb_types_ch9.h"
15 #include "usb/usb_types_stack.h"
16 
17 #ifdef __cplusplus
18 extern "C" {
19 #endif
20 
21 // ------------------------------------------------------ Types --------------------------------------------------------
22 
23 // ----------------------- Events --------------------------
24 
25 typedef enum {
26     USBH_EVENT_DEV_NEW,             /**< A new device has been enumerated and added to the device pool */
27     USBH_EVENT_DEV_GONE,            /**< A device is gone. Clients should close the device */
28     USBH_EVENT_DEV_ALL_FREE,        /**< All devices have been freed */
29 } usbh_event_t;
30 
31 /**
32  * @brief Hub driver requests
33  *
34  * Various requests of the Hub driver that the USBH can make.
35  */
36 typedef enum {
37     USBH_HUB_REQ_PORT_DISABLE,      /**< Request that the Hub driver disable a particular port (occurs after a device
38                                          has been freed). Hub driver should respond with a USBH_HUB_EVENT_PORT_DISABLED */
39     USBH_HUB_REQ_PORT_RECOVER,      /**< Request that the Hub driver recovers a particular port (occurs after a gone
40                                          device has been freed). */
41 } usbh_hub_req_t;
42 
43 /**
44  * @brief Hub driver events for the USBH
45  *
46  * These events as passed by the Hub driver to the USBH via usbh_hub_pass_event()
47  *
48  * USBH_HUB_EVENT_PORT_ERROR:
49  * - The port has encountered an error (such as a sudden disconnection). The device connected to that port is no longer valid.
50  * - The USBH should:
51  *      - Trigger a USBH_EVENT_DEV_GONE
52  *      - Prevent further transfers to the device
53  *      - Trigger the device's cleanup if it is already closed
54  *      - When the last client closes the device via usbh_dev_close(), free the device object and issue a USBH_HUB_REQ_PORT_RECOVER request
55  *
56  * USBH_HUB_EVENT_PORT_DISABLED:
57  * - A previous USBH_HUB_REQ_PORT_DISABLE has completed.
58  * - The USBH should free the device object
59  */
60 typedef enum {
61     USBH_HUB_EVENT_PORT_ERROR,      /**< The port has encountered an error (such as a sudden disconnection). The device
62                                          connected to that port should be marked gone. */
63     USBH_HUB_EVENT_PORT_DISABLED,   /**< Previous USBH_HUB_REQ_PORT_DISABLE request completed */
64 } usbh_hub_event_t;
65 
66 // ---------------------- Callbacks ------------------------
67 
68 /**
69  * @brief Callback used to indicate completion of control transfers submitted usbh_dev_submit_ctrl_urb()
70  * @note This callback is called from within usbh_process()
71  */
72 typedef void (*usbh_ctrl_xfer_cb_t)(usb_device_handle_t dev_hdl, urb_t *urb, void *arg);
73 
74 /**
75  * @brief Callback used to indicate that the USBH has an event
76  *
77  * @note This callback is called from within usbh_process()
78  * @note On a USBH_EVENT_DEV_ALL_FREE event, the dev_hdl argument is set to NULL
79  */
80 typedef void (*usbh_event_cb_t)(usb_device_handle_t dev_hdl, usbh_event_t usbh_event, void *arg);
81 
82 /**
83  * @brief Callback used by the USBH to request actions from the Hub driver
84  *
85  * The Hub Request Callback allows the USBH to request the Hub actions on a particular port. Conversely, the Hub driver
86  * will indicate completion of some of these requests to the USBH via the usbh_hub_event() funtion.
87  */
88 typedef void (*usbh_hub_req_cb_t)(hcd_port_handle_t port_hdl, usbh_hub_req_t hub_req, void *arg);
89 
90 // ----------------------- Objects -------------------------
91 
92 /**
93  * @brief Configuration for an endpoint being allocated using usbh_ep_alloc()
94  */
95 typedef struct {
96     const usb_ep_desc_t *ep_desc;           /**< Endpoint descriptor */
97     hcd_pipe_callback_t pipe_cb;            /**< Endpoint's pipe callback */
98     void *pipe_cb_arg;                      /**< Pipe callback argument */
99     void *context;                          /**< Pipe context */
100 } usbh_ep_config_t;
101 
102 /**
103  * @brief USBH configuration used in usbh_install()
104  */
105 typedef struct {
106     usb_notif_cb_t notif_cb;                /**< Notification callback */
107     void *notif_cb_arg;                     /**< Notification callback argument */
108     usbh_ctrl_xfer_cb_t ctrl_xfer_cb;       /**< Control transfer callback */
109     void *ctrl_xfer_cb_arg;                 /**< Control transfer callback argument */
110     usbh_event_cb_t event_cb;               /**< USBH event callback */
111     void *event_cb_arg;                     /**< USBH event callback argument */
112     hcd_config_t hcd_config;                /**< HCD configuration */
113 } usbh_config_t;
114 
115 // ------------------------------------------------- USBH Functions ----------------------------------------------------
116 
117 /**
118  * @brief Installs the USBH driver
119  *
120  * - This function will internally install the HCD
121  * - This must be called before calling any Hub driver functions
122  *
123  * @note Before calling this function, the Host Controller must already be un-clock gated and reset. The USB PHY
124  *       (internal or external, and associated GPIOs) must already be configured.
125  * @param usbh_config USBH driver configuration
126  * @return esp_err_t
127  */
128 esp_err_t usbh_install(const usbh_config_t *usbh_config);
129 
130 /**
131  * @brief Uninstall the USBH driver
132  *
133  * - This function will uninstall the HCD
134  * - The Hub driver must be uninstalled before calling this function
135  *
136  * @note This function will simply free the resources used by the USBH. The underlying Host Controller and USB PHY will
137  *       not be disabled.
138  * @return esp_err_t
139  */
140 esp_err_t usbh_uninstall(void);
141 
142 /**
143  * @brief USBH processing function
144  *
145  * - USBH processing function that must be called repeatedly to process USBH events
146  * - If blocking, the caller can block until a USB_NOTIF_SOURCE_USBH notification is received before running this
147  *   function
148  *
149  * @note This function can block
150  * @return esp_err_t
151  */
152 esp_err_t usbh_process(void);
153 
154 /**
155  * @brief Get the current number of devices
156  *
157  * @note This function can block
158  * @param[out] num_devs_ret Current number of devices
159  * @return esp_err_t
160  */
161 esp_err_t usbh_num_devs(int *num_devs_ret);
162 
163 // ------------------------------------------------ Device Functions ---------------------------------------------------
164 
165 // --------------------- Device Pool -----------------------
166 
167 /**
168  * @brief Fill list with address of currently connected devices
169  *
170  * - This function fills the provided list with the address of current connected devices
171  * - Device address can then be used in usbh_dev_open()
172  * - If there are more devices than the list_len, this function will only fill
173  *   up to list_len number of devices.
174  *
175  * @param[in] list_len Length of empty list
176  * @param[inout] dev_addr_list Empty list to be filled
177  * @param[out] num_dev_ret Number of devices filled into list
178  * @return esp_err_t
179  */
180 esp_err_t usbh_dev_addr_list_fill(int list_len, uint8_t *dev_addr_list, int *num_dev_ret);
181 
182 /**
183  * @brief Open a device by address
184  *
185  * A device must be opened before it can be used
186  *
187  * @param[in] dev_addr Device address
188  * @param[out] dev_hdl Device handle
189  * @return esp_err_t
190  */
191 esp_err_t usbh_dev_open(uint8_t dev_addr, usb_device_handle_t *dev_hdl);
192 
193 /**
194  * @brief CLose a device
195  *
196  * Device can be opened by calling usbh_dev_open()
197  *
198  * @param[in] dev_hdl Device handle
199  * @return esp_err_t
200  */
201 esp_err_t usbh_dev_close(usb_device_handle_t dev_hdl);
202 
203 /**
204  * @brief Mark that all devices should be freed at the next possible opportunity
205  *
206  * A device marked as free will not be freed until the last client using the device has called usbh_dev_close()
207  *
208  * @return
209  *  - ESP_OK: There were no devices to free to begin with. Current state is all free
210  *  - ESP_ERR_NOT_FINISHED: One or more devices still need to be freed (but have been marked "to be freed")
211  */
212 esp_err_t usbh_dev_mark_all_free(void);
213 
214 // ------------------- Single Device  ----------------------
215 
216 /**
217  * @brief Get a device's address
218  *
219  * @note Can be called without opening the device
220  *
221  * @param[in] dev_hdl Device handle
222  * @param[out] dev_addr Device's address
223  * @return esp_err_t
224  */
225 esp_err_t usbh_dev_get_addr(usb_device_handle_t dev_hdl, uint8_t *dev_addr);
226 
227 /**
228  * @brief Get a device's information
229  *
230  * @note This function can block
231  * @param[in] dev_hdl Device handle
232  * @param[out] dev_info Device information
233  * @return esp_err_t
234  */
235 esp_err_t usbh_dev_get_info(usb_device_handle_t dev_hdl, usb_device_info_t *dev_info);
236 
237 /**
238  * @brief Get a device's device descriptor
239  *
240  * - The device descriptor is cached when the device is created by the Hub driver
241  *
242  * @param[in] dev_hdl Device handle
243  * @param[out] dev_desc_ret Device descriptor
244  * @return esp_err_t
245  */
246 esp_err_t usbh_dev_get_desc(usb_device_handle_t dev_hdl, const usb_device_desc_t **dev_desc_ret);
247 
248 /**
249  * @brief Get a device's active configuration descriptor
250  *
251  * Simply returns a reference to the internally cached configuration descriptor
252  *
253  * @note This function can block
254  * @param[in] dev_hdl Device handle
255  * @param config_desc_ret
256  * @return esp_err_t
257  */
258 esp_err_t usbh_dev_get_config_desc(usb_device_handle_t dev_hdl, const usb_config_desc_t **config_desc_ret);
259 
260 /**
261  * @brief Submit a control transfer (URB) to a device
262  *
263  * @param[in] dev_hdl Device handle
264  * @param[in] urb URB
265  * @return esp_err_t
266  */
267 esp_err_t usbh_dev_submit_ctrl_urb(usb_device_handle_t dev_hdl, urb_t *urb);
268 
269 // ----------------------------------------------- Endpoint Functions -------------------------------------------------
270 
271 /**
272  * @brief Allocate an endpoint on a device
273  *
274  * Clients that have opened a device must call this function to allocate all endpoints in an interface that is claimed.
275  * The pipe handle of the endpoint is returned so that clients can use and control the pipe directly.
276  *
277  * @note This function can block
278  * @note Default pipes are owned by the USBH. For control transfers, use usbh_dev_submit_ctrl_urb() instead
279  * @note Device must be opened by the client first
280  *
281  * @param[in] dev_hdl Device handle
282  * @param[in] ep_config
283  * @param[out] pipe_hdl_ret Pipe handle
284  * @return esp_err_t
285  */
286 esp_err_t usbh_ep_alloc(usb_device_handle_t dev_hdl, usbh_ep_config_t *ep_config, hcd_pipe_handle_t *pipe_hdl_ret);
287 
288 /**
289  * @brief Free and endpoint on a device
290  *
291  * Free an endpoint previously opened by usbh_ep_alloc()
292  *
293  * @note This function can block
294  * @param[in] dev_hdl Device handle
295  * @param[in] bEndpointAddress Endpoint's address
296  * @return esp_err_t
297  */
298 esp_err_t usbh_ep_free(usb_device_handle_t dev_hdl, uint8_t bEndpointAddress);
299 
300 /**
301  * @brief Get the context of an endpoint
302  *
303  * Get the context variable assigned to and endpoint on allocation.
304  *
305  * @note This function can block
306  * @param[in] dev_hdl Device handle
307  * @param[in] bEndpointAddress Endpoint's address
308  * @param[out] context_ret Context variable
309  * @return esp_err_t
310  */
311 esp_err_t usbh_ep_get_context(usb_device_handle_t dev_hdl, uint8_t bEndpointAddress, void **context_ret);
312 
313 // -------------------------------------------------- Hub Functions ----------------------------------------------------
314 
315 // ------------------- Device Related ----------------------
316 
317 /**
318  * @brief Indicates to USBH that the Hub driver is installed
319  *
320  * - The Hub driver must call this function in its installation to indicate the the USBH that it has been installed.
321  * - This should only be called after the USBH has already be installed
322  *
323  * @note Hub Driver only
324  * @param[in] hub_req_callback Hub request callback
325  * @param[in] callback_arg Callback argument
326  * @return esp_err_t
327  */
328 esp_err_t usbh_hub_is_installed(usbh_hub_req_cb_t hub_req_callback, void *callback_arg);
329 
330 /**
331  * @brief Indicates to USBH the start of enumeration for a device
332  *
333  * - The Hub driver calls this function before it starts enumerating a new device.
334  * - The USBH will allocate a new device that will be initialized by the Hub driver using the remaining hub enumeration
335  *   functions.
336  * - The new device's default pipe handle is returned to all the Hub driver to be used during enumeration.
337  *
338  * @note Hub Driver only
339  * @param[in] port_hdl Handle of the port that the device is connected to
340  * @param[in] dev_speed Device's speed
341  * @param[out] new_dev_hdl Device's handle
342  * @param[out] default_pipe_hdl Device's default pipe handle
343  * @return esp_err_t
344  */
345 esp_err_t usbh_hub_add_dev(hcd_port_handle_t port_hdl, usb_speed_t dev_speed, usb_device_handle_t *new_dev_hdl, hcd_pipe_handle_t *default_pipe_hdl);
346 
347 /**
348  * @brief Indicates to the USBH that a hub event has occurred for a particular device
349  *
350  * @param dev_hdl Device handle
351  * @param hub_event Hub event
352  * @return esp_err_t
353  */
354 esp_err_t usbh_hub_pass_event(usb_device_handle_t dev_hdl, usbh_hub_event_t hub_event);
355 
356 // ----------------- Enumeration Related -------------------
357 
358 /**
359  * @brief Assign the enumerating device's address
360  *
361  * @note Hub Driver only
362  * @note Must call in sequence
363  * @param[in] dev_hdl Device handle
364  * @param dev_addr
365  * @return esp_err_t
366  */
367 esp_err_t usbh_hub_enum_fill_dev_addr(usb_device_handle_t dev_hdl, uint8_t dev_addr);
368 
369 /**
370  * @brief Fill the enumerating device's descriptor
371  *
372  * @note Hub Driver only
373  * @note Must call in sequence
374  * @param[in] dev_hdl Device handle
375  * @param device_desc
376  * @return esp_err_t
377  */
378 esp_err_t usbh_hub_enum_fill_dev_desc(usb_device_handle_t dev_hdl, const usb_device_desc_t *device_desc);
379 
380 /**
381  * @brief Fill the enumerating device's active configuration descriptor
382  *
383  * @note Hub Driver only
384  * @note Must call in sequence
385  * @note This function can block
386  * @param[in] dev_hdl Device handle
387  * @param config_desc_full
388  * @return esp_err_t
389  */
390 esp_err_t usbh_hub_enum_fill_config_desc(usb_device_handle_t dev_hdl, const usb_config_desc_t *config_desc_full);
391 
392 /**
393  * @brief Fill one of the string descriptors of the enumerating device
394  *
395  * @note Hub Driver only
396  * @note Must call in sequence
397  * @param dev_hdl Device handle
398  * @param str_desc Pointer to string descriptor
399  * @param select Select which string descriptor. 0/1/2 for Manufacturer/Product/Serial Number string descriptors respecitvely
400  * @return esp_err_t
401  */
402 esp_err_t usbh_hub_enum_fill_str_desc(usb_device_handle_t dev_hdl, const usb_str_desc_t *str_desc, int select);
403 
404 /**
405  * @brief Indicate the device enumeration is completed
406  *
407  * This will all the device to be opened by clients, and also trigger a USBH_EVENT_DEV_NEW event.
408  *
409  * @note Hub Driver only
410  * @note Must call in sequence
411  * @note This function can block
412  * @param[in] dev_hdl Device handle
413  * @return esp_err_t
414  */
415 esp_err_t usbh_hub_enum_done(usb_device_handle_t dev_hdl);
416 
417 /**
418  * @brief Indicate that device enumeration has failed
419  *
420  * This will cause the enumerating device's resources to be cleaned up
421  * The Hub Driver must guarantee that the enumerating device's default pipe is already halted, flushed, and dequeued.
422  *
423  * @note Hub Driver only
424  * @note Must call in sequence
425  * @note This function can block
426  * @param[in] dev_hdl Device handle
427  * @return esp_err_t
428  */
429 esp_err_t usbh_hub_enum_failed(usb_device_handle_t dev_hdl);
430 
431 #ifdef __cplusplus
432 }
433 #endif
434