os/kernelhwsrv/kernel/eka/drivers/soundsc/soundldd.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) 2006-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\soundsc\soundldd.cpp
sl@0
    15
// LDD for the shared chunk sound driver.
sl@0
    16
// 
sl@0
    17
//
sl@0
    18
sl@0
    19
/**
sl@0
    20
 @file
sl@0
    21
 @internalTechnology
sl@0
    22
 @prototype
sl@0
    23
*/
sl@0
    24
sl@0
    25
#include <drivers/soundsc.h>
sl@0
    26
#include <kernel/kern_priv.h>
sl@0
    27
#include <kernel/cache.h>
sl@0
    28
sl@0
    29
//#define USE_PLAY_EOF_TIMER
sl@0
    30
sl@0
    31
// Define TEST_WITH_PAGING_CACHE_FLUSHES to flush the paging cache when testing read/writes to user thread in a data-paging system
sl@0
    32
//#define TEST_WITH_PAGING_CACHE_FLUSHES
sl@0
    33
sl@0
    34
static const char KSoundLddPanic[]="Sound LDD";
sl@0
    35
sl@0
    36
LOCAL_C TInt HighestCapabilitySupported(TUint32 aCapsBitField)
sl@0
    37
	{
sl@0
    38
	TInt n;
sl@0
    39
	for (n=31 ; n>=0 ; n--)
sl@0
    40
		{
sl@0
    41
		if (aCapsBitField&(1<<n))
sl@0
    42
			break;
sl@0
    43
		}
sl@0
    44
	return(n);
sl@0
    45
	}
sl@0
    46
sl@0
    47
/**
sl@0
    48
Standard export function for LDDs. This creates a DLogicalDevice derived object,
sl@0
    49
in this case, DSoundScLddFactory.
sl@0
    50
*/
sl@0
    51
DECLARE_STANDARD_LDD()
sl@0
    52
	{
sl@0
    53
	return new DSoundScLddFactory;
sl@0
    54
	}
sl@0
    55
sl@0
    56
/**
sl@0
    57
Constructor for the sound driver factory class.
sl@0
    58
*/
sl@0
    59
DSoundScLddFactory::DSoundScLddFactory()
sl@0
    60
	{
sl@0
    61
//	iUnitsOpenMask=0;
sl@0
    62
sl@0
    63
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLddFactory::DSoundScLddFactory"));
sl@0
    64
sl@0
    65
	// Set version number for this device.
sl@0
    66
	iVersion=RSoundSc::VersionRequired();
sl@0
    67
	
sl@0
    68
	// Indicate that units / PDD are supported.
sl@0
    69
	iParseMask=KDeviceAllowUnit|KDeviceAllowPhysicalDevice;
sl@0
    70
	
sl@0
    71
	// Leave the units decision to the PDD
sl@0
    72
	iUnitsMask=0xffffffff;
sl@0
    73
	}
sl@0
    74
	
sl@0
    75
/**
sl@0
    76
Second stage constructor for the sound driver factory class.
sl@0
    77
This must at least set a name for the driver object.
sl@0
    78
@return KErrNone if successful, otherwise one of the other system wide error codes.
sl@0
    79
*/
sl@0
    80
TInt DSoundScLddFactory::Install()
sl@0
    81
	{
sl@0
    82
	return(SetName(&KDevSoundScName));
sl@0
    83
	}
sl@0
    84
sl@0
    85
/**
sl@0
    86
Return the 'capabilities' of the sound driver in general.
sl@0
    87
Called in the response to an RDevice::GetCaps() request.
sl@0
    88
@param aDes A user-side descriptor to write the capabilities information into.
sl@0
    89
*/
sl@0
    90
void DSoundScLddFactory::GetCaps(TDes8& aDes) const
sl@0
    91
	{
sl@0
    92
	// Create a capabilities object
sl@0
    93
	TCapsSoundScV01 caps;
sl@0
    94
	caps.iVersion=iVersion;
sl@0
    95
	
sl@0
    96
	// Write it back to user memory
sl@0
    97
	Kern::InfoCopy(aDes,(TUint8*)&caps,sizeof(caps));
sl@0
    98
	}
sl@0
    99
sl@0
   100
/**
sl@0
   101
Called by the kernel's device driver framework to create a logical channel.
sl@0
   102
This is called in the context of the client thread which requested the creation of a logical channel.
sl@0
   103
The thread is in a critical section.
sl@0
   104
@param aChannel Set by this function to point to the created logical channel.
sl@0
   105
@return KErrNone if successful, otherwise one of the other system wide error codes.
sl@0
   106
*/
sl@0
   107
TInt DSoundScLddFactory::Create(DLogicalChannelBase*& aChannel)
sl@0
   108
	{
sl@0
   109
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLddFactory::Create"));
sl@0
   110
	aChannel=new DSoundScLdd;
sl@0
   111
	if (!aChannel)
sl@0
   112
		return(KErrNoMemory);
sl@0
   113
sl@0
   114
	return(KErrNone);
sl@0
   115
	}
sl@0
   116
	
sl@0
   117
/**
sl@0
   118
Check whether a channel has is currently open on the specified unit.
sl@0
   119
@param aUnit The number of the unit to be checked.
sl@0
   120
@return ETrue if a channel is open on the specified channel, EFalse otherwise.
sl@0
   121
@pre The unit info. mutex must be held.
sl@0
   122
*/
sl@0
   123
TBool DSoundScLddFactory::IsUnitOpen(TInt aUnit)
sl@0
   124
	{
sl@0
   125
	return(iUnitsOpenMask&(1<<aUnit));
sl@0
   126
	}
sl@0
   127
sl@0
   128
/**
sl@0
   129
Attempt to change the state of the channel open status for a particular channel.
sl@0
   130
@param aUnit The number of the unit to be updated.
sl@0
   131
@param aIsOpenSetting The required new state for the channel open status: either ETrue to set the status to open or 
sl@0
   132
	EFalse to set the status to closed.
sl@0
   133
@return KErrNone if the status was updated successfully, KErrInUse if an attempt has been made to set the channnel status
sl@0
   134
	to open while it is already open.
sl@0
   135
*/		
sl@0
   136
TInt DSoundScLddFactory::SetUnitOpen(TInt aUnit,TBool aIsOpenSetting)
sl@0
   137
	{
sl@0
   138
	NKern::FMWait(&iUnitInfoMutex); // Acquire the unit info. mutex.
sl@0
   139
	
sl@0
   140
	// Fail a request to open an channel that is already open
sl@0
   141
	if (aIsOpenSetting && IsUnitOpen(aUnit))
sl@0
   142
		{
sl@0
   143
		NKern::FMSignal(&iUnitInfoMutex); // Release the unit info. mutex.
sl@0
   144
		return(KErrInUse);
sl@0
   145
		}
sl@0
   146
	
sl@0
   147
	// Update the open status as requested
sl@0
   148
	if (aIsOpenSetting)
sl@0
   149
		iUnitsOpenMask|=(1<<aUnit);
sl@0
   150
	else
sl@0
   151
		iUnitsOpenMask&=~(1<<aUnit);
sl@0
   152
	
sl@0
   153
	NKern::FMSignal(&iUnitInfoMutex); // Release the unit info. mutex.	
sl@0
   154
	return(KErrNone);
sl@0
   155
	}	
sl@0
   156
sl@0
   157
/**
sl@0
   158
Constructor for the sound driver logical channel.
sl@0
   159
*/
sl@0
   160
DSoundScLdd::DSoundScLdd()
sl@0
   161
	: iPowerDownDfc(DSoundScLdd::PowerDownDfc,this,3),
sl@0
   162
	  iPowerUpDfc(DSoundScLdd::PowerUpDfc,this,3),
sl@0
   163
	  iEofTimer(DSoundScLdd::PlayEofTimerExpired,this),
sl@0
   164
	  iPlayEofDfc(DSoundScLdd::PlayEofTimerDfc,this,3)
sl@0
   165
	{
sl@0
   166
//	iDirection=ESoundDirRecord;
sl@0
   167
//	iState=EOpen;
sl@0
   168
// 	iBufConfig=NULL;
sl@0
   169
//	iPowerHandler=NULL;
sl@0
   170
//	iSoundConfigFlags=0;
sl@0
   171
//	iBytesTransferred=0;
sl@0
   172
//	iBufManager=NULL;
sl@0
   173
//	iTestSettings=0;
sl@0
   174
//	iPlayEofTimerActive=EFalse;
sl@0
   175
//	iThreadOpenCount=0;
sl@0
   176
sl@0
   177
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd::DSoundScLdd"));
sl@0
   178
sl@0
   179
	iUnit=-1;	// Invalid unit number
sl@0
   180
	
sl@0
   181
	// Many drivers would open the client thread's DThread object here. However, since this driver allows a channel to be shared by multiple client 
sl@0
   182
	// threads - we have to open and close the relevent DThread object for each request. 
sl@0
   183
	}
sl@0
   184
sl@0
   185
/**
sl@0
   186
Destructor for the sound driver logical channel.
sl@0
   187
*/
sl@0
   188
DSoundScLdd::~DSoundScLdd()
sl@0
   189
	{
sl@0
   190
sl@0
   191
	if (iNotifyChangeOfHwClientRequest)
sl@0
   192
		Kern::DestroyClientRequest(iNotifyChangeOfHwClientRequest);
sl@0
   193
sl@0
   194
	// Free the TClientRequest structures associated with requests
sl@0
   195
	if (iClientRequests)
sl@0
   196
		{
sl@0
   197
		for (TInt index=0; index<RSoundSc::ERequestRecordData+1; ++index)
sl@0
   198
			if (iClientRequests[index])
sl@0
   199
				Kern::DestroyClientRequest(iClientRequests[index]);
sl@0
   200
sl@0
   201
		delete[] iClientRequests;
sl@0
   202
		}
sl@0
   203
sl@0
   204
	// Check if we need to delete the shared chunk / audio buffers.
sl@0
   205
	if (iBufManager)
sl@0
   206
		delete iBufManager;
sl@0
   207
	
sl@0
   208
	// Delete any memory allocated to hold the current buffer configuration.
sl@0
   209
	if (iBufConfig)
sl@0
   210
		delete iBufConfig;
sl@0
   211
	
sl@0
   212
	// Remove and delete the power handler.
sl@0
   213
	if (iPowerHandler)
sl@0
   214
		{
sl@0
   215
		iPowerHandler->Remove(); 
sl@0
   216
		delete iPowerHandler;
sl@0
   217
		}
sl@0
   218
		
sl@0
   219
	// Delete the request queue
sl@0
   220
	if (iReqQueue)
sl@0
   221
		delete iReqQueue;		
sl@0
   222
	
sl@0
   223
	__ASSERT_DEBUG(iThreadOpenCount==0,Kern::Fault(KSoundLddPanic,__LINE__));	
sl@0
   224
	
sl@0
   225
	// Clear the 'units open mask' in the LDD factory.
sl@0
   226
	if (iUnit>=0)
sl@0
   227
		((DSoundScLddFactory*)iDevice)->SetUnitOpen(iUnit,EFalse);
sl@0
   228
	}
sl@0
   229
	
sl@0
   230
/**
sl@0
   231
Second stage constructor for the sound driver - called by the kernel's device driver framework.
sl@0
   232
This is called in the context of the client thread which requested the creation of a logical channel.
sl@0
   233
The thread is in a critical section.
sl@0
   234
@param aUnit The unit argument supplied by the client.
sl@0
   235
@param aInfo The info argument supplied by the client. Always NULL in this case.
sl@0
   236
@param aVer The version argument supplied by the client.
sl@0
   237
@return KErrNone if successful, otherwise one of the other system wide error codes.
sl@0
   238
*/
sl@0
   239
TInt DSoundScLdd::DoCreate(TInt aUnit, const TDesC8* /*aInfo*/, const TVersion& aVer)
sl@0
   240
	{
sl@0
   241
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd::DoCreate"));
sl@0
   242
	
sl@0
   243
	// Check the client has ECapabilityMultimediaDD capability.
sl@0
   244
	if (!Kern::CurrentThreadHasCapability(ECapabilityMultimediaDD,__PLATSEC_DIAGNOSTIC_STRING("Checked by ESOUNDSC.LDD (Sound driver)")))
sl@0
   245
		return(KErrPermissionDenied);
sl@0
   246
sl@0
   247
	// Check that the sound driver version specified by the client is compatible.
sl@0
   248
	if (!Kern::QueryVersionSupported(RSoundSc::VersionRequired(),aVer))
sl@0
   249
		return(KErrNotSupported);
sl@0
   250
	
sl@0
   251
	// Check that a channel hasn't already been opened on this unit.
sl@0
   252
	TInt r=((DSoundScLddFactory*)iDevice)->SetUnitOpen(aUnit,ETrue); // Try to update 'units open mask' in the LDD factory.
sl@0
   253
	if (r!=KErrNone)
sl@0
   254
		return(r);
sl@0
   255
	iUnit=aUnit;
sl@0
   256
sl@0
   257
	// Create a TClientRequest for each request that can be completed by the DFC thread.  These TClientRequest
sl@0
   258
	// instances are separate to those embedded in the TSoundScRequest structures and are used for requests that
sl@0
   259
	// have no associated TSoundScRequest structure or which are completing prematurely before they can be
sl@0
   260
	// associated with a TSoundScRequest structure
sl@0
   261
	if ((iClientRequests=new TClientRequest*[RSoundSc::ERequestRecordData+1])==NULL)
sl@0
   262
		return KErrNoMemory;
sl@0
   263
sl@0
   264
	for (TInt index=0; index<RSoundSc::ERequestRecordData+1; ++index)
sl@0
   265
		if ((r=Kern::CreateClientRequest(iClientRequests[index]))!=KErrNone)
sl@0
   266
			return r;
sl@0
   267
sl@0
   268
	if ((r=Kern::CreateClientDataRequest(iNotifyChangeOfHwClientRequest))!=KErrNone)
sl@0
   269
		return r;
sl@0
   270
sl@0
   271
	// Initialise the PDD
sl@0
   272
	Pdd()->iLdd=this;
sl@0
   273
	
sl@0
   274
	// Read back the capabilities of this device from the PDD and determine the data transfer direction for this unit.
sl@0
   275
	TPckg<TSoundFormatsSupportedV02> capsBuf(iCaps);
sl@0
   276
	Pdd()->Caps(capsBuf);
sl@0
   277
	iDirection=iCaps.iDirection;
sl@0
   278
sl@0
   279
	// Check the client has UserEnvironment capability if recording.
sl@0
   280
	if(iDirection==ESoundDirRecord)
sl@0
   281
		{
sl@0
   282
		if (!Kern::CurrentThreadHasCapability(ECapabilityUserEnvironment,__PLATSEC_DIAGNOSTIC_STRING("Checked by ESOUNDSC.LDD (Sound driver)")))
sl@0
   283
			return(KErrPermissionDenied);
sl@0
   284
		}
sl@0
   285
	
sl@0
   286
	// Create the appropriate request queue
sl@0
   287
	if (iDirection==ESoundDirPlayback)
sl@0
   288
		iReqQueue=new TSoundScPlayRequestQueue(this);
sl@0
   289
	else
sl@0
   290
		iReqQueue=new TSoundScRequestQueue(this);
sl@0
   291
	if (!iReqQueue)
sl@0
   292
		return(KErrNoMemory);
sl@0
   293
	r=iReqQueue->Create();
sl@0
   294
	if (r!=KErrNone)
sl@0
   295
		return(r);
sl@0
   296
	
sl@0
   297
	// Setup the default audio configuration acording to these capabilities.
sl@0
   298
	iSoundConfig.iChannels=HighestCapabilitySupported(iCaps.iChannels)+1;
sl@0
   299
	__ASSERT_ALWAYS(iSoundConfig.iChannels>0,Kern::Fault(KSoundLddPanic,__LINE__));
sl@0
   300
	iSoundConfig.iRate=(TSoundRate)HighestCapabilitySupported(iCaps.iRates);
sl@0
   301
	__ASSERT_ALWAYS(iSoundConfig.iRate>=0,Kern::Fault(KSoundLddPanic,__LINE__));
sl@0
   302
	iSoundConfig.iEncoding=(TSoundEncoding)HighestCapabilitySupported(iCaps.iEncodings);
sl@0
   303
	__ASSERT_ALWAYS(iSoundConfig.iEncoding>=0,Kern::Fault(KSoundLddPanic,__LINE__));
sl@0
   304
	iSoundConfig.iDataFormat=(TSoundDataFormat)HighestCapabilitySupported(iCaps.iDataFormats);
sl@0
   305
	__ASSERT_ALWAYS(iSoundConfig.iDataFormat>=0,Kern::Fault(KSoundLddPanic,__LINE__));
sl@0
   306
	__ASSERT_ALWAYS(ValidateConfig(iSoundConfig)==KErrNone,Kern::Fault(KSoundLddPanic,__LINE__));
sl@0
   307
	iSoundConfigFlags=0;
sl@0
   308
	
sl@0
   309
	// Setup the default setting for the record level / play volume.
sl@0
   310
	iVolume=KSoundMaxVolume;
sl@0
   311
		
sl@0
   312
	// Set up the correct DFC queue
sl@0
   313
	TDfcQue* dfcq=((DSoundScPdd*)iPdd)->DfcQ(aUnit);
sl@0
   314
	SetDfcQ(dfcq);
sl@0
   315
	iPowerDownDfc.SetDfcQ(dfcq);
sl@0
   316
	iPowerUpDfc.SetDfcQ(dfcq);
sl@0
   317
	iMsgQ.Receive();
sl@0
   318
	
sl@0
   319
	// Create the power handler
sl@0
   320
	iPowerHandler=new DSoundScPowerHandler(this);
sl@0
   321
	if (!iPowerHandler)
sl@0
   322
		return(KErrNoMemory);
sl@0
   323
	iPowerHandler->Add();
sl@0
   324
	
sl@0
   325
	// Power up the hardware.
sl@0
   326
	r=Pdd()->PowerUp();
sl@0
   327
	
sl@0
   328
	return(r);
sl@0
   329
	}
sl@0
   330
	
sl@0
   331
/**
sl@0
   332
Shutdown the audio device.
sl@0
   333
Terminate all device activity and power down the hardware.
sl@0
   334
*/
sl@0
   335
void DSoundScLdd::Shutdown()
sl@0
   336
	{
sl@0
   337
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd::Shutdown"));
sl@0
   338
sl@0
   339
	Pdd()->StopTransfer();
sl@0
   340
	
sl@0
   341
	// Power down the hardware
sl@0
   342
	Pdd()->PowerDown();
sl@0
   343
sl@0
   344
	// Cancel any requests that we may be handling	
sl@0
   345
	DoCancel(RSoundSc::EAllRequests);
sl@0
   346
	
sl@0
   347
	iState=EOpen;
sl@0
   348
sl@0
   349
	// Make sure DFCs and timers are not queued.
sl@0
   350
	iPowerDownDfc.Cancel();
sl@0
   351
	iPowerUpDfc.Cancel();
sl@0
   352
	CancelPlayEofTimer();
sl@0
   353
	}
sl@0
   354
	
sl@0
   355
/**
sl@0
   356
Process a request on this logical channel
sl@0
   357
Called in the context of the client thread.
sl@0
   358
@param aReqNo The request number:
sl@0
   359
  	          ==KMaxTInt: a 'DoCancel' message;
sl@0
   360
	          >=0: a 'DoControl' message with function number equal to value.
sl@0
   361
	          <0: a 'DoRequest' message with function number equal to ~value.
sl@0
   362
@param a1 The first request argument. For DoRequest(), this is a pointer to the TRequestStatus.
sl@0
   363
@param a2 The second request argument. For DoRequest(), this is a pointer to the 2 actual TAny* arguments.
sl@0
   364
@return The result of the request. This is ignored by device driver framework for DoRequest().
sl@0
   365
*/ 
sl@0
   366
TInt DSoundScLdd::Request(TInt aReqNo, TAny* a1, TAny* a2)
sl@0
   367
	{
sl@0
   368
//	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd::Request(%d)",aReqNo));
sl@0
   369
	TInt r;
sl@0
   370
	
sl@0
   371
	// Check for DoControl or DoRequest functions which are configured to execute in kernel thread context. This
sl@0
   372
	// also applies to DoCancel functions and ERequestRecordData requests where recording mode is not yet enabled.
sl@0
   373
	if ((aReqNo<RSoundSc::EMsgControlMax && aReqNo>(~RSoundSc::EMsgRequestMax)) ||
sl@0
   374
	    aReqNo==KMaxTInt ||
sl@0
   375
	    ((~aReqNo)==RSoundSc::ERequestRecordData && (iState==EOpen || iState==EConfigured)) 
sl@0
   376
	   )
sl@0
   377
		{
sl@0
   378
		// Implement in the context of the kernel thread - prepare and issue a kernel message.
sl@0
   379
		r=DLogicalChannel::Request(aReqNo,a1,a2);		
sl@0
   380
		}	
sl@0
   381
	else
sl@0
   382
		{
sl@0
   383
		// Implement in the context of the client thread.	
sl@0
   384
		// Decode the message type and dispatch it to the relevent handler function.
sl@0
   385
		if ((TUint)aReqNo<(TUint)KMaxTInt)
sl@0
   386
			r=DoControl(aReqNo,a1,a2,&Kern::CurrentThread());	// DoControl - process the request.
sl@0
   387
		
sl@0
   388
		else
sl@0
   389
			{
sl@0
   390
			// DoRequest - read the arguments from the client thread and process the request.
sl@0
   391
			TAny* a[2];
sl@0
   392
			kumemget32(a,a2,sizeof(a)); 
sl@0
   393
			TRequestStatus* status=(TRequestStatus*)a1;
sl@0
   394
			NKern::ThreadEnterCS(); 				// Need to be in critical section while manipulating the request/buffer list (for record).
sl@0
   395
			r=DoRequest(~aReqNo,status,a[0],a[1],&Kern::CurrentThread());
sl@0
   396
		
sl@0
   397
			// Complete request if there was an error
sl@0
   398
			if (r!=KErrNone)
sl@0
   399
				CompleteRequest(&Kern::CurrentThread(),status,r);
sl@0
   400
			r=KErrNone;
sl@0
   401
			NKern::ThreadLeaveCS();
sl@0
   402
			}
sl@0
   403
		}
sl@0
   404
//	__KTRACE_OPT(KSOUND1, Kern::Printf("<DSoundScLdd::Request - %d",r));
sl@0
   405
	return(r);
sl@0
   406
	}
