QCamera2: Add HAL support for flashlight

Implemented new API at HAL, allowing framework to turn on flash
devices independently of the sensor. The primary logic is
implemented as a singleton named QCameraFlash, which tracks
the state of any flash devices and interfaces with the driver
to turn them on or off.

Change-Id: I4452e65401140e28aa86184800857a423c9c4b09
diff --git a/camera/QCamera2/Android.mk b/camera/QCamera2/Android.mk
index 2f6149f..2ab12a9 100644
--- a/camera/QCamera2/Android.mk
+++ b/camera/QCamera2/Android.mk
@@ -21,6 +21,7 @@
 LOCAL_SRC_FILES := \
         util/QCameraCmdThread.cpp \
         util/QCameraQueue.cpp \
+        util/QCameraFlash.cpp \
         QCamera2Hal.cpp \
         QCamera2Factory.cpp
 
diff --git a/camera/QCamera2/HAL3/QCamera3HWI.cpp b/camera/QCamera2/HAL3/QCamera3HWI.cpp
index 6086adb..00a65da 100644
--- a/camera/QCamera2/HAL3/QCamera3HWI.cpp
+++ b/camera/QCamera2/HAL3/QCamera3HWI.cpp
@@ -44,6 +44,7 @@
 #include <utils/Trace.h>
 #include <ui/Fence.h>
 #include <gralloc_priv.h>
+#include "util/QCameraFlash.h"
 #include "QCamera3HWI.h"
 #include "QCamera3Mem.h"
 #include "QCamera3Channel.h"
@@ -481,6 +482,15 @@
         ALOGE("Failure: Camera already opened");
         return ALREADY_EXISTS;
     }
+
+    rc = QCameraFlash::getInstance().reserveFlashForCamera(mCameraId);
+    if (rc < 0) {
+        ALOGE("%s: Failed to reserve flash for camera id: %d",
+                __func__,
+                mCameraId);
+        return UNKNOWN_ERROR;
+    }
+
     mCameraHandle = camera_open(mCameraId);
     if (!mCameraHandle) {
         ALOGE("camera_open failed.");
@@ -532,6 +542,12 @@
     }
 #endif
 
+    if (QCameraFlash::getInstance().releaseFlashFromCamera(mCameraId) != 0) {
+        CDBG("%s: Failed to release flash for camera id: %d",
+                __func__,
+                mCameraId);
+    }
+
     return rc;
 }
 
@@ -6896,4 +6912,34 @@
     return;
 }
 
+
+/*===========================================================================
+* FUNCTION   : getFlashInfo
+*
+* DESCRIPTION: Retrieve information about whether the device has a flash.
+*
+* PARAMETERS :
+*   @cameraId  : Camera id to query
+*   @hasFlash  : Boolean indicating whether there is a flash device
+*                associated with given camera
+*   @flashNode : If a flash device exists, this will be its device node.
+*
+* RETURN     :
+*   None
+*==========================================================================*/
+void QCamera3HardwareInterface::getFlashInfo(const int cameraId,
+        bool& hasFlash,
+        char (&flashNode)[QCAMERA_MAX_FILEPATH_LENGTH])
+{
+    cam_capability_t* camCapability = gCamCapability[cameraId];
+    if (NULL == camCapability) {
+        hasFlash = false;
+        flashNode[0] = '\0';
+    } else {
+        hasFlash = camCapability->flash_available;
+        strlcpy(flashNode,
+                (char*)camCapability->flash_dev_name,
+                QCAMERA_MAX_FILEPATH_LENGTH);
+    }
+}
 }; //end namespace qcamera
diff --git a/camera/QCamera2/HAL3/QCamera3HWI.h b/camera/QCamera2/HAL3/QCamera3HWI.h
index c2ac724..44484b6 100644
--- a/camera/QCamera2/HAL3/QCamera3HWI.h
+++ b/camera/QCamera2/HAL3/QCamera3HWI.h
@@ -232,6 +232,10 @@
     bool needOnlineRotation();
     int getJpegQuality();
     QCamera3Exif *getExifData();
