1 /*
2 * Copyright (c) 2015, Freescale Semiconductor, Inc.
3 * Copyright 2016, 2019 NXP
4 * All rights reserved.
5 *
6 * SPDX-License-Identifier: BSD-3-Clause
7 */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11
12 #include "usb_device_config.h"
13 #include "usb.h"
14 #include "usb_device.h"
15
16 #include "usb_device_class.h"
17
18 #if USB_DEVICE_CONFIG_CDC_ACM
19 #include "usb_device_cdc_acm.h"
20
21 /*******************************************************************************
22 * Definitions
23 ******************************************************************************/
24 #define USB_CDC_ACM_ENTER_CRITICAL() \
25 OSA_SR_ALLOC(); \
26 OSA_ENTER_CRITICAL()
27
28 #define USB_CDC_ACM_EXIT_CRITICAL() OSA_EXIT_CRITICAL()
29
30 /*******************************************************************************
31 * Variables
32 ******************************************************************************/
33 /* CDC ACM device instance */
34
USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE)35 USB_GLOBAL USB_RAM_ADDRESS_ALIGNMENT(USB_DATA_ALIGN_SIZE) static usb_device_cdc_acm_struct_t
36 g_cdcAcmHandle[USB_DEVICE_CONFIG_CDC_ACM];
37
38 /*******************************************************************************
39 * Code
40 ******************************************************************************/
41
42 /*!
43 * @brief Allocates the CDC ACM device handle.
44 *
45 * This function allocates the CDC ACM device handle.
46 *
47 * @param handle The class handle of the CDC ACM class.
48 * @return A USB error code or kStatus_USB_Success.
49 */
50 static usb_status_t USB_DeviceCdcAcmAllocateHandle(usb_device_cdc_acm_struct_t **handle)
51 {
52 uint32_t count;
53 for (count = 0U; count < (uint32_t)USB_DEVICE_CONFIG_CDC_ACM; count++)
54 {
55 if (NULL == g_cdcAcmHandle[count].handle)
56 {
57 *handle = &g_cdcAcmHandle[count];
58 return kStatus_USB_Success;
59 }
60 }
61
62 return kStatus_USB_Busy;
63 }
64
65 /*!
66 * @brief Frees the CDC ACM device handle.
67 *
68 * This function frees the CDC ACM device handle.
69 *
70 * @param handle The class handle of the CDC ACM class.
71 * @return A USB error code or kStatus_USB_Success.
72 */
USB_DeviceCdcAcmFreeHandle(usb_device_cdc_acm_struct_t * handle)73 static usb_status_t USB_DeviceCdcAcmFreeHandle(usb_device_cdc_acm_struct_t *handle)
74 {
75 handle->handle = NULL;
76 handle->configStruct = NULL;
77 handle->configuration = 0U;
78 handle->alternate = 0U;
79 return kStatus_USB_Success;
80 }
81
82 /*!
83 * @brief Responds to the interrupt in endpoint event.
84 *
85 * This function responds to the interrupt in endpoint event.
86 *
87 * @param handle The device handle of the CDC ACM device.
88 * @param message The pointer to the message of the endpoint callback.
89 * @param callbackParam The pointer to the parameter of the callback.
90 * @return A USB error code or kStatus_USB_Success.
91 */
USB_DeviceCdcAcmInterruptIn(usb_device_handle handle,usb_device_endpoint_callback_message_struct_t * message,void * callbackParam)92 static usb_status_t USB_DeviceCdcAcmInterruptIn(usb_device_handle handle,
93 usb_device_endpoint_callback_message_struct_t *message,
94 void *callbackParam)
95 {
96 usb_device_cdc_acm_struct_t *cdcAcmHandle;
97 usb_status_t error = kStatus_USB_Error;
98 cdcAcmHandle = (usb_device_cdc_acm_struct_t *)callbackParam;
99 if (NULL == cdcAcmHandle)
100 {
101 return kStatus_USB_InvalidHandle;
102 }
103
104 cdcAcmHandle->interruptIn.isBusy = 0U;
105
106 if ((NULL != cdcAcmHandle->configStruct) && (NULL != cdcAcmHandle->configStruct->classCallback))
107 {
108 /*classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
109 it is from the second parameter of classInit */
110 error = cdcAcmHandle->configStruct->classCallback((class_handle_t)cdcAcmHandle,
111 kUSB_DeviceCdcEventSerialStateNotif, message);
112 }
113 return error;
114 }
115
116 /*!
117 * @brief Responds to the bulk in endpoint event.
118 *
119 * This function responds to the bulk in endpoint event.
120 *
121 * @param handle The device handle of the CDC ACM device.
122 * @param message The pointer to the message of the endpoint callback.
123 * @param callbackParam The pointer to the parameter of the callback.
124 * @return A USB error code or kStatus_USB_Success.
125 */
USB_DeviceCdcAcmBulkIn(usb_device_handle handle,usb_device_endpoint_callback_message_struct_t * message,void * callbackParam)126 static usb_status_t USB_DeviceCdcAcmBulkIn(usb_device_handle handle,
127 usb_device_endpoint_callback_message_struct_t *message,
128 void *callbackParam)
129 {
130 usb_device_cdc_acm_struct_t *cdcAcmHandle;
131 usb_status_t status = kStatus_USB_Error;
132 cdcAcmHandle = (usb_device_cdc_acm_struct_t *)callbackParam;
133
134 if (NULL == cdcAcmHandle)
135 {
136 return kStatus_USB_InvalidHandle;
137 }
138
139 cdcAcmHandle->bulkIn.isBusy = 0U;
140
141 if ((NULL != cdcAcmHandle->configStruct) && (NULL != cdcAcmHandle->configStruct->classCallback))
142 {
143 /*classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
144 it is from the second parameter of classInit */
145 status = cdcAcmHandle->configStruct->classCallback((class_handle_t)cdcAcmHandle,
146 kUSB_DeviceCdcEventSendResponse, message);
147 }
148 return status;
149 }
150
151 /*!
152 * @brief Responds to the bulk out endpoint event.
153 *
154 * This function responds to the bulk out endpoint event.
155 *
156 * @param handle The device handle of the CDC ACM device.
157 * @param message The pointer to the message of the endpoint callback.
158 * @param callbackParam The pointer to the parameter of the callback.
159 * @return A USB error code or kStatus_USB_Success.
160 */
USB_DeviceCdcAcmBulkOut(usb_device_handle handle,usb_device_endpoint_callback_message_struct_t * message,void * callbackParam)161 static usb_status_t USB_DeviceCdcAcmBulkOut(usb_device_handle handle,
162 usb_device_endpoint_callback_message_struct_t *message,
163 void *callbackParam)
164 {
165 usb_device_cdc_acm_struct_t *cdcAcmHandle;
166 usb_status_t status = kStatus_USB_Error;
167 cdcAcmHandle = (usb_device_cdc_acm_struct_t *)callbackParam;
168
169 if (NULL == cdcAcmHandle)
170 {
171 return kStatus_USB_InvalidHandle;
172 }
173
174 cdcAcmHandle->bulkOut.isBusy = 0U;
175
176 if ((NULL != cdcAcmHandle->configStruct) && (NULL != cdcAcmHandle->configStruct->classCallback))
177 {
178 /*classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
179 it is from the second parameter of classInit */
180 status = cdcAcmHandle->configStruct->classCallback((class_handle_t)cdcAcmHandle,
181 kUSB_DeviceCdcEventRecvResponse, message);
182 }
183 return status;
184 }
185
186 /*!
187 * @brief Initializes the endpoints in CDC ACM class.
188 *
189 * This function initializes the endpoints in CDC ACM class.
190 *
191 * @param cdcAcmHandle The class handle of the CDC ACM class.
192 * @return A USB error code or kStatus_USB_Success.
193 */
USB_DeviceCdcAcmEndpointsInit(usb_device_cdc_acm_struct_t * cdcAcmHandle)194 static usb_status_t USB_DeviceCdcAcmEndpointsInit(usb_device_cdc_acm_struct_t *cdcAcmHandle)
195 {
196 usb_device_interface_list_t *interfaceList;
197 usb_device_interface_struct_t *interface = NULL;
198 usb_device_endpoint_callback_struct_t epCallback;
199 usb_status_t error = kStatus_USB_Error;
200 uint32_t count;
201 uint32_t index;
202
203 if (NULL == cdcAcmHandle)
204 {
205 return error;
206 }
207 epCallback.callbackFn = (usb_device_endpoint_callback_t)NULL;
208 /* return error when configuration is invalid (0 or more than the configuration number) */
209 if ((cdcAcmHandle->configuration == 0U) ||
210 (cdcAcmHandle->configuration > cdcAcmHandle->configStruct->classInfomation->configurations))
211 {
212 return error;
213 }
214
215 interfaceList = &cdcAcmHandle->configStruct->classInfomation->interfaceList[cdcAcmHandle->configuration - 1U];
216
217 for (count = 0U; count < interfaceList->count; count++)
218 {
219 if (USB_DEVICE_CONFIG_CDC_COMM_CLASS_CODE == interfaceList->interfaces[count].classCode)
220 {
221 for (index = 0U; index < interfaceList->interfaces[count].count; index++)
222 {
223 if (interfaceList->interfaces[count].interface[index].alternateSetting == cdcAcmHandle->alternate)
224 {
225 interface = &interfaceList->interfaces[count].interface[index];
226 break;
227 }
228 }
229 cdcAcmHandle->interfaceNumber = interfaceList->interfaces[count].interfaceNumber;
230 break;
231 }
232 }
233 if (NULL == interface)
234 {
235 return error;
236 }
237 cdcAcmHandle->commInterfaceHandle = interface;
238 for (count = 0U; count < interface->endpointList.count; count++)
239 {
240 usb_device_endpoint_init_struct_t epInitStruct;
241 epInitStruct.zlt = 0U;
242 epInitStruct.interval = interface->endpointList.endpoint[count].interval;
243 epInitStruct.endpointAddress = interface->endpointList.endpoint[count].endpointAddress;
244 epInitStruct.maxPacketSize = interface->endpointList.endpoint[count].maxPacketSize;
245 epInitStruct.transferType = interface->endpointList.endpoint[count].transferType;
246
247 if ((USB_IN == ((epInitStruct.endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >>
248 USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)) &&
249 (USB_ENDPOINT_INTERRUPT == epInitStruct.transferType))
250 {
251 cdcAcmHandle->interruptIn.ep = (epInitStruct.endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK);
252 cdcAcmHandle->interruptIn.isBusy = 0U;
253 cdcAcmHandle->interruptIn.pipeDataBuffer = (uint8_t *)USB_INVALID_TRANSFER_BUFFER;
254 cdcAcmHandle->interruptIn.pipeStall = 0U;
255 cdcAcmHandle->interruptIn.pipeDataLen = 0U;
256 epCallback.callbackFn = USB_DeviceCdcAcmInterruptIn;
257 }
258
259 epCallback.callbackParam = cdcAcmHandle;
260
261 error = USB_DeviceInitEndpoint(cdcAcmHandle->handle, &epInitStruct, &epCallback);
262 if (kStatus_USB_Success != error)
263 {
264 return error;
265 }
266 }
267
268 for (count = 0U; count < interfaceList->count; count++)
269 {
270 if (USB_DEVICE_CONFIG_CDC_DATA_CLASS_CODE == interfaceList->interfaces[count].classCode)
271 {
272 for (index = 0U; index < interfaceList->interfaces[count].count; index++)
273 {
274 if (interfaceList->interfaces[count].interface[index].alternateSetting == cdcAcmHandle->alternate)
275 {
276 interface = &interfaceList->interfaces[count].interface[index];
277 break;
278 }
279 }
280 break;
281 }
282 }
283
284 cdcAcmHandle->dataInterfaceHandle = interface;
285
286 for (count = 0U; count < interface->endpointList.count; count++)
287 {
288 usb_device_endpoint_init_struct_t epInitStruct;
289 epInitStruct.zlt = 0U;
290 epInitStruct.interval = interface->endpointList.endpoint[count].interval;
291 epInitStruct.endpointAddress = interface->endpointList.endpoint[count].endpointAddress;
292 epInitStruct.maxPacketSize = interface->endpointList.endpoint[count].maxPacketSize;
293 epInitStruct.transferType = interface->endpointList.endpoint[count].transferType;
294
295 if ((USB_IN == ((epInitStruct.endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >>
296 USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)) &&
297 (USB_ENDPOINT_BULK == epInitStruct.transferType))
298 {
299 cdcAcmHandle->bulkIn.ep = (epInitStruct.endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK);
300 cdcAcmHandle->bulkIn.isBusy = 0U;
301 cdcAcmHandle->bulkIn.pipeDataBuffer = (uint8_t *)USB_INVALID_TRANSFER_BUFFER;
302 cdcAcmHandle->bulkIn.pipeStall = 0U;
303 cdcAcmHandle->bulkIn.pipeDataLen = 0U;
304 epCallback.callbackFn = USB_DeviceCdcAcmBulkIn;
305 }
306 else if ((USB_OUT == ((epInitStruct.endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >>
307 USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT)) &&
308 (USB_ENDPOINT_BULK == epInitStruct.transferType))
309 {
310 cdcAcmHandle->bulkOut.ep = (epInitStruct.endpointAddress & USB_DESCRIPTOR_ENDPOINT_ADDRESS_NUMBER_MASK);
311 cdcAcmHandle->bulkOut.isBusy = 0U;
312 cdcAcmHandle->bulkOut.pipeDataBuffer = (uint8_t *)USB_INVALID_TRANSFER_BUFFER;
313 cdcAcmHandle->bulkOut.pipeStall = 0U;
314 cdcAcmHandle->bulkOut.pipeDataLen = 0U;
315 epCallback.callbackFn = USB_DeviceCdcAcmBulkOut;
316 }
317 else
318 {
319 /*no action*/
320 }
321 epCallback.callbackParam = cdcAcmHandle;
322
323 error = USB_DeviceInitEndpoint(cdcAcmHandle->handle, &epInitStruct, &epCallback);
324 }
325 return error;
326 }
327
328 /*!
329 * @brief De-initializes the endpoints in CDC ACM class.
330 *
331 * This function de-initializes the endpoints in CDC ACM class.
332 *
333 * @param cdcAcmHandle The class handle of the CDC ACM class.
334 * @return A USB error code or kStatus_USB_Success.
335 */
USB_DeviceCdcAcmEndpointsDeinit(usb_device_cdc_acm_struct_t * cdcAcmHandle)336 static usb_status_t USB_DeviceCdcAcmEndpointsDeinit(usb_device_cdc_acm_struct_t *cdcAcmHandle)
337 {
338 usb_status_t status = kStatus_USB_Error;
339 uint32_t count;
340
341 if ((NULL == cdcAcmHandle->commInterfaceHandle) || (NULL == cdcAcmHandle->dataInterfaceHandle))
342 {
343 return status;
344 }
345 for (count = 0U; count < cdcAcmHandle->commInterfaceHandle->endpointList.count; count++)
346 {
347 status = USB_DeviceDeinitEndpoint(
348 cdcAcmHandle->handle, cdcAcmHandle->commInterfaceHandle->endpointList.endpoint[count].endpointAddress);
349 }
350 for (count = 0U; count < cdcAcmHandle->dataInterfaceHandle->endpointList.count; count++)
351 {
352 status = USB_DeviceDeinitEndpoint(
353 cdcAcmHandle->handle, cdcAcmHandle->dataInterfaceHandle->endpointList.endpoint[count].endpointAddress);
354 }
355 cdcAcmHandle->commInterfaceHandle = NULL;
356 cdcAcmHandle->dataInterfaceHandle = NULL;
357
358 return status;
359 }
360
361 /*!
362 * @brief Handles the CDC ACM class event.
363 *
364 * This function responses to various events including the common device events and the class specific events.
365 * For class specific events, it calls the class callback defined in the application to deal with the class specific
366 * event.
367 *
368 * @param handle The class handle of the CDC ACM class.
369 * @param event The event type.
370 * @param param The class handle of the CDC ACM class.
371 * @return A USB error code or kStatus_USB_Success.
372 */
USB_DeviceCdcAcmEvent(void * handle,uint32_t event,void * param)373 usb_status_t USB_DeviceCdcAcmEvent(void *handle, uint32_t event, void *param)
374 {
375 usb_device_cdc_acm_struct_t *cdcAcmHandle;
376 usb_device_cdc_acm_request_param_struct_t reqParam;
377 usb_status_t error = kStatus_USB_Error;
378 uint32_t count;
379 uint16_t interfaceAlternate;
380 uint8_t *temp8;
381 uint8_t alternate;
382 usb_device_class_event_t eventCode = (usb_device_class_event_t)event;
383 if ((NULL == param) || (NULL == handle))
384 {
385 return kStatus_USB_InvalidHandle;
386 }
387
388 cdcAcmHandle = (usb_device_cdc_acm_struct_t *)handle;
389
390 switch (eventCode)
391 {
392 case kUSB_DeviceClassEventDeviceReset:
393 /* Bus reset, clear the configuration. */
394 cdcAcmHandle->configuration = 0;
395 error = kStatus_USB_Success;
396 break;
397 case kUSB_DeviceClassEventSetConfiguration:
398 temp8 = ((uint8_t *)param);
399 if (NULL == cdcAcmHandle->configStruct)
400 {
401 break;
402 }
403 if (*temp8 == cdcAcmHandle->configuration)
404 {
405 error = kStatus_USB_Success;
406 break;
407 }
408
409 error = USB_DeviceCdcAcmEndpointsDeinit(cdcAcmHandle);
410 cdcAcmHandle->configuration = *temp8;
411 cdcAcmHandle->alternate = 0U;
412 error = USB_DeviceCdcAcmEndpointsInit(cdcAcmHandle);
413 if (kStatus_USB_Success != error)
414 {
415 #if 0
416 (void)usb_echo("kUSB_DeviceClassEventSetConfiguration, USB_DeviceInitEndpoint fail\r\n");
417 #endif
418 }
419 break;
420 case kUSB_DeviceClassEventSetInterface:
421 if (NULL == cdcAcmHandle->configStruct)
422 {
423 break;
424 }
425
426 interfaceAlternate = *((uint16_t *)param);
427 alternate = (uint8_t)(interfaceAlternate & 0xFFU);
428
429 if (cdcAcmHandle->interfaceNumber != ((uint8_t)(interfaceAlternate >> 8U)))
430 {
431 break;
432 }
433 if (alternate == cdcAcmHandle->alternate)
434 {
435 error = kStatus_USB_Success;
436 break;
437 }
438 error = USB_DeviceCdcAcmEndpointsDeinit(cdcAcmHandle);
439 cdcAcmHandle->alternate = alternate;
440 error = USB_DeviceCdcAcmEndpointsInit(cdcAcmHandle);
441 if (kStatus_USB_Success != error)
442 {
443 #if 0
444 (void)usb_echo("kUSB_DeviceClassEventSetInterface, USB_DeviceInitEndpoint fail\r\n");
445 #endif
446 }
447 break;
448 case kUSB_DeviceClassEventSetEndpointHalt:
449 if ((NULL == cdcAcmHandle->configStruct) || (NULL == cdcAcmHandle->commInterfaceHandle) ||
450 (NULL == cdcAcmHandle->dataInterfaceHandle))
451 {
452 break;
453 }
454 temp8 = ((uint8_t *)param);
455 for (count = 0U; count < cdcAcmHandle->commInterfaceHandle->endpointList.count; count++)
456 {
457 if (*temp8 == cdcAcmHandle->commInterfaceHandle->endpointList.endpoint[count].endpointAddress)
458 {
459 cdcAcmHandle->interruptIn.pipeStall = 1U;
460 error = USB_DeviceStallEndpoint(cdcAcmHandle->handle, *temp8);
461 }
462 }
463 for (count = 0U; count < cdcAcmHandle->dataInterfaceHandle->endpointList.count; count++)
464 {
465 if (*temp8 == cdcAcmHandle->dataInterfaceHandle->endpointList.endpoint[count].endpointAddress)
466 {
467 if (USB_IN == (((*temp8) & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >>
468 USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT))
469 {
470 cdcAcmHandle->bulkIn.pipeStall = 1U;
471 }
472 else
473 {
474 cdcAcmHandle->bulkOut.pipeStall = 1U;
475 }
476 error = USB_DeviceStallEndpoint(cdcAcmHandle->handle, *temp8);
477 }
478 }
479 break;
480 case kUSB_DeviceClassEventClearEndpointHalt:
481 if ((NULL == cdcAcmHandle->configStruct) || (NULL == cdcAcmHandle->commInterfaceHandle) ||
482 (NULL == cdcAcmHandle->dataInterfaceHandle))
483 {
484 break;
485 }
486 temp8 = ((uint8_t *)param);
487 for (count = 0U; count < cdcAcmHandle->commInterfaceHandle->endpointList.count; count++)
488 {
489 if (*temp8 == cdcAcmHandle->commInterfaceHandle->endpointList.endpoint[count].endpointAddress)
490 {
491 error = USB_DeviceUnstallEndpoint(cdcAcmHandle->handle, *temp8);
492 if (USB_IN == (((*temp8) & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >>
493 USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT))
494 {
495 if (0U != cdcAcmHandle->interruptIn.pipeStall)
496 {
497 cdcAcmHandle->interruptIn.pipeStall = 0U;
498 if ((uint8_t *)USB_INVALID_TRANSFER_BUFFER != cdcAcmHandle->interruptIn.pipeDataBuffer)
499 {
500 error = USB_DeviceSendRequest(cdcAcmHandle->handle, (cdcAcmHandle->interruptIn.ep),
501 cdcAcmHandle->interruptIn.pipeDataBuffer,
502 cdcAcmHandle->interruptIn.pipeDataLen);
503 if (kStatus_USB_Success != error)
504 {
505 usb_device_endpoint_callback_message_struct_t endpointCallbackMessage;
506 endpointCallbackMessage.buffer = cdcAcmHandle->interruptIn.pipeDataBuffer;
507 endpointCallbackMessage.length = cdcAcmHandle->interruptIn.pipeDataLen;
508 endpointCallbackMessage.isSetup = 0U;
509 #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
510 if (kStatus_USB_Success != USB_DeviceCdcAcmBulkIn(cdcAcmHandle->handle,
511 (void *)&endpointCallbackMessage,
512 handle))
513 {
514 return kStatus_USB_Error;
515 }
516 #else
517 (void)USB_DeviceCdcAcmBulkIn(cdcAcmHandle->handle, (void *)&endpointCallbackMessage,
518 handle);
519 #endif
520 }
521 cdcAcmHandle->interruptIn.pipeDataBuffer = (uint8_t *)USB_INVALID_TRANSFER_BUFFER;
522 cdcAcmHandle->interruptIn.pipeDataLen = 0U;
523 }
524 }
525 }
526 }
527 }
528 for (count = 0U; count < cdcAcmHandle->dataInterfaceHandle->endpointList.count; count++)
529 {
530 if (*temp8 == cdcAcmHandle->dataInterfaceHandle->endpointList.endpoint[count].endpointAddress)
531 {
532 error = USB_DeviceUnstallEndpoint(cdcAcmHandle->handle, *temp8);
533 if (USB_IN == (((*temp8) & USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_MASK) >>
534 USB_DESCRIPTOR_ENDPOINT_ADDRESS_DIRECTION_SHIFT))
535 {
536 if (0U != cdcAcmHandle->bulkIn.pipeStall)
537 {
538 cdcAcmHandle->bulkIn.pipeStall = 0U;
539 if ((uint8_t *)USB_INVALID_TRANSFER_BUFFER != cdcAcmHandle->bulkIn.pipeDataBuffer)
540 {
541 error = USB_DeviceSendRequest(cdcAcmHandle->handle, (cdcAcmHandle->bulkIn.ep),
542 cdcAcmHandle->bulkIn.pipeDataBuffer,
543 cdcAcmHandle->bulkIn.pipeDataLen);
544 if (kStatus_USB_Success != error)
545 {
546 usb_device_endpoint_callback_message_struct_t endpointCallbackMessage;
547 endpointCallbackMessage.buffer = cdcAcmHandle->bulkIn.pipeDataBuffer;
548 endpointCallbackMessage.length = cdcAcmHandle->bulkIn.pipeDataLen;
549 endpointCallbackMessage.isSetup = 0U;
550 #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
551 if (kStatus_USB_Success != USB_DeviceCdcAcmBulkIn(cdcAcmHandle->handle,
552 (void *)&endpointCallbackMessage,
553 handle))
554 {
555 return kStatus_USB_Error;
556 }
557 #else
558 (void)USB_DeviceCdcAcmBulkIn(cdcAcmHandle->handle, (void *)&endpointCallbackMessage,
559 handle);
560 #endif
561 }
562 cdcAcmHandle->bulkIn.pipeDataBuffer = (uint8_t *)USB_INVALID_TRANSFER_BUFFER;
563 cdcAcmHandle->bulkIn.pipeDataLen = 0U;
564 }
565 }
566 }
567 else
568 {
569 if (0U != cdcAcmHandle->bulkOut.pipeStall)
570 {
571 cdcAcmHandle->bulkOut.pipeStall = 0U;
572 if ((uint8_t *)USB_INVALID_TRANSFER_BUFFER != cdcAcmHandle->bulkOut.pipeDataBuffer)
573 {
574 error = USB_DeviceRecvRequest(cdcAcmHandle->handle, (cdcAcmHandle->bulkOut.ep),
575 cdcAcmHandle->bulkOut.pipeDataBuffer,
576 cdcAcmHandle->bulkOut.pipeDataLen);
577 if (kStatus_USB_Success != error)
578 {
579 usb_device_endpoint_callback_message_struct_t endpointCallbackMessage;
580 endpointCallbackMessage.buffer = cdcAcmHandle->bulkOut.pipeDataBuffer;
581 endpointCallbackMessage.length = cdcAcmHandle->bulkOut.pipeDataLen;
582 endpointCallbackMessage.isSetup = 0U;
583 #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
584 if (kStatus_USB_Success != USB_DeviceCdcAcmBulkOut(cdcAcmHandle->handle,
585 (void *)&endpointCallbackMessage,
586 handle))
587 {
588 return kStatus_USB_Error;
589 }
590 #else
591 (void)USB_DeviceCdcAcmBulkOut(cdcAcmHandle->handle,
592 (void *)&endpointCallbackMessage, handle);
593 #endif
594 }
595 cdcAcmHandle->bulkOut.pipeDataBuffer = (uint8_t *)USB_INVALID_TRANSFER_BUFFER;
596 cdcAcmHandle->bulkOut.pipeDataLen = 0U;
597 }
598 }
599 }
600 }
601 }
602 break;
603 case kUSB_DeviceClassEventClassRequest:
604
605 {
606 usb_device_control_request_struct_t *controlRequest = (usb_device_control_request_struct_t *)param;
607
608 if ((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_RECIPIENT_MASK) !=
609 USB_REQUEST_TYPE_RECIPIENT_INTERFACE)
610 {
611 break;
612 }
613
614 if ((controlRequest->setup->wIndex & 0xFFU) != cdcAcmHandle->interfaceNumber)
615 {
616 break;
617 }
618
619 error = kStatus_USB_InvalidRequest;
620 /* Standard CDC request */
621 reqParam.buffer = &(controlRequest->buffer);
622 reqParam.length = &(controlRequest->length);
623 reqParam.interfaceIndex = controlRequest->setup->wIndex;
624 reqParam.setupValue = controlRequest->setup->wValue;
625 reqParam.isSetup = controlRequest->isSetup;
626 switch (controlRequest->setup->bRequest)
627 {
628 case USB_DEVICE_CDC_REQUEST_SEND_ENCAPSULATED_COMMAND:
629 if (((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) ==
630 USB_REQUEST_TYPE_DIR_OUT) &&
631 (controlRequest->setup->wLength != 0U))
632 {
633 /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
634 it is from the second parameter of classInit */
635 error = cdcAcmHandle->configStruct->classCallback(
636 (class_handle_t)cdcAcmHandle, kUSB_DeviceCdcEventSendEncapsulatedCommand, &reqParam);
637 }
638 break;
639 case USB_DEVICE_CDC_REQUEST_GET_ENCAPSULATED_RESPONSE:
640 if (((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) ==
641 USB_REQUEST_TYPE_DIR_IN) &&
642 (controlRequest->setup->wLength != 0U))
643 {
644 /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
645 it is from the second parameter of classInit */
646 error = cdcAcmHandle->configStruct->classCallback(
647 (class_handle_t)cdcAcmHandle, kUSB_DeviceCdcEventGetEncapsulatedResponse, &reqParam);
648 }
649 break;
650 case USB_DEVICE_CDC_REQUEST_SET_COMM_FEATURE:
651 if (((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) ==
652 USB_REQUEST_TYPE_DIR_OUT) &&
653 (controlRequest->setup->wLength != 0U))
654 {
655 /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
656 it is from the second parameter of classInit */
657 error = cdcAcmHandle->configStruct->classCallback((class_handle_t)cdcAcmHandle,
658 kUSB_DeviceCdcEventSetCommFeature, &reqParam);
659 }
660 break;
661 case USB_DEVICE_CDC_REQUEST_GET_COMM_FEATURE:
662 if (((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) ==
663 USB_REQUEST_TYPE_DIR_IN) &&
664 (controlRequest->setup->wLength != 0U))
665 {
666 /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
667 it is from the second parameter of classInit */
668 error = cdcAcmHandle->configStruct->classCallback((class_handle_t)cdcAcmHandle,
669 kUSB_DeviceCdcEventGetCommFeature, &reqParam);
670 }
671 break;
672 case USB_DEVICE_CDC_REQUEST_CLEAR_COMM_FEATURE:
673 if (((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) ==
674 USB_REQUEST_TYPE_DIR_OUT) &&
675 (controlRequest->setup->wLength == 0U))
676 {
677 /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
678 it is from the second parameter of classInit */
679 error = cdcAcmHandle->configStruct->classCallback(
680 (class_handle_t)cdcAcmHandle, kUSB_DeviceCdcEventClearCommFeature, &reqParam);
681 }
682 break;
683 case USB_DEVICE_CDC_REQUEST_GET_LINE_CODING:
684 if (((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) ==
685 USB_REQUEST_TYPE_DIR_IN) &&
686 (controlRequest->setup->wLength != 0U))
687 {
688 /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
689 it is from the second parameter of classInit */
690 error = cdcAcmHandle->configStruct->classCallback((class_handle_t)cdcAcmHandle,
691 kUSB_DeviceCdcEventGetLineCoding, &reqParam);
692 }
693 break;
694 case USB_DEVICE_CDC_REQUEST_SET_LINE_CODING:
695 if (((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) ==
696 USB_REQUEST_TYPE_DIR_OUT) &&
697 (controlRequest->setup->wLength != 0U))
698 {
699 /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
700 it is from the second parameter of classInit */
701 error = cdcAcmHandle->configStruct->classCallback((class_handle_t)cdcAcmHandle,
702 kUSB_DeviceCdcEventSetLineCoding, &reqParam);
703 }
704 break;
705 case USB_DEVICE_CDC_REQUEST_SET_CONTROL_LINE_STATE:
706 if (((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) ==
707 USB_REQUEST_TYPE_DIR_OUT) &&
708 (controlRequest->setup->wLength == 0U))
709 {
710 /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
711 it is from the second parameter of classInit */
712 error = cdcAcmHandle->configStruct->classCallback(
713 (class_handle_t)cdcAcmHandle, kUSB_DeviceCdcEventSetControlLineState, &reqParam);
714 }
715 break;
716 case USB_DEVICE_CDC_REQUEST_SEND_BREAK:
717 if (((controlRequest->setup->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) ==
718 USB_REQUEST_TYPE_DIR_OUT) &&
719 (controlRequest->setup->wLength == 0U))
720 {
721 /* classCallback is initialized in classInit of s_UsbDeviceClassInterfaceMap,
722 it is from the second parameter of classInit */
723 error = cdcAcmHandle->configStruct->classCallback((class_handle_t)cdcAcmHandle,
724 kUSB_DeviceCdcEventSendBreak, &reqParam);
725 }
726 break;
727 default:
728 /* no action, return kStatus_USB_InvalidRequest */
729 break;
730 }
731 }
732 break;
733 default:
734 /*no action*/
735 break;
736 }
737 return error;
738 }
739
740 /*!
741 * @brief Initializes the USB CDC ACM class.
742 *
743 * This function obtains a usb device handle according to the controller id, initializes the CDC ACM class
744 * with the class configure parameters and creates the mutex for each pipe.
745 *
746 * @param controllerId The id of the controller. The value can be choosen from kUSB_ControllerKhci0,
747 * kUSB_ControllerKhci1, kUSB_ControllerEhci0 or kUSB_ControllerEhci1.
748 * @param config The user configuration structure of type usb_device_class_config_struct_t. The user
749 * populates the members of this structure and passes the pointer of this structure
750 * into this function.
751 * @param handle It is out parameter. The class handle of the CDC ACM class.
752 * @return A USB error code or kStatus_USB_Success.
753 */
USB_DeviceCdcAcmInit(uint8_t controllerId,usb_device_class_config_struct_t * config,class_handle_t * handle)754 usb_status_t USB_DeviceCdcAcmInit(uint8_t controllerId,
755 usb_device_class_config_struct_t *config,
756 class_handle_t *handle)
757 {
758 usb_device_cdc_acm_struct_t *cdcAcmHandle;
759 usb_status_t error;
760
761 error = USB_DeviceCdcAcmAllocateHandle(&cdcAcmHandle);
762
763 if (kStatus_USB_Success != error)
764 {
765 return error;
766 }
767
768 error = USB_DeviceClassGetDeviceHandle(controllerId, &cdcAcmHandle->handle);
769
770 if (kStatus_USB_Success != error)
771 {
772 return error;
773 }
774
775 if (NULL == cdcAcmHandle->handle)
776 {
777 return kStatus_USB_InvalidHandle;
778 }
779 cdcAcmHandle->configStruct = config;
780 cdcAcmHandle->configuration = 0U;
781 cdcAcmHandle->alternate = 0xFF;
782
783 cdcAcmHandle->bulkIn.mutex = (osa_mutex_handle_t)&cdcAcmHandle->bulkIn.mutexBuffer[0];
784 if (KOSA_StatusSuccess != OSA_MutexCreate((cdcAcmHandle->bulkIn.mutex)))
785 {
786 #if 0
787 (void)usb_echo("mutex create error!");
788 #endif
789 }
790 cdcAcmHandle->bulkOut.mutex = (osa_mutex_handle_t)&cdcAcmHandle->bulkOut.mutexBuffer[0];
791 if (KOSA_StatusSuccess != OSA_MutexCreate((cdcAcmHandle->bulkOut.mutex)))
792 {
793 #if 0
794 (void)usb_echo("mutex create error!");
795 #endif
796 }
797 cdcAcmHandle->interruptIn.mutex = (osa_mutex_handle_t)&cdcAcmHandle->interruptIn.mutexBuffer[0];
798 if (KOSA_StatusSuccess != OSA_MutexCreate((cdcAcmHandle->interruptIn.mutex)))
799 {
800 #if 0
801 (void)usb_echo("mutex create error!");
802 #endif
803 }
804 *handle = (class_handle_t)cdcAcmHandle;
805 return error;
806 }
807
808 /*!
809 * @brief De-Initializes the USB CDC ACM class.
810 *
811 * This function destroys the mutex for each pipe, deinit each endpoint of the CDC ACM class and free
812 * the CDC ACM class handle.
813 *
814 * @param handle The class handle of the CDC ACM class.
815 * @return A USB error code or kStatus_USB_Success.
816 */
USB_DeviceCdcAcmDeinit(class_handle_t handle)817 usb_status_t USB_DeviceCdcAcmDeinit(class_handle_t handle)
818 {
819 usb_device_cdc_acm_struct_t *cdcAcmHandle;
820 usb_status_t error;
821
822 cdcAcmHandle = (usb_device_cdc_acm_struct_t *)handle;
823
824 if (NULL == cdcAcmHandle)
825 {
826 return kStatus_USB_InvalidHandle;
827 }
828 if (KOSA_StatusSuccess != OSA_MutexDestroy((cdcAcmHandle->bulkIn.mutex)))
829 {
830 #if 0
831 (void)usb_echo("mutex destroy error!");
832 #endif
833 }
834 if (KOSA_StatusSuccess != OSA_MutexDestroy((cdcAcmHandle->bulkOut.mutex)))
835 {
836 #if 0
837 (void)usb_echo("mutex destroy error!");
838 #endif
839 }
840 if (KOSA_StatusSuccess != OSA_MutexDestroy((cdcAcmHandle->interruptIn.mutex)))
841 {
842 #if 0
843 (void)usb_echo("mutex destroy error!");
844 #endif
845 }
846 error = USB_DeviceCdcAcmEndpointsDeinit(cdcAcmHandle);
847 #if (defined(USB_DEVICE_CONFIG_RETURN_VALUE_CHECK) && (USB_DEVICE_CONFIG_RETURN_VALUE_CHECK > 0U))
848 if (kStatus_USB_Success != USB_DeviceCdcAcmFreeHandle(cdcAcmHandle))
849 {
850 return kStatus_USB_Error;
851 }
852 #else
853 (void)USB_DeviceCdcAcmFreeHandle(cdcAcmHandle);
854 #endif
855 return error;
856 }
857
858 /*!
859 * @brief Prime the endpoint to send packet to host.
860 *
861 * This function checks whether the endpoint is sending packet, then it primes the endpoint
862 * with the buffer address and the buffer length if the pipe is not busy. Otherwise, it ignores this transfer by
863 * returning an error code.
864 *
865 * @param handle The class handle of the CDC ACM class.
866 * @param ep The endpoint number of the transfer.
867 * @param buffer The pointer to the buffer to be transferred.
868 * @param length The length of the buffer to be transferred.
869 * @return A USB error code or kStatus_USB_Success.
870 */
USB_DeviceCdcAcmSend(class_handle_t handle,uint8_t ep,uint8_t * buffer,uint32_t length)871 usb_status_t USB_DeviceCdcAcmSend(class_handle_t handle, uint8_t ep, uint8_t *buffer, uint32_t length)
872 {
873 usb_device_cdc_acm_struct_t *cdcAcmHandle;
874 usb_status_t status = kStatus_USB_Error;
875 usb_device_cdc_acm_pipe_t *cdcAcmPipe = NULL;
876
877 if (NULL == handle)
878 {
879 return kStatus_USB_InvalidHandle;
880 }
881 cdcAcmHandle = (usb_device_cdc_acm_struct_t *)handle;
882
883 if (cdcAcmHandle->bulkIn.ep == ep)
884 {
885 cdcAcmPipe = &(cdcAcmHandle->bulkIn);
886 }
887 else if (cdcAcmHandle->interruptIn.ep == ep)
888 {
889 cdcAcmPipe = &(cdcAcmHandle->interruptIn);
890 }
891 else
892 {
893 /*no action*/
894 }
895
896 if (NULL != cdcAcmPipe)
897 {
898 if (1U == cdcAcmPipe->isBusy)
899 {
900 return kStatus_USB_Busy;
901 }
902 cdcAcmPipe->isBusy = 1U;
903
904 if (0u != cdcAcmPipe->pipeStall)
905 {
906 cdcAcmPipe->pipeDataBuffer = buffer;
907 cdcAcmPipe->pipeDataLen = length;
908 return kStatus_USB_Success;
909 }
910
911 status = USB_DeviceSendRequest(cdcAcmHandle->handle, ep, buffer, length);
912 if (kStatus_USB_Success != status)
913 {
914 cdcAcmPipe->isBusy = 0U;
915 }
916 }
917 return status;
918 }
919
920 /*!
921 * @brief Prime the endpoint to receive packet from host.
922 *
923 * This function checks whether the endpoint is receiving packet, then it primes the endpoint
924 * with the buffer address and the buffer length if the pipe is not busy. Otherwise, it ignores this transfer by
925 * returning an error code.
926 *
927 * @param handle The class handle of the CDC ACM class.
928 * @param ep The endpoint number of the transfer.
929 * @param buffer The pointer to the buffer to be transferred.
930 * @param length The length of the buffer to be transferred.
931 * @return A USB error code or kStatus_USB_Success.
932 */
USB_DeviceCdcAcmRecv(class_handle_t handle,uint8_t ep,uint8_t * buffer,uint32_t length)933 usb_status_t USB_DeviceCdcAcmRecv(class_handle_t handle, uint8_t ep, uint8_t *buffer, uint32_t length)
934 {
935 usb_device_cdc_acm_struct_t *cdcAcmHandle;
936 usb_status_t status;
937 if (NULL == handle)
938 {
939 return kStatus_USB_InvalidHandle;
940 }
941 cdcAcmHandle = (usb_device_cdc_acm_struct_t *)handle;
942
943 if (1U == cdcAcmHandle->bulkOut.isBusy)
944 {
945 return kStatus_USB_Busy;
946 }
947 cdcAcmHandle->bulkOut.isBusy = 1U;
948
949 if (0U != cdcAcmHandle->bulkOut.pipeStall)
950 {
951 cdcAcmHandle->bulkOut.pipeDataBuffer = buffer;
952 cdcAcmHandle->bulkOut.pipeDataLen = length;
953 return kStatus_USB_Success;
954 }
955
956 status = USB_DeviceRecvRequest(cdcAcmHandle->handle, ep, buffer, length);
957 if (kStatus_USB_Success != status)
958 {
959 cdcAcmHandle->bulkOut.isBusy = 0U;
960 }
961 return status;
962 }
963
964 #endif /* USB_DEVICE_CONFIG_CDC_ACM */
965