1 /***************************************************************************//**
2 * \file cy_usbfs_dev_drv_io.c
3 * \version 2.30
4 *
5 * Provides data transfer API implementation of the USBFS driver.
6 *
7 ********************************************************************************
8 * \copyright
9 * Copyright 2018-2023 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(endpoint);
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