+    static void getFlashInfo(const int cameraId,
+            bool& hasFlash,
+            char (&flashNode)[QCAMERA_MAX_FILEPATH_LENGTH]);
+
 private:
     camera3_device_t   mCameraDevice;
     uint8_t            mCameraId;
diff --git a/camera/QCamera2/QCamera2Factory.cpp b/camera/QCamera2/QCamera2Factory.cpp
index cc0be30..e0584b8 100644
--- a/camera/QCamera2/QCamera2Factory.cpp
+++ b/camera/QCamera2/QCamera2Factory.cpp
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2014, The Linux Foundataion. All rights reserved.
+/* Copyright (c) 2012-2015, The Linux Foundataion. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
@@ -38,6 +38,7 @@
 
 #include "HAL/QCamera2HWI.h"
 #include "HAL3/QCamera3HWI.h"
+#include "util/QCameraFlash.h"
 #include "QCamera2Factory.h"
 
 using namespace android;
@@ -186,6 +187,23 @@
 }
 
 /*===========================================================================
+ * FUNCTION   : set_torch_mode
+ *
+ * DESCRIPTION: Attempt to turn on or off the torch mode of the flash unit.
+ *
+ * PARAMETERS :
+ *   @camera_id : camera ID
+ *   @on        : Indicates whether to turn the flash on or off
+ *
+ * RETURN     : 0  -- success
+ *              none-zero failure code
+ *==========================================================================*/
+int QCamera2Factory::set_torch_mode(const char* camera_id, bool on)
+{
+    return gQCamera2Factory->setTorchMode(camera_id, on);
+}
+
+/*===========================================================================
  * FUNCTION   : getNumberOfCameras
  *
  * DESCRIPTION: query number of cameras detected
@@ -260,6 +278,12 @@
 {
     int rc = NO_ERROR;
     mCallbacks = callbacks;
+
+    rc = QCameraFlash::getInstance().registerCallbacks(callbacks);
+    if (rc != 0) {
+        ALOGE("%s : Failed to register callbacks with flash module!", __func__);
+    }
+
     return rc;
 }
 
@@ -353,5 +377,69 @@
     open: QCamera2Factory::camera_device_open,
 };
 
+/*===========================================================================
+ * FUNCTION   : setTorchMode
+ *
+ * DESCRIPTION: Attempt to turn on or off the torch mode of the flash unit.
+ *
+ * PARAMETERS :
+ *   @camera_id : camera ID
+ *   @on        : Indicates whether to turn the flash on or off
+ *
+ * RETURN     : 0  -- success
+ *              none-zero failure code
+ *==========================================================================*/
+int QCamera2Factory::setTorchMode(const char* camera_id, bool on)
+{
+    int retVal(0);
+    long cameraIdLong(-1);
+    int cameraIdInt(-1);
+    char* endPointer = NULL;
+    errno = 0;
+    QCameraFlash& flash = QCameraFlash::getInstance();
+
+    cameraIdLong = strtol(camera_id, &endPointer, 10);
+
+    if ((errno == ERANGE) ||
+            (cameraIdLong < 0) ||
+            (cameraIdLong >= static_cast<long>(get_number_of_cameras())) ||
+            (endPointer == camera_id) ||
+            (*endPointer != '\0')) {
+        retVal = -EINVAL;
+    } else if (on) {
+        cameraIdInt = static_cast<int>(cameraIdLong);
+        retVal = flash.initFlash(cameraIdInt);
+
+        if (retVal == 0) {
+            retVal = flash.setFlashMode(cameraIdInt, on);
+            if ((retVal == 0) && (mCallbacks != NULL)) {
+                mCallbacks->torch_mode_status_change(mCallbacks,
+                        camera_id,
+                        TORCH_MODE_STATUS_AVAILABLE_ON);
+            } else if (retVal == -EALREADY) {
+                // Flash is already on, so treat this as a success.
+                retVal = 0;
+            }
+        }
+    } else {
+        cameraIdInt = static_cast<int>(cameraIdLong);
+        retVal = flash.setFlashMode(cameraIdInt, on);
+
+        if (retVal == 0) {
+            retVal = flash.deinitFlash(cameraIdInt);
+            if ((retVal == 0) && (mCallbacks != NULL)) {
+                mCallbacks->torch_mode_status_change(mCallbacks,
+                        camera_id,
+                        TORCH_MODE_STATUS_AVAILABLE_OFF);
+            }
+        } else if (retVal == -EALREADY) {
+            // Flash is already off, so treat this as a success.
+            retVal = 0;
+        }
+    }
+
+    return retVal;
+}
+
 }; // namespace qcamera
 
