os/kernelhwsrv/kerneltest/e32test/examples/camera1/camera1_ldd.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 2005-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 // its implementation.
    15 // 
    16 //
    17 
    18 /**
    19  @file An example camera device driver which uses Shared Chunks in
    20  @publishedPartner
    21  @prototype 9.1
    22 */
    23 
    24 #include <kernel/kern_priv.h>
    25 #include <kernel/cache.h>
    26 #include "camera1.h"
    27 #include "camera1_dev.h"
    28 
    29 #if 0  // Set true for tracing
    30 #define TRACE(x) x
    31 #else
    32 #define TRACE(x)
    33 #endif
    34 
    35 //
    36 // DCamera1Factory
    37 //
    38 
    39 /**
    40   Standard export function for LDDs. This creates a DLogicalDevice derived object,
    41   in this case, our DCamera1Factory
    42 */
    43 DECLARE_STANDARD_LDD()
    44 	{
    45 	return new DCamera1Factory;
    46 	}
    47 
    48 /**
    49   Constructor
    50 */
    51 DCamera1Factory::DCamera1Factory()
    52 	{
    53 	// Set version number for this device
    54 	iVersion=RCamera1::VersionRequired();
    55 	// Indicate that do support units or a PDD
    56 	iParseMask=0;
    57 	}
    58 
    59 /**
    60   Second stage constructor for DCamera1Factory.
    61   This must at least set a name for the driver object.
    62 
    63   @return KErrNone if successful, otherwise one of the other system wide error codes.
    64 */
    65 TInt DCamera1Factory::Install()
    66 	{
    67 	return SetName(&RCamera1::Name());
    68 	}
    69 
    70 /**
    71   Destructor
    72 */
    73 DCamera1Factory::~DCamera1Factory()
    74 	{
    75 	}
    76 
    77 /**
    78   Return the drivers capabilities.
    79   Called in the response to an RDevice::GetCaps() request.
    80 
    81   @param aDes User-side descriptor to write capabilities information into
    82 */
    83 void DCamera1Factory::GetCaps(TDes8& aDes) const
    84 	{
    85 	// Create a capabilities object
    86 	RCamera1::TCaps caps;
    87 	caps.iVersion = iVersion;
    88 	// Write it back to user memory
    89 	Kern::InfoCopy(aDes,(TUint8*)&caps,sizeof(caps));
    90 	}
    91 
    92 /**
    93   Called by the kernel's device driver framework to create a Logical Channel.
    94   This is called in the context of the user thread (client) which requested the creation of a Logical Channel
    95   (E.g. through a call to RBusLogicalChannel::DoCreate)
    96   The thread is in a critical section.
    97 
    98   @param aChannel Set to point to the created Logical Channel
    99 
   100   @return KErrNone if successful, otherwise one of the other system wide error codes.
   101 */
   102 TInt DCamera1Factory::Create(DLogicalChannelBase*& aChannel)
   103 	{
   104 	aChannel=new DCamera1Channel;
   105 	if(!aChannel)
   106 		return KErrNoMemory;
   107 
   108 	return KErrNone;
   109 	}
   110 
   111 //
   112 // Logical Channel
   113 //
   114 
   115 /**
   116   Default configuration for driver (640x480 pixels of 32bits captured at 15 frames/sec)
   117 */
   118 static const RCamera1::TConfig DefaultConfig = {{640,480},4,15};
   119 
   120 /**
   121   Constructor
   122 */
   123 DCamera1Channel::DCamera1Channel()
   124 	:	iDfcQ(Kern::TimerDfcQ()),  // This test uses the timer DFC queue for DFCs
   125 		iStateChangeDfc(StateChangeDfcTrampoline,this,1),  // DFC is priority '1'
   126 		iConfig(DefaultConfig),
   127 		iCaptureTimer(CaptureDfcTrampoline,this)
   128 	{
   129 	}
   130 
   131 /**
   132   Second stage constructor called by the kernel's device driver framework.
   133   This is called in the context of the user thread (client) which requested the creation of a Logical Channel
   134   (E.g. through a call to RBusLogicalChannel::DoCreate)
   135   The thread is in a critical section.
   136 
   137   @param aUnit The unit argument supplied by the client to RBusLogicalChannel::DoCreate
   138   @param aInfo The info argument supplied by the client to RBusLogicalChannel::DoCreate
   139   @param aVer The version argument supplied by the client to RBusLogicalChannel::DoCreate
   140 
   141   @return KErrNone if successful, otherwise one of the other system wide error codes.
   142 */
   143 TInt DCamera1Channel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer)
   144 	{
   145 	// Check client has EMultimediaDD capability
   146 	if(!Kern::CurrentThreadHasCapability(ECapabilityMultimediaDD,__PLATSEC_DIAGNOSTIC_STRING("Checked by CAPTURE1")))
   147 		return KErrPermissionDenied;
   148 
   149 	// Check version
   150 	if (!Kern::QueryVersionSupported(RCamera1::VersionRequired(),aVer))
   151 		return KErrNotSupported;
   152 
   153 	// Setup DFCs
   154 	iStateChangeDfc.SetDfcQ(iDfcQ);
   155 
   156 	// Done
   157 	return Kern::MutexCreate(iStateChangeMutex,KNullDesC,KMutexOrdGeneral7);
   158 	}
   159 
   160 /**
   161   Destructor
   162 */
   163 DCamera1Channel::~DCamera1Channel()
   164 	{
   165 	DoCancel(RCamera1::EAllRequests);
   166 	EndCapture();
   167 	iStateChangeDfc.Cancel();
   168 	if(iStateChangeMutex)
   169 		iStateChangeMutex->Close(0);
   170 	if(iCaptureBuffers)
   171 		iCaptureBuffers->Close();
   172 	}
   173 
   174 /**
   175   Process a request on this logical channel.
   176 
   177   @param aReqNo Request number:
   178   	            ==KMaxTInt, a 'DoCancel' message
   179 	            >=0, a 'DoControl' message with function number equal to iValue
   180 	            <0, a 'DoRequest' message with function number equal to ~iValue
   181   @param a1     First argument. For DoRequest requests this is a pointer to the TRequestStatus.
   182   @param a2     Second argument. For DoRequest this is a pointer to the 2 actual TAny* arguments.
   183 
   184   @return       Result. Ignored by device driver framework for DoRequest requests.
   185 */
   186 TInt DCamera1Channel::Request(TInt aReqNo, TAny* a1, TAny* a2)
   187 	{
   188 	// Decode the message type and dispatch it to the relevent handler function...
   189 	if ((TUint)aReqNo<(TUint)KMaxTInt)
   190 		return DoControl(aReqNo,a1,a2);
   191 	if(aReqNo==KMaxTInt)
   192 		return DoCancel((TInt)a1);
   193 	return DoRequest(aReqNo,a1,a2);
   194 	}
   195 
   196 /**
   197   Process synchronous 'control' requests
   198 */
   199 TInt DCamera1Channel::DoControl(TInt aFunction, TAny* a1, TAny* a2)
   200 	{
   201 	TRACE(Kern::Printf(">DCamera1Channel::DoControl fn=%d\n",aFunction);)
   202 
   203 	(void)a2;   // a2 not used in this example
   204 
   205 	TInt r = KErrNotSupported;
   206 	switch (aFunction)
   207 		{
   208 		case RCamera1::EGetConfig:
   209 			r = GetConfig((TDes8*)a1);
   210 			break;
   211 
   212 		case RCamera1::ESetConfig:
   213 			r = SetConfig((const TDesC8*)a1);
   214 			break;
   215 
   216 		case RCamera1::EStartCapture:
   217 			r = StartCapture();
   218 			break;
   219 
   220 		case RCamera1::EEndCapture:
   221 			r = EndCapture();
   222 			break;
   223 
   224 		case RCamera1::EReleaseImage:
   225 			r = ImageRelease((TInt)a1);
   226 			break;
   227 
   228 		case RCamera1::ECaptureImage:
   229 			CaptureImage((TRequestStatus*)a1,(TInt)a2);
   230 			break;
   231 		}
   232 
   233 	TRACE(Kern::Printf("<DCamera1Channel::DoControl result=%d\n",r);)
   234 
   235 	return r;
   236 	}
   237 
   238 /**
   239   Process asynchronous requests.
   240   This driver doesn't have any 'DoRequest' requests because we handle asyncronous
   241   requests using 'DoControl' for performance reasons. I.e. to avoid having to read
   242   the arguments with kumemget()
   243 */
   244 TInt DCamera1Channel::DoRequest(TInt aNotReqNo, TAny* a1, TAny* a2)
   245 	{
   246 	TRACE(Kern::Printf(">DCamera1Channel::DoRequest req=%d\n",aNotReqNo);)
   247 
   248 	// Get arguments
   249 	TAny* a[2];
   250 	kumemget32(a,a2,sizeof(a)); 
   251 	TRequestStatus* status=(TRequestStatus*)a1;
   252 	TInt reqNo = ~aNotReqNo;
   253 
   254 	// Do the request
   255 	TInt r;
   256 	switch(reqNo)
   257 		{
   258 		case RCamera1::ECaptureImage:
   259 			// Not used because we do 'ECaptureImage' as a DoControl rather than
   260 			// a DoRequest for performance reasons
   261 
   262 		default:
   263 			r = KErrNotSupported;
   264 			break;
   265 		}
   266 
   267 	// Complete request if there was an error
   268 	if (r!=KErrNone)
   269 		Kern::RequestComplete(&Kern::CurrentThread(),status,r);
   270 
   271 	TRACE(Kern::Printf("<DCamera1Channel::DoRequest result=%d\n",r);)
   272 
   273 	return KErrNone;  // Result is ignored by device driver framework for DoRequest requests
   274 	}
   275 
   276 /**
   277   Process cancelling of asynchronous requests.
   278 */
   279 TInt DCamera1Channel::DoCancel(TUint aMask)
   280 	{
   281 	TRACE(Kern::Printf(">DCamera1Channel::DoCancel mask=%08x\n",aMask);)
   282 
   283 	if(aMask&(1<<RCamera1::ECaptureImage))
   284 		CaptureImageCancel();
   285 
   286 	TRACE(Kern::Printf("<DCamera1Channel::DoCancel\n");)
   287 
   288 	return KErrNone;
   289 	}
   290 
   291 //
   292 // Methods for processing configuration control messages
   293 //
   294 
   295 /**
   296   Process a GetConfig control message. This writes the current driver configuration to a
   297   RCamera1::TConfigBuf supplied by the client.
   298 */
   299 TInt DCamera1Channel::GetConfig(TDes8* aConfigBuf)
   300 	{
   301 	// Write the config to the client
   302 	Kern::InfoCopy(*aConfigBuf,(const TUint8*)&iConfig,sizeof(iConfig));
   303 	return KErrNone;
   304 	}
   305 
   306 /**
   307   Process a SetConfig control message. This sets the driver configuration using a
   308   RCamera1::TConfigBuf supplied by the client.
   309 */
   310 TInt DCamera1Channel::SetConfig(const TDesC8* aConfigBuf)
   311 	{
   312 	// Create a config structure.
   313 	RCamera1::TConfig config(DefaultConfig);
   314 
   315 	// Note: We have constructed a config using DefaultConfig, this is to allow
   316 	// backwards compatibility when a client gives us an old (and shorter) version
   317 	// of the config structure.
   318 
   319 	// Read the config structure from client
   320 	TPtr8 ptr((TUint8*)&config,sizeof(config));
   321 	Kern::KUDesGet(ptr,*aConfigBuf);
   322 
   323 	// For some settings we allow zero to mean default...
   324 	if(!config.iImageSize.iWidth)
   325 		config.iImageSize.iWidth = DefaultConfig.iImageSize.iWidth;
   326 	if(!config.iImageSize.iHeight)
   327 		config.iImageSize.iHeight = DefaultConfig.iImageSize.iHeight;
   328 	if(!config.iImageBytesPerPixel)
   329 		config.iImageBytesPerPixel = DefaultConfig.iImageBytesPerPixel;
   330 
   331 	// Validate configuration
   332 	TInt scale = DefaultConfig.iImageSize.iWidth/config.iImageSize.iWidth;
   333 	if(scale*config.iImageSize.iWidth != DefaultConfig.iImageSize.iWidth)
   334 		return KErrArgument;
   335 	if(scale*config.iImageSize.iHeight != DefaultConfig.iImageSize.iHeight)
   336 		return KErrArgument;
   337 	if(config.iImageBytesPerPixel<=0 || config.iImageBytesPerPixel>4)
   338 		return KErrArgument;
   339 
   340 	if(config.iFrameRate<0)
   341 		return KErrArgument;
   342 	if(config.iNumImageBuffers<1)
   343 		return KErrArgument;
   344 
   345 	TInt imageSize;
   346 	DCaptureBuffers* buffers;
   347 	TInt r;
   348 
   349 	// Need to be in critical section whilst holding a DMutex
   350 	NKern::ThreadEnterCS();
   351 
   352 	// Claim state change mutex. Note, the return value is ignored because a Wait
   353 	// can only fail if the mutex is destroyed whilst waiting for it, this can't 
   354 	// happen in our driver.
   355 	Kern::MutexWait(*iStateChangeMutex);
   356 
   357 	// Check we aren't in the middle of capturing images
   358 	if(iCapturing)
   359 		{
   360 		r = KErrInUse;
   361 		goto done;
   362 		}
   363 
   364 	// Change the config
   365 	iConfig = config; 
   366 	iCaptureRateTicks = config.iFrameRate ? 1000000/config.iFrameRate/NKern::TickPeriod() : KMaxTInt;
   367 	if(iCaptureRateTicks<1)
   368 		iCaptureRateTicks = 1;
   369 
   370 	// Claim ownership of old buffers
   371 	NKern::FMWait(&iCaptureMutex);
   372 	buffers = iCaptureBuffers;
   373 	iCaptureBuffers = NULL;
   374 	NKern::FMSignal(&iCaptureMutex);
   375 
   376 	// Delete old buffers
   377 	if(buffers)
   378 		buffers->Close();
   379 
   380 	// Contruct new buffer object
   381 	imageSize = iConfig.iImageSize.iWidth*iConfig.iImageSize.iHeight*iConfig.iImageBytesPerPixel;
   382 	buffers = DCaptureBuffers::New(2+iConfig.iNumImageBuffers,imageSize);
   383 	if(!buffers)
   384 		{
   385 		r = KErrNoMemory;
   386 		goto done;
   387 		}
   388 
   389 	// Use the new buffers if another thread didn't create them first
   390 	NKern::FMWait(&iCaptureMutex);
   391 	iCaptureBuffers = buffers;
   392 	NKern::FMSignal(&iCaptureMutex);
   393 
   394 	// Create handle for chunk
   395 	r = Kern::MakeHandleAndOpen(NULL, iCaptureBuffers->iChunk);
   396 
   397 done:
   398 	// Release state change mutex
   399 	Kern::MutexSignal(*iStateChangeMutex);
   400 
   401 	NKern::ThreadLeaveCS();
   402 
   403 	return r;
   404 	}
   405 
   406 //
   407 // Methods for processing start/end capture
   408 //
   409 
   410 /**
   411    Start image capturing
   412 */
   413 TInt DCamera1Channel::StartCapture()
   414 	{
   415 	// Need to be in critical section whilst holding a DMutex
   416 	NKern::ThreadEnterCS();
   417 
   418 	// Claim state change mutex. Note, the return value is ignored because a Wait
   419 	// can only fail if the mutex is destroyed whilst waiting for it, this can't 
   420 	// happen in our driver.
   421 	Kern::MutexWait(*iStateChangeMutex);
   422 
   423 	NKern::FMWait(&iCaptureMutex);
   424 
   425 	TInt r;
   426 	if(!iCaptureBuffers)
   427 		r = KErrNotReady;  // SetConfig not yet been called
   428 	else if(iCapturing)
   429 		r = KErrInUse;     // StartCapture has already been called
   430 	else
   431 		{
   432 		// Initialise image buffer state for capturing images
   433 		iCaptureBuffers->Reset();
   434 
   435 		// Flag capturing started
   436 		iCapturing = ETrue;
   437 		r = KErrNone;
   438 		}
   439 
   440 	NKern::FMSignal(&iCaptureMutex);
   441 
   442 	// Get state change DFC to initialise camera hardware for capture
   443 	if(r==KErrNone)
   444 		StateChange(ETrue);
   445 
   446 	// Release state change mutex
   447 	Kern::MutexSignal(*iStateChangeMutex);
   448 
   449 	NKern::ThreadLeaveCS();
   450 
   451 	return r;
   452 	}
   453 
   454 /**
   455    End image capturing
   456 */
   457 TInt DCamera1Channel::EndCapture()
   458 	{
   459 	// Need to be in critical section whilst holding a DMutex
   460 	NKern::ThreadEnterCS();
   461 
   462 	// Claim state change mutex. Note, the return value is ignored because a Wait
   463 	// can only fail if the mutex is destroyed whilst waiting for it, this can't 
   464 	// happen in our driver.
   465 	Kern::MutexWait(*iStateChangeMutex);
   466 
   467 	if(iCapturing)
   468 		{
   469 		// Get state change DFC to reset camera hardware
   470 		StateChange(EFalse);
   471 
   472 		// Flag capture ended
   473 		NKern::FMWait(&iCaptureMutex);
   474 		iCapturing = EFalse;
   475 		NKern::FMSignal(&iCaptureMutex);
   476 
   477 		// Cancel any pending caoture request
   478 		CaptureImageCancel();
   479 		}
   480 
   481 	// Release state change mutex
   482 	Kern::MutexSignal(*iStateChangeMutex);
   483 
   484 	NKern::ThreadLeaveCS();
   485 
   486 	return KErrNone;
   487 	}
   488 
   489 /**
   490   Performs state change on Start/EndCapture by calling state change DFC
   491   Call with iStateChangeMutex held.
   492 
   493   @param aNewState True to start image capture, false to stop image capture.
   494 */
   495 void DCamera1Channel::StateChange(TBool aNewState)
   496 	{
   497 	iNewState = aNewState;
   498 	NKern::FSSetOwner(&iStateChangeSemaphore,NULL);
   499 	iStateChangeDfc.Enque();
   500 	NKern::FSWait(&iStateChangeSemaphore);
   501 	}
   502 
   503 /**
   504   DFC callback called when Start/EndCapture requests are made.
   505 */
   506 void DCamera1Channel::StateChangeDfcTrampoline(TAny* aSelf)
   507 	{
   508 	// Just call non-static method
   509 	((DCamera1Channel*)aSelf)->StateChangeDfc();
   510 	}
   511 
   512 /**
   513   DFC callback called when Start/EndCapture requests are made.
   514 */
   515 void DCamera1Channel::StateChangeDfc()
   516 	{
   517 	TRACE(Kern::Printf(">DCamera1Channel::StateChangeDfc\n");)
   518 
   519 	// Call relevent state change function
   520 	if(iNewState)
   521 		DoStartCapture();
   522 	else
   523 		DoEndCapture();
   524 
   525 	// Signal completion
   526 	NKern::FSSignal(&iStateChangeSemaphore);
   527 
   528 	TRACE(Kern::Printf("<DCamera1Channel::StateChangeDfc\n");)
   529 	}
   530 
   531 //
   532 // Methods for processing CaptureImage
   533 //
   534 
   535 /**
   536   Process Capture Image request 
   537 */
   538 void DCamera1Channel::CaptureImage(TRequestStatus* aRequestStatus,TInt aReleaseImage)
   539 	{
   540 	TInt r=KErrNone;
   541 
   542 	// Get the thread making the request
   543 	DThread* requestThread = &Kern::CurrentThread();
   544 
   545 	// Release image (if one was specified)
   546 	if(aReleaseImage!=-1)
   547 		{
   548 		r = ImageRelease(aReleaseImage);
   549 		if(r!=KErrNone)
   550 			goto done;
   551 		}
   552 
   553 	NKern::FMWait(&iCaptureMutex);
   554 
   555 	if(!iCapturing)
   556 		r = KErrNotReady;     // StartCapture hasn't yet been called
   557 	else if(iCaptureRequestStatus)
   558 		r = KErrInUse;        // There is already a pending CaptureImage request
   559 	else
   560 		{
   561 		// See if an image is already available...
   562 		DImageBuffer* buffer=iCaptureBuffers->ImageForClient();
   563 		if(buffer)
   564 			{
   565 			// Return offset of buffer to client
   566 			r = buffer->iChunkOffset;
   567 			}
   568 		else
   569 			{
   570 			// Image not found...
   571 			if(!iCaptureBuffers->iFreeBuffers[0])
   572 				r = KErrOverflow;  // Out of buffers
   573 			else
   574 				{
   575 				// Wait for new image to become available
   576 				iCaptureRequestStatus = aRequestStatus;
   577 				requestThread->Open(); // can't fail because this is the current thread
   578 				iCaptureRequestThread = requestThread;
   579 				r = KErrNone;
   580 				}
   581 			}
   582 		}
   583 
   584 	NKern::FMSignal(&iCaptureMutex);
   585 
   586 done:
   587 	// Complete request if there was an error
   588 	if (r!=KErrNone)
   589 		Kern::RequestComplete(requestThread,aRequestStatus,r);
   590 	}
   591 
   592 /**
   593   Signal Capture Image request completed
   594 */
   595 void DCamera1Channel::CaptureImageCancel()
   596 	{
   597 	// Need to be in critical section so we don't die whilst owning the capture image request
   598 	NKern::ThreadEnterCS();
   599 
   600 	// Claim the capture image request
   601 	NKern::FMWait(&iCaptureMutex);
   602 	DThread* thread = iCaptureRequestThread;;
   603 	TRequestStatus* status = iCaptureRequestStatus;
   604 	iCaptureRequestStatus = NULL;
   605 	NKern::FMSignal(&iCaptureMutex);
   606 
   607 	// Signal completion
   608 	if(status)
   609 		{
   610 		Kern::RequestComplete(thread,status,KErrCancel);
   611 		thread->Close(0);
   612 		}
   613 
   614 	NKern::ThreadLeaveCS();
   615 	}
   616 
   617 /**
   618   DFC callback called when after a new image has been captured
   619   In this example code this is called by
   620 */
   621 void DCamera1Channel::CaptureDfcTrampoline(TAny* aSelf)
   622 	{
   623 	// Just call non-static method
   624 	((DCamera1Channel*)aSelf)->CaptureDfc();
   625 	}
   626 
   627 /**
   628   DFC callback called when a new image has been captured
   629 */
   630 void DCamera1Channel::CaptureDfc()
   631 	{
   632 	TRACE(Kern::Printf(">DCamera1Channel::CaptureDfc\n");)
   633 
   634 	NKern::FMWait(&iCaptureMutex);
   635 
   636 	// Update image buffers state
   637 	iCaptureBuffers->ImageCaptured();
   638 
   639 	// Did client request an image and is one available?
   640 	DImageBuffer* clientBuffer;
   641 	if(iCaptureRequestStatus && (clientBuffer=iCaptureBuffers->ImageForClient())!=NULL )
   642 		{
   643 		// Claim the client request
   644 		DThread* thread = iCaptureRequestThread;
   645 		TRequestStatus* status = iCaptureRequestStatus;
   646 		iCaptureRequestStatus = NULL;
   647 
   648 		NKern::FMSignal(&iCaptureMutex);
   649 
   650 		// We now own the client request but we don't have to worry about
   651 		// being in a critical section because we are running in a DFC thread
   652 		// which can't be killed
   653 
   654 		// Complete client request with the chunk offset for a captured image
   655 		// (We use AsyncClose() here because we are running in a high priority DFC and
   656 		// don't want to take the penalty for possibly deleting a thread in this context.)
   657 		Kern::RequestComplete(thread,status,clientBuffer->iChunkOffset);
   658 		thread->AsyncClose();
   659 		}
   660 	else
   661 		NKern::FMSignal(&iCaptureMutex);
   662 
   663 	// Get camera hardware to capture next image
   664 	DoNextCapture();
   665 
   666 	TRACE(Kern::Printf("<DCamera1Channel::CaptureDfc\n");)
   667 	}
   668 
   669 /**
   670   Release a buffer which was being used by client
   671 
   672   @param aChunkOffset The chunk offset corresponding to the buffer to be freed
   673 
   674   @return KErrNone if successful.
   675 		  KErrNotFound if no 'in use' buffer had the specified chunk offset.
   676 */
   677 TInt DCamera1Channel::ImageRelease(TInt aChunkOffset)
   678 	{
   679 	// Need to be in critical section so we don't die whilst holding reference on buffers
   680 	NKern::ThreadEnterCS();
   681 
   682 	// Get reference to buffers object and find the buffer we want
   683 	NKern::FMWait(&iCaptureMutex);
   684 	DCaptureBuffers* buffers = iCaptureBuffers;
   685 	DImageBuffer* buffer = NULL;
   686 	if(buffers)
   687 		{
   688 		buffers->Open();
   689 		buffer = buffers->InUseImage(aChunkOffset);
   690 		}
   691 	NKern::FMSignal(&iCaptureMutex);
   692 
   693 	TInt r;
   694 	if(!buffer)
   695 		r = KErrNotFound;	// Buffer not found
   696 	else
   697 		{
   698 		// Purge the CPU cache for the buffer.
   699 		// Note, we don't do this whilst holding iCaptureMutex because it can
   700 		// take a long time.
   701 		// Also, it doesn't mater that e aren't holding the mutex because:
   702 		// 1. The buffer can't be delete because we have a reference count on iCaptureBuffers
   703 		// 2. Reentrancy of the Purge method is safe 
   704 		buffers->Purge(buffer);
   705 
   706 		// Release buffer (move it to the free list)
   707 		NKern::FMWait(&iCaptureMutex);
   708 		r = buffers->ImageRelease(aChunkOffset) ? KErrNone : KErrArgument;
   709 		NKern::FMSignal(&iCaptureMutex);
   710 		}
   711 
   712 	// Close reference on buffers
   713 	if(buffers)
   714 		buffers->Close();
   715 
   716 	NKern::ThreadLeaveCS();
   717 
   718 	return r;
   719 	}
   720 
   721 //
   722 // DCaptureBuffers
   723 //
   724 
   725 /**
   726   Construct a new set of buffers
   727 
   728   @param aNumBuffers Number of buffers
   729   @param aBufferSize Size of each buffer in bytes
   730 
   731   @return Pointer to the created DCaptureBuffers or NULL if the system ran out of memory
   732 */
   733 DCaptureBuffers* DCaptureBuffers::New(TInt aNumBuffers,TInt aBufferSize)
   734 	{
   735 	DCaptureBuffers* buffers = new DCaptureBuffers;
   736 	if(buffers)
   737 		{
   738 		TInt r = buffers->Create(aNumBuffers,aBufferSize);
   739 		if(r==KErrNone)
   740 			return buffers;
   741 		delete buffers;
   742 		// An error other than 'no memory' must be a programming error in the driver
   743 		__NK_ASSERT_ALWAYS(r==KErrNoMemory);
   744 		}
   745 	return NULL;
   746 	}
   747 
   748 /**
   749   Construct with access count of one
   750 */
   751 DCaptureBuffers::DCaptureBuffers()
   752 	: iAccessCount(1)
   753 	{
   754 	}
   755 
   756 /**
   757   Create all buffers and lists
   758 */
   759 TInt DCaptureBuffers::Create(TInt aNumBuffers,TInt aBufferSize)
   760 	{
   761 	// Allocate buffer lists
   762 	DImageBuffer** lists = (DImageBuffer**)Kern::AllocZ(3*aNumBuffers*sizeof(DImageBuffer*));
   763 	if(!lists)
   764 		return KErrNoMemory;
   765 	iBufferLists = lists;
   766 	iFreeBuffers = lists;
   767 	iCompletedBuffers = lists+aNumBuffers;
   768 	iInUseBuffers = lists+2*aNumBuffers;
   769 
   770 	// Calculate sizes
   771 	aBufferSize = Kern::RoundToPageSize(aBufferSize);
   772 	TInt pageSize = Kern::RoundToPageSize(1);
   773 	TUint64 chunkSize = TUint64(aBufferSize+pageSize)*aNumBuffers+pageSize;
   774 	if(chunkSize>(TUint64)KMaxTInt)
   775 		return KErrNoMemory;  // Need more than 2GB of memory!
   776 
   777 	// Create chunk
   778 	TChunkCreateInfo info;
   779 	info.iType = TChunkCreateInfo::ESharedKernelMultiple;
   780 	info.iMaxSize = (TInt)chunkSize;
   781 #ifndef __WINS__
   782 	info.iMapAttr = EMapAttrCachedMax;
   783 #else
   784 	info.iMapAttr = 0;
   785 #endif
   786 	info.iOwnsMemory = ETrue;
   787 	TInt r = Kern::ChunkCreate(info,iChunk,iChunkBase,iChunkMapAttr);
   788 	if(r!=KErrNone)
   789 		return r;
   790 
   791 	// Construct array of buffers
   792 	iNumBuffers = aNumBuffers;
   793 	iImageBuffer = new DImageBuffer[aNumBuffers];
   794 	if(!iImageBuffer)
   795 		return KErrNoMemory;
   796 
   797 	// Create each buffer
   798 	TInt offset = pageSize;
   799 	while(aNumBuffers)
   800 		{
   801 		r = iImageBuffer[--aNumBuffers].Create(iChunk,offset,aBufferSize);
   802 		if(r!=KErrNone)
   803 			return r;
   804 		offset += aBufferSize+pageSize;
   805 		}
   806 
   807 	return KErrNone;
   808 	}
   809 
   810 /**
   811   Destructor
   812 */
   813 DCaptureBuffers::~DCaptureBuffers()
   814 	{
   815 	if(iChunk)
   816 		Kern::ChunkClose(iChunk);
   817 	delete [] iImageBuffer;
   818 	Kern::Free(iBufferLists);
   819 	}
   820 
   821 /**
   822   Increment access count of buffers
   823 */
   824 void DCaptureBuffers::Open()
   825 	{
   826 	__e32_atomic_tas_ord32(&iAccessCount, 1, 1, 0);
   827 	}
   828 
   829 /**
   830   Decrement access count of buffers.
   831   Deleting them if the count is decremented to zero.
   832 */
   833 void DCaptureBuffers::Close()
   834 	{
   835 	__ASSERT_NO_FAST_MUTEX;
   836 	__ASSERT_CRITICAL;
   837 	if(__e32_atomic_tas_ord32(&iAccessCount, 1, -1, 0) == 1)
   838 		AsyncDelete();
   839 	}
   840 
   841 /**
   842   Reset all image buffer lists to reflect the state at the start of image capture process
   843 */
   844 void DCaptureBuffers::Reset()
   845 	{
   846 	// Purge cache for all buffers in use by client.
   847 	DImageBuffer** list = iInUseBuffers;
   848 	DImageBuffer* buffer;
   849 	while((buffer=*list++)!=NULL)
   850 		Purge(buffer);
   851 
   852 	// Get pointers to first buffer
   853 	buffer = iImageBuffer; 
   854 
   855 	// Set buffers for current and next images
   856 	iCurrentBuffer = buffer++;
   857 	iNextBuffer = buffer++;
   858 
   859 	// Add all other buffers to the free list
   860 	DImageBuffer** free = iFreeBuffers;
   861 	DImageBuffer* bufferLimit = iImageBuffer+iNumBuffers; 
   862 	while(buffer<bufferLimit)
   863 		*free++ = buffer++;
   864 	*free = 0;
   865 
   866 	// Start with no completed or used buffers
   867 	iCompletedBuffers[0] = 0;
   868 	iInUseBuffers[0] = 0;
   869 	}
   870 
   871 /**
   872   Purge cache for an image buffer.
   873   @param aBuffer The buffer.
   874 */
   875 void DCaptureBuffers::Purge(DImageBuffer* aBuffer)
   876 	{
   877 	Cache::SyncMemoryBeforeDmaRead(iChunkBase+aBuffer->iChunkOffset,aBuffer->iSize,iChunkMapAttr);
   878 	}
   879 
   880 /**
   881   Remove an image buffer to the start of the given image list.
   882   @return A pointer to the image buffer or NULL if the list was empty
   883 */
   884 DImageBuffer* DCaptureBuffers::Remove(DImageBuffer** aList)
   885 	{
   886 	DImageBuffer* buffer=aList[0];
   887 	if(buffer)
   888 		{
   889 		DImageBuffer* b;
   890 		do
   891 			{
   892 			b=aList[1];
   893 			*aList++ = b;
   894 			}
   895 		while(b);
   896 		}
   897 	return buffer;
   898 	}
   899 
   900 /**
   901   Add an image buffer to the end of the given image list.
   902 */
   903 DImageBuffer* DCaptureBuffers::Add(DImageBuffer** aList, DImageBuffer* aBuffer)
   904 	{
   905 	while(*aList) aList++;
   906 	*aList = aBuffer;
   907 	return aBuffer;
   908 	}
   909 
   910 /**
   911   Update buffer lists after an image has been captured.
   912   @return A pointer to the catptured image buffer
   913 */
   914 DImageBuffer* DCaptureBuffers::ImageCaptured()
   915 	{
   916 	// Add captured image to completed list
   917 	DImageBuffer* buffer = iCurrentBuffer;
   918 	DCaptureBuffers::Add(iCompletedBuffers,buffer);
   919 
   920 	// Make queued buffer the current one
   921 	iCurrentBuffer = iNextBuffer;
   922 
   923 	// Queue a new buffer
   924 	iNextBuffer = DCaptureBuffers::Remove(iFreeBuffers);
   925 	if(!iNextBuffer)
   926 		iNextBuffer = DCaptureBuffers::Remove(iCompletedBuffers);
   927 
   928 	TRACE(Kern::Printf("DCaptureBuffers::ImageCaptured  buf=%08x\n",buffer->iChunkOffset);)
   929 
   930 	return buffer;
   931 	}
   932 
   933 /**
   934   Get the next image from the completed capture list and make it 'in use' by the client
   935 
   936   @return A pointer to the next completed image buffer
   937 */
   938 DImageBuffer* DCaptureBuffers::ImageForClient()
   939 	{
   940 	DImageBuffer* buffer=Remove(iCompletedBuffers);
   941 	if(buffer)
   942 		DCaptureBuffers::Add(iInUseBuffers,buffer);
   943 
   944 	TRACE(Kern::Printf("DCaptureBuffers::ImageForClient buf=%08x\n",buffer ? buffer->iChunkOffset : -1);)
   945 
   946 	return buffer;
   947 	}
   948 
   949 /**
   950   Release (move to free list) the 'in use' image specified by the given chunk offset.
   951 
   952   @param aChunkOffset The chunk offset corresponding to the buffer to be freed
   953 
   954   @return The freed image buffer, or NULL if no 'in use' buffer had the specified chunk offset.
   955 */
   956 DImageBuffer* DCaptureBuffers::ImageRelease(TInt aChunkOffset)
   957 	{
   958 	// Scan 'in use' list for the image buffer
   959 	DImageBuffer** list = iInUseBuffers;
   960 	DImageBuffer* buffer;
   961 	while((buffer=*list++)!=NULL && buffer->iChunkOffset!=aChunkOffset)
   962 		{};
   963 
   964 	// Move buffer to the free list (if found)
   965 	if(buffer)
   966 		buffer = Add(iFreeBuffers,Remove(list-1));
   967 
   968 	TRACE(Kern::Printf("DCaptureBuffers::ImageRelease   buf=%08x\n",buffer ? buffer->iChunkOffset : -1);)
   969 
   970 	return buffer;
   971 	}
   972 
   973 /**
   974   Find the 'in use' image specified by the given chunk offset
   975 
   976   @param aChunkOffset The chunk offset corresponding to the buffer to be freed
   977 
   978   @return The image buffer, or NULL if no 'in use' buffer had the specified chunk offset
   979 */
   980 DImageBuffer* DCaptureBuffers::InUseImage(TInt aChunkOffset)
   981 	{
   982 	// Scan 'in use' list for the image buffer
   983 	DImageBuffer** list = iInUseBuffers;
   984 	DImageBuffer* buffer;
   985 	while((buffer=*list++)!=NULL && buffer->iChunkOffset!=aChunkOffset)
   986 		{};
   987 
   988 	return buffer;
   989 	}
   990 
   991 //
   992 // DImageBuffer
   993 //
   994 
   995 /**
   996   Constructor clears all member data
   997 */
   998 DImageBuffer::DImageBuffer()
   999 	{
  1000 	memclr(this,sizeof(*this));
  1001 	}
  1002 
  1003 /**
  1004   Commit memory for this buffer.
  1005 
  1006   @param aChunk  The chunk into which the memory is to be commited
  1007   @param aOffset The offset within aChunk for the start of the comitted memory.
  1008                  Must be a multiple of the MMU page size.
  1009   @param aSize   The number of bytes of memory to commit.
  1010                  Must be a multiple of the MMU page size.
  1011 
  1012   @return KErrNone if successful, otherwise one of the other system wide error codes.
  1013 */
  1014 TInt DImageBuffer::Create(DChunk* aChunk, TInt aOffset, TInt aSize)
  1015 	{
  1016 	TInt r;
  1017 
  1018 	// Initialise data
  1019 	iChunkOffset = aOffset;
  1020 	iSize = aSize;
  1021 
  1022 	// Try for physically contiguous memory first
  1023 	r = Kern::ChunkCommitContiguous(aChunk,aOffset,aSize,iPhysicalAddress);
  1024 	if(r==KErrNone)
  1025 		return r;
  1026 
  1027 	// failed to get contiguous memory...
  1028 
  1029 	// Mark physical address invalid
  1030 	iPhysicalAddress = KPhysAddrInvalid;
  1031 
  1032 	// Commit discontiguous memory
  1033 	r = Kern::ChunkCommit(aChunk,aOffset,aSize);
  1034 	if(r!=KErrNone)
  1035 		return r;
  1036 
  1037 	// Allocate array for list of physical pages
  1038 	iPhysicalPages = new TPhysAddr[aSize/Kern::RoundToPageSize(1)];
  1039 	if(!iPhysicalPages)
  1040 		return KErrNoMemory;
  1041 
  1042 	// Get physical addresses of pages in buffer
  1043 	TUint32 kernAddr;
  1044 	TUint32 mapAttr;
  1045 	TPhysAddr physAddr;
  1046 	r = Kern::ChunkPhysicalAddress(aChunk,aOffset,aSize,kernAddr,mapAttr,physAddr,iPhysicalPages);
  1047 	// r = 0 or 1 on success. (1 meaning the physical pages are not-contiguous)
  1048 	if(r>=0)
  1049 		r = KErrNone;
  1050 	return r;
  1051 	}
  1052 
  1053 /**
  1054   Destructor
  1055 */
  1056 DImageBuffer::~DImageBuffer()
  1057 	{
  1058 	delete [] iPhysicalPages;
  1059 	}
  1060 
  1061 //
  1062 // Program camera hardware
  1063 //
  1064 
  1065 /**
  1066   Initialise camera hardware to start capturing images
  1067   First buffer to fill is iCaptureBuffers->iCurrentBuffer.
  1068   Next buffer to fill will be iCaptureBuffers->iNextBuffer.
  1069 */
  1070 void DCamera1Channel::DoStartCapture()
  1071 	{
  1072 	// For this example test...
  1073 	
  1074 	TRACE(Kern::Printf("DCamera1Channel::DoStartCapture buf=%08x cnt=%04d\n",iCaptureBuffers->iCurrentBuffer->iChunkOffset,iCaptureCounter);)
  1075 
  1076 	// Initialise frame counter
  1077 	iCaptureCounter = 0;
  1078 
  1079 	// Put frame counter into current image buffer. (This is the 'image' data we capture).
  1080 	*(TInt*)(iCaptureBuffers->iChunkBase+iCaptureBuffers->iCurrentBuffer->iChunkOffset) = iCaptureCounter++;
  1081 
  1082 	// Start the timer
  1083 	TInt r=iCaptureTimer.OneShot(iCaptureRateTicks,ETrue);
  1084 	__NK_ASSERT_ALWAYS(r==KErrNone);
  1085 	}
  1086 
  1087 /**
  1088   Reset camera hardware to stop capturing images
  1089 */
  1090 void DCamera1Channel::DoEndCapture()
  1091 	{
  1092 	// For this example test...
  1093 
  1094 	TRACE(Kern::Printf("DCamera1Channel::DoEndCapture\n");)
  1095 
  1096 	// Cancel the timer
  1097 	iCaptureTimer.Cancel();
  1098 	}
  1099 
  1100 /**
  1101   Setup camera hardware to capture next image
  1102   Next buffer to fill will be iCaptureBuffers->iNextBuffer;
  1103 
  1104   @param aLastImage The last image just captured. I.e. the completed capture which caused
  1105 					this method to be called
  1106 */
  1107 void DCamera1Channel::DoNextCapture()
  1108 	{
  1109 	// For this example test...
  1110 	
  1111 	TRACE(Kern::Printf("DCamera1Channel::DoNextCapture  cur=%08x cnt=%04d nxt=%08x\n",iCaptureBuffers->iCurrentBuffer->iChunkOffset,iCaptureCounter,iCaptureBuffers->iNextBuffer->iChunkOffset);)
  1112 
  1113 	// Put frame counter into current image buffer. (This is the 'image' data we capture).
  1114 	*(TInt*)(iCaptureBuffers->iChunkBase+iCaptureBuffers->iCurrentBuffer->iChunkOffset) = iCaptureCounter++;
  1115 
  1116 	// Restart the timer
  1117 	TInt r = iCaptureTimer.Again(iCaptureRateTicks);
  1118 	if(r==KErrArgument)
  1119 		{
  1120 		// Timer would have already expired.
  1121 		//
  1122 		// In a real device driver this is analogous to iCurrentBuffer already being filled
  1123 		// and the DMA queue being emptied. I.e. we have missed some frames.
  1124 		//
  1125 		// For this test...
  1126 
  1127 		TRACE(Kern::Printf("DCamera1Channel::DoNextCapture frame dropped cnt=%04d\n",iCaptureCounter);)
  1128 
  1129 		// Skip a frame count
  1130 		++iCaptureCounter;
  1131 
  1132 		// Restart timer
  1133 		r = iCaptureTimer.OneShot(iCaptureRateTicks,ETrue);
  1134 		}
  1135 	__NK_ASSERT_ALWAYS(r==KErrNone);
  1136 	}
  1137