os/kernelhwsrv/userlibandfileserver/fileserver/smassstorage/cbulkonlytransport.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of the License "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
//
sl@0
    15
sl@0
    16
/**
sl@0
    17
 @file
sl@0
    18
 @internalTechnology
sl@0
    19
*/
sl@0
    20
#include "cbulkonlytransport.h"
sl@0
    21
#include "cbulkonlytransportusbcldd.h"
sl@0
    22
#include "cbulkonlytransportusbcscldd.h"
sl@0
    23
#include "usbmsshared.h"
sl@0
    24
#include "massstoragedebug.h"
sl@0
    25
#include "cusbmassstorageserver.h"
sl@0
    26
sl@0
    27
sl@0
    28
//CBW offsets
sl@0
    29
LOCAL_D const TInt KCbwSignatureOffset 			= 0;
sl@0
    30
LOCAL_D const TInt KCbwTagOffset 				= 4;
sl@0
    31
LOCAL_D const TInt KCbwDataTransferLengthOffset = 8;
sl@0
    32
LOCAL_D const TInt KCbwFlagOffset 				= 12;
sl@0
    33
LOCAL_D const TInt KCbwLunOffset				= 13;
sl@0
    34
LOCAL_D const TInt KCbwCbLengthOffset  			= 14;
sl@0
    35
sl@0
    36
LOCAL_D const TInt KMaxCbwcbLength 				= 16;
sl@0
    37
sl@0
    38
// CSW offsets
sl@0
    39
LOCAL_D const TInt KCswSingnatureOffset 		= 0;
sl@0
    40
LOCAL_D const TInt KCswTagOffset 				= 4;
sl@0
    41
LOCAL_D const TInt KCswDataResidueOffset 		= 8;
sl@0
    42
LOCAL_D const TInt KCswStatusOffset 			= 12;
sl@0
    43
sl@0
    44
sl@0
    45
sl@0
    46
/**
sl@0
    47
 This function unpacks into the TUsbRequestHdr class from a descriptor with
sl@0
    48
 the alignment that would be introduced on the USB bus.
sl@0
    49
sl@0
    50
 @param aBuffer Input buffer
sl@0
    51
 @param aTarget Unpacked header.
sl@0
    52
 @return Error.
sl@0
    53
 */
sl@0
    54
TInt TUsbRequestHdr::Decode(const TDesC8& aBuffer)
sl@0
    55
sl@0
    56
	{
sl@0
    57
	if (aBuffer.Length() < static_cast<TInt>(KRequestHdrSize))
sl@0
    58
		{
sl@0
    59
        __PRINT1(_L("TUsbRequestHdr::Decode buffer invalid length %d"), aBuffer.Length());
sl@0
    60
		return KErrGeneral;
sl@0
    61
		}
sl@0
    62
sl@0
    63
	iRequestType = aBuffer[0];
sl@0
    64
	iRequest = static_cast<TEp0Request>(aBuffer[1]);
sl@0
    65
	iValue	 = static_cast<TUint16>(aBuffer[2] + (aBuffer[3] << 8));
sl@0
    66
	iIndex	 = static_cast<TUint16>(aBuffer[4] + (aBuffer[5] << 8));
sl@0
    67
	iLength  = static_cast<TUint16>(aBuffer[6] + (aBuffer[7] << 8));
sl@0
    68
    __PRINT5(_L("type=%d request=%d value=%d index=%d length=%d"), iRequestType,iRequest,iValue,iIndex,iLength);
sl@0
    69
sl@0
    70
	return KErrNone;
sl@0
    71
	}
sl@0
    72
sl@0
    73
sl@0
    74
/**
sl@0
    75
This function determines whether data is required by the host in response
sl@0
    76
to a message header.
sl@0
    77
sl@0
    78
@return TBool	Flag indicating whether a data response required.
sl@0
    79
*/
sl@0
    80
TBool TUsbRequestHdr::IsDataResponseRequired() const
sl@0
    81
sl@0
    82
	{
sl@0
    83
	return (iRequestType & 0x80) ? (TBool)ETrue : (TBool)EFalse;
sl@0
    84
	}
sl@0
    85
sl@0
    86
//-------------------------------------
sl@0
    87
/**
sl@0
    88
Create an object of a class derived from CBulkOnlyTransport (default to CBulkOnlyTransportUsbcLdd object)
sl@0
    89
@param aNumDrives - The number of drives available for MS
sl@0
    90
@param aController - reference to the parent
sl@0
    91
@return pointer to newly created derived class object
sl@0
    92
*/
sl@0
    93
CBulkOnlyTransport* CBulkOnlyTransport::NewL(TInt aNumDrives,CUsbMassStorageController& aController)
sl@0
    94
	{
sl@0
    95
	__FNLOG("CBulkOnlyTransport::NewL()");
sl@0
    96
	
sl@0
    97
	return NewL(aNumDrives,aController, (CUsbMassStorageController::TTransportldd) 1);
sl@0
    98
	}
sl@0
    99
sl@0
   100
/**
sl@0
   101
Create an object of a class derived from CBulkOnlyTransport 
sl@0
   102
@param aNumDrives - The number of drives available for MS
sl@0
   103
@param aController - reference to the parent
sl@0
   104
@param aTransportLddFlag - Type of usb client ldd
sl@0
   105
@return pointer to newly created derived class object
sl@0
   106
*/
sl@0
   107