diff --git a/camera/QCamera2/QCamera2Factory.h b/camera/QCamera2/QCamera2Factory.h
index 14dd4ba..d7e3e3d 100644
--- a/camera/QCamera2/QCamera2Factory.h
+++ b/camera/QCamera2/QCamera2Factory.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2014, The Linux Foundataion. All rights reserved.
+/* Copyright (c) 2012-2015, The Linux Foundataion. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
@@ -52,6 +52,7 @@
     static int set_callbacks(const camera_module_callbacks_t *callbacks);
     static int open_legacy(const struct hw_module_t* module,
             const char* id, uint32_t halVersion, struct hw_device_t** device);
+    static int set_torch_mode(const char* camera_id, bool on);
 
 private:
     int getNumberOfCameras();
@@ -60,7 +61,7 @@
     int cameraDeviceOpen(int camera_id, struct hw_device_t **hw_device);
     static int camera_device_open(const struct hw_module_t *module, const char *id,
                 struct hw_device_t **hw_device);
-
+    int setTorchMode(const char* camera_id, bool on);
 public:
     static struct hw_module_methods_t mModuleMethods;
 
diff --git a/camera/QCamera2/QCamera2Hal.cpp b/camera/QCamera2/QCamera2Hal.cpp
index 6d36778..3fb360a 100644
--- a/camera/QCamera2/QCamera2Hal.cpp
+++ b/camera/QCamera2/QCamera2Hal.cpp
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2014, The Linux Foundataion. All rights reserved.
+/* Copyright (c) 2012-2015, The Linux Foundataion. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
@@ -32,7 +32,7 @@
 
 static hw_module_t camera_common = {
     tag: HARDWARE_MODULE_TAG,
-    module_api_version: CAMERA_MODULE_API_VERSION_2_3,
+    module_api_version: CAMERA_MODULE_API_VERSION_2_4,
     hal_api_version: HARDWARE_HAL_API_VERSION,
     id: CAMERA_HARDWARE_MODULE_ID,
     name: "QCamera Module",
@@ -49,6 +49,6 @@
     set_callbacks: qcamera::QCamera2Factory::set_callbacks,
     get_vendor_tag_ops: qcamera::QCamera3VendorTags::get_vendor_tag_ops,
     open_legacy: qcamera::QCamera2Factory::open_legacy,
-    set_torch_mode: NULL,
+    set_torch_mode: qcamera::QCamera2Factory::set_torch_mode,
     reserved: {0}
 };
diff --git a/camera/QCamera2/stack/common/cam_types.h b/camera/QCamera2/stack/common/cam_types.h
index 8770b1b..6794eea 100644
--- a/camera/QCamera2/stack/common/cam_types.h
+++ b/camera/QCamera2/stack/common/cam_types.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2015, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -119,6 +119,8 @@
 #define MAX_INFLIGHT_REQUESTS  6
 #define MIN_INFLIGHT_REQUESTS  3
 
+#define QCAMERA_MAX_FILEPATH_LENGTH 64
+
 typedef enum {
     CAM_HAL_V1 = 1,
     CAM_HAL_V3 = 3
diff --git a/camera/QCamera2/util/QCameraFlash.cpp b/camera/QCamera2/util/QCameraFlash.cpp
new file mode 100644
index 0000000..7b0025c
--- /dev/null
+++ b/camera/QCamera2/util/QCameraFlash.cpp
@@ -0,0 +1,380 @@
+/* Copyright (c) 2015, The Linux Foundataion. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+*     * Redistributions of source code must retain the above copyright
+*       notice, this list of conditions and the following disclaimer.
+*     * Redistributions in binary form must reproduce the above
+*       copyright notice, this list of conditions and the following
+*       disclaimer in the documentation and/or other materials provided
+*       with the distribution.
+*     * Neither the name of The Linux Foundation nor the names of its
+*       contributors may be used to endorse or promote products derived
+*       from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*
+*/
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <linux/media.h>
+#include <media/msmb_camera.h>
+#include <media/msm_cam_sensor.h>
+#include <utils/Log.h>
+
+#include "HAL3/QCamera3HWI.h"
+#include "QCameraFlash.h"
+
+#define STRING_LENGTH_OF_64_BIT_NUMBER 21
+
+volatile uint32_t gCamHal3LogLevel = 1;
+
+namespace qcamera {
+
+/*===========================================================================
+ * FUNCTION   : getInstance
+ *
+ * DESCRIPTION: Get and create the QCameraFlash singleton.
+ *
+ * PARAMETERS : None
+ *
+ * RETURN     : None
+ *==========================================================================*/
+QCameraFlash& QCameraFlash::getInstance()
+{
+    static QCameraFlash flashInstance;
+    return flashInstance;
+}
+
+/*===========================================================================
+ * FUNCTION   : QCameraFlash
+ *
+ * DESCRIPTION: default constructor of QCameraFlash
+ *
+ * PARAMETERS : None
+ *
+ * RETURN     : None
+ *==========================================================================*/
+QCameraFlash::QCameraFlash() : m_callbacks(NULL)
+{
+    memset(&m_flashOn, 0, sizeof(m_flashOn));
+    memset(&m_cameraOpen, 0, sizeof(m_cameraOpen));
+    for (int pos = 0; pos < MM_CAMERA_MAX_NUM_SENSORS; pos++) {
+        m_flashFds[pos] = -1;
+    }
+}
+
+/*===========================================================================
+ * FUNCTION   : ~QCameraFlash
+ *
+ * DESCRIPTION: deconstructor of QCameraFlash
+ *
+ * PARAMETERS : None
+ *
+ * RETURN     : None
+ *==========================================================================*/
+QCameraFlash::~QCameraFlash()
+{
+    for (int pos = 0; pos < MM_CAMERA_MAX_NUM_SENSORS; pos++) {
+        if (m_flashFds[pos] >= 0)
+            {
+                setFlashMode(pos, false);
+                close(m_flashFds[pos]);
+                m_flashFds[pos] = -1;
+            }
+    }
+}
+
+/*===========================================================================
+ * FUNCTION   : registerCallbacks
+ *
+ * DESCRIPTION: provide flash module with reference to callbacks to framework
+ *
+ * PARAMETERS : None
+ *
+ * RETURN     : None
+ *==========================================================================*/
+int32_t QCameraFlash::registerCallbacks(
+        const camera_module_callbacks_t* callbacks)
+{
+    int32_t retVal = 0;
+    m_callbacks = callbacks;
+    return retVal;
+}
+
+/*===========================================================================
+ * FUNCTION   : initFlash
+ *
+ * DESCRIPTION: Reserve and initialize the flash unit associated with a
+ *              given camera id. This function is blocking until the
+ *              operation completes or fails. Each flash unit can be "inited"
+ *              by only one process at a time.
+ *
+ * PARAMETERS :
+ *   @camera_id : Camera id of the flash.
+ *
+ * RETURN     :
+ *   0        : success
+ *   -EBUSY   : The flash unit or the resource needed to turn on the
+ *              the flash is busy, typically because the flash is
+ *              already in use.
+ *   -EINVAL  : No flash present at camera_id.
+ *==========================================================================*/
+int32_t QCameraFlash::initFlash(const int camera_id)
+{
+    int32_t retVal = 0;
+    bool hasFlash = false;
+    char flashNode[QCAMERA_MAX_FILEPATH_LENGTH];
+    char flashPath[QCAMERA_MAX_FILEPATH_LENGTH] = "/dev/";
+
+    if (camera_id < 0 || camera_id >= MM_CAMERA_MAX_NUM_SENSORS) {
+        ALOGE("%s: Invalid camera id: %d", __func__, camera_id);
+        return -EINVAL;
+    }
+
+    QCamera3HardwareInterface::getFlashInfo(camera_id,
+            hasFlash,
+            flashNode);
+
+    strlcat(flashPath,
+            flashNode,
+            sizeof(flashPath));
+
+    if (!hasFlash) {
+        ALOGE("%s: No flash available for camera id: %d",
+                __func__,
+                camera_id);
+        retVal = -EINVAL;
+    } else if (m_cameraOpen[camera_id]) {
+        ALOGE("%s: Camera in use for camera id: %d",
+                __func__,
+                camera_id);
+        retVal = -EBUSY;
+    } else if (m_flashFds[camera_id] >= 0) {
+        CDBG("%s: Flash is already inited for camera id: %d",
+                __func__,
+                camera_id);
+    } else {
+        m_flashFds[camera_id] = open(flashPath, O_RDWR | O_NONBLOCK);
+
+        if (m_flashFds[camera_id] < 0) {
+            ALOGE("%s: Unable to open node '%s'",
+                    __func__,
+                    flashPath);
+            retVal = -EBUSY;
+        } else {
+            struct msm_camera_led_cfg_t cfg;
+            cfg.cfgtype = MSM_CAMERA_LED_INIT;
+            retVal = ioctl(m_flashFds[camera_id],
+                    VIDIOC_MSM_FLASH_LED_DATA_CFG,
+                    &cfg);
+            if (retVal < 0) {
+                ALOGE("%s: Unable to init flash for camera id: %d",
+                        __func__,
+                        camera_id);
+                close(m_flashFds[camera_id]);
+                m_flashFds[camera_id] = -1;
+            }
+        }
+    }
+
+    return retVal;
+}
+
+/*===========================================================================
+ * FUNCTION   : setFlashMode
+ *
+ * DESCRIPTION: Turn on or off the flash associated with a given handle.
+ *              This function is blocking until the operation completes or
+ *              fails.
+ *
+ * PARAMETERS :
+ *   @camera_id  : Camera id of the flash
+ *   @on         : Whether to turn flash on (true) or off (false)
+ *
+ * RETURN     :
+ *   0        : success
+ *   -EINVAL  : No camera present at camera_id, or it is not inited.
+ *   -EALREADY: Flash is already in requested state
+ *==========================================================================*/
+int32_t QCameraFlash::setFlashMode(const int camera_id, const bool mode)
+{
+    int32_t retVal = 0;
+    struct msm_camera_led_cfg_t cfg;
+
+    if (camera_id < 0 || camera_id >= MM_CAMERA_MAX_NUM_SENSORS) {
+        ALOGE("%s: Invalid camera id: %d", __func__, camera_id);
+        retVal = -EINVAL;
+    } else if (mode == m_flashOn[camera_id]) {
+        CDBG("%s: flash %d is already in requested state: %d",
+                __func__,
+                camera_id,
+                mode);
+        retVal = -EALREADY;
+    } else if (m_flashFds[camera_id] < 0) {
+        ALOGE("%s: called for uninited flash: %d", __func__, camera_id);
+        retVal = -EINVAL;
+    }  else {
+        cfg.cfgtype = mode ? MSM_CAMERA_LED_LOW : MSM_CAMERA_LED_OFF;
+        retVal = ioctl(m_flashFds[camera_id],
+                VIDIOC_MSM_FLASH_LED_DATA_CFG,
+                &cfg);
+        if (retVal == 0) {
+            m_flashOn[camera_id] = mode;
+        }
+    }
+    return retVal;
+}
+
+/*===========================================================================
+ * FUNCTION   : deinitFlash
+ *
+ * DESCRIPTION: Release the flash unit associated with a given camera
+ *              position. This function is blocking until the operation
+ *              completes or fails.
+ *
+ * PARAMETERS :
+ *   @camera_id : Camera id of the flash.
+ *
+ * RETURN     :
+ *   0        : success
+ *   -EINVAL  : No camera present at camera_id or not inited.
+ *==========================================================================*/
+int32_t QCameraFlash::deinitFlash(const int camera_id)
+{
+    int32_t retVal = 0;
+
+    if (camera_id < 0 || camera_id >= MM_CAMERA_MAX_NUM_SENSORS) {
+        ALOGE("%s: Invalid camera id: %d", __func__, camera_id);
+        retVal = -EINVAL;
+    } else if (m_flashFds[camera_id] < 0) {
+        ALOGE("%s: called deinitFlash for uninited flash", __func__);
+        retVal = -EINVAL;
+    } else {
+        setFlashMode(camera_id, false);
+
+        struct msm_camera_led_cfg_t cfg;
+        cfg.cfgtype = MSM_CAMERA_LED_RELEASE;
+        retVal = ioctl(m_flashFds[camera_id],
+                VIDIOC_MSM_FLASH_LED_DATA_CFG,
+                &cfg);
+        if (retVal < 0) {
+            ALOGE("%s: Failed to release flash for camera id: %d",
+                    __func__,
+                    camera_id);
+        }
+
+        close(m_flashFds[camera_id]);
+        m_flashFds[camera_id] = -1;
+    }
+
+    return retVal;
+}
+
+/*===========================================================================
+ * FUNCTION   : reserveFlashForCamera
+ *
+ * DESCRIPTION: Give control of the flash to the camera, and notify
+ *              framework that the flash has become unavailable.
+ *
+ * PARAMETERS :
+ *   @camera_id : Camera id of the flash.
+ *
+ * RETURN     :
+ *   0        : success
+ *   -EINVAL  : No camera present at camera_id or not inited.
+ *   -ENOSYS  : No callback available for torch_mode_status_change.
+ *==========================================================================*/
+int32_t QCameraFlash::reserveFlashForCamera(const int camera_id)
+{
+    int32_t retVal = 0;
+
+    if (camera_id < 0 || camera_id >= MM_CAMERA_MAX_NUM_SENSORS) {
+        ALOGE("%s: Invalid camera id: %d", __func__, camera_id);
+        retVal = -EINVAL;
+    } else if (m_cameraOpen[camera_id]) {
+        CDBG("%s: Flash already reserved for camera id: %d",
+                __func__,
+                camera_id);
+    } else {
+        if (m_flashOn[camera_id]) {
+            setFlashMode(camera_id, false);
+            deinitFlash(camera_id);
+        }
+        m_cameraOpen[camera_id] = true;
+
+        if (m_callbacks == NULL ||
+                m_callbacks->torch_mode_status_change == NULL) {
+            ALOGE("%s: Callback is not defined!", __func__);
+            retVal = -ENOSYS;
+        } else {
+            char cameraIdStr[STRING_LENGTH_OF_64_BIT_NUMBER];
+            snprintf(cameraIdStr, STRING_LENGTH_OF_64_BIT_NUMBER,
+                    "%d", camera_id);
+            m_callbacks->torch_mode_status_change(m_callbacks,
+                    cameraIdStr,
+                    TORCH_MODE_STATUS_NOT_AVAILABLE);
+        }
+    }
+
+    return retVal;
+}
+
+/*===========================================================================
+ * FUNCTION   : releaseFlashFromCamera
+ *
+ * DESCRIPTION: Release control of the flash from the camera, and notify
+ *              framework that the flash has become available.
+ *
+ * PARAMETERS :
+ *   @camera_id : Camera id of the flash.
+ *
+ * RETURN     :
+ *   0        : success
+ *   -EINVAL  : No camera present at camera_id or not inited.
+ *   -ENOSYS  : No callback available for torch_mode_status_change.
+ *==========================================================================*/
+int32_t QCameraFlash::releaseFlashFromCamera(const int camera_id)
+{
+    int32_t retVal = 0;
+
+    if (camera_id < 0 || camera_id >= MM_CAMERA_MAX_NUM_SENSORS) {
+        ALOGE("%s: Invalid camera id: %d", __func__, camera_id);
+        retVal = -EINVAL;
+    } else if (!m_cameraOpen[camera_id]) {
+        CDBG("%s: Flash not reserved for camera id: %d",
+                __func__,
+                camera_id);
+    } else {
+        m_cameraOpen[camera_id] = false;
+
+        if (m_callbacks == NULL ||
+                m_callbacks->torch_mode_status_change == NULL) {
+            ALOGE("%s: Callback is not defined!", __func__);
+            retVal = -ENOSYS;
+        } else {
+            char cameraIdStr[STRING_LENGTH_OF_64_BIT_NUMBER];
+            snprintf(cameraIdStr, STRING_LENGTH_OF_64_BIT_NUMBER,
+                    "%d", camera_id);
+            m_callbacks->torch_mode_status_change(m_callbacks,
+                    cameraIdStr,
+                    TORCH_MODE_STATUS_AVAILABLE_OFF);
+        }
+    }
+
+    return retVal;
+}
+
+}; // namespace qcamera
diff --git a/camera/QCamera2/util/QCameraFlash.h b/camera/QCamera2/util/QCameraFlash.h
new file mode 100644
index 0000000..f86b6ee
--- /dev/null
+++ b/camera/QCamera2/util/QCameraFlash.h
@@ -0,0 +1,66 @@
+/* Copyright (c) 2015, The Linux Foundataion. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ *       copyright notice, this list of conditions and the following
+ *       disclaimer in the documentation and/or other materials provided
+ *       with the distribution.
+ *     * Neither the name of The Linux Foundation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef __QCAMERA_FLASH_H__
+#define __QCAMERA_FLASH_H__
+
+#include <hardware/camera_common.h>
+
+extern "C" {
+#include <mm_camera_interface.h>
+}
+
+namespace qcamera {
+
+class QCameraFlash {
+public:
+    static QCameraFlash& getInstance();
+
+    int32_t registerCallbacks(const camera_module_callbacks_t* callbacks);
+    int32_t initFlash(const int camera_id);
+    int32_t setFlashMode(const int camera_id, const bool on);
+    int32_t deinitFlash(const int camera_id);
+    int32_t reserveFlashForCamera(const int camera_id);
+    int32_t releaseFlashFromCamera(const int camera_id);
+
+private:
+    QCameraFlash();
+    virtual ~QCameraFlash();
+    QCameraFlash(const QCameraFlash&);
+    QCameraFlash& operator=(const QCameraFlash&);
+
+    const camera_module_callbacks_t *m_callbacks;
+    int32_t m_flashFds[MM_CAMERA_MAX_NUM_SENSORS];
+    bool m_flashOn[MM_CAMERA_MAX_NUM_SENSORS];
+    bool m_cameraOpen[MM_CAMERA_MAX_NUM_SENSORS];
+};
+
+}; // namespace qcamera
+
+#endif /* __QCAMERA_FLASH_H__ */