usbclasses/usbphoneasmodem/classimplementation/mscfileserver/src/scsiprot.cpp
changeset 35 9d8b04ca6939
child 63 ef2686f7597e
equal deleted inserted replaced
34:7858bc6ead78 35:9d8b04ca6939
       
     1 // Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description: SCSI protocol
       
    14 // 
       
    15 // 
       
    16 
       
    17 #include "scsiprot.h"
       
    18 #include "debug.h"
       
    19 #include "mscfileserver.h"
       
    20 
       
    21 // Helper macros
       
    22 #define LBA(x) static_cast<TUint32>((x[3] << 24) | (x[4] << 16) | (x[5] << 8) | x[6])
       
    23 #define LEN(x) static_cast<TUint16>((x[8] << 8) | x[9])
       
    24 
       
    25 
       
    26 LOCAL_D const TUint KDefaultBlockSize = 0x800;  //default block size for MM
       
    27 
       
    28 LOCAL_D const TUint KUndefinedLun = 0xFFFF;
       
    29 
       
    30 LOCAL_D const TUint8 KAllPages = 0x3F;
       
    31 
       
    32 LOCAL_D const TUint8 KChangeableValues = 0x1;
       
    33 LOCAL_D const TUint8 KDefaultValues = 0x2;
       
    34 
       
    35 /**
       
    36 Default constructor for TSenseInfo
       
    37 */
       
    38 TSenseInfo::TSenseInfo()
       
    39 	: iSenseCode(ENoSense),
       
    40 	  iAdditional(EAscNull),
       
    41 	  iQualifier(EAscqNull)
       
    42 	{}
       
    43 
       
    44 
       
    45 /**
       
    46 Set sense with no additional info.
       
    47 
       
    48 @param aSenseCode sense key
       
    49 */
       
    50 void TSenseInfo::SetSense(TSenseCode aSenseCode)
       
    51 	{
       
    52 	iSenseCode	= static_cast<TUint8>(aSenseCode);
       
    53 	iAdditional = EAscNull;
       
    54 	iQualifier = EAscqNull;
       
    55 	}
       
    56 
       
    57 
       
    58 /**
       
    59 Set sense with additional info.
       
    60 
       
    61 @param aSenseCode sense key
       
    62 @param aAdditional additional sense code (ASC) 
       
    63 */
       
    64 void TSenseInfo::SetSense(TSenseCode aSenseCode, TAdditionalCode aAdditional)
       
    65 
       
    66 	{
       
    67 	iSenseCode = static_cast<TUint8>(aSenseCode);
       
    68     iAdditional = static_cast<TUint8>(aAdditional);
       
    69 	iQualifier = EAscqNull;
       
    70 	}
       
    71 
       
    72 
       
    73 /**
       
    74 Set sense with additional info and qualifier.
       
    75 
       
    76 @param aSenseCode sense key 
       
    77 @param aAdditional additional sense code (ASC) 
       
    78 @param aQualifier additional sense code qualifier (ASCQ)
       
    79 */
       
    80 void TSenseInfo::SetSense(TSenseCode aSenseCode,
       
    81 						  TAdditionalCode aAdditional,
       
    82 						  TAdditionalSenseCodeQualifier aQualifier)
       
    83 	{
       
    84 	iSenseCode = static_cast<TUint8>(aSenseCode);
       
    85     iAdditional = static_cast<TUint8>(aAdditional);
       
    86 	iQualifier = static_cast<TUint8>(aQualifier);
       
    87 	}
       
    88 
       
    89 
       
    90 //-----------------------------------------------
       
    91 
       
    92 /**
       
    93 Creates the CScsiProtocol object.  Called during controller initialisation.
       
    94 
       
    95 @param aFsImage reference to the file system image
       
    96 */
       
    97 CScsiProtocol* CScsiProtocol::NewL(CMscFileController& aController)
       
    98 	{
       
    99 	CScsiProtocol* self = new (ELeave) CScsiProtocol(aController);
       
   100 	CleanupStack::PushL(self);
       
   101 	self->ConstructL();
       
   102 	CleanupStack::Pop();
       
   103 	return self;
       
   104 	}
       
   105 
       
   106 /**
       
   107 c'tor
       
   108 
       
   109 @param aFsImage reference to the file system image
       
   110 */
       
   111 CScsiProtocol::CScsiProtocol(CMscFileController& aController):
       
   112 	iController(aController),
       
   113 	iLastCommand(EUndefinedCommand),
       
   114 	iLastLun(KUndefinedLun),
       
   115 	iMediaWriteSize(KDefaultMediaWriteSize)
       
   116 	{
       
   117 	}
       
   118 
       
   119 
       
   120 CScsiProtocol::~CScsiProtocol()
       
   121 	{
       
   122 	}
       
   123 
       
   124 
       
   125 void CScsiProtocol::ConstructL()
       
   126 	{
       
   127 	TRACE_FUNC
       
   128 	}
       
   129 
       
   130 
       
   131 /**
       
   132 Associates the transport with the protocol. Called during initialisation of the controller.
       
   133 
       
   134 @param aTransport pointer to the transport object
       
   135 */
       
   136 void CScsiProtocol::RegisterTransport(MTransportBase* aTransport)
       
   137 	{
       
   138 	TRACE_FUNC
       
   139 	iTransport = aTransport;
       
   140 	}
       
   141 
       
   142 
       
   143 /**
       
   144 Called by the Transport when it detects that the USB device is either running
       
   145 at High Speed or is at least capable of HS operation. The Protocol can use this
       
   146 information (for instance) to select the optimal write block size to use.
       
   147 
       
   148 This function is preferably called before actual MS data transfer operation
       
   149 starts, and usually only once.
       
   150 
       
   151 */
       
   152 void CScsiProtocol::ReportHighSpeedDevice()
       
   153 	{
       
   154 	TRACE_FUNC
       
   155 	iMediaWriteSize = KHsMediaWriteSize;
       
   156 	TRACE_INFO(( _L( "HS Device reported: SCSI will use %d bytes disk write size"), 
       
   157 	        iMediaWriteSize ))
       
   158 	}
       
   159 
       
   160 
       
   161 TInt CScsiProtocol::SetScsiParameters(TMassStorageConfig aConfig)
       
   162 	{
       
   163 	TRACE_FUNC
       
   164 	iConfig = aConfig;
       
   165 	return KErrNone;
       
   166 	}
       
   167 
       
   168 
       
   169 /**
       
   170 Called by the transport layer when a packet is available for decoding.
       
   171 If an error occurs, the sense code is updated and EFalse is returned.
       
   172 
       
   173 @param aData
       
   174 
       
   175 @return  ETrue if command was decoded and executed successfully
       
   176 */
       
   177 TBool CScsiProtocol::DecodePacket(TPtrC8& aData, TUint aLun)
       
   178 	{
       
   179 	TRACE_FUNC_ENTRY
       
   180 
       
   181 	TUint8 command = aData[1];
       
   182 
       
   183 	if (command != ERequestSense)
       
   184 		{
       
   185 		iSenseInfo.SetSense(TSenseInfo::ENoSense);
       
   186 		}
       
   187 
       
   188 	TRACE_INFO(( _L( "command = 0x%x lun=%d"), command, aLun ))
       
   189 	switch (command)
       
   190 		{
       
   191         case ETestUnitReady:
       
   192             HandleUnitReady(aLun);
       
   193             break;
       
   194 
       
   195         case ERequestSense:
       
   196             HandleRequestSense(aData);
       
   197             break;
       
   198             
       
   199         case EInquiry:
       
   200             HandleInquiry(aData, aLun);
       
   201             break;
       
   202                 
       
   203         case EModeSense:
       
   204             HandleModeSense(aData, aLun);
       
   205             break;
       
   206             
       
   207         case EModeSense10:
       
   208             HandleModeSense10(aData, aLun);
       
   209             break;
       
   210         
       
   211         case EStartStopUnit:
       
   212             HandleStartStopUnit( aData,aLun);
       
   213             break;
       
   214     
       
   215         case EPreventMediaRemoval:
       
   216             HandlePreventMediaRemoval(aData, aLun);
       
   217             break;
       
   218     
       
   219         case EReadCapacity:
       
   220             HandleReadCapacity(aData, aLun);
       
   221             break;
       
   222             
       
   223         case ERead10:
       
   224             HandleRead10(aData, aLun);
       
   225             break;
       
   226             
       
   227         case ERead12:
       
   228             HandleRead12(aData, aLun);
       
   229             break;
       
   230         
       
   231         case EReadTOC:
       
   232             HandleReadTOC(aData, aLun);
       
   233             break;
       
   234         
       
   235         case EGetConfiguration:
       
   236             HandleGetConfiguration(aData, aLun);
       
   237             break;
       
   238     
       
   239 		default:
       
   240 			iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidCmdCode);
       
   241 		}
       
   242 	TRACE_INFO(( _L( "result = %d" ), iSenseInfo.SenseOk() ))
       
   243 	TRACE_FUNC_EXIT
       
   244 	return ( iSenseInfo.SenseOk() );
       
   245 	}
       
   246 
       
   247 
       
   248 /**
       
   249 Checks if drive ready
       
   250 
       
   251 @param aLun Logic unit number 
       
   252 @return pointer to drive correspondent to LUN if drive mounted and ready, NULL otherwise
       
   253 */
       
   254 CFileSystemImage* CScsiProtocol::GetCheckFs(TUint aLun)
       
   255 	{
       
   256 	TRACE_FUNC
       
   257 	TInt err = KErrNone;
       
   258 	CFileSystemImage* image = iController.FsImage( aLun );
       
   259 	
       
   260 	if ( image == NULL )
       
   261 		{
       
   262 		TRACE_ERROR(( _L( "Illegal LUN %d" ), aLun ))
       
   263 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELuNotSupported);
       
   264 		return NULL;
       
   265 		}
       
   266 	
       
   267 	// Image exists, ensure it is opened for access
       
   268     err = image->Open();
       
   269     if ( err == KErrNone )
       
   270         {
       
   271         // Image is now open, if it wasn't already
       
   272         TRACE_INFO(( _L( "Image opened successfully" ) ))
       
   273         return image;
       
   274         }
       
   275     else
       
   276         {
       
   277         // Either file doesn't exist or was removed
       
   278         TRACE_ERROR(( _L( "Error %d opening image" ), err ))
       
   279         iSenseInfo.SetSense( TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent );
       
   280         }
       
   281     return NULL;
       
   282 	}
       
   283 
       
   284 
       
   285 /**
       
   286 Command Parser for the UNIT READY command (0x00)
       
   287 
       
   288 @param aLun Logic unit number 
       
   289 @return ETrue if successful, 
       
   290 */
       
   291 TBool CScsiProtocol::HandleUnitReady(TUint aLun)
       
   292 	{
       
   293 	TRACE_FUNC
       
   294 	return ( GetCheckFs(aLun) != NULL );
       
   295 	}
       
   296 
       
   297 
       
   298 /**
       
   299 Command Parser for the REQUEST SENSE command (0x03)
       
   300 
       
   301 @return ETrue if successful, 
       
   302 */
       
   303 TBool CScsiProtocol::HandleRequestSense(TPtrC8& aData)
       
   304 	{
       
   305 	TRACE_FUNC
       
   306 	TUint length = aData[5];
       
   307 	TRACE_INFO(( _L( "length = %d"), length ))
       
   308 	iCommandBuf.FillZ(KRequestSenseCommandLength);
       
   309 
       
   310 	TSenseInfo* senseInfo;
       
   311 	senseInfo = &iSenseInfo;
       
   312 	iCommandBuf[00] = 0x70; //(current errors)
       
   313 
       
   314 	iCommandBuf[02] = static_cast<TUint8>(senseInfo->iSenseCode & 0x0F);
       
   315 	
       
   316 	iCommandBuf[12] = senseInfo->iAdditional;
       
   317 	iCommandBuf[13] = senseInfo->iQualifier;
       
   318 	if (length<18 && length >=8) 
       
   319 		{
       
   320 		iCommandBuf.SetLength(length);  //length of response code data
       
   321 		iCommandBuf[07] = TUint8(length - 8);  //additional sence length
       
   322 		}
       
   323 	else if (length >= KRequestSenseCommandLength)
       
   324 		{
       
   325 		iCommandBuf[07] = KRequestSenseCommandLength - 8;	// we have max 18 byte to send
       
   326 		}
       
   327 
       
   328 	TRACE_INFO(( _L( "Response=0x%x Sense=0x%x, Additional=0x%x, Qualifier=0x%x\n"),
       
   329 				iCommandBuf[0], iCommandBuf[02], iCommandBuf[12], iCommandBuf[13] ))
       
   330  
       
   331 	TPtrC8 writeBuf = iCommandBuf.Left(length);
       
   332 	iTransport->SetupWriteData(writeBuf);
       
   333 
       
   334 	// clear the sense info
       
   335 	iSenseInfo.SetSense(TSenseInfo::ENoSense);
       
   336 	
       
   337 	return ETrue;
       
   338 	}
       
   339 
       
   340 
       
   341 /**
       
   342 Command Parser for the INQUIRY command (0x12)
       
   343 
       
   344 @param aLun Logic unit number 
       
   345 @return ETrue if successful, 
       
   346 */
       
   347 TBool CScsiProtocol::HandleInquiry(TPtrC8& aData, TUint /*aLun*/ )
       
   348 	{
       
   349 	TRACE_FUNC
       
   350 	
       
   351 	TBool cmdDt = aData[2] & 0x2;
       
   352 	TBool evpd  = aData[2] & 0x1;
       
   353 	TUint8 page = aData[3];
       
   354 	if (cmdDt || evpd || page /*|| aLun >= KUsbMsMaxDrives*/)
       
   355 		{
       
   356 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb); 
       
   357 		return EFalse;
       
   358 		}
       
   359 
       
   360 	iCommandBuf.FillZ(KInquiryCommandLength);
       
   361 
       
   362     iCommandBuf[0] = 0x05; // CD-ROM
       
   363     iCommandBuf[1] = 0x80; // MSB: RMB : Removable
       
   364     iCommandBuf[2] = 0x02; // Version SPC-3
       
   365     iCommandBuf[3] = 0x02; // AERC, TrmTsk, NormACA, Response Data Format
       
   366     iCommandBuf[4] = 0x1F; // Additional Length
       
   367 
       
   368 	TPtr8 vendorId(&iCommandBuf[8], 8, 8);		// Vendor ID (Vendor Specific/Logged by T10)
       
   369 	vendorId.Fill(' ', 8);
       
   370 	vendorId.Copy(iConfig.iVendorId);
       
   371 
       
   372 	TPtr8 productId(&iCommandBuf[16], 16, 16);	// Product ID (Vendor Specific)
       
   373 	productId.Fill(' ', 16);
       
   374 	productId.Copy(iConfig.iProductId);
       
   375 
       
   376 	TPtr8 productRev(&iCommandBuf[32], 4, 4);		// Product Revision Level (Vendor Specific)
       
   377 	productRev.Fill(' ', 4);
       
   378 	productRev.Copy(iConfig.iProductRev);
       
   379 
       
   380     TUint length = aData[5];
       
   381 	TPtrC8 writeBuf = iCommandBuf.Left(length);
       
   382 	iTransport->SetupWriteData(writeBuf);
       
   383 
       
   384 	iSenseInfo.SetSense(TSenseInfo::ENoSense); 
       
   385 	return ETrue;
       
   386 	}
       
   387 
       
   388 
       
   389 /**
       
   390  Command Parser for the START STOP UNIT command (0x1B)
       
   391  
       
   392  @param aData command data (started form position 1)
       
   393  @param aLun Logic unit number 
       
   394  @return ETrue if successful, TFalse otherwise
       
   395  */
       
   396 TBool CScsiProtocol::HandleStartStopUnit(TPtrC8& aData, TUint aLun)
       
   397 	{
       
   398 	TRACE_FUNC
       
   399     CFileSystemImage* image = GetCheckFs(aLun); 
       
   400     if ( image == NULL )
       
   401         {
       
   402         return EFalse;
       
   403         }
       
   404 
       
   405 	const TUint8 KStartMask = 0x01;
       
   406 	const TUint8 KImmedMask = 0x01;
       
   407 	const TUint8 KLoejMask = 0x02;
       
   408 
       
   409 	TBool immed = aData[2] & KImmedMask ? ETrue : EFalse;
       
   410 	TBool start = aData[5] & KStartMask ? ETrue : EFalse;
       
   411 	TBool loej = aData[5] & KLoejMask ? ETrue : EFalse;
       
   412 
       
   413 	TRACE_INFO(( _L( "Data %X %X" ), aData[2], aData[5] ))
       
   414 	TRACE_INFO(( _L( "IMMED = %d" ), immed ))
       
   415 	TRACE_INFO(( _L( "START = %d"), start ))
       
   416 	TRACE_INFO(( _L( "LOEJ  = %d" ), loej ))
       
   417 
       
   418 	TInt err = KErrNone;
       
   419 	if (loej)
       
   420 		{
       
   421 		if (start)	//Start unit
       
   422 			{
       
   423 			// GetCheckFs has already opened the image file
       
   424 			TRACE_INFO(( _L( "Load media" ) ))
       
   425 			}
       
   426 		else		//Stop unit 
       
   427 			{
       
   428 			err = image->Close();
       
   429 			TRACE_INFO(( _L( "Unload media" ) ))
       
   430 			}
       
   431 		}
       
   432 
       
   433 	if (err != KErrNone)  //actually we have error here only if the LUN is incorrect 
       
   434 		{
       
   435 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELuNotSupported);
       
   436 		return EFalse;
       
   437 		}
       
   438 
       
   439 	return ETrue;
       
   440 	}
       
   441 
       
   442 
       
   443 /**
       
   444 Command Parser for the PREVENT/ALLOW MEDIA REMOVAL command (0x1E)
       
   445 
       
   446 @param aData command data (started form position 1)
       
   447 @param aLun Logic unit number 
       
   448 @return ETrue if successful.
       
   449 */
       
   450 TBool CScsiProtocol::HandlePreventMediaRemoval(TPtrC8& aData, TUint aLun)
       
   451 	{
       
   452 	TRACE_FUNC
       
   453     if ( GetCheckFs(aLun) == NULL )
       
   454         {
       
   455         return EFalse;
       
   456         }
       
   457 
       
   458 	TInt prevent = aData[5] & 0x01;
       
   459 
       
   460 	// locking is not supported
       
   461 	if (prevent)
       
   462 		{
       
   463 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
       
   464 		}
       
   465 	return ETrue;
       
   466 	}
       
   467 
       
   468 /** Cancel active state, Invoked by transnport when it stops */
       
   469 TInt CScsiProtocol::Cancel()
       
   470 	{
       
   471 	TRACE_FUNC
       
   472 	return KErrNone;
       
   473 	}
       
   474 
       
   475 /**
       
   476 Command Parser for the READ CAPACITY(10) command (0x25)
       
   477 
       
   478 @param aData command data (started form position 1)
       
   479 @param aLun Logic unit number 
       
   480 @return ETrue if successful.
       
   481 */
       
   482 TBool CScsiProtocol::HandleReadCapacity(TPtrC8& aData, TUint aLun)
       
   483 	{
       
   484 	TRACE_FUNC
       
   485 	CFileSystemImage* image = GetCheckFs(aLun); 
       
   486     if ( image == NULL )
       
   487         {
       
   488         return EFalse;
       
   489         }
       
   490 
       
   491 	TInt pmi = aData[9] & 0x01;
       
   492 	TInt lba = aData[3] | aData[4] | aData[5] | aData[6];
       
   493 
       
   494 	if (pmi || lba)   //do not support partial medium indicator
       
   495 		{
       
   496 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
       
   497 		return EFalse;
       
   498 		} 
       
   499 
       
   500 	TInt64 driveBlocks = image->Size() / MAKE_TINT64(0, KDefaultBlockSize) - 1;
       
   501 	iCommandBuf.FillZ(KReadCapacityCommandLength);
       
   502 	if (I64HIGH(driveBlocks) == 0)
       
   503 		{
       
   504 		TUint32 numBlocks = I64LOW(driveBlocks);
       
   505 
       
   506 		TRACE_INFO(( _L( "Block size=%d, NumBlocks=%d" ), 
       
   507 		        KDefaultBlockSize, numBlocks ))
       
   508 		iCommandBuf[0] = static_cast<TUint8>((numBlocks & 0xFF000000) >> 24);	// Number of blocks
       
   509 		iCommandBuf[1] = static_cast<TUint8>((numBlocks & 0x00FF0000) >> 16);
       
   510 		iCommandBuf[2] = static_cast<TUint8>((numBlocks & 0x0000FF00) >> 8);
       
   511 		iCommandBuf[3] = static_cast<TUint8>((numBlocks & 0x000000FF));
       
   512 		}
       
   513 	else   
       
   514 		{
       
   515 		iCommandBuf[0] = iCommandBuf[1] = iCommandBuf[2] = iCommandBuf[3] = 0xFF;  // indicate that size more then )0xFFFFFFFF
       
   516 		}
       
   517 
       
   518 	iCommandBuf[4] = static_cast<TUint8>((KDefaultBlockSize & 0xFF000000) >> 24);	// Block Size
       
   519 	iCommandBuf[5] = static_cast<TUint8>((KDefaultBlockSize & 0x00FF0000) >> 16);
       
   520 	iCommandBuf[6] = static_cast<TUint8>((KDefaultBlockSize & 0x0000FF00) >> 8);
       
   521 	iCommandBuf[7] = static_cast<TUint8>((KDefaultBlockSize & 0x000000FF));
       
   522 
       
   523 	TPtrC8 writeBuf = iCommandBuf;
       
   524 	iTransport->SetupWriteData(writeBuf);
       
   525 
       
   526 	return ETrue;
       
   527 	}
       
   528 
       
   529 
       
   530 /**
       
   531 Command Parser for the READ10 command (0x28)
       
   532 
       
   533 @param aData command data (started form position 1)
       
   534 @param aLun Logic unit number
       
   535 @return ETrue if successful.
       
   536 */
       
   537 TBool CScsiProtocol::HandleRead10(TPtrC8& aData, TUint aLun)
       
   538 	{
       
   539 	TRACE_FUNC
       
   540     CFileSystemImage* image = GetCheckFs(aLun); 
       
   541     if ( image == NULL )
       
   542         {
       
   543         return EFalse;
       
   544         }
       
   545     
       
   546 	TInt rdProtect = aData[2] >> 5;
       
   547 	if (rdProtect)
       
   548 		{
       
   549 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
       
   550 		return EFalse;
       
   551 		}
       
   552 
       
   553 	const TUint32 lba = LBA(aData);
       
   554 	const TUint16 len = LEN(aData);
       
   555 
       
   556 	TRACE_INFO(( _L( "READ(10) : LBA = %d, Length = %d (blocks)" ), lba, len))
       
   557 
       
   558 	if (!len)
       
   559 		{
       
   560 		return ETrue; // do nothing - this is not an error
       
   561 		}
       
   562 
       
   563 	const TInt64 bOffset = MAKE_TINT64(0, lba) * KDefaultBlockSize;
       
   564 	const TInt bLength = len * KDefaultBlockSize;
       
   565 	const TInt64 theEnd = bOffset + MAKE_TINT64(0, bLength);
       
   566 
       
   567     if (theEnd > image->Size())  //check if media big enough for this request
       
   568 		{
       
   569 		TRACE_ERROR(( _L( "err - Request ends out of media" ) ))
       
   570 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELbaOutOfRange);
       
   571 		return EFalse;
       
   572 		}
       
   573 
       
   574 	// check if our buffer can hold requested data
       
   575 	if (iCommandBuf.MaxLength() < bLength)
       
   576 		{
       
   577 		TRACE_ERROR(( _L( "err - Buffer too small" ) ))
       
   578 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
       
   579 		return EFalse;
       
   580 		}
       
   581 
       
   582 	TInt err = image->Read(bOffset, bLength, iCommandBuf);
       
   583 	if (err != KErrNone)
       
   584 		{
       
   585 		TRACE_ERROR(( _L( "Read failed, err=%d" ), err ))
       
   586 		iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
       
   587 		return EFalse;
       
   588 		}
       
   589 
       
   590 	TPtrC8 writeBuf = iCommandBuf;
       
   591 
       
   592 	// Set up data write to the host
       
   593 	iTransport->SetupWriteData(writeBuf);
       
   594 
       
   595 	return ETrue;
       
   596 	}
       
   597 
       
   598 
       
   599 /**
       
   600 Command Parser for the READ12 command (0xA8)
       
   601 
       
   602 @param aData command data (started form position 1)
       
   603 @param aLun Logic unit number
       
   604 @return ETrue if successful.
       
   605 */
       
   606 TBool CScsiProtocol::HandleRead12(TPtrC8& aData, TUint aLun)
       
   607     {
       
   608     TRACE_FUNC
       
   609     CFileSystemImage* image = GetCheckFs(aLun); 
       
   610     if ( image == NULL )
       
   611         {
       
   612         return EFalse;
       
   613         }
       
   614     TInt rdProtect = aData[2] >> 5;
       
   615     if (rdProtect)
       
   616         {
       
   617         iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
       
   618         return EFalse;
       
   619         }
       
   620 
       
   621     const TUint32 lba = static_cast<TUint32>((aData[3] << 24) | (aData[4] << 16) | (aData[5] << 8) | aData[6]);
       
   622     const TUint32 len = static_cast<TUint32>((aData[7] << 24) | (aData[8] << 16) | (aData[9] << 8) | aData[10]);
       
   623 
       
   624     TRACE_INFO(( _L( "READ(12) : LBA = %d, Length = %d  (blocks)" ), lba, len ))
       
   625 
       
   626     if (!len)
       
   627         {
       
   628         return ETrue; // do nothing - this is not an error
       
   629         }
       
   630 
       
   631     const TInt64 bOffset = MAKE_TINT64(0, lba) * KDefaultBlockSize;
       
   632     const TUint32 bLength = len * KDefaultBlockSize;
       
   633     const TInt64 theEnd = bOffset + MAKE_TINT64(0, bLength);
       
   634 
       
   635     if (theEnd > image->Size())  //check if media big enough for this request
       
   636         {
       
   637         TRACE_ERROR(( _L( "err - Request ends out of media" ) ))
       
   638         iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::ELbaOutOfRange);
       
   639         return EFalse;
       
   640         }
       
   641 
       
   642     // check if our buffer can hold requested data
       
   643     if (iCommandBuf.MaxLength() < bLength)
       
   644         {
       
   645         TRACE_ERROR(( _L( "err - Buffer too small" ) ))
       
   646         iSenseInfo.SetSense(TSenseInfo::EIllegalRequest, TSenseInfo::EInvalidFieldInCdb);
       
   647         return EFalse;
       
   648         }
       
   649 
       
   650     TInt err = image->Read(bOffset, bLength, iCommandBuf);
       
   651     if (err != KErrNone)
       
   652         {
       
   653         TRACE_ERROR(( _L( "Read failed, err=%d" ), err ))
       
   654         iSenseInfo.SetSense(TSenseInfo::ENotReady, TSenseInfo::EMediaNotPresent);
       
   655         return EFalse;
       
   656         }
       
   657 
       
   658     TPtrC8 writeBuf = iCommandBuf;
       
   659 
       
   660     // Set up data write to the host
       
   661     iTransport->SetupWriteData(writeBuf);
       
   662 
       
   663     return ETrue;
       
   664     }
       
   665 
       
   666 /**
       
   667 Called by the transport when the requested data has been read or an error has
       
   668 occurred during the read.
       
   669 
       
   670 @param aError Indicate if an error occurs during reading data by transport.
       
   671 @return KErrAbort if command processing is complete but has failed,
       
   672         KErrCompletion if sufficient data is available in the buffer to process
       
   673         the transfer immediately, KErrNotReady if insufficient data is
       
   674         available in the buffer so the transport should wait for it to arrive,
       
   675         KErrNone if command processing is complete and was successful.
       
   676 */
       
   677 TInt CScsiProtocol::ReadComplete(TInt aError)
       
   678 	{
       
   679 	TRACE_FUNC
       
   680 	TRACE_INFO(( _L( "Error = 0x%X" ), aError ))
       
   681 //	const TInt64 bOffset = iOffset;
       
   682 	TUint8 lastCommand = iLastCommand;
       
   683 	TUint lastLun = iLastLun;
       
   684 
       
   685 	iOffset = 0;
       
   686 	iLastCommand = EUndefinedCommand;
       
   687 	iLastLun = KUndefinedLun;
       
   688 
       
   689 	TRACE_INFO(( _L( "Last command was: %s" ),
       
   690 			 (lastCommand == EUndefinedCommand) ? _S("Undefined") :
       
   691 			 ((lastCommand == EWrite10) ? _S("EWrite10") :
       
   692 			  ((lastCommand == EVerify10) ? _S("EVerify10") :
       
   693 			   _S("Unknown"))) ))
       
   694 
       
   695 	if (aError != KErrNone ||
       
   696 		lastCommand == EUndefinedCommand ||
       
   697 		lastLun == KUndefinedLun)
       
   698 		{
       
   699 		iSenseInfo.SetSense(TSenseInfo::EAbortedCommand);
       
   700 		return KErrAbort;
       
   701 		}
       
   702 
       
   703     CFileSystemImage* image = GetCheckFs(lastLun); 
       
   704     if ( image == NULL )
       
   705         {
       
   706         return KErrAbort;
       
   707         }
       
   708     else
       
   709         {
       
   710         iSenseInfo.SetSense(TSenseInfo::EAbortedCommand);
       
   711         }
       
   712 	return iSenseInfo.SenseOk() ? KErrNone : KErrAbort;
       
   713 	}
       
   714 
       
   715 
       
   716 /**
       
   717 Command Parser for the MODE SENSE(06) command (0x1A)
       
   718 
       
   719 @return ETrue if successful.
       
   720 */
       
   721 TBool CScsiProtocol::HandleModeSense(TPtrC8& aData, TUint /*aLun*/)
       
   722 	{
       
   723 	TRACE_FUNC
       
   724 
       
   725 	TInt pageCode = aData[3] & 0x3F;
       
   726 	TUint8 pageControl= static_cast<TUint8>(aData[3] >>6);
       
   727 
       
   728 	// reserve 4 bytes for Length, Media type, Device-specific parameter and Block descriptor length
       
   729 	iCommandBuf.FillZ(KModeSenseCommandLength);
       
   730 
       
   731 	if (pageCode != KAllPages || pageControl == KChangeableValues) 
       
   732 		{
       
   733 		TRACE_ERROR(( _L( "TSenseInfo::EIllegalRequest,TSenseInfo::EInvalidFieldInCdb")))
       
   734 		iSenseInfo.SetSense(TSenseInfo::EIllegalRequest,TSenseInfo::EInvalidFieldInCdb);
       
   735 		return EFalse;
       
   736 		}
       
   737 	if (pageControl != KDefaultValues)
       
   738 		{
       
   739 	    iCommandBuf[2] = 1<<7;  // set SWP bit at the Device Specific parameters
       
   740 		}
       
   741 
       
   742 	iCommandBuf[0]=3;  //Sending only Mode parameter header
       
   743 
       
   744 	TPtrC8 writeBuf = iCommandBuf;
       
   745 	iTransport->SetupWriteData(writeBuf);
       
   746 
       
   747 	return (iSenseInfo.SenseOk());
       
   748 	}
       
   749 
       
   750 
       
   751 const TUint16 KMaxModeRespLen = 58;
       
   752 /**
       
   753 Command Parser for the MODE SENSE(10) command (0x5A)
       
   754 
       
   755 @return ETrue if successful.
       
   756 */  
       
   757 TBool CScsiProtocol::HandleModeSense10(TPtrC8& aData, TUint /*aLun*/)
       
   758     {
       
   759     TRACE_FUNC
       
   760     
       
   761     TInt pageCode   = aData[3] & 0x3F;
       
   762     TUint8 pageControl= static_cast<TUint8>(aData[3] >>6);
       
   763     
       
   764     iCommandBuf.FillZ(KMaxModeRespLen);
       
   765     
       
   766     TBool allPages = EFalse;
       
   767     TUint16 len = static_cast<TUint16>((aData[8] << 8) | aData[9]);
       
   768     __ASSERT_DEBUG(len > 1, User::Panic(KUsbMsSvrPncCat, EMsWrongLength));
       
   769 
       
   770     iCommandBuf[2] = 0x71; // medium type
       
   771     
       
   772     TInt i = 8;
       
   773     
       
   774     switch (pageCode)
       
   775         {
       
   776         case 0x3F: // All mode pages
       
   777             allPages = ETrue;
       
   778         case 0x1A: // Power condition mode page
       
   779             // byte 0
       
   780             iCommandBuf[i++] = 0x1A; // page code
       
   781             iCommandBuf[i++] = 0x0A; // length
       
   782             iCommandBuf[i++] = 0x00; // reserved
       
   783             iCommandBuf[i++] = 0x00; // IDLE = 0, STANDBY = 0
       
   784             iCommandBuf[i++] = 0x00; 
       
   785             iCommandBuf[i++] = 0x00; 
       
   786             iCommandBuf[i++] = 0x00; 
       
   787             iCommandBuf[i++] = 0x00; // idle timer
       
   788             // byte 8
       
   789             iCommandBuf[i++] = 0x00; 
       
   790             iCommandBuf[i++] = 0x00;
       
   791             iCommandBuf[i++] = 0x00; 
       
   792             iCommandBuf[i++] = 0x00; // standby timer
       
   793             
       
   794             if (!allPages)
       
   795                 {
       
   796                 break;
       
   797                 }
       
   798         case 0x1D: // Timeout and protect mode page
       
   799             // byte 0
       
   800             iCommandBuf[i++] = 0x1D; // page code
       
   801             iCommandBuf[i++] = 0x08; // length
       
   802             iCommandBuf[i++] = 0x00; // reserved
       
   803             iCommandBuf[i++] = 0x00; // reserver
       
   804             iCommandBuf[i++] = 0x00; // G3, TMOE, DISP, SWPP = 0, 0, 0, 0
       
   805             iCommandBuf[i++] = 0x00; // reserved
       
   806             iCommandBuf[i++] = 0x00; 
       
   807             iCommandBuf[i++] = 0x00; // group 1 timeout
       
   808             // byte 8
       
   809             iCommandBuf[i++] = 0x00; 
       
   810             iCommandBuf[i++] = 0x00; // group 2 timeout
       
   811             
       
   812             if (!allPages)
       
   813                 {
       
   814                 break;
       
   815                 }
       
   816         case 0x2A: // MM capabilities and mechanical status page
       
   817             // byte 0
       
   818             iCommandBuf[i++] = 0x2A; // page code
       
   819             iCommandBuf[i++] = 0x1A; // length
       
   820             iCommandBuf[i++] = 0x00; // !CD-R
       
   821             iCommandBuf[i++] = 0x00;
       
   822             iCommandBuf[i++] = 0x30; // mode (mode 2, form 1,2)
       
   823             iCommandBuf[i++] = 0x00;
       
   824             iCommandBuf[i++] = 0x29; // tray, eject, lock
       
   825             iCommandBuf[i++] = 0x00;
       
   826             // byte 8
       
   827             iCommandBuf[i++] = 0x00; //
       
   828             iCommandBuf[i++] = 0x00; // obsolete
       
   829             iCommandBuf[i++] = 0x00; //
       
   830             iCommandBuf[i++] = 0x00; // volume levels
       
   831             iCommandBuf[i++] = 0x00; //
       
   832             iCommandBuf[i++] = 0x00; // buffer size
       
   833             iCommandBuf[i++] = 0x00; //
       
   834             iCommandBuf[i++] = 0x00; // obsolete
       
   835             // byte 16
       
   836             iCommandBuf[i++] = 0x00; // reserved
       
   837             iCommandBuf[i++] = 0x00; // unspecified
       
   838             iCommandBuf[i++] = 0x00; // obsolete
       
   839             iCommandBuf[i++] = 0x00; // obsolete
       
   840             iCommandBuf[i++] = 0x00; // obsolete
       
   841             iCommandBuf[i++] = 0x00; // obsolete
       
   842             iCommandBuf[i++] = 0x00; //
       
   843             iCommandBuf[i++] = 0x00; // copy management revision
       
   844             // byte 24
       
   845             iCommandBuf[i++] = 0x00; // reserved
       
   846             iCommandBuf[i++] = 0x00; // reserved
       
   847             iCommandBuf[i++] = 0x00; // reserved
       
   848             iCommandBuf[i++] = 0x00; // reserved
       
   849             
       
   850             break;
       
   851         default:
       
   852             // Unknown page code
       
   853             iSenseInfo.SetSense(TSenseInfo::EIllegalRequest,TSenseInfo::EInvalidFieldInCdb);
       
   854             return EFalse;
       
   855         }
       
   856    
       
   857     if (i > len)
       
   858         {
       
   859         // don't send more data than the host will accept
       
   860         i = len;
       
   861         }
       
   862     iCommandBuf.SetLength(i);
       
   863     iCommandBuf[1] = (TUint8)(i-2); // length will not exceed 255, so LSB is enough
       
   864     
       
   865     TPtrC8 writeBuf = iCommandBuf;
       
   866     iTransport->SetupWriteData(writeBuf);
       
   867 
       
   868     return (iSenseInfo.SenseOk());
       
   869     }
       
   870 
       
   871 /**
       
   872 Command Parser for the READ TOC/PMA/ATIP command (0x43)
       
   873 
       
   874 @return ETrue if successful.
       
   875 */  
       
   876 TBool CScsiProtocol::HandleReadTOC(TPtrC8& aData, TUint aLun)
       
   877     {
       
   878     TRACE_FUNC
       
   879     if ( GetCheckFs(aLun) == NULL )
       
   880         {
       
   881         return EFalse;
       
   882         }    
       
   883     
       
   884     TUint16 len = static_cast<TUint16>((aData[8] << 8) | aData[9]);
       
   885     
       
   886     if (len == 0)
       
   887         {
       
   888         return ETrue; // allocation length = 0 is not an error
       
   889         }
       
   890     else if (len > 20)
       
   891         {
       
   892         len = 20;
       
   893         }
       
   894     
       
   895     iCommandBuf.FillZ(len);  
       
   896     
       
   897     // TOC header
       
   898     iCommandBuf[0] = 0x00; // length MSB
       
   899     iCommandBuf[1] = len-2; // length LSB
       
   900     iCommandBuf[2] = 0x01; // first track
       
   901     iCommandBuf[3] = 0x01; // last track
       
   902     if (len >= 12)
       
   903         {
       
   904         // Track descriptor, track 1
       
   905         iCommandBuf[5] = 0x14; // ADR | CTRL
       
   906         iCommandBuf[6] = 0x01; // track
       
   907         // Track start address
       
   908         if (aData[2] & 0x02)
       
   909             {
       
   910             // TIME address = 0x00 00 02 00
       
   911             iCommandBuf[10] = 0x02;
       
   912             }
       
   913         }
       
   914     if (len >= 20)
       
   915         {
       
   916         // Track descriptor, lead-out
       
   917         iCommandBuf[13] = 0x14;
       
   918         iCommandBuf[14] = 0xaa;
       
   919         }
       
   920     
       
   921     TPtrC8 writeBuf = iCommandBuf;
       
   922     iTransport->SetupWriteData(writeBuf);
       
   923 
       
   924     return (iSenseInfo.SenseOk());
       
   925     }
       
   926 
       
   927 const TUint16 KFeatureNums[] = { 0x0000, 0x0001, 0x0002, 0x0003,
       
   928                                  0x0010, 0x001E, 0x0100, 0x0105 };
       
   929 const TInt KNumFeatures = sizeof(KFeatureNums) / sizeof(TUint16);
       
   930 const TInt KMaxConfRespLen = 76;
       
   931 
       
   932 /**
       
   933 Command Parser for the GET CONFIGURATION command (0x46)
       
   934 
       
   935 @return ETrue if successful.
       
   936 */  
       
   937 TBool CScsiProtocol::HandleGetConfiguration(TPtrC8& aData, TUint aLun)
       
   938     {
       
   939     TRACE_FUNC
       
   940     if ( GetCheckFs(aLun) == NULL )
       
   941         {
       
   942         return EFalse;
       
   943         }    
       
   944     TUint blockSize = KDefaultBlockSize;
       
   945 
       
   946     TUint8 rt = aData[2] & 0x03;
       
   947     TUint16 feature = static_cast<TUint16>((aData[3] << 8) | aData[4]);
       
   948     TUint16 len =     static_cast<TUint16>((aData[8] << 8) | aData[9]);
       
   949     
       
   950     if (len == 0)
       
   951         {
       
   952         return ETrue; // allocation length = 0 is not an error
       
   953         }
       
   954     
       
   955     iCommandBuf.FillZ(KMaxConfRespLen);  
       
   956     
       
   957     // Feature header
       
   958     iCommandBuf[0] = 0x00;  // length 
       
   959     iCommandBuf[1] = 0x00;  // length 
       
   960     iCommandBuf[2] = 0x00;  // length 
       
   961     iCommandBuf[6] = 0x00;
       
   962     iCommandBuf[7] = 0x08;  // CD-ROM Profile 0x0008
       
   963     
       
   964     TInt i = 8;
       
   965     
       
   966     for (TInt f = 0; f < KNumFeatures; f++)
       
   967         {
       
   968         if ( ( ( rt == 2 ) && ( KFeatureNums[f] == feature ) ) ||
       
   969              ( ( rt != 2 ) && ( KFeatureNums[f] >= feature ) ) )
       
   970             {
       
   971             switch (KFeatureNums[f])
       
   972                 {
       
   973                 case 0x0000:
       
   974                     // Profile list 
       
   975                     iCommandBuf[i++] = 0x00;
       
   976                     iCommandBuf[i++] = 0x00; // feature code = 0x0000
       
   977                     iCommandBuf[i++] = 0x03; // persistent = 1, current = 1
       
   978                     iCommandBuf[i++] = 0x04; // additional length (1 profile desc.)
       
   979                     // Profile descriptor
       
   980                     iCommandBuf[i++] = 0x00;
       
   981                     iCommandBuf[i++] = 0x08; // profile 0x0008
       
   982                     iCommandBuf[i++] = 0x01; // current
       
   983                     iCommandBuf[i++] = 0x00; // reserved
       
   984                     break;
       
   985                 case 0x0001:
       
   986                     // Core feature descriptor
       
   987                     iCommandBuf[i++] = 0x00;
       
   988                     iCommandBuf[i++] = 0x01; // feature code = 0x0001
       
   989                     iCommandBuf[i++] = 0x07; // version = 0001b, persistent = 1, current = 1
       
   990                     iCommandBuf[i++] = 0x08; // additional length
       
   991                     iCommandBuf[i++] = 0x00;
       
   992                     iCommandBuf[i++] = 0x00;
       
   993                     iCommandBuf[i++] = 0x00;
       
   994                     iCommandBuf[i++] = 0x08; // physical interface = 0x00000008 (USB)
       
   995                     iCommandBuf[i++] = 0x01; // DBE = 1
       
   996                     iCommandBuf[i++] = 0x00; // reserved
       
   997                     iCommandBuf[i++] = 0x00; // reserved
       
   998                     iCommandBuf[i++] = 0x00; // reserved
       
   999                     break;
       
  1000                 case 0x0002:
       
  1001                     // Morphing feature descriptor
       
  1002                     iCommandBuf[i++] = 0x00;
       
  1003                     iCommandBuf[i++] = 0x02; // feature code = 0x0002
       
  1004                     iCommandBuf[i++] = 0x07; // version = 0001b, persistent = 1, current = 1
       
  1005                     iCommandBuf[i++] = 0x04; // additional length
       
  1006                     iCommandBuf[i++] = 0x02; // OCEvent = 1, ASYNC = 0
       
  1007                     iCommandBuf[i++] = 0x00; // reserved
       
  1008                     iCommandBuf[i++] = 0x00; // reserved
       
  1009                     iCommandBuf[i++] = 0x00; // reserved
       
  1010                     break;
       
  1011                 case 0x0003:
       
  1012                     // Removable medium feature descriptor
       
  1013                     iCommandBuf[i++] = 0x00;
       
  1014                     iCommandBuf[i++] = 0x03; // feature code = 0x0003
       
  1015                     iCommandBuf[i++] = 0x03; // persistent = 1, current = 1
       
  1016                     iCommandBuf[i++] = 0x04; // additional length
       
  1017                     iCommandBuf[i++] = 0x29; // tray, eject, lock
       
  1018                     iCommandBuf[i++] = 0x00; // reserved
       
  1019                     iCommandBuf[i++] = 0x00; // reserved
       
  1020                     iCommandBuf[i++] = 0x00; // reserved
       
  1021                     break;
       
  1022                 case 0x0010:
       
  1023                     // Random readable feature descriptor
       
  1024                     iCommandBuf[i++] = 0x00;
       
  1025                     iCommandBuf[i++] = 0x10; // feature code = 0x0010
       
  1026                     iCommandBuf[i++] = 0x03; // persistent = 1, current = 1
       
  1027                     iCommandBuf[i++] = 0x08; // additional length
       
  1028                     // Block Size
       
  1029                     iCommandBuf[i++] = static_cast<TUint8>((blockSize & 0xFF000000) >> 24);
       
  1030                     iCommandBuf[i++] = static_cast<TUint8>((blockSize & 0x00FF0000) >> 16);  
       
  1031                     iCommandBuf[i++] = static_cast<TUint8>((blockSize & 0x0000FF00) >> 8);   
       
  1032                     iCommandBuf[i++] = static_cast<TUint8>((blockSize & 0x000000FF));        
       
  1033                     iCommandBuf[i++] = 0x00;
       
  1034                     iCommandBuf[i++] = 0x01; // blocking = 1
       
  1035                     iCommandBuf[i++] = 0x00; // PP = 0
       
  1036                     iCommandBuf[i++] = 0x00; // reserved
       
  1037                     break;
       
  1038                 case 0x001E:
       
  1039                     // CD Read feature descriptor
       
  1040                     iCommandBuf[i++] = 0x00;
       
  1041                     iCommandBuf[i++] = 0x1E; // feature code = 0x001E
       
  1042                     iCommandBuf[i++] = 0x0B; // version = 2, persistent = 1, current = 1
       
  1043                     iCommandBuf[i++] = 0x04; // additional length
       
  1044                     iCommandBuf[i++] = 0x00; // DAP = 0, C2 flags = 0, CD-Text = 0
       
  1045                     iCommandBuf[i++] = 0x00; // reserved
       
  1046                     iCommandBuf[i++] = 0x00; // reserved
       
  1047                     iCommandBuf[i++] = 0x00; // reserved
       
  1048                     break;
       
  1049                 case 0x0100:
       
  1050                     // Power management feature descriptor
       
  1051                     iCommandBuf[i++] = 0x01;
       
  1052                     iCommandBuf[i++] = 0x00; // feature code = 0x0100
       
  1053                     iCommandBuf[i++] = 0x03; // persistent = 1, current = 1
       
  1054                     iCommandBuf[i++] = 0x00; // additional length = 0
       
  1055                     break;    
       
  1056                 case 0x0105:
       
  1057                     // Timeout feature descriptor
       
  1058                     iCommandBuf[i++] = 0x01;
       
  1059                     iCommandBuf[i++] = 0x05; // feature code = 0x0105
       
  1060                     iCommandBuf[i++] = 0x07; // version = 1, persistent = 1, current = 1
       
  1061                     iCommandBuf[i++] = 0x04; // additional length
       
  1062                     iCommandBuf[i++] = 0x00; // G3 = 0
       
  1063                     iCommandBuf[i++] = 0x00; // reserved
       
  1064                     iCommandBuf[i++] = 0x00;
       
  1065                     iCommandBuf[i++] = 0x00; // unit lenght = undefined
       
  1066                     break;
       
  1067                 default:
       
  1068                     break;
       
  1069                 }                
       
  1070             }
       
  1071         }
       
  1072     iCommandBuf[3] = (TUint8)(i-4); // length LSB
       
  1073     if (i > len)
       
  1074         {
       
  1075         // don't send more data than the host will accept
       
  1076         i = len;
       
  1077         }
       
  1078     
       
  1079     TPtrC8 writeBuf = iCommandBuf.Left(i);
       
  1080     iTransport->SetupWriteData(writeBuf);
       
  1081 
       
  1082     return (iSenseInfo.SenseOk());
       
  1083     }
       
  1084