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 /** */
15 /** USBX Component */
16 /** */
17 /** Storage Class */
18 /** */
19 /**************************************************************************/
20 /**************************************************************************/
21
22
23 /* Include necessary system files. */
24
25 #define UX_SOURCE_CODE
26
27 #include "ux_api.h"
28 #include "ux_host_class_storage.h"
29 #include "ux_host_stack.h"
30
31
32 /**************************************************************************/
33 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _ux_host_class_storage_deactivate PORTABLE C */
37 /* 6.1.10 */
38 /* AUTHOR */
39 /* */
40 /* Chaoqiong Xiao, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function is called when this instance of the storage device */
45 /* has been removed from the bus either directly or indirectly. The */
46 /* bulk in\out pipes will be destroyed and the instanced removed. */
47 /* */
48 /* INPUT */
49 /* */
50 /* command Pointer to class command */
51 /* */
52 /* OUTPUT */
53 /* */
54 /* Completion Status */
55 /* */
56 /* CALLS */
57 /* */
58 /* ux_media_close Close media */
59 /* _ux_host_stack_endpoint_transfer_abort Abort transfer request */
60 /* _ux_host_stack_class_instance_destroy Destroy class instance */
61 /* _ux_utility_memory_free Free memory block */
62 /* _ux_host_semaphore_get Get protection semaphore */
63 /* _ux_host_semaphore_delete Delete protection semaphore */
64 /* _ux_utility_thread_schedule_other Schedule other threads */
65 /* */
66 /* CALLED BY */
67 /* */
68 /* Storage Class */
69 /* */
70 /* RELEASE HISTORY */
71 /* */
72 /* DATE NAME DESCRIPTION */
73 /* */
74 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
75 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
76 /* added option to disable FX */
77 /* media integration, used UX_ */
78 /* things instead of FX_ */
79 /* things directly, used host */
80 /* class extension pointer for */
81 /* class specific structured */
82 /* data, */
83 /* resulting in version 6.1 */
84 /* 04-02-2021 Chaoqiong Xiao Modified comment(s), */
85 /* fixed compile issues with */
86 /* some macro options, */
87 /* resulting in version 6.1.6 */
88 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
89 /* improved media insert/eject */
90 /* management without FX, */
91 /* resulting in version 6.1.10 */
92 /* */
93 /**************************************************************************/
_ux_host_class_storage_deactivate(UX_HOST_CLASS_COMMAND * command)94 UINT _ux_host_class_storage_deactivate(UX_HOST_CLASS_COMMAND *command)
95 {
96
97 UINT status;
98 UX_HOST_CLASS_STORAGE *storage;
99 UX_HOST_CLASS_STORAGE_MEDIA *storage_media;
100 UX_HOST_CLASS *class_inst;
101 UINT inst_index;
102 #if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX)
103 UX_MEDIA *media;
104 VOID *memory;
105 #endif
106
107
108 /* Get the instance for this class. */
109 storage = (UX_HOST_CLASS_STORAGE *) command -> ux_host_class_command_instance;
110
111 /* We need the class container. */
112 class_inst = storage -> ux_host_class_storage_class;
113
114 /* Point the media structure to the first media in the container. */
115 storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *) class_inst -> ux_host_class_media;
116
117 /* The storage device is being shut down. */
118 storage -> ux_host_class_storage_state = UX_HOST_CLASS_INSTANCE_SHUTDOWN;
119
120 /* We come to this point when the device has been extracted. So there may have been a transaction
121 being scheduled. We make sure the transaction has been completed by the controller driver.
122 When the device is extracted, the controller tries multiple times the transaction and retires it
123 with a DEVICE_NOT_RESPONDING error code.
124
125 First we take care of endpoint OUT. */
126
127 /* We need to abort transactions on the bulk pipes. */
128 if (storage -> ux_host_class_storage_bulk_out_endpoint != UX_NULL)
129 _ux_host_stack_endpoint_transfer_abort(storage -> ux_host_class_storage_bulk_out_endpoint);
130
131 /* Then endpoint IN. */
132 if (storage -> ux_host_class_storage_bulk_in_endpoint != UX_NULL)
133 _ux_host_stack_endpoint_transfer_abort(storage -> ux_host_class_storage_bulk_in_endpoint);
134
135 #ifdef UX_HOST_CLASS_STORAGE_INCLUDE_LEGACY_PROTOCOL_SUPPORT
136 /* Was the protocol CBI ? */
137 if (storage -> ux_host_class_storage_interface -> ux_interface_descriptor.bInterfaceProtocol == UX_HOST_CLASS_STORAGE_PROTOCOL_CBI)
138 {
139
140 /* Was there an interrupt endpoint? */
141 if (storage -> ux_host_class_storage_interrupt_endpoint != UX_NULL)
142 {
143
144 /* Abort the data transfer on the interrupt endpoint. */
145 _ux_host_stack_endpoint_transfer_abort(storage -> ux_host_class_storage_interrupt_endpoint);
146
147 /* Free the memory that was used by the interrupt endpoint. */
148 if (storage -> ux_host_class_storage_interrupt_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_data_pointer != UX_NULL)
149 _ux_utility_memory_free(storage -> ux_host_class_storage_interrupt_endpoint -> ux_endpoint_transfer_request.ux_transfer_request_data_pointer);
150 }
151 }
152 #endif
153
154 /* The enumeration thread needs to sleep a while to allow the application or the class that may be using
155 endpoints to exit properly. */
156 _ux_host_thread_schedule_other(UX_THREAD_PRIORITY_ENUM);
157
158
159 /* Inform UX_MEDIA (default FileX) of the deactivation of all Media attached to this instance. */
160 for (inst_index = 0; inst_index < UX_HOST_CLASS_STORAGE_MAX_MEDIA; inst_index++)
161 {
162
163 #if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX)
164 /* Get the UX_MEDIA (default FileX) attached to this media. */
165 media = &storage_media -> ux_host_class_storage_media;
166
167 /* Check if the media belongs to the device being removed. */
168 if (((UX_HOST_CLASS_STORAGE *) ux_media_driver_info_get(media)) == storage)
169 {
170
171 /* Check if the media was properly opened. */
172 if (storage_media -> ux_host_class_storage_media_status == UX_HOST_CLASS_STORAGE_MEDIA_MOUNTED)
173 {
174
175 /* We preserve the memory used by this media. */
176 memory = storage_media -> ux_host_class_storage_media_memory;
177
178 /* Ask UX_MEDIA (default FileX) to unmount the partition. */
179 ux_media_close(media);
180
181 /* This device is now unmounted. */
182 storage_media -> ux_host_class_storage_media_status = UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED;
183
184 /* Reset the media ID. */
185 ux_media_id_set(media, 0);
186
187 /* Free the memory block used for data transfer on behalf of UX_MEDIA (default FileX). */
188 _ux_utility_memory_free(memory);
189 }
190 }
191 #else
192
193 /* Check if the media is for this storage. */
194 if (storage_media -> ux_host_class_storage_media_status == UX_USED &&
195 storage_media -> ux_host_class_storage_media_storage == storage)
196 {
197
198 /* Free the storage media. */
199 storage_media -> ux_host_class_storage_media_status = UX_UNUSED;
200
201 /* Invoke callback for media removal. */
202 if (_ux_system_host -> ux_system_host_change_function != UX_NULL)
203 {
204
205 /* Call system change function. */
206 _ux_system_host -> ux_system_host_change_function(UX_STORAGE_MEDIA_REMOVAL,
207 storage -> ux_host_class_storage_class, (VOID *) storage_media);
208 }
209 }
210 #endif
211
212 /* Move to next entry in the media array. */
213 storage_media++;
214 }
215
216 /* Protect thread reentry to this instance. */
217 status = _ux_host_semaphore_get(&storage -> ux_host_class_storage_semaphore, UX_WAIT_FOREVER);
218 UX_PARAMETER_NOT_USED(status);
219
220 /* Destroy the instance. */
221 _ux_host_stack_class_instance_destroy(storage -> ux_host_class_storage_class, (VOID *) storage);
222
223 /* Destroy the protection semaphore. */
224 _ux_host_semaphore_delete(&storage -> ux_host_class_storage_semaphore);
225
226 /* Before we free the device resources, we need to inform the application
227 that the device is removed. */
228 if (_ux_system_host -> ux_system_host_change_function != UX_NULL)
229 {
230
231 /* Inform the application the device is removed. */
232 _ux_system_host -> ux_system_host_change_function(UX_DEVICE_REMOVAL, storage -> ux_host_class_storage_class, (VOID *) storage);
233 }
234
235 /* If trace is enabled, insert this event into the trace buffer. */
236 UX_TRACE_IN_LINE_INSERT(UX_TRACE_HOST_CLASS_STORAGE_DEACTIVATE, storage, 0, 0, 0, UX_TRACE_HOST_CLASS_EVENTS, 0, 0)
237
238 /* If trace is enabled, register this object. */
239 UX_TRACE_OBJECT_UNREGISTER(storage);
240
241 /* Free the storage instance memory. */
242 _ux_utility_memory_free(storage);
243
244 /* Return successful completion. */
245 return(UX_SUCCESS);
246 }
247
248