os/kernelhwsrv/kernel/eka/drivers/usbcsc/usbcsc_bil.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of the License "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
// e32\drivers\usbcsc\usbcsc_bil.cpp
sl@0
    15
// 
sl@0
    16
//
sl@0
    17
sl@0
    18
#include <e32std.h>
sl@0
    19
#include <e32std_private.h>
sl@0
    20
#include <d32usbcsc.h>
sl@0
    21
#include <e32debug.h>
sl@0
    22
sl@0
    23
/** @file usbcsc_bil.cpp
sl@0
    24
sl@0
    25
	Buffer Interface Layer for USB Client Device driver stack, using shared chunks.
sl@0
    26
sl@0
    27
	@internalTechnology
sl@0
    28
*/
sl@0
    29
sl@0
    30
EXPORT_C TInt RDevUsbcScClient::FinalizeInterface()
sl@0
    31
	{
sl@0
    32
	TInt errorOrhandle = DoControl(EControlRealizeInterface); //returns a error value or chunk handle
sl@0
    33
	TInt r = iSharedChunk.SetReturnedHandle(errorOrhandle);
sl@0
    34
	iEndpointStatus = 0x00; //all endpoints are closed at the moment
sl@0
    35
	iAlternateSetting = 0;
sl@0
    36
	iNewAltSetting = 0;
sl@0
    37
	iAltSettingSeq = 0;
sl@0
    38
	return r;
sl@0
    39
	}
sl@0
    40
sl@0
    41
sl@0
    42
EXPORT_C TInt RDevUsbcScClient::FinalizeInterface(RChunk*& aChunk)
sl@0
    43
	{
sl@0
    44
	TInt errorOrhandle = DoControl(EControlRealizeInterface);
sl@0
    45
	iSharedChunk.SetReturnedHandle(errorOrhandle);
sl@0
    46
	iEndpointStatus = 0x00; //all endpoints are closed at the moment
sl@0
    47
	iAlternateSetting = 0;
sl@0
    48
	return aChunk->SetReturnedHandle(errorOrhandle);
sl@0
    49
	}
sl@0
    50
sl@0
    51
sl@0
    52
EXPORT_C TInt RDevUsbcScClient::OpenEndpoint(TEndpointBuffer& aEpB, TInt aEpI)
sl@0
    53
	{
sl@0
    54
	TUsbcScHdrEndpointRecord* endpointInf = NULL;
sl@0
    55
	TBuf8<KUsbDescSize_Endpoint> descriptor;
sl@0
    56
	TUsbcScChunkHeader chunkHeader(iSharedChunk);
sl@0
    57
	//Do some validity checks
sl@0
    58
	if((aEpB.iInState != TEndpointBuffer::ENotValid) && (aEpB.iOutState != TEndpointBuffer::ENotValid))
sl@0
    59
		return KErrArgument;
sl@0
    60
sl@0
    61
	TInt nEndpoints = chunkHeader.GetNumberOfEndpoints(iAlternateSetting);	
sl@0
    62
	if ((aEpI < KEp0Number) && (aEpI > nEndpoints)) // Check endpoint number range 
sl@0
    63
		return KErrNotFound;
sl@0
    64
sl@0
    65
	if(iEndpointStatus & (1 << aEpI)) // Check that endpoint isn't already opene
sl@0
    66
		return KErrInUse;
sl@0
    67
sl@0
    68
	if(aEpI == KEp0Number) //endpoint 0
sl@0
    69
		{
sl@0
    70
		TUsbcScHdrEndpointRecord ep0=  TUsbcScHdrEndpointRecord(KUsbcScEndpointZero, KUsbScHdrEpDirectionBiDir | KUsbScHdrEpTypeControl);
sl@0
    71
		aEpB.Construct(this,iSharedChunk.Base(), &ep0 ,aEpI, 
sl@0
    72
		(SUsbcScBufferHeader*) ((TUint)iSharedChunk.Base() + (chunkHeader.iBuffers)->Ep0Out()->Offset()));
sl@0
    73
sl@0
    74
		aEpB.iBufferStartAddr = (TUint8*) ((TUint)iSharedChunk.Base() + (chunkHeader.iBuffers)->Ep0In()->Offset());
sl@0
    75
		aEpB.iSize = chunkHeader.iBuffers->Ep0In()->Size();
sl@0
    76
		}
sl@0
    77
	else  // If normal endpoint (!ep0)
sl@0
    78
		{
sl@0
    79
		TUsbcScBufferRecord* buf = 	chunkHeader.GetBuffer(iAlternateSetting,aEpI,endpointInf);
sl@0
    80
		if (!buf)
sl@0
    81
			return KErrGeneral;
sl@0
    82
		// Set up endpoint members
sl@0
    83
		aEpB.iBufferStartAddr = (TUint8*)  (buf->Offset() + (TUint)iSharedChunk.Base());
sl@0
    84
		aEpB.iSize = buf->Size();
sl@0
    85
		TInt r = GetEndpointDescriptor(iAlternateSetting, aEpI, descriptor);
sl@0
    86
		if(r != KErrNone) // We need this to be able to calculate alignment
sl@0
    87
			{
sl@0
    88
			return r;
sl@0
    89
			}
sl@0
    90
sl@0
    91
		if (endpointInf->Direction()&KUsbScHdrEpDirectionIn)
sl@0
    92
			{  							//in case of IN endpoints, first endpoint buffer location points to end offset
sl@0
    93
			aEpB.Construct(this,iSharedChunk.Base(),endpointInf,aEpI);
sl@0
    94
			if (iInAltSetting==KErrEof)
sl@0
    95
			aEpB.iInState=TEndpointBuffer::EEOF;
sl@0
    96
sl@0
    97
			}
sl@0
    98
		else
sl@0
    99
			{
sl@0
   100
			SUsbcScBufferHeader *endpointHdr = (SUsbcScBufferHeader *) aEpB.iBufferStartAddr;
sl@0
   101
			//In this case,SUsbcScBufferHeader points to full OUT endpoint header 
sl@0
   102
			aEpB.Construct(this,iSharedChunk.Base(),endpointInf,aEpI, endpointHdr);
sl@0
   103
			}
sl@0
   104
		}
sl@0
   105
	iEndpointStatus |= (1 << aEpI);	
sl@0
   106
sl@0
   107
#ifdef _DEBUG
sl@0
   108
	aEpB.Dump();
sl@0
   109
	RDebug::Printf("iEndpointStatus: %x \n",iEndpointStatus);
sl@0
   110
#endif
sl@0
   111
	return KErrNone;
sl@0
   112
	}