sl@0
   407
sl@0
   408
/**
sl@0
   409
Send a message to the DFC thread for processing by HandleMsg().
sl@0
   410
sl@0
   411
This function is called in the context of the client thread.
sl@0
   412
sl@0
   413
Overridden to ensure client data is copied kernel-side to avoid page-faults.
sl@0
   414
sl@0
   415
@param aMsg  The message to process.
sl@0
   416
sl@0
   417
@return KErrNone if the message was send successfully, otherwise one of the other system-wide error
sl@0
   418
        codes.
sl@0
   419
*/
sl@0
   420
TInt DSoundScLdd::SendMsg(TMessageBase* aMsg)
sl@0
   421
	{
sl@0
   422
	// Executes in context of client thread
sl@0
   423
sl@0
   424
	TThreadMessage& m=*(TThreadMessage*)aMsg;
sl@0
   425
    TInt id = m.iValue;
sl@0
   426
sl@0
   427
	TInt r(KErrNone);
sl@0
   428
	if (id == ~RSoundSc::EMsgRequestPlayData)
sl@0
   429
		{
sl@0
   430
		r = PrePlay(aMsg);
sl@0
   431
		if (r!=KErrNone)
sl@0
   432
			{
sl@0
   433
			// This is an asynchronous request so need to return error through the TRequestStatus
sl@0
   434
			TRequestStatus* status = (TRequestStatus*)(m.Ptr0());
sl@0
   435
			Kern::RequestComplete(status,r);
sl@0
   436
			return(r);
sl@0
   437
			}
sl@0
   438
		r = DLogicalChannel::SendMsg(aMsg);
sl@0
   439
		if (r!=KErrNone)
sl@0
   440
			{
sl@0
   441
			iReqQueue->Free((TSoundScPlayRequest*)m.iArg[1]);	// Return the unused request object	
sl@0
   442
			}
sl@0
   443
		return(r);
sl@0
   444
		}
sl@0
   445
	else if (id == RSoundSc::EMsgControlSetBufChunkCreate || id == RSoundSc::EMsgControlSetBufChunkOpen)
sl@0
   446
		{
sl@0
   447
		r = PreSetBufferChunkCreateOrOpen(aMsg);
sl@0
   448
		if (r!=KErrNone)
sl@0
   449
			{
sl@0
   450
			return(r);
sl@0
   451
			}
sl@0
   452
		}
sl@0
   453
	else if (id == RSoundSc::EMsgControlSetAudioFormat)
sl@0
   454
		{
sl@0
   455
		r = PreSetSoundConfig(aMsg);
sl@0
   456
		if (r!=KErrNone)
sl@0
   457
			{
sl@0
   458
			return(r);
sl@0
   459
			}
sl@0
   460
		}
sl@0
   461
sl@0
   462
	r = DLogicalChannel::SendMsg(aMsg);
sl@0
   463
		
sl@0
   464
sl@0
   465
	return(r);
sl@0
   466
	}
sl@0
   467
sl@0
   468
/**
sl@0
   469
PreProcess a play request on this logical channel
sl@0
   470
Called in the context of the client thread.
sl@0
   471
sl@0
   472
@param aMsg  The message to process.
sl@0
   473
sl@0
   474
@return KErrNone if the parameters are validated and request structure populated. Otherwise a system-wide error.
sl@0
   475
*/ 
sl@0
   476
TInt DSoundScLdd::PrePlay(TMessageBase* aMsg)
sl@0
   477
	{
sl@0
   478
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd::PrePlay"));
sl@0
   479
sl@0
   480
	// Executes in context of client thread
sl@0
   481
sl@0
   482
	TThreadMessage* m=(TThreadMessage*)aMsg;
sl@0
   483
sl@0
   484
	// Copy play information to kernel side before checking
sl@0
   485
	SRequestPlayDataInfo info;
sl@0
   486
	kumemget(&info,m->iArg[1],sizeof(info));
sl@0
   487
sl@0
   488
	__KTRACE_OPT(KSOUND1, Kern::Printf("DSoundScLdd::PrePlay - off %x len %x flg %x ",info.iBufferOffset,info.iLength,info.iFlags));
sl@0
   489
sl@0
   490
	// validate parameters in the play structure
sl@0
   491
sl@0
   492
	// Check that the offset argument is aligned correctly for the PDD.
sl@0
   493
	TUint32 alignmask=(1<<iCaps.iRequestAlignment)-1; // iRequestAlignment holds log to base 2 of alignment required
sl@0
   494
	if ((info.iBufferOffset & alignmask) != 0)
sl@0
   495
		return(KErrArgument);
sl@0
   496
	
sl@0
   497
	// Check that the length argument is compatible with the minimum request size required for the PDD.
sl@0
   498
	if (iCaps.iRequestMinSize && info.iLength%iCaps.iRequestMinSize)
sl@0
   499
		return(KErrArgument);
sl@0
   500
	
sl@0
   501
	// Check that the specified offset and length are valid in the chunk. If so, get a pointer to the corresponding 
sl@0
   502
	// audio buffer object.
sl@0
   503
	TAudioBuffer* buf;
sl@0
   504
	if (iBufManager)
sl@0
   505
		{
sl@0
   506
		TInt r=iBufManager->ValidateRegion(info.iBufferOffset,info.iLength,buf);
sl@0
   507
		if (r!=KErrNone)
sl@0
   508
			return(r);
sl@0
   509
		}
sl@0
   510
	else
sl@0
   511
		{
sl@0
   512
		return(KErrNotReady);
sl@0
   513
		}	
sl@0
   514
sl@0
   515
	// Acquire a free request object and add it to the queue of pending requests.
sl@0
   516
	TSoundScPlayRequest* req=(TSoundScPlayRequest*)iReqQueue->NextFree();
sl@0
   517
	if (!req)
sl@0
   518
		return(KErrGeneral);										// Must have exceeded KMaxSndScRequestsPending.
sl@0
   519
	req->iTf.Init((TUint)buf,info.iBufferOffset,info.iLength,buf); 	// Use pointer to audio buffer as unique ID
sl@0
   520
	req->iFlags=info.iFlags;
sl@0
   521
sl@0
   522
	// replace the argument with a pointer to the kernel-side structure
sl@0
   523
	m->iArg[1]=req;
sl@0
   524
	
sl@0
   525
	__KTRACE_OPT(KSOUND1, Kern::Printf("<DSoundScLdd::PrePlay"));
sl@0
   526
sl@0
   527
	return(KErrNone);
sl@0
   528
	}
sl@0
   529
sl@0
   530
/**
sl@0
   531
PreProcess a SetBufferChunkCreate and SetBufferChunkOpen on this logical channel
sl@0
   532
Called in the context of the client thread.
sl@0
   533
This is synchronous so only need one copy of the data on the kernel-side.
sl@0
   534
sl@0
   535
@param aMsg  The message to process.
sl@0
   536
sl@0
   537
@return KErrNone if the parameters are validated and request structure populated. Otherwise a system-wide error.
sl@0
   538
*/ 
sl@0
   539
TInt DSoundScLdd::PreSetBufferChunkCreateOrOpen(TMessageBase* aMsg)
sl@0
   540
	{
sl@0
   541
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd::PreSetBufferChunkCreateOrOpen"));
sl@0
   542
	TInt r(KErrNone);
sl@0
   543
sl@0
   544
	TThreadMessage* m=(TThreadMessage*)aMsg;
sl@0
   545
sl@0
   546
	TInt length, maxLength;
sl@0
   547
	const TDesC8* userDesc = (const TDesC8*)m->Ptr0();
sl@0
   548
	const TUint8* configData = Kern::KUDesInfo(*userDesc,length,maxLength);
sl@0
   549
sl@0
   550
	//__KTRACE_OPT(KSOUND1, Kern::Printf("DSoundScLdd::PreSetBufferChunkCreateOrOpen - len %x maxlen %x",length,maxLength));
sl@0
   551
sl@0
   552
	// check the descriptor length is >= the base class size
sl@0
   553
	TInt minDesLen=sizeof(TSharedChunkBufConfigBase);
sl@0
   554
	if (length<minDesLen)
sl@0
   555
		return(KErrArgument);
sl@0
   556
sl@0
   557
	// Temporary copy of client-side buffer config structure  
sl@0
   558
	TSharedChunkBufConfigBase chunkBufConfig;
sl@0
   559
sl@0
   560
	kumemget(&chunkBufConfig, configData, minDesLen);
sl@0
   561
sl@0
   562
	//__KTRACE_OPT(KSOUND1, Kern::Printf("DSoundScLdd::PreSetBufferChunkCreateOrOpen - num %x size %x flg %x ",chunkBufConfig.iNumBuffers,chunkBufConfig.iBufferSizeInBytes,chunkBufConfig.iFlags));
sl@0
   563
sl@0
   564
	// check the buffer argument
sl@0
   565
	if (chunkBufConfig.iNumBuffers<=0)
sl@0
   566
		return(KErrArgument);
sl@0
   567
sl@0
   568
	// Validate the rest of the configuration supplied.
sl@0
   569
	if (chunkBufConfig.iBufferSizeInBytes<=0)
sl@0
   570
		return(KErrArgument);
sl@0
   571
sl@0
   572
	if (iDirection==ESoundDirRecord)
sl@0
   573
		{
sl@0
   574
		// If this is a record channel then the size of each buffer must comply with the PDD contraints.
sl@0
   575
		if (iCaps.iRequestMinSize && chunkBufConfig.iBufferSizeInBytes%iCaps.iRequestMinSize)
sl@0
   576
			return(KErrArgument);
sl@0
   577
		}	
sl@0
   578
sl@0
   579
	//Allocate space for the buffer list 
sl@0
   580
	NKern::ThreadEnterCS();
sl@0
   581
	r=ReAllocBufferConfigInfo(chunkBufConfig.iNumBuffers);
sl@0
   582
	NKern::ThreadLeaveCS();
sl@0
   583
	if (r!=KErrNone)
sl@0
   584
		return(r);
sl@0
   585
sl@0
   586
	//__KTRACE_OPT(KSOUND1, Kern::Printf("DSoundScLdd::PreSetBufferChunkCreateOrOpen - cfg %x size %x",iBufConfig,iBufConfigSize));
sl@0
   587
sl@0
   588
	// copy all data into the buffer list 
sl@0
   589
	kumemget(iBufConfig, configData, iBufConfigSize);
sl@0
   590
sl@0
   591
	return(r);
sl@0
   592
	}
sl@0
   593
sl@0
   594
/**
sl@0
   595
PreProcess a SetSoundConfig on this logical channel
sl@0
   596
Called in the context of the client thread.
sl@0
   597
This is synchronous so only need one copy of the data on the kernel-side.
sl@0
   598
sl@0
   599
@param aMsg  The message to process.
sl@0
   600
sl@0
   601
@return KErrNone if the parameters are validated and request structure populated. Otherwise a system-wide error.
sl@0
   602
*/ 
sl@0
   603
TInt DSoundScLdd::PreSetSoundConfig(TMessageBase* aMsg)
sl@0
   604
	{
sl@0
   605
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd::PreSetSoundConfig"));
sl@0
   606
sl@0
   607
	TThreadMessage* m=(TThreadMessage*)aMsg;
sl@0
   608
sl@0
   609
	TPtr8 localPtr((TUint8*)&iTempSoundConfig, sizeof(TCurrentSoundFormatV02));
sl@0
   610
sl@0
   611
	Kern::KUDesGet(localPtr,*(const TDesC8*)m->Ptr0());
sl@0
   612
sl@0
   613
	//__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd::PreSetSoundConfig chan %x rate %x enc %x form %x",
sl@0
   614
	//	iTempSoundConfig.iChannels,iTempSoundConfig.iRate,iTempSoundConfig.iEncoding,iTempSoundConfig.iDataFormat));
sl@0
   615
sl@0
   616
	// Check that it is compatible with this sound device.
sl@0
   617
	TInt r=ValidateConfig(iTempSoundConfig);
sl@0
   618
	
sl@0
   619
	return(r);
sl@0
   620
	}
sl@0
   621
sl@0
   622
/**
sl@0
   623
Processes a message for this logical channel.
sl@0
   624
This function is called in the context of a DFC thread.
sl@0
   625
@param aMsg The message to process.
sl@0
   626
	        The iValue member of this distinguishes the message type:
sl@0
   627
	          iValue==ECloseMsg: channel close message.
sl@0
   628
	          iValue==KMaxTInt: a 'DoCancel' message
sl@0
   629
	          iValue>=0: a 'DoControl' message with function number equal to iValue
sl@0
   630
	          iValue<0: a 'DoRequest' message with function number equal to ~iValue
sl@0
   631
*/
sl@0
   632
void DSoundScLdd::HandleMsg(TMessageBase* aMsg)
sl@0
   633
	{
sl@0
   634
#ifdef _DEBUG
sl@0
   635
#ifdef TEST_WITH_PAGING_CACHE_FLUSHES
sl@0
   636
	Kern::SetRealtimeState(ERealtimeStateOn);  
sl@0
   637
	Kern::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0);
sl@0
   638
#endif
sl@0
   639
#endif
sl@0
   640
sl@0
   641
	TThreadMessage& m=*(TThreadMessage*)aMsg;
sl@0
   642
    TInt id=m.iValue;
sl@0
   643
//	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd::HandleMsg(%d)",id));
sl@0
   644
    
sl@0
   645
	if (id==(TInt)ECloseMsg)
sl@0
   646
		{
sl@0
   647
		// Channel close.
sl@0
   648
		Shutdown();
sl@0
   649
		m.Complete(KErrNone,EFalse);
sl@0
   650
		return;
sl@0
   651
		}
sl@0
   652
    else if (id==KMaxTInt)
sl@0
   653
		{
sl@0
   654
		// DoCancel
sl@0
   655
		DoCancel(m.Int0());
sl@0
   656
		m.Complete(KErrNone,ETrue);
sl@0
   657
		return;
sl@0
   658
		}
sl@0
   659
    else if (id<0)
sl@0
   660
		{
sl@0
   661
		// DoRequest
sl@0
   662
		TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
sl@0
   663
		TInt r=DoRequest(~id,pS,m.Ptr1(),m.Ptr2(),m.Client());
sl@0
   664
		if (r!=KErrNone)
sl@0
   665
			{
sl@0
   666
			iClientRequests[~id]->SetStatus(pS);
sl@0
   667
			CompleteRequest(m.Client(),NULL,r,iClientRequests[~id]);
sl@0
   668
			}
sl@0
   669
		m.Complete(KErrNone,ETrue);
sl@0
   670
		}
sl@0
   671
    else
sl@0
   672
		{
sl@0
   673
		// DoControl
sl@0
   674
		TInt r=DoControl(id,m.Ptr0(),m.Ptr1(),m.Client());
sl@0
   675
		m.Complete(r,ETrue);
sl@0
   676
		}
sl@0
   677
	}
sl@0
   678
sl@0
   679
/**
sl@0
   680
Process a synchronous 'DoControl' request.
sl@0
   681
@param aFunction The request number.
sl@0
   682
@param a1 The first request argument.
sl@0
   683
@param a2 The second request argument.
sl@0
   684
@param aThread The client thread which issued the request.
sl@0
   685
@return The result of the request.
sl@0
   686
*/
sl@0
   687
TInt DSoundScLdd::DoControl(TInt aFunction,TAny* a1,TAny* a2,DThread* aThread)
sl@0
   688
	{
sl@0
   689
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd::DoControl(%d)",aFunction));
sl@0
   690
	
sl@0
   691
	TInt r=KErrNotSupported;
sl@0
   692
	switch (aFunction)
sl@0
   693
		{
sl@0
   694
		case RSoundSc::EControlGetCaps:
sl@0
   695
			{
sl@0
   696
			// Return the capabilities for this device. Read this from the PDD and 
sl@0
   697
			// then write it to the client. 
sl@0
   698
			TSoundFormatsSupportedV02Buf caps;
sl@0
   699
			Pdd()->Caps(caps);
sl@0
   700
			Kern::InfoCopy(*((TDes8*)a1),caps);
sl@0
   701
			r=KErrNone;
sl@0
   702
			break;	
sl@0
   703
			}
sl@0
   704
		case RSoundSc::EControlGetAudioFormat:
sl@0
   705
			{
sl@0
   706
			// Write the current audio configuration back to the client.
sl@0
   707
			TPtrC8 ptr((const TUint8*)&iSoundConfig,sizeof(iSoundConfig));
sl@0
   708
			Kern::InfoCopy(*((TDes8*)a1),ptr);
sl@0
   709
			r=KErrNone;
sl@0
   710
			break;	
sl@0
   711
			}
sl@0
   712
		case RSoundSc::EMsgControlSetAudioFormat:
sl@0
   713
			{
sl@0
   714
			if (iState==EOpen || iState==EConfigured || iPlayEofTimerActive)
sl@0
   715
				{
sl@0
   716
				// If the play EOF timer is active then it is OK to change the audio configuration - but we
sl@0
   717
				// need to bring the PDD out of transfer mode first.
sl@0
   718
				if (iPlayEofTimerActive)
sl@0
   719
					{
sl@0
   720
					CancelPlayEofTimer();
sl@0
   721
					Pdd()->StopTransfer();
sl@0
   722
					}
sl@0
   723
				
sl@0
   724
				r=SetSoundConfig(); 
sl@0
   725
				if (r==KErrNone && (iSoundConfigFlags&KSndScVolumeIsSetup) && iBufConfig)
sl@0
   726
					iState=EConfigured;
sl@0
   727
				}		
sl@0
   728
			else
sl@0
   729
				r=KErrInUse;
sl@0
   730
			break;
sl@0
   731
			}
sl@0
   732
		case RSoundSc::EControlGetBufConfig:
sl@0
   733
			if (iBufConfig)
sl@0
   734
				{
sl@0
   735
				// Write the buffer config to the client.
sl@0
   736
				TPtrC8 ptr((const TUint8*)iBufConfig,iBufConfigSize);
sl@0
   737
				Kern::InfoCopy(*((TDes8*)a1),ptr);
sl@0
   738
				r=KErrNone;	
sl@0
   739
				}	
sl@0
   740
			break;
sl@0
   741
		case RSoundSc::EMsgControlSetBufChunkCreate:
sl@0
   742
			{
sl@0
   743
			if (iState==EOpen || iState==EConfigured || iPlayEofTimerActive)
sl@0
   744
				{
sl@0
   745
				// Need to be in critical section while deleting an exisiting config and creating a new one
sl@0
   746
				NKern::ThreadEnterCS();
sl@0
   747
				r=SetBufferConfig(aThread);
sl@0
   748
				NKern::ThreadLeaveCS();
sl@0
   749
				if (r==KErrNone && (iSoundConfigFlags&KSndScSoundConfigIsSetup) && (iSoundConfigFlags&KSndScVolumeIsSetup))
sl@0
   750
					iState=EConfigured; 		
sl@0
   751
				}
sl@0
   752
			else
sl@0
   753
				r=KErrInUse;
sl@0
   754
			break;
sl@0
   755
			}
sl@0
   756
		case RSoundSc::EMsgControlSetBufChunkOpen:
sl@0
   757
			{
sl@0
   758
			if (iState==EOpen || iState==EConfigured || iPlayEofTimerActive)
sl@0
   759
				{
sl@0
   760
				// Need to be in critical section while deleting an exisiting config and creating a new one
sl@0
   761
				NKern::ThreadEnterCS();
sl@0
   762
				r=SetBufferConfig((TInt)a2,aThread);
sl@0
   763
				NKern::ThreadLeaveCS();
sl@0
   764
				if (r==KErrNone && (iSoundConfigFlags&KSndScSoundConfigIsSetup) && (iSoundConfigFlags&KSndScVolumeIsSetup))
sl@0
   765
					iState=EConfigured; 		
sl@0
   766
				}
sl@0
   767
			else
sl@0
   768
				r=KErrInUse;
sl@0
   769
			break;
sl@0
   770
			}
sl@0
   771
		case RSoundSc::EControlGetVolume:
sl@0
   772
			r=iVolume;
sl@0
   773
			break;
sl@0
   774
		case RSoundSc::EMsgControlSetVolume:
sl@0
   775
			{
sl@0
   776
			r=SetVolume((TInt)a1);
sl@0
   777
			if (r==KErrNone && iState==EOpen && (iSoundConfigFlags&KSndScSoundConfigIsSetup) && iBufConfig)
sl@0
   778
				iState=EConfigured;
sl@0
   779
			break;	
sl@0
   780
			}
sl@0
   781
		case RSoundSc::EMsgControlCancelSpecific:
sl@0
   782
			{
sl@0
   783
			if (iDirection==ESoundDirPlayback)
sl@0
   784
				{
sl@0
   785
				// Don't try to cancel a play transfer that has already started - let it complete in its own time.
sl@0
   786
				TSoundScPlayRequest* req=(TSoundScPlayRequest*)iReqQueue->Find((TRequestStatus*)a1);
sl@0
   787
				if (req && req->iTf.iTfState==TSndScTransfer::ETfNotStarted)
sl@0
   788
					{
sl@0
   789
					iReqQueue->Remove(req);
sl@0
   790
					CompleteRequest(req->iOwningThread,NULL,KErrCancel,req->iClientRequest);
sl@0
   791
					iReqQueue->Free(req);
sl@0
   792
					}
sl@0
   793
				}
sl@0
   794
			else
sl@0
   795
				{
sl@0
   796
				// Need to aquire the buffer/request list mutex when removing record requests - RecordData() runs in
sl@0
   797
				// client thread context and this may access the queue. Record requests a treated differently to play
sl@0
   798
				// requests and you don't have to worry about record requests already being in progress.
sl@0
   799
				NKern::FMWait(&iMutex);
sl@0
   800
				TSoundScRequest* req=iReqQueue->Find((TRequestStatus*)a1);
sl@0
   801
				if (req)
sl@0
   802
					{
sl@0
   803
					iReqQueue->Remove(req);
sl@0
   804
					DThread* thread=req->iOwningThread;				// Take a copy before we free it.
sl@0
   805
					TClientRequest* clreq=req->iClientRequest;		// Take a copy before we free it.
sl@0
   806
					NKern::FMSignal(&iMutex);
sl@0
   807
					iReqQueue->Free(req);
sl@0
   808
					CompleteRequest(thread,NULL,KErrCancel,clreq);
sl@0
   809
					}
sl@0
   810
				else
sl@0
   811
					NKern::FMSignal(&iMutex);	
sl@0
   812
				}
sl@0
   813
			r=KErrNone;	
sl@0
   814
			break;	
sl@0
   815
			}
sl@0
   816
		case RSoundSc::EControlBytesTransferred:
sl@0
   817
			r=iBytesTransferred;
sl@0
   818
			break;
sl@0
   819
		case RSoundSc::EControlResetBytesTransferred:
sl@0
   820
			iBytesTransferred=0;
sl@0
   821
			r=KErrNone;	
sl@0
   822
			break;
sl@0
   823
		case RSoundSc::EMsgControlPause:
sl@0
   824
			if (iState==EActive)
sl@0
   825
				{
sl@0
   826
				// Have to update the status early here because a record PDD may call us back with RecordCallback() in
sl@0
   827
				// handling PauseTransfer() - to complete a partially filled buffer.  
sl@0
   828
				iState=EPaused;
sl@0
   829
				iCompletesWhilePausedCount=0;		
sl@0
   830
				r=Pdd()->PauseTransfer();
sl@0
   831
				if (r!=KErrNone)
sl@0
   832
					iState=EActive;
sl@0
   833
				else if (iDirection==ESoundDirRecord)
sl@0
   834
					{
sl@0
   835
					// For record, complete any pending record requests that are still outstanding following PauseTransfer().
sl@0
   836
					iReqQueue->CompleteAll(KErrCancel);	
sl@0
   837
					}
sl@0
   838
				}
sl@0
   839
			else
sl@0
   840
				r=KErrNotReady;	
sl@0
   841
			break;
sl@0
   842
		case RSoundSc::EMsgControlResume:
sl@0
   843
			if (iState==EPaused)
sl@0
   844
				{
sl@0
   845
				r=Pdd()->ResumeTransfer();
sl@0
   846
				if (r==KErrNone && iDirection==ESoundDirRecord)
sl@0
   847
					r=StartNextRecordTransfers();
sl@0
   848
				if (r==KErrNone)
sl@0
   849
					iState=EActive;	// Successfully resumed transfer - update the status.
sl@0
   850
				}
sl@0
   851
			else
sl@0
   852
				r=KErrNotReady;	
sl@0
   853
			break;
sl@0
   854
		case RSoundSc::EControlReleaseBuffer:
sl@0
   855
			if (iDirection==ESoundDirRecord)
sl@0
   856
				r=ReleaseBuffer((TInt)a1);
sl@0
   857
			break; 
sl@0
   858
		case RSoundSc::EMsgControlCustomConfig:
sl@0
   859
			r=CustomConfig((TInt)a1,a2);
sl@0
   860
			break;
sl@0
   861
		case RSoundSc::EControlTimePlayed:
sl@0
   862
			if (iDirection==ESoundDirPlayback)
sl@0
   863
				{
sl@0
   864
				TInt64 time=0;
sl@0
   865
				r=Pdd()->TimeTransferred(time,iState);
sl@0
   866
				TPtrC8 timePtr((TUint8*)&time,sizeof(TInt64));
sl@0
   867
				Kern::ThreadDesWrite(aThread,a1,timePtr,0,KTruncateToMaxLength,NULL);
sl@0
   868
				}
sl@0
   869
			else
sl@0
   870
				r=KErrNotSupported;
sl@0
   871
			break;
sl@0
   872
		case RSoundSc::EControlTimeRecorded:
sl@0
   873
			if (iDirection==ESoundDirRecord)
sl@0
   874
				{
sl@0
   875
				TInt64 time=0;
sl@0
   876
				r=Pdd()->TimeTransferred(time,iState);
sl@0
   877
				TPtrC8 timePtr((TUint8*)&time,sizeof(TInt64));
sl@0
   878
				Kern::ThreadDesWrite(aThread,a1,timePtr,0,KTruncateToMaxLength,NULL);
sl@0
   879
				}
sl@0
   880
			else
sl@0
   881
				r=KErrNotSupported;
sl@0
   882
			break;
sl@0
   883
		}
sl@0
   884
		
sl@0
   885
	__KTRACE_OPT(KSOUND1, Kern::Printf("<DSoundScLdd::DoControl - %d",r));
sl@0
   886
	return(r);
sl@0
   887
	}
