Added new USB_Device_GetFrameNumber() and USB_Host_GetFrameNumber() functions to...
[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 uint16_t PreviousFrameNumber = USB_Host_GetFrameNumber();
171
172 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
173 Pipe_Unfreeze();
174
175 while (!(Pipe_IsINReceived()))
176 {
177 uint16_t CurrentFrameNumber = USB_Host_GetFrameNumber();
178
179 if (CurrentFrameNumber != PreviousFrameNumber)
180 {
181 PreviousFrameNumber = CurrentFrameNumber;
182
183 if (!(TimeoutMSRem--))
184 return PIPE_RWSTREAM_Timeout;
185 }
186
187 Pipe_Freeze();
188 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
189 Pipe_Unfreeze();
190
191 if (Pipe_IsStalled())
192 {
193 USB_Host_ClearPipeStall(MSInterfaceInfo->Config.DataOUTPipeNumber);
194
195 return PIPE_RWSTREAM_PipeStalled;
196 }
197
198 Pipe_Freeze();
199 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
200 Pipe_Unfreeze();
201
202 if (Pipe_IsStalled())
203 {
204 USB_Host_ClearPipeStall(MSInterfaceInfo->Config.DataINPipeNumber);
205
206 return PIPE_RWSTREAM_PipeStalled;
207 }
208
209 if (USB_HostState == HOST_STATE_Unattached)
210 return PIPE_RWSTREAM_DeviceDisconnected;
211 };
212
213 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
214 Pipe_Freeze();
215
216 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
217 Pipe_Freeze();
218
219 return PIPE_RWSTREAM_NoError;
220 }
221
222 static uint8_t MS_Host_SendReceiveData(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
223 MS_CommandBlockWrapper_t* const SCSICommandBlock,
224 void* BufferPtr)
225 {
226 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
227 uint16_t BytesRem = SCSICommandBlock->DataTransferLength;
228
229 if (SCSICommandBlock->Flags & COMMAND_DIRECTION_DATA_IN)
230 {
231 if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError)
232 {
233 Pipe_Freeze();
234 return ErrorCode;
235 }
236
237 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
238 Pipe_Unfreeze();
239
240 if ((ErrorCode = Pipe_Read_Stream_LE(BufferPtr, BytesRem, NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
241 return ErrorCode;
242
243 Pipe_ClearIN();
244 }
245 else
246 {
247 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
248 Pipe_Unfreeze();
249
250 if ((ErrorCode = Pipe_Write_Stream_LE(BufferPtr, BytesRem, NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
251 return ErrorCode;
252
253 Pipe_ClearOUT();
254
255 while (!(Pipe_IsOUTReady()))
256 {
257 if (USB_HostState == HOST_STATE_Unattached)
258 return PIPE_RWSTREAM_DeviceDisconnected;
259 }
260 }
261
262 Pipe_Freeze();
263
264 return ErrorCode;
265 }
266
267 static uint8_t MS_Host_GetReturnedStatus(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
268 MS_CommandStatusWrapper_t* const SCSICommandStatus)
269 {
270 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
271
272 if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError)
273 return ErrorCode;
274
275 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
276 Pipe_Unfreeze();
277
278 if ((ErrorCode = Pipe_Read_Stream_LE(SCSICommandStatus, sizeof(MS_CommandStatusWrapper_t),
279 NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
280 {
281 return ErrorCode;
282 }
283
284 Pipe_ClearIN();
285 Pipe_Freeze();
286
287 if (SCSICommandStatus->Status != SCSI_Command_Pass)
288 ErrorCode = MS_ERROR_LOGICAL_CMD_FAILED;
289
290 return ErrorCode;
291 }
292
293 uint8_t MS_Host_ResetMSInterface(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo)
294 {
295 USB_ControlRequest = (USB_Request_Header_t)
296 {
297 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
298 .bRequest = REQ_MassStorageReset,
299 .wValue = 0,
300 .wIndex = MSInterfaceInfo->State.InterfaceNumber,
301 .wLength = 0,
302 };
303
304 Pipe_SelectPipe(PIPE_CONTROLPIPE);
305
306 return USB_Host_SendControlRequest(NULL);
307 }
308
309 uint8_t MS_Host_GetMaxLUN(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
310 uint8_t* const MaxLUNIndex)
311 {
312 uint8_t ErrorCode = HOST_SENDCONTROL_Successful;
313
314 USB_ControlRequest = (USB_Request_Header_t)
315 {
316 .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
317 .bRequest = REQ_GetMaxLUN,
318 .wValue = 0,
319 .wIndex = MSInterfaceInfo->State.InterfaceNumber,
320 .wLength = 1,
321 };
322
323 Pipe_SelectPipe(PIPE_CONTROLPIPE);
324
325 if ((ErrorCode = USB_Host_SendControlRequest(MaxLUNIndex)) != HOST_SENDCONTROL_Successful)
326 {
327 *MaxLUNIndex = 0;
328 ErrorCode = HOST_SENDCONTROL_Successful;
329 }
330
331 return ErrorCode;
332 }
333
334 uint8_t MS_Host_GetInquiryData(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
335 const uint8_t LUNIndex,
336 SCSI_Inquiry_Response_t* const InquiryData)
337 {
338 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
339 return HOST_SENDCONTROL_DeviceDisconnected;
340
341 uint8_t ErrorCode;
342
343 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
344 {
345 .DataTransferLength = sizeof(SCSI_Inquiry_Response_t),
346 .Flags = COMMAND_DIRECTION_DATA_IN,
347 .LUN = LUNIndex,
348 .SCSICommandLength = 6,
349 .SCSICommandData =
350 {
351 SCSI_CMD_INQUIRY,
352 0x00, // Reserved
353 0x00, // Reserved
354 0x00, // Reserved
355 sizeof(SCSI_Inquiry_Response_t), // Allocation Length
356 0x00 // Unused (control)
357 }
358 };
359
360 MS_CommandStatusWrapper_t SCSICommandStatus;
361
362 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, InquiryData)) != PIPE_RWSTREAM_NoError)
363 return ErrorCode;
364
365 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
366 return ErrorCode;
367
368 return PIPE_RWSTREAM_NoError;
369 }
370
371 uint8_t MS_Host_TestUnitReady(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
372 const uint8_t LUNIndex)
373 {
374 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
375 return HOST_SENDCONTROL_DeviceDisconnected;
376
377 uint8_t ErrorCode;
378
379 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
380 {
381 .DataTransferLength = 0,
382 .Flags = COMMAND_DIRECTION_DATA_IN,
383 .LUN = LUNIndex,
384 .SCSICommandLength = 6,
385 .SCSICommandData =
386 {
387 SCSI_CMD_TEST_UNIT_READY,
388 0x00, // Reserved
389 0x00, // Reserved
390 0x00, // Reserved
391 0x00, // Reserved
392 0x00 // Unused (control)
393 }
394 };
395
396 MS_CommandStatusWrapper_t SCSICommandStatus;
397
398 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, NULL)) != PIPE_RWSTREAM_NoError)
399 return ErrorCode;
400
401 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
402 return ErrorCode;
403
404 return PIPE_RWSTREAM_NoError;
405 }
406
407 uint8_t MS_Host_ReadDeviceCapacity(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
408 const uint8_t LUNIndex,
409 SCSI_Capacity_t* const DeviceCapacity)
410 {
411 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
412 return HOST_SENDCONTROL_DeviceDisconnected;
413
414 uint8_t ErrorCode;
415
416 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
417 {
418 .DataTransferLength = sizeof(SCSI_Capacity_t),
419 .Flags = COMMAND_DIRECTION_DATA_IN,
420 .LUN = LUNIndex,
421 .SCSICommandLength = 10,
422 .SCSICommandData =
423 {
424 SCSI_CMD_READ_CAPACITY_10,
425 0x00, // Reserved
426 0x00, // MSB of Logical block address
427 0x00,
428 0x00,
429 0x00, // LSB of Logical block address
430 0x00, // Reserved
431 0x00, // Reserved
432 0x00, // Partial Medium Indicator
433 0x00 // Unused (control)
434 }
435 };
436
437 MS_CommandStatusWrapper_t SCSICommandStatus;
438
439 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, DeviceCapacity)) != PIPE_RWSTREAM_NoError)
440 return ErrorCode;
441
442 SwapEndian_n(&DeviceCapacity->Blocks, sizeof(DeviceCapacity->Blocks));
443 SwapEndian_n(&DeviceCapacity->BlockSize, sizeof(DeviceCapacity->BlockSize));
444
445 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
446 return ErrorCode;
447
448 return PIPE_RWSTREAM_NoError;
449 }
450
451 uint8_t MS_Host_RequestSense(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
452 const uint8_t LUNIndex,
453 SCSI_Request_Sense_Response_t* const SenseData)
454 {
455 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
456 return HOST_SENDCONTROL_DeviceDisconnected;
457
458 uint8_t ErrorCode;
459
460 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
461 {
462 .DataTransferLength = sizeof(SCSI_Request_Sense_Response_t),
463 .Flags = COMMAND_DIRECTION_DATA_IN,
464 .LUN = LUNIndex,
465 .SCSICommandLength = 6,
466 .SCSICommandData =
467 {
468 SCSI_CMD_REQUEST_SENSE,
469 0x00, // Reserved
470 0x00, // Reserved
471 0x00, // Reserved
472 sizeof(SCSI_Request_Sense_Response_t), // Allocation Length
473 0x00 // Unused (control)
474 }
475 };
476
477 MS_CommandStatusWrapper_t SCSICommandStatus;
478
479 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, SenseData)) != PIPE_RWSTREAM_NoError)
480 return ErrorCode;
481
482 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
483 return ErrorCode;
484
485 return PIPE_RWSTREAM_NoError;
486 }
487
488 uint8_t MS_Host_PreventAllowMediumRemoval(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
489 const uint8_t LUNIndex,
490 const bool PreventRemoval)
491 {
492 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
493 return HOST_SENDCONTROL_DeviceDisconnected;
494
495 uint8_t ErrorCode;
496
497 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
498 {
499 .DataTransferLength = 0,
500 .Flags = COMMAND_DIRECTION_DATA_OUT,
501 .LUN = LUNIndex,
502 .SCSICommandLength = 6,
503 .SCSICommandData =
504 {
505 SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL,
506 0x00, // Reserved
507 0x00, // Reserved
508 PreventRemoval, // Prevent flag
509 0x00, // Reserved
510 0x00 // Unused (control)
511 }
512 };
513
514 MS_CommandStatusWrapper_t SCSICommandStatus;
515
516 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, NULL)) != PIPE_RWSTREAM_NoError)
517 return ErrorCode;
518
519 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
520 return ErrorCode;
521
522 return PIPE_RWSTREAM_NoError;
523 }
524
525 uint8_t MS_Host_ReadDeviceBlocks(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
526 const uint8_t LUNIndex,
527 const uint32_t BlockAddress,
528 const uint8_t Blocks,
529 const uint16_t BlockSize,
530 void* BlockBuffer)
531 {
532 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
533 return HOST_SENDCONTROL_DeviceDisconnected;
534
535 uint8_t ErrorCode;
536
537 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
538 {
539 .DataTransferLength = ((uint32_t)Blocks * BlockSize),
540 .Flags = COMMAND_DIRECTION_DATA_IN,
541 .LUN = LUNIndex,
542 .SCSICommandLength = 10,
543 .SCSICommandData =
544 {
545 SCSI_CMD_READ_10,
546 0x00, // Unused (control bits, all off)
547 (BlockAddress >> 24), // MSB of Block Address
548 (BlockAddress >> 16),
549 (BlockAddress >> 8),
550 (BlockAddress & 0xFF), // LSB of Block Address
551 0x00, // Reserved
552 0x00, // MSB of Total Blocks to Read
553 Blocks, // LSB of Total Blocks to Read
554 0x00 // Unused (control)
555 }
556 };
557
558 MS_CommandStatusWrapper_t SCSICommandStatus;
559
560 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, BlockBuffer)) != PIPE_RWSTREAM_NoError)
561 return ErrorCode;
562
563 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
564 return ErrorCode;
565
566 return PIPE_RWSTREAM_NoError;
567 }
568
569 uint8_t MS_Host_WriteDeviceBlocks(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
570 const uint8_t LUNIndex,
571 const uint32_t BlockAddress,
572 const uint8_t Blocks,
573 const uint16_t BlockSize,
574 const void* BlockBuffer)
575 {
576 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
577 return HOST_SENDCONTROL_DeviceDisconnected;
578
579 uint8_t ErrorCode;
580
581 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
582 {
583 .DataTransferLength = ((uint32_t)Blocks * BlockSize),
584 .Flags = COMMAND_DIRECTION_DATA_OUT,
585 .LUN = LUNIndex,
586 .SCSICommandLength = 10,
587 .SCSICommandData =
588 {
589 SCSI_CMD_WRITE_10,
590 0x00, // Unused (control bits, all off)
591 (BlockAddress >> 24), // MSB of Block Address
592 (BlockAddress >> 16),
593 (BlockAddress >> 8),
594 (BlockAddress & 0xFF), // LSB of Block Address
595 0x00, // Reserved
596 0x00, // MSB of Total Blocks to Write
597 Blocks, // LSB of Total Blocks to Write
598 0x00 // Unused (control)
599 }
600 };
601
602 MS_CommandStatusWrapper_t SCSICommandStatus;
603
604 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, BlockBuffer)) != PIPE_RWSTREAM_NoError)
605 return ErrorCode;
606
607 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
608 return ErrorCode;
609
610 return PIPE_RWSTREAM_NoError;
611 }
612
613 #endif