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