sl@0
   113
sl@0
   114
sl@0
   115
//Internal, used by RDevUsbcScClient::StartNextOutAlternateSetting(...)
sl@0
   116
//This drains any old data from an OUT buffer, and gets it ready for reading an ep.
sl@0
   117
//aBufferOffset - The offset, into the chunk, that the buffer in question, may be found.
sl@0
   118
 
sl@0
   119
TInt RDevUsbcScClient::Drain(TUint aBufferOffset)
sl@0
   120
{
sl@0
   121
	TUint8* base = iSharedChunk.Base();
sl@0
   122
	SUsbcScBufferHeader* endpointHdr = (SUsbcScBufferHeader*) (aBufferOffset+base);
sl@0
   123
	TUint localTail = endpointHdr->iBilTail;
sl@0
   124
	TUsbcScTransferHeader* currentTransfer;
sl@0
   125
	TUint16 next = (iAltSettingSeq+1)&0xFFFF;
sl@0
   126
	TInt err=KErrNone;
sl@0
   127
sl@0
   128
	while (ETrue)
sl@0
   129
		{
sl@0
   130
		if (localTail == (TUint) endpointHdr->iHead)
sl@0
   131
			{
sl@0
   132
			err = KErrNotReady;
sl@0
   133
			break;
sl@0
   134
			}
sl@0
   135
		currentTransfer = (TUsbcScTransferHeader*) (base + localTail);
sl@0
   136
sl@0
   137
		if (currentTransfer->iAltSettingSeq == next)
sl@0
   138
			{
sl@0
   139
			iNewAltSetting=currentTransfer->iAltSetting; // record new alt setting
sl@0
   140
			break;
sl@0
   141
			}
sl@0
   142
		else
sl@0
   143
			{
sl@0
   144
			localTail = currentTransfer->iNext;
sl@0
   145
			}
sl@0
   146
		} // end while
sl@0
   147
	endpointHdr->iBilTail = localTail;
sl@0
   148
	endpointHdr->iTail = localTail;
sl@0
   149
	return err;
sl@0
   150
}
sl@0
   151
sl@0
   152
//Internal, used by RDevUsbcScClient::StartNextOutAlternateSetting(...)
sl@0
   153
//This method checks that the OUT buffer is ready for reading an ep.
sl@0
   154
//aBufferOffset - The offset, into the chunk, that the buffer in question, may be found.
sl@0
   155
sl@0
   156
