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