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