Fix memory corruption in Host mode Mass Storage Class driver.
[pub/USBasp.git] / LUFA / Drivers / USB / Class / Host / MassStorage.c
1 /*
2 LUFA Library
3 Copyright (C) Dean Camera, 2009.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.fourwalledcubicle.com
7 */
8
9 /*
10 Copyright 2009 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, and distribute this software
13 and its documentation for any purpose and without fee is hereby
14 granted, provided that the above copyright notice appear in all
15 copies and that both that the copyright notice and this
16 permission notice and warranty disclaimer appear in supporting
17 documentation, and that the name of the author not be used in
18 advertising or publicity pertaining to distribution of the
19 software without specific, written prior permission.
20
21 The author disclaim all warranties with regard to this
22 software, including all implied warranties of merchantability
23 and fitness. In no event shall the author be liable for any
24 special, indirect or consequential damages or any damages
25 whatsoever resulting from loss of use, data or profits, whether
26 in an action of contract, negligence or other tortious action,
27 arising out of or in connection with the use or performance of
28 this software.
29 */
30
31 #include "../../HighLevel/USBMode.h"
32 #if defined(USB_CAN_BE_HOST)
33
34 #define INCLUDE_FROM_MS_CLASS_HOST_C
35 #include "MassStorage.h"
36
37 uint8_t MS_Host_ConfigurePipes(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint16_t ConfigDescriptorLength,
38 uint8_t* DeviceConfigDescriptor)
39 {
40 uint8_t FoundEndpoints = 0;
41
42 memset(&MSInterfaceInfo->State, 0x00, sizeof(MSInterfaceInfo->State));
43
44 if (DESCRIPTOR_TYPE(DeviceConfigDescriptor) != DTYPE_Configuration)
45 return MS_ENUMERROR_InvalidConfigDescriptor;
46
47 if (USB_GetNextDescriptorComp(&ConfigDescriptorLength, &DeviceConfigDescriptor,
48 DComp_NextMassStorageInterface) != DESCRIPTOR_SEARCH_COMP_Found)
49 {
50 return MS_ENUMERROR_NoMSInterfaceFound;
51 }
52
53 MSInterfaceInfo->State.InterfaceNumber =
54 #if defined(USE_NONSTANDARD_DESCRIPTOR_NAMES)
55 DESCRIPTOR_PCAST(DeviceConfigDescriptor, USB_Descriptor_Interface_t)->InterfaceNumber;
56 #else
57 DESCRIPTOR_PCAST(DeviceConfigDescriptor, USB_Descriptor_Interface_t)->bInterfaceNumber;
58 #endif
59
60 while (FoundEndpoints != (MS_FOUND_DATAPIPE_IN | MS_FOUND_DATAPIPE_OUT))
61 {
62 if (USB_GetNextDescriptorComp(&ConfigDescriptorLength, &DeviceConfigDescriptor,
63 DComp_NextInterfaceBulkDataEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
64 {
65 return MS_ENUMERROR_EndpointsNotFound;
66 }
67
68 USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(DeviceConfigDescriptor, USB_Descriptor_Endpoint_t);
69
70 if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN)
71 {
72 Pipe_ConfigurePipe(MSInterfaceInfo->Config.DataINPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_IN,
73 EndpointData->EndpointAddress, EndpointData->EndpointSize,
74 PIPE_BANK_DOUBLE);
75 MSInterfaceInfo->State.DataINPipeSize = EndpointData->EndpointSize;
76
77 FoundEndpoints |= MS_FOUND_DATAPIPE_IN;
78 }
79 else
80 {
81 Pipe_ConfigurePipe(MSInterfaceInfo->Config.DataOUTPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_OUT,
82 EndpointData->EndpointAddress, EndpointData->EndpointSize,
83 PIPE_BANK_DOUBLE);
84 MSInterfaceInfo->State.DataOUTPipeSize = EndpointData->EndpointSize;
85
86 FoundEndpoints |= MS_FOUND_DATAPIPE_OUT;
87 }
88 }
89
90 MSInterfaceInfo->State.Active = true;
91 return MS_ENUMERROR_NoError;
92 }
93
94 static uint8_t DComp_NextMassStorageInterface(void* CurrentDescriptor)
95 {
96 if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
97 {
98 if ((DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Interface_t).Class == MASS_STORE_CLASS) &&
99 (DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Interface_t).SubClass == MASS_STORE_SUBCLASS) &&
100 (DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Interface_t).Protocol == MASS_STORE_PROTOCOL))
101 {
102 return DESCRIPTOR_SEARCH_Found;
103 }
104 }
105
106 return DESCRIPTOR_SEARCH_NotFound;
107 }
108
109 static uint8_t DComp_NextInterfaceBulkDataEndpoint(void* CurrentDescriptor)
110 {
111 if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Endpoint)
112 {
113 uint8_t EndpointType = (DESCRIPTOR_CAST(CurrentDescriptor,
114 USB_Descriptor_Endpoint_t).Attributes & EP_TYPE_MASK);
115
116 if (EndpointType == EP_TYPE_BULK)
117 return DESCRIPTOR_SEARCH_Found;
118 }
119 else if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
120 {
121 return DESCRIPTOR_SEARCH_Fail;
122 }
123
124 return DESCRIPTOR_SEARCH_NotFound;
125 }
126
127 void MS_Host_USBTask(USB_ClassInfo_MS_Host_t* MSInterfaceInfo)
128 {
129
130 }
131
132 static uint8_t MS_Host_SendCommand(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, MS_CommandBlockWrapper_t* SCSICommandBlock)
133 {
134 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
135
136 if (++MSInterfaceInfo->State.TransactionTag == 0xFFFFFFFF)
137 MSInterfaceInfo->State.TransactionTag = 1;
138
139 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
140 Pipe_Unfreeze();
141
142 if ((ErrorCode = Pipe_Write_Stream_LE(SCSICommandBlock, sizeof(MS_CommandBlockWrapper_t))) != PIPE_RWSTREAM_NoError)
143 return ErrorCode;
144
145 Pipe_ClearOUT();
146 while(!(Pipe_IsOUTReady()));
147
148 Pipe_Freeze();
149
150 return PIPE_RWSTREAM_NoError;
151 }
152
153 static uint8_t MS_Host_WaitForDataReceived(USB_ClassInfo_MS_Host_t* MSInterfaceInfo)
154 {
155 uint16_t TimeoutMSRem = COMMAND_DATA_TIMEOUT_MS;
156
157 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
158 Pipe_Unfreeze();
159
160 while (!(Pipe_IsINReceived()))
161 {
162 if (USB_INT_HasOccurred(USB_INT_HSOFI))
163 {
164 USB_INT_Clear(USB_INT_HSOFI);
165 TimeoutMSRem--;
166
167 if (!(TimeoutMSRem))
168 return PIPE_RWSTREAM_Timeout;
169 }
170
171 Pipe_Freeze();
172 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
173 Pipe_Unfreeze();
174
175 if (Pipe_IsStalled())
176 {
177 USB_Host_ClearPipeStall(MSInterfaceInfo->Config.DataOUTPipeNumber);
178
179 return PIPE_RWSTREAM_PipeStalled;
180 }
181
182 Pipe_Freeze();
183 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
184 Pipe_Unfreeze();
185
186 if (Pipe_IsStalled())
187 {
188 USB_Host_ClearPipeStall(MSInterfaceInfo->Config.DataINPipeNumber);
189
190 return PIPE_RWSTREAM_PipeStalled;
191 }
192
193 if (USB_HostState == HOST_STATE_Unattached)
194 return PIPE_RWSTREAM_DeviceDisconnected;
195 };
196
197 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
198 Pipe_Freeze();
199
200 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
201 Pipe_Freeze();
202
203 return PIPE_RWSTREAM_NoError;
204 }
205
206 static uint8_t MS_Host_SendReceiveData(USB_ClassInfo_MS_Host_t* MSInterfaceInfo,
207 MS_CommandBlockWrapper_t* SCSICommandBlock, void* BufferPtr)
208 {
209 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
210 uint16_t BytesRem = SCSICommandBlock->DataTransferLength;
211
212 if (SCSICommandBlock->Flags & COMMAND_DIRECTION_DATA_IN)
213 {
214 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
215 Pipe_Unfreeze();
216
217 if ((ErrorCode = Pipe_Read_Stream_LE(BufferPtr, BytesRem)) != PIPE_RWSTREAM_NoError)
218 return ErrorCode;
219
220 Pipe_ClearIN();
221 }
222 else
223 {
224 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
225 Pipe_Unfreeze();
226
227 if ((ErrorCode = Pipe_Write_Stream_LE(BufferPtr, BytesRem)) != PIPE_RWSTREAM_NoError)
228 return ErrorCode;
229
230 Pipe_ClearOUT();
231
232 while (!(Pipe_IsOUTReady()))
233 {
234 if (USB_HostState == HOST_STATE_Unattached)
235 return PIPE_RWSTREAM_DeviceDisconnected;
236 }
237 }
238
239 Pipe_Freeze();
240
241 return PIPE_RWSTREAM_NoError;
242 }
243
244 static uint8_t MS_Host_GetReturnedStatus(USB_ClassInfo_MS_Host_t* MSInterfaceInfo,
245 MS_CommandStatusWrapper_t* SCSICommandStatus)
246 {
247 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
248
249 if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError)
250 return ErrorCode;
251
252 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
253 Pipe_Unfreeze();
254
255 if ((ErrorCode = Pipe_Read_Stream_LE(SCSICommandStatus, sizeof(MS_CommandStatusWrapper_t))) != PIPE_RWSTREAM_NoError)
256 return ErrorCode;
257
258 Pipe_ClearIN();
259 Pipe_Freeze();
260
261 return PIPE_RWSTREAM_NoError;
262 }
263
264 uint8_t MS_Host_ResetMSInterface(USB_ClassInfo_MS_Host_t* MSInterfaceInfo)
265 {
266 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.Active))
267 return HOST_SENDCONTROL_DeviceDisconnect;
268
269 USB_ControlRequest = (USB_Request_Header_t)
270 {
271 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
272 .bRequest = REQ_MassStorageReset,
273 .wValue = 0,
274 .wIndex = MSInterfaceInfo->State.InterfaceNumber,
275 .wLength = 0,
276 };
277
278 Pipe_SelectPipe(PIPE_CONTROLPIPE);
279
280 return USB_Host_SendControlRequest(NULL);
281 }
282
283 uint8_t MS_Host_GetMaxLUN(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t* MaxLUNIndex)
284 {
285 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.Active))
286 return HOST_SENDCONTROL_DeviceDisconnect;
287
288 uint8_t ErrorCode;
289
290 USB_ControlRequest = (USB_Request_Header_t)
291 {
292 .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
293 .bRequest = REQ_GetMaxLUN,
294 .wValue = 0,
295 .wIndex = MSInterfaceInfo->State.InterfaceNumber,
296 .wLength = 1,
297 };
298
299 Pipe_SelectPipe(PIPE_CONTROLPIPE);
300
301 if ((ErrorCode = USB_Host_SendControlRequest(MaxLUNIndex)) == HOST_SENDCONTROL_SetupStalled)
302 {
303 Pipe_ClearStall();
304
305 *MaxLUNIndex = 0;
306 }
307
308 return ErrorCode;
309 }
310
311 uint8_t MS_Host_GetInquiryData(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex, SCSI_Inquiry_Response_t* InquiryData)
312 {
313 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.Active))
314 return HOST_SENDCONTROL_DeviceDisconnect;
315
316 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
317
318 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
319 {
320 .Signature = CBW_SIGNATURE,
321 .Tag = MSInterfaceInfo->State.TransactionTag,
322 .DataTransferLength = sizeof(SCSI_Inquiry_Response_t),
323 .Flags = COMMAND_DIRECTION_DATA_IN,
324 .LUN = LUNIndex,
325 .SCSICommandLength = 6,
326 .SCSICommandData =
327 {
328 SCSI_CMD_INQUIRY,
329 0x00, // Reserved
330 0x00, // Reserved
331 0x00, // Reserved
332 sizeof(SCSI_Inquiry_Response_t), // Allocation Length
333 0x00 // Unused (control)
334 }
335 };
336
337 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock)) != PIPE_RWSTREAM_NoError)
338 {
339 Pipe_Freeze();
340 return ErrorCode;
341 }
342
343 if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError)
344 {
345 Pipe_Freeze();
346 return ErrorCode;
347 }
348
349 if ((ErrorCode = MS_Host_SendReceiveData(MSInterfaceInfo, &SCSICommandBlock, InquiryData)) != PIPE_RWSTREAM_NoError)
350 {
351 Pipe_Freeze();
352 return ErrorCode;
353 }
354
355 MS_CommandStatusWrapper_t SCSICommandStatus;
356 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
357 {
358 Pipe_Freeze();
359 return ErrorCode;
360 }
361
362 if (SCSICommandStatus.Status != SCSI_Command_Pass)
363 ErrorCode = MS_ERROR_LOGICAL_CMD_FAILED;
364
365 return ErrorCode;
366 }
367
368 uint8_t MS_Host_TestUnitReady(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex)
369 {
370 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.Active))
371 return HOST_SENDCONTROL_DeviceDisconnect;
372
373 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
374
375 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
376 {
377 .Signature = CBW_SIGNATURE,
378 .Tag = MSInterfaceInfo->State.TransactionTag,
379 .DataTransferLength = 0,
380 .Flags = COMMAND_DIRECTION_DATA_IN,
381 .LUN = LUNIndex,
382 .SCSICommandLength = 6,
383 .SCSICommandData =
384 {
385 SCSI_CMD_TEST_UNIT_READY,
386 0x00, // Reserved
387 0x00, // Reserved
388 0x00, // Reserved
389 0x00, // Reserved
390 0x00 // Unused (control)
391 }
392 };
393
394 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock)) != PIPE_RWSTREAM_NoError)
395 {
396 Pipe_Freeze();
397 return ErrorCode;
398 }
399
400 MS_CommandStatusWrapper_t SCSICommandStatus;
401 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
402 {
403 Pipe_Freeze();
404 return ErrorCode;
405 }
406
407 if (SCSICommandStatus.Status != SCSI_Command_Pass)
408 ErrorCode = MS_ERROR_LOGICAL_CMD_FAILED;
409
410 return ErrorCode;
411 }
412
413 uint8_t MS_Host_ReadDeviceCapacity(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex,
414 SCSI_Capacity_t* DeviceCapacity)
415 {
416 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.Active))
417 return HOST_SENDCONTROL_DeviceDisconnect;
418
419 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
420
421 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
422 {
423 .Signature = CBW_SIGNATURE,
424 .Tag = MSInterfaceInfo->State.TransactionTag,
425 .DataTransferLength = sizeof(SCSI_Capacity_t),
426 .Flags = COMMAND_DIRECTION_DATA_IN,
427 .LUN = LUNIndex,
428 .SCSICommandLength = 10,
429 .SCSICommandData =
430 {
431 SCSI_CMD_READ_CAPACITY_10,
432 0x00, // Reserved
433 0x00, // MSB of Logical block address
434 0x00,
435 0x00,
436 0x00, // LSB of Logical block address
437 0x00, // Reserved
438 0x00, // Reserved
439 0x00, // Partial Medium Indicator
440 0x00 // Unused (control)
441 }
442 };
443
444 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock)) != PIPE_RWSTREAM_NoError)
445 {
446 Pipe_Freeze();
447 return ErrorCode;
448 }
449
450 if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError)
451 {
452 Pipe_Freeze();
453 return ErrorCode;
454 }
455
456 if ((ErrorCode = MS_Host_SendReceiveData(MSInterfaceInfo, &SCSICommandBlock, DeviceCapacity)) != PIPE_RWSTREAM_NoError)
457 {
458 Pipe_Freeze();
459 return ErrorCode;
460 }
461
462 DeviceCapacity->Blocks = SwapEndian_32(DeviceCapacity->Blocks);
463 DeviceCapacity->BlockSize = SwapEndian_32(DeviceCapacity->BlockSize);
464
465 MS_CommandStatusWrapper_t SCSICommandStatus;
466 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
467 {
468 Pipe_Freeze();
469 return ErrorCode;
470 }
471
472 if (SCSICommandStatus.Status != SCSI_Command_Pass)
473 ErrorCode = MS_ERROR_LOGICAL_CMD_FAILED;
474
475 return ErrorCode;
476 }
477
478 uint8_t MS_Host_RequestSense(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex,
479 SCSI_Request_Sense_Response_t* SenseData)
480 {
481 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.Active))
482 return HOST_SENDCONTROL_DeviceDisconnect;
483
484 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
485
486 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
487 {
488 .Signature = CBW_SIGNATURE,
489 .Tag = MSInterfaceInfo->State.TransactionTag,
490 .DataTransferLength = sizeof(SCSI_Request_Sense_Response_t),
491 .Flags = COMMAND_DIRECTION_DATA_IN,
492 .LUN = LUNIndex,
493 .SCSICommandLength = 6,
494 .SCSICommandData =
495 {
496 SCSI_CMD_REQUEST_SENSE,
497 0x00, // Reserved
498 0x00, // Reserved
499 0x00, // Reserved
500 sizeof(SCSI_Request_Sense_Response_t), // Allocation Length
501 0x00 // Unused (control)
502 }
503 };
504
505 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock)) != PIPE_RWSTREAM_NoError)
506 {
507 Pipe_Freeze();
508 return ErrorCode;
509 }
510
511 if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError)
512 {
513 Pipe_Freeze();
514 return ErrorCode;
515 }
516
517 if ((ErrorCode = MS_Host_SendReceiveData(MSInterfaceInfo, &SCSICommandBlock, SenseData)) != PIPE_RWSTREAM_NoError)
518 {
519 Pipe_Freeze();
520 return ErrorCode;
521 }
522
523 MS_CommandStatusWrapper_t SCSICommandStatus;
524 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
525 {
526 Pipe_Freeze();
527 return ErrorCode;
528 }
529
530 if (SCSICommandStatus.Status != SCSI_Command_Pass)
531 ErrorCode = MS_ERROR_LOGICAL_CMD_FAILED;
532
533 return ErrorCode;
534 }
535
536 uint8_t MS_Host_PreventAllowMediumRemoval(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex, bool PreventRemoval)
537 {
538 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.Active))
539 return HOST_SENDCONTROL_DeviceDisconnect;
540
541 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
542
543 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
544 {
545 .Signature = CBW_SIGNATURE,
546 .Tag = MSInterfaceInfo->State.TransactionTag,
547 .DataTransferLength = 0,
548 .Flags = COMMAND_DIRECTION_DATA_OUT,
549 .LUN = LUNIndex,
550 .SCSICommandLength = 6,
551 .SCSICommandData =
552 {
553 SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL,
554 0x00, // Reserved
555 0x00, // Reserved
556 PreventRemoval, // Prevent flag
557 0x00, // Reserved
558 0x00 // Unused (control)
559 }
560 };
561
562 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock)) != PIPE_RWSTREAM_NoError)
563 {
564 Pipe_Freeze();
565 return ErrorCode;
566 }
567
568 MS_CommandStatusWrapper_t SCSICommandStatus;
569 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
570 {
571 Pipe_Freeze();
572 return ErrorCode;
573 }
574
575 if (SCSICommandStatus.Status != SCSI_Command_Pass)
576 ErrorCode = MS_ERROR_LOGICAL_CMD_FAILED;
577
578 return ErrorCode;
579 }
580
581 uint8_t MS_Host_ReadDeviceBlocks(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex, uint32_t BlockAddress,
582 uint8_t Blocks, uint16_t BlockSize, void* BlockBuffer)
583 {
584 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.Active))
585 return HOST_SENDCONTROL_DeviceDisconnect;
586
587 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
588
589 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
590 {
591 .Signature = CBW_SIGNATURE,
592 .Tag = MSInterfaceInfo->State.TransactionTag,
593 .DataTransferLength = ((uint32_t)Blocks * BlockSize),
594 .Flags = COMMAND_DIRECTION_DATA_IN,
595 .LUN = LUNIndex,
596 .SCSICommandLength = 10,
597 .SCSICommandData =
598 {
599 SCSI_CMD_READ_10,
600 0x00, // Unused (control bits, all off)
601 (BlockAddress >> 24), // MSB of Block Address
602 (BlockAddress >> 16),
603 (BlockAddress >> 8),
604 (BlockAddress & 0xFF), // LSB of Block Address
605 0x00, // Unused (reserved)
606 0x00, // MSB of Total Blocks to Read
607 Blocks, // LSB of Total Blocks to Read
608 0x00 // Unused (control)
609 }
610 };
611
612 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock)) != PIPE_RWSTREAM_NoError)
613 {
614 Pipe_Freeze();
615 return ErrorCode;
616 }
617
618 if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError)
619 {
620 Pipe_Freeze();
621 return ErrorCode;
622 }
623
624 if ((ErrorCode = MS_Host_SendReceiveData(MSInterfaceInfo, &SCSICommandBlock, BlockBuffer)) != PIPE_RWSTREAM_NoError)
625 {
626 Pipe_Freeze();
627 return ErrorCode;
628 }
629
630 MS_CommandStatusWrapper_t SCSICommandStatus;
631 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
632 {
633 Pipe_Freeze();
634 return ErrorCode;
635 }
636
637 if (SCSICommandStatus.Status != SCSI_Command_Pass)
638 ErrorCode = MS_ERROR_LOGICAL_CMD_FAILED;
639
640 return ErrorCode;
641 }
642
643 uint8_t MS_Host_WriteDeviceBlocks(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex, uint32_t BlockAddress,
644 uint8_t Blocks, uint16_t BlockSize, void* BlockBuffer)
645 {
646 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.Active))
647 return HOST_SENDCONTROL_DeviceDisconnect;
648
649 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
650
651 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
652 {
653 .Signature = CBW_SIGNATURE,
654 .Tag = MSInterfaceInfo->State.TransactionTag,
655 .DataTransferLength = ((uint32_t)Blocks * BlockSize),
656 .Flags = COMMAND_DIRECTION_DATA_OUT,
657 .LUN = LUNIndex,
658 .SCSICommandLength = 10,
659 .SCSICommandData =
660 {
661 SCSI_CMD_WRITE_10,
662 0x00, // Unused (control bits, all off)
663 (BlockAddress >> 24), // MSB of Block Address
664 (BlockAddress >> 16),
665 (BlockAddress >> 8),
666 (BlockAddress & 0xFF), // LSB of Block Address
667 0x00, // Unused (reserved)
668 0x00, // MSB of Total Blocks to Write
669 Blocks, // LSB of Total Blocks to Write
670 0x00 // Unused (control)
671 }
672 };
673
674 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock)) != PIPE_RWSTREAM_NoError)
675 {
676 Pipe_Freeze();
677 return ErrorCode;
678 }
679
680 if ((ErrorCode = MS_Host_SendReceiveData(MSInterfaceInfo, &SCSICommandBlock, BlockBuffer)) != PIPE_RWSTREAM_NoError)
681 {
682 Pipe_Freeze();
683 return ErrorCode;
684 }
685
686 MS_CommandStatusWrapper_t SCSICommandStatus;
687 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
688 {
689 Pipe_Freeze();
690 return ErrorCode;
691 }
692
693 if (SCSICommandStatus.Status != SCSI_Command_Pass)
694 ErrorCode = MS_ERROR_LOGICAL_CMD_FAILED;
695
696 return ErrorCode;
697 }
698
699 #endif