| LPCOpen Platform v1.03 LPCOpen Platform for NXP LPC Microcontrollers

- Main Page
- Modules
- Data Structures
- Files
- Related Pages

- File List
- Globals

All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
MassStorageClassHost.c
Go to the documentation of this file.
1 /*
2 * @brief Host mode driver for the library USB Mass Storage Class driver
3 *
4 * @note
5 * Copyright(C) NXP Semiconductors, 2012
6 * Copyright(C) Dean Camera, 2011, 2012
7 * All rights reserved.
8 *
9 * @par
10 * Software that is described herein is for illustrative purposes only
11 * which provides customers with programming information regarding the
12 * LPC products. This software is supplied "AS IS" without any warranties of
13 * any kind, and NXP Semiconductors and its licensor disclaim any and
14 * all warranties, express or implied, including all implied warranties of
15 * merchantability, fitness for a particular purpose and non-infringement of
16 * intellectual property rights. NXP Semiconductors assumes no responsibility
17 * or liability for the use of the software, conveys no license or rights under any
18 * patent, copyright, mask work right, or any other intellectual property rights in
19 * or to any products. NXP Semiconductors reserves the right to make changes
20 * in the software without notification. NXP Semiconductors also makes no
21 * representation or warranty that such application will be suitable for the
22 * specified use without further testing or modification.
23 *
24 * @par
25 * Permission to use, copy, modify, and distribute this software and its
26 * documentation is hereby granted, under NXP Semiconductors' and its
27 * licensor's relevant copyrights in the software, without fee, provided that it
28 * is used in conjunction with NXP Semiconductors microcontrollers. This
29 * copyright, permission, and disclaimer notice must appear in all copies of
30 * this code.
31 */
32
33
34 #define __INCLUDE_FROM_USB_DRIVER
35 #include "../../Core/USBMode.h"
36
37 #if defined(USB_CAN_BE_HOST)
38
39 #define __INCLUDE_FROM_MS_DRIVER
40 #define __INCLUDE_FROM_MASSSTORAGE_HOST_C
41 #include "MassStorageClassHost.h"
42
43 uint8_t MS_Host_ConfigurePipes(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
44 uint16_t ConfigDescriptorSize,
45 void* ConfigDescriptorData)
46 {
47 USB_Descriptor_Endpoint_t* DataINEndpoint = NULL;
48 USB_Descriptor_Endpoint_t* DataOUTEndpoint = NULL;
49 USB_Descriptor_Interface_t* MassStorageInterface = NULL;
50 uint8_t portnum = MSInterfaceInfo->Config.PortNumber;
51
52 memset(&MSInterfaceInfo->State, 0x00, sizeof(MSInterfaceInfo->State));
53
54 if (DESCRIPTOR_TYPE(ConfigDescriptorData) != DTYPE_Configuration)
55 return MS_ENUMERROR_InvalidConfigDescriptor;
56
57 while (!(DataINEndpoint) || !(DataOUTEndpoint))
58 {
59 if (!(MassStorageInterface) ||
60 USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
61 DCOMP_MS_Host_NextMSInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found)
62 {
63 if (USB_GetNextDescriptorComp(&ConfigDescriptorSize, &ConfigDescriptorData,
64 DCOMP_MS_Host_NextMSInterface) != DESCRIPTOR_SEARCH_COMP_Found)
65 {
66 return MS_ENUMERROR_NoCompatibleInterfaceFound;
67 }
68
69 MassStorageInterface = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Interface_t);
70
71 DataINEndpoint = NULL;
72 DataOUTEndpoint = NULL;
73
74 continue;
75 }
76
77 USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(ConfigDescriptorData, USB_Descriptor_Endpoint_t);
78
79 if ((EndpointData->EndpointAddress & ENDPOINT_DIR_MASK) == ENDPOINT_DIR_IN)
80 DataINEndpoint = EndpointData;
81 else
82 DataOUTEndpoint = EndpointData;
83 }
84
85 for (uint8_t PipeNum = 1; PipeNum < PIPE_TOTAL_PIPES; PipeNum++)
86 {
87 uint16_t Size;
88 uint8_t Type;
89 uint8_t Token;
90 uint8_t EndpointAddress;
91 bool DoubleBanked;
92
93 if (PipeNum == MSInterfaceInfo->Config.DataINPipeNumber)
94 {
95 Size = le16_to_cpu(DataINEndpoint->EndpointSize);
96 EndpointAddress = DataINEndpoint->EndpointAddress;
97 Token = PIPE_TOKEN_IN;
98 Type = EP_TYPE_BULK;
99 DoubleBanked = MSInterfaceInfo->Config.DataINPipeDoubleBank;
100
101 MSInterfaceInfo->State.DataINPipeSize = DataINEndpoint->EndpointSize;
102 }
103 else if (PipeNum == MSInterfaceInfo->Config.DataOUTPipeNumber)
104 {
105 Size = le16_to_cpu(DataOUTEndpoint->EndpointSize);
106 EndpointAddress = DataOUTEndpoint->EndpointAddress;
107 Token = PIPE_TOKEN_OUT;
108 Type = EP_TYPE_BULK;
109 DoubleBanked = MSInterfaceInfo->Config.DataOUTPipeDoubleBank;
110
111 MSInterfaceInfo->State.DataOUTPipeSize = DataOUTEndpoint->EndpointSize;
112 }
113 else
114 {
115 continue;
116 }
117
118 if (!(Pipe_ConfigurePipe(portnum,PipeNum, Type, Token, EndpointAddress, Size,
119 DoubleBanked ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE)))
120 {
121 return MS_ENUMERROR_PipeConfigurationFailed;
122 }
123 }
124
125 MSInterfaceInfo->State.InterfaceNumber = MassStorageInterface->InterfaceNumber;
126 MSInterfaceInfo->State.IsActive = true;
127
128 return MS_ENUMERROR_NoError;
129 }
130
131 static uint8_t DCOMP_MS_Host_NextMSInterface(void* const CurrentDescriptor)
132 {
133 USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
134
135 if (Header->Type == DTYPE_Interface)
136 {
137 USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);
138
139 if ((Interface->Class == MS_CSCP_MassStorageClass) &&
140 (Interface->SubClass == MS_CSCP_SCSITransparentSubclass) &&
141 (Interface->Protocol == MS_CSCP_BulkOnlyTransportProtocol))
142 {
143 return DESCRIPTOR_SEARCH_Found;
144 }
145 }
146
147 return DESCRIPTOR_SEARCH_NotFound;
148 }
149
150 static uint8_t DCOMP_MS_Host_NextMSInterfaceEndpoint(void* const CurrentDescriptor)
151 {
152 USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
153
154 if (Header->Type == DTYPE_Endpoint)
155 {
156 USB_Descriptor_Endpoint_t* Endpoint = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Endpoint_t);
157
158 uint8_t EndpointType = (Endpoint->Attributes & EP_TYPE_MASK);
159
160 if ((EndpointType == EP_TYPE_BULK) && (!(Pipe_IsEndpointBound(Endpoint->EndpointAddress))))
161 {
162 return DESCRIPTOR_SEARCH_Found;
163 }
164 }
165 else if (Header->Type == DTYPE_Interface)
166 {
167 return DESCRIPTOR_SEARCH_Fail;
168 }
169
170 return DESCRIPTOR_SEARCH_NotFound;
171 }
172
173 static uint8_t MS_Host_SendCommand(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
174 MS_CommandBlockWrapper_t* const SCSICommandBlock,
175 const void* const BufferPtr)
176 {
177 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
178 uint8_t portnum = MSInterfaceInfo->Config.PortNumber;
179
180 if (++MSInterfaceInfo->State.TransactionTag == 0xFFFFFFFF)
181 MSInterfaceInfo->State.TransactionTag = 1;
182
183 SCSICommandBlock->Signature = CPU_TO_LE32(MS_CBW_SIGNATURE);
184 SCSICommandBlock->Tag = cpu_to_le32(MSInterfaceInfo->State.TransactionTag);
185
186 Pipe_SelectPipe(portnum,MSInterfaceInfo->Config.DataOUTPipeNumber);
187 Pipe_Unfreeze();
188
189 if ((ErrorCode = Pipe_Write_Stream_LE(portnum,SCSICommandBlock, sizeof(MS_CommandBlockWrapper_t),
190 NULL)) != PIPE_RWSTREAM_NoError)
191 {
192 return ErrorCode;
193 }
194
195 Pipe_ClearOUT(portnum);
196 Pipe_WaitUntilReady(portnum);
197
198 Pipe_Freeze();
199
200 if (BufferPtr != NULL)
201 {
202 ErrorCode = MS_Host_SendReceiveData(MSInterfaceInfo, SCSICommandBlock, (void*)BufferPtr);
203
204 if ((ErrorCode != PIPE_RWSTREAM_NoError) && (ErrorCode != PIPE_RWSTREAM_PipeStalled))
205 {
206 Pipe_Freeze();
207 return ErrorCode;
208 }
209 }
210
211 MS_CommandStatusWrapper_t SCSIStatusBlock;
212 return MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSIStatusBlock);
213 }
214
215 static uint8_t MS_Host_WaitForDataReceived(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo)
216 {
217 uint16_t TimeoutMSRem = MS_COMMAND_DATA_TIMEOUT_MS;
218 uint16_t PreviousFrameNumber = USB_Host_GetFrameNumber();
219 uint8_t portnum = MSInterfaceInfo->Config.PortNumber;
220
221 Pipe_SelectPipe(portnum,MSInterfaceInfo->Config.DataINPipeNumber);
222 Pipe_Unfreeze();
223
224 while (!(Pipe_IsINReceived(portnum)))
225 {
226 uint16_t CurrentFrameNumber = USB_Host_GetFrameNumber();
227
228 if (CurrentFrameNumber != PreviousFrameNumber)
229 {
230 PreviousFrameNumber = CurrentFrameNumber;
231
232 if (!(TimeoutMSRem--))
233 return PIPE_RWSTREAM_Timeout;
234 }
235
236 Pipe_Freeze();
237 Pipe_SelectPipe(portnum,MSInterfaceInfo->Config.DataOUTPipeNumber);
238 Pipe_Unfreeze();
239
240 if (Pipe_IsStalled(portnum))
241 {
242 Pipe_ClearStall(portnum);
243 USB_Host_ClearEndpointStall(portnum,Pipe_GetBoundEndpointAddress(portnum));
244 return PIPE_RWSTREAM_PipeStalled;
245 }
246
247 Pipe_Freeze();
248 Pipe_SelectPipe(portnum,MSInterfaceInfo->Config.DataINPipeNumber);
249 Pipe_Unfreeze();
250
251 if (Pipe_IsStalled(portnum))
252 {
253 Pipe_ClearStall(portnum);
254 USB_Host_ClearEndpointStall(portnum,Pipe_GetBoundEndpointAddress(portnum));
255 return PIPE_RWSTREAM_PipeStalled;
256 }
257
258 if (USB_HostState[portnum] == HOST_STATE_Unattached)
259 return PIPE_RWSTREAM_DeviceDisconnected;
260 };
261
262 Pipe_SelectPipe(portnum,MSInterfaceInfo->Config.DataINPipeNumber);
263 Pipe_Freeze();
264
265 Pipe_SelectPipe(portnum,MSInterfaceInfo->Config.DataOUTPipeNumber);
266 Pipe_Freeze();
267
268 return PIPE_RWSTREAM_NoError;
269 }
270
271 static uint8_t MS_Host_SendReceiveData(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
272 MS_CommandBlockWrapper_t* const SCSICommandBlock,
273 void* BufferPtr)
274 {
275 uint16_t BytesRem = le32_to_cpu(SCSICommandBlock->DataTransferLength);
276 uint8_t portnum = MSInterfaceInfo->Config.PortNumber;
277 #if defined(__LPC177X_8X__) || defined(__LPC407X_8X__)
278 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
279
280 if (SCSICommandBlock->Flags & MS_COMMAND_DIR_DATA_IN)
281 {
282 if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError)
283 {
284 Pipe_Freeze();
285 return ErrorCode;
286 }
287
288 Pipe_SelectPipe(portnum,MSInterfaceInfo->Config.DataINPipeNumber);
289 Pipe_Unfreeze();
290
291 if ((ErrorCode = Pipe_Read_Stream_LE(portnum,BufferPtr, BytesRem, NULL)) != PIPE_RWSTREAM_NoError)
292 return ErrorCode;
293
294 Pipe_ClearIN(portnum);
295 }
296 else
297 {
298 Pipe_SelectPipe(portnum,MSInterfaceInfo->Config.DataOUTPipeNumber);
299 Pipe_Unfreeze();
300
301 if ((ErrorCode = Pipe_Write_Stream_LE(portnum,BufferPtr, BytesRem, NULL)) != PIPE_RWSTREAM_NoError)
302 return ErrorCode;
303
304 Pipe_ClearOUT(portnum);
305
306 while (!(Pipe_IsOUTReady(portnum)))
307 {
308 if (USB_HostState[portnum] == HOST_STATE_Unattached)
309 return PIPE_RWSTREAM_DeviceDisconnected;
310 }
311 }
312
313 Pipe_Freeze();
314
315 return ErrorCode;
316 #else
317 uint16_t packsize;
318 if (SCSICommandBlock->Flags & MS_COMMAND_DIR_DATA_IN)
319 {
320 Pipe_SelectPipe(portnum,MSInterfaceInfo->Config.DataINPipeNumber);
321 packsize = MSInterfaceInfo->State.DataINPipeSize;
322 }
323 else
324 {
325 Pipe_SelectPipe(portnum,MSInterfaceInfo->Config.DataOUTPipeNumber);
326 packsize = MSInterfaceInfo->State.DataOUTPipeSize;
327 }
328
329 Pipe_Streaming(portnum,(uint8_t*)BufferPtr,BytesRem,packsize);
330
331 while(!Pipe_IsStatusOK(portnum));
332
333 Pipe_ClearIN(portnum);
334 return PIPE_RWSTREAM_NoError;
335 #endif
336 }
337
338 static uint8_t MS_Host_GetReturnedStatus(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
339 MS_CommandStatusWrapper_t* const SCSICommandStatus)
340 {
341 uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
342 uint8_t portnum = MSInterfaceInfo->Config.PortNumber;
343
344 if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError)
345 return ErrorCode;
346
347 Pipe_SelectPipe(portnum,MSInterfaceInfo->Config.DataINPipeNumber);
348 Pipe_Unfreeze();
349
350 if ((ErrorCode = Pipe_Read_Stream_LE(portnum,SCSICommandStatus, sizeof(MS_CommandStatusWrapper_t),
351 NULL)) != PIPE_RWSTREAM_NoError)
352 {
353 return ErrorCode;
354 }
355
356 Pipe_ClearIN(portnum);
357 Pipe_Freeze();
358
359 if (SCSICommandStatus->Status != MS_SCSI_COMMAND_Pass)
360 ErrorCode = MS_ERROR_LOGICAL_CMD_FAILED;
361
362 return ErrorCode;
363 }
364
365 uint8_t MS_Host_ResetMSInterface(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo)
366 {
367 uint8_t ErrorCode;
368 uint8_t portnum = MSInterfaceInfo->Config.PortNumber;
369 USB_ControlRequest = (USB_Request_Header_t)
370 {
371 .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
372 .bRequest = MS_REQ_MassStorageReset,
373 .wValue = 0,
374 .wIndex = MSInterfaceInfo->State.InterfaceNumber,
375 .wLength = 0,
376 };
377
378 Pipe_SelectPipe(portnum,PIPE_CONTROLPIPE);
379
380 if ((ErrorCode = USB_Host_SendControlRequest(portnum,NULL)) != HOST_SENDCONTROL_Successful)
381 return ErrorCode;
382
383 Pipe_SelectPipe(portnum,MSInterfaceInfo->Config.DataINPipeNumber);
384
385 if ((ErrorCode = USB_Host_ClearEndpointStall(portnum,Pipe_GetBoundEndpointAddress(portnum))) != HOST_SENDCONTROL_Successful)
386 return ErrorCode;
387
388 Pipe_SelectPipe(portnum,MSInterfaceInfo->Config.DataOUTPipeNumber);
389
390 if ((ErrorCode = USB_Host_ClearEndpointStall(portnum,Pipe_GetBoundEndpointAddress(portnum))) != HOST_SENDCONTROL_Successful)
391 return ErrorCode;
392
393 return HOST_SENDCONTROL_Successful;
394 }
395
396 uint8_t MS_Host_GetMaxLUN(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
397 uint8_t* const MaxLUNIndex)
398 {
399 uint8_t ErrorCode;
400 uint8_t portnum = MSInterfaceInfo->Config.PortNumber;
401 USB_ControlRequest = (USB_Request_Header_t)
402 {
403 .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
404 .bRequest = MS_REQ_GetMaxLUN,
405 .wValue = 0,
406 .wIndex = MSInterfaceInfo->State.InterfaceNumber,
407 .wLength = 1,
408 };
409
410 Pipe_SelectPipe(portnum,PIPE_CONTROLPIPE);
411
412 if ((ErrorCode = USB_Host_SendControlRequest(portnum,MaxLUNIndex)) == HOST_SENDCONTROL_SetupStalled)
413 {
414 *MaxLUNIndex = 0;
415 ErrorCode = HOST_SENDCONTROL_Successful;
416 }
417
418 return ErrorCode;
419 }
420
421 uint8_t MS_Host_GetInquiryData(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
422 const uint8_t LUNIndex,
423 SCSI_Inquiry_Response_t* const InquiryData)
424 {
425 uint8_t portnum = MSInterfaceInfo->Config.PortNumber;
426 uint8_t ErrorCode;
427 if ((USB_HostState[portnum] != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
428 return HOST_SENDCONTROL_DeviceDisconnected;
429
430 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
431 {
432 .DataTransferLength = CPU_TO_LE32(sizeof(SCSI_Inquiry_Response_t)),
433 .Flags = MS_COMMAND_DIR_DATA_IN,
434 .LUN = LUNIndex,
435 .SCSICommandLength = 6,
436 .SCSICommandData =
437 {
438 SCSI_CMD_INQUIRY,
439 0x00, // Reserved
440 0x00, // Reserved
441 0x00, // Reserved
442 sizeof(SCSI_Inquiry_Response_t), // Allocation Length
443 0x00 // Unused (control)
444 }
445 };
446
447 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, InquiryData)) != PIPE_RWSTREAM_NoError)
448 return ErrorCode;
449
450 return PIPE_RWSTREAM_NoError;
451 }
452
453 uint8_t MS_Host_TestUnitReady(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
454 const uint8_t LUNIndex)
455 {
456 if ((USB_HostState[MSInterfaceInfo->Config.PortNumber] != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
457 return HOST_SENDCONTROL_DeviceDisconnected;
458
459 uint8_t ErrorCode;
460
461 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
462 {
463 .DataTransferLength = CPU_TO_LE32(0),
464 .Flags = MS_COMMAND_DIR_DATA_IN,
465 .LUN = LUNIndex,
466 .SCSICommandLength = 6,
467 .SCSICommandData =
468 {
469 SCSI_CMD_TEST_UNIT_READY,
470 0x00, // Reserved
471 0x00, // Reserved
472 0x00, // Reserved
473 0x00, // Reserved
474 0x00 // Unused (control)
475 }
476 };
477
478 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, NULL)) != PIPE_RWSTREAM_NoError)
479 return ErrorCode;
480
481 return PIPE_RWSTREAM_NoError;
482 }
483
484 uint8_t MS_Host_ReadDeviceCapacity(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
485 const uint8_t LUNIndex,
486 SCSI_Capacity_t* const DeviceCapacity)
487 {
488 if ((USB_HostState[MSInterfaceInfo->Config.PortNumber] != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
489 return HOST_SENDCONTROL_DeviceDisconnected;
490
491 uint8_t ErrorCode;
492
493 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
494 {
495 .DataTransferLength = CPU_TO_LE32(sizeof(SCSI_Capacity_t)),
496 .Flags = MS_COMMAND_DIR_DATA_IN,
497 .LUN = LUNIndex,
498 .SCSICommandLength = 10,
499 .SCSICommandData =
500 {
501 SCSI_CMD_READ_CAPACITY_10,
502 0x00, // Reserved
503 0x00, // MSB of Logical block address
504 0x00,
505 0x00,
506 0x00, // LSB of Logical block address
507 0x00, // Reserved
508 0x00, // Reserved
509 0x00, // Partial Medium Indicator
510 0x00 // Unused (control)
511 }
512 };
513
514 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, DeviceCapacity)) != PIPE_RWSTREAM_NoError)
515 return ErrorCode;
516
517 DeviceCapacity->Blocks = BE32_TO_CPU(DeviceCapacity->Blocks);
518 DeviceCapacity->BlockSize = BE32_TO_CPU(DeviceCapacity->BlockSize);
519
520 return PIPE_RWSTREAM_NoError;
521 }
522
523 uint8_t MS_Host_RequestSense(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
524 const uint8_t LUNIndex,
525 SCSI_Request_Sense_Response_t* const SenseData)
526 {
527 if ((USB_HostState[MSInterfaceInfo->Config.PortNumber] != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
528 return HOST_SENDCONTROL_DeviceDisconnected;
529
530 uint8_t ErrorCode;
531
532 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
533 {
534 .DataTransferLength = CPU_TO_LE32(sizeof(SCSI_Request_Sense_Response_t)),
535 .Flags = MS_COMMAND_DIR_DATA_IN,
536 .LUN = LUNIndex,
537 .SCSICommandLength = 6,
538 .SCSICommandData =
539 {
540 SCSI_CMD_REQUEST_SENSE,
541 0x00, // Reserved
542 0x00, // Reserved
543 0x00, // Reserved
544 sizeof(SCSI_Request_Sense_Response_t), // Allocation Length
545 0x00 // Unused (control)
546 }
547 };
548
549 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, SenseData)) != PIPE_RWSTREAM_NoError)
550 return ErrorCode;
551
552 return PIPE_RWSTREAM_NoError;
553 }
554
555 uint8_t MS_Host_PreventAllowMediumRemoval(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
556 const uint8_t LUNIndex,
557 const bool PreventRemoval)
558 {
559 if ((USB_HostState[MSInterfaceInfo->Config.PortNumber] != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
560 return HOST_SENDCONTROL_DeviceDisconnected;
561
562 uint8_t ErrorCode;
563
564 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
565 {
566 .DataTransferLength = CPU_TO_LE32(0),
567 .Flags = MS_COMMAND_DIR_DATA_OUT,
568 .LUN = LUNIndex,
569 .SCSICommandLength = 6,
570 .SCSICommandData =
571 {
572 SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL,
573 0x00, // Reserved
574 0x00, // Reserved
575 PreventRemoval, // Prevent flag
576 0x00, // Reserved
577 0x00 // Unused (control)
578 }
579 };
580
581 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, NULL)) != PIPE_RWSTREAM_NoError)
582 return ErrorCode;
583
584 return PIPE_RWSTREAM_NoError;
585 }
586
587 uint8_t MS_Host_ReadDeviceBlocks(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
588 const uint8_t LUNIndex,
589 const uint32_t BlockAddress,
590 const uint8_t Blocks,
591 const uint16_t BlockSize,
592 void* BlockBuffer)
593 {
594 if ((USB_HostState[MSInterfaceInfo->Config.PortNumber] != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
595 return HOST_SENDCONTROL_DeviceDisconnected;
596
597 uint8_t ErrorCode;
598
599 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
600 {
601 .DataTransferLength = cpu_to_le32((uint32_t)Blocks * BlockSize),
602 .Flags = MS_COMMAND_DIR_DATA_IN,
603 .LUN = LUNIndex,
604 .SCSICommandLength = 10,
605 .SCSICommandData =
606 {
607 SCSI_CMD_READ_10,
608 0x00, // Unused (control bits, all off)
609 (BlockAddress >> 24), // MSB of Block Address
610 (BlockAddress >> 16),
611 (BlockAddress >> 8),
612 (BlockAddress & 0xFF), // LSB of Block Address
613 0x00, // Reserved
614 0x00, // MSB of Total Blocks to Read
615 Blocks, // LSB of Total Blocks to Read
616 0x00 // Unused (control)
617 }
618 };
619
620 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, BlockBuffer)) != PIPE_RWSTREAM_NoError)
621 return ErrorCode;
622
623 return PIPE_RWSTREAM_NoError;
624 }
625
626 uint8_t MS_Host_WriteDeviceBlocks(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
627 const uint8_t LUNIndex,
628 const uint32_t BlockAddress,
629 const uint8_t Blocks,
630 const uint16_t BlockSize,
631 const void* BlockBuffer)
632 {
633 if ((USB_HostState[MSInterfaceInfo->Config.PortNumber] != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
634 return HOST_SENDCONTROL_DeviceDisconnected;
635
636 uint8_t ErrorCode;
637
638 MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
639 {
640 .DataTransferLength = cpu_to_le32((uint32_t)Blocks * BlockSize),
641 .Flags = MS_COMMAND_DIR_DATA_OUT,
642 .LUN = LUNIndex,
643 .SCSICommandLength = 10,
644 .SCSICommandData =
645 {
646 SCSI_CMD_WRITE_10,
647 0x00, // Unused (control bits, all off)
648 (BlockAddress >> 24), // MSB of Block Address
649 (BlockAddress >> 16),
650 (BlockAddress >> 8),
651 (BlockAddress & 0xFF), // LSB of Block Address
652 0x00, // Reserved
653 0x00, // MSB of Total Blocks to Write
654 Blocks, // LSB of Total Blocks to Write
655 0x00 // Unused (control)
656 }
657 };
658
659 if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, BlockBuffer)) != PIPE_RWSTREAM_NoError)
660 return ErrorCode;
661
662 return PIPE_RWSTREAM_NoError;
663 }
664
665 #endif
666