kernel/eka/drivers/soundsc/soundldd.cpp
changeset 0 a41df078684a
child 15 4122176ea935
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     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",aTransferID,aBytesRecorded,aTransferResult));
       
  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 (aTransferID==iCurrentRecBufTf.iId || iState==EPaused)
       
  1669 		{
       
  1670 		// Update the count of bytes recorded.
       
  1671 		iBytesTransferred+=aBytesRecorded;
       
  1672 		
       
  1673 		// Update the transfer status of the current buffer.
       
  1674 		if (aTransferResult!=KErrNone)
       
  1675 			{
       
  1676 			// Transfer failed. Mark the buffer as being complete.
       
  1677 			iCurrentRecBufTf.iTfState=TSndScTransfer::ETfDone;	
       
  1678 			}
       
  1679 		else	
       
  1680 			iCurrentRecBufTf.SetCompleted(aBytesRecorded); // Transfer successful so update the progress.
       
  1681 		
       
  1682 		// Check if this is the PDD completing a fragment due to record being paused. In this situation we only allow the
       
  1683 		// PDD to complete one fragment.	
       
  1684 		TAudioBuffer* buf;
       
  1685 		if (iState==EPaused && ++iCompletesWhilePausedCount<2)
       
  1686 			{
       
  1687 			// Complete (i.e. abort) the transfer to the current buffer.
       
  1688 			iCurrentRecBufTf.iTfState=TSndScTransfer::ETfDone; 
       
  1689 			
       
  1690 			// Reset the transfer status for the pending record buffer. This will be switched to the current buffer later
       
  1691 			// in this function - ready for when record is resumed.
       
  1692 			buf=((DRecordBufferManager*)iBufManager)->GetNextRecordBuffer();
       
  1693 			iNextRecBufTf.Init((TUint)buf,buf->iChunkOffset,buf->iSize,buf);		// Use pointer to record buffer as unique ID
       
  1694 			}	
       
  1695 		
       
  1696 		// Check if we have just completed the transfer into the current buffer.	
       
  1697 		if (iCurrentRecBufTf.iTfState==TSndScTransfer::ETfDone)
       
  1698 			HandleCurrentRecordBufferDone(aTransferResult);
       
  1699 		}
       
  1700 			
       
  1701 	// If we're not paused then the PDD should now have the capacity to accept another transfer so queue as many
       
  1702 	// transfers on it as it can accept.
       
  1703 	if (iState==EActive)
       
  1704 		{
       
  1705 #ifdef _DEBUG	
       
  1706 		// Test settings - only possible in debug mode. Test LDD being slow servicing transfer completes from PDD. Disabled.
       
  1707 /*		if (iTestSettings & KSoundScTest_TransferTimeout)
       
  1708 			{
       
  1709 			iTestSettings&=(~KSoundScTest_TransferTimeout);
       
  1710 			Kern::NanoWait(500000000); // Pause for 0.5 second
       
  1711 			} */
       
  1712 #endif
       
  1713 		TInt r=StartNextRecordTransfers();
       
  1714 		if (r!=KErrNone)
       
  1715 			{
       
  1716 			// Problem starting the next transfer. That's fairly serious so complete all pending record requests and 
       
  1717 			// stop recording.
       
  1718 			Pdd()->StopTransfer();
       
  1719 			iReqQueue->CompleteAll(r,&iMutex);
       
  1720 			iState=EConfigured;
       
  1721 			}
       
  1722 		}
       
  1723 	return;
       
  1724 	}
       
  1725 	
       
  1726 /** Perform the necessary processing required when transfer into the current buffer is complete. This involves updating
       
  1727 the buffer lists and possibly complete a request back the client.
       
  1728 @param aTransferResult The result of the transfer being completed: KErrNone if successful, otherwise one of the other
       
  1729 	system wide error codes.
       
  1730 */
       
  1731 void DSoundScLdd::HandleCurrentRecordBufferDone(TInt aTransferResult)
       
  1732 	{
       
  1733 	TAudioBuffer* buf;
       
  1734 	
       
  1735 	// Flush the buffer before acquiring the mutex.
       
  1736 	buf=((DRecordBufferManager*)iBufManager)->GetCurrentRecordBuffer();
       
  1737 	buf->Flush(DBufferManager::EFlushAfterDmaRead);
       
  1738 	
       
  1739 	NKern::FMWait(&iMutex); 		// Acquire the buffer/request list mutex.
       
  1740 	
       
  1741 	// Update the buffer list (by either adding the current buffer to the completed list or the free list).
       
  1742 	TInt bytesRecorded=iCurrentRecBufTf.GetLengthTransferred();
       
  1743 	((DRecordBufferManager*)iBufManager)->SetBufferFilled(bytesRecorded,aTransferResult);
       
  1744     
       
  1745     // The pending buffer now becomes the current one and we need to get a new pending one.
       
  1746     iCurrentRecBufTf=iNextRecBufTf;
       
  1747     buf=((DRecordBufferManager*)iBufManager)->GetNextRecordBuffer();
       
  1748     iNextRecBufTf.Init((TUint)buf,buf->iChunkOffset,buf->iSize,buf);	// Use pointer to record buffer as unique ID
       
  1749     
       
  1750     // Check if there is a client record request pending.
       
  1751     if (!iReqQueue->IsEmpty())
       
  1752     	{
       
  1753     	// A record request is pending. Check if we have had an overflow since the last record request was completed.
       
  1754     	if (((DRecordBufferManager*)iBufManager)->iBufOverflow)
       
  1755     		{
       
  1756     		TSoundScRequest* req=iReqQueue->Remove();
       
  1757     		DThread* thread=req->iOwningThread;					// Take a copy before we free it.
       
  1758 			TClientRequest* clreq = req->iClientRequest;		// Take a copy before we free it.
       
  1759     		((DRecordBufferManager*)iBufManager)->iBufOverflow=EFalse;
       
  1760 			NKern::FMSignal(&iMutex); 							// Release the buffer/request list mutex.
       
  1761 			iReqQueue->Free(req);
       
  1762     		CompleteRequest(thread,NULL,KErrOverflow,clreq);			// Complete the request.
       
  1763     		}
       
  1764     	else
       
  1765     		{
       
  1766 	    	// Check there really is a buffer available. (There's no guarentee the one just completed hasn't
       
  1767 	    	// immediately been queued again: if the client has too many 'in-use' or the one completed was a NULL
       
  1768 	    	// transfer due to pausing).
       
  1769 			TAudioBuffer* buf=((DRecordBufferManager*)iBufManager)->GetBufferForClient();
       
  1770 			if (buf)
       
  1771 				{
       
  1772 				// There still a buffer available so complete the request.
       
  1773 				TSoundScRequest* req=iReqQueue->Remove();
       
  1774 				DThread* thread=req->iOwningThread;							// Take a copy before we free it.
       
  1775 				TClientRequest* clreq = req->iClientRequest;				// Take a copy before we free it.
       
  1776 				NKern::FMSignal(&iMutex); 	// Release the buffer/request list mutex.
       
  1777 				iReqQueue->Free(req);
       
  1778 				if (buf->iResult==KErrNone)
       
  1779 					{
       
  1780 					((TClientDataRequest<TInt>*)clreq)->Data() = buf->iBytesAdded;
       
  1781 					CompleteRequest(thread,NULL,buf->iChunkOffset,clreq);					// Complete the request.	
       
  1782 					}
       
  1783 				else	
       
  1784 					CompleteRequest(thread,NULL,buf->iResult,clreq);				// Complete the request.
       
  1785 				}
       
  1786 			else
       
  1787 				NKern::FMSignal(&iMutex); 	// Release the buffer/request list mutex.	
       
  1788     		}
       
  1789     	}
       
  1790     else
       
  1791     	NKern::FMSignal(&iMutex); 	// Release the buffer/request list mutex.	
       
  1792 	}
       
  1793 	
       
  1794 /**
       
  1795 This function starts the next record data transfer. It starts with the current record buffer - checking whether all of
       
  1796 this has now been transferred or queued for transfer. If not it breaks this down into transfers sizes which are
       
  1797 compatible with the PDD and then repeatedly attempts to queue these on the PDD until the PDF indicates that it can
       
  1798 accept no more transfers for the moment. If the record buffer is fully started in this way and the PDD still has the
       
  1799 capacity to accept more transfers then it moves on to start the pending record buffer.
       
  1800 @return Normally KErrNone unless the PDD incurs an error while attempting to start a new transfer.
       
  1801 */
       
  1802 TInt DSoundScLdd::StartNextRecordTransfers()
       
  1803 	{
       
  1804 	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd::StartNextRecordTransfers"));
       
  1805 	
       
  1806 	// First start with the current record buffer - keep queuing transfers either until this buffer is
       
  1807 	// fully started or until the PDD can accept no more transfers.
       
  1808 	TInt r=KErrNone;
       
  1809 	while (r==KErrNone && iCurrentRecBufTf.iTfState<TSndScTransfer::ETfFullyStarted)
       
  1810 		{
       
  1811 		TInt pos=iCurrentRecBufTf.GetStartOffset();
       
  1812 		TPhysAddr physAddr;
       
  1813 		TInt len=iCurrentRecBufTf.iAudioBuffer->GetFragmentLength(pos,iCurrentRecBufTf.GetNotStartedLen(),physAddr);
       
  1814 		
       
  1815 		r=Pdd()->TransferData(iCurrentRecBufTf.iId,(iBufManager->iChunkBase+pos),physAddr,len);
       
  1816 		__KTRACE_OPT(KSOUND1, Kern::Printf("<PDD:TransferData(off:%x len:%d) - %d",pos,len,r));
       
  1817 		if (r==KErrNone)
       
  1818 			iCurrentRecBufTf.SetStarted(len);	// Successfully queued a transfer - update the status.
       
  1819 		}
       
  1820 	
       
  1821 	// Either the current record transfer is now fully started, or the PDD can accept no more transfers
       
  1822 	// If the PDD can still accept more transfers then move on to the next record buffer - again, keep queuing
       
  1823 	// transfers either until this buffer is fully started or until the PDD can accept no more.
       
  1824 	while (r==KErrNone && iNextRecBufTf.iTfState<TSndScTransfer::ETfFullyStarted)
       
  1825 		{
       
  1826 		TInt pos=iNextRecBufTf.GetStartOffset();
       
  1827 		TPhysAddr physAddr;
       
  1828 		TInt len=iNextRecBufTf.iAudioBuffer->GetFragmentLength(pos,iNextRecBufTf.GetNotStartedLen(),physAddr);
       
  1829 		
       
  1830 		r=Pdd()->TransferData(iNextRecBufTf.iId,(iBufManager->iChunkBase+pos),physAddr,len);
       
  1831 		__KTRACE_OPT(KSOUND1, Kern::Printf("<PDD:TransferData(off:%x len:%d) - %d",pos,len,r));
       
  1832 		if (r==KErrNone)
       
  1833 			iNextRecBufTf.SetStarted(len);	// Successfully queued a transfer - update the status.
       
  1834 		}
       
  1835 	if (r==KErrNotReady)
       
  1836 		r=KErrNone;		// KErrNotReady means the PDD the cannot accept any more requests - this isn't an error.	
       
  1837 	return(r);	
       
  1838 	}	
       
  1839 	
       
  1840 /**
       
  1841 @publishedPartner
       
  1842 @prototype
       
  1843 
       
  1844 Called from the PDD each time it detects a change in the hardware configuration of the device.
       
  1845 @param aHeadsetPresent This is set by the PDD to ETrue if a microphone or headset socket is now present or EFalse if 
       
  1846 such a device is not present.
       
  1847 */
       
  1848 void DSoundScLdd::NotifyChangeOfHwConfigCallback(TBool aHeadsetPresent)
       
  1849 	{
       
  1850 #ifdef _DEBUG
       
  1851 #ifdef TEST_WITH_PAGING_CACHE_FLUSHES 
       
  1852 	Kern::HalFunction(EHalGroupVM,EVMHalFlushCache,0,0);
       
  1853 #endif
       
  1854 #endif
       
  1855 
       
  1856 	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd::NotifyChangeOfHwConfigCallback(Pres:%d)",aHeadsetPresent));
       
  1857 	
       
  1858 	__ASSERT_DEBUG(iCaps.iHwConfigNotificationSupport,Kern::Fault(KSoundLddPanic,__LINE__));		
       
  1859 	
       
  1860 	if (iNotifyChangeOfHwClientRequest->IsReady())
       
  1861 		{
       
  1862 		iNotifyChangeOfHwClientRequest->Data() = aHeadsetPresent;
       
  1863 		CompleteRequest(iChangeOfHwConfigThread,NULL,KErrNone,iNotifyChangeOfHwClientRequest);	// Complete the request.
       
  1864 		}
       
  1865 	}
       
  1866 	
       
  1867 /**
       
  1868 This function validates that a new sound format configuration is both sensible and supported by this device.
       
  1869 @param aConfig A reference to the new sound format configuration object.
       
  1870 */	
       
  1871 TInt DSoundScLdd::ValidateConfig(const TCurrentSoundFormatV02& aConfig)
       
  1872 	{
       
  1873 	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScLdd::ValidateConfig"));
       
  1874 	
       
  1875 	// Check that the audio channel configuration requested is sensible and supported by this device.
       
  1876 	if (aConfig.iChannels<0) 
       
  1877 		return(KErrNotSupported);
       
  1878 	TInt chans=(aConfig.iChannels-1);
       
  1879 	if (!(iCaps.iChannels & (1<<chans)))
       
  1880 		return(KErrNotSupported);
       
  1881 	
       
  1882 	// Check that the sample rate requested is sensible and supported by this device.
       
  1883 	if (aConfig.iRate<0 || !(iCaps.iRates & (1<<aConfig.iRate)))
       
  1884 		return(KErrNotSupported);
       
  1885 	
       
  1886 	// Check that the encoding format requested is sensible and supported by this device.
       
  1887 	if (aConfig.iEncoding<0 || !(iCaps.iEncodings & (1<<aConfig.iEncoding)))
       
  1888 		return(KErrNotSupported);
       
  1889 	
       
  1890 	// Check that the data format requested is sensible and supported by this device.
       
  1891 	if (aConfig.iDataFormat<0 || !(iCaps.iDataFormats & (1<<aConfig.iDataFormat)))
       
  1892 		return(KErrNotSupported);
       
  1893 		
       
  1894 	__KTRACE_OPT(KSOUND1, Kern::Printf("<DSoundScLdd::ValidateConfig - %d",KErrNone));
       
  1895 	return(KErrNone);
       
  1896 	}
       
  1897 	
       
  1898 /**
       
  1899 Increase or decrease the memory area allocated to hold the current buffer configuration in the play/record chunk.
       
  1900 @param aNumBuffers The number of buffers within the new buffer configuration. This determines the size of the memory
       
  1901 	area required.
       
  1902 @pre The thread must be in a critical section. 
       
  1903 */
       
  1904 TInt DSoundScLdd::ReAllocBufferConfigInfo(TInt aNumBuffers)
       
  1905 	{
       
  1906 	if (iBufConfig)
       
  1907 		{
       
  1908 		delete iBufConfig;
       
  1909 		iBufConfig=NULL;
       
  1910 		}	 
       
  1911 	
       
  1912 	iBufConfigSize=aNumBuffers*sizeof(TInt);	
       
  1913 	iBufConfigSize+=sizeof(TSharedChunkBufConfigBase);
       
  1914 	iBufConfig=(TSoundSharedChunkBufConfig*)Kern::AllocZ(iBufConfigSize);
       
  1915 	if (!iBufConfig)
       
  1916 		return(KErrNoMemory);	
       
  1917 	
       
  1918 	return(KErrNone);
       
  1919 	}
       
  1920 
       
  1921 /**
       
  1922 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
       
  1923 is allowed to expire, then the PDD is called to release any resources in use for playback transfer. 
       
  1924 */
       
  1925 void DSoundScLdd::StartPlayEofTimer()
       
  1926 	{
       
  1927 	iEofTimer.Cancel();
       
  1928 	iPlayEofDfc.Cancel();
       
  1929 	iEofTimer.OneShot(NKern::TimerTicks(2000)); // Queue the 2 second EOF timer to stop transfer on the PDD.
       
  1930 	iPlayEofTimerActive=ETrue;
       
  1931 	}
       
  1932 
       
  1933 /**
       
  1934 Cancel the EOF play timer. 
       
  1935 */	
       
  1936 void DSoundScLdd::CancelPlayEofTimer()
       
  1937 	{
       
  1938 	iEofTimer.Cancel();
       
  1939 	iPlayEofDfc.Cancel();
       
  1940 	iPlayEofTimerActive=EFalse;
       
  1941 	}
       
  1942 	
       
  1943 /**
       
  1944 @publishedPartner
       
  1945 @prototype
       
  1946 
       
  1947 Returns the buffer configuration of the play/record chunk.
       
  1948 @return A pointer to the current buffer configuration of the play/record chunk.
       
  1949 */	
       
  1950 TSoundSharedChunkBufConfig* DSoundScLdd::BufConfig()
       
  1951 	{
       
  1952 	return(iBufConfig);
       
  1953 	}
       
  1954 
       
  1955 /**
       
  1956 @publishedPartner
       
  1957 @prototype
       
  1958 
       
  1959 Returns the address of the start of the play/record chunk.
       
  1960 @return The linear address of the start of the play/record chunk.
       
  1961 */	
       
  1962 TLinAddr DSoundScLdd::ChunkBase()
       
  1963 	{
       
  1964 	return(iBufManager->iChunkBase);
       
  1965 	}			
       
  1966 		
       
  1967 /**
       
  1968 The ISR to handle the EOF play timer.
       
  1969 @param aChannel A pointer to the sound driver logical channel object.
       
  1970 */	
       
  1971 void DSoundScLdd::PlayEofTimerExpired(TAny* aChannel)
       
  1972 	{
       
  1973 	DSoundScLdd& drv=*(DSoundScLdd*)aChannel;
       
  1974 	
       
  1975 	drv.iPlayEofDfc.Add();
       
  1976 	}
       
  1977 	
       
  1978 /**
       
  1979 The DFC used to handle the EOF play timer. 
       
  1980 @param aChannel A pointer to the sound driver logical channel object.
       
  1981 */	
       
  1982 void DSoundScLdd::PlayEofTimerDfc(TAny* aChannel)
       
  1983 	{	
       
  1984 	DSoundScLdd& drv=*(DSoundScLdd*)aChannel;
       
  1985 	
       
  1986 	drv.Pdd()->StopTransfer();
       
  1987 	drv.iState=EConfigured;
       
  1988 	drv.iPlayEofTimerActive=EFalse;
       
  1989 	}				
       
  1990 	
       
  1991 /**
       
  1992 The DFC used to handle power down requests from the power manager before a transition into system
       
  1993 shutdown/standby.
       
  1994 @param aChannel A pointer to the sound driver logical channel object.
       
  1995 */
       
  1996 void DSoundScLdd::PowerDownDfc(TAny* aChannel)
       
  1997 	{
       
  1998 	DSoundScLdd& drv=*(DSoundScLdd*)aChannel;
       
  1999 	drv.Shutdown();
       
  2000 	drv.iPowerHandler->PowerDownDone();
       
  2001 	}
       
  2002 	
       
  2003 /**
       
  2004 The DFC used to handle power up requests from the power manager following a transition out of system standby.
       
  2005 @param aChannel A pointer to the sound driver logical channel object.
       
  2006 */	
       
  2007 void DSoundScLdd::PowerUpDfc(TAny* aChannel)
       
  2008 	{
       
  2009 	DSoundScLdd& drv=*(DSoundScLdd*)aChannel;
       
  2010 	
       
  2011 	// Restore the channel to a default state.
       
  2012 	drv.DoCancel(RSoundSc::EAllRequests);
       
  2013 	drv.Pdd()->PowerUp();
       
  2014 	drv.DoSetSoundConfig(drv.iSoundConfig);
       
  2015 	drv.SetVolume(drv.iVolume);			
       
  2016 	drv.iState=(!drv.iBufConfig)?EOpen:EConfigured;
       
  2017 	
       
  2018 	drv.iPowerHandler->PowerUpDone();
       
  2019 	}	
       
  2020 
       
  2021 /** 
       
  2022 Complete an asynchronous request back to the client.
       
  2023 @param aThread The client thread which issued the request.
       
  2024 @param aStatus The TRequestStatus instance that will receive the request status code or NULL if aClientRequest used. 
       
  2025 @param aReason The request status code.  
       
  2026 @param aClientRequest The TClientRequest instance that will receive the request status code or NULL if aStatus used. 
       
  2027 @pre The thread must be in a critical section. 
       
  2028 */
       
  2029 
       
  2030 void DSoundScLdd::CompleteRequest(DThread* aThread, TRequestStatus* aStatus, TInt aReason, TClientRequest* aClientRequest)
       
  2031 	{
       
  2032 	if (aClientRequest)
       
  2033 		{
       
  2034 		if (aClientRequest->IsReady())
       
  2035 			{
       
  2036 			Kern::QueueRequestComplete(aThread,aClientRequest,aReason);
       
  2037 			}
       
  2038 		else
       
  2039 			{
       
  2040 			// should always be ready
       
  2041 			__ASSERT_DEBUG(EFalse,Kern::Fault(KSoundLddPanic,__LINE__));
       
  2042 			}
       
  2043 		}
       
  2044 	else if (aStatus)
       
  2045 		{
       
  2046 		Kern::RequestComplete(aStatus,aReason);		// Complete the request back to the client.
       
  2047 		}
       
  2048 	else
       
  2049 		{
       
  2050 		// never get here - either aStatus or aClientRequest must be valid
       
  2051 		__ASSERT_DEBUG(EFalse,Kern::Fault(KSoundLddPanic,__LINE__));
       
  2052 		}
       
  2053 	
       
  2054 	aThread->AsyncClose();	// Asynchronously close our reference on the client thread - don't want to be blocked if this is final reference. 
       
  2055 	
       
  2056 #ifdef _DEBUG	
       
  2057 	__e32_atomic_add_ord32(&iThreadOpenCount, TUint32(-1));
       
  2058 #endif		
       
  2059 	}
       
  2060 
       
  2061 /**
       
  2062 Constructor for the play request object.
       
  2063 */
       
  2064 TSoundScPlayRequest::TSoundScPlayRequest()
       
  2065 	: TSoundScRequest()
       
  2066 	{
       
  2067 	iFlags=0; 
       
  2068 	iCompletionReason=KErrGeneral;
       
  2069 	}
       
  2070 
       
  2071 /*
       
  2072 Second phase construction of the requests
       
  2073 */
       
  2074 TInt TSoundScPlayRequest::Construct()
       
  2075 	{
       
  2076 	return Kern::CreateClientRequest(iClientRequest);
       
  2077 	}
       
  2078 
       
  2079 /*
       
  2080 Second phase construction of the requests
       
  2081 */
       
  2082 TInt TSoundScRequest::Construct()
       
  2083 	{
       
  2084 	TClientDataRequest<TInt>* tempClientDataRequest=0;
       
  2085 	TInt r = Kern::CreateClientDataRequest(tempClientDataRequest);
       
  2086 	iClientRequest = tempClientDataRequest;
       
  2087 	return r;
       
  2088 	}
       
  2089 
       
  2090 /**
       
  2091 Destructor of play requests
       
  2092 */
       
  2093 TSoundScRequest::~TSoundScRequest()
       
  2094 	{
       
  2095 	Kern::DestroyClientRequest(iClientRequest);
       
  2096 	}
       
  2097 
       
  2098 /**
       
  2099 Constructor for the request object queue.
       
  2100 */
       
  2101 TSoundScRequestQueue::TSoundScRequestQueue(DSoundScLdd* aLdd)
       
  2102 	{
       
  2103 	iLdd=aLdd;
       
  2104 	memclr(&iRequest[0],sizeof(TSoundScRequest*)*KMaxSndScRequestsPending);
       
  2105 	}
       
  2106 	
       
  2107 /**
       
  2108 Destructor for the request object queue.
       
  2109 */
       
  2110 TSoundScRequestQueue::~TSoundScRequestQueue()
       
  2111 	{
       
  2112 	for (TInt i=0 ; i<KMaxSndScRequestsPending ; i++)
       
  2113 		{
       
  2114 		delete iRequest[i];
       
  2115 		}
       
  2116 	}
       
  2117 	
       
  2118 /**
       
  2119 Second stage constructor for the basic request object queue.
       
  2120 @return KErrNone if successful, otherwise one of the other system wide error codes.
       
  2121 @pre The thread must be in a critical section.
       
  2122 */
       
  2123 TInt TSoundScRequestQueue::Create()	
       
  2124 	{
       
  2125 	// Create the set of available request objects and add them to the unused request queue. 	
       
  2126 	for (TInt i=0 ; i<KMaxSndScRequestsPending ; i++)
       
  2127 		{
       
  2128 		iRequest[i]=new TSoundScRequest;		// Normal request object
       
  2129 		if (!iRequest[i])
       
  2130 			return(KErrNoMemory);
       
  2131 		TInt retConstruct = iRequest[i]->Construct();
       
  2132 		if ( retConstruct != KErrNone)
       
  2133 			{
       
  2134 			return(retConstruct);
       
  2135 			}
       
  2136 		iUnusedRequestQ.Add(iRequest[i]);
       
  2137 		}
       
  2138 		
       
  2139 	return(KErrNone);
       
  2140 	}
       
  2141 		
       
  2142 /**
       
  2143 Second stage constructor for the play request object queue.
       
  2144 @return KErrNone if successful, otherwise one of the other system wide error codes.
       
  2145 @pre The thread must be in a critical section.
       
  2146 */
       
  2147 TInt TSoundScPlayRequestQueue::Create()	
       
  2148 	{
       
  2149 	// Create the set of available play request objects and add them to the unused request queue. 	
       
  2150 	for (TInt i=0 ; i<KMaxSndScRequestsPending ; i++)
       
  2151 		{
       
  2152 		iRequest[i]=new TSoundScPlayRequest();
       
  2153 		if (!iRequest[i])
       
  2154 			return(KErrNoMemory);
       
  2155 		TInt retConstruct = iRequest[i]->Construct();
       
  2156 		if ( retConstruct != KErrNone)
       
  2157 			{
       
  2158 			return(retConstruct);
       
  2159 			}
       
  2160 		iUnusedRequestQ.Add(iRequest[i]);
       
  2161 		}
       
  2162 		
       
  2163 	return(KErrNone);
       
  2164 	}	
       
  2165 
       
  2166 /**
       
  2167 Get an unused request object.
       
  2168 @return A pointer to a free request object or NULL if there are none available.
       
  2169 */ 	
       
  2170 TSoundScRequest* TSoundScRequestQueue::NextFree()
       
  2171 	{
       
  2172 	NKern::FMWait(&iUnusedRequestQLock);
       
  2173 	TSoundScRequest* req = (TSoundScRequest*)iUnusedRequestQ.GetFirst();
       
  2174 	NKern::FMSignal(&iUnusedRequestQLock);
       
  2175 	return req;
       
  2176 	}
       
  2177 		
       
  2178 /**
       
  2179 Add a request object to the tail of the pending request queue. 
       
  2180 @param aReq A pointer to the request object to be added to the queue.
       
  2181 */ 
       
  2182 void TSoundScRequestQueue::Add(TSoundScRequest* aReq)	
       
  2183 	{
       
  2184 	iPendRequestQ.Add(aReq);
       
  2185 	} 	
       
  2186 
       
  2187 /**
       
  2188 If the pending request queue is not empty, remove the request object from the head of this queue.
       
  2189 @return A pointer to request object removed or NULL if the list was empty.
       
  2190 */ 
       
  2191 TSoundScRequest* TSoundScRequestQueue::Remove()
       
  2192 	{
       
  2193 	return((TSoundScRequest*)iPendRequestQ.GetFirst());
       
  2194 	}
       
  2195 						
       
  2196 /**
       
  2197 Remove a request object from anywhere in the pending request queue. 
       
  2198 @param aReq A pointer to the request object to be removed from the queue.
       
  2199 @return A pointer to request object removed or NULL if it wasn't found.
       
  2200 */	
       
  2201 TSoundScRequest* TSoundScRequestQueue::Remove(TSoundScRequest* aReq)	
       
  2202 	{
       
  2203 	TSoundScRequest* retReq;
       
  2204 	
       
  2205 	// Scan through the pending queue looking for a request object which matches.
       
  2206 	retReq=(TSoundScRequest*)iPendRequestQ.First();
       
  2207 	while (!IsAnchor(retReq) && retReq!=aReq)
       
  2208 		retReq=(TSoundScRequest*)retReq->iNext;
       
  2209 	
       
  2210 	// If we got a match then remove the request object from the queue and return it.
       
  2211 	if (!IsAnchor(retReq))
       
  2212 		retReq->Deque();
       
  2213 	else
       
  2214 		retReq=NULL;
       
  2215 	return(retReq);
       
  2216 	}
       
  2217 
       
  2218 /**
       
  2219 Free up a request object - making it available for further requests. 
       
  2220 @param aReq A pointer to the request object being freed up.
       
  2221 */ 
       
  2222 void TSoundScRequestQueue::Free(TSoundScRequest* aReq)	
       
  2223 	{
       
  2224 	NKern::FMWait(&iUnusedRequestQLock);
       
  2225 	iUnusedRequestQ.Add(aReq);
       
  2226 	NKern::FMSignal(&iUnusedRequestQLock);
       
  2227 	}
       
  2228 	 
       
  2229 /**
       
  2230 Find a request object (specified by its associated request status pointer) within in the pending request queue. 
       
  2231 @param aStatus The request status pointer of the request object to be found in the queue.
       
  2232 @return A pointer to the request object if it was found or NULL if it wasn't found.
       
  2233 */	
       
  2234 TSoundScRequest* TSoundScRequestQueue::Find(TRequestStatus* aStatus)	
       
  2235 	{
       
  2236 	TSoundScRequest* retReq;
       
  2237 	
       
  2238 	// Scan through the queue looking for a request object containing a TRequestStatus* which matches.
       
  2239 	retReq=(TSoundScRequest*)iPendRequestQ.First();
       
  2240 	while (!IsAnchor(retReq) && retReq->iClientRequest->StatusPtr()!=aStatus)
       
  2241 		retReq=(TSoundScRequest*)retReq->iNext;
       
  2242 		
       
  2243 	return((IsAnchor(retReq))?NULL:retReq);
       
  2244 	}				
       
  2245 	
       
  2246 /**
       
  2247 Remove each request object from the pending request queue, completing each request removed with a specified completion
       
  2248 reason.
       
  2249 @param aCompletionReason The error value to be returned when completing any requests in the queue.
       
  2250 @param aMutex A pointer to a mutex to be aquired when removing requests from the queue. May be NULL.
       
  2251 */		
       
  2252 void TSoundScRequestQueue::CompleteAll(TInt aCompletionReason,NFastMutex* aMutex)	
       
  2253 	{
       
  2254 	if (aMutex)
       
  2255 		NKern::FMWait(aMutex); 							// Acquire the mutex.
       
  2256 	
       
  2257 	TSoundScRequest* req;
       
  2258 	while ((req=Remove())!=NULL)
       
  2259 		{
       
  2260 		if (aMutex)
       
  2261 			NKern::FMSignal(aMutex); 					// Release the mutex while we complete the request.
       
  2262 		iLdd->CompleteRequest(req->iOwningThread,NULL,aCompletionReason,req->iClientRequest);	
       
  2263 		Free(req);	
       
  2264 		if (aMutex)
       
  2265 			NKern::FMWait(aMutex); 						// Re-acquire the mutex.
       
  2266 
       
  2267 		}
       
  2268 		
       
  2269 	if (aMutex)	
       
  2270 		NKern::FMSignal(aMutex); 						// Release mutex.	
       
  2271 	}
       
  2272 
       
  2273 /**
       
  2274 Constructor for the play request object queue.
       
  2275 */					
       
  2276 TSoundScPlayRequestQueue::TSoundScPlayRequestQueue(DSoundScLdd* aLdd)
       
  2277 	: TSoundScRequestQueue(aLdd)
       
  2278 {
       
  2279 }
       
  2280 
       
  2281 /**
       
  2282 Return the play request object from the request queue which is next to be transferrred. If this
       
  2283 play request is being handled using multiple data transfers then the transfer of earlier parts of
       
  2284 this request may already be in progress. 
       
  2285 @return Either a pointer to the next play request object for transfer, or NULL if no more are pending. 	
       
  2286 */
       
  2287 TSoundScPlayRequest* TSoundScPlayRequestQueue::NextRequestForTransfer()
       
  2288 	{
       
  2289 	TSoundScPlayRequest* retReq;
       
  2290 	
       
  2291 	retReq=(TSoundScPlayRequest*)iPendRequestQ.First();
       
  2292 	while (!IsAnchor(retReq) && retReq->iTf.iTfState>TSndScTransfer::ETfPartlyStarted)
       
  2293 		retReq=(TSoundScPlayRequest*)retReq->iNext;
       
  2294 		
       
  2295 	return((IsAnchor(retReq))?NULL:retReq);	
       
  2296 	}	
       
  2297 
       
  2298 /**
       
  2299 Search the play request queue for a particular play request object specified by its transfer ID.
       
  2300 @param aTransferID The transfer ID of the particular play request object to be found.
       
  2301 @param aIsNextToComplete If the search is successful then this indicates whether the request 
       
  2302 object found is the next in the queue to be completed to the client. ETrue if next to be 
       
  2303 completed, EFalse otherwise.
       
  2304 @return Either a pointer to the specified request object, or NULL if it was not found.
       
  2305 */	
       
  2306 TSoundScPlayRequest* TSoundScPlayRequestQueue::Find(TUint aTransferID,TBool& aIsNextToComplete)
       
  2307 	{
       
  2308 	TSoundScPlayRequest* retReq;
       
  2309 	TSoundScPlayRequest* nextToCompleteReq=NULL;
       
  2310 	
       
  2311 	retReq=(TSoundScPlayRequest*)iPendRequestQ.First();
       
  2312 	
       
  2313 	// Walk all the way through the list either until we find the specified object or until we get to the end
       
  2314 	for ( ; !IsAnchor(retReq) ; retReq=(TSoundScPlayRequest*)retReq->iNext )
       
  2315 		{
       
  2316 		// The first request we find which isn't complete must be the next to complete
       
  2317 		if (!nextToCompleteReq && retReq->iTf.iTfState!=TSndScTransfer::ETfDone)
       
  2318 			nextToCompleteReq=retReq;
       
  2319 		if (retReq->iTf.iId==aTransferID)
       
  2320 			break;
       
  2321 		}
       
  2322 	
       
  2323 	if (IsAnchor(retReq))
       
  2324 		return(NULL);		// Object not found
       
  2325 	else
       
  2326 		{
       
  2327 		aIsNextToComplete=(retReq==nextToCompleteReq);
       
  2328 		return(retReq);		// Object found
       
  2329 		}
       
  2330 	}					
       
  2331 /**
       
  2332 Constructor for the audio data transfer class. 
       
  2333 */	
       
  2334 TSndScTransfer::TSndScTransfer()
       
  2335 	{
       
  2336 	iId=0;
       
  2337 	iTfState=ETfNotStarted;
       
  2338 	iAudioBuffer=NULL;
       
  2339 	iLengthTransferred=0;
       
  2340 	iTransfersInProgress=0;
       
  2341 	}
       
  2342 	
       
  2343 /**
       
  2344 Initialisation function for the audio data transfer class.
       
  2345 @param aId A value to uniquely identify this particular transfer.
       
  2346 @param aChunkOffset The start postition of the transfer - an offset within the shared chunk.
       
  2347 @param aLength The total length of the transfer in bytes.
       
  2348 @param anAudioBuffer The audio buffer associated with the transfer.
       
  2349 */		
       
  2350 void TSndScTransfer::Init(TUint aId,TInt aChunkOffset,TInt aLength,TAudioBuffer* anAudioBuffer)
       
  2351 	{
       
  2352 	iId=aId;
       
  2353 	iTfState=ETfNotStarted;
       
  2354 	iAudioBuffer=anAudioBuffer;
       
  2355 	iStartedOffset=aChunkOffset;
       
  2356 	iEndOffset=aChunkOffset+aLength;
       
  2357 	iLengthTransferred=0;
       
  2358 	iTransfersInProgress=0;
       
  2359 	}
       
  2360 	
       
  2361 /**
       
  2362 Update the progress of the audio data transfer with the amount of data now queued for transfer on the audio device.
       
  2363 @param aLength The amount of data (in bytes) that has just been queued on the audio device.
       
  2364 */
       
  2365 void TSndScTransfer::SetStarted(TInt aLength)
       
  2366 	{	
       
  2367 	iTransfersInProgress++;
       
  2368 	iStartedOffset+=aLength;
       
  2369 	TInt notqueued=(iEndOffset - iStartedOffset);
       
  2370 	__ASSERT_ALWAYS(notqueued>=0,Kern::Fault(KSoundLddPanic,__LINE__));
       
  2371 	iTfState=(notqueued) ? ETfPartlyStarted : ETfFullyStarted;
       
  2372 	}
       
  2373 	
       
  2374 /**
       
  2375 Update the progress of the audio data transfer with the amount of data now successfully transfered by the audio device.
       
  2376 @param aLength The amount of data (in bytes) that has just been transferred by the audio device.
       
  2377 @return ETrue if the transfer is now fully complete, otherwise EFalse.
       
  2378 */
       
  2379 TBool TSndScTransfer::SetCompleted(TInt aLength)
       
  2380 	{		
       
  2381 	iLengthTransferred+=aLength;
       
  2382 	iTransfersInProgress--;
       
  2383 	__ASSERT_ALWAYS(iTransfersInProgress>=0,Kern::Fault(KSoundLddPanic,__LINE__));
       
  2384 	
       
  2385 	if (GetNotStartedLen()==0 && iTransfersInProgress==0)
       
  2386 		{
       
  2387 		iTfState=ETfDone;	// Transfer is now fully completed
       
  2388 		return(ETrue);
       
  2389 		}
       
  2390 	else
       
  2391 		return(EFalse);	
       
  2392 	}
       
  2393 		
       
  2394 /**
       
  2395 Constructor for the sound driver power handler class.
       
  2396 @param aChannel A pointer to the sound driver logical channel which owns this power handler.
       
  2397 */
       
  2398 DSoundScPowerHandler::DSoundScPowerHandler(DSoundScLdd* aChannel)
       
  2399 :	DPowerHandler(KDevSoundScName),
       
  2400 	iChannel(aChannel)
       
  2401 	{	
       
  2402 	}
       
  2403 
       
  2404 /**
       
  2405 A request from the power manager for the power down of the audio device.
       
  2406 This is called during a transition of the phone into standby or power off.
       
  2407 @param aState The target power state; can be EPwStandby or EPwOff only.
       
  2408 */
       
  2409 void DSoundScPowerHandler::PowerDown(TPowerState aPowerState)
       
  2410 	{
       
  2411 	(void)aPowerState;
       
  2412 	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScPowerHandler::PowerDown(State-%d)",aPowerState));
       
  2413 	
       
  2414 	// Power-down involves hardware access so queue a DFC to perform this from the driver thread.
       
  2415 	iChannel->iPowerDownDfc.Enque();
       
  2416 	}
       
  2417 
       
  2418 /**
       
  2419 A request from the power manager for the power up of the audio device.
       
  2420 This is called during a transition of the phone out of standby.
       
  2421 */
       
  2422 void DSoundScPowerHandler::PowerUp()
       
  2423 	{
       
  2424 	__KTRACE_OPT(KSOUND1, Kern::Printf(">DSoundScPowerHandler::PowerUp"));
       
  2425 	
       
  2426 	// Power-up involves hardware access so queue a DFC to perform this from the driver thread.
       
  2427 	iChannel->iPowerUpDfc.Enque();
       
  2428 	}	
       
  2429 
       
  2430 /**
       
  2431 Constructor for the buffer manager.
       
  2432 */
       
  2433 DBufferManager::DBufferManager(DSoundScLdd* aLdd)
       
  2434 	: iLdd(aLdd)
       
  2435 	{
       
  2436 //	iChunk=NULL;
       
  2437 //	iNumBuffers=0;
       
  2438 //	iAudioBuffers=NULL;	
       
  2439 //	iMaxTransferLen=0;	
       
  2440 	}
       
  2441 
       
  2442 /**
       
  2443 Destructor for the buffer manager.
       
  2444 @pre The thread must be in a critical section.
       
  2445 */
       
  2446 DBufferManager::~DBufferManager()
       
  2447 	{
       
  2448 	if (iChunk)
       
  2449 		Kern::ChunkClose(iChunk);
       
  2450 	delete[] iAudioBuffers;
       
  2451 	}
       
  2452 		
       
  2453 /**
       
  2454 Second stage constructor for the buffer manager. This version creates a shared chunk and a buffer object for each
       
  2455 buffer specified within this. Then it commits memory within the chunk for each of these buffers. This also involves the
       
  2456 creation of a set of buffer lists to manage the buffers.
       
  2457 @param aBufConfig The shared chunk buffer configuration object specifying the geometry of the buffer configuration
       
  2458 required.
       
  2459 @return KErrNone if successful, otherwise one of the other system wide error codes.
       
  2460 @pre The thread must be in a critical section.
       
  2461 */
       
  2462 TInt DBufferManager::Create(TSoundSharedChunkBufConfig* aBufConfig)
       
  2463 	{
       
  2464 	__KTRACE_OPT(KSOUND1, Kern::Printf(">DBufferManager::Create(Bufs-%d,Sz-%d)",aBufConfig->iNumBuffers,aBufConfig->iBufferSizeInBytes));
       
  2465 
       
  2466 	// Create the required number of buffer objects, and the buffer lists to manage these.
       
  2467 	TInt r=CreateBufferLists(aBufConfig->iNumBuffers);
       
  2468 	if (r!=KErrNone)
       
  2469 		return(r);
       
  2470 		
       
  2471 	TInt chunkSz;
       
  2472 	TInt bufferSz=aBufConfig->iBufferSizeInBytes;
       
  2473 	TInt* bufferOffsetList=&aBufConfig->iBufferOffsetListStart;	
       
  2474 	
       
  2475 	// Calculate the required size for the chunk and the buffer offsets. 
       
  2476 	if (aBufConfig->iFlags & KScFlagUseGuardPages)
       
  2477 		{
       
  2478 		// Commit each buffer separately with an uncommitted guard pages around each buffer.
       
  2479 		TInt guardPageSize=Kern::RoundToPageSize(1);
       
  2480 		bufferSz=Kern::RoundToPageSize(aBufConfig->iBufferSizeInBytes); // Commit size to be a multiple of the MMU page size.
       
  2481 		chunkSz=guardPageSize;											// Leave an un-committed guard page at the start.
       
  2482 		for (TInt i=0 ; i<aBufConfig->iNumBuffers ; i++)
       
  2483 			{
       
  2484 			bufferOffsetList[i]=chunkSz;
       
  2485 			chunkSz += (bufferSz + guardPageSize);						// Leave an un-committed guard page after each buffer.
       
  2486 			}
       
  2487 		}
       
  2488 	else
       
  2489 		{
       
  2490 		// Commit all the buffers contiguously into a single region (ie with no guard pages between each buffer).
       
  2491 		chunkSz=0;
       
  2492 		for (TInt i=0 ; i<aBufConfig->iNumBuffers ; i++)
       
  2493 			{
       
  2494 			bufferOffsetList[i]=chunkSz;
       
  2495 			chunkSz += bufferSz;
       
  2496 			}
       
  2497 		chunkSz=Kern::RoundToPageSize(chunkSz);							// Commit size to be a multiple of the MMU page size.
       
  2498 		}	
       
  2499 	aBufConfig->iFlags|=KScFlagBufOffsetListInUse;
       
  2500 	__KTRACE_OPT(KSOUND1, Kern::Printf("Chunk size is %d bytes",chunkSz));	
       
  2501     
       
  2502     // Create the shared chunk. The PDD supplies most of the chunk create info - but not the maximum size.
       
  2503 	TChunkCreateInfo info;
       
  2504 	info.iMaxSize=chunkSz;
       
  2505 	iLdd->Pdd()->GetChunkCreateInfo(info);		// Call down to the PDD for the rest.
       
  2506 	
       
  2507 	r = Kern::ChunkCreate(info,iChunk,iChunkBase,iChunkMapAttr);
       
  2508 	__KTRACE_OPT(KSOUND1, Kern::Printf("Create chunk - %d",r));	
       
  2509 	if (r!=KErrNone)
       
  2510      	return(r);
       
  2511 	
       
  2512 	if (aBufConfig->iFlags & KScFlagUseGuardPages)
       
  2513 		{
       
  2514 		// Map each of the buffers into the chunk separately - try to allocate physically contiguous RAM pages. Create a buffer object for each buffer.
       
  2515  		TBool isContiguous;
       
  2516  		for (TInt i=0 ; i<aBufConfig->iNumBuffers ; i++)
       
  2517 			{
       
  2518 			r=CommitMemoryForBuffer(bufferOffsetList[i],bufferSz,isContiguous);
       
  2519 			if (r!=KErrNone)
       
  2520 				return(r);
       
  2521 			r=iAudioBuffers[i].Create(iChunk,bufferOffsetList[i],(aBufConfig->iBufferSizeInBytes),isContiguous,this);
       
  2522 			if (r!=KErrNone)
       
  2523 				return(r);	
       
  2524 			}		
       
  2525 		}
       
  2526 	else
       
  2527 		{
       
  2528 		// Map memory for the all buffers into the chunk - try to allocate physically contiguous RAM pages. 
       
  2529  		TBool isContiguous;
       
  2530 		r=CommitMemoryForBuffer(0,chunkSz,isContiguous);
       
  2531 		if (r!=KErrNone)
       
  2532 			return(r);
       
  2533 		
       
  2534 		// Create a buffer object for each buffer.
       
  2535  		for (TInt i=0 ; i<aBufConfig->iNumBuffers ; i++)
       
  2536 			{
       
  2537 			r=iAudioBuffers[i].Create(iChunk,bufferOffsetList[i],(aBufConfig->iBufferSizeInBytes),isContiguous,this);
       
  2538 			if (r!=KErrNone)
       
  2539 				return(r);	
       
  2540 			}	
       
  2541 		}
       
  2542 
       
  2543 	// Read back and store the maximum transfer length supported by this device from the PDD.
       
  2544 	iMaxTransferLen=iLdd->Pdd()->MaxTransferLen();
       
  2545 	
       
  2546     __KTRACE_OPT(KSOUND1, Kern::Printf("<DBufferManager::Create - %d",r));
       
  2547 	return(r);
       
  2548 	}
       
  2549 	
       
  2550 /**
       
  2551 Second stage constructor for the buffer manager. This version opens an existing shared chunk using a client supplied
       
  2552 handle. It then creates a buffer object for each buffer that exists within the chunk as well as creating a set of buffer
       
  2553 lists to manage the buffers.
       
  2554 @param aBufConfig The shared chunk buffer configuration object - specifying the geometry of the buffer configuration
       
  2555 within the shared chunk supplied.
       
  2556 @param aChunkHandle A handle for the shared chunk supplied by the client.
       
  2557 @param anOwningThread The thread in which the given handle is valid.
       
  2558 @return KErrNone if successful, otherwise one of the other system wide error codes.
       
  2559 @pre The thread must be in a critical section.
       
  2560 */
       
  2561 TInt DBufferManager::Create(TSoundSharedChunkBufConfig& aBufConfig,TInt aChunkHandle,DThread* anOwningThread)
       
  2562 	{	
       
  2563 	__KTRACE_OPT(KSOUND1, Kern::Printf(">DBufferManager::Create(Handle-%d)",aChunkHandle));
       
  2564 
       
  2565 	// Validate the buffer configuration information.
       
  2566 	if (!aBufConfig.iFlags&KScFlagBufOffsetListInUse)
       
  2567 		return(KErrArgument);
       
  2568 	TInt numBuffers=aBufConfig.iNumBuffers;
       
  2569 	TInt bufferSizeInBytes=aBufConfig.iBufferSizeInBytes;
       
  2570 	TInt* bufferOffsetList=&aBufConfig.iBufferOffsetListStart;
       
  2571 	TInt r=ValidateBufferOffsets(bufferOffsetList,numBuffers,bufferSizeInBytes);
       
  2572 	if (r<0)
       
  2573 		return(r);
       
  2574 	
       
  2575 	// Create the required number of buffer objects, and the buffer lists to manage these.
       
  2576 	r=CreateBufferLists(numBuffers);
       
  2577 	if (r!=KErrNone)
       
  2578 		return(r);
       
  2579 	
       
  2580 	// Open the shared chunk.
       
  2581 	DChunk* chunk;
       
  2582 	chunk=Kern::OpenSharedChunk(anOwningThread,aChunkHandle,ETrue);
       
  2583 	if (!chunk)
       
  2584 		return(KErrBadHandle);
       
  2585 	iChunk=chunk;
       
  2586 	
       
  2587 	// Read the physical address for the 1st buffer in order to determine the kernel address and the map attributes.
       
  2588 	TInt offset=bufferOffsetList[0];
       
  2589 	TPhysAddr physAddr;
       
  2590 	TLinAddr kernelAddress;
       
  2591 	r=Kern::ChunkPhysicalAddress(iChunk,offset,bufferSizeInBytes,kernelAddress,iChunkMapAttr,physAddr,NULL);
       
  2592 	if (r!=KErrNone)
       
  2593 		return(r);
       
  2594 	iChunkBase=(kernelAddress-offset);
       
  2595 	
       
  2596 	// For each buffer, validate that the buffer specified contains committed memory and store the buffer info. into each buffer object.
       
  2597 	while (numBuffers)
       
  2598 		{
       
  2599 		numBuffers--;
       
  2600 		offset=bufferOffsetList[numBuffers];
       
  2601 		// Assume it isn't contiguous here - Create() will detect and do the right thing if it is contiguous.
       
  2602 		r=iAudioBuffers[numBuffers].Create(iChunk,offset,bufferSizeInBytes,EFalse,this);	
       
  2603 		if (r!=KErrNone)
       
  2604 			return(r);
       
  2605 		}
       
  2606 		
       
  2607 	// Read back and store the maximum transfer length supported by this device from the PDD.
       
  2608 	iMaxTransferLen=iLdd->Pdd()->MaxTransferLen();	
       
  2609 		
       
  2610 	__KTRACE_OPT(KSOUND1, Kern::Printf("<DBufferManager::Create - %d",KErrNone));
       
  2611 	return(KErrNone);
       
  2612 	}
       
  2613 
       
  2614 /**
       
  2615 Allocate an array of buffer objects, - one for each buffer contained within the shared chunk.
       
  2616 @param aNumBuffers The number of buffer objects required.
       
  2617 @return KErrNone if successful, otherwise one of the other system wide error codes.
       
  2618 @pre The thread must be in a critical section.
       
  2619 */
       
  2620 TInt DBufferManager::CreateBufferLists(TInt aNumBuffers)
       
  2621 	{
       
  2622 	__KTRACE_OPT(KSOUND1, Kern::Printf(">DBufferManager::CreateBufferLists(Bufs-%d)",aNumBuffers));
       
  2623 
       
  2624 	// Construct the array of buffers.
       
  2625 	iNumBuffers=aNumBuffers;
       
  2626 	iAudioBuffers=new TAudioBuffer[aNumBuffers];
       
  2627 	if (!iAudioBuffers)
       
  2628 		return(KErrNoMemory);
       
  2629 	
       
  2630 	return(KErrNone);
       
  2631 	}
       
  2632 	
       
  2633 /**
       
  2634 Validate a shared chunk buffer offset list.
       
  2635 @param aBufferOffsetList The buffer offset list to be validated.
       
  2636 @param aNumBuffers The number of offsets that the list contains.
       
  2637 @param aBufferSizeInBytes The size in bytes of each buffer.
       
  2638 @return If the buffer list is found to be valid, the calculated minimum size of the corresponding chunk is returned
       
  2639 	(i.e. a value>=0). Otherwise, KErrArgument is returned.
       
  2640 */
       
  2641 TInt DBufferManager::ValidateBufferOffsets(TInt* aBufferOffsetList,TInt aNumBuffers,TInt aBufferSizeInBytes)	
       
  2642 	{
       
  2643 	TUint32 alignmask=(1<<iLdd->iCaps.iRequestAlignment)-1; // iRequestAlignment holds log to base 2 of alignment required
       
  2644 			
       
  2645 	// Verify each of the buffer offsets supplied
       
  2646 	TInt offset=0;
       
  2647 	for (TInt i=0 ; i<aNumBuffers ; i++)
       
  2648 		{
       
  2649 		// If this is a record channel then the offset must comply with the PDD alignment constraints.
       
  2650 		if (iLdd->iDirection==ESoundDirRecord && ((TUint32)aBufferOffsetList[i] & alignmask) != 0)	
       
  2651 			return(KErrArgument);
       
  2652 			
       
  2653 		// Check the offset doesn't overlap the previous buffer - offset holds the offset to next byte after
       
  2654 		// the previous buffer.
       
  2655 		if (aBufferOffsetList[i]<offset)
       
  2656 			return(KErrArgument);
       
  2657 		
       
  2658 		offset=(aBufferOffsetList[i]+aBufferSizeInBytes);
       
  2659 		}
       
  2660 	return(offset);	
       
  2661 	}
       
  2662 	
       
  2663 /**
       
  2664 Verify that a specified region of the shared chunk (specified by its offset and length) is valid within the 
       
  2665 chunk and corresponds to a region of committed memory.
       
  2666 @param aChunkOffset Offset of the region from the beginning of the chunk.
       
  2667 @param aLength The length in bytes of the region.
       
  2668 @param anAudioBuffer A reference to a pointer to an audio buffer object. On return this will either contain a pointer
       
  2669 to the audio buffer object which corresonds to the specified region, or NULL if the region is invalid.
       
  2670 @return KErrNone if the region is valid, otherwise KErrArgument.
       
  2671 */	
       
  2672 TInt DBufferManager::ValidateRegion(TUint aChunkOffset,TUint aLength,TAudioBuffer*& anAudioBuffer)
       
  2673 	{
       
  2674 	
       
  2675 	TUint bufStart;
       
  2676 	TUint bufEnd;
       
  2677 	TUint regEnd=(aChunkOffset+aLength);
       
  2678 	for (TInt i=0 ; i<iNumBuffers ; i++)
       
  2679 		{
       
  2680 		bufStart=iAudioBuffers[i].iChunkOffset;
       
  2681 		bufEnd=iAudioBuffers[i].iChunkOffset+iAudioBuffers[i].iSize;
       
  2682 		if (aChunkOffset<bufStart || aChunkOffset>=bufEnd)
       
  2683 			continue;
       
  2684 		if (regEnd<=bufEnd)
       
  2685 			{
       
  2686 			anAudioBuffer=&iAudioBuffers[i];
       
  2687 			return(KErrNone);
       
  2688 			}
       
  2689 		}
       
  2690 	return(KErrArgument);
       
  2691 	}
       
  2692 			
       
  2693 /**
       
  2694 Commit memory for a single buffer within the shared chunk.
       
  2695 @param aChunkOffset The offset (in bytes) from start of chunk, which indicates the start of the memory region to be
       
  2696 	committed. Must be a multiple of the MMU page size. 
       
  2697 @param aSize The number of bytes to commit. Must be a multiple of the MMU page size.
       
  2698 @param aIsContiguous On return, this is set to ETrue if the function succeeded in committing physically contiguous memory;
       
  2699 	EFalse if the committed memory is not contiguous.	
       
  2700 @return KErrNone if successful, otherwise one of the other system wide error codes.
       
  2701 */	
       
  2702 TInt DBufferManager::CommitMemoryForBuffer(TInt aChunkOffset,TInt aSize,TBool& aIsContiguous)
       
  2703 	{
       
  2704 	__KTRACE_OPT(KSOUND1, Kern::Printf(">DBufferManager::CommitMemoryForBuffer(Offset-%x,Sz-%d)",aChunkOffset,aSize));
       
  2705 	
       
  2706 	// Try for physically contiguous memory first.
       
  2707 	TInt r;	
       
  2708 	TPhysAddr physicalAddress;
       
  2709 	r=Kern::ChunkCommitContiguous(iChunk,aChunkOffset,aSize,physicalAddress);
       
  2710 	if (r==KErrNone)
       
  2711 		{
       
  2712 		aIsContiguous=ETrue;
       
  2713 		return(r);
       
  2714 		}
       
  2715 			
       
  2716 	// Try to commit memory that isn't contiguous instead.
       
  2717 	aIsContiguous=EFalse;
       
  2718 	r=Kern::ChunkCommit(iChunk,aChunkOffset,aSize);
       
  2719 	return(r);
       
  2720 	}
       
  2721 	
       
  2722 /**
       
  2723 Purge a region of the audio chunk. That is, if this region contains cacheable memory, flush it.
       
  2724 @param aChunkOffset The offset within the chunk for the start of the data to be flushed.
       
  2725 @param aLength The length in bytes of the region to be flushed.
       
  2726 @param aFlushOp The type of flush operation required - @see TFlushOp.
       
  2727 */
       
  2728 void DBufferManager::FlushData(TInt aChunkOffset,TInt aLength,TFlushOp aFlushOp)
       
  2729 	{
       
  2730 	__KTRACE_OPT(KSOUND1, Kern::Printf(">DBufferManager::FlushData(%d)",aFlushOp));
       
  2731 	TLinAddr dataAddr=(iChunkBase+aChunkOffset);
       
  2732 	switch (aFlushOp)
       
  2733 		{
       
  2734 		case EFlushBeforeDmaWrite:
       
  2735 			Cache::SyncMemoryBeforeDmaWrite(dataAddr,aLength,iChunkMapAttr);
       
  2736 			break;
       
  2737 		case EFlushBeforeDmaRead:
       
  2738 			Cache::SyncMemoryBeforeDmaRead(dataAddr,aLength,iChunkMapAttr);
       
  2739 			break;
       
  2740 		case EFlushAfterDmaRead:
       
  2741 			Cache::SyncMemoryAfterDmaRead(dataAddr,aLength);
       
  2742 			break;
       
  2743 		default:
       
  2744 			break;
       
  2745 		}
       
  2746 	}
       
  2747 		
       
  2748 /**
       
  2749 Constructor for the record buffer manager.
       
  2750 */
       
  2751 DRecordBufferManager::DRecordBufferManager(DSoundScLdd* aLdd)
       
  2752 	: DBufferManager(aLdd)
       
  2753 	{
       
  2754 	}
       
  2755 			
       
  2756 /**
       
  2757 Reset all the audio buffer lists to reflect the state at the start of the record capture process.
       
  2758 @pre The buffer/request queue mutex must be held.
       
  2759 */
       
  2760 void DRecordBufferManager::Reset()
       
  2761 	{
       
  2762 	__KTRACE_OPT(KSOUND1, Kern::Printf(">DBufferManager::Reset"));
       
  2763 	TAudioBuffer* pBuf;
       
  2764 	
       
  2765 	// Before reseting buffer lists, purge the cache for all cached buffers currently in use by client.
       
  2766 	pBuf=(TAudioBuffer*)iInUseBufferQ.First();
       
  2767 	SDblQueLink* anchor=&iInUseBufferQ.iA;
       
  2768 	while (pBuf!=anchor)
       
  2769 		{
       
  2770 		pBuf->Flush(DBufferManager::EFlushBeforeDmaRead);
       
  2771 		pBuf=(TAudioBuffer*)pBuf->iNext;
       
  2772 		}
       
  2773 		
       
  2774 	// Start by reseting all the lists.
       
  2775 	iFreeBufferQ.iA.iNext=iFreeBufferQ.iA.iPrev=&iFreeBufferQ.iA;	
       
  2776 	iCompletedBufferQ.iA.iNext=iCompletedBufferQ.iA.iPrev=&iCompletedBufferQ.iA;
       
  2777 	iInUseBufferQ.iA.iNext=iInUseBufferQ.iA.iPrev=&iInUseBufferQ.iA;	
       
  2778 		
       
  2779 	// Set the pointers to the current and the next record buffers.
       
  2780 	pBuf=iAudioBuffers; 		// This is the first buffer
       
  2781 	iCurrentBuffer=pBuf++;
       
  2782 	iNextBuffer = pBuf++;
       
  2783 	
       
  2784 	// Add all other buffers to the free list.
       
  2785 	TAudioBuffer* bufferLimit=iAudioBuffers+iNumBuffers; 
       
  2786 	while(pBuf<bufferLimit)
       
  2787 		iFreeBufferQ.Add(pBuf++);
       
  2788 	
       
  2789 	iBufOverflow=EFalse;	
       
  2790 	}
       
  2791 	
       
  2792 /**
       
  2793 Update buffer lists after a record buffer has been filled.
       
  2794 @param aBytesAdded The number of bytes added to the buffer to get it into the 'filled' state. Of course, this is
       
  2795 	normally equal to the size of the buffer. The exception is when recording has been paused: in which
       
  2796 	case the number of bytes added to 'fill' the buffer may be less than the buffer size.
       
  2797 @param aTransferResult The result of the transfer.	
       
  2798 @return A pointer to the next buffer for recording.
       
  2799 @pre The buffer/request queue mutex must be held.
       
  2800 */
       
  2801 TAudioBuffer* DRecordBufferManager::SetBufferFilled(TInt aBytesAdded,TInt aTransferResult)
       
  2802 	{
       
  2803 	// If record has been paused then its possible (depending on the PDD implementation) that although the current
       
  2804 	// buffer is marked as being filled, no data has been added. If this is the case then there is no point in informing 
       
  2805 	// the client about it. Instead we need to return it to the free list. Otherwise the more normal course of action is
       
  2806 	// to add the current buffer to the completed list ready for the client. If there is any amount of data in the record
       
  2807 	// buffer, this needs to be passed to the client (and if we're not paused then each buffer should actually be full).
       
  2808 	// If an error occured then we always add the buffer to the completed list.
       
  2809 	TAudioBuffer* buffer=iCurrentBuffer;
       
  2810 	if (aBytesAdded || aTransferResult)
       
  2811 		{
       
  2812 		buffer->iBytesAdded=aBytesAdded;
       
  2813 		buffer->iResult=aTransferResult;
       
  2814 		iCompletedBufferQ.Add(buffer);
       
  2815 		}
       
  2816 	else
       
  2817 		iFreeBufferQ.Add(buffer);
       
  2818 
       
  2819 	// Make the pending buffer the current one.
       
  2820 	iCurrentBuffer=iNextBuffer;
       
  2821 
       
  2822 	// Obtain the next pending buffer. If there are none left on the free list then we have to take one back
       
  2823 	// from the completed list.
       
  2824 	iNextBuffer=(TAudioBuffer*)iFreeBufferQ.GetFirst();
       
  2825 	if (!iNextBuffer)
       
  2826 		{
       
  2827 		iNextBuffer=(TAudioBuffer*)iCompletedBufferQ.GetFirst();
       
  2828 		iBufOverflow=ETrue;	// This is the buffer overflow situation.
       
  2829 		}
       
  2830 	__ASSERT_DEBUG(iNextBuffer,Kern::Fault(KSoundLddPanic,__LINE__));	
       
  2831 	iNextBuffer->iBytesAdded=0;
       
  2832 	
       
  2833 	__KTRACE_OPT(KSOUND1, Kern::Printf("<DBufferManager::SetBufferFilled(buf=%08x len=%d)",buffer->iChunkOffset,buffer->iBytesAdded));
       
  2834 	return(iNextBuffer);
       
  2835 	}
       
  2836 
       
  2837 /**
       
  2838 Get the next record buffer from the completed buffer list. If there is no error associated with the buffer, 
       
  2839 make it 'in use' by the client. Otherwise, return the buffer to the free list.
       
  2840 @return A pointer to the next completed buffer or NULL if there isn't one available.
       
  2841 @pre The buffer/request queue mutex must be held.
       
  2842 */
       
  2843 TAudioBuffer* DRecordBufferManager::GetBufferForClient()
       
  2844 	{	
       
  2845 	TAudioBuffer* buffer=(TAudioBuffer*)iCompletedBufferQ.GetFirst();
       
  2846 	if (buffer)
       
  2847 		{
       
  2848 		if (buffer->iResult==KErrNone)
       
  2849 			iInUseBufferQ.Add(buffer);
       
  2850 		else
       
  2851 			iFreeBufferQ.Add(buffer);
       
  2852 		}
       
  2853 	
       
  2854 	__KTRACE_OPT(KSOUND1, Kern::Printf("<DBufferManager::BufferForClient(buf=%08x)",(buffer ? buffer->iChunkOffset : -1)));
       
  2855 	return(buffer);
       
  2856 	}
       
  2857 
       
  2858 /**
       
  2859 Release (move to free list) the 'in use' record buffer specified by the given chunk offset.
       
  2860 @param aChunkOffset The chunk offset corresponding to the buffer to be freed.
       
  2861 @return The freed buffer, or NULL if no 'in use' buffer had the specified chunk offset.
       
  2862 @pre The buffer/request queue mutex must be held.
       
  2863 */
       
  2864 TAudioBuffer* DRecordBufferManager::ReleaseBuffer(TInt aChunkOffset)
       
  2865 	{
       
  2866 	// Scan 'in use' list for the audio buffer
       
  2867 	TAudioBuffer* pBuf;
       
  2868 	pBuf=(TAudioBuffer*)iInUseBufferQ.First();
       
  2869 	SDblQueLink* anchor=&iInUseBufferQ.iA;
       
  2870 	while (pBuf!=anchor && pBuf->iChunkOffset!=aChunkOffset)
       
  2871 		pBuf=(TAudioBuffer*)pBuf->iNext;
       
  2872 	
       
  2873 	// Move buffer to the free list (if found)
       
  2874 	if (pBuf!=anchor)
       
  2875 		iFreeBufferQ.Add(pBuf->Deque());
       
  2876 	else
       
  2877 		pBuf=NULL;
       
  2878 	
       
  2879 	__KTRACE_OPT(KSOUND1, Kern::Printf(">DBufferManager::BufferRelease(buf=%08x)",(pBuf ? pBuf->iChunkOffset : -1)));
       
  2880 	return(pBuf);
       
  2881 	}
       
  2882 
       
  2883 /**
       
  2884 Constructor for the audio buffer class.
       
  2885 Clears all member data
       
  2886 */
       
  2887 TAudioBuffer::TAudioBuffer()
       
  2888 	{
       
  2889 	memclr(this,sizeof(*this));
       
  2890 	}
       
  2891 
       
  2892 /**
       
  2893 Destructor for the audio buffer class.
       
  2894 */
       
  2895 TAudioBuffer::~TAudioBuffer()
       
  2896 	{
       
  2897 	delete[] iPhysicalPages;
       
  2898 	}
       
  2899 	
       
  2900 /**
       
  2901 Second stage constructor for the audio buffer class - validate and acquire information on the memory
       
  2902 allocated to this buffer.
       
  2903 @param aChunk  The chunk in which this buffer belongs.
       
  2904 @param aChunkOffset The offset within aChunk to the start of the audio buffer.
       
  2905 @param aSize The size (in bytes) of the buffer.
       
  2906 @param aIsContiguous A boolean indicating whether the buffer contains physically contiguous memory. Set to ETrue if it
       
  2907 	does physically contiguous memory, EFalse otherwise.		
       
  2908 @param aBufManager A pointer to the buffer manager which owns this object.
       
  2909 @return KErrNone if successful, otherwise one of the other system wide error codes.
       
  2910 @pre The thread must be in a critical section.
       
  2911 */
       
  2912 TInt TAudioBuffer::Create(DChunk* aChunk,TInt aChunkOffset,TInt aSize,TBool aIsContiguous,DBufferManager* aBufManager)
       
  2913 	{
       
  2914 	__KTRACE_OPT(KSOUND1, Kern::Printf(">TAudioBuffer::Create(Off-%x,Sz-%d,Contig-%d)",aChunkOffset,aSize,aIsContiguous));
       
  2915 
       
  2916 	// Save info. on the offset and size of the buffer. Also the buffer manager.
       
  2917 	iChunkOffset=aChunkOffset;
       
  2918 	iSize=aSize;
       
  2919 	iBufManager=aBufManager;
       
  2920 
       
  2921 	TInt r=KErrNone;
       
  2922 	iPhysicalPages=NULL;
       
  2923 	if (!aIsContiguous)
       
  2924 		{
       
  2925 		// Allocate an array for a list of the physical pages.
       
  2926 		iPhysicalPages = new TPhysAddr[aSize/Kern::RoundToPageSize(1)+2];
       
  2927 		if (!iPhysicalPages)
       
  2928 			r=KErrNoMemory;	
       
  2929 		}
       
  2930 		
       
  2931 	if (r==KErrNone)
       
  2932 		{
       
  2933 		// Check that the region of the chunk specified for the buffer contains committed memory. If so, get the physical addresses of the
       
  2934 		// pages in this buffer.
       
  2935 		TUint32 kernAddr;
       
  2936 		TUint32 mapAttr;
       
  2937 		r=Kern::ChunkPhysicalAddress(aChunk,aChunkOffset,aSize,kernAddr,mapAttr,iPhysicalAddress,iPhysicalPages);
       
  2938 		// r = 0 or 1 on success. (1 meaning the physical pages are not contiguous).
       
  2939 		if (r==1)
       
  2940 			{
       
  2941 			// The physical pages are not contiguous.
       
  2942 			iPhysicalAddress=KPhysAddrInvalid;	// Mark the physical address as invalid.
       
  2943 			r=(aIsContiguous) ? KErrGeneral : KErrNone;
       
  2944 			}
       
  2945 		if (r==0)
       
  2946 			{
       
  2947 			delete[] iPhysicalPages;	// We shouldn't retain this info. if the physical pages are contiguous.
       
  2948 			iPhysicalPages=NULL;
       
  2949 			}
       
  2950 			
       
  2951 		}
       
  2952 	__KTRACE_OPT(KSOUND1, Kern::Printf("<TAudioBuffer::Create - %d",r));
       
  2953 	return(r);
       
  2954 	}
       
  2955 
       
  2956 /**
       
  2957 Calculate the length for the next part of a data transfer request so that that the length returned specifies a physically
       
  2958 contiguous region and is also valid for the PDD. If necessary, return a truncated length that meets these criteria. Also,
       
  2959 return the physical address of the start of the region specified.
       
  2960 @param aChunkOffset The offset within the chunk for the start of the data transfer being fragmented.
       
  2961 @param aLengthRemaining The remaining length of the data transfer request.
       
  2962 @param aPhysAddr On return, this contains the physical address corresonding to aChunkOffset.
       
  2963 @return The length calculated.
       
  2964 */	
       
  2965 TInt TAudioBuffer::GetFragmentLength(TInt aChunkOffset,TInt aLengthRemaining,TPhysAddr& aPhysAddr)		
       
  2966 	{
       
  2967 	TInt len;
       
  2968 	TInt bufOffset=(aChunkOffset - iChunkOffset); 	// Convert from chunk offset to buffer offset.
       
  2969 	
       
  2970 	if (iPhysicalAddress==KPhysAddrInvalid)
       
  2971 		{
       
  2972 		// Buffer is not physically contiguous. Truncate length to the next page boundary. Then calculate physical addr.
       
  2973 		// (This function doesn't look for pages which are contiguous within the physical page list - but it could).
       
  2974 		TInt pageSize=Kern::RoundToPageSize(1);
       
  2975 		TInt pageOffset=bufOffset%pageSize;
       
  2976 		len=pageSize - pageOffset;
       
  2977 		aPhysAddr=iPhysicalPages[bufOffset/pageSize] + pageOffset;
       
  2978 		}
       
  2979 	else
       
  2980 		{
       
  2981 		// Buffer is physically contiguous so no need to truncate the length. Then calculate physical address.  
       
  2982 		len=aLengthRemaining;
       
  2983 		aPhysAddr=iPhysicalAddress + bufOffset;
       
  2984 		}
       
  2985 		
       
  2986 	// Ensure length does not exceed the max. supported by the PDD.
       
  2987 	len=Min(iBufManager->iMaxTransferLen,len);		
       
  2988 	return(len);
       
  2989 	}
       
  2990 	
       
  2991 /**
       
  2992 Purge the entire audio buffer. That is, if it contains cacheable memory, flush it.
       
  2993 @param aFlushOp The type of flush operation required - @see DBufferManager::TFlushOp.
       
  2994 */
       
  2995 void TAudioBuffer::Flush(DBufferManager::TFlushOp aFlushOp)
       
  2996 	{
       
  2997 	iBufManager->FlushData(iChunkOffset,iSize,aFlushOp);
       
  2998 	}
       
  2999