CBulkOnlyTransport* CBulkOnlyTransport::NewL(TInt aNumDrives,CUsbMassStorageController& aController, CUsbMassStorageController::TTransportldd aTransportLddFlag)
sl@0
   108
	{
sl@0
   109
	__FNLOG("CBulkOnlyTransport::NewL()");
sl@0
   110
sl@0
   111
	if (aNumDrives <=0 || static_cast<TUint>(aNumDrives) > KUsbMsMaxDrives)
sl@0
   112
		{
sl@0
   113
		User::Leave(KErrArgument);
sl@0
   114
		}
sl@0
   115
sl@0
   116
	CBulkOnlyTransportUsbcScLdd* scTransport;
sl@0
   117
	CBulkOnlyTransportUsbcLdd* nonscTransport;
sl@0
   118
	switch (aTransportLddFlag)
sl@0
   119
		{
sl@0
   120
		case 1: 
sl@0
   121
				nonscTransport = new(ELeave) CBulkOnlyTransportUsbcLdd(aNumDrives, aController);
sl@0
   122
				return nonscTransport;
sl@0
   123
sl@0
   124
		case 2: 
sl@0
   125
				scTransport = new(ELeave) CBulkOnlyTransportUsbcScLdd(aNumDrives, aController);
sl@0
   126
				return scTransport;
sl@0
   127
		default:
sl@0
   128
				return NULL;
sl@0
   129
sl@0
   130
		}
sl@0
   131
	}
sl@0
   132
sl@0
   133
sl@0
   134
TInt CBulkOnlyTransport::InitialiseTransportL(TInt aTransportLddFlag)
sl@0
   135
	{
sl@0
   136
	__FNLOG("CBulkOnlyTransportUsbcScLdd::InitialiseTransportL()");
sl@0
   137
	TInt ret = KErrNone;
sl@0
   138
	MTransportBase* transport;
sl@0
   139
	iController.GetTransport(transport);
sl@0
   140
	switch (aTransportLddFlag)
sl@0
   141
		{
sl@0
   142
		case 2: 
sl@0
   143
				ret = ((CBulkOnlyTransportUsbcScLdd*) transport)->Ldd().Open(0);
sl@0
   144
				if (ret != KErrNone)
sl@0
   145
					{
sl@0
   146
					return ret;
sl@0
   147
					}
sl@0
   148
				else
sl@0
   149
					{
sl@0
   150
					((CBulkOnlyTransportUsbcScLdd*) transport)->Ldd().Close();		
sl@0
   151
					CleanupStack::PushL(transport);
sl@0
   152
					((CBulkOnlyTransportUsbcScLdd*) transport)->ConstructL();
sl@0
   153
					CleanupStack::Pop(transport);
sl@0
   154
					return ret;
sl@0
   155
					}
sl@0
   156
		case 1:
sl@0
   157
				ret = ((CBulkOnlyTransportUsbcLdd*) transport)->Ldd().Open(0);
sl@0
   158
				if (ret != KErrNone)
sl@0
   159
					{
sl@0
   160
					return ret;
sl@0
   161
					}
sl@0
   162
				else
sl@0
   163
					{
sl@0
   164
					((CBulkOnlyTransportUsbcLdd*) transport)->Ldd().Close();
sl@0
   165
					CleanupStack::PushL(transport);
sl@0
   166
					((CBulkOnlyTransportUsbcLdd*) transport)->ConstructL();
sl@0
   167
					CleanupStack::Pop(transport);
sl@0
   168
					return ret;
sl@0
   169
					}
sl@0
   170
		default:
sl@0
   171
				return KErrNotFound;
sl@0
   172
		}
sl@0
   173
	}	
sl@0
   174
sl@0
   175
/**
sl@0
   176
c'tor
sl@0
   177
@param aNumDrives - The number of drives available for MS
sl@0
   178
@param aController - reference to the parent
sl@0
   179
*/
sl@0
   180
CBulkOnlyTransport::CBulkOnlyTransport(TInt aNumDrives,CUsbMassStorageController& aController):
sl@0
   181
	CActive(EPriorityStandard),
sl@0
   182
	iMaxLun(aNumDrives-1),
sl@0
   183
	iController(aController),
sl@0
   184
	iStallAllowed(ETrue),
sl@0
   185
	iInterfaceConfigured(EFalse),
sl@0
   186
	iCommandBufPtr(NULL,0),
sl@0
   187
	iDataBufPtr(NULL,0),
sl@0
   188
	iCswBufPtr(NULL,0),
sl@0
   189
	iPaddingBufPtr(NULL,0),
sl@0
   190
	iWriteBufPtr(NULL,0),
sl@0
   191
	iReadBufPtr(NULL, 0),
sl@0
   192
	iCbwBufPtr(NULL,0)
sl@0
   193
	{
sl@0
   194
	__FNLOG("CBulkOnlyTransport::CBulkOnlyTransport");
sl@0
   195
	}
sl@0
   196
sl@0
   197
/**
sl@0
   198
Destructor
sl@0
   199
*/
sl@0
   200
CBulkOnlyTransport::~CBulkOnlyTransport()
sl@0
   201
	{
sl@0
   202
	__FNLOG("CBulkOnlyTransport::~CBulkOnlyTransport");
sl@0
   203
	if (iInterfaceConfigured)
sl@0
   204
		{
sl@0
   205
		Stop();
sl@0
   206
		}
sl@0
   207
	}
sl@0
   208
sl@0
   209
sl@0
   210
/**
sl@0
   211
Called by the protocol after processing the packet to indicate that more data is required.
sl@0
   212
sl@0
   213
@param aData reference to the data buffer.
sl@0
   214
*/
sl@0
   215
void CBulkOnlyTransport::SetupReadData(TUint aLength)
sl@0
   216
	{
sl@0
   217
	__FNLOG("CBulkOnlyTransport::SetupReadData");
sl@0
   218
	__PRINT1(_L("Length = %d  (bytes)\n"), aLength);
sl@0
   219
	iBufSize = aLength;
sl@0
   220
	iReadSetUp = ETrue;
sl@0
   221
	}
sl@0
   222
sl@0
   223
sl@0
   224
/**
sl@0
   225
Called by the protocol after processing the packet to indicate that data should be written to the host.
sl@0
   226
sl@0
   227
@param aData reference to the data buffer.
sl@0
   228
*/
sl@0
   229
