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