Added explicit ADC channel masks for the standard set of ADC channels, as the single...
[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 #include "../../HighLevel/USBMode.h"
32 #if defined(USB_CAN_BE_HOST)
33
34 #define INCLUDE_FROM_MS_CLASS_HOST_C
35 #include "MassStorage.h"
36
37 uint8_t MS_Host_ConfigurePipes(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, uint16_t ConfigDescriptorSize,
38 void* DeviceConfigDescriptor)
39 {
40 uint8_t FoundEndpoints = 0;
41
42 memset(&MSInterfaceInfo->State, 0x00, sizeof(MSInterfaceInfo->State));
43
44 if (DESCRIPTOR_TYPE(DeviceConfigDescriptor) != DTYPE_Configuration)
45 return MS_ENUMERROR_InvalidConfigDescriptor;
46
47 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &DeviceConfigDescriptor,
48 DComp_NextMSInterface) != DESCRIPTOR_SEARCH_COMP_Found)
49 {
50 return MS_ENUMERROR_NoMSInterfaceFound;
51 }
52
53 MSInterfaceInfo->State.InterfaceNumber = DESCRIPTOR_PCAST(DeviceConfigDescriptor, USB_Descriptor_Interface_t)->InterfaceNumber;
54
55 while (FoundEndpoints != (MS_FOUND_DATAPIPE_IN | MS_FOUND_DATAPIPE_OUT))
56 {
57 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &DeviceConfigDescriptor,
58 DComp_NextMSInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
59 {
60 return MS_ENUMERROR_EndpointsNotFound;
61 }
62
63 USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(DeviceConfigDescriptor, USB_Descriptor_Endpoint_t);
64
65 if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN)
66 {
67 Pipe_ConfigurePipe(MSInterfaceInfo->Config.DataINPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_IN,
68 EndpointData->EndpointAddress, EndpointData->EndpointSize,
69 MSInterfaceInfo->Config.DataINPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE);
70 MSInterfaceInfo->State.DataINPipeSize = EndpointData->EndpointSize;
71
72 FoundEndpoints |= MS_FOUND_DATAPIPE_IN;
73 }
74 else
75 {
76 Pipe_ConfigurePipe(MSInterfaceInfo->Config.DataOUTPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_OUT,
77 EndpointData->EndpointAddress, EndpointData->EndpointSize,
78 MSInterfaceInfo->Config.DataOUTPipeDoubleBank ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE);
79 MSInterfaceInfo->State.DataOUTPipeSize = EndpointData->EndpointSize;
80
81 FoundEndpoints |= MS_FOUND_DATAPIPE_OUT;
82 }
83 }
84
85 MSInterfaceInfo->State.IsActive = true;
86 return MS_ENUMERROR_NoError;
87 }
88
89 static uint8_t DComp_NextMSInterface(void* const CurrentDescriptor)
90 {
91 if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
92 {
93 USB_Descriptor_Interface_t* CurrentInterface = DESCRIPTOR_PCAST(CurrentDescriptor,
94 USB_Descriptor_Interface_t);
95
96 if ((CurrentInterface->Class == MASS_STORE_CLASS) &&
97 (CurrentInterface->SubClass == MASS_STORE_SUBCLASS) &&
98 (CurrentInterface->Protocol == MASS_STORE_PROTOCOL))
99 {
100 return DESCRIPTOR_SEARCH_Found;
101 }
102 }
103
104 return DESCRIPTOR_SEARCH_NotFound;
105 }
106
107 static uint8_t DComp_NextMSInterfaceEndpoint(void* const CurrentDescriptor)
108 {
109 if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Endpoint)
110 {
111 USB_Descriptor_Endpoint_t* CurrentEndpoint = DESCRIPTOR_PCAST(CurrentDescriptor,
112 USB_Descriptor_Endpoint_t);
113
114 uint8_t EndpointType = (CurrentEndpoint->Attributes & EP_TYPE_MASK);
115
116 if ((EndpointType == EP_TYPE_BULK) &&
117 (!(Pipe_IsEndpointBound(CurrentEndpoint->EndpointAddress))))
118 {
119 return DESCRIPTOR_SEARCH_Found;
120 }
121 }
122 else if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
123 {
124 return DESCRIPTOR_SEARCH_Fail;
125 }
126
127 return DESCRIPTOR_SEARCH_NotFound;
128 }
129
130 static uint8_t MS_Host_SendCommand(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, MS_CommandBlockWrapper_t* const SCSICommandBlock,
131 void* BufferPtr)
132 {
133 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
134
135 SCSICommandBlock->Tag = ++MSInterfaceInfo->State.TransactionTag;
136
137 if (MSInterfaceInfo->State.TransactionTag == 0xFFFFFFFF)
138 MSInterfaceInfo->State.TransactionTag = 1;
139
140 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
141 Pipe_Unfreeze();
142
143 if ((ErrorCode = Pipe_Write_Stream_LE(SCSICommandBlock, sizeof(MS_CommandBlockWrapper_t),
144 NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
145 return ErrorCode;
146
147 Pipe_ClearOUT();
148 Pipe_WaitUntilReady();
149
150 Pipe_Freeze();
151
152 if ((BufferPtr != NULL) &&
153 ((ErrorCode = MS_Host_SendReceiveData(MSInterfaceInfo, SCSICommandBlock, BufferPtr)) != PIPE_RWSTREAM_NoError))
154 {
155 Pipe_Freeze();
156 return ErrorCode;
157 }
158
159 return ErrorCode;
160 }
161
162 static uint8_t MS_Host_WaitForDataReceived(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo)
163 {
164 uint16_t TimeoutMSRem = COMMAND_DATA_TIMEOUT_MS;
165
166 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
167 Pipe_Unfreeze();
168
169 while (!(Pipe_IsINReceived()))
170 {
171 if (USB_INT_HasOccurred(USB_INT_HSOFI))
172 {
173 USB_INT_Clear(USB_INT_HSOFI);
174 TimeoutMSRem--;
175
176 if (!(TimeoutMSRem))
177 return PIPE_RWSTREAM_Timeout;
178 }
179
180 Pipe_Freeze();
181 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
182 Pipe_Unfreeze();
183
184 if (Pipe_IsStalled())
185 {
186 USB_Host_ClearPipeStall(MSInterfaceInfo->Config.DataOUTPipeNumber);
187
188 return PIPE_RWSTREAM_PipeStalled;
189 }
190
191 Pipe_Freeze();
192 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
193 Pipe_Unfreeze();
194
195 if (Pipe_IsStalled())
196 {
197 USB_Host_ClearPipeStall(MSInterfaceInfo->Config.DataINPipeNumber);
198
199 return PIPE_RWSTREAM_PipeStalled;
200 }
201
202 if (USB_HostState == HOST_STATE_Unattached)
203 return PIPE_RWSTREAM_DeviceDisconnected;
204 };
205
206 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
207 Pipe_Freeze();
208
209 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
210 Pipe_Freeze();
211
212 return PIPE_RWSTREAM_NoError;
213 }
214
215 static uint8_t MS_Host_SendReceiveData(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
216 MS_CommandBlockWrapper_t* const SCSICommandBlock, void* BufferPtr)
217 {
218 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
219 uint16_t BytesRem = SCSICommandBlock->DataTransferLength;
220
221 if (SCSICommandBlock->Flags & COMMAND_DIRECTION_DATA_IN)
222 {
223 if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError)
224 {
225 Pipe_Freeze();
226 return ErrorCode;
227 }
228
229 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
230 Pipe_Unfreeze();
231
232 if ((ErrorCode = Pipe_Read_Stream_LE(BufferPtr, BytesRem, NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
233 return ErrorCode;
234
235 Pipe_ClearIN();
236 }
237 else
238 {
239 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
240 Pipe_Unfreeze();
241
242 if ((ErrorCode = Pipe_Write_Stream_LE(BufferPtr, BytesRem, NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
243 return ErrorCode;
244
245 Pipe_ClearOUT();
246
247 while (!(Pipe_IsOUTReady()))
248 {
249 if (USB_HostState == HOST_STATE_Unattached)
250 return PIPE_RWSTREAM_DeviceDisconnected;
251 }
252 }
253
254 Pipe_Freeze();
255
256 return ErrorCode;
257 }
258
259 static uint8_t MS_Host_GetReturnedStatus(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
260 MS_CommandStatusWrapper_t* const SCSICommandStatus)
261 {
262 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
263
264 if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError)
265 return ErrorCode;
266
267 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
268 Pipe_Unfreeze();
269
270 if ((ErrorCode = Pipe_Read_Stream_LE(SCSICommandStatus, sizeof(MS_CommandStatusWrapper_t),
271 NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
272 {
273 return ErrorCode;
274 }
275
276 Pipe_ClearIN();
277 Pipe_Freeze();
278
279 if (SCSICommandStatus->Status != SCSI_Command_Pass)
280 ErrorCode = MS_ERROR_LOGICAL_CMD_FAILED;
281
282 return ErrorCode;
283 }
284
285 uint8_t MS_Host_ResetMSInterface(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo)
286 {
287 USB_ControlRequest = (USB_Request_Header_t)
288 {
289 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
290 .bRequest = REQ_MassStorageReset,
291 .wValue = 0,
292 .wIndex = MSInterfaceInfo->State.InterfaceNumber,
293 .wLength = 0,
294 };
295
296 Pipe_SelectPipe(PIPE_CONTROLPIPE);
297
298 return USB_Host_SendControlRequest(NULL);
299 }
300
301 uint8_t MS_Host_GetMaxLUN(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, uint8_t* const MaxLUNIndex)
302 {
303 uint8_t ErrorCode = HOST_SENDCONTROL_Successful;
304
305 USB_ControlRequest = (USB_Request_Header_t)
306 {
307 .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
308 .bRequest = REQ_GetMaxLUN,
309 .wValue = 0,
310 .wIndex = MSInterfaceInfo->State.InterfaceNumber,
311 .wLength = 1,
312 };
313
314 Pipe_SelectPipe(PIPE_CONTROLPIPE);
315
316 if ((ErrorCode = USB_Host_SendControlRequest(MaxLUNIndex)) != HOST_SENDCONTROL_Successful)
317 {
318 *MaxLUNIndex = 0;
319 ErrorCode = HOST_SENDCONTROL_Successful;
320 }
321
322 return ErrorCode;
323 }
324
325 uint8_t MS_Host_GetInquiryData(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex,
326 SCSI_Inquiry_Response_t* const InquiryData)
327 {
328 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
329 return HOST_SENDCONTROL_DeviceDisconnected;
330
331 uint8_t ErrorCode;
332
333 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
334 {
335 .Signature = CBW_SIGNATURE,
336 .DataTransferLength = sizeof(SCSI_Inquiry_Response_t),
337 .Flags = COMMAND_DIRECTION_DATA_IN,
338 .LUN = LUNIndex,
339 .SCSICommandLength = 6,
340 .SCSICommandData =
341 {
342 SCSI_CMD_INQUIRY,
343 0x00, // Reserved
344 0x00, // Reserved
345 0x00, // Reserved
346 sizeof(SCSI_Inquiry_Response_t), // Allocation Length
347 0x00 // Unused (control)
348 }
349 };
350
351 MS_CommandStatusWrapper_t SCSICommandStatus;
352
353 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, InquiryData)) != PIPE_RWSTREAM_NoError)
354 return ErrorCode;
355
356 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
357 return ErrorCode;
358
359 return PIPE_RWSTREAM_NoError;
360 }
361
362 uint8_t MS_Host_TestUnitReady(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex)
363 {
364 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
365 return HOST_SENDCONTROL_DeviceDisconnected;
366
367 uint8_t ErrorCode;
368
369 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
370 {
371 .Signature = CBW_SIGNATURE,
372 .DataTransferLength = 0,
373 .Flags = COMMAND_DIRECTION_DATA_IN,
374 .LUN = LUNIndex,
375 .SCSICommandLength = 6,
376 .SCSICommandData =
377 {
378 SCSI_CMD_TEST_UNIT_READY,
379 0x00, // Reserved
380 0x00, // Reserved
381 0x00, // Reserved
382 0x00, // Reserved
383 0x00 // Unused (control)
384 }
385 };
386
387 MS_CommandStatusWrapper_t SCSICommandStatus;
388
389 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, NULL)) != PIPE_RWSTREAM_NoError)
390 return ErrorCode;
391
392 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
393 return ErrorCode;
394
395 return PIPE_RWSTREAM_NoError;
396 }
397
398 uint8_t MS_Host_ReadDeviceCapacity(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex,
399 SCSI_Capacity_t* const DeviceCapacity)
400 {
401 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
402 return HOST_SENDCONTROL_DeviceDisconnected;
403
404 uint8_t ErrorCode;
405
406 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
407 {
408 .Signature = CBW_SIGNATURE,
409 .DataTransferLength = sizeof(SCSI_Capacity_t),
410 .Flags = COMMAND_DIRECTION_DATA_IN,
411 .LUN = LUNIndex,
412 .SCSICommandLength = 10,
413 .SCSICommandData =
414 {
415 SCSI_CMD_READ_CAPACITY_10,
416 0x00, // Reserved
417 0x00, // MSB of Logical block address
418 0x00,
419 0x00,
420 0x00, // LSB of Logical block address
421 0x00, // Reserved
422 0x00, // Reserved
423 0x00, // Partial Medium Indicator
424 0x00 // Unused (control)
425 }
426 };
427
428 MS_CommandStatusWrapper_t SCSICommandStatus;
429
430 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, DeviceCapacity)) != PIPE_RWSTREAM_NoError)
431 return ErrorCode;
432
433 DeviceCapacity->Blocks = SwapEndian_32(DeviceCapacity->Blocks);
434 DeviceCapacity->BlockSize = SwapEndian_32(DeviceCapacity->BlockSize);
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_RequestSense(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex,
443 SCSI_Request_Sense_Response_t* const SenseData)
444 {
445 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
446 return HOST_SENDCONTROL_DeviceDisconnected;
447
448 uint8_t ErrorCode;
449
450 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
451 {
452 .Signature = CBW_SIGNATURE,
453 .DataTransferLength = sizeof(SCSI_Request_Sense_Response_t),
454 .Flags = COMMAND_DIRECTION_DATA_IN,
455 .LUN = LUNIndex,
456 .SCSICommandLength = 6,
457 .SCSICommandData =
458 {
459 SCSI_CMD_REQUEST_SENSE,
460 0x00, // Reserved
461 0x00, // Reserved
462 0x00, // Reserved
463 sizeof(SCSI_Request_Sense_Response_t), // Allocation Length
464 0x00 // Unused (control)
465 }
466 };
467
468 MS_CommandStatusWrapper_t SCSICommandStatus;
469
470 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, SenseData)) != PIPE_RWSTREAM_NoError)
471 return ErrorCode;
472
473 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
474 return ErrorCode;
475
476 return PIPE_RWSTREAM_NoError;
477 }
478
479 uint8_t MS_Host_PreventAllowMediumRemoval(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex,
480 const bool PreventRemoval)
481 {
482 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
483 return HOST_SENDCONTROL_DeviceDisconnected;
484
485 uint8_t ErrorCode;
486
487 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
488 {
489 .Signature = CBW_SIGNATURE,
490 .DataTransferLength = 0,
491 .Flags = COMMAND_DIRECTION_DATA_OUT,
492 .LUN = LUNIndex,
493 .SCSICommandLength = 6,
494 .SCSICommandData =
495 {
496 SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL,
497 0x00, // Reserved
498 0x00, // Reserved
499 PreventRemoval, // Prevent flag
500 0x00, // Reserved
501 0x00 // Unused (control)
502 }
503 };
504
505 MS_CommandStatusWrapper_t SCSICommandStatus;
506
507 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, NULL)) != PIPE_RWSTREAM_NoError)
508 return ErrorCode;
509
510 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
511 return ErrorCode;
512
513 return PIPE_RWSTREAM_NoError;
514 }
515
516 uint8_t MS_Host_ReadDeviceBlocks(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex, const uint32_t BlockAddress,
517 const uint8_t Blocks, const uint16_t BlockSize, void* BlockBuffer)
518 {
519 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
520 return HOST_SENDCONTROL_DeviceDisconnected;
521
522 uint8_t ErrorCode;
523
524 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
525 {
526 .Signature = CBW_SIGNATURE,
527 .DataTransferLength = ((uint32_t)Blocks * BlockSize),
528 .Flags = COMMAND_DIRECTION_DATA_IN,
529 .LUN = LUNIndex,
530 .SCSICommandLength = 10,
531 .SCSICommandData =
532 {
533 SCSI_CMD_READ_10,
534 0x00, // Unused (control bits, all off)
535 (BlockAddress >> 24), // MSB of Block Address
536 (BlockAddress >> 16),
537 (BlockAddress >> 8),
538 (BlockAddress & 0xFF), // LSB of Block Address
539 0x00, // Unused (reserved)
540 0x00, // MSB of Total Blocks to Read
541 Blocks, // LSB of Total Blocks to Read
542 0x00 // Unused (control)
543 }
544 };
545
546 MS_CommandStatusWrapper_t SCSICommandStatus;
547
548 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, BlockBuffer)) != PIPE_RWSTREAM_NoError)
549 return ErrorCode;
550
551 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
552 return ErrorCode;
553
554 return PIPE_RWSTREAM_NoError;
555 }
556
557 uint8_t MS_Host_WriteDeviceBlocks(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo, const uint8_t LUNIndex, const uint32_t BlockAddress,
558 const uint8_t Blocks, const uint16_t BlockSize, void* BlockBuffer)
559 {
560 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
561 return HOST_SENDCONTROL_DeviceDisconnected;
562
563 uint8_t ErrorCode;
564
565 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
566 {
567 .Signature = CBW_SIGNATURE,
568 .DataTransferLength = ((uint32_t)Blocks * BlockSize),
569 .Flags = COMMAND_DIRECTION_DATA_OUT,
570 .LUN = LUNIndex,
571 .SCSICommandLength = 10,
572 .SCSICommandData =
573 {
574 SCSI_CMD_WRITE_10,
575 0x00, // Unused (control bits, all off)
576 (BlockAddress >> 24), // MSB of Block Address
577 (BlockAddress >> 16),
578 (BlockAddress >> 8),
579 (BlockAddress & 0xFF), // LSB of Block Address
580 0x00, // Unused (reserved)
581 0x00, // MSB of Total Blocks to Write
582 Blocks, // LSB of Total Blocks to Write
583 0x00 // Unused (control)
584 }
585 };
586
587 MS_CommandStatusWrapper_t SCSICommandStatus;
588
589 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, BlockBuffer)) != PIPE_RWSTREAM_NoError)
590 return ErrorCode;
591
592 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
593 return ErrorCode;
594
595 return PIPE_RWSTREAM_NoError;
596 }
597
598 #endif