1 /**
2  * @file xmc_usbh.c
3  * @date 2019-05-07
4  *
5  * @cond
6  **********************************************************************************
7  * XMClib v2.1.24 - XMC Peripheral Driver Library
8  *
9  * Copyright (c) 2015-2019, Infineon Technologies AG
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without modification,are permitted provided that the
13  * following conditions are met:
14  *
15  * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
16  * disclaimer.
17  *
18  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
19  * disclaimer in the documentation and/or other materials provided with the distribution.
20  *
21  * Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote
22  * products derived from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
25  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE  FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29  * WHETHER IN CONTRACT, STRICT LIABILITY,OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  * (To improve the quality of the software, users are encouraged to share modifications, enhancements or bug fixes with
33  * Infineon Technologies AG dave@infineon.com).
34  *
35  *********************************************************************************************************************
36  *
37  * Change History
38  * --------------
39  *
40  * 2016-06-30:
41  *     - Initial <br>
42  * 2016-09-01:
43  *     - Removed Keil specific exclusion<br>
44  * 2018-06-21:
45  *     - Fixed compilation issues for XMC42
46  * 2019-05-07:
47  *     - Fixed compilation warnings
48  * @endcond
49  *
50  */
51 
52 #include "xmc_usbh.h"
53 
54 #if ((UC_SERIES == XMC45) || (UC_SERIES == XMC44) || (UC_SERIES == XMC43) || (UC_SERIES == XMC47) || (UC_SERIES == XMC48))
55 
56 /*Function provides transfer result*/
57 static uint32_t XMC_USBH_PipeTransferGetResult (XMC_USBH_PIPE_HANDLE pipe_hndl);
58 /*Updates the power state of the driver*/
59 static int32_t XMC_USBH_PowerControl (XMC_USBH_POWER_STATE_t state);
60 
61 /*********************************************************** USBH Driver ***************************************************************** */
62 
63 /*Macro to represent USB host driver version*/
64 #define XMC_USBH_DRV_VERSION ((uint16_t)((uint16_t)XMC_LIB_MINOR_VERSION << 8U)|XMC_LIB_PATCH_VERSION)
65 /*Macro used to gate PHY clock and AHB clock*/
66 #define XMC_USBH_PHY_CLK_STOP  (0x03U)
67 /*Macro used to ungate PHY clock and AHB clock*/
68 #define XMC_USBH_PHY_CLK_UNGATE  (0x100U)
69 
70 /* Driver Version */
71 static const XMC_USBH_DRIVER_VERSION_t xmc_usbh_driver_version = { XMC_USBH_API_VERSION, XMC_USBH_DRV_VERSION };
72 
73 /*Variables to hold selected VBUS port pin*/
74 XMC_GPIO_PORT_t * VBUS_port = XMC_GPIO_PORT3;
75 uint32_t VBUS_pin = 2U;
76 
77 /*Array to track nack events on each pipe*/
78 bool is_nack[USBH0_MAX_PIPE_NUM];
79 
80 /* Driver Capabilities */
81 static const XMC_USBH_CAPABILITIES_t xmc_usbh_driver_capabilities = {
82   0x0001U,      /* Root HUB available Ports Mask */
83   0U,           /* Automatic SPLIT packet handling */
84   1U,           /* Signal Connect event */
85   1U,           /* Signal Disconnect event */
86   0U            /* Signal Overcurrent event */
87 };
88 /* Driver state and registers */
89 static XMC_USBH0_DEVICE_t XMC_USBH0_device/* __attribute__((section ("RW_IRAM1")))*/ = {
90    (USB0_GLOBAL_TypeDef *)(USB0_BASE),    /** Global register interface            */
91    ((USB0_CH_TypeDef *)(USB0_CH0_BASE)),  /** Host channel interface               */
92    0,                                     /** Port event callback; set during init */
93    0,                                     /** Pipe event callback; set during init */
94    false,                                 /** init status */
95    XMC_USBH_POWER_OFF,                    /** USB Power status */
96    false                                  /** Port reset state */
97 };
98 
99 /*USB host pipe information. The array stores information related to packet id, data toggle,
100  * pending data transfer information, periodic transfer interval, received data size etc for each
101  * pipe.*/
102 volatile XMC_USBH0_pipe_t pipe[USBH0_MAX_PIPE_NUM];
103 
104 /* FIFO sizes in bytes (total available memory for FIFOs is 1.25 kB) */
105 #define RX_FIFO_SIZE           (1128U)   /* RxFIFO size */
106 #define TX_FIFO_SIZE_NON_PERI  (64U)     /* Non-periodic Tx FIFO size */
107 #define TX_FIFO_SIZE_PERI      (1024U)   /* Periodic Tx FIFO size */
108 
109 /*Stores data FIFO pointer for each pipe*/
110 static uint32_t *XMC_USBH0_dfifo_ptr[USBH0_MAX_PIPE_NUM];
111 
112 /* Local functions */
113 /**
114  * @param   enable Enable (XMC_USBH_CLOCK_GATING_ENABLE) or disable(XMC_USBH_CLOCK_GATING_DISABLE) clock gating
115  * @return  None
116  * \par<b>Description:</b><br>
117  * Enable/disable clock gating depending if feature is supported.
118 */
XMC_lClockGating(uint8_t enable)119 __INLINE static void XMC_lClockGating(uint8_t enable)
120 {
121 #if defined(CLOCK_GATING_SUPPORTED)
122    if (enable == XMC_USBH_CLOCK_GATING_ENABLE)
123    {
124      XMC_SCU_CLOCK_GatePeripheralClock(XMC_SCU_PERIPHERAL_CLOCK_USB0);
125    }
126    if (enable == XMC_USBH_CLOCK_GATING_DISABLE)
127    {
128      XMC_SCU_CLOCK_UngatePeripheralClock(XMC_SCU_PERIPHERAL_CLOCK_USB0);
129    }
130 #else
131    XMC_UNUSED_ARG(enable);
132 #endif
133 
134   return;
135 }
136 
137 /**
138  * @param   ptr_ch Pointer to Channel
139  * @return  None
140  * \par<b>Description:</b><br>
141  * Triggers halt of a channel.
142 */
XMC_lTriggerHaltChannel(USB0_CH_TypeDef * ptr_ch)143 __INLINE static void XMC_lTriggerHaltChannel(USB0_CH_TypeDef *ptr_ch)
144 {
145   ptr_ch->HCINTMSK = USB_CH_HCINT_ChHltd_Msk; /* Enable halt interrupt */
146   ptr_ch->HCCHAR  |= (uint32_t)(USB_CH_HCCHAR_ChEna_Msk | USB_CH_HCCHAR_ChDis_Msk);
147   return;
148 }
149 
150 /**
151  * @param   ptr_pipe Pointer to Pipe
152  * @param   ptr_ch   Pointer to Channel
153  * @return  bool \n
154  *          true = success,\n
155  *          false = fail
156  * \par<b>Description:</b><br>
157  * Start transfer on Pipe. The function uses transfer complete interrupts to transfer data more than maximum
158  * packet size. It takes care of updating data toggle information in subsequent packets related to the same data transfer.
159 */
XMC_lStartTransfer(XMC_USBH0_pipe_t * ptr_pipe,USB0_CH_TypeDef * ptr_ch)160 static bool XMC_lStartTransfer (XMC_USBH0_pipe_t *ptr_pipe, USB0_CH_TypeDef *ptr_ch) {
161   uint32_t  hcchar;
162   uint32_t  hctsiz;
163   uint32_t  hcintmsk;
164   uint32_t  num_remaining_transfer;
165   uint32_t  num_remaining_fifo;
166   uint32_t  num_remaining_queue;
167   uint32_t  txsts = 0U;
168   uint32_t  pckt_num;
169   uint32_t  max_pckt_size;
170   uint8_t   *ptr_src = ptr_pipe->data;
171   uint32_t  *ptr_dest = NULL;
172   uint16_t  cnt;
173   uint32_t loc_index;
174   bool status;
175 
176   if (!(XMC_USBH0_device.global_register->HPRT & USB_HPRT_PrtConnSts_Msk))
177   {
178     status = false;
179   }
180   else
181   {
182     /* Save channel characteristic register to local variable */
183     hcchar   = ptr_ch->HCCHAR;
184     /* Save transfer size register to local variable */
185     hctsiz   = ptr_ch->HCTSIZ_BUFFERMODE;
186     hcintmsk = 0U;
187     cnt      = 0U;
188 
189     /* Prepare transfer */
190     /* Reset EPDir (transfer direction = output) and enable channel */
191     hcchar &= (uint32_t)(~(uint32_t)(USB_CH_HCCHAR_EPDir_Msk | USB_CH_HCCHAR_ChDis_Msk));
192     hcchar |= (uint32_t)USB_CH_HCCHAR_ChEna_Msk;
193 
194     /* Enable default interrupts needed for all transfers */
195     hcintmsk  = (USB_CH_HCINTMSK_XactErrMsk_Msk  |
196                  USB_CH_HCINTMSK_XferComplMsk_Msk |
197                  USB_CH_HCINTMSK_NakMsk_Msk    |
198                  USB_CH_HCINTMSK_StallMsk_Msk)  ;
199     /* Keep PID */
200     hctsiz &=  (uint32_t)USB_CH_HCTSIZ_BUFFERMODE_Pid_Msk;
201 
202     /* Packet specific setup */
203     switch (ptr_pipe->packet & XMC_USBH_PACKET_TOKEN_Msk) {
204       case XMC_USBH_PACKET_IN:
205         /* set transfer direction to input */
206         hcchar   |=  (uint32_t)USB_CH_HCCHAR_EPDir_Msk;
207         /* Enable IN transfer specific interrupts */
208         hcintmsk  |= (uint32_t)( USB_CH_HCINTMSK_DataTglErrMsk_Msk  |
209                        USB_CH_HCINTMSK_BblErrMsk_Msk |
210                        USB_CH_HCINTMSK_AckMsk_Msk    |
211                        USB_CH_HCINTMSK_NakMsk_Msk )  ;
212         break;
213       case XMC_USBH_PACKET_OUT:
214         break;
215       case XMC_USBH_PACKET_SETUP:
216         hctsiz   &= (uint32_t)~USB_CH_HCTSIZ_BUFFERMODE_Pid_Msk  ;
217         hctsiz   |= (uint32_t)USB_CH_HCTSIZx_DPID_MDATA;
218         break;
219       default:
220         break;
221     }
222     /* Prepare PID */
223     switch (ptr_pipe->packet & XMC_USBH_PACKET_DATA_Msk) {
224       case XMC_USBH_PACKET_DATA0:
225         hctsiz   &= (uint32_t)~USB_CH_HCTSIZ_BUFFERMODE_Pid_Msk;
226         hctsiz   |= (uint32_t)USB_CH_HCTSIZx_DPID_DATA0;
227         break;
228       case XMC_USBH_PACKET_DATA1:
229         hctsiz   &= (uint32_t)~USB_CH_HCTSIZ_BUFFERMODE_Pid_Msk;
230         hctsiz   |= (uint32_t)USB_CH_HCTSIZx_DPID_DATA1;
231         break;
232       default:
233         break;
234     }
235 
236     /* Prepare odd/even frame */
237     if ((XMC_USBH0_device.global_register->HFNUM & 1U) != 0U) {
238       hcchar &= (uint32_t)~USB_CH_HCCHAR_OddFrm_Msk;
239     } else {
240       hcchar |= (uint32_t)USB_CH_HCCHAR_OddFrm_Msk;
241     }
242 
243     /* Get transfer type specific status */
244     switch (ptr_pipe->ep_type) {
245       case XMC_USBH_ENDPOINT_CONTROL:
246       case XMC_USBH_ENDPOINT_BULK:
247         if (!(hcchar & USB_CH_HCCHAR_EPDir_Msk)) {
248           txsts = XMC_USBH0_device.global_register->GNPTXSTS;
249         }
250         break;
251       case XMC_USBH_ENDPOINT_ISOCHRONOUS:
252       case XMC_USBH_ENDPOINT_INTERRUPT:
253         if (!(hcchar & USB_CH_HCCHAR_EPDir_Msk)) {
254           txsts = XMC_USBH0_device.global_register->HPTXSTS;
255         }
256         break;
257       default:
258         break;
259     }
260 
261     /* Calculate remaining transfer size */
262     num_remaining_transfer = ptr_pipe->num - ptr_pipe->num_transferred_total;
263     /* Limit transfer to available space inside fifo/queue if OUT transaction */
264     if ((uint32_t)(hcchar & USB_CH_HCCHAR_EPDir_Msk) == 0U) {
265       max_pckt_size =  ptr_pipe->ep_max_packet_size;
266       num_remaining_fifo = (uint32_t)((uint32_t)(txsts & 0x0000FFFFU) <<  2);
267       num_remaining_queue  = (uint32_t)((uint32_t)(txsts & 0x00FF0000U) >> 16);
268       if (num_remaining_transfer > num_remaining_fifo) {
269         num_remaining_transfer = num_remaining_fifo;
270       }
271       pckt_num = (uint32_t)((num_remaining_transfer + (max_pckt_size - 1U)) / max_pckt_size);
272       if (pckt_num > num_remaining_queue) {
273         pckt_num = num_remaining_queue;
274       }
275       if (num_remaining_transfer > (pckt_num * max_pckt_size)) {
276         num_remaining_transfer = pckt_num * max_pckt_size;
277       }
278       cnt = (uint16_t)((num_remaining_transfer + 3U) / 4U);
279       ptr_src  = ptr_pipe->data + ptr_pipe->num_transferred_total;
280       loc_index = ((USB0_CH_TypeDef *)ptr_ch - (USB0_CH_TypeDef *)(XMC_USBH0_device.host_channel_registers));
281       ptr_dest = (uint32_t *)XMC_USBH0_dfifo_ptr[loc_index];
282       /* For OUT/SETUP transfer num_transferring represents num of bytes to be sent */
283       ptr_pipe->num_transferring = num_remaining_transfer;
284     }
285     else {
286       /* For IN transfer num_transferring is zero */
287       ptr_pipe->num_transferring = 0U;
288     }
289     /* Set packet count and transfer size */
290     if (num_remaining_transfer != 0U) {
291       hctsiz |= (((num_remaining_transfer + ptr_pipe->ep_max_packet_size) - 1U) / ptr_pipe->ep_max_packet_size) << 19U;
292       hctsiz |=   num_remaining_transfer;
293     } else {                                                 /* Zero length packet */
294       hctsiz |= ((uint32_t)1U << USB_CH_HCTSIZ_BUFFERMODE_PktCnt_Pos); /* Packet count = 1 */
295       hctsiz |= 0U;                                        /* Transfer size = 0 */
296     }
297     NVIC_DisableIRQ (USB0_0_IRQn);
298     ptr_ch->HCINTMSK = hcintmsk;                  /* Enable channel interrupts */
299     ptr_ch->HCTSIZ_BUFFERMODE = hctsiz;           /* Write ch transfer size */
300     ptr_ch->HCCHAR = hcchar;                      /* Write ch characteristics */
301     while (cnt != 0U) {                           /* Load data */
302 #if defined __TASKING__/*tasking*/
303       *ptr_dest = *((__unaligned uint32_t *)ptr_src);
304 #else/* defined (__GNUC__) || defined (__CC_ARM) || defined (__ICCARM__)*/
305       *ptr_dest = *((__packed uint32_t *)ptr_src);
306 #endif
307       ptr_src  += 4U;
308       cnt--;
309     }
310     NVIC_EnableIRQ  (USB0_0_IRQn);                /* Enable OTG interrupt */
311     status = true;
312   }
313   return status;
314 }
315 
316 /* USB driver API functions */
317 /**
318  * @return      \ref XMC_USBH_DRIVER_VERSION_t
319  * \par<b>Description:</b><br>
320  * Get driver version.
321 */
XMC_USBH_GetVersion(void)322 static XMC_USBH_DRIVER_VERSION_t XMC_USBH_GetVersion (void) { return xmc_usbh_driver_version; }
323 
324 /**
325  * @return  \ref XMC_USBH_CAPABILITIES_t
326  * \par<b>Description:</b><br>
327  * Get driver capabilities.
328 */
XMC_USBH_GetCapabilities(void)329 static XMC_USBH_CAPABILITIES_t XMC_USBH_GetCapabilities (void) { return xmc_usbh_driver_capabilities; }
330 
331 /**
332  * @param   cb_port_event  Pointer to port event callback function \ref ARM_USBH_SignalPortEvent
333  * @param   cb_pipe_event  Pointer to pipe event callback function \ref ARM_USBH_SignalPipeEvent
334  * @return  int32_t \ref Execution_status. 0 if execution is successful.
335  *
336  * \par<b>Description:</b><br>
337  * Initialize USB Host Interface. Registers callback functions to be executed on port event and pipe event.
338  * Initializes FIFO address for each pipe. Configures P3.2 as the VBUS charge pump enable pin.\n
339  *
340  *  \par<b>Related APIs:</b><BR>
341  *  XMC_USBH_Select_VBUS(), XMC_USBH_Uninitialize() \n
342 */
XMC_USBH_Initialize(XMC_USBH_SignalPortEvent_t cb_port_event,XMC_USBH_SignalPipeEvent_t cb_pipe_event)343 static int32_t XMC_USBH_Initialize (XMC_USBH_SignalPortEvent_t cb_port_event,
344                                 XMC_USBH_SignalPipeEvent_t cb_pipe_event) {
345 
346   uint32_t channel;
347   int32_t status = XMC_USBH_DRIVER_OK;
348   if (XMC_USBH0_device.init_done == true)
349   {
350     /*return ok since initialized*/
351   }
352   else
353   {
354     /* assign callbacks */
355     XMC_USBH0_device.SignalPortEvent_cb = cb_port_event;
356     XMC_USBH0_device.SignalPipeEvent_cb = cb_pipe_event;
357 
358     /* assign fifo start addresses */
359     for (channel = 0U; channel < USBH0_MAX_PIPE_NUM; channel++) {
360       XMC_USBH0_dfifo_ptr[channel] = (uint32_t *)((uint32_t)USB0_BASE + ((channel + 1U) * 0x01000U));
361     }
362 
363     XMC_GPIO_SetMode(VBUS_port, (uint8_t)VBUS_pin, XMC_GPIO_MODE_OUTPUT_PUSH_PULL_ALT1);
364 
365     XMC_USBH0_device.init_done = true;
366   }
367   return status;
368 }
369 
370 /**
371  * @return int32_t \ref Execution_status. Returns 0 to indicate success.
372  * \par<b>Description:</b><br>
373  * De-initialize USB Host Interface. Sets the driver power state as powered off. Disables VBUS.\n
374  *
375  * \par<b>Related APIs:</b><BR>
376  *  XMC_USBH_Select_VBUS(), XMC_USBH_Initialize(), XMC_USBH_PortVbusOnOff() \n
377 */
XMC_USBH_Uninitialize(void)378 static int32_t XMC_USBH_Uninitialize (void) {
379   XMC_USBH0_device.init_done = false;
380   (void)XMC_USBH_PowerControl(XMC_USBH_POWER_OFF);
381   return XMC_USBH_DRIVER_OK;
382 }
383 
384 /**
385  * @param  state  Power state. \ref XMC_USBH_POWER_STATE_t
386  * @return int32_t \ref Execution_status. Returns 0 if successful.
387  * \par<b>Description:</b><br>
388  * Control USB Host Interface Power. If power state is set to \ref XMC_USBH_POWER_FULL,
389  * it initializes the peripheral and enables VBUS. If power state is set to \ref XMC_USBH_POWER_OFF,
390  * disables the peripheral and the VBUS.\n
391  *
392  * \par<b>Related APIs:</b><BR>
393  *  XMC_USBH_Select_VBUS(), XMC_USBH_Initialize(), XMC_USBH_PortVbusOnOff(), XMC_USBH_Uninitialize() \n
394 */
XMC_USBH_PowerControl(XMC_USBH_POWER_STATE_t state)395 static int32_t XMC_USBH_PowerControl (XMC_USBH_POWER_STATE_t state) {
396   int32_t status = XMC_USBH_DRIVER_OK;
397   uint32_t loc_value;
398   switch (state) {
399     case XMC_USBH_POWER_LOW:
400       status = XMC_USBH_DRIVER_ERROR_UNSUPPORTED;
401       break;
402     case XMC_USBH_POWER_OFF:
403       NVIC_DisableIRQ  (USB0_0_IRQn);
404       NVIC_ClearPendingIRQ (USB0_0_IRQn); /* Clear pending interrupt */
405       XMC_USBH0_device.power_state =  state; /* Clear powered flag */
406       XMC_USBH0_device.global_register->GAHBCFG  &= (uint32_t)(~USB_GAHBCFG_GlblIntrMsk_Msk); /* Disable USB interrupts */
407       XMC_lClockGating((uint8_t)XMC_USBH_CLOCK_GATING_ENABLE); /* Enable Clock Gating */
408       XMC_USBH0_device.global_register->PCGCCTL  |=  (uint32_t)USB_PCGCCTL_StopPclk_Msk; /* Stop PHY clock */
409       XMC_SCU_POWER_DisableUsb(); /* Disable Power USB */
410       XMC_SCU_RESET_AssertPeripheralReset(XMC_SCU_PERIPHERAL_RESET_USB0); /* reset USB */
411       XMC_USBH0_device.port_reset_active =  false; /* Reset variables */
412       memset((void *)(pipe), 0, (USBH0_MAX_PIPE_NUM * sizeof(XMC_USBH0_pipe_t)));
413       break;
414     case XMC_USBH_POWER_FULL:
415       if (XMC_USBH0_device.init_done == false)
416       {
417         status = XMC_USBH_DRIVER_ERROR;
418         break;
419       } /* not initialized */
420       if (XMC_USBH0_device.power_state == XMC_USBH_POWER_FULL)
421       {
422         status = XMC_USBH_DRIVER_OK;
423         break;
424       } /* already powered */
425       XMC_lClockGating((uint8_t)XMC_USBH_CLOCK_GATING_DISABLE); /* disable clock gating */
426       (void)XMC_USBH_osDelay(2U);
427       XMC_SCU_RESET_DeassertPeripheralReset(XMC_SCU_PERIPHERAL_RESET_USB0); /* deassert reset USB */
428       (void)XMC_USBH_osDelay(2U);
429       (void)XMC_USBH_osDelay(100U);
430       XMC_SCU_POWER_EnableUsb(); /* Enable Power USB */
431 
432       /* On-chip Full-speed PHY */
433       XMC_USBH0_device.global_register->PCGCCTL  &=  (uint32_t)~USB_PCGCCTL_StopPclk_Msk;  /* Start PHY clock */
434       XMC_USBH0_device.global_register->GUSBCFG  |=  (uint32_t)USB_GUSBCFG_PHYSel_Msk;    /* Full-speed transceiver */
435 
436       while ((XMC_USBH0_device.global_register->GRSTCTL & USB_GRSTCTL_AHBIdle_Msk) == 0U) /* wait until AHB master state machine is idle */
437       {
438         /*Wait*/
439       }
440 
441       XMC_USBH0_device.global_register->GRSTCTL |=  (uint32_t)USB_GRSTCTL_CSftRst_Msk; /* Core soft reset */
442 
443       while ((XMC_USBH0_device.global_register->GRSTCTL & USB_GRSTCTL_CSftRst_Msk)  != 0U) /* wait soft reset confirmation */
444       {
445         /*Wait*/
446       }
447       (void)XMC_USBH_osDelay(100U);
448 
449       XMC_USBH0_device.port_reset_active =  false; /* Reset variables */
450       memset((void *)(pipe), 0, (USBH0_MAX_PIPE_NUM * sizeof(XMC_USBH0_pipe_t)));
451 
452       /*Created local copy of GUSBCFG to avoid side effects*/
453       loc_value = XMC_USBH0_device.global_register->GUSBCFG;
454       if (((loc_value & USB_GUSBCFG_ForceHstMode_Msk) == 0U) || \
455           ((loc_value & USB_GUSBCFG_ForceDevMode_Msk) != 0U))
456       {
457         XMC_USBH0_device.global_register->GUSBCFG &= (uint32_t)~USB_GUSBCFG_ForceDevMode_Msk;          /* Clear force device mode */
458         XMC_USBH0_device.global_register->GUSBCFG |=  (uint32_t)USB_GUSBCFG_ForceHstMode_Msk;          /* Force host mode */
459         (void)XMC_USBH_osDelay(100U);
460       }
461 
462       /* FS only, even if HS is supported */
463       XMC_USBH0_device.global_register->HCFG     |=  (uint32_t)(0x200U | USB_CH_HCFG_FSLSSUP(1));
464 
465       /* Rx FIFO setting */
466       XMC_USBH0_device.global_register->GRXFSIZ   = (RX_FIFO_SIZE/4U);
467       /* Non-periodic Tx FIFO setting */
468       XMC_USBH0_device.global_register->GNPTXFSIZ_HOSTMODE = (((uint32_t)(TX_FIFO_SIZE_NON_PERI/4U) << 16) |  (RX_FIFO_SIZE / 4U));
469       /* Periodic Tx FIFO setting */
470       XMC_USBH0_device.global_register->HPTXFSIZ  = ((uint32_t)(TX_FIFO_SIZE_PERI / 4U) << 16U) | ((RX_FIFO_SIZE + TX_FIFO_SIZE_NON_PERI) / 4U);
471       /* Enable channel interrupts */
472       XMC_USBH0_device.global_register->HAINTMSK  = ((uint32_t)1U << USBH0_MAX_PIPE_NUM) - 1U;
473       /* Unmask interrupts */
474       XMC_USBH0_device.global_register->GINTMSK_HOSTMODE   = (
475                         USB_GINTSTS_HOSTMODE_DisconnInt_Msk |
476                         USB_GINTMSK_HOSTMODE_HChIntMsk_Msk    |
477                         USB_GINTMSK_HOSTMODE_PrtIntMsk_Msk   |
478                         USB_GINTMSK_HOSTMODE_RxFLvlMsk_Msk |
479                         USB_GINTMSK_HOSTMODE_SofMsk_Msk  |
480                         USB_GINTMSK_HOSTMODE_WkUpIntMsk_Msk
481                        )   ;
482       /* Set powered state */
483       XMC_USBH0_device.power_state = state;
484       /* Enable interrupts */
485       XMC_USBH0_device.global_register->GAHBCFG  |=  (uint32_t)USB_GAHBCFG_GlblIntrMsk_Msk;
486       /* Set highest interrupt priority */
487       NVIC_SetPriority (USB0_0_IRQn, 0U);
488       NVIC_EnableIRQ   (USB0_0_IRQn);
489       break;
490     default:
491       status = XMC_USBH_DRIVER_ERROR_UNSUPPORTED;
492   }
493   return status;
494 }
495 
496 /**
497  * @param port Root HUB Port Number. Only one port(0) is supported.
498  * @param vbus VBUS state - \n
499  *                 - \b false VBUS off
500  *                 - \b true  VBUS on
501  * @return int32_t \ref Execution_status. Returns 0 if successful.
502  *
503  * \par<b>Description:</b><br>
504  * Set USB port VBUS on/off.
505 */
XMC_USBH_PortVbusOnOff(uint8_t port,bool vbus)506 static int32_t XMC_USBH_PortVbusOnOff (uint8_t port, bool vbus) {
507   int32_t status = XMC_USBH_DRIVER_OK;
508   if (XMC_USBH0_device.power_state == XMC_USBH_POWER_OFF)
509   {
510     status = XMC_USBH_DRIVER_ERROR;
511   }
512   else
513   {
514     if (port != 0U)
515     {
516       status = XMC_USBH_DRIVER_ERROR_PARAMETER;
517     }
518     else
519     {
520       if (vbus != 0U) {
521         /* Port power on */
522         XMC_USBH0_device.global_register->HPRT |=  (uint32_t)USB_HPRT_PrtPwr_Msk;
523         XMC_GPIO_SetMode(VBUS_port, (uint8_t)VBUS_pin, XMC_GPIO_MODE_OUTPUT_PUSH_PULL_ALT1);
524       } else {
525         /* Port power off */
526         XMC_USBH0_device.global_register->HPRT &= (uint32_t)~USB_HPRT_PrtPwr_Msk;
527         XMC_GPIO_SetMode(VBUS_port, (uint8_t)VBUS_pin, XMC_GPIO_MODE_INPUT_TRISTATE);
528       }
529     }
530   }
531   return status;
532 }
533 
534 /**
535  * @param port Root HUB Port Number. Only one port(0) is supported.
536  * @return int32_t Execution status. \ref Execution_status
537  * \par<b>Description:</b><br>
538  * Do USB port reset. Port reset should honor the requirement of 50ms delay before enabling.
539  * The function depends on implementation of XMC_USBH_osDelay() for 1ms delay to achieve required delay.
540  *
541 */
XMC_USBH_PortReset(uint8_t port)542 static int32_t XMC_USBH_PortReset (uint8_t port) {
543   uint32_t hprt;
544   int32_t status = XMC_USBH_DRIVER_OK;
545   if (XMC_USBH0_device.power_state == XMC_USBH_POWER_OFF)
546   {
547     status = XMC_USBH_DRIVER_ERROR;
548   }
549   else
550   {
551     if (port != 0U)
552     {
553       status = XMC_USBH_DRIVER_ERROR_PARAMETER;
554     }
555 
556     XMC_USBH0_device.port_reset_active = true;
557     hprt  =  XMC_USBH0_device.global_register->HPRT;
558     hprt &= (uint32_t)~USB_HPRT_PrtEna_Msk;                            /* Disable port */
559     hprt |= (uint32_t)USB_HPRT_PrtRst_Msk;                            /* Port reset */
560     XMC_USBH0_device.global_register->HPRT = hprt;
561     (void)XMC_USBH_osDelay(50U);                                            /* wait at least 50ms */
562     hprt &= (uint32_t)~USB_HPRT_PrtRst_Msk;                            /* Clear port reset */
563     XMC_USBH0_device.global_register->HPRT = hprt;
564     (void)XMC_USBH_osDelay(50U);                                            /* wait for ISR */
565 
566     /*Wait for the port to be enabled*/
567     while ((XMC_USBH0_device.global_register->HPRT & USB_HPRT_PrtEna_Msk) == 0U)
568     {
569       /*wait*/
570     }
571 
572     if (XMC_USBH0_device.port_reset_active == true)
573     {
574       XMC_USBH0_device.port_reset_active = false;
575       status = XMC_USBH_DRIVER_ERROR;                               /* reset not confirmed inside ISR */
576     }
577   }
578 
579   return status;
580 }
581 
582 /**
583  * @param port USB port number. Only one port(0) is supported.
584  * @return      \ref Execution_status
585  * \par<b>Description:</b><br>
586  * Suspend USB Port (stop generating SOFs).\n
587  *
588  * \par<b>Related APIs:</b><BR>
589  * XMC_USBH_PortResume() \n
590 */
XMC_USBH_PortSuspend(uint8_t port)591 static int32_t XMC_USBH_PortSuspend (uint8_t port)
592 {
593   int32_t status = XMC_USBH_DRIVER_OK;
594   uint32_t hprt;
595   if (XMC_USBH0_device.power_state == XMC_USBH_POWER_OFF)
596   {
597     status = XMC_USBH_DRIVER_ERROR;
598   }
599   else
600   {
601     if (port != 0U)
602     {
603       status = XMC_USBH_DRIVER_ERROR_PARAMETER;
604     }
605     else
606     {
607       hprt = XMC_USBH0_device.global_register->HPRT;
608       hprt &= (uint32_t)~(USB_HPRT_PrtEna_Msk);
609       hprt |= (uint32_t)USB_HPRT_PrtSusp_Msk;
610       XMC_USBH0_device.global_register->HPRT = hprt;
611       /* Stop PHY clock after suspending the bus*/
612       XMC_USBH0_device.global_register->PCGCCTL |= XMC_USBH_PHY_CLK_STOP;
613 
614     }
615   }
616   return status;
617 }
618 
619 /**
620  * @param port USB port number. Only one port(0) is supported.
621  * @return \ref Execution_status
622  * \par<b>Description:</b><br>
623  * Resume suspended USB port (start generating SOFs).\n
624  *
625  * \par<b>Related APIs:</b><BR>
626  * XMC_USBH_PortSuspend() \n
627 */
XMC_USBH_PortResume(uint8_t port)628 static int32_t XMC_USBH_PortResume (uint8_t port)
629 {
630   int32_t status = XMC_USBH_DRIVER_OK;
631   uint32_t hprt;
632   if (XMC_USBH0_device.power_state == XMC_USBH_POWER_OFF)
633   {
634     status = XMC_USBH_DRIVER_ERROR;
635   }
636   else
637   {
638     if (port != 0U)
639     {
640       status = XMC_USBH_DRIVER_ERROR_PARAMETER;
641     }
642     else
643     {
644       /*Ungate PHY clock*/
645       XMC_USBH0_device.global_register->PCGCCTL = XMC_USBH_PHY_CLK_UNGATE;
646       /*Set resume bit*/
647       hprt = XMC_USBH0_device.global_register->HPRT;
648       hprt &= (uint32_t)~(USB_HPRT_PrtEna_Msk);
649       hprt |= (uint32_t)USB_HPRT_PrtRes_Msk;
650       XMC_USBH0_device.global_register->HPRT = hprt;
651 
652       (void)XMC_USBH_osDelay(20U);
653 
654       hprt = XMC_USBH0_device.global_register->HPRT;
655       hprt &= (uint32_t)~(USB_HPRT_PrtEna_Msk);
656       hprt &= (uint32_t)~((uint32_t)USB_HPRT_PrtRes_Msk);
657       XMC_USBH0_device.global_register->HPRT = hprt;
658     }
659   }
660 
661   return status;
662 }
663 
664 /**
665  * @param port USB port number. Only one port(0) is supported.
666  * @return XMC_USBH_PORT_STATE_t Port State
667  *
668  * \par<b>Description:</b><br>
669  * Get current USB port state. The state indicates if the port is connected, port speed
670  * and port overcurrent status.
671 */
XMC_USBH_PortGetState(uint8_t port)672 static XMC_USBH_PORT_STATE_t XMC_USBH_PortGetState (uint8_t port)
673 {
674   XMC_USBH_PORT_STATE_t port_state = { 0U, 0U, 0U };
675   uint32_t hprt;
676 
677   if (XMC_USBH0_device.power_state == XMC_USBH_POWER_OFF)
678   {
679     /*Do not update the port state*/
680   }
681   else
682   {
683     if (port != 0U)
684     {
685       /*Do not update the port state*/
686     }
687     else
688     {
689       hprt = XMC_USBH0_device.global_register->HPRT;
690       if(((hprt & USB_HPRT_PrtConnSts_Msk) != 0U))
691       {
692         port_state.connected   = 1U;
693       }
694       else
695       {
696         port_state.connected   = 0U;
697       }
698       port_state.overcurrent = 0U;
699 
700       switch ((uint32_t)((uint32_t)(hprt & USB_HPRT_PrtSpd_Msk) >> USB_HPRT_PrtSpd_Pos)) {
701         case 1U: /* Full speed */
702          port_state.speed = XMC_USBH_SPEED_FULL;
703          break;
704         default:
705          break;
706       }
707     }
708   }
709   return port_state;
710 }
711 
712 /**
713  * @param dev_addr Device address
714  * @param dev_speed  Device speed
715  * @param hub_addr Hub address. This value should be 0 since hub is not supported.
716  * @param hub_port  USB port number. Only one port(0) is supported.
717  * @param ep_addr Device endpoint address \n
718  *                - ep_addr.0..3: Address \n
719  *                - ep_addr.7:    Direction\n
720  * @param ep_type Endpoint type (ARM_USB_ENDPOINT_xxx)
721  * @param ep_max_packet_size Endpoint maximum packet size
722  * @param ep_interval Endpoint polling interval
723  * @return XMC_USBH_PIPE_HANDLE Pipe handle is a pointer to pipe hardware base address.
724  *
725  * \par<b>Description:</b><br>
726  * Create/allocate a pipe configured with input parameters. The function looks for an unused pipe and configures with input parameters.
727  *
728  * \par<b>Related APIs:</b><BR>
729  * XMC_USBH_PipeModify(), XMC_USBH_PipeDelete(), XMC_USBH_PipeReset(), XMC_USBH_PipeTransfer() \n
730 */
XMC_USBH_PipeCreate(uint8_t dev_addr,uint8_t dev_speed,uint8_t hub_addr,uint8_t hub_port,uint8_t ep_addr,uint8_t ep_type,uint16_t ep_max_packet_size,uint8_t ep_interval)731 static XMC_USBH_PIPE_HANDLE XMC_USBH_PipeCreate (uint8_t dev_addr, uint8_t dev_speed, uint8_t hub_addr, uint8_t hub_port, uint8_t ep_addr, uint8_t ep_type, uint16_t ep_max_packet_size, uint8_t  ep_interval) {
732   XMC_USBH0_pipe_t    *ptr_pipe;
733   USB0_CH_TypeDef *ptr_ch;
734   uint32_t         i;
735   uint32_t loc_val;
736 
737   XMC_UNUSED_ARG(hub_addr);
738   XMC_UNUSED_ARG(hub_port);
739   XMC_UNUSED_ARG(dev_speed);
740 
741   if (XMC_USBH0_device.power_state == XMC_USBH_POWER_OFF)
742   {
743     ptr_ch = (USB0_CH_TypeDef *)NULL;
744   }
745   else
746   {
747    /* get first free pipe available */
748     ptr_ch = (USB0_CH_TypeDef *)(XMC_USBH0_device.host_channel_registers);
749 
750     for (i = 0U; i < USBH0_MAX_PIPE_NUM; i++) {
751       if ((ptr_ch->HCCHAR & 0x3FFFFFFFU) == 0U)
752       {
753         break;
754       }
755       ptr_ch++;
756     }
757 
758     /* free pipe found? */
759     if (i == USBH0_MAX_PIPE_NUM)
760     {
761       ptr_ch = (USB0_CH_TypeDef *)NULL;
762     }
763     else
764     {
765       ptr_pipe = (XMC_USBH0_pipe_t *)(&pipe[(ptr_ch - (USB0_CH_TypeDef *)(XMC_USBH0_device.host_channel_registers))]);
766 
767       memset((void *)ptr_pipe, 0, sizeof(XMC_USBH0_pipe_t));  /* Initialize pipe structure */
768 
769       /* Fill in all fields of Endpoint Descriptor */
770       /*Get the end point direction from the MSB of address*/
771       loc_val = 0U;
772       if (((ep_addr >> 7U) & 0x1U) == 0U)
773       {
774         loc_val = 1U;
775       }
776       ptr_ch->HCCHAR = ((uint32_t)(USB_CH_HCCHARx_MPS(ep_max_packet_size))|
777                        USB_CH_HCCHARx_EPNUM(ep_addr)) |
778                        (uint32_t)(USB_CH_HCCHAR_EPDir_Msk * loc_val) |
779                        (USB_CH_HCCHARx_EPTYPE (ep_type) ) |
780                        (USB_CH_HCCHARx_DEVADDR (dev_addr) ) ;
781       /* Store Pipe settings */
782       ptr_pipe->ep_max_packet_size = ep_max_packet_size;
783       ptr_pipe->ep_type            = ep_type;
784       switch (ep_type) {
785         case XMC_USBH_ENDPOINT_CONTROL:
786         case XMC_USBH_ENDPOINT_BULK:
787           break;
788         case XMC_USBH_ENDPOINT_ISOCHRONOUS:
789         case XMC_USBH_ENDPOINT_INTERRUPT:
790           if (ep_interval > 0U) {
791             ptr_pipe->interval_reload = ep_interval;
792           }
793           ptr_pipe->interval = ptr_pipe->interval_reload;
794           loc_val = ((((uint32_t)ep_max_packet_size >> 11U) + 1U) & 3U);
795           ptr_ch->HCCHAR |= (uint32_t)USB_CH_HCCHARx_MCEC(loc_val);
796           break;
797         default:
798           break;
799       }
800     }
801   }
802   return ((XMC_USBH_EP_HANDLE)ptr_ch);
803 }
804 
805 /**
806  * @param pipe_hndl Pointer returned by the pipe create function. It is the hardware based address of a USB channel.
807  * @param dev_addr Device address to be configured for the pipe.
808  * @param dev_speed  Device speed class.
809  * @param hub_addr Hub address. It should be 0 since hub is not supported.
810  * @param hub_port USB port number. Only one port(0) is supported.
811  * @param ep_max_packet_size Endpoint maximum packet size
812  * @return Execution_status
813  *
814  * \par<b>Description:</b><br>
815  * Modify an existing pipe with input parameters. It can be used to configure the pipe after receiving configuration details from the device.
816  *
817  * \par<b>Related APIs:</b><BR>
818  * XMC_USBH_PipeCreate(), XMC_USBH_PipeDelete(), XMC_USBH_PipeReset(), XMC_USBH_PipeTransfer() \n
819 */
XMC_USBH_PipeModify(XMC_USBH_PIPE_HANDLE pipe_hndl,uint8_t dev_addr,uint8_t dev_speed,uint8_t hub_addr,uint8_t hub_port,uint16_t ep_max_packet_size)820 static int32_t XMC_USBH_PipeModify (XMC_USBH_PIPE_HANDLE pipe_hndl, uint8_t dev_addr, uint8_t dev_speed, uint8_t hub_addr, uint8_t hub_port, uint16_t ep_max_packet_size) {
821   XMC_USBH0_pipe_t    *ptr_pipe;
822   USB0_CH_TypeDef *ptr_ch;
823   uint32_t   hcchar;
824   int32_t status = XMC_USBH_DRIVER_OK;
825 
826   XMC_UNUSED_ARG(hub_addr);
827   XMC_UNUSED_ARG(hub_port);
828   XMC_UNUSED_ARG(dev_speed);
829 
830   if (XMC_USBH0_device.power_state == XMC_USBH_POWER_OFF)
831   {
832     status = XMC_USBH_DRIVER_ERROR;
833   }
834   else
835   {
836     if (pipe_hndl  == 0U)
837     {
838       status = XMC_USBH_DRIVER_ERROR_PARAMETER;
839     }
840     else
841     {
842       ptr_ch   = (USB0_CH_TypeDef *)(pipe_hndl);
843       ptr_pipe = (XMC_USBH0_pipe_t *)(&pipe[(ptr_ch - (USB0_CH_TypeDef *)(XMC_USBH0_device.host_channel_registers))]);
844       if (ptr_pipe->in_use != 0U)
845       {
846         status = XMC_USBH_DRIVER_ERROR_BUSY;
847       }
848       else
849       {
850         /* Fill in all fields of channel */
851         hcchar  =   ptr_ch->HCCHAR;
852         /* Clear fields */
853         hcchar &= (uint32_t)~(USB_CH_HCCHAR_MPS_Msk | USB_CH_HCCHAR_DevAddr_Msk)  ;
854         /* Set fields */
855         hcchar |= (uint32_t)(USB_CH_HCCHARx_MPS(ep_max_packet_size) | (USB_CH_HCCHARx_DEVADDR(dev_addr)));
856         ptr_ch->HCCHAR = hcchar;
857 
858         ptr_pipe->ep_max_packet_size = ep_max_packet_size;
859       }
860     }
861   }
862 
863   return status;
864 }
865 
866 /**
867  * @param pipe_hndl Pointer returned by the pipe create function. It is the hardware based address of a USB channel.
868  * @return Execution_status
869  *
870  * \par<b>Description:</b><br>
871  * Delete pipe from active pipes list. After it is deleted, it can be assigned to new pipe request.
872  *
873  * \par<b>Related APIs:</b><BR>
874  * XMC_USBH_PipeCreate(), XMC_USBH_PipeModify(), XMC_USBH_PipeReset(), XMC_USBH_PipeTransfer() \n
875 */
XMC_USBH_PipeDelete(XMC_USBH_PIPE_HANDLE pipe_hndl)876 static int32_t XMC_USBH_PipeDelete (XMC_USBH_PIPE_HANDLE pipe_hndl) {
877   XMC_USBH0_pipe_t    *ptr_pipe;
878   USB0_CH_TypeDef *ptr_ch;
879   int32_t status = XMC_USBH_DRIVER_OK;
880 
881   if (XMC_USBH0_device.power_state == XMC_USBH_POWER_OFF)
882   {
883     status = XMC_USBH_DRIVER_ERROR;
884   }
885   else
886   {
887     if (pipe_hndl == 0U)
888     {
889       status = XMC_USBH_DRIVER_ERROR_PARAMETER;
890     }
891     else
892     {
893       ptr_ch   = (USB0_CH_TypeDef *)(pipe_hndl);
894       ptr_pipe = (XMC_USBH0_pipe_t    *)(&pipe[(ptr_ch - (USB0_CH_TypeDef *)(XMC_USBH0_device.host_channel_registers))]);
895       if (ptr_pipe->in_use != 0U)
896       {
897         status = XMC_USBH_DRIVER_ERROR_BUSY;
898       }
899       else
900       {
901         ptr_ch->HCCHAR            = 0U;
902         ptr_ch->HCINT             = 0U;
903         ptr_ch->HCINTMSK          = 0U;
904         ptr_ch->HCTSIZ_BUFFERMODE = 0U;
905 
906         memset((void *)ptr_pipe, 0, sizeof(XMC_USBH0_pipe_t));
907       }
908     }
909   }
910 
911   return status;
912 }
913 
914 /**
915  * @param pipe_hndl Pointer returned by the pipe create function. It is the hardware based address of a USB channel.
916  * @return Execution_status
917  * \par<b>Description:</b><br>
918  * Reset pipe by clearing the interrupt mask and resetting the transfer control register.\n
919  *
920  * \par<b>Related APIs:</b><BR>
921  * XMC_USBH_PipeCreate(), XMC_USBH_PipeModify(), XMC_USBH_PipeDelete(), XMC_USBH_PipeTransfer() \n
922 */
XMC_USBH_PipeReset(XMC_USBH_PIPE_HANDLE pipe_hndl)923 static int32_t XMC_USBH_PipeReset (XMC_USBH_PIPE_HANDLE pipe_hndl) {
924   XMC_USBH0_pipe_t    *ptr_pipe;
925   USB0_CH_TypeDef *ptr_ch;
926   int32_t status = XMC_USBH_DRIVER_OK;
927 
928   if (XMC_USBH0_device.power_state == XMC_USBH_POWER_OFF)
929   {
930     status = XMC_USBH_DRIVER_ERROR;
931   }
932   else
933   {
934     if (pipe_hndl  == 0U)
935     {
936       status = XMC_USBH_DRIVER_ERROR_PARAMETER;
937     }
938     else
939     {
940       ptr_ch   = (USB0_CH_TypeDef *)(pipe_hndl);
941       ptr_pipe = (XMC_USBH0_pipe_t    *)(&pipe[(ptr_ch - (USB0_CH_TypeDef *)(XMC_USBH0_device.host_channel_registers))]);
942       if (ptr_pipe->in_use != 0U)
943       {
944         status = XMC_USBH_DRIVER_ERROR_BUSY;
945       }
946       else
947       {
948         ptr_ch->HCINT    = 0U;
949         ptr_ch->HCINTMSK = 0U;
950         ptr_ch->HCTSIZ_BUFFERMODE   = 0U;
951       }
952     }
953   }
954   return status;
955 }
956 
957 /**
958  * @param pipe_hndl Pointer returned by the pipe create function. It is the hardware based address of a USB channel.
959  * @param packet Packet information with bit masks to represent packet data toggle information and packet type.\n
960  *               \ref XMC_USBH_PACKET_DATA0 / \ref XMC_USBH_PACKET_DATA1, \ref XMC_USBH_PACKET_SETUP /
961  *               \ref XMC_USBH_PACKET_OUT / \ref XMC_USBH_PACKET_IN
962  * @param data Pointer to buffer with data to send or for received data to be stored.
963  * @param num Number of data bytes to transfer
964  * @return Execution_status
965  *
966  *  \par<b>Description:</b><BR>
967  *  Transfer packets through USB Pipe. Handles transfer of multiple packets using the pipe transfer complete event.
968  *  The pipe event callback function will be called when the transfer is completed.\n
969  *
970  * \par<b>Related APIs:</b><BR>
971  * XMC_USBH_PipeCreate(), XMC_USBH_PipeModify(), XMC_USBH_PipeDelete(), XMC_USBH_PipeReset() \n
972 */
XMC_USBH_PipeTransfer(XMC_USBH_PIPE_HANDLE pipe_hndl,uint32_t packet,uint8_t * data,uint32_t num)973 static int32_t XMC_USBH_PipeTransfer (XMC_USBH_PIPE_HANDLE pipe_hndl, uint32_t packet, uint8_t *data, uint32_t num) {
974   XMC_USBH0_pipe_t *ptr_pipe;
975   int32_t status = XMC_USBH_DRIVER_OK;
976 
977   if (XMC_USBH0_device.power_state == XMC_USBH_POWER_OFF)
978   {
979     status = XMC_USBH_DRIVER_ERROR;
980   }
981   else
982   {
983 
984     if(!(((((packet & XMC_USBH_PACKET_TOKEN_Msk) == XMC_USBH_PACKET_OUT) ||
985         ((packet & XMC_USBH_PACKET_TOKEN_Msk) == XMC_USBH_PACKET_IN))) ||
986         ((packet & XMC_USBH_PACKET_TOKEN_Msk) == XMC_USBH_PACKET_SETUP )))
987     {
988       status = XMC_USBH_DRIVER_ERROR_PARAMETER;
989     }
990     else
991     {
992       if (pipe_hndl  == 0U)
993       {
994         status = XMC_USBH_DRIVER_ERROR_PARAMETER;
995       }
996       else
997       {
998         if ((XMC_USBH0_device.global_register->HPRT & USB_HPRT_PrtConnSts_Msk) == 0U)
999         {
1000           status = XMC_USBH_DRIVER_ERROR;
1001         }
1002         else
1003         {
1004           ptr_pipe = (XMC_USBH0_pipe_t *)(&pipe[((USB0_CH_TypeDef *)pipe_hndl - (USB0_CH_TypeDef *)(XMC_USBH0_device.host_channel_registers))]);
1005           if (ptr_pipe->in_use != 0U)
1006           {
1007             status = XMC_USBH_DRIVER_ERROR_BUSY;
1008           }
1009           else
1010           {
1011             /* Prepare transfer information */
1012             ptr_pipe->packet                = packet;
1013             ptr_pipe->data                  = data;
1014             ptr_pipe->num                   = num;
1015             ptr_pipe->num_transferred_total = 0U;
1016             ptr_pipe->num_transferring      = 0U;
1017             ptr_pipe->in_use                = 0U;
1018             ptr_pipe->transfer_active       = 0U;
1019             ptr_pipe->interrupt_triggered   = 0U;
1020             ptr_pipe->event                 = 0U;
1021 
1022             if ((ptr_pipe->ep_type == (uint8_t)XMC_USBH_ENDPOINT_INTERRUPT) && (ptr_pipe->interval != 0U)) {
1023               ptr_pipe->in_use              = 1U; /* transfer will be started inside interrupt (SOF) */
1024             } else {
1025               ptr_pipe->transfer_active     = 1U;
1026               ptr_pipe->in_use              = 1U;
1027               if(XMC_lStartTransfer (ptr_pipe, (USB0_CH_TypeDef *)pipe_hndl) == false)
1028               {
1029                 status = XMC_USBH_DRIVER_ERROR;
1030               }
1031             }
1032           }
1033         }
1034       }
1035     }
1036   }
1037   return status;
1038 }
1039 
1040 /**
1041  * @param pipe_hndl Pointer returned by the pipe create function. It is the hardware based address of a USB channel.
1042  * @return uint32_t Number of successfully transferred data bytes
1043  *
1044  *  \par<b>Description:</b><BR>
1045  *  Get result of USB Pipe transfer.
1046  *
1047  * \par<b>Related APIs:</b><BR>
1048  * XMC_USBH_PipeCreate(), XMC_USBH_PipeModify(), XMC_USBH_PipeDelete(), XMC_USBH_PipeTransfer() \n
1049 */
XMC_USBH_PipeTransferGetResult(XMC_USBH_PIPE_HANDLE pipe_hndl)1050 static uint32_t XMC_USBH_PipeTransferGetResult (XMC_USBH_PIPE_HANDLE pipe_hndl) {
1051   uint32_t status;
1052   if (pipe_hndl == 0U)
1053   {
1054     status = 0U;
1055   }
1056   else
1057   {
1058     status = (pipe[((USB0_CH_TypeDef *)pipe_hndl - (USB0_CH_TypeDef *)(XMC_USBH0_device.host_channel_registers))].num_transferred_total);
1059   }
1060   return status;
1061 }
1062 
1063 /**
1064  * @param pipe_hndl Pointer returned by the pipe create function. It is the hardware based address of a USB channel.
1065  * @return Execution_status
1066  *
1067  * \par<b>Description:</b><BR>
1068  * Abort current USB Pipe transfer.\n
1069  *
1070  * \par<b>Related APIs:</b><BR>
1071  * XMC_USBH_PipeCreate(), XMC_USBH_PipeModify(), XMC_USBH_PipeDelete(), XMC_USBH_PipeTransfer() \n
1072 */
XMC_USBH_PipeTransferAbort(XMC_USBH_PIPE_HANDLE pipe_hndl)1073 static int32_t XMC_USBH_PipeTransferAbort (XMC_USBH_PIPE_HANDLE pipe_hndl) {
1074   XMC_USBH0_pipe_t *ptr_pipe;
1075   USB0_CH_TypeDef *ptr_ch;
1076   uint32_t timeout;
1077   int32_t status = XMC_USBH_DRIVER_ERROR;
1078 
1079   ptr_ch = (USB0_CH_TypeDef *) pipe_hndl;
1080 
1081   if (XMC_USBH0_device.power_state == XMC_USBH_POWER_OFF)
1082   {
1083     /*Error in power state*/
1084   }
1085   else
1086   {
1087     if (pipe_hndl  == 0U)
1088     {
1089       status = XMC_USBH_DRIVER_ERROR_PARAMETER;
1090     }
1091     else
1092     {
1093       ptr_pipe = (XMC_USBH0_pipe_t *)(&pipe[(ptr_ch - (USB0_CH_TypeDef *)(XMC_USBH0_device.host_channel_registers))]);
1094 
1095       if (ptr_pipe->in_use != 0U) {
1096         ptr_pipe->in_use = 0U;
1097         /* Disable channel if not yet halted */
1098         if ((ptr_ch->HCINT & USB_CH_HCINT_ChHltd_Msk) == 0U)
1099         {
1100           if (ptr_ch->HCCHAR & USB_CH_HCCHAR_ChEna_Msk)
1101           {
1102             ptr_ch->HCINTMSK = 0U;
1103             (void)XMC_USBH_osDelay(1U);
1104             if (ptr_ch->HCINT & USB_CH_HCINT_NAK_Msk) {
1105               ptr_ch->HCINT  =  USB_CH_HCINTx_ALL;    /* Clear all interrupts */
1106               status = XMC_USBH_DRIVER_OK;
1107             }
1108             else
1109             {
1110               ptr_ch->HCINT  =  USB_CH_HCINTx_ALL;      /* Clear all interrupts */
1111               ptr_ch->HCCHAR =  (uint32_t)(ptr_ch->HCCHAR | USB_CH_HCCHAR_ChEna_Msk | USB_CH_HCCHAR_ChDis_Msk);
1112 
1113               /* wait until channel is halted */
1114               for (timeout = 0U; timeout < 5000U; timeout++) {
1115                 if (ptr_ch->HCINT & USB_CH_HCINT_ChHltd_Msk) {
1116                   ptr_ch->HCINT = USB_CH_HCINTx_ALL;
1117                   status = XMC_USBH_DRIVER_OK;
1118                 }
1119               }
1120             }
1121           }
1122         }
1123       }
1124     }
1125   }
1126 
1127   return status;
1128 }
1129 
1130 /**
1131  * @return Frame number.
1132  *
1133  * \par<b>Description:</b><BR>
1134  * Get current USB Frame Number.
1135 */
XMC_USBH_GetFrameNumber(void)1136 static uint16_t XMC_USBH_GetFrameNumber (void)
1137 {
1138   uint16_t status;
1139 
1140   if (XMC_USBH0_device.power_state == XMC_USBH_POWER_OFF)
1141   {
1142     status = 0U;
1143   }
1144   else
1145   {
1146     status = (uint16_t)((XMC_USBH0_device.global_register->HFNUM) & 0xFFFU);
1147   }
1148   return status;
1149 }
1150 
1151 /**
1152  * @param gintsts USB port interrupt status flag.
1153  *
1154  * \par<b>Description:</b><BR>
1155  * USB host interrupt handler. It updates port and pipe state information based on different events
1156  * generated by the peripheral. It propagates the port events to the callback function registered by the user
1157  * during initialization. When a pipe transfer complete event is detected, it checks if any further data is available
1158  * to be transmitted on the same pipe and continues transmission until data is available. A pipe event is also propagated
1159  * to the user provided pipe event callback function. A transfer complete event will be propagated only when all the data
1160  * is transmitted for an OUT transaction.
1161  *
1162 */
XMC_USBH_HandleIrq(uint32_t gintsts)1163 void XMC_USBH_HandleIrq (uint32_t gintsts) {
1164   XMC_USBH0_pipe_t *ptr_pipe;
1165   USB0_CH_TypeDef *ptr_ch;
1166   uint32_t hprt, haint, hcint, pktcnt, mpsiz;
1167   uint32_t ch;
1168   uint8_t *ptr_data;
1169   uint32_t *dfifo;
1170   uint32_t grxsts, bcnt, dat, len, len_rest;
1171 
1172   /* Host port interrupt */
1173   if ((gintsts & USB_GINTSTS_HOSTMODE_PrtInt_Msk) != 0U) {
1174     hprt = XMC_USBH0_device.global_register->HPRT;
1175     /* Clear port enable */
1176     XMC_USBH0_device.global_register->HPRT = hprt & (uint32_t)(~USB_HPRT_PrtEna_Msk);
1177     if ((hprt & USB_HPRT_PrtConnDet_Msk) != 0U) {
1178       XMC_USBH0_device.global_register->HCFG =  (0x200U | (USB_CH_HCFG_FSLSPCS(1) |
1179                                                     USB_CH_HCFG_FSLSSUP(1)));
1180       /* Ignore connect under reset */
1181       if (XMC_USBH0_device.port_reset_active == false) {
1182         XMC_USBH0_device.SignalPortEvent_cb(0U, XMC_USBH_EVENT_CONNECT);
1183       }
1184     }
1185     if ((hprt & USB_HPRT_PrtEnChng_Msk) != 0U) { /* If port enable changed */
1186       if ((hprt & USB_HPRT_PrtEna_Msk) != 0U) {  /* If device connected */
1187         if (XMC_USBH0_device.port_reset_active == true) {
1188           XMC_USBH0_device.port_reset_active = false;
1189           XMC_USBH0_device.SignalPortEvent_cb(0U, XMC_USBH_EVENT_RESET);
1190         }
1191       }
1192     }
1193   }
1194 
1195   /* Disconnect interrupt */
1196   if ((gintsts & USB_GINTSTS_HOSTMODE_DisconnInt_Msk) != 0U) {
1197     XMC_USBH0_device.global_register->GINTSTS_HOSTMODE = USB_GINTSTS_HOSTMODE_DisconnInt_Msk; /* Clear disconnect interrupt */
1198     /* Ignore disconnect under reset */
1199     if ( XMC_USBH0_device.port_reset_active == false) {
1200       ptr_ch   = (USB0_CH_TypeDef *)(XMC_USBH0_device.host_channel_registers);
1201       ptr_pipe = (XMC_USBH0_pipe_t    *)(pipe);
1202       for (ch = 0U; ch < USBH0_MAX_PIPE_NUM; ch++) {
1203         if (ptr_pipe->in_use != 0U) {
1204           ptr_pipe->in_use = 0U;
1205           ptr_ch->HCINT    = USB_CH_HCINTx_ALL;                                            /* Clear all interrupts */
1206           ptr_ch->HCINTMSK = USB_CH_HCINT_ChHltd_Msk;                           /* Enable halt interrupt */
1207           ptr_ch->HCCHAR  |= (uint32_t)(USB_CH_HCCHAR_ChEna_Msk | USB_CH_HCCHAR_ChDis_Msk); /* Activate Halt */
1208           XMC_USBH0_device.SignalPipeEvent_cb((XMC_USBH_EP_HANDLE)ptr_ch, XMC_USBH_EVENT_BUS_ERROR);
1209         }
1210         ptr_ch++;
1211         ptr_pipe++;
1212       }
1213       XMC_USBH0_device.SignalPortEvent_cb(0U, XMC_USBH_EVENT_DISCONNECT);
1214     }
1215   }
1216   /* Handle receive fifo not-empty interrupt */
1217   if ((gintsts & USB_GINTSTS_HOSTMODE_RxFLvl_Msk) != 0U) {
1218     XMC_USBH0_device.global_register->GINTMSK_HOSTMODE &= (uint32_t)~USB_GINTMSK_HOSTMODE_RxFLvlMsk_Msk;
1219     grxsts     = (XMC_USBH0_device.global_register->GRXSTSP_HOSTMODE);
1220     /* IN Data Packet received ? */
1221     if ((uint32_t)((grxsts >> 17U) & 0x0FU) == (uint32_t)USB_GRXSTSR_HOSTMODE_PktSts_IN_DATA_PKT) {
1222       ch         = (uint32_t)(grxsts & USB_GRXSTSR_DEVICEMODE_EPNum_Msk);
1223       bcnt       = ((uint32_t)(grxsts & USB_GRXSTSR_DEVICEMODE_BCnt_Msk) >> USB_GRXSTSR_DEVICEMODE_BCnt_Pos);
1224       dfifo      = (uint32_t *)XMC_USBH0_dfifo_ptr[ch];
1225       ptr_data   =  pipe[ch].data + pipe[ch].num_transferred_total;
1226       len        =  bcnt / 4U; /* Received number of 32-bit data */
1227       len_rest   =  bcnt & 3U; /* Number of bytes left */
1228       /* Read data from fifo */
1229       /* Read 32 bit sized  data */
1230       while (len != 0U) {
1231 #if defined __TASKING__/*tasking*/
1232         *((__unaligned uint32_t *)ptr_data) = *dfifo;
1233 #else /* defined (__GNUC__) || defined (__CC_ARM) || defined (__ICCARM__)*/
1234         *((__packed uint32_t *)ptr_data) = *dfifo;
1235 #endif
1236 
1237         ptr_data += 4U;
1238         len--;
1239       }
1240       /* Read 8 bit sized data */
1241       if (len_rest != 0U) {
1242 #if defined __TASKING__/*tasking*/
1243         dat = *((__unaligned uint32_t *)dfifo);
1244 #else /* defined (__GNUC__) || defined (__CC_ARM) || defined (__ICCARM__)*/
1245         dat = *((__packed uint32_t *)dfifo);
1246 #endif
1247         while (len_rest != 0U) {
1248           *ptr_data = (uint8_t)dat;
1249           ptr_data++;
1250           dat >>= 8;
1251           len_rest--;
1252         }
1253       }
1254       pipe[ch].num_transferring      += bcnt;
1255       pipe[ch].num_transferred_total += bcnt;
1256     }
1257     XMC_USBH0_device.global_register->GINTMSK_HOSTMODE |= (uint32_t)USB_GINTMSK_HOSTMODE_RxFLvlMsk_Msk;
1258   }
1259 
1260   /* Handle sof interrupt */
1261   if ((gintsts & USB_GINTSTS_HOSTMODE_Sof_Msk) != 0U) { /* If start of frame interrupt */
1262     XMC_USBH0_device.global_register->GINTSTS_HOSTMODE =  USB_GINTSTS_HOSTMODE_Sof_Msk; /* Clear SOF interrupt */
1263     ptr_pipe = (XMC_USBH0_pipe_t *)(pipe);
1264     for (ch = 0U; ch < USBH0_MAX_PIPE_NUM; ch++) {
1265       /* If interrupt transfer is active handle period (interval) */
1266       if ((ptr_pipe->ep_type == (uint8_t)XMC_USBH_ENDPOINT_INTERRUPT) && (ptr_pipe->in_use == 1U)) {
1267         if (ptr_pipe->interval != 0U)
1268         {
1269           ptr_pipe->interval--;
1270           if (ptr_pipe->interval == 0U)
1271           {
1272             ptr_pipe->interval = ptr_pipe->interval_reload;
1273             ptr_pipe->interrupt_triggered = 1U;
1274           }
1275         }
1276       }
1277       ptr_pipe++;
1278     }
1279   }
1280 
1281   /* Handle host ctrl interrupt */
1282   if ((gintsts & USB_GINTSTS_HOSTMODE_HChInt_Msk) != 0U) {
1283     haint = XMC_USBH0_device.global_register->HAINT;
1284     for (ch = 0U; ch < USBH0_MAX_PIPE_NUM; ch++) {
1285       /* Check for interrupt of all channels */
1286       if ((haint & (uint32_t)((uint32_t)1U << ch)) != 0U) {
1287         haint     &= (uint32_t)~((uint32_t)1U << ch);
1288         ptr_ch     =  (USB0_CH_TypeDef *)(XMC_USBH0_device.host_channel_registers) + ch;
1289         ptr_pipe   =  (XMC_USBH0_pipe_t    *)(&pipe[ch]);
1290         /*Local variable for HCINT*/
1291         dat = ptr_ch->HCINT;
1292         hcint      =  (uint32_t)(dat & ptr_ch->HCINTMSK);
1293         if ((hcint & USB_CH_HCINT_ChHltd_Msk) != 0U) {                                  /* channel halted ? */
1294           ptr_ch->HCINTMSK = 0U;                                                        /*  disable all channel interrupts */
1295           ptr_ch->HCINT    = USB_CH_HCINTx_ALL;                                                    /*  clear all interrupts */
1296           ptr_pipe->transfer_active = 0U;                                               /*  set status transfer not active */
1297           hcint = 0U;
1298         }
1299         if ((hcint & USB_CH_HCINT_XferCompl_Msk) != 0U) {                               /* data transfer finished ? */
1300           ptr_ch->HCINT   = USB_CH_HCINTx_ALL;                                                     /*  clear all interrupts */
1301           if ((ptr_ch->HCCHAR & USB_CH_HCCHAR_EPDir_Msk) == 0U) {                       /*  endpoint OUT ? */
1302             ptr_ch->HCINTMSK = 0U;                                                      /*   disable all channel interrupts */
1303             ptr_pipe->transfer_active = 0U;                                             /*   transfer not in progress */
1304             ptr_pipe->num_transferred_total += ptr_pipe->num_transferring;              /*   admin OUT transfer status */
1305             ptr_pipe->num_transferring       = 0U;                                      /*   admin OUT transfer status */
1306             if (ptr_pipe->num_transferred_total == ptr_pipe->num) {                     /*   all bytes transferred ? */
1307               ptr_pipe->in_use = 0U;                                                    /*    release pipe */
1308               ptr_pipe->event = (uint8_t)XMC_USBH_EVENT_TRANSFER_COMPLETE;                       /*    prepare event notification */
1309             }
1310             hcint = 0U;
1311           }
1312           if ((ptr_ch->HCCHAR & USB_CH_HCCHAR_EPDir_Msk) != 0U) {                       /*  endpoint IN ? */
1313             ptr_pipe->in_use = 0U;                                                      /*   release pipe */
1314             ptr_pipe->event = (uint8_t)XMC_USBH_EVENT_TRANSFER_COMPLETE;                         /*   prepare event notification */
1315             XMC_lTriggerHaltChannel(ptr_ch);                                            /*   trigger channel halt */
1316           }
1317         }
1318         if ((hcint & USB_CH_HCINTMSK_AckMsk_Msk) != 0U) {                                /* ACK received ? */
1319           ptr_ch->HCINT = USB_CH_HCINTMSK_AckMsk_Msk;                                    /*  clear ACK interrupt */
1320           is_nack[ch] = false;
1321           if ((ptr_ch->HCCHAR & USB_CH_HCCHAR_EPDir_Msk) != 0U) {                        /*  endpoint IN ? */
1322             if ((ptr_pipe->num != ptr_pipe->num_transferred_total) &&                    /*   if all data was not transferred */
1323                 (ptr_pipe->num_transferring != 0U)                 &&                    /*   if zero-length packet was not received */
1324                ((ptr_pipe->num_transferred_total%ptr_pipe->ep_max_packet_size) == 0U)){  /*   if short packet was not received */
1325                ptr_ch->HCCHAR |= (uint32_t)USB_CH_HCCHAR_ChEna_Msk;                                /*    trigger next transfer */
1326             }
1327           } else {                                                                        /* endpoint OUT */
1328             XMC_lTriggerHaltChannel(ptr_ch);                                              /*  trigger channel halt */
1329           }
1330           hcint = 0U;
1331         }
1332         /*local variable for HCCHAR*/
1333         dat = ptr_ch->HCCHAR;
1334         if (((hcint & (USB_CH_HCINTMSK_StallMsk_Msk |                                    /* STALL */
1335                       USB_CH_HCINTMSK_NakMsk_Msk   |                                     /* or NAK */
1336                       USB_CH_HCINTx_ERRORS )) != 0U) &&                                  /* or transaction error */
1337             ((dat & USB_CH_HCCHAR_EPDir_Msk) == 0U))
1338         {                        /* and endpoint OUT */
1339 
1340             pktcnt = (uint32_t)((ptr_ch->HCTSIZ_BUFFERMODE & USB_CH_HCTSIZ_BUFFERMODE_PktCnt_Msk)  /*  administrate OUT transfer status */
1341                       >> USB_CH_HCTSIZ_BUFFERMODE_PktCnt_Pos);
1342             mpsiz  = (ptr_ch->HCCHAR      ) & 0x000007FFU;
1343             if ((ptr_pipe->num_transferring >= mpsiz) && (pktcnt > 0U)) {
1344               ptr_pipe->num_transferred_total += (uint32_t)(ptr_pipe->num_transferring - (mpsiz * pktcnt));
1345             }
1346             ptr_pipe->num_transferring = 0U;
1347         }
1348 
1349         if ((hcint & USB_CH_HCINTMSK_NakMsk_Msk)!=0U) {                                /* if NAK */
1350             is_nack[ch] = true;
1351             ptr_pipe->event |= (uint8_t)XMC_USBH_EVENT_HANDSHAKE_NAK;
1352             ptr_ch->HCINT = USB_CH_HCINTMSK_NakMsk_Msk;                                /*    clear NAK interrupt */
1353             if ((ptr_ch->HCCHAR & USB_CH_HCCHAR_EPDir_Msk) != 0U) {                    /*    endpoint IN ? */
1354               if (ptr_pipe->ep_type == (uint8_t)XMC_USBH_ENDPOINT_INTERRUPT) {                   /*     is endpoint of type interrupt ? */
1355                 XMC_lTriggerHaltChannel(ptr_ch);                                       /*      trigger channel halt (after halted will be restarted in next sof) */
1356               } else {                                                                 /*     is endpoint not of type interrupt ?*/
1357                 ptr_ch->HCCHAR |= (uint32_t)USB_CH_HCCHAR_ChEna_Msk;                             /*      trigger next transfer */
1358               }
1359             } else { /* If endpoint OUT */                                             /*    endpoint OUT ? */
1360               XMC_lTriggerHaltChannel(ptr_ch);                                         /*     trigger channel halt */
1361             }
1362             hcint = 0U;
1363         }
1364 
1365         if ((hcint & USB_CH_HCINTMSK_StallMsk_Msk) != 0U) {                              /* if STALL */
1366             /*Reset the packet data toggle*/
1367             ptr_ch->HCINT   = USB_CH_HCINTMSK_StallMsk_Msk;                              /*  clear STALL interrupt */
1368             ptr_pipe->in_use = 0U;                                                       /*  release pipe */
1369             ptr_pipe->packet &= (uint32_t)(~XMC_USBH_PACKET_DATA_Msk);
1370             ptr_pipe->packet   |=  (uint32_t)XMC_USBH_PACKET_DATA0;
1371             ptr_pipe->event = (uint8_t)XMC_USBH_EVENT_HANDSHAKE_STALL;                            /*  prepare event notification */
1372             XMC_lTriggerHaltChannel(ptr_ch);                                             /*  trigger channel halt */
1373             hcint = 0U;
1374         }
1375         if ((hcint & USB_CH_HCINTx_ERRORS) != 0U) {                                      /* if transaction error */
1376             ptr_ch->HCINT = USB_CH_HCINTx_ERRORS;                                        /*  clear all error interrupt */
1377             ptr_pipe->in_use = 0U;                                                       /*  release pipe */
1378             ptr_pipe->event = (uint8_t)XMC_USBH_EVENT_BUS_ERROR;                                  /*  prepare event notification */
1379             XMC_lTriggerHaltChannel(ptr_ch);                                             /*  trigger channel halt */
1380             hcint = 0U;
1381         }
1382         if ((ptr_pipe->transfer_active == 0U) && (ptr_pipe->in_use == 0U) && (ptr_pipe->event != 0U)) {
1383           XMC_USBH0_device.SignalPipeEvent_cb((XMC_USBH_EP_HANDLE)ptr_ch, (uint32_t)ptr_pipe->event);
1384           ptr_pipe->event  = 0U;
1385         }
1386       }
1387     }
1388   }
1389   /*Check if remote wakeup event detected*/
1390   if ((gintsts & USB_GINTSTS_HOSTMODE_WkUpInt_Msk) != 0U)
1391   {
1392     XMC_USBH0_device.global_register->GINTSTS_HOSTMODE =  USB_GINTSTS_HOSTMODE_WkUpInt_Msk; /* Clear wakeup interrupt */
1393     /*Recover PHY clock*/
1394     XMC_USBH0_device.global_register->PCGCCTL = XMC_USBH_PHY_CLK_UNGATE;
1395     /*Callback function execution*/
1396     XMC_USBH0_device.SignalPortEvent_cb(0U, XMC_USBH_EVENT_REMOTE_WAKEUP);
1397   }
1398 
1399   /* Handle restarts of unfinished transfers (due to NAK or ACK) */
1400   ptr_pipe = (XMC_USBH0_pipe_t *)(pipe);
1401   for (ch = 0U; ch < USBH0_MAX_PIPE_NUM; ch++) {
1402     if ((ptr_pipe->in_use == 1U) && (ptr_pipe->transfer_active == 0U)) {
1403       /* Restart periodic transfer if not in progress and interval expired */
1404       if (ptr_pipe->ep_type != (uint8_t)XMC_USBH_ENDPOINT_INTERRUPT)
1405       {
1406             /*Data toggle if NACK not received*/
1407             if (!is_nack[ch])
1408             {
1409               switch (ptr_pipe->packet & (uint32_t)XMC_USBH_PACKET_DATA_Msk)
1410               {
1411                 case XMC_USBH_PACKET_DATA0:
1412                   ptr_pipe->packet   &= (uint32_t)~XMC_USBH_PACKET_DATA_Msk;
1413                   ptr_pipe->packet   |= (uint32_t)XMC_USBH_PACKET_DATA1;
1414                   break;
1415                 case XMC_USBH_PACKET_DATA1:
1416                   ptr_pipe->packet   &= (uint32_t)~XMC_USBH_PACKET_DATA_Msk;
1417                   ptr_pipe->packet   |= (uint32_t)XMC_USBH_PACKET_DATA0;
1418                   break;
1419                 default:
1420                   break;
1421               }
1422             }
1423             else
1424             {
1425               is_nack[ch] = false;
1426             }
1427       }
1428       if (((ptr_pipe->ep_type == (uint8_t)XMC_USBH_ENDPOINT_INTERRUPT)&&(ptr_pipe->interrupt_triggered == 1U))||
1429                 (ptr_pipe->ep_type != (uint8_t)XMC_USBH_ENDPOINT_INTERRUPT))
1430       {
1431         ptr_pipe->interrupt_triggered = 0U;
1432         ptr_pipe->transfer_active = 1U;
1433         (void)XMC_lStartTransfer (ptr_pipe, (((USB0_CH_TypeDef *)(XMC_USBH0_device.host_channel_registers)) + ch));
1434       }
1435     }
1436     ptr_pipe++;
1437   }
1438 }
1439 
1440 /*Function provides host mode interrupt status*/
XMC_USBH_GetInterruptStatus(void)1441 uint32_t XMC_USBH_GetInterruptStatus(void)
1442 {
1443   return XMC_USBH0_device.global_register->GINTSTS_HOSTMODE;
1444 }
1445 
1446 /*Function selects the port pin used as DRIVEVBUS*/
XMC_USBH_Select_VBUS(XMC_GPIO_PORT_t * port,uint32_t pin)1447 void XMC_USBH_Select_VBUS(XMC_GPIO_PORT_t* port, uint32_t pin)
1448 {
1449   VBUS_port = port;
1450   VBUS_pin = pin;
1451 
1452   /*Configure the port pin alternate function*/
1453   XMC_GPIO_SetMode(VBUS_port, (uint8_t)VBUS_pin, XMC_GPIO_MODE_OUTPUT_PUSH_PULL_ALT1);
1454 }
1455 
1456 /*Function asserts the remote wakeup request by device by clearing the resume bit*/
XMC_USBH_TurnOffResumeBit(void)1457 void XMC_USBH_TurnOffResumeBit(void)
1458 {
1459   uint32_t hprt;
1460   /*Clear resume bit*/
1461   hprt = XMC_USBH0_device.global_register->HPRT;
1462   hprt &= (uint32_t)~(USB_HPRT_PrtEna_Msk);
1463   hprt &= (uint32_t)~((uint32_t)USB_HPRT_PrtRes_Msk);
1464   XMC_USBH0_device.global_register->HPRT = hprt;
1465 }
1466 
1467 
1468 
1469 /*USB host driver assembling all the implementation into a single CMSIS compliant structure type*/
1470 XMC_USBH_DRIVER_t Driver_USBH0 = {
1471   XMC_USBH_GetVersion,
1472   XMC_USBH_GetCapabilities,
1473   XMC_USBH_Initialize,
1474   XMC_USBH_Uninitialize,
1475   XMC_USBH_PowerControl,
1476   XMC_USBH_PortVbusOnOff,
1477   XMC_USBH_PortReset,
1478   XMC_USBH_PortSuspend,
1479   XMC_USBH_PortResume,
1480   XMC_USBH_PortGetState,
1481   XMC_USBH_PipeCreate,
1482   XMC_USBH_PipeModify,
1483   XMC_USBH_PipeDelete,
1484   XMC_USBH_PipeReset,
1485   XMC_USBH_PipeTransfer,
1486   XMC_USBH_PipeTransferGetResult,
1487   XMC_USBH_PipeTransferAbort,
1488   XMC_USBH_GetFrameNumber
1489 };
1490 
1491 
1492 /*Weak definition of delay function*/
XMC_USBH_osDelay(uint32_t MS)1493 __WEAK uint8_t XMC_USBH_osDelay(uint32_t MS)
1494 {
1495   (void)MS;
1496   /*A precise time delay implementation for this function has to be provided*/
1497   while (1)
1498   {
1499     /*Wait*/
1500   }
1501 }
1502 
1503 #endif
1504