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