void CBulkOnlyTransport::SetupWriteData(TPtrC8& aData)
sl@0
   230
	{
sl@0
   231
	__FNLOG("CBulkOnlyTransport::SetupWriteData");
sl@0
   232
	__PRINT1(_L("Length = %d  (bytes)\n"), aData.Length());
sl@0
   233
	iWriteBufPtr.Set(aData);
sl@0
   234
	iWriteSetUp = ETrue;
sl@0
   235
	}
sl@0
   236
sl@0
   237
sl@0
   238
TInt CBulkOnlyTransport::Start()
sl@0
   239
	{
sl@0
   240
	__FNLOG("CBulkOnlyTransport::Start");
sl@0
   241
sl@0
   242
	TInt err = KErrNone;
sl@0
   243
sl@0
   244
	if (!iProtocol)
sl@0
   245
		{
sl@0
   246
		return KErrBadHandle;   //protocol should be set up before start
sl@0
   247
		}
sl@0
   248
sl@0
   249
	if (IsActive())
sl@0
   250
		{
sl@0
   251
		__PRINT(_L("CBulkOnlyTransport::Start  - active before start!\n"));
sl@0
   252
		return KErrInUse;
sl@0
   253
		}
sl@0
   254
sl@0
   255
	if ((err = SetupConfigurationDescriptor()) 	!= KErrNone ||
sl@0
   256
		(err = SetupInterfaceDescriptors())		!= KErrNone )
sl@0
   257
		{
sl@0
   258
		__PRINT(_L("CBulkOnlyTransport::Start  - Error during descriptors setup!\n"));
sl@0
   259
		return err;
sl@0
   260
		}
sl@0
   261
sl@0
   262
	AllocateEndpointResources();
sl@0
   263
	ActivateDeviceStateNotifier();  // activate notifier wich will wait until USB became configured
sl@0
   264
	TUsbcDeviceState deviceStatus = EUsbcDeviceStateDefault;
sl@0
   265
	err = GetDeviceStatus(deviceStatus);
sl@0
   266
	__PRINT1(_L("CBulkOnlyTransport::Start - Device status = %d\n"), deviceStatus);
sl@0
   267
	if (err == KErrNone && deviceStatus == EUsbcDeviceStateConfigured)
sl@0
   268
		{
sl@0
   269
		__PRINT(_L("CBulkOnlyTransport::Start  - Starting bulk only transport\n"));
sl@0
   270
		err = HwStart();
sl@0
   271
		}
sl@0
   272
sl@0
   273
#ifdef MSDC_MULTITHREADED
sl@0
   274
	TPtr8 aDes1(NULL,0);
sl@0
   275
	TPtr8 aDes2(NULL,0);
sl@0
   276
	GetBufferPointers(aDes1, aDes2);
sl@0
   277
	iProtocol->InitializeBufferPointers(aDes1, aDes2); // have to pass pointer to memory not offsets to initialise TPtr, and lengths
sl@0
   278
#endif
sl@0
   279
sl@0
   280
	iInterfaceConfigured = ETrue;
sl@0
   281
	return err;
sl@0
   282
	}
sl@0
   283
sl@0
   284
TInt CBulkOnlyTransport::HwStart(TBool aDiscard)
sl@0
   285
	{
sl@0
   286
	__FNLOG("CBulkOnlyTransport::HwStart");
sl@0
   287
sl@0
   288
    TInt lun = MaxLun();
sl@0
   289
    do
sl@0
   290
        {
sl@0
   291
        Controller().DriveManager().Connect(lun);
sl@0
   292
        }
sl@0
   293
    while(--lun >= 0);
sl@0
   294
sl@0
   295
	TInt res = StartControlInterface();
sl@0
   296
sl@0
   297
	iCurrentState = ENone;
sl@0
   298
	iWriteSetUp=EFalse;
sl@0
   299
	iReadSetUp=EFalse;
sl@0
   300
	iStarted = ETrue;
sl@0
   301
sl@0
   302
    if (aDiscard)
sl@0
   303
		{
sl@0
   304
		FlushData();
sl@0
   305
		}
sl@0
   306
sl@0
   307
	ReadCBW();
sl@0
   308
	return res;
sl@0
   309
	}
sl@0
   310
sl@0
   311
sl@0
   312
TInt CBulkOnlyTransport::HwStop()
sl@0
   313
	{
sl@0
   314
	__FNLOG("CBulkOnlyTransport::HwStop");
sl@0
   315
	if (iStarted)
sl@0
   316
		{
sl@0
   317
        StopBulkOnlyEndpoint();
sl@0
   318
		CancelControlInterface();
sl@0
   319
		iStarted = EFalse;
sl@0
   320
		}
sl@0
   321
	return KErrNone;
sl@0
   322
	}
sl@0
   323
sl@0
   324
sl@0
   325
void CBulkOnlyTransport::StopBulkOnlyEndpoint()
sl@0
   326
	{
sl@0
   327
	__FNLOG("CBulkOnlyTransport::StopBulkOnlyEndpoint");
sl@0
   328
sl@0
   329
    TInt lun = MaxLun();
sl@0
   330
    do
sl@0
   331
        {
sl@0
   332
        Controller().DriveManager().Disconnect(lun);
sl@0
   333
        }
sl@0
   334
    while(--lun >= 0);
sl@0
   335
	Cancel();
sl@0
   336
	iProtocol->Cancel();
sl@0
   337
	}
sl@0
   338
sl@0
   339
sl@0
   340
TInt CBulkOnlyTransport::HwSuspend()
sl@0
   341
	{
sl@0
   342
	__FNLOG("CBulkOnlyTransport::HwSuspend");
sl@0
   343
sl@0
   344
	TInt lun = MaxLun();
sl@0
   345
	do
sl@0
   346
		{
sl@0
   347
		Controller().DriveManager().Disconnect(lun);
sl@0
   348
		}
sl@0
   349
	while(--lun >= 0);
sl@0
   350
sl@0
   351
	return KErrNone;
sl@0
   352
	}
sl@0
   353
sl@0
   354
sl@0
   355
