/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2019, Google Inc. * * object.cpp - Base object */ #include #include #include #include "log.h" #include "message.h" #include "semaphore.h" #include "thread.h" #include "utils.h" /** * \file object.h * \brief Base object to support automatic signal disconnection */ namespace libcamera { LOG_DEFINE_CATEGORY(Object) /** * \class Object * \brief Base object to support automatic signal disconnection * * The Object class simplifies signal/slot handling for classes implementing * slots. By inheriting from Object, an object is automatically disconnected * from all connected signals when it gets destroyed. * * Object instances are bound to the thread of their parent, or the thread in * which they're created when they have no parent. When a message is posted to * an object, its handler will run in the object's thread. This allows * implementing easy message passing between threads by inheriting from the * Object class. * * Deleting an object from a thread other than the one the object is bound to is * unsafe, unless the caller ensures that the object isn't processing any * message concurrently. * * Object slots connected to signals will also run in the context of the * object's thread, regardless of whether the signal is emitted in the same or * in another thread. * * \sa Message, Signal, Thread */ /** * \brief Construct an Object instance * \param[in] parent The object parent * * The new Object instance is bound to the thread of its \a parent, or to the * current thread if the \a parent is nullptr. */ Object::Object(Object *parent) : parent_(parent), pendingMessages_(0) { thread_ = parent ? parent->thread() : Thread::current(); if (parent) parent->children_.push_back(this); } /** * \brief Destroy an Object instance * * Deleting an Object automatically disconnects all signals from the Object's * slots. All the Object's children are made orphan, but stay bound to their * current thread. */ Object::~Object() { /* * Move signals to a private list to avoid concurrent iteration and * deletion of items from Signal::disconnect(). */ std::list signals(std::move(signals_)); for (SignalBase *signal : signals) signal->disconnect(this); if (pendingMessages_) thread()->removeMessages(this); if (parent_) { auto it = std::find(parent_->children_.begin(), parent_->children_.end(), this); ASSERT(it != parent_->children_.end()); parent_->children_.erase(it); } for (auto child : children_) child->parent_ = nullptr; } /** * \brief Post a message to the object's thread * \param[in] msg The message * * This method posts the message \a msg to the message queue of the object's * thread, to be delivered to the object through the message() method in the * context of its thread. Message ownership is passed to the thread, and the * message will be deleted after being delivered. * * Messages are delivered through the thread's event loop. If the thread is not * running its event loop the message will not be delivered until the event * loop gets started. * * \context This function is \threadsafe. */ void Object::postMessage(std::unique_ptr msg) { thread()->postMessage(std::move(msg), this); } /** * \brief Message handler for the object * \param[in] msg The message * * This virtual method receives messages for the object. It is called in the * context of the object's thread, and can be overridden to process custom * messages. The parent Object::message() method shall be called for any * message not handled by the override method. * * The message \a msg is valid only for the duration of the call, no reference * to it shall be kept after this method returns. */ void Object::message(Message *msg) { switch (msg->type()) { case Message::InvokeMessage: { InvokeMessage *iMsg = static_cast(msg); Semaphore *semaphore = iMsg->semaphore(); iMsg->invoke(); if (semaphore) semaphore->release(); break; } default: break; } } /** * \fn R Object::invokeMethod() * \brief Invoke a method asynchronously on an Object instance * \param[in] func The object method to invoke * \param[in] type Connection type for method invocation * \param[in] args The method arguments * * This method invokes the member method \a func with arguments \a args, based * on the connection \a type. Depending on the type, the method will be called * synchronously in the same thread or asynchronously in the object's thread. * * Arguments \a args passed by value or reference are copied, while pointers * are passed untouched. The caller shall ensure that any pointer argument * remains valid until the method is invoked. * * \context This function is \threadsafe. * * \return For connection types ConnectionTypeDirect and * ConnectionTypeBlocking, return the return value of the invoked method. For * connection type ConnectionTypeQueued, return a default-constructed R value. */ /** * \fn Object::thread() * \brief Retrieve the thread the object is bound to * \context This function is \threadsafe. * \return The thread the object is bound to */ /** * \brief Move the object and all its children to a different thread * \param[in] thread The target thread * * This method moves the object and all its children from the current thread to * the new \a thread. * * Before the object is moved, a Message::ThreadMoveMessage message is sent to * it. The message() method can be reimplement in derived classes to be notified * of the upcoming thread move and perform any required processing. * * Moving an object that has a parent is not allowed, and causes undefined * behaviour. * * \context This function is thread-bound. */ void Object::moveToThread(Thread *thread) { ASSERT(Thread::current() == thread_); if (thread_ == thread) return; if (parent_) { LOG(Object, Error) << "Moving object to thread with a parent is not permitted"; return; } notifyThreadMove(); thread->moveObject(this); } void Object::notifyThreadMove() { Message msg(Message::ThreadMoveMessage); message(&msg); for (auto child : children_) child->notifyThreadMove(); } /** * \fn Object::parent() * \brief Retrieve the object's parent * \return The object's parent */ void Object::connect(SignalBase *signal) { signals_.push_back(signal); } void Object::disconnect(SignalBase *signal) { for (auto iter = signals_.begin(); iter != signals_.end(); ) { if (*iter == signal) iter = signals_.erase(iter); else iter++; } } } /* namespace libcamera */ n113'>113 114 115 116 117
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
 * Copyright (C) 2019, Google Inc.
 *
 * camera3_hal.cpp - Android Camera HALv3 module
 */