TInt RDevUsbcScClient::Peek(TUint aBufferOffset)
sl@0
   157
{
sl@0
   158
	TUint8* base = iSharedChunk.Base();
sl@0
   159
	SUsbcScBufferHeader* endpointHdr = (SUsbcScBufferHeader*) (aBufferOffset+base);
sl@0
   160
	TUint localTail = endpointHdr->iBilTail;
sl@0
   161
	TUsbcScTransferHeader* currentTransfer = (TUsbcScTransferHeader*) (base + localTail);
sl@0
   162
sl@0
   163
	if ((localTail == (TUint)endpointHdr->iHead) || (currentTransfer->iAltSettingSeq != (iAltSettingSeq+1)&0xFFFF))
sl@0
   164
		// if alternate setting has not changed
sl@0
   165
		return KErrNotReady;
sl@0
   166
	else
sl@0
   167
		{
sl@0
   168
		iNewAltSetting=currentTransfer->iAltSetting;
sl@0
   169
		return KErrNone;
sl@0
   170
		}
sl@0
   171
}
sl@0
   172
sl@0
   173
//Internal, used by RDevUsbcScClient::StartNextOutAlternateSetting(...)
sl@0
   174
//This method is called if an alternate setting change happens from a set of ONLY IN endpoints.
sl@0
   175
//Used to find the least possible alternate setting it can return to the user, stored in iNewAltSetting
sl@0
   176
//Returns the sequence number of the 'latest' alternate setting it can switch to
sl@0
   177
sl@0
   178
TInt RDevUsbcScClient::FindNextAlternateSetting()
sl@0
   179
	{
sl@0
   180
	TUsbcScChunkHeader chunkHeader(iSharedChunk);
sl@0
   181
	TUsbcScHdrEndpointRecord* endpointInf = NULL;
sl@0
   182
	TUint bufOff;
sl@0
   183
	TInt altSet;
sl@0
   184
	TInt ep;
sl@0
   185
	TInt bufNum;
sl@0
   186
sl@0
   187
	RArray <TInt> bufferOffset;	// Array to contain all OUT enpoint buffer offsets
sl@0
   188
	// Populate array
sl@0
   189
	for (altSet = 0; altSet < chunkHeader.iAltSettings->iNumOfAltSettings ; altSet++)
sl@0
   190
		{
sl@0
   191
		TInt numEndpoints = chunkHeader.GetNumberOfEndpoints(altSet);
sl@0
   192
		for (ep =  1; ep  <= numEndpoints ; ep ++)
sl@0
   193
			{
sl@0
   194
			bufOff = chunkHeader.GetBuffer(altSet, ep, endpointInf)->Offset();	
sl@0
   195
			if ((endpointInf->Direction() & KUsbScHdrEpDirectionOut) && (bufferOffset.Find(bufOff) == KErrNotFound))
sl@0
   196
				{
sl@0
   197
				bufferOffset.Append(bufOff);
sl@0
   198
				}
sl@0
   199
			}
sl@0
   200
		}
sl@0
   201
sl@0
   202
	TInt err = KErrNotFound;
sl@0
   203
	TUint16 altSetSeqDelta = 0;
sl@0
   204
	TUint16 currentaltSetSeqDelta = 0;
sl@0
   205
	TBool noNewSettingFound = ETrue;
sl@0
   206
	TInt altSetSeq = iAltSettingSeq;
sl@0
   207
	TUint8* base = iSharedChunk.Base();
sl@0
   208
sl@0
   209
	for (bufNum = 0; bufNum < bufferOffset.Count(); bufNum++) // Scan all OUT buffers
sl@0
   210
		{	
sl@0
   211
		SUsbcScBufferHeader* endpointHdr = (SUsbcScBufferHeader*) (bufferOffset[bufNum] + base);
sl@0
   212
		TUint localTail = endpointHdr->iBilTail;
sl@0
   213
		TUsbcScTransferHeader* currentTransfer;
sl@0
   214
		TUint16 next = (iAltSettingSeq+1)&0xFFFF;
sl@0
   215
		
sl@0
   216
		while (ETrue)
sl@0
   217
			{
sl@0
   218
			if (localTail == (TUint) endpointHdr->iHead)
sl@0
   219
				{
sl@0
   220
				break;	// This OUT endpoint buffer has no data, proceed checking with other OUT endpoint buffers
sl@0
   221
				}
sl@0
   222
			currentTransfer = (TUsbcScTransferHeader*) (base + localTail);
sl@0
   223
sl@0
   224
			if (currentTransfer->iAltSettingSeq != iAltSettingSeq) 
sl@0
   225
				{
sl@0
   226
				if (currentTransfer->iAltSettingSeq == next)
sl@0
   227
					{
sl@0
   228
					altSetSeq = currentTransfer->iAltSettingSeq;
sl@0
   229
					iNewAltSetting = currentTransfer->iAltSetting; // record new alt setting
sl@0
   230
					err = KErrNone;
sl@0
   231
					break;
sl@0
   232
					}
sl@0
   233
sl@0
   234
				if (noNewSettingFound)
sl@0
   235
					{
sl@0
   236
					altSetSeqDelta = Abs(iAltSettingSeq - currentTransfer->iAltSettingSeq);
sl@0
   237
					altSetSeq = currentTransfer->iAltSettingSeq;
sl@0
   238
					iNewAltSetting = currentTransfer->iAltSetting; // record new alt setting
sl@0
   239
					noNewSettingFound = EFalse;
sl@0
   240
					}
sl@0
   241
				else
sl@0
   242
					{
sl@0
   243
					currentaltSetSeqDelta = Abs(iAltSettingSeq - currentTransfer->iAltSettingSeq);
sl@0
   244
					if (currentaltSetSeqDelta < altSetSeqDelta)
sl@0
   245
						{
sl@0
   246
						altSetSeqDelta = currentaltSetSeqDelta;
sl@0
   247
						altSetSeq = currentTransfer->iAltSettingSeq;
sl@0
   248
						iNewAltSetting = currentTransfer->iAltSetting;
sl@0
   249
						}
sl@0
   250
					}
sl@0
   251
				break;
sl@0
   252
				}
sl@0
   253
			
sl@0
   254
			localTail = currentTransfer->iNext;
sl@0
   255
			} // end while
sl@0
   256
sl@0
   257
		if (!err) // Found an alt set sequence one after iAltSettingSeq
sl@0
   258
			{
sl@0
   259
			break; // found 'the next' alternate setting, exit for loop
sl@0
   260
			}
sl@0
   261
		
sl@0
   262
		}// for loop
sl@0
   263
sl@0
   264
	return altSetSeq;
sl@0
   265
	}