TInt CBulkOnlyTransport::HwResume()
sl@0
   356
	{
sl@0
   357
	__FNLOG("CBulkOnlyTransport::HwResume");
sl@0
   358
sl@0
   359
    TInt lun = MaxLun();
sl@0
   360
    do
sl@0
   361
        {
sl@0
   362
        Controller().DriveManager().Connect(lun);
sl@0
   363
        }
sl@0
   364
    while(--lun >= 0);
sl@0
   365
sl@0
   366
	return KErrNone;
sl@0
   367
	}
sl@0
   368
sl@0
   369
/**
sl@0
   370
Stops the Bulk Only Transport
sl@0
   371
*/
sl@0
   372
TInt CBulkOnlyTransport::Stop()
sl@0
   373
	{
sl@0
   374
	__FNLOG("CBulkOnlyTransport::Stop");
sl@0
   375
	CancelControlInterface();
sl@0
   376
	CancelDeviceStateNotifier();
sl@0
   377
	Cancel();
sl@0
   378
	if  (iInterfaceConfigured)
sl@0
   379
		{
sl@0
   380
		ReleaseInterface();
sl@0
   381
		SetupConfigurationDescriptor(ETrue);
sl@0
   382
		}
sl@0
   383
	iCurrentState = ENone;
sl@0
   384
	iInterfaceConfigured = EFalse;
sl@0
   385
sl@0
   386
	return KErrNone;
sl@0
   387
	}
sl@0
   388
sl@0
   389
sl@0
   390
sl@0
   391
void CBulkOnlyTransport::DoCancel()
sl@0
   392
	{
sl@0
   393
	__FNLOG("CBulkOnlyTransport::DoCancel");
sl@0
   394
	CancelReadWriteRequests();
sl@0
   395
	}
sl@0
   396
sl@0
   397
sl@0
   398
void CBulkOnlyTransport::Activate(TInt aReason)
sl@0
   399
    {
sl@0
   400
    SetActive();
sl@0
   401
    TRequestStatus* r = &iStatus;
sl@0
   402
    User::RequestComplete(r, aReason);
sl@0
   403
    }
sl@0
   404
sl@0
   405
sl@0
   406
void CBulkOnlyTransport::RunL()
sl@0
   407
	{
sl@0
   408
	__FNLOG("CBulkOnlyTransport::RunL");
sl@0
   409
	if (iStatus != KErrNone)
sl@0
   410
		{
sl@0
   411
		__PRINT1(_L("Error %d in RunL, halt endpoints \n"), iStatus.Int());
sl@0
   412
		SetPermError(); //halt endpoints for reset recovery
sl@0
   413
		return;
sl@0
   414
		}
sl@0
   415
	switch (iCurrentState)
sl@0
   416
		{
sl@0
   417
		case EWaitForCBW:
sl@0
   418
			__PRINT(_L("EWaitForCBW"));
sl@0
   419
			ProcessCbwEvent();
sl@0
   420
			break;
sl@0
   421
sl@0
   422
		case EWritingData:
sl@0
   423
            __PRINT(_L("EWritingData"));
sl@0
   424
			iWriteSetUp = EFalse;  //the buffer was used
sl@0
   425
sl@0
   426
			if (iDataResidue && iStallAllowed)
sl@0
   427
				{
sl@0
   428
				StallEndpointAndWaitForClear();
sl@0
   429
				}
sl@0
   430
sl@0
   431
			SendCSW(iCbwTag, iDataResidue, iCmdStatus);
sl@0
   432
			break;
sl@0
   433
sl@0
   434
		case EReadingData:
sl@0
   435
			{
sl@0
   436
			__PRINT(_L("EReadingData"));
sl@0
   437
sl@0
   438
			ProcessReadingDataEvent();
sl@0
   439
			}
sl@0
   440
			break;
sl@0
   441
sl@0
   442
		case ESendingCSW:
sl@0
   443
			__PRINT(_L("ESendingCSW"));
sl@0
   444
			ReadCBW();
sl@0
   445
			break;
sl@0
   446
sl@0
   447
        case EPermErr:
sl@0
   448
			__PRINT(_L("EPermErr"));
sl@0
   449
			StallEndpointAndWaitForClear();
sl@0
   450
            break;
sl@0
   451
sl@0
   452
        default:
sl@0
   453
			SetPermError();		// unexpected state
sl@0
   454
		}
sl@0
   455
	}
sl@0
   456
sl@0
   457
sl@0
   458
/**
sl@0
   459
Decode the CBW received from the host via OutEndpoint
sl@0
   460
sl@0
   461
- If the header is valid, the data content is passed to the parser.
sl@0
   462
- Depending on the command, more data may be transmitted/received.
sl@0
   463
- ...or the CSW is sent (if not a data command).
sl@0
   464
sl@0
   465
*/
sl@0
   466
