1 /**************************************************************************/
2 /* */
3 /* Copyright (c) Microsoft Corporation. All rights reserved. */
4 /* */
5 /* This software is licensed under the Microsoft Software License */
6 /* Terms for Microsoft Azure RTOS. Full text of the license can be */
7 /* found in the LICENSE file at https://aka.ms/AzureRTOS_EULA */
8 /* and in the root directory of this software. */
9 /* */
10 /**************************************************************************/
11
12
13 /**************************************************************************/
14 /**************************************************************************/
15 /** */
16 /** USBX Component */
17 /** */
18 /** Storage Class */
19 /** */
20 /**************************************************************************/
21 /**************************************************************************/
22
23
24 /* Include necessary system files. */
25
26 #define UX_SOURCE_CODE
27
28 #include "ux_api.h"
29 #include "ux_host_class_storage.h"
30 #include "ux_host_stack.h"
31
32
33 #if !defined(UX_HOST_STANDALONE)
34 /**************************************************************************/
35 /* */
36 /* FUNCTION RELEASE */
37 /* */
38 /* _ux_host_class_storage_thread_entry PORTABLE C */
39 /* 6.1.11 */
40 /* AUTHOR */
41 /* */
42 /* Chaoqiong Xiao, Microsoft Corporation */
43 /* */
44 /* DESCRIPTION */
45 /* */
46 /* This function is awaken every 2 seconds to check if there was a */
47 /* device insertion on a specific media. This is the only way we can */
48 /* remount a media after the storage instance has opened the media to */
49 /* UX_MEDIA (default FileX) and the media is either not present */
50 /* or was removed and is being re-inserted. */
51 /* */
52 /* It's for RTOS mode. */
53 /* */
54 /* INPUT */
55 /* */
56 /* class_address Class address */
57 /* */
58 /* OUTPUT */
59 /* */
60 /* None */
61 /* */
62 /* CALLS */
63 /* */
64 /* ux_media_close Close media */
65 /* _ux_host_class_storage_device_reset Reset device */
66 /* _ux_host_class_storage_media_mount Mount the media */
67 /* _ux_host_class_storage_unit_ready_test */
68 /* Test for unit ready */
69 /* _ux_host_class_storage_media_characteristics_get */
70 /* Get media characteristics */
71 /* _ux_host_class_storage_media_format_capacity_get */
72 /* Get media format capacity */
73 /* _ux_utility_memory_free Free memory block */
74 /* _ux_host_semaphore_get Get a semaphore */
75 /* _ux_host_semaphore_put Put a semaphore */
76 /* _ux_utility_delay_ms Thread sleep */
77 /* */
78 /* CALLED BY */
79 /* */
80 /* ThreadX */
81 /* */
82 /* RELEASE HISTORY */
83 /* */
84 /* DATE NAME DESCRIPTION */
85 /* */
86 /* 05-19-2020 Chaoqiong Xiao Initial Version 6.0 */
87 /* 09-30-2020 Chaoqiong Xiao Modified comment(s), */
88 /* added option to disable FX */
89 /* media integration, used UX_ */
90 /* things instead of FX_ */
91 /* things directly, used host */
92 /* class extension pointer for */
93 /* class specific structured */
94 /* data, */
95 /* resulting in version 6.1 */
96 /* 01-31-2022 Chaoqiong Xiao Modified comment(s), */
97 /* refined macros names, */
98 /* resulting in version 6.1.10 */
99 /* 04-25-2022 Chaoqiong Xiao Modified comment(s), */
100 /* internal clean up, */
101 /* resulting in version 6.1.11 */
102 /* */
103 /**************************************************************************/
_ux_host_class_storage_thread_entry(ULONG class_address)104 VOID _ux_host_class_storage_thread_entry(ULONG class_address)
105 {
106
107 UX_HOST_CLASS *class_inst;
108 UX_HOST_CLASS_STORAGE *storage;
109 UINT status;
110 ULONG lun_index;
111 UX_HOST_CLASS_STORAGE_MEDIA *storage_media;
112 UINT media_index;
113 #if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX)
114 UX_MEDIA *media;
115 UCHAR *memory;
116 #endif
117
118
119 /* Setup pointer to class. */
120 UX_THREAD_EXTENSION_PTR_GET(class_inst, UX_HOST_CLASS, class_address)
121
122 /* This thread goes on forever once started. */
123 while(1)
124 {
125
126 /* We need to wake every 2 seconds or so. */
127 _ux_utility_delay_ms(UX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME);
128
129 /* We need to parse all the storage instances and check for a removable
130 media flag. */
131 storage = (UX_HOST_CLASS_STORAGE *) class_inst -> ux_host_class_first_instance;
132
133 while (storage != UX_NULL)
134 {
135
136 /* Check if the instance is live and the device is removable. */
137 if ((storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_LIVE))
138 {
139
140 /* We need to ensure nobody is accessing this storage instance. We use
141 the storage class instance semaphore to protect. */
142 status = _ux_host_semaphore_get(&storage -> ux_host_class_storage_semaphore, UX_WAIT_FOREVER);
143 if (status != UX_SUCCESS)
144 break;
145
146 /* Each LUN must be parsed and mounted. */
147 for (lun_index = 0; lun_index <= storage -> ux_host_class_storage_max_lun; lun_index++)
148 {
149
150 if (storage -> ux_host_class_storage_lun_removable_media_flags[lun_index] != UX_HOST_CLASS_STORAGE_MEDIA_REMOVABLE)
151 continue;
152
153 /* Check the type of LUN, we only deal with the ones we know how to mount. */
154 if ((storage -> ux_host_class_storage_lun_types[lun_index] == UX_HOST_CLASS_STORAGE_MEDIA_FAT_DISK) ||
155 (storage -> ux_host_class_storage_lun_types[lun_index] == UX_HOST_CLASS_STORAGE_MEDIA_OPTICAL_DISK) ||
156 (storage -> ux_host_class_storage_lun_types[lun_index] == UX_HOST_CLASS_STORAGE_MEDIA_IOMEGA_CLICK))
157 {
158
159 /* Set the LUN into the storage instance. */
160 storage -> ux_host_class_storage_lun = lun_index;
161
162 /* Check if the device is now ready. */
163 status = _ux_host_class_storage_unit_ready_test(storage);
164
165 /* If we have an transport failure here, we are in trouble! The storage device
166 is in an unstable state and should be reset completely. */
167 if (status != UX_SUCCESS)
168 {
169
170 /* Reset device. */
171 _ux_host_class_storage_device_reset(storage);
172 break;
173 }
174
175 /* Process relative to device status. */
176 switch(storage -> ux_host_class_storage_sense_code >> 16)
177 {
178
179 case UX_HOST_CLASS_STORAGE_SENSE_KEY_NOT_READY:
180
181 /* We may need to unmount this partition if it was mounted before.
182 To do so, we need to parse the existing media instance and find out
183 if this partition was already mounted. */
184
185 storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *) class_inst -> ux_host_class_media;
186
187 /* Scan all instances of media. */
188 for (media_index = 0; media_index < UX_HOST_CLASS_STORAGE_MAX_MEDIA;
189 storage_media++, media_index++)
190 {
191 #if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX)
192 /* Get the UX_MEDIA (default FileX) Media attached to this media. */
193 media = &storage_media -> ux_host_class_storage_media;
194
195 /* Check for the storage instance and lun number. */
196 if ((ux_media_id_get(media) != 0) && (ux_media_driver_info_get(media) == (VOID *) storage) &&
197 (storage_media -> ux_host_class_storage_media_lun == storage -> ux_host_class_storage_lun))
198 {
199
200 /* We preserve the memory used by this media. */
201 memory = storage_media -> ux_host_class_storage_media_memory;
202
203 /* Let UX_MEDIA (default FileX) use this instance. */
204 _ux_host_semaphore_put(&storage -> ux_host_class_storage_semaphore);
205
206 /* Ask UX_MEDIA (default FileX) to unmount the partition. */
207 ux_media_close(media);
208
209 /* This device is now unmounted. */
210 storage_media -> ux_host_class_storage_media_status = UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED;
211
212 /* Reset the media ID. */
213 ux_media_id_set(media, 0);
214
215 /* Now, we protect the storage instance. */
216 status = _ux_host_semaphore_get(&storage -> ux_host_class_storage_semaphore, UX_WAIT_FOREVER);
217 if (status != UX_SUCCESS)
218 break;
219
220 /* Free the memory block used for data transfer on behalf of UX_MEDIA (default FileX). */
221 _ux_utility_memory_free(memory);
222 }
223 #else
224
225 /* Check storage instance and lun number. */
226 if (storage_media -> ux_host_class_storage_media_status != UX_USED)
227 continue;
228 if (storage_media -> ux_host_class_storage_media_storage != storage)
229 continue;
230 if (storage_media -> ux_host_class_storage_media_lun != storage -> ux_host_class_storage_lun)
231 continue;
232
233 /* Release the instance. */
234 status = _ux_host_semaphore_put_rc(&storage -> ux_host_class_storage_semaphore);
235
236 /* Free the storage media. */
237 storage_media -> ux_host_class_storage_media_status = UX_UNUSED;
238
239 /* Invoke callback for media removal. */
240 if (_ux_system_host -> ux_system_host_change_function != UX_NULL)
241 {
242
243 /* Call system change function. */
244 _ux_system_host -> ux_system_host_change_function(UX_STORAGE_MEDIA_REMOVAL,
245 storage -> ux_host_class_storage_class, (VOID *) storage_media);
246 }
247
248 /* Now, we protect the storage instance. */
249 status = _ux_host_semaphore_get(&storage -> ux_host_class_storage_semaphore, UX_WAIT_FOREVER);
250 if (status != UX_SUCCESS)
251 break;
252 #endif
253 }
254 break;
255
256 case UX_HOST_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION:
257
258 /* We may need to unmount this partition if it was mounted before.
259 To do so, we need to parse the existing media instance and find out
260 if this partition was already mounted. */
261 storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *) class_inst -> ux_host_class_media;
262
263 /* Scan all instances of media. */
264 for (media_index = 0; media_index < UX_HOST_CLASS_STORAGE_MAX_MEDIA;
265 storage_media++, media_index++)
266 {
267
268 #if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX)
269 /* Get the UX_MEDIA (default FileX) Media attached to this media. */
270 media = &storage_media -> ux_host_class_storage_media;
271
272 /* Check for the storage instance and lun number. */
273 if ((ux_media_id_get(media) != 0) && (ux_media_driver_info_get(media) == (VOID *) storage) &&
274 (storage_media -> ux_host_class_storage_media_lun == storage -> ux_host_class_storage_lun))
275 {
276
277 /* We preserve the memory used by this media. */
278 memory = storage_media -> ux_host_class_storage_media_memory;
279
280 /* Let UX_MEDIA (default FileX) use this instance. */
281 _ux_host_semaphore_put(&storage -> ux_host_class_storage_semaphore);
282
283 /* Ask UX_MEDIA (default FileX) to unmount the partition. */
284 ux_media_close(media);
285
286 /* This device is now unmounted. */
287 storage_media -> ux_host_class_storage_media_status = UX_HOST_CLASS_STORAGE_MEDIA_UNMOUNTED;
288
289 /* Reset the media ID. */
290 ux_media_id_set(media, 0);
291
292 /* Now, we protect the storage instance. */
293 status = _ux_host_semaphore_get(&storage -> ux_host_class_storage_semaphore, UX_WAIT_FOREVER);
294 if (status != UX_SUCCESS)
295 break;
296
297 /* Free the memory block used for data transfer on behalf of FileX. */
298 _ux_utility_memory_free(memory);
299 }
300 #else
301
302 /* Check storage instance and lun number. */
303 if (storage_media -> ux_host_class_storage_media_status != UX_USED)
304 continue;
305 if (storage_media -> ux_host_class_storage_media_storage != storage)
306 continue;
307 if (storage_media -> ux_host_class_storage_media_lun != storage -> ux_host_class_storage_lun)
308 continue;
309
310 /* Release the instance. */
311 status = _ux_host_semaphore_put_rc(&storage -> ux_host_class_storage_semaphore);
312
313 /* Free the storage media. */
314 storage_media -> ux_host_class_storage_media_status = UX_UNUSED;
315
316 /* Invoke callback for media removal. */
317 if (_ux_system_host -> ux_system_host_change_function != UX_NULL)
318 {
319
320 /* Call system change function. */
321 _ux_system_host -> ux_system_host_change_function(UX_STORAGE_MEDIA_REMOVAL,
322 storage -> ux_host_class_storage_class, (VOID *) storage_media);
323 }
324
325 /* Now, we protect the storage instance. */
326 status = _ux_host_semaphore_get(&storage -> ux_host_class_storage_semaphore, UX_WAIT_FOREVER);
327 if (status != UX_SUCCESS)
328 break;
329 #endif
330 }
331
332 /* Now, we need to retest the media to see if it is there. */
333 status = _ux_host_class_storage_unit_ready_test(storage);
334
335 /* If we have an transport failure here, we are in trouble! The storage device
336 is in an unstable state and should be reset completely. */
337 if (status != UX_SUCCESS)
338 {
339
340 /* Reset device. */
341 _ux_host_class_storage_device_reset(storage);
342 break;
343 }
344
345 if (storage -> ux_host_class_storage_sense_code == 0)
346 {
347
348 /* Get the media type supported by this storage device. */
349 status = _ux_host_class_storage_media_characteristics_get(storage);
350 if (status != UX_SUCCESS)
351 break;
352
353 /* Get the format capacity of this storage device. */
354 status = _ux_host_class_storage_media_format_capacity_get(storage);
355 if (status != UX_SUCCESS)
356 break;
357
358 /* Let UX_MEDIA (default FileX) use this instance. */
359 _ux_host_semaphore_put(&storage -> ux_host_class_storage_semaphore);
360
361 #if !defined(UX_HOST_CLASS_STORAGE_NO_FILEX)
362
363 /* The device seems to have been inserted, try to mount it. */
364 _ux_host_class_storage_media_mount(storage, 0);
365 #else
366
367 /* Find a free media slot for inserted media. */
368 storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *) class_inst -> ux_host_class_media;
369 for (media_index = 0; media_index < UX_HOST_CLASS_STORAGE_MAX_MEDIA;
370 storage_media ++, media_index ++)
371 {
372
373 /* Skip used storage media slots. */
374 if (storage_media -> ux_host_class_storage_media_status == UX_USED)
375 continue;
376
377 /* Use this free storage media slot. */
378 storage_media -> ux_host_class_storage_media_status = UX_USED;
379 storage_media -> ux_host_class_storage_media_storage = storage;
380
381 /* Save media information. */
382 storage_media -> ux_host_class_storage_media_lun = (UCHAR)storage -> ux_host_class_storage_lun;
383 storage_media -> ux_host_class_storage_media_sector_size = (USHORT)storage -> ux_host_class_storage_sector_size;
384 storage_media -> ux_host_class_storage_media_number_sectors = storage -> ux_host_class_storage_last_sector_number + 1;
385
386 /* Invoke callback for media insertion. */
387 if (_ux_system_host -> ux_system_host_change_function != UX_NULL)
388 {
389
390 /* Call system change function. */
391 _ux_system_host -> ux_system_host_change_function(UX_STORAGE_MEDIA_INSERTION,
392 storage -> ux_host_class_storage_class, (VOID *) storage_media);
393 }
394 }
395 #endif
396
397 /* Now, we protect the storage instance. */
398 _ux_host_semaphore_get(&storage -> ux_host_class_storage_semaphore, UX_WAIT_FOREVER);
399 }
400 break;
401
402 default:
403 break;
404 }
405 }
406 }
407
408 /* Other threads are now allowed to access this storage instance. */
409 _ux_host_semaphore_put(&storage -> ux_host_class_storage_semaphore);
410 }
411
412 /* Move to the next entry in the storage instances link. */
413 storage = storage -> ux_host_class_storage_next_instance;
414 }
415 }
416 }
417 #endif
418