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