Changed HIDParser to only zero out important values in the Parsed HID Report Item...
[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.Active = 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.Active))
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.Active))
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 ErrorCode;
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.Active))
341 return HOST_SENDCONTROL_DeviceDisconnect;
342
343 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
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 {
367 Pipe_Freeze();
368 return ErrorCode;
369 }
370
371 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
372 {
373 Pipe_Freeze();
374 return ErrorCode;
375 }
376
377 return ErrorCode;
378 }
379
380 uint8_t MS_Host_TestUnitReady(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex)
381 {
382 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.Active))
383 return HOST_SENDCONTROL_DeviceDisconnect;
384
385 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
386
387 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
388 {
389 .Signature = CBW_SIGNATURE,
390 .DataTransferLength = 0,
391 .Flags = COMMAND_DIRECTION_DATA_IN,
392 .LUN = LUNIndex,
393 .SCSICommandLength = 6,
394 .SCSICommandData =
395 {
396 SCSI_CMD_TEST_UNIT_READY,
397 0x00, // Reserved
398 0x00, // Reserved
399 0x00, // Reserved
400 0x00, // Reserved
401 0x00 // Unused (control)
402 }
403 };
404
405 MS_CommandStatusWrapper_t SCSICommandStatus;
406
407 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, NULL)) != PIPE_RWSTREAM_NoError)
408 {
409 Pipe_Freeze();
410 return ErrorCode;
411 }
412
413 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
414 {
415 Pipe_Freeze();
416 return ErrorCode;
417 }
418
419 return ErrorCode;
420 }
421
422 uint8_t MS_Host_ReadDeviceCapacity(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex,
423 SCSI_Capacity_t* DeviceCapacity)
424 {
425 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.Active))
426 return HOST_SENDCONTROL_DeviceDisconnect;
427
428 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
429
430 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
431 {
432 .Signature = CBW_SIGNATURE,
433 .DataTransferLength = sizeof(SCSI_Capacity_t),
434 .Flags = COMMAND_DIRECTION_DATA_IN,
435 .LUN = LUNIndex,
436 .SCSICommandLength = 10,
437 .SCSICommandData =
438 {
439 SCSI_CMD_READ_CAPACITY_10,
440 0x00, // Reserved
441 0x00, // MSB of Logical block address
442 0x00,
443 0x00,
444 0x00, // LSB of Logical block address
445 0x00, // Reserved
446 0x00, // Reserved
447 0x00, // Partial Medium Indicator
448 0x00 // Unused (control)
449 }
450 };
451
452 MS_CommandStatusWrapper_t SCSICommandStatus;
453
454 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, DeviceCapacity)) != PIPE_RWSTREAM_NoError)
455 {
456 Pipe_Freeze();
457 return ErrorCode;
458 }
459
460 DeviceCapacity->Blocks = SwapEndian_32(DeviceCapacity->Blocks);
461 DeviceCapacity->BlockSize = SwapEndian_32(DeviceCapacity->BlockSize);
462
463 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
464 {
465 Pipe_Freeze();
466 return ErrorCode;
467 }
468
469 return ErrorCode;
470 }
471
472 uint8_t MS_Host_RequestSense(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex,
473 SCSI_Request_Sense_Response_t* SenseData)
474 {
475 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.Active))
476 return HOST_SENDCONTROL_DeviceDisconnect;
477
478 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
479
480 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
481 {
482 .Signature = CBW_SIGNATURE,
483 .DataTransferLength = sizeof(SCSI_Request_Sense_Response_t),
484 .Flags = COMMAND_DIRECTION_DATA_IN,
485 .LUN = LUNIndex,
486 .SCSICommandLength = 6,
487 .SCSICommandData =
488 {
489 SCSI_CMD_REQUEST_SENSE,
490 0x00, // Reserved
491 0x00, // Reserved
492 0x00, // Reserved
493 sizeof(SCSI_Request_Sense_Response_t), // Allocation Length
494 0x00 // Unused (control)
495 }
496 };
497
498 MS_CommandStatusWrapper_t SCSICommandStatus;
499
500 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, SenseData)) != PIPE_RWSTREAM_NoError)
501 {
502 Pipe_Freeze();
503 return ErrorCode;
504 }
505
506 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
507 {
508 Pipe_Freeze();
509 return ErrorCode;
510 }
511
512 return ErrorCode;
513 }
514
515 uint8_t MS_Host_PreventAllowMediumRemoval(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex, bool PreventRemoval)
516 {
517 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.Active))
518 return HOST_SENDCONTROL_DeviceDisconnect;
519
520 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
521
522 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
523 {
524 .Signature = CBW_SIGNATURE,
525 .DataTransferLength = 0,
526 .Flags = COMMAND_DIRECTION_DATA_OUT,
527 .LUN = LUNIndex,
528 .SCSICommandLength = 6,
529 .SCSICommandData =
530 {
531 SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL,
532 0x00, // Reserved
533 0x00, // Reserved
534 PreventRemoval, // Prevent flag
535 0x00, // Reserved
536 0x00 // Unused (control)
537 }
538 };
539
540 MS_CommandStatusWrapper_t SCSICommandStatus;
541
542 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, NULL)) != PIPE_RWSTREAM_NoError)
543 {
544 Pipe_Freeze();
545 return ErrorCode;
546 }
547
548 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
549 {
550 Pipe_Freeze();
551 return ErrorCode;
552 }
553
554 return ErrorCode;
555 }
556
557 uint8_t MS_Host_ReadDeviceBlocks(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex, uint32_t BlockAddress,
558 uint8_t Blocks, uint16_t BlockSize, void* BlockBuffer)
559 {
560 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.Active))
561 return HOST_SENDCONTROL_DeviceDisconnect;
562
563 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
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_IN,
570 .LUN = LUNIndex,
571 .SCSICommandLength = 10,
572 .SCSICommandData =
573 {
574 SCSI_CMD_READ_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 Read
582 Blocks, // LSB of Total Blocks to Read
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 {
591 Pipe_Freeze();
592 return ErrorCode;
593 }
594
595 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
596 {
597 Pipe_Freeze();
598 return ErrorCode;
599 }
600
601 return ErrorCode;
602 }
603
604 uint8_t MS_Host_WriteDeviceBlocks(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex, uint32_t BlockAddress,
605 uint8_t Blocks, uint16_t BlockSize, void* BlockBuffer)
606 {
607 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.Active))
608 return HOST_SENDCONTROL_DeviceDisconnect;
609
610 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
611
612 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
613 {
614 .Signature = CBW_SIGNATURE,
615 .DataTransferLength = ((uint32_t)Blocks * BlockSize),
616 .Flags = COMMAND_DIRECTION_DATA_OUT,
617 .LUN = LUNIndex,
618 .SCSICommandLength = 10,
619 .SCSICommandData =
620 {
621 SCSI_CMD_WRITE_10,
622 0x00, // Unused (control bits, all off)
623 (BlockAddress >> 24), // MSB of Block Address
624 (BlockAddress >> 16),
625 (BlockAddress >> 8),
626 (BlockAddress & 0xFF), // LSB of Block Address
627 0x00, // Unused (reserved)
628 0x00, // MSB of Total Blocks to Write
629 Blocks, // LSB of Total Blocks to Write
630 0x00 // Unused (control)
631 }
632 };
633
634 MS_CommandStatusWrapper_t SCSICommandStatus;
635
636 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, BlockBuffer)) != PIPE_RWSTREAM_NoError)
637 {
638 Pipe_Freeze();
639 return ErrorCode;
640 }
641
642 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
643 {
644 Pipe_Freeze();
645 return ErrorCode;
646 }
647
648 return ErrorCode;
649 }
650
651 #endif