blob: bf51ae9664ffda04e794c4984dd8c969ea3be6a9 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "virtual_camera_device.h"
// #include "virtual_camera_stream.h"
#include <ddk/binding.h>
#include <ddk/debug.h>
#include <ddk/platform-defs.h>
#include <fbl/alloc_checker.h>
#include <fbl/unique_ptr.h>
namespace virtual_camera {
zx_status_t VirtualCameraDevice::Create(void* ctx, zx_device_t* parent) {
fbl::AllocChecker ac;
auto device = fbl::make_unique_checked<VirtualCameraDevice>(&ac, parent);
if (!ac.check()) {
return ZX_ERR_NO_MEMORY;
}
zx_status_t status = device->DdkAdd("virtual_camera");
if (status != ZX_OK) {
zxlogf(ERROR, "virtual_camera_device: Could not create virtual camera device: %d\n", status);
return status;
}
// device intentionally leaked as it is now held by DevMgr.
__UNUSED auto* dev = device.release();
return ZX_OK;
}
void VirtualCameraDevice::DdkUnbind() { DdkRemove(); }
void VirtualCameraDevice::DdkRelease() { delete this; }
zx_status_t VirtualCameraDevice::DdkMessage(fidl_msg_t* msg, fidl_txn_t* txn) {
zx_status_t status = fuchsia_hardware_camera_ControlV2_try_dispatch(this, txn, msg, &control_ops);
return status;
}
void VirtualCameraDevice::RemoveStream(uint64_t stream_id) { streams_.erase(stream_id); }
zx_status_t VirtualCameraDevice::GetFormats(uint32_t index, fidl_txn_t* txn) {
fuchsia_hardware_camera_VideoFormat formats[16] = {};
fuchsia_hardware_camera_VideoFormat format = {
.format = {.width = 640,
.height = 480,
.layers = 1,
.pixel_format =
{
.type = fuchsia_sysmem_PixelFormatType_BGRA32,
.has_format_modifier = false,
.format_modifier = {.value = 0},
},
.color_space = {.type = fuchsia_sysmem_ColorSpaceType_SRGB},
.planes = {{.byte_offset = 0, .bytes_per_row = 4 * 640},
{.byte_offset = 0, .bytes_per_row = 4 * 640},
{.byte_offset = 0, .bytes_per_row = 4 * 640},
{.byte_offset = 0, .bytes_per_row = 4 * 640}}},
.rate =
{
.frames_per_sec_numerator = 30,
.frames_per_sec_denominator = 1,
},
};
formats[0] = format;
return fuchsia_hardware_camera_ControlGetFormats_reply(txn, formats, 1, 1, ZX_OK);
}
zx_status_t VirtualCameraDevice::CreateStream(
const fuchsia_sysmem_BufferCollectionInfo* buffer_collection_info,
const fuchsia_camera_common_FrameRate* rate, zx_handle_t stream, zx_handle_t stream_token) {
zx::eventpair stream_event_token = zx::eventpair(stream_token);
zx::channel stream_channel = zx::channel(stream);
fbl::AllocChecker ac;
auto new_stream = fbl::make_unique_checked<VirtualCameraStream>(&ac, this, count_,
std::move(stream_event_token));
if (!ac.check()) {
return ZX_ERR_NO_MEMORY;
}
zx_status_t status = new_stream->Bind(async_get_default_dispatcher(), std::move(stream_channel));
if (status != ZX_OK) {
return status;
}
status = new_stream->Init(buffer_collection_info);
if (status != ZX_OK) {
return status;
}
streams_[count_] = std::move(new_stream);
count_++;
return status;
}
zx_status_t VirtualCameraDevice::GetDeviceInfo(fidl_txn_t* txn) {
fuchsia_hardware_camera_DeviceInfo info;
info.output_capabilities = fuchsia_hardware_camera_CAMERA_OUTPUT_STREAM;
info.max_stream_count = 1;
return fuchsia_hardware_camera_ControlGetDeviceInfo_reply(txn, &info);
}
static constexpr zx_driver_ops_t driver_ops = []() {
zx_driver_ops_t ops = {};
ops.version = DRIVER_OPS_VERSION;
ops.bind = VirtualCameraDevice::Create;
return ops;
}();
} // namespace virtual_camera
// clang-format off
ZIRCON_DRIVER_BEGIN(virtual_camera, virtual_camera::driver_ops, "vcamera", "0.1", 3)
BI_ABORT_IF(NE, BIND_PLATFORM_DEV_VID, PDEV_VID_TEST),
BI_ABORT_IF(NE, BIND_PLATFORM_DEV_PID, PDEV_PID_VCAMERA_TEST),
BI_MATCH_IF(EQ, BIND_PLATFORM_DEV_DID, PDEV_DID_TEST_VCAMERA),
ZIRCON_DRIVER_END(virtual_camera)
// clang-format on