void CBulkOnlyTransport::DecodeCBW()
sl@0
   467
	{
sl@0
   468
	__FNLOG("CBulkOnlyTransport::DecodeCBW");
sl@0
   469
sl@0
   470
	SetCbwPtr();
sl@0
   471
sl@0
   472
	if (!CheckCBW())  //check if CBW valid and meaningful
sl@0
   473
		{
sl@0
   474
        // CBW not valid or meaningful
sl@0
   475
        // Specification says: "If the CBW is not valid, the device shall STALL
sl@0
   476
        // the Bulk-In pipe. Also, the device shall either STALL the Bulk-Out pipe,
sl@0
   477
        // or the device shall accept and discard any Bulk-Out data. The device
sl@0
   478
        // shall maintain this state until a Reset Recovery."
sl@0
   479
        // Here we keep bulk-in ep stalled and ignore bulk-out ep.
sl@0
   480
		SetPermError();
sl@0
   481
		ExpireData((TAny*) (iCbwBufPtr.Ptr()));
sl@0
   482
		return;
sl@0
   483
		}
sl@0
   484
sl@0
   485
	TPtrC8 aData;
sl@0
   486
	aData.Set(&iCbwBufPtr[KCbwCbLengthOffset], KMaxCbwcbLength+1);    //prepare data for protocol starting form Length
sl@0
   487
	TUint8 lun = static_cast<TUint8>(iCbwBufPtr[13] & 0x0f);
sl@0
   488
sl@0
   489
	iCbwTag  =	static_cast<TUint32>(iCbwBufPtr[KCbwTagOffset])		|
sl@0
   490
				static_cast<TUint32>(iCbwBufPtr[KCbwTagOffset+1])	<<8 |
sl@0
   491
				static_cast<TUint32>(iCbwBufPtr[KCbwTagOffset+2])	<<16|
sl@0
   492
				static_cast<TUint32>(iCbwBufPtr[KCbwTagOffset+3])	<<24;
sl@0
   493
sl@0
   494
	TInt i = KCbwDataTransferLengthOffset;
sl@0
   495
	TUint hostDataLength = 	static_cast<TUint32>(iCbwBufPtr[i  ])		|
sl@0
   496
							static_cast<TUint32>(iCbwBufPtr[i+1]) <<8 	|
sl@0
   497
							static_cast<TUint32>(iCbwBufPtr[i+2]) <<16	|
sl@0
   498
							static_cast<TUint32>(iCbwBufPtr[i+3]) <<24;
sl@0
   499
sl@0
   500
	TBool dataToHost = iCbwBufPtr[KCbwFlagOffset] & 0x80;
sl@0
   501
sl@0
   502
	__PRINT4(_L("lun =%d, hostDataLength=%d, CBWtag = 0x%x, dataToHost=%d\n"), lun, hostDataLength, iCbwTag, dataToHost);
sl@0
   503
	//////////////////////////////////////////////
sl@0
   504
	TBool ret = iProtocol->DecodePacket(aData, lun);
sl@0
   505
	//////////////////////////////////////////////
sl@0
   506
	ExpireData((TAny*) (iCbwBufPtr.Ptr()));
sl@0
   507
sl@0
   508
sl@0
   509
	iStallAllowed = ETrue;
sl@0
   510
sl@0
   511
	if (!ret)
sl@0
   512
		{
sl@0
   513
		__PRINT(_L("Command Failed\n"));
sl@0
   514
		iCmdStatus = ECommandFailed;
sl@0
   515
		}
sl@0
   516
	else
sl@0
   517
		{
sl@0
   518
		__PRINT(_L("Command Passed\n"));
sl@0
   519
		iCmdStatus = ECommandPassed;
sl@0
   520
		}
sl@0
   521
sl@0
   522
	if (hostDataLength)    // Host  expected data transfer
sl@0
   523
		{
sl@0
   524
		if (dataToHost)  // send data to host
sl@0
   525
			{
sl@0
   526
			if (!iWriteSetUp) //write buffer was not set up
sl@0
   527
				{
sl@0
   528
				__PRINT(_L("Write buffer was not setup\n"));
sl@0
   529
				iDataResidue =hostDataLength;
sl@0
   530
				__PRINT1(_L("DataResidue (write to host)=%d\n"),iDataResidue);
sl@0
   531
sl@0
   532
//------------------------------------
sl@0
   533
				if (hostDataLength <= KBOTMaxBufSize)
sl@0
   534
					{
sl@0
   535
					__PRINT(_L("Case 4 or 8\n"));
sl@0
   536
					SetPaddingBufPtr(hostDataLength);
sl@0
   537
					iPaddingBufPtr.FillZ(hostDataLength);
sl@0
   538
					TPtrC8 ptr(NULL, 0);
sl@0
   539
					ptr.Set((TUint8*)iPaddingBufPtr.Ptr(), hostDataLength);
sl@0
   540
					WriteData(iStatus, ptr, hostDataLength, EFalse);
sl@0
   541
					iStallAllowed = EFalse;
sl@0
   542
					if (iReadSetUp)  //read buffer WAS set up - case (8)
sl@0
   543
						{
sl@0
   544
						__PRINT(_L("It is Case 8\n"));
sl@0
   545
						iCmdStatus = EPhaseError;
sl@0
   546
						}
sl@0
   547
					return;
sl@0
   548
					}
sl@0
   549
				else
sl@0
   550
//------------------------------------
sl@0
   551
//					Use next block instead of StallEndpointAndWaitForClear(InEndpoint);
sl@0
   552
					{
sl@0
   553
					SetPaddingBufPtr(hostDataLength);
sl@0
   554
					iPaddingBufPtr.FillZ(KBOTMaxBufSize);
sl@0
   555
					TUint c =0;
sl@0
   556
					TRequestStatus status;
sl@0
   557
					while (c<hostDataLength)
sl@0
   558
						{
sl@0
   559
						TInt len;
sl@0
   560
						if (hostDataLength - c >  KBOTMaxBufSize)
sl@0
   561
							{
sl@0
   562
							len = KBOTMaxBufSize;
sl@0
   563
							}
sl@0
   564
						else
sl@0
   565
							{
sl@0
   566
							len = hostDataLength - c;
sl@0
   567
							}
sl@0
   568
sl@0
   569
							TPtrC8 ptr(NULL, 0);
sl@0
   570
							ptr.Set((TUint8*)iPaddingBufPtr.Ptr(), len);
sl@0
   571
							WriteUsb(status, ptr, len);
sl@0
   572
							User::WaitForRequest(status);
sl@0
   573
							c +=  KBOTMaxBufSize;
sl@0
   574
						}
sl@0
   575
					}
sl@0
   576
sl@0
   577
				if (iReadSetUp)  //read buffer WAS set up - case (8)
sl@0
   578
					{
sl@0
   579
					__PRINT(_L("Case 8\n"));
sl@0
   580
					SendCSW(iCbwTag, hostDataLength, EPhaseError);
sl@0
   581
					  //don't care to reset any flag - should get reset recovery
sl@0
   582
					}
sl@0
   583
				else   // case (4)
sl@0
   584
					{
sl@0
   585
					__PRINT(_L("Case 4\n"));
sl@0
   586
					SendCSW(iCbwTag, hostDataLength, iCmdStatus);
sl@0
   587
					}
sl@0
   588
				return;
sl@0
   589
				}	// if (!iWriteSetUp)
sl@0
   590
sl@0
   591
//==================
sl@0
   592
			TUint deviceDataLength = static_cast<TUint>(iWriteBufPtr.Length());
sl@0
   593
			iDataResidue =hostDataLength - deviceDataLength ;
sl@0
   594
			__PRINT2(_L("Device data length = %d, DataResidue (write to host)=%d\n"), deviceDataLength, iDataResidue);
sl@0
   595
sl@0
   596
			if (deviceDataLength < hostDataLength  &&
sl@0
   597
				hostDataLength < KBOTMaxBufSize )
sl@0
   598
					{
sl@0
   599
					__PRINT(_L("Case 5 (padding)\n"));
sl@0
   600
					SetPaddingBufPtr(hostDataLength);
sl@0
   601
					iPaddingBufPtr.Zero();
sl@0
   602
					iPaddingBufPtr.Append(iWriteBufPtr);
sl@0
   603
					iStallAllowed = EFalse;
sl@0
   604
					__PRINT1(_L("iPaddingBufPtr.Length = %d\n"),iPaddingBufPtr.Length());
sl@0
   605
					TPtrC8 ptr(NULL, 0);
sl@0
   606
					ptr.Set((TUint8*)iPaddingBufPtr.Ptr(), hostDataLength);
sl@0
   607
					WriteData(iStatus, ptr, hostDataLength, EFalse);
sl@0
   608
					return;
sl@0
   609
					}
sl@0
   610
sl@0
   611
//===================
sl@0
   612
sl@0
   613
			if (deviceDataLength == hostDataLength)  	//case (6)[==]
sl@0
   614
				{
sl@0
   615
				__PRINT(_L("Case 6\n"));
sl@0
   616
				WriteData(iStatus, iWriteBufPtr, deviceDataLength);
sl@0
   617
				return;
sl@0
   618
				}
sl@0
   619
			else if (deviceDataLength < hostDataLength)	//case (5)[<]
sl@0
   620
				{
sl@0
   621
				__PRINT(_L("Case 5\n"));
sl@0
   622
				WriteData(iStatus, iWriteBufPtr, deviceDataLength, ETrue);		// Send ZLP
sl@0
   623
				return;
sl@0
   624
				}
sl@0
   625
			else 										// deviceDataLength > hostDataLength - case (7)
sl@0
   626
				{
sl@0
   627
				__PRINT(_L("Case 7\n"));
sl@0
   628
				iCmdStatus = EPhaseError;
sl@0
   629
				iDataResidue = 0;
sl@0
   630
				WriteData(iStatus, iWriteBufPtr, hostDataLength);
sl@0
   631
				return;
sl@0
   632
				}
sl@0
   633
			}
sl@0
   634
		else  //read data from host
sl@0
   635
			{
sl@0
   636
			if (!iReadSetUp)
sl@0
   637
				{
sl@0
   638
				iDataResidue = hostDataLength;
sl@0
   639
				__PRINT(_L("Read buffer was not setup\n"));
sl@0
   640
//				Use next block instead of StallEndpointAndWaitForClear(OutEndpoint);
sl@0
   641
				DiscardData(hostDataLength);
sl@0
   642
sl@0
   643
				if (iWriteSetUp) //case (10)
sl@0
   644
					{
sl@0
   645
					__PRINT(_L("case 10\n"));
sl@0
   646
					SendCSW(iCbwTag, hostDataLength, EPhaseError);
sl@0
   647
					}
sl@0
   648
				else // case (9)
sl@0
   649
					{
sl@0
   650
					__PRINT(_L("Case 9\n"));
sl@0
   651
					SendCSW(iCbwTag, hostDataLength, iCmdStatus);
sl@0
   652
					}
sl@0
   653
sl@0
   654
				return;
sl@0
   655
				}
sl@0
   656
sl@0
   657
			TUint deviceDataLength = iBufSize;
sl@0
   658
			iDataResidue = hostDataLength;  // calculate residue later
sl@0
   659
sl@0
   660
			__PRINT2(_L("deviceDataLength = iBufSize = %d, DataResidue = HDL for now (read from host) =%d\n"),deviceDataLength,iDataResidue);
sl@0
   661
sl@0
   662
			if (deviceDataLength <= hostDataLength)  // case (11) and (12)
sl@0
   663
				{
sl@0
   664
				__PRINT(_L("Case 11 or 12\n"));
sl@0
   665
				ReadData(deviceDataLength);
sl@0
   666
				return;
sl@0
   667
				}
sl@0
   668
			if (deviceDataLength > hostDataLength) // case  (13)
sl@0
   669
				{
sl@0
   670
				__PRINT(_L("Case 13\n"));
sl@0
   671
                /**
sl@0
   672
                 * Comment following line in order to pass compliant test.
sl@0
   673
                 * As spec said in case 13:"The device may receive data up to a
sl@0
   674
                 * total of dCBWDataTransferLength."
sl@0
   675
                 * Here we choose to ignore incoming data.
sl@0
   676
                 */
sl@0
   677
				//StallEndpointAndWaitForClear(OutEndpoint); //Stall Out endpoint
sl@0
   678
                if (iReadSetUp)
sl@0
   679
                    {
sl@0
   680
					WriteToClient(hostDataLength);
sl@0
   681
                    iReadSetUp = EFalse;
sl@0
   682
                    }
sl@0
   683
                SendCSW(iCbwTag, hostDataLength, EPhaseError);
sl@0
   684
				return;
sl@0
   685
				}
sl@0
   686
			}
sl@0
   687
		}
sl@0
   688
	else  // Host expected no data transfer
sl@0
   689
		{
sl@0
   690
		__PRINT(_L("No data transfer expected\n"));
sl@0
   691
		iDataResidue = 0;
sl@0
   692
		if (iWriteSetUp || iReadSetUp)   // case (2) and (3)
sl@0
   693
			{
sl@0
   694
			__PRINT(_L("Case 2 or 3\n"));
sl@0
   695
			SendCSW(iCbwTag, 0, EPhaseError);
sl@0
   696
			}
sl@0
   697
		else
sl@0
   698
			{
sl@0
   699
			__PRINT(_L("Case 1\n"));
sl@0
   700
			SendCSW(iCbwTag, 0, iCmdStatus);  //case (1)
sl@0
   701
			}
sl@0
   702
		}
sl@0
   703
	}