sl@0
   888
sl@0
   889
/**
sl@0
   890
Process an asynchronous 'DoRequest' request.
sl@0
   891
@param aFunction The request number.
sl@0
   892
@param aStatus A pointer to the TRequestStatus.
sl@0
   893
@param a1 The first request argument.
sl@0
   894
@param a2 The second request argument.
sl@0
   895
@param aThread The client thread which issued the request.
sl@0
   896
@return The result of the request.
sl@0
   897
*/
sl@0
   898
TInt DSoundScLdd::DoRequest(TInt aFunction, TRequestStatus* aStatus, TAny* a1, TAny* /*a2*/,DThread* aThread)
sl@0
   899
	{
sl@0
   900
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd::DoRequest(%d)",aFunction));
sl@0
   901
	
sl@0
   902
	// Open a reference on the client thread while the request is pending so it's control block can't disappear until this driver has finished with it.
sl@0
   903
	TInt r=aThread->Open();
sl@0
   904
	__ASSERT_ALWAYS(r==KErrNone,Kern::Fault(KSoundLddPanic,__LINE__));
sl@0
   905
#ifdef _DEBUG
sl@0
   906
	__e32_atomic_add_ord32(&iThreadOpenCount, 1);
sl@0
   907
#endif		
sl@0
   908
sl@0
   909
	r=KErrNotSupported;
sl@0
   910
	switch (aFunction)
sl@0
   911
		{
sl@0
   912
		case RSoundSc::EMsgRequestPlayData:
sl@0
   913
			{
sl@0
   914
			if (iDirection==ESoundDirPlayback)
sl@0
   915
				{
sl@0
   916
				if (iState==EOpen)
sl@0
   917
					{
sl@0
   918
					// Not yet fully configured - maybe we can use the default settings.
sl@0
   919
					r=KErrNone;
sl@0
   920
					if (!iBufConfig)
sl@0
   921
						r=KErrNotReady;	// Can't guess a default buffer configuration.
sl@0
   922
					else
sl@0
   923
						{
sl@0
   924
						if (!(iSoundConfigFlags&KSndScSoundConfigIsSetup))
sl@0
   925
							r=DoSetSoundConfig(iSoundConfig);	// Apply default sound configuration.
sl@0
   926
						if (r==KErrNone && !(iSoundConfigFlags&KSndScVolumeIsSetup))
sl@0
   927
							r=SetVolume(iVolume);				// Apply default volume level
sl@0
   928
						}
sl@0
   929
					if (r!=KErrNone)
sl@0
   930
						break;
sl@0
   931
					else
sl@0
   932
						iState=EConfigured;		
sl@0
   933
					}
sl@0
   934
					
sl@0
   935
				if (iState==EConfigured || iState==EActive || iState==EPaused)
sl@0
   936
					{
sl@0
   937
					r=PlayData(aStatus, (TSoundScPlayRequest*)a1,aThread);
sl@0
   938
					}
sl@0
   939
				else
sl@0
   940
					r=KErrNotReady;
sl@0
   941
				}
sl@0
   942
			break;
sl@0
   943
			}
sl@0
   944
		case RSoundSc::ERequestRecordData:
sl@0
   945
			if (iDirection==ESoundDirRecord)
sl@0
   946
				{
sl@0
   947
				// Check if the device has been configured yet
sl@0
   948
				if (iState==EOpen)
sl@0
   949
					{
sl@0
   950
					// Not yet fully configured - maybe we can use the default settings.
sl@0
   951
					r=KErrNone;
sl@0
   952
					if (!iBufConfig)
sl@0
   953
						r=KErrNotReady;	// Can't guess a default buffer configuration.
sl@0
   954
					else
sl@0
   955
						{
sl@0
   956
						if (!(iSoundConfigFlags&KSndScSoundConfigIsSetup))
sl@0
   957
							r=DoSetSoundConfig(iSoundConfig);	// Apply default sound configuration.
sl@0
   958
						if (r==KErrNone && !(iSoundConfigFlags&KSndScVolumeIsSetup))
sl@0
   959
							r=SetVolume(iVolume);				// Apply default volume level
sl@0
   960
						}
sl@0
   961
					if (r!=KErrNone)
sl@0
   962
						break;
sl@0
   963
					else
sl@0
   964
						iState=EConfigured;		
sl@0
   965
					}
sl@0
   966
				// Check if we need to start recording
sl@0
   967
				if (iState==EConfigured)
sl@0
   968
					{
sl@0
   969
					r=StartRecord();
sl@0
   970
					if (r!=KErrNone)
sl@0
   971
						break;
sl@0
   972
					else
sl@0
   973
						iState=EActive;
sl@0
   974
					}	
sl@0
   975
				
sl@0
   976
				// State must be either active or paused so process the record request as appropriate for these states.
sl@0
   977
				r=RecordData(aStatus,(TInt*)a1,aThread);
sl@0
   978
				}
sl@0
   979
			break;
sl@0
   980
		case RSoundSc::ERequestNotifyChangeOfHwConfig:
sl@0
   981
			{
sl@0
   982
			// Check if this device can detect changes in its hardware configuration.
sl@0
   983
			if (iCaps.iHwConfigNotificationSupport)
sl@0
   984
				{
sl@0
   985
				r=KErrNone;
sl@0
   986
				if (!iNotifyChangeOfHwClientRequest->IsReady())
sl@0
   987
					{
sl@0
   988
					iChangeOfHwConfigThread=aThread;
sl@0
   989
					iNotifyChangeOfHwClientRequest->SetDestPtr((TBool*)a1);
sl@0
   990
					r = iNotifyChangeOfHwClientRequest->SetStatus(aStatus);
sl@0
   991
					}
sl@0
   992
				else
sl@0
   993
					r=KErrInUse;
sl@0
   994
				}
sl@0
   995
			else
sl@0
   996
				r=KErrNotSupported;	
sl@0
   997
			break;
sl@0
   998
			}
sl@0
   999
		}
sl@0
  1000
		
sl@0
  1001
	__KTRACE_OPT(KSOUND1, Kern::Printf("<DSoundScLdd::DoRequest - %d",r));
sl@0
  1002
	return(r);
sl@0
  1003
	}
sl@0
  1004
sl@0
  1005
/**
sl@0
  1006
Process the cancelling of asynchronous requests.
sl@0
  1007
@param aMask A mask indicating which requests need to be cancelled.
sl@0
  1008
@return The result of the cancel.
sl@0
  1009
*/
sl@0
  1010
TInt DSoundScLdd::DoCancel(TUint aMask)
sl@0
  1011
	{
sl@0
  1012
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd::DoCancel(%08x)",aMask));
sl@0
  1013
sl@0
  1014
	if (aMask&(1<<RSoundSc::EMsgRequestPlayData))
sl@0
  1015
		{
sl@0
  1016
		Pdd()->StopTransfer();
sl@0
  1017
		iReqQueue->CompleteAll(KErrCancel);					// Cancel any outstanding play requests
sl@0
  1018
		if ((iState==EActive)||(iState==EPaused))
sl@0
  1019
			iState=EConfigured;
sl@0
  1020
		}
sl@0
  1021
	if (aMask&(1<<RSoundSc::ERequestRecordData))
sl@0
  1022
		{
sl@0
  1023
		Pdd()->StopTransfer();
sl@0
  1024
		iReqQueue->CompleteAll(KErrCancel,&iMutex);		// Cancel any outstanding record requests
sl@0
  1025
		if ((iState==EActive)||(iState==EPaused))
sl@0
  1026
			iState=EConfigured;
sl@0
  1027
		}
sl@0
  1028
	if (aMask&(1<<RSoundSc::ERequestNotifyChangeOfHwConfig))
sl@0
  1029
		{
sl@0
  1030
		// Complete any pending hardware change notifier with KErrCancel.
sl@0
  1031
		if (iNotifyChangeOfHwClientRequest->IsReady())
sl@0
  1032
			CompleteRequest(iChangeOfHwConfigThread,NULL,KErrCancel,iNotifyChangeOfHwClientRequest); 
sl@0
  1033
		}		
sl@0
  1034
	return(KErrNone);
sl@0
  1035
	}
sl@0
  1036
sl@0
  1037
/**
sl@0
  1038
Set the current buffer configuration - creating a shared chunk.
sl@0
  1039
@param aBufferConfigBuf A packaged TSharedChunkBufConfigBase derived object holding the buffer configuration settings of
sl@0
  1040
	the shared chunk required.
sl@0
  1041
@param aThread The client thread which has requested to own the chunk.
sl@0
  1042
@return A handle to the shared chunk for the owning thread (a value >0), if successful;
sl@0
  1043
        otherwise one of the other system wide error codes, (a value <0).
sl@0
  1044
@pre The thread must be in a critical section. 
sl@0
  1045
*/	
sl@0
  1046
TInt DSoundScLdd::SetBufferConfig(DThread* aThread)
sl@0
  1047
	{
sl@0
  1048
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd:SetBufferConfig"));
sl@0
  1049
	
sl@0
  1050
	TInt r(KErrNone);
sl@0
  1051
sl@0
  1052
	// Delete any existing buffers and the shared chunk.
sl@0
  1053
	if (iBufManager)
sl@0
  1054
		{
sl@0
  1055
		delete iBufManager;
sl@0
  1056
		iBufManager=NULL;
sl@0
  1057
		} 
sl@0
  1058
						
sl@0
  1059
	// If a handle to the shared chunk was created, close it, using the handle of the thread on which
sl@0
  1060
	// it was created, in case a different thread is now calling us
sl@0
  1061
	if (iChunkHandle>0)
sl@0
  1062
		{
sl@0
  1063
		Kern::CloseHandle(iChunkHandleThread,iChunkHandle);
sl@0
  1064
		iChunkHandle=0;
sl@0
  1065
		}
sl@0
  1066
sl@0
  1067
	// Create the shared chunk, then create buffer objects for the committed buffers within it. This is
sl@0
  1068
	// done by creating a buffer manager - create the apppropraiate version according to the audio direction.
sl@0
  1069
	if (iDirection==ESoundDirPlayback)
sl@0
  1070
		iBufManager=new DBufferManager(this);
sl@0
  1071
	else
sl@0
  1072
		iBufManager=new DRecordBufferManager(this);
sl@0
  1073
	if (!iBufManager)
sl@0
  1074
		return(KErrNoMemory);
sl@0
  1075
	r=iBufManager->Create(iBufConfig);
sl@0
  1076
	if (r!=KErrNone)
sl@0
  1077
		{
sl@0
  1078
		delete iBufManager;
sl@0
  1079
		iBufManager=NULL;
sl@0
  1080
		return(r);
sl@0
  1081
		} 
sl@0
  1082
	
sl@0
  1083
	// Create handle to the shared chunk for the owning thread.
sl@0
  1084
	r=Kern::MakeHandleAndOpen(aThread,iBufManager->iChunk);
sl@0
  1085
sl@0
  1086
	// And save the the chunk and thread handles for later.  Normally the chunk handle will be closed when the chunk
sl@0
  1087
	// is closed, but if the chunk is re-allocated then it will need to be closed before re-allocation.
sl@0
  1088
	iChunkHandle=r;
sl@0
  1089
	iChunkHandleThread=aThread;
sl@0
  1090
sl@0
  1091
	return(r);
sl@0
  1092
	}	
sl@0
  1093
sl@0
  1094
/**
sl@0
  1095
Set the current buffer configuration - using an existing shared chunk.
sl@0
  1096
@param aBufferConfigBuf A packaged TSharedChunkBufConfigBase derived object holding the buffer configuration settings of
sl@0
  1097
	the shared chunk supplied.
sl@0
  1098
@param aChunkHandle A handle for the shared chunk supplied by the client.
sl@0
  1099
@param aThread The thread in which the given handle is valid.
sl@0
  1100
@return KErrNone if successful, otherwise one of the other system wide error codes.
sl@0
  1101
@pre The thread must be in a critical section. 
sl@0
  1102
*/	
sl@0
  1103
TInt DSoundScLdd::SetBufferConfig(TInt aChunkHandle,DThread* aThread)
sl@0
  1104
	{
sl@0
  1105
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd:SetBufferConfig(Handle-%d)",aChunkHandle));
sl@0
  1106
sl@0
  1107
	TInt r(KErrNone);
sl@0
  1108
sl@0
  1109
	// Delete any existing buffers and the shared chunk.
sl@0
  1110
	if (iBufManager)
sl@0
  1111
		{
sl@0
  1112
		delete iBufManager;
sl@0
  1113
		iBufManager=NULL;
sl@0
  1114
		} 
sl@0
  1115
	
sl@0
  1116
	// Open the shared chunk supplied and create buffer objects for the committed buffers within it. This is
sl@0
  1117
	// done by creating a buffer manager - create the apppropraiate version according to the audio direction.
sl@0
  1118
	if (iDirection==ESoundDirPlayback)
sl@0
  1119
		iBufManager=new DBufferManager(this);
sl@0
  1120
	else
sl@0
  1121
		iBufManager=new DRecordBufferManager(this);
sl@0
  1122
	if (!iBufManager)
sl@0
  1123
		return(KErrNoMemory);
sl@0
  1124
	r=iBufManager->Create(*iBufConfig,aChunkHandle,aThread);
sl@0
  1125
	if (r!=KErrNone)
sl@0
  1126
		{
sl@0
  1127
		delete iBufManager;
sl@0
  1128
		iBufManager=NULL;
sl@0
  1129
		} 
sl@0
  1130
	return(r);
sl@0
  1131
	}	
sl@0
  1132
sl@0
  1133
/**
sl@0
  1134
Set the current audio format configuration.
sl@0
  1135
@param aSoundConfigBuf A packaged sound configuration object holding the new audio configuration settings to be used.
sl@0
  1136
@param aThread The client thread which contains the sound configuration object.
sl@0
  1137
@return KErrNone if successful, otherwise one of the other system wide error codes.
sl@0
  1138
*/
sl@0
  1139
TInt DSoundScLdd::SetSoundConfig()
sl@0
  1140
	{
sl@0
  1141
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd:SetSoundConfig"));
sl@0
  1142
	
sl@0
  1143
	TInt r=DoSetSoundConfig(iTempSoundConfig);
sl@0
  1144
sl@0
  1145
	__KTRACE_OPT(KSOUND1, Kern::Printf("<DSoundScLdd::SetSoundConfig - %d",KErrNone));
sl@0
  1146
	return(r);
sl@0
  1147
	}
sl@0
  1148
sl@0
  1149
/**
sl@0
  1150
Apply a new audio format configuration.
sl@0
  1151
@param aSoundConfig A reference to a sound configuration object holding the new audio configuration settings to be applied.
sl@0
  1152
@return KErrNone if successful, otherwise one of the other system wide error codes.
sl@0
  1153
*/	
sl@0
  1154
TInt DSoundScLdd::DoSetSoundConfig(const TCurrentSoundFormatV02& aSoundConfig)
sl@0
  1155
	{
sl@0
  1156
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd:DoSetSoundConfig"));
sl@0
  1157
		
sl@0
  1158
	// We're about to replace any previous configuration - so set the
sl@0
  1159
	// status back to un-configured in case we don't succeed with the new one.
sl@0
  1160
	iSoundConfigFlags&=~KSndScSoundConfigIsSetup;
sl@0
  1161
	
sl@0
  1162
	// Call the PDD to change the hardware configuration according to the new specification.
sl@0
  1163
	// Pass it as a descriptor - to support future changes to the config structure.
sl@0
  1164
	TPtrC8 ptr((TUint8*)&aSoundConfig,sizeof(aSoundConfig));
sl@0
  1165
	TInt r=Pdd()->SetConfig(ptr);
sl@0
  1166
	if (r!=KErrNone)
sl@0
  1167
		return(r);
sl@0
  1168
	
sl@0
  1169
	// Setting up the new play configuration has succeeded so save the new configuration.
sl@0
  1170
	iSoundConfig=aSoundConfig;
sl@0
  1171
	iSoundConfigFlags|=KSndScSoundConfigIsSetup;
sl@0
  1172
	
sl@0
  1173
	// For some devices, the maximum transfer length supported will vary according to the configuration.
sl@0
  1174
	if (iBufManager)
sl@0
  1175
		iBufManager->iMaxTransferLen=Pdd()->MaxTransferLen();
sl@0
  1176
	
sl@0
  1177
	return(r);
sl@0
  1178
	}	
sl@0
  1179
	
sl@0
  1180
/**
sl@0
  1181
Set the current play volume or record level.
sl@0
  1182
@param aVolume The play volume / record level to be set - a value in the range 0 to 255. The value 255 equates to
sl@0
  1183
	the maximum volume and each value below this equates to a 0.5dB step below it.
sl@0
  1184
@return KErrNone if successful, otherwise one of the other system wide error codes.	
sl@0
  1185
*/
sl@0
  1186
TInt DSoundScLdd::SetVolume(TInt aVolume)
sl@0
  1187
	{
sl@0
  1188
	TInt r;
sl@0
  1189
	// Check if the volume specified is in range.
sl@0
  1190
	if (aVolume>=0 && aVolume<=255)
sl@0
  1191
		{
sl@0
  1192
		// Check if we need to change it.
sl@0
  1193
		if (!(iSoundConfigFlags&KSndScVolumeIsSetup) || aVolume!=iVolume)
sl@0
  1194
			{
sl@0
  1195
			// We're about to replace any previous volume setting - so set the
sl@0
  1196
			// status back to un-set in case we don't succeed with the new setting.
sl@0
  1197
			iSoundConfigFlags&=~KSndScVolumeIsSetup;
sl@0
  1198
			
sl@0
  1199
			r=Pdd()->SetVolume(aVolume);
sl@0
  1200
			if (r==KErrNone)
sl@0
  1201
				{
sl@0
  1202
				iVolume=aVolume;
sl@0
  1203
				iSoundConfigFlags|=KSndScVolumeIsSetup;
sl@0
  1204
				}
sl@0
  1205
			}
sl@0
  1206
		else
sl@0
  1207
			r=KErrNone;	
sl@0
  1208
		}
sl@0
  1209
	else
sl@0
  1210
		r=KErrArgument;	
sl@0
  1211
	__KTRACE_OPT(KSOUND1, Kern::Printf("<DSoundScLdd::SetVolume(%d) - %d",aVolume,r));
sl@0
  1212
	return(r);
sl@0
  1213
	}