sl@0
   266
sl@0
   267
EXPORT_C TInt RDevUsbcScClient::StartNextOutAlternateSetting(TBool aFlush)
sl@0
   268
	{
sl@0
   269
	TUsbcScChunkHeader chunkHeader(iSharedChunk);
sl@0
   270
	
sl@0
   271
	//if endpoints are still open, return KErrInUse 
sl@0
   272
	if((iEndpointStatus&~1) != 0)
sl@0
   273
		{
sl@0
   274
		return KErrInUse;
sl@0
   275
		}
sl@0
   276
sl@0
   277
	TInt r;
sl@0
   278
	TInt ep;
sl@0
   279
	TInt noEp;
sl@0
   280
	TUint bufOff;
sl@0
   281
	TBool inEndpointSet = ETrue;
sl@0
   282
	TUsbcScHdrEndpointRecord* endpointInf = NULL;
sl@0
   283
sl@0
   284
	// check if alternate setting contains all IN endpoints
sl@0
   285
	noEp = chunkHeader.GetNumberOfEndpoints(iAlternateSetting);
sl@0
   286
sl@0
   287
	// for each used buffer. 
sl@0
   288
	for (ep=1;ep<=noEp;ep++)
sl@0
   289
		{
sl@0
   290
		bufOff = chunkHeader.GetBuffer(iAlternateSetting,ep,endpointInf)->Offset();	
sl@0
   291
	
sl@0
   292
		if (endpointInf->Direction() & KUsbScHdrEpDirectionOut) 
sl@0
   293
			{
sl@0
   294
			inEndpointSet = EFalse;
sl@0
   295
			if (aFlush)
sl@0
   296
				r = Drain(bufOff); // we need to remove anythng in the way, and get it ready for reading.
sl@0
   297
			else
sl@0
   298
				r = Peek(bufOff); // we need to check it is ready for reading!
sl@0
   299
			if (r) 
sl@0
   300
				return r;
sl@0
   301
			}
sl@0
   302
		}
sl@0
   303
sl@0
   304
sl@0
   305
	TInt altSeq = 0;
sl@0
   306
	if (inEndpointSet)	// If all endpoints in the current alternate setting are IN endpoints
sl@0
   307
		{	// go through all OUT buffers for alternate setting change
sl@0
   308
		altSeq = FindNextAlternateSetting();
sl@0
   309
		}
sl@0
   310
sl@0
   311
	if((iNewAltSetting == iAlternateSetting) && (!inEndpointSet))
sl@0
   312
			{
sl@0
   313
			return KErrNotReady;
sl@0
   314
			}
sl@0
   315
sl@0
   316
	// Find/Set IN alternate setting
sl@0
   317
	TInt ret = StartNextInAlternateSetting();
sl@0
   318
	SUsbcScAlternateSetting* altrec = ((SUsbcScAlternateSetting*) (&ret));
sl@0
   319
sl@0
   320
	if (altrec->iSequence==iAltSettingSeq+1)
sl@0
   321
		{
sl@0
   322
		if (altrec->iSetting!=iNewAltSetting)
sl@0
   323
			return KErrGeneral;
sl@0
   324
		iInAltSetting=iNewAltSetting;
sl@0
   325
		}
sl@0
   326
	else
sl@0
   327
		{
sl@0
   328
		if (inEndpointSet)
sl@0
   329
			{
sl@0
   330
			if ((altSeq == iAltSettingSeq) || (iAltSettingSeq == altrec->iSequence))
sl@0
   331
				{
sl@0
   332
				return KErrNotReady;
sl@0
   333
				}
sl@0
   334
			else if (altSeq != altrec->iSequence)
sl@0
   335
				{
sl@0
   336
				iInAltSetting=KErrEof;
sl@0
   337
				}
sl@0
   338
			}
sl@0
   339
		iInAltSetting=KErrEof;
sl@0
   340
		}
sl@0
   341
sl@0
   342
	iAlternateSetting = iNewAltSetting;
sl@0
   343
	iAltSettingSeq += 1;
sl@0
   344
sl@0
   345
	return iAlternateSetting;
sl@0
   346
	}
