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 #if defined(UX_HOST_STANDALONE)
33
34
35 static inline VOID _ux_host_class_storage_inst_tasks_run(UX_HOST_CLASS_STORAGE *storage);
36
37 static inline UINT _ux_host_class_storage_lun_is_removable(UX_HOST_CLASS_STORAGE *storage);
38 static inline UINT _ux_host_class_storage_lun_type_is_known(UX_HOST_CLASS_STORAGE *storage);
39
40 static inline VOID _ux_host_class_storage_max_lun_save(UX_HOST_CLASS_STORAGE *storage);
41 static inline UINT _ux_host_class_storage_inquiry_save(UX_HOST_CLASS_STORAGE *storage);
42 static inline VOID _ux_host_class_storage_format_cap_save(UX_HOST_CLASS_STORAGE *storage);
43 static inline VOID _ux_host_class_storage_capacity_save(UX_HOST_CLASS_STORAGE *storage);
44 static inline VOID _ux_host_class_storage_unit_ready_check(UX_HOST_CLASS_STORAGE *storage);
45
46 static inline VOID _ux_host_class_storage_lun_media_insert(UX_HOST_CLASS_STORAGE *storage);
47
48 static inline UINT _ux_host_class_storage_transport_sense_check(UX_HOST_CLASS_STORAGE *storage);
49
50 /**************************************************************************/
51 /* */
52 /* FUNCTION RELEASE */
53 /* */
54 /* _ux_host_class_storage_tasks_run PORTABLE C */
55 /* 6.2.0 */
56 /* AUTHOR */
57 /* */
58 /* Chaoqiong Xiao, Microsoft Corporation */
59 /* */
60 /* DESCRIPTION */
61 /* */
62 /* This function is awaken every 2 seconds to check if there was a */
63 /* device insertion on a specific media. This is the only way we can */
64 /* remount a media after the storage instance has opened the media to */
65 /* UX_MEDIA (default FileX) and the media is either not present */
66 /* or was removed and is being re-inserted. */
67 /* */
68 /* INPUT */
69 /* */
70 /* storage Pointer to storage instance */
71 /* */
72 /* OUTPUT */
73 /* */
74 /* None */
75 /* */
76 /* CALLS */
77 /* */
78 /* _ux_host_class_storage_device_reset Reset device */
79 /* _ux_host_class_storage_media_mount Mount the media */
80 /* _ux_host_class_storage_unit_ready_test */
81 /* Test for unit ready */
82 /* _ux_host_class_storage_media_characteristics_get */
83 /* Get media characteristics */
84 /* _ux_host_class_storage_media_format_capacity_get */
85 /* Get media format capacity */
86 /* _ux_utility_memory_free Free memory block */
87 /* */
88 /* CALLED BY */
89 /* */
90 /* USBX Host Stack */
91 /* */
92 /* RELEASE HISTORY */
93 /* */
94 /* DATE NAME DESCRIPTION */
95 /* */
96 /* 01-31-2022 Chaoqiong Xiao Initial Version 6.1.10 */
97 /* 07-29-2022 Chaoqiong Xiao Modified comment(s), */
98 /* fixed parameter/variable */
99 /* names conflict C++ keyword, */
100 /* resulting in version 6.1.12 */
101 /* 10-31-2022 Chaoqiong Xiao Modified comment(s), */
102 /* improved internal logic, */
103 /* resulting in version 6.2.0 */
104 /* */
105 /**************************************************************************/
_ux_host_class_storage_tasks_run(UX_HOST_CLASS * storage_class)106 UINT _ux_host_class_storage_tasks_run(UX_HOST_CLASS *storage_class)
107 {
108 UX_HOST_CLASS_STORAGE *storage;
109
110 /* Validate class entry. */
111 if (storage_class -> ux_host_class_status != UX_USED ||
112 storage_class -> ux_host_class_entry_function != _ux_host_class_storage_entry)
113 return(UX_STATE_IDLE);
114
115 /* Run for class instances. */
116 storage = (UX_HOST_CLASS_STORAGE *)storage_class -> ux_host_class_first_instance;
117 while(storage)
118 {
119
120 /* Run tasks for each storage instance. */
121 storage -> ux_host_class_storage_flags |= UX_HOST_CLASS_STORAGE_FLAG_PROTECT;
122 _ux_host_class_storage_inst_tasks_run(storage);
123 storage -> ux_host_class_storage_flags &= ~UX_HOST_CLASS_STORAGE_FLAG_PROTECT;
124 storage = storage -> ux_host_class_storage_next_instance;
125 }
126 return(UX_STATE_WAIT);
127 }
128
_ux_host_class_storage_inst_tasks_run(UX_HOST_CLASS_STORAGE * storage)129 static inline VOID _ux_host_class_storage_inst_tasks_run(UX_HOST_CLASS_STORAGE *storage)
130 {
131 UX_INTERRUPT_SAVE_AREA
132 UCHAR state;
133 ULONG tick_now, tick_elapsed;
134 UINT status;
135 UX_TRANSFER *trans;
136 UX_INTERFACE *interface_ptr;
137 INT immediate_state;
138
139 /* If storage not live, start initialize. */
140 if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_MOUNTING)
141 {
142 if (storage -> ux_host_class_storage_state_state == UX_STATE_RESET)
143 {
144
145 /* Start initialize sequence Delay() - GetMaxLUN() - Inquiry() - GetFormatCapacity(). */
146 storage -> ux_host_class_storage_state_state = UX_HOST_CLASS_STORAGE_STATE_DELAY_WAIT;
147 storage -> ux_host_class_storage_state_next = UX_HOST_CLASS_STORAGE_STATE_MAX_LUN_GET;
148 storage -> ux_host_class_storage_delay_start = _ux_utility_time_get();
149 storage -> ux_host_class_storage_delay_ms =
150 UX_MS_TO_TICK_NON_ZERO(UX_HOST_CLASS_STORAGE_DEVICE_INIT_DELAY);
151 return;
152 }
153
154 /* OK to process states. */
155 }
156 else if (storage -> ux_host_class_storage_state != UX_HOST_CLASS_INSTANCE_LIVE)
157 {
158
159 /* No need to process states. */
160 storage -> ux_host_class_storage_state_state = UX_STATE_RESET;
161 return;
162 }
163
164 /* Handle read/write states. */
165 if ((storage -> ux_host_class_storage_op_state == UX_STATE_WAIT) &&
166 (storage -> ux_host_class_storage_flags &
167 UX_HOST_CLASS_STORAGE_FLAG_CHECK_CURRENT) == 0)
168 {
169
170 /* Run transport. */
171 status = _ux_host_class_storage_transport_run(storage);
172
173 /* Fatal error. */
174 if (status < UX_STATE_IDLE)
175 {
176 storage -> ux_host_class_storage_op_state = UX_STATE_RESET;
177 return;
178 }
179
180 /* Done with/without error. */
181 if (status <= UX_STATE_NEXT)
182 {
183 storage -> ux_host_class_storage_op_state = UX_STATE_IDLE;
184 return;
185 }
186
187 /* Keep waiting. */
188 /* Main states are frozen in this case. */
189 return;
190 }
191
192 /* Handle main states. */
193 immediate_state = UX_TRUE;
194 while(immediate_state)
195 {
196
197 /* Get current state. */
198 /* Initial check: delay()-GetMaxLUN()-Inquiry()-GetFormatCap()
199 process break on any error. */
200 /* Regular check: delay()-TestReady()-Inquiry()-GetFormatCap()
201 process break on any error. */
202 state = storage -> ux_host_class_storage_state_state;
203 switch(state)
204 {
205 case UX_HOST_CLASS_STORAGE_STATE_MAX_LUN_GET:
206
207 /* Issue GetMaxLun(). */
208 status = _ux_host_class_storage_max_lun_get(storage);
209 if (UX_SUCCESS != status)
210 {
211
212 /* This fails storage activation. */
213 interface_ptr = storage -> ux_host_class_storage_interface;
214 _ux_host_stack_class_instance_destroy(
215 storage -> ux_host_class_storage_class, (VOID *) storage);
216 interface_ptr -> ux_interface_class_instance = (VOID *) UX_NULL;
217 _ux_utility_memory_free(storage);
218 return;
219 }
220
221 /* Roll back to next state. */
222 /* By default TRANSFER -> MAX_LUN_SAVE -> TEST_READY. */
223 continue;
224
225 case UX_HOST_CLASS_STORAGE_STATE_MAX_LUN_SAVE:
226 _ux_host_class_storage_max_lun_save(storage);
227
228 /* Continue to start LUN 0 check from TEST_READY any way. */
229 storage -> ux_host_class_storage_check_lun = 0;
230 storage -> ux_host_class_storage_state_state =
231 UX_HOST_CLASS_STORAGE_STATE_TEST_READY;
232
233 /* Fall through. */
234 case UX_HOST_CLASS_STORAGE_STATE_TEST_READY:
235
236 /* Save the LUN for the follwing sequence to use. */
237 storage -> ux_host_class_storage_lun =
238 storage -> ux_host_class_storage_check_lun;
239
240 /* If storage is not live, skip to do INQUIRY. */
241 if (storage -> ux_host_class_storage_state != UX_HOST_CLASS_INSTANCE_LIVE)
242 {
243 storage -> ux_host_class_storage_state_state =
244 UX_HOST_CLASS_STORAGE_STATE_INQUIRY;
245 continue;
246 }
247
248 /* If LUN is not removable nor known, skip it to check next LUN. */
249 if (!_ux_host_class_storage_lun_is_removable(storage) ||
250 !_ux_host_class_storage_lun_type_is_known(storage))
251 {
252 storage -> ux_host_class_storage_state_state =
253 UX_HOST_CLASS_STORAGE_STATE_NEXT_LUN;
254 continue;
255 }
256
257 /* Prepare TestUnitReady(). */
258 _ux_host_class_storage_unit_ready_test(storage);
259
260 /* Roll back to next - TRANSPORT - TEST_CHECK. */
261 continue;
262
263 case UX_HOST_CLASS_STORAGE_STATE_TEST_CHECK:
264 _ux_host_class_storage_unit_ready_check(storage);
265
266 /* Roll back to next - possible NEXT_LUN/INQUIRY/TEST_READY. */
267 continue;
268
269 case UX_HOST_CLASS_STORAGE_STATE_INQUIRY:
270 status = _ux_host_class_storage_media_characteristics_get(storage);
271 if (status != UX_SUCCESS)
272 {
273
274 /* There is error, break the regular check round. */
275 storage -> ux_host_class_storage_status = status;
276 storage -> ux_host_class_storage_state_state =
277 UX_HOST_CLASS_STORAGE_STATE_CHECK_DONE;
278 }
279
280 /* Roll back to normal next - TRANSPORT - INQUIRY_SAVE. */
281 continue;
282
283 case UX_HOST_CLASS_STORAGE_STATE_INQUIRY_SAVE:
284 status = _ux_host_class_storage_inquiry_save(storage);
285 if (status != UX_SUCCESS)
286 {
287
288 /* Check next LUN. */
289 storage -> ux_host_class_storage_state_state = UX_HOST_CLASS_STORAGE_STATE_NEXT_LUN;
290 continue;
291 }
292
293 /* Next : GetFormatCapacity(). */
294 storage -> ux_host_class_storage_state_state = UX_HOST_CLASS_STORAGE_STATE_FORMAT_CAP_GET;
295
296 /* Fall through. */
297 case UX_HOST_CLASS_STORAGE_STATE_FORMAT_CAP_GET:
298 status = _ux_host_class_storage_media_format_capacity_get(storage);
299 if (status != UX_SUCCESS)
300 {
301
302 /* This error breaks regular check round. */
303 storage -> ux_host_class_storage_status = status;
304 storage -> ux_host_class_storage_state_state =
305 UX_HOST_CLASS_STORAGE_STATE_CHECK_DONE;
306 }
307
308 /* Roll back to normal next - TRANSPORT - FORMAT_CAP_SAVE. */
309 continue;
310
311 case UX_HOST_CLASS_STORAGE_STATE_FORMAT_CAP_SAVE:
312 _ux_host_class_storage_format_cap_save(storage);
313
314 /* Next : GetCapacity() */
315 storage -> ux_host_class_storage_state_state = UX_HOST_CLASS_STORAGE_STATE_CAP_GET;
316
317 /* Fall through. */
318 case UX_HOST_CLASS_STORAGE_STATE_CAP_GET:
319 status = _ux_host_class_storage_media_capacity_get(storage);
320 if (status != UX_SUCCESS)
321 {
322
323 /* This error breaks the regular check round. */
324 storage -> ux_host_class_storage_status = status;
325 storage -> ux_host_class_storage_state_state =
326 UX_HOST_CLASS_STORAGE_STATE_CHECK_DONE;
327 }
328
329 /* Roll back to normal next - TRANSPORT - CAP_SAVE. */
330 continue;
331
332 case UX_HOST_CLASS_STORAGE_STATE_CAP_SAVE:
333 _ux_host_class_storage_capacity_save(storage);
334
335 /* Final step for a single LUN check, going to next LUN. */
336 storage -> ux_host_class_storage_state_state = UX_HOST_CLASS_STORAGE_STATE_NEXT_LUN;
337 continue;
338
339 case UX_HOST_CLASS_STORAGE_STATE_CHECK_START:
340
341 /* Get lock and start check sequence: ready - inquiry - formatCap - cap. */
342 storage -> ux_host_class_storage_state_state = UX_HOST_CLASS_STORAGE_STATE_LOCK_WAIT;
343 storage -> ux_host_class_storage_state_next = UX_HOST_CLASS_STORAGE_STATE_TEST_READY;
344
345 /* Fall through. */
346 case UX_HOST_CLASS_STORAGE_STATE_LOCK_WAIT:
347 UX_DISABLE
348 if (storage -> ux_host_class_storage_flags & UX_HOST_CLASS_STORAGE_FLAG_LOCK)
349 {
350
351 /* Locked, keep state to wait. */
352 UX_RESTORE
353 return;
354 }
355
356 /* I'm locking it. */
357 storage -> ux_host_class_storage_flags |= UX_HOST_CLASS_STORAGE_FLAG_LOCK;
358 UX_RESTORE
359
360 /* Next state. */
361 storage -> ux_host_class_storage_state_state =
362 storage -> ux_host_class_storage_state_next;
363 continue;
364
365 case UX_HOST_CLASS_STORAGE_STATE_NEXT_LUN:
366
367 /* If it's immediate check for current LUN, we are done. */
368 if (storage -> ux_host_class_storage_flags &
369 UX_HOST_CLASS_STORAGE_FLAG_CHECK_CURRENT)
370 {
371
372 /* Go back to idle state. */
373 storage -> ux_host_class_storage_flags &=
374 ~UX_HOST_CLASS_STORAGE_FLAG_CHECK_CURRENT;
375 storage -> ux_host_class_storage_state_state = UX_STATE_IDLE;
376 continue;
377 }
378
379 if (storage -> ux_host_class_storage_check_lun <
380 storage -> ux_host_class_storage_max_lun)
381 {
382
383 /* Check next LUN. */
384 storage -> ux_host_class_storage_check_lun ++;
385 storage -> ux_host_class_storage_state_state =
386 UX_HOST_CLASS_STORAGE_STATE_TEST_READY;
387 }
388 else
389 {
390
391 /* All LUN check is done. */
392 storage -> ux_host_class_storage_state_state =
393 UX_HOST_CLASS_STORAGE_STATE_CHECK_DONE;
394 }
395
396 /* Roll back to next state. */
397 continue;
398
399 case UX_HOST_CLASS_STORAGE_STATE_TRANSPORT:
400 status = _ux_host_class_storage_transport_run(storage);
401
402 /* Errors. */
403 if (status < UX_STATE_NEXT)
404 {
405
406 /* Normal flow is broken, if there is data buffer, free it. */
407 if (storage -> ux_host_class_storage_trans_data)
408 _ux_utility_memory_free(storage -> ux_host_class_storage_trans_data);
409
410 /* No further operations, reset state machine. */
411 storage -> ux_host_class_storage_state_state = UX_STATE_RESET;
412 storage -> ux_host_class_storage_flags &= ~UX_HOST_CLASS_STORAGE_FLAG_LOCK;
413 return;
414 }
415
416 /* Next. */
417 if (status == UX_STATE_NEXT)
418 {
419
420 /* If there is sense handled, rollback to next state. */
421 if (_ux_host_class_storage_transport_sense_check(storage))
422 {
423
424 /* Normal flow is broken, if there is data buffer, free it. */
425 if (storage -> ux_host_class_storage_trans_data)
426 _ux_utility_memory_free(storage -> ux_host_class_storage_trans_data);
427 continue;
428 }
429
430 storage -> ux_host_class_storage_state_state =
431 storage -> ux_host_class_storage_state_next;
432 continue;
433 }
434
435 /* Wait, state no change. */
436 return;
437
438 case UX_HOST_CLASS_STORAGE_STATE_TRANSFER:
439 trans = storage -> ux_host_class_storage_trans;
440 status = _ux_host_stack_transfer_run(trans);
441
442 /* Keep waiting if not done. */
443 if (status > UX_STATE_NEXT)
444 return;
445
446 /* Check status in next state. */
447 storage -> ux_host_class_storage_state_state =
448 storage -> ux_host_class_storage_state_next;
449 continue;
450
451 case UX_HOST_CLASS_STORAGE_STATE_CHECK_DONE:
452
453 /* If it's mounting, do immediate ready check again. */
454 if (storage -> ux_host_class_storage_state == UX_HOST_CLASS_INSTANCE_MOUNTING)
455 {
456 storage -> ux_host_class_storage_state = UX_HOST_CLASS_INSTANCE_LIVE;
457 storage -> ux_host_class_storage_check_lun = 0;
458 storage -> ux_host_class_storage_state_state =
459 UX_HOST_CLASS_STORAGE_STATE_TEST_READY;
460 continue;
461 }
462
463 /* Release the storage. */
464 storage -> ux_host_class_storage_flags &= ~UX_HOST_CLASS_STORAGE_FLAG_LOCK;
465
466 /* Main state idle. */
467 storage -> ux_host_class_storage_state_state = UX_STATE_IDLE;
468 continue;
469
470 case UX_HOST_CLASS_STORAGE_STATE_DELAY_WAIT:
471 tick_now = _ux_utility_time_get();
472 tick_elapsed = _ux_utility_time_elapsed(
473 storage -> ux_host_class_storage_delay_start, tick_now);
474
475 /* If no timeout, state no change, keep waiting. */
476 if (tick_elapsed < storage -> ux_host_class_storage_delay_ms)
477 return;
478
479 /* Roll back to do next state. */
480 storage -> ux_host_class_storage_state_state =
481 storage -> ux_host_class_storage_state_next;
482 continue;
483
484 case UX_STATE_IDLE:
485
486 /* If it's not locked, start delay for checking. */
487 UX_DISABLE
488 if ((storage -> ux_host_class_storage_flags & UX_HOST_CLASS_STORAGE_FLAG_LOCK) == 0)
489 {
490
491 /* Just keep regular checking from LUN 0. */
492 storage -> ux_host_class_storage_check_lun = 0;
493 storage -> ux_host_class_storage_delay_start = _ux_utility_time_get();
494 storage -> ux_host_class_storage_state_state =
495 UX_HOST_CLASS_STORAGE_STATE_DELAY_WAIT;
496 storage -> ux_host_class_storage_state_next =
497 UX_HOST_CLASS_STORAGE_STATE_CHECK_START;
498 storage -> ux_host_class_storage_delay_ms = UX_MS_TO_TICK(
499 UX_HOST_CLASS_STORAGE_THREAD_SLEEP_TIME);
500 UX_RESTORE
501 continue;
502 }
503 UX_RESTORE
504
505 /* Fall through. */
506
507 case UX_STATE_RESET: /* Fall through. */
508 default:
509 break;
510 }
511
512 /* Break the loop. */
513 immediate_state = UX_FALSE;
514 }
515 }
516
_ux_host_class_storage_max_lun_save(UX_HOST_CLASS_STORAGE * storage)517 static inline VOID _ux_host_class_storage_max_lun_save(UX_HOST_CLASS_STORAGE *storage)
518 {
519 UX_TRANSFER *trans = storage -> ux_host_class_storage_trans;
520
521 /* By default max lun is 0. */
522 storage -> ux_host_class_storage_max_lun = 0;
523
524 /* MaxLuN can from success request. */
525 if (trans)
526 {
527
528 /* If success, save max LUN. */
529 if (trans -> ux_transfer_request_completion_code == UX_SUCCESS &&
530 trans -> ux_transfer_request_actual_length == 1)
531 {
532 storage -> ux_host_class_storage_max_lun =
533 *trans -> ux_transfer_request_data_pointer;
534
535 /* Is the max LUN index greater than our LUN array's? */
536 if (storage -> ux_host_class_storage_max_lun > UX_MAX_HOST_LUN - 1)
537 {
538
539 /* Cap it off. */
540 storage -> ux_host_class_storage_max_lun = UX_MAX_HOST_LUN - 1;
541
542 /* Notify application so it knows to increase UX_MAX_HOST_LUN. */
543 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_MEMORY_ERROR);
544
545 /* If trace is enabled, insert this event into the trace buffer. */
546 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_MEMORY_ERROR, storage, 0, 0, UX_TRACE_ERRORS, 0, 0)
547 }
548 }
549
550 /* Allocated buffer for request must be freed here. */
551 _ux_utility_memory_free(trans -> ux_transfer_request_data_pointer);
552 }
553 }
_ux_host_class_storage_inquiry_save(UX_HOST_CLASS_STORAGE * storage)554 static inline UINT _ux_host_class_storage_inquiry_save(UX_HOST_CLASS_STORAGE *storage)
555 {
556 UCHAR *inquiry_response = storage -> ux_host_class_storage_trans_data;
557 UINT lun_index = storage -> ux_host_class_storage_lun;
558 storage -> ux_host_class_storage_media_type = *(inquiry_response +
559 UX_HOST_CLASS_STORAGE_INQUIRY_RESPONSE_PERIPHERAL_TYPE);
560 storage -> ux_host_class_storage_lun_types[lun_index] =
561 storage -> ux_host_class_storage_media_type;
562 storage -> ux_host_class_storage_lun_removable_media_flags[lun_index] =
563 *(inquiry_response +
564 UX_HOST_CLASS_STORAGE_INQUIRY_RESPONSE_REMOVABLE_MEDIA);
565
566 /* Free response buffer. */
567 _ux_utility_memory_free(inquiry_response);
568
569 /* Set default sector size. */
570 switch(storage -> ux_host_class_storage_media_type)
571 {
572 case UX_HOST_CLASS_STORAGE_MEDIA_FAT_DISK:
573 case UX_HOST_CLASS_STORAGE_MEDIA_IOMEGA_CLICK:
574 storage -> ux_host_class_storage_sector_size = UX_HOST_CLASS_STORAGE_SECTOR_SIZE_FAT;
575 break;
576
577 case UX_HOST_CLASS_STORAGE_MEDIA_CDROM:
578 case UX_HOST_CLASS_STORAGE_MEDIA_OPTICAL_DISK:
579 storage -> ux_host_class_storage_sector_size = UX_HOST_CLASS_STORAGE_SECTOR_SIZE_OTHER;
580 break;
581
582 default:
583
584 /* Notify application so it knows to increase UX_MAX_HOST_LUN. */
585 _ux_system_error_handler(UX_SYSTEM_LEVEL_THREAD, UX_SYSTEM_CONTEXT_CLASS, UX_HOST_CLASS_MEDIA_NOT_SUPPORTED);
586
587 /* If trace is enabled, insert this event into the trace buffer. */
588 UX_TRACE_IN_LINE_INSERT(UX_TRACE_ERROR, UX_HOST_CLASS_MEDIA_NOT_SUPPORTED, storage, 0, 0, UX_TRACE_ERRORS, 0, 0)
589
590 return(UX_HOST_CLASS_MEDIA_NOT_SUPPORTED);
591 }
592 return(UX_SUCCESS);
593 }
_ux_host_class_storage_capacity_save(UX_HOST_CLASS_STORAGE * storage)594 static inline VOID _ux_host_class_storage_capacity_save(UX_HOST_CLASS_STORAGE *storage)
595 {
596 UCHAR *capacity_response = storage -> ux_host_class_storage_trans_data;
597
598 /* If capacity response OK, save last LBA and LB size. */
599 if (storage -> ux_host_class_storage_sense_code == 0)
600 {
601 storage -> ux_host_class_storage_last_sector_number =
602 _ux_utility_long_get_big_endian(capacity_response +
603 UX_HOST_CLASS_STORAGE_READ_CAPACITY_DATA_LBA);
604 storage -> ux_host_class_storage_sector_size =
605 _ux_utility_long_get_big_endian(capacity_response +
606 UX_HOST_CLASS_STORAGE_READ_CAPACITY_DATA_SECTOR_SIZE);
607
608 /* Media inserted to LUN. */
609 _ux_host_class_storage_lun_media_insert(storage);
610 }
611
612 /* Free allocated buffer. */
613 _ux_utility_memory_free(capacity_response);
614 }
_ux_host_class_storage_format_cap_save(UX_HOST_CLASS_STORAGE * storage)615 static inline VOID _ux_host_class_storage_format_cap_save(UX_HOST_CLASS_STORAGE *storage)
616 {
617 UCHAR *format_cap_response = storage -> ux_host_class_storage_trans_data;
618
619 /* There is nothing to save. */
620 /* Free allocated resource. */
621 _ux_utility_memory_free(format_cap_response);
622 }
623
_ux_host_class_storage_lun_scan(UX_HOST_CLASS_STORAGE * storage,ULONG do_unmount)624 static inline ULONG _ux_host_class_storage_lun_scan(UX_HOST_CLASS_STORAGE *storage,
625 ULONG do_unmount)
626 {
627 UX_HOST_CLASS *class_inst;
628 UX_HOST_CLASS_STORAGE_MEDIA *storage_media;
629 ULONG media_index;
630 ULONG n_found;
631
632 /* We may need to unmount this partition if it was mounted before.
633 To do so, we need to parse the existing media instance and find out
634 if this partition was already mounted. */
635 class_inst = storage -> ux_host_class_storage_class;
636 storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *) class_inst -> ux_host_class_media;
637
638 /* Scan all instances of media. */
639 for (media_index = 0, n_found = 0;
640 media_index < UX_HOST_CLASS_STORAGE_MAX_MEDIA;
641 storage_media++, media_index++)
642 {
643
644 /* Check storage instance and lun number. */
645 if (storage_media -> ux_host_class_storage_media_status != UX_USED)
646 continue;
647 if (storage_media -> ux_host_class_storage_media_storage != storage)
648 continue;
649 if (storage_media -> ux_host_class_storage_media_lun !=
650 storage -> ux_host_class_storage_lun)
651 continue;
652
653 /* Found mounted media. */
654 n_found ++;
655
656 /* If no unmount, just check next media instance. */
657 if (do_unmount == UX_FALSE)
658 continue;
659
660 /* Free the storage media. */
661 storage_media -> ux_host_class_storage_media_status = UX_UNUSED;
662
663 /* Invoke callback for media removal. */
664 if (_ux_system_host -> ux_system_host_change_function != UX_NULL)
665 {
666
667 /* Call system change function. */
668 _ux_system_host -> ux_system_host_change_function(UX_STORAGE_MEDIA_REMOVAL,
669 storage -> ux_host_class_storage_class,
670 (VOID *) storage_media);
671 }
672 }
673
674 /* Return number of medias found and unmounted. */
675 return(n_found);
676 }
677
_ux_host_class_storage_unit_ready_check(UX_HOST_CLASS_STORAGE * storage)678 static inline VOID _ux_host_class_storage_unit_ready_check(UX_HOST_CLASS_STORAGE *storage)
679 {
680 ULONG n;
681
682 /* The LUN is ready. */
683 if (storage -> ux_host_class_storage_sense_code == 0)
684 {
685
686 /* Check if LUN is mounted. */
687 n = _ux_host_class_storage_lun_scan(storage, UX_FALSE);
688
689 /* If LUN is already mounted, check next LUN. */
690 if (n > 0)
691 {
692
693 /* LUN is mounted, just check next LUN. */
694 storage -> ux_host_class_storage_state_state = UX_HOST_CLASS_STORAGE_STATE_NEXT_LUN;
695 return;
696 }
697
698 /* Next mounting steps : Inquiry() -> ReadFormatCapacity() -> mount(). */
699 storage -> ux_host_class_storage_state_state = UX_HOST_CLASS_STORAGE_STATE_INQUIRY;
700 return;
701 }
702
703 /* The LUN not ready cases have been done before. */
704
705 /* Just check next LUN. */
706 storage -> ux_host_class_storage_state_state = UX_HOST_CLASS_STORAGE_STATE_NEXT_LUN;
707 }
708
_ux_host_class_storage_lun_is_removable(UX_HOST_CLASS_STORAGE * storage)709 static inline UINT _ux_host_class_storage_lun_is_removable(UX_HOST_CLASS_STORAGE *storage)
710 {
711 UINT lun_index = storage -> ux_host_class_storage_lun;
712 UINT removable = storage -> ux_host_class_storage_lun_removable_media_flags[lun_index] &
713 UX_HOST_CLASS_STORAGE_MEDIA_REMOVABLE;
714 return(removable);
715 }
_ux_host_class_storage_lun_type_is_known(UX_HOST_CLASS_STORAGE * storage)716 static inline UINT _ux_host_class_storage_lun_type_is_known(UX_HOST_CLASS_STORAGE *storage)
717 {
718 UINT lun_index = storage -> ux_host_class_storage_lun;
719 UINT lun_type = storage -> ux_host_class_storage_lun_types[lun_index];
720 return((lun_type == UX_HOST_CLASS_STORAGE_MEDIA_FAT_DISK) ||
721 (lun_type == UX_HOST_CLASS_STORAGE_MEDIA_OPTICAL_DISK) ||
722 (lun_type == UX_HOST_CLASS_STORAGE_MEDIA_IOMEGA_CLICK));
723 }
724
_ux_host_class_storage_lun_media_insert(UX_HOST_CLASS_STORAGE * storage)725 static inline VOID _ux_host_class_storage_lun_media_insert(UX_HOST_CLASS_STORAGE *storage)
726 {
727 UX_HOST_CLASS *class_inst;
728 UX_HOST_CLASS_STORAGE_MEDIA *storage_media;
729 INT media_index;
730
731 /* Get class. */
732 class_inst = storage -> ux_host_class_storage_class;
733
734 /* Find a free media slot for inserted media. */
735 storage_media = (UX_HOST_CLASS_STORAGE_MEDIA *) class_inst -> ux_host_class_media;
736 for (media_index = 0; media_index < UX_HOST_CLASS_STORAGE_MAX_MEDIA;
737 storage_media ++, media_index ++)
738 {
739
740 /* Skip used storage media slots. */
741 if (storage_media -> ux_host_class_storage_media_status != UX_USED)
742 {
743
744 /* Use this free storage media slot. */
745 storage_media -> ux_host_class_storage_media_status = UX_USED;
746 storage_media -> ux_host_class_storage_media_storage = storage;
747
748 /* Save media information. */
749 storage_media -> ux_host_class_storage_media_lun = (UCHAR)storage -> ux_host_class_storage_lun;
750 storage_media -> ux_host_class_storage_media_sector_size = (USHORT)storage -> ux_host_class_storage_sector_size;
751 storage_media -> ux_host_class_storage_media_number_sectors = storage -> ux_host_class_storage_last_sector_number + 1;
752
753 /* Invoke callback for media insertion. */
754 if (_ux_system_host -> ux_system_host_change_function != UX_NULL)
755 {
756
757 /* Call system change function. */
758 /* In standalone mode, no state running (read/write) expected in callback. */
759 _ux_system_host -> ux_system_host_change_function(UX_STORAGE_MEDIA_INSERTION,
760 storage -> ux_host_class_storage_class, (VOID *) storage_media);
761 }
762
763 /* Media saved OK. */
764 return;
765 }
766 }
767
768 /* No free slot. */
769 return;
770 }
771
_ux_host_class_storage_transport_sense_check(UX_HOST_CLASS_STORAGE * storage)772 static inline UINT _ux_host_class_storage_transport_sense_check(UX_HOST_CLASS_STORAGE *storage)
773 {
774 ULONG sense_key;
775
776 if (storage -> ux_host_class_storage_sense_code == 0)
777 return(UX_FALSE);
778
779 sense_key = UX_HOST_CLASS_STORAGE_SENSE_KEY(storage -> ux_host_class_storage_sense_code);
780 switch(sense_key)
781 {
782 case UX_HOST_CLASS_STORAGE_SENSE_KEY_NOT_READY:
783
784 /* Remove the mounted LUN media. */
785 _ux_host_class_storage_lun_scan(storage, UX_TRUE);
786
787 /* The LUN is not ready, check next any way. */
788 storage -> ux_host_class_storage_state_state =
789 UX_HOST_CLASS_STORAGE_STATE_NEXT_LUN;
790
791 /* We have changed state. */
792 return(UX_TRUE);
793
794 case UX_HOST_CLASS_STORAGE_SENSE_KEY_UNIT_ATTENTION:
795
796 /* Remove the mounted LUN media. */
797 _ux_host_class_storage_lun_scan(storage, UX_TRUE);
798
799 /* Do immediate ready check again. */
800 storage -> ux_host_class_storage_state_state =
801 UX_HOST_CLASS_STORAGE_STATE_TEST_READY;
802
803 /* We have changed state. */
804 return(UX_TRUE);
805
806 case UX_HOST_CLASS_STORAGE_SENSE_KEY_DATA_PROTECT:
807
808 /* Fall through. */
809 default:
810
811 /* Nothing to do now. */
812 break;
813 }
814
815 /* State manated by others. */
816 return(UX_FALSE);
817 }
818 #endif
819