int DMAReadFromDev(int *size_in_bytes)  // data will be in mem_info[1]
{
  int err, temp;
  unsigned int data[3];
  struct timeval t0, t1;  

  // check if there's data to be read
  err = StatusRegWaitForBit(BITPOS_RX_READY);
  if (err) ERR_OUT("\nFailed StatusRegWaitForBit(BITPOS_RX_READY)\n");

  // check if DMA was pending
  err = Bar0Read(BAR0_DMA1_ADDR_LO, 1, &temp);
  if (err) ERR_OUT("Could not read from BAR0_DMA1_ADDR_LO to determine DMA in progress bit\n");
  if (temp & 1)
    ERR_OUT("DMA1 is still in progress\n");
  // clear BITPOS_RX_READY
  temp = 1<<BITPOS_DMA1_DONE;
  err = Bar0Write(BAR0_STATUS_REG, 1, &temp);
  if (err) ERR_OUT("Could not write BAR0_STATUS_REG to clear BITPOS_DMA1_DONE\n");

  // get length
  err = Bar0Read(BAR0_DMA1_LENSTAT, 1, size_in_bytes);
  if (err) ERR_OUT("Could not read BAR0_DMA1_LENSTAT\n");
  *size_in_bytes &= 0xFFFF;
  if (*size_in_bytes > TC_KMEM_LENGTH_BYTES)
    ERR_OUT("size_in_bytes > TC_KMEM_LENGTH_BYTES\n");

  if (sizeof (int) == 4) 
  {
    data[0] = 0;
    data[1] = (((unsigned int)mem_info[1]) & 0xFFFFFFFC) | 1;
  }
//  else  // 64 bit
//  {
//    data[0] = ((unsigned int)mem_info[1]) >> 32;
//    data[1] = (((unsigned int)mem_info[1]) & 0xFFFFFFFC) | 3;
//  }
  // set up DMA addr
  err = Bar0Write(BAR0_DMA1_ADDR_HI, 2, data);
  if (err) ERR_OUT("Could not write to BAR0_DMA0 registers\n");

  // wait for DMA1 done
  gettimeofday(&t0, NULL); 
  err = StatusRegWaitForBit(BITPOS_DMA1_DONE);
  gettimeofday(&t1, NULL); 
  if (err) ERR_OUT("\nFailed StatusRegWaitForBit(BITPOS_DMA1_DONE)\n");

  RecordTime(&dma1Time, t0, t1);  
  dma1Bytes += *size_in_bytes;
  
  return 0;
}
int DMAWriteToDev(int size_in_bytes)  // data must already be in mem_info[0]
{
  int err, size_in_words, temp, cnt;
  unsigned int data[3];
  struct timeval t0, t1;  
  gettimeofday(&t0, NULL); 
  
  if (size_in_bytes > TC_KMEM_LENGTH_BYTES)
    ERR_OUT("size_in_bytes > TC_KMEM_LENGTH_BYTES\n");

  // check if DMA was pending
  err = Bar0Read(BAR0_DMA0_ADDR_LO, 1, &temp);
  if (err) ERR_OUT("Could not read from BAR0_DMA0_ADDR_LO to determine DMA in progress bit\n");
  if (temp & 1)
    ERR_OUT("DMA0 is still in progress\n");

  data[0] = size_in_bytes;
  if (sizeof (int) == 4) 
  {
    data[1] = 0;
    data[2] = (((unsigned int)mem_info[0]) & 0xFFFFFFFC) | 1;
  }
//  else  // 64 bit
//  {
//    data[1] = ((unsigned int)mem_info[0]) >> 32;
//    data[2] = (((unsigned int)mem_info[0]) & 0xFFFFFFFC) | 3;
//  }
  // set up DMA addr/lenstat
  err = Bar0Write(BAR0_DMA0_LENSTAT, 3, data);
  if (err) ERR_OUT("Could not write to BAR0_DMA0 registers\n");
  
  // wait for DMA0done; in real use, this should be in ISR
  gettimeofday(&t0, NULL); 
  err = StatusRegWaitForBit(BITPOS_DMA0_DONE);
  gettimeofday(&t1, NULL); 
  if (err) ERR_OUT("Failed StatusRegWaitForBit(BITPOS_DMA0_DONE)\n");
  
  RecordTime(&dma0Time, t0, t1);  
  dma0Bytes += size_in_bytes;

  return 0;
}
void CUT_PBASE_T_USBDI_0498::TransferCompleteL(TInt aTransferId,TInt aCompletionCode)
	{
	OstTraceFunctionEntryExt( CUT_PBASE_T_USBDI_0498_TRANSFERCOMPLETEL_ENTRY, this );
	Cancel();
	
	TInt err(KErrNone);
	TBuf<256> msg;
	OstTraceExt3(TRACE_NORMAL, CUT_PBASE_T_USBDI_0498_TRANSFERCOMPLETEL, "Transfer completed (id=%d), aCompletionCode = %d, test step = %d",aTransferId, aCompletionCode, iCaseStep);


	switch(iCaseStep)
		{
		case ETransfer:
			if(aCompletionCode != KErrNone)
				{
				iIfc1OutTransfer[0]->Cancel();
				iIfc1OutTransfer[1]->Cancel();
				iIfc2OutTransfer[0]->Cancel();
				iIfc2OutTransfer[1]->Cancel();
				iIfc1InTransfer[0]->Cancel();
				iIfc1InTransfer[1]->Cancel();
				iIfc2InTransfer[0]->Cancel();
				iIfc2InTransfer[1]->Cancel();
				err = KErrCorrupt;
				msg.Format(_L("<Error %d> The transfer completed with an error."), aCompletionCode);
				break; //switch(iCaseStep)
				}
	
			switch(aTransferId)
				{
				case KIfc1BulkTransferOutId1:
				case KIfc1BulkTransferOutId2:
				case KIfc2BulkTransferOutId1:
				case KIfc2BulkTransferOutId2:
					iTransferComplete |= aTransferId;
					OstTraceExt2(TRACE_NORMAL, CUT_PBASE_T_USBDI_0498_TRANSFERCOMPLETEL_DUP01, "Transfer OUT %d completed (Transfer Completion Aggregation Mask 0x%x)", aTransferId, iTransferComplete);
					break; //switch(aTransferId)

				case KIfc1BulkTransferInId1:
				case KIfc1BulkTransferInId2:
				case KIfc2BulkTransferInId1:
				case KIfc2BulkTransferInId2:
					iTransferComplete |= aTransferId;
					OstTraceExt2(TRACE_NORMAL, CUT_PBASE_T_USBDI_0498_TRANSFERCOMPLETEL_DUP02, "Transfer OUT %d completed (Transfer Completion Aggregation Mask 0x%x)", aTransferId, iTransferComplete);
					break; //switch(aTransferId)

				default:
					iTransferComplete = 0; //reset
					err = KUnexpectedTransferID;
					msg.Format(_L("<Error %d> Unexpected transfer ID, GOT %d, (wanted one of:- %d, %d, %d, %d, %d, %d, %d, or%d)"),
							       err, aTransferId,
							       KIfc1BulkTransferInId1, 
							       KIfc1BulkTransferInId2, 
							       KIfc2BulkTransferInId1, 
							       KIfc2BulkTransferInId2, 
							       KIfc1BulkTransferOutId1, 
							       KIfc1BulkTransferOutId2, 
							       KIfc2BulkTransferOutId1, 
							       KIfc2BulkTransferOutId2
							       );
					break; //switch(aTransferId)
				}
			
			// Transfer Out Response
			if(err==KErrNone && iTimeElapsed[0] == 0 && (iTransferComplete & KIfc1BulkTransferOutIdMask) == KIfc1BulkTransferOutIdMask) 
				//Record time elapsed for Interface 1 if not yet recorded.
				{
				RecordTime(0);
				}
			if(err==KErrNone && iTimeElapsed[1] == 0 && (iTransferComplete & KIfc2BulkTransferOutIdMask) == KIfc2BulkTransferOutIdMask)
				//Record time elapsed for Interface 2 if not yet recorded.
				{
				RecordTime(1);
				}
			if(err==KErrNone && (iTransferComplete & KBulkTransferOutIdMask) == KBulkTransferOutIdMask)
				{
				OstTrace1(TRACE_NORMAL, CUT_PBASE_T_USBDI_0498_TRANSFERCOMPLETEL_DUP03, "All OUT Transfers Completed Successfully: Transfer Completion Aggregation Mask 0x%x", iTransferComplete);
				//Leave validation to the point at which all transfers have completed.
				}
	
			// Transfer In Response
			if(err==KErrNone && iTimeElapsed[2] == 0 && (iTransferComplete & KIfc1BulkTransferInIdMask) == KIfc1BulkTransferInIdMask)
				//Record time elapsed for Interface 1 if not yet recorded.
				{
				RecordTime(2);
				}
			if(err==KErrNone && iTimeElapsed[3] == 0 && (iTransferComplete & KIfc2BulkTransferInIdMask) == KIfc2BulkTransferInIdMask) 
				//Record time elapsed for Interface 2 if not yet recorded.
				{
				RecordTime(3);
				}
			if(err==KErrNone && (iTransferComplete & KBulkTransferInIdMask) == KBulkTransferInIdMask)
				{
				// ok, compare data rcvd now
				OstTrace1(TRACE_NORMAL, CUT_PBASE_T_USBDI_0498_TRANSFERCOMPLETEL_DUP04, "All IN Transfers Completed Successfully: Transfer Completion Aggregation Mask 0x%x", iTransferComplete);
	
				TPtrC8 data1(iIfc1InTransfer[0]->DataPolled());	
				TPtrC8 data2(iIfc1InTransfer[1]->DataPolled());		
				TPtrC8 data3(iIfc2InTransfer[0]->DataPolled());		
				TPtrC8 data4(iIfc2InTransfer[1]->DataPolled());		
				//Validate first transfer on Interface 1 for number of bytes originally written.
				if(ValidateData(data1, KLiteralFrench4(), KHostNumWriteBytes1) == EFalse)
					{
					OstTrace0(TRACE_NORMAL, CUT_PBASE_T_USBDI_0498_TRANSFERCOMPLETEL_DUP05, "Validation failure 1st transfer, Interface 1");
					err = KErrCompletion; //indicates data validation failure
					break; //switch(iCaseStep)
					}

				//Validate second transfer on Interface 1 for number of bytes originally written.
				if(ValidateData(data2, KLiteralFrench4(), KHostNumWriteBytes1, KHostNumWriteBytes2) == EFalse)
					{
					OstTrace0(TRACE_NORMAL, CUT_PBASE_T_USBDI_0498_TRANSFERCOMPLETEL_DUP06, "Validation failure 2nd transfer, Interface 1");
					err = KErrCompletion; //indicates data validation failure
					break; //switch(iCaseStep)
					}
				
				//Validate first transfer on Interface 2 for number of bytes originally written.
				if(ValidateData(data3, KLiteralEnglish2(), KHostNumWriteBytes1) == EFalse)
					{
					OstTrace0(TRACE_NORMAL, CUT_PBASE_T_USBDI_0498_TRANSFERCOMPLETEL_DUP07, "Validation failure 1st transfer, Interface 2");
					err = KErrCompletion; //indicates data validation failure
					break; //switch(iCaseStep)
					}
				
				//Validate second transfer on Interface 2 for number of bytes originally written.
				if(ValidateData(data4, KLiteralEnglish2(), KHostNumWriteBytes1, KHostNumWriteBytes2) == EFalse)
					{
					OstTrace0(TRACE_NORMAL, CUT_PBASE_T_USBDI_0498_TRANSFERCOMPLETEL_DUP08, "Validation failure 2nd transfer, Interface 2");
					err = KErrCompletion; //indicates data validation failure
					break; //switch(iCaseStep)
					}
				
				// Comparison is a match
				OstTrace0(TRACE_NORMAL, CUT_PBASE_T_USBDI_0498_TRANSFERCOMPLETEL_DUP09, "Comparison for IN transfer is a match");
				}
			break; //switch(iCaseStep)

		default:
			err = KUndefinedStep;
			msg.Format(_L("<Error %d> Undefined case step %d reached"),KUndefinedStep, iCaseStep);
			break; //switch(iCaseStep)
		}

	if(err == KErrNone && iTransferComplete == KBulkTransferIdMask)
	/*
	Transfers all complete - now ask device to validate first interface's transfer OUT
	*/
		{
		OstTrace0(TRACE_NORMAL, CUT_PBASE_T_USBDI_0498_TRANSFERCOMPLETEL_DUP10, "Checking all times against each other");
		err = CheckTimes(0, 1, KMaxTimeDiffPercentage);
		err = err?err:CheckTimes(0, 2, KMaxTimeDiffPercentage);
		err = err?err:CheckTimes(0, 3, KMaxTimeDiffPercentage);
		err = err?err:CheckTimes(1, 2, KMaxTimeDiffPercentage);
		err = err?err:CheckTimes(1, 3, KMaxTimeDiffPercentage);
		err = err?err:CheckTimes(2, 3, KMaxTimeDiffPercentage);
		ResetTimes(0);
		ResetTimes(1);
		ResetTimes(2);
		ResetTimes(3);
		
		if(err==KErrNone)
			{
			OstTrace0(TRACE_NORMAL, CUT_PBASE_T_USBDI_0498_TRANSFERCOMPLETEL_DUP11, "Asking client for 'Validate' data written on interface 1");
			iCaseStep = ERequestDeviceValidateIFC1;
			TEndpointStringValidationRequest request(1,1,KLiteralFrench4(),KDeviceNumReadBytes);
			iControlEp0->SendRequest(request,this);
			}
		}

	if(err == KErrCompletion)
		//indicates data validation failure
		{
		msg.Format(_L("<Error %d> Bulk transfer IN data received does not match Bulk Transfer OUT data"), err);
		}

	if(err == KErrTooBig)
		//indicates timing validation failure
		{
		msg.Format(_L("<Error %d> Timer comparison showed too great a difference in transfer times between the two interfaces"), err);
		}
	
	if(err!=KErrNone)
		{	
		OstTrace0(TRACE_NORMAL, CUT_PBASE_T_USBDI_0498_TRANSFERCOMPLETEL_DUP12, msg);
		iCaseStep = EFailed;
		TTestCaseFailed request(err,msg);
		return iControlEp0->SendRequest(request,this);
		}	
	OstTraceFunctionExit1( CUT_PBASE_T_USBDI_0498_TRANSFERCOMPLETEL_EXIT, this );
	}