/**
* struct dma_buf_sync - Synchronize with CPU access.
*
* When a DMA buffer is accessed from the CPU via mmap, it is not always
* possible to guarantee coherency between the CPU-visible map and underlying
* memory. To manage coherency, DMA_BUF_IOCTL_SYNC must be used to bracket
* any CPU access to give the kernel the chance to shuffle memory around if
* needed.
*
* Prior to accessing the map, the client must call DMA_BUF_IOCTL_SYNC
* with DMA_BUF_SYNC_START and the appropriate read/write flags. Once the
* access is complete, the client should call DMA_BUF_IOCTL_SYNC with
* DMA_BUF_SYNC_END and the same read/write flags.
*
* The synchronization provided via DMA_BUF_IOCTL_SYNC only provides cache
* coherency. It does not prevent other processes or devices from
* accessing the memory at the same time. If synchronization with a GPU or
* other device driver is required, it is the client's responsibility to
* wait for buffer to be ready for reading or writing before calling this
* ioctl with DMA_BUF_SYNC_START. Likewise, the client must ensure that
* follow-up work is not submitted to GPU or other device driver until
* after this ioctl has been called with DMA_BUF_SYNC_END?
*
* If the driver or API with which the client is interacting uses implicit
* synchronization, waiting for prior work to complete can be done via
* poll() on the DMA buffer file descriptor. If the driver or API requires
* explicit synchronization, the client may have to wait on a sync_file or
* other synchronization primitive outside the scope of the DMA buffer API.
*/
struct dma_buf_sync {
/**
* @flags: Set of access flags
*
* DMA_BUF_SYNC_START:
* Indicates the start of a map access session.
*
* DMA_BUF_SYNC_END:
* Indicates the end of a map access session.
*
* DMA_BUF_SYNC_READ:
* Indicates that the mapped DMA buffer will be read by the
* client via the CPU map.
*
* DMA_BUF_SYNC_WRITE:
* Indicates that the mapped DMA buffer will be written by the
* client via the CPU map.
*
* DMA_BUF_SYNC_RW:
* An alias for DMA_BUF_SYNC_READ | DMA_BUF_SYNC_WRITE.
*/
__u64 flags;
};
#define DMA_BUF_SYNC_READ (1 << 0)
#define DMA_BUF_SYNC_WRITE (2 << 0)
#define DMA_BUF_SYNC_RW (DMA_BUF_SYNC_READ | DMA_BUF_SYNC_WRITE)
#define DMA_BUF_SYNC_START (0 << 2)
#define DMA_BUF_SYNC_END (1 << 2)
#define DMA_BUF_SYNC_VALID_FLAGS_MASK \
(DMA_BUF_SYNC_RW | DMA_BUF_SYNC_END)
#define DMA_BUF_NAME_LEN 32
/**
* struct dma_buf_export_sync_file - Get a sync_file from a dma-buf
*
* Userspace can perform a DMA_BUF_IOCTL_EXPORT_SYNC_FILE to retrieve the
* current set of fences on a dma-buf file descriptor as a sync_file. CPU
* waits via poll() or other driver-specific mechanisms typically wait on
* whatever fences are on the dma-buf at the time the wait begins. This
* is similar except that it takes a snapshot of the current fences on the
* dma-buf for waiting later instead of waiting immediately. This is
* useful for modern graphics APIs such as Vulkan which assume an explicit
* synchronization model but still need to inter-operate with dma-buf.
*
* The intended usage pattern is the following:
*
* 1. Export a sync_file with flags corresponding to the expected GPU usage
* via DMA_BUF_IOCTL_EXPORT_SYNC_FILE.
*
* 2. Submit rendering work which uses the dma-buf. The work should wait on
* the exported sync file before rendering and produce another sync_file
* when complete.
*
* 3. Import the rendering-complete sync_file into the dma-buf with flags
* corresponding to the GPU usage via DMA_BUF_IOCTL_IMPORT_SYNC_FILE.
*
* Unlike doing implicit synchronization via a GPU kernel driver's exec ioctl,
* the above is not a single atomic operation. If userspace wants to ensure
* ordering via these fences, it is the respnosibility of userspace to use
* locks or other mechanisms to ensure that no other context adds fences or
* submits work between steps 1 and 3 above.
*/
struct dma_buf_export_sync_file {
/**
* @flags: Read/write flags
*
* Must be DMA_BUF_SYNC_READ, DMA_BUF_SYNC_WRITE, or both.
*
* If DMA_BUF_SYNC_READ is set and DMA_BUF_SYNC_WRITE is not set,
* the returned sync file waits on any writers of the dma-buf to
* complete. Waiting on the returned sync file is equivalent to
* poll() with POLLIN.
*
* If DMA_BUF_SYNC_WRITE is set, the returned sync file waits on
* any users of the dma-buf (read or write) to complete. Waiting
* on the returned sync file is equivalent to poll() with POLLOUT.
* If both DMA_BUF_SYNC_WRITE and DMA_BUF_SYNC_READ are set, this
* is equivalent to just DMA_BUF_SYNC_WRITE.
*/
__u32 flags;
/** @fd: Returned sync file descriptor */
__s32 fd;
};
/**
* struct dma_buf_import_sync_file - Insert a sync_file into a dma-buf
*
* Userspace can perform a DMA_BUF_IOCTL_IMPORT_SYNC_FILE to insert a
* sync_file into a dma-buf for the purposes of implicit synchronization
* with other dma-buf consumers. This allows clients using explicitly
* synchronized APIs such as Vulkan to inter-op with dma-buf consumers
* which expect implicit synchronization such as OpenGL or most media
* drivers/video.
*/
struct dma_buf_import_sync_file {
/**
* @flags: Read/write flags
*
* Must be DMA_BUF_SYNC_READ, DMA_BUF_SYNC_WRITE, or both.
*
* If DMA_BUF_SYNC_READ is set and DMA_BUF_SYNC_WRITE is not set,
* this inserts the sync_file as a read-only fence. Any subsequent
* implicitly synchronized writes to this dma-buf will wait on this
* fence but reads will not.
*
* If DMA_BUF_SYNC_WRITE is set, this inserts the sync_file as a
* write fence. All subsequent implicitly synchronized access to
* this dma-buf will wait on this fence.
*/
__u32 flags;
/** @fd: Sync file descriptor */
__s32 fd;
};
#define DMA_BUF_BASE 'b'
#define DMA_BUF_IOCTL_SYNC _IOW(DMA_BUF_BASE, 0, struct dma_buf_sync)
/* 32/64bitness of this uapi was botched in android, there's no difference
* between them in actual uapi, they're just different numbers.
*/
#define DMA_BUF_SET_NAME _IOW(DMA_BUF_BASE, 1, const char *)
#define DMA_BUF_SET_NAME_A _IOW(DMA_BUF_BASE, 1, __u32)
#define DMA_BUF_SET_NAME_B _IOW(DMA_BUF_BASE, 1, __u64)
#define DMA_BUF_IOCTL_EXPORT_SYNC_FILE _IOWR(DMA_BUF_BASE, 2, struct dma_buf_export_sync_file)
#define DMA_BUF_IOCTL_IMPORT_SYNC_FILE _IOW(DMA_BUF_BASE, 3, struct dma_buf_import_sync_file)
#endif
ef='#n134'>134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2019, Google Inc.
*
* camera_hal_manager.cpp - libcamera Android Camera Manager
*/
#include "camera_hal_manager.h"
#include <libcamera/camera.h>
#include <libcamera/property_ids.h>
#include "libcamera/internal/log.h"
#include "camera_device.h"
using namespace libcamera;
LOG_DECLARE_CATEGORY(HAL)
/*
* \class CameraHalManager
*
* The HAL camera manager is initializated at camera_module_t 'hal_init()' time
* and spawns its own thread where libcamera related events are dispatched to.
* It wraps the libcamera CameraManager operations and provides helpers for the
* camera_module_t operations, to retrieve the number of cameras in the system,
* their static information and to open camera devices.
*/
CameraHalManager::CameraHalManager()
: cameraManager_(nullptr), callbacks_(nullptr), numInternalCameras_(0),
nextExternalCameraId_(firstExternalCameraId_)
{
}
CameraHalManager::~CameraHalManager()
{
cameras_.clear();
if (cameraManager_) {
cameraManager_->stop();
delete cameraManager_;
cameraManager_ = nullptr;
}
}
int CameraHalManager::init()
{
cameraManager_ = new CameraManager();
/* Support camera hotplug. */
cameraManager_->cameraAdded.connect(this, &CameraHalManager::cameraAdded);
cameraManager_->cameraRemoved.connect(this, &CameraHalManager::cameraRemoved);
int ret = cameraManager_->start();
if (ret) {
LOG(HAL, Error) << "Failed to start camera manager: "
<< strerror(-ret);
delete cameraManager_;
cameraManager_ = nullptr;
return ret;
}
return 0;
}
CameraDevice *CameraHalManager::open(unsigned int id,
const hw_module_t *hardwareModule)
{
MutexLocker locker(mutex_);
if (!callbacks_) {
LOG(HAL, Error) << "Can't open camera before callbacks are set";
return nullptr;
}
CameraDevice *camera = cameraDeviceFromHalId(id);
if (!camera) {
LOG(HAL, Error) << "Invalid camera id '" << id << "'";
return nullptr;
}
if (camera->open(hardwareModule))
return nullptr;
LOG(HAL, Info) << "Open camera '" << id << "'";
return camera;
}
void CameraHalManager::cameraAdded(std::shared_ptr<Camera> cam)
{
unsigned int id;
bool isCameraExternal = false;
bool isCameraNew = false;
MutexLocker locker(mutex_);
/*
* Each camera is assigned a unique integer ID when it is seen for the
* first time. If the camera has been seen before, the previous ID is
* re-used.
*
* IDs starts from '0' for internal cameras and '1000' for external
* cameras.
*/
auto iter = cameraIdsMap_.find(cam->id());
if (iter != cameraIdsMap_.end()) {
id = iter->second;
} else {
isCameraNew = true;
/*
* Now check if this is an external camera and assign
* its id accordingly.
*/
if (cameraLocation(cam.get()) == properties::CameraLocationExternal) {
isCameraExternal = true;
id = nextExternalCameraId_;
} else {
id = numInternalCameras_;
}
}
/* Create a CameraDevice instance to wrap the libcamera Camera. */
std::shared_ptr<CameraDevice> camera = CameraDevice::create(id, std::move(cam));
int ret = camera->initialize();
if (ret) {
LOG(HAL, Error) << "Failed to initialize camera: " << cam->id();
return;
}
if (isCameraNew) {
cameraIdsMap_.emplace(cam->id(), id);
if (isCameraExternal)
nextExternalCameraId_++;
else
numInternalCameras_++;
}
cameras_.emplace_back(std::move(camera));
if (callbacks_)
callbacks_->camera_device_status_change(callbacks_, id,
CAMERA_DEVICE_STATUS_PRESENT);
LOG(HAL, Debug) << "Camera ID: " << id << " added successfully.";
}
void CameraHalManager::cameraRemoved(std::shared_ptr<Camera> cam)
{
MutexLocker locker(mutex_);
auto iter = std::find_if(cameras_.begin(), cameras_.end(),
[&cam](std::shared_ptr<CameraDevice> &camera) {
return cam == camera->camera();
});
if (iter == cameras_.end())
return;
/*
* CAMERA_DEVICE_STATUS_NOT_PRESENT should be set for external cameras
* only.
*/
unsigned int id = (*iter)->id();
if (id >= firstExternalCameraId_)
callbacks_->camera_device_status_change(callbacks_, id,
CAMERA_DEVICE_STATUS_NOT_PRESENT);
/*
* \todo Check if the camera is already open and running.
* Inform the framework about its absence before deleting its
* reference here.
*/
cameras_.erase(iter);
LOG(HAL, Debug) << "Camera ID: " << id << " removed successfully.";
}
int32_t CameraHalManager::cameraLocation(const Camera *cam)
{
const ControlList &properties = cam->properties();
if (!properties.contains(properties::Location))
return -1;
return properties.get(properties::Location);
}
CameraDevice *CameraHalManager::cameraDeviceFromHalId(unsigned int id)
{
auto iter = std::find_if(cameras_.begin(), cameras_.end(),
[id](std::shared_ptr<CameraDevice> &camera) {
return camera->id() == id;
});
if (iter == cameras_.end())
return nullptr;
return iter->get();
}
unsigned int CameraHalManager::numCameras() const
{
return numInternalCameras_;
}
int CameraHalManager::getCameraInfo(unsigned int id, struct camera_info *info)
{
if (!info)
return -EINVAL;
MutexLocker locker(mutex_);
CameraDevice *camera = cameraDeviceFromHalId(id);
if (!camera) {
LOG(HAL, Error) << "Invalid camera id '" << id << "'";
return -EINVAL;
}
info->facing = camera->facing();
info->orientation = camera->orientation();
info->device_version = CAMERA_DEVICE_API_VERSION_3_3;
info->resource_cost = 0;
info->static_camera_characteristics = camera->getStaticMetadata();
info->conflicting_devices = nullptr;
info->conflicting_devices_length = 0;
return 0;
}
void CameraHalManager::setCallbacks(const camera_module_callbacks_t *callbacks)
{
callbacks_ = callbacks;
MutexLocker locker(mutex_);
/*
* Some external cameras may have been identified before the callbacks_
* were set. Iterate all existing external cameras and mark them as
* CAMERA_DEVICE_STATUS_PRESENT explicitly.
*
* Internal cameras are already assumed to be present at module load
* time by the Android framework.
*/
for (std::shared_ptr<CameraDevice> &camera : cameras_) {
unsigned int id = camera->id();
if (id >= firstExternalCameraId_)
callbacks_->camera_device_status_change(callbacks_, id,
CAMERA_DEVICE_STATUS_PRESENT);
}
}
|