]> git.gir.st - tmk_keyboard.git/blob - tmk_core/protocol/lufa/LUFA-120730/LUFA/Drivers/USB/Class/Host/MassStorageClassHost.c
Merge commit 'a074364c3731d66b56d988c8a6c960a83ea0e0a1' as 'tmk_core'
[tmk_keyboard.git] / tmk_core / protocol / lufa / LUFA-120730 / LUFA / Drivers / USB / Class / Host / MassStorageClassHost.c
1 /*
2 LUFA Library
3 Copyright (C) Dean Camera, 2012.
4
5 dean [at] fourwalledcubicle [dot] com
6 www.lufa-lib.org
7 */
8
9 /*
10 Copyright 2012 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 "../../Core/USBMode.h"
33
34 #if defined(USB_CAN_BE_HOST)
35
36 #define __INCLUDE_FROM_MS_DRIVER
37 #define __INCLUDE_FROM_MASSSTORAGE_HOST_C
38 #include "MassStorageClassHost.h"
39
40 uint8_t MS_Host_ConfigurePipes(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
41 uint16_t ConfigDescriptorSize,
42 void* ConfigDescriptorData)
43 {
44 USB_Descriptor_Endpoint_t* DataINEndpoint = NULL;
45 USB_Descriptor_Endpoint_t* DataOUTEndpoint = NULL;
46 USB_Descriptor_Interface_t* MassStorageInterface = NULL;
47
48 memset(&MSInterfaceInfo->State, 0x00, sizeof(MSInterfaceInfo->State));
49
50 if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration)
51 return MS_ENUMERROR_InvalidConfigDescriptor;
52
53 while (!(DataINEndpoint) || !(DataOUTEndpoint))
54 {
55 if (!(MassStorageInterface) ||
56 USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
57 DCOMP_MS_Host_NextMSInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
58 {
59 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
60 DCOMP_MS_Host_NextMSInterface) != DESCRIPTOR_SEARCH_COMP_Found)
61 {
62 return MS_ENUMERROR_NoCompatibleInterfaceFound;
63 }
64
65 MassStorageInterface = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Interface_t);
66
67 DataINEndpoint = NULL;
68 DataOUTEndpoint = NULL;
69
70 continue;
71 }
72
73 USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t);
74
75 if ((EndpointData->EndpointAddress & ENDPOINT_DIR_MASK) == ENDPOINT_DIR_IN)
76 DataINEndpoint = EndpointData;
77 else
78 DataOUTEndpoint = EndpointData;
79 }
80
81 MSInterfaceInfo->Config.DataINPipe.Size = le16_to_cpu(DataINEndpoint->EndpointSize);
82 MSInterfaceInfo->Config.DataINPipe.EndpointAddress = DataINEndpoint->EndpointAddress;
83 MSInterfaceInfo->Config.DataINPipe.Type = EP_TYPE_BULK;
84
85 MSInterfaceInfo->Config.DataOUTPipe.Size = le16_to_cpu(DataOUTEndpoint->EndpointSize);
86 MSInterfaceInfo->Config.DataOUTPipe.EndpointAddress = DataOUTEndpoint->EndpointAddress;
87 MSInterfaceInfo->Config.DataOUTPipe.Type = EP_TYPE_BULK;
88
89 if (!(Pipe_ConfigurePipeTable(&MSInterfaceInfo->Config.DataINPipe, 1)))
90 return false;
91
92 if (!(Pipe_ConfigurePipeTable(&MSInterfaceInfo->Config.DataOUTPipe, 1)))
93 return false;
94
95 MSInterfaceInfo->State.InterfaceNumber = MassStorageInterface->InterfaceNumber;
96 MSInterfaceInfo->State.IsActive = true;
97
98 return MS_ENUMERROR_NoError;
99 }
100
101 static uint8_t DCOMP_MS_Host_NextMSInterface(void* const CurrentDescriptor)
102 {
103 USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
104
105 if (Header->Type == DTYPE_Interface)
106 {
107 USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);
108
109 if ((Interface->Class == MS_CSCP_MassStorageClass) &&
110 (Interface->SubClass == MS_CSCP_SCSITransparentSubclass) &&
111 (Interface->Protocol == MS_CSCP_BulkOnlyTransportProtocol))
112 {
113 return DESCRIPTOR_SEARCH_Found;
114 }
115 }
116
117 return DESCRIPTOR_SEARCH_NotFound;
118 }
119
120 static uint8_t DCOMP_MS_Host_NextMSInterfaceEndpoint(void* const CurrentDescriptor)
121 {
122 USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
123
124 if (Header->Type == DTYPE_Endpoint)
125 {
126 USB_Descriptor_Endpoint_t* Endpoint = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Endpoint_t);
127
128 uint8_t EndpointType = (Endpoint->Attributes & EP_TYPE_MASK);
129
130 if ((EndpointType == EP_TYPE_BULK) && (!(Pipe_IsEndpointBound(Endpoint->EndpointAddress))))
131 {
132 return DESCRIPTOR_SEARCH_Found;
133 }
134 }
135 else if (Header->Type == DTYPE_Interface)
136 {
137 return DESCRIPTOR_SEARCH_Fail;
138 }
139
140 return DESCRIPTOR_SEARCH_NotFound;
141 }
142
143 static uint8_t MS_Host_SendCommand(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
144 MS_CommandBlockWrapper_t* const SCSICommandBlock,
145 const void* const BufferPtr)
146 {
147 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
148
149 if (++MSInterfaceInfo->State.TransactionTag == 0xFFFFFFFF)
150 MSInterfaceInfo->State.TransactionTag = 1;
151
152 SCSICommandBlock->Signature = CPU_TO_LE32(MS_CBW_SIGNATURE);
153 SCSICommandBlock->Tag = cpu_to_le32(MSInterfaceInfo->State.TransactionTag);
154
155 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipe.Address);
156 Pipe_Unfreeze();
157
158 if ((ErrorCode = Pipe_Write_Stream_LE(SCSICommandBlock, sizeof(MS_CommandBlockWrapper_t),
159 NULL)) != PIPE_RWSTREAM_NoError)
160 {
161 return ErrorCode;
162 }
163
164 Pipe_ClearOUT();
165 Pipe_WaitUntilReady();
166
167 Pipe_Freeze();
168
169 if (BufferPtr != NULL)
170 {
171 ErrorCode = MS_Host_SendReceiveData(MSInterfaceInfo, SCSICommandBlock, (void*)BufferPtr);
172
173 if ((ErrorCode != PIPE_RWSTREAM_NoError) && (ErrorCode != PIPE_RWSTREAM_PipeStalled))
174 {
175 Pipe_Freeze();
176 return ErrorCode;
177 }
178 }
179
180 MS_CommandStatusWrapper_t SCSIStatusBlock;
181 return MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSIStatusBlock);
182 }
183
184 static uint8_t MS_Host_WaitForDataReceived(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo)
185 {
186 uint16_t TimeoutMSRem = MS_COMMAND_DATA_TIMEOUT_MS;
187 uint16_t PreviousFrameNumber = USB_Host_GetFrameNumber();
188
189 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipe.Address);
190 Pipe_Unfreeze();
191
192 while (!(Pipe_IsINReceived()))
193 {
194 uint16_t CurrentFrameNumber = USB_Host_GetFrameNumber();
195
196 if (CurrentFrameNumber != PreviousFrameNumber)
197 {
198 PreviousFrameNumber = CurrentFrameNumber;
199
200 if (!(TimeoutMSRem--))
201 return PIPE_RWSTREAM_Timeout;
202 }
203
204 Pipe_Freeze();
205 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipe.Address);
206 Pipe_Unfreeze();
207
208 if (Pipe_IsStalled())
209 {
210 USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress());
211 return PIPE_RWSTREAM_PipeStalled;
212 }
213
214 Pipe_Freeze();
215 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipe.Address);
216 Pipe_Unfreeze();
217
218 if (Pipe_IsStalled())
219 {
220 USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress());
221 return PIPE_RWSTREAM_PipeStalled;
222 }
223
224 if (USB_HostState == HOST_STATE_Unattached)
225 return PIPE_RWSTREAM_DeviceDisconnected;
226 };
227
228 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipe.Address);
229 Pipe_Freeze();
230
231 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipe.Address);
232 Pipe_Freeze();
233
234 return PIPE_RWSTREAM_NoError;
235 }
236
237 static uint8_t MS_Host_SendReceiveData(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
238 MS_CommandBlockWrapper_t* const SCSICommandBlock,
239 void* BufferPtr)
240 {
241 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
242 uint16_t BytesRem = le32_to_cpu(SCSICommandBlock->DataTransferLength);
243
244 if (SCSICommandBlock->Flags & MS_COMMAND_DIR_DATA_IN)
245 {
246 if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError)
247 {
248 Pipe_Freeze();
249 return ErrorCode;
250 }
251
252 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipe.Address);
253 Pipe_Unfreeze();
254
255 if ((ErrorCode = Pipe_Read_Stream_LE(BufferPtr, BytesRem, NULL)) != PIPE_RWSTREAM_NoError)
256 return ErrorCode;
257
258 Pipe_ClearIN();
259 }
260 else
261 {
262 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipe.Address);
263 Pipe_Unfreeze();
264
265 if ((ErrorCode = Pipe_Write_Stream_LE(BufferPtr, BytesRem, NULL)) != PIPE_RWSTREAM_NoError)
266 return ErrorCode;
267
268 Pipe_ClearOUT();
269
270 while (!(Pipe_IsOUTReady()))
271 {
272 if (USB_HostState == HOST_STATE_Unattached)
273 return PIPE_RWSTREAM_DeviceDisconnected;
274 }
275 }
276
277 Pipe_Freeze();
278
279 return ErrorCode;
280 }
281
282 static uint8_t MS_Host_GetReturnedStatus(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
283 MS_CommandStatusWrapper_t* const SCSICommandStatus)
284 {
285 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
286
287 if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError)
288 return ErrorCode;
289
290 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipe.Address);
291 Pipe_Unfreeze();
292
293 if ((ErrorCode = Pipe_Read_Stream_LE(SCSICommandStatus, sizeof(MS_CommandStatusWrapper_t),
294 NULL)) != PIPE_RWSTREAM_NoError)
295 {
296 return ErrorCode;
297 }
298
299 Pipe_ClearIN();
300 Pipe_Freeze();
301
302 if (SCSICommandStatus->Status != MS_SCSI_COMMAND_Pass)
303 ErrorCode = MS_ERROR_LOGICAL_CMD_FAILED;
304
305 return ErrorCode;
306 }
307
308 uint8_t MS_Host_ResetMSInterface(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo)
309 {
310 uint8_t ErrorCode;
311
312 USB_ControlRequest = (USB_Request_Header_t)
313 {
314 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
315 .bRequest = MS_REQ_MassStorageReset,
316 .wValue = 0,
317 .wIndex = MSInterfaceInfo->State.InterfaceNumber,
318 .wLength = 0,
319 };
320
321 Pipe_SelectPipe(PIPE_CONTROLPIPE);
322
323 if ((ErrorCode = USB_Host_SendControlRequest(NULL)) != HOST_SENDCONTROL_Successful)
324 return ErrorCode;
325
326 Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipe.Address);
327
328 if ((ErrorCode = USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress())) != HOST_SENDCONTROL_Successful)
329 return ErrorCode;
330
331 Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipe.Address);
332
333 if ((ErrorCode = USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress())) != HOST_SENDCONTROL_Successful)
334 return ErrorCode;
335
336 return HOST_SENDCONTROL_Successful;
337 }
338
339 uint8_t MS_Host_GetMaxLUN(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
340 uint8_t* const MaxLUNIndex)
341 {
342 uint8_t ErrorCode;
343
344 USB_ControlRequest = (USB_Request_Header_t)
345 {
346 .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
347 .bRequest = MS_REQ_GetMaxLUN,
348 .wValue = 0,
349 .wIndex = MSInterfaceInfo->State.InterfaceNumber,
350 .wLength = 1,
351 };
352
353 Pipe_SelectPipe(PIPE_CONTROLPIPE);
354
355 if ((ErrorCode = USB_Host_SendControlRequest(MaxLUNIndex)) == HOST_SENDCONTROL_SetupStalled)
356 {
357 *MaxLUNIndex = 0;
358 ErrorCode = HOST_SENDCONTROL_Successful;
359 }
360
361 return ErrorCode;
362 }
363
364 uint8_t MS_Host_GetInquiryData(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
365 const uint8_t LUNIndex,
366 SCSI_Inquiry_Response_t* const InquiryData)
367 {
368 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
369 return HOST_SENDCONTROL_DeviceDisconnected;
370
371 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
372 {
373 .DataTransferLength = CPU_TO_LE32(sizeof(SCSI_Inquiry_Response_t)),
374 .Flags = MS_COMMAND_DIR_DATA_IN,
375 .LUN = LUNIndex,
376 .SCSICommandLength = 6,
377 .SCSICommandData =
378 {
379 SCSI_CMD_INQUIRY,
380 0x00, // Reserved
381 0x00, // Reserved
382 0x00, // Reserved
383 sizeof(SCSI_Inquiry_Response_t), // Allocation Length
384 0x00 // Unused (control)
385 }
386 };
387
388 return MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, InquiryData);
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 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
398 {
399 .DataTransferLength = CPU_TO_LE32(0),
400 .Flags = MS_COMMAND_DIR_DATA_IN,
401 .LUN = LUNIndex,
402 .SCSICommandLength = 6,
403 .SCSICommandData =
404 {
405 SCSI_CMD_TEST_UNIT_READY,
406 0x00, // Reserved
407 0x00, // Reserved
408 0x00, // Reserved
409 0x00, // Reserved
410 0x00 // Unused (control)
411 }
412 };
413
414 return MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, NULL);
415 }
416
417 uint8_t MS_Host_ReadDeviceCapacity(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
418 const uint8_t LUNIndex,
419 SCSI_Capacity_t* const DeviceCapacity)
420 {
421 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
422 return HOST_SENDCONTROL_DeviceDisconnected;
423
424 uint8_t ErrorCode;
425
426 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
427 {
428 .DataTransferLength = CPU_TO_LE32(sizeof(SCSI_Capacity_t)),
429 .Flags = MS_COMMAND_DIR_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 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, DeviceCapacity)) != PIPE_RWSTREAM_NoError)
448 return ErrorCode;
449
450 DeviceCapacity->Blocks = BE32_TO_CPU(DeviceCapacity->Blocks);
451 DeviceCapacity->BlockSize = BE32_TO_CPU(DeviceCapacity->BlockSize);
452
453 return PIPE_RWSTREAM_NoError;
454 }
455
456 uint8_t MS_Host_RequestSense(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
457 const uint8_t LUNIndex,
458 SCSI_Request_Sense_Response_t* const SenseData)
459 {
460 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
461 return HOST_SENDCONTROL_DeviceDisconnected;
462
463 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
464 {
465 .DataTransferLength = CPU_TO_LE32(sizeof(SCSI_Request_Sense_Response_t)),
466 .Flags = MS_COMMAND_DIR_DATA_IN,
467 .LUN = LUNIndex,
468 .SCSICommandLength = 6,
469 .SCSICommandData =
470 {
471 SCSI_CMD_REQUEST_SENSE,
472 0x00, // Reserved
473 0x00, // Reserved
474 0x00, // Reserved
475 sizeof(SCSI_Request_Sense_Response_t), // Allocation Length
476 0x00 // Unused (control)
477 }
478 };
479
480 return MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, SenseData);
481 }
482
483 uint8_t MS_Host_PreventAllowMediumRemoval(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
484 const uint8_t LUNIndex,
485 const bool PreventRemoval)
486 {
487 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
488 return HOST_SENDCONTROL_DeviceDisconnected;
489
490 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
491 {
492 .DataTransferLength = CPU_TO_LE32(0),
493 .Flags = MS_COMMAND_DIR_DATA_OUT,
494 .LUN = LUNIndex,
495 .SCSICommandLength = 6,
496 .SCSICommandData =
497 {
498 SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL,
499 0x00, // Reserved
500 0x00, // Reserved
501 PreventRemoval, // Prevent flag
502 0x00, // Reserved
503 0x00 // Unused (control)
504 }
505 };
506
507 return MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, NULL);
508 }
509
510 uint8_t MS_Host_ReadDeviceBlocks(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
511 const uint8_t LUNIndex,
512 const uint32_t BlockAddress,
513 const uint8_t Blocks,
514 const uint16_t BlockSize,
515 void* BlockBuffer)
516 {
517 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
518 return HOST_SENDCONTROL_DeviceDisconnected;
519
520 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
521 {
522 .DataTransferLength = cpu_to_le32((uint32_t)Blocks * BlockSize),
523 .Flags = MS_COMMAND_DIR_DATA_IN,
524 .LUN = LUNIndex,
525 .SCSICommandLength = 10,
526 .SCSICommandData =
527 {
528 SCSI_CMD_READ_10,
529 0x00, // Unused (control bits, all off)
530 (BlockAddress >> 24), // MSB of Block Address
531 (BlockAddress >> 16),
532 (BlockAddress >> 8),
533 (BlockAddress & 0xFF), // LSB of Block Address
534 0x00, // Reserved
535 0x00, // MSB of Total Blocks to Read
536 Blocks, // LSB of Total Blocks to Read
537 0x00 // Unused (control)
538 }
539 };
540
541 return MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, BlockBuffer);
542 }
543
544 uint8_t MS_Host_WriteDeviceBlocks(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
545 const uint8_t LUNIndex,
546 const uint32_t BlockAddress,
547 const uint8_t Blocks,
548 const uint16_t BlockSize,
549 const void* BlockBuffer)
550 {
551 if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
552 return HOST_SENDCONTROL_DeviceDisconnected;
553
554 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
555 {
556 .DataTransferLength = cpu_to_le32((uint32_t)Blocks * BlockSize),
557 .Flags = MS_COMMAND_DIR_DATA_OUT,
558 .LUN = LUNIndex,
559 .SCSICommandLength = 10,
560 .SCSICommandData =
561 {
562 SCSI_CMD_WRITE_10,
563 0x00, // Unused (control bits, all off)
564 (BlockAddress >> 24), // MSB of Block Address
565 (BlockAddress >> 16),
566 (BlockAddress >> 8),
567 (BlockAddress & 0xFF), // LSB of Block Address
568 0x00, // Reserved
569 0x00, // MSB of Total Blocks to Write
570 Blocks, // LSB of Total Blocks to Write
571 0x00 // Unused (control)
572 }
573 };
574
575 return MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, BlockBuffer);
576 }
577
578 #endif
579
Imprint / Impressum