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 /**   Device Storage Class                                                */
19 /**                                                                       */
20 /**************************************************************************/
21 /**************************************************************************/
22 
23 #define UX_SOURCE_CODE
24 
25 
26 /* Include necessary system files.  */
27 
28 #include "ux_api.h"
29 #include "ux_device_class_storage.h"
30 #include "ux_device_stack.h"
31 
32 #if defined(UX_DEVICE_STANDALONE)
33 
34 /* Internal static inline implements.  */
35 
36 
37 static inline UINT _ux_device_class_storage_task_usb(UX_SLAVE_CLASS_STORAGE *storage);
38 
39 static inline UINT _ux_device_class_storage_reset_wait(UX_SLAVE_CLASS_STORAGE *storage);
40 static inline VOID _ux_device_class_storage_cbw_receive(UX_SLAVE_CLASS_STORAGE *storage);
41 static inline VOID _ux_device_class_storage_cbw_process(UX_SLAVE_CLASS_STORAGE *storage);
42 static inline VOID _ux_device_class_storage_cmd_process(UX_SLAVE_CLASS_STORAGE *storage, UCHAR *cbw);
43 static inline VOID _ux_device_class_storage_data_cases_check(UX_SLAVE_CLASS_STORAGE *storage);
44 static inline VOID _ux_device_class_storage_trans_start(UX_SLAVE_CLASS_STORAGE *storage);
45 static inline UINT _ux_device_class_storage_trans_wait(UX_SLAVE_CLASS_STORAGE *storage);
46 static inline VOID _ux_device_class_storage_trans_error(UX_SLAVE_CLASS_STORAGE *storage);
47 static inline UINT _ux_device_class_storage_data_next(UX_SLAVE_CLASS_STORAGE *storage);
48 
49 static inline VOID _ux_device_class_storage_halt_out(UX_SLAVE_CLASS_STORAGE *storage);
50 static inline VOID _ux_device_class_storage_halt_in(UX_SLAVE_CLASS_STORAGE *storage);
51 static inline VOID _ux_device_class_storage_halt_trans(UX_SLAVE_CLASS_STORAGE *storage);
52 
53 static inline VOID _ux_device_class_storage_task_disk(UX_SLAVE_CLASS_STORAGE *storage);
54 
55 static inline VOID _ux_device_class_storage_disk_start(UX_SLAVE_CLASS_STORAGE *storage);
56 static inline UINT _ux_device_class_storage_disk_wait(UX_SLAVE_CLASS_STORAGE *storage);
57 static inline VOID _ux_device_class_storage_disk_next(UX_SLAVE_CLASS_STORAGE *storage);
58 static inline VOID _ux_device_class_storage_disk_read_next(UX_SLAVE_CLASS_STORAGE *storage);
59 static inline VOID _ux_device_class_storage_disk_write_next(UX_SLAVE_CLASS_STORAGE *storage);
60 static inline VOID _ux_device_class_storage_disk_error(UX_SLAVE_CLASS_STORAGE *storage);
61 
62 
63 /**************************************************************************/
64 /*                                                                        */
65 /*  FUNCTION                                               RELEASE        */
66 /*                                                                        */
67 /*    _ux_device_class_storage_tasks_run                  PORTABLE C      */
68 /*                                                           6.2.0        */
69 /*  AUTHOR                                                                */
70 /*                                                                        */
71 /*    Chaoqiong Xiao, Microsoft Corporation                               */
72 /*                                                                        */
73 /*  DESCRIPTION                                                           */
74 /*                                                                        */
75 /*    This function runs tasks of the storage class.                      */
76 /*    E.g., CBW-DATA-CSW state machine.                                   */
77 /*                                                                        */
78 /*    It's for standalone mode.                                           */
79 /*                                                                        */
80 /*  INPUT                                                                 */
81 /*                                                                        */
82 /*    instance                              Address of storage instance   */
83 /*                                                                        */
84 /*  OUTPUT                                                                */
85 /*                                                                        */
86 /*    UX_STATE_RESET                        Tasks suspended               */
87 /*    UX_STATE_IDLE                         Activated but no task ran     */
88 /*    (others > UX_STATE_IDLE)              Tasks running                 */
89 /*                                                                        */
90 /*  CALLS                                                                 */
91 /*                                                                        */
92 /*    _ux_device_class_storage_format       Storage class format          */
93 /*    _ux_device_class_storage_inquiry      Storage class inquiry         */
94 /*    _ux_device_class_storage_mode_select  Mode select                   */
95 /*    _ux_device_class_storage_mode_sense   Mode sense                    */
96 /*    _ux_device_class_storage_prevent_allow_media_removal                */
97 /*                                          Prevent media removal         */
98 /*    _ux_device_class_storage_read         Read                          */
99 /*    _ux_device_class_storage_read_capacity                              */
100 /*                                          Read capacity                 */
101 /*    _ux_device_class_storage_read_format_capacity                       */
102 /*                                          Read format capacity          */
103 /*    _ux_device_class_storage_request_sense                              */
104 /*                                          Sense request                 */
105 /*    _ux_device_class_storage_start_stop   Start/Stop                    */
106 /*    _ux_device_class_storage_synchronize_cache                          */
107 /*                                          Synchronize cache             */
108 /*    _ux_device_class_storage_test_ready   Ready test                    */
109 /*    _ux_device_class_storage_verify       Verify                        */
110 /*    _ux_device_class_storage_write        Write                         */
111 /*    _ux_device_stack_endpoint_stall       Endpoint stall                */
112 /*    _ux_device_stack_interface_delete     Interface delete              */
113 /*    _ux_device_stack_transfer_request     Transfer request              */
114 /*    _ux_utility_long_get                  Get 32-bit value              */
115 /*    _ux_utility_memory_allocate           Allocate memory               */
116 /*    _ux_utility_semaphore_create          Create semaphore              */
117 /*    _ux_utility_thread_suspend            Suspend thread                */
118 /*                                                                        */
119 /*  CALLED BY                                                             */
120 /*                                                                        */
121 /*    Device Stack                                                        */
122 /*                                                                        */
123 /*  RELEASE HISTORY                                                       */
124 /*                                                                        */
125 /*    DATE              NAME                      DESCRIPTION             */
126 /*                                                                        */
127 /*  01-31-2022     Chaoqiong Xiao           Initial Version 6.1.10        */
128 /*  10-31-2022     Chaoqiong Xiao           Modified comment(s),          */
129 /*                                            improved internal logic,    */
130 /*                                            resulting in version 6.2.0  */
131 /*                                                                        */
132 /**************************************************************************/
_ux_device_class_storage_tasks_run(VOID * instance)133 UINT _ux_device_class_storage_tasks_run(VOID *instance)
134 {
135 
136 UX_SLAVE_CLASS_STORAGE      *storage;
137 UINT                        status;
138 
139 
140     /* Get storage instance.  */
141     storage = (UX_SLAVE_CLASS_STORAGE *) instance;
142 
143     /* Run USB and disk tasks.  */
144     status = _ux_device_class_storage_task_usb(storage);
145     _ux_device_class_storage_task_disk(storage);
146     return(status);
147 }
148 
_ux_device_class_storage_task_usb(UX_SLAVE_CLASS_STORAGE * storage)149 static inline UINT _ux_device_class_storage_task_usb(UX_SLAVE_CLASS_STORAGE *storage)
150 {
151 UX_SLAVE_DEVICE             *device;
152 UCHAR                       state;
153 UINT                        status;
154 INT                         immediate_state = UX_TRUE;
155 
156 
157     /* Get pointer to the device.  */
158     device = &_ux_system_slave -> ux_system_slave_device;
159 
160     /* Run states once.  */
161     while(immediate_state)
162     {
163 
164         /* General check for MSC ready.  */
165         if (device -> ux_slave_device_state != UX_DEVICE_CONFIGURED ||
166             storage -> ux_device_class_storage_ep_in == UX_NULL ||
167             storage -> ux_device_class_storage_ep_out == UX_NULL)
168         {
169             storage -> ux_device_class_storage_state = UX_STATE_RESET;
170             return(UX_STATE_EXIT);
171         }
172 
173         /* Get current state.  */
174         state = storage -> ux_device_class_storage_state;
175 
176         /* Handle different state.  */
177         switch(state)
178         {
179 
180         case UX_STATE_RESET: /* Initial, reset.  */
181             _ux_device_class_storage_cbw_receive(storage);
182 
183             /* Roll back to next state directly.  */
184             continue;
185 
186         case UX_DEVICE_CLASS_STORAGE_STATE_RESET:
187             _ux_device_class_storage_halt_in(storage);
188             _ux_device_class_storage_halt_out(storage);
189             storage -> ux_device_class_storage_state = UX_DEVICE_CLASS_STORAGE_STATE_RESET_WAIT;
190 
191             /* Fall through.  */
192         case UX_DEVICE_CLASS_STORAGE_STATE_RESET_WAIT: /* Wait reset recovery.  */
193             return _ux_device_class_storage_reset_wait(storage);
194 
195         case UX_DEVICE_CLASS_STORAGE_STATE_TRANS_START:
196             _ux_device_class_storage_trans_start(storage);
197 
198             /* Fall through.  */
199         case UX_DEVICE_CLASS_STORAGE_STATE_TRANS_WAIT:
200             status = _ux_device_class_storage_trans_wait(storage);
201 
202             /* Fatal case.  */
203             if (status < UX_STATE_ERROR)
204             {
205 
206                 /* USB idle.  */
207                 storage -> ux_device_class_storage_state = UX_DEVICE_CLASS_STORAGE_STATE_IDLE;
208 
209                 /* Disk notified with USB error.  */
210                 if (storage -> ux_device_class_storage_disk_state !=
211                     UX_DEVICE_CLASS_STORAGE_DISK_IDLE)
212                 {
213                     storage -> ux_device_class_storage_disk_state =
214                                         UX_DEVICE_CLASS_STORAGE_DISK_USB_ERROR;
215                 }
216                 return(UX_STATE_WAIT);
217             }
218 
219             /* Error case.  */
220             if (status == UX_STATE_ERROR)
221             {
222 
223                 /* Stall.  */
224                 _ux_device_class_storage_halt_trans(storage);
225 
226                 /* Disk notified with USB error.  */
227                 if (storage -> ux_device_class_storage_disk_state !=
228                     UX_DEVICE_CLASS_STORAGE_DISK_IDLE)
229                 {
230                     storage -> ux_device_class_storage_disk_state =
231                                         UX_DEVICE_CLASS_STORAGE_DISK_USB_ERROR;
232                 }
233 
234                 /* Update residue.  */
235                 storage -> ux_slave_class_storage_csw_residue =
236                         storage -> ux_slave_class_storage_host_length -
237                         storage -> ux_device_class_storage_data_count;
238 
239                 /* Update the REQUEST_SENSE codes.  */
240                 storage -> ux_slave_class_storage_lun[
241                     storage -> ux_slave_class_storage_cbw_lun].
242                         ux_slave_class_storage_request_sense_status =
243                             UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(0x02,0x54,0x00);
244 
245                 /* Issue CSW.  */
246                 _ux_device_class_storage_csw_send(storage,
247                                     storage -> ux_slave_class_storage_cbw_lun,
248                                     storage -> ux_device_class_storage_ep_in, 0);
249 
250                 return(UX_STATE_WAIT);
251             }
252 
253             /* Success case.  */
254             if (status == UX_STATE_NEXT)
255             {
256 
257                 /* Update data count.  */
258                 storage -> ux_device_class_storage_data_count +=
259                         storage -> ux_device_class_storage_transfer ->
260                                 ux_slave_transfer_request_actual_length;
261 
262                 storage -> ux_device_class_storage_state = UX_DEVICE_CLASS_STORAGE_STATE_TRANS_NEXT;
263             }
264 
265             /* Other cases, keep waiting.  */
266             return(UX_STATE_WAIT);
267 
268         case UX_DEVICE_CLASS_STORAGE_STATE_TRANS_NEXT:
269 
270             /* CBW received: -> CBW handle.  */
271             if (storage -> ux_device_class_storage_cmd_state == UX_DEVICE_CLASS_STORAGE_CMD_CBW)
272             {
273                 _ux_device_class_storage_cbw_process(storage);
274 
275                 /* Apply command in next call anyway.  */
276                 return(UX_STATE_WAIT);
277             }
278 
279             /* CSW sent: -> CSW done - CBW start.  */
280             if (storage -> ux_device_class_storage_cmd_state == UX_DEVICE_CLASS_STORAGE_CMD_CSW)
281             {
282                 if (storage -> ux_slave_class_storage_csw_status == UX_SLAVE_CLASS_STORAGE_CSW_PHASE_ERROR)
283                 {
284                     storage -> ux_device_class_storage_state = UX_DEVICE_CLASS_STORAGE_STATE_RESET;
285                 }
286                 else
287                 {
288                     _ux_device_class_storage_cbw_receive(storage);
289                 }
290                 continue;
291             }
292 
293             /* DATA done: -> process data.  */
294             return _ux_device_class_storage_data_next(storage);
295 
296         case UX_DEVICE_CLASS_STORAGE_STATE_DISK_ERROR:
297             _ux_device_class_storage_trans_error(storage);
298             continue;
299 
300         case UX_DEVICE_CLASS_STORAGE_STATE_IDLE: /* Nothing to do, fall through.  */
301 
302         case UX_DEVICE_CLASS_STORAGE_STATE_DISK_WAIT: /* Nothing to do, fall through.  */
303 
304         default: /* Do nothing.  */
305             break;
306         }
307 
308         /* Unhandled, just break the loop and do again by app call.  */
309         immediate_state = UX_FALSE;
310     }
311 
312     /* Unhandled state.  */
313     return(UX_STATE_EXIT);
314 }
315 
_ux_device_class_storage_cbw_receive(UX_SLAVE_CLASS_STORAGE * storage)316 static inline VOID _ux_device_class_storage_cbw_receive(UX_SLAVE_CLASS_STORAGE *storage)
317 {
318 UX_SLAVE_ENDPOINT   *endpoint;
319 UX_SLAVE_TRANSFER   *transfer;
320 ULONG               max_packet_size;
321 
322 
323     /* Command state: CBW.  */
324     storage -> ux_device_class_storage_cmd_state = UX_DEVICE_CLASS_STORAGE_CMD_CBW;
325     storage -> ux_device_class_storage_data_buffer = UX_NULL;
326 
327     /* Transfer state: START: OUT 31.  */
328     storage -> ux_device_class_storage_state = UX_DEVICE_CLASS_STORAGE_STATE_TRANS_START;
329 
330     endpoint = storage -> ux_device_class_storage_ep_out;
331     max_packet_size = endpoint -> ux_slave_endpoint_descriptor.wMaxPacketSize;
332     transfer = &endpoint -> ux_slave_endpoint_transfer_request;
333 
334     storage -> ux_device_class_storage_transfer = transfer;
335     storage -> ux_device_class_storage_data_length = max_packet_size;
336     storage -> ux_device_class_storage_data_count = 0;
337 }
338 
_ux_device_class_storage_cbw_process(UX_SLAVE_CLASS_STORAGE * storage)339 static inline VOID _ux_device_class_storage_cbw_process(UX_SLAVE_CLASS_STORAGE *storage)
340 {
341 UX_SLAVE_TRANSFER   *cbw_trans;
342 ULONG               cbw_length;
343 UCHAR               *cbw;
344 
345 
346     /* Get transfer.  */
347     cbw_trans = storage -> ux_device_class_storage_transfer;
348 
349     /* If CBW is stalled, just retry.  */
350     if (cbw_trans -> ux_slave_transfer_request_completion_code == UX_TRANSFER_STALLED)
351     {
352         _ux_device_class_storage_cbw_receive(storage);
353         return;
354     }
355 
356     /* Get CBW and length.  */
357     cbw_length = cbw_trans -> ux_slave_transfer_request_actual_length;
358     cbw = cbw_trans -> ux_slave_transfer_request_data_pointer;
359     if (cbw_length != UX_SLAVE_CLASS_STORAGE_CBW_LENGTH)
360     {
361         storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_PHASE_ERROR;
362     }
363     else
364     {
365         _ux_device_class_storage_cmd_process(storage, cbw);
366     }
367 
368     /* If still in CBW phase, there must be CBW structure error, wait reset.  */
369     if (storage -> ux_device_class_storage_cmd_state == UX_DEVICE_CLASS_STORAGE_CMD_CBW)
370     {
371         storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_PHASE_ERROR;
372         storage -> ux_device_class_storage_state = UX_DEVICE_CLASS_STORAGE_STATE_RESET;
373         return;
374     }
375 
376     /* If no error, error cases need check.  */
377     if (storage -> ux_slave_class_storage_csw_status == UX_SLAVE_CLASS_STORAGE_CSW_PASSED)
378     {
379         _ux_device_class_storage_data_cases_check(storage);
380     }
381 
382     /* Error, stall and send CSW.  */
383     if (storage -> ux_slave_class_storage_csw_status)
384     {
385 
386         /* There will not be any disk operation in this case.  */
387         storage -> ux_device_class_storage_disk_state = UX_DEVICE_CLASS_STORAGE_DISK_IDLE;
388 
389         if (storage -> ux_slave_class_storage_host_length &&
390             (storage -> ux_slave_class_storage_cbw_flags &
391                 UX_DEVICE_CLASS_STORAGE_CBW_FLAG_DIR) == 0)
392         {
393             _ux_device_class_storage_halt_out(storage);
394         }
395         else
396         {
397             _ux_device_class_storage_halt_in(storage);
398         }
399 
400         /* Still need CSW phase.  */
401         if (storage -> ux_device_class_storage_cmd_state != UX_DEVICE_CLASS_STORAGE_CMD_CBW)
402             storage -> ux_device_class_storage_cmd_state = UX_DEVICE_CLASS_STORAGE_CMD_ERR;
403     }
404 
405     /* No error, state not changed.  */
406 
407     /* Start CSW if there is no data.  */
408     if (storage -> ux_device_class_storage_cmd_state < UX_DEVICE_CLASS_STORAGE_CMD_WRITE)
409     {
410         _ux_device_class_storage_csw_send(storage,
411                                 storage -> ux_slave_class_storage_cbw_lun,
412                                 storage -> ux_device_class_storage_ep_in, 0);
413     }
414 }
_ux_device_class_storage_cmd_process(UX_SLAVE_CLASS_STORAGE * storage,UCHAR * cbw)415 static inline VOID _ux_device_class_storage_cmd_process(UX_SLAVE_CLASS_STORAGE *storage, UCHAR *cbw)
416 {
417 
418 UX_SLAVE_ENDPOINT   *endpoint_in, *endpoint_out;
419 ULONG               cbwcb_length;
420 UCHAR               *cbwcb;
421 UCHAR               lun;
422 
423 
424     /* Get bCBWLUN.  */
425     lun = *(cbw + UX_SLAVE_CLASS_STORAGE_CBW_LUN);
426     storage -> ux_slave_class_storage_cbw_lun = lun;
427 
428     /* Get bmCBWFlags.  */
429     storage -> ux_slave_class_storage_cbw_flags = *(cbw + UX_SLAVE_CLASS_STORAGE_CBW_FLAGS);
430 
431     /* Get dCBWTag.  */
432     storage -> ux_slave_class_storage_scsi_tag =
433                     _ux_utility_long_get(cbw + UX_SLAVE_CLASS_STORAGE_CBW_TAG);
434 
435     /* Get dCBWDataTransferLength: number of bytes to transfer.  */
436     storage -> ux_slave_class_storage_host_length = _ux_utility_long_get(cbw + UX_SLAVE_CLASS_STORAGE_CBW_DATA_LENGTH);
437 
438     /* Reset CSW status.  */
439     storage -> ux_slave_class_storage_csw_residue = 0;
440     storage -> ux_slave_class_storage_csw_status = 0;
441 
442     /* Check LUN error.  */
443     if (lun >= storage -> ux_slave_class_storage_number_lun)
444     {
445 
446         /* Phase error!  */
447         storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_PHASE_ERROR;
448         return;
449     }
450 
451     /* Check Signature error.  */
452     if (_ux_utility_long_get(cbw) != UX_SLAVE_CLASS_STORAGE_CBW_SIGNATURE_MASK)
453     {
454 
455         /* Phase error!  */
456         storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_PHASE_ERROR;
457         return;
458     }
459 
460     /* Get CBWCB length.  */
461     cbwcb_length = (ULONG)*(cbw + UX_SLAVE_CLASS_STORAGE_CBW_CB_LENGTH);
462 
463     /* Check CBWCB length.  */
464     if (cbwcb_length == 0)
465     {
466 
467         /* Phase error!  */
468         storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_PHASE_ERROR;
469         return;
470     }
471 
472     /* Get endpoints.  */
473     endpoint_in = storage -> ux_device_class_storage_ep_in;
474     endpoint_out = storage -> ux_device_class_storage_ep_out;
475 
476     /* By default set next command state to CSW (no DATA).  */
477     storage -> ux_device_class_storage_cmd_state = UX_DEVICE_CLASS_STORAGE_CMD_CSW;
478     storage -> ux_device_class_storage_device_length = 0;
479     storage -> ux_device_class_storage_data_length = 0;
480     storage -> ux_device_class_storage_data_count = 0;
481 
482     /* Reset disk access state.  */
483     storage -> ux_device_class_storage_disk_state = UX_DEVICE_CLASS_STORAGE_DISK_IDLE;
484 
485     /* Analyze the CBWCB command.  */
486     cbwcb = cbw + UX_SLAVE_CLASS_STORAGE_CBW_CB;
487     storage -> ux_device_class_storage_cmd = *cbwcb;
488     switch(storage -> ux_device_class_storage_cmd)
489     {
490 
491     case UX_SLAVE_CLASS_STORAGE_SCSI_TEST_READY:
492 
493         _ux_device_class_storage_test_ready(storage, lun, endpoint_in, endpoint_out, cbwcb);
494         break;
495 
496     case UX_SLAVE_CLASS_STORAGE_SCSI_REQUEST_SENSE:
497 
498         _ux_device_class_storage_request_sense(storage, lun, endpoint_in, endpoint_out, cbwcb);
499         break;
500 
501     case UX_SLAVE_CLASS_STORAGE_SCSI_FORMAT:
502 
503         _ux_device_class_storage_format(storage, lun, endpoint_in, endpoint_out, cbwcb);
504         break;
505 
506     case UX_SLAVE_CLASS_STORAGE_SCSI_INQUIRY:
507 
508         _ux_device_class_storage_inquiry(storage, lun, endpoint_in, endpoint_out, cbwcb);
509         break;
510 
511     case UX_SLAVE_CLASS_STORAGE_SCSI_START_STOP:
512 
513         _ux_device_class_storage_start_stop(storage, lun, endpoint_in, endpoint_out, cbwcb);
514         break;
515 
516     case UX_SLAVE_CLASS_STORAGE_SCSI_PREVENT_ALLOW_MEDIA_REMOVAL:
517 
518         _ux_device_class_storage_prevent_allow_media_removal(storage, lun, endpoint_in, endpoint_out, cbwcb);
519         break;
520 
521     case UX_SLAVE_CLASS_STORAGE_SCSI_READ_FORMAT_CAPACITY:
522 
523         _ux_device_class_storage_read_format_capacity(storage, lun, endpoint_in, endpoint_out, cbwcb);
524         break;
525 
526     case UX_SLAVE_CLASS_STORAGE_SCSI_READ_CAPACITY:
527 
528         _ux_device_class_storage_read_capacity(storage, lun, endpoint_in, endpoint_out, cbwcb);
529         break;
530 
531     case UX_SLAVE_CLASS_STORAGE_SCSI_VERIFY:
532 
533         _ux_device_class_storage_verify(storage, lun, endpoint_in, endpoint_out, cbwcb);
534         break;
535 
536     case UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SELECT:
537 
538         _ux_device_class_storage_mode_select(storage, lun, endpoint_in, endpoint_out, cbwcb);
539         break;
540 
541     case UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE_SHORT:
542     case UX_SLAVE_CLASS_STORAGE_SCSI_MODE_SENSE:
543 
544         _ux_device_class_storage_mode_sense(storage, lun, endpoint_in, endpoint_out, cbwcb);
545         break;
546 
547     case UX_SLAVE_CLASS_STORAGE_SCSI_READ32:
548 
549         _ux_device_class_storage_read(storage, lun, endpoint_in, endpoint_out, cbwcb,
550                                         UX_SLAVE_CLASS_STORAGE_SCSI_READ32);
551         break;
552 
553     case UX_SLAVE_CLASS_STORAGE_SCSI_READ16:
554 
555         _ux_device_class_storage_read(storage, lun, endpoint_in, endpoint_out, cbwcb,
556                                         UX_SLAVE_CLASS_STORAGE_SCSI_READ16);
557         break;
558 
559     case UX_SLAVE_CLASS_STORAGE_SCSI_WRITE32:
560 
561         _ux_device_class_storage_write(storage, lun, endpoint_in, endpoint_out, cbwcb,
562                                         UX_SLAVE_CLASS_STORAGE_SCSI_WRITE32);
563         break;
564 
565     case UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16:
566 
567         _ux_device_class_storage_write(storage, lun, endpoint_in, endpoint_out, cbwcb,
568                                         UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16);
569         break;
570 
571     case UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE:
572 
573         _ux_device_class_storage_synchronize_cache(storage, lun, endpoint_in, endpoint_out, cbwcb, *(cbwcb));
574         break;
575 
576 #ifdef UX_SLAVE_CLASS_STORAGE_INCLUDE_MMC
577     case UX_SLAVE_CLASS_STORAGE_SCSI_GET_STATUS_NOTIFICATION:
578 
579         _ux_device_class_storage_get_status_notification(storage, lun, endpoint_in, endpoint_out, cbwcb);
580         break;
581 
582     case UX_SLAVE_CLASS_STORAGE_SCSI_GET_CONFIGURATION:
583 
584         _ux_device_class_storage_get_configuration(storage, lun, endpoint_in, endpoint_out, cbwcb);
585         break;
586 
587     case UX_SLAVE_CLASS_STORAGE_SCSI_READ_DISK_INFORMATION:
588 
589         _ux_device_class_storage_read_disk_information(storage, lun, endpoint_in, endpoint_out, cbwcb);
590         break;
591 
592     case UX_SLAVE_CLASS_STORAGE_SCSI_REPORT_KEY:
593 
594         _ux_device_class_storage_report_key(storage, lun, endpoint_in, endpoint_out, cbwcb);
595         break;
596 
597     case UX_SLAVE_CLASS_STORAGE_SCSI_GET_PERFORMANCE:
598 
599         _ux_device_class_storage_get_performance(storage, lun, endpoint_in, endpoint_out, cbwcb);
600         break;
601 
602     case UX_SLAVE_CLASS_STORAGE_SCSI_READ_DVD_STRUCTURE:
603 
604         _ux_device_class_storage_read_dvd_structure(storage, lun, endpoint_in, endpoint_out, cbwcb);
605         break;
606 
607     case UX_SLAVE_CLASS_STORAGE_SCSI_READ_TOC:
608 
609         _ux_device_class_storage_read_toc(storage, lun, endpoint_in, endpoint_out, cbwcb);
610         break;
611 
612 #endif
613 
614     default:
615 
616         /* The command is unknown or unsupported, fail.  */
617         storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_FAILED;
618 
619         /* Initialize the request sense keys.  */
620         storage -> ux_slave_class_storage_lun[lun].ux_slave_class_storage_request_sense_status =
621             UX_DEVICE_CLASS_STORAGE_SENSE_STATUS(UX_SLAVE_CLASS_STORAGE_SENSE_KEY_ILLEGAL_REQUEST,
622                                                 UX_SLAVE_CLASS_STORAGE_ASC_KEY_INVALID_COMMAND,0);
623     }
624 }
_ux_device_class_storage_data_cases_check(UX_SLAVE_CLASS_STORAGE * storage)625 static inline VOID _ux_device_class_storage_data_cases_check(UX_SLAVE_CLASS_STORAGE *storage)
626 {
627 
628     /* ============ 13 cases check.  */
629     /* (1)Hn=Dn, (2)Hn<Di, (3)Hn<Do                          : CBW   */
630     /* (4)Hi>Dn, (5)Hi>Di, (6)Hi=Di, (7)Hi<Di, (8)Hi<>Do     : DATA  */
631     /* (9)Ho>Dn, (10)Ho<>Di, (11)Ho>Do, (12)Ho=Do, (13)Ho<Do : DATA  */
632     /* Hn -----------------------------  */
633     /* Case (1)      : Success/Error  */
634     /* Case (2)(3)   : STALL(IN/OUT), PhaseError.  */
635     /* Hi -------------------------------------------------  */
636     /* Case (6)      : Send DeviceLength, Success/Error.  */
637     /* Case (4)(5)   : Send DeviceLength, STALL(IN), Success/Error, dCSWDataResidue.  */
638     /* Case (7)(8)   : (Send HostLength), STALL(IN), PhaseError.  */
639     /* Ho -----------------------------------------------------------  */
640     /* Case (12)     : Receive, Success/Error.  */
641     /* Case (9)(11)  : STALL(OUT), Success/Error, dCSWDataResidue.  */
642     /* Case (10)(13) : STALL(OUT), PhaseError.  */
643     if (storage -> ux_slave_class_storage_cbw_flags & UX_DEVICE_CLASS_STORAGE_CBW_FLAG_DIR)
644     {
645 
646         /* Hi.  */
647         /* Case (2), (8).  */
648         if (storage -> ux_device_class_storage_cmd_state == UX_DEVICE_CLASS_STORAGE_CMD_WRITE ||
649             storage -> ux_slave_class_storage_host_length == 0)
650         {
651 
652             /* Phase error.  */
653             storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_PHASE_ERROR;
654             return;
655         }
656 
657         /* Case (7).  */
658         if (storage -> ux_slave_class_storage_host_length <
659             storage -> ux_device_class_storage_data_length)
660         {
661 
662             /* Part of data will be sent.  */
663             storage -> ux_device_class_storage_data_length =
664                 storage -> ux_slave_class_storage_host_length;
665         }
666 
667         /* Case (4), (5), (6), (7).  */
668         /* No touch for prepared transfer.  */
669     }
670     else
671     {
672 
673         /* Ho.  */
674         /* Case (3), (10), (13).  */
675         if (storage -> ux_slave_class_storage_host_length <
676                 storage -> ux_device_class_storage_device_length ||
677             storage -> ux_device_class_storage_cmd_state ==
678                 UX_DEVICE_CLASS_STORAGE_CMD_READ)
679         {
680 
681             /* Phase error.  */
682             storage -> ux_slave_class_storage_csw_status =
683                                     UX_SLAVE_CLASS_STORAGE_CSW_PHASE_ERROR;
684             return;
685         }
686 
687         /* Case (9), (11).  */
688         if (storage -> ux_slave_class_storage_host_length !=
689             storage -> ux_device_class_storage_device_length)
690         {
691 
692             /* Update dCSWDataResidue.  */
693             storage -> ux_slave_class_storage_csw_residue =
694                     storage -> ux_slave_class_storage_host_length -
695                         storage -> ux_device_class_storage_device_length;
696 
697             /* Failed.  */
698             storage -> ux_slave_class_storage_csw_status =
699                                         UX_SLAVE_CLASS_STORAGE_CSW_FAILED;
700             return;
701         }
702     }
703 }
_ux_device_class_storage_reset_wait(UX_SLAVE_CLASS_STORAGE * storage)704 static inline UINT _ux_device_class_storage_reset_wait(UX_SLAVE_CLASS_STORAGE *storage)
705 {
706 
707     /* Check PhaseError.  */
708     if ((UCHAR)storage -> ux_slave_class_storage_csw_status !=
709                                         UX_SLAVE_CLASS_STORAGE_CSW_PHASE_ERROR)
710     {
711 
712         /* Reset states.  */
713         storage -> ux_device_class_storage_state = UX_STATE_RESET;
714     }
715     else
716     {
717 
718         /* Keep CBW endpoints halted until status is reset.  */
719         storage -> ux_device_class_storage_state = UX_DEVICE_CLASS_STORAGE_STATE_RESET;
720     }
721 
722     return(UX_STATE_WAIT);
723 }
_ux_device_class_storage_data_next(UX_SLAVE_CLASS_STORAGE * storage)724 static inline UINT _ux_device_class_storage_data_next(UX_SLAVE_CLASS_STORAGE *storage)
725 {
726     switch(storage -> ux_device_class_storage_cmd)
727     {
728 
729     /* Disk read.  */
730     case UX_SLAVE_CLASS_STORAGE_SCSI_READ16:
731         /* Fall through.  */
732     case UX_SLAVE_CLASS_STORAGE_SCSI_READ32:
733 
734         /* Check if all data is done.  */
735         if (storage -> ux_device_class_storage_data_count >=
736             storage -> ux_device_class_storage_data_length)
737         {
738 
739             /* Stall if host expects more data.  */
740             if (storage -> ux_slave_class_storage_host_length >
741                 storage -> ux_device_class_storage_data_length)
742             {
743                 _ux_device_class_storage_halt_in(storage);
744 
745                 /* Update dCSWDataResidue.  */
746                 storage -> ux_slave_class_storage_csw_residue =
747                     storage -> ux_slave_class_storage_host_length -
748                     storage -> ux_device_class_storage_data_length;
749             }
750 
751             /* Set to fail if device expects more data.  */
752             if (storage -> ux_device_class_storage_device_length >
753                 storage -> ux_device_class_storage_data_count)
754             {
755 
756                 /* Update bCSWStatus.  */
757                 storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_FAILED;
758             }
759 
760             /* Issue CSW.  */
761             _ux_device_class_storage_csw_send(storage,
762                         storage -> ux_slave_class_storage_cbw_lun,
763                         storage -> ux_device_class_storage_ep_in,
764                         0 /* Not used.  */);
765         }
766         else
767         {
768 
769             /* Buffer sent, update buffer states.  */
770             storage -> ux_device_class_storage_buffer_state[storage -> ux_device_class_storage_buffer_usb] =
771                     UX_DEVICE_CLASS_STORAGE_BUFFER_EMPTY;
772             storage -> ux_device_class_storage_buffer_usb = !storage -> ux_device_class_storage_buffer_usb;
773             storage -> ux_device_class_storage_transfer -> ux_slave_transfer_request_data_pointer =
774                     storage -> ux_device_class_storage_buffer[storage -> ux_device_class_storage_buffer_usb];
775 
776             /* If disk read not started (waiting free buffer), start it.  */
777             if (storage -> ux_device_class_storage_disk_state == UX_DEVICE_CLASS_STORAGE_DISK_USB_WAIT)
778             {
779                 storage -> ux_device_class_storage_disk_state = UX_DEVICE_CLASS_STORAGE_DISK_OP_START;
780             }
781 
782             /* If there is buffer ready, send next.  */
783             if (storage -> ux_device_class_storage_buffer_state[storage->ux_device_class_storage_buffer_usb] ==
784                 UX_DEVICE_CLASS_STORAGE_BUFFER_FULL)
785             {
786                 storage -> ux_device_class_storage_state = UX_DEVICE_CLASS_STORAGE_STATE_TRANS_START;
787             }
788             else
789             {
790 
791                 /* Wait disk operation to fill buffer.  */
792                 storage -> ux_device_class_storage_state = UX_DEVICE_CLASS_STORAGE_STATE_DISK_WAIT;
793             }
794         }
795         break;
796 
797     /* Disk write.  */
798     case UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16:
799         /* Fall through.  */
800     case UX_SLAVE_CLASS_STORAGE_SCSI_WRITE32:
801 
802         /* Buffer received, update buffer state.  */
803         storage -> ux_device_class_storage_buffer_state[
804                         storage -> ux_device_class_storage_buffer_usb] =
805                                             UX_DEVICE_CLASS_STORAGE_BUFFER_FULL;
806 
807         /* If disk waiting data, Start disk write.  */
808         if (storage -> ux_device_class_storage_disk_state ==
809             UX_DEVICE_CLASS_STORAGE_DISK_USB_WAIT)
810         {
811             storage -> ux_device_class_storage_disk_state =
812                                     UX_DEVICE_CLASS_STORAGE_DISK_OP_START;
813         }
814 
815         /* Check if all data is done.  */
816         if (storage -> ux_device_class_storage_data_count >=
817             storage -> ux_device_class_storage_data_length)
818         {
819 
820             /* Wait disk operation done.  */
821             storage -> ux_device_class_storage_state = UX_DEVICE_CLASS_STORAGE_STATE_DISK_WAIT;
822         }
823         else
824         {
825 
826             /* Buffer received, update buffer states.  */
827             storage -> ux_device_class_storage_buffer_usb =
828                                 !storage -> ux_device_class_storage_buffer_usb;
829             storage -> ux_device_class_storage_transfer ->
830                 ux_slave_transfer_request_data_pointer =
831                             storage -> ux_device_class_storage_buffer[
832                                 storage -> ux_device_class_storage_buffer_usb];
833 
834             /* If there is buffer empty, start it.  */
835             if (storage -> ux_device_class_storage_buffer_state[
836                     storage -> ux_device_class_storage_buffer_usb] ==
837                 UX_DEVICE_CLASS_STORAGE_BUFFER_EMPTY)
838             {
839                 storage -> ux_device_class_storage_state =
840                                     UX_DEVICE_CLASS_STORAGE_STATE_TRANS_START;
841             }
842             else
843             {
844 
845                 /* No buffer available, wait disk operation done.  */
846                 storage -> ux_device_class_storage_state = UX_DEVICE_CLASS_STORAGE_STATE_DISK_WAIT;
847             }
848         }
849         break;
850 
851     /* No further data to send.  */
852     default:
853 
854         /* Stall if host expects more data.  */
855         if (storage -> ux_slave_class_storage_host_length >
856             storage -> ux_device_class_storage_data_count)
857         {
858             _ux_device_class_storage_halt_trans(storage);
859 
860             /* Update dCSWDataResidue.  */
861             storage -> ux_slave_class_storage_csw_residue =
862                 storage -> ux_slave_class_storage_host_length -
863                 storage -> ux_device_class_storage_data_length;
864         }
865 
866         /* Set to fail if device expects more data.  */
867         if (storage -> ux_device_class_storage_device_length >
868             storage -> ux_device_class_storage_data_count)
869         {
870 
871             /* Update bCSWStatus.  */
872             storage -> ux_slave_class_storage_csw_status = UX_SLAVE_CLASS_STORAGE_CSW_FAILED;
873         }
874 
875         /* Issue CSW.  */
876         _ux_device_class_storage_csw_send(storage,
877                     storage -> ux_slave_class_storage_cbw_lun,
878                     storage -> ux_device_class_storage_ep_in,
879                     0 /* Not used.  */);
880     }
881 
882     /* Next task state.  */
883     return(UX_STATE_NEXT);
884 }
_ux_device_class_storage_trans_start(UX_SLAVE_CLASS_STORAGE * storage)885 static inline VOID _ux_device_class_storage_trans_start(UX_SLAVE_CLASS_STORAGE *storage)
886 {
887 ULONG   remaining, host_length, device_length;
888 
889 
890     /* Get remaining transfer length.  */
891     remaining = storage -> ux_device_class_storage_data_length - storage -> ux_device_class_storage_data_count;
892 
893     /* Check if data exceeds buffer length.  */
894     if (remaining > UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE)
895     {
896 
897         /* Send full packets, without ZLP.  */
898         host_length = UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE;
899         device_length = UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE;
900     }
901     else
902     {
903 
904         /* Send packets sliced based on host length and device length.  */
905         device_length = remaining;
906 
907         /* USB CV test expecting stall but not ZLP, so host length is same, but not remaining.  */
908         host_length = remaining;
909     }
910 
911     /* Prepare data if necessary.  */
912     if (storage -> ux_device_class_storage_data_buffer && device_length &&
913         storage -> ux_device_class_storage_cmd_state == UX_DEVICE_CLASS_STORAGE_CMD_READ)
914     {
915         _ux_utility_memory_copy(storage -> ux_device_class_storage_transfer ->
916                                     ux_slave_transfer_request_data_pointer,
917                                 storage -> ux_device_class_storage_data_buffer +
918                                     storage -> ux_device_class_storage_data_count,
919                                 device_length); /* Use case of memcpy is verified. */
920     }
921 
922     /* Save host length and device length for task states.  */
923     storage -> ux_device_class_storage_trans_device_length = device_length;
924     storage -> ux_device_class_storage_trans_host_length = host_length;
925 
926     /* To TRANS_WAIT.  */
927     storage -> ux_device_class_storage_state = UX_DEVICE_CLASS_STORAGE_STATE_TRANS_WAIT;
928 
929     /* Reset transfer state.  */
930     UX_SLAVE_TRANSFER_STATE_RESET(storage -> ux_device_class_storage_transfer);
931 }
_ux_device_class_storage_trans_wait(UX_SLAVE_CLASS_STORAGE * storage)932 static inline UINT _ux_device_class_storage_trans_wait(UX_SLAVE_CLASS_STORAGE *storage)
933 {
934     return _ux_device_stack_transfer_run(storage -> ux_device_class_storage_transfer,
935                                         storage -> ux_device_class_storage_trans_device_length,
936                                         storage -> ux_device_class_storage_trans_host_length);
937 }
_ux_device_class_storage_trans_error(UX_SLAVE_CLASS_STORAGE * storage)938 static inline VOID _ux_device_class_storage_trans_error(UX_SLAVE_CLASS_STORAGE *storage)
939 {
940 
941     /* Abort USB operation if transfer not done.  */
942     if (storage -> ux_device_class_storage_data_count < storage -> ux_device_class_storage_data_length)
943     {
944         if (storage -> ux_slave_class_storage_cbw_flags & UX_DEVICE_CLASS_STORAGE_CBW_FLAG_IN)
945         {
946             _ux_device_class_storage_halt_in(storage);
947         }
948         else
949         {
950             _ux_device_class_storage_halt_out(storage);
951         }
952 
953         /* Update dCSWDataResidue.  */
954         storage -> ux_slave_class_storage_csw_residue =
955             storage -> ux_slave_class_storage_host_length -
956             storage -> ux_device_class_storage_data_count;
957     }
958     else
959     {
960         _ux_device_class_storage_halt_in(storage);
961     }
962 
963     /* Issue CSW.  */
964     _ux_device_class_storage_csw_send(storage,
965             storage -> ux_slave_class_storage_cbw_lun,
966             storage -> ux_device_class_storage_ep_in,
967             0 /* Not used.  */);
968 }
_ux_device_class_storage_halt_out(UX_SLAVE_CLASS_STORAGE * storage)969 static inline VOID _ux_device_class_storage_halt_out(UX_SLAVE_CLASS_STORAGE *storage)
970 {
971     _ux_device_stack_endpoint_stall(storage -> ux_device_class_storage_ep_out);
972 }
_ux_device_class_storage_halt_in(UX_SLAVE_CLASS_STORAGE * storage)973 static inline VOID _ux_device_class_storage_halt_in(UX_SLAVE_CLASS_STORAGE *storage)
974 {
975     _ux_device_stack_endpoint_stall(storage -> ux_device_class_storage_ep_in);
976 }
_ux_device_class_storage_halt_trans(UX_SLAVE_CLASS_STORAGE * storage)977 static inline VOID _ux_device_class_storage_halt_trans(UX_SLAVE_CLASS_STORAGE *storage)
978 {
979 UX_SLAVE_TRANSFER *trans = storage -> ux_device_class_storage_transfer;
980 UX_SLAVE_ENDPOINT *endp = trans -> ux_slave_transfer_request_endpoint;
981     _ux_device_stack_endpoint_stall(endp);
982 }
983 
984 
_ux_device_class_storage_task_disk(UX_SLAVE_CLASS_STORAGE * storage)985 static inline VOID _ux_device_class_storage_task_disk(UX_SLAVE_CLASS_STORAGE *storage)
986 {
987 UCHAR                   state = storage -> ux_device_class_storage_disk_state;
988 UINT                    status;
989 INT                     immediate_state = UX_TRUE;
990 
991     /* Run states once.  */
992     while(immediate_state)
993     {
994 
995         /* Update state.  */
996         state = storage -> ux_device_class_storage_disk_state;
997         switch(state)
998         {
999 
1000         case UX_DEVICE_CLASS_STORAGE_DISK_OP_START:
1001             _ux_device_class_storage_disk_start(storage);
1002             storage -> ux_device_class_storage_disk_state =
1003                                         UX_DEVICE_CLASS_STORAGE_DISK_OP_WAIT;
1004 
1005             /* Fall through.  */
1006         case UX_DEVICE_CLASS_STORAGE_DISK_OP_WAIT:
1007             status = _ux_device_class_storage_disk_wait(storage);
1008 
1009             /* Error case.  */
1010             if (status < UX_STATE_NEXT)
1011             {
1012 
1013                 /* Disk idle.  */
1014                 storage -> ux_device_class_storage_disk_state = UX_DEVICE_CLASS_STORAGE_DISK_IDLE;
1015 
1016                 /* USB notified with disk error.  */
1017                 storage -> ux_device_class_storage_state = UX_DEVICE_CLASS_STORAGE_STATE_DISK_ERROR;
1018             }
1019 
1020             /* Success case.  */
1021             if (status == UX_STATE_NEXT)
1022             {
1023 
1024                 storage -> ux_device_class_storage_disk_state = UX_DEVICE_CLASS_STORAGE_DISK_OP_NEXT;
1025             }
1026 
1027             /* Other cases, keep waiting.  */
1028             return;
1029 
1030         case UX_DEVICE_CLASS_STORAGE_DISK_OP_NEXT:
1031             _ux_device_class_storage_disk_next(storage);
1032             return;
1033 
1034         case UX_DEVICE_CLASS_STORAGE_DISK_USB_ERROR:
1035             _ux_device_class_storage_disk_error(storage);
1036             break;
1037 
1038         case UX_DEVICE_CLASS_STORAGE_DISK_USB_WAIT: /* Nothing to do, fall through.  */
1039 
1040         case UX_DEVICE_CLASS_STORAGE_DISK_IDLE: /* Nothing to do, fall through.  */
1041 
1042         default: /* Nothing to do.  */
1043             break;
1044         }
1045 
1046         /* Task run once, break the loop.  */
1047         immediate_state = UX_FALSE;
1048     }
1049 }
_ux_device_class_storage_disk_start(UX_SLAVE_CLASS_STORAGE * storage)1050 static inline VOID _ux_device_class_storage_disk_start(UX_SLAVE_CLASS_STORAGE *storage)
1051 {
1052 ULONG block_size;
1053 ULONG max_n_blocks;
1054 
1055 
1056     if (storage -> ux_device_class_storage_cmd == UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE)
1057     {
1058 
1059         /* All things sync in one call.  */
1060         storage -> ux_device_class_storage_disk_n_lb = storage -> ux_device_class_storage_cmd_n_lb;
1061         return;
1062     }
1063 
1064     /* Read/write, split the operation by buffer sizes.  */
1065 
1066     /* Max blocks for one buffer.  */
1067     block_size = storage -> ux_slave_class_storage_lun[storage -> ux_slave_class_storage_cbw_lun].
1068                                                         ux_slave_class_storage_media_block_length;
1069     if (block_size == 0)
1070         UX_ASSERT(UX_FALSE);
1071     max_n_blocks = UX_SLAVE_CLASS_STORAGE_BUFFER_SIZE / block_size;
1072 
1073     /* Prepare next disk read.  */
1074     if (storage -> ux_device_class_storage_cmd_n_lb > max_n_blocks)
1075     {
1076         storage -> ux_device_class_storage_disk_n_lb = max_n_blocks;
1077     }
1078     else
1079     {
1080         storage -> ux_device_class_storage_disk_n_lb = storage -> ux_device_class_storage_cmd_n_lb;
1081     }
1082 }
_ux_device_class_storage_disk_wait(UX_SLAVE_CLASS_STORAGE * storage)1083 static inline UINT _ux_device_class_storage_disk_wait(UX_SLAVE_CLASS_STORAGE *storage)
1084 {
1085     switch (storage -> ux_device_class_storage_cmd)
1086     {
1087     case UX_SLAVE_CLASS_STORAGE_SCSI_READ16:
1088     case UX_SLAVE_CLASS_STORAGE_SCSI_READ32:
1089         return storage -> ux_slave_class_storage_lun[storage -> ux_slave_class_storage_cbw_lun].
1090                         ux_slave_class_storage_media_read(storage,
1091                             storage -> ux_slave_class_storage_cbw_lun,
1092                             storage -> ux_device_class_storage_buffer[
1093                                 storage -> ux_device_class_storage_buffer_disk],
1094                             storage -> ux_device_class_storage_disk_n_lb,
1095                             storage -> ux_device_class_storage_cmd_lba,
1096                             &storage -> ux_device_class_storage_media_status);
1097 
1098     case UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16:
1099     case UX_SLAVE_CLASS_STORAGE_SCSI_WRITE32:
1100         return storage -> ux_slave_class_storage_lun[storage -> ux_slave_class_storage_cbw_lun].
1101                         ux_slave_class_storage_media_write(storage,
1102                             storage -> ux_slave_class_storage_cbw_lun,
1103                             storage -> ux_device_class_storage_buffer[
1104                                 storage -> ux_device_class_storage_buffer_disk],
1105                             storage -> ux_device_class_storage_disk_n_lb,
1106                             storage -> ux_device_class_storage_cmd_lba,
1107                             &storage -> ux_device_class_storage_media_status);
1108 
1109     case UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE:
1110         return storage -> ux_slave_class_storage_lun[storage -> ux_slave_class_storage_cbw_lun].
1111                         ux_slave_class_storage_media_flush(storage,
1112                             storage -> ux_slave_class_storage_cbw_lun,
1113                             storage -> ux_device_class_storage_disk_n_lb,
1114                             storage -> ux_device_class_storage_cmd_lba,
1115                             &storage -> ux_device_class_storage_media_status);
1116 
1117     case UX_SLAVE_CLASS_STORAGE_SCSI_VERIFY: /* No nothing for now.  */
1118     default:
1119         break;
1120     }
1121     return(UX_STATE_NEXT);
1122 }
_ux_device_class_storage_disk_next(UX_SLAVE_CLASS_STORAGE * storage)1123 static inline VOID _ux_device_class_storage_disk_next(UX_SLAVE_CLASS_STORAGE *storage)
1124 {
1125 
1126     /* Update disk operation status.  */
1127     storage -> ux_device_class_storage_cmd_lba += storage -> ux_device_class_storage_disk_n_lb;
1128     storage -> ux_device_class_storage_cmd_n_lb -= storage -> ux_device_class_storage_disk_n_lb;
1129 
1130     /* Next check is different for read/write.  */
1131     switch (storage -> ux_device_class_storage_cmd)
1132     {
1133     case UX_SLAVE_CLASS_STORAGE_SCSI_READ16:
1134     case UX_SLAVE_CLASS_STORAGE_SCSI_READ32:
1135         _ux_device_class_storage_disk_read_next(storage);
1136         return;
1137 
1138     case UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16:
1139     case UX_SLAVE_CLASS_STORAGE_SCSI_WRITE32:
1140         _ux_device_class_storage_disk_write_next(storage);
1141         return;
1142 
1143     case UX_SLAVE_CLASS_STORAGE_SCSI_SYNCHRONIZE_CACHE:
1144 
1145         /* Disk is idle now.  */
1146         storage -> ux_device_class_storage_disk_state = UX_DEVICE_CLASS_STORAGE_DISK_IDLE;
1147 
1148         /* Send CSW if not sent yet.  */
1149         if (storage -> ux_device_class_storage_state == UX_DEVICE_CLASS_STORAGE_STATE_DISK_WAIT)
1150         {
1151             _ux_device_class_storage_csw_send(storage,
1152                     storage -> ux_slave_class_storage_cbw_lun,
1153                     storage -> ux_device_class_storage_ep_in,
1154                     0 /* Not used.  */);
1155         }
1156         return;
1157 
1158     default:
1159         storage -> ux_device_class_storage_disk_state = UX_DEVICE_CLASS_STORAGE_DISK_IDLE;
1160         break;
1161     }
1162 }
_ux_device_class_storage_disk_read_next(UX_SLAVE_CLASS_STORAGE * storage)1163 static inline VOID _ux_device_class_storage_disk_read_next(UX_SLAVE_CLASS_STORAGE *storage)
1164 {
1165 
1166     /* Update buffer state : full.  */
1167     storage -> ux_device_class_storage_buffer_state[
1168         storage -> ux_device_class_storage_buffer_disk] =
1169                                     UX_DEVICE_CLASS_STORAGE_BUFFER_FULL;
1170 
1171     /* Check if all disk operation is done.  */
1172     if (storage -> ux_device_class_storage_cmd_n_lb == 0)
1173     {
1174         storage -> ux_device_class_storage_disk_state = UX_DEVICE_CLASS_STORAGE_DISK_IDLE;
1175     }
1176     else
1177     {
1178 
1179         /* Update buffer index.  */
1180         storage -> ux_device_class_storage_buffer_disk =
1181                             !storage -> ux_device_class_storage_buffer_disk;
1182 
1183         /* If buffer is free, start next read.  */
1184         if (UX_DEVICE_CLASS_STORAGE_BUFFER_EMPTY ==
1185             storage -> ux_device_class_storage_buffer_state[
1186                             storage -> ux_device_class_storage_buffer_disk])
1187         {
1188 
1189             /* Start next read.  */
1190             storage -> ux_device_class_storage_disk_state = UX_DEVICE_CLASS_STORAGE_DISK_OP_START;
1191         }
1192         else
1193         {
1194 
1195             /* Wait until buffer sent by USB.  */
1196             storage -> ux_device_class_storage_disk_state = UX_DEVICE_CLASS_STORAGE_DISK_USB_WAIT;
1197         }
1198     }
1199 
1200     /* Start USB transfer.  */
1201     if (storage -> ux_device_class_storage_state ==
1202             UX_DEVICE_CLASS_STORAGE_STATE_DISK_WAIT &&
1203         UX_DEVICE_CLASS_STORAGE_BUFFER_FULL ==
1204         storage -> ux_device_class_storage_buffer_state[
1205             storage -> ux_device_class_storage_buffer_usb])
1206     {
1207         storage -> ux_device_class_storage_state =
1208                                 UX_DEVICE_CLASS_STORAGE_STATE_TRANS_START;
1209     }
1210 }
_ux_device_class_storage_disk_write_next(UX_SLAVE_CLASS_STORAGE * storage)1211 static inline VOID _ux_device_class_storage_disk_write_next(UX_SLAVE_CLASS_STORAGE *storage)
1212 {
1213 
1214     /* Update buffer state : empty.  */
1215     storage -> ux_device_class_storage_buffer_state[
1216             storage -> ux_device_class_storage_buffer_disk] =
1217                                     UX_DEVICE_CLASS_STORAGE_BUFFER_EMPTY;
1218 
1219     /* Check if all disk operation is done.  */
1220     if (storage -> ux_device_class_storage_cmd_n_lb == 0)
1221     {
1222 
1223         /* Disk is idle now.  */
1224         storage -> ux_device_class_storage_disk_state = UX_DEVICE_CLASS_STORAGE_DISK_IDLE;
1225 
1226         /* Issue CSW.  */
1227         _ux_device_class_storage_csw_send(storage,
1228                     storage -> ux_slave_class_storage_cbw_lun,
1229                     storage -> ux_device_class_storage_ep_in,
1230                     0 /* Not used.  */);
1231     }
1232     else
1233     {
1234 
1235         /* Update buffer index.  */
1236         storage -> ux_device_class_storage_buffer_disk =
1237                              !storage -> ux_device_class_storage_buffer_disk;
1238 
1239         /* If buffer is full, start next write.  */
1240         if (UX_DEVICE_CLASS_STORAGE_BUFFER_FULL ==
1241             storage -> ux_device_class_storage_buffer_state[
1242                 storage -> ux_device_class_storage_buffer_disk])
1243         {
1244 
1245             /* Start next write.  */
1246             storage -> ux_device_class_storage_disk_state = UX_DEVICE_CLASS_STORAGE_DISK_OP_START;
1247         }
1248         else
1249         {
1250 
1251             /* Wait until buffer filled by USB.  */
1252             storage -> ux_device_class_storage_disk_state = UX_DEVICE_CLASS_STORAGE_DISK_USB_WAIT;
1253         }
1254 
1255         /* Start USB transfer.  */
1256         if (storage -> ux_device_class_storage_state ==
1257                 UX_DEVICE_CLASS_STORAGE_STATE_DISK_WAIT &&
1258             UX_DEVICE_CLASS_STORAGE_BUFFER_EMPTY ==
1259             storage -> ux_device_class_storage_buffer_state[
1260                 storage -> ux_device_class_storage_buffer_usb])
1261         {
1262             storage -> ux_device_class_storage_state =
1263                                     UX_DEVICE_CLASS_STORAGE_STATE_TRANS_START;
1264         }
1265     }
1266 }
_ux_device_class_storage_disk_error(UX_SLAVE_CLASS_STORAGE * storage)1267 static inline VOID _ux_device_class_storage_disk_error(UX_SLAVE_CLASS_STORAGE *storage)
1268 {
1269     /* Abort disk operation: read or write with NULL!  */
1270     switch (storage -> ux_device_class_storage_cmd)
1271     {
1272     case UX_SLAVE_CLASS_STORAGE_SCSI_READ16:
1273     case UX_SLAVE_CLASS_STORAGE_SCSI_READ32:
1274         storage -> ux_slave_class_storage_lun[storage -> ux_slave_class_storage_cbw_lun].
1275                 ux_slave_class_storage_media_read(storage,
1276                         storage -> ux_slave_class_storage_cbw_lun, UX_NULL, 0, 0, UX_NULL);
1277         break;
1278     case UX_SLAVE_CLASS_STORAGE_SCSI_WRITE16:
1279     case UX_SLAVE_CLASS_STORAGE_SCSI_WRITE32:
1280         storage -> ux_slave_class_storage_lun[storage -> ux_slave_class_storage_cbw_lun].
1281                 ux_slave_class_storage_media_write(storage,
1282                         storage -> ux_slave_class_storage_cbw_lun, UX_NULL, 0, 0, UX_NULL);
1283         break;
1284     default:
1285         break;
1286     }
1287 
1288     /* Change disk state to IDLE.  */
1289     storage -> ux_device_class_storage_disk_state = UX_DEVICE_CLASS_STORAGE_DISK_IDLE;
1290 }
1291 
1292 #endif
1293