kerneltest/e32test/examples/camera1/camera1_ldd.cpp
changeset 0 a41df078684a
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     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