Statistics
| Branch: | Tag: | Revision:

root / LUFA / Drivers / USB / Class / Host / MassStorage.c @ 978b99e5

History | View | Annotate | Download (21.5 KB)

1
/*
2
             LUFA Library
3
     Copyright (C) Dean Camera, 2011.
4

5
  dean [at] fourwalledcubicle [dot] com
6
           www.lufa-lib.org
7
*/
8

    
9
/*
10
  Copyright 2011  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 "MassStorage.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
        for (uint8_t PipeNum = 1; PipeNum < PIPE_TOTAL_PIPES; PipeNum++)
82
        {
83
                uint16_t Size;
84
                uint8_t  Type;
85
                uint8_t  Token;
86
                uint8_t  EndpointAddress;
87
                bool     DoubleBanked;
88

    
89
                if (PipeNum == MSInterfaceInfo->Config.DataINPipeNumber)
90
                {
91
                        Size            = le16_to_cpu(DataINEndpoint->EndpointSize);
92
                        EndpointAddress = DataINEndpoint->EndpointAddress;
93
                        Token           = PIPE_TOKEN_IN;
94
                        Type            = EP_TYPE_BULK;
95
                        DoubleBanked    = MSInterfaceInfo->Config.DataINPipeDoubleBank;
96

    
97
                        MSInterfaceInfo->State.DataINPipeSize = DataINEndpoint->EndpointSize;
98
                }
99
                else if (PipeNum == MSInterfaceInfo->Config.DataOUTPipeNumber)
100
                {
101
                        Size            = le16_to_cpu(DataOUTEndpoint->EndpointSize);
102
                        EndpointAddress = DataOUTEndpoint->EndpointAddress;
103
                        Token           = PIPE_TOKEN_OUT;
104
                        Type            = EP_TYPE_BULK;
105
                        DoubleBanked    = MSInterfaceInfo->Config.DataOUTPipeDoubleBank;
106
                        
107
                        MSInterfaceInfo->State.DataOUTPipeSize = DataOUTEndpoint->EndpointSize;
108
                }
109
                else
110
                {
111
                        continue;
112
                }
113

    
114
                if (!(Pipe_ConfigurePipe(PipeNum, Type, Token, EndpointAddress, Size,
115
                                         DoubleBanked ? PIPE_BANK_DOUBLE : PIPE_BANK_SINGLE)))
116
                {
117
                        return MS_ENUMERROR_PipeConfigurationFailed;
118
                }
119
        }
120

    
121
        MSInterfaceInfo->State.InterfaceNumber = MassStorageInterface->InterfaceNumber;
122
        MSInterfaceInfo->State.IsActive = true;
123

    
124
        return MS_ENUMERROR_NoError;
125
}
126

    
127
static uint8_t DCOMP_MS_Host_NextMSInterface(void* const CurrentDescriptor)
128
{
129
        USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
130

    
131
        if (Header->Type == DTYPE_Interface)
132
        {
133
                USB_Descriptor_Interface_t* Interface = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Interface_t);
134

    
135
                if ((Interface->Class    == MS_CSCP_MassStorageClass)        &&
136
                    (Interface->SubClass == MS_CSCP_SCSITransparentSubclass) &&
137
                    (Interface->Protocol == MS_CSCP_BulkOnlyTransportProtocol))
138
                {
139
                        return DESCRIPTOR_SEARCH_Found;
140
                }
141
        }
142

    
143
        return DESCRIPTOR_SEARCH_NotFound;
144
}
145

    
146
static uint8_t DCOMP_MS_Host_NextMSInterfaceEndpoint(void* const CurrentDescriptor)
147
{
148
        USB_Descriptor_Header_t* Header = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Header_t);
149

    
150
        if (Header->Type == DTYPE_Endpoint)
151
        {
152
                USB_Descriptor_Endpoint_t* Endpoint = DESCRIPTOR_PCAST(CurrentDescriptor, USB_Descriptor_Endpoint_t);
153

    
154
                uint8_t EndpointType = (Endpoint->Attributes & EP_TYPE_MASK);
155

    
156
                if ((EndpointType == EP_TYPE_BULK) && (!(Pipe_IsEndpointBound(Endpoint->EndpointAddress))))
157
                {
158
                        return DESCRIPTOR_SEARCH_Found;
159
                }
160
        }
161
        else if (Header->Type == DTYPE_Interface)
162
        {
163
                return DESCRIPTOR_SEARCH_Fail;
164
        }
165

    
166
        return DESCRIPTOR_SEARCH_NotFound;
167
}
168

    
169
static uint8_t MS_Host_SendCommand(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
170
                                   MS_CommandBlockWrapper_t* const SCSICommandBlock,
171
                                   const void* const BufferPtr)
172
{
173
        uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
174

    
175
        if (++MSInterfaceInfo->State.TransactionTag == 0xFFFFFFFF)
176
          MSInterfaceInfo->State.TransactionTag = 1;
177

    
178
        SCSICommandBlock->Signature = CPU_TO_LE32(MS_CBW_SIGNATURE);
179
        SCSICommandBlock->Tag       = cpu_to_le32(MSInterfaceInfo->State.TransactionTag);
180

    
181
        Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
182
        Pipe_Unfreeze();
183

    
184
        if ((ErrorCode = Pipe_Write_Stream_LE(SCSICommandBlock, sizeof(MS_CommandBlockWrapper_t),
185
                                              NULL)) != PIPE_RWSTREAM_NoError)
186
          return ErrorCode;
187

    
188
        Pipe_ClearOUT();
189
        Pipe_WaitUntilReady();
190

    
191
        Pipe_Freeze();
192

    
193
        if ((BufferPtr != NULL) &&
194
            ((ErrorCode = MS_Host_SendReceiveData(MSInterfaceInfo, SCSICommandBlock, (void*)BufferPtr)) != PIPE_RWSTREAM_NoError))
195
        {
196
                Pipe_Freeze();
197
                return ErrorCode;
198
        }
199

    
200
        return ErrorCode;
201
}
202

    
203
static uint8_t MS_Host_WaitForDataReceived(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo)
204
{
205
        uint16_t TimeoutMSRem        = MS_COMMAND_DATA_TIMEOUT_MS;
206
        uint16_t PreviousFrameNumber = USB_Host_GetFrameNumber();
207

    
208
        Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
209
        Pipe_Unfreeze();
210

    
211
        while (!(Pipe_IsINReceived()))
212
        {
213
                uint16_t CurrentFrameNumber = USB_Host_GetFrameNumber();
214

    
215
                if (CurrentFrameNumber != PreviousFrameNumber)
216
                {
217
                        PreviousFrameNumber = CurrentFrameNumber;
218

    
219
                        if (!(TimeoutMSRem--))
220
                          return PIPE_RWSTREAM_Timeout;
221
                }
222

    
223
                Pipe_Freeze();
224
                Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
225
                Pipe_Unfreeze();
226

    
227
                if (Pipe_IsStalled())
228
                {
229
                        USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress());
230
                        return PIPE_RWSTREAM_PipeStalled;
231
                }
232

    
233
                Pipe_Freeze();
234
                Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
235
                Pipe_Unfreeze();
236

    
237
                if (Pipe_IsStalled())
238
                {
239
                        USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress());
240
                        return PIPE_RWSTREAM_PipeStalled;
241
                }
242

    
243
                if (USB_HostState == HOST_STATE_Unattached)
244
                  return PIPE_RWSTREAM_DeviceDisconnected;
245
        };
246

    
247
        Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
248
        Pipe_Freeze();
249

    
250
        Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
251
        Pipe_Freeze();
252

    
253
        return PIPE_RWSTREAM_NoError;
254
}
255

    
256
static uint8_t MS_Host_SendReceiveData(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
257
                                       MS_CommandBlockWrapper_t* const SCSICommandBlock,
258
                                       void* BufferPtr)
259
{
260
        uint8_t  ErrorCode = PIPE_RWSTREAM_NoError;
261
        uint16_t BytesRem  = le32_to_cpu(SCSICommandBlock->DataTransferLength);
262

    
263
        if (SCSICommandBlock->Flags & MS_COMMAND_DIR_DATA_IN)
264
        {
265
                if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError)
266
                {
267
                        Pipe_Freeze();
268
                        return ErrorCode;
269
                }
270

    
271
                Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
272
                Pipe_Unfreeze();
273

    
274
                if ((ErrorCode = Pipe_Read_Stream_LE(BufferPtr, BytesRem, NULL)) != PIPE_RWSTREAM_NoError)
275
                  return ErrorCode;
276

    
277
                Pipe_ClearIN();
278
        }
279
        else
280
        {
281
                Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
282
                Pipe_Unfreeze();
283

    
284
                if ((ErrorCode = Pipe_Write_Stream_LE(BufferPtr, BytesRem, NULL)) != PIPE_RWSTREAM_NoError)
285
                  return ErrorCode;
286

    
287
                Pipe_ClearOUT();
288

    
289
                while (!(Pipe_IsOUTReady()))
290
                {
291
                        if (USB_HostState == HOST_STATE_Unattached)
292
                          return PIPE_RWSTREAM_DeviceDisconnected;
293
                }
294
        }
295

    
296
        Pipe_Freeze();
297

    
298
        return ErrorCode;
299
}
300

    
301
static uint8_t MS_Host_GetReturnedStatus(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
302
                                         MS_CommandStatusWrapper_t* const SCSICommandStatus)
303
{
304
        uint8_t ErrorCode = PIPE_RWSTREAM_NoError;
305

    
306
        if ((ErrorCode = MS_Host_WaitForDataReceived(MSInterfaceInfo)) != PIPE_RWSTREAM_NoError)
307
          return ErrorCode;
308

    
309
        Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
310
        Pipe_Unfreeze();
311

    
312
        if ((ErrorCode = Pipe_Read_Stream_LE(SCSICommandStatus, sizeof(MS_CommandStatusWrapper_t),
313
                                             NULL)) != PIPE_RWSTREAM_NoError)
314
        {
315
                return ErrorCode;
316
        }
317

    
318
        Pipe_ClearIN();
319
        Pipe_Freeze();
320

    
321
        if (SCSICommandStatus->Status != MS_SCSI_COMMAND_Pass)
322
          ErrorCode = MS_ERROR_LOGICAL_CMD_FAILED;
323

    
324
        return ErrorCode;
325
}
326

    
327
uint8_t MS_Host_ResetMSInterface(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo)
328
{
329
        uint8_t ErrorCode;
330

    
331
        USB_ControlRequest = (USB_Request_Header_t)
332
                {
333
                        .bmRequestType = (REQDIR_HOSTTODEVICE | REQTYPE_CLASS | REQREC_INTERFACE),
334
                        .bRequest      = MS_REQ_MassStorageReset,
335
                        .wValue        = 0,
336
                        .wIndex        = MSInterfaceInfo->State.InterfaceNumber,
337
                        .wLength       = 0,
338
                };
339

    
340
        Pipe_SelectPipe(PIPE_CONTROLPIPE);
341

    
342
        if ((ErrorCode = USB_Host_SendControlRequest(NULL)) != HOST_SENDCONTROL_Successful)
343
          return ErrorCode;
344
        
345
        Pipe_SelectPipe(MSInterfaceInfo->Config.DataINPipeNumber);
346
        
347
        if ((ErrorCode = USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress())) != HOST_SENDCONTROL_Successful)
348
          return ErrorCode;
349

    
350
        Pipe_SelectPipe(MSInterfaceInfo->Config.DataOUTPipeNumber);
351

    
352
        if ((ErrorCode = USB_Host_ClearEndpointStall(Pipe_GetBoundEndpointAddress())) != HOST_SENDCONTROL_Successful)
353
          return ErrorCode;
354

    
355
        return HOST_SENDCONTROL_Successful;
356
}
357

    
358
uint8_t MS_Host_GetMaxLUN(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
359
                          uint8_t* const MaxLUNIndex)
360
{
361
        uint8_t ErrorCode = HOST_SENDCONTROL_Successful;
362

    
363
        USB_ControlRequest = (USB_Request_Header_t)
364
                {
365
                        .bmRequestType = (REQDIR_DEVICETOHOST | REQTYPE_CLASS | REQREC_INTERFACE),
366
                        .bRequest      = MS_REQ_GetMaxLUN,
367
                        .wValue        = 0,
368
                        .wIndex        = MSInterfaceInfo->State.InterfaceNumber,
369
                        .wLength       = 1,
370
                };
371

    
372
        Pipe_SelectPipe(PIPE_CONTROLPIPE);
373

    
374
        if ((ErrorCode = USB_Host_SendControlRequest(MaxLUNIndex)) == HOST_SENDCONTROL_SetupStalled)
375
        {
376
                *MaxLUNIndex = 0;
377
                ErrorCode    = HOST_SENDCONTROL_Successful;
378
        }
379

    
380
        return ErrorCode;
381
}
382

    
383
uint8_t MS_Host_GetInquiryData(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
384
                               const uint8_t LUNIndex,
385
                               SCSI_Inquiry_Response_t* const InquiryData)
386
{
387
        if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
388
          return HOST_SENDCONTROL_DeviceDisconnected;
389

    
390
        uint8_t ErrorCode;
391

    
392
        MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
393
                {
394
                        .DataTransferLength = CPU_TO_LE32(sizeof(SCSI_Inquiry_Response_t)),
395
                        .Flags              = MS_COMMAND_DIR_DATA_IN,
396
                        .LUN                = LUNIndex,
397
                        .SCSICommandLength  = 6,
398
                        .SCSICommandData    =
399
                                {
400
                                        SCSI_CMD_INQUIRY,
401
                                        0x00,                            // Reserved
402
                                        0x00,                            // Reserved
403
                                        0x00,                            // Reserved
404
                                        sizeof(SCSI_Inquiry_Response_t), // Allocation Length
405
                                        0x00                             // Unused (control)
406
                                }
407
                };
408

    
409
        MS_CommandStatusWrapper_t SCSICommandStatus;
410

    
411
        if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, InquiryData)) != PIPE_RWSTREAM_NoError)
412
          return ErrorCode;
413

    
414
        if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
415
          return ErrorCode;
416

    
417
        return PIPE_RWSTREAM_NoError;
418
}
419

    
420
uint8_t MS_Host_TestUnitReady(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
421
                              const uint8_t LUNIndex)
422
{
423
        if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
424
          return HOST_SENDCONTROL_DeviceDisconnected;
425

    
426
        uint8_t ErrorCode;
427

    
428
        MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
429
                {
430
                        .DataTransferLength = CPU_TO_LE32(0),
431
                        .Flags              = MS_COMMAND_DIR_DATA_IN,
432
                        .LUN                = LUNIndex,
433
                        .SCSICommandLength  = 6,
434
                        .SCSICommandData    =
435
                                {
436
                                        SCSI_CMD_TEST_UNIT_READY,
437
                                        0x00,                   // Reserved
438
                                        0x00,                   // Reserved
439
                                        0x00,                   // Reserved
440
                                        0x00,                   // Reserved
441
                                        0x00                    // Unused (control)
442
                                }
443
                };
444

    
445
        MS_CommandStatusWrapper_t SCSICommandStatus;
446

    
447
        if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, NULL)) != PIPE_RWSTREAM_NoError)
448
          return ErrorCode;
449

    
450
        if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
451
          return ErrorCode;
452

    
453
        return PIPE_RWSTREAM_NoError;
454
}
455

    
456
uint8_t MS_Host_ReadDeviceCapacity(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
457
                                   const uint8_t LUNIndex,
458
                                   SCSI_Capacity_t* const DeviceCapacity)
459
{
460
        if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
461
          return HOST_SENDCONTROL_DeviceDisconnected;
462

    
463
        uint8_t ErrorCode;
464

    
465
        MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
466
                {
467
                        .DataTransferLength = CPU_TO_LE32(sizeof(SCSI_Capacity_t)),
468
                        .Flags              = MS_COMMAND_DIR_DATA_IN,
469
                        .LUN                = LUNIndex,
470
                        .SCSICommandLength  = 10,
471
                        .SCSICommandData    =
472
                                {
473
                                        SCSI_CMD_READ_CAPACITY_10,
474
                                        0x00,                   // Reserved
475
                                        0x00,                   // MSB of Logical block address
476
                                        0x00,
477
                                        0x00,
478
                                        0x00,                   // LSB of Logical block address
479
                                        0x00,                   // Reserved
480
                                        0x00,                   // Reserved
481
                                        0x00,                   // Partial Medium Indicator
482
                                        0x00                    // Unused (control)
483
                                }
484
                };
485

    
486
        MS_CommandStatusWrapper_t SCSICommandStatus;
487

    
488
        if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, DeviceCapacity)) != PIPE_RWSTREAM_NoError)
489
          return ErrorCode;
490

    
491
        DeviceCapacity->Blocks    = BE32_TO_CPU(DeviceCapacity->Blocks);
492
        DeviceCapacity->BlockSize = BE32_TO_CPU(DeviceCapacity->BlockSize);
493

    
494
        if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
495
          return ErrorCode;
496

    
497
        return PIPE_RWSTREAM_NoError;
498
}
499

    
500
uint8_t MS_Host_RequestSense(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
501
                             const uint8_t LUNIndex,
502
                             SCSI_Request_Sense_Response_t* const SenseData)
503
{
504
        if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
505
          return HOST_SENDCONTROL_DeviceDisconnected;
506

    
507
        uint8_t ErrorCode;
508

    
509
        MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
510
                {
511
                        .DataTransferLength = CPU_TO_LE32(sizeof(SCSI_Request_Sense_Response_t)),
512
                        .Flags              = MS_COMMAND_DIR_DATA_IN,
513
                        .LUN                = LUNIndex,
514
                        .SCSICommandLength  = 6,
515
                        .SCSICommandData    =
516
                                {
517
                                        SCSI_CMD_REQUEST_SENSE,
518
                                        0x00,                                  // Reserved
519
                                        0x00,                                  // Reserved
520
                                        0x00,                                  // Reserved
521
                                        sizeof(SCSI_Request_Sense_Response_t), // Allocation Length
522
                                        0x00                                   // Unused (control)
523
                                }
524
                };
525

    
526
        MS_CommandStatusWrapper_t SCSICommandStatus;
527

    
528
        if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, SenseData)) != PIPE_RWSTREAM_NoError)
529
          return ErrorCode;
530

    
531
        if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
532
          return ErrorCode;
533

    
534
        return PIPE_RWSTREAM_NoError;
535
}
536

    
537
uint8_t MS_Host_PreventAllowMediumRemoval(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
538
                                          const uint8_t LUNIndex,
539
                                          const bool PreventRemoval)
540
{
541
        if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
542
          return HOST_SENDCONTROL_DeviceDisconnected;
543

    
544
        uint8_t ErrorCode;
545

    
546
        MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
547
                {
548
                        .DataTransferLength = CPU_TO_LE32(0),
549
                        .Flags              = MS_COMMAND_DIR_DATA_OUT,
550
                        .LUN                = LUNIndex,
551
                        .SCSICommandLength  = 6,
552
                        .SCSICommandData    =
553
                                {
554
                                        SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL,
555
                                        0x00,                   // Reserved
556
                                        0x00,                   // Reserved
557
                                        PreventRemoval,         // Prevent flag
558
                                        0x00,                   // Reserved
559
                                        0x00                    // Unused (control)
560
                                }
561
                };
562

    
563
        MS_CommandStatusWrapper_t SCSICommandStatus;
564

    
565
        if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, NULL)) != PIPE_RWSTREAM_NoError)
566
          return ErrorCode;
567

    
568
        if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
569
          return ErrorCode;
570

    
571
        return PIPE_RWSTREAM_NoError;
572
}
573

    
574
uint8_t MS_Host_ReadDeviceBlocks(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
575
                                 const uint8_t LUNIndex,
576
                                 const uint32_t BlockAddress,
577
                                 const uint8_t Blocks,
578
                                 const uint16_t BlockSize,
579
                                 void* BlockBuffer)
580
{
581
        if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
582
          return HOST_SENDCONTROL_DeviceDisconnected;
583

    
584
        uint8_t ErrorCode;
585

    
586
        MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
587
                {
588
                        .DataTransferLength = cpu_to_le32((uint32_t)Blocks * BlockSize),
589
                        .Flags              = MS_COMMAND_DIR_DATA_IN,
590
                        .LUN                = LUNIndex,
591
                        .SCSICommandLength  = 10,
592
                        .SCSICommandData    =
593
                                {
594
                                        SCSI_CMD_READ_10,
595
                                        0x00,                   // Unused (control bits, all off)
596
                                        (BlockAddress >> 24),   // MSB of Block Address
597
                                        (BlockAddress >> 16),
598
                                        (BlockAddress >> 8),
599
                                        (BlockAddress & 0xFF),  // LSB of Block Address
600
                                        0x00,                   // Reserved
601
                                        0x00,                   // MSB of Total Blocks to Read
602
                                        Blocks,                 // LSB of Total Blocks to Read
603
                                        0x00                    // Unused (control)
604
                                }
605
                };
606

    
607
        MS_CommandStatusWrapper_t SCSICommandStatus;
608

    
609
        if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, BlockBuffer)) != PIPE_RWSTREAM_NoError)
610
          return ErrorCode;
611

    
612
        if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
613
          return ErrorCode;
614

    
615
        return PIPE_RWSTREAM_NoError;
616
}
617

    
618
uint8_t MS_Host_WriteDeviceBlocks(USB_ClassInfo_MS_Host_t* const MSInterfaceInfo,
619
                                  const uint8_t LUNIndex,
620
                                  const uint32_t BlockAddress,
621
                                  const uint8_t Blocks,
622
                                  const uint16_t BlockSize,
623
                                  const void* BlockBuffer)
624
{
625
        if ((USB_HostState != HOST_STATE_Configured) || !(MSInterfaceInfo->State.IsActive))
626
          return HOST_SENDCONTROL_DeviceDisconnected;
627

    
628
        uint8_t ErrorCode;
629

    
630
        MS_CommandBlockWrapper_t SCSICommandBlock = (MS_CommandBlockWrapper_t)
631
                {
632
                        .DataTransferLength = cpu_to_le32((uint32_t)Blocks * BlockSize),
633
                        .Flags              = MS_COMMAND_DIR_DATA_OUT,
634
                        .LUN                = LUNIndex,
635
                        .SCSICommandLength  = 10,
636
                        .SCSICommandData    =
637
                                {
638
                                        SCSI_CMD_WRITE_10,
639
                                        0x00,                   // Unused (control bits, all off)
640
                                        (BlockAddress >> 24),   // MSB of Block Address
641
                                        (BlockAddress >> 16),
642
                                        (BlockAddress >> 8),
643
                                        (BlockAddress & 0xFF),  // LSB of Block Address
644
                                        0x00,                   // Reserved
645
                                        0x00,                   // MSB of Total Blocks to Write
646
                                        Blocks,                 // LSB of Total Blocks to Write
647
                                        0x00                    // Unused (control)
648
                                }
649
                };
650

    
651
        MS_CommandStatusWrapper_t SCSICommandStatus;
652

    
653
        if ((ErrorCode = MS_Host_SendCommand(MSInterfaceInfo, &SCSICommandBlock, BlockBuffer)) != PIPE_RWSTREAM_NoError)
654
          return ErrorCode;
655

    
656
        if ((ErrorCode = MS_Host_GetReturnedStatus(MSInterfaceInfo, &SCSICommandStatus)) != PIPE_RWSTREAM_NoError)
657
          return ErrorCode;
658

    
659
        return PIPE_RWSTREAM_NoError;
660
}
661

    
662
#endif
663