sl@0
  1214
	
sl@0
  1215
/**
sl@0
  1216
Handle a play request from the client.
sl@0
  1217
@param aStatus The request status to be signalled when the play request is complete.
sl@0
  1218
@param aChunkOffset Offset from the beginning of the play chunk for the start of data to be played.
sl@0
  1219
@param aLength The number of bytes of data to be played.
sl@0
  1220
@param aFlags The play request flags which were supplied by the client for this request.
sl@0
  1221
@param aThread The client thread which issued the request and which supplied the request status.
sl@0
  1222
@return KErrNone if successful;
sl@0
  1223
        KErrArgument if the offset or length arguments are not fully contained within a buffer or don't meet the
sl@0
  1224
        	alignment contraints of the PDD;
sl@0
  1225
        KErrNoMemory if a memory error was ecountered in the handling of this request.
sl@0
  1226
        otherwise one of the other system-wide error codes.
sl@0
  1227
*/
sl@0
  1228
TInt DSoundScLdd::PlayData(TRequestStatus* aStatus,TSoundScPlayRequest* aRequest,DThread* aThread)
sl@0
  1229
	{
sl@0
  1230
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd:PlayData(off:%x len:%d)",aRequest->iTf.GetStartOffset(),aRequest->iTf.GetNotStartedLen()));
sl@0
  1231
	
sl@0
  1232
	// Purge the region of the play chunk concerned.
sl@0
  1233
	iBufManager->FlushData(aRequest->iTf.GetStartOffset(),aRequest->iTf.GetNotStartedLen(),DBufferManager::EFlushBeforeDmaWrite);
sl@0
  1234
	
sl@0
  1235
	
sl@0
  1236
	TInt r(KErrNone);
sl@0
  1237
sl@0
  1238
	// finalise the request data here
sl@0
  1239
	r = aRequest->iClientRequest->SetStatus(aStatus);
sl@0
  1240
	if (r!=KErrNone)
sl@0
  1241
		return(r);
sl@0
  1242
sl@0
  1243
	aRequest->iOwningThread = aThread;
sl@0
  1244
sl@0
  1245
sl@0
  1246
	// Check whether we have started the codec yet.
sl@0
  1247
	CancelPlayEofTimer();
sl@0
  1248
	if (iState==EConfigured)
sl@0
  1249
		{
sl@0
  1250
		r=Pdd()->StartTransfer();
sl@0
  1251
	
sl@0
  1252
		// Test settings - only possible in debug mode. Test handling of an error returned from the PDD for StartTransfer().
sl@0
  1253
#ifdef _DEBUG	
sl@0
  1254
		if (iTestSettings & KSoundScTest_StartTransferError)
sl@0
  1255
			{
sl@0
  1256
			iTestSettings&=(~KSoundScTest_StartTransferError);
sl@0
  1257
			r=KErrTimedOut;
sl@0
  1258
			// Any time that StartTransfer() is called on the PDD it must have a matching StopTransfer() before
sl@0
  1259
			// it is called again
sl@0
  1260
			Pdd()->StopTransfer();
sl@0
  1261
			}
sl@0
  1262
#endif
sl@0
  1263
		}
sl@0
  1264
	
sl@0
  1265
	if (r==KErrNone)
sl@0
  1266
		{
sl@0
  1267
		// No further error is possible at this stage so add the request to the queue.
sl@0
  1268
		iReqQueue->Add(aRequest);
sl@0
  1269
		
sl@0
  1270
		if (iState!=EPaused)
sl@0
  1271
			{
sl@0
  1272
			iState=EActive;	
sl@0
  1273
			StartNextPlayTransfers(); // Queue as many transfer requests on the PDD as it can accept.
sl@0
  1274
			}
sl@0
  1275
		}
sl@0
  1276
	else
sl@0
  1277
		iReqQueue->Free(aRequest);	// Return the unused request object	
sl@0
  1278
	
sl@0
  1279
	return(r);
sl@0
  1280
	}
sl@0
  1281
	
sl@0
  1282
/**
sl@0
  1283
@publishedPartner
sl@0
  1284
@prototype
sl@0
  1285
sl@0
  1286
Called from the PDD each time it has completed a data transfer from a play buffer.  This function must be called
sl@0
  1287
in the context of the DFC thread used for processing requests.
sl@0
  1288
The function performed here is to check whether the entire transfer for the current request is now complete. Also to
sl@0
  1289
queue further requests on the PDD which should now have the capability to accept more transfers. If the current
sl@0
  1290
request is complete then we signal completion to the client.
sl@0
  1291
@param aTransferID A value provided by the LDD when it initiated the transfer allowing the transfer fragment to be 
sl@0
  1292
	uniquely identified.
sl@0
  1293
@param aTransferResult The result of the transfer being completed: KErrNone if successful, otherwise one of the other
sl@0
  1294
	system wide error codes.
sl@0
  1295
@param aBytesPlayed The number of bytes played from the play buffer.	
sl@0
  1296
*/
sl@0
  1297
void DSoundScLdd::PlayCallback(TUint aTransferID,TInt aTransferResult,TInt aBytesPlayed)
sl@0
  1298
	{
sl@0
  1299
#ifdef _DEBUG
sl@0
  1300
#ifdef TEST_WITH_PAGING_CACHE_FLUSHES
sl@0
  1301
	Kern::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0);
sl@0
  1302
#endif
sl@0
  1303
#endif
sl@0
  1304
	// Test settings - only possible in debug mode.
sl@0
  1305
#ifdef _DEBUG	
sl@0
  1306
	if (iTestSettings & KSoundScTest_TransferDataError)
sl@0
  1307
		{
sl@0
  1308
		iTestSettings&=(~KSoundScTest_TransferDataError);
sl@0
  1309
		aTransferResult=KErrTimedOut;
sl@0
  1310
		}
sl@0
  1311
#endif
sl@0
  1312
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd::PlayCallback(ID:%xH,Len:%d) - %d",aTransferID,aBytesPlayed,aTransferResult));		
sl@0
  1313
	
sl@0
  1314
	// The PDD has completed transfering a fragment. Find the associated request from its ID
sl@0
  1315
	TBool isNextToComplete;
sl@0
  1316
	TSoundScPlayRequest* req=((TSoundScPlayRequestQueue*)iReqQueue)->Find(aTransferID,isNextToComplete);
sl@0
  1317
	
sl@0
  1318
	// Check if this is a fragment from an earlier request which failed - which we should ignore. This is the case if the request cannot be found 
sl@0
  1319
	// (because it was already completed back to client) or if the request status is already set as 'done'. 
sl@0
  1320
	if (req && req->iTf.iTfState!=TSndScTransfer::ETfDone)
sl@0
  1321
		{
sl@0
  1322
		__ASSERT_DEBUG(req->iTf.iTfState!=TSndScTransfer::ETfNotStarted,Kern::Fault(KSoundLddPanic,__LINE__));
sl@0
  1323
		
sl@0
  1324
		// Update the count of bytes played.
sl@0
  1325
		iBytesTransferred+=aBytesPlayed;
sl@0
  1326
		
sl@0
  1327
		if (aTransferResult!=KErrNone)
sl@0
  1328
			{
sl@0
  1329
			// Transfer failed - immediately mark the request as being complete.
sl@0
  1330
			req->SetFail(aTransferResult);
sl@0
  1331
			}
sl@0
  1332
		else
sl@0
  1333
			req->UpdateProgress(aBytesPlayed);	// Transfer successful so update the progress of the request.
sl@0
  1334
									
sl@0
  1335
		// If we have just played an entire request and the PDD has not signalled it ahead of any earlier unfinished ones then complete it back to client.
sl@0
  1336
		if (req->iTf.iTfState==TSndScTransfer::ETfDone && isNextToComplete)
sl@0
  1337
			CompleteAllDonePlayRequests(req);
sl@0
  1338
		}
sl@0
  1339
	
sl@0
  1340
	// PDD should now have the capacity to accept another transfer so queue as many transfers
sl@0
  1341
	// on it as it can accept.
sl@0
  1342
	StartNextPlayTransfers();
sl@0
  1343
		
sl@0
  1344
	
sl@0
  1345
	return;
sl@0
  1346
	}
sl@0
  1347
	
sl@0
  1348
/**
sl@0
  1349
This function checks whether there are any outstanding play requests. While there are, it breaks these down into
sl@0
  1350
transfers sizes which are compatible with the PDD and then repeatedly attempts to queue these data transfers on the
sl@0
  1351
PDD until it indicates that it can accept no more for the moment.
sl@0
  1352
@post Data transfer may be stopped in the PDD and the operating state of the channel moved back to EConfigured.
sl@0
  1353
*/
sl@0
  1354
void DSoundScLdd::StartNextPlayTransfers()
sl@0
  1355
	{
sl@0
  1356
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd::StartNextPlayTransfers"));
sl@0
  1357
	
sl@0
  1358
	// Queue as many transfers on the PDD as it can accept.
sl@0
  1359
	TSoundScPlayRequest* req;
sl@0
  1360
	TInt r=KErrNone;
sl@0
  1361
	while (r==KErrNone && (req=((TSoundScPlayRequestQueue*)iReqQueue)->NextRequestForTransfer())!=NULL)
sl@0
  1362
		{
sl@0
  1363
		TInt pos=req->iTf.GetStartOffset();
sl@0
  1364
		TPhysAddr physAddr;
sl@0
  1365
		TInt len=req->iTf.iAudioBuffer->GetFragmentLength(pos,req->iTf.GetNotStartedLen(),physAddr);
sl@0
  1366
		if (len>0)
sl@0
  1367
			{
sl@0
  1368
			r=Pdd()->TransferData(req->iTf.iId,(iBufManager->iChunkBase+pos),physAddr,len);
sl@0
  1369
			__KTRACE_OPT(KSOUND1, Kern::Printf("<PDD:TransferData(off:%x len:%d) - %d",pos,len,r));
sl@0
  1370
			if (r==KErrNone)
sl@0
  1371
				req->iTf.SetStarted(len);	// Successfully queued a transfer - update the request status.
sl@0
  1372
			else if (r!=KErrNotReady)
sl@0
  1373
				{
sl@0
  1374
				// Transfer error from PDD, fail the request straight away. (Might not be the one at the head of queue).	
sl@0
  1375
				CompletePlayRequest(req,r);
sl@0
  1376
				}	
sl@0
  1377
			}
sl@0
  1378
		else
sl@0
  1379
			{
sl@0
  1380
			// This can only be a zero length play request - just complete it straight away
sl@0
  1381
			CompletePlayRequest(req,KErrNone);	
sl@0
  1382
			}
sl@0
  1383
		} 
sl@0
  1384
	return;	
sl@0
  1385
	}
sl@0
  1386
sl@0
  1387
/**
sl@0
  1388
Complete a client play request back to the client and remove it from the request queue.
sl@0
  1389
@param aReq A pointer to the play request object to be completed.
sl@0
  1390
@post Data transfer may be stopped in the PDD and the operating state of the channel moved back to EConfigured.
sl@0
  1391
*/	
sl@0
  1392
void DSoundScLdd::DoCompletePlayRequest(TSoundScPlayRequest* aReq)
sl@0
  1393
	{
sl@0
  1394
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd::DoCompletePlayRequest(%x) - %d",aReq,aReq->iCompletionReason));
sl@0
  1395
	
sl@0
  1396
	iReqQueue->Remove(aReq);
sl@0
  1397
	
sl@0
  1398
	// If the request queue is now empty then turn off the codec
sl@0
  1399
	if (iReqQueue->IsEmpty())
sl@0
  1400
		{
sl@0
  1401
#ifdef USE_PLAY_EOF_TIMER
sl@0
  1402
		StartPlayEofTimer();
sl@0
  1403
#else
sl@0
  1404
		Pdd()->StopTransfer();
sl@0
  1405
		iState=EConfigured;
sl@0
  1406
#endif						
sl@0
  1407
		// This is an underflow situation.
sl@0
  1408
		if (aReq->iCompletionReason==KErrNone && aReq->iFlags!=KSndFlagLastSample)
sl@0
  1409
			aReq->iCompletionReason=KErrUnderflow;
sl@0
  1410
		}
sl@0
  1411
		
sl@0
  1412
	CompleteRequest(aReq->iOwningThread,NULL,aReq->iCompletionReason,aReq->iClientRequest);
sl@0
  1413
	iReqQueue->Free(aReq);
sl@0
  1414
	return;	
sl@0
  1415
	}
sl@0
  1416
sl@0
  1417
/**
sl@0
  1418
Complete one or more play requests. This function completes the play request specified. It also completes any other play 
sl@0
  1419
requests which immediately follow the one specified in the play request queue and for which transfer has been completed by the PDD.
sl@0
  1420
@param aReq A pointer to the play request object to be completed.
sl@0
  1421
@post Data transfer may be stopped in the PDD and the operating state of the channel moved back to EConfigured.
sl@0
  1422
*/		
sl@0
  1423
void DSoundScLdd::CompleteAllDonePlayRequests(TSoundScPlayRequest* aReq)
sl@0
  1424
	{
sl@0
  1425
	TSoundScPlayRequest* nextReq=aReq;
sl@0
  1426
	TSoundScPlayRequest* req;
sl@0
  1427
	do 
sl@0
  1428
		{
sl@0
  1429
		req=nextReq;
sl@0
  1430
		nextReq=(TSoundScPlayRequest*)req->iNext;
sl@0
  1431
		DoCompletePlayRequest(req);
sl@0
  1432
		}
sl@0
  1433
	while (!iReqQueue->IsAnchor(nextReq) && nextReq->iTf.iTfState==TSndScTransfer::ETfDone);
sl@0
  1434
	return;	
sl@0
  1435
	}	
sl@0
  1436
		
sl@0
  1437
/**
sl@0
  1438
Start the audio device recording data.
sl@0
  1439
@return KErrNone if successful, otherwise one of the other system wide error codes.
sl@0
  1440
*/
sl@0
  1441
TInt DSoundScLdd::StartRecord()
sl@0
  1442
	{
sl@0
  1443
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd::StartRecord"));
sl@0
  1444
		
sl@0
  1445
	// Reset all the audio buffer lists 
sl@0
  1446
	NKern::FMWait(&iMutex); 		// Acquire the buffer/request list mutex.
sl@0
  1447
	((DRecordBufferManager*)iBufManager)->Reset();
sl@0
  1448
	NKern::FMSignal(&iMutex); 		// Release the buffer/request list mutex.
sl@0
  1449
	
sl@0
  1450
	// Reset the transfer status for the current and pending record buffers.
sl@0
  1451
	TAudioBuffer* buf=((DRecordBufferManager*)iBufManager)->GetCurrentRecordBuffer();
sl@0
  1452
	iCurrentRecBufTf.Init((TUint)buf,buf->iChunkOffset,buf->iSize,buf);		// Use pointer to record buffer as unique ID
sl@0
  1453
	buf=((DRecordBufferManager*)iBufManager)->GetNextRecordBuffer();
sl@0
  1454
	iNextRecBufTf.Init((TUint)buf,buf->iChunkOffset,buf->iSize,buf);		// Use pointer to record buffer as unique ID
sl@0
  1455
	
sl@0
  1456
	// Call the PDD to prepare the hardware for recording.
sl@0
  1457
	TInt r=Pdd()->StartTransfer();
sl@0
  1458
	
sl@0
  1459
	// Test settings - only possible in debug mode. Test handling of an error returned from the PDD for StartTransfer().
sl@0
  1460
#ifdef _DEBUG	
sl@0
  1461
	if (iTestSettings & KSoundScTest_StartTransferError)
sl@0
  1462
		{
sl@0
  1463
		iTestSettings&=(~KSoundScTest_StartTransferError);
sl@0
  1464
		r=KErrTimedOut;
sl@0
  1465
		}
sl@0
  1466
#endif		
sl@0
  1467
	
sl@0
  1468
	// Initiate data transfer into the first record buffer(s).	
sl@0
  1469
	if (r==KErrNone)
sl@0
  1470
		r=StartNextRecordTransfers();
sl@0
  1471
	return(r);	
sl@0
  1472
	}
sl@0
  1473
	
sl@0
  1474
/**
sl@0
  1475
Handle a record request from the client once data transfer has been intiated.
sl@0
  1476
@param aStatus The request status to be signalled when the record request is complete. If the request is successful
sl@0
  1477
   then this is set to the offset within the shared chunk where the record data resides. Alternatively, if an error 
sl@0
  1478
   occurs, it will be set to one of the system wide error values.
sl@0
  1479
@param aLengthPtr A pointer to a TInt object in client memory. On completion, the number of bytes successfully
sl@0
  1480
   recorded are written to this object.
sl@0
  1481
@param aThread The client thread which issued the request and which supplied the request status.    	
sl@0
  1482
@return KErrNone if successful;
sl@0
  1483
		KErrInUse: if the client needs to free up record buffers before further record requests can be accepted;
sl@0
  1484
		KErrCancel: if the driver is in paused mode and there are no complete or partially full buffers to return.
sl@0
  1485
        otherwise one of the other system-wide error codes.
sl@0
  1486
*/
sl@0
  1487
TInt DSoundScLdd::RecordData(TRequestStatus* aStatus,TInt* aLengthPtr,DThread* aThread)
sl@0
  1488
	{
sl@0
  1489
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd:RecordData"));
sl@0
  1490
	
sl@0
  1491
	TInt r=KErrNone;
sl@0
  1492
sl@0
  1493
	NKern::FMWait(&iMutex); 		// Acquire the buffer/request list mutex.
sl@0
  1494
	 
sl@0
  1495
	// Check if we have had an overflow since the last record request was completed.
sl@0
  1496
	if (((DRecordBufferManager*)iBufManager)->iBufOverflow)
sl@0
  1497
		{
sl@0
  1498
		((DRecordBufferManager*)iBufManager)->iBufOverflow=EFalse;
sl@0
  1499
		NKern::FMSignal(&iMutex); 	// Release the buffer/request list mutex.	
sl@0
  1500
		return(KErrOverflow);	
sl@0
  1501
		}
sl@0
  1502
	
sl@0
  1503
	// See if there is a buffer already available.
sl@0
  1504
	TAudioBuffer* buf=((DRecordBufferManager*)iBufManager)->GetBufferForClient();
sl@0
  1505
	if (buf)
sl@0
  1506
		{
sl@0
  1507
		// There is an buffer available already - complete the request returning the offset of the buffer to the client.
sl@0
  1508
		NKern::FMSignal(&iMutex); 	// Release the buffer/request list mutex.
sl@0
  1509
		
sl@0
  1510
		r=buf->iResult;
sl@0
  1511
sl@0
  1512
		if (r==KErrNone)
sl@0
  1513
			{
sl@0
  1514
			kumemput(aLengthPtr,&buf->iBytesAdded,sizeof(TInt));
sl@0
  1515
			// Only complete if successful here. Errors will be completed on returning from this method.
sl@0
  1516
			CompleteRequest(aThread,aStatus,(buf->iChunkOffset));
sl@0
  1517
			}
sl@0
  1518
		return(r);	
sl@0
  1519
		}
sl@0
  1520
	
sl@0
  1521
	// If we are paused and there was no un-read data to return to the client then return KErrCancel to prompt them to resume.
sl@0
  1522
	if (iState==EPaused)
sl@0
  1523
		{
sl@0
  1524
		NKern::FMSignal(&iMutex); 	// Release the buffer/request list mutex.
sl@0
  1525
		return(KErrCancel);
sl@0
  1526
		}			
sl@0
  1527
		
sl@0
  1528
	// The buffer 'completed' list is empty. If the buffer 'free' list is empty too then the client needs
sl@0
  1529
	// to free some buffers up - return an error.
sl@0
  1530
	if (((DRecordBufferManager*)iBufManager)->iFreeBufferQ.IsEmpty())
sl@0
  1531
		{
sl@0
  1532
		NKern::FMSignal(&iMutex); 	// Release the buffer/request list mutex.	
sl@0
  1533
		return(KErrInUse);	
sl@0
  1534
		}	
sl@0
  1535
	
sl@0
  1536
	// Acquire a new request object and add it to the queue of pending requests. The request will be completed
sl@0
  1537
	// from the PDD and the DFC thread when a buffer is available.
sl@0
  1538
	NKern::FMSignal(&iMutex);
sl@0
  1539
	TSoundScRequest* req=iReqQueue->NextFree();
sl@0
  1540
	NKern::FMWait(&iMutex);
sl@0
  1541
	if (req)
sl@0
  1542
		{
sl@0
  1543
		r=req->iClientRequest->SetStatus(aStatus);
sl@0
  1544
		req->iOwningThread=aThread;
sl@0
  1545
		((TClientDataRequest<TInt>*)req->iClientRequest)->SetDestPtr((TInt*)aLengthPtr);
sl@0
  1546
		// Add the request to the queue
sl@0
  1547
		iReqQueue->Add(req);		
sl@0
  1548
		}
sl@0
  1549
	else
sl@0
  1550
		r=KErrGeneral;				// Must have exceeded KMaxSndScRequestsPending.
sl@0
  1551
	NKern::FMSignal(&iMutex); 		// Release the buffer/request list mutex.
sl@0
  1552
	
sl@0
  1553
	return(r);
sl@0
  1554
	}
sl@0
  1555
sl@0
  1556
/**
sl@0
  1557
Release a buffer which was being used by client.
sl@0
  1558
@param aChunkOffset The chunk offset corresponding to the buffer to be freed.
sl@0
  1559
@return KErrNone if successful;
sl@0
  1560
		KErrNotFound if no 'in use' buffer had the specified chunk offset.
sl@0
  1561
		KErrNotReady if the channel is not configured (either for audio or its buffer config).
sl@0
  1562
*/
sl@0
  1563