sl@0
   704
sl@0
   705
sl@0
   706
/**
sl@0
   707
Check if CBW Valid and Meaningful.
sl@0
   708
sl@0
   709
@return ETrue if CBW is Valid and Meaningful, EFalse otherwise
sl@0
   710
*/
sl@0
   711
TBool CBulkOnlyTransport::CheckCBW()
sl@0
   712
	{
sl@0
   713
	__FNLOG("CBulkOnlyTransport::CheckCBW");
sl@0
   714
sl@0
   715
    //
sl@0
   716
    // Check valid
sl@0
   717
    //
sl@0
   718
sl@0
   719
    // Check length
sl@0
   720
    if ((TUint) (iCbwBufPtr.Length()) != KCbwLength)
sl@0
   721
        {
sl@0
   722
		__PRINT2(_L("Bad length: %d != KCbwLength"), iCbwBufPtr.Length(), KCbwLength);
sl@0
   723
		return EFalse;
sl@0
   724
        }
sl@0
   725
sl@0
   726
    // Check signature
sl@0
   727
	TInt i = KCbwSignatureOffset;
sl@0
   728
	if (iCbwBufPtr[i  ] != 0x55 ||         // CBW Singature from USB Bulk-Only Transport spec
sl@0
   729
		iCbwBufPtr[i+1] != 0x53 ||
sl@0
   730
		iCbwBufPtr[i+2] != 0x42 ||
sl@0
   731
		iCbwBufPtr[i+3] != 0x43)
sl@0
   732
		{
sl@0
   733
		__PRINT(_L("Bad signature"));
sl@0
   734
		__PRINT4(_L(" 0x%x, 0x%x, 0x%x, 0x%x \n"), iCbwBufPtr[i], iCbwBufPtr[i+1], iCbwBufPtr[i+2],iCbwBufPtr[i+3])
sl@0
   735
		return EFalse;
sl@0
   736
		}
sl@0
   737
sl@0
   738
    //
sl@0
   739
    // Check meaningful
sl@0
   740
    //
sl@0
   741
sl@0
   742
    // Check reserved bits ( must be zero )
sl@0
   743
    if ((iCbwBufPtr[KCbwLunOffset] & 0xF0) || (iCbwBufPtr[KCbwCbLengthOffset] & 0xE0))
sl@0
   744
		{
sl@0
   745
		__PRINT(_L("Reserved bits not zero\n"));
sl@0
   746
		return EFalse;
sl@0
   747
		}
sl@0
   748
sl@0
   749
	// check command block length
sl@0
   750
	TInt cbwcbLength = iCbwBufPtr[KCbwCbLengthOffset] & 0x1F;
sl@0
   751
	if (cbwcbLength >KMaxCbwcbLength)
sl@0
   752
		{
sl@0
   753
		__PRINT(_L("Incorrect block length\n"));
sl@0
   754
		return EFalse;
sl@0
   755
		}
sl@0
   756
sl@0
   757
	//check LUN
sl@0
   758
	TInt8 lun = static_cast<TUint8>(iCbwBufPtr[KCbwLunOffset] & 0x0f);
sl@0
   759
	if (iMaxLun < lun)
sl@0
   760
		{
sl@0
   761
		__PRINT1(_L("bad lun: %d"), lun);
sl@0
   762
		return EFalse;
sl@0
   763
		}
sl@0
   764
sl@0
   765
	return ETrue;
sl@0
   766
	}
