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