#include <hardware/camera_common.h>

#include "libcamera/internal/log.h"

#include "camera_device.h"
#include "camera_hal_manager.h"

using namespace libcamera;

LOG_DEFINE_CATEGORY(HAL)

static CameraHalManager cameraManager;

/*------------------------------------------------------------------------------
 * Android Camera HAL callbacks
 */

static int hal_get_number_of_cameras()
{
	return cameraManager.numCameras();
}

static int hal_get_camera_info(int id, struct camera_info *info)
{
	return cameraManager.getCameraInfo(id, info);
}

static int hal_set_callbacks(const camera_module_callbacks_t *callbacks)
{
	cameraManager.setCallbacks(callbacks);

	return 0;
}

static int hal_open_legacy([[maybe_unused]] const struct hw_module_t *module,
			   [[maybe_unused]] const char *id,
			   [[maybe_unused]] uint32_t halVersion,
			   [[maybe_unused]] struct hw_device_t **device)
{
	return -ENOSYS;
}

static int hal_set_torch_mode([[maybe_unused]] const char *camera_id,
			      [[maybe_unused]] bool enabled)
{
	return -ENOSYS;
}

/*
 * First entry point of the camera HAL module.
 *
 * Initialize the HAL but does not open any camera device yet (see hal_dev_open)
 */
static int hal_init()
{
	LOG(HAL, Info) << "Initialising Android camera HAL";

	cameraManager.init();

	return 0;
}

/*------------------------------------------------------------------------------
 * Android Camera Device
 */

static int hal_dev_open(const hw_module_t *module, const char *name,
			hw_device_t **device)
{
	LOG(HAL, Debug) << "Open camera " << name;

	int id = atoi(name);
	CameraDevice *camera = cameraManager.open(id, module);
	if (!camera) {
		LOG(HAL, Error)
			<< "Failed to open camera module '" << id << "'";
		return -ENODEV;
	}

	*device = &camera->camera3Device()->common;

	return 0;
}

static struct hw_module_methods_t hal_module_methods = {
	.open = hal_dev_open,
};

camera_module_t HAL_MODULE_INFO_SYM = {
	.common = {
		.tag = HARDWARE_MODULE_TAG,
		.module_api_version = CAMERA_MODULE_API_VERSION_2_4,
		.hal_api_version = HARDWARE_HAL_API_VERSION,
		.id = CAMERA_HARDWARE_MODULE_ID,
		.name = "libcamera camera HALv3 module",
		.author = "libcamera",
		.methods = &hal_module_methods,
		.dso = nullptr,
		.reserved = {},
	},

	.get_number_of_cameras = hal_get_number_of_cameras,
	.get_camera_info = hal_get_camera_info,
	.set_callbacks = hal_set_callbacks,
	.get_vendor_tag_ops = nullptr,
	.open_legacy = hal_open_legacy,
	.set_torch_mode = hal_set_torch_mode,
	.init = hal_init,
	.reserved = {},
};