sl@0
   767
sl@0
   768
sl@0
   769
/**
sl@0
   770
Initiate stalling of bulk IN endpoint.
sl@0
   771
Used when protocol wants to force host to initiate a reset recovery.
sl@0
   772
*/
sl@0
   773
void CBulkOnlyTransport::SetPermError()
sl@0
   774
	{
sl@0
   775
	__FNLOG("CBulkOnlyTransport::SetPermError");
sl@0
   776
    iCurrentState = EPermErr;
sl@0
   777
    Activate(KErrNone);
sl@0
   778
	}
sl@0
   779
sl@0
   780
sl@0
   781
/**
sl@0
   782
Send data provided by protocol to the host
sl@0
   783
sl@0
   784
@param aLength amount of data (in bytes) to be send to host
sl@0
   785
*/
sl@0
   786
void CBulkOnlyTransport::WriteData(TRequestStatus& aStatus, TPtrC8& aDes, TUint aLength, TBool aZlpRequired)
sl@0
   787
	{
sl@0
   788
	__FNLOG("CBulkOnlyTransport::WriteData");
sl@0
   789
sl@0
   790
	if (IsActive())
sl@0
   791
		{
sl@0
   792
		__PRINT(_L("Still active\n"));
sl@0
   793
		__ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsBulkOnlyStillActive));
sl@0
   794
		return;
sl@0
   795
		}
sl@0
   796
	WriteUsb(aStatus, aDes, aLength, aZlpRequired);
sl@0
   797
	iCurrentState = EWritingData;
sl@0
   798
	SetActive();
sl@0
   799
	}
sl@0
   800
sl@0
   801
sl@0
   802
/**
sl@0
   803
Send Command Status Wrapper to the host
sl@0
   804
sl@0
   805
@param aTag Echo of Command Block Tag sent by the host.
sl@0
   806
@param aDataResidue the difference between the amount of data expected by the
sl@0
   807
       host, and the actual amount of data processed by the device.
sl@0
   808
@param aStatus indicates the success or failure of the command.
sl@0
   809
*/
sl@0
   810
