-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcy_app_usb.c
472 lines (395 loc) · 15 KB
/
cy_app_usb.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
/***************************************************************************//**
* \file cy_app_usb.c
* \version 2.0
*
* \brief
* Implements the function for USB operation
*
********************************************************************************
* \copyright
* Copyright 2024, Cypress Semiconductor Corporation (an Infineon company)
* or an affiliate of Cypress Semiconductor Corporation. All rights reserved.
* You may use this file only in accordance with the license, terms, conditions,
* disclaimers, and limitations in the end user license agreement accompanying
* the software package with which this file was provided.
*******************************************************************************/
#if CY_APP_USB_ENABLE
#include "cy_pdl.h"
#include "cybsp.h"
#include "cy_app_status.h"
#include "cy_app_usb.h"
#include "cy_app_dmc_vendor.h"
#include "cy_app_flash_log.h"
#include "cy_pdutils.h"
#include "cy_pdstack_dpm.h"
/*******************************************************************************
* Macro definitions
********************************************************************************/
#define USB_EP0_SIZE (8u)
/*******************************************************************************
* Global variables
********************************************************************************/
cy_stc_app_usb_handle_t gl_usb;
uint8_t gl_ep0_buffer[516];
cy_stc_usb_init_ctxt_t *glUsbInitCtx;
/*******************************************************************************
* Function prototypes
********************************************************************************/
static void usb_high_isr(void);
static void usb_medium_isr(void);
static void usb_low_isr(void);
/* USB interrupt configuration */
const cy_stc_sysint_t usb_high_interrupt_cfg =
{
.intrSrc = (IRQn_Type) usb_interrupt_hi_IRQn,
.intrPriority = 0U,
};
const cy_stc_sysint_t usb_medium_interrupt_cfg =
{
.intrSrc = (IRQn_Type) usb_interrupt_med_IRQn,
.intrPriority = 1U,
};
const cy_stc_sysint_t usb_low_interrupt_cfg =
{
.intrSrc = (IRQn_Type) usb_interrupt_lo_IRQn,
.intrPriority = 2U,
};
/***************************************************************************
* Function name: usb_high_isr
********************************************************************************
* Summary:
* Processed the high-priority USB interrupts.
*
***************************************************************************/
static void usb_high_isr(void)
{
/* Call interrupt processing */
Cy_USBFS_Dev_Drv_Interrupt(glUsbInitCtx->base,
Cy_USBFS_Dev_Drv_GetInterruptCauseHi(glUsbInitCtx->base),
glUsbInitCtx->usb_drvContext);
}
/***************************************************************************
* Function name: usb_medium_isr
********************************************************************************
* Summary:
* Process the medium-priority USB interrupts.
*
***************************************************************************/
static void usb_medium_isr(void)
{
/* Call interrupt processing */
Cy_USBFS_Dev_Drv_Interrupt(glUsbInitCtx->base,
Cy_USBFS_Dev_Drv_GetInterruptCauseMed(glUsbInitCtx->base),
glUsbInitCtx->usb_drvContext);
}
/***************************************************************************
* Function name: usb_low_isr
********************************************************************************
* Summary:
* Processes the low-priority USB interrupts.
*
**************************************************************************/
static void usb_low_isr(void)
{
/* Call interrupt processing */
Cy_USBFS_Dev_Drv_Interrupt(glUsbInitCtx->base,
Cy_USBFS_Dev_Drv_GetInterruptCauseLo(glUsbInitCtx->base),
glUsbInitCtx->usb_drvContext);
}
void Cy_App_Usb_Init (cy_stc_usb_init_ctxt_t *usbInitCtx)
{
glUsbInitCtx = usbInitCtx;
if((Cy_PdStack_Dpm_GetContext(TYPEC_PORT_0_IDX))->ptrUsbPdContext->adcVdddMv[CY_USBPD_ADC_ID_0] > 3700)
{
Cy_USBFS_Dev_Drv_RegEnable(glUsbInitCtx->base, glUsbInitCtx->usb_drvContext);
}
else
{
Cy_USBFS_Dev_Drv_RegDisable(glUsbInitCtx->base, glUsbInitCtx->usb_drvContext);
}
Cy_USB_Dev_Init(glUsbInitCtx->base, glUsbInitCtx->drvConfig, glUsbInitCtx->usb_drvContext,
glUsbInitCtx->usbDevice, glUsbInitCtx->usbDevConfig, glUsbInitCtx->usb_devContext);
#if CY_APP_USB_HID_INTF_ENABLE
/* Initialize the HID class */
Cy_USB_Dev_HID_Init(glUsbInitCtx->hidConfig, glUsbInitCtx->usb_hidContext, glUsbInitCtx->usb_devContext);
Cy_USB_Dev_HID_RegisterGetReportCallback(glUsbInitCtx->getReportCallback, glUsbInitCtx->usb_hidContext);
Cy_USB_Dev_HID_RegisterSetReportCallback(glUsbInitCtx->setReportCallback, glUsbInitCtx->usb_hidContext);
#endif /* CY_APP_USB_HID_INTF_ENABLE */
/* Initialize the USB interrupts */
Cy_SysInt_Init(&usb_high_interrupt_cfg, &usb_high_isr);
Cy_SysInt_Init(&usb_medium_interrupt_cfg, &usb_medium_isr);
Cy_SysInt_Init(&usb_low_interrupt_cfg, &usb_low_isr);
/* Enable the USB interrupts */
NVIC_EnableIRQ(usb_high_interrupt_cfg.intrSrc);
NVIC_EnableIRQ(usb_medium_interrupt_cfg.intrSrc);
NVIC_EnableIRQ(usb_low_interrupt_cfg.intrSrc);
}
bool Cy_App_Usb_IsIdle (void)
{
static uint8_t debounce = 0;
if (glUsbInitCtx->usb_devContext->state == CY_USB_DEV_DISABLED)
{
return true;
}
if (0U == Cy_USBFS_Dev_Drv_CheckActivity(glUsbInitCtx->base))
{
debounce ++;
if (debounce >= 6)
{
debounce = 0;
return true;
}
}
else
{
debounce = 0;
}
return false;
}
void Cy_App_Usb_Sleep (void)
{
/* Prepare the device to move to Deep Sleep */
Cy_USBFS_Dev_Drv_Suspend(glUsbInitCtx->base, glUsbInitCtx->usb_drvContext);
#if defined(CY_DEVICE_PMG1S3)
Cy_GPIO_SetInterruptEdge(GPIO_PRT8, 0u, CY_GPIO_INTR_FALLING);
#endif /* defined(CY_DEVICE_PMG1S3) */
}
void Cy_App_Usb_Resume (void)
{
#if defined(CY_DEVICE_PMG1S3)
/* Disable the wake-up interrupt pin */
Cy_GPIO_SetInterruptEdge(GPIO_PRT8, 0u, CY_GPIO_INTR_DISABLE);
#endif /* defined(CY_DEVICE_PMG1S3) */
/* Prepares the USBFS component for operation after exiting Deep Sleep mode */
Cy_USBFS_Dev_Drv_Resume(glUsbInitCtx->base, glUsbInitCtx->usb_drvContext);
}
void Cy_App_Usb_Enable (void)
{
/* Makes device appear on the bus. This function call is blocked,
* till the device enumerates.
*/
Cy_USB_Dev_Connect(false, 1, glUsbInitCtx->usb_devContext);
Cy_USB_Dev_RegisterVendorCallbacks(&Cy_App_Usb_VendorReqReceived, &Cy_App_Usb_VendorReqCompleted, glUsbInitCtx->usb_devContext);
}
void Cy_App_Usb_Disable (void)
{
Cy_USB_Dev_Disconnect(glUsbInitCtx->usb_devContext);
}
void Cy_App_Usb_GetEp0State(void)
{
cy_stc_usb_dev_control_transfer_t *transfer = &glUsbInitCtx->usb_devContext->ControlTransfer;
cy_stc_usbfs_dev_drv_context_t *USB_drv_context = glUsbInitCtx->usb_drvContext;
switch (USB_drv_context->ep0CtrlState)
{
case CY_USBFS_DEV_DRV_EP0_CTRL_STATE_IDLE:
gl_usb.ep0_state = CY_APP_USB_EP0_STATE_DISABLED;
break;
case CY_USBFS_DEV_DRV_EP0_CTRL_STATE_SETUP:
gl_usb.ep0_state = CY_APP_USB_EP0_STATE_SETUP;
break;
case CY_USBFS_DEV_DRV_EP0_CTRL_STATE_DATA:
if(transfer->direction == CY_USB_DEV_DIR_DEVICE_TO_HOST)
{
gl_usb.ep0_state = CY_APP_USB_EP0_STATE_DATA_IN;
}
else{
gl_usb.ep0_state = CY_APP_USB_EP0_STATE_DATA_OUT;
}
break;
case CY_USBFS_DEV_DRV_EP0_CTRL_STATE_STATUS_IN:
gl_usb.ep0_state = CY_APP_USB_EP0_STATE_STATUS_IN;
break;
case CY_USBFS_DEV_DRV_EP0_CTRL_STATE_STATUS_OUT:
gl_usb.ep0_state = CY_APP_USB_EP0_STATE_STATUS_OUT;
break;
default:
gl_usb.ep0_state = CY_APP_USB_EP0_STATE_STALL;
}
}
uint8_t *Cy_App_Usb_GetEp0Buffer(void)
{
return (uint8_t *)gl_ep0_buffer;
}
cy_en_usb_dev_status_t Cy_App_Usb_Ep0SetupWrite(uint8_t *data, uint16_t length, bool last, cy_app_usb_setup_cbk_t cb)
{
cy_stc_usb_dev_control_transfer_t *transfer = &glUsbInitCtx->usb_devContext->ControlTransfer;
if (data == NULL)
{
return CY_USB_DEV_BAD_PARAM;
}
Cy_App_Usb_GetEp0State();
if ((gl_usb.ep0_state != CY_APP_USB_EP0_STATE_SETUP) &&
(gl_usb.ep0_state != CY_APP_USB_EP0_STATE_DATA_IN))
{
return CY_USB_DEV_DRV_HW_DISABLED;
}
transfer->ptr = (uint8_t *)data;
transfer->remaining = length;
if(length == 0)
{
transfer->zlp = true;
}
gl_usb.ep0_xfer_cb = cb;
(void) last;
return CY_USB_DEV_SUCCESS;
}
cy_en_usb_dev_status_t Cy_App_Usb_Ep0SetupRead(uint8_t *data, uint16_t length, cy_app_usb_setup_cbk_t cb)
{
cy_stc_usb_dev_control_transfer_t *transfer = &glUsbInitCtx->usb_devContext->ControlTransfer;
/* All read should be multiple of EP0 size. */
if ((data == NULL) || ((length & (USB_EP0_SIZE - 1)) != 0))
{
return CY_USB_DEV_BAD_PARAM;
}
Cy_App_Usb_GetEp0State();
if ((gl_usb.ep0_state != CY_APP_USB_EP0_STATE_SETUP) &&
(gl_usb.ep0_state != CY_APP_USB_EP0_STATE_DATA_OUT))
{
return CY_USB_DEV_DRV_HW_DISABLED;
}
transfer->buffer = gl_ep0_buffer;
transfer->remaining = length;
transfer->bufferSize = transfer->setup.wLength;
transfer->notify = true;
gl_usb.ep0_state = CY_APP_USB_EP0_STATE_DATA_OUT;
gl_usb.ep0_buffer = data;
gl_usb.ep0_length = length;
gl_usb.ep0_xfer_cb = cb;
return CY_USB_DEV_SUCCESS;
}
bool Cy_App_Usb_IsEpReady(cy_app_usb_ep_index_t ep_index)
{
cy_en_usb_dev_ep_state_t epState;
epState = Cy_USBFS_Dev_Drv_GetEndpointState(glUsbInitCtx->usb_devContext->drvBase, (ep_index), glUsbInitCtx->usb_drvContext);
if ((CY_USB_DEV_EP_COMPLETED == epState) || (CY_USB_DEV_EP_IDLE == epState))
{
return true;
}
return false;
}
cy_en_usb_dev_status_t Cy_App_Usb_WriteSingle(cy_app_usb_ep_index_t ep_index, uint8_t *data, uint8_t count)
{
cy_en_usb_dev_status_t status = CY_USB_DEV_SUCCESS;
uint8_t len;
/* Send status functions which are always <64B. If it is changed, multiple writes occurs.*/
len = CY_PDUTILS_GET_MIN(64, count);
status = Cy_USB_Dev_WriteEpNonBlocking(ep_index, data, len, glUsbInitCtx->usb_devContext);
if (status != CY_USB_DEV_SUCCESS)
{
status = Cy_USB_Dev_AbortEpTransfer(ep_index, glUsbInitCtx->usb_devContext);
}
return status;
}
cy_en_usb_dev_status_t Cy_App_Usb_ReadSingle(cy_app_usb_ep_index_t ep_index, uint8_t *data, uint8_t *count)
{
cy_en_usb_dev_status_t status = CY_USB_DEV_REQUEST_NOT_HANDLED;
uint32_t len, readLen;
cy_en_usb_dev_ep_state_t ep_state;
/* Read the OUT endpoint state */
ep_state = Cy_USBFS_Dev_Drv_GetEndpointState(glUsbInitCtx->usb_devContext->drvBase,
ep_index, glUsbInitCtx->usb_drvContext);
/* Check if any data from USB host is ready to be read */
if (ep_state == CY_USB_DEV_EP_COMPLETED)
{
len = Cy_USB_Dev_GetEpNumToRead(ep_index, glUsbInitCtx->usb_devContext);
status = Cy_USB_Dev_ReadEpNonBlocking(ep_index, data, len, &readLen,glUsbInitCtx->usb_devContext);
if (status != CY_USB_DEV_SUCCESS)
{
status = Cy_USB_Dev_AbortEpTransfer(ep_index,glUsbInitCtx->usb_devContext);
}
else
{
*count = readLen;
}
}
return status;
}
/**
* @brief Load status data into the interrupt endpoint.
*/
cy_en_usb_dev_status_t Cy_App_Usb_SendStatus(cy_app_usb_ep_index_t ep_index, uint8_t *data, uint8_t size)
{
bool ep_state;
cy_en_usb_dev_status_t status = CY_USB_DEV_SUCCESS;
ep_state = Cy_App_Usb_IsEpReady(ep_index);
/* This is the first state. Wait for the IN EP buffer to be free. */
if (ep_state == false)
{
return CY_USB_DEV_DRV_HW_ERROR;
}
/* Copy INT IN data to the EP buffer and send. */
status = Cy_App_Usb_WriteSingle(ep_index, (uint8_t *)data, size);
if (status != CY_USB_DEV_SUCCESS)
{
/* Flush the status endpoint to allow for retry */
status = Cy_USB_Dev_AbortEpTransfer(ep_index, glUsbInitCtx->usb_devContext);
}
return status;
}
/**
* @brief Read the USB data received into a buffer.
*/
cy_en_usb_dev_status_t Cy_App_Usb_ReceiveData(cy_app_usb_ep_index_t ep_index, uint8_t *buffer_p, uint8_t *recd_bytes)
{
cy_en_usb_dev_status_t status = CY_USB_DEV_REQUEST_NOT_HANDLED;
*recd_bytes = 0;
/* This is the first state. Wait for the USB data. */
if (Cy_App_Usb_IsEpReady(ep_index) == true)
{
/* Copies the data if it is available. */
status = Cy_App_Usb_ReadSingle(ep_index, buffer_p, recd_bytes);
}
return status;
}
/**************************************************************************
* Vendor request handling function
* ***********************************************************************/
cy_en_usb_dev_status_t Cy_App_Usb_VendorReqReceived (cy_stc_usb_dev_control_transfer_t *transfer, void *classContext, struct cy_stc_usb_dev_context *devContext)
{
cy_en_usb_dev_status_t status = CY_USB_DEV_REQUEST_NOT_HANDLED;
status = glUsbInitCtx->vendor_req_handler(transfer);
if(status == CY_USB_DEV_REQUEST_NOT_HANDLED)
{
#if CY_APP_FLASH_LOG_ENABLE
/** Application handling */
if(transfer->setup.bRequest == CY_APP_DMC_VDR_RQT_RETRIEVE_FLASH_LOG)
{
uint8_t *ptr = Cy_App_Usb_GetEp0Buffer();
cy_stc_app_flash_log_t *flash_log_ptr;
flash_log_ptr = Cy_App_Debug_FlashReadLogs();
if(flash_log_ptr != NULL)
{
memcpy(ptr, (uint8_t *)flash_log_ptr, CY_APP_DEBUG_FLASH_LOG_SIZE);
status = Cy_App_Usb_Ep0SetupWrite(ptr, CY_APP_DEBUG_FLASH_LOG_SIZE, true, NULL);
}
}
else
#endif /* CY_APP_FLASH_LOG_ENABLE */
{
/* Add handling for other vendor commands. */
status = CY_USB_DEV_SUCCESS;
}
}
(void) classContext;
(void) devContext;
return status;
}
/************************************************************************************
* Vendor request data stage handling
* This API does post processing of the control OUT data stage.
* The actual response to the data stage is taken care by the Middleware itself.
***********************************************************************************/
cy_en_usb_dev_status_t Cy_App_Usb_VendorReqCompleted (cy_stc_usb_dev_control_transfer_t *transfer, void *classContext, struct cy_stc_usb_dev_context *devContext)
{
cy_en_usb_dev_status_t status = CY_USB_DEV_REQUEST_NOT_HANDLED;
memcpy(gl_usb.ep0_buffer, transfer->ptr, gl_usb.ep0_length);
if (gl_usb.ep0_xfer_cb != NULL)
{
status = gl_usb.ep0_xfer_cb(transfer);
}
(void) classContext;
(void) devContext;
return status;
}
#endif /* CY_APP_USB_ENABLE */
/* [] End of file */