/* Copyright (c) 2015-2016, 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
* 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.
*
*/
// System dependencies
#include <stdio.h>
#include <fcntl.h>
#include <media/msm_cam_sensor.h>
// Camera dependencies
#include "HAL3/QCamera3HWI.h"
#include "QCameraFlash.h"
extern "C" {
#include "mm_camera_dbg.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) {
LOGE("Invalid camera id: %d", camera_id);
return -EINVAL;
}
QCamera3HardwareInterface::getFlashInfo(camera_id,
hasFlash,
flashNode);
strlcat(flashPath,
flashNode,
sizeof(flashPath));
if (!hasFlash) {
LOGE("No flash available for camera id: %d",
camera_id);
retVal = -EINVAL;
} else if (m_cameraOpen[camera_id]) {
LOGE("Camera in use for camera id: %d",
camera_id);
retVal = -EBUSY;
} else if (m_flashFds[camera_id] >= 0) {
LOGD("Flash is already inited for camera id: %d",
camera_id);
} else {
m_flashFds[camera_id] = open(flashPath, O_RDWR | O_NONBLOCK);
if (m_flashFds[camera_id] < 0) {
LOGE("Unable to open node '%s'",
flashPath);
retVal = -EBUSY;
} else {
struct msm_flash_cfg_data_t cfg;
struct msm_flash_init_info_t init_info;
memset(&cfg, 0, sizeof(struct msm_flash_cfg_data_t));
memset(&init_info, 0, sizeof(struct msm_flash_init_info_t));
init_info.flash_driver_type = FLASH_DRIVER_DEFAULT;
cfg.cfg.flash_init_info = &init_info;
cfg.cfg_type = CFG_FLASH_INIT;
retVal = ioctl(m_flashFds[camera_id],
VIDIOC_MSM_FLASH_CFG,
&cfg);
if (retVal < 0) {
LOGE("Unable to init flash for camera id: %d",
camera_id);
close(m_flashFds[camera_id]);
m_flashFds[camera_id] = -1;
}
/* wait for PMIC to init */
usleep(5000);
}
}
LOGD("X, retVal = %d", retVal);
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_flash_cfg_data_t cfg;
if (camera_id < 0 || camera_id >= MM_CAMERA_MAX_NUM_SENSORS) {
LOGE("Invalid camera id: %d", camera_id);
retVal = -EINVAL;
} else if (mode == m_flashOn[camera_id]) {
LOGD("flash %d is already in requested state: %d",
camera_id,
mode);
retVal = -EALREADY;
} else if (m_flashFds[camera_id] < 0) {
LOGE("called for uninited flash: %d", camera_id);
retVal = -EINVAL;
} else {
memset(&cfg, 0, sizeof(struct msm_flash_cfg_data_t));
for (int i = 0; i < MAX_LED_TRIGGERS; i++)
cfg.flash_current[i] = QCAMERA_TORCH_CURRENT_VALUE;
cfg.cfg_type = mode ? CFG_FLASH_LOW: CFG_FLASH_OFF;
retVal = ioctl(m_flashFds[camera_id],
VIDIOC_MSM_FLASH_CFG,
&cfg);
if (retVal < 0) {
LOGE("Unable to change flash mode to %d for camera id: %d",
mode, camera_id);
} else
{
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) {
LOGE("Invalid camera id: %d", camera_id);
retVal = -EINVAL;
} else if (m_flashFds[camera_id] < 0) {
LOGE("called deinitFlash for uninited flash");
retVal = -EINVAL;
} else {
setFlashMode(camera_id, false);
struct msm_flash_cfg_data_t cfg;
cfg.cfg_type = CFG_FLASH_RELEASE;
retVal = ioctl(m_flashFds[camera_id],
VIDIOC_MSM_FLASH_CFG,
&cfg);
if (retVal < 0) {
LOGE("Failed to release flash for camera id: %d",
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) {
LOGE("Invalid camera id: %d", camera_id);
retVal = -EINVAL;
} else if (m_cameraOpen[camera_id]) {
LOGD("Flash already reserved for camera id: %d",
camera_id);
} else {
if (m_flashOn[camera_id]) {
setFlashMode(camera_id, false);
deinitFlash(camera_id);
}
m_cameraOpen[camera_id] = true;
bool hasFlash = false;
char flashNode[QCAMERA_MAX_FILEPATH_LENGTH];
QCamera3HardwareInterface::getFlashInfo(camera_id,
hasFlash,
flashNode);
if (m_callbacks == NULL ||
m_callbacks->torch_mode_status_change == NULL) {
LOGE("Callback is not defined!");
retVal = -ENOSYS;
} else if (!hasFlash) {
LOGD("Suppressing callback "
"because no flash exists for camera id: %d",
camera_id);
} 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) {
LOGE("Invalid camera id: %d", camera_id);
retVal = -EINVAL;
} else if (!m_cameraOpen[camera_id]) {
LOGD("Flash not reserved for camera id: %d",
camera_id);
} else {
m_cameraOpen[camera_id] = false;
bool hasFlash = false;
char flashNode[QCAMERA_MAX_FILEPATH_LENGTH];
QCamera3HardwareInterface::getFlashInfo(camera_id,
hasFlash,
flashNode);
if (m_callbacks == NULL ||
m_callbacks->torch_mode_status_change == NULL) {
LOGE("Callback is not defined!");
retVal = -ENOSYS;
} else if (!hasFlash) {
LOGD("Suppressing callback "
"because no flash exists for camera id: %d",
camera_id);
} 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