sl@0
   347
sl@0
   348
sl@0
   349
EXPORT_C TInt RDevUsbcScClient::GetDataTransferChunk(RChunk* & aChunk)
sl@0
   350
	{
sl@0
   351
	aChunk = &iSharedChunk;
sl@0
   352
	return KErrNone;
sl@0
   353
	}
sl@0
   354
sl@0
   355
// Constructor
sl@0
   356
sl@0
   357
EXPORT_C TEndpointBuffer::TEndpointBuffer()
sl@0
   358
		:iInState(ENotValid),
sl@0
   359
		iOutState(ENotValid),
sl@0
   360
		iEndpointNumber(-1),
sl@0
   361
		iBufferNum(-1),
sl@0
   362
		iBufferStartAddr(0),
sl@0
   363
		iSize(0)
sl@0
   364
	{
sl@0
   365
	}
sl@0
   366
sl@0
   367
// Internal, called by RDevUsbcScClient::OpenEndpoint.
sl@0
   368
void TEndpointBuffer::Construct(RDevUsbcScClient* aClient, TUint8* aBaseAddr, const TUsbcScHdrEndpointRecord* aEpType , TInt aEndpointNumber,SUsbcScBufferHeader* aEndpointHdr)
sl@0
   369
	{
sl@0
   370
	iClient		= aClient;
sl@0
   371
	iBaseAddr	= (TUint) aBaseAddr;
sl@0
   372
	iInState 	= (((aEpType->Direction())&KUsbScHdrEpDirectionIn) ? EValid :  ENotValid);
sl@0
   373
	iOutState	= (((aEpType->Direction())&KUsbScHdrEpDirectionOut) ? EValid :  ENotValid);
sl@0
   374
	iBufferNum	= (aEpType->iBufferNo==(KUsbcScEndpointZero&0xFF))?KUsbcScEndpointZero:aEpType->iBufferNo;
sl@0
   375
	iEndpointNumber = aEndpointNumber;
sl@0
   376
sl@0
   377
	iEndpointHdr = aEndpointHdr;
sl@0
   378
	};
sl@0
   379
sl@0
   380
EXPORT_C TInt TEndpointBuffer::GetInBufferRange(TAny*& aStart, TUint& aSize)
sl@0
   381
	{
sl@0
   382
	if ((iInState))
sl@0
   383
		{
sl@0
   384
		return iInState;
sl@0
   385
		}
sl@0
   386
	aStart= iBufferStartAddr;
sl@0
   387
	aSize= iSize;
sl@0
   388
	return KErrNone;
sl@0
   389
	};
sl@0
   390
sl@0
   391
EXPORT_C TInt TEndpointBuffer::GetInBufferRange(TUint& aStart, TUint& aSize)
sl@0
   392
	{
sl@0
   393
	if ((iInState))
sl@0
   394
		return iInState;
sl@0
   395
	aStart=	(TUint) iBufferStartAddr - iBaseAddr;
sl@0
   396
	aSize= iSize;
sl@0
   397
	return KErrNone;
sl@0
   398
	}
sl@0
   399
sl@0
   400
sl@0
   401