TInt DSoundScLdd::ReleaseBuffer(TInt aChunkOffset)	
sl@0
  1564
	{
sl@0
  1565
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd::ReleaseBuffer(%x)",aChunkOffset));
sl@0
  1566
sl@0
  1567
	TInt r=KErrNotReady;
sl@0
  1568
	if (iState!=EOpen && iBufManager)
sl@0
  1569
		{
sl@0
  1570
		TAudioBuffer* buf=NULL;
sl@0
  1571
		NKern::FMWait(&iMutex); 		// Acquire the buffer/request list mutex.
sl@0
  1572
		buf=((DRecordBufferManager*)iBufManager)->ReleaseBuffer(aChunkOffset);
sl@0
  1573
		NKern::FMSignal(&iMutex); 		// Release the buffer/request list mutex.	
sl@0
  1574
		if (buf)
sl@0
  1575
			{
sl@0
  1576
			buf->Flush(DBufferManager::EFlushBeforeDmaRead);
sl@0
  1577
			r=KErrNone;
sl@0
  1578
			}
sl@0
  1579
		else
sl@0
  1580
			r=KErrNotFound;
sl@0
  1581
		}
sl@0
  1582
	return(r);
sl@0
  1583
	}
sl@0
  1584
	
sl@0
  1585
/**
sl@0
  1586
Handle a custom configuration request.
sl@0
  1587
@param aFunction A number identifying the request.
sl@0
  1588
@param aParam A 32-bit value passed to the driver. Its meaning depends on the request.
sl@0
  1589
@return KErrNone if successful, otherwise one of the other system wide error codes.
sl@0
  1590
*/	
sl@0
  1591
TInt DSoundScLdd::CustomConfig(TInt aFunction,TAny* aParam)
sl@0
  1592
	{
sl@0
  1593
	
sl@0
  1594
	TInt r;
sl@0
  1595
	if (aFunction>KSndCustomConfigMaxReserved)
sl@0
  1596
		r=Pdd()->CustomConfig(aFunction,aParam);
sl@0
  1597
	else
sl@0
  1598
		{
sl@0
  1599
		r=KErrNotSupported;
sl@0
  1600
#ifdef _DEBUG		
sl@0
  1601
		switch (aFunction)
sl@0
  1602
			{
sl@0
  1603
			case KSndCustom_ForceHwConfigNotifSupported:
sl@0
  1604
				iCaps.iHwConfigNotificationSupport=ETrue;
sl@0
  1605
				r=KErrNone;
sl@0
  1606
				break;
sl@0
  1607
			case KSndCustom_CompleteChangeOfHwConfig:
sl@0
  1608
				NotifyChangeOfHwConfigCallback((TBool)aParam);
sl@0
  1609
				r=KErrNone;
sl@0
  1610
				break;
sl@0
  1611
			case KSndCustom_ForceStartTransferError:
sl@0
  1612
				iTestSettings|=KSoundScTest_StartTransferError;
sl@0
  1613
				r=KErrNone;
sl@0
  1614
				break;
sl@0
  1615
			case KSndCustom_ForceTransferDataError:
sl@0
  1616
				iTestSettings|=KSoundScTest_TransferDataError;
sl@0
  1617
				r=KErrNone;
sl@0
  1618
				break;
sl@0
  1619
			case KSndCustom_ForceTransferTimeout:
sl@0
  1620
				iTestSettings|=KSoundScTest_TransferTimeout;
sl@0
  1621
				r=KErrNone;
sl@0
  1622
				break;
sl@0
  1623
			}
sl@0
  1624
#endif	
sl@0
  1625
		}
sl@0
  1626
	return(r);	
sl@0
  1627
	}
sl@0
  1628
	
sl@0
  1629
/**
sl@0
  1630
@publishedPartner
sl@0
  1631
@prototype
sl@0
  1632
 
sl@0
  1633
Called from the PDD each time it has completed a data transfer into the current record buffer. 
sl@0
  1634
The function performed here is to check whether the transfer into the current buffer is now complete. Also to queue
sl@0
  1635
further requests on the PDD which should now have the capability to accept more transfers. If transfer into the
sl@0
  1636
current buffer is now complete then we need to update the buffer lists and possibly complete a request back the client.
sl@0
  1637
While recording hasn't been paused and no error has occured then this completed buffer ought to be full. However, when
sl@0
  1638
recording has just been paused, the PDD can also call this function to complete a partially filled record buffer. In fact
sl@0
  1639
in some circumstances, pausing may result in the PDD calling this function where it turns out that no data has been
sl@0
  1640
recorded into this buffer. In this case we don't want to signal a null transfer back to the client.
sl@0
  1641
@param aTransferID A value provided by the LDD when it initiated the transfer allowing the transfer fragment to be 
sl@0
  1642
	uniquely identified.
sl@0
  1643
@param aTransferResult The result of the transfer being completed: KErrNone if successful, otherwise one of the other
sl@0
  1644
	system wide error codes.
sl@0
  1645
@param aBytesRecorded The number of bytes recorded into the record buffer.	
sl@0
  1646
*/
sl@0
  1647
void DSoundScLdd::RecordCallback(TUint aTransferID,TInt aTransferResult,TInt aBytesRecorded)
sl@0
  1648
	{
sl@0
  1649
#ifdef _DEBUG
sl@0
  1650
#ifdef TEST_WITH_PAGING_CACHE_FLUSHES
sl@0
  1651
	Kern::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0);
sl@0
  1652
#endif
sl@0
  1653
#endif
sl@0
  1654
sl@0
  1655
#ifdef _DEBUG	
sl@0
  1656
	// Test settings - only possible in debug mode.
sl@0
  1657
	if (iTestSettings & KSoundScTest_TransferDataError)
sl@0
  1658
		{
sl@0
  1659
		iTestSettings&=(~KSoundScTest_TransferDataError);
sl@0
  1660
		aTransferResult=KErrTimedOut;
sl@0
  1661
		}
sl@0
  1662
#endif
sl@0
  1663
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd::RecordCallback(ID:%xH,Len:%d) - %d (iCurrentRecBufTf.iTfState %d)",aTransferID,aBytesRecorded,aTransferResult, iCurrentRecBufTf.iTfState));
sl@0
  1664
	
sl@0
  1665
	// If the transfer fragment is not for the current record buffer and were not paused then ignore it. Either the PDD
sl@0
  1666
	// has got very confused or more likely its a trailing fragment from an earlier buffer we have already failed. If 
sl@0
  1667
	// we're paused, the PDD doesn't need to bother with a transfer ID, we assume its for the current buffer.
sl@0
  1668
	if (iCurrentRecBufTf.iTfState != TSndScTransfer::ETfDone &&
sl@0
  1669
		(aTransferID==iCurrentRecBufTf.iId || (aTransferID == 0 && iState==EPaused)))
sl@0
  1670
		{
sl@0
  1671
		// Update the count of bytes recorded.
sl@0
  1672
		iBytesTransferred+=aBytesRecorded;
sl@0
  1673
		
sl@0
  1674
		// Update the transfer status of the current buffer.
sl@0
  1675
		if (aTransferResult!=KErrNone)
sl@0
  1676
			{
sl@0
  1677
			// Transfer failed. Mark the buffer as being complete.
sl@0
  1678
			iCurrentRecBufTf.iTfState=TSndScTransfer::ETfDone;	
sl@0
  1679
			}
sl@0
  1680
		else	
sl@0
  1681
			iCurrentRecBufTf.SetCompleted(aBytesRecorded); // Transfer successful so update the progress.
sl@0
  1682
		
sl@0
  1683
		// Check if this is the PDD completing a fragment due to record being paused. In this situation we only allow the
sl@0
  1684
		// PDD to complete one fragment.	
sl@0
  1685
		TAudioBuffer* buf;
sl@0
  1686
		if (iState==EPaused && ++iCompletesWhilePausedCount<2)
sl@0
  1687
			{
sl@0
  1688
			// Complete (i.e. abort) the transfer to the current buffer.
sl@0
  1689
			iCurrentRecBufTf.iTfState=TSndScTransfer::ETfDone; 
sl@0
  1690
			
sl@0
  1691
			// Reset the transfer status for the pending record buffer. This will be switched to the current buffer later
sl@0
  1692
			// in this function - ready for when record is resumed.
sl@0
  1693
			buf=((DRecordBufferManager*)iBufManager)->GetNextRecordBuffer();
sl@0
  1694
			iNextRecBufTf.Init((TUint)buf,buf->iChunkOffset,buf->iSize,buf);		// Use pointer to record buffer as unique ID
sl@0
  1695
			}	
sl@0
  1696
		
sl@0
  1697
		// Check if we have just completed the transfer into the current buffer.	
sl@0
  1698
		if (iCurrentRecBufTf.iTfState==TSndScTransfer::ETfDone)
sl@0
  1699
			HandleCurrentRecordBufferDone(aTransferResult);
sl@0
  1700
		}
sl@0
  1701
			
sl@0
  1702
	// If we're not paused then the PDD should now have the capacity to accept another transfer so queue as many
sl@0
  1703
	// transfers on it as it can accept.
sl@0
  1704
	if (iState==EActive)
sl@0
  1705
		{
sl@0
  1706
#ifdef _DEBUG	
sl@0
  1707
		// Test settings - only possible in debug mode. Test LDD being slow servicing transfer completes from PDD. Disabled.
sl@0
  1708
/*		if (iTestSettings & KSoundScTest_TransferTimeout)
sl@0
  1709
			{
sl@0
  1710
			iTestSettings&=(~KSoundScTest_TransferTimeout);
sl@0
  1711
			Kern::NanoWait(500000000); // Pause for 0.5 second
sl@0
  1712
			} */
sl@0
  1713
#endif
sl@0
  1714
		TInt r=StartNextRecordTransfers();
sl@0
  1715
		if (r!=KErrNone)
sl@0
  1716
			{
sl@0
  1717
			// Problem starting the next transfer. That's fairly serious so complete all pending record requests and 
sl@0
  1718
			// stop recording.
sl@0
  1719
			Pdd()->StopTransfer();
sl@0
  1720
			iReqQueue->CompleteAll(r,&iMutex);
sl@0
  1721
			iState=EConfigured;
sl@0
  1722
			}
sl@0
  1723
		}
sl@0
  1724
	return;
sl@0
  1725
	}
sl@0
  1726
	
sl@0
  1727
/** Perform the necessary processing required when transfer into the current buffer is complete. This involves updating
sl@0
  1728
the buffer lists and possibly complete a request back the client.
sl@0
  1729
@param aTransferResult The result of the transfer being completed: KErrNone if successful, otherwise one of the other
sl@0
  1730
	system wide error codes.
sl@0
  1731
*/
sl@0
  1732
void DSoundScLdd::HandleCurrentRecordBufferDone(TInt aTransferResult)
sl@0
  1733
	{
sl@0
  1734
	TAudioBuffer* buf;
sl@0
  1735
	
sl@0
  1736
	// Flush the buffer before acquiring the mutex.
sl@0
  1737
	buf=((DRecordBufferManager*)iBufManager)->GetCurrentRecordBuffer();
sl@0
  1738
	buf->Flush(DBufferManager::EFlushAfterDmaRead);
sl@0
  1739
	
sl@0
  1740
	NKern::FMWait(&iMutex); 		// Acquire the buffer/request list mutex.
sl@0
  1741
	
sl@0
  1742
	// Update the buffer list (by either adding the current buffer to the completed list or the free list).
sl@0
  1743
	TInt bytesRecorded=iCurrentRecBufTf.GetLengthTransferred();
sl@0
  1744
	((DRecordBufferManager*)iBufManager)->SetBufferFilled(bytesRecorded,aTransferResult);
sl@0
  1745
    
sl@0
  1746
    // The pending buffer now becomes the current one and we need to get a new pending one.
sl@0
  1747
    iCurrentRecBufTf=iNextRecBufTf;
sl@0
  1748
    buf=((DRecordBufferManager*)iBufManager)->GetNextRecordBuffer();
sl@0
  1749
    iNextRecBufTf.Init((TUint)buf,buf->iChunkOffset,buf->iSize,buf);	// Use pointer to record buffer as unique ID
sl@0
  1750
    
sl@0
  1751
    // Check if there is a client record request pending.
sl@0
  1752
    if (!iReqQueue->IsEmpty())
sl@0
  1753
    	{
sl@0
  1754
    	// A record request is pending. Check if we have had an overflow since the last record request was completed.
sl@0
  1755
    	if (((DRecordBufferManager*)iBufManager)->iBufOverflow)
sl@0
  1756
    		{
sl@0
  1757
    		TSoundScRequest* req=iReqQueue->Remove();
sl@0
  1758
    		DThread* thread=req->iOwningThread;					// Take a copy before we free it.
sl@0
  1759
			TClientRequest* clreq = req->iClientRequest;		// Take a copy before we free it.
sl@0
  1760
    		((DRecordBufferManager*)iBufManager)->iBufOverflow=EFalse;
sl@0
  1761
			NKern::FMSignal(&iMutex); 							// Release the buffer/request list mutex.
sl@0
  1762
			iReqQueue->Free(req);
sl@0
  1763
    		CompleteRequest(thread,NULL,KErrOverflow,clreq);			// Complete the request.
sl@0
  1764
    		}
sl@0
  1765
    	else
sl@0
  1766
    		{
sl@0
  1767
	    	// Check there really is a buffer available. (There's no guarentee the one just completed hasn't
sl@0
  1768
	    	// immediately been queued again: if the client has too many 'in-use' or the one completed was a NULL
sl@0
  1769
	    	// transfer due to pausing).
sl@0
  1770
			TAudioBuffer* buf=((DRecordBufferManager*)iBufManager)->GetBufferForClient();
sl@0
  1771
			if (buf)
sl@0
  1772
				{
sl@0
  1773
				// There still a buffer available so complete the request.
sl@0
  1774
				TSoundScRequest* req=iReqQueue->Remove();
sl@0
  1775
				DThread* thread=req->iOwningThread;							// Take a copy before we free it.
sl@0
  1776
				TClientRequest* clreq = req->iClientRequest;				// Take a copy before we free it.
sl@0
  1777
				NKern::FMSignal(&iMutex); 	// Release the buffer/request list mutex.
sl@0
  1778
				iReqQueue->Free(req);
sl@0
  1779
				if (buf->iResult==KErrNone)
sl@0
  1780
					{
sl@0
  1781
					((TClientDataRequest<TInt>*)clreq)->Data() = buf->iBytesAdded;
sl@0
  1782
					CompleteRequest(thread,NULL,buf->iChunkOffset,clreq);					// Complete the request.	
sl@0
  1783
					}
sl@0
  1784
				else	
sl@0
  1785
					CompleteRequest(thread,NULL,buf->iResult,clreq);				// Complete the request.
sl@0
  1786
				}
sl@0
  1787
			else
sl@0
  1788
				NKern::FMSignal(&iMutex); 	// Release the buffer/request list mutex.	
sl@0
  1789
    		}
sl@0
  1790
    	}
sl@0
  1791
    else
sl@0
  1792
    	NKern::FMSignal(&iMutex); 	// Release the buffer/request list mutex.	
sl@0
  1793
	}
sl@0
  1794
	
sl@0
  1795
/**
sl@0
  1796
This function starts the next record data transfer. It starts with the current record buffer - checking whether all of
sl@0
  1797
this has now been transferred or queued for transfer. If not it breaks this down into transfers sizes which are
sl@0
  1798
compatible with the PDD and then repeatedly attempts to queue these on the PDD until the PDF indicates that it can
sl@0
  1799
accept no more transfers for the moment. If the record buffer is fully started in this way and the PDD still has the
sl@0
  1800
capacity to accept more transfers then it moves on to start the pending record buffer.
sl@0
  1801
@return Normally KErrNone unless the PDD incurs an error while attempting to start a new transfer.
sl@0
  1802
*/
sl@0
  1803
TInt DSoundScLdd::StartNextRecordTransfers()
sl@0
  1804
	{
sl@0
  1805
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd::StartNextRecordTransfers"));
sl@0
  1806
	
sl@0
  1807
	// First start with the current record buffer - keep queuing transfers either until this buffer is
sl@0
  1808
	// fully started or until the PDD can accept no more transfers.
sl@0
  1809
	TInt r=KErrNone;
sl@0
  1810
	while (r==KErrNone && iCurrentRecBufTf.iTfState<TSndScTransfer::ETfFullyStarted)
sl@0
  1811
		{
sl@0
  1812
		TInt pos=iCurrentRecBufTf.GetStartOffset();
sl@0
  1813
		TPhysAddr physAddr;
sl@0
  1814
		TInt len=iCurrentRecBufTf.iAudioBuffer->GetFragmentLength(pos,iCurrentRecBufTf.GetNotStartedLen(),physAddr);
sl@0
  1815
		
sl@0
  1816
		r=Pdd()->TransferData(iCurrentRecBufTf.iId,(iBufManager->iChunkBase+pos),physAddr,len);
sl@0
  1817
		__KTRACE_OPT(KSOUND1, Kern::Printf("<PDD:TransferData(off:%x len:%d) A - %d",pos,len,r));
sl@0
  1818
		if (r==KErrNone)
sl@0
  1819
			iCurrentRecBufTf.SetStarted(len);	// Successfully queued a transfer - update the status.
sl@0
  1820
		}
sl@0
  1821
	
sl@0
  1822
	// Either the current record transfer is now fully started, or the PDD can accept no more transfers
sl@0
  1823
	// If the PDD can still accept more transfers then move on to the next record buffer - again, keep queuing
sl@0
  1824
	// transfers either until this buffer is fully started or until the PDD can accept no more.
sl@0
  1825
	while (r==KErrNone && iNextRecBufTf.iTfState<TSndScTransfer::ETfFullyStarted)
sl@0
  1826
		{
sl@0
  1827
		TInt pos=iNextRecBufTf.GetStartOffset();
sl@0
  1828
		TPhysAddr physAddr;
sl@0
  1829
		TInt len=iNextRecBufTf.iAudioBuffer->GetFragmentLength(pos,iNextRecBufTf.GetNotStartedLen(),physAddr);
sl@0
  1830
		
sl@0
  1831
		r=Pdd()->TransferData(iNextRecBufTf.iId,(iBufManager->iChunkBase+pos),physAddr,len);
sl@0
  1832
		__KTRACE_OPT(KSOUND1, Kern::Printf("<PDD:TransferData(off:%x len:%d) B - %d",pos,len,r));
sl@0
  1833
		if (r==KErrNone)
sl@0
  1834
			iNextRecBufTf.SetStarted(len);	// Successfully queued a transfer - update the status.
sl@0
  1835
		}
sl@0
  1836
	if (r==KErrNotReady)
sl@0
  1837
		r=KErrNone;		// KErrNotReady means the PDD the cannot accept any more requests - this isn't an error.	
sl@0
  1838
	return(r);	
sl@0
  1839
	}	
sl@0
  1840
	
sl@0
  1841
/**
sl@0
  1842
@publishedPartner
sl@0
  1843
@prototype
sl@0
  1844
sl@0
  1845
Called from the PDD each time it detects a change in the hardware configuration of the device.
sl@0
  1846
@param aHeadsetPresent This is set by the PDD to ETrue if a microphone or headset socket is now present or EFalse if 
sl@0
  1847
such a device is not present.
sl@0
  1848
*/
sl@0
  1849
void DSoundScLdd::NotifyChangeOfHwConfigCallback(TBool aHeadsetPresent)
sl@0
  1850
	{
sl@0
  1851
#ifdef _DEBUG
sl@0
  1852
#ifdef TEST_WITH_PAGING_CACHE_FLUSHES 
sl@0
  1853
	Kern::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0);
sl@0
  1854
#endif
sl@0
  1855
#endif
sl@0
  1856
sl@0
  1857
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd::NotifyChangeOfHwConfigCallback(Pres:%d)",aHeadsetPresent));
sl@0
  1858
	
sl@0
  1859
	__ASSERT_DEBUG(iCaps.iHwConfigNotificationSupport,Kern::Fault(KSoundLddPanic,__LINE__));		
sl@0
  1860
	
sl@0
  1861
	if (iNotifyChangeOfHwClientRequest->IsReady())
sl@0
  1862
		{
sl@0
  1863
		iNotifyChangeOfHwClientRequest->Data() = aHeadsetPresent;
sl@0
  1864
		CompleteRequest(iChangeOfHwConfigThread,NULL,KErrNone,iNotifyChangeOfHwClientRequest);	// Complete the request.
sl@0
  1865
		}
sl@0
  1866
	}
sl@0
  1867
	
sl@0
  1868
/**
sl@0
  1869
This function validates that a new sound format configuration is both sensible and supported by this device.
sl@0
  1870
@param aConfig A reference to the new sound format configuration object.
sl@0
  1871
*/	
sl@0
  1872
TInt DSoundScLdd::ValidateConfig(const TCurrentSoundFormatV02& aConfig)
sl@0
  1873
	{
sl@0
  1874
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd::ValidateConfig"));
sl@0
  1875
	
sl@0
  1876
	// Check that the audio channel configuration requested is sensible and supported by this device.
sl@0
  1877
	if (aConfig.iChannels<0) 
sl@0
  1878
		return(KErrNotSupported);
sl@0
  1879
	TInt chans=(aConfig.iChannels-1);
sl@0
  1880
	if (!(iCaps.iChannels & (1<<chans)))
sl@0
  1881
		return(KErrNotSupported);
sl@0
  1882
	
sl@0
  1883
	// Check that the sample rate requested is sensible and supported by this device.
sl@0
  1884
	if (aConfig.iRate<0 || !(iCaps.iRates & (1<<aConfig.iRate)))
sl@0
  1885
		return(KErrNotSupported);
sl@0
  1886
	
sl@0
  1887
	// Check that the encoding format requested is sensible and supported by this device.
sl@0
  1888
	if (aConfig.iEncoding<0 || !(iCaps.iEncodings & (1<<aConfig.iEncoding)))
sl@0
  1889
		return(KErrNotSupported);
sl@0
  1890
	
sl@0
  1891
	// Check that the data format requested is sensible and supported by this device.
sl@0
  1892
	if (aConfig.iDataFormat<0 || !(iCaps.iDataFormats & (1<<aConfig.iDataFormat)))
sl@0
  1893
		return(KErrNotSupported);
sl@0
  1894
		
sl@0
  1895
	__KTRACE_OPT(KSOUND1, Kern::Printf("<DSoundScLdd::ValidateConfig - %d",KErrNone));
sl@0
  1896
	return(KErrNone);
sl@0
  1897
	}
