1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11 /**************************************************************************/
12 /**************************************************************************/
13 /** */
14 /** USBX Component */
15 /** */
16 /** Device Audio Class */
17 /** */
18 /**************************************************************************/
19 /**************************************************************************/
20
21 #define UX_SOURCE_CODE
22
23
24 /* Include necessary system files. */
25
26 #include "ux_api.h"
27 #include "ux_device_class_audio.h"
28 #include "ux_device_stack.h"
29
30 #if defined(UX_DEVICE_STANDALONE) && defined(UX_DEVICE_CLASS_AUDIO_INTERRUPT_SUPPORT)
31 /**************************************************************************/
32 /* */
33 /* FUNCTION RELEASE */
34 /* */
35 /* _ux_device_class_audio_interrupt_task_function PORTABLE C */
36 /* 6.3.0 */
37 /* AUTHOR */
38 /* */
39 /* Yajun Xia, Microsoft Corporation */
40 /* */
41 /* DESCRIPTION */
42 /* */
43 /* This function is task of INTERRUPT IN from the Audio class. */
44 /* */
45 /* It's for standalone mode. */
46 /* */
47 /* INPUT */
48 /* */
49 /* audio Address of audio instance */
50 /* */
51 /* OUTPUT */
52 /* */
53 /* State machine Status to check */
54 /* UX_STATE_EXIT Abnormal, to reset state */
55 /* UX_STATE_IDLE No interrupt transfer running */
56 /* UX_STATE_WAIT Keep running, waiting */
57 /* */
58 /* CALLS */
59 /* */
60 /* _ux_system_error_handler System error trap */
61 /* _ux_utility_memory_copy Copy memory */
62 /* _ux_device_stack_transfer_run Run Transfer state machine */
63 /* */
64 /* CALLED BY */
65 /* */
66 /* Audio Class (task) */
67 /* */
68 /* RELEASE HISTORY */
69 /* */
70 /* DATE NAME DESCRIPTION */
71 /* */
72 /* 10-31-2022 Yajun Xia Initial Version 6.2.0 */
73 /* 10-31-2023 Chaoqiong Xiao Modified comment(s), */
74 /* removed an error trap, */
75 /* resulting in version 6.3.0 */
76 /* */
77 /**************************************************************************/
_ux_device_class_audio_interrupt_task_function(UX_DEVICE_CLASS_AUDIO * audio)78 UINT _ux_device_class_audio_interrupt_task_function(UX_DEVICE_CLASS_AUDIO *audio)
79 {
80
81 UINT status;
82 UX_SLAVE_DEVICE *device;
83 UX_SLAVE_ENDPOINT *endpoint;
84 UX_SLAVE_TRANSFER *transfer;
85 UCHAR *buff;
86
87
88 /* Get stack device instance. */
89 device = audio -> ux_device_class_audio_device;
90
91 /* Check if the device is configured. */
92 if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED)
93 {
94
95 /* Error trap. */
96 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_CONFIGURATION_HANDLE_UNKNOWN);
97
98 audio -> ux_device_class_audio_interrupt_task_state = UX_STATE_EXIT;
99 return(UX_STATE_EXIT);
100 }
101
102 /* Get endpoint instance. */
103 endpoint = audio -> ux_device_class_audio_interrupt;
104
105 /* Endpoint not available, maybe it's alternate setting 0,
106 or not exist in framework (accepted use case). */
107 if (endpoint == UX_NULL)
108 {
109 audio -> ux_device_class_audio_interrupt_task_state = UX_STATE_RESET;
110 return(UX_STATE_IDLE);
111 }
112
113 /* No packet in queue */
114 if (audio -> ux_device_class_audio_status_queued == 0)
115 {
116 audio -> ux_device_class_audio_interrupt_task_state = UX_STATE_RESET;
117 audio -> ux_device_class_audio_interrupt_task_status = UX_TRANSFER_NOT_READY;
118 return(UX_STATE_EXIT);
119 }
120
121 /* Get transfer instance. */
122 transfer = &endpoint -> ux_slave_endpoint_transfer_request;
123
124 /* Handle state cases. */
125 switch(audio -> ux_device_class_audio_interrupt_task_state)
126 {
127 case UX_STATE_RESET:
128 audio -> ux_device_class_audio_interrupt_task_state = UX_DEVICE_CLASS_AUDIO_INTERRUPT_START;
129 audio -> ux_device_class_audio_interrupt_task_status = UX_TRANSFER_NO_ANSWER;
130
131 /* Fall through. */
132 case UX_DEVICE_CLASS_AUDIO_INTERRUPT_START:
133 if (audio -> ux_device_class_audio_status_size > transfer -> ux_slave_transfer_request_transfer_length)
134 {
135
136 /* Error trap. */
137 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_ERROR);
138
139 audio -> ux_device_class_audio_interrupt_task_state = UX_STATE_RESET;
140 audio -> ux_device_class_audio_interrupt_task_status = UX_ERROR;
141 return(UX_STATE_EXIT);
142 }
143
144 _ux_utility_memory_copy(transfer -> ux_slave_transfer_request_data_pointer,
145 audio -> ux_device_class_audio_status_tail, audio -> ux_device_class_audio_status_size); /* Use case of memcpy is verified. */
146
147 audio -> ux_device_class_audio_interrupt_task_state = UX_DEVICE_CLASS_AUDIO_INTERRUPT_WAIT;
148
149 /* Fall through. */
150 case UX_DEVICE_CLASS_AUDIO_INTERRUPT_WAIT:
151
152 /* Start frame transfer anyway. */
153 status = _ux_device_stack_transfer_run(transfer, audio -> ux_device_class_audio_status_size,
154 audio -> ux_device_class_audio_status_size);
155
156 /* Any error or success case. */
157 if (status < UX_STATE_NEXT)
158 {
159
160 /* Error notification! */
161 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_TRANSFER_ERROR);
162
163 audio -> ux_device_class_audio_interrupt_task_state = UX_STATE_RESET;
164 audio -> ux_device_class_audio_interrupt_task_status =
165 transfer -> ux_slave_transfer_request_completion_code;
166 return(UX_STATE_EXIT);
167 }
168
169 /* Success case. */
170 if (status == UX_STATE_NEXT)
171 {
172 buff = audio -> ux_device_class_audio_status_tail;
173 buff += audio -> ux_device_class_audio_status_size;
174
175 if (buff >= (audio -> ux_device_class_audio_status_queue + audio -> ux_device_class_audio_status_queue_bytes))
176 buff = audio -> ux_device_class_audio_status_queue;
177
178 audio -> ux_device_class_audio_status_tail = buff;
179 audio -> ux_device_class_audio_status_queued -= audio -> ux_device_class_audio_status_size;
180 audio -> ux_device_class_audio_interrupt_task_state = UX_DEVICE_CLASS_AUDIO_INTERRUPT_START;
181 audio -> ux_device_class_audio_interrupt_task_status =
182 transfer -> ux_slave_transfer_request_completion_code;
183 }
184
185 /* Keep waiting. */
186 return(UX_STATE_WAIT);
187
188 default: /* Error. */
189 audio -> ux_device_class_audio_interrupt_task_state = UX_STATE_RESET;
190 audio -> ux_device_class_audio_interrupt_task_status = UX_INVALID_STATE;
191 break;
192 }
193
194 /* Error case. */
195 return(UX_STATE_EXIT);
196 }
197 #endif
198