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