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