Oops - Keyboard boot report structure should be an array of 6 keycodes.
[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 = DESCRIPTOR_PCAST(DeviceConfigDescriptor, USB_Descriptor_Interface_t)->InterfaceNumber;
54
55 while (FoundEndpoints != (MS_FOUND_DATAPIPE_IN | MS_FOUND_DATAPIPE_OUT))
56 {
57 if (USB_GetNextDescriptorComp(&ConfigDescriptorLength, &DeviceConfigDescriptor,
58 DComp_NextMSInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
59 {
60 return MS_ENUMERROR_EndpointsNotFound;
61 }
62
63 USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(DeviceConfigDescriptor, USB_Descriptor_Endpoint_t);
64
65 if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN)
66 {
67 Pipe_ConfigurePipe(MSInterfaceInfo->Config.DataINPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_IN,
68 EndpointData->EndpointAddress, EndpointData->EndpointSize,
69 PIPE_BANK_DOUBLE);
70 MSInterfaceInfo->State.DataINPipeSize = EndpointData->EndpointSize;
71
72 FoundEndpoints |= MS_FOUND_DATAPIPE_IN;
73 }
74 else
75 {
76 Pipe_ConfigurePipe(MSInterfaceInfo->Config.DataOUTPipeNumber, EP_TYPE_BULK, PIPE_TOKEN_OUT,
77 EndpointData->EndpointAddress, EndpointData->EndpointSize,
78 PIPE_BANK_DOUBLE);
79 MSInterfaceInfo->State.DataOUTPipeSize = EndpointData->EndpointSize;
80
81 FoundEndpoints |= MS_FOUND_DATAPIPE_OUT;
82 }
83 }
84
85 MSInterfaceInfo->State.IsActive = true;
86 return MS_ENUMERROR_NoError;
87 }
88
89 static uint8_t DComp_NextMSInterface(void* CurrentDescriptor)
90 {
91 if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface)
92 {
93 USB_Descriptor_Interface_t* CurrentInterface = DESCRIPTOR_PCAST(CurrentDescriptor,
94 USB_Descriptor_Interface_t);
95
96 if ((CurrentInterface->Class == MASS_STORE_CLASS) &&
97 (CurrentInterface->SubClass == MASS_STORE_SUBCLASS) &&
98 (CurrentInterface->Protocol == MASS_STORE_PROTOCOL))
99 {
100 return DESCRIPTOR_SEARCH_Found;
101 }
102 }
103
104 return DESCRIPTOR_SEARCH_NotFound;
105 }
106
107 static uint8_t DComp_NextMSInterfaceEndpoint(void* CurrentDescriptor)
108 {
109 if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Endpoint)
110 {
111 USB_Descriptor_Endpoint_t* CurrentEndpoint = DESCRIPTOR_PCAST(CurrentDescriptor,
112 USB_Descriptor_Endpoint_t);
113
114 uint8_t EndpointType = (CurrentEndpoint->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),
149 NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
150 return ErrorCode;
151
152 Pipe_ClearOUT();
153 Pipe_WaitUntilReady();
154
155 Pipe_Freeze();
156
157 if ((BufferPtr != NULL) &&
158 ((ErrorCode = MS_Host_SendReceiveData(MSInterfaceInfo, SCSICommandBlock, BufferPtr)) != PIPE_RWSTREAM_NoError))
159 {
160 Pipe_Freeze();
161 return ErrorCode;
162 }
163
164 return ErrorCode;
165 }
166
167 static uint8_t MS_Host_WaitForDataReceived(USB_ClassInfo_MS_Host_t* MSInterfaceInfo)
168 {
169 uint16_t TimeoutMSRem = COMMAND_DATA_TIMEOUT_MS;
170
171 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
172 Pipe_Unfreeze();
173
174 while (!(Pipe_IsINReceived()))
175 {
176 if (USB_INT_HasOccurred(USB_INT_HSOFI))
177 {
178 USB_INT_Clear(USB_INT_HSOFI);
179 TimeoutMSRem--;
180
181 if (!(TimeoutMSRem))
182 return PIPE_RWSTREAM_Timeout;
183 }
184
185 Pipe_Freeze();
186 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
187 Pipe_Unfreeze();
188
189 if (Pipe_IsStalled())
190 {
191 USB_Host_ClearPipeStall(MSInterfaceInfo->Config.DataOUTPipeNumber);
192
193 return PIPE_RWSTREAM_PipeStalled;
194 }
195
196 Pipe_Freeze();
197 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
198 Pipe_Unfreeze();
199
200 if (Pipe_IsStalled())
201 {
202 USB_Host_ClearPipeStall(MSInterfaceInfo->Config.DataINPipeNumber);
203
204 return PIPE_RWSTREAM_PipeStalled;
205 }
206
207 if (USB_HostState == HOST_STATE_Unattached)
208 return PIPE_RWSTREAM_DeviceDisconnected;
209 };
210
211 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
212 Pipe_Freeze();
213
214 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
215 Pipe_Freeze();
216
217 return PIPE_RWSTREAM_NoError;
218 }
219
220 static uint8_t MS_Host_SendReceiveData(USB_ClassInfo_MS_Host_t* MSInterfaceInfo,
221 MS_CommandBlockWrapper_t* SCSICommandBlock, void* BufferPtr)
222 {
223 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
224 uint16_t BytesRem = SCSICommandBlock->DataTransferLength;
225
226 if (SCSICommandBlock->Flags & COMMAND_DIRECTION_DATA_IN)
227 {
228 if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError)
229 {
230 Pipe_Freeze();
231 return ErrorCode;
232 }
233
234 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
235 Pipe_Unfreeze();
236
237 if ((ErrorCode = Pipe_Read_Stream_LE(BufferPtr, BytesRem, NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
238 return ErrorCode;
239
240 Pipe_ClearIN();
241 }
242 else
243 {
244 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
245 Pipe_Unfreeze();
246
247 if ((ErrorCode = Pipe_Write_Stream_LE(BufferPtr, BytesRem, NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
248 return ErrorCode;
249
250 Pipe_ClearOUT();
251
252 while (!(Pipe_IsOUTReady()))
253 {
254 if (USB_HostState == HOST_STATE_Unattached)
255 return PIPE_RWSTREAM_DeviceDisconnected;
256 }
257 }
258
259 Pipe_Freeze();
260
261 return ErrorCode;
262 }
263
264 static uint8_t MS_Host_GetReturnedStatus(USB_ClassInfo_MS_Host_t* MSInterfaceInfo,
265 MS_CommandStatusWrapper_t* SCSICommandStatus)
266 {
267 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
268
269 if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError)
270 return ErrorCode;
271
272 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
273 Pipe_Unfreeze();
274
275 if ((ErrorCode = Pipe_Read_Stream_LE(SCSICommandStatus, sizeof(MS_CommandStatusWrapper_t),
276 NO_STREAM_CALLBACK)) != PIPE_RWSTREAM_NoError)
277 {
278 return ErrorCode;
279 }
280
281 Pipe_ClearIN();
282 Pipe_Freeze();
283
284 if (SCSICommandStatus->Status != SCSI_Command_Pass)
285 ErrorCode = MS_ERROR_LOGICAL_CMD_FAILED;
286
287 return ErrorCode;
288 }
289
290 uint8_t MS_Host_ResetMSInterface(USB_ClassInfo_MS_Host_t* MSInterfaceInfo)
291 {
292 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
293 return HOST_SENDCONTROL_DeviceDisconnect;
294
295 USB_ControlRequest = (USB_Request_Header_t)
296 {
297 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
298 .bRequest = REQ_MassStorageReset,
299 .wValue = 0,
300 .wIndex = MSInterfaceInfo->State.InterfaceNumber,
301 .wLength = 0,
302 };
303
304 Pipe_SelectPipe(PIPE_CONTROLPIPE);
305
306 return USB_Host_SendControlRequest(NULL);
307 }
308
309 uint8_t MS_Host_GetMaxLUN(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t* MaxLUNIndex)
310 {
311 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
312 return HOST_SENDCONTROL_DeviceDisconnect;
313
314 uint8_t ErrorCode;
315
316 USB_ControlRequest = (USB_Request_Header_t)
317 {
318 .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
319 .bRequest = REQ_GetMaxLUN,
320 .wValue = 0,
321 .wIndex = MSInterfaceInfo->State.InterfaceNumber,
322 .wLength = 1,
323 };
324
325 Pipe_SelectPipe(PIPE_CONTROLPIPE);
326
327 if ((ErrorCode = USB_Host_SendControlRequest(MaxLUNIndex)) != HOST_SENDCONTROL_Successful)
328 *MaxLUNIndex = 0;
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.IsActive))
336 return HOST_SENDCONTROL_DeviceDisconnect;
337
338 uint8_t ErrorCode;
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 return ErrorCode;
362
363 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
364 return ErrorCode;
365
366 return PIPE_RWSTREAM_NoError;
367 }
368
369 uint8_t MS_Host_TestUnitReady(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex)
370 {
371 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
372 return HOST_SENDCONTROL_DeviceDisconnect;
373
374 uint8_t ErrorCode;
375
376 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
377 {
378 .Signature = CBW_SIGNATURE,
379 .DataTransferLength = 0,
380 .Flags = COMMAND_DIRECTION_DATA_IN,
381 .LUN = LUNIndex,
382 .SCSICommandLength = 6,
383 .SCSICommandData =
384 {
385 SCSI_CMD_TEST_UNIT_READY,
386 0x00, // Reserved
387 0x00, // Reserved
388 0x00, // Reserved
389 0x00, // Reserved
390 0x00 // Unused (control)
391 }
392 };
393
394 MS_CommandStatusWrapper_t SCSICommandStatus;
395
396 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, NULL)) != PIPE_RWSTREAM_NoError)
397 return ErrorCode;
398
399 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
400 return ErrorCode;
401
402 return PIPE_RWSTREAM_NoError;
403 }
404
405 uint8_t MS_Host_ReadDeviceCapacity(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex,
406 SCSI_Capacity_t* DeviceCapacity)
407 {
408 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
409 return HOST_SENDCONTROL_DeviceDisconnect;
410
411 uint8_t ErrorCode;
412
413 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
414 {
415 .Signature = CBW_SIGNATURE,
416 .DataTransferLength = sizeof(SCSI_Capacity_t),
417 .Flags = COMMAND_DIRECTION_DATA_IN,
418 .LUN = LUNIndex,
419 .SCSICommandLength = 10,
420 .SCSICommandData =
421 {
422 SCSI_CMD_READ_CAPACITY_10,
423 0x00, // Reserved
424 0x00, // MSB of Logical block address
425 0x00,
426 0x00,
427 0x00, // LSB of Logical block address
428 0x00, // Reserved
429 0x00, // Reserved
430 0x00, // Partial Medium Indicator
431 0x00 // Unused (control)
432 }
433 };
434
435 MS_CommandStatusWrapper_t SCSICommandStatus;
436
437 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, DeviceCapacity)) != PIPE_RWSTREAM_NoError)
438 return ErrorCode;
439
440 DeviceCapacity->Blocks = SwapEndian_32(DeviceCapacity->Blocks);
441 DeviceCapacity->BlockSize = SwapEndian_32(DeviceCapacity->BlockSize);
442
443 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
444 return ErrorCode;
445
446 return PIPE_RWSTREAM_NoError;
447 }
448
449 uint8_t MS_Host_RequestSense(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex,
450 SCSI_Request_Sense_Response_t* SenseData)
451 {
452 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
453 return HOST_SENDCONTROL_DeviceDisconnect;
454
455 uint8_t ErrorCode;
456
457 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
458 {
459 .Signature = CBW_SIGNATURE,
460 .DataTransferLength = sizeof(SCSI_Request_Sense_Response_t),
461 .Flags = COMMAND_DIRECTION_DATA_IN,
462 .LUN = LUNIndex,
463 .SCSICommandLength = 6,
464 .SCSICommandData =
465 {
466 SCSI_CMD_REQUEST_SENSE,
467 0x00, // Reserved
468 0x00, // Reserved
469 0x00, // Reserved
470 sizeof(SCSI_Request_Sense_Response_t), // Allocation Length
471 0x00 // Unused (control)
472 }
473 };
474
475 MS_CommandStatusWrapper_t SCSICommandStatus;
476
477 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, SenseData)) != PIPE_RWSTREAM_NoError)
478 return ErrorCode;
479
480 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
481 return ErrorCode;
482
483 return PIPE_RWSTREAM_NoError;
484 }
485
486 uint8_t MS_Host_PreventAllowMediumRemoval(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex, bool PreventRemoval)
487 {
488 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
489 return HOST_SENDCONTROL_DeviceDisconnect;
490
491 uint8_t ErrorCode;
492
493 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
494 {
495 .Signature = CBW_SIGNATURE,
496 .DataTransferLength = 0,
497 .Flags = COMMAND_DIRECTION_DATA_OUT,
498 .LUN = LUNIndex,
499 .SCSICommandLength = 6,
500 .SCSICommandData =
501 {
502 SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL,
503 0x00, // Reserved
504 0x00, // Reserved
505 PreventRemoval, // Prevent flag
506 0x00, // Reserved
507 0x00 // Unused (control)
508 }
509 };
510
511 MS_CommandStatusWrapper_t SCSICommandStatus;
512
513 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, NULL)) != PIPE_RWSTREAM_NoError)
514 return ErrorCode;
515
516 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
517 return ErrorCode;
518
519 return PIPE_RWSTREAM_NoError;
520 }
521
522 uint8_t MS_Host_ReadDeviceBlocks(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex, uint32_t BlockAddress,
523 uint8_t Blocks, uint16_t BlockSize, void* BlockBuffer)
524 {
525 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
526 return HOST_SENDCONTROL_DeviceDisconnect;
527
528 uint8_t ErrorCode;
529
530 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
531 {
532 .Signature = CBW_SIGNATURE,
533 .DataTransferLength = ((uint32_t)Blocks * BlockSize),
534 .Flags = COMMAND_DIRECTION_DATA_IN,
535 .LUN = LUNIndex,
536 .SCSICommandLength = 10,
537 .SCSICommandData =
538 {
539 SCSI_CMD_READ_10,
540 0x00, // Unused (control bits, all off)
541 (BlockAddress >> 24), // MSB of Block Address
542 (BlockAddress >> 16),
543 (BlockAddress >> 8),
544 (BlockAddress & 0xFF), // LSB of Block Address
545 0x00, // Unused (reserved)
546 0x00, // MSB of Total Blocks to Read
547 Blocks, // LSB of Total Blocks to Read
548 0x00 // Unused (control)
549 }
550 };
551
552 MS_CommandStatusWrapper_t SCSICommandStatus;
553
554 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, BlockBuffer)) != PIPE_RWSTREAM_NoError)
555 return ErrorCode;
556
557 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
558 return ErrorCode;
559
560 return PIPE_RWSTREAM_NoError;
561 }
562
563 uint8_t MS_Host_WriteDeviceBlocks(USB_ClassInfo_MS_Host_t* MSInterfaceInfo, uint8_t LUNIndex, uint32_t BlockAddress,
564 uint8_t Blocks, uint16_t BlockSize, void* BlockBuffer)
565 {
566 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
567 return HOST_SENDCONTROL_DeviceDisconnect;
568
569 uint8_t ErrorCode;
570
571 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
572 {
573 .Signature = CBW_SIGNATURE,
574 .DataTransferLength = ((uint32_t)Blocks * BlockSize),
575 .Flags = COMMAND_DIRECTION_DATA_OUT,
576 .LUN = LUNIndex,
577 .SCSICommandLength = 10,
578 .SCSICommandData =
579 {
580 SCSI_CMD_WRITE_10,
581 0x00, // Unused (control bits, all off)
582 (BlockAddress >> 24), // MSB of Block Address
583 (BlockAddress >> 16),
584 (BlockAddress >> 8),
585 (BlockAddress & 0xFF), // LSB of Block Address
586 0x00, // Unused (reserved)
587 0x00, // MSB of Total Blocks to Write
588 Blocks, // LSB of Total Blocks to Write
589 0x00 // Unused (control)
590 }
591 };
592
593 MS_CommandStatusWrapper_t SCSICommandStatus;
594
595 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, BlockBuffer)) != PIPE_RWSTREAM_NoError)
596 return ErrorCode;
597
598 if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
599 return ErrorCode;
600
601 return PIPE_RWSTREAM_NoError;
602 }
603
604 #endif