Update copyright year on all source files.
[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 "../../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 uint16_t Size;
83 uint8_t Type;
84 uint8_t Token;
85 uint8_t EndpointAddress;
86 bool DoubleBanked;
87
88 if (PipeNum == MSInterfaceInfo->Config.DataINPipeNumber)
89 {
90 Size = DataINEndpoint->EndpointSize;
91 EndpointAddress = DataINEndpoint->EndpointAddress;
92 Token = PIPE_TOKEN_IN;
93 Type = EP_TYPE_BULK;
94 DoubleBanked = MSInterfaceInfo->Config.DataINPipeDoubleBank;
95
96 MSInterfaceInfo->State.DataINPipeSize = DataINEndpoint->EndpointSize;
97 }
98 else if (PipeNum == MSInterfaceInfo->Config.DataOUTPipeNumber)
99 {
100 Size = DataOUTEndpoint->EndpointSize;
101 EndpointAddress = DataOUTEndpoint->EndpointAddress;
102 Token = PIPE_TOKEN_OUT;
103 Type = EP_TYPE_BULK;
104 DoubleBanked = MSInterfaceInfo->Config.DataOUTPipeDoubleBank;
105
106 MSInterfaceInfo->State.DataOUTPipeSize = DataOUTEndpoint->EndpointSize;
107 }
108 else
109 {
110 continue;
111 }
112
113 if (!(Pipe_ConfigurePipe(PipeNum, Type, Token, EndpointAddress, Size,
114 DoubleBanked ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE)))
115 {
116 return MS_ENUMERROR_PipeConfigurationFailed;
117 }
118 }
119
120 MSInterfaceInfo->State.InterfaceNumber = MassStorageInterface->InterfaceNumber;
121 MSInterfaceInfo->State.IsActive = true;
122
123 return MS_ENUMERROR_NoError;
124 }
125
126 static uint8_t DCOMP_MS_Host_NextMSInterface(void* const CurrentDescriptor)
127 {
128 USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
129
130 if (Header->Type == DTYPE_Interface)
131 {
132 USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);
133
134 if ((Interface->Class == MS_CSCP_MassStorageClass) &&
135 (Interface->SubClass == MS_CSCP_SCSITransparentSubclass) &&
136 (Interface->Protocol == MS_CSCP_BulkOnlyTransportProtocol))
137 {
138 return DESCRIPTOR_SEARCH_Found;
139 }
140 }
141
142 return DESCRIPTOR_SEARCH_NotFound;
143 }
144
145 static uint8_t DCOMP_MS_Host_NextMSInterfaceEndpoint(void* const CurrentDescriptor)
146 {
147 USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
148
149 if (Header->Type == DTYPE_Endpoint)
150 {
151 USB_Descriptor_Endpoint_t* Endpoint = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Endpoint_t);
152
153 uint8_t EndpointType = (Endpoint->Attributes & EP_TYPE_MASK);
154
155 if ((EndpointType == EP_TYPE_BULK) && (!(Pipe_IsEndpointBound(Endpoint->EndpointAddress))))
156 {
157 return DESCRIPTOR_SEARCH_Found;
158 }
159 }
160 else if (Header->Type == DTYPE_Interface)
161 {
162 return DESCRIPTOR_SEARCH_Fail;
163 }
164
165 return DESCRIPTOR_SEARCH_NotFound;
166 }
167
168 static uint8_t MS_Host_SendCommand(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
169 MS_CommandBlockWrapper_t* const SCSICommandBlock,
170 const void* const BufferPtr)
171 {
172 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
173
174 SCSICommandBlock->Signature = MS_CBW_SIGNATURE;
175 SCSICommandBlock->Tag = ++MSInterfaceInfo->State.TransactionTag;
176
177 if (MSInterfaceInfo->State.TransactionTag == 0xFFFFFFFF)
178 MSInterfaceInfo->State.TransactionTag = 1;
179
180 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
181 Pipe_Unfreeze();
182
183 if ((ErrorCode = Pipe_Write_Stream_LE(SCSICommandBlock, sizeof(MS_CommandBlockWrapper_t),
184 NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
185 return ErrorCode;
186
187 Pipe_ClearOUT();
188 Pipe_WaitUntilReady();
189
190 Pipe_Freeze();
191
192 if ((BufferPtr != NULL) &&
193 ((ErrorCode = MS_Host_SendReceiveData(MSInterfaceInfo, SCSICommandBlock, (void*)BufferPtr)) != PIPE_RWSTREAM_NoError))
194 {
195 Pipe_Freeze();
196 return ErrorCode;
197 }
198
199 return ErrorCode;
200 }
201
202 static uint8_t MS_Host_WaitForDataReceived(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo)
203 {
204 uint16_t TimeoutMSRem = MS_COMMAND_DATA_TIMEOUT_MS;
205 uint16_t PreviousFrameNumber = USB_Host_GetFrameNumber();
206
207 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
208 Pipe_Unfreeze();
209
210 while (!(Pipe_IsINReceived()))
211 {
212 uint16_t CurrentFrameNumber = USB_Host_GetFrameNumber();
213
214 if (CurrentFrameNumber != PreviousFrameNumber)
215 {
216 PreviousFrameNumber = CurrentFrameNumber;
217
218 if (!(TimeoutMSRem--))
219 return PIPE_RWSTREAM_Timeout;
220 }
221
222 Pipe_Freeze();
223 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
224 Pipe_Unfreeze();
225
226 if (Pipe_IsStalled())
227 {
228 USB_Host_ClearPipeStall(MSInterfaceInfo->Config.DataOUTPipeNumber);
229
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_ClearPipeStall(MSInterfaceInfo->Config.DataINPipeNumber);
240
241 return PIPE_RWSTREAM_PipeStalled;
242 }
243
244 if (USB_HostState == HOST_STATE_Unattached)
245 return PIPE_RWSTREAM_DeviceDisconnected;
246 };
247
248 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
249 Pipe_Freeze();
250
251 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
252 Pipe_Freeze();
253
254 return PIPE_RWSTREAM_NoError;
255 }
256
257 static uint8_t MS_Host_SendReceiveData(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
258 MS_CommandBlockWrapper_t* const SCSICommandBlock,
259 void* BufferPtr)
260 {
261 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
262 uint16_t BytesRem = SCSICommandBlock->DataTransferLength;
263
264 if (SCSICommandBlock->Flags & MS_COMMAND_DIR_DATA_IN)
265 {
266 if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError)
267 {
268 Pipe_Freeze();
269 return ErrorCode;
270 }
271
272 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
273 Pipe_Unfreeze();
274
275 if ((ErrorCode = Pipe_Read_Stream_LE(BufferPtr, BytesRem, NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
276 return ErrorCode;
277
278 Pipe_ClearIN();
279 }
280 else
281 {
282 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
283 Pipe_Unfreeze();
284
285 if ((ErrorCode = Pipe_Write_Stream_LE(BufferPtr, BytesRem, NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
286 return ErrorCode;
287
288 Pipe_ClearOUT();
289
290 while (!(Pipe_IsOUTReady()))
291 {
292 if (USB_HostState == HOST_STATE_Unattached)
293 return PIPE_RWSTREAM_DeviceDisconnected;
294 }
295 }
296
297 Pipe_Freeze();
298
299 return ErrorCode;
300 }
301
302 static uint8_t MS_Host_GetReturnedStatus(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
303 MS_CommandStatusWrapper_t* const SCSICommandStatus)
304 {
305 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
306
307 if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError)
308 return ErrorCode;
309
310 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
311 Pipe_Unfreeze();
312
313 if ((ErrorCode = Pipe_Read_Stream_LE(SCSICommandStatus, sizeof(MS_CommandStatusWrapper_t),
314 NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
315 {
316 return ErrorCode;
317 }
318
319 Pipe_ClearIN();
320 Pipe_Freeze();
321
322 if (SCSICommandStatus->Status != MS_SCSI_COMMAND_Pass)
323 ErrorCode = MS_ERROR_LOGICAL_CMD_FAILED;
324
325 return ErrorCode;
326 }
327
328 uint8_t MS_Host_ResetMSInterface(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo)
329 {
330 USB_ControlRequest = (USB_Request_Header_t)
331 {
332 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
333 .bRequest = MS_REQ_MassStorageReset,
334 .wValue = 0,
335 .wIndex = MSInterfaceInfo->State.InterfaceNumber,
336 .wLength = 0,
337 };
338
339 Pipe_SelectPipe(PIPE_CONTROLPIPE);
340
341 return USB_Host_SendControlRequest(NULL);
342 }
343
344 uint8_t MS_Host_GetMaxLUN(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
345 uint8_t* const MaxLUNIndex)
346 {
347 uint8_t ErrorCode = HOST_SENDCONTROL_Successful;
348
349 USB_ControlRequest = (USB_Request_Header_t)
350 {
351 .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
352 .bRequest = MS_REQ_GetMaxLUN,
353 .wValue = 0,
354 .wIndex = MSInterfaceInfo->State.InterfaceNumber,
355 .wLength = 1,
356 };
357
358 Pipe_SelectPipe(PIPE_CONTROLPIPE);
359
360 if ((ErrorCode = USB_Host_SendControlRequest(MaxLUNIndex)) != HOST_SENDCONTROL_Successful)
361 {
362 *MaxLUNIndex = 0;
363 ErrorCode = HOST_SENDCONTROL_Successful;
364 }
365
366 return ErrorCode;
367 }
368
369 uint8_t MS_Host_GetInquiryData(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
370 const uint8_t LUNIndex,
371 SCSI_Inquiry_Response_t* const InquiryData)
372 {
373 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
374 return HOST_SENDCONTROL_DeviceDisconnected;
375
376 uint8_t ErrorCode;
377
378 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
379 {
380 .DataTransferLength = sizeof(SCSI_Inquiry_Response_t),
381 .Flags = MS_COMMAND_DIR_DATA_IN,
382 .LUN = LUNIndex,
383 .SCSICommandLength = 6,
384 .SCSICommandData =
385 {
386 SCSI_CMD_INQUIRY,
387 0x00, // Reserved
388 0x00, // Reserved
389 0x00, // Reserved
390 sizeof(SCSI_Inquiry_Response_t), // Allocation Length
391 0x00 // Unused (control)
392 }
393 };
394
395 MS_CommandStatusWrapper_t SCSICommandStatus;
396
397 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, InquiryData)) != PIPE_RWSTREAM_NoError)
398 return ErrorCode;
399
400 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
401 return ErrorCode;
402
403 return PIPE_RWSTREAM_NoError;
404 }
405
406 uint8_t MS_Host_TestUnitReady(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
407 const uint8_t LUNIndex)
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 = 0,
417 .Flags = MS_COMMAND_DIR_DATA_IN,
418 .LUN = LUNIndex,
419 .SCSICommandLength = 6,
420 .SCSICommandData =
421 {
422 SCSI_CMD_TEST_UNIT_READY,
423 0x00, // Reserved
424 0x00, // Reserved
425 0x00, // Reserved
426 0x00, // Reserved
427 0x00 // Unused (control)
428 }
429 };
430
431 MS_CommandStatusWrapper_t SCSICommandStatus;
432
433 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, NULL)) != PIPE_RWSTREAM_NoError)
434 return ErrorCode;
435
436 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
437 return ErrorCode;
438
439 return PIPE_RWSTREAM_NoError;
440 }
441
442 uint8_t MS_Host_ReadDeviceCapacity(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
443 const uint8_t LUNIndex,
444 SCSI_Capacity_t* const DeviceCapacity)
445 {
446 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
447 return HOST_SENDCONTROL_DeviceDisconnected;
448
449 uint8_t ErrorCode;
450
451 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
452 {
453 .DataTransferLength = sizeof(SCSI_Capacity_t),
454 .Flags = MS_COMMAND_DIR_DATA_IN,
455 .LUN = LUNIndex,
456 .SCSICommandLength = 10,
457 .SCSICommandData =
458 {
459 SCSI_CMD_READ_CAPACITY_10,
460 0x00, // Reserved
461 0x00, // MSB of Logical block address
462 0x00,
463 0x00,
464 0x00, // LSB of Logical block address
465 0x00, // Reserved
466 0x00, // Reserved
467 0x00, // Partial Medium Indicator
468 0x00 // Unused (control)
469 }
470 };
471
472 MS_CommandStatusWrapper_t SCSICommandStatus;
473
474 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, DeviceCapacity)) != PIPE_RWSTREAM_NoError)
475 return ErrorCode;
476
477 SwapEndian_n(&DeviceCapacity->Blocks, sizeof(DeviceCapacity->Blocks));
478 SwapEndian_n(&DeviceCapacity->BlockSize, sizeof(DeviceCapacity->BlockSize));
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_RequestSense(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
487 const uint8_t LUNIndex,
488 SCSI_Request_Sense_Response_t* const SenseData)
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 = sizeof(SCSI_Request_Sense_Response_t),
498 .Flags = MS_COMMAND_DIR_DATA_IN,
499 .LUN = LUNIndex,
500 .SCSICommandLength = 6,
501 .SCSICommandData =
502 {
503 SCSI_CMD_REQUEST_SENSE,
504 0x00, // Reserved
505 0x00, // Reserved
506 0x00, // Reserved
507 sizeof(SCSI_Request_Sense_Response_t), // Allocation Length
508 0x00 // Unused (control)
509 }
510 };
511
512 MS_CommandStatusWrapper_t SCSICommandStatus;
513
514 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, SenseData)) != 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_PreventAllowMediumRemoval(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
524 const uint8_t LUNIndex,
525 const bool PreventRemoval)
526 {
527 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
528 return HOST_SENDCONTROL_DeviceDisconnected;
529
530 uint8_t ErrorCode;
531
532 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
533 {
534 .DataTransferLength = 0,
535 .Flags = MS_COMMAND_DIR_DATA_OUT,
536 .LUN = LUNIndex,
537 .SCSICommandLength = 6,
538 .SCSICommandData =
539 {
540 SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL,
541 0x00, // Reserved
542 0x00, // Reserved
543 PreventRemoval, // Prevent flag
544 0x00, // Reserved
545 0x00 // Unused (control)
546 }
547 };
548
549 MS_CommandStatusWrapper_t SCSICommandStatus;
550
551 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, NULL)) != PIPE_RWSTREAM_NoError)
552 return ErrorCode;
553
554 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
555 return ErrorCode;
556
557 return PIPE_RWSTREAM_NoError;
558 }
559
560 uint8_t MS_Host_ReadDeviceBlocks(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
561 const uint8_t LUNIndex,
562 const uint32_t BlockAddress,
563 const uint8_t Blocks,
564 const uint16_t BlockSize,
565 void* BlockBuffer)
566 {
567 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
568 return HOST_SENDCONTROL_DeviceDisconnected;
569
570 uint8_t ErrorCode;
571
572 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
573 {
574 .DataTransferLength = ((uint32_t)Blocks * BlockSize),
575 .Flags = MS_COMMAND_DIR_DATA_IN,
576 .LUN = LUNIndex,
577 .SCSICommandLength = 10,
578 .SCSICommandData =
579 {
580 SCSI_CMD_READ_10,
581 0x00, // Unused (control bits, all off)
582 (BlockAddress >> 24), // MSB of Block Address
583 (BlockAddress >> 16),
584 (BlockAddress >> 8),
585 (BlockAddress & 0xFF), // LSB of Block Address
586 0x00, // Reserved
587 0x00, // MSB of Total Blocks to Read
588 Blocks, // LSB of Total Blocks to Read
589 0x00 // Unused (control)
590 }
591 };
592
593 MS_CommandStatusWrapper_t SCSICommandStatus;
594
595 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, BlockBuffer)) != PIPE_RWSTREAM_NoError)
596 return ErrorCode;
597
598 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
599 return ErrorCode;
600
601 return PIPE_RWSTREAM_NoError;
602 }
603
604 uint8_t MS_Host_WriteDeviceBlocks(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
605 const uint8_t LUNIndex,
606 const uint32_t BlockAddress,
607 const uint8_t Blocks,
608 const uint16_t BlockSize,
609 const void* BlockBuffer)
610 {
611 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
612 return HOST_SENDCONTROL_DeviceDisconnected;
613
614 uint8_t ErrorCode;
615
616 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
617 {
618 .DataTransferLength = ((uint32_t)Blocks * BlockSize),
619 .Flags = MS_COMMAND_DIR_DATA_OUT,
620 .LUN = LUNIndex,
621 .SCSICommandLength = 10,
622 .SCSICommandData =
623 {
624 SCSI_CMD_WRITE_10,
625 0x00, // Unused (control bits, all off)
626 (BlockAddress >> 24), // MSB of Block Address
627 (BlockAddress >> 16),
628 (BlockAddress >> 8),
629 (BlockAddress & 0xFF), // LSB of Block Address
630 0x00, // Reserved
631 0x00, // MSB of Total Blocks to Write
632 Blocks, // LSB of Total Blocks to Write
633 0x00 // Unused (control)
634 }
635 };
636
637 MS_CommandStatusWrapper_t SCSICommandStatus;
638
639 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, BlockBuffer)) != PIPE_RWSTREAM_NoError)
640 return ErrorCode;
641
642 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
643 return ErrorCode;
644
645 return PIPE_RWSTREAM_NoError;
646 }
647
648 #endif
649