1 /*
2 * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #pragma once
8
9 #ifdef __cplusplus
10 extern "C" {
11 #endif
12
13 /*
14 NOTE: Thread safety is the responsibility fo the HAL user. All USB Host HAL
15 functions must be called from critical sections unless specified otherwise
16 */
17
18 #include <stdlib.h>
19 #include <stddef.h>
20 #include "soc/usbh_struct.h"
21 #include "hal/usbh_ll.h"
22 #include "hal/usb_types_private.h"
23 #include "hal/assert.h"
24
25 // ------------------------------------------------ Macros and Types ---------------------------------------------------
26
27 // ------------------ Constants/Configs --------------------
28
29 #define USBH_HAL_DMA_MEM_ALIGN 512
30 #define USBH_HAL_FRAME_LIST_MEM_ALIGN 512 //The frame list needs to be 512 bytes aligned (contrary to the databook)
31 #define USBH_HAL_NUM_CHAN 8
32 #define USBH_HAL_XFER_DESC_SIZE (sizeof(usbh_ll_dma_qtd_t))
33 #define USBH_HAL_FIFO_TOTAL_USABLE_LINES 200 //Although we have a 256 lines, only 200 lines are usuable due to EPINFO_CTL
34
35 /**
36 * @brief FIFO size configuration structure
37 */
38 typedef struct {
39 uint32_t rx_fifo_lines; /**< Size of the RX FIFO in terms the number of FIFO lines */
40 uint32_t nptx_fifo_lines; /**< Size of the Non-periodic FIFO in terms the number of FIFO lines */
41 uint32_t ptx_fifo_lines; /**< Size of the Periodic FIFO in terms the number of FIFO lines */
42 } usbh_hal_fifo_config_t;
43
44 // --------------------- HAL Events ------------------------
45
46 /**
47 * @brief Host port HAL events
48 */
49 typedef enum {
50 USBH_HAL_PORT_EVENT_NONE, /**< No event occurred, or could not decode interrupt */
51 USBH_HAL_PORT_EVENT_CHAN, /**< A channel event has occurred. Call the the channel event handler instead */
52 USBH_HAL_PORT_EVENT_CONN, /**< The host port has detected a connection */
53 USBH_HAL_PORT_EVENT_DISCONN, /**< The host port has been disconnected */
54 USBH_HAL_PORT_EVENT_ENABLED, /**< The host port has been enabled (i.e., connected to a device that has been reset. Started sending SOFs) */
55 USBH_HAL_PORT_EVENT_DISABLED, /**< The host port has been disabled (no more SOFs). Could be due to disable/reset request, or a port error (e.g. port babble condition. See 11.8.1 of USB2.0 spec) */
56 USBH_HAL_PORT_EVENT_OVRCUR, /**< The host port has encountered an overcurrent condition */
57 USBH_HAL_PORT_EVENT_OVRCUR_CLR, /**< The host port has been cleared of the overcurrent condition */
58 } usbh_hal_port_event_t;
59
60 /**
61 * @brief Channel events
62 */
63 typedef enum {
64 USBH_HAL_CHAN_EVENT_CPLT, /**< The channel has completed execution of a transfer descriptor that had the USBH_HAL_XFER_DESC_FLAG_HOC flag set. Channel is now halted */
65 USBH_HAL_CHAN_EVENT_ERROR, /**< The channel has encountered an error. Channel is now halted. */
66 USBH_HAL_CHAN_EVENT_HALT_REQ, /**< The channel has been successfully halted as requested */
67 USBH_HAL_CHAN_EVENT_NONE, /**< No event (interrupt ran for internal processing) */
68 } usbh_hal_chan_event_t;
69
70 // --------------------- HAL Errors ------------------------
71
72 /**
73 * @brief Channel errors
74 */
75 typedef enum {
76 USBH_HAL_CHAN_ERROR_XCS_XACT = 0, /**< Excessive (three consecutive) transaction errors (e.g., no response, bad CRC etc */
77 USBH_HAL_CHAN_ERROR_BNA, /**< Buffer Not Available error (i.e., An inactive transfer descriptor was fetched by the channel) */
78 USBH_HAL_CHAN_ERROR_PKT_BBL, /**< Packet babbler error (packet exceeded MPS) */
79 USBH_HAL_CHAN_ERROR_STALL, /**< STALL response received */
80 } usbh_hal_chan_error_t;
81
82 // ------------- Transfer Descriptor Related ---------------
83
84 /**
85 * @brief Flags used to describe the type of transfer descriptor to fill
86 */
87 #define USBH_HAL_XFER_DESC_FLAG_IN 0x01 /**< Indicates this transfer descriptor is of the IN direction */
88 #define USBH_HAL_XFER_DESC_FLAG_SETUP 0x02 /**< Indicates this transfer descriptor is an OUT setup */
89 #define USBH_HAL_XFER_DESC_FLAG_HOC 0x04 /**< Indicates that the channel will be halted after this transfer descriptor completes */
90
91 /**
92 * @brief Status value of a transfer descriptor
93 *
94 * A transfer descriptor's status remains unexecuted until the entire transfer descriptor completes (either successfully
95 * or an error). Therefore, if a channel halt is requested before a transfer descriptor completes, the transfer
96 * descriptor remains unexecuted.
97 */
98 #define USBH_HAL_XFER_DESC_STS_SUCCESS USBH_LL_QTD_STATUS_SUCCESS
99 #define USBH_HAL_XFER_DESC_STS_PKTERR USBH_LL_QTD_STATUS_PKTERR
100 #define USBH_HAL_XFER_DESC_STS_BUFFER_ERR USBH_LL_QTD_STATUS_BUFFER
101 #define USBH_HAL_XFER_DESC_STS_NOT_EXECUTED USBH_LL_QTD_STATUS_NOT_EXECUTED
102
103 // -------------------- Object Types -----------------------
104
105 /**
106 * @brief Endpoint characteristics structure
107 */
108 typedef struct {
109 union {
110 struct {
111 usb_priv_xfer_type_t type: 2; /**< The type of endpoint */
112 uint32_t bEndpointAddress: 8; /**< Endpoint address (containing endpoint number and direction) */
113 uint32_t mps: 11; /**< Maximum Packet Size */
114 uint32_t dev_addr: 8; /**< Device Address */
115 uint32_t ls_via_fs_hub: 1; /**< The endpoint is on a LS device that is routed through an FS hub.
116 Setting this bit will lead to the addition of the PREamble packet */
117 uint32_t reserved2: 2;
118 };
119 uint32_t val;
120 };
121 struct {
122 usb_hal_interval_t interval; /**< The interval of the endpoint */
123 uint32_t phase_offset_frames; /**< Phase offset in number of frames */
124 } periodic; /**< Characteristic for periodic (interrupt/isochronous) endpoints only */
125 } usbh_hal_ep_char_t;
126
127 /**
128 * @brief Channel object
129 */
130 typedef struct {
131 //Channel control, status, and information
132 union {
133 struct {
134 uint32_t active: 1; /**< Debugging bit to indicate whether channel is enabled */
135 uint32_t halt_requested: 1; /**< A halt has been requested */
136 uint32_t reserved: 2;
137 uint32_t chan_idx: 4; /**< The index number of the channel */
138 uint32_t reserved24: 24;
139 };
140 uint32_t val;
141 } flags; /**< Flags regarding channel's status and information */
142 usb_host_chan_regs_t *regs; /**< Pointer to the channel's register set */
143 usbh_hal_chan_error_t error; /**< The last error that occurred on the channel */
144 usb_priv_xfer_type_t type; /**< The transfer type of the channel */
145 void *chan_ctx; /**< Context variable for the owner of the channel */
146 } usbh_hal_chan_t;
147
148 /**
149 * @brief HAL context structure
150 */
151 typedef struct {
152 //Context
153 usbh_dev_t *dev; /**< Pointer to base address of DWC_OTG registers */
154 //Host Port related
155 uint32_t *periodic_frame_list; /**< Pointer to scheduling frame list */
156 usb_hal_frame_list_len_t frame_list_len; /**< Length of the periodic scheduling frame list */
157 union {
158 struct {
159 uint32_t dbnc_lock_enabled: 1; /**< Debounce lock enabled */
160 uint32_t fifo_sizes_set: 1; /**< Whether the FIFO sizes have been set or not */
161 uint32_t periodic_sched_enabled: 1; /**< Periodic scheduling (for interrupt and isochronous transfers) is enabled */
162 uint32_t reserved: 5;
163 uint32_t reserved24: 24;
164 };
165 uint32_t val;
166 } flags;
167 //Channel related
168 struct {
169 int num_allocd; /**< Number of channels currently allocated */
170 uint32_t chan_pend_intrs_msk; /**< Bit mask of channels with pending interrupts */
171 usbh_hal_chan_t *hdls[USBH_HAL_NUM_CHAN]; /**< Handles of each channel. Set to NULL if channel has not been allocated */
172 } channels;
173 } usbh_hal_context_t;
174
175 // -------------------------------------------------- Core (Global) ----------------------------------------------------
176
177 /**
178 * @brief Initialize the HAL context and check if DWC_OTG is alive
179 *
180 * Entry:
181 * - The peripheral must have been reset and clock un-gated
182 * - The USB PHY (internal or external) and associated GPIOs must already be configured
183 * - GPIO pins configured
184 * - Interrupt allocated but DISABLED (in case of an unknown interupt state)
185 * Exit:
186 * - Checks to see if DWC_OTG is alive, and if HW version/config is correct
187 * - HAl context initialized
188 * - Sets default values to some global and OTG registers (GAHBCFG and GUSBCFG)
189 * - Umask global interrupt signal
190 * - Put DWC_OTG into host mode. Require 25ms delay before this takes effect.
191 * - State -> USBH_HAL_PORT_STATE_OTG
192 * - Interrupts cleared. Users can now enable their ISR
193 *
194 * @param[inout] hal Context of the HAL layer
195 */
196 void usbh_hal_init(usbh_hal_context_t *hal);
197
198 /**
199 * @brief Deinitialize the HAL context
200 *
201 * Entry:
202 * - All channels must be properly disabled, and any pending events handled
203 * Exit:
204 * - DWC_OTG global interrupt disabled
205 * - HAL context deinitialized
206 *
207 * @param hal Context of the HAL layer
208 */
209 void usbh_hal_deinit(usbh_hal_context_t *hal);
210
211 /**
212 * @brief Issue a soft reset to the controller
213 *
214 * This should be called when the host port encounters an error event or has been disconnected. Before calling this,
215 * users are responsible for safely freeing all channels as a soft reset will wipe all host port and channel registers.
216 * This function will result in the host port being put back into same state as after calling usbh_hal_init().
217 *
218 * @note This has nothing to do with a USB bus reset. It simply resets the peripheral
219 *
220 * @param hal Context of the HAL layer
221 */
222 void usbh_hal_core_soft_reset(usbh_hal_context_t *hal);
223
224 /**
225 * @brief Set FIFO sizes
226 *
227 * This function will set the sizes of each of the FIFOs (RX FIFO, Non-periodic TX FIFO, Periodic TX FIFO) and must be
228 * called at least once before allocating the channel. Based on the type of endpoints (and the endpionts' MPS), there
229 * may be situations where this function may need to be called again to resize the FIFOs. If resizing FIFOs dynamically,
230 * it is the user's responsibility to ensure there are no active channels when this function is called.
231 *
232 * @note The totol size of all the FIFOs must be less than or equal to USBH_HAL_FIFO_TOTAL_USABLE_LINES
233 * @note After a port reset, the FIFO size registers will reset to their default values, so this function must be called
234 * again post reset.
235 *
236 * @param hal Context of the HAL layer
237 * @param fifo_config FIFO configuration
238 */
239 void usbh_hal_set_fifo_size(usbh_hal_context_t *hal, const usbh_hal_fifo_config_t *fifo_config);
240
241 // ---------------------------------------------------- Host Port ------------------------------------------------------
242
243 // ------------------ Host Port Control --------------------
244
245 /**
246 * @brief Initialize the host port
247 *
248 * - Will enable the host port's interrupts allowing port and channel events to occur
249 *
250 * @param hal Context of the HAL layer
251 */
usbh_hal_port_init(usbh_hal_context_t * hal)252 static inline void usbh_hal_port_init(usbh_hal_context_t *hal)
253 {
254 //Configure Host related interrupts
255 usbh_ll_haintmsk_dis_chan_intr(hal->dev, 0xFFFFFFFF); //Disable interrupts for all channels
256 usb_ll_en_intrs(hal->dev, USB_LL_INTR_CORE_PRTINT | USB_LL_INTR_CORE_HCHINT);
257 }
258
259 /**
260 * @brief Deinitialize the host port
261 *
262 * - Will disable the host port's interrupts preventing further port aand channel events from ocurring
263 *
264 * @param hal Context of the HAL layer
265 */
usbh_hal_port_deinit(usbh_hal_context_t * hal)266 static inline void usbh_hal_port_deinit(usbh_hal_context_t *hal)
267 {
268 //Disable Host port and channel interrupts
269 usb_ll_dis_intrs(hal->dev, USB_LL_INTR_CORE_PRTINT | USB_LL_INTR_CORE_HCHINT);
270 }
271
272 /**
273 * @brief Toggle the host port's power
274 *
275 * @param hal Context of the HAL layer
276 * @param power_on Whether to power ON or OFF the port
277 */
usbh_hal_port_toggle_power(usbh_hal_context_t * hal,bool power_on)278 static inline void usbh_hal_port_toggle_power(usbh_hal_context_t *hal, bool power_on)
279 {
280 if (power_on) {
281 usbh_ll_hprt_en_pwr(hal->dev);
282 } else {
283 usbh_ll_hprt_dis_pwr(hal->dev);
284 }
285 }
286
287 /**
288 * @brief Toggle reset signal on the bus
289 *
290 * The reset signal should be held for at least 10ms
291 * Entry:
292 * - Host port detects a device connection or Host port is already enabled
293 * Exit:
294 * - On release of the reset signal, a USBH_HAL_PORT_EVENT_ENABLED will be generated
295 *
296 * @note If the host port is already enabled, then issuing a reset will cause it be disabled and generate a
297 * USBH_HAL_PORT_EVENT_DISABLED event. The host port will not be enabled until the reset signal is released (thus
298 * generating the USBH_HAL_PORT_EVENT_ENABLED event)
299 *
300 * @param hal Context of the HAL layer
301 * @param enable Enable/disable reset signal
302 */
usbh_hal_port_toggle_reset(usbh_hal_context_t * hal,bool enable)303 static inline void usbh_hal_port_toggle_reset(usbh_hal_context_t *hal, bool enable)
304 {
305 HAL_ASSERT(hal->channels.num_allocd == 0); //Cannot reset if there are still allocated channels
306 usbh_ll_hprt_set_port_reset(hal->dev, enable);
307 }
308
309 /**
310 * @brief Enable the host port
311 *
312 * Entry:
313 * - Host port enabled event triggered following a reset
314 * Exit:
315 * - Host port enabled to operate in scatter/gather DMA mode
316 * - DMA fifo sizes configured
317 *
318 * @param hal Context of the HAL layer
319 */
320 void usbh_hal_port_enable(usbh_hal_context_t *hal);
321
322 /**
323 * @brief Disable the host port
324 *
325 * Exit:
326 * - Host port disabled event triggered
327 *
328 * @param hal Context of the HAL layer
329 */
usbh_hal_port_disable(usbh_hal_context_t * hal)330 static inline void usbh_hal_port_disable(usbh_hal_context_t *hal)
331 {
332 usbh_ll_hprt_port_dis(hal->dev);
333 }
334
335 /**
336 * @brief Suspend the host port
337 *
338 * @param hal Context of the HAL layers
339 */
usbh_hal_port_suspend(usbh_hal_context_t * hal)340 static inline void usbh_hal_port_suspend(usbh_hal_context_t *hal)
341 {
342 usbh_ll_hprt_set_port_suspend(hal->dev);
343 }
344
345 /**
346 * @brief Toggle resume signal on the bus
347 *
348 * Hosts should hold the resume signal for at least 20ms
349 *
350 * @note If a remote wakeup event occurs, the resume signal is driven and cleared automatically.
351 *
352 * @param hal Context of the HAL layer
353 * @param enable Enable/disable resume signal
354 */
usbh_hal_port_toggle_resume(usbh_hal_context_t * hal,bool enable)355 static inline void usbh_hal_port_toggle_resume(usbh_hal_context_t *hal, bool enable)
356 {
357 if (enable) {
358 usbh_ll_hprt_set_port_resume(hal->dev);
359 } else {
360 usbh_ll_hprt_clr_port_resume(hal->dev);
361 }
362 }
363
364 /**
365 * @brief Check whether the resume signal is being driven
366 *
367 * If a remote wakeup event occurs, the core will automatically drive and clear the resume signal for the required
368 * amount of time. Call this function to check whether the resume signal has completed.
369 *
370 * @param hal Context of the HAL layer
371 * @return true Resume signal is still being driven
372 * @return false Resume signal is no longer driven
373 */
usbh_hal_port_check_resume(usbh_hal_context_t * hal)374 static inline bool usbh_hal_port_check_resume(usbh_hal_context_t *hal)
375 {
376 return usbh_ll_hprt_get_port_resume(hal->dev);
377 }
378
379 // ---------------- Host Port Scheduling -------------------
380
381 /**
382 * @brief Sets the periodic scheduling frame list
383 *
384 * @note This function must be called before attempting configuring any channels to be period via
385 * usbh_hal_chan_set_ep_char()
386 *
387 * @param hal Context of the HAL layer
388 * @param frame_list Base address of the frame list
389 * @param frame_list_len Number of entries in the frame list (can only be 8, 16, 32, 64)
390 */
usbh_hal_port_set_frame_list(usbh_hal_context_t * hal,uint32_t * frame_list,usb_hal_frame_list_len_t len)391 static inline void usbh_hal_port_set_frame_list(usbh_hal_context_t *hal, uint32_t *frame_list, usb_hal_frame_list_len_t len)
392 {
393 //Clear and save frame list
394 hal->periodic_frame_list = frame_list;
395 hal->frame_list_len = len;
396 }
397
398 /**
399 * @brief Get the pointer to the periodic scheduling frame list
400 *
401 * @param hal Context of the HAL layer
402 * @return uint32_t* Base address of the periodic scheduling frame list
403 */
usbh_hal_port_get_frame_list(usbh_hal_context_t * hal)404 static inline uint32_t *usbh_hal_port_get_frame_list(usbh_hal_context_t *hal)
405 {
406 return hal->periodic_frame_list;
407 }
408
409 /**
410 * @brief Enable periodic scheduling
411 *
412 * @note The periodic frame list must be set via usbh_hal_port_set_frame_list() should be set before calling this
413 * function
414 * @note This function must be called before activating any periodic channels
415 *
416 * @param hal Context of the HAL layer
417 */
usbh_hal_port_periodic_enable(usbh_hal_context_t * hal)418 static inline void usbh_hal_port_periodic_enable(usbh_hal_context_t *hal)
419 {
420 HAL_ASSERT(hal->periodic_frame_list != NULL);
421 usbh_ll_set_frame_list_base_addr(hal->dev, (uint32_t)hal->periodic_frame_list);
422 usbh_ll_hcfg_set_num_frame_list_entries(hal->dev, hal->frame_list_len);
423 usbh_ll_hcfg_en_perio_sched(hal->dev);
424 hal->flags.periodic_sched_enabled = 1;
425 }
426
427 /**
428 * @brief Disable periodic scheduling
429 *
430 * Disabling periodic scheduling will save a bit of DMA bandwith (as the controller will no longer fetch the schedule
431 * from the frame list).
432 *
433 * @note Before disabling periodic scheduling, it is the user's responsibility to ensure that all periodic channels have
434 * halted safely.
435 *
436 * @param hal Context of the HAL layer
437 */
usbh_hal_port_periodic_disable(usbh_hal_context_t * hal)438 static inline void usbh_hal_port_periodic_disable(usbh_hal_context_t *hal)
439 {
440 HAL_ASSERT(hal->flags.periodic_sched_enabled);
441 usbh_ll_hcfg_dis_perio_sched(hal->dev);
442 hal->flags.periodic_sched_enabled = 0;
443 }
444
usbh_hal_port_get_cur_frame_num(usbh_hal_context_t * hal)445 static inline uint32_t usbh_hal_port_get_cur_frame_num(usbh_hal_context_t *hal)
446 {
447 return usbh_ll_get_frm_num(hal->dev);
448 }
449
450 // --------------- Host Port Status/State ------------------
451
452 /**
453 * @brief Check if a device is currently connected to the host port
454 *
455 * This function is intended to be called after one of the following events followed by an adequate debounce delay
456 * - USBH_HAL_PORT_EVENT_CONN
457 * - USBH_HAL_PORT_EVENT_DISCONN
458 *
459 * @note No other connection/disconnection event will occur again until the debounce lock is disabled via
460 * usbh_hal_disable_debounce_lock()
461 *
462 * @param hal Context of the HAL layer
463 * @return true A device is connected to the host port
464 * @return false A device is not connected to the host port
465 */
usbh_hal_port_check_if_connected(usbh_hal_context_t * hal)466 static inline bool usbh_hal_port_check_if_connected(usbh_hal_context_t *hal)
467 {
468 return usbh_ll_hprt_get_conn_status(hal->dev);
469 }
470
471 /**
472 * @brief Check the speed (LS/FS) of the device connected to the host port
473 *
474 * @note This function should only be called after confirming that a device is connected to the host port
475 *
476 * @param hal Context of the HAL layer
477 * @return usb_priv_speed_t Speed of the connected device (FS or LS only on the esp32-s2 and esp32-s3)
478 */
usbh_hal_port_get_conn_speed(usbh_hal_context_t * hal)479 static inline usb_priv_speed_t usbh_hal_port_get_conn_speed(usbh_hal_context_t *hal)
480 {
481 return usbh_ll_hprt_get_speed(hal->dev);
482 }
483
484 /**
485 * @brief Disable the debounce lock
486 *
487 * This function must be called after calling usbh_hal_port_check_if_connected() and will allow connection/disconnection
488 * events to occur again. Any pending connection or disconenction interrupts are cleared.
489 *
490 * @param hal Context of the HAL layer
491 */
usbh_hal_disable_debounce_lock(usbh_hal_context_t * hal)492 static inline void usbh_hal_disable_debounce_lock(usbh_hal_context_t *hal)
493 {
494 hal->flags.dbnc_lock_enabled = 0;
495 //Clear Conenction and disconenction interrupt in case it triggered again
496 usb_ll_intr_clear(hal->dev, USB_LL_INTR_CORE_DISCONNINT);
497 usbh_ll_hprt_intr_clear(hal->dev, USBH_LL_INTR_HPRT_PRTCONNDET);
498 //Reenable the hprt (connection) and disconnection interrupts
499 usb_ll_en_intrs(hal->dev, USB_LL_INTR_CORE_PRTINT | USB_LL_INTR_CORE_DISCONNINT);
500 }
501
502 // ----------------------------------------------------- Channel -------------------------------------------------------
503
504 // ----------------- Channel Allocation --------------------
505
506 /**
507 * @brief Allocate a channel
508 *
509 * @param[in] hal Context of the HAL layer
510 * @param[inout] chan_obj Empty channel object
511 * @param[in] chan_ctx Context variable for the allocator of the channel
512 * @return true Channel successfully allocated
513 * @return false Failed to allocate channel
514 */
515 bool usbh_hal_chan_alloc(usbh_hal_context_t *hal, usbh_hal_chan_t *chan_obj, void *chan_ctx);
516
517 /**
518 * @brief Free a channel
519 *
520 * @param[in] hal Context of the HAL layer
521 * @param[in] chan_obj Channel object
522 */
523 void usbh_hal_chan_free(usbh_hal_context_t *hal, usbh_hal_chan_t *chan_obj);
524
525 // ---------------- Channel Configuration ------------------
526
527 /**
528 * @brief Get the context variable of the channel
529 *
530 * @param[in] chan_obj Channel object
531 * @return void* The context variable of the channel
532 */
usbh_hal_chan_get_context(usbh_hal_chan_t * chan_obj)533 static inline void *usbh_hal_chan_get_context(usbh_hal_chan_t *chan_obj)
534 {
535 return chan_obj->chan_ctx;
536 }
537
538 /**
539 * @brief Set the endpoint information for a particular channel
540 *
541 * This should be called when a channel switches target from one EP to another
542 *
543 * @note the channel must be in the disabled state in order to change its EP
544 * information
545 *
546 * @param hal Context of the HAL layer
547 * @param chan_obj Channel object
548 * @param ep_char Endpoint characteristics
549 */
550 void usbh_hal_chan_set_ep_char(usbh_hal_context_t *hal, usbh_hal_chan_t *chan_obj, usbh_hal_ep_char_t *ep_char);
551
552 /**
553 * @brief Set the direction of the channel
554 *
555 * This is a convenience function to flip the direction of a channel without
556 * needing to reconfigure all of the channel's EP info. This is used primarily
557 * for control transfers.
558 *
559 * @note This function should only be called when the channel is halted
560 *
561 * @param chan_obj Channel object
562 * @param is_in Whether the direction is IN
563 */
usbh_hal_chan_set_dir(usbh_hal_chan_t * chan_obj,bool is_in)564 static inline void usbh_hal_chan_set_dir(usbh_hal_chan_t *chan_obj, bool is_in)
565 {
566 //Cannot change direction whilst channel is still active or in error
567 HAL_ASSERT(!chan_obj->flags.active);
568 usbh_ll_chan_set_dir(chan_obj->regs, is_in);
569 }
570
571 /**
572 * @brief Set the next Packet ID of the channel (e.g., DATA0/DATA1)
573 *
574 * This should be called when a channel switches target from one EP to another
575 * or when change stages for a control transfer
576 *
577 * @note The channel should only be called when the channel is in the
578 * halted state.
579 *
580 * @param chan_obj Channel object
581 * @param pid PID of the next DATA packet (DATA0 or DATA1)
582 */
usbh_hal_chan_set_pid(usbh_hal_chan_t * chan_obj,int pid)583 static inline void usbh_hal_chan_set_pid(usbh_hal_chan_t *chan_obj, int pid)
584 {
585 //Cannot change pid whilst channel is still active or in error
586 HAL_ASSERT(!chan_obj->flags.active);
587 //Update channel object and set the register
588 usbh_ll_chan_set_pid(chan_obj->regs, pid);
589 }
590
591 /**
592 * @brief Get the next PID of a channel
593 *
594 * Returns the next PID (DATA0 or DATA1) of the channel. This function should be
595 * used when the next PID of a pipe needs to be saved (e.g., when switching pipes
596 * on a channel)
597 *
598 * @param chan_obj Channel object
599 * @return uint32_t Starting PID of the next transfer (DATA0 or DATA1)
600 */
usbh_hal_chan_get_pid(usbh_hal_chan_t * chan_obj)601 static inline uint32_t usbh_hal_chan_get_pid(usbh_hal_chan_t *chan_obj)
602 {
603 HAL_ASSERT(!chan_obj->flags.active);
604 return usbh_ll_chan_get_pid(chan_obj->regs);
605 }
606
607 // ------------------- Channel Control ---------------------
608
609 /**
610 * @brief Activate a channel
611 *
612 * Activating a channel will cause the channel to start executing transfer descriptors.
613 *
614 * @note This function should only be called on channels that were previously halted
615 * @note An event will be generated when the channel is halted
616 *
617 * @param chan_obj Channel object
618 * @param xfer_desc_list A filled transfer descriptor list
619 * @param desc_list_len Transfer descriptor list length
620 * @param start_idx Index of the starting transfer descriptor in the list
621 */
622 void usbh_hal_chan_activate(usbh_hal_chan_t *chan_obj, void *xfer_desc_list, int desc_list_len, int start_idx);
623
624 /**
625 * @brief Get the index of the current transfer descriptor
626 *
627 * @param chan_obj Channel object
628 * @return int Descriptor index
629 */
usbh_hal_chan_get_qtd_idx(usbh_hal_chan_t * chan_obj)630 static inline int usbh_hal_chan_get_qtd_idx(usbh_hal_chan_t *chan_obj)
631 {
632 return usbh_ll_chan_get_ctd(chan_obj->regs);
633 }
634
635 /**
636 * @brief Request to halt a channel
637 *
638 * This function should be called in order to halt a channel. If the channel is already halted, this function will
639 * return true. If the channel is still active, this function will return false and users must wait for the
640 * USBH_HAL_CHAN_EVENT_HALT_REQ event before treating the channel as halted.
641 *
642 * @note When a transfer is in progress (i.e., the channel is active) and a halt is requested, the channel will halt
643 * after the next USB packet is completed. If the transfer has more pending packets, the transfer will just be
644 * marked as USBH_HAL_XFER_DESC_STS_NOT_EXECUTED.
645 *
646 * @param chan_obj Channel object
647 * @return true The channel is already halted
648 * @return false The halt was requested, wait for USBH_HAL_CHAN_EVENT_HALT_REQ
649 */
650 bool usbh_hal_chan_request_halt(usbh_hal_chan_t *chan_obj);
651
652 /**
653 * @brief Indicate that a channel is halted after a port error
654 *
655 * When a port error occurs (e.g., discconect, overcurrent):
656 * - Any previously active channels will remain active (i.e., they will not receive a channel interrupt)
657 * - Attempting to disable them using usbh_hal_chan_request_halt() will NOT generate an interrupt for ISOC channels
658 * (probalby something to do with the periodic scheduling)
659 *
660 * However, the channel's enable bit can be left as 1 since after a port error, a soft reset will be done anyways.
661 * This function simply updates the channels internal state variable to indicate it is halted (thus allowing it to be
662 * freed).
663 *
664 * @param chan_obj Channel object
665 */
usbh_hal_chan_mark_halted(usbh_hal_chan_t * chan_obj)666 static inline void usbh_hal_chan_mark_halted(usbh_hal_chan_t *chan_obj)
667 {
668 chan_obj->flags.active = 0;
669 }
670
671 /**
672 * @brief Get a channel's error
673 *
674 * @param chan_obj Channel object
675 * @return usbh_hal_chan_error_t The type of error the channel has encountered
676 */
usbh_hal_chan_get_error(usbh_hal_chan_t * chan_obj)677 static inline usbh_hal_chan_error_t usbh_hal_chan_get_error(usbh_hal_chan_t *chan_obj)
678 {
679 return chan_obj->error;
680 }
681
682 // -------------------------------------------- Transfer Descriptor List -----------------------------------------------
683
684 /**
685 * @brief Fill a single entry in a transfer descriptor list
686 *
687 * - Depending on the transfer type, a single transfer descriptor may corresponds
688 * - A stage of a transfer (for control transfers)
689 * - A frame of a transfer interval (for interrupt and isoc)
690 * - An entire transfer (for bulk transfers)
691 * - Check the various USBH_HAL_XFER_DESC_FLAG_ flags for filling a specific type of descriptor
692 * - For IN transfer entries, set the USBH_HAL_XFER_DESC_FLAG_IN. The transfer size must also be an integer multiple of
693 * the endpoint's MPS
694 *
695 * @note Critical section is not required for this function
696 *
697 * @param desc_list Transfer descriptor list
698 * @param desc_idx Transfer descriptor index
699 * @param xfer_data_buff Transfer data buffer
700 * @param xfer_len Transfer length
701 * @param flags Transfer flags
702 */
usbh_hal_xfer_desc_fill(void * desc_list,uint32_t desc_idx,uint8_t * xfer_data_buff,int xfer_len,uint32_t flags)703 static inline void usbh_hal_xfer_desc_fill(void *desc_list, uint32_t desc_idx, uint8_t *xfer_data_buff, int xfer_len, uint32_t flags)
704 {
705 usbh_ll_dma_qtd_t *qtd_list = (usbh_ll_dma_qtd_t *)desc_list;
706 if (flags & USBH_HAL_XFER_DESC_FLAG_IN) {
707 usbh_ll_set_qtd_in(&qtd_list[desc_idx],
708 xfer_data_buff, xfer_len,
709 flags & USBH_HAL_XFER_DESC_FLAG_HOC);
710 } else {
711 usbh_ll_set_qtd_out(&qtd_list[desc_idx],
712 xfer_data_buff,
713 xfer_len,
714 flags & USBH_HAL_XFER_DESC_FLAG_HOC,
715 flags & USBH_HAL_XFER_DESC_FLAG_SETUP);
716 }
717 }
718
719 /**
720 * @brief Clear a transfer descriptor (sets all its fields to NULL)
721 *
722 * @param desc_list Transfer descriptor list
723 * @param desc_idx Transfer descriptor index
724 */
usbh_hal_xfer_desc_clear(void * desc_list,uint32_t desc_idx)725 static inline void usbh_hal_xfer_desc_clear(void *desc_list, uint32_t desc_idx)
726 {
727 usbh_ll_dma_qtd_t *qtd_list = (usbh_ll_dma_qtd_t *)desc_list;
728 usbh_ll_set_qtd_null(&qtd_list[desc_idx]);
729 }
730
731 /**
732 * @brief Parse a transfer decriptor's results
733 *
734 * @param desc_list Transfer descriptor list
735 * @param desc_idx Transfer descriptor index
736 * @param[out] xfer_rem_len Remaining length of the transfer in bytes
737 * @param[out] xfer_status Status of the transfer
738 *
739 * @note Critical section is not required for this function
740 */
usbh_hal_xfer_desc_parse(void * desc_list,uint32_t desc_idx,int * xfer_rem_len,int * xfer_status)741 static inline void usbh_hal_xfer_desc_parse(void *desc_list, uint32_t desc_idx, int *xfer_rem_len, int *xfer_status)
742 {
743 usbh_ll_dma_qtd_t *qtd_list = (usbh_ll_dma_qtd_t *)desc_list;
744 usbh_ll_get_qtd_status(&qtd_list[desc_idx], xfer_rem_len, xfer_status);
745 //Clear the QTD to prevent it from being read again
746 usbh_ll_set_qtd_null(&qtd_list[desc_idx]);
747 }
748
749 // ------------------------------------------------- Event Handling ----------------------------------------------------
750
751 /**
752 * @brief Decode global and host port interrupts
753 *
754 * - Reads and clears global and host port interrupt registers
755 * - Decodes the interrupt bits to determine what host port event occurred
756 *
757 * @note This should be the first interrupt decode function to be run
758 *
759 * @param hal Context of the HAL layer
760 * @return usbh_hal_port_event_t Host port event
761 */
762 usbh_hal_port_event_t usbh_hal_decode_intr(usbh_hal_context_t *hal);
763
764 /**
765 * @brief Gets the next channel with a pending interrupt
766 *
767 * If no channel is pending an interrupt, this function will return NULL. If one or more channels are pending an
768 * interrupt, this function returns one of the channel's objects. Call this function repeatedly until it returns NULL.
769 *
770 * @param hal Context of the HAL layer
771 * @return usbh_hal_chan_t* Channel object. NULL if no channel are pending an interrupt.
772 */
773 usbh_hal_chan_t *usbh_hal_get_chan_pending_intr(usbh_hal_context_t *hal);
774
775 /**
776 * @brief Decode a particular channel's interrupt
777 *
778 * - Reads and clears the interrupt register of the channel
779 * - Returns the corresponding event for that channel
780 *
781 * @param chan_obj Channel object
782 * @note If the host port has an error (e.g., a sudden disconnect or an port error), any active channels will not
783 * receive an interrupt. Each active channel must be manually halted.
784 * @return usbh_hal_chan_event_t Channel event
785 */
786 usbh_hal_chan_event_t usbh_hal_chan_decode_intr(usbh_hal_chan_t *chan_obj);
787
788 #ifdef __cplusplus
789 }
790 #endif
791