navienginebsp/ne1_tb/soundsc/soundsc_channel.cpp
changeset 0 5de814552237
equal deleted inserted replaced
-1:000000000000 0:5de814552237
       
     1 /*
       
     2 * Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  
       
    15 * \bsp\hwip_nec_naviengine\ne1_tb\soundsc\soundsc_channel.cpp
       
    16 * Implementation of the NE1_TBVariant playback and record shared chunk sound physical device driver (PDD).
       
    17 * This file is part of the NE1_TBVariant Base port
       
    18 * Unit is identified by the time of its creation by the DSoundScPddNE1_TB - by specifying TSoundDirection
       
    19 * (either ESoundDirRecord or ESoundDirPlayback) as the constructor parameter.
       
    20 *
       
    21 */
       
    22 
       
    23 
       
    24 
       
    25 /**
       
    26  @file
       
    27 */
       
    28 #include <navienginedma.h>
       
    29 #include <i2s.h>
       
    30 #include <nkern.h>
       
    31 #include "soundsc_plat.h"
       
    32 
       
    33 #if _DEBUG
       
    34 static const char KSoundPDDPanicCat[] = "SOUNDSC PDD, line:";
       
    35 #endif
       
    36 
       
    37 // physical address of the I2S channel 0 Tx register
       
    38 const TUint32 KHwI2S0TxPhys = KHwI2S0Phys + KHoI2STx;
       
    39 
       
    40 // physical address of the I2S channel 0 Rx register
       
    41 const TUint32 KHwI2S0RxPhys = KHwI2S0Phys + KHoI2SRx;
       
    42 
       
    43 /**
       
    44 Constructor for the NE1_TBVariant playback shared chunk sound driver physical device driver (PDD).
       
    45 */
       
    46 DNE1_TBSoundScPddChannel::DNE1_TBSoundScPddChannel(TSoundDirection aSoundDirection) :
       
    47 	iPowerUpDfc(PowerUpCallback, this, 0)
       
    48 	{
       
    49 	// The data transfer direction for this unit is specified as the constuctor parameter
       
    50 	__KTRACE_SND(Kern::Printf("DNE1_TBSoundScPddChannel(%d)::DNE1_TBSoundScPddChannel()", aSoundDirection));
       
    51 
       
    52 	iCaps.iDirection = aSoundDirection;
       
    53 
       
    54 	// store direction for I2s calls
       
    55 	if(aSoundDirection == ESoundDirRecord)
       
    56 		{
       
    57 		iI2sDirection = I2s::ERx;
       
    58 		}
       
    59 	else
       
    60 		{
       
    61 		iI2sDirection = I2s::ETx;
       
    62 		}
       
    63 	}
       
    64 
       
    65 /**
       
    66 Destructor for the NE1_TBVariant playback shared chunk sound driver physical device driver (PDD).
       
    67 */
       
    68 DNE1_TBSoundScPddChannel::~DNE1_TBSoundScPddChannel()
       
    69 	{
       
    70 	__KTRACE_SND(Kern::Printf("DNE1_TBSoundScPddChannel(%d)::~DNE1_TBSoundScPddChannel()", iCaps.iDirection));
       
    71 
       
    72 	// Delete the DMA request objects
       
    73 	for (TInt i=0; i<KMaxDmaRequests; i++)
       
    74 		{
       
    75 		delete iDmaRequest[i];
       
    76 		}
       
    77 
       
    78 	// Close the DMA channel.
       
    79 	if (iDmaChannel)
       
    80 		{
       
    81 		iDmaChannel->Close();
       
    82 		}
       
    83 	}
       
    84 
       
    85 /**
       
    86 Second stage constructor for the NE1_TBVariant playback shared chunk sound driver physical device driver (PDD).
       
    87 Note that this constructor is called before the second stage constructor for the LDD so it is not
       
    88 possible to call methods on the LDD here.
       
    89 @return KErrNone if successful, otherwise one of the other system wide error codes.
       
    90 */
       
    91 TInt DNE1_TBSoundScPddChannel::DoCreate()
       
    92 	{
       
    93 	__KTRACE_SND(Kern::Printf("DNE1_TBSoundScPddChannel(%d)::DoCreate", iCaps.iDirection));
       
    94 	TInt r = KErrNone;
       
    95 
       
    96 	// Setup the capabilities of this device.
       
    97 	SetCaps();
       
    98 
       
    99 	if (iCaps.iDirection == ESoundDirRecord)
       
   100 		{
       
   101 		iPowerUpDfc.SetDfcQ(DfcQ(KSoundScRxUnit0));
       
   102 		}
       
   103 	else
       
   104 		{
       
   105 		iPowerUpDfc.SetDfcQ(DfcQ(KSoundScTxUnit0));
       
   106 		}
       
   107 
       
   108 	// Setup the DMA channel information for this channel.
       
   109 	// note, that the channel type (Playback/Record) is stored in the iDirection
       
   110 	// and the I2s::TI2sDirection in iI2sDirection.
       
   111 	TDmaChannel::SCreateInfo info;
       
   112 	if (iCaps.iDirection == ESoundDirRecord)
       
   113 		{
       
   114 		info.iCookie = EDMAChannelI2S0RX;
       
   115 		}
       
   116 	else
       
   117 		{
       
   118 		info.iCookie = EDMAChannelI2S0TX;
       
   119 		}
       
   120 
       
   121 	if (iCaps.iDirection == ESoundDirRecord)
       
   122 		{
       
   123 		info.iDfcQ = DfcQ(KSoundScRxUnit0);
       
   124 		}
       
   125 	else
       
   126 		{
       
   127 		info.iDfcQ = DfcQ(KSoundScTxUnit0);
       
   128 		}
       
   129 
       
   130 	info.iDfcPriority = 0; // and set priority to 0 (the same as for RX channel)
       
   131 	info.iDesCount = KMaxDmaRequests;
       
   132 
       
   133 	// Try to open the DMA channel for a given direction (Playback or Record specified in iCookie)
       
   134 	// If this channel was already opened at this point - the DMA framework will return KErrInUse.
       
   135 	r = TDmaChannel::Open(info, iDmaChannel);
       
   136 	if (r != KErrNone)
       
   137 		{
       
   138 		return r;
       
   139 		}
       
   140 
       
   141 	// Create the DMA request objects for use with the DMA channel.
       
   142 	for (TInt i = 0; i < KMaxDmaRequests; i++)
       
   143 		{
       
   144 		iDmaRequest[i] = new DNE1_TBSoundScDmaRequest(*iDmaChannel,this, 0);
       
   145 		if (iDmaRequest[i] == NULL)
       
   146 			{
       
   147 			return KErrNoMemory;
       
   148 			}
       
   149 
       
   150 		r = iDmaRequest[i]->CreateMonoBuffer();
       
   151 		if (r != KErrNone)
       
   152 			{
       
   153 			return r;
       
   154 			}
       
   155 		}
       
   156 
       
   157 	// initialize the hardware FIFO of the I2S bus for this particular direction (iI2sDIrection).
       
   158 	// Because on this bus - both channels' (left and right) FIFO can't be enabled separately
       
   159 	// it is enough to call EnableFIFO for either of them (I2s::ELeft in this case).
       
   160 	r = I2s::EnableFIFO(KI2sChanNum, I2s::ELeft, iI2sDirection);
       
   161 	if (r != KErrNone)
       
   162 		{
       
   163 		return r;
       
   164 		}
       
   165 
       
   166 	// set the I2S bus hardware FIFO threshold for each channel of a given direction
       
   167 	r = I2s::SetFIFOThreshold(KI2sChanNum, I2s::ELeft, iI2sDirection, KFifoThreshold);
       
   168 	if (r != KErrNone)
       
   169 		{
       
   170 		return r;
       
   171 		}
       
   172 
       
   173 	r = I2s::SetFIFOThreshold(KI2sChanNum, I2s::ERight, iI2sDirection, KFifoThreshold);
       
   174 	if (r != KErrNone)
       
   175 		{
       
   176 		return r;
       
   177 		}
       
   178 
       
   179 
       
   180 	return KErrNone;
       
   181 	}
       
   182 
       
   183 /**
       
   184 Return the DFC queue to be used by this playback device.
       
   185 @return The DFC queue to use.
       
   186 */
       
   187 TDfcQue* DNE1_TBSoundScPddChannel::DfcQ(TInt /*aUnit*/)
       
   188 	{
       
   189 	return(iPhysicalDevice->iDfcQ);
       
   190 	}
       
   191 
       
   192 /**
       
   193 Called from the LDD to return the shared chunk create information to be used by this play device.
       
   194 @param aChunkCreateInfo A chunk create info. object to be to be filled with the settings
       
   195 						required for this device.
       
   196 */
       
   197 void DNE1_TBSoundScPddChannel::GetChunkCreateInfo(TChunkCreateInfo& aChunkCreateInfo)
       
   198 	{
       
   199 	__KTRACE_SND(Kern::Printf("DNE1_TBSoundScPddChannel(%d)::GetChunkCreateInfo", iCaps.iDirection));
       
   200 
       
   201 	// Setup the shared chunk create information in aChunkCreateInfo for this play device.
       
   202 	aChunkCreateInfo.iType = TChunkCreateInfo::ESharedKernelMultiple;
       
   203 	aChunkCreateInfo.iMapAttr = EMapAttrFullyBlocking | EMapAttrWriteUser; // not cached, user writable
       
   204 	aChunkCreateInfo.iOwnsMemory = ETrue; 	// Using RAM pages.
       
   205 	aChunkCreateInfo.iDestroyedDfc = NULL; 	// No chunk destroy DFC.
       
   206 	}
       
   207 
       
   208 /**
       
   209 Called from the LDD to return the capabilities of this device.
       
   210 @param aCapsBuf A packaged TSoundFormatsSupportedV02 object to be filled with the play
       
   211 				capabilities of this device. This descriptor is in kernel memory and can be accessed directly.
       
   212 @see TSoundFormatsSupportedV02.
       
   213 */
       
   214 void DNE1_TBSoundScPddChannel::Caps(TDes8& aCapsBuf) const
       
   215 	{
       
   216 	__KTRACE_SND(Kern::Printf("DNE1_TBSoundScPddChannel(%d)::Caps", iCaps.iDirection));
       
   217 
       
   218 	// Copy iCaps back.
       
   219 	TPtrC8 ptr((const TUint8*)&iCaps,sizeof(iCaps));
       
   220 	aCapsBuf.FillZ(aCapsBuf.MaxLength());
       
   221 	aCapsBuf=ptr.Left(Min(ptr.Length(),aCapsBuf.MaxLength()));
       
   222 	}
       
   223 
       
   224 /**
       
   225 Called from the LDD to return the maximum transfer length in bytes that this device can support in a single data transfer.
       
   226 @return The maximum transfer length in bytes.
       
   227 */
       
   228 TInt DNE1_TBSoundScPddChannel::MaxTransferLen() const
       
   229 	{
       
   230 	__KTRACE_SND(Kern::Printf("DNE1_TBSoundScPddChannel(%d)::MaxTransferLen() %x (%d)", iCaps.iDirection,KMaxDmaTransferLen,KMaxDmaTransferLen));
       
   231 	return(KMaxDmaTransferLen);
       
   232 	}
       
   233 
       
   234 /**
       
   235 Called from the LDD to configure or reconfigure the device using the the configuration supplied.
       
   236 @param aConfigBuf A packaged TCurrentSoundFormatV02 object which contains the new configuration settings.
       
   237 				  This descriptor is in kernel memory and can be accessed directly.
       
   238 @return KErrNone if successful, otherwise one of the other system wide error codes.
       
   239 @see TCurrentSoundFormatV02.
       
   240 */
       
   241 TInt DNE1_TBSoundScPddChannel::SetConfig(const TDesC8& aConfigBuf)
       
   242 	{
       
   243 	__KTRACE_SND(Kern::Printf("DNE1_TBSoundScPddChannel(%d)::SetConfig", iCaps.iDirection));
       
   244 	TInt r=KErrNone;
       
   245 
       
   246 	// Read the new configuration from the LDD.
       
   247 	TCurrentSoundFormatV02 config;
       
   248 	TPtr8 ptr((TUint8*)&config,sizeof(config));
       
   249 	Kern::InfoCopy(ptr,aConfigBuf);
       
   250 
       
   251 	// Set the I2S interface as bidirectional and master
       
   252 	TI2sConfigV01 i2sconfig = {I2s::EMaster, I2s::EBidirectional};
       
   253 	TPckgBuf<TI2sConfigV01> i2sconf(i2sconfig);
       
   254 
       
   255 	r = I2s::ConfigureInterface(KI2sChanNum, &i2sconf);
       
   256 	if(r != KErrNone)
       
   257 		{
       
   258 		return r;
       
   259 		}
       
   260 
       
   261 	// Apply the specified audio configuration to the audio device.
       
   262 	if(config.iChannels > 2)
       
   263 		{
       
   264 		return KErrNotSupported;
       
   265 		}
       
   266 
       
   267 	r = I2s::EnableDMA(KI2sChanNum, iI2sDirection);
       
   268 	if(r != KErrNone)
       
   269 		{
       
   270 		return r;
       
   271 		}
       
   272 
       
   273 	switch (config.iEncoding)
       
   274 		{
       
   275 		case ESoundEncoding16BitPCM:
       
   276 			r = I2s::SetSampleLength(KI2sChanNum, I2s::ELeft, I2s::ESample16Bit);
       
   277 			if(r!=KErrNone)
       
   278 				{
       
   279 				break;
       
   280 				}
       
   281 			r = I2s::SetFrameLengthAndFormat(KI2sChanNum, I2s::EFrame48Bit,  16);
       
   282 			break;
       
   283 		default:
       
   284 			r =  KErrNotSupported;
       
   285 		}
       
   286 
       
   287 	// might be also be'KErrInUse' here - so we shouldn't continue..
       
   288 	if(r!=KErrNone)
       
   289 		{
       
   290 		return r;
       
   291 		}
       
   292 
       
   293 	// BPS = rate * bytes_per_sample * num_of_channels
       
   294 	switch(config.iRate)
       
   295 		{
       
   296 		case ESoundRate11025Hz:
       
   297 			r = I2s::SetSamplingRate(KI2sChanNum, I2s::E11_025KHz);
       
   298 			break;
       
   299 
       
   300 		case ESoundRate22050Hz:
       
   301 			r = I2s::SetSamplingRate(KI2sChanNum, I2s::E22_05KHz);
       
   302 			break;
       
   303 
       
   304 		case ESoundRate44100Hz:
       
   305 			r = I2s::SetSamplingRate(KI2sChanNum, I2s::E44_1KHz);
       
   306 			break;
       
   307 
       
   308 		default:
       
   309 			r = KErrNotSupported;
       
   310 		}
       
   311 
       
   312 	// if we support it - copy the new configuration
       
   313 	if(r == KErrNone)
       
   314 		{
       
   315 		iCurrentConfig = config;
       
   316 		}
       
   317 	return(r);
       
   318 	}
       
   319 
       
   320 /**
       
   321 Called from the LDD to set the play volume.
       
   322 @param aVolume The play volume to be set - a value in the range 0 to 255. The value 255 equates
       
   323 	to the maximum volume and each value below this equates to a 0.5dB step below it.
       
   324 @return KErrNone if successful, otherwise one of the other system wide error codes.
       
   325 */
       
   326 TInt DNE1_TBSoundScPddChannel::SetVolume(TInt aVolume)
       
   327 	{
       
   328 	__KTRACE_SND(Kern::Printf("DNE1_TBSoundScPddChannel(%d)::SetVolume", iCaps.iDirection));
       
   329 	TInt r;
       
   330 	// Set the specified play volume on the audio device.
       
   331 	if (iCaps.iDirection == ESoundDirRecord)
       
   332 		{
       
   333 		r = iPhysicalDevice->iCodec->SetRecordVolume(aVolume);
       
   334 		}
       
   335 	else
       
   336 		{
       
   337 		r = iPhysicalDevice->iCodec->SetPlayVolume(aVolume);
       
   338 		}
       
   339 	return(r);
       
   340 	}
       
   341 
       
   342 /**
       
   343 Called from the LDD to prepare the audio device for playback.
       
   344 @return KErrNone if successful, otherwise one of the other system wide error codes.
       
   345 */
       
   346 
       
   347 TInt DNE1_TBSoundScPddChannel::StartTransfer()
       
   348 	{
       
   349 	__KTRACE_SND(Kern::Printf("DNE1_TBSoundScPddChannel(%d)::StartTransfer", iCaps.iDirection));
       
   350 	TInt r = I2s::Start(KI2sChanNum, iI2sDirection);
       
   351 	return(r);
       
   352 	}
       
   353 
       
   354 /**
       
   355 Called from the LDD to initiate the playback of a portion of data to the audio device.
       
   356 When the transfer is complete, the PDD signals this event using the LDD function PlayCallback().
       
   357 @param aTransferID A value assigned by the LDD to allow it to uniquely identify a particular transfer fragment.
       
   358 @param aLinAddr The linear address within the shared chunk of the start of the data to be played.
       
   359 @param aPhysAddr The physical address within the shared chunk of the start of the data to be played.
       
   360 @param aNumBytes The number of bytes to be played.
       
   361 @return KErrNone if the transfer has been initiated successfully;
       
   362   		KErrNotReady if the device is unable to accept the transfer for the moment;
       
   363 		otherwise one of the other system-wide error codes.
       
   364 */
       
   365 TInt DNE1_TBSoundScPddChannel::TransferData(TUint aTransferID,TLinAddr aLinAddr,TPhysAddr /*aPhysAddr*/,TInt aNumBytes)
       
   366 	{
       
   367 	__KTRACE_SND(Kern::Printf("DNE1_TBSoundScPddChannel(%d)::TransferData(ID:%xH,Addr:%xH,Len:%d)",iCaps.iDirection,aTransferID,aLinAddr,aNumBytes));
       
   368 	TInt r = KErrNone;
       
   369 
       
   370 	// Check that we can accept the request
       
   371 	if (iPendingPlay >= KMaxDmaRequests)
       
   372 		{
       
   373 		return KErrNotReady;
       
   374 		}
       
   375 	else
       
   376 		{
       
   377 		// Set the DMA transfer..
       
   378 		// DSoundScDmaRequest, as a friend class checks iChannels and iDirection of the transfer
       
   379 		r = iDmaRequest[iFlag]->SetDmaTransfer(aTransferID, aLinAddr, aNumBytes);
       
   380 		if (r != KErrNone)
       
   381 			{
       
   382 			__KTRACE_SND(Kern::Printf("DMA Fragment error (%d), r= %d", iCaps.iDirection, r));
       
   383 			return r;
       
   384 			}
       
   385 		else
       
   386 			{
       
   387 			iDmaRequest[iFlag]->Queue();
       
   388 			iPendingPlay++;
       
   389 			if ((++iFlag) >= KMaxDmaRequests)
       
   390 				iFlag = 0;
       
   391 			}
       
   392 		}
       
   393 	return KErrNone;
       
   394 	}
       
   395 
       
   396 /**
       
   397 Called from the LDD to terminate the playback of a data to the device and to release any resources necessary for playback.
       
   398 This is called soon after the last pending play request from the client has been completed. Once this function had been
       
   399 called, the LDD will not issue any further TransferData() commands without first issueing a StartTransfer() command.
       
   400 */
       
   401 void DNE1_TBSoundScPddChannel::StopTransfer()
       
   402 	{
       
   403 	__KTRACE_SND(Kern::Printf("DNE1_TBSoundScPddChannel(%d)::StopTransfer", iCaps.iDirection));
       
   404 
       
   405 	// Stop the DMA channel.
       
   406 #ifdef _DEBUG
       
   407 	TInt r = I2s::Stop(KI2sChanNum, iI2sDirection);
       
   408 	__ASSERT_DEBUG(r == KErrNone, Kern::Fault(KSoundPDDPanicCat, __LINE__));
       
   409 #else
       
   410 	I2s::Stop(KI2sChanNum, iI2sDirection);
       
   411 #endif
       
   412 
       
   413 	iDmaChannel->CancelAll();
       
   414 	iFlag = 0;
       
   415 	iPendingPlay = 0;
       
   416 	}
       
   417 
       
   418 /**
       
   419 Called from the LDD to halt the playback of data to the sound device but not to release any resources necessary for
       
   420 playback.
       
   421 If possible, any active transfer should be suspended in such a way that it can be resumed later - starting from next
       
   422 sample following the one last played.
       
   423 @return KErrNone if successful, otherwise one of the other system wide error codes.
       
   424 */
       
   425 TInt DNE1_TBSoundScPddChannel::PauseTransfer()
       
   426 	{
       
   427 	__KTRACE_SND(Kern::Printf("DNE1_TBSoundScPddChannel(%d)::PauseTransfer, pending %d", iCaps.iDirection, iPendingPlay));
       
   428 
       
   429 	// Halt transfer on the audio device.
       
   430 	TInt r = I2s::Stop(KI2sChanNum, iI2sDirection);
       
   431 	if(r != KErrNone)
       
   432 		{
       
   433 		return r;
       
   434 		}
       
   435 
       
   436 	if (iCaps.iDirection == ESoundDirRecord)
       
   437 		{
       
   438 	    // for Record, we need to figure out how much data was actually
       
   439 		// transfered and provide this to the LDD..
       
   440 		if (iPendingPlay)
       
   441 			{
       
   442 			iDmaChannel->CancelAll();
       
   443 			TInt byteCount = 0; // Unless dma API is extended..
       
   444 			Ldd()->RecordCallback(0,KErrNone, byteCount);	// We can use a NULL transfer ID when pausing.
       
   445 			iPendingPlay=0;
       
   446 			}
       
   447 	    iFlag=0;
       
   448 		}
       
   449 
       
   450 	return(r);
       
   451 	}
       
   452 
       
   453 /**
       
   454 Called from the LDD to resume the playback of data to the sound device following a request to halt playback.
       
   455 If possible, any transfer which was active when the device was halted should be resumed - starting from next sample
       
   456 following the one last played. Once complete, it should be reported using PlayCallback()
       
   457 as normal.
       
   458 @return KErrNone if successful, otherwise one of the other system wide error codes.
       
   459 */
       
   460 TInt DNE1_TBSoundScPddChannel::ResumeTransfer()
       
   461 	{
       
   462 	__KTRACE_SND(Kern::Printf("DNE1_TBSoundScPddChannel(%d)::ResumeTransfer, pending %d", iCaps.iDirection, iPendingPlay));
       
   463 
       
   464 	// Resume playback on the audio device.
       
   465 	TInt r = I2s::Start(KI2sChanNum, iI2sDirection);
       
   466 	return(r);
       
   467 	}
       
   468 
       
   469 
       
   470 NFastSemaphore DNE1_TBSoundScPddChannel::iFastSem;
       
   471 
       
   472 void DNE1_TBSoundScPddChannel::PowerUpCallback (TAny *aArg)
       
   473 	{
       
   474 	DNE1_TBSoundScPddChannel *a= (DNE1_TBSoundScPddChannel*)aArg;
       
   475 	__KTRACE_SND(Kern::Printf("powerUpCallback(%d)", a->iCaps.iDirection));
       
   476 
       
   477 	// PowerUp the Codec
       
   478 	a->iPowerUpStatus = RCS42AudioCodec::Open(a->iPhysicalDevice->iCodec);
       
   479 
       
   480 	// signal will unblock the thread blocked in call to PowerUp() method.
       
   481 	NKern::FSSignal(&a->iFastSem);
       
   482 	}
       
   483 
       
   484 /**
       
   485 Called from the LDD to power up the sound device when the channel
       
   486 is first opened and if ever the phone is brought out of standby mode.
       
   487 @return KErrNone if successful, otherwise one of the other system wide error codes.
       
   488 */
       
   489 TInt DNE1_TBSoundScPddChannel::PowerUp()
       
   490 	{
       
   491 	// Power up the audio device.
       
   492 	__KTRACE_SND(Kern::Printf("DNE1_TBSoundScPddChannel(%d)::PowerUp", iCaps.iDirection));
       
   493 
       
   494 	// need to power up the device in the context of the driver's thread
       
   495 	// (blocking the calling thread)
       
   496 	TDfcQue* dfcQ;
       
   497 	if (iCaps.iDirection == ESoundDirRecord)
       
   498 		{
       
   499 		dfcQ = DfcQ(KSoundScRxUnit0);
       
   500 		}
       
   501 	else
       
   502 		{
       
   503 		dfcQ = DfcQ(KSoundScTxUnit0);
       
   504 		}
       
   505 
       
   506 	if(dfcQ->iThread != NKern::CurrentThread())
       
   507 		{
       
   508 		iPowerUpDfc.Enque();
       
   509 		iFastSem.iOwningThread = NKern::CurrentThread();
       
   510 		NKern::FSWait(&iFastSem);
       
   511 		}
       
   512 	else
       
   513 		{
       
   514 		iPowerUpStatus = RCS42AudioCodec::Open(iPhysicalDevice->iCodec);
       
   515 		}
       
   516 
       
   517 	return iPowerUpStatus;
       
   518 	}
       
   519 
       
   520 /**
       
   521 Called from the LDD in the context of the driver thread to power down the sound device when the
       
   522 channel is closed and just before the phone powers down when being turned off or going into standby.
       
   523 */
       
   524 void DNE1_TBSoundScPddChannel::PowerDown()
       
   525 	{
       
   526 	__KTRACE_SND(Kern::Printf("DNE1_TBSoundScPddChannel(%d)::PowerDown", iCaps.iDirection));
       
   527 	// Power down the audio device.
       
   528 	// note, that reference-counting Codec will be powered-down if this call closes the last instance
       
   529 	RCS42AudioCodec::Close(iPhysicalDevice->iCodec);
       
   530 	}
       
   531 
       
   532 /**
       
   533 Called from the LDD to handle a custom configuration request.
       
   534 @param aFunction A number identifying the request.
       
   535 @param aParam A 32-bit value passed to the driver. Its meaning depends on the request.
       
   536 @return KErrNone if successful, otherwise one of the other system wide error codes.
       
   537 */
       
   538 TInt DNE1_TBSoundScPddChannel::CustomConfig(TInt /*aFunction*/,TAny* /*aParam*/)
       
   539 	{
       
   540 	return(KErrNotSupported);
       
   541 	}
       
   542 
       
   543 /**
       
   544 Called each time a playback DMA transfer completes - from the DMA callback function in the sound thread's DFC context.
       
   545 @param aTransferID The transfer ID of the DMA transfer.
       
   546 @param aTransferResult The result of the DMA transfer.
       
   547 @param aBytesTransferred The number of bytes transferred.
       
   548 */
       
   549 void DNE1_TBSoundScPddChannel::PlayCallback(TUint aTransferID,TInt aTransferResult,TInt aBytesTransferred)
       
   550 	{
       
   551 	__KTRACE_SND(Kern::Printf("DNE1_TBSoundScPddChannel(%d)::PlayCallback, ID %x, result %d, pending: %d", iCaps.iDirection, aTransferID, aTransferResult, iPendingPlay));
       
   552 
       
   553 	--iPendingPlay;
       
   554 
       
   555 	if(iCaps.iDirection == ESoundDirRecord)
       
   556 		{
       
   557 		Ldd()->RecordCallback(aTransferID,aTransferResult,aBytesTransferred);
       
   558 		}
       
   559 	else
       
   560 		{
       
   561 		Ldd()->PlayCallback(aTransferID,aTransferResult,aBytesTransferred);
       
   562 		}
       
   563 	}
       
   564 
       
   565 /**
       
   566 Initialise the data member DNE1_TBSoundScPddChannel::iCaps with the play capabilities of this audio playback device.
       
   567 */
       
   568 void DNE1_TBSoundScPddChannel::SetCaps()
       
   569 	{
       
   570 	__KTRACE_SND(Kern::Printf("DNE1_TBSoundScPddChannel(%d)::SetCaps", iCaps.iDirection));
       
   571 
       
   572 	// The audio channel configurations supported by this unit
       
   573 	// This unit supports both mono and stereo
       
   574 	iCaps.iChannels = (KSoundMonoChannel | KSoundStereoChannel);
       
   575 
       
   576 	// This unit supports only some of the sample rates offered by Symbian OS
       
   577 	iCaps.iRates = (KSoundRate11025Hz | KSoundRate22050Hz | KSoundRate44100Hz);
       
   578 
       
   579 	// The encoding formats supported
       
   580 	// until we'll be able to set the transfer source/dest lengths for DMA transfers
       
   581 	// only support for this one
       
   582 	iCaps.iEncodings = KSoundEncoding16BitPCM;
       
   583 
       
   584 	// This unit only supports interleaved data format when playing stereo;  that is, a PCM data
       
   585 	// stream where the left and right channel samples are interleaved as L-R-L-R-L-R etc.
       
   586 	iCaps.iDataFormats = KSoundDataFormatInterleaved;
       
   587 
       
   588 	// The minimum request size that the device can support. All requests to play or record data must be of a
       
   589 	//	length that is a multiple of this value.
       
   590 	iCaps.iRequestMinSize = 4;
       
   591 
       
   592 	// The logarithm to base 2 of the alignment required for request arguments. All requests to play or
       
   593 	//	record data must specify locations in the shared chunk which conform to this alignment.
       
   594 	iCaps.iRequestAlignment = 2;
       
   595 
       
   596 	// Indicates whether this unit is capable of detecting changes in its hardware configuration.
       
   597 	iCaps.iHwConfigNotificationSupport = EFalse;
       
   598 	}
       
   599 
       
   600 /**
       
   601 Constructor for a shared chunk sound driver playback DMA request.
       
   602 */
       
   603 DNE1_TBSoundScDmaRequest::DNE1_TBSoundScDmaRequest(TDmaChannel& aChannel, DNE1_TBSoundScPddChannel* aPdd, TInt aMaxTransferSize)
       
   604 	: DDmaRequest(aChannel,DNE1_TBSoundScDmaRequest::DmaService,this,aMaxTransferSize),
       
   605 	  iPdd(aPdd)
       
   606 	{
       
   607 	}
       
   608 
       
   609 DNE1_TBSoundScDmaRequest::~DNE1_TBSoundScDmaRequest()
       
   610 	{
       
   611 	// release buffer used for mono playback
       
   612 	if (iChunk)
       
   613 		{
       
   614 		iChunk->Close(NULL);
       
   615 		}
       
   616 
       
   617 	if (iBuffPhys)
       
   618 		{
       
   619 		Epoc::FreePhysicalRam(iBuffPhys, KMaxDmaTransferLen*2);
       
   620 		}
       
   621 	}
       
   622 
       
   623 TInt DNE1_TBSoundScDmaRequest::CreateMonoBuffer()
       
   624 	{
       
   625 	// alloc memory for buffer - we might need to play mono samples..
       
   626 	TInt r = Epoc::AllocPhysicalRam(KMaxDmaTransferLen*2, iBuffPhys);
       
   627 	if(r != KErrNone)
       
   628 		{
       
   629 		return r;
       
   630 		}
       
   631 
       
   632 	// map this buffer as non-cachable and writtable only by supervisor.
       
   633 	r = DPlatChunkHw::New(iChunk, iBuffPhys, KMaxDmaTransferLen*2,
       
   634 							  EMapAttrSupRw | EMapAttrFullyBlocking);
       
   635 	if (r != KErrNone)
       
   636 		{
       
   637 		return r;
       
   638 		}
       
   639 
       
   640 	iBufLin = iChunk->LinearAddress();
       
   641 
       
   642 	return KErrNone;
       
   643 	}
       
   644 
       
   645 //
       
   646 TInt DNE1_TBSoundScDmaRequest::SetDmaTransfer(TUint aTransferID, TLinAddr aLinAddr, TInt aNumBytes)
       
   647 	{
       
   648 	__ASSERT_DEBUG(iBufLin != NULL, Kern::Fault(KSoundPDDPanicCat, __LINE__));
       
   649 	TInt r = KErrNone;
       
   650 
       
   651 	// store TransferID
       
   652 	iTransferID = aTransferID;
       
   653 
       
   654 	if (iPdd->iCurrentConfig.iChannels == 1)
       
   655 		{
       
   656 		// Set the DMA source information - local buffer, which is always
       
   657 		// twice as big for mono transfers..
       
   658 		iTransferSize = aNumBytes*2;
       
   659 
       
   660 		// Store the original address of the data supplied.. this will be used
       
   661 		// as the destination address for recorded mono data..
       
   662 		if (iPdd->iCaps.iDirection == ESoundDirRecord)
       
   663 			{
       
   664 			// store address of the orginal buffer,
       
   665 			// where we need to copy the recorded data back - after the transfer has finished
       
   666 			iAddrLinOrig = aLinAddr;
       
   667 
       
   668 			r = Fragment(KHwI2S0RxPhys, iBufLin, iTransferSize,
       
   669 					KDmaMemDest | KDmaIncDest | KDmaPhysAddrSrc,
       
   670 					(TUint32)this);
       
   671 			}
       
   672 		else // this is a Play (Tx) unit
       
   673 		// This is a mono transfer request so we need to copy data to the internal buffer
       
   674 		// and transfer it as interleaved stereo - since this is the only format supported
       
   675 		// by the I2S bus.
       
   676 			{
       
   677 			TInt16 *src = (TInt16*)aLinAddr;
       
   678 			TInt32 *dst = (TInt32*)iBufLin;
       
   679 
       
   680 			// copy data to the local buffer (2 bytes at the time) -to play mono in both channels
       
   681 			for (TInt i = 0; i < aNumBytes/2; i++)
       
   682 				{
       
   683 				*dst++ = TInt32((*src) << 16) | (*src & 0xffff);
       
   684 				src++;
       
   685 				}
       
   686 
       
   687 			r = Fragment(iBufLin, KHwI2S0TxPhys, iTransferSize,
       
   688 					KDmaMemSrc | KDmaIncSrc | KDmaPhysAddrDest,
       
   689 					(TUint32)this);
       
   690 			}
       
   691 		}
       
   692 	else // it's stereo, interleaved data, which can be transferred directly
       
   693 		{
       
   694 		// Supply the DMA source information - original data in the shared chunk
       
   695 		iTransferSize = aNumBytes;
       
   696 
       
   697 		if (iPdd->iCaps.iDirection == ESoundDirRecord)
       
   698 			{
       
   699 			r = Fragment(KHwI2S0RxPhys, aLinAddr, iTransferSize,
       
   700 					KDmaMemDest | KDmaIncDest | KDmaPhysAddrSrc,
       
   701 					(TUint32)this);
       
   702 			}
       
   703 		else // this is a Play (Tx) unit
       
   704 			{
       
   705 			r = Fragment(aLinAddr, KHwI2S0TxPhys, iTransferSize,
       
   706 					KDmaMemSrc | KDmaIncSrc | KDmaPhysAddrDest,
       
   707 					(TUint32)this);
       
   708 			}
       
   709 		}
       
   710 	return r;
       
   711 	}
       
   712 
       
   713 /**
       
   714 DMA tx service routine. Called in the sound thread's DFC context by the s/w DMA controller.
       
   715 @param aResult Status of DMA transfer.
       
   716 @param aArg Argument passed to DMA controller.
       
   717 */
       
   718 void DNE1_TBSoundScDmaRequest::DmaService(TResult aResult, TAny* aArg)
       
   719 	{
       
   720 	DNE1_TBSoundScDmaRequest& req = *(DNE1_TBSoundScDmaRequest*)aArg;
       
   721 	__KTRACE_SND( Kern::Printf("DmaService(%d) %d",req.iPdd->iCaps.iDirection, aResult));
       
   722 
       
   723 	TInt res = KErrNone;
       
   724 	TInt bytesTransferred = req.iTransferSize;
       
   725 	if (aResult!=DDmaRequest::EOk)
       
   726 		{
       
   727 		res = KErrCorrupt;
       
   728 		bytesTransferred = 0;
       
   729 		}
       
   730 
       
   731 	// if this was mono transfered as stereo..
       
   732 	if (req.iPdd->iCurrentConfig.iChannels == 1)
       
   733 		{
       
   734 		// adjust back the number of bytes transfered
       
   735 		bytesTransferred /= 2;
       
   736 
       
   737 		// if this request is a part of record unit
       
   738 		// copy data to back to the shared chunk provided by the LDD
       
   739 		if (req.iPdd->iCaps.iDirection == ESoundDirRecord)
       
   740 			{
       
   741 			TInt32 *src = (TInt32*)req.iBufLin;
       
   742 			TInt16 *dst = (TInt16*)req.iAddrLinOrig;
       
   743 
       
   744 			for (TInt i = 0; i < bytesTransferred; i+=2)
       
   745 				{
       
   746 				*dst++ = TInt16(*src++);
       
   747 				}
       
   748 			}
       
   749 		}
       
   750 
       
   751 	// Inform the LDD of the result of the transfer.
       
   752 	req.iPdd->PlayCallback(req.iTransferID,res,bytesTransferred);
       
   753 
       
   754 	return;
       
   755 	}
       
   756