Changed over www.fourwalledcubicle.com links to the new www.lufa-lib.org redirect...
[pub/USBasp.git] / LUFA / Drivers / USB / Class / Host / MassStorage.c
1 /*
2 LUFA Library
3 Copyright (C) Dean Camera, 2010.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.lufa-lib.org
7 */
8
9 /*
10 Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
11
12 Permission to use, copy, modify, distribute, and sell this
13 software and its documentation for any purpose is hereby granted
14 without fee, provided that the above copyright notice appear in
15 all 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 #define __INCLUDE_FROM_USB_DRIVER
32 #include "../../HighLevel/USBMode.h"
33 #if defined(USB_CAN_BE_HOST)
34
35 #define __INCLUDE_FROM_MS_DRIVER
36 #define __INCLUDE_FROM_MASSSTORAGE_HOST_C
37 #include "MassStorage.h"
38
39 uint8_t MS_Host_ConfigurePipes(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
40 uint16_t ConfigDescriptorSize,
41 void* ConfigDescriptorData)
42 {
43 USB_Descriptor_Endpoint_t* DataINEndpoint = NULL;
44 USB_Descriptor_Endpoint_t* DataOUTEndpoint = NULL;
45 USB_Descriptor_Interface_t* MassStorageInterface = NULL;
46
47 memset(&MSInterfaceInfo->State, 0x00, sizeof(MSInterfaceInfo->State));
48
49 if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration)
50 return MS_ENUMERROR_InvalidConfigDescriptor;
51
52 while (!(DataINEndpoint) || !(DataOUTEndpoint))
53 {
54 if (!(MassStorageInterface) ||
55 USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
56 DCOMP_MS_Host_NextMSInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
57 {
58 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
59 DCOMP_MS_Host_NextMSInterface) != DESCRIPTOR_SEARCH_COMP_Found)
60 {
61 return MS_ENUMERROR_NoCompatibleInterfaceFound;
62 }
63
64 MassStorageInterface = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Interface_t);
65
66 DataINEndpoint = NULL;
67 DataOUTEndpoint = NULL;
68
69 continue;
70 }
71
72 USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t);
73
74 if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN)
75 DataINEndpoint = EndpointData;
76 else
77 DataOUTEndpoint = EndpointData;
78 }
79
80 for (uint8_t PipeNum = 1; PipeNum < PIPE_TOTAL_PIPES; PipeNum++)
81 {
82 if (PipeNum == MSInterfaceInfo->Config.DataINPipeNumber)
83 {
84 Pipe_ConfigurePipe(PipeNum, EP_TYPE_BULK, PIPE_TOKEN_IN,
85 DataINEndpoint->EndpointAddress, DataINEndpoint->EndpointSize,
86 MSInterfaceInfo->Config.DataINPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE);
87
88 MSInterfaceInfo->State.DataINPipeSize = DataINEndpoint->EndpointSize;
89 }
90 else if (PipeNum == MSInterfaceInfo->Config.DataOUTPipeNumber)
91 {
92 Pipe_ConfigurePipe(PipeNum, EP_TYPE_BULK, PIPE_TOKEN_OUT,
93 DataOUTEndpoint->EndpointAddress, DataOUTEndpoint->EndpointSize,
94 MSInterfaceInfo->Config.DataOUTPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE);
95
96 MSInterfaceInfo->State.DataOUTPipeSize = DataOUTEndpoint->EndpointSize;
97 }
98 }
99
100 MSInterfaceInfo->State.InterfaceNumber = MassStorageInterface->InterfaceNumber;
101 MSInterfaceInfo->State.IsActive = true;
102
103 return MS_ENUMERROR_NoError;
104 }
105
106 static uint8_t DCOMP_MS_Host_NextMSInterface(void* const CurrentDescriptor)
107 {
108 if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
109 {
110 USB_Descriptor_Interface_t* CurrentInterface = DESCRIPTOR_PCAST(CurrentDescriptor,
111 USB_Descriptor_Interface_t);
112
113 if ((CurrentInterface->Class == MS_CSCP_MassStorageClass) &&
114 (CurrentInterface->SubClass == MS_CSCP_SCSITransparentSubclass) &&
115 (CurrentInterface->Protocol == MS_CSCP_BulkOnlyTransportProtocol))
116 {
117 return DESCRIPTOR_SEARCH_Found;
118 }
119 }
120
121 return DESCRIPTOR_SEARCH_NotFound;
122 }
123
124 static uint8_t DCOMP_MS_Host_NextMSInterfaceEndpoint(void* const CurrentDescriptor)
125 {
126 if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Endpoint)
127 {
128 USB_Descriptor_Endpoint_t* CurrentEndpoint = DESCRIPTOR_PCAST(CurrentDescriptor,
129 USB_Descriptor_Endpoint_t);
130
131 uint8_t EndpointType = (CurrentEndpoint->Attributes & EP_TYPE_MASK);
132
133 if ((EndpointType == EP_TYPE_BULK) &&
134 (!(Pipe_IsEndpointBound(CurrentEndpoint->EndpointAddress))))
135 {
136 return DESCRIPTOR_SEARCH_Found;
137 }
138 }
139 else if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
140 {
141 return DESCRIPTOR_SEARCH_Fail;
142 }
143
144 return DESCRIPTOR_SEARCH_NotFound;
145 }
146
147 static uint8_t MS_Host_SendCommand(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
148 MS_CommandBlockWrapper_t* const SCSICommandBlock,
149 const void* const BufferPtr)
150 {
151 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
152
153 SCSICommandBlock->Signature = MS_CBW_SIGNATURE;
154 SCSICommandBlock->Tag = ++MSInterfaceInfo->State.TransactionTag;
155
156 if (MSInterfaceInfo->State.TransactionTag == 0xFFFFFFFF)
157 MSInterfaceInfo->State.TransactionTag = 1;
158
159 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
160 Pipe_Unfreeze();
161
162 if ((ErrorCode = Pipe_Write_Stream_LE(SCSICommandBlock, sizeof(MS_CommandBlockWrapper_t),
163 NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
164 return ErrorCode;
165
166 Pipe_ClearOUT();
167 Pipe_WaitUntilReady();
168
169 Pipe_Freeze();
170
171 if ((BufferPtr != NULL) &&
172 ((ErrorCode = MS_Host_SendReceiveData(MSInterfaceInfo, SCSICommandBlock, (void*)BufferPtr)) != PIPE_RWSTREAM_NoError))
173 {
174 Pipe_Freeze();
175 return ErrorCode;
176 }
177
178 return ErrorCode;
179 }
180
181 static uint8_t MS_Host_WaitForDataReceived(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo)
182 {
183 uint16_t TimeoutMSRem = MS_COMMAND_DATA_TIMEOUT_MS;
184 uint16_t PreviousFrameNumber = USB_Host_GetFrameNumber();
185
186 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
187 Pipe_Unfreeze();
188
189 while (!(Pipe_IsINReceived()))
190 {
191 uint16_t CurrentFrameNumber = USB_Host_GetFrameNumber();
192
193 if (CurrentFrameNumber != PreviousFrameNumber)
194 {
195 PreviousFrameNumber = CurrentFrameNumber;
196
197 if (!(TimeoutMSRem--))
198 return PIPE_RWSTREAM_Timeout;
199 }
200
201 Pipe_Freeze();
202 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
203 Pipe_Unfreeze();
204
205 if (Pipe_IsStalled())
206 {
207 USB_Host_ClearPipeStall(MSInterfaceInfo->Config.DataOUTPipeNumber);
208
209 return PIPE_RWSTREAM_PipeStalled;
210 }
211
212 Pipe_Freeze();
213 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
214 Pipe_Unfreeze();
215
216 if (Pipe_IsStalled())
217 {
218 USB_Host_ClearPipeStall(MSInterfaceInfo->Config.DataINPipeNumber);
219
220 return PIPE_RWSTREAM_PipeStalled;
221 }
222
223 if (USB_HostState == HOST_STATE_Unattached)
224 return PIPE_RWSTREAM_DeviceDisconnected;
225 };
226
227 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
228 Pipe_Freeze();
229
230 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
231 Pipe_Freeze();
232
233 return PIPE_RWSTREAM_NoError;
234 }
235
236 static uint8_t MS_Host_SendReceiveData(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
237 MS_CommandBlockWrapper_t* const SCSICommandBlock,
238 void* BufferPtr)
239 {
240 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
241 uint16_t BytesRem = SCSICommandBlock->DataTransferLength;
242
243 if (SCSICommandBlock->Flags & MS_COMMAND_DIR_DATA_IN)
244 {
245 if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError)
246 {
247 Pipe_Freeze();
248 return ErrorCode;
249 }
250
251 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
252 Pipe_Unfreeze();
253
254 if ((ErrorCode = Pipe_Read_Stream_LE(BufferPtr, BytesRem, NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
255 return ErrorCode;
256
257 Pipe_ClearIN();
258 }
259 else
260 {
261 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
262 Pipe_Unfreeze();
263
264 if ((ErrorCode = Pipe_Write_Stream_LE(BufferPtr, BytesRem, NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
265 return ErrorCode;
266
267 Pipe_ClearOUT();
268
269 while (!(Pipe_IsOUTReady()))
270 {
271 if (USB_HostState == HOST_STATE_Unattached)
272 return PIPE_RWSTREAM_DeviceDisconnected;
273 }
274 }
275
276 Pipe_Freeze();
277
278 return ErrorCode;
279 }
280
281 static uint8_t MS_Host_GetReturnedStatus(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
282 MS_CommandStatusWrapper_t* const SCSICommandStatus)
283 {
284 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
285
286 if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError)
287 return ErrorCode;
288
289 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
290 Pipe_Unfreeze();
291
292 if ((ErrorCode = Pipe_Read_Stream_LE(SCSICommandStatus, sizeof(MS_CommandStatusWrapper_t),
293 NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
294 {
295 return ErrorCode;
296 }
297
298 Pipe_ClearIN();
299 Pipe_Freeze();
300
301 if (SCSICommandStatus->Status != MS_SCSI_COMMAND_Pass)
302 ErrorCode = MS_ERROR_LOGICAL_CMD_FAILED;
303
304 return ErrorCode;
305 }
306
307 uint8_t MS_Host_ResetMSInterface(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo)
308 {
309 USB_ControlRequest = (USB_Request_Header_t)
310 {
311 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
312 .bRequest = MS_REQ_MassStorageReset,
313 .wValue = 0,
314 .wIndex = MSInterfaceInfo->State.InterfaceNumber,
315 .wLength = 0,
316 };
317
318 Pipe_SelectPipe(PIPE_CONTROLPIPE);
319
320 return USB_Host_SendControlRequest(NULL);
321 }
322
323 uint8_t MS_Host_GetMaxLUN(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
324 uint8_t* const MaxLUNIndex)
325 {
326 uint8_t ErrorCode = HOST_SENDCONTROL_Successful;
327
328 USB_ControlRequest = (USB_Request_Header_t)
329 {
330 .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
331 .bRequest = MS_REQ_GetMaxLUN,
332 .wValue = 0,
333 .wIndex = MSInterfaceInfo->State.InterfaceNumber,
334 .wLength = 1,
335 };
336
337 Pipe_SelectPipe(PIPE_CONTROLPIPE);
338
339 if ((ErrorCode = USB_Host_SendControlRequest(MaxLUNIndex)) != HOST_SENDCONTROL_Successful)
340 {
341 *MaxLUNIndex = 0;
342 ErrorCode = HOST_SENDCONTROL_Successful;
343 }
344
345 return ErrorCode;
346 }
347
348 uint8_t MS_Host_GetInquiryData(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
349 const uint8_t LUNIndex,
350 SCSI_Inquiry_Response_t* const InquiryData)
351 {
352 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
353 return HOST_SENDCONTROL_DeviceDisconnected;
354
355 uint8_t ErrorCode;
356
357 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
358 {
359 .DataTransferLength = sizeof(SCSI_Inquiry_Response_t),
360 .Flags = MS_COMMAND_DIR_DATA_IN,
361 .LUN = LUNIndex,
362 .SCSICommandLength = 6,
363 .SCSICommandData =
364 {
365 SCSI_CMD_INQUIRY,
366 0x00, // Reserved
367 0x00, // Reserved
368 0x00, // Reserved
369 sizeof(SCSI_Inquiry_Response_t), // Allocation Length
370 0x00 // Unused (control)
371 }
372 };
373
374 MS_CommandStatusWrapper_t SCSICommandStatus;
375
376 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, InquiryData)) != PIPE_RWSTREAM_NoError)
377 return ErrorCode;
378
379 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
380 return ErrorCode;
381
382 return PIPE_RWSTREAM_NoError;
383 }
384
385 uint8_t MS_Host_TestUnitReady(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
386 const uint8_t LUNIndex)
387 {
388 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
389 return HOST_SENDCONTROL_DeviceDisconnected;
390
391 uint8_t ErrorCode;
392
393 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
394 {
395 .DataTransferLength = 0,
396 .Flags = MS_COMMAND_DIR_DATA_IN,
397 .LUN = LUNIndex,
398 .SCSICommandLength = 6,
399 .SCSICommandData =
400 {
401 SCSI_CMD_TEST_UNIT_READY,
402 0x00, // Reserved
403 0x00, // Reserved
404 0x00, // Reserved
405 0x00, // Reserved
406 0x00 // Unused (control)
407 }
408 };
409
410 MS_CommandStatusWrapper_t SCSICommandStatus;
411
412 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, NULL)) != PIPE_RWSTREAM_NoError)
413 return ErrorCode;
414
415 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
416 return ErrorCode;
417
418 return PIPE_RWSTREAM_NoError;
419 }
420
421 uint8_t MS_Host_ReadDeviceCapacity(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
422 const uint8_t LUNIndex,
423 SCSI_Capacity_t* const DeviceCapacity)
424 {
425 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
426 return HOST_SENDCONTROL_DeviceDisconnected;
427
428 uint8_t ErrorCode;
429
430 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
431 {
432 .DataTransferLength = sizeof(SCSI_Capacity_t),
433 .Flags = MS_COMMAND_DIR_DATA_IN,
434 .LUN = LUNIndex,
435 .SCSICommandLength = 10,
436 .SCSICommandData =
437 {
438 SCSI_CMD_READ_CAPACITY_10,
439 0x00, // Reserved
440 0x00, // MSB of Logical block address
441 0x00,
442 0x00,
443 0x00, // LSB of Logical block address
444 0x00, // Reserved
445 0x00, // Reserved
446 0x00, // Partial Medium Indicator
447 0x00 // Unused (control)
448 }
449 };
450
451 MS_CommandStatusWrapper_t SCSICommandStatus;
452
453 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, DeviceCapacity)) != PIPE_RWSTREAM_NoError)
454 return ErrorCode;
455
456 SwapEndian_n(&DeviceCapacity->Blocks, sizeof(DeviceCapacity->Blocks));
457 SwapEndian_n(&DeviceCapacity->BlockSize, sizeof(DeviceCapacity->BlockSize));
458
459 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
460 return ErrorCode;
461
462 return PIPE_RWSTREAM_NoError;
463 }
464
465 uint8_t MS_Host_RequestSense(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
466 const uint8_t LUNIndex,
467 SCSI_Request_Sense_Response_t* const SenseData)
468 {
469 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
470 return HOST_SENDCONTROL_DeviceDisconnected;
471
472 uint8_t ErrorCode;
473
474 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
475 {
476 .DataTransferLength = sizeof(SCSI_Request_Sense_Response_t),
477 .Flags = MS_COMMAND_DIR_DATA_IN,
478 .LUN = LUNIndex,
479 .SCSICommandLength = 6,
480 .SCSICommandData =
481 {
482 SCSI_CMD_REQUEST_SENSE,
483 0x00, // Reserved
484 0x00, // Reserved
485 0x00, // Reserved
486 sizeof(SCSI_Request_Sense_Response_t), // Allocation Length
487 0x00 // Unused (control)
488 }
489 };
490
491 MS_CommandStatusWrapper_t SCSICommandStatus;
492
493 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, SenseData)) != PIPE_RWSTREAM_NoError)
494 return ErrorCode;
495
496 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
497 return ErrorCode;
498
499 return PIPE_RWSTREAM_NoError;
500 }
501
502 uint8_t MS_Host_PreventAllowMediumRemoval(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
503 const uint8_t LUNIndex,
504 const bool PreventRemoval)
505 {
506 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
507 return HOST_SENDCONTROL_DeviceDisconnected;
508
509 uint8_t ErrorCode;
510
511 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
512 {
513 .DataTransferLength = 0,
514 .Flags = MS_COMMAND_DIR_DATA_OUT,
515 .LUN = LUNIndex,
516 .SCSICommandLength = 6,
517 .SCSICommandData =
518 {
519 SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL,
520 0x00, // Reserved
521 0x00, // Reserved
522 PreventRemoval, // Prevent flag
523 0x00, // Reserved
524 0x00 // Unused (control)
525 }
526 };
527
528 MS_CommandStatusWrapper_t SCSICommandStatus;
529
530 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, NULL)) != PIPE_RWSTREAM_NoError)
531 return ErrorCode;
532
533 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
534 return ErrorCode;
535
536 return PIPE_RWSTREAM_NoError;
537 }
538
539 uint8_t MS_Host_ReadDeviceBlocks(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
540 const uint8_t LUNIndex,
541 const uint32_t BlockAddress,
542 const uint8_t Blocks,
543 const uint16_t BlockSize,
544 void* BlockBuffer)
545 {
546 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
547 return HOST_SENDCONTROL_DeviceDisconnected;
548
549 uint8_t ErrorCode;
550
551 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
552 {
553 .DataTransferLength = ((uint32_t)Blocks * BlockSize),
554 .Flags = MS_COMMAND_DIR_DATA_IN,
555 .LUN = LUNIndex,
556 .SCSICommandLength = 10,
557 .SCSICommandData =
558 {
559 SCSI_CMD_READ_10,
560 0x00, // Unused (control bits, all off)
561 (BlockAddress >> 24), // MSB of Block Address
562 (BlockAddress >> 16),
563 (BlockAddress >> 8),
564 (BlockAddress & 0xFF), // LSB of Block Address
565 0x00, // Reserved
566 0x00, // MSB of Total Blocks to Read
567 Blocks, // LSB of Total Blocks to Read
568 0x00 // Unused (control)
569 }
570 };
571
572 MS_CommandStatusWrapper_t SCSICommandStatus;
573
574 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, BlockBuffer)) != PIPE_RWSTREAM_NoError)
575 return ErrorCode;
576
577 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
578 return ErrorCode;
579
580 return PIPE_RWSTREAM_NoError;
581 }
582
583 uint8_t MS_Host_WriteDeviceBlocks(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
584 const uint8_t LUNIndex,
585 const uint32_t BlockAddress,
586 const uint8_t Blocks,
587 const uint16_t BlockSize,
588 const void* BlockBuffer)
589 {
590 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
591 return HOST_SENDCONTROL_DeviceDisconnected;
592
593 uint8_t ErrorCode;
594
595 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
596 {
597 .DataTransferLength = ((uint32_t)Blocks * BlockSize),
598 .Flags = MS_COMMAND_DIR_DATA_OUT,
599 .LUN = LUNIndex,
600 .SCSICommandLength = 10,
601 .SCSICommandData =
602 {
603 SCSI_CMD_WRITE_10,
604 0x00, // Unused (control bits, all off)
605 (BlockAddress >> 24), // MSB of Block Address
606 (BlockAddress >> 16),
607 (BlockAddress >> 8),
608 (BlockAddress & 0xFF), // LSB of Block Address
609 0x00, // Reserved
610 0x00, // MSB of Total Blocks to Write
611 Blocks, // LSB of Total Blocks to Write
612 0x00 // Unused (control)
613 }
614 };
615
616 MS_CommandStatusWrapper_t SCSICommandStatus;
617
618 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, BlockBuffer)) != PIPE_RWSTREAM_NoError)
619 return ErrorCode;
620
621 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
622 return ErrorCode;
623
624 return PIPE_RWSTREAM_NoError;
625 }
626
627 #endif
628