sl@0
  1898
	
sl@0
  1899
/**
sl@0
  1900
Increase or decrease the memory area allocated to hold the current buffer configuration in the play/record chunk.
sl@0
  1901
@param aNumBuffers The number of buffers within the new buffer configuration. This determines the size of the memory
sl@0
  1902
	area required.
sl@0
  1903
@pre The thread must be in a critical section. 
sl@0
  1904
*/
sl@0
  1905
TInt DSoundScLdd::ReAllocBufferConfigInfo(TInt aNumBuffers)
sl@0
  1906
	{
sl@0
  1907
	if (iBufConfig)
sl@0
  1908
		{
sl@0
  1909
		delete iBufConfig;
sl@0
  1910
		iBufConfig=NULL;
sl@0
  1911
		}	 
sl@0
  1912
	
sl@0
  1913
	iBufConfigSize=aNumBuffers*sizeof(TInt);	
sl@0
  1914
	iBufConfigSize+=sizeof(TSharedChunkBufConfigBase);
sl@0
  1915
	iBufConfig=(TSoundSharedChunkBufConfig*)Kern::AllocZ(iBufConfigSize);
sl@0
  1916
	if (!iBufConfig)
sl@0
  1917
		return(KErrNoMemory);	
sl@0
  1918
	
sl@0
  1919
	return(KErrNone);
sl@0
  1920
	}
sl@0
  1921
sl@0
  1922
/**
sl@0
  1923
Start the EOF play timer. A 2 second timer is queued each time the transfer of playback data ceases by the LLD and if it
sl@0
  1924
is allowed to expire, then the PDD is called to release any resources in use for playback transfer. 
sl@0
  1925
*/
sl@0
  1926
void DSoundScLdd::StartPlayEofTimer()
sl@0
  1927
	{
sl@0
  1928
	iEofTimer.Cancel();
sl@0
  1929
	iPlayEofDfc.Cancel();
sl@0
  1930
	iEofTimer.OneShot(NKern::TimerTicks(2000)); // Queue the 2 second EOF timer to stop transfer on the PDD.
sl@0
  1931
	iPlayEofTimerActive=ETrue;
sl@0
  1932
	}
sl@0
  1933
sl@0
  1934
/**
sl@0
  1935
Cancel the EOF play timer. 
sl@0
  1936
*/	
sl@0
  1937
void DSoundScLdd::CancelPlayEofTimer()
sl@0
  1938
	{
sl@0
  1939
	iEofTimer.Cancel();
sl@0
  1940
	iPlayEofDfc.Cancel();
sl@0
  1941
	iPlayEofTimerActive=EFalse;
sl@0
  1942
	}
sl@0
  1943
	
sl@0
  1944
/**
sl@0
  1945
@publishedPartner
sl@0
  1946
@prototype
sl@0
  1947
sl@0
  1948
Returns the buffer configuration of the play/record chunk.
sl@0
  1949
@return A pointer to the current buffer configuration of the play/record chunk.
sl@0
  1950
*/	
sl@0
  1951
TSoundSharedChunkBufConfig* DSoundScLdd::BufConfig()
sl@0
  1952
	{
sl@0
  1953
	return(iBufConfig);
sl@0
  1954
	}
sl@0
  1955
sl@0
  1956
/**
sl@0
  1957
@publishedPartner
sl@0
  1958
@prototype
sl@0
  1959
sl@0
  1960
Returns the address of the start of the play/record chunk.
sl@0
  1961
@return The linear address of the start of the play/record chunk.
sl@0
  1962
*/	
sl@0
  1963
TLinAddr DSoundScLdd::ChunkBase()
sl@0
  1964
	{
sl@0
  1965
	return(iBufManager->iChunkBase);
sl@0
  1966
	}			
sl@0
  1967
		
sl@0
  1968
/**
sl@0
  1969
The ISR to handle the EOF play timer.
sl@0
  1970
@param aChannel A pointer to the sound driver logical channel object.
sl@0
  1971
*/	
sl@0
  1972
void DSoundScLdd::PlayEofTimerExpired(TAny* aChannel)
sl@0
  1973
	{
sl@0
  1974
	DSoundScLdd& drv=*(DSoundScLdd*)aChannel;
sl@0
  1975
	
sl@0
  1976
	drv.iPlayEofDfc.Add();
sl@0
  1977
	}
sl@0
  1978
	
sl@0
  1979
/**
sl@0
  1980
The DFC used to handle the EOF play timer. 
sl@0
  1981
@param aChannel A pointer to the sound driver logical channel object.
sl@0
  1982
*/	
sl@0
  1983
void DSoundScLdd::PlayEofTimerDfc(TAny* aChannel)
sl@0
  1984
	{	
sl@0
  1985
	DSoundScLdd& drv=*(DSoundScLdd*)aChannel;
sl@0
  1986
	
sl@0
  1987
	drv.Pdd()->StopTransfer();
sl@0
  1988
	drv.iState=EConfigured;
sl@0
  1989
	drv.iPlayEofTimerActive=EFalse;
sl@0
  1990
	}				
sl@0
  1991
	
sl@0
  1992
/**
sl@0
  1993
The DFC used to handle power down requests from the power manager before a transition into system
sl@0
  1994
shutdown/standby.
sl@0
  1995
@param aChannel A pointer to the sound driver logical channel object.
sl@0
  1996
*/
sl@0
  1997
void DSoundScLdd::PowerDownDfc(TAny* aChannel)
sl@0
  1998
	{
sl@0
  1999
	DSoundScLdd& drv=*(DSoundScLdd*)aChannel;
sl@0
  2000
	drv.Shutdown();
sl@0
  2001
	drv.iPowerHandler->PowerDownDone();
sl@0
  2002
	}
sl@0
  2003
	
sl@0
  2004
/**
sl@0
  2005
The DFC used to handle power up requests from the power manager following a transition out of system standby.
sl@0
  2006
@param aChannel A pointer to the sound driver logical channel object.
sl@0
  2007
*/	
sl@0
  2008
void DSoundScLdd::PowerUpDfc(TAny* aChannel)
sl@0
  2009
	{
sl@0
  2010
	DSoundScLdd& drv=*(DSoundScLdd*)aChannel;
sl@0
  2011
	
sl@0
  2012
	// Restore the channel to a default state.
sl@0
  2013
	drv.DoCancel(RSoundSc::EAllRequests);
sl@0
  2014
	drv.Pdd()->PowerUp();
sl@0
  2015
	drv.DoSetSoundConfig(drv.iSoundConfig);
sl@0
  2016
	drv.SetVolume(drv.iVolume);			
sl@0
  2017
	drv.iState=(!drv.iBufConfig)?EOpen:EConfigured;
sl@0
  2018
	
sl@0
  2019
	drv.iPowerHandler->PowerUpDone();
sl@0
  2020
	}	
sl@0
  2021
sl@0
  2022
/** 
sl@0
  2023
Complete an asynchronous request back to the client.
sl@0
  2024
@param aThread The client thread which issued the request.
sl@0
  2025
@param aStatus The TRequestStatus instance that will receive the request status code or NULL if aClientRequest used. 
sl@0
  2026
@param aReason The request status code.  
sl@0
  2027
@param aClientRequest The TClientRequest instance that will receive the request status code or NULL if aStatus used. 
sl@0
  2028
@pre The thread must be in a critical section. 
sl@0
  2029
*/
sl@0
  2030
sl@0
  2031
void DSoundScLdd::CompleteRequest(DThread* aThread, TRequestStatus* aStatus, TInt aReason, TClientRequest* aClientRequest)
sl@0
  2032
	{
sl@0
  2033
	if (aClientRequest)
sl@0
  2034
		{
sl@0
  2035
		if (aClientRequest->IsReady())
sl@0
  2036
			{
sl@0
  2037
			Kern::QueueRequestComplete(aThread,aClientRequest,aReason);
sl@0
  2038
			}
sl@0
  2039
		else
sl@0
  2040
			{
sl@0
  2041
			// should always be ready
sl@0
  2042
			__ASSERT_DEBUG(EFalse,Kern::Fault(KSoundLddPanic,__LINE__));
sl@0
  2043
			}
sl@0
  2044
		}
sl@0
  2045
	else if (aStatus)
sl@0
  2046
		{
sl@0
  2047
		Kern::RequestComplete(aStatus,aReason);		// Complete the request back to the client.
sl@0
  2048
		}
sl@0
  2049
	else
sl@0
  2050
		{
sl@0
  2051
		// never get here - either aStatus or aClientRequest must be valid
sl@0
  2052
		__ASSERT_DEBUG(EFalse,Kern::Fault(KSoundLddPanic,__LINE__));
sl@0
  2053
		}
sl@0
  2054
	
sl@0
  2055
	aThread->AsyncClose();	// Asynchronously close our reference on the client thread - don't want to be blocked if this is final reference. 
sl@0
  2056
	
sl@0
  2057
#ifdef _DEBUG	
sl@0
  2058
	__e32_atomic_add_ord32(&iThreadOpenCount, TUint32(-1));
sl@0
  2059
#endif		
sl@0
  2060
	}
sl@0
  2061
sl@0
  2062
/**
sl@0
  2063
Constructor for the play request object.
sl@0
  2064
*/
sl@0
  2065
TSoundScPlayRequest::TSoundScPlayRequest()
sl@0
  2066
	: TSoundScRequest()
sl@0
  2067
	{
sl@0
  2068
	iFlags=0; 
sl@0
  2069
	iCompletionReason=KErrGeneral;
sl@0
  2070
	}
sl@0
  2071
sl@0
  2072
/*
sl@0
  2073
Second phase construction of the requests
sl@0
  2074
*/
sl@0
  2075
TInt TSoundScPlayRequest::Construct()
sl@0
  2076
	{
sl@0
  2077
	return Kern::CreateClientRequest(iClientRequest);
sl@0
  2078
	}
sl@0
  2079
sl@0
  2080
/*
sl@0
  2081
Second phase construction of the requests
sl@0
  2082
*/
sl@0
  2083
TInt TSoundScRequest::Construct()
sl@0
  2084
	{
sl@0
  2085
	TClientDataRequest<TInt>* tempClientDataRequest=0;
sl@0
  2086
	TInt r = Kern::CreateClientDataRequest(tempClientDataRequest);
sl@0
  2087
	iClientRequest = tempClientDataRequest;
sl@0
  2088
	return r;
sl@0
  2089
	}
sl@0
  2090
sl@0
  2091
/**
sl@0
  2092
Destructor of play requests
sl@0
  2093
*/
sl@0
  2094
TSoundScRequest::~TSoundScRequest()
sl@0
  2095
	{
sl@0
  2096
	Kern::DestroyClientRequest(iClientRequest);
sl@0
  2097
	}
sl@0
  2098
sl@0
  2099
/**
sl@0
  2100
Constructor for the request object queue.
sl@0
  2101
*/
sl@0
  2102
TSoundScRequestQueue::TSoundScRequestQueue(DSoundScLdd* aLdd)
sl@0
  2103
	{
sl@0
  2104
	iLdd=aLdd;
sl@0
  2105
	memclr(&iRequest[0],sizeof(TSoundScRequest*)*KMaxSndScRequestsPending);
sl@0
  2106
	}
sl@0
  2107
	
sl@0
  2108
/**
sl@0
  2109
Destructor for the request object queue.
sl@0
  2110
*/
sl@0
  2111
TSoundScRequestQueue::~TSoundScRequestQueue()
sl@0
  2112
	{
sl@0
  2113
	for (TInt i=0 ; i<KMaxSndScRequestsPending ; i++)
sl@0
  2114
		{
sl@0
  2115
		delete iRequest[i];
sl@0
  2116
		}
sl@0
  2117
	}
sl@0
  2118
	
sl@0
  2119
/**
sl@0
  2120
Second stage constructor for the basic request object queue.
sl@0
  2121
@return KErrNone if successful, otherwise one of the other system wide error codes.
sl@0
  2122
@pre The thread must be in a critical section.
sl@0
  2123
*/
sl@0
  2124
TInt TSoundScRequestQueue::Create()	
sl@0
  2125
	{
sl@0
  2126
	// Create the set of available request objects and add them to the unused request queue. 	
sl@0
  2127
	for (TInt i=0 ; i<KMaxSndScRequestsPending ; i++)
sl@0
  2128
		{
sl@0
  2129
		iRequest[i]=new TSoundScRequest;		// Normal request object
sl@0
  2130
		if (!iRequest[i])
sl@0
  2131
			return(KErrNoMemory);
sl@0
  2132
		TInt retConstruct = iRequest[i]->Construct();
sl@0
  2133
		if ( retConstruct != KErrNone)
sl@0
  2134
			{
sl@0
  2135
			return(retConstruct);
sl@0
  2136
			}
sl@0
  2137
		iUnusedRequestQ.Add(iRequest[i]);
sl@0
  2138
		}
sl@0
  2139
		
sl@0
  2140
	return(KErrNone);
sl@0
  2141
	}
sl@0
  2142
		
sl@0
  2143
/**
sl@0
  2144
Second stage constructor for the play request object queue.
sl@0
  2145
@return KErrNone if successful, otherwise one of the other system wide error codes.
sl@0
  2146
@pre The thread must be in a critical section.
sl@0
  2147
*/
sl@0
  2148
TInt TSoundScPlayRequestQueue::Create()	
sl@0
  2149
	{
sl@0
  2150
	// Create the set of available play request objects and add them to the unused request queue. 	
sl@0
  2151
	for (TInt i=0 ; i<KMaxSndScRequestsPending ; i++)
sl@0
  2152
		{
sl@0
  2153
		iRequest[i]=new TSoundScPlayRequest();
sl@0
  2154
		if (!iRequest[i])
sl@0
  2155
			return(KErrNoMemory);
sl@0
  2156
		TInt retConstruct = iRequest[i]->Construct();
sl@0
  2157
		if ( retConstruct != KErrNone)
sl@0
  2158
			{
sl@0
  2159
			return(retConstruct);
sl@0
  2160
			}
sl@0
  2161
		iUnusedRequestQ.Add(iRequest[i]);
sl@0
  2162
		}
sl@0
  2163
		
sl@0
  2164
	return(KErrNone);
sl@0
  2165
	}	
sl@0
  2166
sl@0
  2167
/**
sl@0
  2168
Get an unused request object.
sl@0
  2169
@return A pointer to a free request object or NULL if there are none available.
sl@0
  2170
*/ 	
sl@0
  2171
TSoundScRequest* TSoundScRequestQueue::NextFree()
sl@0
  2172
	{
sl@0
  2173
	NKern::FMWait(&iUnusedRequestQLock);
sl@0
  2174
	TSoundScRequest* req = (TSoundScRequest*)iUnusedRequestQ.GetFirst();
sl@0
  2175
	NKern::FMSignal(&iUnusedRequestQLock);
sl@0
  2176
	return req;
sl@0
  2177
	}
sl@0
  2178
		
sl@0
  2179
/**
sl@0
  2180
Add a request object to the tail of the pending request queue. 
sl@0
  2181
@param aReq A pointer to the request object to be added to the queue.
sl@0
  2182
*/ 
sl@0
  2183
void TSoundScRequestQueue::Add(TSoundScRequest* aReq)	
sl@0
  2184
	{
sl@0
  2185
	iPendRequestQ.Add(aReq);
sl@0
  2186
	} 	
sl@0
  2187
sl@0
  2188
/**
sl@0
  2189
If the pending request queue is not empty, remove the request object from the head of this queue.
sl@0
  2190
@return A pointer to request object removed or NULL if the list was empty.
sl@0
  2191
*/ 
sl@0
  2192
TSoundScRequest* TSoundScRequestQueue::Remove()
sl@0
  2193
	{
sl@0
  2194
	return((TSoundScRequest*)iPendRequestQ.GetFirst());
sl@0
  2195
	}
sl@0
  2196
						
sl@0
  2197
/**
sl@0
  2198
Remove a request object from anywhere in the pending request queue. 
sl@0
  2199
@param aReq A pointer to the request object to be removed from the queue.
sl@0
  2200
@return A pointer to request object removed or NULL if it wasn't found.
sl@0
  2201
*/	
sl@0
  2202
TSoundScRequest* TSoundScRequestQueue::Remove(TSoundScRequest* aReq)	
sl@0
  2203
	{
sl@0
  2204
	TSoundScRequest* retReq;
sl@0
  2205
	
sl@0
  2206
	// Scan through the pending queue looking for a request object which matches.
sl@0
  2207
	retReq=(TSoundScRequest*)iPendRequestQ.First();
sl@0
  2208
	while (!IsAnchor(retReq) && retReq!=aReq)
sl@0
  2209
		retReq=(TSoundScRequest*)retReq->iNext;
sl@0
  2210
	
sl@0
  2211
	// If we got a match then remove the request object from the queue and return it.
sl@0
  2212
	if (!IsAnchor(retReq))
sl@0
  2213
		retReq->Deque();
sl@0
  2214
	else
sl@0
  2215
		retReq=NULL;
sl@0
  2216
	return(retReq);
sl@0
  2217
	}
sl@0
  2218
sl@0
  2219
/**
sl@0
  2220
Free up a request object - making it available for further requests. 
sl@0
  2221
@param aReq A pointer to the request object being freed up.
sl@0
  2222
*/ 
sl@0
  2223
void TSoundScRequestQueue::Free(TSoundScRequest* aReq)	
sl@0
  2224
	{
sl@0
  2225
	NKern::FMWait(&iUnusedRequestQLock);
sl@0
  2226
	iUnusedRequestQ.Add(aReq);
sl@0
  2227
	NKern::FMSignal(&iUnusedRequestQLock);
sl@0
  2228
	}
sl@0
  2229
	 
sl@0
  2230
/**
sl@0
  2231
Find a request object (specified by its associated request status pointer) within in the pending request queue. 
sl@0
  2232
@param aStatus The request status pointer of the request object to be found in the queue.
sl@0
  2233
@return A pointer to the request object if it was found or NULL if it wasn't found.
sl@0
  2234
*/	
sl@0
  2235
TSoundScRequest* TSoundScRequestQueue::Find(TRequestStatus* aStatus)	
sl@0
  2236
	{
sl@0
  2237
	TSoundScRequest* retReq;
sl@0
  2238
	
sl@0
  2239
	// Scan through the queue looking for a request object containing a TRequestStatus* which matches.
sl@0
  2240
	retReq=(TSoundScRequest*)iPendRequestQ.First();
sl@0
  2241
	while (!IsAnchor(retReq) && retReq->iClientRequest->StatusPtr()!=aStatus)
sl@0
  2242
		retReq=(TSoundScRequest*)retReq->iNext;
sl@0
  2243
		
sl@0
  2244
	return((IsAnchor(retReq))?NULL:retReq);
sl@0
  2245
	}				
sl@0
  2246
	
sl@0
  2247
/**
sl@0
  2248
Remove each request object from the pending request queue, completing each request removed with a specified completion
sl@0
  2249
reason.
sl@0
  2250
@param aCompletionReason The error value to be returned when completing any requests in the queue.
sl@0
  2251
@param aMutex A pointer to a mutex to be aquired when removing requests from the queue. May be NULL.
sl@0
  2252
*/		
sl@0
  2253
void TSoundScRequestQueue::CompleteAll(TInt aCompletionReason,NFastMutex* aMutex)	
sl@0
  2254
	{
sl@0
  2255
	if (aMutex)
sl@0
  2256
		NKern::FMWait(aMutex); 							// Acquire the mutex.
sl@0
  2257
	
sl@0
  2258
	TSoundScRequest* req;
sl@0
  2259
	while ((req=Remove())!=NULL)
sl@0
  2260
		{
sl@0
  2261
		if (aMutex)
sl@0
  2262
			NKern::FMSignal(aMutex); 					// Release the mutex while we complete the request.
sl@0
  2263
		iLdd->CompleteRequest(req->iOwningThread,NULL,aCompletionReason,req->iClientRequest);	
sl@0
  2264
		Free(req);	
sl@0
  2265
		if (aMutex)
sl@0
  2266
			NKern::FMWait(aMutex); 						// Re-acquire the mutex.
sl@0
  2267
sl@0
  2268
		}
sl@0
  2269
		
sl@0
  2270
	if (aMutex)	
sl@0
  2271
		NKern::FMSignal(aMutex); 						// Release mutex.	
sl@0
  2272
	}
sl@0
  2273
sl@0
  2274
/**
sl@0
  2275
Constructor for the play request object queue.
sl@0
  2276
*/					
sl@0
  2277
TSoundScPlayRequestQueue::TSoundScPlayRequestQueue(DSoundScLdd* aLdd)
sl@0
  2278
	: TSoundScRequestQueue(aLdd)
sl@0
  2279
{
sl@0
  2280
}
sl@0
  2281
sl@0
  2282
/**
sl@0
  2283
Return the play request object from the request queue which is next to be transferrred. If this
sl@0
  2284
play request is being handled using multiple data transfers then the transfer of earlier parts of
sl@0
  2285
this request may already be in progress. 
sl@0
  2286
@return Either a pointer to the next play request object for transfer, or NULL if no more are pending. 	
sl@0
  2287
*/
sl@0
  2288
TSoundScPlayRequest* TSoundScPlayRequestQueue::NextRequestForTransfer()
sl@0
  2289
	{
sl@0
  2290
	TSoundScPlayRequest* retReq;
sl@0
  2291
	
sl@0
  2292
	retReq=(TSoundScPlayRequest*)iPendRequestQ.First();
sl@0
  2293
	while (!IsAnchor(retReq) && retReq->iTf.iTfState>TSndScTransfer::ETfPartlyStarted)
sl@0
  2294
		retReq=(TSoundScPlayRequest*)retReq->iNext;
sl@0
  2295
		
sl@0
  2296
	return((IsAnchor(retReq))?NULL:retReq);	
sl@0
  2297
	}	
sl@0
  2298
sl@0
  2299
