Fixed HID Parser's largest report size bit count not including the size of the last...
[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_DIR_MASK) == ENDPOINT_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 = le16_to_cpu(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 = le16_to_cpu(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 if (++MSInterfaceInfo->State.TransactionTag == 0xFFFFFFFF)
176 MSInterfaceInfo->State.TransactionTag = 1;
177
178 SCSICommandBlock->Signature = CPU_TO_LE32(MS_CBW_SIGNATURE);
179 SCSICommandBlock->Tag = cpu_to_le32(MSInterfaceInfo->State.TransactionTag);
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_ClearEndpointStall(Pipe_GetBoundEndpointAddress());
230 return PIPE_RWSTREAM_PipeStalled;
231 }
232
233 Pipe_Freeze();
234 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
235 Pipe_Unfreeze();
236
237 if (Pipe_IsStalled())
238 {
239 USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress());
240 return PIPE_RWSTREAM_PipeStalled;
241 }
242
243 if (USB_HostState == HOST_STATE_Unattached)
244 return PIPE_RWSTREAM_DeviceDisconnected;
245 };
246
247 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
248 Pipe_Freeze();
249
250 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
251 Pipe_Freeze();
252
253 return PIPE_RWSTREAM_NoError;
254 }
255
256 static uint8_t MS_Host_SendReceiveData(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
257 MS_CommandBlockWrapper_t* const SCSICommandBlock,
258 void* BufferPtr)
259 {
260 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
261 uint16_t BytesRem = le32_to_cpu(SCSICommandBlock->DataTransferLength);
262
263 if (SCSICommandBlock->Flags & MS_COMMAND_DIR_DATA_IN)
264 {
265 if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError)
266 {
267 Pipe_Freeze();
268 return ErrorCode;
269 }
270
271 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
272 Pipe_Unfreeze();
273
274 if ((ErrorCode = Pipe_Read_Stream_LE(BufferPtr, BytesRem, NULL)) != PIPE_RWSTREAM_NoError)
275 return ErrorCode;
276
277 Pipe_ClearIN();
278 }
279 else
280 {
281 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
282 Pipe_Unfreeze();
283
284 if ((ErrorCode = Pipe_Write_Stream_LE(BufferPtr, BytesRem, NULL)) != PIPE_RWSTREAM_NoError)
285 return ErrorCode;
286
287 Pipe_ClearOUT();
288
289 while (!(Pipe_IsOUTReady()))
290 {
291 if (USB_HostState == HOST_STATE_Unattached)
292 return PIPE_RWSTREAM_DeviceDisconnected;
293 }
294 }
295
296 Pipe_Freeze();
297
298 return ErrorCode;
299 }
300
301 static uint8_t MS_Host_GetReturnedStatus(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
302 MS_CommandStatusWrapper_t* const SCSICommandStatus)
303 {
304 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
305
306 if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError)
307 return ErrorCode;
308
309 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
310 Pipe_Unfreeze();
311
312 if ((ErrorCode = Pipe_Read_Stream_LE(SCSICommandStatus, sizeof(MS_CommandStatusWrapper_t),
313 NULL)) != PIPE_RWSTREAM_NoError)
314 {
315 return ErrorCode;
316 }
317
318 Pipe_ClearIN();
319 Pipe_Freeze();
320
321 if (SCSICommandStatus->Status != MS_SCSI_COMMAND_Pass)
322 ErrorCode = MS_ERROR_LOGICAL_CMD_FAILED;
323
324 return ErrorCode;
325 }
326
327 uint8_t MS_Host_ResetMSInterface(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo)
328 {
329 uint8_t ErrorCode;
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 if ((ErrorCode = USB_Host_SendControlRequest(NULL)) != HOST_SENDCONTROL_Successful)
343 return ErrorCode;
344
345 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
346
347 if ((ErrorCode = USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress())) != HOST_SENDCONTROL_Successful)
348 return ErrorCode;
349
350 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
351
352 if ((ErrorCode = USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress())) != HOST_SENDCONTROL_Successful)
353 return ErrorCode;
354
355 return HOST_SENDCONTROL_Successful;
356 }
357
358 uint8_t MS_Host_GetMaxLUN(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
359 uint8_t* const MaxLUNIndex)
360 {
361 uint8_t ErrorCode = HOST_SENDCONTROL_Successful;
362
363 USB_ControlRequest = (USB_Request_Header_t)
364 {
365 .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
366 .bRequest = MS_REQ_GetMaxLUN,
367 .wValue = 0,
368 .wIndex = MSInterfaceInfo->State.InterfaceNumber,
369 .wLength = 1,
370 };
371
372 Pipe_SelectPipe(PIPE_CONTROLPIPE);
373
374 if ((ErrorCode = USB_Host_SendControlRequest(MaxLUNIndex)) == HOST_SENDCONTROL_SetupStalled)
375 {
376 *MaxLUNIndex = 0;
377 ErrorCode = HOST_SENDCONTROL_Successful;
378 }
379
380 return ErrorCode;
381 }
382
383 uint8_t MS_Host_GetInquiryData(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
384 const uint8_t LUNIndex,
385 SCSI_Inquiry_Response_t* const InquiryData)
386 {
387 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
388 return HOST_SENDCONTROL_DeviceDisconnected;
389
390 uint8_t ErrorCode;
391
392 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
393 {
394 .DataTransferLength = CPU_TO_LE32(sizeof(SCSI_Inquiry_Response_t)),
395 .Flags = MS_COMMAND_DIR_DATA_IN,
396 .LUN = LUNIndex,
397 .SCSICommandLength = 6,
398 .SCSICommandData =
399 {
400 SCSI_CMD_INQUIRY,
401 0x00, // Reserved
402 0x00, // Reserved
403 0x00, // Reserved
404 sizeof(SCSI_Inquiry_Response_t), // Allocation Length
405 0x00 // Unused (control)
406 }
407 };
408
409 MS_CommandStatusWrapper_t SCSICommandStatus;
410
411 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, InquiryData)) != PIPE_RWSTREAM_NoError)
412 return ErrorCode;
413
414 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
415 return ErrorCode;
416
417 return PIPE_RWSTREAM_NoError;
418 }
419
420 uint8_t MS_Host_TestUnitReady(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
421 const uint8_t LUNIndex)
422 {
423 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
424 return HOST_SENDCONTROL_DeviceDisconnected;
425
426 uint8_t ErrorCode;
427
428 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
429 {
430 .DataTransferLength = CPU_TO_LE32(0),
431 .Flags = MS_COMMAND_DIR_DATA_IN,
432 .LUN = LUNIndex,
433 .SCSICommandLength = 6,
434 .SCSICommandData =
435 {
436 SCSI_CMD_TEST_UNIT_READY,
437 0x00, // Reserved
438 0x00, // Reserved
439 0x00, // Reserved
440 0x00, // Reserved
441 0x00 // Unused (control)
442 }
443 };
444
445 MS_CommandStatusWrapper_t SCSICommandStatus;
446
447 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, NULL)) != PIPE_RWSTREAM_NoError)
448 return ErrorCode;
449
450 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
451 return ErrorCode;
452
453 return PIPE_RWSTREAM_NoError;
454 }
455
456 uint8_t MS_Host_ReadDeviceCapacity(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
457 const uint8_t LUNIndex,
458 SCSI_Capacity_t* const DeviceCapacity)
459 {
460 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
461 return HOST_SENDCONTROL_DeviceDisconnected;
462
463 uint8_t ErrorCode;
464
465 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
466 {
467 .DataTransferLength = CPU_TO_LE32(sizeof(SCSI_Capacity_t)),
468 .Flags = MS_COMMAND_DIR_DATA_IN,
469 .LUN = LUNIndex,
470 .SCSICommandLength = 10,
471 .SCSICommandData =
472 {
473 SCSI_CMD_READ_CAPACITY_10,
474 0x00, // Reserved
475 0x00, // MSB of Logical block address
476 0x00,
477 0x00,
478 0x00, // LSB of Logical block address
479 0x00, // Reserved
480 0x00, // Reserved
481 0x00, // Partial Medium Indicator
482 0x00 // Unused (control)
483 }
484 };
485
486 MS_CommandStatusWrapper_t SCSICommandStatus;
487
488 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, DeviceCapacity)) != PIPE_RWSTREAM_NoError)
489 return ErrorCode;
490
491 DeviceCapacity->Blocks = BE32_TO_CPU(DeviceCapacity->Blocks);
492 DeviceCapacity->BlockSize = BE32_TO_CPU(DeviceCapacity->BlockSize);
493
494 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
495 return ErrorCode;
496
497 return PIPE_RWSTREAM_NoError;
498 }
499
500 uint8_t MS_Host_RequestSense(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
501 const uint8_t LUNIndex,
502 SCSI_Request_Sense_Response_t* const SenseData)
503 {
504 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
505 return HOST_SENDCONTROL_DeviceDisconnected;
506
507 uint8_t ErrorCode;
508
509 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
510 {
511 .DataTransferLength = CPU_TO_LE32(sizeof(SCSI_Request_Sense_Response_t)),
512 .Flags = MS_COMMAND_DIR_DATA_IN,
513 .LUN = LUNIndex,
514 .SCSICommandLength = 6,
515 .SCSICommandData =
516 {
517 SCSI_CMD_REQUEST_SENSE,
518 0x00, // Reserved
519 0x00, // Reserved
520 0x00, // Reserved
521 sizeof(SCSI_Request_Sense_Response_t), // Allocation Length
522 0x00 // Unused (control)
523 }
524 };
525
526 MS_CommandStatusWrapper_t SCSICommandStatus;
527
528 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, SenseData)) != PIPE_RWSTREAM_NoError)
529 return ErrorCode;
530
531 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
532 return ErrorCode;
533
534 return PIPE_RWSTREAM_NoError;
535 }
536
537 uint8_t MS_Host_PreventAllowMediumRemoval(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
538 const uint8_t LUNIndex,
539 const bool PreventRemoval)
540 {
541 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
542 return HOST_SENDCONTROL_DeviceDisconnected;
543
544 uint8_t ErrorCode;
545
546 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
547 {
548 .DataTransferLength = CPU_TO_LE32(0),
549 .Flags = MS_COMMAND_DIR_DATA_OUT,
550 .LUN = LUNIndex,
551 .SCSICommandLength = 6,
552 .SCSICommandData =
553 {
554 SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL,
555 0x00, // Reserved
556 0x00, // Reserved
557 PreventRemoval, // Prevent flag
558 0x00, // Reserved
559 0x00 // Unused (control)
560 }
561 };
562
563 MS_CommandStatusWrapper_t SCSICommandStatus;
564
565 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, NULL)) != PIPE_RWSTREAM_NoError)
566 return ErrorCode;
567
568 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
569 return ErrorCode;
570
571 return PIPE_RWSTREAM_NoError;
572 }
573
574 uint8_t MS_Host_ReadDeviceBlocks(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
575 const uint8_t LUNIndex,
576 const uint32_t BlockAddress,
577 const uint8_t Blocks,
578 const uint16_t BlockSize,
579 void* BlockBuffer)
580 {
581 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
582 return HOST_SENDCONTROL_DeviceDisconnected;
583
584 uint8_t ErrorCode;
585
586 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
587 {
588 .DataTransferLength = cpu_to_le32((uint32_t)Blocks * BlockSize),
589 .Flags = MS_COMMAND_DIR_DATA_IN,
590 .LUN = LUNIndex,
591 .SCSICommandLength = 10,
592 .SCSICommandData =
593 {
594 SCSI_CMD_READ_10,
595 0x00, // Unused (control bits, all off)
596 (BlockAddress >> 24), // MSB of Block Address
597 (BlockAddress >> 16),
598 (BlockAddress >> 8),
599 (BlockAddress & 0xFF), // LSB of Block Address
600 0x00, // Reserved
601 0x00, // MSB of Total Blocks to Read
602 Blocks, // LSB of Total Blocks to Read
603 0x00 // Unused (control)
604 }
605 };
606
607 MS_CommandStatusWrapper_t SCSICommandStatus;
608
609 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, BlockBuffer)) != PIPE_RWSTREAM_NoError)
610 return ErrorCode;
611
612 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
613 return ErrorCode;
614
615 return PIPE_RWSTREAM_NoError;
616 }
617
618 uint8_t MS_Host_WriteDeviceBlocks(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
619 const uint8_t LUNIndex,
620 const uint32_t BlockAddress,
621 const uint8_t Blocks,
622 const uint16_t BlockSize,
623 const void* BlockBuffer)
624 {
625 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
626 return HOST_SENDCONTROL_DeviceDisconnected;
627
628 uint8_t ErrorCode;
629
630 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
631 {
632 .DataTransferLength = cpu_to_le32((uint32_t)Blocks * BlockSize),
633 .Flags = MS_COMMAND_DIR_DATA_OUT,
634 .LUN = LUNIndex,
635 .SCSICommandLength = 10,
636 .SCSICommandData =
637 {
638 SCSI_CMD_WRITE_10,
639 0x00, // Unused (control bits, all off)
640 (BlockAddress >> 24), // MSB of Block Address
641 (BlockAddress >> 16),
642 (BlockAddress >> 8),
643 (BlockAddress & 0xFF), // LSB of Block Address
644 0x00, // Reserved
645 0x00, // MSB of Total Blocks to Write
646 Blocks, // LSB of Total Blocks to Write
647 0x00 // Unused (control)
648 }
649 };
650
651 MS_CommandStatusWrapper_t SCSICommandStatus;
652
653 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, BlockBuffer)) != PIPE_RWSTREAM_NoError)
654 return ErrorCode;
655
656 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
657 return ErrorCode;
658
659 return PIPE_RWSTREAM_NoError;
660 }
661
662 #endif
663