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