/**
sl@0
  2300
Search the play request queue for a particular play request object specified by its transfer ID.
sl@0
  2301
@param aTransferID The transfer ID of the particular play request object to be found.
sl@0
  2302
@param aIsNextToComplete If the search is successful then this indicates whether the request 
sl@0
  2303
object found is the next in the queue to be completed to the client. ETrue if next to be 
sl@0
  2304
completed, EFalse otherwise.
sl@0
  2305
@return Either a pointer to the specified request object, or NULL if it was not found.
sl@0
  2306
*/	
sl@0
  2307
TSoundScPlayRequest* TSoundScPlayRequestQueue::Find(TUint aTransferID,TBool& aIsNextToComplete)
sl@0
  2308
	{
sl@0
  2309
	TSoundScPlayRequest* retReq;
sl@0
  2310
	TSoundScPlayRequest* nextToCompleteReq=NULL;
sl@0
  2311
	
sl@0
  2312
	retReq=(TSoundScPlayRequest*)iPendRequestQ.First();
sl@0
  2313
	
sl@0
  2314
	// Walk all the way through the list either until we find the specified object or until we get to the end
sl@0
  2315
	for ( ; !IsAnchor(retReq) ; retReq=(TSoundScPlayRequest*)retReq->iNext )
sl@0
  2316
		{
sl@0
  2317
		// The first request we find which isn't complete must be the next to complete
sl@0
  2318
		if (!nextToCompleteReq && retReq->iTf.iTfState!=TSndScTransfer::ETfDone)
sl@0
  2319
			nextToCompleteReq=retReq;
sl@0
  2320
		if (retReq->iTf.iId==aTransferID)
sl@0
  2321
			break;
sl@0
  2322
		}
sl@0
  2323
	
sl@0
  2324
	if (IsAnchor(retReq))
sl@0
  2325
		return(NULL);		// Object not found
sl@0
  2326
	else
sl@0
  2327
		{
sl@0
  2328
		aIsNextToComplete=(retReq==nextToCompleteReq);
sl@0
  2329
		return(retReq);		// Object found
sl@0
  2330
		}
sl@0
  2331
	}					
sl@0
  2332
/**
sl@0
  2333
Constructor for the audio data transfer class. 
sl@0
  2334
*/	
sl@0
  2335
TSndScTransfer::TSndScTransfer()
sl@0
  2336
	{
sl@0
  2337
	iId=0;
sl@0
  2338
	iTfState=ETfNotStarted;
sl@0
  2339
	iAudioBuffer=NULL;
sl@0
  2340
	iLengthTransferred=0;
sl@0
  2341
	iTransfersInProgress=0;
sl@0
  2342
	}
sl@0
  2343
	
sl@0
  2344
/**
sl@0
  2345
Initialisation function for the audio data transfer class.
sl@0
  2346
@param aId A value to uniquely identify this particular transfer.
sl@0
  2347
@param aChunkOffset The start postition of the transfer - an offset within the shared chunk.
sl@0
  2348
@param aLength The total length of the transfer in bytes.
sl@0
  2349
@param anAudioBuffer The audio buffer associated with the transfer.
sl@0
  2350
*/		
sl@0
  2351
void TSndScTransfer::Init(TUint aId,TInt aChunkOffset,TInt aLength,TAudioBuffer* anAudioBuffer)
sl@0
  2352
	{
sl@0
  2353
	iId=aId;
sl@0
  2354
	iTfState=ETfNotStarted;
sl@0
  2355
	iAudioBuffer=anAudioBuffer;
sl@0
  2356
	iStartedOffset=aChunkOffset;
sl@0
  2357
	iEndOffset=aChunkOffset+aLength;
sl@0
  2358
	iLengthTransferred=0;
sl@0
  2359
	iTransfersInProgress=0;
sl@0
  2360
	}
sl@0
  2361
	
sl@0
  2362
/**
sl@0
  2363
Update the progress of the audio data transfer with the amount of data now queued for transfer on the audio device.
sl@0
  2364
@param aLength The amount of data (in bytes) that has just been queued on the audio device.
sl@0
  2365
*/
sl@0
  2366
void TSndScTransfer::SetStarted(TInt aLength)
sl@0
  2367
	{	
sl@0
  2368
	iTransfersInProgress++;
sl@0
  2369
	iStartedOffset+=aLength;
sl@0
  2370
	TInt notqueued=(iEndOffset - iStartedOffset);
sl@0
  2371
	__ASSERT_ALWAYS(notqueued>=0,Kern::Fault(KSoundLddPanic,__LINE__));
sl@0
  2372
	iTfState=(notqueued) ? ETfPartlyStarted : ETfFullyStarted;
sl@0
  2373
	}
sl@0
  2374
	
sl@0
  2375
/**
sl@0
  2376
Update the progress of the audio data transfer with the amount of data now successfully transfered by the audio device.
sl@0
  2377
@param aLength The amount of data (in bytes) that has just been transferred by the audio device.
sl@0
  2378
@return ETrue if the transfer is now fully complete, otherwise EFalse.
sl@0
  2379
*/
sl@0
  2380
TBool TSndScTransfer::SetCompleted(TInt aLength)
sl@0
  2381
	{		
sl@0
  2382
	iLengthTransferred+=aLength;
sl@0
  2383
	iTransfersInProgress--;
sl@0
  2384
	__ASSERT_ALWAYS(iTransfersInProgress>=0,Kern::Fault(KSoundLddPanic,__LINE__));
sl@0
  2385
	
sl@0
  2386
	if (GetNotStartedLen()==0 && iTransfersInProgress==0)
sl@0
  2387
		{
sl@0
  2388
		iTfState=ETfDone;	// Transfer is now fully completed
sl@0
  2389
		return(ETrue);
sl@0
  2390
		}
sl@0
  2391
	else
sl@0
  2392
		return(EFalse);	
sl@0
  2393
	}
sl@0
  2394
		
sl@0
  2395
/**
sl@0
  2396
Constructor for the sound driver power handler class.
sl@0
  2397
@param aChannel A pointer to the sound driver logical channel which owns this power handler.
sl@0
  2398
*/
sl@0
  2399
DSoundScPowerHandler::DSoundScPowerHandler(DSoundScLdd* aChannel)
sl@0
  2400
:	DPowerHandler(KDevSoundScName),
sl@0
  2401
	iChannel(aChannel)
sl@0
  2402
	{	
sl@0
  2403
	}
sl@0
  2404
sl@0
  2405
/**
sl@0
  2406
A request from the power manager for the power down of the audio device.
sl@0
  2407
This is called during a transition of the phone into standby or power off.
sl@0
  2408
@param aState The target power state; can be EPwStandby or EPwOff only.
sl@0
  2409
*/
sl@0
  2410
void DSoundScPowerHandler::PowerDown(TPowerState aPowerState)
sl@0
  2411
	{
sl@0
  2412
	(void)aPowerState;
sl@0
  2413
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScPowerHandler::PowerDown(State-%d)",aPowerState));
sl@0
  2414
	
sl@0
  2415
	// Power-down involves hardware access so queue a DFC to perform this from the driver thread.
sl@0
  2416
	iChannel->iPowerDownDfc.Enque();
sl@0
  2417
	}
sl@0
  2418
sl@0
  2419
/**
sl@0
  2420
A request from the power manager for the power up of the audio device.
sl@0
  2421
This is called during a transition of the phone out of standby.
sl@0
  2422
*/
sl@0
  2423
void DSoundScPowerHandler::PowerUp()
sl@0
  2424
	{
sl@0
  2425
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScPowerHandler::PowerUp"));
sl@0
  2426
	
sl@0
  2427
	// Power-up involves hardware access so queue a DFC to perform this from the driver thread.
sl@0
  2428
	iChannel->iPowerUpDfc.Enque();
sl@0
  2429
	}	
sl@0
  2430
sl@0
  2431
/**
sl@0
  2432
Constructor for the buffer manager.
sl@0
  2433
*/
sl@0
  2434
DBufferManager::DBufferManager(DSoundScLdd* aLdd)
sl@0
  2435
	: iLdd(aLdd)
sl@0
  2436
	{
sl@0
  2437
//	iChunk=NULL;
sl@0
  2438
//	iNumBuffers=0;
sl@0
  2439
//	iAudioBuffers=NULL;	
sl@0
  2440
//	iMaxTransferLen=0;	
sl@0
  2441
	}
sl@0
  2442
sl@0
  2443
/**
sl@0
  2444
Destructor for the buffer manager.
sl@0
  2445
@pre The thread must be in a critical section.
sl@0
  2446
*/
sl@0
  2447
DBufferManager::~DBufferManager()
sl@0
  2448
	{
sl@0
  2449
	if (iChunk)
sl@0
  2450
		Kern::ChunkClose(iChunk);
sl@0
  2451
	delete[] iAudioBuffers;
sl@0
  2452
	}
sl@0
  2453
		
sl@0
  2454
/**
sl@0
  2455
Second stage constructor for the buffer manager. This version creates a shared chunk and a buffer object for each
sl@0
  2456
buffer specified within this. Then it commits memory within the chunk for each of these buffers. This also involves the
sl@0
  2457
creation of a set of buffer lists to manage the buffers.
sl@0
  2458
@param aBufConfig The shared chunk buffer configuration object specifying the geometry of the buffer configuration
sl@0
  2459
required.
sl@0
  2460
@return KErrNone if successful, otherwise one of the other system wide error codes.
sl@0
  2461
@pre The thread must be in a critical section.
sl@0
  2462
*/
sl@0
  2463
TInt DBufferManager::Create(TSoundSharedChunkBufConfig* aBufConfig)
sl@0
  2464
	{
sl@0
  2465
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DBufferManager::Create(Bufs-%d,Sz-%d)",aBufConfig->iNumBuffers,aBufConfig->iBufferSizeInBytes));
sl@0
  2466
sl@0
  2467
	// Create the required number of buffer objects, and the buffer lists to manage these.
sl@0
  2468
	TInt r=CreateBufferLists(aBufConfig->iNumBuffers);
sl@0
  2469
	if (r!=KErrNone)
sl@0
  2470
		return(r);
sl@0
  2471
		
sl@0
  2472
	TInt chunkSz;
sl@0
  2473
	TInt bufferSz=aBufConfig->iBufferSizeInBytes;
sl@0
  2474
	TInt* bufferOffsetList=&aBufConfig->iBufferOffsetListStart;	
sl@0
  2475
	
sl@0
  2476
	// Calculate the required size for the chunk and the buffer offsets. 
sl@0
  2477
	if (aBufConfig->iFlags & KScFlagUseGuardPages)
sl@0
  2478
		{
sl@0
  2479
		// Commit each buffer separately with an uncommitted guard pages around each buffer.
sl@0
  2480
		TInt guardPageSize=Kern::RoundToPageSize(1);
sl@0
  2481
		bufferSz=Kern::RoundToPageSize(aBufConfig->iBufferSizeInBytes); // Commit size to be a multiple of the MMU page size.
sl@0
  2482
		chunkSz=guardPageSize;											// Leave an un-committed guard page at the start.
sl@0
  2483
		for (TInt i=0 ; i<aBufConfig->iNumBuffers ; i++)
sl@0
  2484
			{
sl@0
  2485
			bufferOffsetList[i]=chunkSz;
sl@0
  2486
			chunkSz += (bufferSz + guardPageSize);						// Leave an un-committed guard page after each buffer.
sl@0
  2487
			}
sl@0
  2488
		}
sl@0
  2489
	else
sl@0
  2490
		{
sl@0
  2491
		// Commit all the buffers contiguously into a single region (ie with no guard pages between each buffer).
sl@0
  2492
		chunkSz=0;
sl@0
  2493
		for (TInt i=0 ; i<aBufConfig->iNumBuffers ; i++)
sl@0
  2494
			{
sl@0
  2495
			bufferOffsetList[i]=chunkSz;
sl@0
  2496
			chunkSz += bufferSz;
sl@0
  2497
			}
sl@0
  2498
		chunkSz=Kern::RoundToPageSize(chunkSz);							// Commit size to be a multiple of the MMU page size.
sl@0
  2499
		}	
sl@0
  2500
	aBufConfig->iFlags|=KScFlagBufOffsetListInUse;
sl@0
  2501
	__KTRACE_OPT(KSOUND1, Kern::Printf("Chunk size is %d bytes",chunkSz));	
sl@0
  2502
    
sl@0
  2503
    // Create the shared chunk. The PDD supplies most of the chunk create info - but not the maximum size.
sl@0
  2504
	TChunkCreateInfo info;
sl@0
  2505
	info.iMaxSize=chunkSz;
sl@0
  2506
	iLdd->Pdd()->GetChunkCreateInfo(info);		// Call down to the PDD for the rest.
sl@0
  2507
	
sl@0
  2508
	r = Kern::ChunkCreate(info,iChunk,iChunkBase,iChunkMapAttr);
sl@0
  2509
	__KTRACE_OPT(KSOUND1, Kern::Printf("Create chunk - %d",r));	
sl@0
  2510
	if (r!=KErrNone)
sl@0
  2511
     	return(r);
sl@0
  2512
	
sl@0
  2513
	if (aBufConfig->iFlags & KScFlagUseGuardPages)
sl@0
  2514
		{
sl@0
  2515
		// Map each of the buffers into the chunk separately - try to allocate physically contiguous RAM pages. Create a buffer object for each buffer.
sl@0
  2516
 		TBool isContiguous;
sl@0
  2517
 		for (TInt i=0 ; i<aBufConfig->iNumBuffers ; i++)
sl@0
  2518
			{
sl@0
  2519
			r=CommitMemoryForBuffer(bufferOffsetList[i],bufferSz,isContiguous);
sl@0
  2520
			if (r!=KErrNone)
sl@0
  2521
				return(r);
sl@0
  2522
			r=iAudioBuffers[i].Create(iChunk,bufferOffsetList[i],(aBufConfig->iBufferSizeInBytes),isContiguous,this);
sl@0
  2523
			if (r!=KErrNone)
sl@0
  2524
				return(r);	
sl@0
  2525
			}		
sl@0
  2526
		}
sl@0
  2527
	else
sl@0
  2528
		{
sl@0
  2529
		// Map memory for the all buffers into the chunk - try to allocate physically contiguous RAM pages. 
sl@0
  2530
 		TBool isContiguous;
sl@0
  2531
		r=CommitMemoryForBuffer(0,chunkSz,isContiguous);
sl@0
  2532
		if (r!=KErrNone)
sl@0
  2533
			return(r);
sl@0
  2534
		
sl@0
  2535
		// Create a buffer object for each buffer.
sl@0
  2536
 		for (TInt i=0 ; i<aBufConfig->iNumBuffers ; i++)
sl@0
  2537
			{
sl@0
  2538
			r=iAudioBuffers[i].Create(iChunk,bufferOffsetList[i],(aBufConfig->iBufferSizeInBytes),isContiguous,this);
sl@0
  2539
			if (r!=KErrNone)
sl@0
  2540
				return(r);	
sl@0
  2541
			}	
sl@0
  2542
		}
sl@0
  2543
sl@0
  2544
	// Read back and store the maximum transfer length supported by this device from the PDD.
sl@0
  2545
	iMaxTransferLen=iLdd->Pdd()->MaxTransferLen();
sl@0
  2546
	
sl@0
  2547
    __KTRACE_OPT(KSOUND1, Kern::Printf("<DBufferManager::Create - %d",r));
sl@0
  2548
	return(r);
sl@0
  2549
	}
sl@0
  2550
	
sl@0
  2551
/**
sl@0
  2552
Second stage constructor for the buffer manager. This version opens an existing shared chunk using a client supplied
sl@0
  2553
handle. It then creates a buffer object for each buffer that exists within the chunk as well as creating a set of buffer
sl@0
  2554
lists to manage the buffers.
sl@0
  2555
@param aBufConfig The shared chunk buffer configuration object - specifying the geometry of the buffer configuration
sl@0
  2556
within the shared chunk supplied.
sl@0
  2557
@param aChunkHandle A handle for the shared chunk supplied by the client.
sl@0
  2558
@param anOwningThread The thread in which the given handle is valid.
sl@0
  2559
@return KErrNone if successful, otherwise one of the other system wide error codes.
sl@0
  2560
@pre The thread must be in a critical section.
sl@0
  2561
*/
sl@0
  2562
TInt DBufferManager::Create(TSoundSharedChunkBufConfig& aBufConfig,TInt aChunkHandle,DThread* anOwningThread)
sl@0
  2563
	{	
sl@0
  2564
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DBufferManager::Create(Handle-%d)",aChunkHandle));
sl@0
  2565
sl@0
  2566
	// Validate the buffer configuration information.
sl@0
  2567
	if (!aBufConfig.iFlags&KScFlagBufOffsetListInUse)
sl@0
  2568
		return(KErrArgument);
sl@0
  2569
	TInt numBuffers=aBufConfig.iNumBuffers;
sl@0
  2570
	TInt bufferSizeInBytes=aBufConfig.iBufferSizeInBytes;
sl@0
  2571
	TInt* bufferOffsetList=&aBufConfig.iBufferOffsetListStart;
sl@0
  2572
	TInt r=ValidateBufferOffsets(bufferOffsetList,numBuffers,bufferSizeInBytes);
sl@0
  2573
	if (r<0)
sl@0
  2574
		return(r);
sl@0
  2575
	
sl@0
  2576
	// Create the required number of buffer objects, and the buffer lists to manage these.
sl@0
  2577
	r=CreateBufferLists(numBuffers);
sl@0
  2578
	if (r!=KErrNone)
sl@0
  2579
		return(r);
sl@0
  2580
	
sl@0
  2581
	// Open the shared chunk.
sl@0
  2582
	DChunk* chunk;
sl@0
  2583
	chunk=Kern::OpenSharedChunk(anOwningThread,aChunkHandle,ETrue);
sl@0
  2584
	if (!chunk)
sl@0
  2585
		return(KErrBadHandle);
sl@0
  2586
	iChunk=chunk;
sl@0
  2587
	
sl@0
  2588
	// Read the physical address for the 1st buffer in order to determine the kernel address and the map attributes.
sl@0
  2589
	TInt offset=bufferOffsetList[0];
sl@0
  2590
	TPhysAddr physAddr;
sl@0
  2591
	TLinAddr kernelAddress;
sl@0
  2592
	r=Kern::ChunkPhysicalAddress(iChunk,offset,bufferSizeInBytes,kernelAddress,iChunkMapAttr,physAddr,NULL);
sl@0
  2593
	if (r!=KErrNone)
sl@0
  2594
		return(r);
sl@0
  2595
	iChunkBase=(kernelAddress-offset);
sl@0
  2596
	
sl@0
  2597
	// For each buffer, validate that the buffer specified contains committed memory and store the buffer info. into each buffer object.
sl@0
  2598
	while (numBuffers)
sl@0
  2599
		{
sl@0
  2600
		numBuffers--;
sl@0
  2601
		offset=bufferOffsetList[numBuffers];
sl@0
  2602
		// Assume it isn't contiguous here - Create() will detect and do the right thing if it is contiguous.
sl@0
  2603
		r=iAudioBuffers[numBuffers].Create(iChunk,offset,bufferSizeInBytes,EFalse,this);	
sl@0
  2604
		if (r!=KErrNone)
sl@0
  2605
			return(r);
sl@0
  2606
		}
sl@0
  2607
		
sl@0
  2608
	// Read back and store the maximum transfer length supported by this device from the PDD.
sl@0
  2609
	iMaxTransferLen=iLdd->Pdd()->MaxTransferLen();	
sl@0
  2610
		
sl@0
  2611
	__KTRACE_OPT(KSOUND1, Kern::Printf("<DBufferManager::Create - %d",KErrNone));
sl@0
  2612
	return(KErrNone);
sl@0
  2613
	}
sl@0
  2614
sl@0
  2615
/**
sl@0
  2616
Allocate an array of buffer objects, - one for each buffer contained within the shared chunk.
sl@0
  2617
@param aNumBuffers The number of buffer objects required.
sl@0
  2618
@return KErrNone if successful, otherwise one of the other system wide error codes.
sl@0
  2619
@pre The thread must be in a critical section.
sl@0
  2620
*/
sl@0
  2621
TInt DBufferManager::CreateBufferLists(TInt aNumBuffers)
sl@0
  2622
	{
sl@0
  2623
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DBufferManager::CreateBufferLists(Bufs-%d)",aNumBuffers));
sl@0
  2624
sl@0
  2625
	// Construct the array of buffers.
sl@0
  2626
	iNumBuffers=aNumBuffers;
sl@0
  2627
	iAudioBuffers=new TAudioBuffer[aNumBuffers];
sl@0
  2628
	if (!iAudioBuffers)
sl@0
  2629
		return(KErrNoMemory);
sl@0
  2630
	
sl@0
  2631
	return(KErrNone);
sl@0
  2632
	}
sl@0
  2633
	
sl@0
  2634
/**
sl@0
  2635
Validate a shared chunk buffer offset list.
sl@0
  2636
@param aBufferOffsetList The buffer offset list to be validated.
sl@0
  2637
@param aNumBuffers The number of offsets that the list contains.
sl@0
  2638
@param aBufferSizeInBytes The size in bytes of each buffer.
sl@0
  2639
@return If the buffer list is found to be valid, the calculated minimum size of the corresponding chunk is returned
sl@0
  2640
	(i.e. a value>=0). Otherwise, KErrArgument is returned.
sl@0
  2641
*/
sl@0
  2642
TInt DBufferManager::ValidateBufferOffsets(TInt* aBufferOffsetList,TInt aNumBuffers,TInt aBufferSizeInBytes)	
sl@0
  2643
	{
sl@0
  2644
	TUint32 alignmask=(1<<iLdd->iCaps.iRequestAlignment)-1; // iRequestAlignment holds log to base 2 of alignment required
sl@0
  2645
			
sl@0
  2646
	// Verify each of the buffer offsets supplied
sl@0
  2647
	TInt offset=0;
sl@0
  2648
	for (TInt i=0 ; i<aNumBuffers ; i++)
sl@0
  2649
		{
sl@0
  2650
		// If this is a record channel then the offset must comply with the PDD alignment constraints.
sl@0
  2651
		if (iLdd->iDirection==ESoundDirRecord && ((TUint32)aBufferOffsetList[i] & alignmask) != 0)	
sl@0
  2652
			return(KErrArgument);
sl@0
  2653
			
sl@0
  2654
		// Check the offset doesn't overlap the previous buffer - offset holds the offset to next byte after
sl@0
  2655
		// the previous buffer.
sl@0
  2656
		if (aBufferOffsetList[i]<offset)
sl@0
  2657
			return(KErrArgument);
sl@0
  2658
		
sl@0
  2659
		offset=(aBufferOffsetList[i]+aBufferSizeInBytes);
sl@0
  2660
		}
sl@0
  2661
	return(offset);	
sl@0
  2662
	}