EXPORT_C TInt TEndpointBuffer::GetBuffer(TAny*& aBuffer,TUint& aSize,TBool& aZLP,TRequestStatus& aStatus,TUint aLength)
sl@0
   402
	{
sl@0
   403
	if (iOutState)
sl@0
   404
		return iOutState;
sl@0
   405
sl@0
   406
	TUsbcScTransferHeader* currentTransfer;
sl@0
   407
	TInt r;
sl@0
   408
	do // until we have a transfer with data.
sl@0
   409
		{
sl@0
   410
		iEndpointHdr->iTail = iEndpointHdr->iBilTail; 
sl@0
   411
		if(iEndpointHdr->iBilTail == iEndpointHdr->iHead)  //If no new data, create request
sl@0
   412
			{
sl@0
   413
			r = iClient->ReadDataNotify(iBufferNum,aStatus);
sl@0
   414
			if (r!=KErrCompletion)  // Data could arrive since we checked.
sl@0
   415
				return r;
sl@0
   416
			}
sl@0
   417
		currentTransfer = (TUsbcScTransferHeader*) (iBaseAddr + iEndpointHdr->iBilTail);
sl@0
   418
sl@0
   419
		iEndpointHdr->iBilTail = currentTransfer->iNext;
sl@0
   420
		aZLP = (currentTransfer->iFlags & KUsbcScShortPacket)!=EFalse;
sl@0
   421
sl@0
   422
		if(currentTransfer->iAltSettingSeq != (iClient->iAltSettingSeq))  // if alternate setting has changed
sl@0
   423
			{
sl@0
   424
			if (currentTransfer->iAltSettingSeq == (iClient->iAltSettingSeq+1))	   //Note- KIS ATM, if multiple alternate setting changes happen
sl@0
   425
				iClient->iNewAltSetting = currentTransfer->iAltSetting; //before StartNextOutAlternateSetting is called, 		   
sl@0
   426
																	   //this variable will reflect the latest requested AlternateSetting
sl@0
   427
sl@0
   428
sl@0
   429
			if (iEndpointNumber != KEp0Number)
sl@0
   430
				{
sl@0
   431
//				iOutState =  EEOF;	
sl@0
   432
				return KErrEof;
sl@0
   433
				}
sl@0
   434
			else if ((currentTransfer->iBytes==0) && (!aZLP)) 
sl@0
   435
				{
sl@0
   436
				return KErrAlternateSettingChanged;
sl@0
   437
				}
sl@0
   438
			}						
sl@0
   439
sl@0
   440
		}
sl@0
   441
	while ((currentTransfer->iBytes==0) && (!aZLP)); // ignore empty transfers
sl@0
   442
sl@0
   443
	aBuffer = currentTransfer->iData.i;
sl@0
   444
	aSize = currentTransfer->iBytes;	
sl@0
   445
	return (currentTransfer->iFlags & KUsbcScStateChange)?KStateChange:KErrCompletion;	
sl@0
   446
	}
sl@0
   447
sl@0
   448
EXPORT_C TInt TEndpointBuffer::TakeBuffer(TAny*& aBuffer,TUint& aSize,TBool& aZLP,TRequestStatus& aStatus,TUint aLength)
sl@0
   449
	{
sl@0
   450
	if (iOutState)
sl@0
   451
		return iOutState;
sl@0
   452
sl@0
   453
	TUsbcScTransferHeader* currentTransfer;
sl@0
   454
	TInt r;
sl@0
   455
	do // until we have a transfer with data.
sl@0
   456
		{
sl@0
   457
		if(iEndpointHdr->iBilTail == iEndpointHdr->iHead)  //If no new data, create request
sl@0
   458
			{
sl@0
   459
			r = iClient->ReadDataNotify(iBufferNum,aStatus);
sl@0
   460
			if (r!=KErrCompletion)  // Data could arrive since we checked.
sl@0
   461
				{
sl@0
   462
				return r;
sl@0
   463
				}
sl@0
   464
			}
sl@0
   465
sl@0
   466
		currentTransfer = (TUsbcScTransferHeader*) (iBaseAddr + iEndpointHdr->iBilTail);
sl@0
   467
		iEndpointHdr->iBilTail = currentTransfer->iNext;
sl@0
   468
		aZLP = (currentTransfer->iFlags & KUsbcScShortPacket)!=EFalse; // True if short packet else false 
sl@0
   469
sl@0
   470
		if(currentTransfer->iAltSettingSeq != (iClient->iAltSettingSeq))  // if alternate setting has changed
sl@0
   471
			{
sl@0
   472
			if (currentTransfer->iAltSettingSeq == (iClient->iAltSettingSeq+1))	   //Note- KIS ATM, if multiple alternate setting changes happen
sl@0
   473
				iClient->iNewAltSetting = currentTransfer->iAltSetting; //before StartNextOutAlternateSetting is called, 		   
sl@0
   474
																	   //this variable will reflect the latest requested AlternateSetting
sl@0
   475
			Expire(currentTransfer->iData.i);
sl@0
   476
			if (iEndpointNumber != KEp0Number)
sl@0
   477
				{
sl@0
   478
//				iOutState = EEOF;
sl@0
   479
				return KErrEof;
sl@0
   480
				}
sl@0
   481
			else if ((currentTransfer->iBytes==0) && (!aZLP)) 
sl@0
   482
				{
sl@0
   483
				return KErrAlternateSettingChanged;
sl@0
   484
				}
sl@0
   485
sl@0
   486
			}	
sl@0
   487
sl@0
   488
		if ((currentTransfer->iBytes==0) && (!aZLP)) // here , if empty transfer with alt setting information, Call expire 
sl@0
   489
			{
sl@0
   490
			Expire(currentTransfer->iData.i);
sl@0
   491
			}
sl@0
   492
		}
sl@0
   493
	while ((currentTransfer->iBytes==0) && (!aZLP)); // ignore empty transfers
sl@0
   494
sl@0
   495
	aBuffer = currentTransfer->iData.i;
sl@0
   496
	aSize = currentTransfer->iBytes;
sl@0
   497
	return (currentTransfer->iFlags & KUsbcScStateChange)?KStateChange:KErrCompletion;	
sl@0
   498
	}
