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