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