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