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