os/kernelhwsrv/userlibandfileserver/fileserver/smassstorage/cbulkonlytransport.cpp
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/userlibandfileserver/fileserver/smassstorage/cbulkonlytransport.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,918 @@
1.4 +// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +/**
1.20 + @file
1.21 + @internalTechnology
1.22 +*/
1.23 +#include "cbulkonlytransport.h"
1.24 +#include "cbulkonlytransportusbcldd.h"
1.25 +#include "cbulkonlytransportusbcscldd.h"
1.26 +#include "usbmsshared.h"
1.27 +#include "massstoragedebug.h"
1.28 +#include "cusbmassstorageserver.h"
1.29 +
1.30 +
1.31 +//CBW offsets
1.32 +LOCAL_D const TInt KCbwSignatureOffset = 0;
1.33 +LOCAL_D const TInt KCbwTagOffset = 4;
1.34 +LOCAL_D const TInt KCbwDataTransferLengthOffset = 8;
1.35 +LOCAL_D const TInt KCbwFlagOffset = 12;
1.36 +LOCAL_D const TInt KCbwLunOffset = 13;
1.37 +LOCAL_D const TInt KCbwCbLengthOffset = 14;
1.38 +
1.39 +LOCAL_D const TInt KMaxCbwcbLength = 16;
1.40 +
1.41 +// CSW offsets
1.42 +LOCAL_D const TInt KCswSingnatureOffset = 0;
1.43 +LOCAL_D const TInt KCswTagOffset = 4;
1.44 +LOCAL_D const TInt KCswDataResidueOffset = 8;
1.45 +LOCAL_D const TInt KCswStatusOffset = 12;
1.46 +
1.47 +
1.48 +
1.49 +/**
1.50 + This function unpacks into the TUsbRequestHdr class from a descriptor with
1.51 + the alignment that would be introduced on the USB bus.
1.52 +
1.53 + @param aBuffer Input buffer
1.54 + @param aTarget Unpacked header.
1.55 + @return Error.
1.56 + */
1.57 +TInt TUsbRequestHdr::Decode(const TDesC8& aBuffer)
1.58 +
1.59 + {
1.60 + if (aBuffer.Length() < static_cast<TInt>(KRequestHdrSize))
1.61 + {
1.62 + __PRINT1(_L("TUsbRequestHdr::Decode buffer invalid length %d"), aBuffer.Length());
1.63 + return KErrGeneral;
1.64 + }
1.65 +
1.66 + iRequestType = aBuffer[0];
1.67 + iRequest = static_cast<TEp0Request>(aBuffer[1]);
1.68 + iValue = static_cast<TUint16>(aBuffer[2] + (aBuffer[3] << 8));
1.69 + iIndex = static_cast<TUint16>(aBuffer[4] + (aBuffer[5] << 8));
1.70 + iLength = static_cast<TUint16>(aBuffer[6] + (aBuffer[7] << 8));
1.71 + __PRINT5(_L("type=%d request=%d value=%d index=%d length=%d"), iRequestType,iRequest,iValue,iIndex,iLength);
1.72 +
1.73 + return KErrNone;
1.74 + }
1.75 +
1.76 +
1.77 +/**
1.78 +This function determines whether data is required by the host in response
1.79 +to a message header.
1.80 +
1.81 +@return TBool Flag indicating whether a data response required.
1.82 +*/
1.83 +TBool TUsbRequestHdr::IsDataResponseRequired() const
1.84 +
1.85 + {
1.86 + return (iRequestType & 0x80) ? (TBool)ETrue : (TBool)EFalse;
1.87 + }
1.88 +
1.89 +//-------------------------------------
1.90 +/**
1.91 +Create an object of a class derived from CBulkOnlyTransport (default to CBulkOnlyTransportUsbcLdd object)
1.92 +@param aNumDrives - The number of drives available for MS
1.93 +@param aController - reference to the parent
1.94 +@return pointer to newly created derived class object
1.95 +*/
1.96 +CBulkOnlyTransport* CBulkOnlyTransport::NewL(TInt aNumDrives,CUsbMassStorageController& aController)
1.97 + {
1.98 + __FNLOG("CBulkOnlyTransport::NewL()");
1.99 +
1.100 + return NewL(aNumDrives,aController, (CUsbMassStorageController::TTransportldd) 1);
1.101 + }
1.102 +
1.103 +/**
1.104 +Create an object of a class derived from CBulkOnlyTransport
1.105 +@param aNumDrives - The number of drives available for MS
1.106 +@param aController - reference to the parent
1.107 +@param aTransportLddFlag - Type of usb client ldd
1.108 +@return pointer to newly created derived class object
1.109 +*/
1.110 +CBulkOnlyTransport* CBulkOnlyTransport::NewL(TInt aNumDrives,CUsbMassStorageController& aController, CUsbMassStorageController::TTransportldd aTransportLddFlag)
1.111 + {
1.112 + __FNLOG("CBulkOnlyTransport::NewL()");
1.113 +
1.114 + if (aNumDrives <=0 || static_cast<TUint>(aNumDrives) > KUsbMsMaxDrives)
1.115 + {
1.116 + User::Leave(KErrArgument);
1.117 + }
1.118 +
1.119 + CBulkOnlyTransportUsbcScLdd* scTransport;
1.120 + CBulkOnlyTransportUsbcLdd* nonscTransport;
1.121 + switch (aTransportLddFlag)
1.122 + {
1.123 + case 1:
1.124 + nonscTransport = new(ELeave) CBulkOnlyTransportUsbcLdd(aNumDrives, aController);
1.125 + return nonscTransport;
1.126 +
1.127 + case 2:
1.128 + scTransport = new(ELeave) CBulkOnlyTransportUsbcScLdd(aNumDrives, aController);
1.129 + return scTransport;
1.130 + default:
1.131 + return NULL;
1.132 +
1.133 + }
1.134 + }
1.135 +
1.136 +
1.137 +TInt CBulkOnlyTransport::InitialiseTransportL(TInt aTransportLddFlag)
1.138 + {
1.139 + __FNLOG("CBulkOnlyTransportUsbcScLdd::InitialiseTransportL()");
1.140 + TInt ret = KErrNone;
1.141 + MTransportBase* transport;
1.142 + iController.GetTransport(transport);
1.143 + switch (aTransportLddFlag)
1.144 + {
1.145 + case 2:
1.146 + ret = ((CBulkOnlyTransportUsbcScLdd*) transport)->Ldd().Open(0);
1.147 + if (ret != KErrNone)
1.148 + {
1.149 + return ret;
1.150 + }
1.151 + else
1.152 + {
1.153 + ((CBulkOnlyTransportUsbcScLdd*) transport)->Ldd().Close();
1.154 + CleanupStack::PushL(transport);
1.155 + ((CBulkOnlyTransportUsbcScLdd*) transport)->ConstructL();
1.156 + CleanupStack::Pop(transport);
1.157 + return ret;
1.158 + }
1.159 + case 1:
1.160 + ret = ((CBulkOnlyTransportUsbcLdd*) transport)->Ldd().Open(0);
1.161 + if (ret != KErrNone)
1.162 + {
1.163 + return ret;
1.164 + }
1.165 + else
1.166 + {
1.167 + ((CBulkOnlyTransportUsbcLdd*) transport)->Ldd().Close();
1.168 + CleanupStack::PushL(transport);
1.169 + ((CBulkOnlyTransportUsbcLdd*) transport)->ConstructL();
1.170 + CleanupStack::Pop(transport);
1.171 + return ret;
1.172 + }
1.173 + default:
1.174 + return KErrNotFound;
1.175 + }
1.176 + }
1.177 +
1.178 +/**
1.179 +c'tor
1.180 +@param aNumDrives - The number of drives available for MS
1.181 +@param aController - reference to the parent
1.182 +*/
1.183 +CBulkOnlyTransport::CBulkOnlyTransport(TInt aNumDrives,CUsbMassStorageController& aController):
1.184 + CActive(EPriorityStandard),
1.185 + iMaxLun(aNumDrives-1),
1.186 + iController(aController),
1.187 + iStallAllowed(ETrue),
1.188 + iInterfaceConfigured(EFalse),
1.189 + iCommandBufPtr(NULL,0),
1.190 + iDataBufPtr(NULL,0),
1.191 + iCswBufPtr(NULL,0),
1.192 + iPaddingBufPtr(NULL,0),
1.193 + iWriteBufPtr(NULL,0),
1.194 + iReadBufPtr(NULL, 0),
1.195 + iCbwBufPtr(NULL,0)
1.196 + {
1.197 + __FNLOG("CBulkOnlyTransport::CBulkOnlyTransport");
1.198 + }
1.199 +
1.200 +/**
1.201 +Destructor
1.202 +*/
1.203 +CBulkOnlyTransport::~CBulkOnlyTransport()
1.204 + {
1.205 + __FNLOG("CBulkOnlyTransport::~CBulkOnlyTransport");
1.206 + if (iInterfaceConfigured)
1.207 + {
1.208 + Stop();
1.209 + }
1.210 + }
1.211 +
1.212 +
1.213 +/**
1.214 +Called by the protocol after processing the packet to indicate that more data is required.
1.215 +
1.216 +@param aData reference to the data buffer.
1.217 +*/
1.218 +void CBulkOnlyTransport::SetupReadData(TUint aLength)
1.219 + {
1.220 + __FNLOG("CBulkOnlyTransport::SetupReadData");
1.221 + __PRINT1(_L("Length = %d (bytes)\n"), aLength);
1.222 + iBufSize = aLength;
1.223 + iReadSetUp = ETrue;
1.224 + }
1.225 +
1.226 +
1.227 +/**
1.228 +Called by the protocol after processing the packet to indicate that data should be written to the host.
1.229 +
1.230 +@param aData reference to the data buffer.
1.231 +*/
1.232 +void CBulkOnlyTransport::SetupWriteData(TPtrC8& aData)
1.233 + {
1.234 + __FNLOG("CBulkOnlyTransport::SetupWriteData");
1.235 + __PRINT1(_L("Length = %d (bytes)\n"), aData.Length());
1.236 + iWriteBufPtr.Set(aData);
1.237 + iWriteSetUp = ETrue;
1.238 + }
1.239 +
1.240 +
1.241 +TInt CBulkOnlyTransport::Start()
1.242 + {
1.243 + __FNLOG("CBulkOnlyTransport::Start");
1.244 +
1.245 + TInt err = KErrNone;
1.246 +
1.247 + if (!iProtocol)
1.248 + {
1.249 + return KErrBadHandle; //protocol should be set up before start
1.250 + }
1.251 +
1.252 + if (IsActive())
1.253 + {
1.254 + __PRINT(_L("CBulkOnlyTransport::Start - active before start!\n"));
1.255 + return KErrInUse;
1.256 + }
1.257 +
1.258 + if ((err = SetupConfigurationDescriptor()) != KErrNone ||
1.259 + (err = SetupInterfaceDescriptors()) != KErrNone )
1.260 + {
1.261 + __PRINT(_L("CBulkOnlyTransport::Start - Error during descriptors setup!\n"));
1.262 + return err;
1.263 + }
1.264 +
1.265 + AllocateEndpointResources();
1.266 + ActivateDeviceStateNotifier(); // activate notifier wich will wait until USB became configured
1.267 + TUsbcDeviceState deviceStatus = EUsbcDeviceStateDefault;
1.268 + err = GetDeviceStatus(deviceStatus);
1.269 + __PRINT1(_L("CBulkOnlyTransport::Start - Device status = %d\n"), deviceStatus);
1.270 + if (err == KErrNone && deviceStatus == EUsbcDeviceStateConfigured)
1.271 + {
1.272 + __PRINT(_L("CBulkOnlyTransport::Start - Starting bulk only transport\n"));
1.273 + err = HwStart();
1.274 + }
1.275 +
1.276 +#ifdef MSDC_MULTITHREADED
1.277 + TPtr8 aDes1(NULL,0);
1.278 + TPtr8 aDes2(NULL,0);
1.279 + GetBufferPointers(aDes1, aDes2);
1.280 + iProtocol->InitializeBufferPointers(aDes1, aDes2); // have to pass pointer to memory not offsets to initialise TPtr, and lengths
1.281 +#endif
1.282 +
1.283 + iInterfaceConfigured = ETrue;
1.284 + return err;
1.285 + }
1.286 +
1.287 +TInt CBulkOnlyTransport::HwStart(TBool aDiscard)
1.288 + {
1.289 + __FNLOG("CBulkOnlyTransport::HwStart");
1.290 +
1.291 + TInt lun = MaxLun();
1.292 + do
1.293 + {
1.294 + Controller().DriveManager().Connect(lun);
1.295 + }
1.296 + while(--lun >= 0);
1.297 +
1.298 + TInt res = StartControlInterface();
1.299 +
1.300 + iCurrentState = ENone;
1.301 + iWriteSetUp=EFalse;
1.302 + iReadSetUp=EFalse;
1.303 + iStarted = ETrue;
1.304 +
1.305 + if (aDiscard)
1.306 + {
1.307 + FlushData();
1.308 + }
1.309 +
1.310 + ReadCBW();
1.311 + return res;
1.312 + }
1.313 +
1.314 +
1.315 +TInt CBulkOnlyTransport::HwStop()
1.316 + {
1.317 + __FNLOG("CBulkOnlyTransport::HwStop");
1.318 + if (iStarted)
1.319 + {
1.320 + StopBulkOnlyEndpoint();
1.321 + CancelControlInterface();
1.322 + iStarted = EFalse;
1.323 + }
1.324 + return KErrNone;
1.325 + }
1.326 +
1.327 +
1.328 +void CBulkOnlyTransport::StopBulkOnlyEndpoint()
1.329 + {
1.330 + __FNLOG("CBulkOnlyTransport::StopBulkOnlyEndpoint");
1.331 +
1.332 + TInt lun = MaxLun();
1.333 + do
1.334 + {
1.335 + Controller().DriveManager().Disconnect(lun);
1.336 + }
1.337 + while(--lun >= 0);
1.338 + Cancel();
1.339 + iProtocol->Cancel();
1.340 + }
1.341 +
1.342 +
1.343 +TInt CBulkOnlyTransport::HwSuspend()
1.344 + {
1.345 + __FNLOG("CBulkOnlyTransport::HwSuspend");
1.346 +
1.347 + TInt lun = MaxLun();
1.348 + do
1.349 + {
1.350 + Controller().DriveManager().Disconnect(lun);
1.351 + }
1.352 + while(--lun >= 0);
1.353 +
1.354 + return KErrNone;
1.355 + }
1.356 +
1.357 +
1.358 +TInt CBulkOnlyTransport::HwResume()
1.359 + {
1.360 + __FNLOG("CBulkOnlyTransport::HwResume");
1.361 +
1.362 + TInt lun = MaxLun();
1.363 + do
1.364 + {
1.365 + Controller().DriveManager().Connect(lun);
1.366 + }
1.367 + while(--lun >= 0);
1.368 +
1.369 + return KErrNone;
1.370 + }
1.371 +
1.372 +/**
1.373 +Stops the Bulk Only Transport
1.374 +*/
1.375 +TInt CBulkOnlyTransport::Stop()
1.376 + {
1.377 + __FNLOG("CBulkOnlyTransport::Stop");
1.378 + CancelControlInterface();
1.379 + CancelDeviceStateNotifier();
1.380 + Cancel();
1.381 + if (iInterfaceConfigured)
1.382 + {
1.383 + ReleaseInterface();
1.384 + SetupConfigurationDescriptor(ETrue);
1.385 + }
1.386 + iCurrentState = ENone;
1.387 + iInterfaceConfigured = EFalse;
1.388 +
1.389 + return KErrNone;
1.390 + }
1.391 +
1.392 +
1.393 +
1.394 +void CBulkOnlyTransport::DoCancel()
1.395 + {
1.396 + __FNLOG("CBulkOnlyTransport::DoCancel");
1.397 + CancelReadWriteRequests();
1.398 + }
1.399 +
1.400 +
1.401 +void CBulkOnlyTransport::Activate(TInt aReason)
1.402 + {
1.403 + SetActive();
1.404 + TRequestStatus* r = &iStatus;
1.405 + User::RequestComplete(r, aReason);
1.406 + }
1.407 +
1.408 +
1.409 +void CBulkOnlyTransport::RunL()
1.410 + {
1.411 + __FNLOG("CBulkOnlyTransport::RunL");
1.412 + if (iStatus != KErrNone)
1.413 + {
1.414 + __PRINT1(_L("Error %d in RunL, halt endpoints \n"), iStatus.Int());
1.415 + SetPermError(); //halt endpoints for reset recovery
1.416 + return;
1.417 + }
1.418 + switch (iCurrentState)
1.419 + {
1.420 + case EWaitForCBW:
1.421 + __PRINT(_L("EWaitForCBW"));
1.422 + ProcessCbwEvent();
1.423 + break;
1.424 +
1.425 + case EWritingData:
1.426 + __PRINT(_L("EWritingData"));
1.427 + iWriteSetUp = EFalse; //the buffer was used
1.428 +
1.429 + if (iDataResidue && iStallAllowed)
1.430 + {
1.431 + StallEndpointAndWaitForClear();
1.432 + }
1.433 +
1.434 + SendCSW(iCbwTag, iDataResidue, iCmdStatus);
1.435 + break;
1.436 +
1.437 + case EReadingData:
1.438 + {
1.439 + __PRINT(_L("EReadingData"));
1.440 +
1.441 + ProcessReadingDataEvent();
1.442 + }
1.443 + break;
1.444 +
1.445 + case ESendingCSW:
1.446 + __PRINT(_L("ESendingCSW"));
1.447 + ReadCBW();
1.448 + break;
1.449 +
1.450 + case EPermErr:
1.451 + __PRINT(_L("EPermErr"));
1.452 + StallEndpointAndWaitForClear();
1.453 + break;
1.454 +
1.455 + default:
1.456 + SetPermError(); // unexpected state
1.457 + }
1.458 + }
1.459 +
1.460 +
1.461 +/**
1.462 +Decode the CBW received from the host via OutEndpoint
1.463 +
1.464 +- If the header is valid, the data content is passed to the parser.
1.465 +- Depending on the command, more data may be transmitted/received.
1.466 +- ...or the CSW is sent (if not a data command).
1.467 +
1.468 +*/
1.469 +void CBulkOnlyTransport::DecodeCBW()
1.470 + {
1.471 + __FNLOG("CBulkOnlyTransport::DecodeCBW");
1.472 +
1.473 + SetCbwPtr();
1.474 +
1.475 + if (!CheckCBW()) //check if CBW valid and meaningful
1.476 + {
1.477 + // CBW not valid or meaningful
1.478 + // Specification says: "If the CBW is not valid, the device shall STALL
1.479 + // the Bulk-In pipe. Also, the device shall either STALL the Bulk-Out pipe,
1.480 + // or the device shall accept and discard any Bulk-Out data. The device
1.481 + // shall maintain this state until a Reset Recovery."
1.482 + // Here we keep bulk-in ep stalled and ignore bulk-out ep.
1.483 + SetPermError();
1.484 + ExpireData((TAny*) (iCbwBufPtr.Ptr()));
1.485 + return;
1.486 + }
1.487 +
1.488 + TPtrC8 aData;
1.489 + aData.Set(&iCbwBufPtr[KCbwCbLengthOffset], KMaxCbwcbLength+1); //prepare data for protocol starting form Length
1.490 + TUint8 lun = static_cast<TUint8>(iCbwBufPtr[13] & 0x0f);
1.491 +
1.492 + iCbwTag = static_cast<TUint32>(iCbwBufPtr[KCbwTagOffset]) |
1.493 + static_cast<TUint32>(iCbwBufPtr[KCbwTagOffset+1]) <<8 |
1.494 + static_cast<TUint32>(iCbwBufPtr[KCbwTagOffset+2]) <<16|
1.495 + static_cast<TUint32>(iCbwBufPtr[KCbwTagOffset+3]) <<24;
1.496 +
1.497 + TInt i = KCbwDataTransferLengthOffset;
1.498 + TUint hostDataLength = static_cast<TUint32>(iCbwBufPtr[i ]) |
1.499 + static_cast<TUint32>(iCbwBufPtr[i+1]) <<8 |
1.500 + static_cast<TUint32>(iCbwBufPtr[i+2]) <<16 |
1.501 + static_cast<TUint32>(iCbwBufPtr[i+3]) <<24;
1.502 +
1.503 + TBool dataToHost = iCbwBufPtr[KCbwFlagOffset] & 0x80;
1.504 +
1.505 + __PRINT4(_L("lun =%d, hostDataLength=%d, CBWtag = 0x%x, dataToHost=%d\n"), lun, hostDataLength, iCbwTag, dataToHost);
1.506 + //////////////////////////////////////////////
1.507 + TBool ret = iProtocol->DecodePacket(aData, lun);
1.508 + //////////////////////////////////////////////
1.509 + ExpireData((TAny*) (iCbwBufPtr.Ptr()));
1.510 +
1.511 +
1.512 + iStallAllowed = ETrue;
1.513 +
1.514 + if (!ret)
1.515 + {
1.516 + __PRINT(_L("Command Failed\n"));
1.517 + iCmdStatus = ECommandFailed;
1.518 + }
1.519 + else
1.520 + {
1.521 + __PRINT(_L("Command Passed\n"));
1.522 + iCmdStatus = ECommandPassed;
1.523 + }
1.524 +
1.525 + if (hostDataLength) // Host expected data transfer
1.526 + {
1.527 + if (dataToHost) // send data to host
1.528 + {
1.529 + if (!iWriteSetUp) //write buffer was not set up
1.530 + {
1.531 + __PRINT(_L("Write buffer was not setup\n"));
1.532 + iDataResidue =hostDataLength;
1.533 + __PRINT1(_L("DataResidue (write to host)=%d\n"),iDataResidue);
1.534 +
1.535 +//------------------------------------
1.536 + if (hostDataLength <= KBOTMaxBufSize)
1.537 + {
1.538 + __PRINT(_L("Case 4 or 8\n"));
1.539 + SetPaddingBufPtr(hostDataLength);
1.540 + iPaddingBufPtr.FillZ(hostDataLength);
1.541 + TPtrC8 ptr(NULL, 0);
1.542 + ptr.Set((TUint8*)iPaddingBufPtr.Ptr(), hostDataLength);
1.543 + WriteData(iStatus, ptr, hostDataLength, EFalse);
1.544 + iStallAllowed = EFalse;
1.545 + if (iReadSetUp) //read buffer WAS set up - case (8)
1.546 + {
1.547 + __PRINT(_L("It is Case 8\n"));
1.548 + iCmdStatus = EPhaseError;
1.549 + }
1.550 + return;
1.551 + }
1.552 + else
1.553 +//------------------------------------
1.554 +// Use next block instead of StallEndpointAndWaitForClear(InEndpoint);
1.555 + {
1.556 + SetPaddingBufPtr(hostDataLength);
1.557 + iPaddingBufPtr.FillZ(KBOTMaxBufSize);
1.558 + TUint c =0;
1.559 + TRequestStatus status;
1.560 + while (c<hostDataLength)
1.561 + {
1.562 + TInt len;
1.563 + if (hostDataLength - c > KBOTMaxBufSize)
1.564 + {
1.565 + len = KBOTMaxBufSize;
1.566 + }
1.567 + else
1.568 + {
1.569 + len = hostDataLength - c;
1.570 + }
1.571 +
1.572 + TPtrC8 ptr(NULL, 0);
1.573 + ptr.Set((TUint8*)iPaddingBufPtr.Ptr(), len);
1.574 + WriteUsb(status, ptr, len);
1.575 + User::WaitForRequest(status);
1.576 + c += KBOTMaxBufSize;
1.577 + }
1.578 + }
1.579 +
1.580 + if (iReadSetUp) //read buffer WAS set up - case (8)
1.581 + {
1.582 + __PRINT(_L("Case 8\n"));
1.583 + SendCSW(iCbwTag, hostDataLength, EPhaseError);
1.584 + //don't care to reset any flag - should get reset recovery
1.585 + }
1.586 + else // case (4)
1.587 + {
1.588 + __PRINT(_L("Case 4\n"));
1.589 + SendCSW(iCbwTag, hostDataLength, iCmdStatus);
1.590 + }
1.591 + return;
1.592 + } // if (!iWriteSetUp)
1.593 +
1.594 +//==================
1.595 + TUint deviceDataLength = static_cast<TUint>(iWriteBufPtr.Length());
1.596 + iDataResidue =hostDataLength - deviceDataLength ;
1.597 + __PRINT2(_L("Device data length = %d, DataResidue (write to host)=%d\n"), deviceDataLength, iDataResidue);
1.598 +
1.599 + if (deviceDataLength < hostDataLength &&
1.600 + hostDataLength < KBOTMaxBufSize )
1.601 + {
1.602 + __PRINT(_L("Case 5 (padding)\n"));
1.603 + SetPaddingBufPtr(hostDataLength);
1.604 + iPaddingBufPtr.Zero();
1.605 + iPaddingBufPtr.Append(iWriteBufPtr);
1.606 + iStallAllowed = EFalse;
1.607 + __PRINT1(_L("iPaddingBufPtr.Length = %d\n"),iPaddingBufPtr.Length());
1.608 + TPtrC8 ptr(NULL, 0);
1.609 + ptr.Set((TUint8*)iPaddingBufPtr.Ptr(), hostDataLength);
1.610 + WriteData(iStatus, ptr, hostDataLength, EFalse);
1.611 + return;
1.612 + }
1.613 +
1.614 +//===================
1.615 +
1.616 + if (deviceDataLength == hostDataLength) //case (6)[==]
1.617 + {
1.618 + __PRINT(_L("Case 6\n"));
1.619 + WriteData(iStatus, iWriteBufPtr, deviceDataLength);
1.620 + return;
1.621 + }
1.622 + else if (deviceDataLength < hostDataLength) //case (5)[<]
1.623 + {
1.624 + __PRINT(_L("Case 5\n"));
1.625 + WriteData(iStatus, iWriteBufPtr, deviceDataLength, ETrue); // Send ZLP
1.626 + return;
1.627 + }
1.628 + else // deviceDataLength > hostDataLength - case (7)
1.629 + {
1.630 + __PRINT(_L("Case 7\n"));
1.631 + iCmdStatus = EPhaseError;
1.632 + iDataResidue = 0;
1.633 + WriteData(iStatus, iWriteBufPtr, hostDataLength);
1.634 + return;
1.635 + }
1.636 + }
1.637 + else //read data from host
1.638 + {
1.639 + if (!iReadSetUp)
1.640 + {
1.641 + iDataResidue = hostDataLength;
1.642 + __PRINT(_L("Read buffer was not setup\n"));
1.643 +// Use next block instead of StallEndpointAndWaitForClear(OutEndpoint);
1.644 + DiscardData(hostDataLength);
1.645 +
1.646 + if (iWriteSetUp) //case (10)
1.647 + {
1.648 + __PRINT(_L("case 10\n"));
1.649 + SendCSW(iCbwTag, hostDataLength, EPhaseError);
1.650 + }
1.651 + else // case (9)
1.652 + {
1.653 + __PRINT(_L("Case 9\n"));
1.654 + SendCSW(iCbwTag, hostDataLength, iCmdStatus);
1.655 + }
1.656 +
1.657 + return;
1.658 + }
1.659 +
1.660 + TUint deviceDataLength = iBufSize;
1.661 + iDataResidue = hostDataLength; // calculate residue later
1.662 +
1.663 + __PRINT2(_L("deviceDataLength = iBufSize = %d, DataResidue = HDL for now (read from host) =%d\n"),deviceDataLength,iDataResidue);
1.664 +
1.665 + if (deviceDataLength <= hostDataLength) // case (11) and (12)
1.666 + {
1.667 + __PRINT(_L("Case 11 or 12\n"));
1.668 + ReadData(deviceDataLength);
1.669 + return;
1.670 + }
1.671 + if (deviceDataLength > hostDataLength) // case (13)
1.672 + {
1.673 + __PRINT(_L("Case 13\n"));
1.674 + /**
1.675 + * Comment following line in order to pass compliant test.
1.676 + * As spec said in case 13:"The device may receive data up to a
1.677 + * total of dCBWDataTransferLength."
1.678 + * Here we choose to ignore incoming data.
1.679 + */
1.680 + //StallEndpointAndWaitForClear(OutEndpoint); //Stall Out endpoint
1.681 + if (iReadSetUp)
1.682 + {
1.683 + WriteToClient(hostDataLength);
1.684 + iReadSetUp = EFalse;
1.685 + }
1.686 + SendCSW(iCbwTag, hostDataLength, EPhaseError);
1.687 + return;
1.688 + }
1.689 + }
1.690 + }
1.691 + else // Host expected no data transfer
1.692 + {
1.693 + __PRINT(_L("No data transfer expected\n"));
1.694 + iDataResidue = 0;
1.695 + if (iWriteSetUp || iReadSetUp) // case (2) and (3)
1.696 + {
1.697 + __PRINT(_L("Case 2 or 3\n"));
1.698 + SendCSW(iCbwTag, 0, EPhaseError);
1.699 + }
1.700 + else
1.701 + {
1.702 + __PRINT(_L("Case 1\n"));
1.703 + SendCSW(iCbwTag, 0, iCmdStatus); //case (1)
1.704 + }
1.705 + }
1.706 + }
1.707 +
1.708 +
1.709 +/**
1.710 +Check if CBW Valid and Meaningful.
1.711 +
1.712 +@return ETrue if CBW is Valid and Meaningful, EFalse otherwise
1.713 +*/
1.714 +TBool CBulkOnlyTransport::CheckCBW()
1.715 + {
1.716 + __FNLOG("CBulkOnlyTransport::CheckCBW");
1.717 +
1.718 + //
1.719 + // Check valid
1.720 + //
1.721 +
1.722 + // Check length
1.723 + if ((TUint) (iCbwBufPtr.Length()) != KCbwLength)
1.724 + {
1.725 + __PRINT2(_L("Bad length: %d != KCbwLength"), iCbwBufPtr.Length(), KCbwLength);
1.726 + return EFalse;
1.727 + }
1.728 +
1.729 + // Check signature
1.730 + TInt i = KCbwSignatureOffset;
1.731 + if (iCbwBufPtr[i ] != 0x55 || // CBW Singature from USB Bulk-Only Transport spec
1.732 + iCbwBufPtr[i+1] != 0x53 ||
1.733 + iCbwBufPtr[i+2] != 0x42 ||
1.734 + iCbwBufPtr[i+3] != 0x43)
1.735 + {
1.736 + __PRINT(_L("Bad signature"));
1.737 + __PRINT4(_L(" 0x%x, 0x%x, 0x%x, 0x%x \n"), iCbwBufPtr[i], iCbwBufPtr[i+1], iCbwBufPtr[i+2],iCbwBufPtr[i+3])
1.738 + return EFalse;
1.739 + }
1.740 +
1.741 + //
1.742 + // Check meaningful
1.743 + //
1.744 +
1.745 + // Check reserved bits ( must be zero )
1.746 + if ((iCbwBufPtr[KCbwLunOffset] & 0xF0) || (iCbwBufPtr[KCbwCbLengthOffset] & 0xE0))
1.747 + {
1.748 + __PRINT(_L("Reserved bits not zero\n"));
1.749 + return EFalse;
1.750 + }
1.751 +
1.752 + // check command block length
1.753 + TInt cbwcbLength = iCbwBufPtr[KCbwCbLengthOffset] & 0x1F;
1.754 + if (cbwcbLength >KMaxCbwcbLength)
1.755 + {
1.756 + __PRINT(_L("Incorrect block length\n"));
1.757 + return EFalse;
1.758 + }
1.759 +
1.760 + //check LUN
1.761 + TInt8 lun = static_cast<TUint8>(iCbwBufPtr[KCbwLunOffset] & 0x0f);
1.762 + if (iMaxLun < lun)
1.763 + {
1.764 + __PRINT1(_L("bad lun: %d"), lun);
1.765 + return EFalse;
1.766 + }
1.767 +
1.768 + return ETrue;
1.769 + }
1.770 +
1.771 +
1.772 +/**
1.773 +Initiate stalling of bulk IN endpoint.
1.774 +Used when protocol wants to force host to initiate a reset recovery.
1.775 +*/
1.776 +void CBulkOnlyTransport::SetPermError()
1.777 + {
1.778 + __FNLOG("CBulkOnlyTransport::SetPermError");
1.779 + iCurrentState = EPermErr;
1.780 + Activate(KErrNone);
1.781 + }
1.782 +
1.783 +
1.784 +/**
1.785 +Send data provided by protocol to the host
1.786 +
1.787 +@param aLength amount of data (in bytes) to be send to host
1.788 +*/
1.789 +void CBulkOnlyTransport::WriteData(TRequestStatus& aStatus, TPtrC8& aDes, TUint aLength, TBool aZlpRequired)
1.790 + {
1.791 + __FNLOG("CBulkOnlyTransport::WriteData");
1.792 +
1.793 + if (IsActive())
1.794 + {
1.795 + __PRINT(_L("Still active\n"));
1.796 + __ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsBulkOnlyStillActive));
1.797 + return;
1.798 + }
1.799 + WriteUsb(aStatus, aDes, aLength, aZlpRequired);
1.800 + iCurrentState = EWritingData;
1.801 + SetActive();
1.802 + }
1.803 +
1.804 +
1.805 +/**
1.806 +Send Command Status Wrapper to the host
1.807 +
1.808 +@param aTag Echo of Command Block Tag sent by the host.
1.809 +@param aDataResidue the difference between the amount of data expected by the
1.810 + host, and the actual amount of data processed by the device.
1.811 +@param aStatus indicates the success or failure of the command.
1.812 +*/
1.813 +void CBulkOnlyTransport::SendCSW(TUint aTag, TUint aDataResidue, TCswStatus aStatus)
1.814 + {
1.815 + __FNLOG("CBulkOnlyTransport::SendCSW");
1.816 + __PRINT2(_L("DataResidue = %d, Status = %d \n"), aDataResidue, aStatus);
1.817 +
1.818 + if (IsActive())
1.819 + {
1.820 + __PRINT(_L("Still active\n"));
1.821 + __ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsBulkOnlyStillActive));
1.822 + return;
1.823 + }
1.824 +
1.825 + SetCswBufPtr(KCswLength);
1.826 + TInt i = KCswSingnatureOffset;
1.827 + iCswBufPtr[i ] = 0x55; // CSW Singature from USB Bulk-Only Transport spec
1.828 + iCswBufPtr[i+1] = 0x53;
1.829 + iCswBufPtr[i+2] = 0x42;
1.830 + iCswBufPtr[i+3] = 0x53;
1.831 +
1.832 + i = KCswTagOffset;
1.833 +
1.834 + iCswBufPtr[i ] = static_cast<TUint8>((aTag & 0x000000FF));
1.835 + iCswBufPtr[i+1] = static_cast<TUint8>((aTag & 0x0000FF00) >> 8);
1.836 + iCswBufPtr[i+2] = static_cast<TUint8>((aTag & 0x00FF0000) >> 16);
1.837 + iCswBufPtr[i+3] = static_cast<TUint8>((aTag & 0xFF000000) >> 24);
1.838 +
1.839 + i = KCswDataResidueOffset;
1.840 + iCswBufPtr[i ] = static_cast<TUint8>((aDataResidue & 0x000000FF));
1.841 + iCswBufPtr[i+1] = static_cast<TUint8>((aDataResidue & 0x0000FF00) >> 8);
1.842 + iCswBufPtr[i+2] = static_cast<TUint8>((aDataResidue & 0x00FF0000) >> 16);
1.843 + iCswBufPtr[i+3] = static_cast<TUint8>((aDataResidue & 0xFF000000) >> 24);
1.844 +
1.845 + iCswBufPtr[KCswStatusOffset] = static_cast<TUint8>(aStatus);
1.846 +
1.847 + TPtrC8 ptr(NULL, 0);
1.848 + ptr.Set((const TUint8*)iCswBufPtr.Ptr(), KCswLength);
1.849 +
1.850 + WriteUsb(iStatus, ptr, KCswLength);
1.851 +
1.852 + iCurrentState = ESendingCSW;
1.853 +
1.854 + SetActive();
1.855 + }
1.856 +
1.857 +
1.858 +/**
1.859 +Associates the transport with the protocol. Called during initialization of the controller.
1.860 +
1.861 +@param aProtocol reference to the protocol
1.862 +*/
1.863 +void CBulkOnlyTransport::RegisterProtocol(MProtocolBase& aProtocol)
1.864 + {
1.865 + __FNLOG("CBulkOnlyTransport::RegisterProtocol");
1.866 + iProtocol = &aProtocol;
1.867 + }
1.868 +
1.869 +
1.870 +/**
1.871 +Used by CControlInterface
1.872 +
1.873 +@return reference to the controller which instantiate the CBulkOnlyTransport
1.874 +*/
1.875 +CUsbMassStorageController& CBulkOnlyTransport::Controller()
1.876 + {
1.877 + return iController;
1.878 + }
1.879 +
1.880 +
1.881 +/**
1.882 +@return the number of logical units supported by the device.
1.883 +Logical Unit Numbers on the device shall be numbered contiguously starting from LUN
1.884 +0 to a maximum LUN of 15 (Fh).
1.885 +*/
1.886 +TInt CBulkOnlyTransport::MaxLun()
1.887 + {
1.888 + return iMaxLun;
1.889 + }
1.890 +
1.891 +
1.892 +void CBulkOnlyTransport::GetCommandBufPtr(TPtr8& aDes, TUint aLength) // Set pointer to buffer of specified aLength for command
1.893 + {
1.894 + aDes.Set(SetCommandBufPtr(aLength));
1.895 + }
1.896 +
1.897 +void CBulkOnlyTransport::GetReadDataBufPtr(TPtr8& aDes) // Set pointer to buffer into which data is to be read from drive (Read10)
1.898 + {
1.899 + aDes.Set(SetDataBufPtr());
1.900 + }
1.901 +
1.902 +
1.903 +void CBulkOnlyTransport::GetWriteDataBufPtr(TPtrC8& aDes) // Set pointer to buffer from which data is to be written to drive (Write10)
1.904 + {
1.905 + aDes.Set(iReadBufPtr);
1.906 + }
1.907 +
1.908 +#ifdef MSDC_MULTITHREADED
1.909 +void CBulkOnlyTransport::ProcessReadData(TAny* aAddress)
1.910 + {
1.911 + ExpireData(aAddress);
1.912 + }
1.913 +#endif
1.914 +
1.915 +
1.916 +
1.917 +
1.918 +
1.919 +
1.920 +
1.921 +