sl@0: // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // template\template_variant\camerasc\camerasc_sensor.cpp sl@0: // Implementation of the template shared chunk camera physical device driver (PDD). sl@0: // This file is part of the Template Base port sl@0: // sl@0: // sl@0: sl@0: /** sl@0: @file sl@0: */ sl@0: sl@0: #include "camerasc_plat.h" sl@0: #include sl@0: sl@0: // XXX - Temporary structure containing a logo to be displayed. Remove this when sl@0: // changing this template into a "real" camera driver sl@0: #include "logoyuv2.cpp" sl@0: sl@0: sl@0: #define RGBtoBGR565(red, green, blue) (((blue & 0xf8) << 8) | ((green & 0xfc) << 3) | ((red & 0xf8) >> 3)); sl@0: sl@0: #define YUVtoYUV565(luma, blueC, redC) (((luma & 0xf8) << 8) | ((blueC & 0xfc) << 3) | ((redC & 0xf8) >> 3)); sl@0: sl@0: // Frame sizes and their associated frame rates supported by the Template sensor. This selection was sl@0: // obtained by observation of typical formats supported by phones already on the market; It is arbitrary sl@0: // and can be easily added to if desired sl@0: static const SDevCamFrameSize FrameSizes[] = sl@0: { sl@0: { 320, 240, 1, 30 } , // QVGA - 0.075 MP sl@0: // XXX: Although not used in this template driver, the following are suggested standard frame sizes sl@0: // that should be implemented in your camera driver, as well as 320 x 240 above. Remember to change sl@0: // KNumFrameSizes below if you change the number of sizes defined in here! sl@0: { 640, 480, 1, 30 }, // VGA - 0.3 MP sl@0: { 800, 600, 1, 30 }, // SVGA - 0.5 MP sl@0: { 1024, 768, 1, 30 }, // XGA - 0.8 MP sl@0: { 2048, 1536, 1, 15 }, // QXGA - 3 MP sl@0: //{ 2560, 1600, 1, 30 } // WQXGA - 4.1 MP sl@0: }; sl@0: sl@0: // This constant must be updated if the number of frame sizes listed above changes sl@0: static const TInt KNumFrameSizes = sizeof(FrameSizes) / sizeof(SDevCamFrameSize); sl@0: sl@0: // Pixel formats supported by the three different capture modes. These are mapped onto the appropriate sl@0: // array of supported frame rates by the FrameSizeCaps() function sl@0: static const SDevCamPixelFormat PixelFormats[] = sl@0: { sl@0: // Image pixel formats sl@0: { EUidPixelFormatYUV_422Interleaved, KNumFrameSizes, 2 }, sl@0: sl@0: // Video pixel formats sl@0: { EUidPixelFormatYUV_422Interleaved, KNumFrameSizes, 2 }, sl@0: sl@0: // View finder pixel formats sl@0: { EUidPixelFormatYUV_422Interleaved, KNumFrameSizes, 2 } sl@0: sl@0: }; sl@0: sl@0: // These constants must be updated if the number of pixel formats listed above changes sl@0: static const TInt KNumImagePixelFormats = 1; sl@0: static const TInt KNumVideoPixelFormats = 1; sl@0: static const TInt KNumViewFinderPixelFormats = 1; sl@0: sl@0: // Alternate logo images after this many frames sl@0: static const TInt KAlternateLogoFrameInterval = 5; sl@0: sl@0: static void ImageTimerCallback(TAny* aSensorIf) sl@0: { sl@0: DTemplateSensorIf* sensor = (DTemplateSensorIf*) aSensorIf; sl@0: sl@0: // XXX - Call the buffer done function in the sensor class. In this case we are just emulating the sl@0: // interrupt and DFC callback that would happen when an image is captured, so we always pass in KErrNone. sl@0: // In a real driver, we would read the hardware here to check that the capture happened successfully and sl@0: // would pass in the appropriate error code sl@0: sensor->BufferDoneCallback(KErrNone); sl@0: } sl@0: sl@0: /** sl@0: Saves a configuration specifying such details as dimensions and pixel format in which the sensor should sl@0: capture images. sl@0: @param aConfig A TCameraConfigV02 structure containing the settings to be used. sl@0: @return KErrNone if successful, otherwise one of the other system wide error codes. sl@0: */ sl@0: TInt DSensorIf::SetConfig(const TCameraConfigV02& aConfig) sl@0: { sl@0: // Manual settings for flash mode, focus, white balance etc. are not supported by the sensor, sl@0: // so check for these and return KErrNotSupported if they have been requested sl@0: if ((aConfig.iFlashMode != ECamFlashNone) || sl@0: (aConfig.iExposureMode != ECamExposureAuto) || sl@0: (aConfig.iZoom != 0) /*|| sl@0: (aConfig.iWhiteBalanceMode != ECamWBAuto) || sl@0: (aConfig.iContrast != ECamContrastAuto) || sl@0: (aConfig.iBrightness != ECamBrightnessAuto)*/) sl@0: { sl@0: // XXX: Remove this once support is addded for these modes sl@0: return KErrNotSupported; sl@0: } sl@0: sl@0: // As well as saving the configuration, also save copies of the width and height for easy access, sl@0: // as they are accessed frequently, as well as the offset in bytes between lines sl@0: iConfig = aConfig; sl@0: iWidth = aConfig.iFrameSize.iWidth; sl@0: iHeight = aConfig.iFrameSize.iHeight; sl@0: iLineOffset = (iWidth * iConfig.iPixelFormat.iPixelWidthInBytes); sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** sl@0: Constructor for the Template sensor class. sl@0: */ sl@0: sl@0: DTemplateSensorIf::DTemplateSensorIf(MSensorObserver& aObserver, TDfcQue* aDFCQueue) sl@0: : iDFCQueue(aDFCQueue) sl@0: { sl@0: iObserver = &aObserver; sl@0: iXDirection = iYDirection = 1; sl@0: sl@0: iCounter = 0; sl@0: iFlipSwitch = EFalse; sl@0: } sl@0: sl@0: /** sl@0: Second stage constructor for the Template sensor class. sl@0: sl@0: @return KErrNone if successful, otherwise one of the other system wide error codes. sl@0: */ sl@0: TInt DTemplateSensorIf::DoCreate() sl@0: { sl@0: __KTRACE_CAM(Kern::Printf("> DTemplateSensorIf::DoCreate()")); sl@0: sl@0: TInt r = KErrNone; sl@0: sl@0: for (TInt index = 0; index < KTotalCameraRequests; ++index) sl@0: { sl@0: if ((iImageTimerDFCs[index] = new TDfc(ImageTimerCallback, this, iDFCQueue, 0)) == NULL) sl@0: { sl@0: r = KErrNoMemory; sl@0: sl@0: break; sl@0: } sl@0: } sl@0: sl@0: __KTRACE_CAM(Kern::Printf("< DTemplateSensorIf::DoCreate() => Returning %d", r)); sl@0: sl@0: return r; sl@0: } sl@0: sl@0: /** sl@0: Destructor for the Template sensor class. sl@0: */ sl@0: DTemplateSensorIf::~DTemplateSensorIf() sl@0: { sl@0: for (TInt index = 0; index < KTotalCameraRequests; ++index) sl@0: { sl@0: iImageTimers[index].Cancel(); sl@0: delete iImageTimerDFCs[index]; sl@0: } sl@0: } sl@0: sl@0: /** sl@0: Called by the underlying sensor class when an image has been captured. sl@0: @param aResult KErrNone if the image was captured successfully, otherwise one of sl@0: the other system wide error codes. sl@0: @return KErrNone if successful, otherwise one of the other system wide error codes. sl@0: */ sl@0: TInt DTemplateSensorIf::BufferDoneCallback(TInt aResult) sl@0: { sl@0: TInt r = KErrNone; sl@0: sl@0: NKern::LockedDec(iPendingRequests); sl@0: sl@0: TLinAddr linAddr; sl@0: TPhysAddr physAddr; sl@0: sl@0: // Call the LDD to let it know that an image capture has completed. If the LDD needs more images sl@0: // to be captured, then it will return KErrNone and the virtual and physical addresses of the sl@0: // next buffer to be filled will be returned in linAddr and physAddr respectively. Note that as sl@0: // will as starting a capture of an image in here, the LDD may also call CaptureNextImage() to start sl@0: // capture as well sl@0: r = iObserver->NotifyImageCaptureEvent(aResult, linAddr, physAddr); sl@0: sl@0: if (r == KErrNone) sl@0: { sl@0: iNextRequest = ((iNextRequest + 1) % KTotalCameraRequests); sl@0: NKern::LockedInc(iPendingRequests); sl@0: sl@0: // XXX: Temporary code to be removed in a real driver. Fill the buffer for testing sl@0: // with user side code sl@0: FillBuffer(linAddr); sl@0: sl@0: // XXX: Send buffer to sensor. Normally the address of the buffer passed in in aLinAddr and sl@0: // aPhysAddr would be programmed into the sensor and/or bus hardware here and an interrupt sl@0: // would be generated when the iamge had been captured into the buffer. In this simulated sl@0: // driver we will use a nanokernel timer to simulate this process sl@0: iImageTimers[iNextRequest].OneShot(iImageTimerTicks, *iImageTimerDFCs[iNextRequest]); sl@0: } sl@0: sl@0: return r; sl@0: } sl@0: sl@0: /** sl@0: Fills a buffer with a white background with a moving logo on top. sl@0: @param aBuffer Pointer to the buffer to be filled. sl@0: */ sl@0: void DTemplateSensorIf::FillBuffer(TLinAddr aBuffer) sl@0: { sl@0: const TUint8* LogoData = Logo.iPixelData; sl@0: const TUint8* LogoData2 = Logo.iPixelData2; sl@0: TInt index = 0; sl@0: TInt numPixels = (iConfig.iFrameSize.iWidth * iConfig.iFrameSize.iHeight); sl@0: TUint yC, uC, vC; sl@0: TUint16* buffer = (TUint16*) aBuffer; sl@0: sl@0: // Alternate between the two logos for cheesy animation effect sl@0: if( ++iCounter == KAlternateLogoFrameInterval ) sl@0: { sl@0: iFlipSwitch ^= 1; sl@0: iCounter = 0; sl@0: } sl@0: sl@0: sl@0: // Set the "photo" background to be all white sl@0: memset(buffer, 0xff, (numPixels * 2)); sl@0: sl@0: // Point to the correct location in the buffer at which to render the logo sl@0: buffer += ((iY * iConfig.iFrameSize.iWidth) + iX); sl@0: sl@0: // Iterate through the data for the logo and copy it into the "photo" sl@0: for (TUint y = 0; y < Logo.iHeight; ++y) sl@0: { sl@0: for (TUint x = 0; x < Logo.iWidth; ++x) sl@0: { sl@0: // The logo is in 24 bit BGR format so read each pixel and convert it to 16 bit BGR565 sl@0: // before writing it into the "photo" buffer sl@0: if( iFlipSwitch ) sl@0: { sl@0: yC = LogoData[index]; sl@0: uC = LogoData[index + 1]; sl@0: vC = LogoData[index + 2]; sl@0: } sl@0: else sl@0: { sl@0: yC = LogoData2[index]; sl@0: uC = LogoData2[index + 1]; sl@0: vC = LogoData2[index + 2]; sl@0: } sl@0: sl@0: *buffer++ = YUVtoYUV565(yC, uC, vC); sl@0: // Point to the next source pixel sl@0: index += 3; sl@0: } sl@0: sl@0: // Point to the start of the next line in the buffer, taking into account that the logo sl@0: // is narrower than the buffer sl@0: buffer += (iConfig.iFrameSize.iWidth - Logo.iWidth); sl@0: } sl@0: sl@0: // Bounce the logo around in the X direction. This will take effect the next time this is called sl@0: iX += iXDirection; sl@0: sl@0: if (iX <= 0) sl@0: { sl@0: iX = 0; sl@0: iXDirection = -iXDirection; sl@0: } sl@0: else if (iX >= (TInt) (iConfig.iFrameSize.iWidth - Logo.iWidth)) sl@0: { sl@0: iX = (iConfig.iFrameSize.iWidth - Logo.iWidth); sl@0: iXDirection = -iXDirection; sl@0: } sl@0: sl@0: // Bounce the logo around in the Y direction. This will take effect the next time this is called sl@0: iY += iYDirection; sl@0: sl@0: if (iY <= 0) sl@0: { sl@0: iY = 0; sl@0: iYDirection = -iYDirection; sl@0: } sl@0: else if (iY >= (TInt) (iConfig.iFrameSize.iHeight - Logo.iHeight)) sl@0: { sl@0: iY = (iConfig.iFrameSize.iHeight - Logo.iHeight); sl@0: iYDirection = -iYDirection; sl@0: } sl@0: sl@0: // Now flush the cache to memory, taking into account the size of each pixel. This is not normally sl@0: // necessary but given that we are emulating a camera driver in software we must ensure that the sl@0: // cache is flushed to memory. This is because in a real driver the buffer will have been filled sl@0: // by DMA so upon return to the LDD, the LDD will discard the contents of the cache to ensure the sl@0: // DMA-written data is ok. In the case of filling the buffer using the CPU in this virtual camera sl@0: // driver, that would result in the data being discarded! sl@0: Cache::SyncMemoryBeforeDmaWrite((TLinAddr) aBuffer, (numPixels * iConfig.iPixelFormat.iPixelWidthInBytes)); sl@0: } sl@0: sl@0: /** sl@0: Based on the capture mode and pixel format passed in, copies an array of supported SFrameSize sl@0: structures into a buffer supplied by the LDD. These frame sizes and their associated frame rates sl@0: will reflect the capabilities of the given capture mode and pixel format. sl@0: @param aCaptureMode The capture mode for which to obtain the supported frame sizes. sl@0: @param aUidPixelFormat The UID of the pixel format (as defined in \epoc32\include\pixelformats.h) sl@0: for which to obtain the supported frame sizes. sl@0: @param aFrameSizeCapsBuf A reference to a descriptor that contains a buffer into which to place sl@0: the frame size structures. It is up to the LDD to ensure that this is sl@0: large enough to hold all of the frame sizes. sl@0: @return Always KErrNone. sl@0: */ sl@0: TInt DTemplateSensorIf::FrameSizeCaps(TDevCamCaptureMode /*aCaptureMode*/, TUidPixelFormat /*aUidPixelFormat*/, TDes8& aFrameSizeCapsBuf) sl@0: { sl@0: TPtrC8 sourceFrameSizes((const TUint8*) FrameSizes, sizeof(FrameSizes)); sl@0: sl@0: // Ensure the buffer passed in from the LDD is large enough and copy the requested frame sizes sl@0: if (aFrameSizeCapsBuf.Size() < sourceFrameSizes.Size()) sl@0: { sl@0: Kern::Printf("*** ECapsBufferTooSmall: %d vs %d", sl@0: aFrameSizeCapsBuf.Size(), sl@0: sourceFrameSizes.Size()); sl@0: Kern::Fault("camerasc", ECapsBufferTooSmall); sl@0: } sl@0: sl@0: //__ASSERT_DEBUG((aFrameSizeCapsBuf.Size() >= sourceFrameSizes.Size()), Kern::Fault("camerasc", ECapsBufferTooSmall)); sl@0: aFrameSizeCapsBuf = sourceFrameSizes; sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** sl@0: Allocates a buffer large enough to hold the TCameraCapsV02 structure and its succeeding array of sl@0: pixel formats, and populates the structure and array with information about the capabilities of sl@0: the sensor. sl@0: @param aCameraCaps Reference to a pointer into which to place the pointer to allocated buffer sl@0: @return Size of the capabilities structure if successful, otherwise one of the other system wide sl@0: error codes. sl@0: */ sl@0: TInt DTemplateSensorIf::GetCaps(TCameraCapsV02*& aCameraCaps) sl@0: { sl@0: // Allocate a buffer large enough to hold the TCameraCapsV02 structure and the array of pixel formats sl@0: // that will follow it sl@0: TInt r = (sizeof(TCameraCapsV02) + sizeof(PixelFormats)); sl@0: TUint8* capsBuffer = new TUint8[r]; sl@0: sl@0: if (capsBuffer) sl@0: { sl@0: aCameraCaps = (TCameraCapsV02*) capsBuffer; sl@0: sl@0: // No special modes are supported at the moment sl@0: aCameraCaps->iFlashModes = ECamFlashNone; sl@0: aCameraCaps->iExposureModes = ECamExposureAuto; // or None? sl@0: // do we still need whitebalance mode filed? sl@0: aCameraCaps->iWhiteBalanceModes = ECamWBAuto | ECamWBDaylight | ECamWBCloudy | ECamWBTungsten | ECamWBFluorescent | ECamWBFlash | ECamWBSnow | ECamWBBeach; sl@0: aCameraCaps->iMinZoom = 0; sl@0: aCameraCaps->iMaxZoom = 0; sl@0: aCameraCaps->iCapsMisc = KCamMiscContrast | KCamMiscBrightness | KCamMiscColorEffect; sl@0: sl@0: // There isn't really such thing as inwards or outwards orientation on an SDP, but we'll pretend it's sl@0: // an outwards facing camera sl@0: aCameraCaps->iOrientation = ECamOrientationOutwards; sl@0: sl@0: // Initialise the number of different pixel formats supported sl@0: aCameraCaps->iNumImagePixelFormats = KNumImagePixelFormats; sl@0: aCameraCaps->iNumVideoPixelFormats = KNumVideoPixelFormats; sl@0: aCameraCaps->iNumViewFinderPixelFormats = KNumViewFinderPixelFormats; sl@0: sl@0: for (TInt i = 0; i < ECamAttributeMax; i++) sl@0: { sl@0: if (ECamAttributeColorEffect == (TDevCamDynamicAttribute)(i)) sl@0: { sl@0: // WhiteBalance sl@0: // In case of white balance, we shouldn't use MIN and MAX values as some of them in between MIN and MAX can be missed out. sl@0: // As this is fake driver, There doesn't seem to be any major issue though. sl@0: aCameraCaps->iDynamicRange[i].iMin = ECamWBAuto; sl@0: aCameraCaps->iDynamicRange[i].iMax = ECamWBBeach; sl@0: aCameraCaps->iDynamicRange[i].iDefault = ECamWBAuto; sl@0: } sl@0: else sl@0: { sl@0: // TBC :: Contrast, Brightness sl@0: aCameraCaps->iDynamicRange[i].iMin = 0; sl@0: aCameraCaps->iDynamicRange[i].iMax = 6; sl@0: aCameraCaps->iDynamicRange[i].iDefault = 3; sl@0: } sl@0: } sl@0: sl@0: // Setup some descriptors pointing to the pixel format array and the array passed in by the LDD sl@0: // (located at the end of the TCameraCapsV02 structure) and copy the pixel format array sl@0: TPtrC8 sourcePixelFormats((const TUint8*) PixelFormats, sizeof(PixelFormats)); sl@0: TPtr8 destPixelFormats((capsBuffer + sizeof(TCameraCapsV02)), sizeof(PixelFormats), sizeof(PixelFormats)); sl@0: destPixelFormats = sourcePixelFormats; sl@0: } sl@0: else sl@0: { sl@0: r = KErrNoMemory; sl@0: } sl@0: sl@0: return r; sl@0: } sl@0: sl@0: /** sl@0: Powers up the sensor hardware. sl@0: @return KErrNone if successful, otherwise one of the other system wide error codes. sl@0: */ sl@0: TInt DTemplateSensorIf::RequestPower() sl@0: { sl@0: __KTRACE_CAM(Kern::Printf("> DTemplateSensorIf::RequestPower()")); sl@0: sl@0: TInt r = KErrNone; sl@0: sl@0: __KTRACE_CAM(Kern::Printf("< DTemplateSensorIf::RequestPower() => Returning %d", r)); sl@0: sl@0: return r; sl@0: } sl@0: sl@0: /** sl@0: Powers down the sensor hardware. sl@0: @return KErrNone if successful, otherwise one of the other system wide error codes. sl@0: */ sl@0: TInt DTemplateSensorIf::RelinquishPower() sl@0: { sl@0: __KTRACE_CAM(Kern::Printf("> DTemplateSensorIf::RelinquishPower()")); sl@0: sl@0: TInt r = KErrNone; sl@0: sl@0: __KTRACE_CAM(Kern::Printf("< DTemplateSensorIf::RelinquishPower() => Returning %d", r)); sl@0: sl@0: return r; sl@0: } sl@0: sl@0: /** sl@0: Begins capture of the next image into the buffer provided. This function assumes that sl@0: Start() has already been called to start capture. However, Stop() may also have been sl@0: subsequently called (for example to pause capture) and in this case, this function will sl@0: handle restarting the sensor. sl@0: @param aLinAddr A virtual pointer to the buffer into which to capture the image. sl@0: @param aPhysAddr A physical pointer to the buffer into which to capture the image. sl@0: This points to the same memory as aLinAddr. sl@0: @return KErrNone if successful. sl@0: KErrNotReady if there are no free requests to capture the image. sl@0: Otherwise one of the other system wide error codes. sl@0: */ sl@0: TInt DTemplateSensorIf::CaptureNextImage(TLinAddr aLinAddr, TPhysAddr /*aPhysAddr*/) sl@0: { sl@0: TInt r = KErrNone; sl@0: sl@0: // Only start capturing the next image if there are any pending request slots available sl@0: if (iPendingRequests < KTotalCameraRequests) sl@0: { sl@0: // Queue a transfer on the next available channel and indicate that the channel is sl@0: // in use sl@0: iNextRequest = ((iNextRequest + 1) % KTotalCameraRequests); sl@0: NKern::LockedInc(iPendingRequests); sl@0: sl@0: // XXX: Temporary code to be removed in a real driver. Fill the buffer for testing sl@0: // with user side code. This is to simulate an image being captured into the buffer that sl@0: // has been passed in in aLinAddr. As well as aLinAddr, which points to the virtual sl@0: // address of the buffer, the LDD will pass in the physical address as well, in aPhysAddr. sl@0: // Depending on the underlying sensor hardware and/or bus in use, you will have to choose sl@0: // which of these to use sl@0: FillBuffer(aLinAddr); sl@0: sl@0: // XXX: Send buffer to sensor. Normally the address of the buffer passed in in aLinAddr and sl@0: // aPhysAddr would be programmed into the sensor and/or bus hardware here and an interrupt sl@0: // would be generated when the iamge had been captured into the buffer. In this simulated sl@0: // driver we will use a nanokernel timer to simulate this process sl@0: iImageTimers[iNextRequest].OneShot(iImageTimerTicks, *iImageTimerDFCs[iNextRequest]); sl@0: sl@0: // If capturing has not yet started or has been paused by Stop(), start it sl@0: if (!(iEnabled)) sl@0: { sl@0: iEnabled = ETrue; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: r = KErrNotReady; sl@0: } sl@0: sl@0: return r; sl@0: } sl@0: sl@0: /** sl@0: Begins capture of the first image into the buffer provided. This function is similar to sl@0: CaptureNextImage(), except that it will perform any extra sensor intitialisation required sl@0: to start capture. sl@0: @param aCaptureMode The capture mode for which to start capturing. sl@0: @param aLinAddr A virtual pointer to the buffer into which to capture the image. sl@0: @param aPhysAddr A physical pointer to the buffer into which to capture the image. sl@0: This points to the same memory as aLinAddr. sl@0: @return KErrNone if successful sl@0: KErrInUse if capture is already under way. sl@0: KErrNotSupported if the frame size and/or frame rate are out of range. sl@0: Otherwise one of the other system wide error codes. sl@0: */ sl@0: TInt DTemplateSensorIf::Start(TDevCamCaptureMode /*aCaptureMode*/, TLinAddr aLinAddr, TPhysAddr aPhysAddr) sl@0: { sl@0: __KTRACE_CAM(Kern::Printf("> DTemplateSensorIf::Start()")); sl@0: sl@0: TInt r = KErrNone; sl@0: sl@0: // XXX - In a real camera driver, in here we would initialise start the capturing process in here. sl@0: // When an image is captured, the sensor hardware (or maybe the CSI bus) will generate an sl@0: // which will then be enqueued into the DFC queue that was passed into the constructor of sl@0: // the sensor class. It is important to do the DFC processing in this DFC queue rather than sl@0: // a separate one because it ensures that fucntions in the PDD and LDD are called in a serialised sl@0: // manner, without the need for mutexts. In this example camera driver we will convert the sl@0: // framerate into a nanokernel tick count and will use an NTimer.OneShot() call to simulate sl@0: // the sensor interrupt and DFC callback. Divides are slow so we'll calculate the tick count sl@0: // here and will save it for later use sl@0: iImageTimerTicks = ((1000000 / NKern::TickPeriod()) / iConfig.iFrameRate); sl@0: sl@0: // XXX - Once the one off hardware initialisation has been done for starting a new capture, then sl@0: // subsequent captures can usually reuse the same code in CaptureNextImage() for starting sl@0: // the next capture sl@0: r = CaptureNextImage(aLinAddr, aPhysAddr); sl@0: sl@0: __KTRACE_CAM(Kern::Printf("< DTemplateSensorIf::Start() => Returning %d", r)); sl@0: sl@0: return r; sl@0: } sl@0: sl@0: /** sl@0: Stops capturing any image capture that is currently in progress. This function will act sl@0: more like a Pause() than a Stop() capturing can be restarted from where it was stopped. sl@0: */ sl@0: TInt DTemplateSensorIf::Stop() sl@0: { sl@0: __KTRACE_CAM(Kern::Printf("> DTemplateSensorIf::Stop()")); sl@0: sl@0: iEnabled = EFalse; sl@0: iPendingRequests = iNextRequest = 0; sl@0: sl@0: // XXX - Cancel all of our pending image timer callbacks. In a real driver we would write to the sl@0: // sensor and/or bus hardware here to cause them to cancel any pending image captures sl@0: for (TInt index = 0; index < KTotalCameraRequests; ++index) sl@0: { sl@0: iImageTimers[index].Cancel(); sl@0: } sl@0: sl@0: __KTRACE_CAM(Kern::Printf("< DTemplateSensorIf::Stop()")); sl@0: sl@0: return KErrNone; sl@0: }