sl@0
   499
sl@0
   500
EXPORT_C TInt TEndpointBuffer::Expire()
sl@0
   501
	{
sl@0
   502
	if (!(iOutState != ENotValid))
sl@0
   503
		return iOutState;
sl@0
   504
sl@0
   505
	if (iEndpointHdr->iTail != iEndpointHdr->iBilTail)
sl@0
   506
		{
sl@0
   507
		TUsbcScTransferHeader* currentTransfer = (TUsbcScTransferHeader*) (iBaseAddr + iEndpointHdr->iTail);
sl@0
   508
		iEndpointHdr->iTail = currentTransfer->iNext;
sl@0
   509
		}
sl@0
   510
	return KErrNone;
sl@0
   511
	}
sl@0
   512
sl@0
   513
EXPORT_C TInt TEndpointBuffer::Expire(TAny* aAddress)
sl@0
   514
	{
sl@0
   515
	if (!(iOutState != ENotValid))
sl@0
   516
		return iOutState;
sl@0
   517
sl@0
   518
	TUint headerSize = sizeof(TUsbcScTransferHeader)-4; // TransferHeader includes 4 bytes of data.
sl@0
   519
	TInt transferToExpire = ((TUint) aAddress - headerSize);
sl@0
   520
	TInt offsetToExpire = transferToExpire - iBaseAddr; 
sl@0
   521
sl@0
   522
	TInt currentTail = iEndpointHdr->iTail;
sl@0
   523
sl@0
   524
	TInt prevTail = NULL;
sl@0
   525
	TBool found = EFalse;
sl@0
   526
	while (currentTail != iEndpointHdr->iBilTail)
sl@0
   527
		{
sl@0
   528
		TUsbcScTransferHeader* currentTransfer = (TUsbcScTransferHeader*) (iBaseAddr + currentTail);
sl@0
   529
		if (currentTail == offsetToExpire)		// found which to expire
sl@0
   530
			{
sl@0
   531
			found = ETrue;
sl@0
   532
			// This offset is to be expired
sl@0
   533
			if (prevTail == NULL)
sl@0
   534
				{
sl@0
   535
				// The offset is at the list head
sl@0
   536
				iEndpointHdr->iTail = currentTransfer->iNext;	
sl@0
   537
				}
sl@0
   538
			else
sl@0
   539
				{
sl@0
   540
				// The offset is NOT at the list head
sl@0
   541
				// This leaves a GAP in the buffer which will not be filled unless the 'transfers' before 'currentTail' are expired
sl@0
   542
				currentTail = currentTransfer->iNext;
sl@0
   543
				TUsbcScTransferHeader* prevTransfer = (TUsbcScTransferHeader*) (iBaseAddr + prevTail);
sl@0
   544
				prevTransfer->iNext = currentTail;
sl@0
   545
				}
sl@0
   546
			break;
sl@0
   547
			}
sl@0
   548
		prevTail = currentTail;
sl@0
   549
		currentTail = currentTransfer->iNext;
sl@0
   550
		}
sl@0
   551
	return found ? KErrNone : KErrNotFound;
sl@0
   552
	}
sl@0
   553
sl@0
   554
	
sl@0
   555
EXPORT_C TInt TEndpointBuffer::WriteBuffer(TAny* aBuffer,TUint aSize,TBool aZLP,TRequestStatus& aStatus)
sl@0
   556
	{
sl@0
   557
	if (iInState)
sl@0
   558
		return iInState;
sl@0
   559
sl@0
   560
	iClient->WriteData(iBufferNum, ((TUint)aBuffer - (TUint)iBaseAddr),aSize,aZLP,aStatus);
sl@0
   561
	return KErrNone;
sl@0
   562
	}
sl@0
   563
sl@0
   564
sl@0
   565
EXPORT_C TInt TEndpointBuffer::WriteBuffer(TUint aOffset,TUint aSize,TBool aZLP,TRequestStatus& aStatus)
sl@0
   566
	{
sl@0
   567
	if (iInState)
sl@0
   568
		return iInState;
sl@0
   569
sl@0
   570
	iClient->WriteData(iBufferNum,aOffset,aSize,aZLP,aStatus);
sl@0
   571
	return KErrNone;
sl@0
   572
	}