void CBulkOnlyTransport::SendCSW(TUint aTag, TUint aDataResidue, TCswStatus aStatus)
sl@0
   811
	{
sl@0
   812
	__FNLOG("CBulkOnlyTransport::SendCSW");
sl@0
   813
	__PRINT2(_L("DataResidue = %d, Status = %d \n"), aDataResidue, aStatus);
sl@0
   814
sl@0
   815
	if (IsActive())
sl@0
   816
		{
sl@0
   817
		__PRINT(_L("Still active\n"));
sl@0
   818
		__ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsBulkOnlyStillActive));
sl@0
   819
		return;
sl@0
   820
		}
sl@0
   821
sl@0
   822
	SetCswBufPtr(KCswLength);
sl@0
   823
	TInt i = KCswSingnatureOffset;
sl@0
   824
	iCswBufPtr[i  ] = 0x55;   // CSW Singature from USB Bulk-Only Transport spec
sl@0
   825
	iCswBufPtr[i+1] = 0x53;
sl@0
   826
	iCswBufPtr[i+2] = 0x42;
sl@0
   827
	iCswBufPtr[i+3] = 0x53;
sl@0
   828
sl@0
   829
	i = KCswTagOffset;
sl@0
   830
sl@0
   831
	iCswBufPtr[i  ] = static_cast<TUint8>((aTag & 0x000000FF));
sl@0
   832
	iCswBufPtr[i+1] = static_cast<TUint8>((aTag & 0x0000FF00) >> 8);
sl@0
   833
	iCswBufPtr[i+2] = static_cast<TUint8>((aTag & 0x00FF0000) >> 16);
sl@0
   834
	iCswBufPtr[i+3] = static_cast<TUint8>((aTag & 0xFF000000) >> 24);
sl@0
   835
sl@0
   836
	i = KCswDataResidueOffset;
sl@0
   837
	iCswBufPtr[i  ] = static_cast<TUint8>((aDataResidue & 0x000000FF));
sl@0
   838
	iCswBufPtr[i+1] = static_cast<TUint8>((aDataResidue & 0x0000FF00) >> 8);
sl@0
   839
	iCswBufPtr[i+2] = static_cast<TUint8>((aDataResidue & 0x00FF0000) >> 16);
sl@0
   840
	iCswBufPtr[i+3] = static_cast<TUint8>((aDataResidue & 0xFF000000) >> 24);
sl@0
   841
sl@0
   842
	iCswBufPtr[KCswStatusOffset] = static_cast<TUint8>(aStatus);
sl@0
   843
sl@0
   844
	TPtrC8 ptr(NULL, 0);
sl@0
   845
	ptr.Set((const TUint8*)iCswBufPtr.Ptr(), KCswLength);
sl@0
   846
sl@0
   847
	WriteUsb(iStatus, ptr, KCswLength);
sl@0
   848
sl@0
   849
	iCurrentState = ESendingCSW;
sl@0
   850
sl@0
   851
	SetActive();
sl@0
   852
	}
sl@0
   853
sl@0
   854
sl@0
   855
/**
sl@0
   856
Associates the transport with the protocol.  Called during initialization of the controller.
sl@0
   857
sl@0
   858
@param aProtocol reference to the protocol
sl@0
   859
*/
sl@0
   860
void CBulkOnlyTransport::RegisterProtocol(MProtocolBase& aProtocol)
sl@0
   861
	{
sl@0
   862
	__FNLOG("CBulkOnlyTransport::RegisterProtocol");
sl@0
   863
	iProtocol = &aProtocol;
sl@0
   864
	}
sl@0
   865
sl@0
   866
sl@0
   867
/**
sl@0
   868
Used by CControlInterface
sl@0
   869
sl@0
   870
@return reference to the controller which instantiate the CBulkOnlyTransport
sl@0
   871
*/
sl@0
   872
CUsbMassStorageController& CBulkOnlyTransport::Controller()
sl@0
   873
	{
sl@0
   874
	return iController;
sl@0
   875
	}
sl@0
   876
sl@0
   877
sl@0
   878
/**
sl@0
   879
@return the number of logical units supported by the device.
sl@0
   880
Logical Unit Numbers on the device shall be numbered contiguously starting from LUN
sl@0
   881
0 to a maximum LUN of 15 (Fh).
sl@0
   882
*/
sl@0
   883
TInt CBulkOnlyTransport::MaxLun()
sl@0
   884
	{
sl@0
   885
	return iMaxLun;
sl@0
   886
	}
sl@0
   887
sl@0
   888
sl@0
   889
void CBulkOnlyTransport::GetCommandBufPtr(TPtr8& aDes, TUint aLength) // Set pointer to buffer of specified aLength for command
sl@0
   890
	{
sl@0
   891
	aDes.Set(SetCommandBufPtr(aLength));
sl@0
   892
	}
sl@0
   893
sl@0
   894
void CBulkOnlyTransport::GetReadDataBufPtr(TPtr8& aDes) // Set pointer to buffer into which data is to be read from drive (Read10)
sl@0
   895
	{
sl@0
   896
	aDes.Set(SetDataBufPtr());
sl@0
   897
	}
sl@0
   898
sl@0
   899
sl@0
   900
void CBulkOnlyTransport::GetWriteDataBufPtr(TPtrC8& aDes) // Set pointer to buffer from which data is to be written to drive (Write10)
sl@0
   901
	{
sl@0
   902
	aDes.Set(iReadBufPtr);
sl@0
   903
	}
sl@0
   904
sl@0
   905
#ifdef MSDC_MULTITHREADED
sl@0
   906
void CBulkOnlyTransport::ProcessReadData(TAny* aAddress)
sl@0
   907
	{
sl@0
   908
	ExpireData(aAddress);
sl@0
   909
	}
sl@0
   910
#endif
sl@0
   911
sl@0
   912
sl@0
   913
sl@0
   914
sl@0
   915
sl@0
   916
sl@0
   917
sl@0
   918