1 /***************************************************************************//**
2 * \file cy_usbfs_dev_drv_io.c
3 * \version 2.20.2
4 *
5 * Provides data transfer API implementation of the USBFS driver.
6 *
7 ********************************************************************************
8 * \copyright
9 * Copyright 2018-2020 Cypress Semiconductor Corporation
10 * SPDX-License-Identifier: Apache-2.0
11 *
12 * Licensed under the Apache License, Version 2.0 (the "License");
13 * you may not use this file except in compliance with the License.
14 * You may obtain a copy of the License at
15 *
16 *     http://www.apache.org/licenses/LICENSE-2.0
17 *
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
23 *******************************************************************************/
24 
25 #include "cy_device.h"
26 
27 #if defined (CY_IP_MXUSBFS) && defined (CY_IP_MXPERI)
28 
29 #include <string.h>
30 #include "cy_usbfs_dev_drv_pvt.h"
31 
32 #if defined(__cplusplus)
33 extern "C" {
34 #endif
35 
36 /*******************************************************************************
37 *                        Internal Constants
38 *******************************************************************************/
39 
40 /* The time to wait (in milliseconds) for completion of a BULK or INTERRUPT transfer (max packet 64 bytes).
41 * The transfer takes 48.5 us = (1/ 12) * (32 (IN/OUT) + (64 * 8 + 32) (DATA) + 16 (ACK) + 6 (EOPs)), used 50 us.
42 */
43 #define WAIT_TRANSFER_COMPLETE     (50U)
44 
45 /* Dedicated IN and OUT endpoints buffer: 32 bytes (2^5) */
46 #define ENDPOINTS_BUFFER_SIZE   (0x55UL)
47 
48 /* The number of bytes transferred by 1 Y-loop */
49 #define DMA_YLOOP_INCREMENT     (32UL)
50 
51 /* All arbiter interrupt sources */
52 #define ENDPOINT_ARB_INTR_SOURCES_ALL    (USBFS_USBDEV_ARB_EP_IN_BUF_FULL_Msk | \
53                                           USBFS_USBDEV_ARB_EP_DMA_GNT_Msk     | \
54                                           USBFS_USBDEV_ARB_EP_BUF_OVER_Msk    | \
55                                           USBFS_USBDEV_ARB_EP_BUF_UNDER_Msk   | \
56                                           USBFS_USBDEV_ARB_EP_ERR_Msk         | \
57                                           USBFS_USBDEV_ARB_EP_DMA_TERMIN_Msk)
58 
59 /* Arbiter interrupt sources for OUT and IN endpoints when mode is
60 * CY_USBFS_DEV_DRV_EP_MANAGEMENT_DMA_AUTO.
61 */
62 #define ENDPOINT_ARB_INTR_SOURCES_CPU       (USBFS_USBDEV_ARB_EP_ERR_Msk)
63 
64 #define OUT_ENDPOINT_ARB_INTR_SOURCES_CPU   (USBFS_USBDEV_ARB_EP_ERR_Msk)
65 
66 #define IN_ENDPOINT_ARB_INTR_SOURCES_DMA    (USBFS_USBDEV_ARB_EP_IN_BUF_FULL_Msk | \
67                                              USBFS_USBDEV_ARB_EP_ERR_Msk)
68 
69 #define OUT_ENDPOINT_ARB_INTR_SOURCES_DMA   (USBFS_USBDEV_ARB_EP_DMA_GNT_Msk | \
70                                              USBFS_USBDEV_ARB_EP_ERR_Msk)
71 
72 
73 /*******************************************************************************
74 *                        Internal Functions Prototypes
75 *******************************************************************************/
76 static void DisableEndpoint(USBFS_Type *base, uint32_t endpoint, cy_stc_usbfs_dev_drv_context_t *context);
77 
78 
79 /*******************************************************************************
80 * Function Name: DisableEndpoint
81 ****************************************************************************//**
82 *
83 * Disables the endpoint operation.
84 *
85 * \param base
86 * The pointer to the USBFS instance.
87 *
88 * \param endpoint
89 * The data endpoint number.
90 *
91 * \param context
92 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
93 * allocated by the user. The structure is used during the USBFS Device
94 * operation for internal configuration and data retention. The user must not
95 * modify anything in this structure.
96 *
97 *******************************************************************************/
DisableEndpoint(USBFS_Type * base,uint32_t endpoint,cy_stc_usbfs_dev_drv_context_t * context)98 static void DisableEndpoint(USBFS_Type *base, uint32_t endpoint, cy_stc_usbfs_dev_drv_context_t *context)
99 {
100     /* Disables endpoint SIE mode and sets the appropriate state */
101     Cy_USBFS_Dev_Drv_SetSieEpMode(base, endpoint, CY_USBFS_DEV_DRV_EP_CR_DISABLE);
102     context->epPool[endpoint].state = CY_USB_DEV_EP_DISABLED;
103 }
104 
105 
106 /*******************************************************************************
107 * Function Name: Cy_USBFS_Dev_Drv_ConfigDevice
108 ****************************************************************************//**
109 *
110 * Sets the basic device configuration (clears previous configuration).
111 * Call this function after the endpoints were configured to complete the
112 * device configuration.
113 *
114 * \param base
115 * The pointer to the USBFS instance.
116 *
117 * \param context
118 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
119 * allocated by the user. The structure is used during the USBFS Device
120 * operation for internal configuration and data retention. The user must not
121 * modify anything in this structure.
122 *
123 *******************************************************************************/
Cy_USBFS_Dev_Drv_ConfigDevice(USBFS_Type * base,cy_stc_usbfs_dev_drv_context_t * context)124 void Cy_USBFS_Dev_Drv_ConfigDevice(USBFS_Type *base, cy_stc_usbfs_dev_drv_context_t *context)
125 {
126     if (CY_USBFS_DEV_DRV_EP_MANAGEMENT_CPU != context->mode)
127     {
128         uint32_t autoMemMask = 0U;
129 
130         if (CY_USBFS_DEV_DRV_EP_MANAGEMENT_DMA_AUTO == context->mode)
131         {
132             autoMemMask = USBFS_USBDEV_ARB_CFG_AUTO_MEM_Msk;
133 
134             /* Configure DMA burst size */
135             USBFS_DEV_DMA_THRES16(base) = DMA_YLOOP_INCREMENT;
136             USBFS_DEV_BUF_SIZE(base)    = ENDPOINTS_BUFFER_SIZE;
137 
138             /* USBFS_DEV_EP_ACTIVE and USBFS_DEV_EP_TYPE are set when endpoint is added */
139         }
140 
141         /* The configuration completes: Generates a rising edge for the USBDEV_ARB_CFG.CFG_CMP bit */
142         USBFS_DEV_ARB_CFG(base)  = _VAL2FLD(USBFS_USBDEV_ARB_CFG_DMA_CFG, context->mode) |
143                                    autoMemMask;
144         /* Read the register to ensure that the write is flushed out to the hardware */
145         (void) USBFS_DEV_ARB_CFG(base);
146         USBFS_DEV_ARB_CFG(base) |= USBFS_USBDEV_ARB_CFG_CFG_CMP_Msk;
147         (void) USBFS_DEV_ARB_CFG(base);
148     }
149 }
150 
151 
152 /*******************************************************************************
153 * Function Name: Cy_USBFS_Dev_Drv_UnConfigureDevice
154 ****************************************************************************//**
155 *
156 * Clears device configuration.
157 * Call this function before setting a configuration or a configuration failure
158 * to set the configuration into the default state.
159 * Alternately, call \ref Cy_USBFS_Dev_Drv_RemoveEndpoint for each active endpoint.
160 *
161 * \param base
162 * The pointer to the USBFS instance.
163 *
164 * \param context
165 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
166 * allocated by the user. The structure is used during the USBFS Device
167 * operation for internal configuration and data retention. The user must not
168 * modify anything in this structure.
169 *
170 *******************************************************************************/
Cy_USBFS_Dev_Drv_UnConfigureDevice(USBFS_Type * base,cy_stc_usbfs_dev_drv_context_t * context)171 void Cy_USBFS_Dev_Drv_UnConfigureDevice(USBFS_Type *base, cy_stc_usbfs_dev_drv_context_t *context)
172 {
173     uint32_t endpoint;
174 
175     /* Clears the buffer pointer */
176     context->curBufAddr = 0U;
177 
178     /* Removes all active endpoints */
179     context->activeEpMask = 0U;
180 
181     /* Disables the SIE and Arbiter interrupts */
182     USBFS_DEV_SIE_EP_INT_EN(base) = 0UL;
183     USBFS_DEV_ARB_INT_EN(base)    = 0UL;
184 
185     /* Clear endpoints configuration */
186     for (endpoint = 0U; endpoint <  CY_USBFS_DEV_DRV_NUM_EPS_MAX; ++endpoint)
187     {
188         /* Disable endpoint operation */
189         DisableEndpoint(base, endpoint, context);
190     }
191 }
192 
193 
194 /*******************************************************************************
195 * Function Name: GetEndpointBuffer
196 ****************************************************************************//**
197 *
198 * Returns a start position in the allocated buffer for the data endpoint.
199 *
200 * \param size
201 * The data endpoint buffer size.
202 *
203 * \param idx
204 * The start position of the allocated endpoint buffer.
205 *
206 * \param context
207 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
208 * allocated by the user. The structure is used during the USBFS Device
209 * operation for internal configuration and data retention. The user must not
210 * modify anything in this structure.
211 *
212 * \return
213 * The status code of the function execution \ref cy_en_usbfs_dev_drv_status_t.
214 *
215 *******************************************************************************/
GetEndpointBuffer(uint32_t size,uint32_t * idx,cy_stc_usbfs_dev_drv_context_t * context)216 cy_en_usbfs_dev_drv_status_t GetEndpointBuffer(uint32_t size, uint32_t *idx, cy_stc_usbfs_dev_drv_context_t *context)
217 {
218     cy_en_usbfs_dev_drv_status_t retStatus = CY_USBFS_DEV_DRV_BUF_ALLOC_FAILED;
219     uint32_t bufSize;
220     uint32_t nextBufAddr;
221 
222     /* Get max buffer size */
223     bufSize = (CY_USBFS_DEV_DRV_EP_MANAGEMENT_DMA_AUTO != context->mode) ?
224                 CY_USBFS_DEV_DRV_HW_BUFFER_SIZE :
225                 context->epSharedBufSize;
226 
227     /* Gets a next buffer address. Note: the end buffer size must be even for the 16-bit access. */
228     nextBufAddr  = (context->curBufAddr + size);
229     nextBufAddr += (context->useReg16) ? (size & 0x01U) : 0U;
230 
231     /* Checks whether there is enough space in the buffer. */
232     if (nextBufAddr <= bufSize)
233     {
234         /* Updates the pointers */
235         *idx = context->curBufAddr;
236         context->curBufAddr = (uint16_t) nextBufAddr;
237 
238         retStatus = CY_USBFS_DEV_DRV_SUCCESS;
239     }
240 
241     return retStatus;
242 }
243 
244 
245 /*******************************************************************************
246 * Function Name: RestoreEndpointHwBuffer
247 ****************************************************************************//**
248 *
249 * Restores the endpoint active configuration for
250 * \ref CY_USBFS_DEV_DRV_EP_MANAGEMENT_CPU and
251 * \ref CY_USBFS_DEV_DRV_EP_MANAGEMENT_DMA modes.
252 *
253 * \param base
254 * The pointer to the USBFS instance.
255 *
256 * \param mode
257 * Endpoints management mode.
258 *
259 * \param endpointData
260 * The pointer to the endpoint data structure.
261 *
262 *******************************************************************************/
RestoreEndpointHwBuffer(USBFS_Type * base,cy_en_usbfs_dev_drv_ep_management_mode_t mode,cy_stc_usbfs_dev_drv_endpoint_data_t * endpointData)263 void RestoreEndpointHwBuffer(USBFS_Type *base,
264                              cy_en_usbfs_dev_drv_ep_management_mode_t mode,
265                              cy_stc_usbfs_dev_drv_endpoint_data_t *endpointData)
266 {
267     bool inDirection  = IS_EP_DIR_IN(endpointData->address);
268     uint32_t endpoint = EPADDR2PHY(endpointData->address);
269 
270     /* Clears the  state: MEM_DATA is not non-retention */
271     endpointData->state = CY_USB_DEV_EP_IDLE;
272 
273     /* Sets the Arbiter read and write pointers */
274     Cy_USBFS_Dev_Drv_SetArbWriteAddr(base, endpoint, (uint32_t) endpointData->startBuf);
275     Cy_USBFS_Dev_Drv_SetArbReadAddr (base, endpoint, (uint32_t) endpointData->startBuf);
276 
277     /* Enables the endpoint Arbiter interrupt sources */
278     if (CY_USBFS_DEV_DRV_EP_MANAGEMENT_DMA == mode)
279     {
280         /* Enables the Arbiter interrupt sources for endpoint */
281         Cy_USBFS_Dev_Drv_SetArbEpInterruptMask(base, endpoint, (inDirection ?
282                                                                 IN_ENDPOINT_ARB_INTR_SOURCES_DMA :
283                                                                 OUT_ENDPOINT_ARB_INTR_SOURCES_DMA));
284 
285         /* Enables the Arbiter interrupt for endpoint */
286         Cy_USBFS_Dev_Drv_EnableArbEpInterrupt(base, endpoint);
287 
288         /* Enables the DMA channel */
289          Cy_DMA_Channel_Enable(endpointData->base, endpointData->chNum);
290     }
291     else
292     {
293         /* Enables the error interrupt triggered by SIE */
294         Cy_USBFS_Dev_Drv_SetArbEpInterruptMask(base, endpoint, ENDPOINT_ARB_INTR_SOURCES_CPU);
295     }
296 
297     /* Enables the SIE interrupt for the endpoint */
298     Cy_USBFS_Dev_Drv_EnableSieEpInterrupt(base, endpoint);
299 
300     /* Sets an arbiter configuration */
301     Cy_USBFS_Dev_Drv_SetArbEpConfig(base, endpoint, (USBFS_USBDEV_ARB_EP1_CFG_CRC_BYPASS_Msk |
302                                                      USBFS_USBDEV_ARB_EP1_CFG_RESET_PTR_Msk));
303 
304     /* Set endpoint mode to not respond to host */
305     Cy_USBFS_Dev_Drv_SetSieEpMode(base, endpoint, GetEndpointInactiveMode((uint32_t) endpointData->sieMode));
306 }
307 
308 
309 /*******************************************************************************
310 * Function Name: AddEndpointHwBuffer
311 ****************************************************************************//**
312 *
313 * Implements \ref Cy_USBFS_Dev_Drv_AddEndpoint for
314 * \ref CY_USBFS_DEV_DRV_EP_MANAGEMENT_CPU and
315 * \ref CY_USBFS_DEV_DRV_EP_MANAGEMENT_DMA modes.
316 *
317 * \param base
318 * The pointer to the USBFS instance.
319 *
320 * \param config
321 * The pointer to data endpoint configuration \ref cy_stc_usb_dev_ep_config_t.
322 *
323 * \param context
324 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
325 * allocated by the user. The structure is used during the USBFS Device
326 * operation for internal configuration and data retention. The user must not
327 * modify anything in this structure.
328 *
329 * \return
330 * The status code of the function execution \ref cy_en_usbfs_dev_drv_status_t.
331 *
332 *******************************************************************************/
AddEndpointHwBuffer(USBFS_Type * base,cy_stc_usb_dev_ep_config_t const * config,cy_stc_usbfs_dev_drv_context_t * context)333 cy_en_usbfs_dev_drv_status_t AddEndpointHwBuffer(USBFS_Type *base,
334                                                  cy_stc_usb_dev_ep_config_t const *config,
335                                                  cy_stc_usbfs_dev_drv_context_t   *context)
336 {
337     uint32_t endpoint = EPADDR2PHY(config->endpointAddr);
338 
339     /* Gets a pointer to the endpoint data */
340     cy_stc_usbfs_dev_drv_endpoint_data_t *endpointData = &context->epPool[endpoint];
341 
342     /* Gets a buffer for the endpoint using the hardware buffer */
343     if (config->allocBuffer)
344     {
345         uint32_t bufOffset;
346 
347         /* Gets a buffer for the endpoint */
348         cy_en_usbfs_dev_drv_status_t retStatus = GetEndpointBuffer((uint32_t) config->bufferSize, &bufOffset, context);
349         if (CY_USBFS_DEV_DRV_SUCCESS != retStatus)
350         {
351             return retStatus;
352         }
353 
354         /* Sets the Arbiter read and write pointers */
355         endpointData->startBuf = (uint16_t) bufOffset;
356         Cy_USBFS_Dev_Drv_SetArbWriteAddr(base, endpoint, bufOffset);
357         Cy_USBFS_Dev_Drv_SetArbReadAddr (base, endpoint, bufOffset);
358     }
359 
360     /* Enables the endpoint for the operation */
361     if (config->enableEndpoint)
362     {
363         bool inDirection = IS_EP_DIR_IN(config->endpointAddr);
364 
365         /* Configures the endpoint */
366         endpointData->state   = CY_USB_DEV_EP_IDLE;
367         endpointData->address = config->endpointAddr;
368         endpointData->toggle  = 0U;
369         endpointData->bufferSize = config->maxPacketSize;
370         endpointData->sieMode = GetEndpointActiveMode(inDirection, config->attributes);
371         endpointData->isPending = false;
372 
373         /* Sets an arbiter configuration (clears DMA requests) */
374         Cy_USBFS_Dev_Drv_SetArbEpConfig(base, endpoint, (USBFS_USBDEV_ARB_EP1_CFG_CRC_BYPASS_Msk |
375                                                          USBFS_USBDEV_ARB_EP1_CFG_RESET_PTR_Msk));
376 
377         /* Flushes the IN endpoint buffer to discard the loaded data.
378         * It happens when: an alternate settings change is requested and the IN
379         * endpoint buffer is full (not read by the Host).
380         */
381         if (inDirection)
382         {
383             Cy_USBFS_Dev_Drv_FlushInBuffer(base, endpoint);
384         }
385 
386         /* Enables the endpoint arbiter interrupt sources */
387         if (CY_USBFS_DEV_DRV_EP_MANAGEMENT_DMA == context->mode)
388         {
389             /* Configures the DMA based on the endpoint direction */
390             cy_en_usbfs_dev_drv_status_t retStatus = DmaEndpointInit(base, context->mode, context->useReg16, &context->epPool[endpoint]);
391             if (CY_USBFS_DEV_DRV_SUCCESS != retStatus)
392             {
393                 return retStatus;
394             }
395 
396             /* Enables the arbiter interrupt sources for the endpoint */
397             Cy_USBFS_Dev_Drv_SetArbEpInterruptMask(base, endpoint, (inDirection ?
398                                                                     IN_ENDPOINT_ARB_INTR_SOURCES_DMA :
399                                                                     OUT_ENDPOINT_ARB_INTR_SOURCES_DMA));
400 
401             /* Enables the arbiter interrupt for the endpoint */
402             Cy_USBFS_Dev_Drv_EnableArbEpInterrupt(base, endpoint);
403         }
404         else
405         {
406             /* Enables the error interrupt triggered by SIE */
407             Cy_USBFS_Dev_Drv_SetArbEpInterruptMask(base, endpoint, ENDPOINT_ARB_INTR_SOURCES_CPU);
408         }
409 
410         /* Enables the SIE interrupt for the endpoint */
411         Cy_USBFS_Dev_Drv_EnableSieEpInterrupt(base, endpoint);
412 
413         /* Sets endpoint mode to not respond to the host */
414         Cy_USBFS_Dev_Drv_SetSieEpMode(base, endpoint, GetEndpointInactiveMode((uint32_t) endpointData->sieMode));
415     }
416 
417     return CY_USBFS_DEV_DRV_SUCCESS;
418 }
419 
420 
421 /*******************************************************************************
422 * Function Name: Cy_USBFS_Dev_Drv_RemoveEndpoint
423 ****************************************************************************//**
424 *
425 * Removes a data endpoint (release hardware resources allocated by data endpoint).
426 *
427 * \param base
428 * The pointer to the USBFS instance.
429 *
430 * \param endpointAddr
431 * The data endpoint address (7 bit - direction, 3-0 bits - endpoint number).
432 *
433 * \param context
434 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
435 * allocated by the user. The structure is used during the USBFS Device
436 * operation for internal configuration and data retention. The user must not
437 * modify anything in this structure.
438 *
439 * \return
440 * Status code of the function execution \ref cy_en_usbfs_dev_drv_status_t.
441 *
442 *******************************************************************************/
Cy_USBFS_Dev_Drv_RemoveEndpoint(USBFS_Type * base,uint32_t endpointAddr,cy_stc_usbfs_dev_drv_context_t * context)443 cy_en_usbfs_dev_drv_status_t Cy_USBFS_Dev_Drv_RemoveEndpoint(USBFS_Type *base,
444                                                              uint32_t    endpointAddr,
445                                                              cy_stc_usbfs_dev_drv_context_t *context)
446 {
447     uint32_t endpoint = EPADDR2EP(endpointAddr);
448 
449     /* Checks if the endpoint is supported by the driver */
450     if (false == IS_EP_VALID(endpoint))
451     {
452         return CY_USBFS_DEV_DRV_BAD_PARAM;
453     }
454 
455     endpoint = EP2PHY(endpoint);
456 
457     /* Disable endpoint operation */
458     DisableEndpoint(base, endpoint, context);
459 
460     /* Disable SIE and Arbiter interrupt for endpoint */
461     Cy_USBFS_Dev_Drv_DisableSieEpInterrupt(base, endpoint);
462     Cy_USBFS_Dev_Drv_DisableArbEpInterrupt(base, endpoint);
463 
464     /* Clear SIE and Arbiter interrupt for endpoint */
465     Cy_USBFS_Dev_Drv_ClearSieEpInterrupt(base, endpoint);
466     Cy_USBFS_Dev_Drv_ClearArbEpInterrupt(base, endpoint, ENDPOINT_ARB_INTR_SOURCES_ALL);
467 
468     /* Removes the active endpoint */
469     context->activeEpMask &= (uint8_t) ~EP2MASK(endpont);
470 
471     /* Clear abort mask for endpoint */
472     context->epAbortMask &= (uint8_t) ~EP2MASK(endpoint);
473 
474     return CY_USBFS_DEV_DRV_SUCCESS;
475 }
476 
477 
478 /*******************************************************************************
479 * Function Name: Cy_USBFS_Dev_Drv_EnableOutEndpoint
480 ****************************************************************************//**
481 *
482 * Enables the OUT data endpoint to be read by the Host.
483 *
484 * \param base
485 * The pointer to the USBFS instance.
486 *
487 * \param endpoint
488 * The OUT data endpoint number.
489 *
490 * \param context
491 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
492 * allocated by the user. The structure is used during the USBFS Device
493 * operation for internal configuration and data retention. The user must not
494 * modify anything in this structure.
495 *
496 * \return
497 * Status code of the function execution \ref cy_en_usbfs_dev_drv_status_t.
498 *
499 * \note
500 * The OUT endpoints are not enabled by default. The endpoints must be enabled
501 * before calling \ref Cy_USBFS_Dev_Drv_ReadOutEndpoint to read data from an endpoint.
502 *
503 *******************************************************************************/
Cy_USBFS_Dev_Drv_EnableOutEndpoint(USBFS_Type * base,uint32_t endpoint,cy_stc_usbfs_dev_drv_context_t * context)504 void Cy_USBFS_Dev_Drv_EnableOutEndpoint(USBFS_Type *base,
505                                         uint32_t    endpoint,
506                                         cy_stc_usbfs_dev_drv_context_t *context)
507 {
508     CY_ASSERT_L1(IS_EP_VALID(endpoint));
509 
510     endpoint = EP2PHY(endpoint);
511     CY_ASSERT_L1(IS_EP_DIR_OUT(context->epPool[endpoint].address));
512 
513     /* Get pointer to endpoint data */
514     cy_stc_usbfs_dev_drv_endpoint_data_t *endpointData = &context->epPool[endpoint];
515 
516     /* Clear abort mask for the endpoint (there is no transfer during abort) */
517     context->epAbortMask &= (uint8_t) ~EP2MASK(endpoint);
518 
519     /* Endpoint pending: Waits for the host write data after exiting this function */
520     endpointData->state = CY_USB_DEV_EP_PENDING;
521 
522     /* Arm endpoint: Host is allowed to write data */
523     Cy_USBFS_Dev_Drv_SetSieEpMode(base, endpoint, (uint32_t) endpointData->sieMode);
524 }
525 
526 
527 /*******************************************************************************
528 * Function Name: LoadInEndpointCpu
529 ****************************************************************************//**
530 *
531 * Implements \ref Cy_USBFS_Dev_Drv_LoadInEndpoint for
532 * \ref CY_USBFS_DEV_DRV_EP_MANAGEMENT_CPU mode.
533 *
534 * \param base
535 * The pointer to the USBFS instance.
536 *
537 * \param endpoint
538 * The IN data endpoint number.
539 *
540 * \param buffer
541 * The pointer to the buffer containing data bytes to load.
542 *
543 * \param size
544 * The number of bytes to load into endpoint.
545 * This value must be less than or equal to endpoint maximum packet size.
546 *
547 * \param context
548 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
549 * allocated by the user. The structure is used during the USBFS Device
550 * operation for internal configuration and data retention. The user must not
551 * modify anything in this structure.
552 *
553 * \return
554 * Status code of the function execution \ref cy_en_usbfs_dev_drv_status_t.
555 *
556 *******************************************************************************/
LoadInEndpointCpu(USBFS_Type * base,uint32_t endpoint,uint8_t const * buffer,uint32_t size,cy_stc_usbfs_dev_drv_context_t * context)557 cy_en_usbfs_dev_drv_status_t LoadInEndpointCpu(USBFS_Type   *base,
558                                                uint32_t      endpoint,
559                                                uint8_t const *buffer,
560                                                uint32_t      size,
561                                                cy_stc_usbfs_dev_drv_context_t *context)
562 {
563     /* Get pointer to endpoint data */
564     cy_stc_usbfs_dev_drv_endpoint_data_t *endpointData = &context->epPool[endpoint];
565 
566     /* Request to load more bytes than endpoint buffer */
567     if (size > endpointData->bufferSize)
568     {
569         return CY_USBFS_DEV_DRV_BAD_PARAM;
570     }
571 
572     /* Clear abort mask for the endpoint (there is no transfer during abort) */
573     context->epAbortMask &= (uint8_t) ~EP2MASK(endpoint);
574 
575     /* Endpoint pending: Waits for the host read data after exiting this function */
576     endpointData->state = CY_USB_DEV_EP_PENDING;
577 
578     /* Set count and data toggle */
579     Cy_USBFS_Dev_Drv_SetSieEpCount(base, endpoint, size, (uint32_t) endpointData->toggle);
580 
581     if (0U == size)
582     {
583         /* Arm endpoint: endpoint ACK Host request */
584         Cy_USBFS_Dev_Drv_SetSieEpMode(base, endpoint, (uint32_t) endpointData->sieMode);
585     }
586     else
587     {
588         uint32_t idx;
589 
590         if (context->useReg16)
591         {
592             /* Get pointer to the buffer */
593             CY_MISRA_DEVIATE_LINE('MISRA C-2012 Rule 11.3', 'Cast buffer parameter is safe. User must use special macro to allocate buffer, which handles alignment issues.');
594             uint16_t const *ptr = (uint16_t const *) buffer;
595 
596             /* Get number of writes into the 16-bit register */
597             size = GET_SIZE16(size);
598 
599             /* Copy data from the user buffer into the hardware buffer */
600             for (idx = 0U; idx < size; ++idx)
601             {
602                 Cy_USBFS_Dev_Drv_WriteData16(base, endpoint, ptr[idx]);
603             }
604         }
605         else
606         {
607 
608             /* Copy data from the user buffer into the hardware buffer */
609             for (idx = 0U; idx < size; ++idx)
610             {
611                 Cy_USBFS_Dev_Drv_WriteData(base, endpoint, buffer[idx]);
612             }
613         }
614 
615         /* Arm endpoint: endpoint ACK host request */
616         Cy_USBFS_Dev_Drv_SetSieEpMode(base, endpoint, (uint32_t) endpointData->sieMode);
617     }
618 
619     return CY_USBFS_DEV_DRV_SUCCESS;
620 }
621 
622 
623 /*******************************************************************************
624 * Function Name: ReadOutEndpointCpu
625 ****************************************************************************//**
626 *
627 * Implements \ref Cy_USBFS_Dev_Drv_ReadOutEndpoint for
628 * \ref CY_USBFS_DEV_DRV_EP_MANAGEMENT_CPU mode.
629 *
630 * \param base
631 * The pointer to the USBFS instance.
632 *
633 * \param endpoint
634 * The OUT data endpoint number.
635 *
636 * \param buffer
637 * Pointer to the buffer that stores data that was read.
638 *
639 * \param size
640 * The number of bytes to read from endpoint.
641 * This value must be less than or equal to endpoint maximum packet size.
642 *
643 * \param actSize
644 * The number of bytes that were actually read.
645 *
646 * \param context
647 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
648 * allocated by the user. The structure is used during the USBFS Device
649 * operation for internal configuration and data retention. The user must not
650 * modify anything in this structure.
651 *
652 * \return
653 * Status code of the function execution \ref cy_en_usbfs_dev_drv_status_t.
654 *
655 *******************************************************************************/
ReadOutEndpointCpu(USBFS_Type * base,uint32_t endpoint,uint8_t * buffer,uint32_t size,uint32_t * actSize,cy_stc_usbfs_dev_drv_context_t * context)656 cy_en_usbfs_dev_drv_status_t ReadOutEndpointCpu(USBFS_Type *base,
657                                                 uint32_t   endpoint,
658                                                 uint8_t    *buffer,
659                                                 uint32_t   size,
660                                                 uint32_t   *actSize,
661                                                 cy_stc_usbfs_dev_drv_context_t *context)
662 {
663     uint32_t idx;
664     uint32_t numToCopy;
665 
666     /* Suppress a compiler warning about unused variables */
667     (void) context;
668 
669     /* Get number of received bytes */
670     numToCopy = Cy_USBFS_Dev_Drv_GetSieEpCount(base, endpoint);
671 
672     /* Initialize actual number of copied bytes */
673     *actSize = 0U;
674 
675     /* Endpoint received more bytes than provided buffer */
676     if (numToCopy > size)
677     {
678         return CY_USBFS_DEV_DRV_BAD_PARAM;
679     }
680 
681     /* Nothing to copy (zero length packet) return success */
682     if (0U == numToCopy)
683     {
684         return CY_USBFS_DEV_DRV_SUCCESS;
685     }
686 
687     /* Update number of copied bytes */
688     *actSize = numToCopy;
689 
690     if (context->useReg16)
691     {
692         /* Get pointer to the buffer */
693         CY_MISRA_DEVIATE_LINE('MISRA C-2012 Rule 11.3', 'Cast buffer parameter is safe. User must use special macro to xallocate buffer, which handles alignment issues.');
694         uint16_t *ptr = (uint16_t *) buffer;
695 
696         /* Get number of reads from 16-bit register */
697         numToCopy = GET_SIZE16(numToCopy);
698 
699         /* Copy data from the hardware buffer into user buffer */
700         for (idx = 0U; idx < numToCopy; ++idx)
701         {
702             ptr[idx] = Cy_USBFS_Dev_Drv_ReadData16(base, endpoint);
703         }
704     }
705     else
706     {
707         /* Copy data from the hardware buffer into the user buffer */
708         for (idx = 0U; idx < numToCopy; ++idx)
709         {
710             buffer[idx] = Cy_USBFS_Dev_Drv_ReadData(base, endpoint);
711         }
712     }
713 
714     return CY_USBFS_DEV_DRV_SUCCESS;
715 }
716 
717 
718 /*******************************************************************************
719 * Function Name: Cy_USBFS_Dev_Drv_Abort
720 ****************************************************************************//**
721 *
722 * Abort operation for data endpoint.
723 * If there is any bus activity after the abort operation requested, the function
724 * waits for its completion or a timeout. A timeout is the time to transfer the
725 * bulk or an interrupt packet of the maximum playload size. If this bus activity is
726 * a transfer to the aborting endpoint, the received data is lost and the endpoint
727 * transfer completion callbacks are not invoked.
728 * After the function returns a new read or write, the endpoint operation can be submitted.
729 *
730 * \param base
731 * The pointer to the USBFS instance.
732 *
733 * \param endpoint
734 * The data endpoint number.
735 *
736 * \param context
737 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
738 * allocated by the user. The structure is used during the USBFS Device
739 * operation for internal configuration and data retention. The user must not
740 * modify anything in this structure.
741 *
742 * \return
743 * Data endpoint state \ref cy_en_usb_dev_ep_state_t after abort was applied.
744 *
745 * \note
746 * - This abort operation is not supported for the ISOC endpoints because
747 *   these endpoints do not have a handshake and are always accessible to the
748 *   USB Host. Therefore, an abort can cause unexpected behavior.
749 * - The function uses the critical section to protect from the endpoint transfer
750 *   complete interrupt.
751 *
752 *******************************************************************************/
Cy_USBFS_Dev_Drv_Abort(USBFS_Type * base,uint32_t endpoint,cy_stc_usbfs_dev_drv_context_t * context)753 cy_en_usbfs_dev_drv_status_t Cy_USBFS_Dev_Drv_Abort(USBFS_Type *base,
754                                                     uint32_t   endpoint,
755                                                     cy_stc_usbfs_dev_drv_context_t *context)
756 {
757     cy_en_usbfs_dev_drv_status_t retStatus = CY_USBFS_DEV_DRV_BAD_PARAM;
758     cy_stc_usbfs_dev_drv_endpoint_data_t *endpointData;
759     bool flushBuffer = true;
760     uint32_t intrState;
761 
762     /* Checks if the endpoint is supported by the driver */
763     if (false == IS_EP_VALID(endpoint))
764     {
765         return retStatus;
766     }
767 
768     endpoint = EP2PHY(endpoint);
769     endpointData = &context->epPool[endpoint];
770 
771     /* Locks from the context modification by the endpoint completion interrupt */
772     intrState = Cy_SysLib_EnterCriticalSection();
773 
774     /* Checks whether the endpoint is configured */
775     if (CY_USB_DEV_EP_DISABLED == endpointData->state)
776     {
777         return retStatus;
778     }
779     else if (CY_USB_DEV_EP_STALLED == endpointData->state)
780     {
781         /* Aborts a pending transfer if the endpoint is stalled */
782         context->epAbortMask |= (uint8_t) EP2MASK(endpoint);
783         endpointData->isPending = false;
784     }
785     else if (CY_USB_DEV_EP_PENDING == endpointData->state)
786     {
787         bool isocEp = false;
788 
789         /* Sets an abort mask to discard the completion events */
790         context->epAbortMask |= (uint8_t) EP2MASK(endpoint);
791         endpointData->state   = CY_USB_DEV_EP_IDLE;
792 
793         /* Clears the bus busy activity */
794         (void) Cy_USBFS_Dev_Drv_CheckActivity(base);
795 
796         if (endpointData->sieMode == CY_USBFS_DEV_DRV_EP_CR_ACK_IN)
797         {
798             Cy_USBFS_Dev_Drv_SetSieEpMode(base, endpoint, CY_USBFS_DEV_DRV_EP_CR_NAK_IN);
799         }
800         else if (endpointData->sieMode == CY_USBFS_DEV_DRV_EP_CR_ACK_OUT)
801         {
802             Cy_USBFS_Dev_Drv_SetSieEpMode(base, endpoint, CY_USBFS_DEV_DRV_EP_CR_NAK_OUT);
803         }
804         else
805         {
806             /* Does not wait for the ISOC endpoint */
807             isocEp = true;
808         }
809 
810         if (false == isocEp)
811         {
812             /* If there is a bus activity, it could be a transfer to the aborted endpoint */
813             if (Cy_USBFS_Dev_Drv_CheckActivity(base))
814             {
815                 /* Releases the lock */
816                 Cy_SysLib_ExitCriticalSection(intrState);
817 
818                 uint32_t timeout = WAIT_TRANSFER_COMPLETE;
819 
820                 /* Waits for BULK or INTERRUPT transfer completion or a NACK interrupt */
821                 while ( (timeout != 0U) &&
822                         (0U != (context->epAbortMask & EP2MASK(endpoint))) )
823                 {
824                     if (false == Cy_USBFS_Dev_Drv_CheckActivity(base))
825                     {
826                         break;
827                     }
828 
829                     Cy_SysLib_DelayUs(1U);
830                     --timeout;
831                 }
832             }
833         }
834 
835         /* The abort mask is cleared in the endpoint completion interrupt OR
836         *  on a following call of the endpoint Remove, LoadIn or EnableOut function.
837         */
838     }
839     else
840     {
841         /* Does nothing for all other states: CY_USB_DEV_EP_IDLE or CY_USB_DEV_EP_COMPLETED */
842         flushBuffer = false;
843         retStatus = CY_USBFS_DEV_DRV_SUCCESS;
844     }
845 
846     /* Releases the lock */
847     Cy_SysLib_ExitCriticalSection(intrState);
848 
849     if (flushBuffer)
850     {
851         bool inDirection = IS_EP_DIR_IN(endpointData->address);
852 
853         /* Initializes the pointers to functions that work with the data endpoint */
854         switch(context->mode)
855         {
856             case CY_USBFS_DEV_DRV_EP_MANAGEMENT_CPU:
857             case CY_USBFS_DEV_DRV_EP_MANAGEMENT_DMA:
858             {
859                 /* IN endpoint: Flushes the buffer to discard the loaded data.
860                 *  OUT endpoint: Leaves the written data in the buffer.
861                 */
862                 if (inDirection)
863                 {
864                     Cy_USBFS_Dev_Drv_FlushInBuffer(base, endpoint);
865                 }
866 
867                 retStatus = CY_USBFS_DEV_DRV_SUCCESS;
868             }
869             break;
870 
871             case CY_USBFS_DEV_DRV_EP_MANAGEMENT_DMA_AUTO:
872             {
873                 /* IN endpoint: Flushes the buffer to discard the loaded data.
874                 *  OUT endpoint: Waits for DMA to complete if a transfer has been started.
875                 */
876                 retStatus = DynamicEndpointReConfiguration(base, inDirection, endpoint);
877             }
878             break;
879 
880             default:
881                 /* Unknown mode */
882                 break;
883         }
884     }
885 
886     return retStatus;
887 }
888 
889 
890 /*******************************************************************************
891 * Function Name: Cy_USBFS_Dev_Drv_StallEndpoint
892 ****************************************************************************//**
893 *
894 * Configures data endpoint to STALL any request intended for it.
895 *
896 * \param base
897 * The pointer to the USBFS instance.
898 *
899 * \param endpoint
900 * The data endpoint number.
901 *
902 * \param context
903 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
904 * allocated by the user. The structure is used during the USBFS Device
905 * operation for internal configuration and data retention. The user must not
906 * modify anything in this structure.
907 *
908 * \return
909 * Status code of the function execution \ref cy_en_usbfs_dev_drv_status_t.
910 *
911 *******************************************************************************/
Cy_USBFS_Dev_Drv_StallEndpoint(USBFS_Type * base,uint32_t endpoint,cy_stc_usbfs_dev_drv_context_t * context)912 cy_en_usbfs_dev_drv_status_t Cy_USBFS_Dev_Drv_StallEndpoint(USBFS_Type *base,
913                                                             uint32_t    endpoint,
914                                                             cy_stc_usbfs_dev_drv_context_t *context)
915 {
916     cy_stc_usbfs_dev_drv_endpoint_data_t *endpointData;
917 
918     /* Check if endpoint is supported by driver */
919     if (false == IS_EP_VALID(endpoint))
920     {
921         return CY_USBFS_DEV_DRV_BAD_PARAM;
922     }
923 
924     endpoint = EP2PHY(endpoint);
925     endpointData = &context->epPool[endpoint];
926 
927     /* Check whether endpoint is configured */
928     if (CY_USB_DEV_EP_DISABLED == endpointData->state)
929     {
930         return CY_USBFS_DEV_DRV_BAD_PARAM;
931     }
932 
933     /* Store current endpoint state to restore it after Stall clear */
934     endpointData->isPending = (CY_USB_DEV_EP_PENDING == endpointData->state);
935 
936     /* Stall endpoint */
937     Cy_USBFS_Dev_Drv_SetSieEpStall(base, IS_EP_DIR_IN(endpointData->address), endpoint);
938     endpointData->state = CY_USB_DEV_EP_STALLED;
939 
940     return CY_USBFS_DEV_DRV_SUCCESS;
941 }
942 
943 
944 /*******************************************************************************
945 * Function Name: Cy_USBFS_Dev_Drv_UnStallEndpoint
946 ****************************************************************************//**
947 *
948 * Release data endpoint STALL condition and clears data toggle bit.
949 * The endpoint is returned to the same state as it was before STALL request.
950 *
951 * \param base
952 * The pointer to the USBFS instance.
953 *
954 * \param endpoint
955 * The data endpoint number.
956 *
957 * \param context
958 * The pointer to the context structure \ref cy_stc_usbfs_dev_drv_context_t
959 * allocated by the user. The structure is used during the USBFS Device
960 * operation for internal configuration and data retention. The user must not
961 * modify anything in this structure.
962 *
963 * \return
964 * Status code of the function execution \ref cy_en_usbfs_dev_drv_status_t.
965 *
966 *******************************************************************************/
Cy_USBFS_Dev_Drv_UnStallEndpoint(USBFS_Type * base,uint32_t endpoint,cy_stc_usbfs_dev_drv_context_t * context)967 cy_en_usbfs_dev_drv_status_t Cy_USBFS_Dev_Drv_UnStallEndpoint(USBFS_Type *base,
968                                                               uint32_t    endpoint,
969                                                               cy_stc_usbfs_dev_drv_context_t *context)
970 {
971     cy_stc_usbfs_dev_drv_endpoint_data_t *endpointData;
972 
973     /* Check whether the endpoint is supported by the driver */
974     if (false == IS_EP_VALID(endpoint))
975     {
976         return CY_USBFS_DEV_DRV_BAD_PARAM;
977     }
978 
979     endpoint = EP2PHY(endpoint);
980     endpointData = &context->epPool[endpoint];
981 
982     /* Check whether the endpoint is configured */
983     if (CY_USB_DEV_EP_DISABLED == endpointData->state)
984     {
985         return CY_USBFS_DEV_DRV_BAD_PARAM;
986     }
987 
988     /* Clear toggle bit */
989     endpointData->toggle = 0U;
990 
991     if (endpointData->isPending)
992     {
993         /* Restore pending state */
994         endpointData->state = CY_USB_DEV_EP_PENDING;
995 
996         /* Clear toggle and enable endpoint to respond to host */
997         Cy_USBFS_Dev_Drv_ClearSieEpToggle(base, endpoint);
998         Cy_USBFS_Dev_Drv_ClearSieEpStall (base, endpoint, (uint32_t) endpointData->sieMode);
999     }
1000     else
1001     {
1002         /* Endpoint is ready for operation */
1003         context->epPool[endpoint].state = CY_USB_DEV_EP_IDLE;
1004 
1005         /* Set endpoint inactive mode */
1006         Cy_USBFS_Dev_Drv_ClearSieEpToggle(base, endpoint);
1007         Cy_USBFS_Dev_Drv_ClearSieEpStall (base, endpoint, GetEndpointInactiveMode((uint32_t) endpointData->sieMode));
1008     }
1009 
1010     return CY_USBFS_DEV_DRV_SUCCESS;
1011 }
1012 
1013 #if defined(__cplusplus)
1014 }
1015 #endif
1016 
1017 #endif /* CY_IP_MXUSBFS */
1018 
1019 
1020 /* [] END OF FILE */
1021