sl@0
  2663
	
sl@0
  2664
/**
sl@0
  2665
Verify that a specified region of the shared chunk (specified by its offset and length) is valid within the 
sl@0
  2666
chunk and corresponds to a region of committed memory.
sl@0
  2667
@param aChunkOffset Offset of the region from the beginning of the chunk.
sl@0
  2668
@param aLength The length in bytes of the region.
sl@0
  2669
@param anAudioBuffer A reference to a pointer to an audio buffer object. On return this will either contain a pointer
sl@0
  2670
to the audio buffer object which corresonds to the specified region, or NULL if the region is invalid.
sl@0
  2671
@return KErrNone if the region is valid, otherwise KErrArgument.
sl@0
  2672
*/	
sl@0
  2673
TInt DBufferManager::ValidateRegion(TUint aChunkOffset,TUint aLength,TAudioBuffer*& anAudioBuffer)
sl@0
  2674
	{
sl@0
  2675
	
sl@0
  2676
	TUint bufStart;
sl@0
  2677
	TUint bufEnd;
sl@0
  2678
	TUint regEnd=(aChunkOffset+aLength);
sl@0
  2679
	for (TInt i=0 ; i<iNumBuffers ; i++)
sl@0
  2680
		{
sl@0
  2681
		bufStart=iAudioBuffers[i].iChunkOffset;
sl@0
  2682
		bufEnd=iAudioBuffers[i].iChunkOffset+iAudioBuffers[i].iSize;
sl@0
  2683
		if (aChunkOffset<bufStart || aChunkOffset>=bufEnd)
sl@0
  2684
			continue;
sl@0
  2685
		if (regEnd<=bufEnd)
sl@0
  2686
			{
sl@0
  2687
			anAudioBuffer=&iAudioBuffers[i];
sl@0
  2688
			return(KErrNone);
sl@0
  2689
			}
sl@0
  2690
		}
sl@0
  2691
	return(KErrArgument);
sl@0
  2692
	}
sl@0
  2693
			
sl@0
  2694
/**
sl@0
  2695
Commit memory for a single buffer within the shared chunk.
sl@0
  2696
@param aChunkOffset The offset (in bytes) from start of chunk, which indicates the start of the memory region to be
sl@0
  2697
	committed. Must be a multiple of the MMU page size. 
sl@0
  2698
@param aSize The number of bytes to commit. Must be a multiple of the MMU page size.
sl@0
  2699
@param aIsContiguous On return, this is set to ETrue if the function succeeded in committing physically contiguous memory;
sl@0
  2700
	EFalse if the committed memory is not contiguous.	
sl@0
  2701
@return KErrNone if successful, otherwise one of the other system wide error codes.
sl@0
  2702
*/	
sl@0
  2703
TInt DBufferManager::CommitMemoryForBuffer(TInt aChunkOffset,TInt aSize,TBool& aIsContiguous)
sl@0
  2704
	{
sl@0
  2705
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DBufferManager::CommitMemoryForBuffer(Offset-%x,Sz-%d)",aChunkOffset,aSize));
sl@0
  2706
	
sl@0
  2707
	// Try for physically contiguous memory first.
sl@0
  2708
	TInt r;	
sl@0
  2709
	TPhysAddr physicalAddress;
sl@0
  2710
	r=Kern::ChunkCommitContiguous(iChunk,aChunkOffset,aSize,physicalAddress);
sl@0
  2711
	if (r==KErrNone)
sl@0
  2712
		{
sl@0
  2713
		aIsContiguous=ETrue;
sl@0
  2714
		return(r);
sl@0
  2715
		}
sl@0
  2716
			
sl@0
  2717
	// Try to commit memory that isn't contiguous instead.
sl@0
  2718
	aIsContiguous=EFalse;
sl@0
  2719
	r=Kern::ChunkCommit(iChunk,aChunkOffset,aSize);
sl@0
  2720
	return(r);
sl@0
  2721
	}
sl@0
  2722
	
sl@0
  2723
/**
sl@0
  2724
Purge a region of the audio chunk. That is, if this region contains cacheable memory, flush it.
sl@0
  2725
@param aChunkOffset The offset within the chunk for the start of the data to be flushed.
sl@0
  2726
@param aLength The length in bytes of the region to be flushed.
sl@0
  2727
@param aFlushOp The type of flush operation required - @see TFlushOp.
sl@0
  2728
*/
sl@0
  2729
void DBufferManager::FlushData(TInt aChunkOffset,TInt aLength,TFlushOp aFlushOp)
sl@0
  2730
	{
sl@0
  2731
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DBufferManager::FlushData(%d)",aFlushOp));
sl@0
  2732
	TLinAddr dataAddr=(iChunkBase+aChunkOffset);
sl@0
  2733
	switch (aFlushOp)
sl@0
  2734
		{
sl@0
  2735
		case EFlushBeforeDmaWrite:
sl@0
  2736
			Cache::SyncMemoryBeforeDmaWrite(dataAddr,aLength,iChunkMapAttr);
sl@0
  2737
			break;
sl@0
  2738
		case EFlushBeforeDmaRead:
sl@0
  2739
			Cache::SyncMemoryBeforeDmaRead(dataAddr,aLength,iChunkMapAttr);
sl@0
  2740
			break;
sl@0
  2741
		case EFlushAfterDmaRead:
sl@0
  2742
			Cache::SyncMemoryAfterDmaRead(dataAddr,aLength);
sl@0
  2743
			break;
sl@0
  2744
		default:
sl@0
  2745
			break;
sl@0
  2746
		}
sl@0
  2747
	}
sl@0
  2748
		
sl@0
  2749
/**
sl@0
  2750
Constructor for the record buffer manager.
sl@0
  2751
*/
sl@0
  2752
DRecordBufferManager::DRecordBufferManager(DSoundScLdd* aLdd)
sl@0
  2753
	: DBufferManager(aLdd)
sl@0
  2754
	{
sl@0
  2755
	}
sl@0
  2756
			
sl@0
  2757
/**
sl@0
  2758
Reset all the audio buffer lists to reflect the state at the start of the record capture process.
sl@0
  2759
@pre The buffer/request queue mutex must be held.
sl@0
  2760
*/
sl@0
  2761
void DRecordBufferManager::Reset()
sl@0
  2762
	{
sl@0
  2763
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DBufferManager::Reset"));
sl@0
  2764
	TAudioBuffer* pBuf;
sl@0
  2765
	
sl@0
  2766
	// Before reseting buffer lists, purge the cache for all cached buffers currently in use by client.
sl@0
  2767
	pBuf=(TAudioBuffer*)iInUseBufferQ.First();
sl@0
  2768
	SDblQueLink* anchor=&iInUseBufferQ.iA;
sl@0
  2769
	while (pBuf!=anchor)
sl@0
  2770
		{
sl@0
  2771
		pBuf->Flush(DBufferManager::EFlushBeforeDmaRead);
sl@0
  2772
		pBuf=(TAudioBuffer*)pBuf->iNext;
sl@0
  2773
		}
sl@0
  2774
		
sl@0
  2775
	// Start by reseting all the lists.
sl@0
  2776
	iFreeBufferQ.iA.iNext=iFreeBufferQ.iA.iPrev=&iFreeBufferQ.iA;	
sl@0
  2777
	iCompletedBufferQ.iA.iNext=iCompletedBufferQ.iA.iPrev=&iCompletedBufferQ.iA;
sl@0
  2778
	iInUseBufferQ.iA.iNext=iInUseBufferQ.iA.iPrev=&iInUseBufferQ.iA;	
sl@0
  2779
		
sl@0
  2780
	// Set the pointers to the current and the next record buffers.
sl@0
  2781
	pBuf=iAudioBuffers; 		// This is the first buffer
sl@0
  2782
	iCurrentBuffer=pBuf++;
sl@0
  2783
	iNextBuffer = pBuf++;
sl@0
  2784
	
sl@0
  2785
	// Add all other buffers to the free list.
sl@0
  2786
	TAudioBuffer* bufferLimit=iAudioBuffers+iNumBuffers; 
sl@0
  2787
	while(pBuf<bufferLimit)
sl@0
  2788
		iFreeBufferQ.Add(pBuf++);
sl@0
  2789
	
sl@0
  2790
	iBufOverflow=EFalse;	
sl@0
  2791
	}
sl@0
  2792
	
sl@0
  2793
/**
sl@0
  2794
Update buffer lists after a record buffer has been filled.
sl@0
  2795
@param aBytesAdded The number of bytes added to the buffer to get it into the 'filled' state. Of course, this is
sl@0
  2796
	normally equal to the size of the buffer. The exception is when recording has been paused: in which
sl@0
  2797
	case the number of bytes added to 'fill' the buffer may be less than the buffer size.
sl@0
  2798
@param aTransferResult The result of the transfer.	
sl@0
  2799
@return A pointer to the next buffer for recording.
sl@0
  2800
@pre The buffer/request queue mutex must be held.
sl@0
  2801
*/
sl@0
  2802
TAudioBuffer* DRecordBufferManager::SetBufferFilled(TInt aBytesAdded,TInt aTransferResult)
sl@0
  2803
	{
sl@0
  2804
	// If record has been paused then its possible (depending on the PDD implementation) that although the current
sl@0
  2805
	// buffer is marked as being filled, no data has been added. If this is the case then there is no point in informing 
sl@0
  2806
	// the client about it. Instead we need to return it to the free list. Otherwise the more normal course of action is
sl@0
  2807
	// to add the current buffer to the completed list ready for the client. If there is any amount of data in the record
sl@0
  2808
	// buffer, this needs to be passed to the client (and if we're not paused then each buffer should actually be full).
sl@0
  2809
	// If an error occured then we always add the buffer to the completed list.
sl@0
  2810
	TAudioBuffer* buffer=iCurrentBuffer;
sl@0
  2811
	if (aBytesAdded || aTransferResult)
sl@0
  2812
		{
sl@0
  2813
		buffer->iBytesAdded=aBytesAdded;
sl@0
  2814
		buffer->iResult=aTransferResult;
sl@0
  2815
		iCompletedBufferQ.Add(buffer);
sl@0
  2816
		}
sl@0
  2817
	else
sl@0
  2818
		iFreeBufferQ.Add(buffer);
sl@0
  2819
sl@0
  2820
	// Make the pending buffer the current one.
sl@0
  2821
	iCurrentBuffer=iNextBuffer;
sl@0
  2822
sl@0
  2823
	// Obtain the next pending buffer. If there are none left on the free list then we have to take one back
sl@0
  2824
	// from the completed list.
sl@0
  2825
	iNextBuffer=(TAudioBuffer*)iFreeBufferQ.GetFirst();
sl@0
  2826
	if (!iNextBuffer)
sl@0
  2827
		{
sl@0
  2828
		iNextBuffer=(TAudioBuffer*)iCompletedBufferQ.GetFirst();
sl@0
  2829
		iBufOverflow=ETrue;	// This is the buffer overflow situation.
sl@0
  2830
		}
sl@0
  2831
	__ASSERT_DEBUG(iNextBuffer,Kern::Fault(KSoundLddPanic,__LINE__));	
sl@0
  2832
	iNextBuffer->iBytesAdded=0;
sl@0
  2833
	
sl@0
  2834
	__KTRACE_OPT(KSOUND1, Kern::Printf("<DBufferManager::SetBufferFilled(buf=%08x len=%d)",buffer->iChunkOffset,buffer->iBytesAdded));
sl@0
  2835
	return(iNextBuffer);
sl@0
  2836
	}
sl@0
  2837
sl@0
  2838
/**
sl@0
  2839
Get the next record buffer from the completed buffer list. If there is no error associated with the buffer, 
sl@0
  2840
make it 'in use' by the client. Otherwise, return the buffer to the free list.
sl@0
  2841
@return A pointer to the next completed buffer or NULL if there isn't one available.
sl@0
  2842
@pre The buffer/request queue mutex must be held.
sl@0
  2843
*/
sl@0
  2844
TAudioBuffer* DRecordBufferManager::GetBufferForClient()
sl@0
  2845
	{	
sl@0
  2846
	TAudioBuffer* buffer=(TAudioBuffer*)iCompletedBufferQ.GetFirst();
sl@0
  2847
	if (buffer)
sl@0
  2848
		{
sl@0
  2849
		if (buffer->iResult==KErrNone)
sl@0
  2850
			iInUseBufferQ.Add(buffer);
sl@0
  2851
		else
sl@0
  2852
			iFreeBufferQ.Add(buffer);
sl@0
  2853
		}
sl@0
  2854
	
sl@0
  2855
	__KTRACE_OPT(KSOUND1, Kern::Printf("<DBufferManager::BufferForClient(buf=%08x)",(buffer ? buffer->iChunkOffset : -1)));
sl@0
  2856
	return(buffer);
sl@0
  2857
	}
sl@0
  2858
sl@0
  2859
/**
sl@0
  2860
Release (move to free list) the 'in use' record buffer specified by the given chunk offset.
sl@0
  2861
@param aChunkOffset The chunk offset corresponding to the buffer to be freed.
sl@0
  2862
@return The freed buffer, or NULL if no 'in use' buffer had the specified chunk offset.
sl@0
  2863
@pre The buffer/request queue mutex must be held.
sl@0
  2864
*/
sl@0
  2865
TAudioBuffer* DRecordBufferManager::ReleaseBuffer(TInt aChunkOffset)
sl@0
  2866
	{
sl@0
  2867
	// Scan 'in use' list for the audio buffer
sl@0
  2868
	TAudioBuffer* pBuf;
sl@0
  2869
	pBuf=(TAudioBuffer*)iInUseBufferQ.First();
sl@0
  2870
	SDblQueLink* anchor=&iInUseBufferQ.iA;
sl@0
  2871
	while (pBuf!=anchor && pBuf->iChunkOffset!=aChunkOffset)
sl@0
  2872
		pBuf=(TAudioBuffer*)pBuf->iNext;
sl@0
  2873
	
sl@0
  2874
	// Move buffer to the free list (if found)
sl@0
  2875
	if (pBuf!=anchor)
sl@0
  2876
		iFreeBufferQ.Add(pBuf->Deque());
sl@0
  2877
	else
sl@0
  2878
		pBuf=NULL;
sl@0
  2879
	
sl@0
  2880
	__KTRACE_OPT(KSOUND1, Kern::Printf(">DBufferManager::BufferRelease(buf=%08x)",(pBuf ? pBuf->iChunkOffset : -1)));
sl@0
  2881
	return(pBuf);
sl@0
  2882
	}
sl@0
  2883
sl@0
  2884
/**
sl@0
  2885
Constructor for the audio buffer class.
sl@0
  2886
Clears all member data
sl@0
  2887
*/
sl@0
  2888
TAudioBuffer::TAudioBuffer()
sl@0
  2889
	{
sl@0
  2890
	memclr(this,sizeof(*this));
sl@0
  2891
	}
sl@0
  2892
sl@0
  2893
/**
sl@0
  2894
Destructor for the audio buffer class.
sl@0
  2895
*/
sl@0
  2896
TAudioBuffer::~TAudioBuffer()
sl@0
  2897
	{
sl@0
  2898
	delete[] iPhysicalPages;
sl@0
  2899
	}
sl@0
  2900
	
sl@0
  2901
/**
sl@0
  2902
Second stage constructor for the audio buffer class - validate and acquire information on the memory
sl@0
  2903
allocated to this buffer.
sl@0
  2904
@param aChunk  The chunk in which this buffer belongs.
sl@0
  2905
@param aChunkOffset The offset within aChunk to the start of the audio buffer.
sl@0
  2906
@param aSize The size (in bytes) of the buffer.
sl@0
  2907
@param aIsContiguous A boolean indicating whether the buffer contains physically contiguous memory. Set to ETrue if it
sl@0
  2908
	does physically contiguous memory, EFalse otherwise.		
sl@0
  2909
@param aBufManager A pointer to the buffer manager which owns this object.
sl@0
  2910
@return KErrNone if successful, otherwise one of the other system wide error codes.
sl@0
  2911
@pre The thread must be in a critical section.
sl@0
  2912
*/
sl@0
  2913
TInt TAudioBuffer::Create(DChunk* aChunk,TInt aChunkOffset,TInt aSize,TBool aIsContiguous,DBufferManager* aBufManager)
sl@0
  2914
	{
sl@0
  2915
	__KTRACE_OPT(KSOUND1, Kern::Printf(">TAudioBuffer::Create(Off-%x,Sz-%d,Contig-%d)",aChunkOffset,aSize,aIsContiguous));
sl@0
  2916
sl@0
  2917
	// Save info. on the offset and size of the buffer. Also the buffer manager.
sl@0
  2918
	iChunkOffset=aChunkOffset;
sl@0
  2919
	iSize=aSize;
sl@0
  2920
	iBufManager=aBufManager;
sl@0
  2921
sl@0
  2922
	TInt r=KErrNone;
sl@0
  2923
	iPhysicalPages=NULL;
sl@0
  2924
	if (!aIsContiguous)
sl@0
  2925
		{
sl@0
  2926
		// Allocate an array for a list of the physical pages.
sl@0
  2927
		iPhysicalPages = new TPhysAddr[aSize/Kern::RoundToPageSize(1)+2];
sl@0
  2928
		if (!iPhysicalPages)
sl@0
  2929
			r=KErrNoMemory;	
sl@0
  2930
		}
sl@0
  2931
		
sl@0
  2932
	if (r==KErrNone)
sl@0
  2933
		{
sl@0
  2934
		// Check that the region of the chunk specified for the buffer contains committed memory. If so, get the physical addresses of the
sl@0
  2935
		// pages in this buffer.
sl@0
  2936
		TUint32 kernAddr;
sl@0
  2937
		TUint32 mapAttr;
sl@0
  2938
		r=Kern::ChunkPhysicalAddress(aChunk,aChunkOffset,aSize,kernAddr,mapAttr,iPhysicalAddress,iPhysicalPages);
sl@0
  2939
		// r = 0 or 1 on success. (1 meaning the physical pages are not contiguous).
sl@0
  2940
		if (r==1)
sl@0
  2941
			{
sl@0
  2942
			// The physical pages are not contiguous.
sl@0
  2943
			iPhysicalAddress=KPhysAddrInvalid;	// Mark the physical address as invalid.
sl@0
  2944
			r=(aIsContiguous) ? KErrGeneral : KErrNone;
sl@0
  2945
			}
sl@0
  2946
		if (r==0)
sl@0
  2947
			{
sl@0
  2948
			delete[] iPhysicalPages;	// We shouldn't retain this info. if the physical pages are contiguous.
sl@0
  2949
			iPhysicalPages=NULL;
sl@0
  2950
			}
sl@0
  2951
			
sl@0
  2952
		}
sl@0
  2953
	__KTRACE_OPT(KSOUND1, Kern::Printf("<TAudioBuffer::Create - %d",r));
sl@0
  2954
	return(r);
sl@0
  2955
	}
sl@0
  2956
sl@0
  2957
/**
sl@0
  2958
Calculate the length for the next part of a data transfer request so that that the length returned specifies a physically
sl@0
  2959
contiguous region and is also valid for the PDD. If necessary, return a truncated length that meets these criteria. Also,
sl@0
  2960
return the physical address of the start of the region specified.
sl@0
  2961
@param aChunkOffset The offset within the chunk for the start of the data transfer being fragmented.
sl@0
  2962
@param aLengthRemaining The remaining length of the data transfer request.
sl@0
  2963
@param aPhysAddr On return, this contains the physical address corresonding to aChunkOffset.
sl@0
  2964
@return The length calculated.
sl@0
  2965
*/	
sl@0
  2966
TInt TAudioBuffer::GetFragmentLength(TInt aChunkOffset,TInt aLengthRemaining,TPhysAddr& aPhysAddr)		
sl@0
  2967
	{
sl@0
  2968
	TInt len;
sl@0
  2969
	TInt bufOffset=(aChunkOffset - iChunkOffset); 	// Convert from chunk offset to buffer offset.
sl@0
  2970
	
sl@0
  2971
	if (iPhysicalAddress==KPhysAddrInvalid)
sl@0
  2972
		{
sl@0
  2973
		// Buffer is not physically contiguous. Truncate length to the next page boundary. Then calculate physical addr.
sl@0
  2974
		// (This function doesn't look for pages which are contiguous within the physical page list - but it could).
sl@0
  2975
		TInt pageSize=Kern::RoundToPageSize(1);
sl@0
  2976
		TInt pageOffset=bufOffset%pageSize;
sl@0
  2977
		len=pageSize - pageOffset;
sl@0
  2978
		aPhysAddr=iPhysicalPages[bufOffset/pageSize] + pageOffset;
sl@0
  2979
		}
sl@0
  2980
	else
sl@0
  2981
		{
sl@0
  2982
		// Buffer is physically contiguous so no need to truncate the length. Then calculate physical address.  
sl@0
  2983
		len=aLengthRemaining;
sl@0
  2984
		aPhysAddr=iPhysicalAddress + bufOffset;
sl@0
  2985
		}
sl@0
  2986
		
sl@0
  2987
	// Ensure length does not exceed the max. supported by the PDD.
sl@0
  2988
	len=Min(iBufManager->iMaxTransferLen,len);		
sl@0
  2989
	return(len);
sl@0
  2990
	}
sl@0
  2991
	
sl@0
  2992
/**
sl@0
  2993
Purge the entire audio buffer. That is, if it contains cacheable memory, flush it.
sl@0
  2994
@param aFlushOp The type of flush operation required - @see DBufferManager::TFlushOp.
sl@0
  2995
*/
sl@0
  2996
void TAudioBuffer::Flush(DBufferManager::TFlushOp aFlushOp)
sl@0
  2997
	{
sl@0
  2998
	iBufManager->FlushData(iChunkOffset,iSize,aFlushOp);
sl@0
  2999
	}
sl@0
  3000