sl@0
   573
sl@0
   574
sl@0
   575
/**
sl@0
   576
Closes the endpoint buffer
sl@0
   577
@return			KErrNone if close is successfull
sl@0
   578
*/	
sl@0
   579
EXPORT_C TInt TEndpointBuffer::Close()
sl@0
   580
	{
sl@0
   581
	if ((iInState == ENotValid) && (iOutState == ENotValid))
sl@0
   582
		return KErrNotFound;
sl@0
   583
	if (iOutState != ENotValid)
sl@0
   584
		{
sl@0
   585
		TUsbcScTransferHeader* currentTransfer = (TUsbcScTransferHeader*) (iBaseAddr + iEndpointHdr->iTail);
sl@0
   586
		//Incase of AlternateSetting changes and using TEndpointBuffer::GetBuffer, iTail is always one 'transfer' behind iBilTail
sl@0
   587
		//Incase of AlternateSetting changes and using TEndpointBuffer::TakeBuffer, this shuold force the user to update iTail & only then closes the endpoint buffer
sl@0
   588
		if (((TInt) currentTransfer->iNext != iEndpointHdr->iBilTail) && (iEndpointHdr->iTail != iEndpointHdr->iBilTail))
sl@0
   589
			return KErrNotReady;
sl@0
   590
		}
sl@0
   591
	iClient->iEndpointStatus &= ~(1 << iEndpointNumber); //reset the bit corresponding to endpoint
sl@0
   592
	iInState = ENotValid;
sl@0
   593
	iOutState = ENotValid;
sl@0
   594
	return KErrNone;
sl@0
   595
	}
sl@0
   596
sl@0
   597
sl@0
   598
  
sl@0
   599
EXPORT_C TUsbcScChunkHeader::TUsbcScChunkHeader(RChunk aChunk)
sl@0
   600
	{
sl@0
   601
	iChunk = aChunk;
sl@0
   602
	iBuffers     = (TUsbcScChunkBuffersHeader*)    (aChunk.Base()+((TUsbcScChunkHdrOffs*)iChunk.Base())->iBuffers);
sl@0
   603
	iAltSettings = (TUsbcScChunkAltSettingHeader*) (aChunk.Base()+((TUsbcScChunkHdrOffs*)iChunk.Base())->iAltSettings);
sl@0
   604
	}
sl@0
   605
sl@0
   606
EXPORT_C TInt TUsbcScChunkHeader::GetNumberOfEndpoints(TInt aAltSetting)
sl@0
   607
	{
sl@0
   608
	if ((aAltSetting<0) || (aAltSetting>=iAltSettings->iNumOfAltSettings))
sl@0
   609
		return KErrArgument;
sl@0
   610
	return  *((TInt*) (iAltSettings->iAltTableOffset[aAltSetting] + (TInt) iChunk.Base()));
sl@0
   611
	}
sl@0
   612
sl@0
   613
sl@0
   614
EXPORT_C TUsbcScBufferRecord* TUsbcScChunkHeader::GetBuffer(TInt aAltSetting, TInt aEndpoint, TUsbcScHdrEndpointRecord*& aEndpointInf)
sl@0
   615
	{
sl@0
   616
	if ((aAltSetting<0) || (aAltSetting>=iAltSettings->iNumOfAltSettings))
sl@0
   617
		return NULL;
sl@0
   618
	TInt8* iEndpoint = (TInt8*) (iAltSettings->iAltTableOffset[aAltSetting] + (TInt) iChunk.Base());
sl@0
   619
	if ((aEndpoint<=0) || (aEndpoint>*iEndpoint))
sl@0
   620
		return NULL;
sl@0
   621
	aEndpointInf = (TUsbcScHdrEndpointRecord*) &(iEndpoint[aEndpoint*iAltSettings->iEpRecordSize]);
sl@0
   622
	return iBuffers->Buffers(aEndpointInf->iBufferNo);
sl@0
   623
	}
sl@0
   624
sl@0
   625
sl@0
   626
/* Debug functions */
sl@0
   627
sl@0
   628
EXPORT_C void TEndpointBuffer::Dump()
sl@0
   629
	{
sl@0
   630
	RDebug::Printf("TEndpointBuffer::Dump iBufferStart: 0x%x, iSize: 0x%x, iEndpointNumber: 0x%x, iBufferNum: %d, iInState: 0x%x iOutState: 0x%x\n",
sl@0
   631
							iBufferStartAddr,iSize,iEndpointNumber,iBufferNum,iInState,iOutState);
sl@0
   632
	}
sl@0
   633